固化七月迭代审计治理进展以隔离线上热修
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 参数类型错误未通过。
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
accessauditapp "github.com/break/junhong_cmp_fiber/internal/application/accessaudit"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
@@ -12,26 +13,33 @@ import (
|
||||
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type AuthorizationService struct {
|
||||
db *gorm.DB
|
||||
enterpriseStore *postgres.EnterpriseStore
|
||||
iotCardStore *postgres.IotCardStore
|
||||
authorizationStore *postgres.EnterpriseCardAuthorizationStore
|
||||
logger *zap.Logger
|
||||
accessAudit accessauditapp.Writer
|
||||
}
|
||||
|
||||
func NewAuthorizationService(
|
||||
db *gorm.DB,
|
||||
enterpriseStore *postgres.EnterpriseStore,
|
||||
iotCardStore *postgres.IotCardStore,
|
||||
authorizationStore *postgres.EnterpriseCardAuthorizationStore,
|
||||
logger *zap.Logger,
|
||||
accessAudit accessauditapp.Writer,
|
||||
) *AuthorizationService {
|
||||
return &AuthorizationService{
|
||||
db: db,
|
||||
enterpriseStore: enterpriseStore,
|
||||
iotCardStore: iotCardStore,
|
||||
authorizationStore: authorizationStore,
|
||||
logger: logger,
|
||||
accessAudit: accessAudit,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,6 +413,9 @@ func (s *AuthorizationService) UpdateRecordRemark(ctx context.Context, id uint,
|
||||
if userID == 0 {
|
||||
return nil, errors.New(errors.CodeUnauthorized, "用户信息无效")
|
||||
}
|
||||
if s.db == nil || s.accessAudit == nil {
|
||||
return nil, errors.New(errors.CodeInvalidStatus, "企业卡授权审计接缝未配置")
|
||||
}
|
||||
|
||||
record, err := s.authorizationStore.GetByIDWithJoin(ctx, id)
|
||||
if err != nil {
|
||||
@@ -420,23 +431,97 @@ func (s *AuthorizationService) UpdateRecordRemark(ctx context.Context, id uint,
|
||||
case constants.UserTypeAgent:
|
||||
// 代理用户: 只能修改自己创建的授权记录
|
||||
if record.AuthorizedBy != userID {
|
||||
return nil, errors.New(errors.CodeForbidden, "只能修改自己创建的授权记录备注")
|
||||
err := errors.New(errors.CodeForbidden, "只能修改自己创建的授权记录备注")
|
||||
s.recordRemarkFailure(ctx, record, err)
|
||||
return nil, err
|
||||
}
|
||||
case constants.UserTypeEnterprise:
|
||||
// 企业用户: 禁止修改授权记录备注
|
||||
return nil, errors.New(errors.CodeForbidden, "企业用户不允许修改授权记录备注")
|
||||
err := errors.New(errors.CodeForbidden, "企业用户不允许修改授权记录备注")
|
||||
s.recordRemarkFailure(ctx, record, err)
|
||||
return nil, err
|
||||
default:
|
||||
return nil, errors.New(errors.CodeForbidden, "无权限修改授权记录备注")
|
||||
}
|
||||
|
||||
if err := s.authorizationStore.UpdateRemarkWithConstraint(ctx, id, remark, record.AuthorizedBy); err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, errors.New(errors.CodeNotFound, "授权记录不存在")
|
||||
}
|
||||
err := errors.New(errors.CodeForbidden, "无权限修改授权记录备注")
|
||||
s.recordRemarkFailure(ctx, record, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.GetRecordDetail(ctx, id)
|
||||
var enterprise model.Enterprise
|
||||
var card model.IotCard
|
||||
var auth model.EnterpriseCardAuthorization
|
||||
var ownerShop *model.Shop
|
||||
err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&auth, id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return errors.New(errors.CodeNotFound, "授权记录不存在")
|
||||
}
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "查询授权记录失败")
|
||||
}
|
||||
if userType == constants.UserTypeAgent && auth.AuthorizedBy != userID {
|
||||
return errors.New(errors.CodeForbidden, "只能修改自己创建的授权记录备注")
|
||||
}
|
||||
if err := tx.First(&enterprise, auth.EnterpriseID).Error; err != nil {
|
||||
return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
|
||||
}
|
||||
if err := tx.First(&card, auth.CardID).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "查询授权卡失败")
|
||||
}
|
||||
if enterprise.OwnerShopID != nil {
|
||||
var shop model.Shop
|
||||
if err := tx.Unscoped().First(&shop, *enterprise.OwnerShopID).Error; err == nil {
|
||||
ownerShop = &shop
|
||||
}
|
||||
}
|
||||
beforeRemark := auth.Remark
|
||||
if beforeRemark == remark {
|
||||
return nil
|
||||
}
|
||||
if err := tx.Model(&model.EnterpriseCardAuthorization{}).Where("id = ?", auth.ID).Update("remark", remark).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "更新授权备注失败")
|
||||
}
|
||||
auth.Remark = remark
|
||||
return s.accessAudit.WriteAccessChange(ctx, tx, accessauditapp.ChangeAudit{
|
||||
ActionCode: constants.AuditActionEnterpriseCardRemarkUpdated, Summary: "更新企业卡授权备注",
|
||||
OperatorID: userID, Enterprise: &enterprise, Shop: ownerShop,
|
||||
Cards: []accessauditapp.IotCardChange{{
|
||||
Card: &card, Relation: constants.AuditResourceRelationReference,
|
||||
SubjectVisibility: constants.AuditSubjectInternalOnly,
|
||||
}},
|
||||
CardAuthorizations: []accessauditapp.EnterpriseCardAuthorizationChange{{
|
||||
Authorization: &auth,
|
||||
BeforeData: map[string]any{"remark": beforeRemark}, AfterData: map[string]any{"remark": remark},
|
||||
}},
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
s.recordRemarkFailure(ctx, record, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result, err := s.GetRecordDetail(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *AuthorizationService) recordRemarkFailure(ctx context.Context, record *postgres.AuthorizationWithJoin, originalErr error) {
|
||||
if record == nil {
|
||||
return
|
||||
}
|
||||
enterprise, _ := s.enterpriseStore.GetByID(ctx, record.EnterpriseID)
|
||||
card, _ := s.iotCardStore.GetByID(ctx, record.CardID)
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
ID: record.ID, EnterpriseID: record.EnterpriseID, CardID: record.CardID,
|
||||
AuthorizedBy: record.AuthorizedBy, AuthorizerType: record.AuthorizerType,
|
||||
AuthorizedAt: record.AuthorizedAt, RevokedBy: record.RevokedBy, RevokedAt: record.RevokedAt, Remark: record.Remark,
|
||||
}
|
||||
accessauditapp.RecordFailure(ctx, s.db, s.accessAudit, accessauditapp.ChangeAudit{
|
||||
ActionCode: constants.AuditActionEnterpriseCardRemarkUpdated, Summary: "更新企业卡授权备注失败",
|
||||
Result: enterpriseCardFailureResult(originalErr), OperatorID: middleware.GetUserIDFromContext(ctx),
|
||||
Enterprise: enterprise, Cards: []accessauditapp.IotCardChange{{Card: card}},
|
||||
CardAuthorizations: []accessauditapp.EnterpriseCardAuthorizationChange{{Authorization: auth}},
|
||||
}, originalErr)
|
||||
}
|
||||
|
||||
func parseDate(dateStr string) (time.Time, error) {
|
||||
|
||||
Reference in New Issue
Block a user