LicenseManger/internal/service/license.go

710 lines
12 KiB
Go
Raw Normal View History

2024-11-14 14:55:43 +00:00
package service
import (
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"strings"
"time"
"licserver/internal/model"
"gorm.io/gorm"
)
type LicenseService struct {
db *gorm.DB
}
func NewLicenseService(db *gorm.DB) *LicenseService {
return &LicenseService{db: db}
}
// 生成授权码
func generateLicenseCode() (string, error) {
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}
// 创建授权码
type LicenseCreateInput struct {
LicenseType string `json:"license_type" binding:"required"`
Duration int `json:"duration"` // 时间授权的有效期(分钟)
MaxUses int `json:"max_uses"` // 次数授权的使用次数
Count int `json:"count" binding:"required,min=1"` // 生成数量
Remark string `json:"remark"` // 备注
BindCount int `json:"bind_count"` // 可绑定次数,默认为-1无限制
}
func (s *LicenseService) CreateLicenses(input *LicenseCreateInput, createdBy uint) ([]model.LicenseCode, error) {
// 验证参数
input.LicenseType = strings.ToLower(input.LicenseType) // 转为小写
switch input.LicenseType {
case "time":
if input.Duration <= 0 {
return nil, errors.New("时间授权必须指定有效期")
}
case "count":
if input.MaxUses <= 0 {
return nil, errors.New("次数授权必须指定使用次数")
}
case "permanent":
// 永久授权不需要额外参数
default:
return nil, errors.New("无效的授权类型")
}
// 如果未指定绑定次数,设置为默认值-1
if input.BindCount == 0 {
input.BindCount = -1
}
// 生成批次号
batchNo := time.Now().Format("20060102150405")
licenses := make([]model.LicenseCode, 0, input.Count)
for i := 0; i < input.Count; i++ {
code, err := generateLicenseCode()
if err != nil {
return nil, err
}
license := model.LicenseCode{
Code: code,
LicenseType: input.LicenseType,
Duration: input.Duration,
MaxUses: input.MaxUses,
Status: "unused",
CreatedBy: createdBy,
BatchNo: batchNo,
Remark: input.Remark,
BindCount: input.BindCount,
}
licenses = append(licenses, license)
}
// 批量创建授权码
if err := s.db.Create(&licenses).Error; err != nil {
return nil, err
}
return licenses, nil
}
// 验证并使用授权码
func (s *LicenseService) UseLicense(code, deviceUID, ip string) (*model.LicenseCode, error) {
var license model.LicenseCode
if err := s.db.Where("code = ?", code).First(&license).Error; err != nil {
return nil, errors.New("授权码不存在")
}
// 检查授权码状态
if license.Status != "unused" {
return nil, errors.New("授权码已被使用")
}
// 检查绑定次数
if license.BindCount == 0 {
return nil, errors.New("授权码已达到最大绑定次数限制")
}
// 更新授权码状态
updates := map[string]interface{}{
"status": "used",
"used_by": deviceUID,
"used_at": time.Now(),
}
// 如果不是无限制,减少绑定次数
if license.BindCount > 0 {
updates["bind_count"] = license.BindCount - 1
}
if err := s.db.Model(&license).Updates(updates).Error; err != nil {
return nil, err
}
// 记录使用日志
log := model.LicenseLog{
LicenseID: license.ID,
DeviceUID: deviceUID,
Action: "use",
IP: ip,
Status: "success",
Message: fmt.Sprintf("设备 %s 使用授权码", deviceUID),
}
if err := s.db.Create(&log).Error; err != nil {
return nil, err
}
return &license, nil
}
// 获取授权码列表
func (s *LicenseService) GetLicenses(status, licenseType, batchNo string, page, pageSize int) ([]model.LicenseCode, int64, error) {
var licenses []model.LicenseCode
var total int64
query := s.db.Model(&model.LicenseCode{})
if status != "" {
query = query.Where("status = ?", strings.ToLower(status))
}
if licenseType != "" {
query = query.Where("license_type = ?", strings.ToLower(licenseType))
}
if batchNo != "" {
query = query.Where("batch_no = ?", batchNo)
}
// 获取所有符合条件的授权码
var allLicenses []model.LicenseCode
if err := query.Find(&allLicenses).Error; err != nil {
return nil, 0, err
}
// 检查每个授权码的有效性
for i := range allLicenses {
if allLicenses[i].Status == "used" {
if err := s.CheckLicenseValidity(allLicenses[i].Code); err != nil {
// 如果检查失败,更新状态
s.db.Model(&allLicenses[i]).Update("status", "expired")
allLicenses[i].Status = "expired"
}
}
}
total = int64(len(allLicenses))
// 分页
if page > 0 && pageSize > 0 {
start := (page - 1) * pageSize
end := start + pageSize
if start < len(allLicenses) {
if end > len(allLicenses) {
end = len(allLicenses)
}
licenses = allLicenses[start:end]
}
} else {
licenses = allLicenses
}
return licenses, total, nil
}
// 获取授权码使用日志
func (s *LicenseService) GetLicenseLogs(licenseID uint, page, pageSize int) ([]model.LicenseLog, int64, error) {
var logs []model.LicenseLog
var total int64
query := s.db.Model(&model.LicenseLog{}).Where("license_id = ?", licenseID)
query.Count(&total)
if page > 0 && pageSize > 0 {
offset := (page - 1) * pageSize
query = query.Offset(offset).Limit(pageSize)
}
err := query.Order("created_at DESC").Find(&logs).Error
return logs, total, err
}
// ExportLogs 导出授权码日志
func (s *LicenseService) ExportLogs(licenseID uint) ([]byte, error) {
logs, _, err := s.GetLicenseLogs(licenseID, 0, 0) // 获取所有日志
if err != nil {
return nil, err
}
// 创建CSV内容
var content strings.Builder
content.WriteString("操作类,设备UID,IP地址,状态,详细信息,时间\n")
for _, log := range logs {
// 转换操作类型
action := map[string]string{
"create": "创建",
"use": "使用",
"verify": "验证",
}[log.Action]
// 转换状态
status := map[string]string{
"success": "成功",
"failed": "失败",
}[log.Status]
// 写入一行记录
content.WriteString(fmt.Sprintf("%s,%s,%s,%s,%s,%s\n",
action,
log.DeviceUID,
log.IP,
status,
log.Message,
log.CreatedAt.Format("2006-01-02 15:04:05"),
))
}
return []byte(content.String()), nil
}
// 撤销授权码
func (s *LicenseService) RevokeLicense(code string, userID uint) error {
var license model.LicenseCode
if err := s.db.Where("code = ?", code).First(&license).Error; err != nil {
return errors.New("授权码不存在")
}
// 检查权限
if license.CreatedBy != userID {
return errors.New("无权操作此授权码")
}
// 更新状态
if err := s.db.Model(&license).Update("status", "revoked").Error; err != nil {
return err
}
// 记录日志
log := model.LicenseLog{
LicenseID: license.ID,
Action: "revoke",
Status: "success",
Message: "授权码已撤销",
}
s.db.Create(&log)
return nil
}
// 批量撤销授权码
func (s *LicenseService) RevokeLicenses(codes []string, userID uint) error {
return s.db.Transaction(func(tx *gorm.DB) error {
for _, code := range codes {
var license model.LicenseCode
if err := tx.Where("code = ?", code).First(&license).Error; err != nil {
continue
}
// 检查权限
if license.CreatedBy != userID {
continue
}
// 更新状态
if err := tx.Model(&license).Update("status", "revoked").Error; err != nil {
return err
}
// 记录日志
log := model.LicenseLog{
LicenseID: license.ID,
Action: "revoke",
Status: "success",
Message: "授权码已撤销",
}
tx.Create(&log)
}
return nil
})
}
// 验证授权码
func (s *LicenseService) ValidateLicense(code string) (*model.LicenseCode, error) {
var license model.LicenseCode
if err := s.db.Where("code = ?", code).First(&license).Error; err != nil {
return nil, errors.New("无效的授权码")
}
// 检查状态
if license.Status != "unused" {
return nil, errors.New("授权码已被使用或已撤销")
}
return &license, nil
}
// 导出授权码
func (s *LicenseService) ExportLicenses(codes []string) ([]byte, error) {
var licenses []model.LicenseCode
if err := s.db.Where("code IN ?", codes).Find(&licenses).Error; err != nil {
return nil, err
}
// 创建CSV内容
var content strings.Builder
content.WriteString("授权码,授权类型,有效期(天),使用次数,状态,使用设备,使用时间,批次号,备注\n")
for _, license := range licenses {
// 转换授权类型
licenseType := map[string]string{
"time": "时间授权",
"count": "次数授权",
"permanent": "永久授权",
}[license.LicenseType]
// 转换状态
status := map[string]string{
"unused": "未使用",
"used": "已使用",
"revoked": "已撤销",
}[license.Status]
// 写入一行记录
content.WriteString(fmt.Sprintf("%s,%s,%d,%d,%s,%s,%s,%s,%s\n",
license.Code,
licenseType,
license.Duration,
license.MaxUses,
status,
license.UsedBy,
license.UsedAt.Format("2006-01-02 15:04:05"),
license.BatchNo,
license.Remark,
))
}
return []byte(content.String()), nil
}
// 获取授权码统计信息
func (s *LicenseService) GetLicenseStats() (map[string]interface{}, error) {
var stats struct {
Total int64
Unused int64
Used int64
Revoked int64
Today int64
ThisWeek int64
ThisMonth int64
}
// 获取总数
s.db.Model(&model.LicenseCode{}).Count(&stats.Total)
// 获取各状态数量
s.db.Model(&model.LicenseCode{}).Where("status = ?", "unused").Count(&stats.Unused)
s.db.Model(&model.LicenseCode{}).Where("status = ?", "used").Count(&stats.Used)
s.db.Model(&model.LicenseCode{}).Where("status = ?", "revoked").Count(&stats.Revoked)
// 获取今日创建数量
today := time.Now().Format("2006-01-02")
s.db.Model(&model.LicenseCode{}).Where("DATE(created_at) = ?", today).Count(&stats.Today)
// 获取本周创建数量
weekStart := time.Now().AddDate(0, 0, -int(time.Now().Weekday()))
s.db.Model(&model.LicenseCode{}).Where("created_at >= ?", weekStart).Count(&stats.ThisWeek)
// 获取本月创建数量
monthStart := time.Now().Format("2006-01") + "-01"
s.db.Model(&model.LicenseCode{}).Where("created_at >= ?", monthStart).Count(&stats.ThisMonth)
return map[string]interface{}{
"total": stats.Total,
"unused": stats.Unused,
"used": stats.Used,
"revoked": stats.Revoked,
"today": stats.Today,
"this_week": stats.ThisWeek,
"this_month": stats.ThisMonth,
}, nil
}
// 添加检查授权码有效性的方法
func (s *LicenseService) CheckLicenseValidity(code string) error {
var license model.LicenseCode
if err := s.db.Where("code = ?", code).First(&license).Error; err != nil {
return errors.New("授权码不存在")
}
if license.Status != "unused" && license.Status != "used" {
return errors.New("授权码已被撤销或过期")
}
// 检查授权类型特定的限制
switch license.LicenseType {
case "time":
// 计算过期时间
expireTime := license.UsedAt.Add(time.Duration(license.Duration) * time.Minute)
if time.Now().After(expireTime) {
// 更新状态为过期
s.db.Model(&license).Update("status", "expired")
return errors.New("授权码已过期")
}
case "count":
if license.UsedCount >= license.MaxUses {
// 更新状态为过期
s.db.Model(&license).Update("status", "expired")
return errors.New("授权码使用次数已达上限")
}
}
return nil
}
// GetLicenseByCode 通过授权码获取授权信息
func (s *LicenseService) GetLicenseByCode(code string) (*model.LicenseCode, error) {
var license model.LicenseCode
if err := s.db.Where("code = ?", code).First(&license).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("授权码不存在")
}
return nil, err
}
return &license, nil
}