2020-05-01 15:58:01 -04:00
|
|
|
'use strict';
|
|
|
|
|
|
2020-12-01 10:37:42 -05:00
|
|
|
const validator = require('validator');
|
|
|
|
|
|
2020-10-16 10:34:37 -04:00
|
|
|
const api = require('../../api');
|
2020-05-01 15:58:01 -04:00
|
|
|
const topics = require('../../topics');
|
2020-12-03 15:04:23 -05:00
|
|
|
const privileges = require('../../privileges');
|
2020-05-01 15:58:01 -04:00
|
|
|
|
|
|
|
|
const helpers = require('../helpers');
|
2020-12-09 16:46:19 -05:00
|
|
|
const middleware = require('../../middleware');
|
2020-12-01 10:37:42 -05:00
|
|
|
const uploadsController = require('../uploads');
|
2020-05-01 15:58:01 -04:00
|
|
|
|
|
|
|
|
const Topics = module.exports;
|
|
|
|
|
|
2020-12-29 10:31:53 -05:00
|
|
|
Topics.get = async (req, res) => {
|
|
|
|
|
helpers.formatApiResponse(200, res, await api.topics.get(req, req.params));
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-01 15:58:01 -04:00
|
|
|
Topics.create = async (req, res) => {
|
2020-10-16 10:34:37 -04:00
|
|
|
const payload = await api.topics.create(req, req.body);
|
|
|
|
|
if (payload.queued) {
|
|
|
|
|
helpers.formatApiResponse(202, res, payload);
|
|
|
|
|
} else {
|
|
|
|
|
helpers.formatApiResponse(200, res, payload);
|
2020-05-01 15:58:01 -04:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.reply = async (req, res) => {
|
2020-10-16 11:01:10 -04:00
|
|
|
const payload = await api.topics.reply(req, { ...req.body, tid: req.params.tid });
|
|
|
|
|
helpers.formatApiResponse(200, res, payload);
|
2020-05-01 15:58:01 -04:00
|
|
|
};
|
2020-10-02 16:35:45 -04:00
|
|
|
|
|
|
|
|
Topics.delete = async (req, res) => {
|
2020-10-16 21:36:59 -04:00
|
|
|
await api.topics.delete(req, { tids: [req.params.tid] });
|
2020-10-02 16:35:45 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.restore = async (req, res) => {
|
2020-10-16 21:36:59 -04:00
|
|
|
await api.topics.restore(req, { tids: [req.params.tid] });
|
2020-10-02 16:35:45 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.purge = async (req, res) => {
|
2020-10-16 21:36:59 -04:00
|
|
|
await api.topics.purge(req, { tids: [req.params.tid] });
|
2020-10-02 16:35:45 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.pin = async (req, res) => {
|
2020-11-20 11:31:14 -05:00
|
|
|
// Pin expiry was not available w/ sockets hence not included in api lib method
|
|
|
|
|
if (req.body.expiry) {
|
2020-12-01 16:25:13 -05:00
|
|
|
await topics.tools.setPinExpiry(req.params.tid, req.body.expiry, req.uid);
|
2020-11-20 11:31:14 -05:00
|
|
|
}
|
2021-11-18 16:42:18 -05:00
|
|
|
await api.topics.pin(req, { tids: [req.params.tid] });
|
2020-11-20 11:31:14 -05:00
|
|
|
|
2020-10-02 16:35:45 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.unpin = async (req, res) => {
|
2020-10-16 21:36:59 -04:00
|
|
|
await api.topics.unpin(req, { tids: [req.params.tid] });
|
2020-10-02 16:35:45 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.lock = async (req, res) => {
|
2020-10-16 21:36:59 -04:00
|
|
|
await api.topics.lock(req, { tids: [req.params.tid] });
|
2020-10-02 16:35:45 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.unlock = async (req, res) => {
|
2020-10-16 21:36:59 -04:00
|
|
|
await api.topics.unlock(req, { tids: [req.params.tid] });
|
2020-10-02 16:35:45 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
2020-10-06 11:36:52 -04:00
|
|
|
Topics.follow = async (req, res) => {
|
2020-10-16 12:30:14 -04:00
|
|
|
await api.topics.follow(req, req.params);
|
2020-10-06 11:36:52 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.ignore = async (req, res) => {
|
2020-10-16 12:30:14 -04:00
|
|
|
await api.topics.ignore(req, req.params);
|
2020-10-06 11:36:52 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.unfollow = async (req, res) => {
|
2020-10-16 12:30:14 -04:00
|
|
|
await api.topics.unfollow(req, req.params);
|
2020-10-06 11:36:52 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
2020-10-06 11:54:25 -04:00
|
|
|
Topics.addTags = async (req, res) => {
|
2021-01-12 17:38:35 -05:00
|
|
|
if (!await privileges.topics.canEdit(req.params.tid, req.user.uid)) {
|
|
|
|
|
return helpers.formatApiResponse(403, res);
|
|
|
|
|
}
|
2021-07-12 19:25:04 -04:00
|
|
|
const cid = await topics.getTopicField(req.params.tid, 'cid');
|
|
|
|
|
await topics.validateTags(req.body.tags, cid, req.user.uid, req.params.tid);
|
|
|
|
|
const tags = await topics.filterTags(req.body.tags);
|
2021-01-12 17:38:35 -05:00
|
|
|
|
2021-07-12 19:25:04 -04:00
|
|
|
await topics.addTags(tags, [req.params.tid]);
|
2020-10-06 11:54:25 -04:00
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Topics.deleteTags = async (req, res) => {
|
2021-01-12 17:38:35 -05:00
|
|
|
if (!await privileges.topics.canEdit(req.params.tid, req.user.uid)) {
|
|
|
|
|
return helpers.formatApiResponse(403, res);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-06 11:54:25 -04:00
|
|
|
await topics.deleteTopicTags(req.params.tid);
|
|
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
2020-12-01 10:37:42 -05:00
|
|
|
|
2020-12-03 15:04:23 -05:00
|
|
|
Topics.getThumbs = async (req, res) => {
|
2021-11-18 16:42:18 -05:00
|
|
|
if (isFinite(req.params.tid)) { // post_uuids can be passed in occasionally, in that case no checks are necessary
|
2021-01-17 15:43:21 -05:00
|
|
|
const [exists, canRead] = await Promise.all([
|
|
|
|
|
topics.exists(req.params.tid),
|
|
|
|
|
privileges.topics.can('topics:read', req.params.tid, req.uid),
|
|
|
|
|
]);
|
|
|
|
|
if (!exists || !canRead) {
|
|
|
|
|
return helpers.formatApiResponse(403, res);
|
|
|
|
|
}
|
2021-01-12 17:38:35 -05:00
|
|
|
}
|
|
|
|
|
|
2020-12-03 15:04:23 -05:00
|
|
|
helpers.formatApiResponse(200, res, await topics.thumbs.get(req.params.tid));
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-04 16:42:39 -05:00
|
|
|
Topics.addThumb = async (req, res) => {
|
2020-12-04 09:37:50 -05:00
|
|
|
await checkThumbPrivileges({ tid: req.params.tid, uid: req.user.uid, res });
|
2020-12-03 16:48:57 -05:00
|
|
|
if (res.headersSent) {
|
|
|
|
|
return;
|
2020-12-03 15:04:23 -05:00
|
|
|
}
|
|
|
|
|
|
2021-11-18 16:42:18 -05:00
|
|
|
const files = await uploadsController.uploadThumb(req, res); // response is handled here
|
2020-12-01 10:37:42 -05:00
|
|
|
|
|
|
|
|
// Add uploaded files to topic zset
|
2020-12-04 11:47:22 -05:00
|
|
|
if (files && files.length) {
|
|
|
|
|
await Promise.all(files.map(async (fileObj) => {
|
2020-12-09 15:47:58 -05:00
|
|
|
await topics.thumbs.associate({
|
|
|
|
|
id: req.params.tid,
|
2021-02-12 17:11:32 -05:00
|
|
|
path: fileObj.path || fileObj.url,
|
2020-12-09 15:47:58 -05:00
|
|
|
});
|
2020-12-04 11:47:22 -05:00
|
|
|
}));
|
|
|
|
|
}
|
2020-12-01 10:37:42 -05:00
|
|
|
};
|
|
|
|
|
|
2020-12-04 09:37:50 -05:00
|
|
|
Topics.migrateThumbs = async (req, res) => {
|
|
|
|
|
await Promise.all([
|
|
|
|
|
checkThumbPrivileges({ tid: req.params.tid, uid: req.user.uid, res }),
|
|
|
|
|
checkThumbPrivileges({ tid: req.body.tid, uid: req.user.uid, res }),
|
|
|
|
|
]);
|
|
|
|
|
if (res.headersSent) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await topics.thumbs.migrate(req.params.tid, req.body.tid);
|
|
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-01 10:37:42 -05:00
|
|
|
Topics.deleteThumb = async (req, res) => {
|
2020-12-09 15:47:58 -05:00
|
|
|
if (!req.body.path.startsWith('http')) {
|
2021-02-04 00:01:39 -07:00
|
|
|
await middleware.assert.path(req, res, () => {});
|
2020-12-09 15:47:58 -05:00
|
|
|
if (res.headersSent) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-04 09:37:50 -05:00
|
|
|
await checkThumbPrivileges({ tid: req.params.tid, uid: req.user.uid, res });
|
2020-12-03 16:48:57 -05:00
|
|
|
if (res.headersSent) {
|
|
|
|
|
return;
|
2020-12-03 15:04:23 -05:00
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:50:30 -05:00
|
|
|
await topics.thumbs.delete(req.params.tid, req.body.path);
|
2020-12-01 10:37:42 -05:00
|
|
|
helpers.formatApiResponse(200, res, await topics.thumbs.get(req.params.tid));
|
|
|
|
|
};
|
2020-12-03 16:48:57 -05:00
|
|
|
|
2021-02-16 11:54:04 -05:00
|
|
|
Topics.reorderThumbs = async (req, res) => {
|
|
|
|
|
await checkThumbPrivileges({ tid: req.params.tid, uid: req.user.uid, res });
|
|
|
|
|
if (res.headersSent) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const exists = await topics.thumbs.exists(req.params.tid, req.body.path);
|
|
|
|
|
if (!exists) {
|
|
|
|
|
return helpers.formatApiResponse(404, res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await topics.thumbs.associate({
|
|
|
|
|
id: req.params.tid,
|
|
|
|
|
path: req.body.path,
|
|
|
|
|
score: req.body.order,
|
|
|
|
|
});
|
|
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-04 09:37:50 -05:00
|
|
|
async function checkThumbPrivileges({ tid, uid, res }) {
|
2021-02-04 02:07:29 -07:00
|
|
|
// req.params.tid could be either a tid (pushing a new thumb to an existing topic)
|
|
|
|
|
// or a post UUID (a new topic being composed)
|
2020-12-04 09:37:50 -05:00
|
|
|
const isUUID = validator.isUUID(tid);
|
2020-12-03 16:48:57 -05:00
|
|
|
|
|
|
|
|
// Sanity-check the tid if it's strictly not a uuid
|
2020-12-04 09:37:50 -05:00
|
|
|
if (!isUUID && (isNaN(parseInt(tid, 10)) || !await topics.exists(tid))) {
|
2020-12-03 16:48:57 -05:00
|
|
|
return helpers.formatApiResponse(404, res, new Error('[[error:no-topic]]'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// While drafts are not protected, tids are
|
2020-12-04 09:37:50 -05:00
|
|
|
if (!isUUID && !await privileges.topics.canEdit(tid, uid)) {
|
2020-12-03 16:48:57 -05:00
|
|
|
return helpers.formatApiResponse(403, res, new Error('[[error:no-privileges]]'));
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-13 10:09:17 -05:00
|
|
|
|
|
|
|
|
Topics.getEvents = async (req, res) => {
|
|
|
|
|
if (!await privileges.topics.can('topics:read', req.params.tid, req.uid)) {
|
|
|
|
|
return helpers.formatApiResponse(403, res);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-17 23:34:01 -05:00
|
|
|
helpers.formatApiResponse(200, res, await topics.events.get(req.params.tid, req.uid));
|
2021-01-13 10:09:17 -05:00
|
|
|
};
|
2021-08-10 19:39:51 -04:00
|
|
|
|
|
|
|
|
Topics.deleteEvent = async (req, res) => {
|
|
|
|
|
if (!await privileges.topics.isAdminOrMod(req.params.tid, req.uid)) {
|
|
|
|
|
return helpers.formatApiResponse(403, res);
|
|
|
|
|
}
|
|
|
|
|
await topics.events.purge(req.params.tid, [req.params.eventId]);
|
|
|
|
|
helpers.formatApiResponse(200, res);
|
|
|
|
|
};
|