owpengram-server/internal/domain/welcome_message.go
Astra 69d64f3d80 welcome message: point updates-channel mention at @ziodotsh
Rename the official updates channel mention from @zio to @ziodotsh in the
welcome message template and update the affected send-message test.
2026-09-09 13:49:07 +01:00

77 lines
2.9 KiB
Go

package domain
import (
"fmt"
"math"
"strings"
)
// officialUpdatesChannelMention is the public @username of the updates channel
// linked from the welcome message. It is carried both in the template text and
// in a MessageEntityMention so clients render it as a tappable link.
const officialUpdatesChannelMention = "@ziodotsh"
const officialWelcomeMessageTemplate = "👋 Welcome to OwpenGram!\n\nYou just signed in via %s.\n\nIf this wasn't you, revoke this session from \"Settings > Privacy and Security > Active sessions\" immediately.\n\nIf you haven't already, feel free to join " + officialUpdatesChannelMention + " for all the latest updates!"
// OfficialWelcomeMessage builds the account-visible incoming message sent
// from the official system account on every completed sign-in (SignUp and
// every subsequent SignIn/SignInWithEmail), regardless of delivery channel.
// Unlike OfficialLoginCodeMessage this never embeds a secret, so it is safe
// to send unconditionally — it exists to give the account owner (and, on a
// self-hosted single-admin server, that's usually also "the admin") a
// visible record of every session start.
func OfficialWelcomeMessage(userID int64, method string, date int) (Message, error) {
method = strings.TrimSpace(method)
if userID <= 0 || IsSystemUserID(userID) || method == "" || date < 0 || date > math.MaxInt32 {
return Message{}, fmt.Errorf("%w: user=%d method=%q date=%d", ErrLoginCodeDeliveryInvalid, userID, method, date)
}
body := fmt.Sprintf(officialWelcomeMessageTemplate, method)
msg := Message{
OwnerUserID: userID,
Peer: Peer{Type: PeerTypeUser, ID: OfficialSystemUserID},
From: Peer{Type: PeerTypeUser, ID: OfficialSystemUserID},
Date: date,
Body: body,
}
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
// OfficialWelcomeMessage. Email-signup accounts are identified by
// SignupEmail (see NewEmailSignupDisplayPhone) rather than by their stored
// Phone, which — once assigned — is an ordinary-looking short number that
// carries no information about the signup method.
func SignInMethodLabel(u User) string {
if u.SignupEmail != "" {
return "email"
}
return "phone number"
}