mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
refactor: generate a topic id when asserting a new topic
This commit is contained in:
@@ -73,14 +73,17 @@ Notes.getParentChain = async (uid, input) => {
|
|||||||
return chain;
|
return chain;
|
||||||
};
|
};
|
||||||
|
|
||||||
Notes.assertParentChain = async (chain) => {
|
Notes.assertParentChain = async (chain, tid) => {
|
||||||
const data = [];
|
const data = [];
|
||||||
chain.reduce((child, parent) => {
|
chain.reduce((child, parent) => {
|
||||||
data.push([`pid:${parent.pid}:replies`, child.timestamp, child.pid]);
|
data.push([`pid:${parent.pid}:replies`, child.timestamp, child.pid]);
|
||||||
return parent;
|
return parent;
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.sortedSetAddBulk(data);
|
await Promise.all([
|
||||||
|
db.sortedSetAddBulk(data),
|
||||||
|
db.setObjectBulk(chain.map(post => [`post:${post.pid}`, { tid }])),
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
Notes.assertTopic = async (uid, id) => {
|
Notes.assertTopic = async (uid, id) => {
|
||||||
@@ -92,22 +95,22 @@ Notes.assertTopic = async (uid, id) => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const chain = Array.from(await Notes.getParentChain(uid, id));
|
const chain = Array.from(await Notes.getParentChain(uid, id));
|
||||||
const { pid: tid, uid: authorId, timestamp, name, content } = chain[chain.length - 1];
|
let { pid: mainPid, tid, uid: authorId, timestamp, name, content } = chain[chain.length - 1];
|
||||||
|
|
||||||
const members = await db.isSortedSetMembers(`tidRemote:${tid}:posts`, chain.map(p => p.pid));
|
const members = await db.isSortedSetMembers(`tidRemote:${tid}:posts`, chain.map(p => p.pid));
|
||||||
if (members.every(Boolean)) {
|
if (tid && members.every(Boolean)) {
|
||||||
// All cached, return early.
|
// All cached, return early.
|
||||||
winston.info('[notes/assertTopic] No new notes to process.');
|
winston.info('[notes/assertTopic] No new notes to process.');
|
||||||
return tid;
|
return tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
let title = name || utils.stripHTMLTags(content);
|
tid = tid || utils.generateUUID();
|
||||||
if (title.length > 256) {
|
|
||||||
title = `${title.slice(0, 256)}...`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cid = await topics.getTopicField(tid, 'cid');
|
const cid = await topics.getTopicField(tid, 'cid');
|
||||||
|
|
||||||
|
let title = name || utils.decodeHTMLEntities(utils.stripHTMLTags(content));
|
||||||
|
if (title.length > 64) {
|
||||||
|
title = `${title.slice(0, 64)}...`;
|
||||||
|
}
|
||||||
|
|
||||||
const unprocessed = chain.filter((p, idx) => !members[idx]);
|
const unprocessed = chain.filter((p, idx) => !members[idx]);
|
||||||
winston.info(`[notes/assertTopic] ${unprocessed.length} new note(s) found.`);
|
winston.info(`[notes/assertTopic] ${unprocessed.length} new note(s) found.`);
|
||||||
|
|
||||||
@@ -121,16 +124,16 @@ Notes.assertTopic = async (uid, id) => {
|
|||||||
tid,
|
tid,
|
||||||
uid: authorId,
|
uid: authorId,
|
||||||
cid: cid || -1,
|
cid: cid || -1,
|
||||||
mainPid: tid,
|
mainPid,
|
||||||
title,
|
title,
|
||||||
slug: `remote?resource=${encodeURIComponent(tid)}`,
|
slug: `../world/${tid}`,
|
||||||
timestamp,
|
timestamp,
|
||||||
}),
|
}),
|
||||||
db.sortedSetAdd(`tidRemote:${tid}:posts`, timestamps, ids),
|
db.sortedSetAdd(`tidRemote:${tid}:posts`, timestamps, ids),
|
||||||
Notes.assert(uid, unprocessed),
|
Notes.assert(uid, unprocessed),
|
||||||
]);
|
]);
|
||||||
await Promise.all([ // must be done after .assert()
|
await Promise.all([ // must be done after .assert()
|
||||||
Notes.assertParentChain(chain),
|
Notes.assertParentChain(chain, tid),
|
||||||
Notes.updateTopicCounts(tid),
|
Notes.updateTopicCounts(tid),
|
||||||
topics.updateLastPostTimeFromLastPid(tid),
|
topics.updateLastPostTimeFromLastPid(tid),
|
||||||
topics.updateTeaser(tid),
|
topics.updateTeaser(tid),
|
||||||
|
|||||||
@@ -44,14 +44,13 @@ controller.get = async function (req, res, next) {
|
|||||||
* Ideally we would use the existing topicsController.get...
|
* Ideally we would use the existing topicsController.get...
|
||||||
* this controller may be a stopgap towards that end goal.
|
* this controller may be a stopgap towards that end goal.
|
||||||
*/
|
*/
|
||||||
const pid = await notes.resolveId(req.uid, req.query.resource);
|
// const pid = await notes.resolveId(req.uid, req.query.resource);
|
||||||
if (pid !== req.query.resource) {
|
// if (pid !== req.query.resource) {
|
||||||
return helpers.redirect(res, `/topic/remote?resource=${pid}`, true);
|
// return helpers.redirect(res, `/topic/remote?resource=${pid}`, true);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const tid = await notes.assertTopic(req.uid, req.query.resource);
|
const tid = req.params.topic_id;
|
||||||
|
let postIndex = parseInt(req.params.post_index, 10) || 1;
|
||||||
let postIndex = Math.max(1, await db.sortedSetRank(`tidRemote:${tid}:posts`, req.query.resource));
|
|
||||||
const [
|
const [
|
||||||
userPrivileges,
|
userPrivileges,
|
||||||
settings,
|
settings,
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ function modifyPost(post, fields) {
|
|||||||
if (activitypub.helpers.isUri(post.pid)) {
|
if (activitypub.helpers.isUri(post.pid)) {
|
||||||
intFields.splice(intFields.indexOf('pid'), 1);
|
intFields.splice(intFields.indexOf('pid'), 1);
|
||||||
intFields.splice(intFields.indexOf('uid'), 1);
|
intFields.splice(intFields.indexOf('uid'), 1);
|
||||||
|
intFields.splice(intFields.indexOf('tid'), 1);
|
||||||
}
|
}
|
||||||
db.parseIntFields(post, intFields, fields);
|
db.parseIntFields(post, intFields, fields);
|
||||||
if (post.hasOwnProperty('upvotes') && post.hasOwnProperty('downvotes')) {
|
if (post.hasOwnProperty('upvotes') && post.hasOwnProperty('downvotes')) {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
const helpers = require('./helpers');
|
const helpers = require('./helpers');
|
||||||
|
|
||||||
module.exports = function (app, middleware, controllers) {
|
module.exports = function (app, middleware, controllers) {
|
||||||
helpers.setupPageRoute(app, '/world/:view?', [middleware.activitypub.enabled], controllers.activitypub.topics.list);
|
helpers.setupPageRoute(app, '/world', [middleware.activitypub.enabled], controllers.activitypub.topics.list);
|
||||||
|
helpers.setupPageRoute(app, '/world/:topic_id/:post_index?', [middleware.activitypub.enabled], controllers.activitypub.topics.get);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These controllers only respond if the sender is making an json+activitypub style call (i.e. S2S-only)
|
* These controllers only respond if the sender is making an json+activitypub style call (i.e. S2S-only)
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const validator = require('validator');
|
||||||
|
|
||||||
const topics = require('../../topics');
|
const topics = require('../../topics');
|
||||||
const privileges = require('../../privileges');
|
const privileges = require('../../privileges');
|
||||||
const meta = require('../../meta');
|
const meta = require('../../meta');
|
||||||
const utils = require('../../utils');
|
const utils = require('../../utils');
|
||||||
const social = require('../../social');
|
const social = require('../../social');
|
||||||
const activitypub = require('../../activitypub');
|
|
||||||
|
|
||||||
module.exports = function (SocketTopics) {
|
module.exports = function (SocketTopics) {
|
||||||
SocketTopics.loadMore = async function (socket, data) {
|
SocketTopics.loadMore = async function (socket, data) {
|
||||||
@@ -22,7 +23,7 @@ module.exports = function (SocketTopics) {
|
|||||||
throw new Error('[[error:no-privileges]]');
|
throw new Error('[[error:no-privileges]]');
|
||||||
}
|
}
|
||||||
|
|
||||||
const setPrefix = activitypub.helpers.isUri(data.tid) ? 'tidRemote' : 'tid';
|
const setPrefix = validator.isUUID(String(data.tid)) ? 'tidRemote' : 'tid';
|
||||||
const set = data.topicPostSort === 'most_votes' ? `${setPrefix}:${data.tid}:posts:votes` : `${setPrefix}:${data.tid}:posts`;
|
const set = data.topicPostSort === 'most_votes' ? `${setPrefix}:${data.tid}:posts:votes` : `${setPrefix}:${data.tid}:posts`;
|
||||||
const reverse = data.topicPostSort === 'newest_to_oldest' || data.topicPostSort === 'most_votes';
|
const reverse = data.topicPostSort === 'newest_to_oldest' || data.topicPostSort === 'most_votes';
|
||||||
let start = Math.max(0, parseInt(data.after, 10));
|
let start = Math.max(0, parseInt(data.after, 10));
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ const categories = require('../categories');
|
|||||||
const utils = require('../utils');
|
const utils = require('../utils');
|
||||||
const translator = require('../translator');
|
const translator = require('../translator');
|
||||||
const plugins = require('../plugins');
|
const plugins = require('../plugins');
|
||||||
const activitypub = require('../activitypub');
|
|
||||||
|
|
||||||
const intFields = [
|
const intFields = [
|
||||||
'tid', 'cid', 'uid', 'mainPid', 'postcount',
|
'tid', 'cid', 'uid', 'mainPid', 'postcount',
|
||||||
@@ -27,7 +26,7 @@ module.exports = function (Topics) {
|
|||||||
fields.push('timestamp');
|
fields.push('timestamp');
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = tids.map(tid => `${activitypub.helpers.isUri(tid) ? 'topicRemote' : 'topic'}:${tid}`);
|
const keys = tids.map(tid => `${validator.isUUID(String(tid)) ? 'topicRemote' : 'topic'}:${tid}`);
|
||||||
const topics = await db.getObjects(keys, fields);
|
const topics = await db.getObjects(keys, fields);
|
||||||
const result = await plugins.hooks.fire('filter:topic.getFields', {
|
const result = await plugins.hooks.fire('filter:topic.getFields', {
|
||||||
tids: tids,
|
tids: tids,
|
||||||
@@ -64,12 +63,12 @@ module.exports = function (Topics) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Topics.setTopicField = async function (tid, field, value) {
|
Topics.setTopicField = async function (tid, field, value) {
|
||||||
const setPrefix = activitypub.helpers.isUri(tid) ? 'topicRemote' : 'topic';
|
const setPrefix = validator.isUUID(String(tid)) ? 'topicRemote' : 'topic';
|
||||||
await db.setObjectField(`${setPrefix}:${tid}`, field, value);
|
await db.setObjectField(`${setPrefix}:${tid}`, field, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
Topics.setTopicFields = async function (tid, data) {
|
Topics.setTopicFields = async function (tid, data) {
|
||||||
const setPrefix = activitypub.helpers.isUri(tid) ? 'topicRemote' : 'topic';
|
const setPrefix = validator.isUUID(String(tid)) ? 'topicRemote' : 'topic';
|
||||||
await db.setObject(`${setPrefix}:${tid}`, data);
|
await db.setObject(`${setPrefix}:${tid}`, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -98,7 +97,7 @@ function modifyTopic(topic, fields) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activitypub.helpers.isUri(topic.tid)) {
|
if (validator.isUUID(String(topic.tid))) {
|
||||||
intFields.splice(intFields.indexOf('uid'), 1);
|
intFields.splice(intFields.indexOf('uid'), 1);
|
||||||
intFields.splice(intFields.indexOf('tid'), 1);
|
intFields.splice(intFields.indexOf('tid'), 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ Topics.getTopicsByTids = async function (tids, options) {
|
|||||||
const topics = await Topics.getTopicsData(tids);
|
const topics = await Topics.getTopicsData(tids);
|
||||||
const uids = _.uniq(topics
|
const uids = _.uniq(topics
|
||||||
.map(t => t && t.uid && t.uid.toString())
|
.map(t => t && t.uid && t.uid.toString())
|
||||||
.filter(v => utils.isNumber(v) || activitypub.helpers.isUri(v)));
|
.filter(v => utils.isNumber(v) || validator.isUUID(String(v))));
|
||||||
const cids = _.uniq(topics
|
const cids = _.uniq(topics
|
||||||
.map(t => t && t.cid && t.cid.toString())
|
.map(t => t && t.cid && t.cid.toString())
|
||||||
.filter(v => utils.isNumber(v) || activitypub.helpers.isUri(v)));
|
.filter(v => utils.isNumber(v) || validator.isUUID(String(v))));
|
||||||
const guestTopics = topics.filter(t => t && t.uid === 0);
|
const guestTopics = topics.filter(t => t && t.uid === 0);
|
||||||
|
|
||||||
async function loadGuestHandles() {
|
async function loadGuestHandles() {
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ module.exports = function (Topics) {
|
|||||||
Topics.getLatestUndeletedReply = async function (tid) {
|
Topics.getLatestUndeletedReply = async function (tid) {
|
||||||
let isDeleted = false;
|
let isDeleted = false;
|
||||||
let index = 0;
|
let index = 0;
|
||||||
const setPrefix = activitypub.helpers.isUri(tid) ? 'tidRemote' : 'tid';
|
const setPrefix = validator.isUUID(String(tid)) ? 'tidRemote' : 'tid';
|
||||||
do {
|
do {
|
||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
const pids = await db.getSortedSetRevRange(`${setPrefix}:${tid}:posts`, index, index);
|
const pids = await db.getSortedSetRevRange(`${setPrefix}:${tid}:posts`, index, index);
|
||||||
@@ -312,7 +312,7 @@ module.exports = function (Topics) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function incrementFieldAndUpdateSortedSet(tid, field, by, set) {
|
async function incrementFieldAndUpdateSortedSet(tid, field, by, set) {
|
||||||
const value = await db.incrObjectFieldBy(`${activitypub.helpers.isUri(tid) ? 'topicRemote' : 'topic'}:${tid}`, field, by);
|
const value = await db.incrObjectFieldBy(`${validator.isUUID(String(tid)) ? 'topicRemote' : 'topic'}:${tid}`, field, by);
|
||||||
await db[Array.isArray(set) ? 'sortedSetsAdd' : 'sortedSetAdd'](set, value, tid);
|
await db[Array.isArray(set) ? 'sortedSetsAdd' : 'sortedSetAdd'](set, value, tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const validator = require('validator');
|
||||||
|
|
||||||
const db = require('../database');
|
const db = require('../database');
|
||||||
const plugins = require('../plugins');
|
const plugins = require('../plugins');
|
||||||
const posts = require('../posts');
|
const posts = require('../posts');
|
||||||
const activitypub = require('../activitypub');
|
|
||||||
|
|
||||||
module.exports = function (Topics) {
|
module.exports = function (Topics) {
|
||||||
const terms = {
|
const terms = {
|
||||||
@@ -74,7 +75,7 @@ module.exports = function (Topics) {
|
|||||||
data = await plugins.hooks.fire('filter:topics.updateRecent', { tid: tid, timestamp: timestamp });
|
data = await plugins.hooks.fire('filter:topics.updateRecent', { tid: tid, timestamp: timestamp });
|
||||||
}
|
}
|
||||||
if (data && data.tid && data.timestamp) {
|
if (data && data.tid && data.timestamp) {
|
||||||
const setPrefix = activitypub.helpers.isUri(data.tid) ? 'topicsRemote' : 'topics';
|
const setPrefix = validator.isUUID(String(data.tid)) ? 'topicsRemote' : 'topics';
|
||||||
await db.sortedSetAdd(`${setPrefix}:recent`, data.timestamp, data.tid);
|
await db.sortedSetAdd(`${setPrefix}:recent`, data.timestamp, data.tid);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user