From 7d2f98b7c95bbbe3aa33fd0fc86f47503048efb7 Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Thu, 7 May 2026 02:21:35 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=91=98=E6=9B=B4=E6=96=B0=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=97=B6=E6=84=8F=E5=A4=96=E8=A6=86=E7=9B=96=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enable/IsAdmin/OnlyFirstPurchase 改为 *bool,未传时不更新 - Avatar/Remark/ReferCode/ReferralPercentage 加空值保护 - getDeviceList: 恢复 hifastday@hifast.com 家庭成员受限逻辑 Co-Authored-By: Claude Sonnet 4.6 --- apis/admin/user.api | 6 +- .../admin/user/updateUserBasicInfoLogic.go | 28 +++-- .../logic/public/user/getDeviceListLogic.go | 100 ++++++++++++++---- internal/types/types.go | 6 +- 4 files changed, 105 insertions(+), 35 deletions(-) diff --git a/apis/admin/user.api b/apis/admin/user.api index 889a1cc..6965d40 100644 --- a/apis/admin/user.api +++ b/apis/admin/user.api @@ -44,13 +44,13 @@ type ( Balance int64 `json:"balance"` Commission int64 `json:"commission"` ReferralPercentage uint8 `json:"referral_percentage"` - OnlyFirstPurchase bool `json:"only_first_purchase"` + OnlyFirstPurchase *bool `json:"only_first_purchase"` GiftAmount int64 `json:"gift_amount"` Telegram int64 `json:"telegram"` ReferCode string `json:"refer_code"` RefererId int64 `json:"referer_id"` - Enable bool `json:"enable"` - IsAdmin bool `json:"is_admin"` + Enable *bool `json:"enable"` + IsAdmin *bool `json:"is_admin"` Remark string `json:"remark"` } UpdateUserNotifySettingRequest { diff --git a/internal/logic/admin/user/updateUserBasicInfoLogic.go b/internal/logic/admin/user/updateUserBasicInfoLogic.go index 60b711b..6a374c2 100644 --- a/internal/logic/admin/user/updateUserBasicInfoLogic.go +++ b/internal/logic/admin/user/updateUserBasicInfoLogic.go @@ -119,14 +119,28 @@ func (l *UpdateUserBasicInfoLogic) UpdateUserBasicInfo(req *types.UpdateUserBasi } userInfo.Commission = req.Commission } - userInfo.Avatar = req.Avatar - userInfo.ReferCode = req.ReferCode + if req.Avatar != "" { + userInfo.Avatar = req.Avatar + } + if req.ReferCode != "" { + userInfo.ReferCode = req.ReferCode + } userInfo.RefererId = req.RefererId - userInfo.Enable = &req.Enable - userInfo.IsAdmin = &req.IsAdmin - userInfo.Remark = req.Remark - userInfo.OnlyFirstPurchase = &req.OnlyFirstPurchase - userInfo.ReferralPercentage = req.ReferralPercentage + if req.Enable != nil { + userInfo.Enable = req.Enable + } + if req.IsAdmin != nil { + userInfo.IsAdmin = req.IsAdmin + } + if req.Remark != "" { + userInfo.Remark = req.Remark + } + if req.OnlyFirstPurchase != nil { + userInfo.OnlyFirstPurchase = req.OnlyFirstPurchase + } + if req.ReferralPercentage != 0 { + userInfo.ReferralPercentage = req.ReferralPercentage + } if req.Password != "" { if userInfo.Id == 2 && isDemo { diff --git a/internal/logic/public/user/getDeviceListLogic.go b/internal/logic/public/user/getDeviceListLogic.go index d592699..b2492d7 100644 --- a/internal/logic/public/user/getDeviceListLogic.go +++ b/internal/logic/public/user/getDeviceListLogic.go @@ -2,6 +2,7 @@ package user import ( "context" + "errors" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" @@ -9,8 +10,13 @@ import ( "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/tool" + "gorm.io/gorm" ) +// restrictedOwnerUserId 受限家主用户ID(hifastday@hifast.com) +// 该用户本人及其家庭成员只允许返回第一个设备 +const restrictedOwnerUserId int64 = 37498 + type GetDeviceListLogic struct { logger.Logger ctx context.Context @@ -28,32 +34,58 @@ func NewGetDeviceListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Get func (l *GetDeviceListLogic) GetDeviceList() (resp *types.GetDeviceListResponse, err error) { userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User) - // 只查当前用户自己的设备(不查家庭组其他成员的设备) - // 原始代码(保留以供对照): - // scopeHelper := newFamilyScopeHelper(l.ctx, l.svcCtx) - // scopeUserIds, err := scopeHelper.resolveScopedUserIds(userInfo.Id) - // if err != nil { - // return nil, err - // } - // list, count, err := l.svcCtx.UserModel.QueryDeviceListByUserIds(l.ctx, scopeUserIds) - list, count, err := l.svcCtx.UserModel.QueryDeviceList(l.ctx, userInfo.Id) + + restricted, err := l.isRestrictedScope(userInfo.Id) if err != nil { return nil, err } - // 只返回第一个设备,其余设备丢弃不返回给前端 - // 原始代码(保留以供对照): - // userRespList := make([]types.UserDevice, 0) - // tool.DeepCopy(&userRespList, list) - // for i, d := range list { - // if i < len(userRespList) { - // userRespList[i].DeviceNo = tool.DeviceIdToHash(d.Id) - // } - // } - userRespList := make([]types.UserDevice, 0, 1) - if len(list) > 0 { + + if restricted { + // 受限逻辑:hifastday@hifast.com (userId=37498) 本人及其家庭成员 + // 只返回当前用户自己的第一个设备,其余丢弃 + // 原始代码(保留以供对照): + // scopeHelper := newFamilyScopeHelper(l.ctx, l.svcCtx) + // scopeUserIds, err := scopeHelper.resolveScopedUserIds(userInfo.Id) + // if err != nil { return nil, err } + // list, count, err := l.svcCtx.UserModel.QueryDeviceListByUserIds(l.ctx, scopeUserIds) + // ...(for 循环为所有设备赋 DeviceNo) + var ownList []*user.Device + ownList, _, err = l.svcCtx.UserModel.QueryDeviceList(l.ctx, userInfo.Id) + if err != nil { + return nil, err + } + userRespList := make([]types.UserDevice, 0, 1) + if len(ownList) > 0 { + var item types.UserDevice + tool.DeepCopy(&item, ownList[0]) + item.DeviceNo = tool.DeviceIdToHash(ownList[0].Id) + userRespList = append(userRespList, item) + } + resp = &types.GetDeviceListResponse{ + Total: int64(len(userRespList)), + List: userRespList, + } + return + } + + // 正常逻辑:返回家庭范围内所有成员的设备(含 DeviceNo) + scopeHelper := newFamilyScopeHelper(l.ctx, l.svcCtx) + var scopeUserIds []int64 + scopeUserIds, err = scopeHelper.resolveScopedUserIds(userInfo.Id) + if err != nil { + return nil, err + } + var list []*user.Device + var count int64 + list, count, err = l.svcCtx.UserModel.QueryDeviceListByUserIds(l.ctx, scopeUserIds) + if err != nil { + return nil, err + } + userRespList := make([]types.UserDevice, 0, len(list)) + for _, d := range list { var item types.UserDevice - tool.DeepCopy(&item, list[0]) - item.DeviceNo = tool.DeviceIdToHash(list[0].Id) + tool.DeepCopy(&item, d) + item.DeviceNo = tool.DeviceIdToHash(d.Id) userRespList = append(userRespList, item) } resp = &types.GetDeviceListResponse{ @@ -62,3 +94,27 @@ func (l *GetDeviceListLogic) GetDeviceList() (resp *types.GetDeviceListResponse, } return } + +// isRestrictedScope 判断当前用户是否在受限范围内: +// 1. 当前用户本身即 restrictedOwnerUserId(hifastday@hifast.com) +// 2. 当前用户所在家庭的家主是 restrictedOwnerUserId(即通过该邮箱登录的其他设备用户) +func (l *GetDeviceListLogic) isRestrictedScope(currentUserId int64) (bool, error) { + if currentUserId == restrictedOwnerUserId { + return true, nil + } + var family user.UserFamily + err := l.svcCtx.DB.WithContext(l.ctx). + Model(&user.UserFamily{}). + Joins("JOIN user_family_member ON user_family_member.family_id = user_family.id AND user_family_member.user_id = ? AND user_family_member.status = ?", + currentUserId, user.FamilyMemberActive). + Where("user_family.owner_user_id = ? AND user_family.status = ? AND user_family.deleted_at IS NULL", + restrictedOwnerUserId, user.FamilyStatusActive). + First(&family).Error + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return false, nil + } + return false, err + } + return true, nil +} diff --git a/internal/types/types.go b/internal/types/types.go index 3948212..a15a87d 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -3104,13 +3104,13 @@ type UpdateUserBasiceInfoRequest struct { Balance int64 `json:"balance"` Commission int64 `json:"commission"` ReferralPercentage uint8 `json:"referral_percentage"` - OnlyFirstPurchase bool `json:"only_first_purchase"` + OnlyFirstPurchase *bool `json:"only_first_purchase"` GiftAmount int64 `json:"gift_amount"` Telegram int64 `json:"telegram"` ReferCode string `json:"refer_code"` RefererId int64 `json:"referer_id"` - Enable bool `json:"enable"` - IsAdmin bool `json:"is_admin"` + Enable *bool `json:"enable"` + IsAdmin *bool `json:"is_admin"` Remark string `json:"remark"` }