Files
st/server/api/v1/app/extension.go
2026-02-14 06:20:05 +08:00

578 lines
16 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 app
import (
"io"
"strconv"
"git.echol.cn/loser/st/server/global"
"git.echol.cn/loser/st/server/middleware"
"git.echol.cn/loser/st/server/model/app/request"
"git.echol.cn/loser/st/server/model/app/response"
sysResponse "git.echol.cn/loser/st/server/model/common/response"
"git.echol.cn/loser/st/server/service"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type ExtensionApi struct{}
var extensionService = service.ServiceGroupApp.AppServiceGroup.ExtensionService
// CreateExtension 创建扩展
// @Summary 创建扩展
// @Description 创建一个新的扩展
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param data body request.CreateExtensionRequest true "扩展信息"
// @Success 200 {object} response.Response{data=response.ExtensionResponse}
// @Router /app/extension [post]
func (a *ExtensionApi) CreateExtension(c *gin.Context) {
userID := middleware.GetAppUserID(c)
var req request.CreateExtensionRequest
if err := c.ShouldBindJSON(&req); err != nil {
sysResponse.FailWithMessage(err.Error(), c)
return
}
ext, err := extensionService.CreateExtension(userID, &req)
if err != nil {
global.GVA_LOG.Error("创建扩展失败", zap.Error(err))
sysResponse.FailWithMessage("创建失败: "+err.Error(), c)
return
}
sysResponse.OkWithData(response.ToExtensionResponse(ext), c)
}
// UpdateExtension 更新扩展
// @Summary 更新扩展
// @Description 更新扩展信息
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Param data body request.UpdateExtensionRequest true "扩展信息"
// @Success 200 {object} response.Response
// @Router /app/extension/:id [put]
func (a *ExtensionApi) UpdateExtension(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
var req request.UpdateExtensionRequest
if err := c.ShouldBindJSON(&req); err != nil {
sysResponse.FailWithMessage(err.Error(), c)
return
}
if err := extensionService.UpdateExtension(userID, extID, &req); err != nil {
global.GVA_LOG.Error("更新扩展失败", zap.Error(err))
sysResponse.FailWithMessage("更新失败: "+err.Error(), c)
return
}
sysResponse.OkWithMessage("更新成功", c)
}
// DeleteExtension 删除扩展
// @Summary 删除扩展
// @Description 删除/卸载扩展
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Success 200 {object} response.Response
// @Router /app/extension/:id [delete]
func (a *ExtensionApi) DeleteExtension(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
if err := extensionService.DeleteExtension(userID, extID); err != nil {
global.GVA_LOG.Error("删除扩展失败", zap.Error(err))
sysResponse.FailWithMessage("删除失败: "+err.Error(), c)
return
}
sysResponse.OkWithMessage("删除成功", c)
}
// GetExtension 获取扩展详情
// @Summary 获取扩展详情
// @Description 获取扩展详细信息
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Success 200 {object} response.Response{data=response.ExtensionResponse}
// @Router /app/extension/:id [get]
func (a *ExtensionApi) GetExtension(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
ext, err := extensionService.GetExtension(userID, extID)
if err != nil {
global.GVA_LOG.Error("获取扩展失败", zap.Error(err))
sysResponse.FailWithMessage("获取失败: "+err.Error(), c)
return
}
sysResponse.OkWithData(response.ToExtensionResponse(ext), c)
}
// GetExtensionList 获取扩展列表
// @Summary 获取扩展列表
// @Description 获取扩展列表
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param keyword query string false "关键词"
// @Param extensionType query string false "扩展类型"
// @Param category query string false "分类"
// @Param isEnabled query bool false "是否启用"
// @Param page query int false "页码"
// @Param pageSize query int false "每页大小"
// @Success 200 {object} response.Response{data=response.ExtensionListResponse}
// @Router /app/extension [get]
func (a *ExtensionApi) GetExtensionList(c *gin.Context) {
userID := middleware.GetAppUserID(c)
var req request.ExtensionListRequest
if err := c.ShouldBindQuery(&req); err != nil {
sysResponse.FailWithMessage(err.Error(), c)
return
}
// 默认分页
if req.Page < 1 {
req.Page = 1
}
if req.PageSize < 1 {
req.PageSize = 20
}
extensions, total, err := extensionService.GetExtensionList(userID, &req)
if err != nil {
global.GVA_LOG.Error("获取扩展列表失败", zap.Error(err))
sysResponse.FailWithMessage("获取失败: "+err.Error(), c)
return
}
list := make([]response.ExtensionResponse, 0, len(extensions))
for i := range extensions {
list = append(list, response.ToExtensionResponse(&extensions[i]))
}
sysResponse.OkWithData(response.ExtensionListResponse{
List: list,
Total: total,
Page: req.Page,
PageSize: req.PageSize,
}, c)
}
// GetEnabledExtensions 获取启用的扩展列表
// @Summary 获取启用的扩展列表
// @Description 获取当前用户所有已启用的扩展
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Success 200 {object} response.Response{data=[]response.ExtensionResponse}
// @Router /app/extension/enabled [get]
func (a *ExtensionApi) GetEnabledExtensions(c *gin.Context) {
userID := middleware.GetAppUserID(c)
extensions, err := extensionService.GetEnabledExtensions(userID)
if err != nil {
global.GVA_LOG.Error("获取启用扩展失败", zap.Error(err))
sysResponse.FailWithMessage("获取失败: "+err.Error(), c)
return
}
list := make([]response.ExtensionResponse, 0, len(extensions))
for i := range extensions {
list = append(list, response.ToExtensionResponse(&extensions[i]))
}
sysResponse.OkWithData(list, c)
}
// ToggleExtension 启用/禁用扩展
// @Summary 启用/禁用扩展
// @Description 切换扩展的启用状态
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Param data body request.ToggleExtensionRequest true "启用状态"
// @Success 200 {object} response.Response
// @Router /app/extension/:id/toggle [post]
func (a *ExtensionApi) ToggleExtension(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
var req request.ToggleExtensionRequest
if err := c.ShouldBindJSON(&req); err != nil {
sysResponse.FailWithMessage(err.Error(), c)
return
}
if err := extensionService.ToggleExtension(userID, extID, req.IsEnabled); err != nil {
global.GVA_LOG.Error("切换扩展状态失败", zap.Error(err))
sysResponse.FailWithMessage("操作失败: "+err.Error(), c)
return
}
msg := "已禁用"
if req.IsEnabled {
msg = "已启用"
}
sysResponse.OkWithMessage(msg, c)
}
// GetExtensionSettings 获取扩展设置
// @Summary 获取扩展设置
// @Description 获取扩展的个性化设置
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Success 200 {object} response.Response
// @Router /app/extension/:id/settings [get]
func (a *ExtensionApi) GetExtensionSettings(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
settings, err := extensionService.GetExtensionSettings(userID, extID)
if err != nil {
global.GVA_LOG.Error("获取扩展设置失败", zap.Error(err))
sysResponse.FailWithMessage("获取失败: "+err.Error(), c)
return
}
sysResponse.OkWithData(settings, c)
}
// UpdateExtensionSettings 更新扩展设置
// @Summary 更新扩展设置
// @Description 更新扩展的个性化设置
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Param data body request.UpdateExtensionSettingsRequest true "设置数据"
// @Success 200 {object} response.Response
// @Router /app/extension/:id/settings [put]
func (a *ExtensionApi) UpdateExtensionSettings(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
var req request.UpdateExtensionSettingsRequest
if err := c.ShouldBindJSON(&req); err != nil {
sysResponse.FailWithMessage(err.Error(), c)
return
}
if err := extensionService.UpdateExtensionSettings(userID, extID, req.Settings); err != nil {
global.GVA_LOG.Error("更新扩展设置失败", zap.Error(err))
sysResponse.FailWithMessage("更新失败: "+err.Error(), c)
return
}
sysResponse.OkWithMessage("设置已保存", c)
}
// GetExtensionManifest 获取扩展 manifest
// @Summary 获取扩展 manifest
// @Description 获取扩展的 manifest 数据
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Success 200 {object} response.Response
// @Router /app/extension/:id/manifest [get]
func (a *ExtensionApi) GetExtensionManifest(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
manifest, err := extensionService.GetExtensionManifest(userID, extID)
if err != nil {
global.GVA_LOG.Error("获取扩展 manifest 失败", zap.Error(err))
sysResponse.FailWithMessage("获取失败: "+err.Error(), c)
return
}
sysResponse.OkWithData(manifest, c)
}
// ImportExtension 导入扩展
// @Summary 导入扩展
// @Description 从 ZIP 压缩包或 JSON 文件导入扩展
// @Tags 扩展管理
// @Accept multipart/form-data
// @Produce json
// @Param file formData file true "扩展文件zip/json"
// @Success 200 {object} response.Response{data=response.ExtensionResponse}
// @Router /app/extension/import [post]
func (a *ExtensionApi) ImportExtension(c *gin.Context) {
userID := middleware.GetAppUserID(c)
// 获取文件
file, err := c.FormFile("file")
if err != nil {
sysResponse.FailWithMessage("请上传扩展文件(支持 .zip 或 .json", c)
return
}
// 文件大小限制100MBzip 包可能较大)
if file.Size > 100<<20 {
sysResponse.FailWithMessage("文件大小不能超过 100MB", c)
return
}
// 读取文件内容
src, err := file.Open()
if err != nil {
global.GVA_LOG.Error("打开文件失败", zap.Error(err))
sysResponse.FailWithMessage("文件读取失败", c)
return
}
defer src.Close()
fileData, err := io.ReadAll(src)
if err != nil {
global.GVA_LOG.Error("读取文件内容失败", zap.Error(err))
sysResponse.FailWithMessage("文件读取失败", c)
return
}
filename := file.Filename
ext, err := extensionService.ImportExtension(userID, filename, fileData)
if err != nil {
global.GVA_LOG.Error("导入扩展失败", zap.Error(err))
sysResponse.FailWithMessage("导入失败: "+err.Error(), c)
return
}
sysResponse.OkWithData(response.ToExtensionResponse(ext), c)
}
// ExportExtension 导出扩展
// @Summary 导出扩展
// @Description 导出扩展数据为 JSON
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Success 200 {object} response.ExtensionResponse
// @Router /app/extension/:id/export [get]
func (a *ExtensionApi) ExportExtension(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
exportData, err := extensionService.ExportExtension(userID, extID)
if err != nil {
global.GVA_LOG.Error("导出扩展失败", zap.Error(err))
sysResponse.FailWithMessage("导出失败: "+err.Error(), c)
return
}
sysResponse.OkWithData(exportData, c)
}
// InstallFromUrl 从 URL 安装扩展
// @Summary 从 URL 安装扩展
// @Description 智能识别 Git URL 或 Manifest URL 安装扩展
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param data body request.InstallExtensionRequest true "安装参数"
// @Success 200 {object} response.Response
// @Router /app/extension/install/url [post]
func (a *ExtensionApi) InstallFromUrl(c *gin.Context) {
userID := middleware.GetAppUserID(c)
var req request.InstallExtensionRequest
if err := c.ShouldBindJSON(&req); err != nil {
sysResponse.FailWithMessage(err.Error(), c)
return
}
branch := req.Branch
if branch == "" {
branch = "main"
}
// 智能识别 URL 类型并安装
ext, err := extensionService.InstallExtensionFromURL(userID, req.URL, branch)
if err != nil {
global.GVA_LOG.Error("从 URL 安装扩展失败", zap.Error(err))
sysResponse.FailWithMessage("安装失败: "+err.Error(), c)
return
}
sysResponse.OkWithData(response.ToExtensionResponse(ext), c)
}
// InstallFromGit 从 Git URL 安装扩展
// @Summary 从 Git URL 安装扩展
// @Description 从 Git 仓库克隆安装扩展
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param data body request.InstallExtensionRequest true "安装参数"
// @Success 200 {object} response.Response{data=response.ExtensionResponse}
// @Router /app/extension/install/git [post]
func (a *ExtensionApi) InstallFromGit(c *gin.Context) {
userID := middleware.GetAppUserID(c)
var req request.InstallExtensionRequest
if err := c.ShouldBindJSON(&req); err != nil {
sysResponse.FailWithMessage(err.Error(), c)
return
}
branch := req.Branch
if branch == "" {
branch = "main"
}
// 执行 git clone 安装
ext, err := extensionService.InstallExtensionFromGit(userID, req.URL, branch)
if err != nil {
global.GVA_LOG.Error("从 Git 安装扩展失败", zap.Error(err))
sysResponse.FailWithMessage("安装失败: "+err.Error(), c)
return
}
sysResponse.OkWithData(response.ToExtensionResponse(ext), c)
}
// UpgradeExtension 升级扩展
// @Summary 升级扩展
// @Description 从源地址重新安装以升级扩展
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Success 200 {object} response.Response{data=response.ExtensionResponse}
// @Router /app/extension/:id/upgrade [post]
func (a *ExtensionApi) UpgradeExtension(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
ext, err := extensionService.UpgradeExtension(userID, extID)
if err != nil {
global.GVA_LOG.Error("升级扩展失败", zap.Error(err))
sysResponse.FailWithMessage("升级失败: "+err.Error(), c)
return
}
sysResponse.OkWithData(response.ToExtensionResponse(ext), c)
}
// UpdateStats 更新扩展统计
// @Summary 更新扩展统计
// @Description 更新扩展的使用统计信息
// @Tags 扩展管理
// @Accept json
// @Produce json
// @Param id path int true "扩展ID"
// @Success 200 {object} response.Response
// @Router /app/extension/:id/stats [post]
func (a *ExtensionApi) UpdateStats(c *gin.Context) {
userID := middleware.GetAppUserID(c)
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
sysResponse.FailWithMessage("无效的扩展ID", c)
return
}
extID := uint(id)
var req struct {
Action string `json:"action" binding:"required"`
Value int `json:"value"`
}
if err := c.ShouldBindJSON(&req); err != nil {
sysResponse.FailWithMessage(err.Error(), c)
return
}
if req.Value == 0 {
req.Value = 1
}
if err := extensionService.UpdateExtensionStats(userID, extID, req.Action, req.Value); err != nil {
global.GVA_LOG.Error("更新统计失败", zap.Error(err))
sysResponse.FailWithMessage("更新失败: "+err.Error(), c)
return
}
sysResponse.OkWithMessage("统计已更新", c)
}