// Package logic is the admin application layer (popadmin ops over V3 data). package logic import ( "context" "errors" "time" adminentity "spark-server/internal/module/admin/entity" adminmodel "spark-server/internal/module/admin/model" friendentity "spark-server/internal/module/friend/entity" grouplogic "spark-server/internal/module/group/logic" userentity "spark-server/internal/module/user/entity" ) var ErrNotReady = errors.New("admin: repository not ready") // Service orchestrates admin use-cases. SQL lives in model.Repo. type UserDisabler interface { DisableAccount(ctx context.Context, userID int64) error } type Service struct { repo Repository groups *grouplogic.Service ids IDGen disabler UserDisabler } type IDGen interface { NextID() (int64, error) } // Repository is admin read/write over V3 tables. Model implements it. type Repository interface { ListUsers(ctx context.Context, emailLike string, page, size int) ([]adminmodel.UserRow, int64, error) UsersByEmail(ctx context.Context, email string) ([]adminmodel.UserRow, error) UserByID(ctx context.Context, id int64) (*adminmodel.UserRow, error) UsersByNickname(ctx context.Context, nickname string) ([]adminmodel.UserRow, error) UsersByDevice(ctx context.Context, deviceID string, deviceIDNum uint64) ([]adminmodel.UserRow, error) UsersByIP(ctx context.Context, ip string) ([]adminmodel.UserRow, error) SetUserStatusByEmail(ctx context.Context, email string, status userentity.Status) error SetNicknameByEmail(ctx context.Context, email, nickname string) error ClearAvatarByEmail(ctx context.Context, email string) error SameIPRank(ctx context.Context, limit int) ([]adminmodel.SameIPRankRow, error) LookupUserIDByEmail(ctx context.Context, email string) (int64, error) ListGroups(ctx context.Context, q string) ([]adminmodel.GroupRow, error) GroupByID(ctx context.Context, groupID int64) (*adminmodel.GroupRow, error) ActiveGroupOwner(ctx context.Context, groupID int64) (int64, error) ListGroupMembers(ctx context.Context, groupID int64) ([]adminmodel.GroupMemberRow, error) ListGroupMessages(ctx context.Context, groupID int64, limit int) ([]adminmodel.MessageRow, error) ListComplaints(ctx context.Context, limit int) ([]adminmodel.ComplaintRow, error) InsertComplaint(ctx context.Context, r *friendentity.Report) error ImStats(ctx context.Context) (*adminentity.ImStats, error) ListRecentMessages(ctx context.Context, fetchLimit int, from, to *time.Time) ([]adminmodel.MessageRow, error) ListUserConversations(ctx context.Context, userID int64) ([]adminmodel.ConversationRow, error) } func NewService(repo Repository, groups *grouplogic.Service, ids IDGen) *Service { return &Service{repo: repo, groups: groups, ids: ids} } func (s *Service) BindUserDisabler(d UserDisabler) { if s == nil { return } s.disabler = d } func (s *Service) ready() bool { return s != nil && s.repo != nil }