mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-27 06:00:21 +01:00
enhance(antenna): Botの投稿を除外できるように (#13603)
* enhance(antenna): Botの投稿を除外できるように (MisskeyIO#545)
(cherry picked from commit a95ce067c6
)
* Update Changelog
* remove translations
* spdx
---------
Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
This commit is contained in:
parent
7795045b23
commit
f4838e50b4
16 changed files with 55 additions and 2 deletions
|
@ -1,6 +1,8 @@
|
|||
## Unreleased
|
||||
|
||||
### General
|
||||
- Enhance: アンテナでBotによるノートを除外できるように
|
||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
|
||||
- Fix: Play作成時に設定した公開範囲が機能していない問題を修正
|
||||
|
||||
### Client
|
||||
|
|
4
locales/index.d.ts
vendored
4
locales/index.d.ts
vendored
|
@ -1616,6 +1616,10 @@ export interface Locale extends ILocale {
|
|||
* 除外キーワード
|
||||
*/
|
||||
"antennaExcludeKeywords": string;
|
||||
/**
|
||||
* Botアカウントを除外
|
||||
*/
|
||||
"antennaExcludeBots": string;
|
||||
/**
|
||||
* スペースで区切るとAND指定になり、改行で区切るとOR指定になります
|
||||
*/
|
||||
|
|
|
@ -400,6 +400,7 @@ name: "名前"
|
|||
antennaSource: "受信ソース"
|
||||
antennaKeywords: "受信キーワード"
|
||||
antennaExcludeKeywords: "除外キーワード"
|
||||
antennaExcludeBots: "Botアカウントを除外"
|
||||
antennaKeywordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
|
||||
notifyAntenna: "新しいノートを通知する"
|
||||
withFileAntenna: "ファイルが添付されたノートのみ"
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class AntennaExcludeBots1710919614510 {
|
||||
name = 'AntennaExcludeBots1710919614510'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ADD "excludeBots" boolean NOT NULL DEFAULT false`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "excludeBots"`);
|
||||
}
|
||||
}
|
|
@ -92,7 +92,7 @@ export class AntennaService implements OnApplicationShutdown {
|
|||
}
|
||||
|
||||
@bindThis
|
||||
public async addNoteToAntennas(note: MiNote, noteUser: { id: MiUser['id']; username: string; host: string | null; }): Promise<void> {
|
||||
public async addNoteToAntennas(note: MiNote, noteUser: { id: MiUser['id']; username: string; host: string | null; isBot: boolean; }): Promise<void> {
|
||||
const antennas = await this.getAntennas();
|
||||
const antennasWithMatchResult = await Promise.all(antennas.map(antenna => this.checkHitAntenna(antenna, note, noteUser).then(hit => [antenna, hit] as const)));
|
||||
const matchedAntennas = antennasWithMatchResult.filter(([, hit]) => hit).map(([antenna]) => antenna);
|
||||
|
@ -110,10 +110,12 @@ export class AntennaService implements OnApplicationShutdown {
|
|||
// NOTE: フォローしているユーザーのノート、リストのユーザーのノート、グループのユーザーのノート指定はパフォーマンス上の理由で無効になっている
|
||||
|
||||
@bindThis
|
||||
public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; }): Promise<boolean> {
|
||||
public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; isBot: boolean; }): Promise<boolean> {
|
||||
if (note.visibility === 'specified') return false;
|
||||
if (note.visibility === 'followers') return false;
|
||||
|
||||
if (antenna.excludeBots && noteUser.isBot) return false;
|
||||
|
||||
if (antenna.localOnly && noteUser.host != null) return false;
|
||||
|
||||
if (!antenna.withReplies && note.replyId != null) return false;
|
||||
|
|
|
@ -39,6 +39,7 @@ export class AntennaEntityService {
|
|||
caseSensitive: antenna.caseSensitive,
|
||||
localOnly: antenna.localOnly,
|
||||
notify: antenna.notify,
|
||||
excludeBots: antenna.excludeBots,
|
||||
withReplies: antenna.withReplies,
|
||||
withFile: antenna.withFile,
|
||||
isActive: antenna.isActive,
|
||||
|
|
|
@ -72,6 +72,11 @@ export class MiAntenna {
|
|||
})
|
||||
public caseSensitive: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public excludeBots: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
|
|
|
@ -76,6 +76,11 @@ export const packedAntennaSchema = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
excludeBots: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
default: false,
|
||||
},
|
||||
withReplies: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
|
|
|
@ -81,6 +81,7 @@ export class ExportAntennasProcessorService {
|
|||
}) : null,
|
||||
caseSensitive: antenna.caseSensitive,
|
||||
localOnly: antenna.localOnly,
|
||||
excludeBots: antenna.excludeBots,
|
||||
withReplies: antenna.withReplies,
|
||||
withFile: antenna.withFile,
|
||||
notify: antenna.notify,
|
||||
|
|
|
@ -44,6 +44,7 @@ const validate = new Ajv().compile({
|
|||
} },
|
||||
caseSensitive: { type: 'boolean' },
|
||||
localOnly: { type: 'boolean' },
|
||||
excludeBots: { type: 'boolean' },
|
||||
withReplies: { type: 'boolean' },
|
||||
withFile: { type: 'boolean' },
|
||||
notify: { type: 'boolean' },
|
||||
|
@ -88,6 +89,7 @@ export class ImportAntennasProcessorService {
|
|||
users: (antenna.src === 'list' && antenna.userListAccts !== null ? antenna.userListAccts : antenna.users).filter(Boolean),
|
||||
caseSensitive: antenna.caseSensitive,
|
||||
localOnly: antenna.localOnly,
|
||||
excludeBots: antenna.excludeBots,
|
||||
withReplies: antenna.withReplies,
|
||||
withFile: antenna.withFile,
|
||||
notify: antenna.notify,
|
||||
|
|
|
@ -64,6 +64,7 @@ export const paramDef = {
|
|||
} },
|
||||
caseSensitive: { type: 'boolean' },
|
||||
localOnly: { type: 'boolean' },
|
||||
excludeBots: { type: 'boolean' },
|
||||
withReplies: { type: 'boolean' },
|
||||
withFile: { type: 'boolean' },
|
||||
notify: { type: 'boolean' },
|
||||
|
@ -124,6 +125,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
users: ps.users,
|
||||
caseSensitive: ps.caseSensitive,
|
||||
localOnly: ps.localOnly,
|
||||
excludeBots: ps.excludeBots,
|
||||
withReplies: ps.withReplies,
|
||||
withFile: ps.withFile,
|
||||
notify: ps.notify,
|
||||
|
|
|
@ -63,6 +63,7 @@ export const paramDef = {
|
|||
} },
|
||||
caseSensitive: { type: 'boolean' },
|
||||
localOnly: { type: 'boolean' },
|
||||
excludeBots: { type: 'boolean' },
|
||||
withReplies: { type: 'boolean' },
|
||||
withFile: { type: 'boolean' },
|
||||
notify: { type: 'boolean' },
|
||||
|
@ -120,6 +121,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
users: ps.users,
|
||||
caseSensitive: ps.caseSensitive,
|
||||
localOnly: ps.localOnly,
|
||||
excludeBots: ps.excludeBots,
|
||||
withReplies: ps.withReplies,
|
||||
withFile: ps.withFile,
|
||||
notify: ps.notify,
|
||||
|
|
|
@ -44,6 +44,7 @@ describe('アンテナ', () => {
|
|||
users: [''],
|
||||
withFile: false,
|
||||
withReplies: false,
|
||||
excludeBots: false,
|
||||
};
|
||||
|
||||
let root: User;
|
||||
|
@ -156,6 +157,7 @@ describe('アンテナ', () => {
|
|||
users: [''],
|
||||
withFile: false,
|
||||
withReplies: false,
|
||||
excludeBots: false,
|
||||
localOnly: false,
|
||||
};
|
||||
assert.deepStrictEqual(response, expected);
|
||||
|
|
|
@ -26,6 +26,7 @@ const draft = ref({
|
|||
users: [],
|
||||
keywords: [],
|
||||
excludeKeywords: [],
|
||||
excludeBots: false,
|
||||
withReplies: false,
|
||||
caseSensitive: false,
|
||||
localOnly: false,
|
||||
|
|
|
@ -26,6 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #label>{{ i18n.ts.users }}</template>
|
||||
<template #caption>{{ i18n.ts.antennaUsersDescription }} <button class="_textButton" @click="addUser">{{ i18n.ts.addUser }}</button></template>
|
||||
</MkTextarea>
|
||||
<MkSwitch v-model="excludeBots">{{ i18n.ts.antennaExcludeBots }}</MkSwitch>
|
||||
<MkSwitch v-model="withReplies">{{ i18n.ts.withReplies }}</MkSwitch>
|
||||
<MkTextarea v-model="keywords">
|
||||
<template #label>{{ i18n.ts.antennaKeywords }}</template>
|
||||
|
@ -78,6 +79,7 @@ const keywords = ref<string>(props.antenna.keywords.map(x => x.join(' ')).join('
|
|||
const excludeKeywords = ref<string>(props.antenna.excludeKeywords.map(x => x.join(' ')).join('\n'));
|
||||
const caseSensitive = ref<boolean>(props.antenna.caseSensitive);
|
||||
const localOnly = ref<boolean>(props.antenna.localOnly);
|
||||
const excludeBots = ref<boolean>(props.antenna.excludeBots);
|
||||
const withReplies = ref<boolean>(props.antenna.withReplies);
|
||||
const withFile = ref<boolean>(props.antenna.withFile);
|
||||
const notify = ref<boolean>(props.antenna.notify);
|
||||
|
@ -94,6 +96,7 @@ async function saveAntenna() {
|
|||
name: name.value,
|
||||
src: src.value,
|
||||
userListId: userListId.value,
|
||||
excludeBots: excludeBots.value,
|
||||
withReplies: withReplies.value,
|
||||
withFile: withFile.value,
|
||||
notify: notify.value,
|
||||
|
|
|
@ -4434,6 +4434,8 @@ export type components = {
|
|||
localOnly: boolean;
|
||||
notify: boolean;
|
||||
/** @default false */
|
||||
excludeBots: boolean;
|
||||
/** @default false */
|
||||
withReplies: boolean;
|
||||
withFile: boolean;
|
||||
isActive: boolean;
|
||||
|
@ -9654,6 +9656,7 @@ export type operations = {
|
|||
users: string[];
|
||||
caseSensitive: boolean;
|
||||
localOnly?: boolean;
|
||||
excludeBots?: boolean;
|
||||
withReplies: boolean;
|
||||
withFile: boolean;
|
||||
notify: boolean;
|
||||
|
@ -9935,6 +9938,7 @@ export type operations = {
|
|||
users?: string[];
|
||||
caseSensitive?: boolean;
|
||||
localOnly?: boolean;
|
||||
excludeBots?: boolean;
|
||||
withReplies?: boolean;
|
||||
withFile?: boolean;
|
||||
notify?: boolean;
|
||||
|
|
Loading…
Reference in a new issue