fix: defer federation of new topics when topic is scheduled, tie activitypub api module to global enable toggle

This commit is contained in:
Julian Lam
2024-02-26 15:39:09 -05:00
parent aadac7053a
commit 5f85e70006
4 changed files with 57 additions and 17 deletions

View File

@@ -211,7 +211,7 @@ Mocks.note = async (post) => {
const raw = await posts.getPostField(post.pid, 'content'); const raw = await posts.getPostField(post.pid, 'content');
// todo: post visibility, category privileges integration // todo: post visibility
const to = [activitypub._constants.publicAddress]; const to = [activitypub._constants.publicAddress];
const cc = [`${nconf.get('url')}/uid/${post.user.uid}/followers`]; const cc = [`${nconf.get('url')}/uid/${post.user.uid}/followers`];

View File

@@ -9,14 +9,29 @@
*/ */
const nconf = require('nconf'); const nconf = require('nconf');
const winston = require('winston');
const db = require('../database'); const db = require('../database');
const meta = require('../meta');
const privileges = require('../privileges');
const activitypub = require('../activitypub'); const activitypub = require('../activitypub');
const posts = require('../posts'); const posts = require('../posts');
const activitypubApi = module.exports; const activitypubApi = module.exports;
activitypubApi.follow = async (caller, { uid } = {}) => { function noop() {}
function enabledCheck(next) {
return async function (caller, params) {
if (!meta.config.activitypubEnabled) {
return noop;
}
next(caller, params);
};
}
activitypubApi.follow = enabledCheck(async (caller, { uid } = {}) => {
const result = await activitypub.helpers.query(uid); const result = await activitypub.helpers.query(uid);
if (!result) { if (!result) {
throw new Error('[[error:activitypub.invalid-id]]'); throw new Error('[[error:activitypub.invalid-id]]');
@@ -26,10 +41,10 @@ activitypubApi.follow = async (caller, { uid } = {}) => {
type: 'Follow', type: 'Follow',
object: result.actorUri, object: result.actorUri,
}); });
}; });
// should be .undo.follow // should be .undo.follow
activitypubApi.unfollow = async (caller, { uid }) => { activitypubApi.unfollow = enabledCheck(async (caller, { uid }) => {
const result = await activitypub.helpers.query(uid); const result = await activitypub.helpers.query(uid);
if (!result) { if (!result) {
throw new Error('[[error:activitypub.invalid-id]]'); throw new Error('[[error:activitypub.invalid-id]]');
@@ -48,7 +63,7 @@ activitypubApi.unfollow = async (caller, { uid }) => {
db.sortedSetRemove(`followingRemote:${caller.uid}`, result.actorUri), db.sortedSetRemove(`followingRemote:${caller.uid}`, result.actorUri),
db.decrObjectField(`user:${caller.uid}`, 'followingRemoteCount'), db.decrObjectField(`user:${caller.uid}`, 'followingRemoteCount'),
]); ]);
}; });
activitypubApi.create = {}; activitypubApi.create = {};
@@ -65,12 +80,18 @@ async function buildRecipients(object, uid) {
return { targets }; return { targets };
} }
activitypubApi.create.post = async (caller, { pid }) => { activitypubApi.create.post = enabledCheck(async (caller, { pid }) => {
const post = (await posts.getPostSummaryByPids([pid], caller.uid, { stripTags: false })).pop(); const post = (await posts.getPostSummaryByPids([pid], caller.uid, { stripTags: false })).pop();
if (!post) { if (!post) {
return; return;
} }
const allowed = await privileges.posts.can('topics:read', pid, activitypub._constants.uid);
if (!allowed) {
winston.verbose(`[activitypub/api] Not federating creation of pid ${pid} to the fediverse due to privileges.`);
return;
}
const object = await activitypub.mocks.note(post); const object = await activitypub.mocks.note(post);
const { targets } = await buildRecipients(object, post.user.uid); const { targets } = await buildRecipients(object, post.user.uid);
@@ -82,11 +103,11 @@ activitypubApi.create.post = async (caller, { pid }) => {
}; };
await activitypub.send('uid', caller.uid, Array.from(targets), payload); await activitypub.send('uid', caller.uid, Array.from(targets), payload);
}; });
activitypubApi.update = {}; activitypubApi.update = {};
activitypubApi.update.profile = async (caller, { uid }) => { activitypubApi.update.profile = enabledCheck(async (caller, { uid }) => {
const [object, followers] = await Promise.all([ const [object, followers] = await Promise.all([
activitypub.mocks.actors.user(uid), activitypub.mocks.actors.user(uid),
db.getSortedSetMembers(`followersRemote:${caller.uid}`), db.getSortedSetMembers(`followersRemote:${caller.uid}`),
@@ -98,12 +119,18 @@ activitypubApi.update.profile = async (caller, { uid }) => {
cc: [], cc: [],
object, object,
}); });
}; });
activitypubApi.update.note = async (caller, { post }) => { activitypubApi.update.note = enabledCheck(async (caller, { post }) => {
const object = await activitypub.mocks.note(post); const object = await activitypub.mocks.note(post);
const { targets } = await buildRecipients(object, post.user.uid); const { targets } = await buildRecipients(object, post.user.uid);
const allowed = await privileges.posts.can('topics:read', post.pid, activitypub._constants.uid);
if (!allowed) {
winston.verbose(`[activitypub/api] Not federating update of pid ${post.pid} to the fediverse due to privileges.`);
return;
}
const payload = { const payload = {
type: 'Update', type: 'Update',
to: object.to, to: object.to,
@@ -112,12 +139,12 @@ activitypubApi.update.note = async (caller, { post }) => {
}; };
await activitypub.send('uid', caller.uid, Array.from(targets), payload); await activitypub.send('uid', caller.uid, Array.from(targets), payload);
}; });
activitypubApi.like = {}; activitypubApi.like = {};
activitypubApi.like.note = async (caller, { pid }) => { activitypubApi.like.note = enabledCheck(async (caller, { pid }) => {
if (!activitypub.helpers.isUri(pid)) { if (!activitypub.helpers.isUri(pid)) { // remote only
return; return;
} }
@@ -130,13 +157,13 @@ activitypubApi.like.note = async (caller, { pid }) => {
type: 'Like', type: 'Like',
object: pid, object: pid,
}); });
}; });
activitypubApi.undo = {}; activitypubApi.undo = {};
// activitypubApi.undo.follow = // activitypubApi.undo.follow =
activitypubApi.undo.like = async (caller, { pid }) => { activitypubApi.undo.like = enabledCheck(async (caller, { pid }) => {
if (!activitypub.helpers.isUri(pid)) { if (!activitypub.helpers.isUri(pid)) {
return; return;
} }
@@ -154,4 +181,4 @@ activitypubApi.undo.like = async (caller, { pid }) => {
object: pid, object: pid,
}, },
}); });
}; });

