owpengram-server/internal/rpc/username_notify.go
Egor Egorov fff8de783a
feat: add NFT usernames and bot verification (#22)
Implements collectible usernames, official verification workflows, and third-party bot verification after maintainer protocol and migration review.

The composite activity/moderation rating remains an admin-only read model; Telegram Stars Rating wire fields stay unset pending a dedicated official-semantics implementation.

Reviewed-Head: 2796345775ea0f908fb7734601e5e1dee4b653b9
Original-Head: fa082b892fd5180c9c9bc53c81c21cf5d250a75b

Co-authored-by: Egor Egorov <business.egor.sg@gmail.com>
2026-07-28 01:18:00 +08:00

64 lines
2.1 KiB
Go

package rpc
import (
"context"
"fmt"
"telesrv/internal/domain"
)
// NotifyPeerUsernamesChanged is the domain-only edge hook invoked after a
// collectible username registry mutation commits. It invalidates the cached
// peer projection and pushes the ordinary non-PTS updateUser/updateChannel
// refresh to online viewers. The shared projection paths preload the registry
// once, so fan-out cannot turn the change into an N+1 query.
func (r *Router) NotifyPeerUsernamesChanged(ctx context.Context, peer domain.Peer) error {
if r == nil {
return nil
}
if peer.ID <= 0 {
return fmt.Errorf("notify peer usernames changed: invalid peer id %d", peer.ID)
}
switch peer.Type {
case domain.PeerTypeUser:
return r.notifyUserUsernamesChanged(ctx, peer.ID)
case domain.PeerTypeChannel:
return r.notifyChannelUsernamesChanged(ctx, peer.ID)
default:
return fmt.Errorf("notify peer usernames changed: unsupported peer type %q for peer %d", peer.Type, peer.ID)
}
}
func (r *Router) notifyUserUsernamesChanged(ctx context.Context, userID int64) error {
r.invalidateRPCProjectionForUser(userID)
if r.deps.Users == nil {
return nil
}
user, found, err := r.verificationUser(ctx, userID)
if err != nil {
return fmt.Errorf("notify peer usernames changed: load user %d: %w", userID, err)
}
if !found || user.ID == 0 {
return fmt.Errorf("notify peer usernames changed: user %d not found", userID)
}
return r.NotifyUserModerationFlagsChanged(ctx, user)
}
func (r *Router) notifyChannelUsernamesChanged(ctx context.Context, channelID int64) error {
r.invalidateRPCProjectionForChannel(channelID)
if r.deps.Channels == nil {
return nil
}
directory, ok := r.deps.Channels.(verificationChannelDirectory)
if !ok {
return fmt.Errorf("notify peer usernames changed: channel service does not expose GetChannelByID")
}
channel, err := directory.GetChannelByID(ctx, channelID)
if err != nil {
return fmt.Errorf("notify peer usernames changed: load channel %d: %w", channelID, err)
}
if channel.ID == 0 {
return fmt.Errorf("notify peer usernames changed: channel %d not found", channelID)
}
return r.NotifyChannelChanged(ctx, channel)
}