From b27d4219f90c2cb5328e8508737625bc87131220 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sun, 26 Nov 2023 15:01:07 -1000 Subject: [PATCH] Add favourites endpoint --- README.md | 2 +- server/api/api/v1/favourites/index.ts | 80 +++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 server/api/api/v1/favourites/index.ts diff --git a/README.md b/README.md index 898884f8..ea144cab 100644 --- a/README.md +++ b/README.md @@ -162,12 +162,12 @@ Working endpoints are: Tests needed but completed: - `/api/v1/media/:id` +- `/api/v1/favourites` Endpoints left: - `/api/v1/reports` - `/api/v1/accounts/:id/lists` -- `/api/v1/favourites` - `/api/v1/accounts/:id/following` - `/api/v1/follow_requests` - `/api/v1/follow_requests/:account_id/authorize` diff --git a/server/api/api/v1/favourites/index.ts b/server/api/api/v1/favourites/index.ts new file mode 100644 index 00000000..55e0a672 --- /dev/null +++ b/server/api/api/v1/favourites/index.ts @@ -0,0 +1,80 @@ +import { errorResponse, jsonResponse } from "@response"; +import { getFromRequest } from "~database/entities/User"; +import { applyConfig } from "@api"; +import { client } from "~database/datasource"; +import { parseRequest } from "@request"; +import { statusAndUserRelations, statusToAPI } from "~database/entities/Status"; + +export const meta = applyConfig({ + allowedMethods: ["GET"], + route: "/api/v1/favourites", + ratelimits: { + max: 100, + duration: 60, + }, + auth: { + required: true, + }, +}); + +export default async (req: Request): Promise => { + const { user } = await getFromRequest(req); + + const { + limit = 20, + max_id, + min_id, + since_id, + } = await parseRequest<{ + max_id?: string; + since_id?: string; + min_id?: string; + limit?: number; + }>(req); + + if (limit < 1 || limit > 40) { + return errorResponse("Limit must be between 1 and 40", 400); + } + + if (!user) return errorResponse("Unauthorized", 401); + + const objects = await client.status.findMany({ + where: { + id: { + lt: max_id ?? undefined, + gte: since_id ?? undefined, + gt: min_id ?? undefined, + }, + likes: { + some: { + likerId: user.id, + }, + }, + }, + include: statusAndUserRelations, + take: limit, + orderBy: { + id: "desc", + }, + }); + + // Constuct HTTP Link header (next and prev) + const linkHeader = []; + if (objects.length > 0) { + const urlWithoutQuery = req.url.split("?")[0]; + linkHeader.push( + `<${urlWithoutQuery}?max_id=${objects.at(-1)?.id}>; rel="next"`, + `<${urlWithoutQuery}?min_id=${objects[0].id}>; rel="prev"` + ); + } + + return jsonResponse( + await Promise.all( + objects.map(async status => statusToAPI(status, user)) + ), + 200, + { + Link: linkHeader.join(", "), + } + ); +};