parent
72a49f334a
commit
9208825975
6 changed files with 80 additions and 7 deletions
|
@ -13,6 +13,8 @@
|
||||||
- ActivityPub: リモートユーザーのDeleteアクティビティに対応
|
- ActivityPub: リモートユーザーのDeleteアクティビティに対応
|
||||||
- ActivityPub: add resolver check for blocked instance
|
- ActivityPub: add resolver check for blocked instance
|
||||||
- ActivityPub: deliverキューのメモリ使用量を削減
|
- ActivityPub: deliverキューのメモリ使用量を削減
|
||||||
|
- API: 管理者用アカウント削除APIを実装(/admin/accounts/delete)
|
||||||
|
- リモートユーザーの削除も可能に
|
||||||
- アカウントが凍結された場合に、凍結された旨を表示してからログアウトするように
|
- アカウントが凍結された場合に、凍結された旨を表示してからログアウトするように
|
||||||
- 凍結されたアカウントにログインしようとしたときに、凍結されている旨を表示するように
|
- 凍結されたアカウントにログインしようとしたときに、凍結されている旨を表示するように
|
||||||
- リスト、アンテナタイムラインを個別ページとして分割
|
- リスト、アンテナタイムラインを個別ページとして分割
|
||||||
|
|
|
@ -173,9 +173,10 @@ export function createImportUserListsJob(user: ThinUser, fileId: DriveFile['id']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createDeleteAccountJob(user: ThinUser) {
|
export function createDeleteAccountJob(user: ThinUser, opts: { soft?: boolean; }) {
|
||||||
return dbQueue.add('deleteAccount', {
|
return dbQueue.add('deleteAccount', {
|
||||||
user: user
|
user: user,
|
||||||
|
soft: opts.soft
|
||||||
}, {
|
}, {
|
||||||
removeOnComplete: true,
|
removeOnComplete: true,
|
||||||
removeOnFail: true
|
removeOnFail: true
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as Bull from 'bull';
|
import * as Bull from 'bull';
|
||||||
import { queueLogger } from '../../logger';
|
import { queueLogger } from '../../logger';
|
||||||
import { DriveFiles, Notes, UserProfiles, Users } from '@/models/index';
|
import { DriveFiles, Notes, UserProfiles, Users } from '@/models/index';
|
||||||
import { DbUserJobData } from '@/queue/types';
|
import { DbUserDeleteJobData } from '@/queue/types';
|
||||||
import { Note } from '@/models/entities/note';
|
import { Note } from '@/models/entities/note';
|
||||||
import { DriveFile } from '@/models/entities/drive-file';
|
import { DriveFile } from '@/models/entities/drive-file';
|
||||||
import { MoreThan } from 'typeorm';
|
import { MoreThan } from 'typeorm';
|
||||||
|
@ -10,7 +10,7 @@ import { sendEmail } from '@/services/send-email';
|
||||||
|
|
||||||
const logger = queueLogger.createSubLogger('delete-account');
|
const logger = queueLogger.createSubLogger('delete-account');
|
||||||
|
|
||||||
export async function deleteAccount(job: Bull.Job<DbUserJobData>): Promise<string | void> {
|
export async function deleteAccount(job: Bull.Job<DbUserDeleteJobData>): Promise<string | void> {
|
||||||
logger.info(`Deleting account of ${job.data.user.id} ...`);
|
logger.info(`Deleting account of ${job.data.user.id} ...`);
|
||||||
|
|
||||||
const user = await Users.findOne(job.data.user.id);
|
const user = await Users.findOne(job.data.user.id);
|
||||||
|
@ -83,7 +83,12 @@ export async function deleteAccount(job: Bull.Job<DbUserJobData>): Promise<strin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Users.delete(job.data.user.id);
|
// soft指定されている場合は物理削除しない
|
||||||
|
if (job.data.soft) {
|
||||||
|
// nop
|
||||||
|
} else {
|
||||||
|
await Users.delete(job.data.user.id);
|
||||||
|
}
|
||||||
|
|
||||||
return 'Account deleted';
|
return 'Account deleted';
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,17 @@ export type InboxJobData = {
|
||||||
signature: httpSignature.IParsedSignature;
|
signature: httpSignature.IParsedSignature;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DbJobData = DbUserJobData | DbUserImportJobData;
|
export type DbJobData = DbUserJobData | DbUserImportJobData | DbUserDeleteJobData;
|
||||||
|
|
||||||
export type DbUserJobData = {
|
export type DbUserJobData = {
|
||||||
user: ThinUser;
|
user: ThinUser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DbUserDeleteJobData = {
|
||||||
|
user: ThinUser;
|
||||||
|
soft?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type DbUserImportJobData = {
|
export type DbUserImportJobData = {
|
||||||
user: ThinUser;
|
user: ThinUser;
|
||||||
fileId: DriveFile['id'];
|
fileId: DriveFile['id'];
|
||||||
|
|
58
src/server/api/endpoints/admin/accounts/delete.ts
Normal file
58
src/server/api/endpoints/admin/accounts/delete.ts
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import $ from 'cafy';
|
||||||
|
import define from '../../../define';
|
||||||
|
import { Users } from '@/models/index';
|
||||||
|
import { doPostSuspend } from '@/services/suspend-user';
|
||||||
|
import { publishUserEvent } from '@/services/stream';
|
||||||
|
import { createDeleteAccountJob } from '@/queue';
|
||||||
|
import { ID } from '@/misc/cafy-id';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['admin'],
|
||||||
|
|
||||||
|
requireCredential: true as const,
|
||||||
|
requireModerator: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
userId: {
|
||||||
|
validator: $.type(ID),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, async (ps, me) => {
|
||||||
|
const user = await Users.findOne(ps.userId);
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
throw new Error('user not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.isAdmin) {
|
||||||
|
throw new Error('cannot suspend admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.isModerator) {
|
||||||
|
throw new Error('cannot suspend moderator');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Users.isLocalUser(user)) {
|
||||||
|
// 物理削除する前にDelete activityを送信する
|
||||||
|
await doPostSuspend(user).catch(e => {});
|
||||||
|
|
||||||
|
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', {});
|
||||||
|
}
|
||||||
|
});
|
|
@ -35,7 +35,9 @@ export default define(meta, async (ps, user) => {
|
||||||
// 物理削除する前にDelete activityを送信する
|
// 物理削除する前にDelete activityを送信する
|
||||||
await doPostSuspend(user).catch(e => {});
|
await doPostSuspend(user).catch(e => {});
|
||||||
|
|
||||||
createDeleteAccountJob(user);
|
createDeleteAccountJob(user, {
|
||||||
|
soft: false
|
||||||
|
});
|
||||||
|
|
||||||
await Users.update(user.id, {
|
await Users.update(user.id, {
|
||||||
isDeleted: true,
|
isDeleted: true,
|
||||||
|
|
Loading…
Reference in a new issue