同步历史版本代码
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/perfect-panel/server/internal/model/user"
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type familyJoinResult struct {
|
||||
FamilyId int64
|
||||
OwnerUserId int64
|
||||
}
|
||||
|
||||
type familyBindingHelper struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func newFamilyBindingHelper(ctx context.Context, svcCtx *svc.ServiceContext) *familyBindingHelper {
|
||||
return &familyBindingHelper{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *familyBindingHelper) getUserEmailMethod(userId int64) (*user.AuthMethods, error) {
|
||||
method, err := h.svcCtx.UserModel.FindUserAuthMethodByUserId(h.ctx, "email", userId)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user email auth method failed")
|
||||
}
|
||||
return method, nil
|
||||
}
|
||||
|
||||
func (h *familyBindingHelper) validateJoinFamily(ownerUserId, memberUserId int64) error {
|
||||
if ownerUserId == memberUserId {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyAlreadyBound), "user already bound to this family")
|
||||
}
|
||||
|
||||
var ownerFamily user.UserFamily
|
||||
err := h.svcCtx.DB.WithContext(h.ctx).
|
||||
Unscoped().
|
||||
Model(&user.UserFamily{}).
|
||||
Where("owner_user_id = ? AND status = ?", ownerUserId, user.FamilyStatusActive).
|
||||
First(&ownerFamily).Error
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query owner family failed")
|
||||
}
|
||||
|
||||
var memberRecord user.UserFamilyMember
|
||||
err = h.svcCtx.DB.WithContext(h.ctx).
|
||||
Unscoped().
|
||||
Model(&user.UserFamilyMember{}).
|
||||
Where("user_id = ?", memberUserId).
|
||||
First(&memberRecord).Error
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query member family relation failed")
|
||||
}
|
||||
if err == nil {
|
||||
if ownerFamily.Id != 0 && memberRecord.FamilyId == ownerFamily.Id {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyAlreadyBound), "user already in this family")
|
||||
}
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyCrossBindForbidden), "user already belongs to another family")
|
||||
}
|
||||
|
||||
if ownerFamily.Id == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var activeCount int64
|
||||
if err = h.svcCtx.DB.WithContext(h.ctx).
|
||||
Model(&user.UserFamilyMember{}).
|
||||
Where("family_id = ? AND status = ?", ownerFamily.Id, user.FamilyMemberActive).
|
||||
Count(&activeCount).Error; err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "count family members failed")
|
||||
}
|
||||
if activeCount >= ownerFamily.MaxMembers {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyMemberLimitExceeded), "family member limit exceeded")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *familyBindingHelper) joinFamily(ownerUserId, memberUserId int64, source string) (*familyJoinResult, error) {
|
||||
if ownerUserId == memberUserId {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.FamilyAlreadyBound), "user already bound to this family")
|
||||
}
|
||||
|
||||
result := &familyJoinResult{
|
||||
OwnerUserId: ownerUserId,
|
||||
}
|
||||
|
||||
err := h.svcCtx.DB.WithContext(h.ctx).Transaction(func(tx *gorm.DB) error {
|
||||
ownerFamily, err := h.getOrCreateOwnerFamily(tx, ownerUserId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result.FamilyId = ownerFamily.Id
|
||||
|
||||
if err = h.ensureOwnerMember(tx, ownerFamily.Id, ownerUserId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var memberRecord user.UserFamilyMember
|
||||
err = tx.Unscoped().Model(&user.UserFamilyMember{}).Where("user_id = ?", memberUserId).First(&memberRecord).Error
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query member family relation failed")
|
||||
}
|
||||
memberExists := err == nil
|
||||
|
||||
if memberExists {
|
||||
if memberRecord.FamilyId == ownerFamily.Id {
|
||||
if memberRecord.Status == user.FamilyMemberActive {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyAlreadyBound), "user already in this family")
|
||||
}
|
||||
} else {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyCrossBindForbidden), "user already belongs to another family")
|
||||
}
|
||||
}
|
||||
|
||||
var activeCount int64
|
||||
if err = tx.Model(&user.UserFamilyMember{}).
|
||||
Where("family_id = ? AND status = ?", ownerFamily.Id, user.FamilyMemberActive).
|
||||
Count(&activeCount).Error; err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "count family members failed")
|
||||
}
|
||||
if activeCount >= ownerFamily.MaxMembers {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyMemberLimitExceeded), "family member limit exceeded")
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
if !memberExists {
|
||||
memberRecord = user.UserFamilyMember{
|
||||
FamilyId: ownerFamily.Id,
|
||||
UserId: memberUserId,
|
||||
Role: user.FamilyRoleMember,
|
||||
Status: user.FamilyMemberActive,
|
||||
JoinSource: source,
|
||||
JoinedAt: now,
|
||||
}
|
||||
if err = tx.Create(&memberRecord).Error; err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create family member failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
memberRecord.Status = user.FamilyMemberActive
|
||||
memberRecord.Role = user.FamilyRoleMember
|
||||
memberRecord.JoinSource = source
|
||||
memberRecord.JoinedAt = now
|
||||
memberRecord.LeftAt = nil
|
||||
if err = tx.Save(&memberRecord).Error; err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update family member failed")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (h *familyBindingHelper) getOrCreateOwnerFamily(tx *gorm.DB, ownerUserId int64) (*user.UserFamily, error) {
|
||||
var ownerFamily user.UserFamily
|
||||
err := tx.Unscoped().Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||
Model(&user.UserFamily{}).
|
||||
Where("owner_user_id = ?", ownerUserId).
|
||||
First(&ownerFamily).Error
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query owner family failed")
|
||||
}
|
||||
ownerFamily = user.UserFamily{
|
||||
OwnerUserId: ownerUserId,
|
||||
MaxMembers: user.DefaultFamilyMaxSize,
|
||||
Status: user.FamilyStatusActive,
|
||||
}
|
||||
if err = tx.Create(&ownerFamily).Error; err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create owner family failed")
|
||||
}
|
||||
} else if ownerFamily.Status != user.FamilyStatusActive || ownerFamily.DeletedAt.Valid {
|
||||
ownerFamily.Status = user.FamilyStatusActive
|
||||
ownerFamily.DeletedAt = gorm.DeletedAt{}
|
||||
if err = tx.Unscoped().Save(&ownerFamily).Error; err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "activate owner family failed")
|
||||
}
|
||||
}
|
||||
return &ownerFamily, nil
|
||||
}
|
||||
|
||||
func (h *familyBindingHelper) ensureOwnerMember(tx *gorm.DB, familyId, ownerUserId int64) error {
|
||||
var ownerMember user.UserFamilyMember
|
||||
err := tx.Unscoped().Model(&user.UserFamilyMember{}).Where("user_id = ?", ownerUserId).First(&ownerMember).Error
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query owner family member failed")
|
||||
}
|
||||
ownerMember = user.UserFamilyMember{
|
||||
FamilyId: familyId,
|
||||
UserId: ownerUserId,
|
||||
Role: user.FamilyRoleOwner,
|
||||
Status: user.FamilyMemberActive,
|
||||
JoinSource: "owner_init",
|
||||
JoinedAt: time.Now(),
|
||||
}
|
||||
if err = tx.Create(&ownerMember).Error; err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create owner family member failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if ownerMember.FamilyId != familyId {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyCrossBindForbidden), "owner already belongs to another family")
|
||||
}
|
||||
if ownerMember.Status != user.FamilyMemberActive || ownerMember.Role != user.FamilyRoleOwner || ownerMember.DeletedAt.Valid {
|
||||
ownerMember.Status = user.FamilyMemberActive
|
||||
ownerMember.Role = user.FamilyRoleOwner
|
||||
ownerMember.LeftAt = nil
|
||||
ownerMember.DeletedAt = gorm.DeletedAt{}
|
||||
if err = tx.Unscoped().Save(&ownerMember).Error; err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update owner family member failed")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user