From e2c2c9df4a3ed8fe32e8a063acd9bcf6143142e5 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Sat, 23 Feb 2019 20:16:36 +0100 Subject: [PATCH] Fix role membership management endpoints & ctrls --- api/system/spec.json | 34 ++++++++++----- api/system/spec/role.json | 34 ++++++++++----- docs/system/README.md | 24 +++++++--- messaging/types/channel.perms.gen.go | 2 +- messaging/types/organisation.perms.gen.go | 16 +++---- messaging/types/role.perms.gen.go | 2 +- system/repository/role.go | 7 +++ system/rest/handlers/role.go | 14 +++++- system/rest/request/role.go | 53 +++++++++++++++++++---- system/rest/role.go | 22 ++++++++-- system/service/role.go | 6 +++ 11 files changed, 163 insertions(+), 51 deletions(-) diff --git a/api/system/spec.json b/api/system/spec.json index abb5eabc7..b9aad052f 100644 --- a/api/system/spec.json +++ b/api/system/spec.json @@ -334,10 +334,10 @@ } }, { - "name": "memberAdd", - "method": "POST", - "title": "Add member to a role", - "path": "/{roleID}/memberAdd", + "name": "memberList", + "method": "GET", + "title": "Returns all role members", + "path": "/{roleID}/members", "parameters": { "path": [ { @@ -346,8 +346,22 @@ "required": true, "title": "Source Role ID" } - ], - "post": [ + ] + } + }, + { + "name": "memberAdd", + "method": "POST", + "title": "Add member to a role", + "path": "/{roleID}/member/{userID}", + "parameters": { + "path": [ + { + "type": "uint64", + "name": "roleID", + "required": true, + "title": "Source Role ID" + }, { "type": "uint64", "name": "userID", @@ -359,9 +373,9 @@ }, { "name": "memberRemove", - "method": "POST", + "method": "DELETE", "title": "Remove member from a role", - "path": "/{roleID}/memberRemove", + "path": "/{roleID}/member/{userID}", "parameters": { "path": [ { @@ -369,9 +383,7 @@ "name": "roleID", "required": true, "title": "Source Role ID" - } - ], - "post": [ + }, { "type": "uint64", "name": "userID", diff --git a/api/system/spec/role.json b/api/system/spec/role.json index 87742fe54..4461f508f 100644 --- a/api/system/spec/role.json +++ b/api/system/spec/role.json @@ -176,10 +176,10 @@ } }, { - "Name": "memberAdd", - "Method": "POST", - "Title": "Add member to a role", - "Path": "/{roleID}/memberAdd", + "Name": "memberList", + "Method": "GET", + "Title": "Returns all role members", + "Path": "/{roleID}/members", "Parameters": { "path": [ { @@ -188,8 +188,22 @@ "title": "Source Role ID", "type": "uint64" } - ], - "post": [ + ] + } + }, + { + "Name": "memberAdd", + "Method": "POST", + "Title": "Add member to a role", + "Path": "/{roleID}/member/{userID}", + "Parameters": { + "path": [ + { + "name": "roleID", + "required": true, + "title": "Source Role ID", + "type": "uint64" + }, { "name": "userID", "required": true, @@ -201,9 +215,9 @@ }, { "Name": "memberRemove", - "Method": "POST", + "Method": "DELETE", "Title": "Remove member from a role", - "Path": "/{roleID}/memberRemove", + "Path": "/{roleID}/member/{userID}", "Parameters": { "path": [ { @@ -211,9 +225,7 @@ "required": true, "title": "Source Role ID", "type": "uint64" - } - ], - "post": [ + }, { "name": "userID", "required": true, diff --git a/docs/system/README.md b/docs/system/README.md index d762e6e23..9279350df 100644 --- a/docs/system/README.md +++ b/docs/system/README.md @@ -318,20 +318,34 @@ An organisation may have many roles. Roles may have many channels available. Acc | roleID | uint64 | PATH | Source Role ID | N/A | YES | | destination | uint64 | POST | Destination Role ID | N/A | YES | -## Add member to a role +## Returns all role members #### Method | URI | Protocol | Method | Authentication | | --- | -------- | ------ | -------------- | -| `/roles/{roleID}/memberAdd` | HTTP/S | POST | Client ID, Session ID | +| `/roles/{roleID}/members` | HTTP/S | GET | Client ID, Session ID | #### Request parameters | Parameter | Type | Method | Description | Default | Required? | | --------- | ---- | ------ | ----------- | ------- | --------- | | roleID | uint64 | PATH | Source Role ID | N/A | YES | -| userID | uint64 | POST | User ID | N/A | YES | + +## Add member to a role + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/roles/{roleID}/member/{userID}` | HTTP/S | POST | Client ID, Session ID | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| roleID | uint64 | PATH | Source Role ID | N/A | YES | +| userID | uint64 | PATH | User ID | N/A | YES | ## Remove member from a role @@ -339,14 +353,14 @@ An organisation may have many roles. Roles may have many channels available. Acc | URI | Protocol | Method | Authentication | | --- | -------- | ------ | -------------- | -| `/roles/{roleID}/memberRemove` | HTTP/S | POST | Client ID, Session ID | +| `/roles/{roleID}/member/{userID}` | HTTP/S | DELETE | Client ID, Session ID | #### Request parameters | Parameter | Type | Method | Description | Default | Required? | | --------- | ---- | ------ | ----------- | ------- | --------- | | roleID | uint64 | PATH | Source Role ID | N/A | YES | -| userID | uint64 | POST | User ID | N/A | YES | +| userID | uint64 | PATH | User ID | N/A | YES | diff --git a/messaging/types/channel.perms.gen.go b/messaging/types/channel.perms.gen.go index 539373162..e83d44942 100644 --- a/messaging/types/channel.perms.gen.go +++ b/messaging/types/channel.perms.gen.go @@ -64,13 +64,13 @@ func (*Channel) Permissions() []rules.OperationGroup { func (*Channel) PermissionDefault(key string) rules.Access { values := map[string]rules.Access{ + "message.embed": rules.Inherit, "message.attach": rules.Inherit, "message.update_own": rules.Inherit, "message.update_all": rules.Inherit, "message.react": rules.Inherit, "manage.webhooks": rules.Inherit, "message.send": rules.Inherit, - "message.embed": rules.Inherit, } if value, ok := values[key]; ok { return value diff --git a/messaging/types/organisation.perms.gen.go b/messaging/types/organisation.perms.gen.go index 879b2af38..a0ab3a27f 100644 --- a/messaging/types/organisation.perms.gen.go +++ b/messaging/types/organisation.perms.gen.go @@ -94,18 +94,18 @@ func (*Organisation) Permissions() []rules.OperationGroup { func (*Organisation) PermissionDefault(key string) rules.Access { values := map[string]rules.Access{ - "audit": rules.Deny, - "manage.organisation": rules.Deny, - "manage.roles": rules.Deny, - "manage.channels": rules.Deny, - "manage.webhooks": rules.Deny, - "message.attach": rules.Allow, + "message.send": rules.Allow, + "message.update_own": rules.Allow, "message.update_all": rules.Deny, "message.react": rules.Allow, "admin": rules.Deny, - "message.send": rules.Allow, + "manage.organisation": rules.Deny, + "manage.channels": rules.Deny, "message.embed": rules.Allow, - "message.update_own": rules.Allow, + "message.attach": rules.Allow, + "audit": rules.Deny, + "manage.roles": rules.Deny, + "manage.webhooks": rules.Deny, } if value, ok := values[key]; ok { return value diff --git a/messaging/types/role.perms.gen.go b/messaging/types/role.perms.gen.go index f8273e418..d2cac4b6f 100644 --- a/messaging/types/role.perms.gen.go +++ b/messaging/types/role.perms.gen.go @@ -64,13 +64,13 @@ func (*Role) Permissions() []rules.OperationGroup { func (*Role) PermissionDefault(key string) rules.Access { values := map[string]rules.Access{ - "message.embed": rules.Inherit, "message.attach": rules.Inherit, "message.update_own": rules.Inherit, "message.update_all": rules.Inherit, "message.react": rules.Inherit, "manage.webhooks": rules.Inherit, "message.send": rules.Inherit, + "message.embed": rules.Inherit, } if value, ok := values[key]; ok { return value diff --git a/system/repository/role.go b/system/repository/role.go index a4a64f8f5..21e4be766 100644 --- a/system/repository/role.go +++ b/system/repository/role.go @@ -27,6 +27,7 @@ type ( MergeByID(id, targetRoleID uint64) error MoveByID(id, targetOrganisationID uint64) error + MemberFindByRoleID(roleID uint64) ([]*types.RoleMember, error) MemberAddByID(id, userID uint64) error MemberRemoveByID(id, userID uint64) error } @@ -140,6 +141,12 @@ func (r *role) MoveByID(id, targetOrganisationID uint64) error { return ErrNotImplemented } +func (r *role) MemberFindByRoleID(roleID uint64) (mm []*types.RoleMember, err error) { + rval := make([]*types.RoleMember, 0) + sql := "SELECT * FROM " + r.members + " WHERE rel_role = ?" + return rval, r.db().Select(&rval, sql, roleID) +} + func (r *role) MemberAddByID(id, userID uint64) error { mod := &types.RoleMember{ RoleID: id, diff --git a/system/rest/handlers/role.go b/system/rest/handlers/role.go index a58a0139f..0766e9195 100644 --- a/system/rest/handlers/role.go +++ b/system/rest/handlers/role.go @@ -35,6 +35,7 @@ type RoleAPI interface { Archive(context.Context, *request.RoleArchive) (interface{}, error) Move(context.Context, *request.RoleMove) (interface{}, error) Merge(context.Context, *request.RoleMerge) (interface{}, error) + MemberList(context.Context, *request.RoleMemberList) (interface{}, error) MemberAdd(context.Context, *request.RoleMemberAdd) (interface{}, error) MemberRemove(context.Context, *request.RoleMemberRemove) (interface{}, error) } @@ -49,6 +50,7 @@ type Role struct { Archive func(http.ResponseWriter, *http.Request) Move func(http.ResponseWriter, *http.Request) Merge func(http.ResponseWriter, *http.Request) + MemberList func(http.ResponseWriter, *http.Request) MemberAdd func(http.ResponseWriter, *http.Request) MemberRemove func(http.ResponseWriter, *http.Request) } @@ -111,6 +113,13 @@ func NewRole(rh RoleAPI) *Role { return rh.Merge(r.Context(), params) }) }, + MemberList: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewRoleMemberList() + resputil.JSON(w, params.Fill(r), func() (interface{}, error) { + return rh.MemberList(r.Context(), params) + }) + }, MemberAdd: func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() params := request.NewRoleMemberAdd() @@ -140,8 +149,9 @@ func (rh *Role) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http r.Post("/{roleID}/archive", rh.Archive) r.Post("/{roleID}/move", rh.Move) r.Post("/{roleID}/merge", rh.Merge) - r.Post("/{roleID}/memberAdd", rh.MemberAdd) - r.Post("/{roleID}/memberRemove", rh.MemberRemove) + r.Get("/{roleID}/members", rh.MemberList) + r.Post("/{roleID}/member/{userID}", rh.MemberAdd) + r.Delete("/{roleID}/member/{userID}", rh.MemberRemove) }) }) } diff --git a/system/rest/request/role.go b/system/rest/request/role.go index fce6356a1..51725fef3 100644 --- a/system/rest/request/role.go +++ b/system/rest/request/role.go @@ -398,6 +398,49 @@ func (ro *RoleMerge) Fill(r *http.Request) (err error) { var _ RequestFiller = NewRoleMerge() +// Role memberList request parameters +type RoleMemberList struct { + RoleID uint64 `json:",string"` +} + +func NewRoleMemberList() *RoleMemberList { + return &RoleMemberList{} +} + +func (ro *RoleMemberList) Fill(r *http.Request) (err error) { + if strings.ToLower(r.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(r.Body).Decode(ro) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = r.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := r.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := r.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + ro.RoleID = parseUInt64(chi.URLParam(r, "roleID")) + + return err +} + +var _ RequestFiller = NewRoleMemberList() + // Role memberAdd request parameters type RoleMemberAdd struct { RoleID uint64 `json:",string"` @@ -436,10 +479,7 @@ func (ro *RoleMemberAdd) Fill(r *http.Request) (err error) { } ro.RoleID = parseUInt64(chi.URLParam(r, "roleID")) - if val, ok := post["userID"]; ok { - - ro.UserID = parseUInt64(val) - } + ro.UserID = parseUInt64(chi.URLParam(r, "userID")) return err } @@ -484,10 +524,7 @@ func (ro *RoleMemberRemove) Fill(r *http.Request) (err error) { } ro.RoleID = parseUInt64(chi.URLParam(r, "roleID")) - if val, ok := post["userID"]; ok { - - ro.UserID = parseUInt64(val) - } + ro.UserID = parseUInt64(chi.URLParam(r, "userID")) return err } diff --git a/system/rest/role.go b/system/rest/role.go index 52d4d382d..b70602cf1 100644 --- a/system/rest/role.go +++ b/system/rest/role.go @@ -3,6 +3,7 @@ package rest import ( "context" + "github.com/davecgh/go-spew/spew" "github.com/pkg/errors" "github.com/crusttech/crust/system/rest/request" @@ -35,20 +36,20 @@ func (ctrl *Role) List(ctx context.Context, r *request.RoleList) (interface{}, e } func (ctrl *Role) Create(ctx context.Context, r *request.RoleCreate) (interface{}, error) { - org := &types.Role{ + role := &types.Role{ Name: r.Name, } - return ctrl.svc.role.With(ctx).Create(org) + return ctrl.svc.role.With(ctx).Create(role) } func (ctrl *Role) Update(ctx context.Context, r *request.RoleUpdate) (interface{}, error) { - org := &types.Role{ + role := &types.Role{ ID: r.RoleID, Name: r.Name, } - return ctrl.svc.role.With(ctx).Update(org) + return ctrl.svc.role.With(ctx).Update(role) } func (ctrl *Role) Remove(ctx context.Context, r *request.RoleRemove) (interface{}, error) { @@ -67,6 +68,19 @@ func (ctrl *Role) Move(ctx context.Context, r *request.RoleMove) (interface{}, e return nil, ctrl.svc.role.With(ctx).Move(r.RoleID, r.OrganisationID) } +func (ctrl *Role) MemberList(ctx context.Context, r *request.RoleMemberList) (interface{}, error) { + if mm, err := ctrl.svc.role.With(ctx).MemberList(r.RoleID); err != nil { + return nil, err + } else { + rval := make([]uint64, len(mm)) + for i := range mm { + rval[i] = mm[i].UserID + } + spew.Dump(rval) + return rval, nil + } +} + func (ctrl *Role) MemberAdd(ctx context.Context, r *request.RoleMemberAdd) (interface{}, error) { return nil, ctrl.svc.role.With(ctx).MemberAdd(r.RoleID, r.UserID) } diff --git a/system/service/role.go b/system/service/role.go index 1f3b9212a..1d6837799 100644 --- a/system/service/role.go +++ b/system/service/role.go @@ -32,6 +32,7 @@ type ( Unarchive(ID uint64) error Delete(ID uint64) error + MemberList(roleID uint64) ([]*types.RoleMember, error) MemberAdd(roleID, userID uint64) error MemberRemove(roleID, userID uint64) error } @@ -118,6 +119,11 @@ func (svc *role) Move(id, targetOrganisationID uint64) error { return svc.role.MoveByID(id, targetOrganisationID) } +func (svc *role) MemberList(roleID uint64) ([]*types.RoleMember, error) { + // @todo: permission check if current user can read role members + return svc.role.MemberFindByRoleID(roleID) +} + func (svc *role) MemberAdd(id, userID uint64) error { // @todo: permission check if current user can add user in to a role return svc.role.MemberAddByID(id, userID)