From b3e41b74a16baaaeb8c220f7bdbaaf4a6b362195 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Sun, 14 Sep 2025 20:54:20 -0400 Subject: [PATCH] implement admin/restart-migration endpoint --- .../backend/src/server/api/endpoint-list.ts | 1 + .../api/endpoints/admin/restart-migration.ts | 67 +++++++++++++++++++ packages/backend/src/types.ts | 6 ++ packages/misskey-js/src/consts.ts | 6 ++ packages/misskey-js/src/entities.ts | 3 + 5 files changed, 83 insertions(+) create mode 100644 packages/backend/src/server/api/endpoints/admin/restart-migration.ts diff --git a/packages/backend/src/server/api/endpoint-list.ts b/packages/backend/src/server/api/endpoint-list.ts index 54e8cfe841..6df96546a7 100644 --- a/packages/backend/src/server/api/endpoint-list.ts +++ b/packages/backend/src/server/api/endpoint-list.ts @@ -87,6 +87,7 @@ export * as 'admin/relays/add' from './endpoints/admin/relays/add.js'; export * as 'admin/relays/list' from './endpoints/admin/relays/list.js'; export * as 'admin/relays/remove' from './endpoints/admin/relays/remove.js'; export * as 'admin/reset-password' from './endpoints/admin/reset-password.js'; +export * as 'admin/restart-migration' from './endpoints/admin/restart-migration.js'; export * as 'admin/resolve-abuse-user-report' from './endpoints/admin/resolve-abuse-user-report.js'; export * as 'admin/roles/annotate-condition' from './endpoints/admin/roles/annotate-condition.js'; export * as 'admin/roles/assign' from './endpoints/admin/roles/assign.js'; diff --git a/packages/backend/src/server/api/endpoints/admin/restart-migration.ts b/packages/backend/src/server/api/endpoints/admin/restart-migration.ts new file mode 100644 index 0000000000..520bf2560a --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/restart-migration.ts @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { CacheService } from '@/core/CacheService.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { AccountMoveService } from '@/core/AccountMoveService.js'; +import { ApiError } from '@/server/api/error.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireAdmin: true, + kind: 'write:admin:restart-migration', + + errors: { + accountHasNotMigrated: { + message: 'Account has not migrated anywhere.', + code: 'ACCOUNT_HAS_NOT_MIGRATED', + id: 'ddcf173a-00f2-4aa4-ba12-cddd131bacf4', + }, + }, + + res: {}, +} as const; + +export const paramDef = { + type: 'object', + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, + required: ['userId'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private readonly cacheService: CacheService, + private readonly moderationLogService: ModerationLogService, + private readonly accountMoveService: AccountMoveService, + ) { + super(meta, paramDef, async (ps, me) => { + try { + const user = await this.cacheService.findUserById(ps.userId); + await this.accountMoveService.restartMigration(user); + + await this.moderationLogService.log(me, 'restartMigration', { + userId: user.id, + userUsername: user.username, + userHost: user.host, + }); + } catch (err) { + // TODO allow this mapping stuff to be defined in the meta + if (err instanceof IdentifiableError && err.id === 'ddcf173a-00f2-4aa4-ba12-cddd131bacf4') { + throw new ApiError(meta.errors.accountHasNotMigrated); + } else { + throw err; + } + } + }); + } +} diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index e799447117..850f47ad52 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -108,6 +108,7 @@ export const moderationLogTypes = [ 'deleteGlobalAnnouncement', 'deleteUserAnnouncement', 'resetPassword', + 'restartMigration', 'setMandatoryCW', 'setMandatoryCWForNote', 'setMandatoryCWForInstance', @@ -290,6 +291,11 @@ export type ModerationLogPayloads = { userUsername: string; userHost: string | null; }; + restartMigration: { + userId: string; + userUsername: string; + userHost: string | null; + }; setMandatoryCW: { newCW: string | null; oldCW: string | null; diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index 0b7f8f4eac..616e7488fa 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -90,6 +90,7 @@ export const permissions = [ 'write:admin:unset-user-banner', 'write:admin:unsuspend-user', 'write:admin:reject-quotes', + 'write:admin:restart-migration', 'write:admin:meta', 'write:admin:user-note', 'write:admin:roles', @@ -339,6 +340,11 @@ export type ModerationLogPayloads = { userUsername: string; userHost: string | null; }; + restartMigration: { + userId: string; + userUsername: string; + userHost: string | null; + }; setMandatoryCW: { newCW: string | null; oldCW: string | null; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 6b369fc52d..abc3f08bb8 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -139,6 +139,9 @@ export type ModerationLog = { } | { type: 'setMandatoryCWForInstance'; info: ModerationLogPayloads['setMandatoryCWForInstance']; +} | { + type: 'restartMigration'; + info: ModerationLogPayloads['restartMigration']; } | { type: 'resetPassword'; info: ModerationLogPayloads['resetPassword'];