84 lines
2.8 KiB
Go
84 lines
2.8 KiB
Go
package logic
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"spark-server/internal/module/group/entity"
|
|
"spark-server/internal/pkg/errs"
|
|
"spark-server/internal/pkg/i18n"
|
|
"spark-server/internal/pkg/reqctx"
|
|
"spark-server/internal/pkg/validate"
|
|
)
|
|
|
|
type CreateInput struct {
|
|
Name string `json:"name" validate:"required,min=1,max=32" label:"field.group_name" errmsg:"required:validate.group.name_required;min:validate.group.name_invalid;max:validate.group.name_invalid"`
|
|
MemberUIDs []int64 `json:"member_uids" validate:"required,min=1,max=199,dive,gt=0" label:"field.member_uids" errmsg:"required:validate.group.members_required;min:validate.group.members_required;max:validate.group.members_invalid"`
|
|
}
|
|
|
|
func (s *Service) Create(ctx context.Context, ownerID int64, in *CreateInput) (*View, error) {
|
|
if !s.ready() || ownerID <= 0 {
|
|
return nil, errs.ErrUnauthorized
|
|
}
|
|
if in == nil {
|
|
return nil, errs.ErrInvalidArgument
|
|
}
|
|
if err := validate.StructLang(reqctx.Lang(ctx), in); err != nil {
|
|
return nil, err
|
|
}
|
|
invitees, err := s.collectInvitees(ctx, ownerID, in.MemberUIDs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
convID, err := s.ids.NextID()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
now := nowMS()
|
|
g := &entity.Group{
|
|
ConversationID: convID, Name: strings.TrimSpace(in.Name),
|
|
OwnerID: ownerID, MemberCount: 1 + len(invitees), Status: entity.StatusActive,
|
|
CreatedAtMS: now, UpdatedAtMS: now,
|
|
}
|
|
members := ownerAndInvitees(g.ID, ownerID, invitees, now)
|
|
if err := s.repo.CreateGroup(ctx, g, members); err != nil {
|
|
return nil, err
|
|
}
|
|
s.invalidateMembers(g.ConversationID)
|
|
s.stampAvatar(ctx, g, ownerID, invitees)
|
|
_ = s.notice(ctx, g, ownerID, entity.SystemKindCreated, invitees)
|
|
return viewOf(g, &entity.Member{UserID: ownerID, Role: entity.RoleOwner}), nil
|
|
}
|
|
|
|
func (s *Service) collectInvitees(ctx context.Context, ownerID int64, uids []int64) ([]int64, error) {
|
|
lang := reqctx.Lang(ctx)
|
|
out := make([]int64, 0, len(uids))
|
|
for _, uid := range entity.UniqueUIDs(uids) {
|
|
if uid == ownerID {
|
|
continue
|
|
}
|
|
if err := s.activeUser(ctx, uid); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := s.requireFriend(ctx, ownerID, uid); err != nil {
|
|
return nil, err
|
|
}
|
|
out = append(out, uid)
|
|
}
|
|
if len(out) == 0 {
|
|
return nil, errs.ErrInvalidArgument.WithMsg(i18n.T(lang, i18n.KeyGroupMembersRequired, nil))
|
|
}
|
|
if 1+len(out) > entity.MaxMembers {
|
|
return nil, errs.ErrInvalidArgument.WithMsg(i18n.T(lang, i18n.KeyGroupFull, nil))
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func ownerAndInvitees(groupID, ownerID int64, invitees []int64, now int64) []*entity.Member {
|
|
members := []*entity.Member{{GroupID: groupID, UserID: ownerID, Role: entity.RoleOwner, JoinedAtMS: now}}
|
|
for _, uid := range invitees {
|
|
members = append(members, &entity.Member{GroupID: groupID, UserID: uid, Role: entity.RoleMember, JoinedAtMS: now})
|
|
}
|
|
return members
|
|
}
|