server: refactor to always use deleteAccount service

This should reduce code duplication around how deletion of an actor is
handled.
This commit is contained in:
Johann150 2023-01-07 19:28:18 +01:00
parent 8772181b6f
commit 1eda1760d1
Signed by untrusted user: Johann150
GPG key ID: 9EE6577A2A06F8F1
5 changed files with 34 additions and 49 deletions

View file

@ -155,7 +155,14 @@ export class User {
}) })
public isExplorable: boolean; public isExplorable: boolean;
// アカウントが削除されたかどうかのフラグだが、完全に削除される際は物理削除なので実質削除されるまでの「削除が進行しているかどうか」のフラグ // for local users:
// Indicates a deletion in progress.
// A hard delete of the record will follow after the deletion finishes.
//
// for remote users:
// Indicates the user was deleted by an admin.
// The users' data is not deleted from the database to keep them from reappearing.
// A hard delete of the record may follow if we receive a matching Delete activity.
@Column('boolean', { @Column('boolean', {
default: false, default: false,
comment: 'Whether the User is deleted.', comment: 'Whether the User is deleted.',

View file

@ -83,10 +83,8 @@ export async function deleteAccount(job: Bull.Job<DbUserDeleteJobData>): Promise
} }
} }
// soft指定されている場合は物理削除しない // No physical deletion if soft is specified.
if (job.data.soft) { if (!job.data.soft) {
// nop
} else {
await Users.delete(job.data.user.id); await Users.delete(job.data.user.id);
} }

View file

@ -1,7 +1,7 @@
import { createDeleteAccountJob } from '@/queue/index.js';
import { CacheableRemoteUser } from '@/models/entities/user.js'; import { CacheableRemoteUser } from '@/models/entities/user.js';
import { Users } from '@/models/index.js'; import { Users } from '@/models/index.js';
import { apLogger } from '@/remote/activitypub/logger.js'; import { apLogger } from '@/remote/activitypub/logger.js';
import { deleteAccount } from '@/services/delete-account.js';
export async function deleteActor(actor: CacheableRemoteUser, uri: string): Promise<string> { export async function deleteActor(actor: CacheableRemoteUser, uri: string): Promise<string> {
apLogger.info(`Deleting the Actor: ${uri}`); apLogger.info(`Deleting the Actor: ${uri}`);
@ -17,14 +17,9 @@ export async function deleteActor(actor: CacheableRemoteUser, uri: string): Prom
return 'ok: gone'; return 'ok: gone';
} }
if (user.isDeleted) { if (user.isDeleted) {
apLogger.info('skip: already deleted'); // the actual deletion already happened by an admin, just delete the record
await Users.delete(actor.id);
} else {
await deleteAccount(actor);
} }
const job = await createDeleteAccountJob(actor);
await Users.update(actor.id, {
isDeleted: true,
});
return `ok: queued ${job.name} ${job.id}`;
} }

View file

@ -1,8 +1,6 @@
import { Users } from '@/models/index.js'; import { Users } from '@/models/index.js';
import { ApiError } from '@/server/api/error.js'; import { ApiError } from '@/server/api/error.js';
import { doPostSuspend } from '@/services/suspend-user.js'; import { deleteAccount } from '@/services/delete-account.js';
import { publishUserEvent } from '@/services/stream.js';
import { createDeleteAccountJob } from '@/queue/index.js';
import define from '../../../define.js'; import define from '../../../define.js';
export const meta = { export const meta = {
@ -24,7 +22,10 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps) => { export default define(meta, paramDef, async (ps) => {
const user = await Users.findOneBy({ id: ps.userId }); const user = await Users.findOneBy({
id: ps.userId,
isDeleted: false,
});
if (user == null) { if (user == null) {
throw new ApiError('NO_SUCH_USER'); throw new ApiError('NO_SUCH_USER');
@ -34,25 +35,5 @@ export default define(meta, paramDef, async (ps) => {
throw new ApiError('IS_MODERATOR'); throw new ApiError('IS_MODERATOR');
} }
if (Users.isLocalUser(user)) { await deleteAccount(user);
// 物理削除する前にDelete activityを送信する
await doPostSuspend(user).catch(() => {});
createDeleteAccountJob(user, {
soft: false,
});
} else {
createDeleteAccountJob(user, {
soft: true, // リモートユーザーの削除は、完全にDBから物理削除してしまうと再度連合してきてアカウントが復活する可能性があるため、soft指定する
});
}
await Users.update(user.id, {
isDeleted: true,
});
if (Users.isLocalUser(user)) {
// Terminate streaming
publishUserEvent(user.id, 'terminate', {});
}
}); });

View file

@ -7,17 +7,21 @@ export async function deleteAccount(user: {
id: string; id: string;
host: string | null; host: string | null;
}): Promise<void> { }): Promise<void> {
// Send Delete activity before physical deletion
await doPostSuspend(user).catch(() => {});
createDeleteAccountJob(user, {
soft: false,
});
await Users.update(user.id, { await Users.update(user.id, {
isDeleted: true, isDeleted: true,
}); });
// Terminate streaming if (Users.isLocalUser(user)) {
publishUserEvent(user.id, 'terminate', {}); // Terminate streaming
publishUserEvent(user.id, 'terminate', {});
}
// Send Delete activity before physical deletion
await doPostSuspend(user).catch(() => {});
createDeleteAccountJob(user, {
// Deleting remote users is specified as SOFT, because if they are physically deleted
// from the DB completely, they may be reassociated and their accounts may be reinstated.
soft: Users.isLocalUser(user),
});
} }