summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints/notes/timeline.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server/api/endpoints/notes/timeline.ts')
-rw-r--r--packages/backend/src/server/api/endpoints/notes/timeline.ts52
1 files changed, 32 insertions, 20 deletions
diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts
index eeeb797efc..fe9c412be4 100644
--- a/packages/backend/src/server/api/endpoints/notes/timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts
@@ -5,7 +5,7 @@
import { Brackets } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common';
-import type { NotesRepository, ChannelFollowingsRepository, MiMeta } from '@/models/_.js';
+import type { NotesRepository, MiMeta } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueryService } from '@/core/QueryService.js';
import ActiveUsersChart from '@/core/chart/charts/active-users.js';
@@ -16,6 +16,8 @@ import { CacheService } from '@/core/CacheService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { MiLocalUser } from '@/models/User.js';
import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js';
+import { ChannelMutingService } from '@/core/ChannelMutingService.js';
+import { ChannelFollowingService } from '@/core/ChannelFollowingService.js';
export const meta = {
tags: ['notes'],
@@ -61,15 +63,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
- @Inject(DI.channelFollowingsRepository)
- private channelFollowingsRepository: ChannelFollowingsRepository,
-
private noteEntityService: NoteEntityService,
private activeUsersChart: ActiveUsersChart,
private idService: IdService,
private cacheService: CacheService,
private fanoutTimelineEndpointService: FanoutTimelineEndpointService,
private userFollowingService: UserFollowingService,
+ private channelMutingService: ChannelMutingService,
+ private channelFollowingService: ChannelFollowingService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
@@ -140,11 +141,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private async getFromDb(ps: { untilId: string | null; sinceId: string | null; limit: number; includeMyRenotes: boolean; includeRenotedMyNotes: boolean; includeLocalRenotes: boolean; withFiles: boolean; withRenotes: boolean; }, me: MiLocalUser) {
const followees = await this.userFollowingService.getFollowees(me.id);
- const followingChannels = await this.channelFollowingsRepository.find({
- where: {
- followerId: me.id,
- },
- });
+
+ const mutingChannelIds = await this.channelMutingService
+ .list({ requestUserId: me.id }, { idOnly: true })
+ .then(x => x.map(x => x.id));
+ const followingChannelIds = await this.channelFollowingService
+ .list({ requestUserId: me.id }, { idOnly: true })
+ .then(x => x.map(x => x.id).filter(x => !mutingChannelIds.includes(x)));
//#region Construct query
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
@@ -154,15 +157,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.leftJoinAndSelect('reply.user', 'replyUser')
.leftJoinAndSelect('renote.user', 'renoteUser');
- if (followees.length > 0 && followingChannels.length > 0) {
+ if (followees.length > 0 && followingChannelIds.length > 0) {
// ユーザー・チャンネルともにフォローあり
const meOrFolloweeIds = [me.id, ...followees.map(f => f.followeeId)];
- const followingChannelIds = followingChannels.map(x => x.followeeId);
query.andWhere(new Brackets(qb => {
qb
.where(new Brackets(qb2 => {
qb2
- .where('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds })
+ .andWhere('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds })
.andWhere('note.channelId IS NULL');
}))
.orWhere('note.channelId IN (:...followingChannelIds)', { followingChannelIds });
@@ -170,22 +172,32 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} else if (followees.length > 0) {
// ユーザーフォローのみ(チャンネルフォローなし)
const meOrFolloweeIds = [me.id, ...followees.map(f => f.followeeId)];
- query
- .andWhere('note.channelId IS NULL')
- .andWhere('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds });
- } else if (followingChannels.length > 0) {
+ query.andWhere(new Brackets(qb => {
+ qb
+ .andWhere('note.channelId IS NULL')
+ .andWhere('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds });
+ if (mutingChannelIds.length > 0) {
+ qb.andWhere('note.renoteChannelId NOT IN (:...mutingChannelIds)', { mutingChannelIds });
+ }
+ }));
+ } else if (followingChannelIds.length > 0) {
// チャンネルフォローのみ(ユーザーフォローなし)
- const followingChannelIds = followingChannels.map(x => x.followeeId);
query.andWhere(new Brackets(qb => {
qb
+ // renoteChannelIdは見る必要が無い
+ // ・HTLに流れてくるチャンネル=フォローしているチャンネル
+ // ・HTLにフォロー外のチャンネルが流れるのは、フォローしているユーザがそのチャンネル投稿をリノートした場合のみ
+ // つまり、ユーザフォローしてない前提のこのブロックでは見る必要が無い
.where('note.channelId IN (:...followingChannelIds)', { followingChannelIds })
.orWhere('note.userId = :meId', { meId: me.id });
}));
} else {
// フォローなし
- query
- .andWhere('note.channelId IS NULL')
- .andWhere('note.userId = :meId', { meId: me.id });
+ query.andWhere(new Brackets(qb => {
+ qb
+ .andWhere('note.channelId IS NULL')
+ .andWhere('note.userId = :meId', { meId: me.id });
+ }));
}
query.andWhere(new Brackets(qb => {