feat: new API route for removing privileges

The old route was a DELETE method that took a request body. The
body is sometimes stripped by some proxies, so this new method
does not require a request body, and the member (to whom the privilege
is revoked) is now in the route itself as a parameter.
This commit is contained in:
Julian Lam
2026-03-04 11:12:36 -05:00
parent 8a371d23ca
commit b4c0066737
5 changed files with 143 additions and 5 deletions

View File

@@ -136,8 +136,11 @@ put:
delete:
tags:
- categories
summary: Rescinds category privilege for user/group
description: This operation rescinds a category privilege for a specific user or group
summary: Rescinds category privilege for user/group (Deprecated)
description: |
This method is **deprecated**, please use `DELETE /categories/:cid/:privilege/:member` instead when removing privileges via the API.
This operation rescinds a category privilege for a specific user or group
parameters:
- in: path
name: cid

View File

@@ -0,0 +1,125 @@
delete:
tags:
- categories
summary: Rescinds category privilege for user/group
description: This operation rescinds a category privilege for a specific user or group
parameters:
- in: path
name: cid
schema:
type: string
required: true
description: a valid category id, `0` for global privileges, `admin` for admin privileges
example: 1
- in: path
name: privilege
schema:
type: string
required: true
description: The specific privilege you would like to rescind. Privileges for groups must be prefixed `group:`
example: 'groups:ban'
responses:
'200':
description: Privilege successfully rescinded
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../../components/schemas/Status.yaml#/Status
response:
type: object
properties:
labelData:
type: array
items:
type: object
properties:
label:
type: string
description: the name of the privilege displayed in the ACP dashboard
type:
type: string
description: type of the privilege (one of viewing, posting, moderation or other)
users:
type: array
items:
type: object
properties:
uid:
type: number
description: A user identifier
example: 1
username:
type: string
description: A friendly name for a given user account
example: Dragon Fruit
displayname:
type: string
description: This is either username or fullname depending on forum and user settings
example: Dragon Fruit
picture:
type: string
description: A URL pointing to a picture to be used as the user's avatar
example: 'https://images.unsplash.com/photo-1560070094-e1f2ddec4337?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=256&h=256&q=80'
nullable: true
'icon:text':
type: string
description: A single-letter representation of a username. This is used in the auto-generated icon given to users without an avatar
example: D
'icon:bgColor':
type: string
description: A six-character hexadecimal colour code assigned to the user. This value is used in conjunction with `icon:text` for the user's auto-generated icon
example: '#9c27b0'
banned:
type: number
description: A Boolean representing whether a user is banned or not
example: 0
banned_until_readable:
type: string
description: An ISO 8601 formatted date string representing the moment a ban will be lifted, or the words "Not Banned"
example: Not Banned
privileges:
type: object
additionalProperties:
description: A set of privileges with either true or false
groups:
type: array
items:
type: object
properties:
name:
type: string
nameEscaped:
type: string
privileges:
type: object
additionalProperties:
description: A set of privileges with either true or false
types:
type: object
description: Each privilege will have a key in this object, the value will be the type of the privilege (viewing, posting, moderation or other)
isPrivate:
type: boolean
isSystem:
type: boolean
keys:
type: object
properties:
users:
type: array
items:
type: string
description: "Privilege name"
groups:
type: array
items:
type: string
description: "Privilege name"
columnCountUserOther:
type: number
description: "The number of additional user privileges added by plugins"
columnCountGroupOther:
type: number
description: "The number of additional user privileges added by plugins"

View File

@@ -248,7 +248,16 @@ define('admin/manage/privileges', [
applyPrivilegesToColumn(inputSelectorFn, sourceChecked);
};
Privileges.setPrivilege = (member, privilege, state) => api[state ? 'put' : 'del'](`/categories/${isNaN(cid) ? 0 : cid}/privileges/${encodeURIComponent(privilege)}`, { member });
Privileges.setPrivilege = (member, privilege, state) => {
const method = state ? 'put' : 'del';
let url = `/categories/${isNaN(cid) ? 0 : cid}/privileges/${encodeURIComponent(privilege)}`;
const payload = { member };
if (!state) {
url += `/${member}`;
delete payload.member;
}
return api[method](url, payload);
};
Privileges.addUserToPrivilegeTable = function () {
const modal = bootbox.dialog({

View File

@@ -83,12 +83,12 @@ Categories.getPrivileges = async (req, res) => {
};
Categories.setPrivilege = async (req, res) => {
const { cid, privilege } = req.params;
const { cid, privilege, member } = req.params;
await api.categories.setPrivilege(req, {
cid,
privilege,
member: req.body.member,
member: member || req.body.member,
set: req.method === 'PUT',
});

View File

@@ -27,6 +27,7 @@ module.exports = function () {
setupApiRoute(router, 'get', '/:cid/privileges', [...middlewares], controllers.write.categories.getPrivileges);
setupApiRoute(router, 'put', '/:cid/privileges/:privilege', [...middlewares, middleware.checkRequired.bind(null, ['member'])], controllers.write.categories.setPrivilege);
setupApiRoute(router, 'delete', '/:cid/privileges/:privilege', [...middlewares, middleware.checkRequired.bind(null, ['member'])], controllers.write.categories.setPrivilege);
setupApiRoute(router, 'delete', '/:cid/privileges/:privilege/:member', [...middlewares], controllers.write.categories.setPrivilege);
setupApiRoute(router, 'put', '/:cid/moderator/:uid', [...middlewares, middleware.assert.category], controllers.write.categories.setModerator);
setupApiRoute(router, 'delete', '/:cid/moderator/:uid', [...middlewares, middleware.assert.category], controllers.write.categories.setModerator);