121 lines
4.4 KiB
Go
121 lines
4.4 KiB
Go
package logic
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
friendentity "spark-server/internal/module/friend/entity"
|
|
"spark-server/internal/module/moment/entity"
|
|
userentity "spark-server/internal/module/user/entity"
|
|
"spark-server/internal/pkg/media"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// Repository persists Moments. Model implements it.
|
|
type Repository interface {
|
|
CreatePost(ctx context.Context, post *entity.Post, audience []int64) error
|
|
GetPost(ctx context.Context, id int64) (*entity.Post, error)
|
|
ListByAuthors(ctx context.Context, authorIDs []int64, cursor int64, limit int) ([]*entity.Post, error)
|
|
ListByAuthor(ctx context.Context, authorID, cursor int64, limit int) ([]*entity.Post, error)
|
|
SoftDeletePost(ctx context.Context, userID, postID int64) (*entity.Post, error)
|
|
ListAudience(ctx context.Context, postIDs []int64) (map[int64][]int64, error)
|
|
ListLikes(ctx context.Context, postIDs []int64) (map[int64][]*entity.Like, error)
|
|
AddLike(ctx context.Context, like *entity.Like) (created bool, err error)
|
|
RemoveLike(ctx context.Context, postID, userID int64) error
|
|
ListComments(ctx context.Context, postIDs []int64) (map[int64][]*entity.Comment, error)
|
|
GetComment(ctx context.Context, id int64) (*entity.Comment, error)
|
|
AddComment(ctx context.Context, c *entity.Comment) error
|
|
SoftDeleteComment(ctx context.Context, id int64) error
|
|
CreateNotices(ctx context.Context, rows []*entity.Notice) error
|
|
ListNotices(ctx context.Context, userID, cursor int64, limit int) ([]*entity.Notice, error)
|
|
MarkNoticesRead(ctx context.Context, userID, cursor int64) error
|
|
GetSettings(ctx context.Context, userID int64) (*entity.Settings, error)
|
|
ListSettings(ctx context.Context, userIDs []int64) (map[int64]*entity.Settings, error)
|
|
UpsertSettings(ctx context.Context, s *entity.Settings) error
|
|
AdvanceRead(ctx context.Context, userID, postID int64) error
|
|
ListHides(ctx context.Context, userID int64) ([]*entity.Hide, error)
|
|
HideHimIDs(ctx context.Context, userID int64) ([]int64, error)
|
|
HideMeFromIDs(ctx context.Context, viewerID int64) ([]int64, error)
|
|
UpsertHide(ctx context.Context, h *entity.Hide) error
|
|
DeleteHide(ctx context.Context, userID, peerID int64) error
|
|
ListAllByAuthor(ctx context.Context, authorID int64) ([]*entity.Post, error)
|
|
PurgeUser(ctx context.Context, userID int64) error
|
|
}
|
|
|
|
// Friends is the friend graph used for visibility. Friend module implements it.
|
|
type Friends interface {
|
|
AreFriends(ctx context.Context, a, b int64) (bool, error)
|
|
ListFriendIDs(ctx context.Context, userID int64) ([]int64, error)
|
|
ListBlockedPeerIDs(ctx context.Context, userID int64) ([]int64, error)
|
|
Relation(ctx context.Context, userID, peerID int64) (*friendentity.Relation, error)
|
|
BlockedEither(ctx context.Context, a, b int64) (bool, error)
|
|
}
|
|
|
|
// Users loads profile cards.
|
|
type Users interface {
|
|
Get(ctx context.Context, id int64) (*userentity.User, error)
|
|
}
|
|
|
|
// Objects deletes Moments media. Nil skips GC.
|
|
type Objects interface {
|
|
Delete(ctx context.Context, key string) error
|
|
}
|
|
|
|
// IDGen issues Snowflake ids for posts, comments, and notices.
|
|
type IDGen interface {
|
|
NextID() (int64, error)
|
|
}
|
|
|
|
// Service is the Moments use-case layer (HTTP and TCP share it).
|
|
type Service struct {
|
|
repo Repository
|
|
friends Friends
|
|
users Users
|
|
objects Objects
|
|
ids IDGen
|
|
burst *burst
|
|
media media.Policy
|
|
log *zap.Logger
|
|
gate TextGate
|
|
}
|
|
|
|
func NewService(repo Repository, friends Friends, users Users, objects Objects, ids IDGen) *Service {
|
|
return &Service{repo: repo, friends: friends, users: users, objects: objects, ids: ids, burst: newBurst(), log: zap.NewNop()}
|
|
}
|
|
|
|
// ConfigureMedia sets user-path media detection (client compresses; server checks declared meta).
|
|
func (s *Service) ConfigureMedia(p media.Policy, log *zap.Logger) {
|
|
if s == nil {
|
|
return
|
|
}
|
|
s.media = p
|
|
if log != nil {
|
|
s.log = log
|
|
}
|
|
}
|
|
|
|
func (s *Service) ready() bool {
|
|
return s != nil && s.repo != nil && s.friends != nil && s.users != nil && s.ids != nil
|
|
}
|
|
|
|
// TextGate scans user-authored text. Nil skips the check.
|
|
type TextGate interface {
|
|
GateText(ctx context.Context, userID int64, text string) (string, error)
|
|
}
|
|
|
|
// BindModeration wires the shared sensitive-word gate.
|
|
func (s *Service) BindModeration(gate TextGate) {
|
|
if s == nil {
|
|
return
|
|
}
|
|
s.gate = gate
|
|
}
|
|
|
|
func (s *Service) gateText(ctx context.Context, userID int64, text string) (string, error) {
|
|
if s == nil || s.gate == nil || strings.TrimSpace(text) == "" {
|
|
return text, nil
|
|
}
|
|
return s.gate.GateText(ctx, userID, text)
|
|
}
|