diff --git a/apihandler/document.go b/apihandler/document.go index 3f4a2ae..284add4 100644 --- a/apihandler/document.go +++ b/apihandler/document.go @@ -277,3 +277,81 @@ func (h *V1Handler) V1DocumentDELETE(c echo.Context) error { return c.JSON(response.StatusCode, response) } + +// V1DocumentKeyPUT +func (h *V1Handler) V1DocumentKeyPUT(c echo.Context) (err error) { + var request apirequest.V1DocumentKeyPUT + var response apiresponse.V1DocumentKeyPUT + + bucket := c.Param("bucket") + document := c.Param("document") + newKey := c.Bind( + + request, err = apirequest.NewV1DocumentKeyPUT(bucket, document, newKey) + if err != nil { + response.StatusCode = http.StatusBadRequest + response.Message = err.Error() + + return c.JSON(response.StatusCode, response) + } + + if !request.Complete() { + response.StatusCode = http.StatusBadRequest + response.Message = "Incomplete V1DocumentKeyPUT request received" + + return c.JSON(response.StatusCode, response) + } + + var allowed bool + for bucketAllowed := range h.Config.Server.Documents.Buckets { + if bucket == bucketAllowed { + allowed = true + } + } + + if !allowed { + return c.JSON(apiresponse.NotFoundResponse()) + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + bucketExists, err := h.MediaClient.MinioClient.BucketExists(ctx, bucket) + if err != nil { + return c.JSON(http.StatusInternalServerError, "Could not validate bucket exists") + } + + if !bucketExists { + return c.JSON(apiresponse.NotFoundResponse()) + } + + if _, err := h.MediaClient.MinioClient.StatObject(ctx, bucket, document, minio.StatObjectOptions{}); err != nil { + if err.Error() == "The specified key does not exist." { + + return c.JSON(apiresponse.NotFoundResponse()) + } + + response.Message = fmt.Sprintf("Could not obtain information on %s/%s", bucket, document) + response.StatusCode = http.StatusInternalServerError + + return c.JSON(response.StatusCode, response) + } + + if _, err := h.MediaClient.MinioClient.CopyObject(ctx, + minio.CopyDestOptions{Bucket: bucket, Object: newKey}, + minio.CopySrcOptions{Bucket: bucket, Object: document}, + ); err != nil { + response.StatusCode = http.StatusInternalServerError + response.Message = "Impossible de copier un document pour le renommer" + return c.JSON(response.StatusCode, response) + } + + //TODO verify copy was successful + + //TODO delete old file + + //TODO cleanup + + //TODO return result + +} diff --git a/apirequest/document.go b/apirequest/document.go index b5c1191..3953a6d 100644 --- a/apirequest/document.go +++ b/apirequest/document.go @@ -163,3 +163,57 @@ func (request V1DocumentDELETE) Request(v *voki.Voki) (response apiresponse.V1Do return response, v.UnmarshalIfComplete(http.MethodDelete, fmt.Sprintf("/v1/bucket/%s/%s", request.Params.Bucket, request.Params.Document), nil, true, &response) } + +var _ request.Requester[apiresponse.V1DocumentKeyPUT] = V1DocumentKeyPUT{} + +type V1DocumentKeyPUT struct { + Data struct { + NewKey string `json:"newKey"` + } + Params struct { + Bucket string `json:"bucket"` + Document string `json:"document"` + } +} + +func NewV1DocumentKeyPUT(bucket, document, newKey string) (request V1DocumentKeyPUT, err error) { + if bucket == "" { + err = fmt.Errorf("NewV1DocumentKeyPUT requires non-nil bucket name") + return + } + + request.Params.Bucket = bucket + + if document == "" { + err = fmt.Errorf("NewV1DocumentKeyPUT requires non-nil src document name") + return + } + + request.Params.Document = document + + if newKey == "" { + err = fmt.Errorf("NewV1DocumentKeyPUT requires non-nil dst document name") + } + + request.Data.NewKey = newKey + + return +} + +func (request V1DocumentKeyPUT) Complete() bool { + return request.Params.Bucket != "" && request.Params.Document != "" && request.Data.NewKey != "" +} + +func (request V1DocumentKeyPUT) Request(v *voki.Voki) (response apiresponse.V1DocumentKeyPUT, err error) { + if !request.Complete() { + err = fmt.Errorf("Incomplete V1DocumentKeyPUT request") + return + } + + var buf bytes.Buffer + if err = json.NewEncoder(&buf).Encode(request.Data); err != nil { + return + } + + return response, v.UnmarshalIfComplete(http.MethodPut, fmt.Sprintf("/v1/bucket/%s/%s", request.Params.Bucket, request.Params.Document), &buf, true, &response) +} diff --git a/apiresponse/document.go b/apiresponse/document.go index b6518b9..488a65e 100644 --- a/apiresponse/document.go +++ b/apiresponse/document.go @@ -25,3 +25,11 @@ type V1DocumentPOST struct { type V1DocumentDELETE struct { Response } + +type V1DocumentKeyPUT struct { + Response + Data struct { + Bucket string + Key string + } +} diff --git a/cmd/server.go b/cmd/server.go index fc7f54b..1028f89 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -224,6 +224,13 @@ func RunServer() { log.Fatal(err) } + if err := pave.EchoRegister[ + apirequest.V1DocumentKeyPUT, + apiresponse.V1DocumentKeyPUT](groupV1, &p, "/v1", http.MethodPut, "/:bucket/:document", "Renommer un document", "V1DocumentKeyPUT", v1Handler.V1DocumentKeyPUT); err != nil { + + log.Fatal(err) + } + if err := pave.EchoRegister[ apirequest.V1SpecGET, apiresponse.V1SpecGET](groupV1, &p, "/v1", http.MethodGet, "/spec", apihandler.DescriptionV1SpecGET, "V1SpecGET", v1Handler.V1SpecGET); err != nil {