spec(backend/stream): モデレーターにも一般ユーザーと同じく通常の投稿はcdn経由で配信するように (MisskeyIO#920)
This commit is contained in:
parent
d7d270b789
commit
020c4f1716
14 changed files with 97 additions and 43 deletions
|
@ -350,7 +350,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
* 指定ユーザーのバッジロール一覧取得
|
* 指定ユーザーのバッジロール一覧取得
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async getUserBadgeRoles(userId: MiUser['id']) {
|
public async getUserBadgeRoles(userId: MiUser['id'], publicOnly: boolean) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId }));
|
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) {
|
if (badgeCondRoles.length > 0) {
|
||||||
const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null;
|
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));
|
const matchedBadgeCondRoles = badgeCondRoles.filter(r => this.evalCond(user!, assignedRoles, r.condFormula));
|
||||||
return [...assignedBadgeRoles, ...matchedBadgeCondRoles];
|
return this.sortAndMapBadgeRoles([...assignedBadgeRoles, ...matchedBadgeCondRoles], publicOnly);
|
||||||
} else {
|
} 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
|
@bindThis
|
||||||
public async getUserPolicies(userId: MiUser['id'] | null): Promise<RolePolicies> {
|
public async getUserPolicies(userId: MiUser['id'] | null): Promise<RolePolicies> {
|
||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
|
|
|
@ -499,16 +499,7 @@ export class UserEntityService implements OnModuleInit {
|
||||||
} : undefined) : undefined,
|
} : undefined) : undefined,
|
||||||
emojis: this.customEmojiService.populateEmojis(user.emojis, user.host),
|
emojis: this.customEmojiService.populateEmojis(user.emojis, user.host),
|
||||||
onlineStatus: this.getOnlineStatus(user),
|
onlineStatus: this.getOnlineStatus(user),
|
||||||
badgeRoles: this.roleService.getUserBadgeRoles(user.id).then((rs) => rs
|
badgeRoles: this.roleService.getUserBadgeRoles(user.id, !iAmModerator),
|
||||||
.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,
|
|
||||||
})),
|
|
||||||
),
|
|
||||||
|
|
||||||
...(isDetailed ? {
|
...(isDetailed ? {
|
||||||
url: profile!.url,
|
url: profile!.url,
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { bindThis } from '@/decorators.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
import { MiLocalUser } from '@/models/User.js';
|
import { MiLocalUser } from '@/models/User.js';
|
||||||
import { UserService } from '@/core/UserService.js';
|
import { UserService } from '@/core/UserService.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import { ChannelFollowingService } from '@/core/ChannelFollowingService.js';
|
import { ChannelFollowingService } from '@/core/ChannelFollowingService.js';
|
||||||
import { AuthenticateService, AuthenticationError } from './AuthenticateService.js';
|
import { AuthenticateService, AuthenticationError } from './AuthenticateService.js';
|
||||||
import MainStreamConnection from './stream/Connection.js';
|
import MainStreamConnection from './stream/Connection.js';
|
||||||
|
@ -40,6 +41,7 @@ export class StreamingApiServerService {
|
||||||
private channelsService: ChannelsService,
|
private channelsService: ChannelsService,
|
||||||
private notificationService: NotificationService,
|
private notificationService: NotificationService,
|
||||||
private usersService: UserService,
|
private usersService: UserService,
|
||||||
|
private roleService: RoleService,
|
||||||
private channelFollowingService: ChannelFollowingService,
|
private channelFollowingService: ChannelFollowingService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
@ -99,6 +101,7 @@ export class StreamingApiServerService {
|
||||||
this.noteReadService,
|
this.noteReadService,
|
||||||
this.notificationService,
|
this.notificationService,
|
||||||
this.cacheService,
|
this.cacheService,
|
||||||
|
this.roleService,
|
||||||
this.channelFollowingService,
|
this.channelFollowingService,
|
||||||
user, app,
|
user, app,
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { CacheService } from '@/core/CacheService.js';
|
||||||
import { MiFollowing, MiUserProfile } from '@/models/_.js';
|
import { MiFollowing, MiUserProfile } from '@/models/_.js';
|
||||||
import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js';
|
import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js';
|
||||||
import { ChannelFollowingService } from '@/core/ChannelFollowingService.js';
|
import { ChannelFollowingService } from '@/core/ChannelFollowingService.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import type { ChannelsService } from './ChannelsService.js';
|
import type { ChannelsService } from './ChannelsService.js';
|
||||||
import type { EventEmitter } from 'events';
|
import type { EventEmitter } from 'events';
|
||||||
import type Channel from './channel.js';
|
import type Channel from './channel.js';
|
||||||
|
@ -31,6 +32,7 @@ export default class Connection {
|
||||||
private subscribingNotes: any = {};
|
private subscribingNotes: any = {};
|
||||||
private cachedNotes: Packed<'Note'>[] = [];
|
private cachedNotes: Packed<'Note'>[] = [];
|
||||||
public userProfile: MiUserProfile | null = null;
|
public userProfile: MiUserProfile | null = null;
|
||||||
|
public isModerator = false;
|
||||||
public following: Record<string, Pick<MiFollowing, 'withReplies'> | undefined> = {};
|
public following: Record<string, Pick<MiFollowing, 'withReplies'> | undefined> = {};
|
||||||
public followingChannels: Set<string> = new Set();
|
public followingChannels: Set<string> = new Set();
|
||||||
public userIdsWhoMeMuting: Set<string> = new Set();
|
public userIdsWhoMeMuting: Set<string> = new Set();
|
||||||
|
@ -44,6 +46,7 @@ export default class Connection {
|
||||||
private noteReadService: NoteReadService,
|
private noteReadService: NoteReadService,
|
||||||
private notificationService: NotificationService,
|
private notificationService: NotificationService,
|
||||||
private cacheService: CacheService,
|
private cacheService: CacheService,
|
||||||
|
private roleService: RoleService,
|
||||||
private channelFollowingService: ChannelFollowingService,
|
private channelFollowingService: ChannelFollowingService,
|
||||||
|
|
||||||
user: MiUser | null | undefined,
|
user: MiUser | null | undefined,
|
||||||
|
@ -77,6 +80,7 @@ export default class Connection {
|
||||||
public async init() {
|
public async init() {
|
||||||
if (this.user != null) {
|
if (this.user != null) {
|
||||||
await this.fetch();
|
await this.fetch();
|
||||||
|
this.isModerator = await this.roleService.isModerator(this.user);
|
||||||
|
|
||||||
if (!this.fetchIntervalId) {
|
if (!this.fetchIntervalId) {
|
||||||
this.fetchIntervalId = setInterval(this.fetch, 1000 * 10);
|
this.fetchIntervalId = setInterval(this.fetch, 1000 * 10);
|
||||||
|
|
|
@ -30,6 +30,10 @@ export default abstract class Channel {
|
||||||
return this.connection.userProfile;
|
return this.connection.userProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected get iAmModerator() {
|
||||||
|
return this.connection.isModerator;
|
||||||
|
}
|
||||||
|
|
||||||
protected get following() {
|
protected get following() {
|
||||||
return this.connection.following;
|
return this.connection.following;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
|
||||||
import { bindThis } from '@/decorators.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 type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||||
import Channel, { type MiChannelService } from '../channel.js';
|
import Channel, { type MiChannelService } from '../channel.js';
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ class AntennaChannel extends Channel {
|
||||||
private minimize: boolean;
|
private minimize: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
|
|
||||||
id: string,
|
id: string,
|
||||||
|
@ -56,11 +58,14 @@ class AntennaChannel extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
||||||
|
const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined;
|
||||||
|
|
||||||
this.send('note', {
|
this.send('note', {
|
||||||
id: note.id, myReaction: note.myReaction,
|
id: note.id, myReaction: note.myReaction,
|
||||||
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
||||||
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
||||||
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
||||||
|
...(badgeRoles?.length ? { user: { badgeRoles } } : {}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.send('note', note);
|
this.send('note', note);
|
||||||
|
@ -84,6 +89,7 @@ export class AntennaChannelService implements MiChannelService<true> {
|
||||||
public readonly kind = AntennaChannel.kind;
|
public readonly kind = AntennaChannel.kind;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
@ -91,6 +97,7 @@ export class AntennaChannelService implements MiChannelService<true> {
|
||||||
@bindThis
|
@bindThis
|
||||||
public create(id: string, connection: Channel['connection']): AntennaChannel {
|
public create(id: string, connection: Channel['connection']): AntennaChannel {
|
||||||
return new AntennaChannel(
|
return new AntennaChannel(
|
||||||
|
this.roleService,
|
||||||
this.noteEntityService,
|
this.noteEntityService,
|
||||||
id,
|
id,
|
||||||
connection,
|
connection,
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
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 { 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 { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||||
import Channel, { type MiChannelService } from '../channel.js';
|
import Channel, { type MiChannelService } from '../channel.js';
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ class ChannelChannel extends Channel {
|
||||||
private minimize: boolean;
|
private minimize: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
|
|
||||||
id: string,
|
id: string,
|
||||||
|
@ -62,11 +64,14 @@ class ChannelChannel extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
||||||
|
const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined;
|
||||||
|
|
||||||
this.send('note', {
|
this.send('note', {
|
||||||
id: note.id, myReaction: note.myReaction,
|
id: note.id, myReaction: note.myReaction,
|
||||||
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
||||||
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
||||||
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
||||||
|
...(badgeRoles?.length ? { user: { badgeRoles } } : {}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.send('note', note);
|
this.send('note', note);
|
||||||
|
@ -87,6 +92,7 @@ export class ChannelChannelService implements MiChannelService<false> {
|
||||||
public readonly kind = ChannelChannel.kind;
|
public readonly kind = ChannelChannel.kind;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
@ -94,6 +100,7 @@ export class ChannelChannelService implements MiChannelService<false> {
|
||||||
@bindThis
|
@bindThis
|
||||||
public create(id: string, connection: Channel['connection']): ChannelChannel {
|
public create(id: string, connection: Channel['connection']): ChannelChannel {
|
||||||
return new ChannelChannel(
|
return new ChannelChannel(
|
||||||
|
this.roleService,
|
||||||
this.noteEntityService,
|
this.noteEntityService,
|
||||||
id,
|
id,
|
||||||
connection,
|
connection,
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
import { MetaService } from '@/core/MetaService.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 { RoleService } from '@/core/RoleService.js';
|
||||||
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||||
import Channel, { type MiChannelService } from '../channel.js';
|
import Channel, { type MiChannelService } from '../channel.js';
|
||||||
|
|
||||||
|
@ -92,11 +92,14 @@ class GlobalTimelineChannel extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
||||||
|
const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined;
|
||||||
|
|
||||||
this.send('note', {
|
this.send('note', {
|
||||||
id: note.id, myReaction: note.myReaction,
|
id: note.id, myReaction: note.myReaction,
|
||||||
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
||||||
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
||||||
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
||||||
|
...(badgeRoles?.length ? { user: { badgeRoles } } : {}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.send('note', note);
|
this.send('note', note);
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
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 { 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 { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||||
import Channel, { type MiChannelService } from '../channel.js';
|
import Channel, { type MiChannelService } from '../channel.js';
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ class HomeTimelineChannel extends Channel {
|
||||||
private minimize: boolean;
|
private minimize: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
|
|
||||||
id: string,
|
id: string,
|
||||||
|
@ -96,11 +98,14 @@ class HomeTimelineChannel extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
||||||
|
const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined;
|
||||||
|
|
||||||
this.send('note', {
|
this.send('note', {
|
||||||
id: note.id, myReaction: note.myReaction,
|
id: note.id, myReaction: note.myReaction,
|
||||||
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
||||||
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
||||||
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
||||||
|
...(badgeRoles?.length ? { user: { badgeRoles } } : {}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.send('note', note);
|
this.send('note', note);
|
||||||
|
@ -121,6 +126,7 @@ export class HomeTimelineChannelService implements MiChannelService<true> {
|
||||||
public readonly kind = HomeTimelineChannel.kind;
|
public readonly kind = HomeTimelineChannel.kind;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
@ -128,6 +134,7 @@ export class HomeTimelineChannelService implements MiChannelService<true> {
|
||||||
@bindThis
|
@bindThis
|
||||||
public create(id: string, connection: Channel['connection']): HomeTimelineChannel {
|
public create(id: string, connection: Channel['connection']): HomeTimelineChannel {
|
||||||
return new HomeTimelineChannel(
|
return new HomeTimelineChannel(
|
||||||
|
this.roleService,
|
||||||
this.noteEntityService,
|
this.noteEntityService,
|
||||||
id,
|
id,
|
||||||
connection,
|
connection,
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
import { MetaService } from '@/core/MetaService.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 { RoleService } from '@/core/RoleService.js';
|
||||||
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||||
import Channel, { type MiChannelService } from '../channel.js';
|
import Channel, { type MiChannelService } from '../channel.js';
|
||||||
|
|
||||||
|
@ -110,11 +110,14 @@ class HybridTimelineChannel extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
||||||
|
const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined;
|
||||||
|
|
||||||
this.send('note', {
|
this.send('note', {
|
||||||
id: note.id, myReaction: note.myReaction,
|
id: note.id, myReaction: note.myReaction,
|
||||||
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
||||||
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
||||||
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
||||||
|
...(badgeRoles?.length ? { user: { badgeRoles } } : {}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.send('note', note);
|
this.send('note', note);
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
import { MetaService } from '@/core/MetaService.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 { RoleService } from '@/core/RoleService.js';
|
||||||
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { isQuotePacked, isRenotePacked } from '@/misc/is-renote.js';
|
import { isQuotePacked, isRenotePacked } from '@/misc/is-renote.js';
|
||||||
import Channel, { type MiChannelService } from '../channel.js';
|
import Channel, { type MiChannelService } from '../channel.js';
|
||||||
|
|
||||||
|
@ -95,11 +95,14 @@ class LocalTimelineChannel extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
||||||
|
const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined;
|
||||||
|
|
||||||
this.send('note', {
|
this.send('note', {
|
||||||
id: note.id, myReaction: note.myReaction,
|
id: note.id, myReaction: note.myReaction,
|
||||||
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
||||||
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
||||||
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
||||||
|
...(badgeRoles?.length ? { user: { badgeRoles } } : {}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.send('note', note);
|
this.send('note', note);
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||||
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||||
import Channel, { type MiChannelService } from '../channel.js';
|
import Channel, { type MiChannelService } from '../channel.js';
|
||||||
|
@ -19,8 +19,8 @@ class RoleTimelineChannel extends Channel {
|
||||||
private minimize: boolean;
|
private minimize: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private roleservice: RoleService,
|
|
||||||
|
|
||||||
id: string,
|
id: string,
|
||||||
connection: Channel['connection'],
|
connection: Channel['connection'],
|
||||||
|
@ -42,7 +42,7 @@ class RoleTimelineChannel extends Channel {
|
||||||
if (data.type === 'note') {
|
if (data.type === 'note') {
|
||||||
const note = data.body;
|
const note = data.body;
|
||||||
|
|
||||||
if (!(await this.roleservice.isExplorable({ id: this.roleId }))) {
|
if (!(await this.roleService.isExplorable({ id: this.roleId }))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (note.visibility !== 'public') return;
|
if (note.visibility !== 'public') return;
|
||||||
|
@ -78,11 +78,14 @@ class RoleTimelineChannel extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
||||||
|
const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined;
|
||||||
|
|
||||||
this.send('note', {
|
this.send('note', {
|
||||||
id: note.id, myReaction: note.myReaction,
|
id: note.id, myReaction: note.myReaction,
|
||||||
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
||||||
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
||||||
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
||||||
|
...(badgeRoles?.length ? { user: { badgeRoles } } : {}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.send('note', note);
|
this.send('note', note);
|
||||||
|
@ -106,16 +109,16 @@ export class RoleTimelineChannelService implements MiChannelService<false> {
|
||||||
public readonly kind = RoleTimelineChannel.kind;
|
public readonly kind = RoleTimelineChannel.kind;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private roleservice: RoleService,
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public create(id: string, connection: Channel['connection']): RoleTimelineChannel {
|
public create(id: string, connection: Channel['connection']): RoleTimelineChannel {
|
||||||
return new RoleTimelineChannel(
|
return new RoleTimelineChannel(
|
||||||
|
this.roleService,
|
||||||
this.noteEntityService,
|
this.noteEntityService,
|
||||||
this.roleservice,
|
|
||||||
id,
|
id,
|
||||||
connection,
|
connection,
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
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 { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.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 { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
|
||||||
import Channel, { type MiChannelService } from '../channel.js';
|
import Channel, { type MiChannelService } from '../channel.js';
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ class UserListChannel extends Channel {
|
||||||
constructor(
|
constructor(
|
||||||
private userListsRepository: UserListsRepository,
|
private userListsRepository: UserListsRepository,
|
||||||
private userListMembershipsRepository: UserListMembershipsRepository,
|
private userListMembershipsRepository: UserListMembershipsRepository,
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
|
|
||||||
id: string,
|
id: string,
|
||||||
|
@ -135,11 +137,14 @@ class UserListChannel extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
if (this.minimize && ['public', 'home'].includes(note.visibility)) {
|
||||||
|
const badgeRoles = this.iAmModerator ? await this.roleService.getUserBadgeRoles(note.userId, false) : undefined;
|
||||||
|
|
||||||
this.send('note', {
|
this.send('note', {
|
||||||
id: note.id, myReaction: note.myReaction,
|
id: note.id, myReaction: note.myReaction,
|
||||||
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
poll: note.poll?.choices ? { choices: note.poll.choices } : undefined,
|
||||||
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
reply: note.reply?.myReaction ? { myReaction: note.reply.myReaction } : undefined,
|
||||||
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
renote: note.renote?.myReaction ? { myReaction: note.renote.myReaction } : undefined,
|
||||||
|
...(badgeRoles?.length ? { user: { badgeRoles } } : {}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.send('note', note);
|
this.send('note', note);
|
||||||
|
@ -169,6 +174,7 @@ export class UserListChannelService implements MiChannelService<false> {
|
||||||
@Inject(DI.userListMembershipsRepository)
|
@Inject(DI.userListMembershipsRepository)
|
||||||
private userListMembershipsRepository: UserListMembershipsRepository,
|
private userListMembershipsRepository: UserListMembershipsRepository,
|
||||||
|
|
||||||
|
private roleService: RoleService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
@ -178,6 +184,7 @@ export class UserListChannelService implements MiChannelService<false> {
|
||||||
return new UserListChannel(
|
return new UserListChannel(
|
||||||
this.userListsRepository,
|
this.userListsRepository,
|
||||||
this.userListMembershipsRepository,
|
this.userListMembershipsRepository,
|
||||||
|
this.roleService,
|
||||||
this.noteEntityService,
|
this.noteEntityService,
|
||||||
id,
|
id,
|
||||||
connection,
|
connection,
|
||||||
|
|
|
@ -24,7 +24,7 @@ import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { deepMerge } from '@/scripts/merge.js';
|
import { deepMerge } from '@/scripts/merge.js';
|
||||||
import { $i, iAmModerator } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { Paging } from '@/components/MkPagination.vue';
|
import { Paging } from '@/components/MkPagination.vue';
|
||||||
|
@ -108,7 +108,6 @@ async function prepend(data) {
|
||||||
let connection: Misskey.ChannelConnection | null = null;
|
let connection: Misskey.ChannelConnection | null = null;
|
||||||
let connection2: Misskey.ChannelConnection | null = null;
|
let connection2: Misskey.ChannelConnection | null = null;
|
||||||
let paginationQuery: Paging | null = null;
|
let paginationQuery: Paging | null = null;
|
||||||
const minimize = !iAmModerator;
|
|
||||||
|
|
||||||
const stream = useStream();
|
const stream = useStream();
|
||||||
|
|
||||||
|
@ -117,13 +116,13 @@ function connectChannel() {
|
||||||
if (props.antenna == null) return;
|
if (props.antenna == null) return;
|
||||||
connection = stream.useChannel('antenna', {
|
connection = stream.useChannel('antenna', {
|
||||||
antennaId: props.antenna,
|
antennaId: props.antenna,
|
||||||
minimize: minimize,
|
minimize: true,
|
||||||
});
|
});
|
||||||
} else if (props.src === 'home') {
|
} else if (props.src === 'home') {
|
||||||
connection = stream.useChannel('homeTimeline', {
|
connection = stream.useChannel('homeTimeline', {
|
||||||
withRenotes: props.withRenotes,
|
withRenotes: props.withRenotes,
|
||||||
withFiles: props.onlyFiles ? true : undefined,
|
withFiles: props.onlyFiles ? true : undefined,
|
||||||
minimize: minimize,
|
minimize: true,
|
||||||
});
|
});
|
||||||
connection2 = stream.useChannel('main');
|
connection2 = stream.useChannel('main');
|
||||||
} else if (props.src === 'local') {
|
} else if (props.src === 'local') {
|
||||||
|
@ -131,27 +130,27 @@ function connectChannel() {
|
||||||
withRenotes: props.withRenotes,
|
withRenotes: props.withRenotes,
|
||||||
withReplies: props.withReplies,
|
withReplies: props.withReplies,
|
||||||
withFiles: props.onlyFiles ? true : undefined,
|
withFiles: props.onlyFiles ? true : undefined,
|
||||||
minimize: minimize,
|
minimize: true,
|
||||||
});
|
});
|
||||||
} else if (props.src === 'media') {
|
} else if (props.src === 'media') {
|
||||||
connection = stream.useChannel('hybridTimeline', {
|
connection = stream.useChannel('hybridTimeline', {
|
||||||
withRenotes: props.withRenotes,
|
withRenotes: props.withRenotes,
|
||||||
withReplies: props.withReplies,
|
withReplies: props.withReplies,
|
||||||
withFiles: true,
|
withFiles: true,
|
||||||
minimize: minimize,
|
minimize: true,
|
||||||
});
|
});
|
||||||
} else if (props.src === 'social') {
|
} else if (props.src === 'social') {
|
||||||
connection = stream.useChannel('hybridTimeline', {
|
connection = stream.useChannel('hybridTimeline', {
|
||||||
withRenotes: props.withRenotes,
|
withRenotes: props.withRenotes,
|
||||||
withReplies: props.withReplies,
|
withReplies: props.withReplies,
|
||||||
withFiles: props.onlyFiles ? true : undefined,
|
withFiles: props.onlyFiles ? true : undefined,
|
||||||
minimize: minimize,
|
minimize: true,
|
||||||
});
|
});
|
||||||
} else if (props.src === 'global') {
|
} else if (props.src === 'global') {
|
||||||
connection = stream.useChannel('globalTimeline', {
|
connection = stream.useChannel('globalTimeline', {
|
||||||
withRenotes: props.withRenotes,
|
withRenotes: props.withRenotes,
|
||||||
withFiles: props.onlyFiles ? true : undefined,
|
withFiles: props.onlyFiles ? true : undefined,
|
||||||
minimize: minimize,
|
minimize: true,
|
||||||
});
|
});
|
||||||
} else if (props.src === 'mentions') {
|
} else if (props.src === 'mentions') {
|
||||||
connection = stream.useChannel('main');
|
connection = stream.useChannel('main');
|
||||||
|
@ -170,19 +169,19 @@ function connectChannel() {
|
||||||
withRenotes: props.withRenotes,
|
withRenotes: props.withRenotes,
|
||||||
withFiles: props.onlyFiles ? true : undefined,
|
withFiles: props.onlyFiles ? true : undefined,
|
||||||
listId: props.list,
|
listId: props.list,
|
||||||
minimize: minimize,
|
minimize: true,
|
||||||
});
|
});
|
||||||
} else if (props.src === 'channel') {
|
} else if (props.src === 'channel') {
|
||||||
if (props.channel == null) return;
|
if (props.channel == null) return;
|
||||||
connection = stream.useChannel('channel', {
|
connection = stream.useChannel('channel', {
|
||||||
channelId: props.channel,
|
channelId: props.channel,
|
||||||
minimize: minimize,
|
minimize: true,
|
||||||
});
|
});
|
||||||
} else if (props.src === 'role') {
|
} else if (props.src === 'role') {
|
||||||
if (props.role == null) return;
|
if (props.role == null) return;
|
||||||
connection = stream.useChannel('roleTimeline', {
|
connection = stream.useChannel('roleTimeline', {
|
||||||
roleId: props.role,
|
roleId: props.role,
|
||||||
minimize: minimize,
|
minimize: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (props.src !== 'directs' && props.src !== 'mentions') connection?.on('note', prepend);
|
if (props.src !== 'directs' && props.src !== 'mentions') connection?.on('note', prepend);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue