diff --git a/api/application.go b/api/application.go index 585ec31c..a169cdb7 100644 --- a/api/application.go +++ b/api/application.go @@ -29,6 +29,23 @@ type ApplicationAPI struct { ImageDir string } +// Application Params Model +// +// Params allowed to create or update Applications +// +// swagger:model ApplicationParams +type ApplicationParams struct { + // The application name. This is how the application should be displayed to the user. + // + // required: true + // example: Backup Server + Name string `form:"name" query:"name" json:"name" binding:"required"` + // The description of the application. + // + // example: Backup server for the interwebs + Description string `form:"description" query:"description" json:"description"` +} + // CreateApplication creates an application and returns the access token. // swagger:operation POST /application application createApp // @@ -44,7 +61,7 @@ type ApplicationAPI struct { // description: the application to add // required: true // schema: -// $ref: "#/definitions/Application" +// $ref: "#/definitions/ApplicationParams" // responses: // 200: // description: Ok @@ -63,11 +80,16 @@ type ApplicationAPI struct { // schema: // $ref: "#/definitions/Error" func (a *ApplicationAPI) CreateApplication(ctx *gin.Context) { - app := model.Application{} - if err := ctx.Bind(&app); err == nil { - app.Token = auth.GenerateNotExistingToken(generateApplicationToken, a.applicationExists) - app.UserID = auth.GetUserID(ctx) - app.Internal = false + applicationParams := ApplicationParams{} + if err := ctx.Bind(&applicationParams); err == nil { + app := model.Application{ + Name: applicationParams.Name, + Description: applicationParams.Description, + Token: auth.GenerateNotExistingToken(generateApplicationToken, a.applicationExists), + UserID: auth.GetUserID(ctx), + Internal: false, + } + if success := successOrAbort(ctx, 500, a.DB.CreateApplication(&app)); !success { return } @@ -184,7 +206,7 @@ func (a *ApplicationAPI) DeleteApplication(ctx *gin.Context) { // description: the application to update // required: true // schema: -// $ref: "#/definitions/Application" +// $ref: "#/definitions/ApplicationParams" // - name: id // in: path // description: the application id @@ -219,10 +241,10 @@ func (a *ApplicationAPI) UpdateApplication(ctx *gin.Context) { return } if app != nil && app.UserID == auth.GetUserID(ctx) { - newValues := &model.Application{} - if err := ctx.Bind(newValues); err == nil { - app.Description = newValues.Description - app.Name = newValues.Name + applicationParams := ApplicationParams{} + if err := ctx.Bind(&applicationParams); err == nil { + app.Description = applicationParams.Description + app.Name = applicationParams.Name if success := successOrAbort(ctx, 500, a.DB.UpdateApplication(app)); !success { return diff --git a/api/application_test.go b/api/application_test.go index 61236b13..c7fe43d5 100644 --- a/api/application_test.go +++ b/api/application_test.go @@ -2,6 +2,7 @@ package api import ( "bytes" + "encoding/json" "errors" "io" "io/ioutil" @@ -107,6 +108,35 @@ func (s *ApplicationSuite) Test_CreateApplication_expectBadRequestOnEmptyName() } } +func (s *ApplicationSuite) Test_CreateApplication_ignoresReadOnlyPropertiesInParams() { + s.db.User(5) + + test.WithUser(s.ctx, 5) + s.withJSON(&model.Application{ + Name: "name", + Description: "description", + ID: 333, + Internal: true, + Token: "token", + Image: "adfdf", + }) + + s.a.CreateApplication(s.ctx) + + expectedJSONValue, _ := json.Marshal(&model.Application{ + ID: 1, + Token: firstApplicationToken, + UserID: 5, + Name: "name", + Description: "description", + Internal: false, + Image: "static/defaultapp.png", + }) + + assert.Equal(s.T(), 200, s.recorder.Code) + assert.Equal(s.T(), string(expectedJSONValue), s.recorder.Body.String()) +} + func (s *ApplicationSuite) Test_DeleteApplication_expectNotFoundOnCurrentUserIsNotOwner() { s.db.User(2) s.db.User(5).App(5) @@ -505,6 +535,12 @@ func (s *ApplicationSuite) withFormData(formData string) { s.ctx.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded") } +func (s *ApplicationSuite) withJSON(value interface{}) { + jsonVal, _ := json.Marshal(value) + s.ctx.Request = httptest.NewRequest("POST", "/application", bytes.NewBuffer(jsonVal)) + s.ctx.Request.Header.Set("Content-Type", "application/json") +} + // A modified version of https://stackoverflow.com/a/20397167/4244993 from Attila O. func upload(values map[string]*os.File) (contentType string, buffer bytes.Buffer, err error) { w := multipart.NewWriter(&buffer) diff --git a/docs/spec.json b/docs/spec.json index c499ddde..d51a3a75 100644 --- a/docs/spec.json +++ b/docs/spec.json @@ -99,7 +99,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/Application" + "$ref": "#/definitions/ApplicationParams" } } ], @@ -162,7 +162,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/Application" + "$ref": "#/definitions/ApplicationParams" } }, { @@ -1948,6 +1948,29 @@ }, "x-go-package": "github.com/gotify/server/v2/model" }, + "ApplicationParams": { + "description": "Params allowed to create or update Applications", + "type": "object", + "title": "Application Params Model", + "required": [ + "name" + ], + "properties": { + "description": { + "description": "The description of the application.", + "type": "string", + "x-go-name": "Description", + "example": "Backup server for the interwebs" + }, + "name": { + "description": "The application name. This is how the application should be displayed to the user.", + "type": "string", + "x-go-name": "Name", + "example": "Backup Server" + } + }, + "x-go-package": "github.com/gotify/server/v2/api" + }, "Client": { "description": "The Client holds information about a device which can receive notifications (and other stuff).", "type": "object",