feat: ユーザを除外できるアンテナ (#11277)

* feat: ユーザを除外できるアンテナ

* feat(backend/api): ユーザを除外できるアンテナの作成・更新

* feat(frontend): ユーザを除外できるアンテナの作成・更新

* docs(changelog): add アンテナで一部のユーザを除外したすべてのノートから受信できるようになりました

* fix: d.ts生成時にexport defaultを生成するように

* fix CHANGELOG.md

---------

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
anatawa12 2023-09-22 16:52:43 +09:00 committed by GitHub
parent 90a5511a54
commit 526b3ae0e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 26 additions and 6 deletions

View file

@ -30,6 +30,7 @@
- Feat: プロフィールでのリンク検証 - Feat: プロフィールでのリンク検証
- Feat: 通知をテストできるようになりました - Feat: 通知をテストできるようになりました
- Feat: PWAのアイコンが設定できるようになりました - Feat: PWAのアイコンが設定できるようになりました
- Enhance: アンテナの受信ソースに指定したユーザを除外するものを追加
- Enhance: 二要素認証設定時のセキュリティを強化 - Enhance: 二要素認証設定時のセキュリティを強化
- パスワード入力が必要な操作を行う際、二要素認証が有効であれば確認コードの入力も必要になりました - パスワード入力が必要な操作を行う際、二要素認証が有効であれば確認コードの入力も必要になりました
- Enhance: manifest.jsonをオーバーライド可能に - Enhance: manifest.jsonをオーバーライド可能に

1
locales/index.d.ts vendored
View file

@ -1917,6 +1917,7 @@ export interface Locale {
"homeTimeline": string; "homeTimeline": string;
"users": string; "users": string;
"userList": string; "userList": string;
"userBlacklist": string;
}; };
"_weekday": { "_weekday": {
"sunday": string; "sunday": string;

View file

@ -1834,6 +1834,7 @@ _antennaSources:
homeTimeline: "フォローしているユーザーのノート" homeTimeline: "フォローしているユーザーのノート"
users: "指定した一人または複数のユーザーのノート" users: "指定した一人または複数のユーザーのノート"
userList: "指定したリストのユーザーのノート" userList: "指定したリストのユーザーのノート"
userBlacklist: "指定した一人または複数のユーザーを除いた全てのノート"
_weekday: _weekday:
sunday: "日曜日" sunday: "日曜日"

View file

@ -0,0 +1,10 @@
export class UserBlacklistAnntena1689325027964 {
name = 'UserBlacklistAnntena1689325027964'
async up(queryRunner) {
await queryRunner.query(`ALTER TYPE "antenna_src_enum" ADD VALUE 'users_blacklist' AFTER 'list'`);
}
async down(queryRunner) {
}
}

View file

@ -119,6 +119,12 @@ export class AntennaService implements OnApplicationShutdown {
return this.utilityService.getFullApAccount(username, host).toLowerCase(); return this.utilityService.getFullApAccount(username, host).toLowerCase();
}); });
if (!accts.includes(this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase())) return false; if (!accts.includes(this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase())) return false;
} else if (antenna.src === 'users_blacklist') {
const accts = antenna.users.map(x => {
const { username, host } = Acct.parse(x);
return this.utilityService.getFullApAccount(username, host).toLowerCase();
});
if (accts.includes(this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase())) return false;
} }
const keywords = antenna.keywords const keywords = antenna.keywords

View file

@ -41,8 +41,8 @@ export class MiAntenna {
}) })
public name: string; public name: string;
@Column('enum', { enum: ['home', 'all', 'users', 'list'] }) @Column('enum', { enum: ['home', 'all', 'users', 'list', 'users_blacklist'] })
public src: 'home' | 'all' | 'users' | 'list'; public src: 'home' | 'all' | 'users' | 'list' | 'users_blacklist';
@Column({ @Column({
...id(), ...id(),

View file

@ -47,7 +47,7 @@ export const packedAntennaSchema = {
src: { src: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
enum: ['home', 'all', 'users', 'list'], enum: ['home', 'all', 'users', 'list', 'users_blacklist'],
}, },
userListId: { userListId: {
type: 'string', type: 'string',

View file

@ -47,7 +47,7 @@ export const paramDef = {
type: 'object', type: 'object',
properties: { properties: {
name: { type: 'string', minLength: 1, maxLength: 100 }, name: { type: 'string', minLength: 1, maxLength: 100 },
src: { type: 'string', enum: ['home', 'all', 'users', 'list'] }, src: { type: 'string', enum: ['home', 'all', 'users', 'list', 'users_blacklist'] },
userListId: { type: 'string', format: 'misskey:id', nullable: true }, userListId: { type: 'string', format: 'misskey:id', nullable: true },
keywords: { type: 'array', items: { keywords: { type: 'array', items: {
type: 'array', items: { type: 'array', items: {

View file

@ -46,7 +46,7 @@ export const paramDef = {
properties: { properties: {
antennaId: { type: 'string', format: 'misskey:id' }, antennaId: { type: 'string', format: 'misskey:id' },
name: { type: 'string', minLength: 1, maxLength: 100 }, name: { type: 'string', minLength: 1, maxLength: 100 },
src: { type: 'string', enum: ['home', 'all', 'users', 'list'] }, src: { type: 'string', enum: ['home', 'all', 'users', 'list', 'users_blacklist'] },
userListId: { type: 'string', format: 'misskey:id', nullable: true }, userListId: { type: 'string', format: 'misskey:id', nullable: true },
keywords: { type: 'array', items: { keywords: { type: 'array', items: {
type: 'array', items: { type: 'array', items: {

View file

@ -16,12 +16,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<!--<option value="home">{{ i18n.ts._antennaSources.homeTimeline }}</option>--> <!--<option value="home">{{ i18n.ts._antennaSources.homeTimeline }}</option>-->
<option value="users">{{ i18n.ts._antennaSources.users }}</option> <option value="users">{{ i18n.ts._antennaSources.users }}</option>
<!--<option value="list">{{ i18n.ts._antennaSources.userList }}</option>--> <!--<option value="list">{{ i18n.ts._antennaSources.userList }}</option>-->
<option value="users_blacklist">{{ i18n.ts._antennaSources.userBlacklist }}</option>
</MkSelect> </MkSelect>
<MkSelect v-if="src === 'list'" v-model="userListId"> <MkSelect v-if="src === 'list'" v-model="userListId">
<template #label>{{ i18n.ts.userList }}</template> <template #label>{{ i18n.ts.userList }}</template>
<option v-for="list in userLists" :key="list.id" :value="list.id">{{ list.name }}</option> <option v-for="list in userLists" :key="list.id" :value="list.id">{{ list.name }}</option>
</MkSelect> </MkSelect>
<MkTextarea v-else-if="src === 'users'" v-model="users"> <MkTextarea v-else-if="src === 'users' || src === 'users_blacklist'" v-model="users">
<template #label>{{ i18n.ts.users }}</template> <template #label>{{ i18n.ts.users }}</template>
<template #caption>{{ i18n.ts.antennaUsersDescription }} <button class="_textButton" @click="addUser">{{ i18n.ts.addUser }}</button></template> <template #caption>{{ i18n.ts.antennaUsersDescription }} <button class="_textButton" @click="addUser">{{ i18n.ts.addUser }}</button></template>
</MkTextarea> </MkTextarea>