Constraint: 切换 main 前必须保存当前七月分支全部项目进展,套餐生效提案仅属于 Iteration/7-11。 Rejected: 将七月套餐修复直接移植到 main | 两个分支的可靠投递架构不同。 Confidence: medium Scope-risk: broad Directive: 不得将本提交整体 cherry-pick 到 main;main 套餐热修必须基于其纯 Asynq 代码独立实施。 Tested: git diff --check;openspec validate fix-package-activation-starvation --strict。 Not-tested: 按用户要求未运行自动化测试;go build ./... 因当前审计改造中的 Enterprise 模型字面量和 role.recordFailure 参数类型错误未通过。
145 lines
5.3 KiB
Go
145 lines
5.3 KiB
Go
// Package role 提供角色默认信用模板的应用用例。
|
|
package role
|
|
|
|
import (
|
|
"context"
|
|
stdErrors "errors"
|
|
|
|
accessauditapp "github.com/break/junhong_cmp_fiber/internal/application/accessaudit"
|
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
|
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
|
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// PermissionChecker 检查平台账号是否拥有独立信用模板权限。
|
|
type PermissionChecker interface {
|
|
CheckPermission(ctx context.Context, userID uint, permCode string, platform string) (bool, error)
|
|
}
|
|
|
|
// DefaultCreditService 更新客户角色的新建代理默认信用模板。
|
|
type DefaultCreditService struct {
|
|
db *gorm.DB
|
|
permissionChecker PermissionChecker
|
|
accessAudit accessauditapp.Writer
|
|
}
|
|
|
|
// NewDefaultCreditService 创建角色默认信用模板服务。
|
|
func NewDefaultCreditService(db *gorm.DB, permissionChecker PermissionChecker, accessAudit accessauditapp.Writer) *DefaultCreditService {
|
|
return &DefaultCreditService{db: db, permissionChecker: permissionChecker, accessAudit: accessAudit}
|
|
}
|
|
|
|
// Update 更新模板;该操作不扫描或修改任何既有钱包。
|
|
func (s *DefaultCreditService) Update(ctx context.Context, roleID uint, enabled bool, limit int64) (*model.Role, error) {
|
|
operatorID := middleware.GetUserIDFromContext(ctx)
|
|
if operatorID == 0 {
|
|
return nil, errors.New(errors.CodeUnauthorized)
|
|
}
|
|
if err := s.authorize(ctx, operatorID); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := validateDefaultCredit(enabled, limit); err != nil {
|
|
return nil, err
|
|
}
|
|
var role model.Role
|
|
var beforeData map[string]any
|
|
err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Clauses().First(&role, roleID).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return errors.New(errors.CodeRoleNotFound)
|
|
}
|
|
return errors.Wrap(errors.CodeInternalError, err, "读取角色失败")
|
|
}
|
|
beforeData = defaultCreditAuditData(&role)
|
|
if role.RoleType != constants.RoleTypeCustomer {
|
|
return errors.New(errors.CodeInvalidParam, "只有客户角色可以配置新建代理默认信用")
|
|
}
|
|
|
|
result := tx.Model(&model.Role{}).
|
|
Where("id = ? AND role_type = ?", roleID, constants.RoleTypeCustomer).
|
|
Updates(map[string]any{
|
|
"default_credit_enabled": enabled,
|
|
"default_credit_limit": limit,
|
|
"updater": operatorID,
|
|
})
|
|
if result.Error != nil {
|
|
return errors.Wrap(errors.CodeInternalError, result.Error, "更新角色默认信用失败")
|
|
}
|
|
if result.RowsAffected != 1 {
|
|
return errors.New(errors.CodeConflict, "角色默认信用已发生变化,请刷新后重试")
|
|
}
|
|
role.DefaultCreditEnabled = enabled
|
|
role.DefaultCreditLimit = limit
|
|
role.Updater = operatorID
|
|
if s.accessAudit == nil {
|
|
return errors.New(errors.CodeInvalidStatus, "角色默认信用审计接缝未配置")
|
|
}
|
|
return s.accessAudit.WriteAccessChange(ctx, tx, accessauditapp.ChangeAudit{
|
|
ActionCode: constants.AuditActionRoleDefaultCreditUpdated, Summary: "更新角色默认信用模板", Result: constants.AuditResultSuccess,
|
|
OperatorID: operatorID, Role: &role, BeforeData: beforeData, AfterData: defaultCreditAuditData(&role),
|
|
})
|
|
})
|
|
if err != nil {
|
|
if role.ID != 0 {
|
|
accessauditapp.RecordFailure(ctx, s.db, s.accessAudit, accessauditapp.ChangeAudit{
|
|
ActionCode: constants.AuditActionRoleDefaultCreditUpdated, Summary: "更新角色默认信用模板失败",
|
|
Result: defaultCreditAuditResult(err), OperatorID: operatorID, Role: &role, BeforeData: beforeData,
|
|
}, err)
|
|
}
|
|
return nil, err
|
|
}
|
|
return &role, nil
|
|
}
|
|
|
|
func defaultCreditAuditData(role *model.Role) map[string]any {
|
|
return map[string]any{
|
|
"role_name": role.RoleName, "role_type": role.RoleType,
|
|
"default_credit_enabled": role.DefaultCreditEnabled, "default_credit_limit": role.DefaultCreditLimit,
|
|
}
|
|
}
|
|
|
|
func defaultCreditAuditResult(err error) string {
|
|
var appErr *errors.AppError
|
|
if !stdErrors.As(err, &appErr) {
|
|
return constants.AuditResultFailed
|
|
}
|
|
switch appErr.Code {
|
|
case errors.CodeInternalError, errors.CodeDatabaseError, errors.CodeRedisError:
|
|
return constants.AuditResultFailed
|
|
default:
|
|
return constants.AuditResultDenied
|
|
}
|
|
}
|
|
|
|
func (s *DefaultCreditService) authorize(ctx context.Context, operatorID uint) error {
|
|
userType := middleware.GetUserTypeFromContext(ctx)
|
|
if userType == constants.UserTypeSuperAdmin {
|
|
return nil
|
|
}
|
|
if userType != constants.UserTypePlatform || s.permissionChecker == nil {
|
|
return errors.New(errors.CodeForbidden, "无权限配置角色默认信用")
|
|
}
|
|
hasPermission, err := s.permissionChecker.CheckPermission(ctx, operatorID, constants.PermissionRoleDefaultCreditManage, constants.PlatformWeb)
|
|
if err != nil {
|
|
return errors.Wrap(errors.CodeInternalError, err, "检查角色默认信用权限失败")
|
|
}
|
|
if !hasPermission {
|
|
return errors.New(errors.CodeForbidden, "无权限配置角色默认信用")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateDefaultCredit(enabled bool, limit int64) error {
|
|
if limit < 0 {
|
|
return errors.New(errors.CodeInvalidParam, "默认信用额度不能为负数")
|
|
}
|
|
if enabled && limit == 0 {
|
|
return errors.New(errors.CodeInvalidParam, "启用默认信用时额度必须大于零")
|
|
}
|
|
if !enabled && limit != 0 {
|
|
return errors.New(errors.CodeInvalidParam, "关闭默认信用时额度必须为零")
|
|
}
|
|
return nil
|
|
}
|