From 020c4f1716c759b40ea08cca8e42e5f71c38c0d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=82=8F=E3=82=8F=E3=82=8F=E3=81=A8=E3=83=BC?= =?UTF-8?q?=E3=81=AB=E3=82=85?= <17376330+u1-liquid@users.noreply.github.com> Date: Wed, 29 Jan 2025 07:30:05 +0900 Subject: [PATCH] =?UTF-8?q?spec(backend/stream):=20=E3=83=A2=E3=83=87?= =?UTF-8?q?=E3=83=AC=E3=83=BC=E3=82=BF=E3=83=BC=E3=81=AB=E3=82=82=E4=B8=80?= =?UTF-8?q?=E8=88=AC=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC=E3=81=A8=E5=90=8C?= =?UTF-8?q?=E3=81=98=E3=81=8F=E9=80=9A=E5=B8=B8=E3=81=AE=E6=8A=95=E7=A8=BF?= =?UTF-8?q?=E3=81=AFcdn=E7=B5=8C=E7=94=B1=E3=81=A7=E9=85=8D=E4=BF=A1?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(MisskeyIO#920)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/core/RoleService.ts | 19 ++++++++++++++--- .../src/core/entities/UserEntityService.ts | 11 +--------- .../server/api/StreamingApiServerService.ts | 3 +++ .../src/server/api/stream/Connection.ts | 4 ++++ .../backend/src/server/api/stream/channel.ts | 4 ++++ .../src/server/api/stream/channels/antenna.ts | 9 +++++++- .../src/server/api/stream/channels/channel.ts | 11 ++++++++-- .../api/stream/channels/global-timeline.ts | 7 +++++-- .../api/stream/channels/home-timeline.ts | 11 ++++++++-- .../api/stream/channels/hybrid-timeline.ts | 7 +++++-- .../api/stream/channels/local-timeline.ts | 7 +++++-- .../api/stream/channels/role-timeline.ts | 13 +++++++----- .../server/api/stream/channels/user-list.ts | 13 +++++++++--- .../frontend/src/components/MkTimeline.vue | 21 +++++++++---------- 14 files changed, 97 insertions(+), 43 deletions(-) diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 60c935887..50f074d07 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -350,7 +350,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { * 指定ユーザーのバッジロール一覧取得 */ @bindThis - public async getUserBadgeRoles(userId: MiUser['id']) { + public async getUserBadgeRoles(userId: MiUser['id'], publicOnly: boolean) { const now = Date.now(); let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId })); // 期限切れのロールを除外 @@ -362,12 +362,25 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { if (badgeCondRoles.length > 0) { const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null; const matchedBadgeCondRoles = badgeCondRoles.filter(r => this.evalCond(user!, assignedRoles, r.condFormula)); - return [...assignedBadgeRoles, ...matchedBadgeCondRoles]; + return this.sortAndMapBadgeRoles([...assignedBadgeRoles, ...matchedBadgeCondRoles], publicOnly); } else { - return assignedBadgeRoles; + return this.sortAndMapBadgeRoles(assignedBadgeRoles, publicOnly); } } + @bindThis + private sortAndMapBadgeRoles(roles: MiRole[], publicOnly: boolean) { + return roles + .filter((r) => r.isPublic || !publicOnly) + .sort((a, b) => b.displayOrder - a.displayOrder) + .map((r) => ({ + name: r.name, + iconUrl: r.iconUrl, + displayOrder: r.displayOrder, + behavior: r.badgeBehavior ?? undefined, + })); + } + @bindThis public async getUserPolicies(userId: MiUser['id'] | null): Promise { const meta = await this.metaService.fetch(); diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index e9bf5a397..74b18d9a4 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -499,16 +499,7 @@ export class UserEntityService implements OnModuleInit { } : undefined) : undefined, emojis: this.customEmojiService.populateEmojis(user.emojis, user.host), onlineStatus: this.getOnlineStatus(user), - badgeRoles: this.roleService.getUserBadgeRoles(user.id).then((rs) => rs - .filter((r) => r.isPublic || iAmModerator) - .sort((a, b) => b.displayOrder - a.displayOrder) - .map((r) => ({ - name: r.name, - iconUrl: r.iconUrl, - displayOrder: r.displayOrder, - behavior: r.badgeBehavior ?? undefined, - })), - ), + badgeRoles: this.roleService.getUserBadgeRoles(user.id, !iAmModerator), ...(isDetailed ? { url: profile!.url, diff --git a/packages/backend/src/server/api/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts index 76a34cc18..4da4edb4f 100644 --- a/packages/backend/src/server/api/StreamingApiServerService.ts +++ b/packages/backend/src/server/api/StreamingApiServerService.ts @@ -15,6 +15,7 @@ import { bindThis } from '@/decorators.js'; import { CacheService } from '@/core/CacheService.js'; import { MiLocalUser } from '@/models/User.js'; import { UserService } from '@/core/UserService.js'; +import { RoleService } from '@/core/RoleService.js'; import { ChannelFollowingService } from '@/core/ChannelFollowingService.js'; import { AuthenticateService, AuthenticationError } from './AuthenticateService.js'; import MainStreamConnection from './stream/Connection.js'; @@ -40,6 +41,7 @@ export class StreamingApiServerService { private channelsService: ChannelsService, private notificationService: NotificationService, private usersService: UserService, + private roleService: RoleService, private channelFollowingService: ChannelFollowingService, ) { } @@ -99,6 +101,7 @@ export class StreamingApiServerService { this.noteReadService, this.notificationService, this.cacheService, + this.roleService, this.channelFollowingService, user, app, ); diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts index 41c0feccc..2e7b8d3cf 100644 --- a/packages/backend/src/server/api/stream/Connection.ts +++ b/packages/backend/src/server/api/stream/Connection.ts @@ -14,6 +14,7 @@ import { CacheService } from '@/core/CacheService.js'; import { MiFollowing, MiUserProfile } from '@/models/_.js'; import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js'; import { ChannelFollowingService } from '@/core/ChannelFollowingService.js'; +import { RoleService } from '@/core/RoleService.js'; import type { ChannelsService } from './ChannelsService.js'; import type { EventEmitter } from 'events'; import type Channel from './channel.js'; @@ -31,6 +32,7 @@ export default class Connection { private subscribingNotes: any = {}; private cachedNotes: Packed<'Note'>[] = []; public userProfile: MiUserProfile | null = null; + public isModerator = false; public following: Record | undefined> = {}; public followingChannels: Set = new Set(); public userIdsWhoMeMuting: Set = new Set(); @@ -44,6 +46,7 @@ export default class Connection { private noteReadService: NoteReadService, private notificationService: NotificationService, private cacheService: CacheService, + private roleService: RoleService, private channelFollowingService: ChannelFollowingService, user: MiUser | null | undefined, @@ -77,6 +80,7 @@ export default class Connection { public async init() { if (this.user != null) { await this.fetch(); + this.isModerator = await this.roleService.isModerator(this.user); if (!this.fetchIntervalId) { this.fetchIntervalId = setInterval(this.fetch, 1000 * 10); diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts index a267d27fb..a8983b740 100644 --- a/packages/backend/src/server/api/stream/channel.ts +++ b/packages/backend/src/server/api/stream/channel.ts @@ -30,6 +30,10 @@ export default abstract class Channel { return this.connection.userProfile; } + protected get iAmModerator() { + return this.connection.isModerator; + } + protected get following() { return this.connection.following; } diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts index f47a644de..3bc2c789a 100644 --- a/packages/backend/src/server/api/stream/channels/antenna.ts +++ b/packages/backend/src/server/api/stream/channels/antenna.ts @@ -4,8 +4,9 @@ */ import { Injectable } from '@nestjs/common'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; +import { RoleService } from '@/core/RoleService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -18,6 +19,7 @@ class AntennaChannel extends Channel { private minimize: boolean; constructor( + private roleService: RoleService, private noteEntityService: NoteEntityService, id: string, @@ -56,11 +58,14 @@ class AntennaChannel extends Channel { } if (this.minimize && ['public', 'home'].includes(note.visibility)) { + const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined; + this.send('note', { id: note.id, myReaction: note.myReaction, poll: note.poll?.choices ? { choices: note.poll.choices } : undefined, reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined, renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined, + ...(badgeRoles?.length ? { user: { badgeRoles } } : {}), }); } else { this.send('note', note); @@ -84,6 +89,7 @@ export class AntennaChannelService implements MiChannelService { public readonly kind = AntennaChannel.kind; constructor( + private roleService: RoleService, private noteEntityService: NoteEntityService, ) { } @@ -91,6 +97,7 @@ export class AntennaChannelService implements MiChannelService { @bindThis public create(id: string, connection: Channel['connection']): AntennaChannel { return new AntennaChannel( + this.roleService, this.noteEntityService, id, connection, diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts index 7ebc2ed56..23312a628 100644 --- a/packages/backend/src/server/api/stream/channels/channel.ts +++ b/packages/backend/src/server/api/stream/channels/channel.ts @@ -4,9 +4,10 @@ */ import { Injectable } from '@nestjs/common'; -import type { Packed } from '@/misc/json-schema.js'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; +import type { Packed } from '@/misc/json-schema.js'; +import { RoleService } from '@/core/RoleService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -18,6 +19,7 @@ class ChannelChannel extends Channel { private minimize: boolean; constructor( + private roleService: RoleService, private noteEntityService: NoteEntityService, id: string, @@ -62,11 +64,14 @@ class ChannelChannel extends Channel { } if (this.minimize && ['public', 'home'].includes(note.visibility)) { + const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined; + this.send('note', { id: note.id, myReaction: note.myReaction, poll: note.poll?.choices ? { choices: note.poll.choices } : undefined, reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined, renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined, + ...(badgeRoles?.length ? { user: { badgeRoles } } : {}), }); } else { this.send('note', note); @@ -87,6 +92,7 @@ export class ChannelChannelService implements MiChannelService { public readonly kind = ChannelChannel.kind; constructor( + private roleService: RoleService, private noteEntityService: NoteEntityService, ) { } @@ -94,6 +100,7 @@ export class ChannelChannelService implements MiChannelService { @bindThis public create(id: string, connection: Channel['connection']): ChannelChannel { return new ChannelChannel( + this.roleService, this.noteEntityService, id, connection, diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index 371449cfd..4a7283919 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -4,11 +4,11 @@ */ import { Injectable } from '@nestjs/common'; +import { bindThis } from '@/decorators.js'; import type { Packed } from '@/misc/json-schema.js'; import { MetaService } from '@/core/MetaService.js'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; -import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -92,11 +92,14 @@ class GlobalTimelineChannel extends Channel { } if (this.minimize && ['public', 'home'].includes(note.visibility)) { + const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined; + this.send('note', { id: note.id, myReaction: note.myReaction, poll: note.poll?.choices ? { choices: note.poll.choices } : undefined, reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined, renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined, + ...(badgeRoles?.length ? { user: { badgeRoles } } : {}), }); } else { this.send('note', note); diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index 7b38cb59c..22c14259e 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -4,9 +4,10 @@ */ import { Injectable } from '@nestjs/common'; -import type { Packed } from '@/misc/json-schema.js'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; +import type { Packed } from '@/misc/json-schema.js'; +import { RoleService } from '@/core/RoleService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -20,6 +21,7 @@ class HomeTimelineChannel extends Channel { private minimize: boolean; constructor( + private roleService: RoleService, private noteEntityService: NoteEntityService, id: string, @@ -96,11 +98,14 @@ class HomeTimelineChannel extends Channel { } if (this.minimize && ['public', 'home'].includes(note.visibility)) { + const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined; + this.send('note', { id: note.id, myReaction: note.myReaction, poll: note.poll?.choices ? { choices: note.poll.choices } : undefined, reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined, renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined, + ...(badgeRoles?.length ? { user: { badgeRoles } } : {}), }); } else { this.send('note', note); @@ -121,6 +126,7 @@ export class HomeTimelineChannelService implements MiChannelService { public readonly kind = HomeTimelineChannel.kind; constructor( + private roleService: RoleService, private noteEntityService: NoteEntityService, ) { } @@ -128,6 +134,7 @@ export class HomeTimelineChannelService implements MiChannelService { @bindThis public create(id: string, connection: Channel['connection']): HomeTimelineChannel { return new HomeTimelineChannel( + this.roleService, this.noteEntityService, id, connection, diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index 4103fb5dc..2065594e0 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -4,11 +4,11 @@ */ import { Injectable } from '@nestjs/common'; +import { bindThis } from '@/decorators.js'; import type { Packed } from '@/misc/json-schema.js'; import { MetaService } from '@/core/MetaService.js'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; -import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -110,11 +110,14 @@ class HybridTimelineChannel extends Channel { } if (this.minimize && ['public', 'home'].includes(note.visibility)) { + const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined; + this.send('note', { id: note.id, myReaction: note.myReaction, poll: note.poll?.choices ? { choices: note.poll.choices } : undefined, reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined, renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined, + ...(badgeRoles?.length ? { user: { badgeRoles } } : {}), }); } else { this.send('note', note); diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 99d94ace9..7547b3b43 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -4,11 +4,11 @@ */ import { Injectable } from '@nestjs/common'; +import { bindThis } from '@/decorators.js'; import type { Packed } from '@/misc/json-schema.js'; import { MetaService } from '@/core/MetaService.js'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; -import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { isQuotePacked, isRenotePacked } from '@/misc/is-renote.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -95,11 +95,14 @@ class LocalTimelineChannel extends Channel { } if (this.minimize && ['public', 'home'].includes(note.visibility)) { + const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined; + this.send('note', { id: note.id, myReaction: note.myReaction, poll: note.poll?.choices ? { choices: note.poll.choices } : undefined, reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined, renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined, + ...(badgeRoles?.length ? { user: { badgeRoles } } : {}), }); } else { this.send('note', note); diff --git a/packages/backend/src/server/api/stream/channels/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts index b735507e2..057999ffd 100644 --- a/packages/backend/src/server/api/stream/channels/role-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts @@ -4,9 +4,9 @@ */ import { Injectable } from '@nestjs/common'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -19,8 +19,8 @@ class RoleTimelineChannel extends Channel { private minimize: boolean; constructor( + private roleService: RoleService, private noteEntityService: NoteEntityService, - private roleservice: RoleService, id: string, connection: Channel['connection'], @@ -42,7 +42,7 @@ class RoleTimelineChannel extends Channel { if (data.type === 'note') { const note = data.body; - if (!(await this.roleservice.isExplorable({ id: this.roleId }))) { + if (!(await this.roleService.isExplorable({ id: this.roleId }))) { return; } if (note.visibility !== 'public') return; @@ -78,11 +78,14 @@ class RoleTimelineChannel extends Channel { } if (this.minimize && ['public', 'home'].includes(note.visibility)) { + const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined; + this.send('note', { id: note.id, myReaction: note.myReaction, poll: note.poll?.choices ? { choices: note.poll.choices } : undefined, reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined, renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined, + ...(badgeRoles?.length ? { user: { badgeRoles } } : {}), }); } else { this.send('note', note); @@ -106,16 +109,16 @@ export class RoleTimelineChannelService implements MiChannelService { public readonly kind = RoleTimelineChannel.kind; constructor( + private roleService: RoleService, private noteEntityService: NoteEntityService, - private roleservice: RoleService, ) { } @bindThis public create(id: string, connection: Channel['connection']): RoleTimelineChannel { return new RoleTimelineChannel( + this.roleService, this.noteEntityService, - this.roleservice, id, connection, ); diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts index 4b8df4368..af1b0134b 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -4,11 +4,12 @@ */ import { Inject, Injectable } from '@nestjs/common'; -import type { MiUserListMembership, UserListMembershipsRepository, UserListsRepository } from '@/models/_.js'; -import type { Packed } from '@/misc/json-schema.js'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; +import type { MiUserListMembership, UserListMembershipsRepository, UserListsRepository } from '@/models/_.js'; +import type { Packed } from '@/misc/json-schema.js'; +import { RoleService } from '@/core/RoleService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -26,6 +27,7 @@ class UserListChannel extends Channel { constructor( private userListsRepository: UserListsRepository, private userListMembershipsRepository: UserListMembershipsRepository, + private roleService: RoleService, private noteEntityService: NoteEntityService, id: string, @@ -135,11 +137,14 @@ class UserListChannel extends Channel { } if (this.minimize && ['public', 'home'].includes(note.visibility)) { + const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined; + this.send('note', { id: note.id, myReaction: note.myReaction, poll: note.poll?.choices ? { choices: note.poll.choices } : undefined, reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined, renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined, + ...(badgeRoles?.length ? { user: { badgeRoles } } : {}), }); } else { this.send('note', note); @@ -169,6 +174,7 @@ export class UserListChannelService implements MiChannelService { @Inject(DI.userListMembershipsRepository) private userListMembershipsRepository: UserListMembershipsRepository, + private roleService: RoleService, private noteEntityService: NoteEntityService, ) { } @@ -178,6 +184,7 @@ export class UserListChannelService implements MiChannelService { return new UserListChannel( this.userListsRepository, this.userListMembershipsRepository, + this.roleService, this.noteEntityService, id, connection, diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index cf451d4a0..daf0becde 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -24,7 +24,7 @@ import MkPullToRefresh from '@/components/MkPullToRefresh.vue'; import { useStream } from '@/stream.js'; import * as sound from '@/scripts/sound.js'; import { deepMerge } from '@/scripts/merge.js'; -import { $i, iAmModerator } from '@/account.js'; +import { $i } from '@/account.js'; import { instance } from '@/instance.js'; import { defaultStore } from '@/store.js'; import { Paging } from '@/components/MkPagination.vue'; @@ -108,7 +108,6 @@ async function prepend(data) { let connection: Misskey.ChannelConnection | null = null; let connection2: Misskey.ChannelConnection | null = null; let paginationQuery: Paging | null = null; -const minimize = !iAmModerator; const stream = useStream(); @@ -117,13 +116,13 @@ function connectChannel() { if (props.antenna == null) return; connection = stream.useChannel('antenna', { antennaId: props.antenna, - minimize: minimize, + minimize: true, }); } else if (props.src === 'home') { connection = stream.useChannel('homeTimeline', { withRenotes: props.withRenotes, withFiles: props.onlyFiles ? true : undefined, - minimize: minimize, + minimize: true, }); connection2 = stream.useChannel('main'); } else if (props.src === 'local') { @@ -131,27 +130,27 @@ function connectChannel() { withRenotes: props.withRenotes, withReplies: props.withReplies, withFiles: props.onlyFiles ? true : undefined, - minimize: minimize, + minimize: true, }); } else if (props.src === 'media') { connection = stream.useChannel('hybridTimeline', { withRenotes: props.withRenotes, withReplies: props.withReplies, withFiles: true, - minimize: minimize, + minimize: true, }); } else if (props.src === 'social') { connection = stream.useChannel('hybridTimeline', { withRenotes: props.withRenotes, withReplies: props.withReplies, withFiles: props.onlyFiles ? true : undefined, - minimize: minimize, + minimize: true, }); } else if (props.src === 'global') { connection = stream.useChannel('globalTimeline', { withRenotes: props.withRenotes, withFiles: props.onlyFiles ? true : undefined, - minimize: minimize, + minimize: true, }); } else if (props.src === 'mentions') { connection = stream.useChannel('main'); @@ -170,19 +169,19 @@ function connectChannel() { withRenotes: props.withRenotes, withFiles: props.onlyFiles ? true : undefined, listId: props.list, - minimize: minimize, + minimize: true, }); } else if (props.src === 'channel') { if (props.channel == null) return; connection = stream.useChannel('channel', { channelId: props.channel, - minimize: minimize, + minimize: true, }); } else if (props.src === 'role') { if (props.role == null) return; connection = stream.useChannel('roleTimeline', { roleId: props.role, - minimize: minimize, + minimize: true, }); } if (props.src !== 'directs' && props.src !== 'mentions') connection?.on('note', prepend);