Merge 7dd6fe8663 into fc7655c808
This commit is contained in:
commit
47184f1087
|
|
@ -29,6 +29,7 @@
|
|||
- JSONによるClient Information Discoveryを行うには、レスポンスの`Content-Type`ヘッダーが`application/json`である必要があります
|
||||
- 従来の実装(12 February 2022版・HTML Microformat形式)も引き続きサポートされます
|
||||
- Enhance: メモリ使用量を削減
|
||||
- Fix: リアルタイム更新時にロックダウン設定が考慮されていない問題を修正
|
||||
|
||||
## 2025.12.2
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { DebounceLoader } from '@/misc/loader.js';
|
|||
import { IdService } from '@/core/IdService.js';
|
||||
import { shouldHideNoteByTime } from '@/misc/should-hide-note-by-time.js';
|
||||
import { ReactionsBufferingService } from '@/core/ReactionsBufferingService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import type { OnModuleInit } from '@nestjs/common';
|
||||
import type { CustomEmojiService } from '../CustomEmojiService.js';
|
||||
import type { ReactionService } from '../ReactionService.js';
|
||||
|
|
@ -101,6 +102,7 @@ export class NoteEntityService implements OnModuleInit {
|
|||
//private reactionService: ReactionService,
|
||||
//private reactionsBufferingService: ReactionsBufferingService,
|
||||
//private idService: IdService,
|
||||
private cacheService: CacheService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -125,75 +127,65 @@ export class NoteEntityService implements OnModuleInit {
|
|||
}
|
||||
|
||||
@bindThis
|
||||
private async hideNote(packedNote: Packed<'Note'>, meId: MiUser['id'] | null): Promise<void> {
|
||||
if (meId === packedNote.userId) return;
|
||||
|
||||
public async shouldHideNote(packedNote: Packed<'Note'>, meId: MiUser['id'] | null): Promise<boolean> {
|
||||
if (meId === packedNote.userId) return false;
|
||||
// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど)
|
||||
let hide = false;
|
||||
|
||||
if (packedNote.user.requireSigninToViewContents && meId == null) {
|
||||
hide = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!hide) {
|
||||
const hiddenBefore = packedNote.user.makeNotesHiddenBefore;
|
||||
if (shouldHideNoteByTime(hiddenBefore, packedNote.createdAt)) {
|
||||
hide = true;
|
||||
}
|
||||
const hiddenBefore = packedNote.user.makeNotesHiddenBefore;
|
||||
if (shouldHideNoteByTime(hiddenBefore, packedNote.createdAt)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// visibility が specified かつ自分が指定されていなかったら非表示
|
||||
if (!hide) {
|
||||
if (packedNote.visibility === 'specified') {
|
||||
if (meId == null) {
|
||||
hide = true;
|
||||
} else {
|
||||
// 指定されているかどうか
|
||||
const specified = packedNote.visibleUserIds!.some(id => meId === id);
|
||||
if (packedNote.visibility === 'specified') {
|
||||
if (meId == null) {
|
||||
return true;
|
||||
} else {
|
||||
// 指定されているかどうか
|
||||
const specified = packedNote.visibleUserIds!.some(id => meId === id);
|
||||
|
||||
if (!specified) {
|
||||
hide = true;
|
||||
}
|
||||
if (!specified) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示
|
||||
if (!hide) {
|
||||
if (packedNote.visibility === 'followers') {
|
||||
if (meId == null) {
|
||||
hide = true;
|
||||
} else if (packedNote.reply && (meId === packedNote.reply.userId)) {
|
||||
// 自分の投稿に対するリプライ
|
||||
hide = false;
|
||||
} else if (packedNote.mentions && packedNote.mentions.some(id => meId === id)) {
|
||||
// 自分へのメンション
|
||||
hide = false;
|
||||
} else {
|
||||
// フォロワーかどうか
|
||||
// TODO: 当関数呼び出しごとにクエリが走るのは重そうだからなんとかする
|
||||
const isFollowing = await this.followingsRepository.exists({
|
||||
where: {
|
||||
followeeId: packedNote.userId,
|
||||
followerId: meId,
|
||||
},
|
||||
});
|
||||
|
||||
hide = !isFollowing;
|
||||
if (packedNote.visibility === 'followers') {
|
||||
if (meId == null) {
|
||||
return true;
|
||||
} else if (packedNote.reply && (meId === packedNote.reply.userId)) {
|
||||
// 自分の投稿に対するリプライ
|
||||
return false;
|
||||
} else if (packedNote.mentions && packedNote.mentions.some(id => meId === id)) {
|
||||
// 自分へのメンション
|
||||
return false;
|
||||
} else {
|
||||
// フォロワーかどうか
|
||||
const followings = await this.cacheService.userFollowingsCache.fetch(meId);
|
||||
if (!Object.hasOwn(followings, packedNote.userId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hide) {
|
||||
packedNote.visibleUserIds = undefined;
|
||||
packedNote.fileIds = [];
|
||||
packedNote.files = [];
|
||||
packedNote.text = null;
|
||||
packedNote.poll = undefined;
|
||||
packedNote.cw = null;
|
||||
packedNote.isHidden = true;
|
||||
// TODO: hiddenReason みたいなのを提供しても良さそう
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public hideNote(packedNote: Packed<'Note'>): void {
|
||||
packedNote.visibleUserIds = undefined;
|
||||
packedNote.fileIds = [];
|
||||
packedNote.files = [];
|
||||
packedNote.text = null;
|
||||
packedNote.poll = undefined;
|
||||
packedNote.cw = null;
|
||||
packedNote.isHidden = true;
|
||||
// TODO: hiddenReason みたいなのを提供しても良さそう
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -468,8 +460,8 @@ export class NoteEntityService implements OnModuleInit {
|
|||
|
||||
this.treatVisibility(packed);
|
||||
|
||||
if (!opts.skipHide) {
|
||||
await this.hideNote(packed, meId);
|
||||
if (!opts.skipHide && await this.shouldHideNote(packed, meId)) {
|
||||
this.hideNote(packed);
|
||||
}
|
||||
|
||||
return packed;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { SigninApiService } from './api/SigninApiService.js';
|
|||
import { SigninService } from './api/SigninService.js';
|
||||
import { SignupApiService } from './api/SignupApiService.js';
|
||||
import { StreamingApiServerService } from './api/StreamingApiServerService.js';
|
||||
import { NoteStreamingLockdownService } from './api/stream/NoteStreamingLockdownService.js';
|
||||
import { OpenApiServerService } from './api/openapi/OpenApiServerService.js';
|
||||
import { ClientServerService } from './web/ClientServerService.js';
|
||||
import { HtmlTemplateService } from './web/HtmlTemplateService.js';
|
||||
|
|
@ -80,6 +81,7 @@ import { SigninWithPasskeyApiService } from './api/SigninWithPasskeyApiService.j
|
|||
SigninService,
|
||||
SignupApiService,
|
||||
StreamingApiServerService,
|
||||
NoteStreamingLockdownService,
|
||||
MainChannel,
|
||||
AdminChannel,
|
||||
AntennaChannel,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||
import type { Packed } from '@/misc/json-schema.js';
|
||||
import type { MiUser } from '@/models/User.js';
|
||||
|
||||
type HiddenLayer = 'note' | 'renote' | 'renoteRenote';
|
||||
|
||||
type LockdownCheckResult =
|
||||
| { shouldSkip: true }
|
||||
| { shouldSkip: false; hiddenLayers: Set<HiddenLayer> };
|
||||
|
||||
@Injectable()
|
||||
export class NoteStreamingLockdownService {
|
||||
constructor(
|
||||
private noteEntityService: NoteEntityService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* ロックダウン設定に基づいてノートの可視性を判定する(純粋関数)
|
||||
* 副作用なしで判定のみを行う
|
||||
*
|
||||
* @param note - 判定対象のノート
|
||||
* @param meId - 閲覧者のユーザーID(未ログインの場合はnull)
|
||||
* @returns shouldSkip: true の場合はノートを流さない、false の場合は hiddenLayers に基づいて隠す
|
||||
*/
|
||||
@bindThis
|
||||
public async checkLockdown(
|
||||
note: Packed<'Note'>,
|
||||
meId: MiUser['id'] | null,
|
||||
): Promise<LockdownCheckResult> {
|
||||
const hiddenLayers = new Set<HiddenLayer>();
|
||||
|
||||
// 1階層目: note自体
|
||||
const shouldHideThisNote = await this.noteEntityService.shouldHideNote(note, meId);
|
||||
if (shouldHideThisNote) {
|
||||
if (isRenotePacked(note) && isQuotePacked(note)) {
|
||||
// 引用リノートの場合、内容を隠して流す
|
||||
hiddenLayers.add('note');
|
||||
} else if (isRenotePacked(note)) {
|
||||
// 純粋リノートの場合、流さない
|
||||
return { shouldSkip: true };
|
||||
} else {
|
||||
// 通常ノートの場合、内容を隠して流す
|
||||
hiddenLayers.add('note');
|
||||
}
|
||||
}
|
||||
|
||||
// 2階層目: note.renote
|
||||
if (isRenotePacked(note) && note.renote) {
|
||||
const shouldHideRenote = await this.noteEntityService.shouldHideNote(note.renote, meId);
|
||||
if (shouldHideRenote) {
|
||||
if (isQuotePacked(note)) {
|
||||
// noteが引用リノートの場合、renote部分だけ隠す
|
||||
hiddenLayers.add('renote');
|
||||
} else {
|
||||
// noteが純粋リノートの場合、流さない
|
||||
return { shouldSkip: true };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3階層目: note.renote.renote
|
||||
if (isRenotePacked(note) && note.renote &&
|
||||
isRenotePacked(note.renote) && note.renote.renote) {
|
||||
const shouldHideRenoteRenote = await this.noteEntityService.shouldHideNote(note.renote.renote, meId);
|
||||
if (shouldHideRenoteRenote) {
|
||||
if (isQuotePacked(note.renote)) {
|
||||
// note.renoteが引用リノートの場合、renote.renote部分だけ隠す
|
||||
hiddenLayers.add('renoteRenote');
|
||||
} else {
|
||||
// note.renoteが純粋リノートの場合、note.renoteの意味がなくなるので流さない
|
||||
return { shouldSkip: true };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { shouldSkip: false, hiddenLayers };
|
||||
}
|
||||
|
||||
/**
|
||||
* hiddenLayersに基づいてノートの内容を隠す(副作用あり)
|
||||
*
|
||||
* @param note - 処理対象のノート
|
||||
* @param hiddenLayers - 隠す階層のセット
|
||||
*/
|
||||
@bindThis
|
||||
public applyHiding(
|
||||
note: Packed<'Note'>,
|
||||
hiddenLayers: Set<HiddenLayer>,
|
||||
): void {
|
||||
if (hiddenLayers.has('note')) {
|
||||
this.noteEntityService.hideNote(note);
|
||||
}
|
||||
if (hiddenLayers.has('renote') && note.renote) {
|
||||
this.noteEntityService.hideNote(note.renote);
|
||||
}
|
||||
if (hiddenLayers.has('renoteRenote') && note.renote && note.renote.renote) {
|
||||
this.noteEntityService.hideNote(note.renote.renote);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ストリーミング配信用にノートのロックダウン処理を適用する(便利メソッド)
|
||||
* checkLockdown + applyHiding を一括で行う
|
||||
*
|
||||
* @param note - 処理対象のノート(必要に応じて内容が隠される)
|
||||
* @param meId - 閲覧者のユーザーID(未ログインの場合はnull)
|
||||
* @returns shouldSkip: true の場合はノートを流さない
|
||||
*/
|
||||
@bindThis
|
||||
public async processLockdown(
|
||||
note: Packed<'Note'>,
|
||||
meId: MiUser['id'] | null,
|
||||
): Promise<{ shouldSkip: boolean }> {
|
||||
const result = await this.checkLockdown(note, meId);
|
||||
if (result.shouldSkip) {
|
||||
return { shouldSkip: true };
|
||||
}
|
||||
this.applyHiding(note, result.hiddenLayers);
|
||||
return { shouldSkip: false };
|
||||
}
|
||||
}
|
||||
|
|
@ -6,9 +6,11 @@
|
|||
import { Inject, Injectable, Scope } from '@nestjs/common';
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||
import type { JsonObject } from '@/misc/json-value.js';
|
||||
import Channel, { type ChannelRequest } from '../channel.js';
|
||||
import { NoteStreamingLockdownService } from '../NoteStreamingLockdownService.js';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
|
|
@ -24,6 +26,7 @@ export class AntennaChannel extends Channel {
|
|||
request: ChannelRequest,
|
||||
|
||||
private noteEntityService: NoteEntityService,
|
||||
private noteStreamingFilterService: NoteStreamingLockdownService,
|
||||
) {
|
||||
super(request);
|
||||
//this.onEvent = this.onEvent.bind(this);
|
||||
|
|
@ -45,6 +48,18 @@ export class AntennaChannel extends Channel {
|
|||
|
||||
if (this.isNoteMutedOrBlocked(note)) return;
|
||||
|
||||
const { shouldSkip: shouldSkipByLockdown } = await this.noteStreamingFilterService.processLockdown(note, this.user?.id ?? null);
|
||||
if (shouldSkipByLockdown) return;
|
||||
|
||||
if (this.user) {
|
||||
if (isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.send('note', note);
|
||||
} else {
|
||||
this.send(data.type, data.body);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { isInstanceMuted } from '@/misc/is-instance-muted.js';
|
|||
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||
import type { JsonObject } from '@/misc/json-value.js';
|
||||
import Channel, { type ChannelRequest } from '../channel.js';
|
||||
import { NoteStreamingLockdownService } from '../NoteStreamingLockdownService.js';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
|
|
@ -26,6 +27,7 @@ export class ChannelChannel extends Channel {
|
|||
request: ChannelRequest,
|
||||
|
||||
private noteEntityService: NoteEntityService,
|
||||
private noteStreamingFilterService: NoteStreamingLockdownService,
|
||||
) {
|
||||
super(request);
|
||||
//this.onNote = this.onNote.bind(this);
|
||||
|
|
@ -50,10 +52,15 @@ export class ChannelChannel extends Channel {
|
|||
|
||||
if (this.isNoteMutedOrBlocked(note)) return;
|
||||
|
||||
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
const { shouldSkip: shouldSkipByLockdown } = await this.noteStreamingFilterService.processLockdown(note, this.user?.id ?? null);
|
||||
if (shouldSkipByLockdown) return;
|
||||
|
||||
if (this.user) {
|
||||
if (isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { RoleService } from '@/core/RoleService.js';
|
|||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||
import type { JsonObject } from '@/misc/json-value.js';
|
||||
import Channel, { type ChannelRequest } from '../channel.js';
|
||||
import { NoteStreamingLockdownService } from '../NoteStreamingLockdownService.js';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
|
|
@ -29,6 +30,7 @@ export class GlobalTimelineChannel extends Channel {
|
|||
private metaService: MetaService,
|
||||
private roleService: RoleService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private noteStreamingFilterService: NoteStreamingLockdownService,
|
||||
) {
|
||||
super(request);
|
||||
//this.onNote = this.onNote.bind(this);
|
||||
|
|
@ -60,10 +62,15 @@ export class GlobalTimelineChannel extends Channel {
|
|||
|
||||
if (this.isNoteMutedOrBlocked(note)) return;
|
||||
|
||||
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
const { shouldSkip: shouldSkipByLockdown } = await this.noteStreamingFilterService.processLockdown(note, this.user?.id ?? null);
|
||||
if (shouldSkipByLockdown) return;
|
||||
|
||||
if (this.user) {
|
||||
if (isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||
import type { JsonObject } from '@/misc/json-value.js';
|
||||
import Channel, { type ChannelRequest } from '../channel.js';
|
||||
import { NoteStreamingLockdownService } from '../NoteStreamingLockdownService.js';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
|
|
@ -25,6 +26,7 @@ export class HashtagChannel extends Channel {
|
|||
request: ChannelRequest,
|
||||
|
||||
private noteEntityService: NoteEntityService,
|
||||
private noteStreamingFilterService: NoteStreamingLockdownService,
|
||||
) {
|
||||
super(request);
|
||||
//this.onNote = this.onNote.bind(this);
|
||||
|
|
@ -48,10 +50,15 @@ export class HashtagChannel extends Channel {
|
|||
|
||||
if (this.isNoteMutedOrBlocked(note)) return;
|
||||
|
||||
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
const { shouldSkip: shouldSkipByLockdown } = await this.noteStreamingFilterService.processLockdown(note, this.user?.id ?? null);
|
||||
if (shouldSkipByLockdown) return;
|
||||
|
||||
if (this.user) {
|
||||
if (isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||
import type { JsonObject } from '@/misc/json-value.js';
|
||||
import Channel, { type ChannelRequest } from '../channel.js';
|
||||
import { NoteStreamingLockdownService } from '../NoteStreamingLockdownService.js';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
|
|
@ -26,6 +27,7 @@ export class HomeTimelineChannel extends Channel {
|
|||
request: ChannelRequest,
|
||||
|
||||
private noteEntityService: NoteEntityService,
|
||||
private noteStreamingFilterService: NoteStreamingLockdownService,
|
||||
) {
|
||||
super(request);
|
||||
//this.onNote = this.onNote.bind(this);
|
||||
|
|
@ -84,10 +86,15 @@ export class HomeTimelineChannel extends Channel {
|
|||
|
||||
if (this.isNoteMutedOrBlocked(note)) return;
|
||||
|
||||
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
const { shouldSkip: shouldSkipByLockdown } = await this.noteStreamingFilterService.processLockdown(note, this.user?.id ?? null);
|
||||
if (shouldSkipByLockdown) return;
|
||||
|
||||
if (this.user) {
|
||||
if (isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { RoleService } from '@/core/RoleService.js';
|
|||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||
import type { JsonObject } from '@/misc/json-value.js';
|
||||
import Channel, { type ChannelRequest } from '../channel.js';
|
||||
import { NoteStreamingLockdownService } from '../NoteStreamingLockdownService.js';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
|
|
@ -31,6 +32,7 @@ export class HybridTimelineChannel extends Channel {
|
|||
private metaService: MetaService,
|
||||
private roleService: RoleService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private noteStreamingFilterService: NoteStreamingLockdownService,
|
||||
) {
|
||||
super(request);
|
||||
//this.onNote = this.onNote.bind(this);
|
||||
|
|
@ -104,10 +106,15 @@ export class HybridTimelineChannel extends Channel {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.user && note.renoteId && !note.text) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
const { shouldSkip: shouldSkipByLockdown } = await this.noteStreamingFilterService.processLockdown(note, this.user?.id ?? null);
|
||||
if (shouldSkipByLockdown) return;
|
||||
|
||||
if (this.user) {
|
||||
if (isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { RoleService } from '@/core/RoleService.js';
|
|||
import { isQuotePacked, isRenotePacked } from '@/misc/is-renote.js';
|
||||
import type { JsonObject } from '@/misc/json-value.js';
|
||||
import Channel, { type ChannelRequest } from '../channel.js';
|
||||
import { NoteStreamingLockdownService } from '../NoteStreamingLockdownService.js';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
|
|
@ -30,6 +31,7 @@ export class LocalTimelineChannel extends Channel {
|
|||
private metaService: MetaService,
|
||||
private roleService: RoleService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private noteStreamingFilterService: NoteStreamingLockdownService,
|
||||
) {
|
||||
super(request);
|
||||
//this.onNote = this.onNote.bind(this);
|
||||
|
|
@ -70,10 +72,15 @@ export class LocalTimelineChannel extends Channel {
|
|||
|
||||
if (this.isNoteMutedOrBlocked(note)) return;
|
||||
|
||||
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
const { shouldSkip: shouldSkipByLockdown } = await this.noteStreamingFilterService.processLockdown(note, this.user?.id ?? null);
|
||||
if (shouldSkipByLockdown) return;
|
||||
|
||||
if (this.user) {
|
||||
if (isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ import { Inject, Injectable, Scope } from '@nestjs/common';
|
|||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||
import type { JsonObject } from '@/misc/json-value.js';
|
||||
import Channel, { type ChannelRequest } from '../channel.js';
|
||||
import { NoteStreamingLockdownService } from '../NoteStreamingLockdownService.js';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
|
|
@ -25,6 +27,7 @@ export class RoleTimelineChannel extends Channel {
|
|||
|
||||
private noteEntityService: NoteEntityService,
|
||||
private roleservice: RoleService,
|
||||
private noteStreamingFilterService: NoteStreamingLockdownService,
|
||||
) {
|
||||
super(request);
|
||||
//this.onNote = this.onNote.bind(this);
|
||||
|
|
@ -50,6 +53,18 @@ export class RoleTimelineChannel extends Channel {
|
|||
|
||||
if (this.isNoteMutedOrBlocked(note)) return;
|
||||
|
||||
const { shouldSkip: shouldSkipByLockdown } = await this.noteStreamingFilterService.processLockdown(note, this.user?.id ?? null);
|
||||
if (shouldSkipByLockdown) return;
|
||||
|
||||
if (this.user) {
|
||||
if (isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.send('note', note);
|
||||
} else {
|
||||
this.send(data.type, data.body);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||
import type { JsonObject } from '@/misc/json-value.js';
|
||||
import Channel, { type ChannelRequest } from '../channel.js';
|
||||
import { NoteStreamingLockdownService } from '../NoteStreamingLockdownService.js';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
|
|
@ -36,6 +37,7 @@ export class UserListChannel extends Channel {
|
|||
request: ChannelRequest,
|
||||
|
||||
private noteEntityService: NoteEntityService,
|
||||
private noteStreamingFilterService: NoteStreamingLockdownService,
|
||||
) {
|
||||
super(request);
|
||||
//this.updateListUsers = this.updateListUsers.bind(this);
|
||||
|
|
@ -117,10 +119,15 @@ export class UserListChannel extends Channel {
|
|||
|
||||
if (this.isNoteMutedOrBlocked(note)) return;
|
||||
|
||||
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
const { shouldSkip: shouldSkipByLockdown } = await this.noteStreamingFilterService.processLockdown(note, this.user?.id ?? null);
|
||||
if (shouldSkipByLockdown) return;
|
||||
|
||||
if (this.user) {
|
||||
if (isRenotePacked(note) && !isQuotePacked(note)) {
|
||||
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
|
||||
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);
|
||||
note.renote.myReaction = myRenoteReaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue