forked from FoundKeyGang/FoundKey
Merge branch 'feature/user-instance-mute' into mk.absturztau.be
This commit is contained in:
commit
eea03fcbe0
18 changed files with 188 additions and 0 deletions
|
@ -9,6 +9,9 @@
|
||||||
|
|
||||||
## 12.x.x (unreleased)
|
## 12.x.x (unreleased)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Added a user-level instance mute in user settings
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
|
|
@ -59,6 +59,7 @@ mention: "Mention"
|
||||||
mentions: "Mentions"
|
mentions: "Mentions"
|
||||||
directNotes: "Direct notes"
|
directNotes: "Direct notes"
|
||||||
importAndExport: "Import / Export"
|
importAndExport: "Import / Export"
|
||||||
|
instanceMute: "Instance Mutes"
|
||||||
import: "Import"
|
import: "Import"
|
||||||
export: "Export"
|
export: "Export"
|
||||||
files: "Files"
|
files: "Files"
|
||||||
|
@ -959,6 +960,11 @@ _wordMute:
|
||||||
soft: "Soft"
|
soft: "Soft"
|
||||||
hard: "Hard"
|
hard: "Hard"
|
||||||
mutedNotes: "Muted notes"
|
mutedNotes: "Muted notes"
|
||||||
|
_instanceMute:
|
||||||
|
instanceMuteDescription: "Will mute any notes/renotes from the listed instances, including a user replying to a user from a muted instance."
|
||||||
|
instanceMuteDescription2: "Separate with newlines"
|
||||||
|
title: "Hides notes from listed instances"
|
||||||
|
heading: "List of instances to be muted"
|
||||||
_theme:
|
_theme:
|
||||||
explore: "Explore Themes"
|
explore: "Explore Themes"
|
||||||
install: "Install a theme"
|
install: "Install a theme"
|
||||||
|
|
|
@ -588,6 +588,7 @@ smtpSecure: "SMTP 接続に暗黙的なSSL/TLSを使用する"
|
||||||
smtpSecureInfo: "STARTTLS使用時はオフにします。"
|
smtpSecureInfo: "STARTTLS使用時はオフにします。"
|
||||||
testEmail: "配信テスト"
|
testEmail: "配信テスト"
|
||||||
wordMute: "ワードミュート"
|
wordMute: "ワードミュート"
|
||||||
|
instanceMute: "インスタンスミュート"
|
||||||
userSaysSomething: "{name}が何かを言いました"
|
userSaysSomething: "{name}が何かを言いました"
|
||||||
makeActive: "アクティブにする"
|
makeActive: "アクティブにする"
|
||||||
display: "表示"
|
display: "表示"
|
||||||
|
@ -977,6 +978,12 @@ _wordMute:
|
||||||
hard: "ハード"
|
hard: "ハード"
|
||||||
mutedNotes: "ミュートされたノート"
|
mutedNotes: "ミュートされたノート"
|
||||||
|
|
||||||
|
_instanceMute:
|
||||||
|
instanceMuteDescription: "ミュートしたインスタンスのユーザーからの返信を含めて、設定したインスタンスの全てのノートとRenoteをミュートします。"
|
||||||
|
instanceMuteDescription2: "改行で区切って設定します"
|
||||||
|
title: "設定したインスタンスのノートを隠します。"
|
||||||
|
heading: "ミュートするインスタンス"
|
||||||
|
|
||||||
_theme:
|
_theme:
|
||||||
explore: "テーマを探す"
|
explore: "テーマを探す"
|
||||||
install: "テーマのインストール"
|
install: "テーマのインストール"
|
||||||
|
|
15
migration/1629968054000_userInstanceBlocks.ts
Normal file
15
migration/1629968054000_userInstanceBlocks.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||||
|
|
||||||
|
export class userInstanceBlocks1629968054000 implements MigrationInterface {
|
||||||
|
name = 'userInstanceBlocks1629968054000'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ADD "mutedInstances" jsonb NOT NULL DEFAULT '[]'`);
|
||||||
|
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."mutedInstances" IS 'List of instances muted by the user.'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "mutedInstances"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,6 +35,7 @@
|
||||||
<FormLink :active="page === 'import-export'" replace to="/settings/import-export"><template #icon><i class="fas fa-boxes"></i></template>{{ $ts.importAndExport }}</FormLink>
|
<FormLink :active="page === 'import-export'" replace to="/settings/import-export"><template #icon><i class="fas fa-boxes"></i></template>{{ $ts.importAndExport }}</FormLink>
|
||||||
<FormLink :active="page === 'mute-block'" replace to="/settings/mute-block"><template #icon><i class="fas fa-ban"></i></template>{{ $ts.muteAndBlock }}</FormLink>
|
<FormLink :active="page === 'mute-block'" replace to="/settings/mute-block"><template #icon><i class="fas fa-ban"></i></template>{{ $ts.muteAndBlock }}</FormLink>
|
||||||
<FormLink :active="page === 'word-mute'" replace to="/settings/word-mute"><template #icon><i class="fas fa-comment-slash"></i></template>{{ $ts.wordMute }}</FormLink>
|
<FormLink :active="page === 'word-mute'" replace to="/settings/word-mute"><template #icon><i class="fas fa-comment-slash"></i></template>{{ $ts.wordMute }}</FormLink>
|
||||||
|
<FormLink :active="page === 'instance-mute'" replace to="/settings/instance-mute"><template #icon><i class="fas fa-volume-mute"></i></template>{{ $ts.instanceMute }}</FormLink>
|
||||||
<FormLink :active="page === 'api'" replace to="/settings/api"><template #icon><i class="fas fa-key"></i></template>API</FormLink>
|
<FormLink :active="page === 'api'" replace to="/settings/api"><template #icon><i class="fas fa-key"></i></template>API</FormLink>
|
||||||
<FormLink :active="page === 'other'" replace to="/settings/other"><template #icon><i class="fas fa-ellipsis-h"></i></template>{{ $ts.other }}</FormLink>
|
<FormLink :active="page === 'other'" replace to="/settings/other"><template #icon><i class="fas fa-ellipsis-h"></i></template>{{ $ts.other }}</FormLink>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
@ -108,6 +109,7 @@ export default defineComponent({
|
||||||
case 'notifications': return defineAsyncComponent(() => import('./notifications.vue'));
|
case 'notifications': return defineAsyncComponent(() => import('./notifications.vue'));
|
||||||
case 'mute-block': return defineAsyncComponent(() => import('./mute-block.vue'));
|
case 'mute-block': return defineAsyncComponent(() => import('./mute-block.vue'));
|
||||||
case 'word-mute': return defineAsyncComponent(() => import('./word-mute.vue'));
|
case 'word-mute': return defineAsyncComponent(() => import('./word-mute.vue'));
|
||||||
|
case 'instance-mute': return defineAsyncComponent(() => import('./instance-mute.vue'));
|
||||||
case 'integration': return defineAsyncComponent(() => import('./integration.vue'));
|
case 'integration': return defineAsyncComponent(() => import('./integration.vue'));
|
||||||
case 'security': return defineAsyncComponent(() => import('./security.vue'));
|
case 'security': return defineAsyncComponent(() => import('./security.vue'));
|
||||||
case '2fa': return defineAsyncComponent(() => import('./2fa.vue'));
|
case '2fa': return defineAsyncComponent(() => import('./2fa.vue'));
|
||||||
|
|
83
src/client/pages/settings/instance-mute.vue
Normal file
83
src/client/pages/settings/instance-mute.vue
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<FormBase>
|
||||||
|
<div class="_formItem">
|
||||||
|
<FormInfo>{{ $ts._instanceMute.title}}</FormInfo>
|
||||||
|
<FormTextarea v-model:value="instanceMutes">
|
||||||
|
<span>{{$ts._instanceMute.heading}}</span>
|
||||||
|
<template #desc>{{ $ts._instanceMute.instanceMuteDescription}}<br>{{$ts._instanceMute.instanceMuteDescription2}}</template>
|
||||||
|
</FormTextarea>
|
||||||
|
</div>
|
||||||
|
<FormButton @click="save()" primary inline :disabled="!changed"><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
|
||||||
|
</FormBase>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import FormBase from '@client/components/form/base.vue';
|
||||||
|
import FormTextarea from '@client/components/form/textarea.vue';
|
||||||
|
import FormInfo from '@client/components/form/info.vue';
|
||||||
|
import FormKeyValueView from '@client/components/form/key-value-view.vue';
|
||||||
|
import FormButton from '@client/components/form/button.vue';
|
||||||
|
import * as os from '@client/os';
|
||||||
|
import number from '@client/filters/number';
|
||||||
|
import * as symbols from '@client/symbols';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
FormBase,
|
||||||
|
FormButton,
|
||||||
|
FormTextarea,
|
||||||
|
FormKeyValueView,
|
||||||
|
FormInfo,
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['info'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
[symbols.PAGE_INFO]: {
|
||||||
|
title: this.$ts.instanceMute,
|
||||||
|
icon: 'fas fa-volume-mute'
|
||||||
|
},
|
||||||
|
tab: 'soft',
|
||||||
|
instanceMutes: '',
|
||||||
|
changed: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
instanceMutes: {
|
||||||
|
handler() {
|
||||||
|
this.changed = true;
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.$emit('info', this[symbols.PAGE_INFO]);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
async created() {
|
||||||
|
this.instanceMutes = this.$i.mutedInstances.join('\n');
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async save() {
|
||||||
|
let mutes = this.instanceMutes.trim().split('\n').map(el => el.trim()).filter(el => el);
|
||||||
|
await os.api('i/update', {
|
||||||
|
mutedInstances: mutes,
|
||||||
|
});
|
||||||
|
this.changed = false;
|
||||||
|
|
||||||
|
// Refresh filtered list to signal to the user how they've been saved
|
||||||
|
this.instanceMutes = mutes.join('\n');
|
||||||
|
},
|
||||||
|
|
||||||
|
number //?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
12
src/misc/is-instance-muted.ts
Normal file
12
src/misc/is-instance-muted.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { PackedNote } from '@/models/repositories/note';
|
||||||
|
import { User } from '@/models/entities/user';
|
||||||
|
|
||||||
|
export function isInstanceMuted(note: PackedNote, muted_instances: string[]): boolean {
|
||||||
|
const note_user = (note.user as User);
|
||||||
|
const note_reply_user = ((note.reply as PackedNote)?.user as User);
|
||||||
|
const note_renote_user = ((note.renote as PackedNote)?.user as User);
|
||||||
|
|
||||||
|
return muted_instances.includes(note_user.host ?? '') ||
|
||||||
|
muted_instances.includes(note_reply_user?.host ?? '') ||
|
||||||
|
muted_instances.includes(note_renote_user?.host ?? '');
|
||||||
|
}
|
|
@ -178,6 +178,11 @@ export class UserProfile {
|
||||||
})
|
})
|
||||||
public mutedWords: string[][];
|
public mutedWords: string[][];
|
||||||
|
|
||||||
|
@Column('jsonb', {
|
||||||
|
default: []
|
||||||
|
})
|
||||||
|
public mutedInstances: string[];
|
||||||
|
|
||||||
@Column('enum', {
|
@Column('enum', {
|
||||||
enum: notificationTypes,
|
enum: notificationTypes,
|
||||||
array: true,
|
array: true,
|
||||||
|
|
|
@ -270,6 +270,7 @@ export class UserRepository extends Repository<User> {
|
||||||
hasPendingReceivedFollowRequest: this.getHasPendingReceivedFollowRequest(user.id),
|
hasPendingReceivedFollowRequest: this.getHasPendingReceivedFollowRequest(user.id),
|
||||||
integrations: profile!.integrations,
|
integrations: profile!.integrations,
|
||||||
mutedWords: profile!.mutedWords,
|
mutedWords: profile!.mutedWords,
|
||||||
|
mutedInstances: profile!.mutedInstances,
|
||||||
mutingNotificationTypes: profile!.mutingNotificationTypes,
|
mutingNotificationTypes: profile!.mutingNotificationTypes,
|
||||||
emailNotificationTypes: profile!.emailNotificationTypes,
|
emailNotificationTypes: profile!.emailNotificationTypes,
|
||||||
} : {}),
|
} : {}),
|
||||||
|
@ -617,6 +618,10 @@ export const packedUserSchema = {
|
||||||
type: 'array' as const,
|
type: 'array' as const,
|
||||||
nullable: false as const, optional: true as const
|
nullable: false as const, optional: true as const
|
||||||
},
|
},
|
||||||
|
mutedInstances: {
|
||||||
|
type: 'array' as const,
|
||||||
|
nullable: false as const, optional: true as const
|
||||||
|
},
|
||||||
mutingNotificationTypes: {
|
mutingNotificationTypes: {
|
||||||
type: 'array' as const,
|
type: 'array' as const,
|
||||||
nullable: false as const, optional: true as const
|
nullable: false as const, optional: true as const
|
||||||
|
|
24
src/server/api/common/generate-muted-instance-query.ts
Normal file
24
src/server/api/common/generate-muted-instance-query.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { User } from '@/models/entities/user';
|
||||||
|
import { UserProfiles } from '@/models/index';
|
||||||
|
import { SelectQueryBuilder, Brackets } from 'typeorm';
|
||||||
|
|
||||||
|
export function generateMutedInstanceQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }) {
|
||||||
|
const mutingQuery = UserProfiles.createQueryBuilder('user_profile')
|
||||||
|
.select('user_profile.mutedInstances')
|
||||||
|
.where('user_profile.userId = :muterId', { muterId: me.id });
|
||||||
|
|
||||||
|
q
|
||||||
|
.andWhere(new Brackets(qb => { qb
|
||||||
|
.andWhere('note.userHost IS NULL')
|
||||||
|
.orWhere(`NOT((${ mutingQuery.getQuery() })::jsonb ? note.userHost)`);
|
||||||
|
}))
|
||||||
|
.andWhere(new Brackets(qb => { qb
|
||||||
|
.where(`note.replyUserHost IS NULL`)
|
||||||
|
.orWhere(`NOT ((${ mutingQuery.getQuery() })::jsonb ? note.replyUserHost)`);
|
||||||
|
}))
|
||||||
|
.andWhere(new Brackets(qb => { qb
|
||||||
|
.where(`note.renoteUserHost IS NULL`)
|
||||||
|
.orWhere(`NOT ((${ mutingQuery.getQuery() })::jsonb ? note.renoteUserHost)`);
|
||||||
|
}));
|
||||||
|
q.setParameters(mutingQuery.getParameters());
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import { ID } from '@/misc/cafy-id';
|
||||||
import { readNotification } from '../../common/read-notification';
|
import { readNotification } from '../../common/read-notification';
|
||||||
import define from '../../define';
|
import define from '../../define';
|
||||||
import { makePaginationQuery } from '../../common/make-pagination-query';
|
import { makePaginationQuery } from '../../common/make-pagination-query';
|
||||||
|
import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query';
|
||||||
import { Notifications, Followings, Mutings, Users } from '@/models/index';
|
import { Notifications, Followings, Mutings, Users } from '@/models/index';
|
||||||
import { notificationTypes } from '../../../../types';
|
import { notificationTypes } from '../../../../types';
|
||||||
import read from '@/services/note/read';
|
import read from '@/services/note/read';
|
||||||
|
@ -92,6 +93,8 @@ export default define(meta, async (ps, user) => {
|
||||||
query.andWhere(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`);
|
query.andWhere(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`);
|
||||||
query.setParameters(mutingQuery.getParameters());
|
query.setParameters(mutingQuery.getParameters());
|
||||||
|
|
||||||
|
generateMutedInstanceQuery(query, user);
|
||||||
|
|
||||||
query.andWhere(`notification.notifierId NOT IN (${ suspendedQuery.getQuery() })`);
|
query.andWhere(`notification.notifierId NOT IN (${ suspendedQuery.getQuery() })`);
|
||||||
|
|
||||||
if (ps.following) {
|
if (ps.following) {
|
||||||
|
|
|
@ -108,6 +108,10 @@ export const meta = {
|
||||||
validator: $.optional.arr($.arr($.str))
|
validator: $.optional.arr($.arr($.str))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mutedInstances: {
|
||||||
|
validator: $.optional.arr($.str)
|
||||||
|
},
|
||||||
|
|
||||||
mutingNotificationTypes: {
|
mutingNotificationTypes: {
|
||||||
validator: $.optional.arr($.str.or(notificationTypes as unknown as string[]))
|
validator: $.optional.arr($.str.or(notificationTypes as unknown as string[]))
|
||||||
},
|
},
|
||||||
|
@ -176,6 +180,7 @@ export default define(meta, async (ps, _user, token) => {
|
||||||
profileUpdates.mutedWords = ps.mutedWords;
|
profileUpdates.mutedWords = ps.mutedWords;
|
||||||
profileUpdates.enableWordMute = ps.mutedWords.length > 0;
|
profileUpdates.enableWordMute = ps.mutedWords.length > 0;
|
||||||
}
|
}
|
||||||
|
if (ps.mutedInstances !== undefined) profileUpdates.mutedInstances = ps.mutedInstances;
|
||||||
if (ps.mutingNotificationTypes !== undefined) profileUpdates.mutingNotificationTypes = ps.mutingNotificationTypes as typeof notificationTypes[number][];
|
if (ps.mutingNotificationTypes !== undefined) profileUpdates.mutingNotificationTypes = ps.mutingNotificationTypes as typeof notificationTypes[number][];
|
||||||
if (typeof ps.isLocked === 'boolean') updates.isLocked = ps.isLocked;
|
if (typeof ps.isLocked === 'boolean') updates.isLocked = ps.isLocked;
|
||||||
if (typeof ps.isExplorable === 'boolean') updates.isExplorable = ps.isExplorable;
|
if (typeof ps.isExplorable === 'boolean') updates.isExplorable = ps.isExplorable;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { ApiError } from '../../error';
|
||||||
import { makePaginationQuery } from '../../common/make-pagination-query';
|
import { makePaginationQuery } from '../../common/make-pagination-query';
|
||||||
import { Notes } from '@/models/index';
|
import { Notes } from '@/models/index';
|
||||||
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
|
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
|
||||||
|
import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query';
|
||||||
import { activeUsersChart } from '@/services/chart/index';
|
import { activeUsersChart } from '@/services/chart/index';
|
||||||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||||
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
|
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
|
||||||
|
@ -83,6 +84,7 @@ export default define(meta, async (ps, user) => {
|
||||||
if (user) generateMutedUserQuery(query, user);
|
if (user) generateMutedUserQuery(query, user);
|
||||||
if (user) generateMutedNoteQuery(query, user);
|
if (user) generateMutedNoteQuery(query, user);
|
||||||
if (user) generateBlockedUserQuery(query, user);
|
if (user) generateBlockedUserQuery(query, user);
|
||||||
|
if (user) generateMutedInstanceQuery(query, user);
|
||||||
|
|
||||||
if (ps.withFiles) {
|
if (ps.withFiles) {
|
||||||
query.andWhere('note.fileIds != \'{}\'');
|
query.andWhere('note.fileIds != \'{}\'');
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { Followings, Notes } from '@/models/index';
|
||||||
import { Brackets } from 'typeorm';
|
import { Brackets } from 'typeorm';
|
||||||
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
|
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
|
||||||
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
|
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
|
||||||
|
import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query';
|
||||||
import { activeUsersChart } from '@/services/chart/index';
|
import { activeUsersChart } from '@/services/chart/index';
|
||||||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||||
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
|
import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
|
||||||
|
@ -108,6 +109,7 @@ export default define(meta, async (ps, user) => {
|
||||||
generateRepliesQuery(query, user);
|
generateRepliesQuery(query, user);
|
||||||
generateVisibilityQuery(query, user);
|
generateVisibilityQuery(query, user);
|
||||||
generateMutedUserQuery(query, user);
|
generateMutedUserQuery(query, user);
|
||||||
|
generateMutedInstanceQuery(query, user);
|
||||||
generateMutedNoteQuery(query, user);
|
generateMutedNoteQuery(query, user);
|
||||||
generateBlockedUserQuery(query, user);
|
generateBlockedUserQuery(query, user);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query';
|
||||||
import { Notes, Followings } from '@/models/index';
|
import { Notes, Followings } from '@/models/index';
|
||||||
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
|
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
|
||||||
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
|
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
|
||||||
|
import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query';
|
||||||
import { activeUsersChart } from '@/services/chart/index';
|
import { activeUsersChart } from '@/services/chart/index';
|
||||||
import { Brackets } from 'typeorm';
|
import { Brackets } from 'typeorm';
|
||||||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||||
|
@ -100,6 +101,7 @@ export default define(meta, async (ps, user) => {
|
||||||
generateRepliesQuery(query, user);
|
generateRepliesQuery(query, user);
|
||||||
generateVisibilityQuery(query, user);
|
generateVisibilityQuery(query, user);
|
||||||
generateMutedUserQuery(query, user);
|
generateMutedUserQuery(query, user);
|
||||||
|
generateMutedInstanceQuery(query, user);
|
||||||
generateMutedNoteQuery(query, user);
|
generateMutedNoteQuery(query, user);
|
||||||
generateBlockedUserQuery(query, user);
|
generateBlockedUserQuery(query, user);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { Notes } from '@/models/index';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
import { PackedNote } from '@/models/repositories/note';
|
||||||
import { checkWordMute } from '@/misc/check-word-mute';
|
import { checkWordMute } from '@/misc/check-word-mute';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { isInstanceMuted } from '@/misc/is-instance-muted';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'globalTimeline';
|
public readonly chName = 'globalTimeline';
|
||||||
|
@ -48,6 +49,9 @@ export default class extends Channel {
|
||||||
if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
|
if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore notes from instances the user has muted
|
||||||
|
if (isInstanceMuted(note, this.userProfile?.mutedInstances ?? [])) return;
|
||||||
|
|
||||||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||||
if (isMutedUserRelated(note, this.muting)) return;
|
if (isMutedUserRelated(note, this.muting)) return;
|
||||||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { Notes } from '@/models/index';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
import { PackedNote } from '@/models/repositories/note';
|
||||||
import { checkWordMute } from '@/misc/check-word-mute';
|
import { checkWordMute } from '@/misc/check-word-mute';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { isInstanceMuted } from '@/misc/is-instance-muted';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'homeTimeline';
|
public readonly chName = 'homeTimeline';
|
||||||
|
@ -26,6 +27,9 @@ export default class extends Channel {
|
||||||
if ((this.user!.id !== note.userId) && !this.following.has(note.userId)) return;
|
if ((this.user!.id !== note.userId) && !this.following.has(note.userId)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore notes from instances the user has muted
|
||||||
|
if (isInstanceMuted(note, this.userProfile?.mutedInstances ?? [])) return;
|
||||||
|
|
||||||
if (['followers', 'specified'].includes(note.visibility)) {
|
if (['followers', 'specified'].includes(note.visibility)) {
|
||||||
note = await Notes.pack(note.id, this.user!, {
|
note = await Notes.pack(note.id, this.user!, {
|
||||||
detail: true
|
detail: true
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { PackedNote } from '@/models/repositories/note';
|
||||||
import { PackedUser } from '@/models/repositories/user';
|
import { PackedUser } from '@/models/repositories/user';
|
||||||
import { checkWordMute } from '@/misc/check-word-mute';
|
import { checkWordMute } from '@/misc/check-word-mute';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { isInstanceMuted } from '@/misc/is-instance-muted';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'hybridTimeline';
|
public readonly chName = 'hybridTimeline';
|
||||||
|
@ -58,6 +59,9 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore notes from instances the user has muted
|
||||||
|
if (isInstanceMuted(note, this.userProfile?.mutedInstances ?? [])) return;
|
||||||
|
|
||||||
// 関係ない返信は除外
|
// 関係ない返信は除外
|
||||||
if (note.reply) {
|
if (note.reply) {
|
||||||
const reply = note.reply as PackedNote;
|
const reply = note.reply as PackedNote;
|
||||||
|
|
Loading…
Reference in a new issue