fix: cascading bugs during deletion.
- During cascade deletion, the posts deleted by the cascade are not published to noteStream. - During cascade deletion, the notes count of instance and user is incorrect.
This commit is contained in:
parent
06985abe08
commit
6e8d1a167f
1 changed files with 45 additions and 12 deletions
|
@ -6,7 +6,7 @@ import renderUndo from "@/remote/activitypub/renderer/undo.js";
|
|||
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
|
||||
import renderTombstone from "@/remote/activitypub/renderer/tombstone.js";
|
||||
import config from "@/config/index.js";
|
||||
import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js";
|
||||
import { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js";
|
||||
import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js";
|
||||
import { Notes, Users, Instances } from "@/models/index.js";
|
||||
import {
|
||||
|
@ -16,8 +16,13 @@ import {
|
|||
import { countSameRenotes } from "@/misc/count-same-renotes.js";
|
||||
import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js";
|
||||
import { deliverToRelays } from "@/services/relay.js";
|
||||
import type { IActivity } from "@/remote/activitypub/type.js";
|
||||
|
||||
async function recalculateNotesCountOfUser(user: { id: User["id"] }) {
|
||||
async function recalculateNotesCountOfUser(user: {
|
||||
id: User["id"];
|
||||
host: null;
|
||||
}) {
|
||||
if (!Users.isLocalUser(user)) return;
|
||||
const newCount = await Notes.createQueryBuilder()
|
||||
.where(`"userId" = :id`, { id: user.id })
|
||||
.getCount();
|
||||
|
@ -35,6 +40,7 @@ async function recalculateNotesCountOfUser(user: { id: User["id"] }) {
|
|||
* 投稿を削除します。
|
||||
* @param user 投稿者
|
||||
* @param note 投稿
|
||||
* @param deleteFromDb false if called by making private
|
||||
*/
|
||||
export default async function (
|
||||
user: { id: User["id"]; uri: User["uri"]; host: User["host"] },
|
||||
|
@ -58,6 +64,16 @@ export default async function (
|
|||
await Notes.decrement({ id: note.replyId }, "repliesCount", 1);
|
||||
}
|
||||
|
||||
const cascadingNotes = await findCascadingNotes(note);
|
||||
const affectedLocalUsers: Record<
|
||||
User["id"],
|
||||
{ id: User["id"]; uri: User["uri"]; host: null }
|
||||
> = {};
|
||||
if (Users.isLocalUser(user)) {
|
||||
affectedLocalUsers[user.id] = user;
|
||||
}
|
||||
const instanceNotesCountDecreasement: Record<string, number> = {};
|
||||
|
||||
if (!quiet) {
|
||||
// Only broadcast "deleted" to local if the note is deleted from db
|
||||
if (deleteFromDb) {
|
||||
|
@ -101,12 +117,23 @@ export default async function (
|
|||
}
|
||||
|
||||
// also deliever delete activity to cascaded notes
|
||||
const cascadingNotes = (await findCascadingNotes(note)).filter(
|
||||
(note) => !note.localOnly,
|
||||
); // filter out local-only notes
|
||||
for (const cascadingNote of cascadingNotes) {
|
||||
if (cascadingNote.userId !== user.id) {
|
||||
// For others, the post appears to have been deleted and publishNoteStream is also required.
|
||||
publishNoteStream(cascadingNote.id, "deleted", {
|
||||
deletedAt: deletedAt,
|
||||
});
|
||||
}
|
||||
|
||||
if (!cascadingNote.user) continue;
|
||||
if (!Users.isLocalUser(cascadingNote.user)) continue;
|
||||
if (!Users.isLocalUser(cascadingNote.user)) {
|
||||
if (!Users.isRemoteUser(cascadingNote.user)) continue;
|
||||
instanceNotesCountDecreasement[cascadingNote.user.host] ??= 0;
|
||||
instanceNotesCountDecreasement[cascadingNote.user.host]++;
|
||||
continue; // filter out remote users
|
||||
}
|
||||
affectedLocalUsers[cascadingNote.user.id] ??= cascadingNote.user;
|
||||
if (cascadingNote.localOnly) continue; // filter out local-only notes
|
||||
const content = renderActivity(
|
||||
renderDelete(
|
||||
renderTombstone(`${config.url}/notes/${cascadingNote.id}`),
|
||||
|
@ -118,8 +145,14 @@ export default async function (
|
|||
//#endregion
|
||||
|
||||
if (Users.isRemoteUser(user)) {
|
||||
registerOrFetchInstanceDoc(user.host).then((i) => {
|
||||
Instances.decrement({ id: i.id }, "notesCount", 1);
|
||||
instanceNotesCountDecreasement[user.host] ??= 0;
|
||||
instanceNotesCountDecreasement[user.host]++;
|
||||
}
|
||||
for (const [host, number] of Object.entries(
|
||||
instanceNotesCountDecreasement,
|
||||
)) {
|
||||
registerOrFetchInstanceDoc(host).then((i) => {
|
||||
Instances.decrement({ id: i.id }, "notesCount", number);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -130,9 +163,9 @@ export default async function (
|
|||
userId: user.id,
|
||||
});
|
||||
|
||||
if (Users.isLocalUser(user)) {
|
||||
for (const [_, affectedUser] of Object.entries(affectedLocalUsers)) {
|
||||
// For the case of cascading deletion, it cannot be solved by simply reducing the notesCount by 1.
|
||||
recalculateNotesCountOfUser(user);
|
||||
recalculateNotesCountOfUser(affectedUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +192,7 @@ async function findCascadingNotes(note: Note) {
|
|||
};
|
||||
await recursive(note.id);
|
||||
|
||||
return cascadingNotes.filter((note) => note.userHost === null); // filter out non-local users
|
||||
return cascadingNotes;
|
||||
}
|
||||
|
||||
async function getMentionedRemoteUsers(note: Note) {
|
||||
|
@ -190,7 +223,7 @@ async function getMentionedRemoteUsers(note: Note) {
|
|||
async function deliverToConcerned(
|
||||
user: { id: ILocalUser["id"]; host: null },
|
||||
note: Note,
|
||||
content: any,
|
||||
content: IActivity | null,
|
||||
) {
|
||||
deliverToFollowers(user, content);
|
||||
deliverToRelays(user, content);
|
||||
|
|
Loading…
Reference in a new issue