From b6dfafd1c14a19daebd11f689e4fc68d88f68b05 Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Thu, 23 Mar 2023 18:44:14 +0100 Subject: [PATCH] fix endpoints --- README.md | 26 +++++++++++++------------- api/db.go | 2 +- api/handlers.go | 14 +++++++------- api/server.go | 24 ++++++++++++------------ cmd/root.go | 2 +- upctl/lib/client.go | 24 ++++++++++++++++-------- upctl/lib/client_test.go | 16 ++++++++-------- upctl/upctl.hcl | 2 +- 8 files changed, 59 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 43895ef..120e5bc 100644 --- a/README.md +++ b/README.md @@ -151,19 +151,19 @@ Every endpoint returns a JSON object. Each returned object contains the data req #### Endpoints -| HTTP Method | Endpoint | Parameters | Input | Returns | Description | -|-------------|-------------------|---------------------|----------------------------|---------------------------------------|-----------------------------------------------| -| GET | /v1/uploads | apicontext,q,expire | | List of upload objects | list upload objects | -| POST | /v1/uploads | | multipart-formdata file[s] | List of 1 upload object if successful | upload a file and create a new upload object | -| GET | /v1/uploads/{id} | | | List of 1 upload object if successful | list one specific upload object matching {id} | -| DELETE | /v1/uploads/{id} | | | Noting | delete an upload object identified by {id} | -| PUT | /v1/uploads/{id} | | JSON upload object | List of 1 upload object if successful | modify an upload object identified by {id} | -| GET | /v1/download/{id} | | | File download | Download the file associated with the object | -| GET | /v1/forms | apicontext,q,expire | | List of form objects | list form objects | -| POST | /v1/forms | | JSON form object | List of 1 form object if successful | create a new form object | -| GET | /v1/forms/{id} | | | List of 1 form object if successful | list one specific form object matching {id} | -| DELETE | /v1/forms/{id} | | | Noting | delete an form object identified by {id} | -| PUT | /v1/forms/{id} | | JSON form object | List of 1 form object if successful | modify an form object identified by {id} | +| HTTP Method | Endpoint | Parameters | Input | Returns | Description | +|-------------|-----------------------|---------------------|----------------------------|---------------------------------------|-----------------------------------------------| +| GET | /v1/uploads | apicontext,q,expire | | List of upload objects | list upload objects | +| POST | /v1/uploads | | multipart-formdata file[s] | List of 1 upload object if successful | upload a file and create a new upload object | +| GET | /v1/uploads/{id} | | | List of 1 upload object if successful | list one specific upload object matching {id} | +| DELETE | /v1/uploads/{id} | | | Noting | delete an upload object identified by {id} | +| PUT | /v1/uploads/{id} | | JSON upload object | List of 1 upload object if successful | modify an upload object identified by {id} | +| GET | /v1/uploads/{id}/file | | | File download | Download the file associated with the object | +| GET | /v1/forms | apicontext,q,expire | | List of form objects | list form objects | +| POST | /v1/forms | | JSON form object | List of 1 form object if successful | create a new form object | +| GET | /v1/forms/{id} | | | List of 1 form object if successful | list one specific form object matching {id} | +| DELETE | /v1/forms/{id} | | | Noting | delete an form object identified by {id} | +| PUT | /v1/forms/{id} | | JSON form object | List of 1 form object if successful | modify an form object identified by {id} | #### Consumer URLs diff --git a/api/db.go b/api/db.go index 24613a1..11ad1f9 100644 --- a/api/db.go +++ b/api/db.go @@ -106,7 +106,7 @@ func (db *Db) Delete(apicontext string, id string) error { return err } -func (db *Db) List(apicontext string, filter string) (*common.Uploads, error) { +func (db *Db) UploadsList(apicontext string, filter string) (*common.Uploads, error) { uploads := &common.Uploads{} err := db.bolt.View(func(tx *bolt.Tx) error { diff --git a/api/handlers.go b/api/handlers.go index f9ad2c0..43c54f2 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -34,7 +34,7 @@ type SetContext struct { Apicontext string `json:"apicontext" form:"apicontext"` } -func FilePut(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { +func UploadPost(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { // supports upload of multiple files with: // // curl -X POST localhost:8080/putfile \ @@ -106,6 +106,7 @@ func FilePut(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { "Could not process uploaded file[s]: "+err.Error()) } entry.File = Newfilename + entry.Url = returnUrl Log("Now serving %s from %s/%s", returnUrl, cfg.StorageDir, id) Log("Expire set to: %s", entry.Expire) @@ -117,12 +118,11 @@ func FilePut(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { // everything went well so far res := &common.Uploads{Entries: []*common.Upload{entry}} res.Success = true - res.Message = "Download url: " + returnUrl res.Code = fiber.StatusOK return c.Status(fiber.StatusOK).JSON(res) } -func FileGet(c *fiber.Ctx, cfg *cfg.Config, db *Db, shallExpire ...bool) error { +func UploadFetch(c *fiber.Ctx, cfg *cfg.Config, db *Db, shallExpire ...bool) error { // deliver a file and delete it if expire is set to asap // we ignore c.Params("file"), cause it may be malign. Also we've @@ -173,7 +173,7 @@ func FileGet(c *fiber.Ctx, cfg *cfg.Config, db *Db, shallExpire ...bool) error { } // delete file, id dir and db entry -func DeleteUpload(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { +func UploadDelete(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { id, err := common.Untaint(c.Params("id"), cfg.RegKey) if err != nil { @@ -206,7 +206,7 @@ func DeleteUpload(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { } // returns the whole list + error code, no post processing by server -func List(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { +func UploadsList(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { // fetch filter from body(json expected) setcontext := new(SetContext) if err := c.BodyParser(setcontext); err != nil { @@ -228,7 +228,7 @@ func List(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { } // get list - uploads, err := db.List(apicontext, filter) + uploads, err := db.UploadsList(apicontext, filter) if err != nil { return JsonStatus(c, fiber.StatusForbidden, "Unable to list uploads: "+err.Error()) @@ -242,7 +242,7 @@ func List(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { } // returns just one upload obj + error code, no post processing by server -func Describe(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { +func UploadDescribe(c *fiber.Ctx, cfg *cfg.Config, db *Db) error { id, err := common.Untaint(c.Params("id"), cfg.RegKey) if err != nil { return JsonStatus(c, fiber.StatusForbidden, diff --git a/api/server.go b/api/server.go index 9a4aee8..aa5e4ef 100644 --- a/api/server.go +++ b/api/server.go @@ -56,29 +56,29 @@ func Runserver(conf *cfg.Config, args []string) error { api := router.Group(conf.ApiPrefix + ApiVersion) { // upload - api.Post("/uploads/", auth, func(c *fiber.Ctx) error { - return FilePut(c, conf, db) + api.Post("/uploads", auth, func(c *fiber.Ctx) error { + return UploadPost(c, conf, db) }) // remove - api.Delete("/uploads/:id/", auth, func(c *fiber.Ctx) error { - err := DeleteUpload(c, conf, db) + api.Delete("/uploads/:id", auth, func(c *fiber.Ctx) error { + err := UploadDelete(c, conf, db) return SendResponse(c, "", err) }) // listing api.Get("/uploads", auth, func(c *fiber.Ctx) error { - return List(c, conf, db) + return UploadsList(c, conf, db) }) // info/describe - api.Get("/upload/:id/", auth, func(c *fiber.Ctx) error { - return Describe(c, conf, db) + api.Get("/uploads/:id", auth, func(c *fiber.Ctx) error { + return UploadDescribe(c, conf, db) }) // download w/o expire - api.Get("/download/:id/", auth, func(c *fiber.Ctx) error { - return FileGet(c, conf, db) + api.Get("/uploads/:id/file", auth, func(c *fiber.Ctx) error { + return UploadFetch(c, conf, db) }) } @@ -89,11 +89,11 @@ func Runserver(conf *cfg.Config, args []string) error { }) router.Get("/download/:id/:file", func(c *fiber.Ctx) error { - return FileGet(c, conf, db, shallExpire) + return UploadFetch(c, conf, db, shallExpire) }) - router.Get("/download/:id/", func(c *fiber.Ctx) error { - return FileGet(c, conf, db, shallExpire) + router.Get("/download/:id", func(c *fiber.Ctx) error { + return UploadFetch(c, conf, db, shallExpire) }) } diff --git a/cmd/root.go b/cmd/root.go index 2c99b0b..2fe9daf 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -59,7 +59,7 @@ func Execute() error { f.BoolVarP(&conf.Debug, "debug", "d", false, "Enable debugging") f.StringVarP(&conf.Listen, "listen", "l", ":8080", "listen to custom ip:port (use [ip]:port for ipv6)") f.StringVarP(&conf.StorageDir, "storagedir", "s", "/tmp", "storage directory for uploaded files") - f.StringVarP(&conf.ApiPrefix, "apiprefix", "a", "/api", "API endpoint path") + f.StringVarP(&conf.ApiPrefix, "apiprefix", "a", "", "API endpoint path") f.StringVarP(&conf.Url, "url", "u", "", "HTTP endpoint w/o path") f.StringVarP(&conf.DbFile, "dbfile", "D", "/tmp/uploads.db", "Bold database file to use") f.StringVarP(&conf.Super, "super", "", "", "The API Context which has permissions on all contexts") diff --git a/upctl/lib/client.go b/upctl/lib/client.go index 942ef2b..dc7b330 100644 --- a/upctl/lib/client.go +++ b/upctl/lib/client.go @@ -135,11 +135,6 @@ func HandleResponse(c *cfg.Config, resp *req.Response) error { // we expect a json response, extract the error, if any r := Response{} - if err := json.Unmarshal([]byte(resp.String()), &r); err != nil { - // text output! - r.Message = resp.String() - } - if c.Debug { trace := resp.Request.TraceInfo() fmt.Println(trace.Blame()) @@ -147,6 +142,15 @@ func HandleResponse(c *cfg.Config, resp *req.Response) error { fmt.Println(trace) } + if !resp.IsSuccessState() { + return fmt.Errorf("bad response: %s", resp.Status) + } + + if err := json.Unmarshal([]byte(resp.String()), &r); err != nil { + // text output! + r.Message = resp.String() + } + if !r.Success { if len(r.Message) == 0 { if resp.Err != nil { @@ -200,7 +204,7 @@ func UploadFiles(w io.Writer, c *cfg.Config, args []string) error { } func List(w io.Writer, c *cfg.Config, args []string) error { - rq := Setup(c, "/list/") + rq := Setup(c, "/uploads") params := &ListParams{Apicontext: c.Apicontext} resp, err := rq.R. @@ -245,7 +249,7 @@ func Describe(w io.Writer, c *cfg.Config, args []string) error { id := args[0] // we describe only 1 object - rq := Setup(c, "/upload/"+id+"/") + rq := Setup(c, "/uploads/"+id+"/") resp, err := rq.R.Get(rq.Url) if err != nil { @@ -266,7 +270,7 @@ func Download(w io.Writer, c *cfg.Config, args []string) error { id := args[0] - rq := Setup(c, "/uploads/"+id+"/") + rq := Setup(c, "/uploads/"+id+"/file") if !c.Silent { // progres bar @@ -289,6 +293,10 @@ func Download(w io.Writer, c *cfg.Config, args []string) error { return err } + if !resp.IsSuccessState() { + return fmt.Errorf("bad response: %s", resp.Status) + } + _, params, err := mime.ParseMediaType(resp.Header.Get("Content-Disposition")) if err != nil { os.Remove(id) diff --git a/upctl/lib/client_test.go b/upctl/lib/client_test.go index 7f2e1be..20a30cb 100644 --- a/upctl/lib/client_test.go +++ b/upctl/lib/client_test.go @@ -33,7 +33,7 @@ import ( "testing" ) -const endpoint string = "http://localhost:8080/api/v1" +const endpoint string = "http://localhost:8080/v1" type Unit struct { name string @@ -200,7 +200,7 @@ func TestList(t *testing.T) { name: "list", apikey: "token", wantfail: false, - route: "/list/", + route: "/uploads", sendcode: 200, sendjson: listing, files: []string{}, @@ -211,7 +211,7 @@ func TestList(t *testing.T) { name: "list-catch-empty-json", apikey: "token", wantfail: true, - route: "/list/", + route: "/uploads", sendcode: 404, sendjson: "", files: []string{}, @@ -221,7 +221,7 @@ func TestList(t *testing.T) { name: "list-catch-no-access", apikey: "token", wantfail: true, - route: "/list/", + route: "/uploads", sendcode: 503, sendjson: listingnoaccess, files: []string{}, @@ -261,7 +261,7 @@ func TestDescribe(t *testing.T) { name: "describe", apikey: "token", wantfail: false, - route: "/upload/", + route: "/uploads/", sendcode: 200, sendjson: listing, files: []string{"cc2c965a"}, @@ -272,7 +272,7 @@ func TestDescribe(t *testing.T) { name: "describe-catch-empty-json", apikey: "token", wantfail: true, - route: "/upload/", + route: "/uploads/", sendcode: 200, sendjson: "", files: []string{"cc2c965a"}, @@ -282,7 +282,7 @@ func TestDescribe(t *testing.T) { name: "describe-catch-no-access", apikey: "token", wantfail: true, - route: "/upload/", + route: "/uploads/", sendcode: 503, sendjson: listingnoaccess, files: []string{"cc2c965a"}, @@ -395,7 +395,7 @@ func TestDownload(t *testing.T) { for _, unit := range tests { var w bytes.Buffer - unit.route += unit.files[0] + "/" + unit.route += unit.files[0] + "/file" Intercept(unit) Check(t, unit, &w, Download(&w, conf, unit.files)) diff --git a/upctl/upctl.hcl b/upctl/upctl.hcl index 5b521d5..fc989e6 100644 --- a/upctl/upctl.hcl +++ b/upctl/upctl.hcl @@ -1,2 +1,2 @@ -endpoint = "http://localhost:8080/api/v1" +endpoint = "http://localhost:8080/v1" apikey = "970b391f22f515d96b3e9b86a2c62c627968828e47b356994d2e583188b4190a"