From 9f974de245e5d4da81d6849016df3354e965060c Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 2 Mar 2025 19:08:05 +0100 Subject: [PATCH] Add /collections/:id/series & /collections/:id/movies --- api/src/controllers/shows/collections.ts | 166 +++++++++++++++++- .../controllers/shows/{shows.ts => logic.ts} | 0 api/src/controllers/shows/movies.ts | 2 +- api/src/controllers/shows/series.ts | 2 +- 4 files changed, 167 insertions(+), 3 deletions(-) rename api/src/controllers/shows/{shows.ts => logic.ts} (100%) diff --git a/api/src/controllers/shows/collections.ts b/api/src/controllers/shows/collections.ts index 2123dd7b..f378158b 100644 --- a/api/src/controllers/shows/collections.ts +++ b/api/src/controllers/shows/collections.ts @@ -9,15 +9,17 @@ import { } from "~/models/collections"; import { KError } from "~/models/error"; import { duneCollection } from "~/models/examples"; +import { Movie } from "~/models/movie"; import { AcceptLanguage, Filter, Page, createPage, + isUuid, processLanguages, } from "~/models/utils"; import { desc } from "~/models/utils/descriptions"; -import { getShow, getShows, showFilters, showSort } from "./shows"; +import { getShow, getShows, showFilters, showSort } from "./logic"; export const collections = new Elysia({ prefix: "/collections", @@ -168,4 +170,166 @@ export const collections = new Elysia({ 422: KError, }, }, + ) + .get( + "/:id/movies", + async ({ + params: { id }, + query: { limit, after, query, sort, filter, preferOriginal }, + headers: { "accept-language": languages }, + request: { url }, + error, + }) => { + const [collection] = await db + .select({ pk: shows.pk }) + .from(shows) + .where( + and( + eq(shows.kind, "collection"), + isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id), + ), + ) + .limit(1); + + if (!collection) { + return error(404, { + status: 404, + message: `No collection with the id or slug: '${id}'.`, + }); + } + + const langs = processLanguages(languages); + const items = await getShows({ + limit, + after, + query, + sort, + filter: and( + eq(shows.collectionPk, collection.pk), + eq(shows.kind, "movie"), + filter, + ), + languages: langs, + preferOriginal, + }); + return createPage(items, { url, sort, limit }); + }, + { + detail: { description: "Get all movies in a collection" }, + params: t.Object({ + id: t.String({ + description: "The id or slug of the collection.", + example: duneCollection.slug, + }), + }), + query: t.Object({ + sort: showSort, + filter: t.Optional(Filter({ def: showFilters })), + query: t.Optional(t.String({ description: desc.query })), + limit: t.Integer({ + minimum: 1, + maximum: 250, + default: 50, + description: "Max page size.", + }), + after: t.Optional(t.String({ description: desc.after })), + preferOriginal: t.Optional( + t.Boolean({ + description: desc.preferOriginal, + }), + ), + }), + headers: t.Object({ + "accept-language": AcceptLanguage({ autoFallback: true }), + }), + response: { + 200: Page(Movie), + 404: { + ...KError, + description: "No collection found with the given id or slug.", + }, + 422: KError, + }, + }, + ) + .get( + "/:id/series", + async ({ + params: { id }, + query: { limit, after, query, sort, filter, preferOriginal }, + headers: { "accept-language": languages }, + request: { url }, + error, + }) => { + const [collection] = await db + .select({ pk: shows.pk }) + .from(shows) + .where( + and( + eq(shows.kind, "collection"), + isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id), + ), + ) + .limit(1); + + if (!collection) { + return error(404, { + status: 404, + message: `No collection with the id or slug: '${id}'.`, + }); + } + + const langs = processLanguages(languages); + const items = await getShows({ + limit, + after, + query, + sort, + filter: and( + eq(shows.collectionPk, collection.pk), + eq(shows.kind, "serie"), + filter, + ), + languages: langs, + preferOriginal, + }); + return createPage(items, { url, sort, limit }); + }, + { + detail: { description: "Get all series in a collection" }, + params: t.Object({ + id: t.String({ + description: "The id or slug of the collection.", + example: duneCollection.slug, + }), + }), + query: t.Object({ + sort: showSort, + filter: t.Optional(Filter({ def: showFilters })), + query: t.Optional(t.String({ description: desc.query })), + limit: t.Integer({ + minimum: 1, + maximum: 250, + default: 50, + description: "Max page size.", + }), + after: t.Optional(t.String({ description: desc.after })), + preferOriginal: t.Optional( + t.Boolean({ + description: desc.preferOriginal, + }), + ), + }), + headers: t.Object({ + "accept-language": AcceptLanguage({ autoFallback: true }), + }), + response: { + 200: Page(Movie), + 404: { + ...KError, + description: "No collection found with the given id or slug.", + }, + 422: KError, + }, + }, ); diff --git a/api/src/controllers/shows/shows.ts b/api/src/controllers/shows/logic.ts similarity index 100% rename from api/src/controllers/shows/shows.ts rename to api/src/controllers/shows/logic.ts diff --git a/api/src/controllers/shows/movies.ts b/api/src/controllers/shows/movies.ts index 10bbbec4..eb011711 100644 --- a/api/src/controllers/shows/movies.ts +++ b/api/src/controllers/shows/movies.ts @@ -13,7 +13,7 @@ import { processLanguages, } from "~/models/utils"; import { desc } from "~/models/utils/descriptions"; -import { getShow, getShows, showFilters, showSort } from "./shows"; +import { getShow, getShows, showFilters, showSort } from "./logic"; export const movies = new Elysia({ prefix: "/movies", tags: ["movies"] }) .model({ diff --git a/api/src/controllers/shows/series.ts b/api/src/controllers/shows/series.ts index 36c854ba..f903621e 100644 --- a/api/src/controllers/shows/series.ts +++ b/api/src/controllers/shows/series.ts @@ -13,7 +13,7 @@ import { processLanguages, } from "~/models/utils"; import { desc } from "~/models/utils/descriptions"; -import { getShow, getShows, showFilters, showSort } from "./shows"; +import { getShow, getShows, showFilters, showSort } from "./logic"; export const series = new Elysia({ prefix: "/series", tags: ["series"] }) .model({