Files
NetworkAuth/controllers/admin/app.go
skyle1995 6dad3971de New interface management
Optimize the pop-up interface
2025-10-25 01:43:03 +08:00

1571 lines
42 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package admin
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"encoding/json"
"net/http"
"networkDev/database"
"networkDev/models"
"networkDev/utils"
"strconv"
"strings"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
)
// AppsFragmentHandler 应用列表页面片段处理器
func AppsFragmentHandler(w http.ResponseWriter, r *http.Request) {
utils.RenderTemplate(w, "apps.html", map[string]interface{}{
"Title": "应用管理",
})
}
// AppsListHandler 应用列表API处理器
func AppsListHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 获取分页参数
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
if page <= 0 {
page = 1
}
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
if limit <= 0 {
limit = 10
}
// 获取搜索参数
search := strings.TrimSpace(r.URL.Query().Get("search"))
// 构建查询
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
var apps []models.App
var total int64
query := db.Model(&models.App{})
// 如果有搜索条件
if search != "" {
query = query.Where("name LIKE ? OR uuid LIKE ?", "%"+search+"%", "%"+search+"%")
}
// 获取总数
if err := query.Count(&total).Error; err != nil {
logrus.WithError(err).Error("Failed to count apps")
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
// 分页查询
offset := (page - 1) * limit
if err := query.Order("created_at DESC").Offset(offset).Limit(limit).Find(&apps).Error; err != nil {
logrus.WithError(err).Error("Failed to query apps")
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
// 返回结果
response := map[string]interface{}{
"code": 0,
"msg": "success",
"count": total,
"data": apps,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppGetAppDataHandler 获取应用数据处理器
func AppGetAppDataHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 获取UUID参数
uuid := r.URL.Query().Get("uuid")
if uuid == "" {
response := map[string]interface{}{
"code": 1,
"msg": "应用UUID不能为空",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 获取数据库连接
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 查找应用
var app models.App
if err := db.Where("uuid = ?", uuid).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 解码base64应用数据内容
var appData string
if app.AppData != "" {
decodedBytes, err := base64.StdEncoding.DecodeString(app.AppData)
if err != nil {
logrus.WithError(err).Error("Failed to decode app data")
// 如果解码失败,返回空字符串
appData = ""
} else {
appData = string(decodedBytes)
}
}
response := map[string]interface{}{
"code": 0,
"msg": "获取成功",
"data": map[string]interface{}{
"app_data": appData,
},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppGetAnnouncementHandler 获取应用程序公告处理器
func AppGetAnnouncementHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 获取UUID参数
uuid := r.URL.Query().Get("uuid")
if uuid == "" {
response := map[string]interface{}{
"code": 1,
"msg": "应用UUID不能为空",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 获取数据库连接
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 查找应用
var app models.App
if err := db.Where("uuid = ?", uuid).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 解码base64公告内容
var announcement string
if app.Announcement != "" {
decodedBytes, err := base64.StdEncoding.DecodeString(app.Announcement)
if err != nil {
logrus.WithError(err).Error("Failed to decode announcement")
// 如果解码失败,返回空字符串
announcement = ""
} else {
announcement = string(decodedBytes)
}
}
response := map[string]interface{}{
"code": 0,
"msg": "获取成功",
"data": map[string]interface{}{
"announcement": announcement,
},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppResetSecretHandler 重置应用密钥API处理器
func AppResetSecretHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
UUID string `json:"uuid"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
if req.UUID == "" {
http.Error(w, "应用UUID不能为空", http.StatusBadRequest)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
return
}
// 查找应用
var app models.App
if err := db.Where("uuid = ?", req.UUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app by UUID")
http.Error(w, "应用不存在", http.StatusNotFound)
return
}
// 生成新的密钥
bytes := make([]byte, 16)
if _, err := rand.Read(bytes); err != nil {
logrus.WithError(err).Error("Failed to generate random secret")
http.Error(w, "生成密钥失败", http.StatusInternalServerError)
return
}
newSecret := strings.ToUpper(hex.EncodeToString(bytes))
// 更新密钥
if err := db.Model(&app).Update("secret", newSecret).Error; err != nil {
logrus.WithError(err).Error("Failed to update app secret")
http.Error(w, "更新密钥失败", http.StatusInternalServerError)
return
}
response := map[string]interface{}{
"code": 0,
"msg": "密钥重置成功",
"data": map[string]interface{}{
"uuid": app.UUID,
"secret": newSecret,
},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppCreateHandler 创建应用API处理器
func AppCreateHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
Name string `json:"name"`
Version string `json:"version"`
Status int `json:"status"`
DownloadType int `json:"download_type"`
ForceUpdate int `json:"force_update"`
DownloadURL string `json:"download_url"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logrus.WithError(err).Error("Failed to decode JSON request")
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
// 验证必填字段
if strings.TrimSpace(req.Name) == "" {
logrus.Error("App name is empty")
http.Error(w, "应用名称不能为空", http.StatusBadRequest)
return
}
// 设置默认值
if req.Version == "" {
req.Version = "1.0.0"
}
logrus.WithFields(logrus.Fields{
"name": req.Name,
"version": req.Version,
"status": req.Status,
"download_type": req.DownloadType,
"download_url": req.DownloadURL,
"force_update": req.ForceUpdate,
}).Info("Received app create request")
// 创建应用
app := models.App{
Name: strings.TrimSpace(req.Name),
Version: req.Version,
Status: req.Status,
DownloadType: req.DownloadType,
DownloadURL: strings.TrimSpace(req.DownloadURL),
ForceUpdate: req.ForceUpdate,
}
// 确保UUID和Secret被设置虽然BeforeCreate钩子应该处理这些但为了保险起见
if app.UUID == "" {
app.UUID = strings.ToUpper(uuid.New().String())
}
if app.Secret == "" {
// 生成32位大写16进制随机字符
bytes := make([]byte, 16) // 16字节 = 32位16进制字符
rand.Read(bytes)
app.Secret = strings.ToUpper(hex.EncodeToString(bytes))
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
return
}
// 开始事务
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 创建应用
if err := tx.Create(&app).Error; err != nil {
tx.Rollback()
logrus.WithError(err).Error("Failed to create app")
http.Error(w, "创建应用失败", http.StatusInternalServerError)
return
}
// 为应用创建所有默认接口
defaultAPITypes := []int{
models.APITypeGetBulletin, // 获取程序公告
models.APITypeGetUpdateUrl, // 获取更新地址
models.APITypeCheckAppVersion, // 检测最新版本
models.APITypeGetCardInfo, // 获取卡密信息
models.APITypeSingleLogin, // 卡密登录
models.APITypeUserLogin, // 用户登录
models.APITypeUserRegin, // 用户注册
models.APITypeUserRecharge, // 用户充值
models.APITypeCardRegin, // 卡密注册
models.APITypeLogOut, // 退出登录
models.APITypeGetExpired, // 获取到期时间
models.APITypeCheckUserStatus, // 检测账号状态
models.APITypeGetAppData, // 获取程序数据
models.APITypeGetVariable, // 获取变量数据
models.APITypeUpdatePwd, // 修改账号密码
models.APITypeMacChangeBind, // 机器码转绑
models.APITypeIPChangeBind, // IP转绑
models.APITypeDisableUser, // 封停用户
models.APITypeBlackUser, // 添加黑名单
models.APITypeUserDeductedTime, // 扣除时间
}
// 批量创建默认接口
for _, apiType := range defaultAPITypes {
api := models.API{
APIType: apiType,
AppUUID: app.UUID,
Status: 1, // 默认启用
SubmitAlgorithm: models.AlgorithmNone, // 默认不加密
ReturnAlgorithm: models.AlgorithmNone, // 默认不加密
}
if err := tx.Create(&api).Error; err != nil {
tx.Rollback()
logrus.WithError(err).WithField("api_type", apiType).Error("Failed to create default API")
http.Error(w, "创建默认接口失败", http.StatusInternalServerError)
return
}
}
// 提交事务
if err := tx.Commit().Error; err != nil {
logrus.WithError(err).Error("Failed to commit transaction")
http.Error(w, "提交事务失败", http.StatusInternalServerError)
return
}
logrus.WithField("app_uuid", app.UUID).Info("Successfully created app with default APIs")
response := map[string]interface{}{
"code": 0,
"msg": "创建成功",
"data": app,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppUpdateHandler 更新应用API处理器
func AppUpdateHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
ID uint `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Status int `json:"status"`
DownloadType int `json:"download_type"`
DownloadURL string `json:"download_url"`
ForceUpdate int `json:"force_update"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
// 验证必填字段
if req.ID == 0 {
http.Error(w, "应用ID不能为空", http.StatusBadRequest)
return
}
if strings.TrimSpace(req.Name) == "" {
http.Error(w, "应用名称不能为空", http.StatusBadRequest)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
return
}
// 查找应用
var app models.App
if err := db.First(&app, req.ID).Error; err != nil {
http.Error(w, "应用不存在", http.StatusNotFound)
return
}
// 更新字段
app.Name = strings.TrimSpace(req.Name)
app.Version = req.Version
app.Status = req.Status
app.DownloadType = req.DownloadType
app.DownloadURL = strings.TrimSpace(req.DownloadURL)
app.ForceUpdate = req.ForceUpdate
if err := db.Save(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to update app")
http.Error(w, "更新应用失败", http.StatusInternalServerError)
return
}
response := map[string]interface{}{
"code": 0,
"msg": "更新成功",
"data": app,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppDeleteHandler 删除应用API处理器
func AppDeleteHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
ID uint `json:"id"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
if req.ID == 0 {
http.Error(w, "应用ID不能为空", http.StatusBadRequest)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
return
}
// 开始事务
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 首先获取应用信息以获取UUID
var app models.App
if err := tx.First(&app, req.ID).Error; err != nil {
tx.Rollback()
logrus.WithError(err).Error("Failed to find app")
http.Error(w, "应用不存在", http.StatusNotFound)
return
}
// 删除该应用的所有相关接口
if err := tx.Where("app_uuid = ?", app.UUID).Delete(&models.API{}).Error; err != nil {
tx.Rollback()
logrus.WithError(err).Error("Failed to delete related APIs")
http.Error(w, "删除相关接口失败", http.StatusInternalServerError)
return
}
// 删除应用
if err := tx.Delete(&models.App{}, req.ID).Error; err != nil {
tx.Rollback()
logrus.WithError(err).Error("Failed to delete app")
http.Error(w, "删除应用失败", http.StatusInternalServerError)
return
}
// 提交事务
if err := tx.Commit().Error; err != nil {
logrus.WithError(err).Error("Failed to commit transaction")
http.Error(w, "提交事务失败", http.StatusInternalServerError)
return
}
logrus.WithFields(logrus.Fields{
"app_id": req.ID,
"app_uuid": app.UUID,
}).Info("Successfully deleted app and related APIs")
response := map[string]interface{}{
"code": 0,
"msg": "删除成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppsBatchDeleteHandler 批量删除应用API处理器
func AppsBatchDeleteHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
IDs []uint `json:"ids"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
if len(req.IDs) == 0 {
http.Error(w, "请选择要删除的应用", http.StatusBadRequest)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
return
}
// 开始事务
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 首先获取要删除的应用的UUID列表
var apps []models.App
if err := tx.Where("id IN ?", req.IDs).Find(&apps).Error; err != nil {
tx.Rollback()
logrus.WithError(err).Error("Failed to find apps")
http.Error(w, "查找应用失败", http.StatusInternalServerError)
return
}
// 提取UUID列表
var appUUIDs []string
for _, app := range apps {
appUUIDs = append(appUUIDs, app.UUID)
}
// 删除这些应用的所有相关接口
if len(appUUIDs) > 0 {
if err := tx.Where("app_uuid IN ?", appUUIDs).Delete(&models.API{}).Error; err != nil {
tx.Rollback()
logrus.WithError(err).Error("Failed to delete related APIs")
http.Error(w, "删除相关接口失败", http.StatusInternalServerError)
return
}
}
// 批量删除应用
if err := tx.Delete(&models.App{}, req.IDs).Error; err != nil {
tx.Rollback()
logrus.WithError(err).Error("Failed to batch delete apps")
http.Error(w, "批量删除失败", http.StatusInternalServerError)
return
}
// 提交事务
if err := tx.Commit().Error; err != nil {
logrus.WithError(err).Error("Failed to commit transaction")
http.Error(w, "提交事务失败", http.StatusInternalServerError)
return
}
logrus.WithFields(logrus.Fields{
"app_ids": req.IDs,
"app_uuids": appUUIDs,
}).Info("Successfully batch deleted apps and related APIs")
response := map[string]interface{}{
"code": 0,
"msg": "批量删除成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppsBatchUpdateStatusHandler 批量更新应用状态API处理器
func AppsBatchUpdateStatusHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
IDs []uint `json:"ids"`
Status int `json:"status"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
if len(req.IDs) == 0 {
http.Error(w, "请选择要更新的应用", http.StatusBadRequest)
return
}
if req.Status != 0 && req.Status != 1 {
http.Error(w, "状态值无效", http.StatusBadRequest)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
return
}
// 批量更新状态
if err := db.Model(&models.App{}).Where("id IN ?", req.IDs).Update("status", req.Status).Error; err != nil {
logrus.WithError(err).Error("Failed to batch update app status")
http.Error(w, "批量更新状态失败", http.StatusInternalServerError)
return
}
statusText := "禁用"
if req.Status == 1 {
statusText = "启用"
}
response := map[string]interface{}{
"code": 0,
"msg": "批量" + statusText + "成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppUpdateAppDataHandler 更新应用数据处理器
func AppUpdateAppDataHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 解析请求体
var req struct {
UUID string `json:"uuid"`
AppData string `json:"app_data"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logrus.WithError(err).Error("Failed to decode request body")
response := map[string]interface{}{
"code": 1,
"msg": "请求参数格式错误",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID
if req.UUID == "" {
response := map[string]interface{}{
"code": 1,
"msg": "应用UUID不能为空",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID格式
if _, err := uuid.Parse(req.UUID); err != nil {
logrus.WithError(err).Error("Invalid UUID format")
response := map[string]interface{}{
"code": 1,
"msg": "无效的UUID格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 获取数据库连接
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 查找应用
var app models.App
if err := db.Where("uuid = ?", req.UUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 对应用数据内容进行base64编码
encodedAppData := base64.StdEncoding.EncodeToString([]byte(req.AppData))
// 更新应用的数据内容
if err := db.Model(&app).Update("app_data", encodedAppData).Error; err != nil {
logrus.WithError(err).Error("Failed to update app data")
response := map[string]interface{}{
"code": 1,
"msg": "更新应用数据失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
logrus.WithFields(logrus.Fields{
"app_uuid": req.UUID,
"app_name": app.Name,
}).Info("App data updated successfully")
response := map[string]interface{}{
"code": 0,
"msg": "应用数据更新成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppUpdateAnnouncementHandler 更新应用程序公告处理器
func AppUpdateAnnouncementHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 解析请求体
var req struct {
UUID string `json:"uuid"`
Announcement string `json:"announcement"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logrus.WithError(err).Error("Failed to decode request body")
response := map[string]interface{}{
"code": 1,
"msg": "请求参数格式错误",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID
if req.UUID == "" {
response := map[string]interface{}{
"code": 1,
"msg": "应用UUID不能为空",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID格式
if _, err := uuid.Parse(req.UUID); err != nil {
logrus.WithError(err).Error("Invalid UUID format")
response := map[string]interface{}{
"code": 1,
"msg": "无效的UUID格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 获取数据库连接
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 查找应用
var app models.App
if err := db.Where("uuid = ?", req.UUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 对公告内容进行base64编码
encodedAnnouncement := base64.StdEncoding.EncodeToString([]byte(req.Announcement))
// 更新应用的公告内容
if err := db.Model(&app).Update("announcement", encodedAnnouncement).Error; err != nil {
logrus.WithError(err).Error("Failed to update app announcement")
response := map[string]interface{}{
"code": 1,
"msg": "更新程序公告失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
logrus.WithFields(logrus.Fields{
"app_uuid": req.UUID,
"app_name": app.Name,
}).Info("App announcement updated successfully")
response := map[string]interface{}{
"code": 0,
"msg": "程序公告更新成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// ... existing code ...
// AppGetMultiConfigHandler 获取应用多开配置
func AppGetMultiConfigHandler(w http.ResponseWriter, r *http.Request) {
appUUID := r.URL.Query().Get("uuid")
if appUUID == "" {
http.Error(w, "缺少应用UUID", http.StatusBadRequest)
return
}
// 验证UUID格式
if _, err := uuid.Parse(appUUID); err != nil {
http.Error(w, "无效的UUID格式", http.StatusBadRequest)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
return
}
var app models.App
if err := db.Where("uuid = ?", appUUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
http.Error(w, "应用不存在", http.StatusNotFound)
return
}
// 返回多开配置信息
response := map[string]interface{}{
"login_type": app.LoginType,
"multi_open_scope": app.MultiOpenScope,
"clean_interval": app.CleanInterval,
"check_interval": app.CheckInterval,
"multi_open_count": app.MultiOpenCount,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppUpdateMultiConfigHandler 更新应用多开配置
func AppUpdateMultiConfigHandler(w http.ResponseWriter, r *http.Request) {
var req struct {
UUID string `json:"uuid"`
LoginType int `json:"login_type"`
MultiOpenScope int `json:"multi_open_scope"`
CleanInterval int `json:"clean_interval"`
CheckInterval int `json:"check_interval"`
MultiOpenCount int `json:"multi_open_count"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
// 验证UUID格式
if _, err := uuid.Parse(req.UUID); err != nil {
http.Error(w, "无效的UUID格式", http.StatusBadRequest)
return
}
// 验证参数范围
if req.LoginType < 0 || req.LoginType > 1 {
http.Error(w, "登录方式参数无效", http.StatusBadRequest)
return
}
if req.MultiOpenScope < 0 || req.MultiOpenScope > 2 {
http.Error(w, "多开范围参数无效", http.StatusBadRequest)
return
}
if req.CleanInterval < 1 {
http.Error(w, "清理间隔必须大于0", http.StatusBadRequest)
return
}
if req.CheckInterval < 1 {
http.Error(w, "校验间隔必须大于0", http.StatusBadRequest)
return
}
if req.MultiOpenCount < 1 {
http.Error(w, "多开数量必须大于0", http.StatusBadRequest)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
http.Error(w, "数据库连接失败", http.StatusInternalServerError)
return
}
// 查找应用
var app models.App
if err := db.Where("uuid = ?", req.UUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
http.Error(w, "应用不存在", http.StatusNotFound)
return
}
// 更新多开配置
updates := map[string]interface{}{
"login_type": req.LoginType,
"multi_open_scope": req.MultiOpenScope,
"clean_interval": req.CleanInterval,
"check_interval": req.CheckInterval,
"multi_open_count": req.MultiOpenCount,
}
if err := db.Model(&app).Updates(updates).Error; err != nil {
logrus.WithError(err).Error("Failed to update app multi config")
http.Error(w, "更新多开配置失败", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": "多开配置更新成功"})
}
// AppGetBindConfigHandler 获取应用绑定配置
func AppGetBindConfigHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
appUUID := r.URL.Query().Get("uuid")
if appUUID == "" {
response := map[string]interface{}{
"code": 1,
"msg": "缺少应用UUID",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID格式
if _, err := uuid.Parse(appUUID); err != nil {
response := map[string]interface{}{
"code": 1,
"msg": "无效的UUID格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
var app models.App
if err := db.Where("uuid = ?", appUUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 返回绑定配置信息
response := map[string]interface{}{
"machine_verify": app.MachineVerify,
"machine_rebind_enabled": app.MachineRebindEnabled,
"machine_rebind_limit": app.MachineRebindLimit,
"machine_free_count": app.MachineFreeCount,
"machine_rebind_count": app.MachineRebindCount,
"machine_rebind_deduct": app.MachineRebindDeduct,
"ip_verify": app.IPVerify,
"ip_rebind_enabled": app.IPRebindEnabled,
"ip_rebind_limit": app.IPRebindLimit,
"ip_free_count": app.IPFreeCount,
"ip_rebind_count": app.IPRebindCount,
"ip_rebind_deduct": app.IPRebindDeduct,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppUpdateBindConfigHandler 更新应用绑定配置
func AppUpdateBindConfigHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
UUID string `json:"uuid"`
MachineVerify int `json:"machine_verify"`
MachineRebindEnabled int `json:"machine_rebind_enabled"`
MachineRebindLimit int `json:"machine_rebind_limit"`
MachineFreeCount int `json:"machine_free_count"`
MachineRebindCount int `json:"machine_rebind_count"`
MachineRebindDeduct int `json:"machine_rebind_deduct"`
IPVerify int `json:"ip_verify"`
IPRebindEnabled int `json:"ip_rebind_enabled"`
IPRebindLimit int `json:"ip_rebind_limit"`
IPFreeCount int `json:"ip_free_count"`
IPRebindCount int `json:"ip_rebind_count"`
IPRebindDeduct int `json:"ip_rebind_deduct"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logrus.WithError(err).Error("Failed to decode JSON request")
response := map[string]interface{}{
"code": 1,
"msg": "无效的JSON格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID
if req.UUID == "" {
response := map[string]interface{}{
"code": 1,
"msg": "应用UUID不能为空",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if _, err := uuid.Parse(req.UUID); err != nil {
response := map[string]interface{}{
"code": 1,
"msg": "无效的UUID格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证参数范围
if req.MachineVerify < 0 || req.MachineVerify > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "机器验证参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.MachineRebindLimit < 0 || req.MachineRebindLimit > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "机器重绑限制参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.IPVerify < 0 || req.IPVerify > 3 {
response := map[string]interface{}{
"code": 1,
"msg": "IP地址验证参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.IPRebindLimit < 0 || req.IPRebindLimit > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "IP地址重绑限制参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.MachineRebindEnabled < 0 || req.MachineRebindEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "机器重绑开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.IPRebindEnabled < 0 || req.IPRebindEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "IP地址重绑开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.MachineFreeCount < 0 || req.MachineRebindCount < 0 || req.MachineRebindDeduct < 0 ||
req.IPFreeCount < 0 || req.IPRebindCount < 0 || req.IPRebindDeduct < 0 {
response := map[string]interface{}{
"code": 1,
"msg": "数量参数不能为负数",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 查找应用
var app models.App
if err := db.Where("uuid = ?", req.UUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 更新绑定配置
updates := map[string]interface{}{
"machine_verify": req.MachineVerify,
"machine_rebind_enabled": req.MachineRebindEnabled,
"machine_rebind_limit": req.MachineRebindLimit,
"machine_free_count": req.MachineFreeCount,
"machine_rebind_count": req.MachineRebindCount,
"machine_rebind_deduct": req.MachineRebindDeduct,
"ip_verify": req.IPVerify,
"ip_rebind_enabled": req.IPRebindEnabled,
"ip_rebind_limit": req.IPRebindLimit,
"ip_free_count": req.IPFreeCount,
"ip_rebind_count": req.IPRebindCount,
"ip_rebind_deduct": req.IPRebindDeduct,
}
if err := db.Model(&app).Updates(updates).Error; err != nil {
logrus.WithError(err).Error("Failed to update app bind config")
response := map[string]interface{}{
"code": 1,
"msg": "更新绑定配置失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
response := map[string]interface{}{
"code": 0,
"msg": "绑定配置更新成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppGetRegisterConfigHandler 获取应用注册配置
func AppGetRegisterConfigHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
appUUID := r.URL.Query().Get("uuid")
if appUUID == "" {
response := map[string]interface{}{
"code": 1,
"msg": "缺少应用UUID",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID格式
if _, err := uuid.Parse(appUUID); err != nil {
response := map[string]interface{}{
"code": 1,
"msg": "无效的UUID格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
var app models.App
if err := db.Where("uuid = ?", appUUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 返回注册配置信息
response := map[string]interface{}{
"register_enabled": app.RegisterEnabled,
"register_limit_enabled": app.RegisterLimitEnabled,
"register_limit_time": app.RegisterLimitTime,
"register_count": app.RegisterCount,
"trial_enabled": app.TrialEnabled,
"trial_limit_time": app.TrialLimitTime,
"trial_duration": app.TrialDuration,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// AppUpdateRegisterConfigHandler 更新应用注册配置
func AppUpdateRegisterConfigHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
UUID string `json:"uuid"`
RegisterEnabled int `json:"register_enabled"`
RegisterLimitEnabled int `json:"register_limit_enabled"`
RegisterLimitTime int `json:"register_limit_time"`
RegisterCount int `json:"register_count"`
TrialEnabled int `json:"trial_enabled"`
TrialLimitTime int `json:"trial_limit_time"`
TrialDuration int `json:"trial_duration"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logrus.WithError(err).Error("Failed to decode JSON request")
response := map[string]interface{}{
"code": 1,
"msg": "无效的JSON格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证UUID
if req.UUID == "" {
response := map[string]interface{}{
"code": 1,
"msg": "应用UUID不能为空",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if _, err := uuid.Parse(req.UUID); err != nil {
response := map[string]interface{}{
"code": 1,
"msg": "无效的UUID格式",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 验证参数范围
if req.RegisterEnabled < 0 || req.RegisterEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "账号注册开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.RegisterLimitEnabled < 0 || req.RegisterLimitEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "注册限制开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.RegisterLimitTime < 0 || req.RegisterLimitTime > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "注册限制时间参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.RegisterCount < 1 {
response := map[string]interface{}{
"code": 1,
"msg": "注册次数必须大于0",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.TrialEnabled < 0 || req.TrialEnabled > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "领取试用开关参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.TrialLimitTime < 0 || req.TrialLimitTime > 1 {
response := map[string]interface{}{
"code": 1,
"msg": "试用限制时间参数无效",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
if req.TrialDuration < 0 {
response := map[string]interface{}{
"code": 1,
"msg": "试用时间不能为负数",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
db, err := database.GetDB()
if err != nil {
logrus.WithError(err).Error("Failed to get database connection")
response := map[string]interface{}{
"code": 1,
"msg": "数据库连接失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 查找应用
var app models.App
if err := db.Where("uuid = ?", req.UUID).First(&app).Error; err != nil {
logrus.WithError(err).Error("Failed to find app")
response := map[string]interface{}{
"code": 1,
"msg": "应用不存在",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
// 更新注册配置
updates := map[string]interface{}{
"register_enabled": req.RegisterEnabled,
"register_limit_enabled": req.RegisterLimitEnabled,
"register_limit_time": req.RegisterLimitTime,
"register_count": req.RegisterCount,
"trial_enabled": req.TrialEnabled,
"trial_limit_time": req.TrialLimitTime,
"trial_duration": req.TrialDuration,
}
if err := db.Model(&app).Updates(updates).Error; err != nil {
logrus.WithError(err).Error("Failed to update app register config")
response := map[string]interface{}{
"code": 1,
"msg": "更新注册配置失败",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
return
}
response := map[string]interface{}{
"code": 0,
"msg": "注册配置更新成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}