Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(moderation): モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 #222

Merged
merged 3 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,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 @@ -561,6 +561,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 @@ -558,6 +558,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 @@ -23,6 +23,8 @@ import * as ep___admin_abuseReportResolver_update from './endpoints/admin/abuse-
import * as ep___admin_abuseReportResolver_delete from './endpoints/admin/abuse-report-resolver/delete.js';
import * as ep___admin_abuseReportResolver_list from './endpoints/admin/abuse-report-resolver/list.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 @@ -372,6 +374,8 @@ const $admin_abuseReportResolver_update: Provider = { provide: 'ep:admin/abuse-r
const $admin_abuseReportResolver_list: Provider = { provide: 'ep:admin/abuse-report-resolver/list', useClass: ep___admin_abuseReportResolver_list.default };
const $admin_abuseReportResolver_delete: Provider = { provide: 'ep:admin/abuse-report-resolver/delete', useClass: ep___admin_abuseReportResolver_delete.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 @@ -725,6 +729,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_abuseReportResolver_list,
$admin_abuseReportResolver_update,
$admin_deleteAllFilesOfAUser,
$admin_deleteUserAvatar,
$admin_deleteUserBanner,
$admin_drive_cleanRemoteFiles,
$admin_drive_cleanup,
$admin_drive_files,
Expand Down Expand Up @@ -1072,6 +1078,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_abuseReportResolver_list,
$admin_abuseReportResolver_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 @@ -23,6 +23,8 @@ import * as ep___admin_abuseReportResolver_update from './endpoints/admin/abuse-
import * as ep___admin_abuseReportResolver_delete from './endpoints/admin/abuse-report-resolver/delete.js';
import * as ep___admin_abuseReportResolver_list from './endpoints/admin/abuse-report-resolver/list.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 @@ -370,6 +372,8 @@ const eps = [
['admin/abuse-report-resolver/delete', ep___admin_abuseReportResolver_delete],
['admin/abuse-report-resolver/update', ep___admin_abuseReportResolver_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/index.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/index.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/user-info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton v-if="user.host == null && iAmModerator" inline style="margin-right: 8px;" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton>
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
</div>
<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>

<MkFolder>
<template #icon><i class="ti ti-license"></i></template>
Expand Down Expand Up @@ -345,6 +349,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
16 changes: 14 additions & 2 deletions packages/misskey-js/etc/misskey-js.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,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 Expand Up @@ -2844,8 +2856,8 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u
// Warnings were encountered during analysis:
//
// src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts
// src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
// src/api.types.ts:633:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
// src/api.types.ts:20:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
// src/api.types.ts:635:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
// src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)
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
Loading