1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-14 13:25:48 +02:00

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

@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { id } from './util/id.js';
import { MiUser } from './User.js';
import { MiChannel } from './Channel.js';
@Entity('channel_muting')
@Index(['userId', 'channelId'], {})
export class MiChannelMuting {
@PrimaryColumn(id())
public id: string;
@Index()
@Column({
...id(),
})
public userId: MiUser['id'];
@ManyToOne(type => MiUser, {
onDelete: 'CASCADE',
})
@JoinColumn()
public user: MiUser | null;
@Index()
@Column({
...id(),
})
public channelId: MiChannel['id'];
@ManyToOne(type => MiChannel, {
onDelete: 'CASCADE',
})
@JoinColumn()
public channel: MiChannel | null;
@Index()
@Column('timestamp with time zone', {
nullable: true,
})
public expiresAt: Date | null;
}

View File

@@ -248,6 +248,14 @@ export class MiNote {
})
public renoteUserHost: string | null;
@Column({
...id(),
nullable: true,
comment: '[Denormalized]',
})
public renoteChannelId: MiChannel['id'] | null;
//#endregion
constructor(data: Partial<MiNote>) {
if (data == null) return;

View File

@@ -21,6 +21,7 @@ import {
MiChannel,
MiChannelFavorite,
MiChannelFollowing,
MiChannelMuting,
MiClip,
MiClipFavorite,
MiClipNote,
@@ -429,6 +430,12 @@ const $channelFavoritesRepository: Provider = {
inject: [DI.db],
};
const $channelMutingRepository: Provider = {
provide: DI.channelMutingRepository,
useFactory: (db: DataSource) => db.getRepository(MiChannelMuting).extend(miRepository as MiRepository<MiChannelMuting>),
inject: [DI.db],
};
const $registryItemsRepository: Provider = {
provide: DI.registryItemsRepository,
useFactory: (db: DataSource) => db.getRepository(MiRegistryItem).extend(miRepository as MiRepository<MiRegistryItem>),
@@ -597,6 +604,7 @@ const $reversiGamesRepository: Provider = {
$channelsRepository,
$channelFollowingsRepository,
$channelFavoritesRepository,
$channelMutingRepository,
$registryItemsRepository,
$webhooksRepository,
$systemWebhooksRepository,
@@ -674,6 +682,7 @@ const $reversiGamesRepository: Provider = {
$channelsRepository,
$channelFollowingsRepository,
$channelFavoritesRepository,
$channelMutingRepository,
$registryItemsRepository,
$webhooksRepository,
$systemWebhooksRepository,

View File

@@ -32,6 +32,7 @@ import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
import { MiChannel } from '@/models/Channel.js';
import { MiChannelFavorite } from '@/models/ChannelFavorite.js';
import { MiChannelFollowing } from '@/models/ChannelFollowing.js';
import { MiChannelMuting } from "@/models/ChannelMuting.js";
import { MiChatApproval } from '@/models/ChatApproval.js';
import { MiChatMessage } from '@/models/ChatMessage.js';
import { MiChatRoom } from '@/models/ChatRoom.js';
@@ -172,6 +173,7 @@ export {
MiBlocking,
MiChannelFollowing,
MiChannelFavorite,
MiChannelMuting,
MiClip,
MiClipNote,
MiClipFavorite,
@@ -251,6 +253,7 @@ export type AuthSessionsRepository = Repository<MiAuthSession> & MiRepository<Mi
export type BlockingsRepository = Repository<MiBlocking> & MiRepository<MiBlocking>;
export type ChannelFollowingsRepository = Repository<MiChannelFollowing> & MiRepository<MiChannelFollowing>;
export type ChannelFavoritesRepository = Repository<MiChannelFavorite> & MiRepository<MiChannelFavorite>;
export type ChannelMutingRepository = Repository<MiChannelMuting> & MiRepository<MiChannelMuting>;
export type ClipsRepository = Repository<MiClip> & MiRepository<MiClip>;
export type ClipNotesRepository = Repository<MiClipNote> & MiRepository<MiClipNote>;
export type ClipFavoritesRepository = Repository<MiClipFavorite> & MiRepository<MiClipFavorite>;

View File

@@ -80,6 +80,10 @@ export const packedChannelSchema = {
type: 'boolean',
optional: true, nullable: false,
},
isMuting: {
type: 'boolean',
optional: true, nullable: false,
},
pinnedNotes: {
type: 'array',
optional: true, nullable: false,