enhance(moderation): 管理者がアカウントの物理削除・論理削除を選べるように (MisskeyIO#581)

This commit is contained in:
まっちゃとーにゅ 2024-03-30 15:55:36 +09:00 committed by GitHub
parent acc10c0709
commit b4420f895e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 13 deletions

View File

@ -37,6 +37,7 @@ export const paramDef = {
type: 'object', type: 'object',
properties: { properties: {
userId: { type: 'string', format: 'misskey:id' }, userId: { type: 'string', format: 'misskey:id' },
soft: { type: 'boolean', default: true, description: 'Since deletion by an administrator is a moderation action, the default is to soft delete.' },
}, },
required: ['userId'], required: ['userId'],
} as const; } as const;
@ -56,8 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (user == null) throw new ApiError(meta.errors.userNotFound); if (user == null) throw new ApiError(meta.errors.userNotFound);
if (await this.roleService.isModerator(user)) throw new ApiError(meta.errors.cannotDeleteModerator); if (await this.roleService.isModerator(user)) throw new ApiError(meta.errors.cannotDeleteModerator);
// 管理者からの削除ということはモデレーション行為なので、soft delete にする await this.deleteAccountService.deleteAccount(user, ps.soft, me);
await this.deleteAccountService.deleteAccount(user, true, me);
}); });
} }
} }

View File

@ -58,11 +58,16 @@ SPDX-License-Identifier: AGPL-3.0-only
<FormSection> <FormSection>
<div class="_gaps"> <div class="_gaps">
<MkSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch> <MkFolder v-if="iAmModerator" defaultOpen>
<template #icon><i class="ti ti-shield"></i></template>
<div> <template #label>{{ i18n.ts.moderation }}</template>
<MkButton v-if="user.host == null" inline style="margin-right: 8px;" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton> <div class="_gaps">
</div> <MkSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch>
<MkButton v-if="user.host == null" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton>
<MkButton inline danger @click="unsetUserAvatar"><i class="ti ti-user-circle"></i> {{ i18n.ts.unsetUserAvatar }}</MkButton>
<MkButton inline danger @click="unsetUserBanner"><i class="ti ti-photo"></i> {{ i18n.ts.unsetUserBanner }}</MkButton>
</div>
</MkFolder>
<MkFolder> <MkFolder>
<template #icon><i class="ti ti-license"></i></template> <template #icon><i class="ti ti-license"></i></template>
@ -87,11 +92,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
</MkFolder> </MkFolder>
<div class="_buttons"> <MkFolder v-if="$i.isAdmin">
<MkButton v-if="iAmModerator" inline danger @click="unsetUserAvatar"><i class="ti ti-user-circle"></i> {{ i18n.ts.unsetUserAvatar }}</MkButton> <template #icon><i class="ti ti-user-x"></i></template>
<MkButton v-if="iAmModerator" inline danger @click="unsetUserBanner"><i class="ti ti-photo"></i> {{ i18n.ts.unsetUserBanner }}</MkButton> <template #label>{{ i18n.ts.deleteAccount }}</template>
</div> <div class="_gaps">
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton> <MkButton inline danger @click="deleteAccount(true)"><i class="ti ti-user-x"></i> {{ i18n.ts.deleteAccount }}</MkButton>
<MkButton inline danger @click="deleteAccount(false)"><i class="ti ti-file-shredder"></i> {{ i18n.ts.deleteAccount }} ({{ i18n.ts.all }})</MkButton>
</div>
</MkFolder>
</div> </div>
</FormSection> </FormSection>
</div> </div>
@ -380,7 +388,7 @@ async function deleteAllFiles() {
} }
} }
async function deleteAccount() { async function deleteAccount(soft: boolean) {
const confirm = await os.confirm({ const confirm = await os.confirm({
type: 'warning', type: 'warning',
text: i18n.ts.deleteAccountConfirm, text: i18n.ts.deleteAccountConfirm,
@ -395,6 +403,7 @@ async function deleteAccount() {
if (typed.result === user.value?.username) { if (typed.result === user.value?.username) {
await os.apiWithDialog('admin/accounts/delete', { await os.apiWithDialog('admin/accounts/delete', {
userId: user.value.id, userId: user.value.id,
soft,
}).then(refreshUser); }).then(refreshUser);
} else { } else {
os.alert({ os.alert({

View File

@ -5438,6 +5438,11 @@ export type operations = {
'application/json': { 'application/json': {
/** Format: misskey:id */ /** Format: misskey:id */
userId: string; userId: string;
/**
* @description Since deletion by an administrator is a moderation action, the default is to soft delete.
* @default true
*/
soft?: boolean;
}; };
}; };
}; };