diff --git a/locales/en-US.yml b/locales/en-US.yml index 852013f8ba..a763d96728 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -630,6 +630,7 @@ unsetUserBanner: "Unset banner" unsetUserBannerConfirm: "Are you sure you want to unset the banner?" deleteAllFiles: "Delete all files" deleteAllFilesConfirm: "Are you sure that you want to delete all files?" +deleteAllFilesQueued: "Deletion of all files queued" removeAllFollowing: "Unfollow all followed users" removeAllFollowingDescription: "Executing this unfollows all accounts from {host}. Please run this if the instance e.g. no longer exists." userSuspended: "This user has been suspended." @@ -1339,6 +1340,10 @@ confirmWhenRevealingSensitiveMedia: "Confirm when revealing sensitive media" sensitiveMediaRevealConfirm: "This media might be sensitive. Are you sure you want to reveal it?" createdLists: "Created lists" createdAntennas: "Created antennas" +severAllFollowRelations: "Break following relationships" +severAllFollowRelationsConfirm: "Really break all follow relationships? This is irreversible! This will break {followingCount} following and {followersCount} follower relations on {instanceName}!" +severAllFollowRelationsQueued: "Severing all follow relations with {host} queued." + _delivery: status: "Delivery status" stop: "Suspend delivery" diff --git a/locales/index.d.ts b/locales/index.d.ts index 57d5536cf4..f77457108e 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -2536,6 +2536,10 @@ export interface Locale extends ILocale { * すべてのファイルを削除しますか? */ "deleteAllFilesConfirm": string; + /** + * キューに入れられたすべてのファイルの削除 + */ + "deleteAllFilesQueued": string; /** * フォローを全解除 */ @@ -5373,6 +5377,18 @@ export interface Locale extends ILocale { * 作成したアンテナ */ "createdAntennas": string; + /** + * 以下の関係をすべて断ち切る + */ + "severAllFollowRelations": string; + /** + * すべての人間関係を壊す?これは不可逆です!これは{instanceName}の{followingCount}フォローと{followersCount}フォロワーの関係を壊す! + */ + "severAllFollowRelationsConfirm": ParameterizedString<"instanceName" | "followingCount" | "followersCount">; + /** + * キューに入れられた{host}とのすべてのフォロー関係を切断する。 + */ + "severAllFollowRelationsQueued": ParameterizedString<"host">; "_delivery": { /** * 配信状態 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index ceb8e04419..d688160968 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -630,6 +630,7 @@ unsetUserBanner: "バナーを解除" unsetUserBannerConfirm: "バナーを解除しますか?" deleteAllFiles: "すべてのファイルを削除" deleteAllFilesConfirm: "すべてのファイルを削除しますか?" +deleteAllFilesQueued: "キューに入れられたすべてのファイルの削除" removeAllFollowing: "フォローを全解除" removeAllFollowingDescription: "{host}からのフォローをすべて解除します。そのサーバーがもう存在しなくなった場合などに実行してください。" userSuspended: "このユーザーは凍結されています。" @@ -1339,6 +1340,9 @@ confirmWhenRevealingSensitiveMedia: "センシティブなメディアを表示 sensitiveMediaRevealConfirm: "センシティブなメディアです。表示しますか?" createdLists: "作成したリスト" createdAntennas: "作成したアンテナ" +severAllFollowRelations: "以下の関係をすべて断ち切る" +severAllFollowRelationsConfirm: "すべての人間関係を壊す?これは不可逆です!これは{instanceName}の{followingCount}フォローと{followersCount}フォロワーの関係を壊す!" +severAllFollowRelationsQueued: "キューに入れられた{host}とのすべてのフォロー関係を切断する。" _delivery: status: "配信状態" diff --git a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts index 9e93310746..601c898f52 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts @@ -31,15 +31,20 @@ export default class extends Endpoint { // eslint- @Inject(DI.usersRepository) private usersRepository: UsersRepository, - @Inject(DI.notesRepository) + @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, private queueService: QueueService, ) { super(meta, paramDef, async (ps, me) => { - const followings = await this.followingsRepository.findBy({ - followerHost: ps.host, - }); + const followings = await this.followingsRepository.findBy([ + { + followeeHost: ps.host, + }, + { + followerHost: ps.host, + }, + ]); const pairs = await Promise.all(followings.map(f => Promise.all([ this.usersRepository.findOneByOrFail({ id: f.followerId }), diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue index 5401ea51e0..95371036aa 100644 --- a/packages/frontend/src/pages/instance-info.vue +++ b/packages/frontend/src/pages/instance-info.vue @@ -43,8 +43,12 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts._delivery._type[suspensionState] }} - {{ i18n.ts._delivery.stop }} - {{ i18n.ts._delivery.resume }} +
+ {{ i18n.ts.deleteAllFiles }} + {{ i18n.ts.severAllFollowRelations }} + {{ i18n.ts._delivery.stop }} + {{ i18n.ts._delivery.resume }} +
{{ i18n.ts.blockedByBase }} {{ i18n.ts.blockThisInstance }} {{ i18n.ts.silencedByBase }} @@ -300,6 +304,43 @@ function refreshMetadata(): void { }); } +async function deleteAllFiles(): void { + const confirm = await os.confirm({ + type: 'danger', + text: i18n.ts.deleteAllFilesConfirm, + }); + if (confirm.canceled) return; + + if (!instance.value) throw new Error('No instance?'); + await misskeyApi('admin/federation/delete-all-files', { + host: instance.value.host, + }); + await os.alert({ + text: i18n.ts.deleteAllFilesQueued, + }); +} + +async function severAllFollowRelations(): void { + if (!instance.value) throw new Error('No instance?'); + + const confirm = await os.confirm({ + type: 'danger', + text: i18n.tsx.severAllFollowRelationsConfirm({ + instanceName: meta.value.shortName ?? meta.value.name, + followingCount: instance.value.followingCount, + followersCount: instance.value.followersCount, + }), + }); + if (confirm.canceled) return; + + await misskeyApi('admin/federation/remove-all-following', { + host: instance.value.host, + }); + await os.alert({ + text: i18n.tsx.severAllFollowRelationsQueued({ host: instance.value.host }), + }); +} + fetch(); const headerActions = computed(() => [{