From 2c9817414484af08617c18cff464146892ebcd3d Mon Sep 17 00:00:00 2001 From: Victor Lacasse-Beaudoin Date: Mon, 24 Jul 2023 14:29:19 -0400 Subject: [PATCH] =?UTF-8?q?Migrer=20utilisation=20d'API=20handlers=20?= =?UTF-8?q?=C3=A0=20serverhandlers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/server.go | 354 ++------------------------------------------------ 1 file changed, 9 insertions(+), 345 deletions(-) diff --git a/cmd/server.go b/cmd/server.go index cef05fc..9c30316 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -4,7 +4,6 @@ Copyright © 2023 AGECEM package cmd import ( - "context" "crypto/subtle" "encoding/json" "fmt" @@ -14,9 +13,7 @@ import ( "html/template" "io" "net/http" - "sort" - "github.com/minio/minio-go/v7" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -24,6 +21,7 @@ import ( "git.agecem.com/agecem/agecem-org/config" "git.agecem.com/agecem/agecem-org/media" "git.agecem.com/agecem/agecem-org/public" + "git.agecem.com/agecem/agecem-org/serverhandlers" "git.agecem.com/agecem/agecem-org/templates" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" @@ -196,21 +194,21 @@ func RunServer() { // API Routes - groupV1.GET("", handleV1) + groupV1.GET("", serverhandlers.HandleV1) - groupV1.POST("/seed", handleV1Seed) + groupV1.POST("/seed", serverhandlers.HandleV1Seed) - groupV1.GET("/bucket", handleV1BucketList) + groupV1.GET("/bucket", serverhandlers.HandleV1BucketList) - groupV1.GET("/bucket/:bucket", handleV1BucketRead) + groupV1.GET("/bucket/:bucket", serverhandlers.HandleV1BucketRead) - groupV1.POST("/bucket/:bucket", handleV1DocumentCreate) + groupV1.POST("/bucket/:bucket", serverhandlers.HandleV1DocumentCreate) - groupV1.GET("/bucket/:bucket/:document", handleV1DocumentRead) + groupV1.GET("/bucket/:bucket/:document", serverhandlers.HandleV1DocumentRead) - groupV1.PUT("/bucket/:bucket/:document", handleV1DocumentUpdate) + groupV1.PUT("/bucket/:bucket/:document", serverhandlers.HandleV1DocumentUpdate) - groupV1.DELETE("/bucket/:bucket/:document", handleV1DocumentDelete) + groupV1.DELETE("/bucket/:bucket/:document", serverhandlers.HandleV1DocumentDelete) // HTML Routes @@ -250,340 +248,6 @@ func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Con return t.templates.ExecuteTemplate(w, name, data) } -// API Handlers - -// handleV1 affiche les routes accessibles. -// Les routes sont triées selon .Path, pour les rendre plus facilement navigables. -func handleV1(c echo.Context) error { - routes := c.Echo().Routes() - sort.Slice(routes, func(i, j int) bool { return routes[i].Path < routes[j].Path }) - return c.JSON(http.StatusOK, routes) -} - -// handleV1Seed créé des buckets dans minio selon la liste de buckets dans server.documents.buckets -// Les buckets sont créés avec paramètres par défaut, et sont ensuite visible dans /v1/bucket. -func handleV1Seed(c echo.Context) error { - mediaClient, err := media.NewMediaClientFromViper() - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during media.NewMediaClientFromViper()", - "error": err.Error(), - }) - } - - new_buckets, err := mediaClient.Seed() - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during mediaClient.Seed()", - "error": err.Error(), - }) - } - - var message string - if len(new_buckets) == 0 { - message = "All buckets already exist" - - } else { - message = "Buckets successfully created" - } - - return c.JSON(http.StatusOK, map[string]interface{}{ - "message": message, - "buckets": new_buckets, - }) -} - -// handleV1BucketList affiche les buckets permis par server.documents.buckets, qui existent. -func handleV1BucketList(c echo.Context) error { - mediaClient, err := media.NewMediaClientFromViper() - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during media.NewMediaClientFromViper()", - "error": err.Error(), - }) - } - - var buckets []string - - for _, bucket_name := range cfg.Server.Documents.Buckets { - exists, err := mediaClient.MinioClient.BucketExists(context.Background(), bucket_name) - if err != nil { - return c.JSON(http.StatusInternalServerError, "Error during minio#BucketExists") - } - - if exists { - buckets = append(buckets, bucket_name) - } - } - - return c.JSON(http.StatusOK, buckets) -} - -func handleV1BucketRead(c echo.Context) error { - bucket := c.Param("bucket") - - allowed := false - for _, bucket_allowed := range cfg.Server.Documents.Buckets { - if bucket == bucket_allowed { - allowed = true - } - } - - if !allowed { - /* - return c.JSON(http.StatusBadRequest, map[string]string{ - "message": "Bucket is not allowed in server.documents.buckets", - }) - */ - return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) - } - - ctx, cancel := context.WithCancel(context.Background()) - - defer cancel() - - mediaClient, err := media.NewMediaClientFromViper() - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during media.NewMediaClientFromViper()", - "error": err.Error(), - }) - } - - exists, err := mediaClient.MinioClient.BucketExists(ctx, bucket) - if err != nil { - return c.JSON(http.StatusInternalServerError, "Error during minio#BucketExists") - } - - if !exists { - return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) - } - - var keys []string - - objectCh := mediaClient.MinioClient.ListObjects(ctx, bucket, minio.ListObjectsOptions{}) - for object := range objectCh { - if object.Err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during minio#ListObjects", - }) - } - - keys = append(keys, object.Key) - } - - return c.JSON(http.StatusOK, keys) -} - -// handleV1DocumentCreate permet d'ajouter un object dans un bucket, par multipart/form-data -func handleV1DocumentCreate(c echo.Context) error { - bucket := c.Param("bucket") - - form_file, err := c.FormFile("document") - if err != nil { - return c.JSON(http.StatusBadRequest, map[string]interface{}{ - "message": "Error during handleV1DocumentCreate's echo#Context.FormFile", - "error": err, - }) - } - - allowed := false - for _, bucket_allowed := range cfg.Server.Documents.Buckets { - if bucket == bucket_allowed { - allowed = true - } - } - - if !allowed { - return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) - } - - ctx, cancel := context.WithCancel(context.Background()) - - defer cancel() - - mediaClient, err := media.NewMediaClientFromViper() - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during media.NewMediaClientFromViper()", - "error": err.Error(), - }) - } - - src, err := form_file.Open() - if err != nil { - return err - } - defer src.Close() - - /* - reg, err := regexp.Compile("[^.a-zA-Z0-9_-]+") - if err != nil { - return c.Render(http.StatusInternalServerError, "documentation-html", nil) - } - - filename_processed := reg.ReplaceAllString(form_file.Filename, "") - */ - - info, err := mediaClient.MinioClient.PutObject(ctx, bucket, form_file.Filename, src, form_file.Size, minio.PutObjectOptions{ - ContentType: form_file.Header.Get("Content-Type"), - }) - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during minio#PutObject", - }) - } - - return c.JSON(http.StatusOK, map[string]interface{}{ - "message": "ok", - "info": map[string]interface{}{ - "bucket": info.Bucket, - "key": info.Key, - "size": info.Size, - }, - }) -} - -// handleV1DocumentRead permet de lire le contenu d'un fichier et protentiellement de le télécharger -func handleV1DocumentRead(c echo.Context) error { - bucket := c.Param("bucket") - document := c.Param("document") - - allowed := false - for _, bucket_allowed := range cfg.Server.Documents.Buckets { - if bucket == bucket_allowed { - allowed = true - } - } - - if !allowed { - return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) - } - - ctx, cancel := context.WithCancel(context.Background()) - - defer cancel() - - mediaClient, err := media.NewMediaClientFromViper() - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during media.NewMediaClientFromViper()", - "error": err.Error(), - }) - } - - bucket_exists, err := mediaClient.MinioClient.BucketExists(ctx, bucket) - if err != nil { - return c.JSON(http.StatusInternalServerError, "Error during minio#BucketExists") - } - - if !bucket_exists { - return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) - } - - document_info, err := mediaClient.MinioClient.StatObject(ctx, bucket, document, minio.StatObjectOptions{}) - - if err != nil { - if err.Error() == "The specified key does not exist." { - - return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) - } - - return c.JSON(http.StatusInternalServerError, map[string]interface{}{ - "message": "Error during minio#StatObject", - }) - } - - _ = document_info - - document_object, err := mediaClient.MinioClient.GetObject(ctx, bucket, document, minio.GetObjectOptions{}) - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during minio#GetObject", - }) - } - - defer document_object.Close() - - return c.Stream(http.StatusOK, document_info.ContentType, document_object) -} - -// handleV1DocumentUpdate permet de mettre à jour certains champs d'un object, comme le Content-Type ou le Filename -func handleV1DocumentUpdate(c echo.Context) error { - return c.JSON(http.StatusNotImplemented, map[string]string{ - "message": "Not Implemented", - }) -} - -// handleV1DocumentDelete permet de supprimer un object -func handleV1DocumentDelete(c echo.Context) error { - bucket := c.Param("bucket") - document := c.Param("document") - - allowed := false - for _, bucket_allowed := range cfg.Server.Documents.Buckets { - if bucket == bucket_allowed { - allowed = true - } - } - - if !allowed { - /* - return c.JSON(http.StatusBadRequest, map[string]string{ - "message": "Bucket is not allowed in server.documents.buckets", - }) - */ - return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) - } - - ctx, cancel := context.WithCancel(context.Background()) - - defer cancel() - - mediaClient, err := media.NewMediaClientFromViper() - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during media.NewMediaClientFromViper()", - "error": err.Error(), - }) - } - - bucket_exists, err := mediaClient.MinioClient.BucketExists(ctx, bucket) - if err != nil { - return c.JSON(http.StatusInternalServerError, "Error during minio#BucketExists") - } - - if !bucket_exists { - return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) - } - - document_info, err := mediaClient.MinioClient.StatObject(ctx, bucket, document, minio.StatObjectOptions{}) - if err != nil { - if err.Error() == "The specified key does not exist." { - - return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) - } - - return c.JSON(http.StatusInternalServerError, map[string]interface{}{ - "message": "Error during minio#StatObject", - }) - } - - //TODO Add error validation - _ = document_info - - err = mediaClient.MinioClient.RemoveObject(ctx, bucket, document, minio.RemoveObjectOptions{}) - if err != nil { - return c.JSON(http.StatusInternalServerError, map[string]string{ - "message": "Error during minio#RemoveObject", - }) - } - - return c.JSON(http.StatusOK, map[string]string{ - "message": "Document deleted", - }) -} - // HTML Handlers func handleIndex(c echo.Context) error {