From f825dcc81198d20f904dc6d3c323f0c4f9f4a2c1 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Mon, 18 Sep 2023 23:12:04 +0200 Subject: [PATCH] [mastodon-client] Respect minId query param --- .../src/server/api/mastodon/helpers/note.ts | 43 +++++++++++++++++-- .../server/api/mastodon/helpers/timeline.ts | 16 +++---- .../src/server/api/mastodon/helpers/user.ts | 8 ++-- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/helpers/note.ts b/packages/backend/src/server/api/mastodon/helpers/note.ts index a8524d976..ff5560e89 100644 --- a/packages/backend/src/server/api/mastodon/helpers/note.ts +++ b/packages/backend/src/server/api/mastodon/helpers/note.ts @@ -7,7 +7,7 @@ import { Note } from "@/models/entities/note.js"; import { ILocalUser } from "@/models/entities/user.js"; import querystring from "node:querystring"; import { getNote } from "@/server/api/common/getters.js"; -import { SelectQueryBuilder } from "typeorm"; +import { ObjectLiteral, SelectQueryBuilder } from "typeorm"; export class NoteHelpers { public static async getNoteDescendants(note: Note | string, user: ILocalUser | null, limit: number = 10, depth: number = 2): Promise { @@ -46,7 +46,44 @@ export class NoteHelpers { return notes; } - public static async execQuery(query: SelectQueryBuilder, limit: number): Promise { + public static makePaginationQuery( + q: SelectQueryBuilder, + sinceId?: string, + maxId?: string, + minId?: string + ) { + if (sinceId && minId) throw new Error("Can't user both sinceId and minId params"); + + if (sinceId && maxId) { + q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: sinceId }); + q.andWhere(`${q.alias}.id < :maxId`, { maxId: maxId }); + q.orderBy(`${q.alias}.id`, "DESC"); + } if (minId && maxId) { + q.andWhere(`${q.alias}.id > :minId`, { minId: minId }); + q.andWhere(`${q.alias}.id < :maxId`, { maxId: maxId }); + q.orderBy(`${q.alias}.id`, "ASC"); + } else if (sinceId) { + q.andWhere(`${q.alias}.id > :sinceId`, { sinceId: sinceId }); + q.orderBy(`${q.alias}.id`, "DESC"); + } else if (minId) { + q.andWhere(`${q.alias}.id > :minId`, { minId: minId }); + q.orderBy(`${q.alias}.id`, "ASC"); + } else if (maxId) { + q.andWhere(`${q.alias}.id < :maxId`, { maxId: maxId }); + q.orderBy(`${q.alias}.id`, "DESC"); + } else { + q.orderBy(`${q.alias}.id`, "DESC"); + } + return q; + } + + /** + * + * @param query + * @param limit + * @param reverse whether the result needs to be .reverse()'d. Set this to true when the parameter minId is not undefined in the original request. + */ + public static async execQuery(query: SelectQueryBuilder, limit: number, reverse: boolean): Promise { // We fetch more than requested because some may be filtered out, and if there's less than // requested, the pagination stops. const found = []; @@ -67,6 +104,6 @@ export class NoteHelpers { found.length = limit; } - return found; + return reverse ? found.reverse() : found; } } diff --git a/packages/backend/src/server/api/mastodon/helpers/timeline.ts b/packages/backend/src/server/api/mastodon/helpers/timeline.ts index 538eec4aa..9291df6e9 100644 --- a/packages/backend/src/server/api/mastodon/helpers/timeline.ts +++ b/packages/backend/src/server/api/mastodon/helpers/timeline.ts @@ -31,11 +31,11 @@ export class TimelineHelpers { .select("following.followeeId") .where("following.followerId = :followerId", {followerId: user.id}); - //FIXME respect minId - const query = makePaginationQuery( + const query = NoteHelpers.makePaginationQuery( Notes.createQueryBuilder("note"), - sinceId ?? minId, + sinceId, maxId, + minId ) .andWhere( new Brackets((qb) => { @@ -67,7 +67,7 @@ export class TimelineHelpers { query.andWhere("note.visibility != 'hidden'"); - return NoteHelpers.execQuery(query, limit); + return NoteHelpers.execQuery(query, limit, minId !== undefined); } public static async getPublicTimeline(user: ILocalUser, maxId: string | undefined, sinceId: string | undefined, minId: string | undefined, limit: number = 20, onlyMedia: boolean = false, local: boolean = false, remote: boolean = false): Promise { @@ -84,11 +84,11 @@ export class TimelineHelpers { throw new Error("local and remote are mutually exclusive options"); } - //FIXME respect minId - const query = makePaginationQuery( + const query = NoteHelpers.makePaginationQuery( Notes.createQueryBuilder("note"), - sinceId ?? minId, + sinceId, maxId, + minId ) .andWhere("note.visibility = 'public'"); @@ -121,6 +121,6 @@ export class TimelineHelpers { query.andWhere("note.visibility != 'hidden'"); - return NoteHelpers.execQuery(query, limit); + return NoteHelpers.execQuery(query, limit, minId !== undefined); } } diff --git a/packages/backend/src/server/api/mastodon/helpers/user.ts b/packages/backend/src/server/api/mastodon/helpers/user.ts index ee2e41b83..59beee885 100644 --- a/packages/backend/src/server/api/mastodon/helpers/user.ts +++ b/packages/backend/src/server/api/mastodon/helpers/user.ts @@ -31,11 +31,11 @@ export class UserHelpers { return []; } - //FIXME respect minId - const query = makePaginationQuery( + const query = NoteHelpers.makePaginationQuery( Notes.createQueryBuilder("note"), - sinceId ?? minId, + sinceId, maxId, + minId ) .andWhere("note.userId = :userId", { userId: user.id }); @@ -66,7 +66,7 @@ export class UserHelpers { query.andWhere("note.visibility != 'hidden'"); - return NoteHelpers.execQuery(query, limit); + return NoteHelpers.execQuery(query, limit, minId !== undefined); } public static async getUserCached(id: string, cache: AccountCache = UserHelpers.getFreshAccountCache()): Promise {