Merge branch 'develop' into emoji-request
This commit is contained in:
commit
198f7748ce
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- Feat: アンテナでローカルの投稿のみ収集できるようになりました
|
- Feat: アンテナでローカルの投稿のみ収集できるようになりました
|
||||||
|
- Feat: サーバーサイレンス機能が追加されました
|
||||||
|
- Enhance: 依存関係の更新
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Enhance: TLの返信表示オプションを記憶するように
|
- Enhance: TLの返信表示オプションを記憶するように
|
||||||
|
|
|
@ -195,6 +195,7 @@ perHour: "Per Hour"
|
||||||
perDay: "Per Day"
|
perDay: "Per Day"
|
||||||
stopActivityDelivery: "Stop sending activities"
|
stopActivityDelivery: "Stop sending activities"
|
||||||
blockThisInstance: "Block this instance"
|
blockThisInstance: "Block this instance"
|
||||||
|
silenceThisInstance: "Silence this instance"
|
||||||
operations: "Operations"
|
operations: "Operations"
|
||||||
software: "Software"
|
software: "Software"
|
||||||
version: "Version"
|
version: "Version"
|
||||||
|
@ -213,6 +214,13 @@ clearQueueConfirmText: "Any undelivered notes remaining in the queue will not be
|
||||||
clearCachedFiles: "Clear cache"
|
clearCachedFiles: "Clear cache"
|
||||||
clearCachedFilesConfirm: "Are you sure that you want to delete all cached remote files?"
|
clearCachedFilesConfirm: "Are you sure that you want to delete all cached remote files?"
|
||||||
blockedInstances: "Blocked Instances"
|
blockedInstances: "Blocked Instances"
|
||||||
|
silencedInstances: "Silenced Instances"
|
||||||
|
silencedInstancesDescription: "List the hostnames of the instances that you want to\
|
||||||
|
\ silence. Accounts in the listed instances are treated as \"Silenced\", can only make follow requests, and cannot mention local accounts if not followed. This will not affect the blocked instances."
|
||||||
|
hiddenTags: "Hidden Hashtags"
|
||||||
|
hiddenTagsDescription: "List the hashtags (without the #) of the hashtags you wish\
|
||||||
|
\ to hide from trending and explore. Hidden hashtags are still discoverable via\
|
||||||
|
\ other means. Blocked instances are not affected even if listed here."
|
||||||
blockedInstancesDescription: "List the hostnames of the instances that you want to block separated by linebreaks. Listed instances will no longer be able to communicate with this instance."
|
blockedInstancesDescription: "List the hostnames of the instances that you want to block separated by linebreaks. Listed instances will no longer be able to communicate with this instance."
|
||||||
muteAndBlock: "Mutes and Blocks"
|
muteAndBlock: "Mutes and Blocks"
|
||||||
mutedUsers: "Muted users"
|
mutedUsers: "Muted users"
|
||||||
|
@ -794,7 +802,7 @@ active: "Active"
|
||||||
offline: "Offline"
|
offline: "Offline"
|
||||||
notRecommended: "Not recommended"
|
notRecommended: "Not recommended"
|
||||||
botProtection: "Bot Protection"
|
botProtection: "Bot Protection"
|
||||||
instanceBlocking: "Blocked Instances"
|
instanceBlocking: "Blocked/Silenced Instances"
|
||||||
selectAccount: "Select account"
|
selectAccount: "Select account"
|
||||||
switchAccount: "Switch account"
|
switchAccount: "Switch account"
|
||||||
enabled: "Enabled"
|
enabled: "Enabled"
|
||||||
|
|
3
locales/index.d.ts
vendored
3
locales/index.d.ts
vendored
|
@ -198,6 +198,7 @@ export interface Locale {
|
||||||
"perDay": string;
|
"perDay": string;
|
||||||
"stopActivityDelivery": string;
|
"stopActivityDelivery": string;
|
||||||
"blockThisInstance": string;
|
"blockThisInstance": string;
|
||||||
|
"silenceThisInstance": string;
|
||||||
"operations": string;
|
"operations": string;
|
||||||
"software": string;
|
"software": string;
|
||||||
"version": string;
|
"version": string;
|
||||||
|
@ -217,6 +218,8 @@ export interface Locale {
|
||||||
"clearCachedFilesConfirm": string;
|
"clearCachedFilesConfirm": string;
|
||||||
"blockedInstances": string;
|
"blockedInstances": string;
|
||||||
"blockedInstancesDescription": string;
|
"blockedInstancesDescription": string;
|
||||||
|
"silencedInstances": string;
|
||||||
|
"silencedInstancesDescription": string;
|
||||||
"muteAndBlock": string;
|
"muteAndBlock": string;
|
||||||
"mutedUsers": string;
|
"mutedUsers": string;
|
||||||
"blockedUsers": string;
|
"blockedUsers": string;
|
||||||
|
|
|
@ -195,6 +195,7 @@ perHour: "1時間ごと"
|
||||||
perDay: "1日ごと"
|
perDay: "1日ごと"
|
||||||
stopActivityDelivery: "アクティビティの配送を停止"
|
stopActivityDelivery: "アクティビティの配送を停止"
|
||||||
blockThisInstance: "このサーバーをブロック"
|
blockThisInstance: "このサーバーをブロック"
|
||||||
|
silenceThisInstance: "サーバーをサイレンス"
|
||||||
operations: "操作"
|
operations: "操作"
|
||||||
software: "ソフトウェア"
|
software: "ソフトウェア"
|
||||||
version: "バージョン"
|
version: "バージョン"
|
||||||
|
@ -213,7 +214,9 @@ clearQueueConfirmText: "未配達の投稿は配送されなくなります。
|
||||||
clearCachedFiles: "キャッシュをクリア"
|
clearCachedFiles: "キャッシュをクリア"
|
||||||
clearCachedFilesConfirm: "キャッシュされたリモートファイルをすべて削除しますか?"
|
clearCachedFilesConfirm: "キャッシュされたリモートファイルをすべて削除しますか?"
|
||||||
blockedInstances: "ブロックしたサーバー"
|
blockedInstances: "ブロックしたサーバー"
|
||||||
blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定します。ブロックされたサーバーは、このサーバーとやり取りできなくなります。サブドメインもブロックされます。"
|
blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定します。ブロックされたサーバーは、このインスタンスとやり取りできなくなります。"
|
||||||
|
silencedInstances: "サイレンスしたサーバー"
|
||||||
|
silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定します。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなります。ブロックしたインスタンスには影響しません。"
|
||||||
muteAndBlock: "ミュートとブロック"
|
muteAndBlock: "ミュートとブロック"
|
||||||
mutedUsers: "ミュートしたユーザー"
|
mutedUsers: "ミュートしたユーザー"
|
||||||
blockedUsers: "ブロックしたユーザー"
|
blockedUsers: "ブロックしたユーザー"
|
||||||
|
@ -797,7 +800,7 @@ active: "アクティブ"
|
||||||
offline: "オフライン"
|
offline: "オフライン"
|
||||||
notRecommended: "非推奨"
|
notRecommended: "非推奨"
|
||||||
botProtection: "Botプロテクション"
|
botProtection: "Botプロテクション"
|
||||||
instanceBlocking: "サーバーブロック"
|
instanceBlocking: "サーバーブロック・サイレンス"
|
||||||
selectAccount: "アカウントを選択"
|
selectAccount: "アカウントを選択"
|
||||||
switchAccount: "アカウントを切り替え"
|
switchAccount: "アカウントを切り替え"
|
||||||
enabled: "有効"
|
enabled: "有効"
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
"@typescript-eslint/eslint-plugin": "6.7.5",
|
"@typescript-eslint/eslint-plugin": "6.7.5",
|
||||||
"@typescript-eslint/parser": "6.7.5",
|
"@typescript-eslint/parser": "6.7.5",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "13.3.0",
|
"cypress": "13.3.1",
|
||||||
"eslint": "8.51.0",
|
"eslint": "8.51.0",
|
||||||
"start-server-and-test": "2.0.1"
|
"start-server-and-test": "2.0.1"
|
||||||
},
|
},
|
||||||
|
|
16
packages/backend/migration/1697247230117-InstanceSilence.js
Normal file
16
packages/backend/migration/1697247230117-InstanceSilence.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class InstanceSilence1697247230117 {
|
||||||
|
name = 'InstanceSilence1697247230117'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "silencedHosts" character varying(1024) array NOT NULL DEFAULT '{}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "silencedHosts"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,10 +75,10 @@
|
||||||
"@nestjs/core": "10.2.7",
|
"@nestjs/core": "10.2.7",
|
||||||
"@nestjs/testing": "10.2.7",
|
"@nestjs/testing": "10.2.7",
|
||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
"@simplewebauthn/server": "8.2.0",
|
"@simplewebauthn/server": "8.3.2",
|
||||||
"@sinonjs/fake-timers": "11.1.0",
|
"@sinonjs/fake-timers": "11.1.0",
|
||||||
"@swc/cli": "0.1.62",
|
"@swc/cli": "0.1.62",
|
||||||
"@swc/core": "1.3.92",
|
"@swc/core": "1.3.93",
|
||||||
"accepts": "1.3.8",
|
"accepts": "1.3.8",
|
||||||
"ajv": "8.12.0",
|
"ajv": "8.12.0",
|
||||||
"archiver": "6.0.1",
|
"archiver": "6.0.1",
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"body-parser": "1.20.2",
|
"body-parser": "1.20.2",
|
||||||
"bullmq": "4.12.3",
|
"bullmq": "4.12.4",
|
||||||
"cacheable-lookup": "7.0.0",
|
"cacheable-lookup": "7.0.0",
|
||||||
"cbor": "9.0.1",
|
"cbor": "9.0.1",
|
||||||
"chalk": "5.3.0",
|
"chalk": "5.3.0",
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
"content-disposition": "0.5.4",
|
"content-disposition": "0.5.4",
|
||||||
"date-fns": "2.30.0",
|
"date-fns": "2.30.0",
|
||||||
"deep-email-validator": "0.1.21",
|
"deep-email-validator": "0.1.21",
|
||||||
"fastify": "4.23.2",
|
"fastify": "4.24.2",
|
||||||
"feed": "4.2.2",
|
"feed": "4.2.2",
|
||||||
"file-type": "18.5.0",
|
"file-type": "18.5.0",
|
||||||
"fluent-ffmpeg": "2.1.2",
|
"fluent-ffmpeg": "2.1.2",
|
||||||
|
@ -121,13 +121,13 @@
|
||||||
"mime-types": "2.1.35",
|
"mime-types": "2.1.35",
|
||||||
"misskey-js": "workspace:*",
|
"misskey-js": "workspace:*",
|
||||||
"ms": "3.0.0-canary.1",
|
"ms": "3.0.0-canary.1",
|
||||||
"nanoid": "5.0.1",
|
"nanoid": "5.0.2",
|
||||||
"nested-property": "4.0.0",
|
"nested-property": "4.0.0",
|
||||||
"node-fetch": "3.3.2",
|
"node-fetch": "3.3.2",
|
||||||
"nodemailer": "6.9.6",
|
"nodemailer": "6.9.6",
|
||||||
"nsfwjs": "2.4.2",
|
"nsfwjs": "2.4.2",
|
||||||
"oauth": "0.10.0",
|
"oauth": "0.10.0",
|
||||||
"oauth2orize": "1.11.1",
|
"oauth2orize": "1.12.0",
|
||||||
"oauth2orize-pkce": "0.1.2",
|
"oauth2orize-pkce": "0.1.2",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
"otpauth": "9.1.5",
|
"otpauth": "9.1.5",
|
||||||
|
@ -183,26 +183,26 @@
|
||||||
"@types/fluent-ffmpeg": "2.1.22",
|
"@types/fluent-ffmpeg": "2.1.22",
|
||||||
"@types/http-link-header": "1.0.3",
|
"@types/http-link-header": "1.0.3",
|
||||||
"@types/jest": "29.5.5",
|
"@types/jest": "29.5.5",
|
||||||
"@types/js-yaml": "4.0.6",
|
"@types/js-yaml": "4.0.7",
|
||||||
"@types/jsdom": "21.1.3",
|
"@types/jsdom": "21.1.3",
|
||||||
"@types/jsonld": "1.5.10",
|
"@types/jsonld": "1.5.10",
|
||||||
"@types/jsrsasign": "10.5.9",
|
"@types/jsrsasign": "10.5.9",
|
||||||
"@types/mime-types": "2.1.2",
|
"@types/mime-types": "2.1.2",
|
||||||
"@types/ms": "0.7.32",
|
"@types/ms": "0.7.32",
|
||||||
"@types/node": "20.8.4",
|
"@types/node": "20.8.6",
|
||||||
"@types/node-fetch": "3.0.3",
|
"@types/node-fetch": "3.0.3",
|
||||||
"@types/nodemailer": "6.4.11",
|
"@types/nodemailer": "6.4.11",
|
||||||
"@types/oauth": "0.9.2",
|
"@types/oauth": "0.9.2",
|
||||||
"@types/oauth2orize": "1.11.1",
|
"@types/oauth2orize": "1.11.1",
|
||||||
"@types/oauth2orize-pkce": "0.1.0",
|
"@types/oauth2orize-pkce": "0.1.0",
|
||||||
"@types/pg": "8.10.4",
|
"@types/pg": "8.10.5",
|
||||||
"@types/pug": "2.0.7",
|
"@types/pug": "2.0.7",
|
||||||
"@types/punycode": "2.1.0",
|
"@types/punycode": "2.1.0",
|
||||||
"@types/qrcode": "1.5.2",
|
"@types/qrcode": "1.5.2",
|
||||||
"@types/random-seed": "0.3.3",
|
"@types/random-seed": "0.3.3",
|
||||||
"@types/ratelimiter": "3.4.4",
|
"@types/ratelimiter": "3.4.4",
|
||||||
"@types/rename": "1.0.5",
|
"@types/rename": "1.0.5",
|
||||||
"@types/sanitize-html": "2.9.1",
|
"@types/sanitize-html": "2.9.2",
|
||||||
"@types/semver": "7.5.3",
|
"@types/semver": "7.5.3",
|
||||||
"@types/sharp": "0.32.0",
|
"@types/sharp": "0.32.0",
|
||||||
"@types/simple-oauth2": "5.0.5",
|
"@types/simple-oauth2": "5.0.5",
|
||||||
|
@ -211,7 +211,7 @@
|
||||||
"@types/tmp": "0.2.4",
|
"@types/tmp": "0.2.4",
|
||||||
"@types/vary": "1.1.1",
|
"@types/vary": "1.1.1",
|
||||||
"@types/web-push": "3.6.1",
|
"@types/web-push": "3.6.1",
|
||||||
"@types/ws": "8.5.6",
|
"@types/ws": "8.5.7",
|
||||||
"@typescript-eslint/eslint-plugin": "6.7.5",
|
"@typescript-eslint/eslint-plugin": "6.7.5",
|
||||||
"@typescript-eslint/parser": "6.7.5",
|
"@typescript-eslint/parser": "6.7.5",
|
||||||
"aws-sdk-client-mock": "3.0.0",
|
"aws-sdk-client-mock": "3.0.0",
|
||||||
|
|
|
@ -56,6 +56,7 @@ import { SearchService } from '@/core/SearchService.js';
|
||||||
import { FeaturedService } from '@/core/FeaturedService.js';
|
import { FeaturedService } from '@/core/FeaturedService.js';
|
||||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||||
import { nyaize } from '@/misc/nyaize.js';
|
import { nyaize } from '@/misc/nyaize.js';
|
||||||
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
|
||||||
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
||||||
|
|
||||||
|
@ -215,6 +216,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
private perUserNotesChart: PerUserNotesChart,
|
private perUserNotesChart: PerUserNotesChart,
|
||||||
private activeUsersChart: ActiveUsersChart,
|
private activeUsersChart: ActiveUsersChart,
|
||||||
private instanceChart: InstanceChart,
|
private instanceChart: InstanceChart,
|
||||||
|
private utilityService: UtilityService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -259,6 +261,12 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const inSilencedInstance = this.utilityService.isSilencedHost((await this.metaService.fetch()).silencedHosts, user.host);
|
||||||
|
|
||||||
|
if (data.visibility === 'public' && inSilencedInstance && user.host !== null) {
|
||||||
|
data.visibility = 'home';
|
||||||
|
}
|
||||||
|
|
||||||
if (data.renote) {
|
if (data.renote) {
|
||||||
switch (data.renote.visibility) {
|
switch (data.renote.visibility) {
|
||||||
case 'public':
|
case 'public':
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable, OnModuleInit, forwardRef } from '@nestjs/common';
|
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
import { ModuleRef } from '@nestjs/core';
|
import { ModuleRef } from '@nestjs/core';
|
||||||
import { IsNull } from 'typeorm';
|
import { IsNull } from 'typeorm';
|
||||||
import type { MiLocalUser, MiPartialLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser } from '@/models/User.js';
|
import type { MiLocalUser, MiPartialLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser } from '@/models/User.js';
|
||||||
|
@ -34,6 +34,7 @@ import { MetaService } from '@/core/MetaService.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { AccountMoveService } from '@/core/AccountMoveService.js';
|
import { AccountMoveService } from '@/core/AccountMoveService.js';
|
||||||
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import Logger from '../logger.js';
|
import Logger from '../logger.js';
|
||||||
|
|
||||||
const logger = new Logger('following/create');
|
const logger = new Logger('following/create');
|
||||||
|
@ -70,6 +71,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
@Inject(DI.instancesRepository)
|
@Inject(DI.instancesRepository)
|
||||||
private instancesRepository: InstancesRepository,
|
private instancesRepository: InstancesRepository,
|
||||||
private cacheService: CacheService,
|
private cacheService: CacheService,
|
||||||
|
private utilityService: UtilityService,
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
|
@ -119,15 +121,16 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id });
|
const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id });
|
||||||
|
|
||||||
// フォロー対象が鍵アカウントである or
|
// フォロー対象が鍵アカウントである or
|
||||||
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
|
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
|
||||||
// フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである
|
// フォロワーがローカルユーザーであり、フォロー対象がリモートユーザーである or
|
||||||
|
// フォロワーがローカルユーザーであり、フォロー対象がサイレンスされているサーバーである
|
||||||
// 上記のいずれかに当てはまる場合はすぐフォローせずにフォローリクエストを発行しておく
|
// 上記のいずれかに当てはまる場合はすぐフォローせずにフォローリクエストを発行しておく
|
||||||
if (
|
if (
|
||||||
followee.isLocked ||
|
followee.isLocked ||
|
||||||
(followeeProfile.carefulBot && follower.isBot) ||
|
(followeeProfile.carefulBot && follower.isBot) ||
|
||||||
(this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee) && process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING !== 'true')
|
(this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee) && process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING !== 'true') ||
|
||||||
|
(this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower) && this.utilityService.isSilencedHost((await this.metaService.fetch()).silencedHosts, follower.host))
|
||||||
) {
|
) {
|
||||||
let autoAccept = false;
|
let autoAccept = false;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,12 @@ export class UtilityService {
|
||||||
return blockedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
|
return blockedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public isSilencedHost(silencedHosts: string[] | undefined, host: string | null): boolean {
|
||||||
|
if (!silencedHosts || host == null) return false;
|
||||||
|
return silencedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public extractDbHost(uri: string): string {
|
public extractDbHost(uri: string): string {
|
||||||
const url = new URL(uri);
|
const url = new URL(uri);
|
||||||
|
|
|
@ -3,9 +3,8 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
import type { } from '@/models/Blocking.js';
|
|
||||||
import type { MiInstance } from '@/models/Instance.js';
|
import type { MiInstance } from '@/models/Instance.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
@ -43,6 +42,7 @@ export class InstanceEntityService {
|
||||||
description: instance.description,
|
description: instance.description,
|
||||||
maintainerName: instance.maintainerName,
|
maintainerName: instance.maintainerName,
|
||||||
maintainerEmail: instance.maintainerEmail,
|
maintainerEmail: instance.maintainerEmail,
|
||||||
|
isSilenced: this.utilityService.isSilencedHost(meta.silencedHosts, instance.host),
|
||||||
iconUrl: instance.iconUrl,
|
iconUrl: instance.iconUrl,
|
||||||
faviconUrl: instance.faviconUrl,
|
faviconUrl: instance.faviconUrl,
|
||||||
themeColor: instance.themeColor,
|
themeColor: instance.themeColor,
|
||||||
|
|
|
@ -76,6 +76,11 @@ export class MiMeta {
|
||||||
})
|
})
|
||||||
public sensitiveWords: string[];
|
public sensitiveWords: string[];
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 1024, array: true, default: '{}',
|
||||||
|
})
|
||||||
|
public silencedHosts: string[];
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 1024,
|
length: 1024,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
|
@ -93,6 +93,11 @@ export const packedFederationInstanceSchema = {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
},
|
},
|
||||||
|
isSilenced: {
|
||||||
|
type: "boolean",
|
||||||
|
optional: false,
|
||||||
|
nullable: false,
|
||||||
|
},
|
||||||
infoUpdatedAt: {
|
infoUpdatedAt: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
|
|
|
@ -105,6 +105,16 @@ export const meta = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
|
silencedHosts: {
|
||||||
|
type: "array",
|
||||||
|
optional: true,
|
||||||
|
nullable: false,
|
||||||
|
items: {
|
||||||
|
type: "string",
|
||||||
|
optional: false,
|
||||||
|
nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
pinnedUsers: {
|
pinnedUsers: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
@ -367,6 +377,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
pinnedUsers: instance.pinnedUsers,
|
pinnedUsers: instance.pinnedUsers,
|
||||||
hiddenTags: instance.hiddenTags,
|
hiddenTags: instance.hiddenTags,
|
||||||
blockedHosts: instance.blockedHosts,
|
blockedHosts: instance.blockedHosts,
|
||||||
|
silencedHosts: instance.silencedHosts,
|
||||||
sensitiveWords: instance.sensitiveWords,
|
sensitiveWords: instance.sensitiveWords,
|
||||||
preservedUsernames: instance.preservedUsernames,
|
preservedUsernames: instance.preservedUsernames,
|
||||||
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
||||||
|
|
|
@ -20,18 +20,26 @@ export const paramDef = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
disableRegistration: { type: 'boolean', nullable: true },
|
disableRegistration: { type: 'boolean', nullable: true },
|
||||||
pinnedUsers: { type: 'array', nullable: true, items: {
|
pinnedUsers: {
|
||||||
type: 'string',
|
type: 'array', nullable: true, items: {
|
||||||
} },
|
type: 'string',
|
||||||
hiddenTags: { type: 'array', nullable: true, items: {
|
},
|
||||||
type: 'string',
|
},
|
||||||
} },
|
hiddenTags: {
|
||||||
blockedHosts: { type: 'array', nullable: true, items: {
|
type: 'array', nullable: true, items: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
} },
|
},
|
||||||
sensitiveWords: { type: 'array', nullable: true, items: {
|
},
|
||||||
type: 'string',
|
blockedHosts: {
|
||||||
} },
|
type: 'array', nullable: true, items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sensitiveWords: {
|
||||||
|
type: 'array', nullable: true, items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' },
|
themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' },
|
||||||
mascotImageUrl: { type: 'string', nullable: true },
|
mascotImageUrl: { type: 'string', nullable: true },
|
||||||
bannerUrl: { type: 'string', nullable: true },
|
bannerUrl: { type: 'string', nullable: true },
|
||||||
|
@ -67,9 +75,11 @@ export const paramDef = {
|
||||||
proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true },
|
proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
maintainerName: { type: 'string', nullable: true },
|
maintainerName: { type: 'string', nullable: true },
|
||||||
maintainerEmail: { type: 'string', nullable: true },
|
maintainerEmail: { type: 'string', nullable: true },
|
||||||
langs: { type: 'array', items: {
|
langs: {
|
||||||
type: 'string',
|
type: 'array', items: {
|
||||||
} },
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
summalyProxy: { type: 'string', nullable: true },
|
summalyProxy: { type: 'string', nullable: true },
|
||||||
deeplAuthKey: { type: 'string', nullable: true },
|
deeplAuthKey: { type: 'string', nullable: true },
|
||||||
deeplIsPro: { type: 'boolean' },
|
deeplIsPro: { type: 'boolean' },
|
||||||
|
@ -115,6 +125,13 @@ export const paramDef = {
|
||||||
perUserHomeTimelineCacheMax: { type: 'integer' },
|
perUserHomeTimelineCacheMax: { type: 'integer' },
|
||||||
perUserListTimelineCacheMax: { type: 'integer' },
|
perUserListTimelineCacheMax: { type: 'integer' },
|
||||||
notesPerOneAd: { type: 'integer' },
|
notesPerOneAd: { type: 'integer' },
|
||||||
|
silencedHosts: {
|
||||||
|
type: 'array',
|
||||||
|
nullable: true,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -147,7 +164,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
if (Array.isArray(ps.sensitiveWords)) {
|
if (Array.isArray(ps.sensitiveWords)) {
|
||||||
set.sensitiveWords = ps.sensitiveWords.filter(Boolean);
|
set.sensitiveWords = ps.sensitiveWords.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
if (Array.isArray(ps.silencedHosts)) {
|
||||||
|
let lastValue = '';
|
||||||
|
set.silencedHosts = ps.silencedHosts.sort().filter((h) => {
|
||||||
|
const lv = lastValue;
|
||||||
|
lastValue = h;
|
||||||
|
return h !== '' && h !== lv && !set.blockedHosts?.includes(h);
|
||||||
|
});
|
||||||
|
}
|
||||||
if (ps.themeColor !== undefined) {
|
if (ps.themeColor !== undefined) {
|
||||||
set.themeColor = ps.themeColor;
|
set.themeColor = ps.themeColor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ export const paramDef = {
|
||||||
blocked: { type: 'boolean', nullable: true },
|
blocked: { type: 'boolean', nullable: true },
|
||||||
notResponding: { type: 'boolean', nullable: true },
|
notResponding: { type: 'boolean', nullable: true },
|
||||||
suspended: { type: 'boolean', nullable: true },
|
suspended: { type: 'boolean', nullable: true },
|
||||||
|
silenced: { type: "boolean", nullable: true },
|
||||||
federating: { type: 'boolean', nullable: true },
|
federating: { type: 'boolean', nullable: true },
|
||||||
subscribing: { type: 'boolean', nullable: true },
|
subscribing: { type: 'boolean', nullable: true },
|
||||||
publishing: { type: 'boolean', nullable: true },
|
publishing: { type: 'boolean', nullable: true },
|
||||||
|
@ -102,6 +103,23 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof ps.silenced === "boolean") {
|
||||||
|
const meta = await this.metaService.fetch(true);
|
||||||
|
|
||||||
|
if (ps.silenced) {
|
||||||
|
if (meta.silencedHosts.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
query.andWhere("instance.host IN (:...silences)", {
|
||||||
|
silences: meta.silencedHosts,
|
||||||
|
});
|
||||||
|
} else if (meta.silencedHosts.length > 0) {
|
||||||
|
query.andWhere("instance.host NOT IN (:...silences)", {
|
||||||
|
silences: meta.silencedHosts,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof ps.federating === 'boolean') {
|
if (typeof ps.federating === 'boolean') {
|
||||||
if (ps.federating) {
|
if (ps.federating) {
|
||||||
query.andWhere('((instance.followingCount > 0) OR (instance.followersCount > 0))');
|
query.andWhere('((instance.followingCount > 0) OR (instance.followersCount > 0))');
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"@github/webauthn-json": "2.1.1",
|
"@github/webauthn-json": "2.1.1",
|
||||||
"@rollup/plugin-alias": "5.0.1",
|
"@rollup/plugin-alias": "5.0.1",
|
||||||
"@rollup/plugin-json": "6.0.1",
|
"@rollup/plugin-json": "6.0.1",
|
||||||
"@rollup/plugin-replace": "5.0.3",
|
"@rollup/plugin-replace": "5.0.4",
|
||||||
"@rollup/pluginutils": "5.0.5",
|
"@rollup/pluginutils": "5.0.5",
|
||||||
"@syuilo/aiscript": "0.16.0",
|
"@syuilo/aiscript": "0.16.0",
|
||||||
"@tabler/icons-webfont": "2.37.0",
|
"@tabler/icons-webfont": "2.37.0",
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
"@vue/compiler-sfc": "3.3.4",
|
"@vue/compiler-sfc": "3.3.4",
|
||||||
"astring": "1.8.6",
|
"astring": "1.8.6",
|
||||||
"autosize": "6.0.1",
|
"autosize": "6.0.1",
|
||||||
"broadcast-channel": "5.3.0",
|
"broadcast-channel": "5.4.0",
|
||||||
"browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3",
|
"browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3",
|
||||||
"buraha": "0.0.1",
|
"buraha": "0.0.1",
|
||||||
"canvas-confetti": "1.6.1",
|
"canvas-confetti": "1.6.1",
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
"chartjs-chart-matrix": "2.0.1",
|
"chartjs-chart-matrix": "2.0.1",
|
||||||
"chartjs-plugin-gradient": "0.6.1",
|
"chartjs-plugin-gradient": "0.6.1",
|
||||||
"chartjs-plugin-zoom": "2.0.1",
|
"chartjs-plugin-zoom": "2.0.1",
|
||||||
"chromatic": "7.2.3",
|
"chromatic": "7.4.0",
|
||||||
"compare-versions": "6.1.0",
|
"compare-versions": "6.1.0",
|
||||||
"cropperjs": "2.0.0-beta.4",
|
"cropperjs": "2.0.0-beta.4",
|
||||||
"date-fns": "2.30.0",
|
"date-fns": "2.30.0",
|
||||||
|
@ -57,9 +57,9 @@
|
||||||
"prismjs": "1.29.0",
|
"prismjs": "1.29.0",
|
||||||
"punycode": "2.3.0",
|
"punycode": "2.3.0",
|
||||||
"querystring": "0.2.1",
|
"querystring": "0.2.1",
|
||||||
"rollup": "4.0.2",
|
"rollup": "4.1.4",
|
||||||
"sanitize-html": "2.11.0",
|
"sanitize-html": "2.11.0",
|
||||||
"sass": "1.69.1",
|
"sass": "1.69.3",
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"three": "0.157.0",
|
"three": "0.157.0",
|
||||||
|
@ -101,21 +101,21 @@
|
||||||
"@types/estree": "1.0.2",
|
"@types/estree": "1.0.2",
|
||||||
"@types/matter-js": "0.19.1",
|
"@types/matter-js": "0.19.1",
|
||||||
"@types/micromatch": "4.0.3",
|
"@types/micromatch": "4.0.3",
|
||||||
"@types/node": "20.8.4",
|
"@types/node": "20.8.6",
|
||||||
"@types/punycode": "2.1.0",
|
"@types/punycode": "2.1.0",
|
||||||
"@types/sanitize-html": "2.9.1",
|
"@types/sanitize-html": "2.9.2",
|
||||||
"@types/throttle-debounce": "5.0.0",
|
"@types/throttle-debounce": "5.0.0",
|
||||||
"@types/tinycolor2": "1.4.4",
|
"@types/tinycolor2": "1.4.4",
|
||||||
"@types/uuid": "9.0.5",
|
"@types/uuid": "9.0.5",
|
||||||
"@types/websocket": "1.0.7",
|
"@types/websocket": "1.0.7",
|
||||||
"@types/ws": "8.5.6",
|
"@types/ws": "8.5.7",
|
||||||
"@typescript-eslint/eslint-plugin": "6.7.5",
|
"@typescript-eslint/eslint-plugin": "6.7.5",
|
||||||
"@typescript-eslint/parser": "6.7.5",
|
"@typescript-eslint/parser": "6.7.5",
|
||||||
"@vitest/coverage-v8": "0.34.6",
|
"@vitest/coverage-v8": "0.34.6",
|
||||||
"@vue/runtime-core": "3.3.4",
|
"@vue/runtime-core": "3.3.4",
|
||||||
"acorn": "8.10.0",
|
"acorn": "8.10.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "13.3.0",
|
"cypress": "13.3.1",
|
||||||
"eslint": "8.51.0",
|
"eslint": "8.51.0",
|
||||||
"eslint-plugin-import": "2.28.1",
|
"eslint-plugin-import": "2.28.1",
|
||||||
"eslint-plugin-vue": "9.17.0",
|
"eslint-plugin-vue": "9.17.0",
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
"happy-dom": "10.0.3",
|
"happy-dom": "10.0.3",
|
||||||
"micromatch": "4.0.5",
|
"micromatch": "4.0.5",
|
||||||
"msw": "1.3.2",
|
"msw": "1.3.2",
|
||||||
"msw-storybook-addon": "1.8.0",
|
"msw-storybook-addon": "1.9.0",
|
||||||
"nodemon": "3.0.1",
|
"nodemon": "3.0.1",
|
||||||
"prettier": "3.0.3",
|
"prettier": "3.0.3",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
@ -136,6 +136,6 @@
|
||||||
"vitest": "0.34.6",
|
"vitest": "0.34.6",
|
||||||
"vitest-fetch-mock": "0.2.2",
|
"vitest-fetch-mock": "0.2.2",
|
||||||
"vue-eslint-parser": "9.3.2",
|
"vue-eslint-parser": "9.3.2",
|
||||||
"vue-tsc": "1.8.18"
|
"vue-tsc": "1.8.19"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="[$style.root, { yellow: instance.isNotResponding, red: instance.isBlocked, gray: instance.isSuspended }]">
|
<div :class="[$style.root, { yellow: instance.isNotResponding, red: instance.isBlocked, gray: instance.isSuspended, blue: instance.isSilenced }]">
|
||||||
<img class="icon" :src="getInstanceIcon(instance)" alt="" loading="lazy"/>
|
<img class="icon" :src="getInstanceIcon(instance)" alt="" loading="lazy"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<span class="host">{{ instance.name ?? instance.host }}</span>
|
<span class="host">{{ instance.name ?? instance.host }}</span>
|
||||||
|
@ -89,6 +89,12 @@ function getInstanceIcon(instance): string {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:global(.blue) {
|
||||||
|
--c: rgba(0, 42, 255, 0.15);
|
||||||
|
background-image: linear-gradient(45deg, var(--c) 16.67%, transparent 16.67%, transparent 50%, var(--c) 50%, var(--c) 66.67%, transparent 66.67%, transparent 100%);
|
||||||
|
background-size: 16px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
&:global(.yellow) {
|
&:global(.yellow) {
|
||||||
--c: rgb(255 196 0 / 15%);
|
--c: rgb(255 196 0 / 15%);
|
||||||
background-image: linear-gradient(45deg, var(--c) 16.67%, transparent 16.67%, transparent 50%, var(--c) 50%, var(--c) 66.67%, transparent 66.67%, transparent 100%);
|
background-image: linear-gradient(45deg, var(--c) 16.67%, transparent 16.67%, transparent 50%, var(--c) 50%, var(--c) 66.67%, transparent 66.67%, transparent 100%);
|
||||||
|
|
|
@ -18,6 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<option value="subscribing">{{ i18n.ts.subscribing }}</option>
|
<option value="subscribing">{{ i18n.ts.subscribing }}</option>
|
||||||
<option value="publishing">{{ i18n.ts.publishing }}</option>
|
<option value="publishing">{{ i18n.ts.publishing }}</option>
|
||||||
<option value="suspended">{{ i18n.ts.suspended }}</option>
|
<option value="suspended">{{ i18n.ts.suspended }}</option>
|
||||||
|
<option value="silenced">{{ i18n.ts.silence }}</option>
|
||||||
<option value="blocked">{{ i18n.ts.blocked }}</option>
|
<option value="blocked">{{ i18n.ts.blocked }}</option>
|
||||||
<option value="notResponding">{{ i18n.ts.notResponding }}</option>
|
<option value="notResponding">{{ i18n.ts.notResponding }}</option>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
|
@ -78,6 +79,7 @@ const pagination = {
|
||||||
state === 'publishing' ? { publishing: true } :
|
state === 'publishing' ? { publishing: true } :
|
||||||
state === 'suspended' ? { suspended: true } :
|
state === 'suspended' ? { suspended: true } :
|
||||||
state === 'blocked' ? { blocked: true } :
|
state === 'blocked' ? { blocked: true } :
|
||||||
|
state === 'silenced' ? { silenced: true } :
|
||||||
state === 'notResponding' ? { notResponding: true } :
|
state === 'notResponding' ? { notResponding: true } :
|
||||||
{}),
|
{}),
|
||||||
})),
|
})),
|
||||||
|
@ -86,6 +88,7 @@ const pagination = {
|
||||||
function getStatus(instance) {
|
function getStatus(instance) {
|
||||||
if (instance.isSuspended) return 'Suspended';
|
if (instance.isSuspended) return 'Suspended';
|
||||||
if (instance.isBlocked) return 'Blocked';
|
if (instance.isBlocked) return 'Blocked';
|
||||||
|
if (instance.isSilenced) return 'Silenced';
|
||||||
if (instance.isNotResponding) return 'Error';
|
if (instance.isNotResponding) return 'Error';
|
||||||
return 'Alive';
|
return 'Alive';
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||||
<FormSuspense :p="init">
|
<FormSuspense :p="init">
|
||||||
<MkTextarea v-model="blockedHosts">
|
<MkTextarea v-if="tab === 'block'" v-model="blockedHosts">
|
||||||
<span>{{ i18n.ts.blockedInstances }}</span>
|
<span>{{ i18n.ts.blockedInstances }}</span>
|
||||||
<template #caption>{{ i18n.ts.blockedInstancesDescription }}</template>
|
<template #caption>{{ i18n.ts.blockedInstancesDescription }}</template>
|
||||||
</MkTextarea>
|
</MkTextarea>
|
||||||
|
<MkTextarea v-else-if="tab === 'silence'" v-model="silencedHosts" class="_formBlock">
|
||||||
|
<span>{{ i18n.ts.silencedInstances }}</span>
|
||||||
|
<template #caption>{{ i18n.ts.silencedInstancesDescription }}</template>
|
||||||
|
</MkTextarea>
|
||||||
<MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
|
<MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
|
||||||
</FormSuspense>
|
</FormSuspense>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
|
@ -22,7 +25,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {} from 'vue';
|
|
||||||
import XHeader from './_header_.vue';
|
import XHeader from './_header_.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
@ -33,15 +35,20 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
|
||||||
let blockedHosts: string = $ref('');
|
let blockedHosts: string = $ref('');
|
||||||
|
let silencedHosts: string = $ref('');
|
||||||
|
let tab = $ref('block');
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
const meta = await os.api('admin/meta');
|
const meta = await os.api('admin/meta');
|
||||||
blockedHosts = meta.blockedHosts.join('\n');
|
blockedHosts = meta.blockedHosts.join('\n');
|
||||||
|
silencedHosts = meta.silencedHosts.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
os.apiWithDialog('admin/update-meta', {
|
os.apiWithDialog('admin/update-meta', {
|
||||||
blockedHosts: blockedHosts.split('\n') || [],
|
blockedHosts: blockedHosts.split('\n') || [],
|
||||||
|
silencedHosts: silencedHosts.split('\n') || [],
|
||||||
|
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance();
|
||||||
});
|
});
|
||||||
|
@ -49,7 +56,15 @@ function save() {
|
||||||
|
|
||||||
const headerActions = $computed(() => []);
|
const headerActions = $computed(() => []);
|
||||||
|
|
||||||
const headerTabs = $computed(() => []);
|
const headerTabs = $computed(() => [{
|
||||||
|
key: 'block',
|
||||||
|
title: i18n.ts.block,
|
||||||
|
icon: 'ti ti-ban',
|
||||||
|
}, {
|
||||||
|
key: 'silence',
|
||||||
|
title: i18n.ts.silence,
|
||||||
|
icon: 'ti ti-eye-off',
|
||||||
|
}]);
|
||||||
|
|
||||||
definePageMetadata({
|
definePageMetadata({
|
||||||
title: i18n.ts.instanceBlocking,
|
title: i18n.ts.instanceBlocking,
|
||||||
|
|
|
@ -36,7 +36,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<MkSwitch v-model="suspended" :disabled="!instance" @update:modelValue="toggleSuspend">{{ i18n.ts.stopActivityDelivery }}</MkSwitch>
|
<MkSwitch v-model="suspended" :disabled="!instance" @update:modelValue="toggleSuspend">{{ i18n.ts.stopActivityDelivery }}</MkSwitch>
|
||||||
<MkSwitch v-model="isBlocked" :disabled="!meta || !instance" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch>
|
<MkSwitch v-model="isBlocked" :disabled="!meta || !instance" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch>
|
||||||
<MkButton @click="refreshMetadata"><i class="ti ti-refresh"></i> Refresh metadata</MkButton>
|
<MkSwitch v-model="isSilenced" :disabled="!meta || !instance" @update:modelValue="toggleSilenced">{{ i18n.ts.silenceThisInstance }}</MkSwitch>
|
||||||
|
<MkButton @click="refreshMetadata"><i class="ti ti-refresh"></i> Refresh metadata</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
|
@ -147,6 +148,7 @@ let meta = $ref<Misskey.entities.AdminInstanceMetadata | null>(null);
|
||||||
let instance = $ref<Misskey.entities.Instance | null>(null);
|
let instance = $ref<Misskey.entities.Instance | null>(null);
|
||||||
let suspended = $ref(false);
|
let suspended = $ref(false);
|
||||||
let isBlocked = $ref(false);
|
let isBlocked = $ref(false);
|
||||||
|
let isSilenced = $ref(false);
|
||||||
let faviconUrl = $ref<string | null>(null);
|
let faviconUrl = $ref<string | null>(null);
|
||||||
|
|
||||||
const usersPagination = {
|
const usersPagination = {
|
||||||
|
@ -169,7 +171,8 @@ async function fetch(): Promise<void> {
|
||||||
});
|
});
|
||||||
suspended = instance.isSuspended;
|
suspended = instance.isSuspended;
|
||||||
isBlocked = instance.isBlocked;
|
isBlocked = instance.isBlocked;
|
||||||
faviconUrl = getProxiedImageUrlNullable(instance.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.iconUrl, 'preview');
|
isSilenced = instance.isSilenced;
|
||||||
|
faviconUrl = getProxiedImageUrlNullable(instance.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.iconUrl, 'preview');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleBlock(): Promise<void> {
|
async function toggleBlock(): Promise<void> {
|
||||||
|
@ -180,7 +183,14 @@ async function toggleBlock(): Promise<void> {
|
||||||
blockedHosts: isBlocked ? meta.blockedHosts.concat([host]) : meta.blockedHosts.filter(x => x !== host),
|
blockedHosts: isBlocked ? meta.blockedHosts.concat([host]) : meta.blockedHosts.filter(x => x !== host),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
async function toggleSilenced(): Promise<void> {
|
||||||
|
if (!meta) throw new Error('No meta?');
|
||||||
|
if (!instance) throw new Error('No instance?');
|
||||||
|
const { host } = instance;
|
||||||
|
await os.api('admin/update-meta', {
|
||||||
|
silencedHosts: isSilenced ? meta.silencedHosts.concat([host]) : meta.silencedHosts.filter(x => x !== host),
|
||||||
|
});
|
||||||
|
}
|
||||||
async function toggleSuspend(): Promise<void> {
|
async function toggleSuspend(): Promise<void> {
|
||||||
if (!instance) throw new Error('No instance?');
|
if (!instance) throw new Error('No instance?');
|
||||||
await os.api('admin/federation/update-instance', {
|
await os.api('admin/federation/update-instance', {
|
||||||
|
|
|
@ -29,6 +29,7 @@ type Ad = TODO_2;
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type AdminInstanceMetadata = DetailedInstanceMetadata & {
|
type AdminInstanceMetadata = DetailedInstanceMetadata & {
|
||||||
blockedHosts: string[];
|
blockedHosts: string[];
|
||||||
|
silencedHosts: string[];
|
||||||
app192IconUrl: string | null;
|
app192IconUrl: string | null;
|
||||||
app512IconUrl: string | null;
|
app512IconUrl: string | null;
|
||||||
manifestJsonOverride: string;
|
manifestJsonOverride: string;
|
||||||
|
@ -2360,6 +2361,7 @@ type Instance = {
|
||||||
lastCommunicatedAt: DateString;
|
lastCommunicatedAt: DateString;
|
||||||
isNotResponding: boolean;
|
isNotResponding: boolean;
|
||||||
isSuspended: boolean;
|
isSuspended: boolean;
|
||||||
|
isSilenced: boolean;
|
||||||
isBlocked: boolean;
|
isBlocked: boolean;
|
||||||
softwareName: string | null;
|
softwareName: string | null;
|
||||||
softwareVersion: string | null;
|
softwareVersion: string | null;
|
||||||
|
@ -2986,7 +2988,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u
|
||||||
// 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:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
|
||||||
// src/api.types.ts:630:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
|
// src/api.types.ts:630:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
|
||||||
// src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts
|
// src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts
|
||||||
// src/entities.ts:601:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
|
// src/entities.ts:603:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" 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
|
// 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)
|
// (No @packageDocumentation comment for this package)
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
"@microsoft/api-extractor": "7.38.0",
|
"@microsoft/api-extractor": "7.38.0",
|
||||||
"@swc/jest": "0.2.29",
|
"@swc/jest": "0.2.29",
|
||||||
"@types/jest": "29.5.5",
|
"@types/jest": "29.5.5",
|
||||||
"@types/node": "20.8.4",
|
"@types/node": "20.8.6",
|
||||||
"@typescript-eslint/eslint-plugin": "6.7.5",
|
"@typescript-eslint/eslint-plugin": "6.7.5",
|
||||||
"@typescript-eslint/parser": "6.7.5",
|
"@typescript-eslint/parser": "6.7.5",
|
||||||
"eslint": "8.51.0",
|
"eslint": "8.51.0",
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@swc/cli": "0.1.62",
|
"@swc/cli": "0.1.62",
|
||||||
"@swc/core": "1.3.92",
|
"@swc/core": "1.3.93",
|
||||||
"eventemitter3": "5.0.1",
|
"eventemitter3": "5.0.1",
|
||||||
"reconnecting-websocket": "4.4.0"
|
"reconnecting-websocket": "4.4.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -386,6 +386,7 @@ export type InstanceMetadata = LiteInstanceMetadata | DetailedInstanceMetadata;
|
||||||
export type AdminInstanceMetadata = DetailedInstanceMetadata & {
|
export type AdminInstanceMetadata = DetailedInstanceMetadata & {
|
||||||
// TODO: There are more fields.
|
// TODO: There are more fields.
|
||||||
blockedHosts: string[];
|
blockedHosts: string[];
|
||||||
|
silencedHosts: string[];
|
||||||
app192IconUrl: string | null;
|
app192IconUrl: string | null;
|
||||||
app512IconUrl: string | null;
|
app512IconUrl: string | null;
|
||||||
manifestJsonOverride: string;
|
manifestJsonOverride: string;
|
||||||
|
@ -546,6 +547,7 @@ export type Instance = {
|
||||||
lastCommunicatedAt: DateString;
|
lastCommunicatedAt: DateString;
|
||||||
isNotResponding: boolean;
|
isNotResponding: boolean;
|
||||||
isSuspended: boolean;
|
isSuspended: boolean;
|
||||||
|
isSilenced: boolean;
|
||||||
isBlocked: boolean;
|
isBlocked: boolean;
|
||||||
softwareName: string | null;
|
softwareName: string | null;
|
||||||
softwareVersion: string | null;
|
softwareVersion: string | null;
|
||||||
|
|
655
pnpm-lock.yaml
655
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue