fix: 修复管理员更新用户信息时意外覆盖字段的问题
Build docker and publish / build (20.15.1) (push) Has been cancelled

- Enable/IsAdmin/OnlyFirstPurchase 改为 *bool,未传时不更新
- Avatar/Remark/ReferCode/ReferralPercentage 加空值保护
- getDeviceList: 恢复 hifastday@hifast.com 家庭成员受限逻辑

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 02:21:35 -07:00
parent 8bc8e81e95
commit 7d2f98b7c9
4 changed files with 105 additions and 35 deletions
+3 -3
View File
@@ -44,13 +44,13 @@ type (
Balance int64 `json:"balance"` Balance int64 `json:"balance"`
Commission int64 `json:"commission"` Commission int64 `json:"commission"`
ReferralPercentage uint8 `json:"referral_percentage"` ReferralPercentage uint8 `json:"referral_percentage"`
OnlyFirstPurchase bool `json:"only_first_purchase"` OnlyFirstPurchase *bool `json:"only_first_purchase"`
GiftAmount int64 `json:"gift_amount"` GiftAmount int64 `json:"gift_amount"`
Telegram int64 `json:"telegram"` Telegram int64 `json:"telegram"`
ReferCode string `json:"refer_code"` ReferCode string `json:"refer_code"`
RefererId int64 `json:"referer_id"` RefererId int64 `json:"referer_id"`
Enable bool `json:"enable"` Enable *bool `json:"enable"`
IsAdmin bool `json:"is_admin"` IsAdmin *bool `json:"is_admin"`
Remark string `json:"remark"` Remark string `json:"remark"`
} }
UpdateUserNotifySettingRequest { UpdateUserNotifySettingRequest {
@@ -119,14 +119,28 @@ func (l *UpdateUserBasicInfoLogic) UpdateUserBasicInfo(req *types.UpdateUserBasi
} }
userInfo.Commission = req.Commission userInfo.Commission = req.Commission
} }
userInfo.Avatar = req.Avatar if req.Avatar != "" {
userInfo.ReferCode = req.ReferCode userInfo.Avatar = req.Avatar
}
if req.ReferCode != "" {
userInfo.ReferCode = req.ReferCode
}
userInfo.RefererId = req.RefererId userInfo.RefererId = req.RefererId
userInfo.Enable = &req.Enable if req.Enable != nil {
userInfo.IsAdmin = &req.IsAdmin userInfo.Enable = req.Enable
userInfo.Remark = req.Remark }
userInfo.OnlyFirstPurchase = &req.OnlyFirstPurchase if req.IsAdmin != nil {
userInfo.ReferralPercentage = req.ReferralPercentage 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 req.Password != "" {
if userInfo.Id == 2 && isDemo { if userInfo.Id == 2 && isDemo {
@@ -2,6 +2,7 @@ package user
import ( import (
"context" "context"
"errors"
"github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc" "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/constant"
"github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/tool"
"gorm.io/gorm"
) )
// restrictedOwnerUserId 受限家主用户IDhifastday@hifast.com
// 该用户本人及其家庭成员只允许返回第一个设备
const restrictedOwnerUserId int64 = 37498
type GetDeviceListLogic struct { type GetDeviceListLogic struct {
logger.Logger logger.Logger
ctx context.Context 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) { func (l *GetDeviceListLogic) GetDeviceList() (resp *types.GetDeviceListResponse, err error) {
userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User) userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User)
// 只查当前用户自己的设备(不查家庭组其他成员的设备)
// 原始代码(保留以供对照): restricted, err := l.isRestrictedScope(userInfo.Id)
// 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)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// 只返回第一个设备,其余设备丢弃不返回给前端
// 原始代码(保留以供对照): if restricted {
// userRespList := make([]types.UserDevice, 0) // 受限逻辑:hifastday@hifast.com (userId=37498) 本人及其家庭成员
// tool.DeepCopy(&userRespList, list) // 只返回当前用户自己的第一个设备,其余丢弃
// for i, d := range list { // 原始代码(保留以供对照):
// if i < len(userRespList) { // scopeHelper := newFamilyScopeHelper(l.ctx, l.svcCtx)
// userRespList[i].DeviceNo = tool.DeviceIdToHash(d.Id) // scopeUserIds, err := scopeHelper.resolveScopedUserIds(userInfo.Id)
// } // if err != nil { return nil, err }
// } // list, count, err := l.svcCtx.UserModel.QueryDeviceListByUserIds(l.ctx, scopeUserIds)
userRespList := make([]types.UserDevice, 0, 1) // ...for 循环为所有设备赋 DeviceNo
if len(list) > 0 { 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 var item types.UserDevice
tool.DeepCopy(&item, list[0]) tool.DeepCopy(&item, d)
item.DeviceNo = tool.DeviceIdToHash(list[0].Id) item.DeviceNo = tool.DeviceIdToHash(d.Id)
userRespList = append(userRespList, item) userRespList = append(userRespList, item)
} }
resp = &types.GetDeviceListResponse{ resp = &types.GetDeviceListResponse{
@@ -62,3 +94,27 @@ func (l *GetDeviceListLogic) GetDeviceList() (resp *types.GetDeviceListResponse,
} }
return return
} }
// isRestrictedScope 判断当前用户是否在受限范围内:
// 1. 当前用户本身即 restrictedOwnerUserIdhifastday@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
}
+3 -3
View File
@@ -3104,13 +3104,13 @@ type UpdateUserBasiceInfoRequest struct {
Balance int64 `json:"balance"` Balance int64 `json:"balance"`
Commission int64 `json:"commission"` Commission int64 `json:"commission"`
ReferralPercentage uint8 `json:"referral_percentage"` ReferralPercentage uint8 `json:"referral_percentage"`
OnlyFirstPurchase bool `json:"only_first_purchase"` OnlyFirstPurchase *bool `json:"only_first_purchase"`
GiftAmount int64 `json:"gift_amount"` GiftAmount int64 `json:"gift_amount"`
Telegram int64 `json:"telegram"` Telegram int64 `json:"telegram"`
ReferCode string `json:"refer_code"` ReferCode string `json:"refer_code"`
RefererId int64 `json:"referer_id"` RefererId int64 `json:"referer_id"`
Enable bool `json:"enable"` Enable *bool `json:"enable"`
IsAdmin bool `json:"is_admin"` IsAdmin *bool `json:"is_admin"`
Remark string `json:"remark"` Remark string `json:"remark"`
} }