Files
siujamo 033082954a refactor: rename module to pipely and migrate web UI to MUI
- Rename Go module from onixbyte.com/message-converter-manifest to onixbyte.com/pipely
- Replace shadcn UI with Material UI components across all pages
- Add axios-based API client in shared/web-client with credentials management
- Organise API calls into feature modules: auth, devices, deployments, artefacts, users
- Add .env.example with VITE_API_BASE_URL pointing to pipely.onixbyte.com
- Fix deprecated FormEvent → MouseEvent in dialog submit handlers
2026-07-07 14:40:09 +08:00

138 lines
3.0 KiB
Go

package artefact
import (
"crypto/sha256"
"errors"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strconv"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"onixbyte.com/pipely/internal/database"
"onixbyte.com/pipely/internal/model"
)
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)
}