2026-07-03 15:58:29 +08:00
|
|
|
package controller
|
|
|
|
|
|
|
|
|
|
import (
|
2026-07-18 10:52:32 +08:00
|
|
|
"encoding/json"
|
2026-07-03 15:58:29 +08:00
|
|
|
"strconv"
|
|
|
|
|
|
2026-07-18 10:52:32 +08:00
|
|
|
"seeyon-filesystem/config"
|
2026-07-03 15:58:29 +08:00
|
|
|
"seeyon-filesystem/dto"
|
|
|
|
|
"seeyon-filesystem/model"
|
|
|
|
|
"seeyon-filesystem/service"
|
|
|
|
|
"seeyon-filesystem/utils"
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// AdminController 管理后台控制器
|
|
|
|
|
type AdminController struct {
|
|
|
|
|
adminService *service.AdminService
|
|
|
|
|
storageService *service.StorageTestService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewAdminController() *AdminController {
|
|
|
|
|
return &AdminController{
|
|
|
|
|
adminService: service.NewAdminService(),
|
|
|
|
|
storageService: service.NewStorageTestService(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-18 10:52:32 +08:00
|
|
|
// ========== 授权管理 ==========
|
|
|
|
|
|
|
|
|
|
// GetLicense 获取当前授权信息
|
|
|
|
|
// GET /api/admin/license
|
|
|
|
|
func (c *AdminController) GetLicense(ctx *gin.Context) {
|
|
|
|
|
licensePath := config.AppConfig.License.FilePath
|
|
|
|
|
if licensePath == "" {
|
|
|
|
|
licensePath = "license.json"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := utils.ReadAndVerifyLicense(licensePath, config.AppConfig.License.VerifyURL, "seeyon-filesystem", "1.0")
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.Success(ctx, gin.H{
|
|
|
|
|
"status": "invalid",
|
|
|
|
|
"message": err.Error(),
|
|
|
|
|
"machine_id": utils.GetMachineID(),
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
utils.Success(ctx, gin.H{
|
|
|
|
|
"status": map[bool]string{true: "valid", false: "invalid"}[resp.Valid],
|
|
|
|
|
"message": resp.Message,
|
|
|
|
|
"machine_id": utils.GetMachineID(),
|
|
|
|
|
"product": resp.Product,
|
|
|
|
|
"customer_id": resp.CustomerID,
|
|
|
|
|
"customer": resp.Customer,
|
|
|
|
|
"contact": resp.Contact,
|
|
|
|
|
"phone": resp.Phone,
|
|
|
|
|
"expire_at": resp.ExpireAt,
|
|
|
|
|
"max_users": resp.MaxUsers,
|
|
|
|
|
"max_files": resp.MaxFiles,
|
|
|
|
|
"features": resp.Features,
|
|
|
|
|
"expire_days": resp.ExpireDays,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GenerateLicense 生成授权码
|
|
|
|
|
// POST /api/admin/license/generate
|
|
|
|
|
func (c *AdminController) GenerateLicense(ctx *gin.Context) {
|
|
|
|
|
var req struct {
|
|
|
|
|
TargetMachineID string `json:"target_machine_id"`
|
|
|
|
|
CustomerID string `json:"customer_id"`
|
|
|
|
|
Customer string `json:"customer"`
|
|
|
|
|
Contact string `json:"contact"`
|
|
|
|
|
Phone string `json:"phone"`
|
|
|
|
|
MaxUsers int `json:"max_users"`
|
|
|
|
|
MaxFiles int `json:"max_files"`
|
|
|
|
|
Features string `json:"features"`
|
|
|
|
|
ExpireAt string `json:"expire_at"` // RFC3339格式, 空=永久
|
|
|
|
|
Version string `json:"version"`
|
|
|
|
|
}
|
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if req.Features == "" {
|
|
|
|
|
req.Features = "*"
|
|
|
|
|
}
|
|
|
|
|
if req.Version == "" {
|
|
|
|
|
req.Version = "1.0"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
license := &utils.LicenseInfo{
|
|
|
|
|
Product: "seeyon-filesystem",
|
|
|
|
|
CustomerID: req.CustomerID,
|
|
|
|
|
Customer: req.Customer,
|
|
|
|
|
Contact: req.Contact,
|
|
|
|
|
Phone: req.Phone,
|
|
|
|
|
MachineID: req.TargetMachineID,
|
|
|
|
|
MaxUsers: req.MaxUsers,
|
|
|
|
|
MaxFiles: req.MaxFiles,
|
|
|
|
|
Features: req.Features,
|
|
|
|
|
ExpireAt: req.ExpireAt,
|
|
|
|
|
}
|
|
|
|
|
utils.SignLicense(license)
|
|
|
|
|
|
|
|
|
|
// 返回标准格式
|
|
|
|
|
licenseFile := map[string]interface{}{
|
|
|
|
|
"productType": "seeyon-filesystem",
|
|
|
|
|
"version": req.Version,
|
|
|
|
|
"licenseStr": license.LicenseStr,
|
|
|
|
|
}
|
|
|
|
|
fileJSON, _ := json.Marshal(licenseFile)
|
|
|
|
|
|
|
|
|
|
utils.Success(ctx, gin.H{
|
|
|
|
|
"license_file": string(fileJSON), // 保存为 license.json
|
|
|
|
|
"license": license,
|
|
|
|
|
"machine_id": utils.GetMachineID(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 15:58:29 +08:00
|
|
|
// ========== 用户管理 ==========
|
|
|
|
|
|
|
|
|
|
// ListUsers 用户列表
|
|
|
|
|
// GET /api/admin/users?page=1&size=20
|
|
|
|
|
func (c *AdminController) ListUsers(ctx *gin.Context) {
|
|
|
|
|
page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
|
|
|
|
|
size, _ := strconv.Atoi(ctx.DefaultQuery("size", "20"))
|
|
|
|
|
if page < 1 { page = 1 }
|
|
|
|
|
if size < 1 || size > 100 { size = 20 }
|
|
|
|
|
|
|
|
|
|
users, total, err := c.adminService.ListUsers(page, size)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.ServerError(ctx, "查询用户失败")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.PageSuccess(ctx, users, total, page, size)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateUser 创建用户
|
|
|
|
|
// POST /api/admin/users
|
|
|
|
|
func (c *AdminController) CreateUser(ctx *gin.Context) {
|
|
|
|
|
var req dto.UserCreateRequest
|
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.CreateUser(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "用户创建成功", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdateUser 更新用户
|
|
|
|
|
// PUT /api/admin/users/:id
|
|
|
|
|
func (c *AdminController) UpdateUser(ctx *gin.Context) {
|
|
|
|
|
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "无效的用户ID")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var req dto.UserUpdateRequest
|
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.UpdateUser(id, &req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "更新成功", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeleteUser 删除用户
|
|
|
|
|
// DELETE /api/admin/users/:id
|
|
|
|
|
func (c *AdminController) DeleteUser(ctx *gin.Context) {
|
|
|
|
|
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "无效的用户ID")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.DeleteUser(id); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "删除成功", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ResetPassword 重置密码
|
|
|
|
|
// PUT /api/admin/users/:id/password
|
|
|
|
|
func (c *AdminController) ResetPassword(ctx *gin.Context) {
|
|
|
|
|
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "无效的用户ID")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var req struct {
|
|
|
|
|
Password string `json:"password" binding:"required,min=6"`
|
|
|
|
|
}
|
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.ResetPassword(id, req.Password); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "密码重置成功", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ========== 存储策略管理 ==========
|
|
|
|
|
|
|
|
|
|
// ListStoragePolicies 存储策略列表
|
|
|
|
|
// GET /api/admin/storage-policies
|
|
|
|
|
func (c *AdminController) ListStoragePolicies(ctx *gin.Context) {
|
|
|
|
|
policies, err := c.adminService.ListStoragePolicies()
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.ServerError(ctx, "查询失败")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(ctx, policies)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateStoragePolicy 创建存储策略
|
|
|
|
|
// POST /api/admin/storage-policies
|
|
|
|
|
func (c *AdminController) CreateStoragePolicy(ctx *gin.Context) {
|
|
|
|
|
var req dto.StoragePolicyCreateRequest
|
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.CreateStoragePolicy(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "创建成功", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdateStoragePolicy 更新存储策略
|
|
|
|
|
// PUT /api/admin/storage-policies/:id
|
|
|
|
|
func (c *AdminController) UpdateStoragePolicy(ctx *gin.Context) {
|
|
|
|
|
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "无效的策略ID")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var req dto.StoragePolicyUpdateRequest
|
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.UpdateStoragePolicy(id, &req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "更新成功", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeleteStoragePolicy 删除存储策略
|
|
|
|
|
// DELETE /api/admin/storage-policies/:id
|
|
|
|
|
func (c *AdminController) DeleteStoragePolicy(ctx *gin.Context) {
|
|
|
|
|
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "无效的策略ID")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.DeleteStoragePolicy(id); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "删除成功", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TestStoragePolicy 测试存储策略连通性
|
|
|
|
|
// POST /api/admin/storage-policies/:id/test
|
|
|
|
|
func (c *AdminController) TestStoragePolicy(ctx *gin.Context) {
|
|
|
|
|
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "无效的策略ID")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result, err := c.storageService.TestPolicy(id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(ctx, result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TestNewStoragePolicy 测试新配置(未保存)
|
|
|
|
|
// POST /api/admin/storage-policies/test
|
|
|
|
|
func (c *AdminController) TestNewStoragePolicy(ctx *gin.Context) {
|
|
|
|
|
var req struct {
|
|
|
|
|
Type string `json:"type" binding:"required"`
|
|
|
|
|
Config dto.PolicyConfigDTO `json:"config" binding:"required"`
|
|
|
|
|
}
|
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cfg := model.PolicyConfig{
|
|
|
|
|
BasePath: req.Config.BasePath,
|
|
|
|
|
Endpoint: req.Config.Endpoint,
|
|
|
|
|
Bucket: req.Config.Bucket,
|
|
|
|
|
AccessKey: req.Config.AccessKey,
|
|
|
|
|
SecretKey: req.Config.SecretKey,
|
|
|
|
|
Region: req.Config.Region,
|
|
|
|
|
UseSSL: req.Config.UseSSL,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result := c.storageService.TestNewPolicy(req.Type, cfg)
|
|
|
|
|
utils.Success(ctx, result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ========== 组织架构管理 ==========
|
|
|
|
|
|
|
|
|
|
// ListDepartments 部门列表(树形)
|
|
|
|
|
// GET /api/admin/departments
|
|
|
|
|
func (c *AdminController) ListDepartments(ctx *gin.Context) {
|
|
|
|
|
depts, err := c.adminService.ListDepartments()
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.ServerError(ctx, "查询失败")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(ctx, depts)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateDepartment 创建部门
|
|
|
|
|
// POST /api/admin/departments
|
|
|
|
|
func (c *AdminController) CreateDepartment(ctx *gin.Context) {
|
|
|
|
|
var req dto.DeptCreateRequest
|
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.CreateDepartment(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "创建成功", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdateDepartment 更新部门
|
|
|
|
|
// PUT /api/admin/departments/:id
|
|
|
|
|
func (c *AdminController) UpdateDepartment(ctx *gin.Context) {
|
|
|
|
|
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "无效的部门ID")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var req dto.DeptUpdateRequest
|
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "参数错误: "+err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.UpdateDepartment(id, &req); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "更新成功", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeleteDepartment 删除部门
|
|
|
|
|
// DELETE /api/admin/departments/:id
|
|
|
|
|
func (c *AdminController) DeleteDepartment(ctx *gin.Context) {
|
|
|
|
|
id, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.BadRequest(ctx, "无效的部门ID")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.adminService.DeleteDepartment(id); err != nil {
|
|
|
|
|
utils.BadRequest(ctx, err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.SuccessWithMessage(ctx, "删除成功", nil)
|
|
|
|
|
}
|