mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 11:35:55 +01:00
feat: mentions support
This commit is contained in:
@@ -93,30 +93,39 @@ Actors.assert = async (ids, options = {}) => {
|
||||
const exists = await db.isSortedSetMembers('usersRemote:lastCrawled', profiles.map(p => p.uid));
|
||||
const uidsForCurrent = profiles.map((p, idx) => (exists[idx] ? p.uid : 0));
|
||||
const current = await user.getUsersFields(uidsForCurrent, ['username', 'fullname']);
|
||||
const searchQueries = profiles.reduce((memo, profile, idx) => {
|
||||
const queries = profiles.reduce((memo, profile, idx) => {
|
||||
if (profile) {
|
||||
const { username, fullname } = current[idx];
|
||||
|
||||
if (username !== profile.username) {
|
||||
memo.remove.push(['ap.preferredUsername:sorted', `${username.toLowerCase()}:${profile.uid}`]);
|
||||
memo.add.push(['ap.preferredUsername:sorted', 0, `${profile.username.toLowerCase()}:${profile.uid}`]);
|
||||
if (uidsForCurrent[idx] !== 0) {
|
||||
memo.searchRemove.push(['ap.preferredUsername:sorted', `${username.toLowerCase()}:${profile.uid}`]);
|
||||
memo.handleRemove.push(username.toLowerCase());
|
||||
}
|
||||
|
||||
memo.searchAdd.push(['ap.preferredUsername:sorted', 0, `${profile.username.toLowerCase()}:${profile.uid}`]);
|
||||
memo.handleAdd[profile.username.toLowerCase()] = profile.uid;
|
||||
}
|
||||
|
||||
if (fullname !== profile.fullname) {
|
||||
memo.remove.push(['ap.name:sorted', `${fullname.toLowerCase()}:${profile.uid}`]);
|
||||
memo.add.push(['ap.name:sorted', 0, `${profile.fullname.toLowerCase()}:${profile.uid}`]);
|
||||
if (uidsForCurrent[idx] !== 0) {
|
||||
memo.searchRemove.push(['ap.name:sorted', `${fullname.toLowerCase()}:${profile.uid}`]);
|
||||
}
|
||||
|
||||
memo.searchAdd.push(['ap.name:sorted', 0, `${profile.fullname.toLowerCase()}:${profile.uid}`]);
|
||||
}
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, { remove: [], add: [] });
|
||||
}, { searchRemove: [], searchAdd: [], handleRemove: [], handleAdd: {} });
|
||||
|
||||
await Promise.all([
|
||||
db.setObjectBulk(bulkSet),
|
||||
db.sortedSetAdd('usersRemote:lastCrawled', ids.map((id, idx) => (profiles[idx] ? now : null)).filter(Boolean), ids.filter((id, idx) => profiles[idx])),
|
||||
db.sortedSetRemove('ap.preferredUsername:sorted', searchQueries.remove),
|
||||
db.sortedSetRemoveBulk(searchQueries.remove),
|
||||
db.sortedSetAddBulk(searchQueries.add),
|
||||
db.sortedSetAdd('usersRemote:lastCrawled', profiles.map(p => now), profiles.map(p => p.uid)),
|
||||
db.sortedSetRemoveBulk(queries.searchRemove),
|
||||
db.sortedSetAddBulk(queries.searchAdd),
|
||||
db.deleteObjectFields('handle:uid', queries.handleRemove),
|
||||
db.setObject('handle:uid', queries.handleAdd),
|
||||
]);
|
||||
|
||||
return actors.every(Boolean);
|
||||
|
||||
@@ -235,9 +235,17 @@ Mocks.note = async (post) => {
|
||||
|
||||
if (matches.size) {
|
||||
tag = tag || [];
|
||||
Array.from(matches).map(match => ({
|
||||
tag.push(...Array.from(matches).map(({ id: href, slug: name }) => {
|
||||
if (utils.isNumber(href)) { // local ref
|
||||
href = `${nconf.get('url')}/user/${name.slice(1)}`;
|
||||
name = `${name}@${nconf.get('url_parsed').hostname}`;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'Mention',
|
||||
name: match,
|
||||
href,
|
||||
name,
|
||||
};
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ const privileges = require('../privileges');
|
||||
const user = require('../user');
|
||||
const topics = require('../topics');
|
||||
const posts = require('../posts');
|
||||
const plugins = require('../plugins');
|
||||
const utils = require('../utils');
|
||||
|
||||
const activitypub = module.parent.exports;
|
||||
@@ -59,6 +60,9 @@ Notes.assert = async (uid, input, options = {}) => {
|
||||
delete hash._activitypub;
|
||||
// should call internal method here to create/edit post
|
||||
await db.setObject(key, hash);
|
||||
const post = await posts.getPostData(id);
|
||||
post._activitypub = postData._activitypub;
|
||||
plugins.hooks.fire(`action:post.${(exists && options.update) ? 'edit' : 'save'}`, { post });
|
||||
winston.verbose(`[activitypub/notes.assert] Note ${id} saved.`);
|
||||
}
|
||||
}));
|
||||
@@ -176,17 +180,14 @@ Notes.getParentChain = async (uid, input) => {
|
||||
return chain;
|
||||
};
|
||||
|
||||
Notes.assertParentChain = async (chain, tid) => {
|
||||
Notes.assertParentChain = async (chain) => {
|
||||
const data = [];
|
||||
chain.reduce((child, parent) => {
|
||||
data.push([`pid:${parent.pid}:replies`, child.timestamp, child.pid]);
|
||||
return parent;
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
db.sortedSetAddBulk(data),
|
||||
db.setObjectBulk(chain.map(post => [`post:${post.pid}`, { tid }])),
|
||||
]);
|
||||
await db.sortedSetAddBulk(data);
|
||||
};
|
||||
|
||||
Notes.assertTopic = async (uid, id) => {
|
||||
@@ -238,7 +239,10 @@ Notes.assertTopic = async (uid, id) => {
|
||||
tid = tid || utils.generateUUID();
|
||||
mainPost.tid = tid;
|
||||
|
||||
const unprocessed = chain.filter((p, idx) => !members[idx]);
|
||||
const unprocessed = chain.map((post) => {
|
||||
post.tid = tid; // add tid to post hash
|
||||
return post;
|
||||
}).filter((p, idx) => !members[idx]);
|
||||
winston.verbose(`[notes/assertTopic] ${unprocessed.length} new note(s) found.`);
|
||||
|
||||
const [ids, timestamps] = [
|
||||
@@ -275,7 +279,7 @@ Notes.assertTopic = async (uid, id) => {
|
||||
Notes.assert(uid, unprocessed),
|
||||
]);
|
||||
await Promise.all([ // must be done after .assert()
|
||||
Notes.assertParentChain(chain, tid),
|
||||
Notes.assertParentChain(chain),
|
||||
Notes.updateTopicCounts(tid),
|
||||
Notes.syncUserInboxes(tid),
|
||||
topics.updateLastPostTimeFromLastPid(tid),
|
||||
|
||||
@@ -4,12 +4,14 @@ const querystring = require('querystring');
|
||||
|
||||
const posts = require('../posts');
|
||||
const privileges = require('../privileges');
|
||||
const utils = require('../utils');
|
||||
|
||||
const helpers = require('./helpers');
|
||||
|
||||
const postsController = module.exports;
|
||||
|
||||
postsController.redirectToPost = async function (req, res, next) {
|
||||
const pid = parseInt(req.params.pid, 10);
|
||||
const pid = utils.isNumber(req.params.pid) ? parseInt(req.params.pid, 10) : req.params.pid;
|
||||
if (!pid) {
|
||||
return next();
|
||||
}
|
||||
|
||||
28
src/upgrades/4.0.0/searchable_remote_users.js
Normal file
28
src/upgrades/4.0.0/searchable_remote_users.js
Normal file
@@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
const db = require('../../database');
|
||||
|
||||
module.exports = {
|
||||
name: 'Allow remote user profiles to be searched',
|
||||
// remember, month is zero-indexed (so January is 0, December is 11)
|
||||
timestamp: Date.UTC(2024, 2, 1),
|
||||
method: async () => {
|
||||
const ids = await db.getSortedSetMembers('usersRemote:lastCrawled');
|
||||
const data = await db.getObjectsFields(ids.map(id => `userRemote:${id}`), ['username', 'fullname']);
|
||||
|
||||
const queries = data.reduce((memo, profile, idx) => {
|
||||
if (profile && profile.username && profile.fullname) {
|
||||
memo.zset.push(['ap.preferredUsername:sorted', 0, `${profile.username.toLowerCase()}:${ids[idx]}`]);
|
||||
memo.zset.push(['ap.name:sorted', 0, `${profile.fullname.toLowerCase()}:${ids[idx]}`]);
|
||||
memo.hash[profile.username.toLowerCase()] = ids[idx];
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, { zset: [], hash: {} });
|
||||
|
||||
await Promise.all([
|
||||
db.sortedSetAddBulk(queries.zset),
|
||||
db.setObject('handle:uid', queries.hash),
|
||||
]);
|
||||
},
|
||||
};
|
||||
@@ -111,11 +111,8 @@ User.getUidByUserslug = async function (userslug) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fix this! Forces a remote call, this is bad. Should be done in actors.assert
|
||||
// then mentions. should return actor uri or url or something to parsePost.
|
||||
if (userslug.includes('@')) {
|
||||
const { actorUri } = await activitypub.helpers.query(userslug);
|
||||
return actorUri;
|
||||
return (await db.getObjectField('handle:uid', userslug)) || 0;
|
||||
}
|
||||
|
||||
return await db.sortedSetScore('userslug:uid', userslug);
|
||||
|
||||
Reference in New Issue
Block a user