One message per problem: a reminder replaces, a blip says nothing (issues 373 and 369)
The operator stopped believing the mesh's notifications: one problem stood twice on the desk (a reminder beside the message it followed, an escalation then a reminder 31 s later), a unit failing again at each apply was said again 22 times, and a question's buttons outlived it on a reminder the ask's end never reached. - messenger: a reminder or escalation is said in place of the problem's message (Replace under its handle), alone, never as a digest line; a problem first said in a digest gets its own message next time. A reminder counts from when it was last said. A clearing is said once it stays cleared 2 min (10 min once it came back); back before that, the message continues without a word. Cleared before ever said and back: said. An ask's expiry is said with its day. - desk-channel: a send or show under a handle already shown replaces its notification by the notifier's replace id. - telegram: the same deletes the earlier message and sends the new one, ringing as its kind rings; one it cannot delete loses its buttons.
This commit is contained in:
@@ -10,7 +10,8 @@ package main
|
||||
// handle). Up to 4096 characters arrive whole; longer is cut and the cut said (D1). A warning or a
|
||||
// clearing arrives without sound, an urgent message or a question rings (D4). A rate limit is waited out
|
||||
// as told (D5); a refusal is a permanent failure, said to the router, never retried; an edit to the same
|
||||
// text is a success (D6). A message that cannot be delivered after three tries is said as failed.
|
||||
// text is a success (D6). A message that cannot be delivered after three tries is said as failed. A
|
||||
// `send` or `show` under a handle already shown replaces that message: deleted, and the new one sent.
|
||||
// - **What arrives** is long-polled: outbound only. A tapped button is said as a `choice` with the sender
|
||||
// the service authenticated, and acknowledged on the phone with the router's word on it — what was
|
||||
// recorded, or why it was not — which comes as a reply to the tap; without one in TapWait, with words that
|
||||
@@ -232,11 +233,19 @@ func (c *Channel) Take(subject string, body json.RawMessage) error {
|
||||
words, buttons := text(m), c.buttons(m)
|
||||
silent := m.Silent || (!m.Urgent && len(buttons) == 0)
|
||||
var place *Placed
|
||||
if verb == asks.Edit {
|
||||
if verb == asks.Edit || !m.Secret {
|
||||
if place, err = c.Store.Placed(m.Handle); err != nil {
|
||||
return err // the state is away: offered again
|
||||
}
|
||||
}
|
||||
if verb != asks.Edit && place != nil {
|
||||
// **A message said again under a handle already shown replaces it** (issue 373): a reminder or an
|
||||
// escalation is one message per problem, not one more beside it. An edit here notifies nobody, so the
|
||||
// earlier message is deleted and this one sent, ringing as its kind rings; one the service will not
|
||||
// delete loses its buttons and says where the newer one is.
|
||||
c.replaced(*place)
|
||||
place = nil
|
||||
}
|
||||
for try := 1; ; try++ {
|
||||
var id int64
|
||||
switch {
|
||||
@@ -274,6 +283,19 @@ func (c *Channel) Take(subject string, body json.RawMessage) error {
|
||||
}
|
||||
}
|
||||
|
||||
// replaced takes an earlier message out of the chat: deleted, or where the service refuses that (a message
|
||||
// older than two days), its buttons taken away and the newer message named.
|
||||
func (c *Channel) replaced(p Placed) {
|
||||
err := c.Bot.Delete(p.Chat, p.ID)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
c.Logf("[telegram] an earlier message could not be deleted (%v); its buttons are taken away instead", err)
|
||||
if err := c.Bot.Edit(p.Chat, p.ID, "Replaced by a newer message below.", nil); err != nil && !gone(err) {
|
||||
c.Logf("[telegram] an earlier message could not be marked replaced either: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Channel) newMessage(handle string, chat int64, words string, buttons [][2]string, silent bool, id *int64) error {
|
||||
got, err := c.Bot.Send(chat, words, buttons, silent)
|
||||
if err != nil {
|
||||
|
||||
@@ -580,3 +580,48 @@ func TestAToastIsCutAtTelegramsBound(t *testing.T) {
|
||||
t.Errorf("toast %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 373: a reminder or an escalation is sent under the handle of the message it follows, and replaces it:
|
||||
// the earlier one leaves the chat and the new one rings as its kind rings. One the service will not delete
|
||||
// loses its buttons. A new handle is a new message, and nothing is deleted.
|
||||
func TestAMessageSaidAgainUnderItsHandleReplacesTheEarlierOne(t *testing.T) {
|
||||
c, f, _, st := newChannel(t, goodToken)
|
||||
subject, body := work(asks.Show, asks.Message{Handle: "m1", Title: "Urgent: ace silent", Urgent: true, To: "42",
|
||||
Buttons: []asks.Button{{Label: "Silence for a week", Ticket: "0123456789abcdef0123456789abcdef"}}})
|
||||
if err := c.Take(subject, body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
first := st.placed["m1"].ID
|
||||
subject, body = work(asks.Send, asks.Message{Handle: "m2", Title: "another problem", To: "42"})
|
||||
_ = c.Take(subject, body)
|
||||
if len(f.of("deleteMessage")) != 0 {
|
||||
t.Fatal("a new handle deleted a message")
|
||||
}
|
||||
subject, body = work(asks.Show, asks.Message{Handle: "m1", Title: "Still open: ace silent", Urgent: true, To: "42",
|
||||
Buttons: []asks.Button{{Label: "Silence for a week", Ticket: "fedcba9876543210fedcba9876543210"}}})
|
||||
if err := c.Take(subject, body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
del := f.of("deleteMessage")
|
||||
if len(del) != 1 || del[0].Body["message_id"] != float64(first) {
|
||||
t.Fatalf("the earlier message was not deleted: %+v", del)
|
||||
}
|
||||
sent := f.of("sendMessage")
|
||||
if len(sent) != 3 || sent[2].Body["disable_notification"] != false || st.placed["m1"].ID == first {
|
||||
t.Fatalf("the reminder was not sent ringing in its place: %d sends, placed %d", len(sent), st.placed["m1"].ID)
|
||||
}
|
||||
// The service refuses the delete: the earlier message loses its buttons instead.
|
||||
f.answer["deleteMessage"] = func(map[string]any) (int, string) {
|
||||
return 400, `{"ok":false,"error_code":400,"description":"Bad Request: message can't be deleted"}`
|
||||
}
|
||||
second := st.placed["m1"].ID
|
||||
subject, body = work(asks.Send, asks.Message{Handle: "m1", Title: "Now urgent: ace silent", Urgent: true, To: "42"})
|
||||
_ = c.Take(subject, body)
|
||||
ed := f.of("editMessageText")
|
||||
if len(ed) != 1 || ed[0].Body["message_id"] != float64(second) || !strings.Contains(ed[0].Body["text"].(string), "Replaced") {
|
||||
t.Fatalf("an undeletable earlier message kept its buttons: %+v", ed)
|
||||
}
|
||||
if kb, _ := json.Marshal(ed[0].Body["reply_markup"]); string(kb) != `{"inline_keyboard":[]}` {
|
||||
t.Errorf("its buttons stayed: %s", kb)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user