spark-server/internal/module/friend/logic/accept.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

74 lines
2.4 KiB
Go

package logic
import (
"context"
"errors"
"strings"
"time"
"spark-server/internal/module/friend/entity"
"spark-server/internal/pkg/errs"
"spark-server/internal/pkg/i18n"
"spark-server/internal/pkg/reqctx"
"spark-server/internal/pkg/validate"
)
// AcceptInput creates a bidirectional friendship from a pending incoming request.
type AcceptInput struct {
RequestID int64 `json:"request_id" validate:"required,gt=0" label:"field.request_id" errmsg:"required:validate.friend.request_required"`
Remark string `json:"remark" validate:"omitempty,max=64" label:"field.remark" errmsg:"max:validate.friend.remark_invalid"`
}
type AcceptResult struct {
UID int64 `json:"uid"`
}
func (s *Service) Accept(ctx context.Context, userID int64, in AcceptInput) (*AcceptResult, error) {
if !s.ready() || userID <= 0 {
return nil, errs.ErrUnauthorized
}
if err := validate.StructLang(reqctx.Lang(ctx), in); err != nil {
return nil, err
}
req, err := s.repo.GetRequest(ctx, in.RequestID)
if err != nil {
return nil, err
}
lang := reqctx.Lang(ctx)
if req.ToUser != userID || req.Status != entity.RequestPending {
return nil, errs.ErrForbidden.WithMsg(i18n.T(lang, i18n.KeyFriendRequestInvalid, nil))
}
if err := s.canApply(ctx, userID, req.FromUser); err != nil {
if !errors.Is(err, errs.ErrDuplicate) {
return nil, err
}
}
if err := s.becomeFriends(ctx, req, userID, strings.TrimSpace(in.Remark)); err != nil {
return nil, err
}
return &AcceptResult{UID: req.FromUser}, nil
}
func (s *Service) becomeFriends(ctx context.Context, req *entity.Request, accepter int64, accepterRemark string) error {
now := time.Now()
rel := entity.NewRelation(req.FromUser, req.ToUser, now)
ids := []int64{req.ID}
if reverse, err := s.repo.GetRequestByPair(ctx, accepter, req.FromUser); err == nil && reverse.ID != req.ID {
ids = append(ids, reverse.ID)
}
remarks := make([]entity.Remark, 0, 2)
if strings.TrimSpace(req.Remark) != "" {
remarks = append(remarks, entity.Remark{UserID: req.FromUser, FriendID: req.ToUser, Text: req.Remark, UpdatedAt: now})
}
if accepterRemark != "" {
remarks = append(remarks, entity.Remark{UserID: accepter, FriendID: req.FromUser, Text: accepterRemark, UpdatedAt: now})
}
if err := s.repo.AcceptFriend(ctx, entity.AcceptParams{Relation: rel, Requests: ids, Remarks: remarks}); err != nil {
return err
}
if s.greeter != nil {
_ = s.greeter.BecameFriends(ctx, req.FromUser, req.ToUser)
}
return nil
}