From 0fe8c0134c32b060e318da14d4ad4d1510b69d29 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 7 Oct 2023 14:02:05 +0900 Subject: [PATCH 1/8] =?UTF-8?q?enhance(backend):=20notes/global-timeline?= =?UTF-8?q?=E5=BE=A9=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 - .../api/endpoints/notes/global-timeline.ts | 33 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1f8f7b8d4..7f2b8ac44d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,6 @@ ### Changes - API: users/notes, notes/local-timeline で fileType 指定はできなくなりました -- API: notes/global-timeline は現在常に `[]` を返します - API: notes/featured でページネーションは他APIと同様 untilId を使って行うようになりました ### General diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index e5a86905d6..be7557c213 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -67,8 +67,37 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.gtlDisabled); } - // TODO? - return []; + //#region Construct query + const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), + ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) + .andWhere('note.visibility = \'public\'') + .andWhere('note.channelId IS NULL') + .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); + + if (me) { + this.queryService.generateMutedUserQuery(query, me); + this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserRenotesQueryForNotes(query, me); + } + + if (ps.withFiles) { + query.andWhere('note.fileIds != \'{}\''); + } + //#endregion + + const timeline = await query.limit(ps.limit).getMany(); + + process.nextTick(() => { + if (me) { + this.activeUsersChart.read(me); + } + }); + + return await this.noteEntityService.packMany(timeline, me); }); } } From dc435fb8eefdbfc1260f5fd0b8aea51ddaca2b59 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 7 Oct 2023 14:05:58 +0900 Subject: [PATCH 2/8] enhance(backend): tweak hashtag trend --- packages/backend/src/core/HashtagService.ts | 7 +++++-- .../backend/src/server/api/endpoints/hashtags/trend.ts | 6 ------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/core/HashtagService.ts b/packages/backend/src/core/HashtagService.ts index 4900fa90a1..1a06767da8 100644 --- a/packages/backend/src/core/HashtagService.ts +++ b/packages/backend/src/core/HashtagService.ts @@ -5,7 +5,6 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; -import { getLineAndCharacterOfPosition } from 'typescript'; import { DI } from '@/di-symbols.js'; import type { MiUser } from '@/models/User.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js'; @@ -15,6 +14,7 @@ import type { HashtagsRepository } from '@/models/_.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import { FeaturedService } from '@/core/FeaturedService.js'; +import { MetaService } from '@/core/MetaService.js'; @Injectable() export class HashtagService { @@ -28,6 +28,7 @@ export class HashtagService { private userEntityService: UserEntityService, private featuredService: FeaturedService, private idService: IdService, + private metaService: MetaService, ) { } @@ -157,7 +158,9 @@ export class HashtagService { @bindThis public async updateHashtagsRanking(hashtag: string, userId: MiUser['id']): Promise { - // TODO: instance.hiddenTagsの考慮 + const instance = await this.metaService.fetch(); + const hiddenTags = instance.hiddenTags.map(t => normalizeForSearch(t)); + if (hiddenTags.includes(hashtag)) return; // YYYYMMDDHHmm (10分間隔) const now = new Date(); diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts index a69e007a40..8f382eb96b 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts @@ -5,8 +5,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; -import { MetaService } from '@/core/MetaService.js'; import { DI } from '@/di-symbols.js'; import { FeaturedService } from '@/core/FeaturedService.js'; import { HashtagService } from '@/core/HashtagService.js'; @@ -55,14 +53,10 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - private metaService: MetaService, private featuredService: FeaturedService, private hashtagService: HashtagService, ) { super(meta, paramDef, async () => { - const instance = await this.metaService.fetch(true); - const hiddenTags = instance.hiddenTags.map(t => normalizeForSearch(t)); - const ranking = await this.featuredService.getHashtagsRanking(10); const charts = ranking.length === 0 ? {} : await this.hashtagService.getCharts(ranking, 20); From aae1034d621501a7121a73db660fcd7c6998d9ff Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 7 Oct 2023 14:10:45 +0900 Subject: [PATCH 3/8] 2023.10.0-beta.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a52c773dd8..df51a05f88 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2023.10.0-beta.5", + "version": "2023.10.0-beta.6", "codename": "nasubi", "repository": { "type": "git", From fb3338029bdb72543345c9a69cbe5318b5676233 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 7 Oct 2023 17:48:10 +0900 Subject: [PATCH 4/8] refactor --- .../server/api/endpoints/antennas/notes.ts | 12 +++---- .../api/endpoints/notes/hybrid-timeline.ts | 32 ++++++++----------- .../api/endpoints/notes/local-timeline.ts | 16 ++++------ .../server/api/endpoints/notes/timeline.ts | 16 ++++------ .../api/endpoints/notes/user-list-timeline.ts | 16 ++++------ .../src/server/api/endpoints/roles/notes.ts | 12 +++---- 6 files changed, 40 insertions(+), 64 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 63e542cb62..b563f704a8 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -86,17 +86,13 @@ export default class extends Endpoint { // eslint- }); const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1 - const noteIdsRes = await this.redisForTimelines.xrevrange( + + const noteIds = await this.redisForTimelines.xrevrange( `antennaTimeline:${antenna.id}`, ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit); - - if (noteIdsRes.length === 0) { - return []; - } - - const noteIds = noteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId); + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)); if (noteIds.length === 0) { return []; diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 8e7f2a2a98..33ffd42a76 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -92,26 +92,22 @@ export default class extends Endpoint { // eslint- let timeline: MiNote[] = []; const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1 - let htlNoteIdsRes: [string, string[]][] = []; - let ltlNoteIdsRes: [string, string[]][] = []; - if (!ps.sinceId && !ps.sinceDate) { - [htlNoteIdsRes, ltlNoteIdsRes] = await Promise.all([ - this.redisForTimelines.xrevrange( - ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, - ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', - ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit), - this.redisForTimelines.xrevrange( - ps.withFiles ? 'localTimelineWithFiles' : 'localTimeline', - ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', - ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit), - ]); - } + const [htlNoteIds, ltlNoteIds] = await Promise.all([ + this.redisForTimelines.xrevrange( + ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, + ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', + ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)), + this.redisForTimelines.xrevrange( + ps.withFiles ? 'localTimelineWithFiles' : 'localTimeline', + ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', + ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)), + ]); - const htlNoteIds = htlNoteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId); - const ltlNoteIds = ltlNoteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId); let noteIds = Array.from(new Set([...htlNoteIds, ...ltlNoteIds])); noteIds.sort((a, b) => a > b ? -1 : 1); noteIds = noteIds.slice(0, ps.limit); diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index ac8f8d610e..b9305e8e26 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -88,17 +88,13 @@ export default class extends Endpoint { // eslint- let timeline: MiNote[] = []; const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1 - let noteIdsRes: [string, string[]][] = []; - if (!ps.sinceId && !ps.sinceDate) { - noteIdsRes = await this.redisForTimelines.xrevrange( - ps.withFiles ? 'localTimelineWithFiles' : 'localTimeline', - ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', - ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit); - } - - const noteIds = noteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId); + const noteIds = await this.redisForTimelines.xrevrange( + ps.withFiles ? 'localTimelineWithFiles' : 'localTimeline', + ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', + ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)); if (noteIds.length === 0) { return []; diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index 7442356978..cd2ec8fe29 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -79,17 +79,13 @@ export default class extends Endpoint { // eslint- let timeline: MiNote[] = []; const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1 - let noteIdsRes: [string, string[]][] = []; - if (!ps.sinceId && !ps.sinceDate) { - noteIdsRes = await this.redisForTimelines.xrevrange( - ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, - ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', - ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit); - } - - const noteIds = noteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId); + const noteIds = await this.redisForTimelines.xrevrange( + ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, + ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', + ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)); if (noteIds.length === 0) { return []; diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index d11e9751b3..2eec6297c0 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -103,17 +103,13 @@ export default class extends Endpoint { // eslint- let timeline: MiNote[] = []; const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1 - let noteIdsRes: [string, string[]][] = []; - if (!ps.sinceId && !ps.sinceDate) { - noteIdsRes = await this.redisForTimelines.xrevrange( - ps.withFiles ? `userListTimelineWithFiles:${list.id}` : `userListTimeline:${list.id}`, - ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', - ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit); - } - - const noteIds = noteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId); + const noteIds = await this.redisForTimelines.xrevrange( + ps.withFiles ? `userListTimelineWithFiles:${list.id}` : `userListTimeline:${list.id}`, + ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', + ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)); if (noteIds.length === 0) { return []; diff --git a/packages/backend/src/server/api/endpoints/roles/notes.ts b/packages/backend/src/server/api/endpoints/roles/notes.ts index f2533efa36..3f2b31c02f 100644 --- a/packages/backend/src/server/api/endpoints/roles/notes.ts +++ b/packages/backend/src/server/api/endpoints/roles/notes.ts @@ -79,17 +79,13 @@ export default class extends Endpoint { // eslint- return []; } const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1 - const noteIdsRes = await this.redisForTimelines.xrevrange( + + const noteIds = await this.redisForTimelines.xrevrange( `roleTimeline:${role.id}`, ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit); - - if (noteIdsRes.length === 0) { - return []; - } - - const noteIds = noteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId); + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)); if (noteIds.length === 0) { return []; From 69de8cad7cc0664db10f8459ebb752b75f669a81 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 7 Oct 2023 17:57:15 +0900 Subject: [PATCH 5/8] refactor --- .../src/server/api/endpoints/users/notes.ts | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 23c2811fb9..4c0f0cc588 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -81,38 +81,36 @@ export default class extends Endpoint { // eslint- let timeline: MiNote[] = []; const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1 - let noteIdsRes: [string, string[]][] = []; - let repliesNoteIdsRes: [string, string[]][] = []; - let channelNoteIdsRes: [string, string[]][] = []; - if (!ps.sinceId && !ps.sinceDate) { - [noteIdsRes, repliesNoteIdsRes, channelNoteIdsRes] = await Promise.all([ - this.redisForTimelines.xrevrange( - ps.withFiles ? `userTimelineWithFiles:${ps.userId}` : `userTimeline:${ps.userId}`, + const [noteIdsRes, repliesNoteIdsRes, channelNoteIdsRes] = await Promise.all([ + this.redisForTimelines.xrevrange( + ps.withFiles ? `userTimelineWithFiles:${ps.userId}` : `userTimeline:${ps.userId}`, + ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', + ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)), + ps.withReplies + ? this.redisForTimelines.xrevrange( + `userTimelineWithReplies:${ps.userId}`, ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit), - ps.withReplies - ? this.redisForTimelines.xrevrange( - `userTimelineWithReplies:${ps.userId}`, - ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', - ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit) - : Promise.resolve([]), - ps.withChannelNotes - ? this.redisForTimelines.xrevrange( - `userTimelineWithChannel:${ps.userId}`, - ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', - ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', - 'COUNT', limit) - : Promise.resolve([]), - ]); - } + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)) + : Promise.resolve([]), + ps.withChannelNotes + ? this.redisForTimelines.xrevrange( + `userTimelineWithChannel:${ps.userId}`, + ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : ps.untilDate ?? '+', + ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : ps.sinceDate ?? '-', + 'COUNT', limit, + ).then(res => res.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId)) + : Promise.resolve([]), + ]); let noteIds = Array.from(new Set([ - ...noteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId), - ...repliesNoteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId), - ...channelNoteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId && x !== ps.sinceId), + ...noteIdsRes, + ...repliesNoteIdsRes, + ...channelNoteIdsRes, ])); noteIds.sort((a, b) => a > b ? -1 : 1); noteIds = noteIds.slice(0, ps.limit); From 8c684d539181f030d03db1a6e0f408ae5d8a93ce Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 7 Oct 2023 18:00:56 +0900 Subject: [PATCH 6/8] =?UTF-8?q?enhance(backend):=20User=20TL=E3=82=92Redis?= =?UTF-8?q?=E3=81=AB=E3=82=AD=E3=83=A3=E3=83=83=E3=82=B7=E3=83=A5=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=82=8B=E4=BB=A5=E5=89=8D=E3=81=BE=E3=81=A7=E9=81=A1?= =?UTF-8?q?=E3=82=8C=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #11958 --- .../src/server/api/endpoints/users/notes.ts | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 4c0f0cc588..becc6debbb 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -10,10 +10,10 @@ import type { MiNote, NotesRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { DI } from '@/di-symbols.js'; -import { GetterService } from '@/server/api/GetterService.js'; import { CacheService } from '@/core/CacheService.js'; import { IdService } from '@/core/IdService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; +import { QueryService } from '@/core/QueryService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -67,7 +67,7 @@ export default class extends Endpoint { // eslint- private notesRepository: NotesRepository, private noteEntityService: NoteEntityService, - private getterService: GetterService, + private queryService: QueryService, private cacheService: CacheService, private idService: IdService, ) { @@ -148,6 +148,43 @@ export default class extends Endpoint { // eslint- timeline.sort((a, b) => a.id > b.id ? -1 : 1); + // fallback to database + if (timeline.length === 0) { + //#region Construct query + const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) + .andWhere('note.userId = :userId', { userId: ps.userId }) + .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('note.reply', 'reply') + .leftJoinAndSelect('note.renote', 'renote') + .leftJoinAndSelect('note.channel', 'channel') + .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('renote.user', 'renoteUser'); + + query.andWhere(new Brackets(qb => { + qb.orWhere('note.channelId IS NULL'); + qb.orWhere('channel.isSensitive = false'); + })); + + this.queryService.generateVisibilityQuery(query, me); + + if (ps.withFiles) { + query.andWhere('note.fileIds != \'{}\''); + } + + if (ps.includeMyRenotes === false) { + query.andWhere(new Brackets(qb => { + qb.orWhere('note.userId != :userId', { userId: ps.userId }); + qb.orWhere('note.renoteId IS NULL'); + qb.orWhere('note.text IS NOT NULL'); + qb.orWhere('note.fileIds != \'{}\''); + qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); + })); + } + //#endregion + + timeline = await query.limit(ps.limit).getMany(); + } + return await this.noteEntityService.packMany(timeline, me); }); } From 986623dbdca61473fb4e60ff746c6c77e3a9d442 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 7 Oct 2023 18:21:16 +0900 Subject: [PATCH 7/8] fix(backend): fix sql error when featured notes is zero --- .../src/server/api/endpoints/users/featured-notes.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/users/featured-notes.ts b/packages/backend/src/server/api/endpoints/users/featured-notes.ts index fdf36a6ae0..dec0b7a122 100644 --- a/packages/backend/src/server/api/endpoints/users/featured-notes.ts +++ b/packages/backend/src/server/api/endpoints/users/featured-notes.ts @@ -50,16 +50,16 @@ export default class extends Endpoint { // eslint- super(meta, paramDef, async (ps, me) => { let noteIds = await this.featuredService.getPerUserNotesRanking(ps.userId, 50); - if (noteIds.length === 0) { - return []; - } - noteIds.sort((a, b) => a > b ? -1 : 1); if (ps.untilId) { noteIds = noteIds.filter(id => id < ps.untilId!); } noteIds = noteIds.slice(0, ps.limit); + if (noteIds.length === 0) { + return []; + } + const query = this.notesRepository.createQueryBuilder('note') .where('note.id IN (:...noteIds)', { noteIds: noteIds }) .innerJoinAndSelect('note.user', 'user') From 6d5e18aa8dbfc5fbf15b12d0f711921df03e9372 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 7 Oct 2023 18:21:30 +0900 Subject: [PATCH 8/8] 2023.10.0-beta.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index df51a05f88..d298fbed90 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2023.10.0-beta.6", + "version": "2023.10.0-beta.7", "codename": "nasubi", "repository": { "type": "git",