mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: allow user.search to handle remote handles, beginning of mentions support
This commit is contained in:
@@ -10,8 +10,8 @@
|
||||
window.slugify = factory(XRegExp);
|
||||
}
|
||||
}(function (XRegExp) {
|
||||
const invalidUnicodeChars = XRegExp('[^\\p{L}\\s\\d\\-_]', 'g');
|
||||
const invalidLatinChars = /[^\w\s\d\-_]/g;
|
||||
const invalidUnicodeChars = XRegExp('[^\\p{L}\\s\\d\\-_@.]', 'g');
|
||||
const invalidLatinChars = /[^\w\s\d\-_@.]/g;
|
||||
const trimRegex = /^\s+|\s+$/g;
|
||||
const collapseWhitespace = /\s+/g;
|
||||
const collapseDash = /-+/g;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const winston = require('winston');
|
||||
|
||||
const db = require('../database');
|
||||
const user = require('../user');
|
||||
const utils = require('../utils');
|
||||
|
||||
const activitypub = module.parent.exports;
|
||||
@@ -89,9 +90,33 @@ Actors.assert = async (ids, options = {}) => {
|
||||
bulkSet.push(['followersUrl:uid', Object.fromEntries(followersUrlMap)]);
|
||||
}
|
||||
|
||||
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) => {
|
||||
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 (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}`]);
|
||||
}
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, { remove: [], add: [] });
|
||||
|
||||
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),
|
||||
]);
|
||||
|
||||
return actors.every(Boolean);
|
||||
|
||||
@@ -57,10 +57,16 @@ Helpers.query = async (id) => {
|
||||
({ href: actorUri } = actorUri);
|
||||
}
|
||||
|
||||
const { publicKey } = body;
|
||||
const { subject, publicKey } = body;
|
||||
const payload = { subject, username, hostname, actorUri, publicKey };
|
||||
|
||||
webfingerCache.set(id, { username, hostname, actorUri, publicKey });
|
||||
return { username, hostname, actorUri, publicKey };
|
||||
const claimedId = subject.slice(5);
|
||||
webfingerCache.set(claimedId, payload);
|
||||
if (claimedId !== id) {
|
||||
webfingerCache.set(id, payload);
|
||||
}
|
||||
|
||||
return payload;
|
||||
};
|
||||
|
||||
Helpers.generateKeys = async (type, id) => {
|
||||
|
||||
@@ -9,6 +9,7 @@ const user = require('../user');
|
||||
const categories = require('../categories');
|
||||
const posts = require('../posts');
|
||||
const topics = require('../topics');
|
||||
const plugins = require('../plugins');
|
||||
const utils = require('../utils');
|
||||
|
||||
const activitypub = module.parent.exports;
|
||||
@@ -227,6 +228,20 @@ Mocks.note = async (post) => {
|
||||
}));
|
||||
}
|
||||
|
||||
const mentionsEnabled = await plugins.isActive('nodebb-plugin-mentions');
|
||||
if (mentionsEnabled) {
|
||||
const mentions = require.main.require('nodebb-plugin-mentions');
|
||||
const matches = await mentions.getMatches(post.content);
|
||||
|
||||
if (matches.size) {
|
||||
tag = tag || [];
|
||||
Array.from(matches).map(match => ({
|
||||
type: 'Mention',
|
||||
name: match,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
const object = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id,
|
||||
|
||||
@@ -111,6 +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;
|
||||
|
||||
@@ -7,6 +7,7 @@ const meta = require('../meta');
|
||||
const plugins = require('../plugins');
|
||||
const db = require('../database');
|
||||
const groups = require('../groups');
|
||||
const activitypub = require('../activitypub');
|
||||
const utils = require('../utils');
|
||||
|
||||
module.exports = function (User) {
|
||||
@@ -42,9 +43,21 @@ module.exports = function (User) {
|
||||
} else {
|
||||
const searchMethod = data.findUids || findUids;
|
||||
uids = await searchMethod(query, searchBy, data.hardCap);
|
||||
|
||||
const mapping = {
|
||||
username: 'ap.preferredUsername',
|
||||
fullname: 'ap.name',
|
||||
};
|
||||
if (meta.config.activitypubEnabled && mapping.hasOwnProperty(searchBy)) {
|
||||
uids = uids.concat(await searchMethod(query, mapping[searchBy], data.hardCap));
|
||||
}
|
||||
}
|
||||
|
||||
uids = await filterAndSortUids(uids, data);
|
||||
if (data.hardCap > 0) {
|
||||
uids.length = data.hardCap;
|
||||
}
|
||||
|
||||
const result = await plugins.hooks.fire('filter:users.search', { uids: uids, uid: uid });
|
||||
uids = result.uids;
|
||||
|
||||
@@ -62,7 +75,8 @@ module.exports = function (User) {
|
||||
|
||||
const userData = await User.getUsers(uids, uid);
|
||||
searchResult.timing = (process.elapsedTimeSince(startTime) / 1000).toFixed(2);
|
||||
searchResult.users = userData.filter(user => user && user.uid > 0);
|
||||
searchResult.users = userData.filter(user => (user &&
|
||||
utils.isNumber(user.uid) ? user.uid > 0 : activitypub.helpers.isUri(user.uid)));
|
||||
return searchResult;
|
||||
};
|
||||
|
||||
@@ -78,12 +92,17 @@ module.exports = function (User) {
|
||||
hardCap = hardCap || resultsPerPage * 10;
|
||||
|
||||
const data = await db.getSortedSetRangeByLex(`${searchBy}:sorted`, min, max, 0, hardCap);
|
||||
const uids = data.map(data => data.split(':').pop());
|
||||
// const uids = data.map(data => data.split(':').pop());
|
||||
const uids = data.map((data) => {
|
||||
data = data.split(':');
|
||||
data.shift();
|
||||
return data.join(':');
|
||||
});
|
||||
return uids;
|
||||
}
|
||||
|
||||
async function filterAndSortUids(uids, data) {
|
||||
uids = uids.filter(uid => parseInt(uid, 10));
|
||||
uids = uids.filter(uid => parseInt(uid, 10) || activitypub.helpers.isUri(uid));
|
||||
let filters = data.filters || [];
|
||||
filters = Array.isArray(filters) ? filters : [data.filters];
|
||||
const fields = [];
|
||||
|
||||
Reference in New Issue
Block a user