package model import ( "context" "time" "gorm.io/gorm" "gorm.io/gorm/clause" "spark-server/internal/module/friend/entity" "spark-server/internal/pkg/errs" ) // FriendRequest maps table friend_requests. type FriendRequest struct { ID int64 `gorm:"column:id;primaryKey;comment:Snowflake 申请 id"` FromUser int64 `gorm:"column:from_user;comment:申请人 user_id"` ToUser int64 `gorm:"column:to_user;comment:被申请人 user_id"` Source int `gorm:"column:source;comment:来源:1=二维码 2=邮箱 3=spark_id"` Reason string `gorm:"column:reason;comment:申请理由"` Remark string `gorm:"column:remark;comment:申请人对对方的备注,同意后写入自己的好友边"` Status int `gorm:"column:status;comment:1=待处理 2=已同意 3=已拒绝"` CreatedAt time.Time `gorm:"column:created_at;comment:首次申请时间"` UpdatedAt time.Time `gorm:"column:updated_at;comment:最近一次申请或处理时间"` } func (FriendRequest) TableName() string { return "friend_requests" } func (r *FriendRequest) entity() *entity.Request { if r == nil { return nil } return &entity.Request{ ID: r.ID, FromUser: r.FromUser, ToUser: r.ToUser, Source: entity.Source(r.Source), Reason: r.Reason, Remark: r.Remark, Status: entity.RequestStatus(r.Status), CreatedAt: r.CreatedAt, UpdatedAt: r.UpdatedAt, } } func requestFromEntity(r *entity.Request) FriendRequest { return FriendRequest{ ID: r.ID, FromUser: r.FromUser, ToUser: r.ToUser, Source: int(r.Source), Reason: r.Reason, Remark: r.Remark, Status: int(r.Status), CreatedAt: r.CreatedAt, UpdatedAt: r.UpdatedAt, } } func (m *Repo) GetRequest(ctx context.Context, id int64) (*entity.Request, error) { db, err := m.session(ctx) if err != nil { return nil, err } var row FriendRequest if err := db.Where("id = ?", id).Take(&row).Error; err != nil { return nil, mapDBErr(err) } return row.entity(), nil } func (m *Repo) GetRequestByPair(ctx context.Context, from, to int64) (*entity.Request, error) { db, err := m.session(ctx) if err != nil { return nil, err } var row FriendRequest if err := db.Where("from_user = ? AND to_user = ?", from, to).Take(&row).Error; err != nil { return nil, mapDBErr(err) } return row.entity(), nil } func (m *Repo) UpsertRequest(ctx context.Context, req *entity.Request) error { if req == nil || req.FromUser <= 0 || req.ToUser <= 0 { return errs.ErrInvalidArgument } db, err := m.session(ctx) if err != nil { return err } row := requestFromEntity(req) err = db.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "from_user"}, {Name: "to_user"}}, DoUpdates: clause.AssignmentColumns([]string{"source", "reason", "remark", "status", "updated_at"}), }).Create(&row).Error if err != nil { return mapDBErr(err) } saved, err := m.GetRequestByPair(ctx, req.FromUser, req.ToUser) if err != nil { return err } *req = *saved return nil } func (m *Repo) ListIncoming(ctx context.Context, toUserID int64, status entity.RequestStatus, limit int) ([]*entity.Request, error) { db, err := m.session(ctx) if err != nil { return nil, err } limit = entity.ClampLimit(limit) var rows []FriendRequest q := db.Where("to_user = ?", toUserID) if status > 0 { q = q.Where("status = ?", status) } if err := q.Order("updated_at DESC").Limit(limit).Find(&rows).Error; err != nil { return nil, mapDBErr(err) } out := make([]*entity.Request, 0, len(rows)) for i := range rows { out = append(out, rows[i].entity()) } return out, nil } func markRequestsAccepted(tx *gorm.DB, ids []int64, at time.Time) error { if len(ids) == 0 { return nil } return mapDBErr(tx.Model(&FriendRequest{}).Where("id IN ?", ids).Updates(map[string]any{ "status": entity.RequestAccepted, "updated_at": at, }).Error) } func rejectPairRequests(tx *gorm.DB, a, b int64, at time.Time) error { return mapDBErr(tx.Model(&FriendRequest{}). Where("(from_user = ? AND to_user = ?) OR (from_user = ? AND to_user = ?)", a, b, b, a). Where("status = ?", entity.RequestPending). Updates(map[string]any{"status": entity.RequestRejected, "updated_at": at}).Error) }