import { apiRoute, auth, reusedResponses } from "@/api"; import { createRoute, z } from "@hono/zod-openapi"; import { Timeline } from "@versia/kit/db"; import { RolePermissions, Users } from "@versia/kit/tables"; import { and, gt, gte, lt, sql } from "drizzle-orm"; import { Account as AccountSchema } from "~/classes/schemas/account"; const route = createRoute({ method: "get", path: "/api/v1/blocks", summary: "View your blocks.", description: "View blocked users.", externalDocs: { url: "https://docs.joinmastodon.org/methods/blocks/#get", }, tags: ["Blocks"], middleware: [ auth({ auth: true, scopes: ["read:blocks"], permissions: [RolePermissions.ManageOwnBlocks], }), ] as const, request: { query: z.object({ max_id: AccountSchema.shape.id.optional().openapi({ description: "All results returned will be lesser than this ID. In effect, sets an upper bound on results.", example: "8d35243d-b959-43e2-8bac-1a9d4eaea2aa", }), since_id: AccountSchema.shape.id.optional().openapi({ description: "All results returned will be greater than this ID. In effect, sets a lower bound on results.", example: undefined, }), min_id: AccountSchema.shape.id.optional().openapi({ description: "Returns results immediately newer than this ID. In effect, sets a cursor at this ID and paginates forward.", example: undefined, }), limit: z.coerce.number().int().min(1).max(80).default(40).openapi({ description: "Maximum number of results to return.", }), }), }, responses: { 200: { description: "List of blocked users", content: { "application/json": { schema: z.array(AccountSchema), }, }, headers: z.object({ link: z .string() .optional() .openapi({ description: "Links to the next and previous pages", example: `; rel="next", ; rel="prev"`, externalDocs: { url: "https://docs.joinmastodon.org/api/guidelines/#pagination", }, }), }), }, ...reusedResponses, }, }); export default apiRoute((app) => app.openapi(route, async (context) => { const { max_id, since_id, min_id, limit } = context.req.valid("query"); const { user } = context.get("auth"); const { objects: blocks, link } = await Timeline.getUserTimeline( and( max_id ? lt(Users.id, max_id) : undefined, since_id ? gte(Users.id, since_id) : undefined, min_id ? gt(Users.id, min_id) : undefined, sql`EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."subjectId" = ${Users.id} AND "Relationships"."ownerId" = ${user.id} AND "Relationships"."blocking" = true)`, ), limit, new URL(context.req.url), ); return context.json( blocks.map((u) => u.toApi()), 200, { Link: link, }, ); }), );