feat: Per-user renote mute (#10249)

* feat: per-user renote muting

From FoundKey/c414f24a2c https://akkoma.dev/FoundKeyGang/FoundKey

* Update ja-JP.yml

* Delete renote-muting.ts

* rename

* fix ids

* lint

* fix

* Update CHANGELOG.md

* リノートをミュートしたユーザー一覧を見れるように

* 🎨

* add test

* fix test

---------

Co-authored-by: Hélène <pleroma-dev@helene.moe>
This commit is contained in:
syuilo
2023-03-08 08:56:09 +09:00
committed by GitHub
parent 8bf6911d4b
commit 4c2f7c64cc
43 changed files with 683 additions and 26 deletions

View File

@@ -27,6 +27,10 @@ export default abstract class Channel {
return this.connection.muting;
}
protected get renoteMuting() {
return this.connection.renoteMuting;
}
protected get blocking() {
return this.connection.blocking;
}

View File

@@ -39,6 +39,8 @@ class AntennaChannel extends Channel {
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.blocking)) return;
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting)) return;
this.connection.cacheNote(note);
this.send('note', note);

View File

@@ -51,6 +51,8 @@ class ChannelChannel extends Channel {
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.blocking)) return;
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting)) return;
this.connection.cacheNote(note);
this.send('note', note);

View File

@@ -68,6 +68,8 @@ class GlobalTimelineChannel extends Channel {
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.blocking)) return;
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting)) return;
// 流れてきたNoteがミュートすべきNoteだったら無視する
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、

View File

@@ -49,6 +49,8 @@ class HashtagChannel extends Channel {
if (isUserRelated(note, this.muting)) return;
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.blocking)) return;
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting)) return;
this.connection.cacheNote(note);

View File

@@ -75,6 +75,8 @@ class HomeTimelineChannel extends Channel {
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.blocking)) return;
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting)) return;
// 流れてきたNoteがミュートすべきNoteだったら無視する
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、

View File

@@ -86,6 +86,8 @@ class HybridTimelineChannel extends Channel {
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.blocking)) return;
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting)) return;
// 流れてきたNoteがミュートすべきNoteだったら無視する
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、

View File

@@ -65,6 +65,8 @@ class LocalTimelineChannel extends Channel {
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.blocking)) return;
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting)) return;
// 流れてきたNoteがミュートすべきNoteだったら無視する
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
// 現状では、ワードミュートにおけるMutedNoteレコードの追加処理はストリーミングに流す処理と並列で行われるため、

View File

@@ -93,6 +93,8 @@ class UserListChannel extends Channel {
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.blocking)) return;
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting)) return;
this.send('note', note);
}

View File

@@ -1,6 +1,6 @@
import type { User } from '@/models/entities/User.js';
import type { Channel as ChannelModel } from '@/models/entities/Channel.js';
import type { FollowingsRepository, MutingsRepository, UserProfilesRepository, ChannelFollowingsRepository, BlockingsRepository } from '@/models/index.js';
import type { FollowingsRepository, MutingsRepository, RenoteMutingsRepository, UserProfilesRepository, ChannelFollowingsRepository, BlockingsRepository } from '@/models/index.js';
import type { AccessToken } from '@/models/entities/AccessToken.js';
import type { UserProfile } from '@/models/entities/UserProfile.js';
import type { Packed } from '@/misc/schema.js';
@@ -22,6 +22,7 @@ export default class Connection {
public userProfile?: UserProfile | null;
public following: Set<User['id']> = new Set();
public muting: Set<User['id']> = new Set();
public renoteMuting: Set<User['id']> = new Set();
public blocking: Set<User['id']> = new Set(); // "被"blocking
public followingChannels: Set<ChannelModel['id']> = new Set();
public token?: AccessToken;
@@ -34,6 +35,7 @@ export default class Connection {
constructor(
private followingsRepository: FollowingsRepository,
private mutingsRepository: MutingsRepository,
private renoteMutingsRepository: RenoteMutingsRepository,
private blockingsRepository: BlockingsRepository,
private channelFollowingsRepository: ChannelFollowingsRepository,
private userProfilesRepository: UserProfilesRepository,
@@ -66,6 +68,7 @@ export default class Connection {
if (this.user) {
this.updateFollowing();
this.updateMuting();
this.updateRenoteMuting();
this.updateBlocking();
this.updateFollowingChannels();
this.updateUserProfile();
@@ -93,6 +96,7 @@ export default class Connection {
this.muting.delete(data.body.id);
break;
// TODO: renote mute events
// TODO: block events
case 'followChannel':
@@ -342,6 +346,18 @@ export default class Connection {
this.muting = new Set<string>(mutings.map(x => x.muteeId));
}
@bindThis
private async updateRenoteMuting() {
const renoteMutings = await this.renoteMutingsRepository.find({
where: {
muterId: this.user!.id,
},
select: ['muteeId'],
});
this.renoteMuting = new Set<string>(renoteMutings.map(x => x.muteeId));
}
@bindThis
private async updateBlocking() { // ここでいうBlockingは被Blockingの意
const blockings = await this.blockingsRepository.find({