From 966c4117ecac1dae2c8bca43c761939409ce3259 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 18 Jan 2021 15:31:14 -0500 Subject: [PATCH] refactor(api): post move to write API --- public/openapi/write.yaml | 2 ++ public/openapi/write/posts/pid/move.yaml | 36 +++++++++++++++++++ public/src/client/topic/move-post.js | 14 ++++---- src/api/posts.js | 22 ++++++++++++ src/controllers/write/posts.js | 8 +++++ src/middleware/assert.js | 2 +- src/routes/write/posts.js | 2 ++ src/socket.io/posts/move.js | 44 +++++------------------- test/api.js | 6 ++++ 9 files changed, 93 insertions(+), 43 deletions(-) create mode 100644 public/openapi/write/posts/pid/move.yaml diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml index 628f21836c..c1ea408afa 100644 --- a/public/openapi/write.yaml +++ b/public/openapi/write.yaml @@ -104,6 +104,8 @@ paths: $ref: 'write/posts/pid.yaml' /posts/{pid}/state: $ref: 'write/posts/pid/state.yaml' + /posts/{pid}/move: + $ref: 'write/posts/pid/move.yaml' /posts/{pid}/vote: $ref: 'write/posts/pid/vote.yaml' /posts/{pid}/bookmark: diff --git a/public/openapi/write/posts/pid/move.yaml b/public/openapi/write/posts/pid/move.yaml new file mode 100644 index 0000000000..7198554ffb --- /dev/null +++ b/public/openapi/write/posts/pid/move.yaml @@ -0,0 +1,36 @@ +put: + tags: + - posts + summary: move a post + description: This operation moves a post to a different topic. + parameters: + - in: path + name: pid + schema: + type: number + required: true + description: a valid post id + example: 5 + requestBody: + content: + application/json: + schema: + type: object + properties: + tid: + type: number + description: a valid topic id + example: 4 + responses: + '200': + description: Post successfully moved + 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/public/src/client/topic/move-post.js b/public/src/client/topic/move-post.js index 16eb4590fb..8a5e68fe32 100644 --- a/public/src/client/topic/move-post.js +++ b/public/src/client/topic/move-post.js @@ -2,8 +2,8 @@ define('forum/topic/move-post', [ - 'components', 'postSelect', 'translator', 'alerts', -], function (components, postSelect, translator, alerts) { + 'components', 'postSelect', 'translator', 'alerts', 'api', +], function (components, postSelect, translator, alerts, api) { var MovePost = {}; var moveModal; @@ -100,10 +100,10 @@ define('forum/topic/move-post', [ if (!ajaxify.data.template.topic || !data.tid) { return; } - socket.emit('posts.movePosts', { pids: data.pids, tid: data.tid }, function (err) { - if (err) { - return app.alertError(err.message); - } + + Promise.all(data.pids.map(pid => api.put(`/posts/${pid}/move`, { + tid: data.tid, + }))).then(() => { data.pids.forEach(function (pid) { components.get('post', 'pid', pid).fadeOut(500, function () { $(this).remove(); @@ -111,7 +111,7 @@ define('forum/topic/move-post', [ }); closeMoveModal(); - }); + }).catch(app.alertError); } function closeMoveModal() { diff --git a/src/api/posts.js b/src/api/posts.js index c1582765e2..301df87a2e 100644 --- a/src/api/posts.js +++ b/src/api/posts.js @@ -13,6 +13,7 @@ const events = require('../events'); const privileges = require('../privileges'); const apiHelpers = require('./helpers'); const websockets = require('../socket.io'); +const socketHelpers = require('../socket.io/helpers'); const postsAPI = module.exports; @@ -195,6 +196,27 @@ async function isMainAndLastPost(pid) { }; } +postsAPI.move = async function (caller, data) { + const canMove = await Promise.all([ + privileges.topics.isAdminOrMod(data.tid, caller.uid), + privileges.posts.canMove(data.pid, caller.uid), + ]); + if (!canMove.every(Boolean)) { + throw new Error('[[error:no-privileges]]'); + } + + await topics.movePostToTopic(caller.uid, data.pid, data.tid); + + const [postDeleted, topicDeleted] = await Promise.all([ + posts.getPostField(data.pid, 'deleted'), + topics.getTopicField(data.tid, 'deleted'), + ]); + + if (!postDeleted && !topicDeleted) { + socketHelpers.sendNotificationToPostOwner(data.pid, caller.uid, 'move', 'notifications:moved_your_post'); + } +}; + postsAPI.upvote = async function (caller, data) { return await apiHelpers.postCommand(caller, 'upvote', 'voted', 'notifications:upvoted_your_post_in', data); }; diff --git a/src/controllers/write/posts.js b/src/controllers/write/posts.js index 197e699c31..8cd094848c 100644 --- a/src/controllers/write/posts.js +++ b/src/controllers/write/posts.js @@ -38,6 +38,14 @@ Posts.delete = async (req, res) => { helpers.formatApiResponse(200, res); }; +Posts.move = async (req, res) => { + await api.posts.move(req, { + pid: req.params.pid, + tid: req.body.tid, + }); + helpers.formatApiResponse(200, res); +}; + async function mock(req) { const tid = await posts.getPostField(req.params.pid, 'tid'); return { pid: req.params.pid, room_id: `topic_${tid}` }; diff --git a/src/middleware/assert.js b/src/middleware/assert.js index 80fd009e7a..6f2617fdcb 100644 --- a/src/middleware/assert.js +++ b/src/middleware/assert.js @@ -46,7 +46,7 @@ Assert.topic = helpers.try(async (req, res, next) => { Assert.post = helpers.try(async (req, res, next) => { if (!await posts.exists(req.params.pid)) { - return controllerHelpers.formatApiResponse(404, res, new Error('[[error:no-topic]]')); + return controllerHelpers.formatApiResponse(404, res, new Error('[[error:no-post]]')); } next(); diff --git a/src/routes/write/posts.js b/src/routes/write/posts.js index c7a68e94c2..d842270e82 100644 --- a/src/routes/write/posts.js +++ b/src/routes/write/posts.js @@ -18,6 +18,8 @@ module.exports = function () { setupApiRoute(router, 'put', '/:pid/state', [...middlewares, middleware.assert.post], controllers.write.posts.restore); setupApiRoute(router, 'delete', '/:pid/state', [...middlewares, middleware.assert.post], controllers.write.posts.delete); + setupApiRoute(router, 'put', '/:pid/move', [...middlewares, middleware.assert.post, middleware.checkRequired.bind(null, ['tid'])], controllers.write.posts.move); + setupApiRoute(router, 'put', '/:pid/vote', [...middlewares, middleware.checkRequired.bind(null, ['delta']), middleware.assert.post], controllers.write.posts.vote); setupApiRoute(router, 'delete', '/:pid/vote', [...middlewares, middleware.assert.post], controllers.write.posts.unvote); diff --git a/src/socket.io/posts/move.js b/src/socket.io/posts/move.js index c1637fad51..d802454b97 100644 --- a/src/socket.io/posts/move.js +++ b/src/socket.io/posts/move.js @@ -1,45 +1,19 @@ 'use strict'; -const privileges = require('../../privileges'); -const topics = require('../../topics'); -const posts = require('../../posts'); -const socketHelpers = require('../helpers'); +const api = require('../../api'); +const sockets = require('..'); module.exports = function (SocketPosts) { SocketPosts.movePost = async function (socket, data) { - await SocketPosts.movePosts(socket, { pids: [data.pid], tid: data.tid }); + sockets.warnDeprecated(socket, 'PUT /api/v3/posts/:pid/move'); + await api.posts.move(socket, data); }; SocketPosts.movePosts = async function (socket, data) { - if (!socket.uid) { - throw new Error('[[error:not-logged-in]]'); - } - - if (!data || !Array.isArray(data.pids) || !data.tid) { - throw new Error('[[error:invalid-data]]'); - } - - const canMove = await privileges.topics.isAdminOrMod(data.tid, socket.uid); - if (!canMove) { - throw new Error('[[error:no-privileges]]'); - } - - for (const pid of data.pids) { - /* eslint-disable no-await-in-loop */ - const canMove = await privileges.posts.canMove(pid, socket.uid); - if (!canMove) { - throw new Error('[[error:no-privileges]]'); - } - await topics.movePostToTopic(socket.uid, pid, data.tid); - - const [postDeleted, topicDeleted] = await Promise.all([ - posts.getPostField(pid, 'deleted'), - topics.getTopicField(data.tid, 'deleted'), - ]); - - if (!postDeleted && !topicDeleted) { - socketHelpers.sendNotificationToPostOwner(pid, socket.uid, 'move', 'notifications:moved_your_post'); - } - } + sockets.warnDeprecated(socket, 'PUT /api/v3/posts/:pid/move'); + await Promise.all(data.pids.map(async pid => api.posts.move(socket, { + tid: data.tid, + pid, + }))); }; }; diff --git a/test/api.js b/test/api.js index 730682a7e9..7401b152ea 100644 --- a/test/api.js +++ b/test/api.js @@ -135,6 +135,12 @@ describe('API', async () => { title: 'Test Topic 2', content: 'Test topic 2 content', }); + await topics.post({ + uid: unprivUid, + cid: testCategory.cid, + title: 'Test Topic 3', + content: 'Test topic 3 content', + }); // Create a sample flag await flags.create('post', 1, unprivUid, 'sample reasons', Date.now());