修复气站合同用户权限与服务关系边界

This commit is contained in:
czl231
2026-08-18 22:49:14 +08:00
parent 61a61f916b
commit 9a31cadf5f
27 changed files with 635 additions and 59 deletions

View File

@@ -17,6 +17,12 @@ type gasUserListItem struct {
DeliveryBasicID uint64 `gorm:"column:delivery_basic_id" json:"delivery_basic_id"`
}
// gasUserDetail 标识用户是否仅因当前气站合同而可见,前端据此进入只读模式。
type gasUserDetail struct {
models.UserAccount
ContractReadonly bool `json:"contract_readonly"`
}
// scopedUserList 将用户列表与当前气站唯一有效服务关系绑定,避免返回跨站归属。
func scopedUserList(databaseService *gorm.DB, gasBasicID uint64) *gorm.DB {
return common.ActiveRecords(databaseService.Model(&models.UserAccount{})).
@@ -52,8 +58,35 @@ func GetUser(ctx *gin.Context) {
if !ok {
return
}
user, relation, ok := requireUser(ctx, ctx.Param("identity"), station.ID)
if !ok {
user, relation, err := findCurrentGasUser(impl.DBService, ctx.Param("identity"), station.ID)
contractReadonly := false
var contractDeliveryBasicID uint64
if err != nil {
contractUser, contractErr := findContractScopedUser(
impl.DBService, ctx.Param("identity"), station.ID, ctx.Query("contract_identity"),
)
err = contractErr
if err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
user = contractUser.UserAccount
contractReadonly = true
contractDeliveryBasicID = contractUser.ContractDeliveryBasicID
}
if contractReadonly {
// 合同范围只返回用户主档,不泄露地址、钱包或其他服务关系上下文。
detail := gasUserDetail{UserAccount: user, ContractReadonly: true}
response, responseErr := common.PublicResourceResponse(gin.H{
"user": detail,
"relation": gin.H{"delivery_basic_id": contractDeliveryBasicID},
"addresses": []models.UserAddress{},
})
if responseErr != nil {
infra.Response.Error(ctx, responseErr)
return
}
infra.Response.Success(ctx, response)
return
}
var addresses []models.UserAddress
@@ -69,15 +102,21 @@ func GetUser(ctx *gin.Context) {
infra.Response.Success(ctx, response)
}
// GetUserAvatar 返回与当前气站存在服务关系的用户受保护头像。
// GetUserAvatar 返回与当前气站存在服务关系或合同引用关系的用户受保护头像。
func GetUserAvatar(ctx *gin.Context) {
station, ok := currentGas(ctx)
if !ok {
return
}
user, _, ok := requireUser(ctx, ctx.Param("identity"), station.ID)
if !ok {
return
user, _, err := findCurrentGasUser(impl.DBService, ctx.Param("identity"), station.ID)
if err != nil {
contractUser, contractErr := findContractScopedUser(impl.DBService, ctx.Param("identity"), station.ID, "")
err = contractErr
if err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
user = contractUser.UserAccount
}
upload.ServeAvatar(ctx, user.Avatar)
}