View File

@@ -80,7 +80,10 @@ topicsAPI.create = async function (caller, data) {
socketHelpers.emitToUids('event:new_post', { posts: [result.postData] }, [caller.uid]); socketHelpers.emitToUids('event:new_post', { posts: [result.postData] }, [caller.uid]);
socketHelpers.emitToUids('event:new_topic', result.topicData, [caller.uid]); socketHelpers.emitToUids('event:new_topic', result.topicData, [caller.uid]);
socketHelpers.notifyNew(caller.uid, 'newTopic', { posts: [result.postData], topic: result.topicData }); socketHelpers.notifyNew(caller.uid, 'newTopic', { posts: [result.postData], topic: result.topicData });
if (!isScheduling) {
activitypubApi.create.post(caller, { pid: result.postData.pid }); activitypubApi.create.post(caller, { pid: result.postData.pid });
}
return result.topicData; return result.topicData;
}; };

View File

@@ -10,6 +10,7 @@ const socketHelpers = require('../socket.io/helpers');
const topics = require('./index'); const topics = require('./index');
const groups = require('../groups'); const groups = require('../groups');
const user = require('../user'); const user = require('../user');
const api = require('../api');
const Scheduled = module.exports; const Scheduled = module.exports;
@@ -47,6 +48,7 @@ async function postTids(tids) {
sendNotifications(uids, topicsData), sendNotifications(uids, topicsData),
updateUserLastposttimes(uids, topicsData), updateUserLastposttimes(uids, topicsData),
updateGroupPosts(uids, topicsData), updateGroupPosts(uids, topicsData),
federatePosts(uids, topicsData),
...topicsData.map(topicData => unpin(topicData.tid, topicData)), ...topicsData.map(topicData => unpin(topicData.tid, topicData)),
)); ));
} }
@@ -149,6 +151,14 @@ async function updateGroupPosts(uids, topicsData) {
})); }));
} }
function federatePosts(uids, topicData) {
topicData.forEach(({ mainPid: pid }, idx) => {
const uid = uids[idx];
api.activitypub.create.post({ uid }, { pid });
});
}
async function shiftPostTimes(tid, timestamp) { async function shiftPostTimes(tid, timestamp) {
const pids = (await posts.getPidsFromSet(`tid:${tid}:posts`, 0, -1, false)); const pids = (await posts.getPidsFromSet(`tid:${tid}:posts`, 0, -1, false));
// Leaving other related score values intact, since they reflect post order correctly, and it seems that's good enough // Leaving other related score values intact, since they reflect post order correctly, and it seems that's good enough