* **feat**: add support for setting watch state via category ID and member UID in route params

* **feat**: update category watch/privilege routes and logic to use `member` param instead of `uid`/`member` body field

* **feat**: add support for unfollowing via actor parameter in category routes

* **feat**: add deprecation warnings for legacy category routes and refactor privilege fetching to inline async call

* docs: add openapi specs for new category routes with path parameters

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* fix: some minor errors in file paths

* feat: support path extraction from req.query in assert.path middleware

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* feat: support message from both query and body in removeQueuedPost

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* fix: remove ai-added check that path is defined, it is not required

* fix: send message as query param instead of in body, when rejecting queued post

* lint: comma dangle

* `feat(openapi): add optional query parameter support for topic delete endpoints`

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* feat: add query parameter and make request body optional for topic thumbnail deletion

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* feat: support query params for thumb path and crosspost id in topics endpoints

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* feat: add query params for mute/unmute reason and timestamp

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* docs: update unmute API to support query params for reason and until timestamp

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* docs: update unmute endpoint to support reason via request body

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* feat: add reason parameter support to users.unmute

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>

* feat: allow unban reason to be sent via req.query

* fix: timestamps are unix timestamps not 8601

* docs: mute shouldn't have been updated

* chore: remove deprecation warnings

---------

Co-authored-by: aider (ollama/ministral-3:8b) <aider@aider.chat>
This commit is contained in:
Julian Lam
2026-04-20 09:54:49 -04:00
committed by GitHub
parent c8d851837b
commit e395fb0919
15 changed files with 314 additions and 29 deletions

View File

@@ -0,0 +1,39 @@
delete:
tags:
- categories
summary: unsynchronize category
description: |
**This operation requires an enabled activitypub integration**
Removes a "follow" relationship between another activitypub-enabled actor.
Unlike the synchronization request, this does not require an acceptance from the remote end.
N.B. This method only severs the link for incoming content.
parameters:
- in: path
name: cid
schema:
type: string
required: true
description: a valid category id
example: 1
- in: path
name: actor
schema:
type: string
required: true
description: A valid actor uri or webfinger handle
example: https%3A%2F%2Fexample.org%2Ffoobar
responses:
'200':
description: successfully unsynchronized category
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../../components/schemas/Status.yaml#/Status
response:
type: object
properties: {}

View File

@@ -0,0 +1,132 @@
delete:
tags:
- categories
summary: Rescinds category privilege for user
description: This operation rescinds a category privilege for a specific user
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
example: 'groups:ban'
- in: path
name: member
schema:
type: string
required: true
description: A valid user id
example: '1'
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 group privileges added by plugins"

View File

@@ -0,0 +1,51 @@
delete:
tags:
- categories
summary: update watch state for specific user
description: |
This operation changes the watch state for a specific user in the category.
Unlike the general watch state update, this route takes the user ID directly in the path.
Note that a category can be watched, not watched, or ignored:
* A category that is watched will have topics that show up in both `/unread` and `/recent`
* A category that is *not* watched will have topics that show up in `/recent` but not `/unread`
* A category that is ignored will not have topics that show up in either route.
This API call does not pertain to notifications for new topics in categories.
That behaviour is handled by a third-party plugin — nodebb-plugin-category-notifications
Additionally, when a category's watch state is updated, all of that category's children also have their watch states updated.
parameters:
- in: path
name: cid
schema:
type: string
required: true
description: a valid category id
example: 1
- in: path
name: member
schema:
type: string
required: true
description: a valid user id
example: 1
responses:
'200':
description: categories watch state successfully updated
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../../components/schemas/Status.yaml#/Status
response:
type: object
properties:
modified:
type: array
description: A list of cids that have had their watch states modified.
items:
type: string

View File

@@ -77,8 +77,15 @@ delete:
required: true
description: a valid topic id
example: 1
- in: query
name: cid
schema:
type: integer
required: false
description: Category ID of the crosspost to remove (alternative to request body)
example: 1
requestBody:
required: true
required: false
content:
application/json:
schema:
@@ -101,4 +108,4 @@ delete:
type: object
properties:
crossposts:
$ref: ../../../components/schemas/CrosspostObject.yaml#/CrosspostsArray
$ref: ../../../components/schemas/CrosspostObject.yaml#/CrosspostsArray

View File

@@ -96,8 +96,15 @@ delete:
required: true
description: a valid topic id
example: 1
- in: query
name: path
schema:
type: string
required: false
description: Relative path to the topic thumbnail (alternative to request body)
example: files/test.png
requestBody:
required: true
required: false
content:
application/json:
schema:
@@ -131,4 +138,4 @@ delete:
type: string
url:
type: string
description: Path to a topic thumbnail
description: Path to a topic thumbnail

View File

@@ -47,6 +47,24 @@ delete:
required: true
description: uid of the user to unmute
example: 2
- name: reason
in: query
schema:
type: string
nullable: true
description: Reason for the unmute
example: Reason for the unmute
requestBody:
content:
application/json:
schema:
type: object
properties:
reason:
type: string
nullable: true
description: Reason for the unmute
example: Reason for the unmute
responses:
'200':
description: successfully unmuted user
@@ -58,4 +76,4 @@ delete:
status:
$ref: ../../../components/schemas/Status.yaml#/Status
response:
type: object
type: object