From d428f9377b4423231a25313a0e40fa1bccb09d3a Mon Sep 17 00:00:00 2001 From: Jeff Ortel Date: Wed, 25 Sep 2024 09:11:39 -0700 Subject: [PATCH] Post file directly. Signed-off-by: Jeff Ortel --- api/analysis.go | 38 ++++++++------ api/file.go | 111 +++++++++++++++++++++++------------------ binding/application.go | 12 +---- hack/add/analysis.sh | 29 +++-------- 4 files changed, 94 insertions(+), 96 deletions(-) diff --git a/api/analysis.go b/api/analysis.go index e48f9143..62dd87af 100644 --- a/api/analysis.go +++ b/api/analysis.go @@ -324,12 +324,23 @@ func (h AnalysisHandler) AppList(ctx *gin.Context) { // @summary Create an analysis. // @description Create an analysis. // @description Form fields: -// @description - file: file that contains the api.Analysis resource. -// @description - issues: file that multiple api.Issue resources. -// @description - dependencies: file that multiple api.TechDependency resources. +// @description - file: A manifest file that contains 3 sections +// @description containing documents delimited by markers. +// @description The manifest must contain ALL markers even when sections are empty. +// @description Note: `^]` = `\x1D` = GS (group separator). +// @description Section markers: +// @description ^]BEGIN-MAIN^] +// @description ^]END-MAIN^] +// @description ^]BEGIN-ISSUES^] +// @description ^]END-ISSUES^] +// @description ^]BEGIN-DEPS^] +// @description ^]END-DEPS^] +// @description The encoding must be: +// @description - application/json +// @description - application/x-yaml // @tags analyses // @produce json -// @success 201 {object} api.Ref +// @success 201 {object} api.Analysis // @router /application/{id}/analyses [post] // @param id path int true "Application ID" func (h AnalysisHandler) AppCreate(ctx *gin.Context) { @@ -349,19 +360,19 @@ func (h AnalysisHandler) AppCreate(ctx *gin.Context) { db := h.DB(ctx) // // Manifest - ref := &Ref{} - err := h.Bind(ctx, ref) + fh := FileHandler{} + name := fmt.Sprintf("app.%d.manifest", id) + file, err := fh.create(ctx, name) if err != nil { _ = ctx.Error(err) return } - file := &model.File{} - err = db.First(file, ref.ID).Error - if err != nil { - err = &BadRequestError{err.Error()} - _ = ctx.Error(err) - return - } + defer func() { + err = fh.delete(ctx, file) + if err != nil { + _ = ctx.Error(err) + } + }() reader := &ManifestReader{} f, err := reader.open(file.Path, BeginMainMarker, EndMainMarker) if err != nil { @@ -2870,7 +2881,6 @@ func (r *yamlEncoder) embed(object any) encoder { // The manifest must contain ALL markers even when sections are empty. // Note: `^]` = `\x1D` = GS (group separator). // Section markers: -// // ^]BEGIN-MAIN^] // ^]END-MAIN^] // ^]BEGIN-ISSUES^] diff --git a/api/file.go b/api/file.go index cb47a14d..010508c9 100644 --- a/api/file.go +++ b/api/file.go @@ -70,53 +70,11 @@ func (h FileHandler) List(ctx *gin.Context) { // @router /files [post] // @param name path string true "File name" func (h FileHandler) Create(ctx *gin.Context) { - var err error - input, err := ctx.FormFile(FileField) - if err != nil { - err = &BadRequestError{err.Error()} - _ = ctx.Error(err) - return - } - m := &model.File{} - m.Name = ctx.Param(ID) - m.Encoding = input.Header.Get(ContentType) - m.CreateUser = h.BaseHandler.CurrentUser(ctx) - result := h.DB(ctx).Create(&m) - if result.Error != nil { - _ = ctx.Error(result.Error) - return - } - defer func() { - if err != nil { - h.Status(ctx, http.StatusInternalServerError) - _ = h.DB(ctx).Delete(&m) - return - } - }() - reader, err := input.Open() + m, err := h.create(ctx, ctx.Param(ID)) if err != nil { - err = &BadRequestError{err.Error()} _ = ctx.Error(err) return } - defer func() { - _ = reader.Close() - }() - writer, err := os.Create(m.Path) - if err != nil { - return - } - defer func() { - _ = writer.Close() - }() - _, err = io.Copy(writer, reader) - if err != nil { - return - } - err = os.Chmod(m.Path, 0666) - if err != nil { - return - } r := File{} r.With(m) h.Respond(ctx, http.StatusCreated, r) @@ -225,20 +183,75 @@ func (h FileHandler) Delete(ctx *gin.Context) { _ = ctx.Error(err) return } - err = os.Remove(m.Path) + err = h.delete(ctx, m) if err != nil { - if !os.IsNotExist(err) { - _ = ctx.Error(err) + _ = ctx.Error(err) + return + } + + h.Status(ctx, http.StatusNoContent) +} + +// create a file. +func (h FileHandler) create(ctx *gin.Context, name string) (m *model.File, err error) { + input, err := ctx.FormFile(FileField) + if err != nil { + err = &BadRequestError{err.Error()} + return + } + m = &model.File{} + m.Name = name + m.Encoding = input.Header.Get(ContentType) + m.CreateUser = h.BaseHandler.CurrentUser(ctx) + db := h.DB(ctx) + err = db.Create(&m).Error + if err != nil { + return + } + defer func() { + if err != nil { + h.Status(ctx, http.StatusInternalServerError) + _ = h.DB(ctx).Delete(&m) return } + }() + reader, err := input.Open() + if err != nil { + err = &BadRequestError{err.Error()} + return } - err = h.DB(ctx).Delete(m).Error + defer func() { + _ = reader.Close() + }() + writer, err := os.Create(m.Path) + if err != nil { + return + } + defer func() { + _ = writer.Close() + }() + _, err = io.Copy(writer, reader) if err != nil { - _ = ctx.Error(err) return } + err = os.Chmod(m.Path, 0666) + if err != nil { + return + } + return +} - h.Status(ctx, http.StatusNoContent) +// delete the specified file. +func (h FileHandler) delete(ctx *gin.Context, m *model.File) (err error) { + err = os.Remove(m.Path) + if err != nil { + if !os.IsNotExist(err) { + return + } + } + db := h.DB(ctx) + err = db.Delete(m).Error + return } // File REST resource. diff --git a/binding/application.go b/binding/application.go index 770578d8..0460258c 100644 --- a/binding/application.go +++ b/binding/application.go @@ -317,14 +317,12 @@ type Analysis struct { // The manifest must contain ALL markers even when sections are empty. // Note: `^]` = `\x1D` = GS (group separator). // Section markers: -// // ^]BEGIN-MAIN^] // ^]END-MAIN^] // ^]BEGIN-ISSUES^] // ^]END-ISSUES^] // ^]BEGIN-DEPS^] // ^]END-DEPS^] -// // The encoding must be: // - application/json // - application/x-yaml @@ -339,17 +337,11 @@ func (h *Analysis) Create(manifest, encoding string) (err error) { "Encoding: %s not supported", encoding) } - file := File{client: h.client} - f, err := file.PostEncoded(manifest, encoding) - if err != nil { - return - } - ref := &api.Ref{ID: f.ID} + r := &api.Analysis{} path := Path(api.AppAnalysesRoot).Inject(Params{api.ID: h.appId}) - err = h.client.Post(path, ref) + err = h.client.FilePostEncoded(path, manifest, r, encoding) if err != nil { return } - _ = file.Delete(f.ID) return } diff --git a/hack/add/analysis.sh b/hack/add/analysis.sh index 4243db0a..568ff334 100755 --- a/hack/add/analysis.sh +++ b/hack/add/analysis.sh @@ -204,38 +204,21 @@ echo "Manifest (file) GENERATED: ${file}" # # Post manifest. -code=$(curl -kSs -o ${tmp} -w "%{http_code}" -F "file=@${file};type=application/x-yaml" http://${host}/files/manifest) +code=$(curl -kSs -o ${tmp} -w "%{http_code}" \ + -F "file=@${file};type=application/x-yaml" \ + -H 'Accept:application/x-yaml' \ + http://${host}/applications/${appId}/analyses) if [ ! $? -eq 0 ] then exit $? fi case ${code} in 201) - manifestId=$(cat ${tmp}|jq .id) - echo "manifest (file): ${name} posted. id=${manifestId}" - ;; - *) - echo "manifest (file) post - FAILED: ${code}." + echo "Analysis: created." cat ${tmp} - exit 1 -esac -# -# Post analysis. -d=" -id: ${manifestId} -" -code=$(curl -kSs -o ${tmp} -w "%{http_code}" ${host}/applications/${appId}/analyses -H "Content-Type:application/x-yaml" -d "${d}") -if [ ! $? -eq 0 ] -then - exit $? -fi -case ${code} in - 201) - id=$(cat ${tmp}|jq .id) - echo "analysis: ${name} posted. id=${id}" ;; *) - echo "analysis post - FAILED: ${code}." + echo "Analysis create - FAILED: ${code}." cat ${tmp} exit 1 esac