diff --git a/cmd/telesrv/main.go b/cmd/telesrv/main.go index e297a8d8..060bf48c 100644 --- a/cmd/telesrv/main.go +++ b/cmd/telesrv/main.go @@ -1007,12 +1007,10 @@ func run(logger *zap.Logger) error { account.WithLoginEmailVerification(codeStore, loginEmailSender, cfg.AuthCodeTTL, cfg.AuthCodeMaxAttempts, cfg.LoginEmailCodeLength)) } accountService := account.NewService(passwordStore, accountOptions...) - reservedUsernameStore := postgres.NewReservedUsernameStore(pool) botsService := botsapp.NewService(userStore, botStore, messageStore, botsapp.WithLogger(logger.Named("bots")), botsapp.WithBlockChecker(contactStore), botsapp.WithPublicChannelUsernameResolver(channelStore), - botsapp.WithReservedUsernames(reservedUsernameStore), botsapp.WithUserCache(userCache), botsapp.WithStickerSetCreator(filesService), botsapp.WithGifCatalogSource(filesService), @@ -1205,6 +1203,7 @@ func run(logger *zap.Logger) error { // Collectible (NFT) usernames are an optional read model projected at the // protocol edge. collectibleUsernameStore := postgres.NewCollectibleUsernameStore(pool) + reservedUsernameStore := postgres.NewReservedUsernameStore(pool) usernamesService := usernamesapp.NewService( usernamesapp.WithRegistryStore(collectibleUsernameStore), usernamesapp.WithCollectibleStore(collectibleUsernameStore), diff --git a/internal/app/bots/service.go b/internal/app/bots/service.go index ac564336..fe171cad 100644 --- a/internal/app/bots/service.go +++ b/internal/app/bots/service.go @@ -121,7 +121,6 @@ type Service struct { messages store.MessageStore blocker blockChecker channels publicChannelUsernameResolver - reserved reservedUsernameChecker stickers stickerSetCreator installer userStickerSetInstaller aiChat aiChatGenerator @@ -200,21 +199,6 @@ func WithBotAvatarStore(a botAvatarStore) Option { // WithPublicChannelUsernameResolver 注入公开频道 username 查询能力,用于 bot // username 预检,避免 bot 与 public channel 产生同名可见入口。 -// reservedUsernameChecker reports whether a name is on the operator blocklist. -type reservedUsernameChecker interface { - IsReserved(ctx context.Context, usernameLower string) (bool, error) -} - -// WithReservedUsernames wires the operator username blocklist so CheckUsername -// reports a reserved bot name as taken instead of available. -func WithReservedUsernames(c reservedUsernameChecker) Option { - return func(s *Service) { - if c != nil { - s.reserved = c - } - } -} - func WithPublicChannelUsernameResolver(c publicChannelUsernameResolver) Option { return func(s *Service) { if c != nil { @@ -549,13 +533,6 @@ func (s *Service) CheckUsername(ctx context.Context, ownerUserID int64, username if !domain.ValidBotUsername(username) { return false, domain.ErrBotUsernameInvalid } - if s.reserved != nil { - if r, err := s.reserved.IsReserved(ctx, strings.ToLower(username)); err != nil { - return false, err - } else if r { - return false, nil - } - } if _, found, err := s.users.ByUsername(ctx, username); err != nil { return false, err } else if found { diff --git a/internal/store/memory/channel_settings.go b/internal/store/memory/channel_settings.go index c5c173cc..14f9089e 100644 --- a/internal/store/memory/channel_settings.go +++ b/internal/store/memory/channel_settings.go @@ -128,9 +128,6 @@ func (s *ChannelStore) CheckUsername(_ context.Context, userID, channelID int64, return false, err } usernameLower := strings.ToLower(strings.TrimSpace(strings.TrimPrefix(username, "@"))) - if s.usernameRegistry != nil && s.usernameRegistry.nameReserved(usernameLower) { - return false, nil - } for id, channel := range s.channels { if channel.Deleted || channel.Username == "" { continue diff --git a/internal/store/memory/collectible_username.go b/internal/store/memory/collectible_username.go index f4c79f8a..e53850f6 100644 --- a/internal/store/memory/collectible_username.go +++ b/internal/store/memory/collectible_username.go @@ -67,10 +67,8 @@ func (s *CollectibleUsernameStore) WithReservedUsernames(reserved *ReservedUsern return s } -// nameReserved reports whether a name is on the operator blocklist. It touches -// only s.reserved (its own lock), so it is safe from any context. -func (s *CollectibleUsernameStore) nameReserved(usernameLower string) bool { - if s == nil || s.reserved == nil { +func (s *CollectibleUsernameStore) nameReservedLocked(usernameLower string) bool { + if s.reserved == nil { return false } r, _ := s.reserved.IsReserved(context.Background(), usernameLower) @@ -121,7 +119,7 @@ func (s *CollectibleUsernameStore) SetEditableUsername(_ context.Context, peer d return false, domain.ErrUsernameInvalid } key := strings.ToLower(username) - if s.nameReserved(key) { + if s.nameReservedLocked(key) { return false, domain.ErrUsernameOccupied } if existing, ok := s.registry[key]; ok { @@ -336,7 +334,7 @@ func (s *CollectibleUsernameStore) MintCollectibleUsername(_ context.Context, re if _, ok := s.registry[key]; ok { return domain.CollectibleUsername{}, false, domain.ErrUsernameOccupied } - if s.nameReserved(key) { + if s.nameReservedLocked(key) { return domain.CollectibleUsername{}, false, domain.ErrUsernameOccupied } now := time.Now().UTC() diff --git a/internal/store/memory/reserved_username_test.go b/internal/store/memory/reserved_username_test.go deleted file mode 100644 index f6f01e9b..00000000 --- a/internal/store/memory/reserved_username_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package memory - -import ( - "context" - "testing" - - "telesrv/internal/domain" -) - -func TestCheckUsernameReportsReservedAsTaken(t *testing.T) { - ctx := context.Background() - reserved := NewReservedUsernameStore() - if _, err := reserved.ReserveUsername(ctx, "support", "official", "ops"); err != nil { - t.Fatalf("seed reserve: %v", err) - } - registry := NewCollectibleUsernameStore().WithReservedUsernames(reserved) - - users := NewUserStore() - users.AttachUsernameRegistry(registry) - u, _ := users.Create(ctx, domain.User{AccessHash: 1, Phone: "15550001000", FirstName: "A"}) - if ok, err := users.CheckUsername(ctx, u.ID, "support"); err != nil || ok { - t.Fatalf("CheckUsername(reserved) = %v, %v; want false, nil", ok, err) - } - if ok, err := users.CheckUsername(ctx, u.ID, "freename"); err != nil || !ok { - t.Fatalf("CheckUsername(free) = %v, %v; want true, nil", ok, err) - } - - channels := NewChannelStore() - channels.AttachUsernameRegistry(registry) - created, err := channels.CreateChannel(ctx, domain.CreateChannelRequest{CreatorUserID: u.ID, Title: "C", Megagroup: true, Date: 1}) - if err != nil { - t.Fatalf("create channel: %v", err) - } - if ok, err := channels.CheckUsername(ctx, u.ID, created.Channel.ID, "support"); err != nil || ok { - t.Fatalf("channel CheckUsername(reserved) = %v, %v; want false, nil", ok, err) - } -} diff --git a/internal/store/memory/users.go b/internal/store/memory/users.go index 0b3656c0..196851a7 100644 --- a/internal/store/memory/users.go +++ b/internal/store/memory/users.go @@ -158,9 +158,6 @@ func (s *UserStore) CheckUsername(_ context.Context, userID int64, username stri if username == "" { return true, nil } - if s.usernameRegistry != nil && s.usernameRegistry.nameReserved(username) { - return false, nil - } s.mu.RLock() defer s.mu.RUnlock() for id, u := range s.byID { diff --git a/internal/store/postgres/peer_username.go b/internal/store/postgres/peer_username.go index 7af1face..1de75769 100644 --- a/internal/store/postgres/peer_username.go +++ b/internal/store/postgres/peer_username.go @@ -77,11 +77,6 @@ func usernameReservedTx(ctx context.Context, db sqlcgen.DBTX, usernameLower stri } func peerUsernameAvailable(ctx context.Context, db sqlcgen.DBTX, usernameLower, peerType string, peerID int64) (bool, error) { - if reserved, err := usernameReservedTx(ctx, db, usernameLower); err != nil { - return false, err - } else if reserved { - return false, nil - } owner, found, err := getPeerUsernameOwner(ctx, db, usernameLower, false) if err != nil || !found { return !found, err