diff --git a/graph/mutators/user.js b/graph/mutators/user.js index 3a08535d2..a7a20b4ec 100644 --- a/graph/mutators/user.js +++ b/graph/mutators/user.js @@ -6,6 +6,7 @@ const { SET_USER_USERNAME_STATUS, SET_USER_BAN_STATUS, SET_USER_SUSPENSION_STATUS, + UPDATE_USER_ROLES, } = require('../../perms/constants'); const setUserUsernameStatus = async (ctx, id, status) => { @@ -47,16 +48,26 @@ const setUsername = async (ctx, id, username) => { return UsersService.setUsername(id, username, ctx.user.id); }; +const addRole = (ctx, id, role) => { + return UsersService.addRoleToUser(id, role); +}; + +const removeRole = (ctx, id, role) => { + return UsersService.removeRoleFromUser(id, role); +}; + module.exports = (ctx) => { let mutators = { User: { - ignoreUser: () => Promise.reject(errors.ErrNotAuthorized), + addRole: () => Promise.reject(errors.ErrNotAuthorized), changeUsername: () => Promise.reject(errors.ErrNotAuthorized), - setUsername: () => Promise.reject(errors.ErrNotAuthorized), - stopIgnoringUser: () => Promise.reject(errors.ErrNotAuthorized), - setUserUsernameStatus: () => Promise.reject(errors.ErrNotAuthorized), + ignoreUser: () => Promise.reject(errors.ErrNotAuthorized), + removeRole: () => Promise.reject(errors.ErrNotAuthorized), setUserBanStatus: () => Promise.reject(errors.ErrNotAuthorized), setUserSuspensionStatus: () => Promise.reject(errors.ErrNotAuthorized), + setUserUsernameStatus: () => Promise.reject(errors.ErrNotAuthorized), + setUsername: () => Promise.reject(errors.ErrNotAuthorized), + stopIgnoringUser: () => Promise.reject(errors.ErrNotAuthorized), } }; @@ -64,6 +75,11 @@ module.exports = (ctx) => { mutators.User.ignoreUser = (action) => ignoreUser(ctx, action); mutators.User.stopIgnoringUser = (action) => stopIgnoringUser(ctx, action); + if (ctx.user.can(UPDATE_USER_ROLES)) { + mutators.User.addRole = (id, role) => addRole(ctx, id, role); + mutators.User.removeRole = (id, role) => removeRole(ctx, id, role); + } + if (ctx.user.can(CHANGE_USERNAME)) { mutators.User.changeUsername = (id, username) => changeUsername(ctx, id, username); } diff --git a/graph/resolvers/root_mutation.js b/graph/resolvers/root_mutation.js index 2b2592dc4..f13739dec 100644 --- a/graph/resolvers/root_mutation.js +++ b/graph/resolvers/root_mutation.js @@ -55,6 +55,12 @@ const RootMutation = { updateAssetStatus: async (_, {id, input: status}, {mutators: {Asset}}) => { await Asset.updateStatus(id, status); }, + addUserRole: async (_, {id, role}, {mutators: {User}}) => { + await User.addRole(id, role); + }, + removeUserRole: async (_, {id, role}, {mutators: {User}}) => { + await User.removeRole(id, role); + }, setCommentStatus: async (_, {id, status}, {mutators: {Comment}, pubsub}) => { const comment = await Comment.setStatus({id, status}); if (status === 'ACCEPTED') { diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index d2d2943ce..8d9224768 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -1377,6 +1377,12 @@ type SetUsernameResponse implements Response { errors: [UserError!] } +type ModifyUserRoleResponse implements Response { + + # An array of errors relating to the mutation that occurred. + errors: [UserError!] +} + # All mutations for the application are defined on this object. type RootMutation { @@ -1438,6 +1444,12 @@ type RootMutation { # Removes a tag. removeTag(tag: ModifyTagInput!): ModifyTagResponse + # Adds a role to a user. + addUserRole(id: ID!, role: USER_ROLES!): ModifyUserRoleResponse + + # Removes a role from a user. + removeUserRole(id: ID!, role: USER_ROLES!): ModifyUserRoleResponse + # Updates settings on a given asset. # Mutation is restricted. updateAssetSettings(id: ID!, input: AssetSettingsInput!): UpdateAssetSettingsResponse diff --git a/perms/constants/mutation.js b/perms/constants/mutation.js index 72ec0458c..06e5b6f0f 100644 --- a/perms/constants/mutation.js +++ b/perms/constants/mutation.js @@ -17,5 +17,5 @@ module.exports = { REVOKE_TOKEN: 'REVOKE_TOKEN', UPDATE_ASSET_SETTINGS: 'UPDATE_ASSET_SETTINGS', UPDATE_ASSET_STATUS: 'UPDATE_ASSET_STATUS', - UPDATE_SETTINGS: 'UPDATE_SETTINGS' + UPDATE_SETTINGS: 'UPDATE_SETTINGS', }; diff --git a/routes/api/users/index.js b/routes/api/users/index.js index 24f5b65e0..7dbd95a71 100644 --- a/routes/api/users/index.js +++ b/routes/api/users/index.js @@ -55,6 +55,15 @@ router.post('/:user_id/role', authorization.needed('ADMIN', 'MODERATOR'), async } }); +router.delete('/:user_id/role', authorization.needed('ADMIN', 'MODERATOR'), async (req, res, next) => { + try { + await UsersService.removeRoleFromUser(req.params.user_id, req.body.role); + res.status(204).end(); + } catch (e) { + next(e); + } +}); + // create a local user. router.post('/', async (req, res, next) => { const {email, password, username} = req.body;