From a603b602e6d9f13e3c5b0495fb7c9b663d96f844 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 17 May 2024 07:39:59 -1000 Subject: [PATCH] fix(federation): :bug: Fix multiple incorrect outputs in federation routes --- bun.lockb | Bin 269660 -> 269660 bytes database/entities/Federation.ts | 3 +- packages/database-interface/user.ts | 11 +--- server/api/objects/{[uuid] => :id}/index.ts | 8 +-- server/api/users/:uuid/outbox/index.ts | 59 ++++++++++++-------- 5 files changed, 45 insertions(+), 36 deletions(-) rename server/api/objects/{[uuid] => :id}/index.ts (91%) diff --git a/bun.lockb b/bun.lockb index 9a45bbe6425991a76dd0c63be862936bd93d2f4a..fe1c6e283e7291c1dd750c08e597a944d1caa647 100755 GIT binary patch delta 237 zcmV|v z)I4$o_YGiqPH&o9Yp2&NPI9RG&n@=%p!a1tojkMg%XcdeLQ&DUowO{TK>%8|xqF9g nZUKjFZUVP$ZUfg40Wr5le*=&#my(+UAeYdM0|&SKs{>$h_#16$ delta 237 zcmVkr`n%GjWa+k zT{Pe!<;=sgK2|X8;6;uP5Vjc;sQ@Wdx{adGpQ+rp)j0uJG(hnchpZ$h@=$Ja diff --git a/database/entities/Federation.ts b/database/entities/Federation.ts index 3c9d2462..f78e3f6d 100644 --- a/database/entities/Federation.ts +++ b/database/entities/Federation.ts @@ -5,7 +5,8 @@ import { import { config } from "config-manager"; import type { User } from "~packages/database-interface/user"; -export const localObjectURI = (id: string) => `/objects/${id}`; +export const localObjectURI = (id: string) => + new URL(`/objects/${id}`, config.http.base_url).toString(); export const objectToInboxRequest = async ( object: typeof EntityValidator.$Entity, diff --git a/packages/database-interface/user.ts b/packages/database-interface/user.ts index 9533547a..b62e39fb 100644 --- a/packages/database-interface/user.ts +++ b/packages/database-interface/user.ts @@ -268,11 +268,7 @@ export class User { inbox: data.inbox, outbox: data.outbox, }, - fields: - data.fields?.map((f) => ({ - key: f.name, - value: f.value, - })) ?? [], + fields: data.fields ?? [], updatedAt: new Date(data.created_at).toISOString(), instanceId: instance.id, avatar: data.avatar @@ -537,10 +533,7 @@ export class User { avatar: urlToContentFormat(this.getAvatarUrl(config)) ?? undefined, header: urlToContentFormat(this.getHeaderUrl(config)) ?? undefined, display_name: user.displayName, - fields: user.fields.map((f) => ({ - name: f.key, - value: f.value, - })), + fields: user.fields, public_key: { actor: new URL( `/users/${user.id}`, diff --git a/server/api/objects/[uuid]/index.ts b/server/api/objects/:id/index.ts similarity index 91% rename from server/api/objects/[uuid]/index.ts rename to server/api/objects/:id/index.ts index 5ded42b1..e80e4b04 100644 --- a/server/api/objects/[uuid]/index.ts +++ b/server/api/objects/:id/index.ts @@ -24,7 +24,7 @@ export const meta = applyConfig({ export const schemas = { param: z.object({ - uuid: z.string().uuid(), + id: z.string().uuid(), }), }; @@ -34,14 +34,14 @@ export default (app: Hono) => meta.route, zValidator("param", schemas.param, handleZodError), async (context) => { - const { uuid } = context.req.valid("param"); + const { id } = context.req.valid("param"); let foundObject: Note | Like | null = null; let apiObject: typeof EntityValidator.$Entity | null = null; foundObject = await Note.fromSql( and( - eq(Notes.id, uuid), + eq(Notes.id, id), inArray(Notes.visibility, ["public", "unlisted"]), ), ); @@ -52,7 +52,7 @@ export default (app: Hono) => (await db.query.Likes.findFirst({ where: (like, { eq, and }) => and( - eq(like.id, uuid), + eq(like.id, id), sql`EXISTS (SELECT 1 FROM statuses WHERE statuses.id = ${like.likedId} AND statuses.visibility IN ('public', 'unlisted'))`, ), })) ?? null; diff --git a/server/api/users/:uuid/outbox/index.ts b/server/api/users/:uuid/outbox/index.ts index de7656de..2ec74794 100644 --- a/server/api/users/:uuid/outbox/index.ts +++ b/server/api/users/:uuid/outbox/index.ts @@ -1,6 +1,6 @@ import { applyConfig, handleZodError } from "@api"; import { zValidator } from "@hono/zod-validator"; -import { jsonResponse } from "@response"; +import { errorResponse, jsonResponse } from "@response"; import { and, count, eq, inArray } from "drizzle-orm"; import type { Hono } from "hono"; import { z } from "zod"; @@ -8,6 +8,7 @@ import { db } from "~drizzle/db"; import { Notes } from "~drizzle/schema"; import { config } from "~packages/config-manager"; import { Note } from "~packages/database-interface/note"; +import { User } from "~packages/database-interface/user"; export const meta = applyConfig({ allowedMethods: ["GET"], @@ -30,6 +31,8 @@ export const schemas = { }), }; +const NOTES_PER_PAGE = 20; + export default (app: Hono) => app.on( meta.allowedMethods, @@ -39,8 +42,13 @@ export default (app: Hono) => async (context) => { const { uuid } = context.req.valid("param"); + const author = await User.fromId(uuid); + + if (!author) { + return errorResponse("User not found", 404); + } + const pageNumber = Number(context.req.valid("query").page) || 1; - const host = new URL(config.http.base_url).hostname; const notes = await Note.manyFromSql( and( @@ -48,33 +56,40 @@ export default (app: Hono) => inArray(Notes.visibility, ["public", "unlisted"]), ), undefined, - 20, - 20 * (pageNumber - 1), + NOTES_PER_PAGE, + NOTES_PER_PAGE * (pageNumber - 1), ); - const totalNotes = await db - .select({ - count: count(), - }) - .from(Notes) - .where( - and( - eq(Notes.authorId, uuid), - inArray(Notes.visibility, ["public", "unlisted"]), - ), - ); + const totalNotes = ( + await db + .select({ + count: count(), + }) + .from(Notes) + .where( + and( + eq(Notes.authorId, uuid), + inArray(Notes.visibility, ["public", "unlisted"]), + ), + ) + )[0].count; return jsonResponse({ - first: `${host}/users/${uuid}/outbox?page=1`, - last: `${host}/users/${uuid}/outbox?page=1`, - total_items: totalNotes, - // Server actor - author: new URL( - "/users/actor", + first: new URL( + `/users/${uuid}/outbox?page=1`, config.http.base_url, ).toString(), + last: new URL( + `/users/${uuid}/outbox?page=${Math.ceil( + totalNotes / NOTES_PER_PAGE, + )}`, + config.http.base_url, + ).toString(), + total_items: totalNotes, + // Server actor + author: author.getUri(), next: - notes.length === 20 + notes.length === NOTES_PER_PAGE ? new URL( `/users/${uuid}/outbox?page=${pageNumber + 1}`, config.http.base_url,