[PLT-7793] Added /users/tokens endpoint (#8038)
* Added /users/tokens/all endpoint - UserAccessStore now has getAll method - Added tests - Added route - Added handler * Remove space fix check-style * Remove blank space check-style * Fixes for make check-style * Remove extra code that is un-needed in user_test.go * Rename endpoint + grammar - Renamed /users/tokens/all to /users/tokens - Renamed getUserAccessTokens to getUserAccessTokensForUser - Renamed getAllUserAccessTokens to getUserAccessTokens - Minor Grammar changes * Add localization for sql_user_access_token.get_all * Fix minor plural spelling
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
66bdf830b5
Коммит
fd3fa8f8dc
18
api4/user.go
18
api4/user.go
@@ -58,7 +58,8 @@ func (api *API) InitUser() {
|
|||||||
api.BaseRoutes.User.Handle("/audits", api.ApiSessionRequired(getUserAudits)).Methods("GET")
|
api.BaseRoutes.User.Handle("/audits", api.ApiSessionRequired(getUserAudits)).Methods("GET")
|
||||||
|
|
||||||
api.BaseRoutes.User.Handle("/tokens", api.ApiSessionRequired(createUserAccessToken)).Methods("POST")
|
api.BaseRoutes.User.Handle("/tokens", api.ApiSessionRequired(createUserAccessToken)).Methods("POST")
|
||||||
api.BaseRoutes.User.Handle("/tokens", api.ApiSessionRequired(getUserAccessTokens)).Methods("GET")
|
api.BaseRoutes.User.Handle("/tokens", api.ApiSessionRequired(getUserAccessTokensForUser)).Methods("GET")
|
||||||
|
api.BaseRoutes.Users.Handle("/tokens", api.ApiSessionRequired(getUserAccessTokens)).Methods("GET")
|
||||||
api.BaseRoutes.Users.Handle("/tokens/{token_id:[A-Za-z0-9]+}", api.ApiSessionRequired(getUserAccessToken)).Methods("GET")
|
api.BaseRoutes.Users.Handle("/tokens/{token_id:[A-Za-z0-9]+}", api.ApiSessionRequired(getUserAccessToken)).Methods("GET")
|
||||||
api.BaseRoutes.Users.Handle("/tokens/revoke", api.ApiSessionRequired(revokeUserAccessToken)).Methods("POST")
|
api.BaseRoutes.Users.Handle("/tokens/revoke", api.ApiSessionRequired(revokeUserAccessToken)).Methods("POST")
|
||||||
api.BaseRoutes.Users.Handle("/tokens/disable", api.ApiSessionRequired(disableUserAccessToken)).Methods("POST")
|
api.BaseRoutes.Users.Handle("/tokens/disable", api.ApiSessionRequired(disableUserAccessToken)).Methods("POST")
|
||||||
@@ -1241,6 +1242,21 @@ func createUserAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getUserAccessTokens(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getUserAccessTokens(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
accessTokens, err := c.App.GetUserAccessTokens(c.Params.Page, c.Params.PerPage)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(model.UserAccessTokenListToJson(accessTokens)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserAccessTokensForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
c.RequireUserId()
|
c.RequireUserId()
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -2450,6 +2450,23 @@ func TestGetUserAccessToken(t *testing.T) {
|
|||||||
if len(rtokens) != 2 {
|
if len(rtokens) != 2 {
|
||||||
t.Fatal("should have 2 tokens")
|
t.Fatal("should have 2 tokens")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, resp = Client.GetUserAccessTokens(0,100)
|
||||||
|
CheckForbiddenStatus(t, resp)
|
||||||
|
|
||||||
|
rtokens, resp = AdminClient.GetUserAccessTokens(1,1)
|
||||||
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
|
if len(rtokens) != 1 {
|
||||||
|
t.Fatal("should have 1 token")
|
||||||
|
}
|
||||||
|
|
||||||
|
rtokens, resp = AdminClient.GetUserAccessTokens(0,2)
|
||||||
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
|
if len(rtokens) != 2 {
|
||||||
|
t.Fatal("should have 2 tokens")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRevokeUserAccessToken(t *testing.T) {
|
func TestRevokeUserAccessToken(t *testing.T) {
|
||||||
|
|||||||
@@ -356,6 +356,19 @@ func (a *App) EnableUserAccessToken(token *model.UserAccessToken) *model.AppErro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) GetUserAccessTokens(page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
|
||||||
|
if result := <-a.Srv.Store.UserAccessToken().GetAll(page*perPage, perPage); result.Err != nil {
|
||||||
|
return nil, result.Err
|
||||||
|
} else {
|
||||||
|
tokens := result.Data.([]*model.UserAccessToken)
|
||||||
|
for _, token := range tokens {
|
||||||
|
token.Token = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
|
func (a *App) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
|
||||||
if result := <-a.Srv.Store.UserAccessToken().GetByUser(userId, page*perPage, perPage); result.Err != nil {
|
if result := <-a.Srv.Store.UserAccessToken().GetByUser(userId, page*perPage, perPage); result.Err != nil {
|
||||||
return nil, result.Err
|
return nil, result.Err
|
||||||
|
|||||||
@@ -6782,6 +6782,10 @@
|
|||||||
"id": "store.sql_user_access_token.get_by_token.app_error",
|
"id": "store.sql_user_access_token.get_by_token.app_error",
|
||||||
"translation": "We couldn't get the personal access token by token"
|
"translation": "We couldn't get the personal access token by token"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_user_access_token.get_all.app_error",
|
||||||
|
"translation": "We couldn't get all personal access tokens"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "store.sql_user_access_token.get_by_user.app_error",
|
"id": "store.sql_user_access_token.get_by_user.app_error",
|
||||||
"translation": "We couldn't get the personal access tokens by user"
|
"translation": "We couldn't get the personal access tokens by user"
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ func (c *Client4) GetUserRoute(userId string) string {
|
|||||||
return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId)
|
return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client4) GetUserAccessTokensRoute() string {
|
||||||
|
return fmt.Sprintf(c.GetUsersRoute() + "/tokens")
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client4) GetUserAccessTokenRoute(tokenId string) string {
|
func (c *Client4) GetUserAccessTokenRoute(tokenId string) string {
|
||||||
return fmt.Sprintf(c.GetUsersRoute()+"/tokens/%v", tokenId)
|
return fmt.Sprintf(c.GetUsersRoute()+"/tokens/%v", tokenId)
|
||||||
}
|
}
|
||||||
@@ -1035,10 +1039,23 @@ func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserAccessToken will get a user access token's id, description and the user_id
|
// GetUserAccessTokens will get a page of access tokens' id, description, is_active
|
||||||
// of the user it is for. The actual token will not be returned. Must have the
|
// and the user_id in the system. The actual token will not be returned. Must have
|
||||||
// 'read_user_access_token' permission and if getting for another user, must have the
|
// the 'manage_system' permission.
|
||||||
// 'edit_other_users' permission.
|
func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken, *Response) {
|
||||||
|
query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
|
||||||
|
if r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, ""); err != nil {
|
||||||
|
return nil, BuildErrorResponse(r, err)
|
||||||
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
|
return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserAccessToken will get a user access tokens' id, description, is_active
|
||||||
|
// and the user_id of the user it is for. The actual token will not be returned.
|
||||||
|
// Must have the 'read_user_access_token' permission and if getting for another
|
||||||
|
// user, must have the 'edit_other_users' permission.
|
||||||
func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Response) {
|
func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Response) {
|
||||||
if r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), ""); err != nil {
|
if r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), ""); err != nil {
|
||||||
return nil, BuildErrorResponse(r, err)
|
return nil, BuildErrorResponse(r, err)
|
||||||
|
|||||||
@@ -171,6 +171,18 @@ func (s SqlUserAccessTokenStore) Get(tokenId string) store.StoreChannel {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlUserAccessTokenStore) GetAll(offset, limit int) store.StoreChannel {
|
||||||
|
return store.Do(func(result *store.StoreResult) {
|
||||||
|
tokens := []*model.UserAccessToken{}
|
||||||
|
|
||||||
|
if _, err := s.GetReplica().Select(&tokens, "SELECT * FROM UserAccessTokens LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
|
||||||
|
result.Err = model.NewAppError("SqlUserAccessTokenStore.GetAll", "store.sql_user_access_token.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Data = tokens
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlUserAccessTokenStore) GetByToken(tokenString string) store.StoreChannel {
|
func (s SqlUserAccessTokenStore) GetByToken(tokenString string) store.StoreChannel {
|
||||||
return store.Do(func(result *store.StoreResult) {
|
return store.Do(func(result *store.StoreResult) {
|
||||||
token := model.UserAccessToken{}
|
token := model.UserAccessToken{}
|
||||||
|
|||||||
@@ -446,6 +446,7 @@ type UserAccessTokenStore interface {
|
|||||||
Delete(tokenId string) StoreChannel
|
Delete(tokenId string) StoreChannel
|
||||||
DeleteAllForUser(userId string) StoreChannel
|
DeleteAllForUser(userId string) StoreChannel
|
||||||
Get(tokenId string) StoreChannel
|
Get(tokenId string) StoreChannel
|
||||||
|
GetAll(offset int, limit int) StoreChannel
|
||||||
GetByToken(tokenString string) StoreChannel
|
GetByToken(tokenString string) StoreChannel
|
||||||
GetByUser(userId string, page, perPage int) StoreChannel
|
GetByUser(userId string, page, perPage int) StoreChannel
|
||||||
UpdateTokenEnable(tokenId string) StoreChannel
|
UpdateTokenEnable(tokenId string) StoreChannel
|
||||||
|
|||||||
@@ -61,6 +61,22 @@ func (_m *UserAccessTokenStore) Get(tokenId string) store.StoreChannel {
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAll provides a mock function with given fields:
|
||||||
|
func (_m *UserAccessTokenStore) GetAll(page int, perPage int) store.StoreChannel {
|
||||||
|
ret := _m.Called(page, perPage)
|
||||||
|
|
||||||
|
var r0 store.StoreChannel
|
||||||
|
if rf, ok := ret.Get(0).(func(int, int) store.StoreChannel); ok {
|
||||||
|
r0 = rf(page, perPage)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(store.StoreChannel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
// GetByToken provides a mock function with given fields: tokenString
|
// GetByToken provides a mock function with given fields: tokenString
|
||||||
func (_m *UserAccessTokenStore) GetByToken(tokenString string) store.StoreChannel {
|
func (_m *UserAccessTokenStore) GetByToken(tokenString string) store.StoreChannel {
|
||||||
ret := _m.Called(tokenString)
|
ret := _m.Called(tokenString)
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ func testUserAccessTokenSaveGetDelete(t *testing.T, ss store.Store) {
|
|||||||
t.Fatal("received incorrect number of tokens after save")
|
t.Fatal("received incorrect number of tokens after save")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if result := <-ss.UserAccessToken().GetAll(0, 100); result.Err != nil {
|
||||||
|
t.Fatal(result.Err)
|
||||||
|
} else if received := result.Data.([]*model.UserAccessToken); len(received) != 1 {
|
||||||
|
t.Fatal("received incorrect number of tokens after save")
|
||||||
|
}
|
||||||
|
|
||||||
if result := <-ss.UserAccessToken().Delete(uat.Id); result.Err != nil {
|
if result := <-ss.UserAccessToken().Delete(uat.Id); result.Err != nil {
|
||||||
t.Fatal(result.Err)
|
t.Fatal(result.Err)
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user