From c2e0c9fce46f1741a709e7a34d48d994c9fa5b42 Mon Sep 17 00:00:00 2001 From: m Date: Sun, 12 Jul 2026 09:15:06 +0200 Subject: [PATCH] create file into db --- backend/cmd/server/main.go | 25 ++++---- backend/internal/db/files.sql.go | 7 +-- backend/internal/db/migrations/schema.sql | 2 +- backend/internal/db/models.go | 14 ++--- backend/internal/handlers/files.go | 72 +++++++++++++++++++---- backend/internal/handlers/handlers.go | 11 ++++ backend/internal/handlers/health.go | 2 +- backend/internal/handlers/ocr.go | 4 +- backend/internal/service/checksum.go | 22 +++++++ 9 files changed, 122 insertions(+), 37 deletions(-) create mode 100644 backend/internal/handlers/handlers.go create mode 100644 backend/internal/service/checksum.go diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index 75bb501..5b870d1 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -21,24 +21,25 @@ func main() { } defer database.Close() - _ = database // will be passed to handlers once queries are implemented + queries := db.New(database) + h := handlers.New(queries) r := gin.Default() - r.GET("/api/v1/health", handlers.Health) + r.GET("/api/v1/health", h.Health) - r.GET("/api/v1/files", handlers.ListFiles) - r.GET("/api/v1/file/:id", handlers.ListFile) - r.POST("/api/v1/files/upload", handlers.UploadFile) - r.GET("/api/v1/files/:id", handlers.GetFile) - r.DELETE("/api/v1/files/:id", handlers.DeleteFile) - r.GET("/api/v1/files/search", handlers.SearchFiles) + r.GET("/api/v1/files", h.ListFiles) + r.GET("/api/v1/file/:id", h.ListFile) + r.POST("/api/v1/files/upload", h.UploadFile) + r.GET("/api/v1/files/:id", h.GetFile) + r.DELETE("/api/v1/files/:id", h.DeleteFile) + r.GET("/api/v1/files/search", h.SearchFiles) - r.POST("/api/v1/files/:id/tags", handlers.AddTags) - r.GET("/api/v1/files/:id/tags", handlers.GetTags) + r.POST("/api/v1/files/:id/tags", h.AddTags) + r.GET("/api/v1/files/:id/tags", h.GetTags) - r.POST("/api/v1/ocr/jobs", handlers.CreateOcrJob) - r.GET("/api/v1/ocr/jobs/:id", handlers.GetOcrJobStatus) + r.POST("/api/v1/ocr/jobs", h.CreateOcrJob) + r.GET("/api/v1/ocr/jobs/:id", h.GetOcrJobStatus) log.Printf("Server starting on port %s", port) if err := r.Run(":" + port); err != nil { diff --git a/backend/internal/db/files.sql.go b/backend/internal/db/files.sql.go index 21aa12d..b1b584d 100644 --- a/backend/internal/db/files.sql.go +++ b/backend/internal/db/files.sql.go @@ -7,7 +7,6 @@ package db import ( "context" - "database/sql" ) const createFile = `-- name: CreateFile :one @@ -20,9 +19,9 @@ RETURNING id, name, storage_key, checksum, created_at, updated_at, deleted_at ` type CreateFileParams struct { - Name string `json:"name"` - StorageKey string `json:"storage_key"` - Checksum sql.NullString `json:"checksum"` + Name string `json:"name"` + StorageKey string `json:"storage_key"` + Checksum string `json:"checksum"` } func (q *Queries) CreateFile(ctx context.Context, arg CreateFileParams) (File, error) { diff --git a/backend/internal/db/migrations/schema.sql b/backend/internal/db/migrations/schema.sql index d4f9c65..54bf01d 100644 --- a/backend/internal/db/migrations/schema.sql +++ b/backend/internal/db/migrations/schema.sql @@ -2,7 +2,7 @@ CREATE TABLE files ( id TEXT PRIMARY KEY, name TEXT NOT NULL, storage_key TEXT NOT NULL, - checksum TEXT, + checksum TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, deleted_at INTEGER diff --git a/backend/internal/db/models.go b/backend/internal/db/models.go index 973b2a8..9160ac7 100644 --- a/backend/internal/db/models.go +++ b/backend/internal/db/models.go @@ -9,13 +9,13 @@ import ( ) type File struct { - ID string `json:"id"` - Name string `json:"name"` - StorageKey string `json:"storage_key"` - Checksum sql.NullString `json:"checksum"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` - DeletedAt sql.NullInt64 `json:"deleted_at"` + ID string `json:"id"` + Name string `json:"name"` + StorageKey string `json:"storage_key"` + Checksum string `json:"checksum"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` + DeletedAt sql.NullInt64 `json:"deleted_at"` } type FileTag struct { diff --git a/backend/internal/handlers/files.go b/backend/internal/handlers/files.go index cddc557..3c87dc7 100644 --- a/backend/internal/handlers/files.go +++ b/backend/internal/handlers/files.go @@ -1,6 +1,8 @@ package handlers import ( + "context" + "fmt" "net/http" "os" "path" @@ -8,11 +10,12 @@ import ( "strconv" "github.com/gin-gonic/gin" + "github.com/vaultdrop/backend/internal/db" "github.com/vaultdrop/backend/internal/service" ) // retourne qui est delete qui est updated et created -func SyncFiles(c *gin.Context) { +func (h *Handlers) SyncFiles(c *gin.Context) { c.JSON(http.StatusNotImplemented, gin.H{ "error": gin.H{ "code": "NOT_IMPLEMENTED", @@ -21,7 +24,7 @@ func SyncFiles(c *gin.Context) { }) } -func ListFiles(c *gin.Context) { +func (h *Handlers) ListFiles(c *gin.Context) { dirs, err := os.ReadDir("./uploads/") @@ -79,7 +82,7 @@ func ListFiles(c *gin.Context) { }) } -func ListFile(c *gin.Context) { +func (h *Handlers) ListFile(c *gin.Context) { id := c.Param("id") @@ -144,7 +147,7 @@ func ListFile(c *gin.Context) { }) } -func GetFile(c *gin.Context) { +func (h *Handlers) GetFile(c *gin.Context) { exp, _ := strconv.ParseInt(c.Query("expires"), 10, 64) @@ -167,7 +170,9 @@ func GetFile(c *gin.Context) { } -func UploadFile(c *gin.Context) { +func (h *Handlers) UploadFile(c *gin.Context) { + + ctx := context.Background() file, err := c.FormFile("file") @@ -182,7 +187,53 @@ func UploadFile(c *gin.Context) { dst := filepath.Join("./uploads/", filepath.Base(file.Filename)) - c.SaveUploadedFile(file, dst) + err = c.SaveUploadedFile(file, dst) + + if err != nil { + + c.JSON(http.StatusInternalServerError, gin.H{ + "error": gin.H{ + "code": "ERROR", + "message": "Uploaded", + }, + }) + + return + + } + + fileByte, err := os.ReadFile(dst) + + if err != nil { + + // fmt.Println("error reading file") + + c.JSON(http.StatusInternalServerError, gin.H{ + "error": gin.H{ + "code": "ERROR", + "message": "Error reading file", + }, + }) + + return + + } + + checksum := service.CreateSHA256Hash(fileByte) + // save generate meta data + createFileParams := db.CreateFileParams{ + Name: file.Filename, + StorageKey: dst, + Checksum: string(checksum[:]), + } + + dbFile, err := h.queries.CreateFile(ctx, createFileParams) + + if err != nil { + fmt.Println(err) + } + + fmt.Println(dbFile.Checksum) c.JSON(http.StatusOK, gin.H{ "error": gin.H{ @@ -190,9 +241,10 @@ func UploadFile(c *gin.Context) { "message": "Uploaded", }, }) + } -func DeleteFile(c *gin.Context) { +func (h *Handlers) DeleteFile(c *gin.Context) { c.JSON(http.StatusNotImplemented, gin.H{ "error": gin.H{ "code": "NOT_IMPLEMENTED", @@ -201,7 +253,7 @@ func DeleteFile(c *gin.Context) { }) } -func SearchFiles(c *gin.Context) { +func (h *Handlers) SearchFiles(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "data": []interface{}{}, "meta": gin.H{ @@ -211,7 +263,7 @@ func SearchFiles(c *gin.Context) { }) } -func AddTags(c *gin.Context) { +func (h *Handlers) AddTags(c *gin.Context) { c.JSON(http.StatusNotImplemented, gin.H{ "error": gin.H{ "code": "NOT_IMPLEMENTED", @@ -220,7 +272,7 @@ func AddTags(c *gin.Context) { }) } -func GetTags(c *gin.Context) { +func (h *Handlers) GetTags(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "data": []interface{}{}, }) diff --git a/backend/internal/handlers/handlers.go b/backend/internal/handlers/handlers.go new file mode 100644 index 0000000..7216b92 --- /dev/null +++ b/backend/internal/handlers/handlers.go @@ -0,0 +1,11 @@ +package handlers + +import "github.com/vaultdrop/backend/internal/db" + +type Handlers struct { + queries *db.Queries +} + +func New(queries *db.Queries) *Handlers { + return &Handlers{queries: queries} +} diff --git a/backend/internal/handlers/health.go b/backend/internal/handlers/health.go index d1c0687..e1313e3 100644 --- a/backend/internal/handlers/health.go +++ b/backend/internal/handlers/health.go @@ -6,7 +6,7 @@ import ( "github.com/gin-gonic/gin" ) -func Health(c *gin.Context) { +func (h *Handlers) Health(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "data": gin.H{ "status": "healthy", diff --git a/backend/internal/handlers/ocr.go b/backend/internal/handlers/ocr.go index 9cefd82..1f02b11 100644 --- a/backend/internal/handlers/ocr.go +++ b/backend/internal/handlers/ocr.go @@ -6,7 +6,7 @@ import ( "github.com/gin-gonic/gin" ) -func CreateOcrJob(c *gin.Context) { +func (h *Handlers) CreateOcrJob(c *gin.Context) { c.JSON(http.StatusNotImplemented, gin.H{ "error": gin.H{ "code": "NOT_IMPLEMENTED", @@ -15,7 +15,7 @@ func CreateOcrJob(c *gin.Context) { }) } -func GetOcrJobStatus(c *gin.Context) { +func (h *Handlers) GetOcrJobStatus(c *gin.Context) { c.JSON(http.StatusNotFound, gin.H{ "error": gin.H{ "code": "JOB_NOT_FOUND", diff --git a/backend/internal/service/checksum.go b/backend/internal/service/checksum.go new file mode 100644 index 0000000..f2c2b3a --- /dev/null +++ b/backend/internal/service/checksum.go @@ -0,0 +1,22 @@ +package service + +import ( + "crypto/sha256" + "crypto/subtle" +) + +func CreateSHA256Hash(data []byte) []byte { + hasher := sha256.New() + + hasher.Write(data) + + return hasher.Sum(nil) +} + +func CompareHash(x, y []byte) bool { + if len(x) != len(y) { + return false + } + + return subtle.ConstantTimeCompare(x, y) == 1 +}