feat: 添加记录授权变更历史的功能,并构建配置快照
This commit is contained in:
1 parent
1756657cc1
commit
454a474a36
3 files changed
+148
-49
No files matched your search
@@ -284,3 +284,8 @@ func (r *authorizationCodeRepository) GetAuthorizationChangeList(ctx context.Con
|
||||
TotalPages: totalPages,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RecordAuthorizationChange 记录授权变更历史
|
||||
func (r *authorizationCodeRepository) RecordAuthorizationChange(ctx context.Context, change *models.AuthorizationChange) error {
|
||||
return r.db.WithContext(ctx).Create(change).Error
|
||||
}
|
||||
@@ -2,27 +2,27 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
"license-manager/internal/models"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CustomerRepository 客户数据访问接口
|
||||
type CustomerRepository interface {
|
||||
// GetCustomerList 查询客户列表
|
||||
GetCustomerList(ctx context.Context, req *models.CustomerListRequest) (*models.CustomerListResponse, error)
|
||||
|
||||
|
||||
// GetCustomerByID 根据ID获取客户信息
|
||||
GetCustomerByID(ctx context.Context, id string) (*models.Customer, error)
|
||||
|
||||
|
||||
// CreateCustomer 创建客户
|
||||
CreateCustomer(ctx context.Context, customer *models.Customer) error
|
||||
|
||||
|
||||
// UpdateCustomer 更新客户信息
|
||||
UpdateCustomer(ctx context.Context, customer *models.Customer) error
|
||||
|
||||
|
||||
// DeleteCustomer 删除客户
|
||||
DeleteCustomer(ctx context.Context, id string) error
|
||||
|
||||
|
||||
// GetCustomerCount 获取客户总数(用于统计)
|
||||
GetCustomerCount(ctx context.Context, filters map[string]interface{}) (int64, error)
|
||||
}
|
||||
@@ -31,19 +31,19 @@ type CustomerRepository interface {
|
||||
type UserRepository interface {
|
||||
// GetUserByUsername 根据用户名获取用户
|
||||
GetUserByUsername(ctx context.Context, username string) (*models.User, error)
|
||||
|
||||
|
||||
// GetUserByID 根据ID获取用户
|
||||
GetUserByID(ctx context.Context, id string) (*models.User, error)
|
||||
|
||||
|
||||
// UpdateUser 更新用户信息
|
||||
UpdateUser(ctx context.Context, user *models.User) error
|
||||
|
||||
|
||||
// IncrementLoginAttempts 增加登录失败次数
|
||||
IncrementLoginAttempts(ctx context.Context, id string) error
|
||||
|
||||
|
||||
// ResetLoginAttempts 重置登录失败次数
|
||||
ResetLoginAttempts(ctx context.Context, id string) error
|
||||
|
||||
|
||||
// LockUser 锁定用户账号
|
||||
LockUser(ctx context.Context, id string, lockDuration int) error
|
||||
}
|
||||
@@ -52,52 +52,55 @@ type UserRepository interface {
|
||||
type AuthorizationCodeRepository interface {
|
||||
// CreateAuthorizationCode 创建授权码
|
||||
CreateAuthorizationCode(ctx context.Context, authCode *models.AuthorizationCode) error
|
||||
|
||||
|
||||
// GetAuthorizationCodeByID 根据ID获取授权码
|
||||
GetAuthorizationCodeByID(ctx context.Context, id string) (*models.AuthorizationCode, error)
|
||||
|
||||
|
||||
// GetAuthorizationCodeList 查询授权码列表
|
||||
GetAuthorizationCodeList(ctx context.Context, req *models.AuthorizationCodeListRequest) (*models.AuthorizationCodeListResponse, error)
|
||||
|
||||
|
||||
// UpdateAuthorizationCode 更新授权码
|
||||
UpdateAuthorizationCode(ctx context.Context, authCode *models.AuthorizationCode) error
|
||||
|
||||
|
||||
// DeleteAuthorizationCode 删除授权码(软删除)
|
||||
DeleteAuthorizationCode(ctx context.Context, id string) error
|
||||
|
||||
|
||||
// CheckCustomerExists 检查客户是否存在
|
||||
CheckCustomerExists(ctx context.Context, customerID string) (bool, error)
|
||||
|
||||
|
||||
// GetAuthorizationChangeList 查询授权变更历史列表
|
||||
GetAuthorizationChangeList(ctx context.Context, authCodeID string, req *models.AuthorizationChangeListRequest) (*models.AuthorizationChangeListResponse, error)
|
||||
|
||||
// RecordAuthorizationChange 记录授权变更历史
|
||||
RecordAuthorizationChange(ctx context.Context, change *models.AuthorizationChange) error
|
||||
}
|
||||
|
||||
// LicenseRepository 许可证数据访问接口
|
||||
type LicenseRepository interface {
|
||||
// GetLicenseList 查询许可证列表
|
||||
GetLicenseList(ctx context.Context, req *models.LicenseListRequest) (*models.LicenseListResponse, error)
|
||||
|
||||
|
||||
// GetLicenseByID 根据ID获取许可证信息
|
||||
GetLicenseByID(ctx context.Context, id string) (*models.License, error)
|
||||
|
||||
|
||||
// CreateLicense 创建许可证
|
||||
CreateLicense(ctx context.Context, license *models.License) error
|
||||
|
||||
|
||||
// UpdateLicense 更新许可证信息
|
||||
UpdateLicense(ctx context.Context, license *models.License) error
|
||||
|
||||
|
||||
// CheckAuthorizationCodeExists 检查授权码是否存在
|
||||
CheckAuthorizationCodeExists(ctx context.Context, authCodeID string) (bool, error)
|
||||
|
||||
|
||||
// GetAuthorizationCodeByID 根据ID获取授权码信息
|
||||
GetAuthorizationCodeByID(ctx context.Context, authCodeID string) (*models.AuthorizationCode, error)
|
||||
|
||||
|
||||
// GetAuthorizationCodeByCode 根据授权码获取授权码信息
|
||||
GetAuthorizationCodeByCode(ctx context.Context, code string) (*models.AuthorizationCode, error)
|
||||
|
||||
|
||||
// GetLicenseByKey 根据许可证密钥获取许可证信息
|
||||
GetLicenseByKey(ctx context.Context, licenseKey string) (*models.License, error)
|
||||
|
||||
|
||||
// GetActiveLicenseCount 获取指定授权码的激活许可证数量
|
||||
GetActiveLicenseCount(ctx context.Context, authCodeID string) (int64, error)
|
||||
}
|
||||
@@ -106,7 +109,7 @@ type LicenseRepository interface {
|
||||
type DashboardRepository interface {
|
||||
// GetAuthorizationTrendData 获取授权趋势数据
|
||||
GetAuthorizationTrendData(ctx context.Context, startDate, endDate time.Time) ([]models.TrendData, error)
|
||||
|
||||
|
||||
// GetRecentAuthorizations 获取最近授权列表
|
||||
GetRecentAuthorizations(ctx context.Context, req *models.DashboardRecentAuthorizationsRequest) (*models.DashboardRecentAuthorizationsResponse, error)
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -16,9 +17,9 @@ import (
|
||||
)
|
||||
|
||||
type authorizationCodeService struct {
|
||||
authCodeRepo repository.AuthorizationCodeRepository
|
||||
customerRepo repository.CustomerRepository
|
||||
licenseRepo repository.LicenseRepository
|
||||
authCodeRepo repository.AuthorizationCodeRepository
|
||||
customerRepo repository.CustomerRepository
|
||||
licenseRepo repository.LicenseRepository
|
||||
}
|
||||
|
||||
// NewAuthorizationCodeService 创建授权码服务实例
|
||||
@@ -28,9 +29,9 @@ func NewAuthorizationCodeService(
|
||||
licenseRepo repository.LicenseRepository,
|
||||
) AuthorizationCodeService {
|
||||
return &authorizationCodeService{
|
||||
authCodeRepo: authCodeRepo,
|
||||
customerRepo: customerRepo,
|
||||
licenseRepo: licenseRepo,
|
||||
authCodeRepo: authCodeRepo,
|
||||
customerRepo: customerRepo,
|
||||
licenseRepo: licenseRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +268,10 @@ func (s *authorizationCodeService) UpdateAuthorizationCode(ctx context.Context,
|
||||
}
|
||||
|
||||
// 获取当前用户ID
|
||||
// currentUserID := "admin_uuid" // TODO: 从JWT token中获取
|
||||
currentUserID := "admin_uuid" // TODO: 从JWT token中获取
|
||||
|
||||
// 记录变更前的配置
|
||||
oldConfig := s.buildConfigSnapshot(existingAuthCode)
|
||||
|
||||
// 只更新提供的字段
|
||||
if req.SoftwareID != nil {
|
||||
@@ -320,9 +324,6 @@ func (s *authorizationCodeService) UpdateAuthorizationCode(ctx context.Context,
|
||||
existingAuthCode.CustomParameters = models.JSON(customParametersBytes)
|
||||
}
|
||||
|
||||
// 设置更新者 - 注意这里没有UpdatedBy字段,会通过BeforeUpdate钩子自动设置UpdatedAt
|
||||
// existingAuthCode.UpdatedBy = ¤tUserID // 如果表结构有这个字段的话
|
||||
|
||||
// 委托给Repository层进行数据更新
|
||||
if err := s.authCodeRepo.UpdateAuthorizationCode(ctx, existingAuthCode); err != nil {
|
||||
return nil, i18n.NewI18nError("900004", lang, err.Error())
|
||||
@@ -331,8 +332,11 @@ func (s *authorizationCodeService) UpdateAuthorizationCode(ctx context.Context,
|
||||
// 填充多语言显示字段和计算状态
|
||||
s.fillAuthorizationCodeDisplayFields(existingAuthCode, lang)
|
||||
|
||||
// TODO: 记录变更历史到 authorization_changes 表
|
||||
// s.recordAuthorizationChange(ctx, id, req.ChangeType, req.Reason, currentUserID)
|
||||
// 记录变更历史到 authorization_changes 表
|
||||
newConfig := s.buildConfigSnapshot(existingAuthCode)
|
||||
if err := s.recordAuthorizationChange(ctx, id, req.ChangeType, req.Reason, currentUserID, oldConfig, newConfig); err != nil {
|
||||
log.Printf("记录授权变更历史失败: %v", err)
|
||||
}
|
||||
|
||||
return existingAuthCode, nil
|
||||
}
|
||||
@@ -361,6 +365,9 @@ func (s *authorizationCodeService) LockUnlockAuthorizationCode(ctx context.Conte
|
||||
// 获取当前用户ID
|
||||
currentUserID := "admin_uuid" // TODO: 从JWT token中获取
|
||||
|
||||
// 记录变更前的配置
|
||||
oldConfig := s.buildConfigSnapshot(existingAuthCode)
|
||||
|
||||
// 更新锁定状态
|
||||
now := time.Now()
|
||||
existingAuthCode.IsLocked = req.IsLocked
|
||||
@@ -385,12 +392,15 @@ func (s *authorizationCodeService) LockUnlockAuthorizationCode(ctx context.Conte
|
||||
// 填充多语言显示字段和计算状态
|
||||
s.fillAuthorizationCodeDisplayFields(existingAuthCode, lang)
|
||||
|
||||
// TODO: 记录变更历史到 authorization_changes 表
|
||||
// changeType := "lock"
|
||||
// if !req.IsLocked {
|
||||
// changeType = "unlock"
|
||||
// }
|
||||
// s.recordAuthorizationChange(ctx, id, changeType, req.Reason, currentUserID)
|
||||
// 记录变更历史到 authorization_changes 表
|
||||
changeType := "lock"
|
||||
if !req.IsLocked {
|
||||
changeType = "unlock"
|
||||
}
|
||||
newConfig := s.buildConfigSnapshot(existingAuthCode)
|
||||
if err := s.recordAuthorizationChange(ctx, id, changeType, req.Reason, currentUserID, oldConfig, newConfig); err != nil {
|
||||
log.Printf("记录授权变更历史失败: %v", err)
|
||||
}
|
||||
|
||||
return existingAuthCode, nil
|
||||
}
|
||||
@@ -404,8 +414,11 @@ func (s *authorizationCodeService) DeleteAuthorizationCode(ctx context.Context,
|
||||
return i18n.NewI18nError("900001", lang)
|
||||
}
|
||||
|
||||
// 获取当前用户ID
|
||||
currentUserID := "admin_uuid" // TODO: 从JWT token中获取
|
||||
|
||||
// 先查询现有授权码,确保存在
|
||||
_, err := s.authCodeRepo.GetAuthorizationCodeByID(ctx, id)
|
||||
existingAuthCode, err := s.authCodeRepo.GetAuthorizationCodeByID(ctx, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, repository.ErrAuthorizationCodeNotFound) {
|
||||
return i18n.NewI18nError("300001", lang)
|
||||
@@ -413,18 +426,96 @@ func (s *authorizationCodeService) DeleteAuthorizationCode(ctx context.Context,
|
||||
return i18n.NewI18nError("900004", lang, err.Error())
|
||||
}
|
||||
|
||||
// 记录变更前的配置
|
||||
oldConfig := s.buildConfigSnapshot(existingAuthCode)
|
||||
|
||||
// 委托给Repository层进行软删除
|
||||
if err := s.authCodeRepo.DeleteAuthorizationCode(ctx, id); err != nil {
|
||||
return i18n.NewI18nError("900004", lang, err.Error())
|
||||
}
|
||||
|
||||
// TODO: 记录变更历史到 authorization_changes 表
|
||||
// currentUserID := "admin_uuid" // TODO: 从JWT token中获取
|
||||
// s.recordAuthorizationChange(ctx, id, "delete", nil, currentUserID)
|
||||
// 记录变更历史到 authorization_changes 表
|
||||
emptyConfig := make(map[string]interface{})
|
||||
if err := s.recordAuthorizationChange(ctx, id, "delete", nil, currentUserID, oldConfig, emptyConfig); err != nil {
|
||||
log.Printf("记录授权变更历史失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// recordAuthorizationChange 记录授权变更历史
|
||||
func (s *authorizationCodeService) recordAuthorizationChange(ctx context.Context, authCodeID string, changeType string, reason *string, operatorID string, oldConfig, newConfig map[string]interface{}) error {
|
||||
// 构建变更历史记录
|
||||
change := &models.AuthorizationChange{
|
||||
AuthorizationCodeID: authCodeID,
|
||||
ChangeType: changeType,
|
||||
OperatorID: operatorID,
|
||||
Reason: reason,
|
||||
}
|
||||
|
||||
// 序列化配置为JSON
|
||||
if oldConfig != nil {
|
||||
oldConfigBytes, err := json.Marshal(oldConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
change.OldConfig = models.JSON(oldConfigBytes)
|
||||
}
|
||||
|
||||
if newConfig != nil {
|
||||
newConfigBytes, err := json.Marshal(newConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
change.NewConfig = models.JSON(newConfigBytes)
|
||||
}
|
||||
|
||||
// 委托给Repository层记录变更历史
|
||||
return s.authCodeRepo.RecordAuthorizationChange(ctx, change)
|
||||
}
|
||||
|
||||
// buildConfigSnapshot 构建配置快照,用于记录变更历史
|
||||
func (s *authorizationCodeService) buildConfigSnapshot(authCode *models.AuthorizationCode) map[string]interface{} {
|
||||
config := make(map[string]interface{})
|
||||
|
||||
// 基础配置
|
||||
config["code"] = authCode.Code
|
||||
config["software_id"] = authCode.SoftwareID
|
||||
config["description"] = authCode.Description
|
||||
config["start_date"] = authCode.StartDate.Format(time.RFC3339)
|
||||
config["end_date"] = authCode.EndDate.Format(time.RFC3339)
|
||||
config["deployment_type"] = authCode.DeploymentType
|
||||
config["encryption_type"] = authCode.EncryptionType
|
||||
config["software_version"] = authCode.SoftwareVersion
|
||||
config["max_activations"] = authCode.MaxActivations
|
||||
config["is_locked"] = authCode.IsLocked
|
||||
config["lock_reason"] = authCode.LockReason
|
||||
|
||||
// JSON配置字段
|
||||
if len(authCode.FeatureConfig) > 0 {
|
||||
var featureConfig map[string]interface{}
|
||||
if err := json.Unmarshal(authCode.FeatureConfig, &featureConfig); err == nil {
|
||||
config["feature_config"] = featureConfig
|
||||
}
|
||||
}
|
||||
|
||||
if len(authCode.UsageLimits) > 0 {
|
||||
var usageLimits map[string]interface{}
|
||||
if err := json.Unmarshal(authCode.UsageLimits, &usageLimits); err == nil {
|
||||
config["usage_limits"] = usageLimits
|
||||
}
|
||||
}
|
||||
|
||||
if len(authCode.CustomParameters) > 0 {
|
||||
var customParameters map[string]interface{}
|
||||
if err := json.Unmarshal(authCode.CustomParameters, &customParameters); err == nil {
|
||||
config["custom_parameters"] = customParameters
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// fillAuthCodeDisplayFields 填充授权码列表项多语言显示字段
|
||||
func (s *authorizationCodeService) fillAuthCodeDisplayFields(item *models.AuthorizationCodeListItem, lang string, now time.Time) {
|
||||
// 计算状态
|
||||
|
||||
Reference in new issue
Block a user