diff --git a/src/api/activitypub.js b/src/api/activitypub.js index dd0cd4a19f..463c57a4bb 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -223,10 +223,37 @@ activitypubApi.flag = enabledCheck(async (caller, flag) => { if (flag.type === 'post' && activitypub.helpers.isUri(flag.targetUid)) { reportedIds.push(flag.targetUid); } - const reason = flag.reports.filter(report => report.reporter.uid === caller.uid).at(-1); + const reason = flag.reason || + (flag.reports && flag.reports.filter(report => report.reporter.uid === caller.uid).at(-1).value); await activitypub.send('uid', caller.uid, reportedIds, { + id: `${nconf.get('url')}/${flag.type}/${encodeURIComponent(flag.targetId)}#activity/flag/${caller.uid}`, type: 'Flag', object: reportedIds, - content: reason ? reason.value : undefined, + content: reason, }); + await db.sortedSetAdd(`flag:${flag.flagId}:remote`, Date.now(), caller.uid); +}); + +activitypubApi.undo.flag = enabledCheck(async (caller, flag) => { + if (!activitypub.helpers.isUri(flag.targetId)) { + return; + } + const reportedIds = [flag.targetId]; + if (flag.type === 'post' && activitypub.helpers.isUri(flag.targetUid)) { + reportedIds.push(flag.targetUid); + } + const reason = flag.reason || + (flag.reports && flag.reports.filter(report => report.reporter.uid === caller.uid).at(-1).value); + await activitypub.send('uid', caller.uid, reportedIds, { + id: `${nconf.get('url')}/${flag.type}/${encodeURIComponent(flag.targetId)}#activity/undo:flag/${caller.uid}`, + type: 'Undo', + object: { + id: `${nconf.get('url')}/${flag.type}/${encodeURIComponent(flag.targetId)}#activity/flag/${caller.uid}`, + actor: `${nconf.get('url')}/uid/${caller.uid}`, + type: 'Flag', + object: reportedIds, + content: reason, + }, + }); + await db.sortedSetRemove(`flag:${flag.flagId}:remote`, caller.uid); }); diff --git a/src/flags.js b/src/flags.js index d62f9e00ba..864057729c 100644 --- a/src/flags.js +++ b/src/flags.js @@ -418,7 +418,7 @@ Flags.create = async function (type, id, uid, reason, timestamp, forceFlag = fal if (targetFlagged) { const flagId = await Flags.getFlagIdByTarget(type, id); await Promise.all([ - Flags.addReport(flagId, type, id, uid, reason, timestamp), + Flags.addReport(flagId, type, id, uid, reason, timestamp, targetUid, notifyRemote), Flags.update(flagId, uid, { state: 'open', report: 'added', @@ -439,7 +439,7 @@ Flags.create = async function (type, id, uid, reason, timestamp, forceFlag = fal targetUid: targetUid, datetime: timestamp, }), - Flags.addReport(flagId, type, id, uid, reason, timestamp), + Flags.addReport(flagId, type, id, uid, reason, timestamp, targetUid, notifyRemote), db.sortedSetAdd('flags:datetime', timestamp, flagId), // by time, the default db.sortedSetAdd(`flags:byType:${type}`, timestamp, flagId), // by flag type db.sortedSetIncrBy('flags:byTarget', 1, [type, id].join(':')), // by flag target (score is count) @@ -478,7 +478,7 @@ Flags.create = async function (type, id, uid, reason, timestamp, forceFlag = fal if (notifyRemote && activitypub.helpers.isUri(id)) { const caller = await user.getUserData(uid); - activitypubApi.flag(caller, flagObj); + activitypubApi.flag(caller, { ...flagObj, reason }); } plugins.hooks.fire('action:flags.create', { flag: flagObj }); @@ -528,6 +528,13 @@ Flags.purge = async function (flagIds) { 'flags:byTarget', flagData.map(flagObj => [flagObj.type, flagObj.targetId].join(':')) ), + flagData.flatMap( + async (flagObj, i) => allReporterUids[i].map(async (uid) => { + if (await db.isSortedSetMember(`flag:${flagObj.flagId}:remote`, uid)) { + await activitypubApi.undo.flag({ uid }, flagObj); + } + }) + ), ]); }; @@ -553,7 +560,7 @@ Flags.getReports = async function (flagId) { }; // Not meant to be called directly, call Flags.create() instead. -Flags.addReport = async function (flagId, type, id, uid, reason, timestamp) { +Flags.addReport = async function (flagId, type, id, uid, reason, timestamp, targetUid, notifyRemote) { await db.sortedSetAddBulk([ [`flags:byReporter:${uid}`, timestamp, flagId], [`flag:${flagId}:reports`, timestamp, [uid, reason].join(';')], @@ -561,6 +568,10 @@ Flags.addReport = async function (flagId, type, id, uid, reason, timestamp) { ['flags:hash', flagId, [type, id, uid].join(':')], ]); + if (notifyRemote && activitypub.helpers.isUri(id)) { + await activitypubApi.flag({ uid }, { flagId, type, targetId: id, targetUid, uid, reason, timestamp }); + } + plugins.hooks.fire('action:flags.addReport', { flagId, type, id, uid, reason, timestamp }); }; @@ -586,6 +597,11 @@ Flags.rescindReport = async (type, id, uid) => { throw new Error('[[error:cant-locate-flag-report]]'); } + if (await db.isSortedSetMember(`flag:${flagId}:remote`, uid)) { + const flag = await Flags.get(flagId); + await activitypubApi.undo.flag({ uid }, flag); + } + await db.sortedSetRemoveBulk([ [`flags:byReporter:${uid}`, flagId], [`flag:${flagId}:reports`, [uid, reason].join(';')],