mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: topic delete/restore/purge/(un)pin/(un)lock
This commit is contained in:
@@ -534,6 +534,135 @@ paths:
|
||||
$ref: '#/components/schemas/Status'
|
||||
response:
|
||||
$ref: components/schemas/PostsObject.yaml#/PostsObject
|
||||
delete:
|
||||
tags:
|
||||
- topics
|
||||
summary: Delete a topic
|
||||
description: This operation purges a topic and all of its posts (careful, there is no confirmation!)
|
||||
responses:
|
||||
'200':
|
||||
description: Topic successfully purged
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
/topics/{tid}/state:
|
||||
delete:
|
||||
tags:
|
||||
- topics
|
||||
summary: Delete a topic
|
||||
description: This operation deletes an existing topic.
|
||||
responses:
|
||||
'200':
|
||||
description: Topic successfully deleted
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
put:
|
||||
tags:
|
||||
- topics
|
||||
summary: Restore a topic
|
||||
description: This operation restores a topic.
|
||||
responses:
|
||||
'200':
|
||||
description: Topic successfully restored
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
/topics/{tid}/lock:
|
||||
delete:
|
||||
tags:
|
||||
- topics
|
||||
summary: Lock a topic
|
||||
description: This operation locks an existing topic.
|
||||
responses:
|
||||
'200':
|
||||
description: Topic successfully locked
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
put:
|
||||
tags:
|
||||
- topics
|
||||
summary: Unlock a topic
|
||||
description: This operation unlocks a topic.
|
||||
responses:
|
||||
'200':
|
||||
description: Topic successfully unlocked
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
/topics/{tid}/state:
|
||||
delete:
|
||||
tags:
|
||||
- topics
|
||||
summary: Pin a topic
|
||||
description: This operation pins an existing topic.
|
||||
responses:
|
||||
'200':
|
||||
description: Topic successfully pinned
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
put:
|
||||
tags:
|
||||
- topics
|
||||
summary: Unpin a topic
|
||||
description: This operation unpins a topic.
|
||||
responses:
|
||||
'200':
|
||||
description: Topic successfully unpinned
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
components:
|
||||
schemas:
|
||||
Status:
|
||||
|
||||
@@ -5,7 +5,8 @@ define('forum/topic/threadTools', [
|
||||
'components',
|
||||
'translator',
|
||||
'handleBack',
|
||||
], function (components, translator, handleBack) {
|
||||
'api',
|
||||
], function (components, translator, handleBack, api) {
|
||||
var ThreadTools = {};
|
||||
|
||||
ThreadTools.init = function (tid, topicContainer) {
|
||||
@@ -27,22 +28,22 @@ define('forum/topic/threadTools', [
|
||||
});
|
||||
|
||||
topicContainer.on('click', '[component="topic/lock"]', function () {
|
||||
socket.emit('topics.lock', { tids: [tid], cid: ajaxify.data.cid });
|
||||
api.put(`/topics/${tid}/lock`);
|
||||
return false;
|
||||
});
|
||||
|
||||
topicContainer.on('click', '[component="topic/unlock"]', function () {
|
||||
socket.emit('topics.unlock', { tids: [tid], cid: ajaxify.data.cid });
|
||||
api.del(`/topics/${tid}/lock`);
|
||||
return false;
|
||||
});
|
||||
|
||||
topicContainer.on('click', '[component="topic/pin"]', function () {
|
||||
socket.emit('topics.pin', { tids: [tid], cid: ajaxify.data.cid });
|
||||
api.put(`/topics/${tid}/pin`);
|
||||
return false;
|
||||
});
|
||||
|
||||
topicContainer.on('click', '[component="topic/unpin"]', function () {
|
||||
socket.emit('topics.unpin', { tids: [tid], cid: ajaxify.data.cid });
|
||||
api.del(`/topics/${tid}/pin`);
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -176,11 +177,9 @@ define('forum/topic/threadTools', [
|
||||
return;
|
||||
}
|
||||
|
||||
socket.emit('topics.' + command, { tids: [tid], cid: ajaxify.data.cid }, function (err) {
|
||||
if (err) {
|
||||
app.alertError(err.message);
|
||||
}
|
||||
});
|
||||
const method = command === 'restore' ? 'put' : 'del';
|
||||
const suffix = command !== 'purge' ? '/state' : '';
|
||||
api[method](`/topics/${tid}${suffix}`, undefined, undefined, err => app.alertError(err.status.message));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ const topics = require('../../topics');
|
||||
const posts = require('../../posts');
|
||||
const user = require('../../user');
|
||||
const meta = require('../../meta');
|
||||
const events = require('../../events');
|
||||
const privileges = require('../../privileges');
|
||||
|
||||
const helpers = require('../helpers');
|
||||
const socketHelpers = require('../../socket.io/helpers');
|
||||
@@ -71,3 +73,86 @@ Topics.reply = async (req, res) => {
|
||||
user.updateOnlineUsers(req.user.uid);
|
||||
socketHelpers.notifyNew(req.user.uid, 'newPost', result);
|
||||
};
|
||||
|
||||
Topics.delete = async (req, res) => {
|
||||
await doTopicAction('delete', 'event:topic_deleted', req, {
|
||||
tids: [req.params.tid],
|
||||
});
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
Topics.restore = async (req, res) => {
|
||||
await doTopicAction('restore', 'event:topic_restored', req, {
|
||||
tids: [req.params.tid],
|
||||
});
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
Topics.purge = async (req, res) => {
|
||||
await doTopicAction('purge', 'event:topic_purged', req, {
|
||||
tids: [req.params.tid],
|
||||
});
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
Topics.pin = async (req, res) => {
|
||||
await doTopicAction('pin', 'event:topic_pinned', req, {
|
||||
tids: [req.params.tid],
|
||||
});
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
Topics.unpin = async (req, res) => {
|
||||
await doTopicAction('unpin', 'event:topic_unpinned', req, {
|
||||
tids: [req.params.tid],
|
||||
});
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
Topics.lock = async (req, res) => {
|
||||
await doTopicAction('lock', 'event:topic_locked', req, {
|
||||
tids: [req.params.tid],
|
||||
});
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
Topics.unlock = async (req, res) => {
|
||||
await doTopicAction('unlock', 'event:topic_unlocked', req, {
|
||||
tids: [req.params.tid],
|
||||
});
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
async function doTopicAction(action, event, socket, { tids }) {
|
||||
if (!Array.isArray(tids)) {
|
||||
throw new Error('[[error:invalid-tid]]');
|
||||
}
|
||||
|
||||
if (typeof topics.tools[action] !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
const uids = await user.getUidsFromSet('users:online', 0, -1);
|
||||
|
||||
await Promise.all(tids.map(async function (tid) {
|
||||
const title = await topics.getTopicField(tid, 'title');
|
||||
const data = await topics.tools[action](tid, socket.uid);
|
||||
const notifyUids = await privileges.categories.filterUids('topics:read', data.cid, uids);
|
||||
socketHelpers.emitToTopicAndCategory(event, data, notifyUids);
|
||||
await logTopicAction(action, socket, tid, title);
|
||||
}));
|
||||
}
|
||||
|
||||
async function logTopicAction(action, req, tid, title) {
|
||||
var actionsToLog = ['delete', 'restore', 'purge'];
|
||||
if (!actionsToLog.includes(action)) {
|
||||
return;
|
||||
}
|
||||
await events.log({
|
||||
type: 'topic-' + action,
|
||||
uid: req.uid,
|
||||
ip: req.ip,
|
||||
tid: tid,
|
||||
title: String(title),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,50 +12,17 @@ module.exports = function () {
|
||||
|
||||
setupApiRoute(router, '/', middleware, [...middlewares, middleware.checkRequired.bind(null, ['cid', 'title', 'content'])], 'post', controllers.write.topics.create);
|
||||
setupApiRoute(router, '/:tid', middleware, [...middlewares, middleware.checkRequired.bind(null, ['content']), middleware.assertTopic], 'post', controllers.write.topics.reply);
|
||||
// setupApiRoute(router, '/:cid', middleware, [...middlewares, middleware.isAdmin], 'put', controllers.write.categories.update);
|
||||
// setupApiRoute(router, '/:cid', middleware, [...middlewares, middleware.isAdmin], 'delete', controllers.write.categories.delete);
|
||||
setupApiRoute(router, '/:tid', middleware, [...middlewares, middleware.assertTopic], 'delete', controllers.write.topics.purge);
|
||||
|
||||
// app.route('/:tid')
|
||||
// .delete(apiMiddleware.requireUser, apiMiddleware.validateTid, function(req, res) {
|
||||
// Topics.purgePostsAndTopic(req.params.tid, req.params._uid, function(err) {
|
||||
// errorHandler.handle(err, res);
|
||||
// });
|
||||
// })
|
||||
// .put(apiMiddleware.requireUser, function(req, res) {
|
||||
// if (!utils.checkRequired(['pid', 'content'], req, res)) {
|
||||
// return false;
|
||||
// }
|
||||
setupApiRoute(router, '/:tid/state', middleware, [...middlewares, middleware.assertTopic], 'put', controllers.write.topics.restore);
|
||||
setupApiRoute(router, '/:tid/state', middleware, [...middlewares, middleware.assertTopic], 'delete', controllers.write.topics.delete);
|
||||
|
||||
// var payload = {
|
||||
// uid: req.user.uid,
|
||||
// pid: req.body.pid,
|
||||
// content: req.body.content,
|
||||
// options: {}
|
||||
// };
|
||||
// console.log(payload);
|
||||
setupApiRoute(router, '/:tid/pin', middleware, [...middlewares, middleware.assertTopic], 'put', controllers.write.topics.pin);
|
||||
setupApiRoute(router, '/:tid/pin', middleware, [...middlewares, middleware.assertTopic], 'delete', controllers.write.topics.unpin);
|
||||
|
||||
// // Maybe a "set if available" utils method may come in handy
|
||||
// if (req.body.handle) { payload.handle = req.body.handle; }
|
||||
// if (req.body.title) { payload.title = req.body.title; }
|
||||
// if (req.body.topic_thumb) { payload.options.topic_thumb = req.body.topic_thumb; }
|
||||
// if (req.body.tags) { payload.options.tags = req.body.tags; }
|
||||
setupApiRoute(router, '/:tid/lock', middleware, [...middlewares, middleware.assertTopic], 'put', controllers.write.topics.lock);
|
||||
setupApiRoute(router, '/:tid/lock', middleware, [...middlewares, middleware.assertTopic], 'delete', controllers.write.topics.unlock);
|
||||
|
||||
// Posts.edit(payload, function(err, returnData) {
|
||||
// errorHandler.handle(err, res, returnData);
|
||||
// });
|
||||
// });
|
||||
|
||||
// app.route('/:tid/state')
|
||||
// .put(apiMiddleware.requireUser, apiMiddleware.validateTid, function (req, res) {
|
||||
// Topics.restore(req.params.tid, req.params._uid, function (err) {
|
||||
// errorHandler.handle(err, res);
|
||||
// });
|
||||
// })
|
||||
// .delete(apiMiddleware.requireUser, apiMiddleware.validateTid, function (req, res) {
|
||||
// Topics.delete(req.params.tid, req.params._uid, function (err) {
|
||||
// errorHandler.handle(err, res);
|
||||
// });
|
||||
// });
|
||||
|
||||
// app.route('/:tid/follow')
|
||||
// .put(apiMiddleware.requireUser, apiMiddleware.validateTid, function(req, res) {
|
||||
@@ -85,17 +52,5 @@ module.exports = function () {
|
||||
// });
|
||||
// });
|
||||
|
||||
// app.route('/:tid/pin')
|
||||
// .put(apiMiddleware.requireUser, apiMiddleware.validateTid, function(req, res) {
|
||||
// Topics.tools.pin(req.params.tid, req.user.uid, function(err) {
|
||||
// errorHandler.handle(err, res);
|
||||
// });
|
||||
// })
|
||||
// .delete(apiMiddleware.requireUser, apiMiddleware.validateTid, function(req, res) {
|
||||
// Topics.tools.unpin(req.params.tid, req.user.uid, function(err) {
|
||||
// errorHandler.handle(err, res);
|
||||
// });
|
||||
// });
|
||||
|
||||
return router;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ const events = require('../../events');
|
||||
const privileges = require('../../privileges');
|
||||
const plugins = require('../../plugins');
|
||||
const socketHelpers = require('../helpers');
|
||||
const sockets = require('..');
|
||||
|
||||
module.exports = function (SocketTopics) {
|
||||
SocketTopics.loadTopicTools = async function (socket, data) {
|
||||
@@ -34,30 +35,37 @@ module.exports = function (SocketTopics) {
|
||||
};
|
||||
|
||||
SocketTopics.delete = async function (socket, data) {
|
||||
sockets.warnDeprecated(socket, 'DELETE /api/v1/topics/state');
|
||||
await SocketTopics.doTopicAction('delete', 'event:topic_deleted', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.restore = async function (socket, data) {
|
||||
sockets.warnDeprecated(socket, 'PUT /api/v1/topics/state');
|
||||
await SocketTopics.doTopicAction('restore', 'event:topic_restored', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.purge = async function (socket, data) {
|
||||
sockets.warnDeprecated(socket, 'DELETE /api/v1/topics');
|
||||
await SocketTopics.doTopicAction('purge', 'event:topic_purged', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.lock = async function (socket, data) {
|
||||
sockets.warnDeprecated(socket, 'PUT /api/v1/topics/lock');
|
||||
await SocketTopics.doTopicAction('lock', 'event:topic_locked', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.unlock = async function (socket, data) {
|
||||
sockets.warnDeprecated(socket, 'DELETE /api/v1/topics/lock');
|
||||
await SocketTopics.doTopicAction('unlock', 'event:topic_unlocked', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.pin = async function (socket, data) {
|
||||
sockets.warnDeprecated(socket, 'PUT /api/v1/topics/pin');
|
||||
await SocketTopics.doTopicAction('pin', 'event:topic_pinned', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.unpin = async function (socket, data) {
|
||||
sockets.warnDeprecated(socket, 'DELETE /api/v1/topics/pin');
|
||||
await SocketTopics.doTopicAction('unpin', 'event:topic_unpinned', socket, data);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user