2026-07-07 10:29:28 +08:00
|
|
|
package artefact
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"crypto/sha256"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
2026-07-07 14:40:09 +08:00
|
|
|
"onixbyte.com/pipely/internal/database"
|
|
|
|
|
"onixbyte.com/pipely/internal/model"
|
2026-07-07 10:29:28 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Handler struct {
|
|
|
|
|
db *gorm.DB
|
|
|
|
|
artefactDir string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewHandler(db *gorm.DB, artefactDir string) *Handler {
|
|
|
|
|
return &Handler{db: db, artefactDir: artefactDir}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *Handler) Upload(c *gin.Context) {
|
|
|
|
|
version := c.PostForm("version")
|
|
|
|
|
if version == "" {
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "version is required"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deltaRef := c.PostForm("deltaRef")
|
|
|
|
|
metadata := c.PostForm("metadata")
|
|
|
|
|
if metadata == "" {
|
|
|
|
|
metadata = "{}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file, header, err := c.Request.FormFile("file")
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "file is required: " + err.Error()})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
|
|
destDir := filepath.Join(h.artefactDir, version)
|
|
|
|
|
if err := os.MkdirAll(destDir, 0755); err != nil {
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create directory"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
destPath := filepath.Join(destDir, header.Filename)
|
|
|
|
|
out, err := os.Create(destPath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create file"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer out.Close()
|
|
|
|
|
|
|
|
|
|
hasher := sha256.New()
|
|
|
|
|
writer := io.MultiWriter(out, hasher)
|
|
|
|
|
|
|
|
|
|
size, err := io.Copy(writer, file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to write file"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sha256Hash := fmt.Sprintf("%x", hasher.Sum(nil))
|
|
|
|
|
|
|
|
|
|
artefact := &model.Artefact{
|
|
|
|
|
Version: version,
|
|
|
|
|
FileName: header.Filename,
|
|
|
|
|
FilePath: destPath,
|
|
|
|
|
FileSize: size,
|
|
|
|
|
SHA256Hash: sha256Hash,
|
|
|
|
|
DeltaRef: deltaRef,
|
|
|
|
|
IsDelta: deltaRef != "",
|
|
|
|
|
Metadata: metadata,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := database.CreateArtefact(h.db, artefact); err != nil {
|
|
|
|
|
os.Remove(destPath)
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save artefact: " + err.Error()})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusCreated, artefact)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *Handler) List(c *gin.Context) {
|
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
|
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))
|
|
|
|
|
|
|
|
|
|
if page < 1 {
|
|
|
|
|
page = 1
|
|
|
|
|
}
|
|
|
|
|
if pageSize < 1 || pageSize > 100 {
|
|
|
|
|
pageSize = 20
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
artefacts, total, err := database.ListArtefacts(h.db, page, pageSize)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, model.PaginatedResponse{
|
|
|
|
|
Data: artefacts,
|
|
|
|
|
Total: total,
|
|
|
|
|
Page: page,
|
|
|
|
|
PageSize: pageSize,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *Handler) Get(c *gin.Context) {
|
|
|
|
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
artefact, err := database.GetArtefactByID(h.db, id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
|
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Artefact not found"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, artefact)
|
|
|
|
|
}
|