各种配置项修复,优化到后台管理端配置

This commit is contained in:
shanshanzhong 2026-03-04 19:42:21 -08:00
parent 3415262017
commit 2215df8c0b
6 changed files with 157 additions and 20 deletions

View File

@ -0,0 +1,4 @@
DROP INDEX `idx_user_deleted_at` ON `user_auth_methods`;
ALTER TABLE `user_auth_methods`
DROP COLUMN `deleted_at`;

View File

@ -0,0 +1,4 @@
ALTER TABLE `user_auth_methods`
ADD COLUMN `deleted_at` DATETIME(3) DEFAULT NULL COMMENT 'Deletion Time';
CREATE INDEX `idx_user_deleted_at` ON `user_auth_methods` (`user_id`, `deleted_at`);

View File

@ -40,6 +40,25 @@ func (h *familyBindingHelper) getUserEmailMethod(userId int64) (*user.AuthMethod
return method, nil
}
func validateMemberJoinConflict(ownerFamilyId int64, memberRecord *user.UserFamilyMember) error {
if memberRecord == nil {
return nil
}
if ownerFamilyId != 0 && memberRecord.FamilyId == ownerFamilyId {
if memberRecord.Status == user.FamilyMemberActive {
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyAlreadyBound), "user already in this family")
}
return nil
}
if memberRecord.Status == user.FamilyMemberActive {
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyCrossBindForbidden), "user already belongs to another family")
}
return 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")
@ -49,13 +68,14 @@ func (h *familyBindingHelper) validateJoinFamily(ownerUserId, memberUserId int64
err := h.svcCtx.DB.WithContext(h.ctx).
Unscoped().
Model(&user.UserFamily{}).
Where("owner_user_id = ? AND status = ?", ownerUserId, user.FamilyStatusActive).
Where("owner_user_id = ?", ownerUserId).
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
memberExists := false
err = h.svcCtx.DB.WithContext(h.ctx).
Unscoped().
Model(&user.UserFamilyMember{}).
@ -65,10 +85,12 @@ func (h *familyBindingHelper) validateJoinFamily(ownerUserId, memberUserId int64
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")
memberExists = true
}
if memberExists {
if err = validateMemberJoinConflict(ownerFamily.Id, &memberRecord); err != nil {
return err
}
return errors.Wrapf(xerr.NewErrCode(xerr.FamilyCrossBindForbidden), "user already belongs to another family")
}
if ownerFamily.Id == 0 {
@ -116,12 +138,8 @@ func (h *familyBindingHelper) joinFamily(ownerUserId, memberUserId int64, source
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")
if err = validateMemberJoinConflict(ownerFamily.Id, &memberRecord); err != nil {
return err
}
}
@ -151,12 +169,16 @@ func (h *familyBindingHelper) joinFamily(ownerUserId, memberUserId int64, source
return nil
}
if memberRecord.FamilyId != ownerFamily.Id {
memberRecord.FamilyId = ownerFamily.Id
}
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 {
memberRecord.DeletedAt = gorm.DeletedAt{}
if err = tx.Unscoped().Save(&memberRecord).Error; err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update family member failed")
}
return nil

View File

@ -0,0 +1,107 @@
package user
import (
stderrors "errors"
"testing"
modelUser "github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/pkg/xerr"
pkgerrors "github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
func extractFamilyJoinCode(err error) uint32 {
if err == nil {
return 0
}
var codeErr *xerr.CodeError
if stderrors.As(pkgerrors.Cause(err), &codeErr) {
return codeErr.GetErrCode()
}
return 0
}
func TestValidateMemberJoinConflict(t *testing.T) {
ownerFamilyID := int64(11)
testCases := []struct {
name string
ownerFamily int64
memberRecord *modelUser.UserFamilyMember
wantCode uint32
}{
{
name: "no member record",
ownerFamily: ownerFamilyID,
wantCode: 0,
},
{
name: "same family active member",
ownerFamily: ownerFamilyID,
memberRecord: &modelUser.UserFamilyMember{
FamilyId: ownerFamilyID,
Status: modelUser.FamilyMemberActive,
},
wantCode: xerr.FamilyAlreadyBound,
},
{
name: "same family left member",
ownerFamily: ownerFamilyID,
memberRecord: &modelUser.UserFamilyMember{
FamilyId: ownerFamilyID,
Status: modelUser.FamilyMemberLeft,
},
wantCode: 0,
},
{
name: "same family removed member",
ownerFamily: ownerFamilyID,
memberRecord: &modelUser.UserFamilyMember{
FamilyId: ownerFamilyID,
Status: modelUser.FamilyMemberRemoved,
},
wantCode: 0,
},
{
name: "cross family active member",
ownerFamily: ownerFamilyID,
memberRecord: &modelUser.UserFamilyMember{
FamilyId: ownerFamilyID + 1,
Status: modelUser.FamilyMemberActive,
},
wantCode: xerr.FamilyCrossBindForbidden,
},
{
name: "cross family left member",
ownerFamily: ownerFamilyID,
memberRecord: &modelUser.UserFamilyMember{
FamilyId: ownerFamilyID + 1,
Status: modelUser.FamilyMemberLeft,
},
wantCode: 0,
},
{
name: "cross family removed member",
ownerFamily: ownerFamilyID,
memberRecord: &modelUser.UserFamilyMember{
FamilyId: ownerFamilyID + 1,
Status: modelUser.FamilyMemberRemoved,
},
wantCode: 0,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
err := validateMemberJoinConflict(testCase.ownerFamily, testCase.memberRecord)
if testCase.wantCode == 0 {
require.NoError(t, err)
return
}
require.Error(t, err)
require.Equal(t, testCase.wantCode, extractFamilyJoinCode(err))
})
}
}

View File

@ -36,12 +36,12 @@ func init() {
RegisterIPLimit: "Too many registrations",
EmailBindError: "Email already bound",
UserBindInviteCodeExist: "Invite code already bound",
FamilyMemberLimitExceeded: "Family member limit exceeded",
FamilyAlreadyBound: "Family already bound",
FamilyCrossBindForbidden: "Cross-family binding is forbidden",
FamilyNotExist: "Family does not exist",
FamilyStatusInvalid: "Family status is invalid",
FamilyOwnerOperationForbidden: "Owner operation is forbidden",
FamilyMemberLimitExceeded: "家庭成员数量已达上限",
FamilyAlreadyBound: "已绑定家庭组",
FamilyCrossBindForbidden: "禁止跨家庭组绑定",
FamilyNotExist: "家庭组不存在",
FamilyStatusInvalid: "家庭组状态无效",
FamilyOwnerOperationForbidden: "家庭组所有者不允许此操作",
// Node error
NodeExist: "Node already exists",

View File

@ -7,9 +7,9 @@ import (
)
func TestFamilyErrorCodeMessages(t *testing.T) {
require.Equal(t, "Family member limit exceeded", MapErrMsg(FamilyMemberLimitExceeded))
require.Equal(t, "Family already bound", MapErrMsg(FamilyAlreadyBound))
require.Equal(t, "Cross-family binding is forbidden", MapErrMsg(FamilyCrossBindForbidden))
require.Equal(t, "家庭成员数量已达上限", MapErrMsg(FamilyMemberLimitExceeded))
require.Equal(t, "已绑定家庭组", MapErrMsg(FamilyAlreadyBound))
require.Equal(t, "禁止跨家庭组绑定", MapErrMsg(FamilyCrossBindForbidden))
}
func TestFamilyErrorCodeIsRegistered(t *testing.T) {