Implement PUT /users/{user_id}/roles endpoint for APIv4 (#5238)
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
187aff9fa8
Коммит
36f43edba3
@@ -6,6 +6,7 @@ package api4
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -213,10 +214,12 @@ func CheckUserSanitization(t *testing.T, user *model.User) {
|
|||||||
|
|
||||||
func CheckEtag(t *testing.T, data interface{}, resp *model.Response) {
|
func CheckEtag(t *testing.T, data interface{}, resp *model.Response) {
|
||||||
if !reflect.ValueOf(data).IsNil() {
|
if !reflect.ValueOf(data).IsNil() {
|
||||||
|
debug.PrintStack()
|
||||||
t.Fatal("etag data was not nil")
|
t.Fatal("etag data was not nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusNotModified {
|
if resp.StatusCode != http.StatusNotModified {
|
||||||
|
debug.PrintStack()
|
||||||
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
||||||
t.Log("expected: " + strconv.Itoa(http.StatusNotModified))
|
t.Log("expected: " + strconv.Itoa(http.StatusNotModified))
|
||||||
t.Fatal("wrong status code for etag")
|
t.Fatal("wrong status code for etag")
|
||||||
@@ -225,17 +228,20 @@ func CheckEtag(t *testing.T, data interface{}, resp *model.Response) {
|
|||||||
|
|
||||||
func CheckNoError(t *testing.T, resp *model.Response) {
|
func CheckNoError(t *testing.T, resp *model.Response) {
|
||||||
if resp.Error != nil {
|
if resp.Error != nil {
|
||||||
t.Fatal(resp.Error)
|
debug.PrintStack()
|
||||||
|
t.Fatal("Expected no error, got " + resp.Error.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckForbiddenStatus(t *testing.T, resp *model.Response) {
|
func CheckForbiddenStatus(t *testing.T, resp *model.Response) {
|
||||||
if resp.Error == nil {
|
if resp.Error == nil {
|
||||||
|
debug.PrintStack()
|
||||||
t.Fatal("should have errored with status:" + strconv.Itoa(http.StatusForbidden))
|
t.Fatal("should have errored with status:" + strconv.Itoa(http.StatusForbidden))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusForbidden {
|
if resp.StatusCode != http.StatusForbidden {
|
||||||
|
debug.PrintStack()
|
||||||
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
||||||
t.Log("expected: " + strconv.Itoa(http.StatusForbidden))
|
t.Log("expected: " + strconv.Itoa(http.StatusForbidden))
|
||||||
t.Fatal("wrong status code")
|
t.Fatal("wrong status code")
|
||||||
@@ -244,11 +250,13 @@ func CheckForbiddenStatus(t *testing.T, resp *model.Response) {
|
|||||||
|
|
||||||
func CheckUnauthorizedStatus(t *testing.T, resp *model.Response) {
|
func CheckUnauthorizedStatus(t *testing.T, resp *model.Response) {
|
||||||
if resp.Error == nil {
|
if resp.Error == nil {
|
||||||
|
debug.PrintStack()
|
||||||
t.Fatal("should have errored with status:" + strconv.Itoa(http.StatusUnauthorized))
|
t.Fatal("should have errored with status:" + strconv.Itoa(http.StatusUnauthorized))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusUnauthorized {
|
if resp.StatusCode != http.StatusUnauthorized {
|
||||||
|
debug.PrintStack()
|
||||||
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
||||||
t.Log("expected: " + strconv.Itoa(http.StatusUnauthorized))
|
t.Log("expected: " + strconv.Itoa(http.StatusUnauthorized))
|
||||||
t.Fatal("wrong status code")
|
t.Fatal("wrong status code")
|
||||||
@@ -257,11 +265,13 @@ func CheckUnauthorizedStatus(t *testing.T, resp *model.Response) {
|
|||||||
|
|
||||||
func CheckNotFoundStatus(t *testing.T, resp *model.Response) {
|
func CheckNotFoundStatus(t *testing.T, resp *model.Response) {
|
||||||
if resp.Error == nil {
|
if resp.Error == nil {
|
||||||
|
debug.PrintStack()
|
||||||
t.Fatal("should have errored with status:" + strconv.Itoa(http.StatusNotFound))
|
t.Fatal("should have errored with status:" + strconv.Itoa(http.StatusNotFound))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusNotFound {
|
if resp.StatusCode != http.StatusNotFound {
|
||||||
|
debug.PrintStack()
|
||||||
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
||||||
t.Log("expected: " + strconv.Itoa(http.StatusNotFound))
|
t.Log("expected: " + strconv.Itoa(http.StatusNotFound))
|
||||||
t.Fatal("wrong status code")
|
t.Fatal("wrong status code")
|
||||||
@@ -270,11 +280,13 @@ func CheckNotFoundStatus(t *testing.T, resp *model.Response) {
|
|||||||
|
|
||||||
func CheckBadRequestStatus(t *testing.T, resp *model.Response) {
|
func CheckBadRequestStatus(t *testing.T, resp *model.Response) {
|
||||||
if resp.Error == nil {
|
if resp.Error == nil {
|
||||||
|
debug.PrintStack()
|
||||||
t.Fatal("should have errored with status:" + strconv.Itoa(http.StatusBadRequest))
|
t.Fatal("should have errored with status:" + strconv.Itoa(http.StatusBadRequest))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusBadRequest {
|
if resp.StatusCode != http.StatusBadRequest {
|
||||||
|
debug.PrintStack()
|
||||||
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
t.Log("actual: " + strconv.Itoa(resp.StatusCode))
|
||||||
t.Log("expected: " + strconv.Itoa(http.StatusBadRequest))
|
t.Log("expected: " + strconv.Itoa(http.StatusBadRequest))
|
||||||
t.Fatal("wrong status code")
|
t.Fatal("wrong status code")
|
||||||
@@ -283,11 +295,13 @@ func CheckBadRequestStatus(t *testing.T, resp *model.Response) {
|
|||||||
|
|
||||||
func CheckErrorMessage(t *testing.T, resp *model.Response, errorId string) {
|
func CheckErrorMessage(t *testing.T, resp *model.Response, errorId string) {
|
||||||
if resp.Error == nil {
|
if resp.Error == nil {
|
||||||
|
debug.PrintStack()
|
||||||
t.Fatal("should have errored with message:" + errorId)
|
t.Fatal("should have errored with message:" + errorId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Error.Id != errorId {
|
if resp.Error.Id != errorId {
|
||||||
|
debug.PrintStack()
|
||||||
t.Log("actual: " + resp.Error.Id)
|
t.Log("actual: " + resp.Error.Id)
|
||||||
t.Log("expected: " + errorId)
|
t.Log("expected: " + errorId)
|
||||||
t.Fatal("incorrect error message")
|
t.Fatal("incorrect error message")
|
||||||
|
|||||||
30
api4/user.go
30
api4/user.go
@@ -18,6 +18,7 @@ func InitUser() {
|
|||||||
BaseRoutes.Users.Handle("", ApiHandler(createUser)).Methods("POST")
|
BaseRoutes.Users.Handle("", ApiHandler(createUser)).Methods("POST")
|
||||||
BaseRoutes.User.Handle("", ApiSessionRequired(getUser)).Methods("GET")
|
BaseRoutes.User.Handle("", ApiSessionRequired(getUser)).Methods("GET")
|
||||||
BaseRoutes.User.Handle("", ApiSessionRequired(updateUser)).Methods("PUT")
|
BaseRoutes.User.Handle("", ApiSessionRequired(updateUser)).Methods("PUT")
|
||||||
|
BaseRoutes.User.Handle("/roles", ApiSessionRequired(updateUserRoles)).Methods("PUT")
|
||||||
|
|
||||||
BaseRoutes.Users.Handle("/login", ApiHandler(login)).Methods("POST")
|
BaseRoutes.Users.Handle("/login", ApiHandler(login)).Methods("POST")
|
||||||
BaseRoutes.Users.Handle("/logout", ApiHandler(logout)).Methods("POST")
|
BaseRoutes.Users.Handle("/logout", ApiHandler(logout)).Methods("POST")
|
||||||
@@ -109,6 +110,35 @@ func updateUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateUserRoles(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
props := model.MapFromJson(r.Body)
|
||||||
|
|
||||||
|
newRoles := props["roles"]
|
||||||
|
if !model.IsValidUserRoles(newRoles) {
|
||||||
|
c.SetInvalidParam("roles")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_ROLES) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_MANAGE_ROLES)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := app.UpdateUserRoles(c.Params.UserId, newRoles); err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
c.LogAuditWithUserId(c.Params.UserId, "roles="+newRoles)
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnStatusOK(w)
|
||||||
|
}
|
||||||
|
|
||||||
func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
props := model.MapFromJson(r.Body)
|
props := model.MapFromJson(r.Body)
|
||||||
|
|
||||||
|
|||||||
@@ -182,3 +182,27 @@ func TestUpdateUser(t *testing.T) {
|
|||||||
_, resp = th.SystemAdminClient.UpdateUser(user)
|
_, resp = th.SystemAdminClient.UpdateUser(user)
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateUserRoles(t *testing.T) {
|
||||||
|
th := Setup().InitBasic().InitSystemAdmin()
|
||||||
|
Client := th.Client
|
||||||
|
SystemAdminClient := th.SystemAdminClient
|
||||||
|
|
||||||
|
_, resp := Client.UpdateUserRoles(th.SystemAdminUser.Id, model.ROLE_SYSTEM_USER.Id)
|
||||||
|
CheckForbiddenStatus(t, resp)
|
||||||
|
|
||||||
|
_, resp = SystemAdminClient.UpdateUserRoles(th.BasicUser.Id, model.ROLE_SYSTEM_USER.Id)
|
||||||
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
|
_, resp = SystemAdminClient.UpdateUserRoles(th.BasicUser.Id, model.ROLE_SYSTEM_USER.Id+" "+model.ROLE_SYSTEM_ADMIN.Id)
|
||||||
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
|
_, resp = SystemAdminClient.UpdateUserRoles(th.BasicUser.Id, "junk")
|
||||||
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|
||||||
|
_, resp = SystemAdminClient.UpdateUserRoles("junk", model.ROLE_SYSTEM_USER.Id)
|
||||||
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|
||||||
|
_, resp = SystemAdminClient.UpdateUserRoles(model.NewId(), model.ROLE_SYSTEM_USER.Id)
|
||||||
|
CheckBadRequestStatus(t, resp)
|
||||||
|
}
|
||||||
|
|||||||
@@ -212,6 +212,17 @@ func (c *Client4) UpdateUser(user *User) (*User, *Response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateUserRoles updates a user's roles in the system. A user can have "system_user" and "system_admin" roles.
|
||||||
|
func (c *Client4) UpdateUserRoles(userId, roles string) (bool, *Response) {
|
||||||
|
requestBody := map[string]string{"roles": roles}
|
||||||
|
if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody)); err != nil {
|
||||||
|
return false, &Response{StatusCode: r.StatusCode, Error: err}
|
||||||
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
|
return CheckStatusOK(r), BuildResponse(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Team Section
|
// Team Section
|
||||||
|
|
||||||
// CreateTeam creates a team in the system based on the provided team struct.
|
// CreateTeam creates a team in the system based on the provided team struct.
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user