@@ -11,7 +11,7 @@ | |||
branch = "master" | |||
name = "code.gitea.io/sdk" | |||
packages = ["gitea"] | |||
revision = "b2308e3f700875a3642a78bd3f6e5db8ef6f974d" | |||
revision = "ec80752c9512cf07fc62ddc42565118183743942" | |||
[[projects]] | |||
name = "github.com/PuerkitoBio/goquery" |
@@ -0,0 +1,50 @@ | |||
// Copyright 2018 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package integrations | |||
import ( | |||
"net/http" | |||
"testing" | |||
"code.gitea.io/gitea/models" | |||
api "code.gitea.io/sdk/gitea" | |||
) | |||
// TestAPICreateAndDeleteToken tests that token that was just created can be deleted | |||
func TestAPICreateAndDeleteToken(t *testing.T) { | |||
prepareTestEnv(t) | |||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User) | |||
req := NewRequestWithJSON(t, "POST", "/api/v1/users/user1/tokens", map[string]string{ | |||
"name": "test-key-1", | |||
}) | |||
req = AddBasicAuthHeader(req, user.Name) | |||
resp := MakeRequest(t, req, http.StatusCreated) | |||
var newAccessToken api.AccessToken | |||
DecodeJSON(t, resp, &newAccessToken) | |||
models.AssertExistsAndLoadBean(t, &models.AccessToken{ | |||
ID: newAccessToken.ID, | |||
Name: newAccessToken.Name, | |||
Sha1: newAccessToken.Sha1, | |||
UID: user.ID, | |||
}) | |||
req = NewRequestf(t, "DELETE", "/api/v1/users/user1/tokens/%d", newAccessToken.ID) | |||
req = AddBasicAuthHeader(req, user.Name) | |||
MakeRequest(t, req, http.StatusNoContent) | |||
models.AssertNotExistsBean(t, &models.AccessToken{ID: newAccessToken.ID}) | |||
} | |||
// TestAPIDeleteMissingToken ensures that error is thrown when token not found | |||
func TestAPIDeleteMissingToken(t *testing.T) { | |||
prepareTestEnv(t) | |||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User) | |||
req := NewRequestf(t, "DELETE", "/api/v1/users/user1/tokens/%d", models.NonexistentID) | |||
req = AddBasicAuthHeader(req, user.Name) | |||
MakeRequest(t, req, http.StatusNotFound) | |||
} |
@@ -256,6 +256,11 @@ func NewRequestWithBody(t testing.TB, method, urlStr string, body io.Reader) *ht | |||
return request | |||
} | |||
func AddBasicAuthHeader(request *http.Request, username string) *http.Request { | |||
request.SetBasicAuth(username, userPassword) | |||
return request | |||
} | |||
const NoExpectedStatus = -1 | |||
func MakeRequest(t testing.TB, req *http.Request, expectedStatus int) *httptest.ResponseRecorder { |
@@ -5441,6 +5441,39 @@ | |||
} | |||
} | |||
}, | |||
"/users/{username}/tokens/{token}": { | |||
"delete": { | |||
"produces": [ | |||
"application/json" | |||
], | |||
"tags": [ | |||
"user" | |||
], | |||
"summary": "delete an access token", | |||
"operationId": "userDeleteAccessToken", | |||
"parameters": [ | |||
{ | |||
"type": "string", | |||
"description": "username of user", | |||
"name": "username", | |||
"in": "path", | |||
"required": true | |||
}, | |||
{ | |||
"type": "integer", | |||
"description": "token to be deleted", | |||
"name": "token", | |||
"in": "path", | |||
"required": true | |||
} | |||
], | |||
"responses": { | |||
"204": { | |||
"$ref": "#/responses/empty" | |||
} | |||
} | |||
} | |||
}, | |||
"/version": { | |||
"get": { | |||
"produces": [ | |||
@@ -7479,6 +7512,10 @@ | |||
"AccessToken": { | |||
"description": "AccessToken represents a API access token.", | |||
"headers": { | |||
"id": { | |||
"type": "integer", | |||
"format": "int64" | |||
}, | |||
"name": { | |||
"type": "string" | |||
}, |
@@ -302,6 +302,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Group("/tokens", func() { | |||
m.Combo("").Get(user.ListAccessTokens). | |||
Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken) | |||
m.Combo("/:id").Delete(user.DeleteAccessToken) | |||
}, reqBasicAuth()) | |||
}) | |||
}) |
@@ -1,4 +1,5 @@ | |||
// Copyright 2014 The Gogs Authors. All rights reserved. | |||
// Copyright 2018 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
@@ -36,6 +37,7 @@ func ListAccessTokens(ctx *context.APIContext) { | |||
apiTokens := make([]*api.AccessToken, len(tokens)) | |||
for i := range tokens { | |||
apiTokens[i] = &api.AccessToken{ | |||
ID: tokens[i].ID, | |||
Name: tokens[i].Name, | |||
Sha1: tokens[i].Sha1, | |||
} | |||
@@ -72,5 +74,40 @@ func CreateAccessToken(ctx *context.APIContext, form api.CreateAccessTokenOption | |||
ctx.JSON(201, &api.AccessToken{ | |||
Name: t.Name, | |||
Sha1: t.Sha1, | |||
ID: t.ID, | |||
}) | |||
} | |||
// DeleteAccessToken delete access tokens | |||
func DeleteAccessToken(ctx *context.APIContext) { | |||
// swagger:operation DELETE /users/{username}/tokens/{token} user userDeleteAccessToken | |||
// --- | |||
// summary: delete an access token | |||
// produces: | |||
// - application/json | |||
// parameters: | |||
// - name: username | |||
// in: path | |||
// description: username of user | |||
// type: string | |||
// required: true | |||
// - name: token | |||
// in: path | |||
// description: token to be deleted | |||
// type: integer | |||
// required: true | |||
// responses: | |||
// "204": | |||
// "$ref": "#/responses/empty" | |||
tokenID := ctx.ParamsInt64(":id") | |||
if err := models.DeleteAccessTokenByID(tokenID, ctx.User.ID); err != nil { | |||
if models.IsErrAccessTokenNotExist(err) { | |||
ctx.Status(404) | |||
} else { | |||
ctx.Error(500, "DeleteAccessTokenByID", err) | |||
} | |||
return | |||
} | |||
ctx.Status(204) | |||
} |
@@ -20,6 +20,7 @@ func BasicAuthEncode(user, pass string) string { | |||
// AccessToken represents a API access token. | |||
// swagger:response AccessToken | |||
type AccessToken struct { | |||
ID int64 `json:"id"` | |||
Name string `json:"name"` | |||
Sha1 string `json:"sha1"` | |||
} | |||
@@ -54,3 +55,9 @@ func (c *Client) CreateAccessToken(user, pass string, opt CreateAccessTokenOptio | |||
"Authorization": []string{"Basic " + BasicAuthEncode(user, pass)}}, | |||
bytes.NewReader(body), t) | |||
} | |||
// DeleteAccessToken delete token with key id | |||
func (c *Client) DeleteAccessToken(user string, keyID int64) error { | |||
_, err := c.getResponse("DELETE", fmt.Sprintf("/user/%s/tokens/%d", user, keyID), nil, nil) | |||
return err | |||
} |