213 lines
4.6 KiB
Go
213 lines
4.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"nebula/internal/api/response"
|
|
"nebula/internal/asset"
|
|
"path/filepath"
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type AssetHandler struct {
|
|
service *asset.AssetService
|
|
}
|
|
|
|
func NewAssetHandler(service *asset.AssetService) *AssetHandler {
|
|
return &AssetHandler{service: service}
|
|
}
|
|
|
|
// List 获取所有资源列表
|
|
// GET /api/assets
|
|
func (h *AssetHandler) List(c *gin.Context) {
|
|
assets, err := h.service.List()
|
|
if err != nil {
|
|
response.FailServer(c, err.Error())
|
|
return
|
|
}
|
|
response.Ok(c, assets)
|
|
}
|
|
|
|
// ListByRelease 获取指定发布版本的所有资源
|
|
// GET /api/releases/:id/assets
|
|
func (h *AssetHandler) ListByRelease(c *gin.Context) {
|
|
releaseID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.FailBadRequest(c, "invalid release id")
|
|
return
|
|
}
|
|
|
|
assets, err := h.service.ListByRelease(uint(releaseID))
|
|
if err != nil {
|
|
response.FailServer(c, err.Error())
|
|
return
|
|
}
|
|
response.Ok(c, assets)
|
|
}
|
|
|
|
// Get 获取单个资源详情
|
|
// GET /api/assets/:id
|
|
func (h *AssetHandler) Get(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.FailBadRequest(c, "invalid asset id")
|
|
return
|
|
}
|
|
|
|
ast, err := h.service.Get(uint(id))
|
|
if err != nil {
|
|
response.FailServer(c, err.Error())
|
|
return
|
|
}
|
|
response.Ok(c, ast)
|
|
}
|
|
|
|
// Upload 上传文件并创建资源
|
|
// POST /api/releases/:id/assets/upload
|
|
func (h *AssetHandler) Upload(c *gin.Context) {
|
|
releaseID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.FailBadRequest(c, "invalid release id")
|
|
return
|
|
}
|
|
|
|
// 获取表单参数
|
|
platform := c.PostForm("platform")
|
|
arch := c.PostForm("arch")
|
|
|
|
if platform == "" || arch == "" {
|
|
response.FailBadRequest(c, "platform and arch are required")
|
|
return
|
|
}
|
|
|
|
// 获取上传的文件
|
|
file, err := c.FormFile("file")
|
|
if err != nil {
|
|
response.FailBadRequest(c, "file is required")
|
|
return
|
|
}
|
|
|
|
// 验证文件扩展名(可选)
|
|
ext := filepath.Ext(file.Filename)
|
|
allowedExts := map[string]bool{
|
|
".exe": true, ".dmg": true, ".pkg": true, ".deb": true,
|
|
".rpm": true, ".appimage": true, ".zip": true, ".tar.gz": true,
|
|
".msi": true, ".app": true,
|
|
}
|
|
if !allowedExts[ext] {
|
|
response.FailBadRequest(c, "unsupported file type: "+ext)
|
|
return
|
|
}
|
|
|
|
// 上传文件
|
|
ast, err := h.service.Upload(uint(releaseID), platform, arch, file)
|
|
if err != nil {
|
|
response.FailServer(c, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Ok(c, ast)
|
|
}
|
|
|
|
// Create 创建资源记录(用于外部 URL)
|
|
// POST /api/assets
|
|
func (h *AssetHandler) Create(c *gin.Context) {
|
|
var ast asset.Asset
|
|
if err := c.ShouldBindJSON(&ast); err != nil {
|
|
response.FailBadRequest(c, err.Error())
|
|
return
|
|
}
|
|
|
|
// 基本验证
|
|
if ast.ReleaseID == 0 {
|
|
response.FailBadRequest(c, "releaseId is required")
|
|
return
|
|
}
|
|
if ast.Platform == "" {
|
|
response.FailBadRequest(c, "platform is required")
|
|
return
|
|
}
|
|
if ast.Arch == "" {
|
|
response.FailBadRequest(c, "arch is required")
|
|
return
|
|
}
|
|
if ast.URL == "" {
|
|
response.FailBadRequest(c, "url is required")
|
|
return
|
|
}
|
|
|
|
err := h.service.Create(ast)
|
|
if err != nil {
|
|
response.FailServer(c, err.Error())
|
|
return
|
|
}
|
|
response.OkMsg(c, "created")
|
|
}
|
|
|
|
// Update 更新资源信息
|
|
// PUT /api/assets/:id
|
|
func (h *AssetHandler) Update(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.FailBadRequest(c, "invalid asset id")
|
|
return
|
|
}
|
|
|
|
var ast asset.Asset
|
|
if err := c.ShouldBindJSON(&ast); err != nil {
|
|
response.FailBadRequest(c, err.Error())
|
|
return
|
|
}
|
|
|
|
data := map[string]any{
|
|
"platform": ast.Platform,
|
|
"arch": ast.Arch,
|
|
"signature": ast.Signature,
|
|
"checksum": ast.Checksum,
|
|
}
|
|
|
|
err = h.service.Update(uint(id), data)
|
|
if err != nil {
|
|
response.FailServer(c, err.Error())
|
|
return
|
|
}
|
|
response.OkMsg(c, "updated")
|
|
}
|
|
|
|
// Delete 删除资源
|
|
// DELETE /api/assets/:id
|
|
func (h *AssetHandler) Delete(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.FailBadRequest(c, "invalid asset id")
|
|
return
|
|
}
|
|
|
|
err = h.service.Delete(uint(id))
|
|
if err != nil {
|
|
response.FailServer(c, err.Error())
|
|
return
|
|
}
|
|
response.OkMsg(c, "deleted")
|
|
}
|
|
|
|
// Download 下载资源文件
|
|
// GET /api/assets/:id/download
|
|
func (h *AssetHandler) Download(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
response.FailBadRequest(c, "invalid asset id")
|
|
return
|
|
}
|
|
|
|
// 获取存储路径
|
|
storagePath, err := h.service.GetStoragePath(uint(id))
|
|
if err != nil {
|
|
response.FailServer(c, err.Error())
|
|
return
|
|
}
|
|
|
|
// 返回文件(Gin 会自动处理文件下载)
|
|
c.File(storagePath)
|
|
}
|