Skip to content

Commit

Permalink
feat(moderation): モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (MisskeyIO…
Browse files Browse the repository at this point in the history
…#222)

Co-authored-by: まっちゃとーにゅ <[email protected]>
  • Loading branch information
nafu-at and u1-liquid committed Nov 17, 2023
1 parent 81420a0 commit e0eb5a7
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 0 deletions.
4 changes: 4 additions & 0 deletions locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,10 @@ output: "Output"
script: "Script"
disablePagesScript: "Disable AiScript on Pages"
updateRemoteUser: "Update remote user information"
deleteUserAvatar: "Delete user icon"
deleteUserAvatarConfirm: "Are you sure that you want to delete this user's icon?"
deleteUserBanner: "Delete user banner"
deleteUserBannerConfirm: "Are you sure that you want to delete this user's banner?"
deleteAllFiles: "Delete all files"
deleteAllFilesConfirm: "Are you sure that you want to delete all files?"
removeAllFollowing: "Unfollow all followed users"
Expand Down
4 changes: 4 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,10 @@ export interface Locale {
"script": string;
"disablePagesScript": string;
"updateRemoteUser": string;
"deleteUserAvatar": string;
"deleteUserAvatarConfirm": string;
"deleteUserBanner": string;
"deleteUserBannerConfirm": string;
"deleteAllFiles": string;
"deleteAllFilesConfirm": string;
"removeAllFollowing": string;
Expand Down
4 changes: 4 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,10 @@ output: "出力"
script: "スクリプト"
disablePagesScript: "Pagesのスクリプトを無効にする"
updateRemoteUser: "リモートユーザー情報の更新"
deleteUserAvatar: "アイコンを削除"
deleteUserAvatarConfirm: "アイコンを削除しますか?"
deleteUserBanner: "バナーを削除"
deleteUserBannerConfirm: "バナーを削除しますか?"
deleteAllFiles: "すべてのファイルを削除"
deleteAllFilesConfirm: "すべてのファイルを削除しますか?"
removeAllFollowing: "フォローを全解除"
Expand Down
8 changes: 8 additions & 0 deletions packages/backend/src/server/api/EndpointsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d
import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js';
import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js';
import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js';
import * as ep___admin_deleteUserAvatar from './endpoints/admin/delete-user-avatar.js';
import * as ep___admin_deleteUserBanner from './endpoints/admin/delete-user-banner.js';
import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js';
import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js';
import * as ep___admin_drive_files from './endpoints/admin/drive/files.js';
Expand Down Expand Up @@ -382,6 +384,8 @@ const $admin_avatarDecorations_delete: Provider = { provide: 'ep:admin/avatar-de
const $admin_avatarDecorations_list: Provider = { provide: 'ep:admin/avatar-decorations/list', useClass: ep___admin_avatarDecorations_list.default };
const $admin_avatarDecorations_update: Provider = { provide: 'ep:admin/avatar-decorations/update', useClass: ep___admin_avatarDecorations_update.default };
const $admin_deleteAllFilesOfAUser: Provider = { provide: 'ep:admin/delete-all-files-of-a-user', useClass: ep___admin_deleteAllFilesOfAUser.default };
const $admin_deleteUserAvatar: Provider = { provide: 'ep:admin/delete-user-avatar', useClass: ep___admin_deleteUserAvatar.default };
const $admin_deleteUserBanner: Provider = { provide: 'ep:admin/delete-user-banner', useClass: ep___admin_deleteUserBanner.default };
const $admin_drive_cleanRemoteFiles: Provider = { provide: 'ep:admin/drive/clean-remote-files', useClass: ep___admin_drive_cleanRemoteFiles.default };
const $admin_drive_cleanup: Provider = { provide: 'ep:admin/drive/cleanup', useClass: ep___admin_drive_cleanup.default };
const $admin_drive_files: Provider = { provide: 'ep:admin/drive/files', useClass: ep___admin_drive_files.default };
Expand Down Expand Up @@ -744,6 +748,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_avatarDecorations_list,
$admin_avatarDecorations_update,
$admin_deleteAllFilesOfAUser,
$admin_deleteUserAvatar,
$admin_deleteUserBanner,
$admin_drive_cleanRemoteFiles,
$admin_drive_cleanup,
$admin_drive_files,
Expand Down Expand Up @@ -1100,6 +1106,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_avatarDecorations_list,
$admin_avatarDecorations_update,
$admin_deleteAllFilesOfAUser,
$admin_deleteUserAvatar,
$admin_deleteUserBanner,
$admin_drive_cleanRemoteFiles,
$admin_drive_cleanup,
$admin_drive_files,
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/server/api/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import * as ep___admin_avatarDecorations_delete from './endpoints/admin/avatar-d
import * as ep___admin_avatarDecorations_list from './endpoints/admin/avatar-decorations/list.js';
import * as ep___admin_avatarDecorations_update from './endpoints/admin/avatar-decorations/update.js';
import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js';
import * as ep___admin_deleteUserAvatar from './endpoints/admin/delete-user-avatar.js';
import * as ep___admin_deleteUserBanner from './endpoints/admin/delete-user-banner.js';
import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js';
import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js';
import * as ep___admin_drive_files from './endpoints/admin/drive/files.js';
Expand Down Expand Up @@ -380,6 +382,8 @@ const eps = [
['admin/avatar-decorations/list', ep___admin_avatarDecorations_list],
['admin/avatar-decorations/update', ep___admin_avatarDecorations_update],
['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser],
['admin/delete-user-avatar', ep___admin_deleteUserAvatar],
['admin/delete-user-banner', ep___admin_deleteUserBanner],
['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles],
['admin/drive/cleanup', ep___admin_drive_cleanup],
['admin/drive/files', ep___admin_drive_files],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { Inject, Injectable } from '@nestjs/common';
import type { UsersRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';

export const meta = {
tags: ['admin'],

requireCredential: true,
requireModerator: true,
} as const;

export const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;

// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
) {
super(meta, paramDef, async (ps, me) => {
const user = await this.usersRepository.findOneBy({ id: ps.userId });

if (user == null) {
throw new Error('user not found');
}

await this.usersRepository.update(user.id, {
avatar: null,
avatarId: null,
avatarUrl: null,
avatarBlurhash: null,
});
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { Inject, Injectable } from '@nestjs/common';
import type { UsersRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';

export const meta = {
tags: ['admin'],

requireCredential: true,
requireModerator: true,
} as const;

export const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;

// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
) {
super(meta, paramDef, async (ps, me) => {
const user = await this.usersRepository.findOneBy({ id: ps.userId });

if (user == null) {
throw new Error('user not found');
}

await this.usersRepository.update(user.id, {
banner: null,
bannerId: null,
bannerUrl: null,
bannerBlurhash: null,
});
});
}
}
42 changes: 42 additions & 0 deletions packages/frontend/src/pages/admin-user.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
</MkFolder>

<div>
<MkButton v-if="iAmModerator" inline danger style="margin-right: 8px;" @click="deleteUserAvatar"><i class="ti ti-user-circle"></i> {{ i18n.ts.deleteUserAvatar }}</MkButton>
<MkButton v-if="iAmModerator" inline danger @click="deleteUserBanner"><i class="ti ti-photo"></i> {{ i18n.ts.deleteUserBanner }}</MkButton>
</div>
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
</div>
</FormSection>
Expand Down Expand Up @@ -322,6 +326,44 @@ async function toggleSuspend(v) {
}
}

async function deleteUserAvatar() {
const confirm = await os.confirm({
type: 'warning',
text: i18n.ts.deleteUserAvatarConfirm,
});
if (confirm.canceled) return;
const process = async () => {
await os.api('admin/delete-user-avatar', { userId: user.id });
os.success();
};
await process().catch(err => {
os.alert({
type: 'error',
text: err.toString(),
});
});
refreshUser();
}

async function deleteUserBanner() {
const confirm = await os.confirm({
type: 'warning',
text: i18n.ts.deleteUserBannerConfirm,
});
if (confirm.canceled) return;
const process = async () => {
await os.api('admin/delete-user-banner', { userId: user.id });
os.success();
};
await process().catch(err => {
os.alert({
type: 'error',
text: err.toString(),
});
});
refreshUser();
}

async function deleteAllFiles() {
const confirm = await os.confirm({
type: 'warning',
Expand Down
12 changes: 12 additions & 0 deletions packages/misskey-js/etc/misskey-js.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,18 @@ export type Endpoints = {
};
res: null;
};
'admin/delete-user-avatar': {
req: {
userId: User['id'];
};
res: null;
};
'admin/delete-user-banner': {
req: {
userId: User['id'];
};
res: null;
};
'admin/delete-logs': {
req: NoParams;
res: null;
Expand Down
2 changes: 2 additions & 0 deletions packages/misskey-js/src/api.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export type Endpoints = {
// admin
'admin/abuse-user-reports': { req: TODO; res: TODO; };
'admin/delete-all-files-of-a-user': { req: { userId: User['id']; }; res: null; };
'admin/delete-user-avatar': { req: { userId: User['id']; }; res: null; };
'admin/delete-user-banner': { req: { userId: User['id']; }; res: null; };
'admin/delete-logs': { req: NoParams; res: null; };
'admin/get-index-stats': { req: TODO; res: TODO; };
'admin/get-table-stats': { req: TODO; res: TODO; };
Expand Down

0 comments on commit e0eb5a7

Please sign in to comment.