spark-server/internal/module/friend/model/friend_request.go
zhr ae9a71034d feat: implement Spark IM V3 modular monolith
Add HTTP /v1 MVC, TCP send path, groups with server-side member-avatar collage, object-storage upload, and friends/favorites around the architecture-v3 layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 19:52:11 +08:00

133 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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:申请人对对方的备注,同意后写入 friend_remarks"`
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: r.Source,
Reason: r.Reason, Remark: r.Remark, Status: 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: r.Source,
Reason: r.Reason, Remark: r.Remark, Status: 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, 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)
}