Add api methods for getting and updating user oauth2 applications. Signed-off-by: Dan Molik <dan@danmolik.com> Co-authored-by: techknowlogick <techknowlogick@gitea.io>tags/v1.21.12.1
| @@ -19,6 +19,8 @@ func TestOAuth2Application(t *testing.T) { | |||||
| defer prepareTestEnv(t)() | defer prepareTestEnv(t)() | ||||
| testAPICreateOAuth2Application(t) | testAPICreateOAuth2Application(t) | ||||
| testAPIListOAuth2Applications(t) | testAPIListOAuth2Applications(t) | ||||
| testAPIGetOAuth2Application(t) | |||||
| testAPIUpdateOAuth2Application(t) | |||||
| testAPIDeleteOAuth2Application(t) | testAPIDeleteOAuth2Application(t) | ||||
| } | } | ||||
| @@ -83,9 +85,6 @@ func testAPIDeleteOAuth2Application(t *testing.T) { | |||||
| oldApp := models.AssertExistsAndLoadBean(t, &models.OAuth2Application{ | oldApp := models.AssertExistsAndLoadBean(t, &models.OAuth2Application{ | ||||
| UID: user.ID, | UID: user.ID, | ||||
| Name: "test-app-1", | Name: "test-app-1", | ||||
| RedirectURIs: []string{ | |||||
| "http://www.google.com", | |||||
| }, | |||||
| }).(*models.OAuth2Application) | }).(*models.OAuth2Application) | ||||
| urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2/%d?token=%s", oldApp.ID, token) | urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2/%d?token=%s", oldApp.ID, token) | ||||
| @@ -94,3 +93,67 @@ func testAPIDeleteOAuth2Application(t *testing.T) { | |||||
| models.AssertNotExistsBean(t, &models.OAuth2Application{UID: oldApp.UID, Name: oldApp.Name}) | models.AssertNotExistsBean(t, &models.OAuth2Application{UID: oldApp.UID, Name: oldApp.Name}) | ||||
| } | } | ||||
| func testAPIGetOAuth2Application(t *testing.T) { | |||||
| user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) | |||||
| session := loginUser(t, user.Name) | |||||
| token := getTokenForLoggedInUser(t, session) | |||||
| existApp := models.AssertExistsAndLoadBean(t, &models.OAuth2Application{ | |||||
| UID: user.ID, | |||||
| Name: "test-app-1", | |||||
| RedirectURIs: []string{ | |||||
| "http://www.google.com", | |||||
| }, | |||||
| }).(*models.OAuth2Application) | |||||
| urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2/%d?token=%s", existApp.ID, token) | |||||
| req := NewRequest(t, "GET", urlStr) | |||||
| resp := session.MakeRequest(t, req, http.StatusOK) | |||||
| var app api.OAuth2Application | |||||
| DecodeJSON(t, resp, &app) | |||||
| expectedApp := app | |||||
| assert.EqualValues(t, existApp.Name, expectedApp.Name) | |||||
| assert.EqualValues(t, existApp.ClientID, expectedApp.ClientID) | |||||
| assert.Len(t, expectedApp.ClientID, 36) | |||||
| assert.Empty(t, expectedApp.ClientSecret) | |||||
| assert.EqualValues(t, len(expectedApp.RedirectURIs), 1) | |||||
| assert.EqualValues(t, existApp.RedirectURIs[0], expectedApp.RedirectURIs[0]) | |||||
| models.AssertExistsAndLoadBean(t, &models.OAuth2Application{ID: expectedApp.ID, Name: expectedApp.Name}) | |||||
| } | |||||
| func testAPIUpdateOAuth2Application(t *testing.T) { | |||||
| user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) | |||||
| existApp := models.AssertExistsAndLoadBean(t, &models.OAuth2Application{ | |||||
| UID: user.ID, | |||||
| Name: "test-app-1", | |||||
| RedirectURIs: []string{ | |||||
| "http://www.google.com", | |||||
| }, | |||||
| }).(*models.OAuth2Application) | |||||
| appBody := api.CreateOAuth2ApplicationOptions{ | |||||
| Name: "test-app-1", | |||||
| RedirectURIs: []string{ | |||||
| "http://www.google.com/", | |||||
| "http://www.github.com/", | |||||
| }, | |||||
| } | |||||
| urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2/%d", existApp.ID) | |||||
| req := NewRequestWithJSON(t, "PATCH", urlStr, &appBody) | |||||
| req = AddBasicAuthHeader(req, user.Name) | |||||
| resp := MakeRequest(t, req, http.StatusOK) | |||||
| var app api.OAuth2Application | |||||
| DecodeJSON(t, resp, &app) | |||||
| expectedApp := app | |||||
| assert.EqualValues(t, len(expectedApp.RedirectURIs), 2) | |||||
| assert.EqualValues(t, expectedApp.RedirectURIs[0], appBody.RedirectURIs[0]) | |||||
| assert.EqualValues(t, expectedApp.RedirectURIs[1], appBody.RedirectURIs[1]) | |||||
| models.AssertExistsAndLoadBean(t, &models.OAuth2Application{ID: expectedApp.ID, Name: expectedApp.Name}) | |||||
| } | |||||
| @@ -580,7 +580,10 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Combo("/oauth2"). | m.Combo("/oauth2"). | ||||
| Get(user.ListOauth2Applications). | Get(user.ListOauth2Applications). | ||||
| Post(bind(api.CreateOAuth2ApplicationOptions{}), user.CreateOauth2Application) | Post(bind(api.CreateOAuth2ApplicationOptions{}), user.CreateOauth2Application) | ||||
| m.Delete("/oauth2/:id", user.DeleteOauth2Application) | |||||
| m.Combo("/oauth2/:id"). | |||||
| Delete(user.DeleteOauth2Application). | |||||
| Patch(bind(api.CreateOAuth2ApplicationOptions{}), user.UpdateOauth2Application). | |||||
| Get(user.GetOauth2Application) | |||||
| }, reqToken()) | }, reqToken()) | ||||
| m.Group("/gpg_keys", func() { | m.Group("/gpg_keys", func() { | ||||
| @@ -231,3 +231,89 @@ func DeleteOauth2Application(ctx *context.APIContext) { | |||||
| ctx.Status(http.StatusNoContent) | ctx.Status(http.StatusNoContent) | ||||
| } | } | ||||
| // GetOauth2Application get OAuth2 Application | |||||
| func GetOauth2Application(ctx *context.APIContext) { | |||||
| // swagger:operation GET /user/applications/oauth2/{id} user userGetOAuth2Application | |||||
| // --- | |||||
| // summary: get an OAuth2 Application | |||||
| // produces: | |||||
| // - application/json | |||||
| // parameters: | |||||
| // - name: id | |||||
| // in: path | |||||
| // description: Application ID to be found | |||||
| // type: integer | |||||
| // format: int64 | |||||
| // required: true | |||||
| // responses: | |||||
| // "200": | |||||
| // "$ref": "#/responses/OAuth2Application" | |||||
| appID := ctx.ParamsInt64(":id") | |||||
| app, err := models.GetOAuth2ApplicationByID(appID) | |||||
| if err != nil { | |||||
| if models.IsErrOauthClientIDInvalid(err) || models.IsErrOAuthApplicationNotFound(err) { | |||||
| ctx.NotFound() | |||||
| } else { | |||||
| ctx.Error(http.StatusInternalServerError, "GetOauth2ApplicationByID", err) | |||||
| } | |||||
| return | |||||
| } | |||||
| app.ClientSecret = "" | |||||
| ctx.JSON(http.StatusOK, convert.ToOAuth2Application(app)) | |||||
| } | |||||
| // UpdateOauth2Application update OAuth2 Application | |||||
| func UpdateOauth2Application(ctx *context.APIContext, data api.CreateOAuth2ApplicationOptions) { | |||||
| // swagger:operation PATCH /user/applications/oauth2/{id} user userUpdateOAuth2Application | |||||
| // --- | |||||
| // summary: update an OAuth2 Application, this includes regenerating the client secret | |||||
| // produces: | |||||
| // - application/json | |||||
| // parameters: | |||||
| // - name: id | |||||
| // in: path | |||||
| // description: application to be updated | |||||
| // type: integer | |||||
| // format: int64 | |||||
| // required: true | |||||
| // - name: body | |||||
| // in: body | |||||
| // required: true | |||||
| // schema: | |||||
| // "$ref": "#/definitions/CreateOAuth2ApplicationOptions" | |||||
| // responses: | |||||
| // "200": | |||||
| // "$ref": "#/responses/OAuth2Application" | |||||
| appID := ctx.ParamsInt64(":id") | |||||
| err := models.UpdateOAuth2Application(models.UpdateOAuth2ApplicationOptions{ | |||||
| Name: data.Name, | |||||
| UserID: ctx.User.ID, | |||||
| ID: appID, | |||||
| RedirectURIs: data.RedirectURIs, | |||||
| }) | |||||
| if err != nil { | |||||
| ctx.Error(http.StatusBadRequest, "", "error updating oauth2 application") | |||||
| return | |||||
| } | |||||
| app, err := models.GetOAuth2ApplicationByID(appID) | |||||
| if err != nil { | |||||
| if models.IsErrOauthClientIDInvalid(err) || models.IsErrOAuthApplicationNotFound(err) { | |||||
| ctx.NotFound() | |||||
| } else { | |||||
| ctx.Error(http.StatusInternalServerError, "UpdateOauth2ApplicationByID", err) | |||||
| } | |||||
| return | |||||
| } | |||||
| secret, err := app.GenerateClientSecret() | |||||
| if err != nil { | |||||
| ctx.Error(http.StatusBadRequest, "", "error updating application secret") | |||||
| return | |||||
| } | |||||
| app.ClientSecret = secret | |||||
| ctx.JSON(http.StatusOK, convert.ToOAuth2Application(app)) | |||||
| } | |||||
| @@ -8360,6 +8360,31 @@ | |||||
| } | } | ||||
| }, | }, | ||||
| "/user/applications/oauth2/{id}": { | "/user/applications/oauth2/{id}": { | ||||
| "get": { | |||||
| "produces": [ | |||||
| "application/json" | |||||
| ], | |||||
| "tags": [ | |||||
| "user" | |||||
| ], | |||||
| "summary": "get an OAuth2 Application", | |||||
| "operationId": "userGetOAuth2Application", | |||||
| "parameters": [ | |||||
| { | |||||
| "type": "integer", | |||||
| "format": "int64", | |||||
| "description": "Application ID to be found", | |||||
| "name": "id", | |||||
| "in": "path", | |||||
| "required": true | |||||
| } | |||||
| ], | |||||
| "responses": { | |||||
| "200": { | |||||
| "$ref": "#/responses/OAuth2Application" | |||||
| } | |||||
| } | |||||
| }, | |||||
| "delete": { | "delete": { | ||||
| "produces": [ | "produces": [ | ||||
| "application/json" | "application/json" | ||||
| @@ -8384,6 +8409,39 @@ | |||||
| "$ref": "#/responses/empty" | "$ref": "#/responses/empty" | ||||
| } | } | ||||
| } | } | ||||
| }, | |||||
| "patch": { | |||||
| "produces": [ | |||||
| "application/json" | |||||
| ], | |||||
| "tags": [ | |||||
| "user" | |||||
| ], | |||||
| "summary": "update an OAuth2 Application, this includes regenerating the client secret", | |||||
| "operationId": "userUpdateOAuth2Application", | |||||
| "parameters": [ | |||||
| { | |||||
| "type": "integer", | |||||
| "format": "int64", | |||||
| "description": "application to be updated", | |||||
| "name": "id", | |||||
| "in": "path", | |||||
| "required": true | |||||
| }, | |||||
| { | |||||
| "name": "body", | |||||
| "in": "body", | |||||
| "required": true, | |||||
| "schema": { | |||||
| "$ref": "#/definitions/CreateOAuth2ApplicationOptions" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "responses": { | |||||
| "200": { | |||||
| "$ref": "#/responses/OAuth2Application" | |||||
| } | |||||
| } | |||||
| } | } | ||||
| }, | }, | ||||
| "/user/emails": { | "/user/emails": { | ||||