feat: チャンネルミュートの実装 (#14105)

* add channel_muting table and entities

* add channel_muting services

* タイムライン取得処理への組み込み

* misskey-jsの型とインターフェース生成

* Channelスキーマにミュート情報を追加

* フロントエンドの実装

* 条件が逆だったのを修正

* 期限切れミュートを掃除する機能を実装

* TLの抽出条件調節

* 名前の変更と変更不要の差分をロールバック

* 修正漏れ

* isChannelRelatedの条件に誤りがあった

* [wip] テスト追加

* テストの追加と検出した不備の修正

* fix test

* fix CHANGELOG.md

* 通常はFTTにしておく

* 実装忘れ対応

* fix merge

* fix merge

* add channel tl test

* fix CHANGELOG.md

* remove unused import

* fix lint

* fix test

* fix favorite -> favorited

* exclude -> include

* fix CHANGELOG.md

* fix CHANGELOG.md

* maintenance

* fix CHANGELOG.md

* fix

* fix ci

* regenerate

* fix

* Revert "fix"

This reverts commit 699d50c6ec.

* fixed

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
おさむのひと
2025-11-07 08:39:21 +09:00
committed by GitHub
parent e74ab35de3
commit 729abbef62
53 changed files with 3564 additions and 151 deletions

View File

@@ -13,6 +13,7 @@ import { DI } from '@/di-symbols.js';
import { IdService } from '@/core/IdService.js';
import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js';
import { MiLocalUser } from '@/models/User.js';
import { ChannelMutingService } from '@/core/ChannelMutingService.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -70,6 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private queryService: QueryService,
private fanoutTimelineEndpointService: FanoutTimelineEndpointService,
private activeUsersChart: ActiveUsersChart,
private channelMutingService: ChannelMutingService,
) {
super(meta, paramDef, async (ps, me) => {
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
@@ -98,6 +100,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
useDbFallback: true,
redisTimelines: [`channelTimeline:${channel.id}`],
excludePureRenotes: false,
ignoreAuthorChannelFromMute: true,
dbFallback: async (untilId, sinceId, limit) => {
return await this.getFromDb({ untilId, sinceId, limit, channelId: channel.id }, me);
},
@@ -122,6 +125,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('note.channel', 'channel');
this.queryService.generateBaseNoteFilteringQuery(query, me);
if (me) {
const mutingChannelIds = await this.channelMutingService
.list({ requestUserId: me.id }, { idOnly: true })
.then(x => x.map(x => x.id).filter(x => x !== ps.channelId));
if (mutingChannelIds.length > 0) {
query.andWhere('note.channelId NOT IN (:...mutingChannelIds)', { mutingChannelIds });
query.andWhere('note.renoteChannelId NOT IN (:...mutingChannelIds)', { mutingChannelIds });
}
}
//#endregion
return await query.limit(ps.limit).getMany();