diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 968448992..ce25095d5 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -203,6 +203,7 @@ done: "完了" processing: "処理中" preview: "プレビュー" default: "デフォルト" +defaultValueIs: "デフォルト: {value}" noCustomEmojis: "絵文字はありません" noJobs: "ジョブはありません" federating: "連合中" @@ -855,6 +856,8 @@ noEmailServerWarning: "メールサーバーの設定がされていません。 thereIsUnresolvedAbuseReportWarning: "未対応の通報があります。" recommended: "推奨" check: "チェック" +driveCapOverrideLabel: "このユーザーのドライブ容量上限を変更" +driveCapOverrideCaption: "0以下を指定すると解除されます。" requireAdminForView: "閲覧するには管理者アカウントでログインしている必要があります。" isSystemAccount: "システムにより自動で作成・管理されているアカウントです。" typeToConfirm: "この操作を行うには {x} と入力してください" diff --git a/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js b/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js new file mode 100644 index 000000000..f257cd112 --- /dev/null +++ b/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js @@ -0,0 +1,13 @@ +export class driveCapacityOverrideMb1655813815729 { + name = 'driveCapacityOverrideMb1655813815729' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "driveCapacityOverrideMb" integer`); + await queryRunner.query(`COMMENT ON COLUMN "user"."driveCapacityOverrideMb" IS 'Overrides user drive capacity limit'`); + } + + async down(queryRunner) { + await queryRunner.query(`COMMENT ON COLUMN "user"."driveCapacityOverrideMb" IS 'Overrides user drive capacity limit'`); + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "driveCapacityOverrideMb"`); + } +} diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts index df92fb825..bc9446be4 100644 --- a/packages/backend/src/models/entities/user.ts +++ b/packages/backend/src/models/entities/user.ts @@ -218,6 +218,12 @@ export class User { }) public token: string | null; + @Column('integer', { + nullable: true, + comment: 'Overrides user drive capacity limit', + }) + public driveCapacityOverrideMb: number | null; + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index 8a4e48efd..645091395 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -315,6 +315,7 @@ export const UserRepository = db.getRepository(User).extend({ } : undefined) : undefined, emojis: populateEmojis(user.emojis, user.host), onlineStatus: this.getOnlineStatus(user), + driveCapacityOverrideMb: user.driveCapacityOverrideMb, ...(opts.detail ? { url: profile!.url, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 4a2ecebd8..4644f34d9 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -314,6 +314,7 @@ import * as ep___users_search from './endpoints/users/search.js'; import * as ep___users_show from './endpoints/users/show.js'; import * as ep___users_stats from './endpoints/users/stats.js'; import * as ep___fetchRss from './endpoints/fetch-rss.js'; +import * as ep___admin_driveCapOverride from './endpoints/admin/drive-capacity-override.js'; const eps = [ ['admin/meta', ep___admin_meta], @@ -629,6 +630,7 @@ const eps = [ ['users/search', ep___users_search], ['users/show', ep___users_show], ['users/stats', ep___users_stats], + ['admin/drive-capacity-override', ep___admin_driveCapOverride], ['fetch-rss', ep___fetchRss], ]; diff --git a/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts b/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts new file mode 100644 index 000000000..a4b29770e --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/drive-capacity-override.ts @@ -0,0 +1,47 @@ +import define from '../../define.js'; +import { Users } from '@/models/index.js'; +import { User } from '@/models/entities/user.js'; +import { insertModerationLog } from '@/services/insert-moderation-log.js'; +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, +} as const; + +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + overrideMb: { type: 'number', nullable: true }, + }, + required: ['userId', 'overrideMb'], +} as const; + +// eslint-disable-next-line import/no-default-export +export default define(meta, paramDef, async (ps, me) => { + const user = await Users.findOneBy({ id: ps.userId }); + + if (user == null) { + throw new Error('user not found'); + } + + if (!Users.isLocalUser(user)) { + throw new Error('user is not local user'); + } + + /*if (user.isAdmin) { + throw new Error('cannot suspend admin'); + } + if (user.isModerator) { + throw new Error('cannot suspend moderator'); + }*/ + + await Users.update(user.id, { + driveCapacityOverrideMb: ps.overrideMb, + }); + + insertModerationLog(me, 'change-drive-capacity-override', { + targetId: user.id, + }); +}); diff --git a/packages/backend/src/server/api/endpoints/drive.ts b/packages/backend/src/server/api/endpoints/drive.ts index 47e940cdd..82497adef 100644 --- a/packages/backend/src/server/api/endpoints/drive.ts +++ b/packages/backend/src/server/api/endpoints/drive.ts @@ -39,7 +39,7 @@ export default define(meta, paramDef, async (ps, user) => { const usage = await DriveFiles.calcDriveUsageOf(user.id); return { - capacity: 1024 * 1024 * instance.localDriveCapacityMb, + capacity: 1024 * 1024 * (user.driveCapacityOverrideMb || instance.localDriveCapacityMb), usage: usage, }; }); diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index a25413187..0dfad11cf 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -307,7 +307,7 @@ async function deleteOldFile(user: IRemoteUser) { type AddFileArgs = { /** User who wish to add file */ - user: { id: User['id']; host: User['host'] } | null; + user: { id: User['id']; host: User['host']; driveCapacityOverrideMb: User['driveCapacityOverrideMb'] } | null; /** File path */ path: string; /** Name */ @@ -371,9 +371,16 @@ export async function addFile({ //#region Check drive usage if (user && !isLink) { const usage = await DriveFiles.calcDriveUsageOf(user); + const u = await Users.findOneBy({ id: user.id }); const instance = await fetchMeta(); - const driveCapacity = 1024 * 1024 * (Users.isLocalUser(user) ? instance.localDriveCapacityMb : instance.remoteDriveCapacityMb); + let driveCapacity = 1024 * 1024 * (Users.isLocalUser(user) ? instance.localDriveCapacityMb : instance.remoteDriveCapacityMb); + + if (Users.isLocalUser(user) && u?.driveCapacityOverrideMb != null) { + driveCapacity = 1024 * 1024 * u.driveCapacityOverrideMb; + logger.debug('drive capacity override applied'); + logger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`); + } logger.debug(`drive usage is ${usage} (max: ${driveCapacity})`); diff --git a/packages/client/src/components/code-core.vue b/packages/client/src/components/code-core.vue index 45a38afe0..65dee5cda 100644 --- a/packages/client/src/components/code-core.vue +++ b/packages/client/src/components/code-core.vue @@ -5,7 +5,7 @@