first commit, i i have no idea what i have done

This commit is contained in:
tdv
2025-08-31 22:42:08 +03:00
commit c5632f6a37
177 changed files with 9173 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
package handlers
import (
"context"
"fmt"
"mime/multipart"
"net/http"
"path"
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/minio/minio-go/v7"
"gorm.io/gorm"
"smoop-api/internal/dto"
"smoop-api/internal/models"
)
type RecordsHandler struct {
db *gorm.DB
minio *minio.Client
recordsBucket string
presignTTL time.Duration
}
func NewRecordsHandler(db *gorm.DB, mc *minio.Client, bucket string, ttl time.Duration) *RecordsHandler {
return &RecordsHandler{db: db, minio: mc, recordsBucket: bucket, presignTTL: ttl}
}
func (h *RecordsHandler) Upload(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "file required"})
return
}
guid := c.PostForm("guid")
if guid == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "guid required"})
return
}
startedAt, _ := strconv.ParseInt(c.PostForm("startedAt"), 10, 64)
stoppedAt, _ := strconv.ParseInt(c.PostForm("stoppedAt"), 10, 64)
var dev models.Device
if err := h.db.Where("guid = ?", guid).First(&dev).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "device not found"})
return
}
objKey := fmt.Sprintf("%s/%d_%s", guid, time.Now().UnixNano(), path.Base(file.Filename))
if err := h.putFile(c, file, h.recordsBucket, objKey); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "upload failed"})
return
}
rec := models.Record{
DeviceGUID: dev.GUID,
StartedAt: startedAt,
StoppedAt: stoppedAt,
ObjectKey: objKey,
}
if err := h.db.Create(&rec).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "db save failed"})
return
}
c.JSON(http.StatusCreated, dto.RecordDto{ID: rec.ID, StartedAt: rec.StartedAt, StoppedAt: rec.StoppedAt})
}
func (h *RecordsHandler) putFile(c *gin.Context, fh *multipart.FileHeader, bucket, object string) error {
src, err := fh.Open()
if err != nil {
return err
}
defer src.Close()
_, err = h.minio.PutObject(c, bucket, object, src, fh.Size, minio.PutObjectOptions{
ContentType: fh.Header.Get("Content-Type"),
ContentDisposition: "attachment; filename=" + fh.Filename,
})
return err
}
func (h *RecordsHandler) List(c *gin.Context) {
guid := c.Query("guid")
if guid == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "guid is required"})
return
}
offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50"))
if limit <= 0 || limit > 200 {
limit = 50
}
var total int64
h.db.Model(&models.Record{}).Where("device_guid = ?", guid).Count(&total)
var recs []models.Record
if err := h.db.Where("device_guid = ?", guid).Order("id desc").Offset(offset).Limit(limit).Find(&recs).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "query failed"})
return
}
out := make([]dto.RecordDto, 0, len(recs))
for _, r := range recs {
out = append(out, dto.RecordDto{ID: r.ID, StartedAt: r.StartedAt, StoppedAt: r.StoppedAt})
}
c.JSON(http.StatusOK, dto.RecordListDto{Records: out, Offset: offset, Limit: limit, Total: total})
}
func (h *RecordsHandler) File(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var rec models.Record
if err := h.db.First(&rec, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
u, err := h.minio.PresignedGetObject(context.Background(), h.recordsBucket, rec.ObjectKey, h.presignTTL, nil)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "presign failed"})
return
}
c.Redirect(http.StatusFound, u.String())
}