diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml index 79657b519e..286583352b 100644 --- a/public/openapi/write.yaml +++ b/public/openapi/write.yaml @@ -136,6 +136,8 @@ paths: $ref: 'write/categories/cid/privileges/privilege.yaml' /categories/{cid}/moderator/{uid}: $ref: 'write/categories/cid/moderator/uid.yaml' + /categories/{cid}/follow: + $ref: 'write/categories/cid/follow.yaml' /topics/: $ref: 'write/topics.yaml' /topics/{tid}: diff --git a/public/openapi/write/categories/cid/follow.yaml b/public/openapi/write/categories/cid/follow.yaml new file mode 100644 index 0000000000..cd8f8a0b96 --- /dev/null +++ b/public/openapi/write/categories/cid/follow.yaml @@ -0,0 +1,85 @@ +put: + tags: + - categories + summary: synchronize category + description: | + **This operation requires an enabled activitypub integration** + + Establishes a "follow" relationship between another activitypub-enabled actor. + Until an "accept" response is received, the synchronization will stay in a pending state. + Upon acceptance, a one-way sync is achieved; the other actor will need to follow the same category in order to achieve full two-way synchronization. + parameters: + - in: path + name: cid + schema: + type: string + required: true + description: a valid category id + example: 1 + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + actor: + type: string + description: A valid actor uri or webfinger handle + example: 'foobar@example.org' + responses: + '200': + description: successfully sent category synchronization request + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object + properties: {} +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 + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + actor: + type: string + description: A valid actor uri or webfinger handle + example: 'foobar@example.org' + responses: + '200': + description: successfully unsynchronized category + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object + properties: {} \ No newline at end of file diff --git a/src/controllers/write/categories.js b/src/controllers/write/categories.js index 3a0b6ae0f7..8a2a002713 100644 --- a/src/controllers/write/categories.js +++ b/src/controllers/write/categories.js @@ -106,9 +106,13 @@ Categories.setModerator = async (req, res) => { helpers.formatApiResponse(200, res, privilegeSet); }; -Categories.follow = async (req, res) => { +Categories.follow = async (req, res, next) => { const { actor } = req.body; - const id = req.params.cid; + const id = parseInt(req.params.cid, 10); + + if (!id) { // disallow cid 0 + return next(); + } await api.activitypub.follow(req, { type: 'cid', @@ -116,12 +120,16 @@ Categories.follow = async (req, res) => { actor, }); - res.sendStatus(200); + helpers.formatApiResponse(200, res, {}); }; -Categories.unfollow = async (req, res) => { +Categories.unfollow = async (req, res, next) => { const { actor } = req.body; - const id = req.params.cid; + const id = parseInt(req.params.cid, 10); + + if (!id) { // disallow cid 0 + return next(); + } await api.activitypub.unfollow(req, { type: 'cid', @@ -129,5 +137,5 @@ Categories.unfollow = async (req, res) => { actor, }); - res.sendStatus(200); + helpers.formatApiResponse(200, res, {}); }; diff --git a/src/routes/write/categories.js b/src/routes/write/categories.js index 0ce47a5073..066e75bb96 100644 --- a/src/routes/write/categories.js +++ b/src/routes/write/categories.js @@ -31,8 +31,8 @@ module.exports = function () { 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); - setupApiRoute(router, 'put', '/:cid/follow', [...middlewares, middleware.admin.checkPrivileges, middleware.assert.category], controllers.write.categories.follow); - setupApiRoute(router, 'delete', '/:cid/follow', [...middlewares, middleware.admin.checkPrivileges, middleware.assert.category], controllers.write.categories.unfollow); + setupApiRoute(router, 'put', '/:cid/follow', [...middlewares, middleware.activitypub.enabled, middleware.admin.checkPrivileges, middleware.assert.category], controllers.write.categories.follow); + setupApiRoute(router, 'delete', '/:cid/follow', [...middlewares, middleware.activitypub.enabled, middleware.admin.checkPrivileges, middleware.assert.category], controllers.write.categories.unfollow); return router; };