Merge remote-tracking branch 'upstream/main' into merge-gramsrv-2965f5d

This commit is contained in:
onysd 2026-07-20 23:43:51 +03:00
commit ebb0be38d9
355 changed files with 44640 additions and 2320 deletions

View file

@ -7,6 +7,7 @@ import (
"strings"
"sync"
"telesrv/internal/domain"
"time"
)
// UserStore 是 store.UserStore 的内存实现。ID 与 PG identity 使用同一业务起点。
@ -66,7 +67,7 @@ func (s *UserStore) ByPhone(_ context.Context, phone string) (domain.User, bool,
s.mu.RLock()
defer s.mu.RUnlock()
for _, u := range s.byID {
if u.Phone == phone {
if !u.Deleted && u.Phone == phone {
return u, true, nil
}
}
@ -105,6 +106,9 @@ func (s *UserStore) ByPhones(_ context.Context, phones []string) ([]domain.User,
out := make([]domain.User, 0, len(want))
seenIDs := map[int64]struct{}{}
for _, u := range s.byID {
if u.Deleted {
continue
}
if _, ok := want[u.Phone]; !ok {
continue
}
@ -126,7 +130,7 @@ func (s *UserStore) ByUsername(_ context.Context, username string) (domain.User,
s.mu.RLock()
defer s.mu.RUnlock()
for _, u := range s.byID {
if strings.ToLower(u.Username) == username {
if !u.Deleted && strings.ToLower(u.Username) == username {
return u, true, nil
}
}
@ -141,7 +145,7 @@ func (s *UserStore) CheckUsername(_ context.Context, userID int64, username stri
s.mu.RLock()
defer s.mu.RUnlock()
for id, u := range s.byID {
if strings.ToLower(u.Username) == username && id != userID {
if !u.Deleted && strings.ToLower(u.Username) == username && id != userID {
return false, nil
}
}
@ -161,7 +165,7 @@ func (s *UserStore) Search(_ context.Context, currentUserID int64, query, phoneQ
defer s.mu.RUnlock()
users := make([]domain.User, 0)
for _, u := range s.byID {
if u.ID == currentUserID {
if u.ID == currentUserID || u.Deleted {
continue
}
if userMatchesSearch(u, query, phoneQuery) {
@ -183,7 +187,7 @@ func (s *UserStore) UpdateUsername(_ context.Context, userID int64, username str
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok {
if !ok || u.Deleted {
return domain.User{}, domain.ErrUsernameNotOccupied
}
if usernameLower != "" {
@ -202,7 +206,7 @@ func (s *UserStore) UpdateProfile(_ context.Context, userID int64, firstName, la
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok {
if !ok || u.Deleted {
return domain.User{}, domain.ErrUsernameNotOccupied
}
u.FirstName = firstName
@ -216,7 +220,7 @@ func (s *UserStore) UpdateBirthday(_ context.Context, userID int64, birthday dom
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok {
if !ok || u.Deleted {
return domain.User{}, domain.ErrUserNotFound
}
u.Birthday = birthday
@ -228,7 +232,7 @@ func (s *UserStore) UpdatePersonalChannel(_ context.Context, userID int64, chann
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok {
if !ok || u.Deleted {
return domain.User{}, domain.ErrUserNotFound
}
u.PersonalChannelID = channelID
@ -242,7 +246,7 @@ func (s *UserStore) bumpBotInfoVersion(userID int64) (int, bool) {
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok || !u.Bot {
if !ok || u.Deleted || !u.Bot {
return 0, false
}
u.BotInfoVersion++
@ -255,7 +259,7 @@ func (s *UserStore) updateBotProfile(userID int64, setName bool, name string, se
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok || !u.Bot {
if !ok || u.Deleted || !u.Bot {
return false
}
if setName {
@ -273,7 +277,7 @@ func (s *UserStore) SetPremiumUntil(_ context.Context, userID int64, until int)
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok {
if !ok || u.Deleted {
return domain.User{}, domain.ErrUserNotFound
}
if until < 0 {
@ -289,7 +293,7 @@ func (s *UserStore) SetVerified(_ context.Context, userID int64, verified bool)
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok {
if !ok || u.Deleted {
return domain.User{}, domain.ErrUserNotFound
}
u.Verified = verified
@ -306,7 +310,7 @@ func (s *UserStore) SweepExpiredPremium(_ context.Context, now int64, limit int)
defer s.mu.Unlock()
out := make([]domain.User, 0)
for id, u := range s.byID {
if u.PremiumUntil <= 0 || int64(u.PremiumUntil) > now {
if u.Deleted || u.PremiumUntil <= 0 || int64(u.PremiumUntil) > now {
continue
}
u.PremiumUntil = 0
@ -320,19 +324,20 @@ func (s *UserStore) SweepExpiredPremium(_ context.Context, now int64, limit int)
return out, nil
}
// UpdateEmojiStatus 更新用户自定义 emoji statusdocumentID=0 表示清除)。
func (s *UserStore) UpdateEmojiStatus(_ context.Context, userID int64, documentID int64, until int) (domain.User, error) {
// UpdateEmojiStatus 更新用户自定义 emoji status零值表示清除)。
func (s *UserStore) UpdateEmojiStatus(_ context.Context, userID int64, status domain.UserEmojiStatus) (domain.User, error) {
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok {
if !ok || u.Deleted {
return domain.User{}, domain.ErrUserNotFound
}
if documentID == 0 {
until = 0
if !status.Valid() {
return domain.User{}, domain.ErrStarGiftCollectibleInvalid
}
u.EmojiStatusDocumentID = documentID
u.EmojiStatusUntil = until
u.EmojiStatusDocumentID = status.DocumentID
u.EmojiStatusUntil = status.Until
u.EmojiStatusCollectible = status.Collectible
s.byID[userID] = u
return u, nil
}
@ -341,7 +346,7 @@ func (s *UserStore) UpdateColor(_ context.Context, userID int64, forProfile bool
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok {
if !ok || u.Deleted {
return domain.User{}, domain.ErrUserNotFound
}
if forProfile {
@ -360,7 +365,7 @@ func (s *UserStore) UpdateLastSeen(_ context.Context, userID int64, lastSeenAt i
s.mu.Lock()
defer s.mu.Unlock()
u, ok := s.byID[userID]
if !ok {
if !ok || u.Deleted {
return domain.ErrUsernameNotOccupied
}
if lastSeenAt > u.LastSeenAt {
@ -405,6 +410,9 @@ func (s *UserStore) Create(_ context.Context, u domain.User) (domain.User, error
}
u.ID = s.nextID
s.nextID++
if u.CreatedAt.IsZero() {
u.CreatedAt = time.Now().UTC()
}
s.byID[u.ID] = u
return u, nil
}