merge: Add controls to delete all files or sever all relations with a remote instance (!654)

View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/654

Approved-by: Marie <github@yuugi.dev>
Approved-by: Hazelnoot <acomputerdog@gmail.com>
This commit is contained in:
Hazelnoot 2024-10-06 21:33:39 +00:00
commit 934e007698
5 changed files with 77 additions and 6 deletions

View file

@ -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"

16
locales/index.d.ts vendored
View file

@ -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": {
/**
*

View file

@ -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: "配信状態"

View file

@ -31,15 +31,20 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // 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 }),

View file

@ -43,8 +43,12 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts._delivery._type[suspensionState] }}
</template>
</MkKeyValue>
<MkButton v-if="suspensionState === 'none'" :disabled="!instance" danger @click="stopDelivery">{{ i18n.ts._delivery.stop }}</MkButton>
<MkButton v-if="suspensionState !== 'none'" :disabled="!instance" @click="resumeDelivery">{{ i18n.ts._delivery.resume }}</MkButton>
<div class="_buttons">
<MkButton inline :disabled="!instance" danger @click="deleteAllFiles">{{ i18n.ts.deleteAllFiles }}</MkButton>
<MkButton inline :disabled="!instance" danger @click="severAllFollowRelations">{{ i18n.ts.severAllFollowRelations }}</MkButton>
<MkButton v-if="suspensionState === 'none'" inline :disabled="!instance" danger @click="stopDelivery">{{ i18n.ts._delivery.stop }}</MkButton>
<MkButton v-if="suspensionState !== 'none'" inline :disabled="!instance" @click="resumeDelivery">{{ i18n.ts._delivery.resume }}</MkButton>
</div>
<MkInfo v-if="isBaseBlocked" warn>{{ i18n.ts.blockedByBase }}</MkInfo>
<MkSwitch v-model="isBlocked" :disabled="!meta || !instance || isBaseBlocked" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch>
<MkInfo v-if="isBaseSilenced" warn>{{ i18n.ts.silencedByBase }}</MkInfo>
@ -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(() => [{