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>
74 lines
2.4 KiB
Go
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
|
|
}
|