welcome message: link @zio with a mention entity
This commit is contained in:
parent
4d781a52bb
commit
d4fe056854
2 changed files with 62 additions and 2 deletions
|
|
@ -10,6 +10,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// officialUpdatesChannelMention is the public @username of the updates channel
|
||||||
|
// linked from the welcome message when the resolved body includes it. It is
|
||||||
|
// carried in a MessageEntityMention wherever it appears in body so clients
|
||||||
|
// render it as a tappable link; the mention itself lives in the default
|
||||||
|
// templates in login_welcome_template.go (or an admin-panel override), not
|
||||||
|
// hardcoded here.
|
||||||
|
const officialUpdatesChannelMention = "@zio"
|
||||||
|
|
||||||
// OfficialWelcomeMessage builds the account-visible incoming message sent
|
// OfficialWelcomeMessage builds the account-visible incoming message sent
|
||||||
// from the official system account on every completed sign-in (SignUp and
|
// from the official system account on every completed sign-in (SignUp and
|
||||||
// every subsequent SignIn/SignInWithEmail), regardless of delivery channel.
|
// every subsequent SignIn/SignInWithEmail), regardless of delivery channel.
|
||||||
|
|
@ -28,13 +36,42 @@ func OfficialWelcomeMessage(userID int64, body string, date int) (Message, error
|
||||||
if userID <= 0 || IsSystemUserID(userID) || body == "" || date < 0 || date > math.MaxInt32 {
|
if userID <= 0 || IsSystemUserID(userID) || body == "" || date < 0 || date > math.MaxInt32 {
|
||||||
return Message{}, fmt.Errorf("%w: user=%d date=%d", ErrLoginCodeDeliveryInvalid, userID, date)
|
return Message{}, fmt.Errorf("%w: user=%d date=%d", ErrLoginCodeDeliveryInvalid, userID, date)
|
||||||
}
|
}
|
||||||
return Message{
|
msg := Message{
|
||||||
OwnerUserID: userID,
|
OwnerUserID: userID,
|
||||||
Peer: Peer{Type: PeerTypeUser, ID: OfficialSystemUserID},
|
Peer: Peer{Type: PeerTypeUser, ID: OfficialSystemUserID},
|
||||||
From: Peer{Type: PeerTypeUser, ID: OfficialSystemUserID},
|
From: Peer{Type: PeerTypeUser, ID: OfficialSystemUserID},
|
||||||
Date: date,
|
Date: date,
|
||||||
Body: body,
|
Body: body,
|
||||||
}, nil
|
}
|
||||||
|
if ent, ok := usernameMentionEntity(body, officialUpdatesChannelMention); ok {
|
||||||
|
msg.Entities = []MessageEntity{ent}
|
||||||
|
}
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// usernameMentionEntity locates mention ("@name") in text and returns a
|
||||||
|
// MessageEntityMention spanning it, with the UTF-16 offset/length clients expect.
|
||||||
|
func usernameMentionEntity(text, mention string) (MessageEntity, bool) {
|
||||||
|
before, _, found := strings.Cut(text, mention)
|
||||||
|
if !found {
|
||||||
|
return MessageEntity{}, false
|
||||||
|
}
|
||||||
|
return MessageEntity{
|
||||||
|
Type: MessageEntityMention,
|
||||||
|
Offset: utf16Len(before),
|
||||||
|
Length: utf16Len(mention),
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func utf16Len(s string) int {
|
||||||
|
n := 0
|
||||||
|
for _, r := range s {
|
||||||
|
n++
|
||||||
|
if r > 0xffff {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignInMethodLabel returns the human-readable method name embedded in
|
// SignInMethodLabel returns the human-readable method name embedded in
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package domain
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
"unicode/utf16"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWelcomeMessageContentAndFingerprint(t *testing.T) {
|
func TestWelcomeMessageContentAndFingerprint(t *testing.T) {
|
||||||
|
|
@ -52,3 +53,25 @@ func TestNextWelcomeRevision(t *testing.T) {
|
||||||
t.Fatalf("zero revision err = %v", err)
|
t.Fatalf("zero revision err = %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOfficialWelcomeMessageLinksUpdatesChannel(t *testing.T) {
|
||||||
|
body := "Welcome! Join " + officialUpdatesChannelMention + " for updates."
|
||||||
|
msg, err := OfficialWelcomeMessage(1780243200, body, 1_700_000_000)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("body %q: %v", body, err)
|
||||||
|
}
|
||||||
|
if len(msg.Entities) != 1 {
|
||||||
|
t.Fatalf("body %q: entities = %+v, want one mention", body, msg.Entities)
|
||||||
|
}
|
||||||
|
ent := msg.Entities[0]
|
||||||
|
if ent.Type != MessageEntityMention {
|
||||||
|
t.Fatalf("entity type = %q, want mention", ent.Type)
|
||||||
|
}
|
||||||
|
units := utf16.Encode([]rune(msg.Body))
|
||||||
|
if ent.Offset < 0 || ent.Length <= 0 || ent.Offset+ent.Length > len(units) {
|
||||||
|
t.Fatalf("entity %+v out of bounds for body of %d utf16 units", ent, len(units))
|
||||||
|
}
|
||||||
|
if got := string(utf16.Decode(units[ent.Offset : ent.Offset+ent.Length])); got != officialUpdatesChannelMention {
|
||||||
|
t.Fatalf("entity spans %q, want %q", got, officialUpdatesChannelMention)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue