diff --git a/api/src/controllers/seed/index.ts b/api/src/controllers/seed/index.ts index c87f643f..cbcd5be6 100644 --- a/api/src/controllers/seed/index.ts +++ b/api/src/controllers/seed/index.ts @@ -1,29 +1,37 @@ import { Value } from "@sinclair/typebox/value"; import Elysia from "elysia"; import { KError } from "~/models/error"; -import { Movie, SeedMovie } from "~/models/movie"; +import { SeedMovie } from "~/models/movie"; +import { SeedSerie } from "~/models/serie"; import { Resource } from "~/models/utils"; import { comment } from "~/utils"; import { SeedMovieResponse, seedMovie } from "./movies"; +import { SeedSerieResponse, seedSerie } from "./series"; export const seed = new Elysia() .model({ - movie: Movie, "seed-movie": SeedMovie, "seed-movie-response": SeedMovieResponse, + "seed-serie": SeedSerie, + "seed-serie-response": SeedSerieResponse, }) .post( "/movies", async ({ body, error }) => { // needed due to https://github.com/elysiajs/elysia/issues/671 - body = Value.Decode(SeedMovie, body); + const movie = Value.Decode(SeedMovie, body) as SeedMovie; - const ret = await seedMovie(body); - if (ret.status === 422) return error(422, ret); - return error(ret.status, ret); + const ret = await seedMovie(movie); + if ("status" in ret) return error(ret.status, ret as any); + return error(ret.updated ? 200 : 201, ret); }, { - body: "seed-movie", + detail: { + tags: ["movies"], + description: + "Create a movie & all related metadata. Can also link videos.", + }, + body: SeedMovie, response: { 200: { ...SeedMovieResponse, @@ -31,18 +39,47 @@ export const seed = new Elysia() }, 201: { ...SeedMovieResponse, description: "Created a new movie." }, 409: { - ...Resource, + ...Resource(), description: comment` A movie with the same slug but a different air date already exists. Change the slug and re-run the request. `, }, - 422: { ...KError, description: "Invalid schema in body." }, + 422: KError, }, + }, + ) + .post( + "/series", + async ({ body, error }) => { + // needed due to https://github.com/elysiajs/elysia/issues/671 + const serie = Value.Decode(SeedSerie, body) as SeedSerie; + + const ret = await seedSerie(serie); + if ("status" in ret) return error(ret.status, ret as any); + return error(ret.updated ? 200 : 201, ret); + }, + { detail: { - tags: ["movies"], + tags: ["series"], description: - "Create a movie & all related metadata. Can also link videos.", + "Create a series & all related metadata. Can also link videos.", + }, + body: SeedSerie, + response: { + 200: { + ...SeedSerieResponse, + description: "Existing serie edited/updated.", + }, + 201: { ...SeedSerieResponse, description: "Created a new serie." }, + 409: { + ...Resource(), + description: comment` + A serie with the same slug but a different air date already exists. + Change the slug and re-run the request. + `, + }, + 422: KError, }, }, ); diff --git a/api/src/controllers/seed/series.ts b/api/src/controllers/seed/series.ts new file mode 100644 index 00000000..948889e6 --- /dev/null +++ b/api/src/controllers/seed/series.ts @@ -0,0 +1,51 @@ +import { t } from "elysia"; +import type { SeedSerie } from "~/models/serie"; +import { getYear } from "~/utils"; +import { insertShow } from "./insert/shows"; +import { guessNextRefresh } from "./refresh"; +import { insertEntries } from "./insert/entries"; + +export const SeedSerieResponse = t.Object({ + id: t.String({ format: "uuid" }), + slug: t.String({ format: "slug", examples: ["bubble"] }), +}); +export type SeedSerieResponse = typeof SeedSerieResponse.static; + +export const seedSerie = async ( + seed: SeedSerie, +): Promise< + | (SeedSerieResponse & { updated: boolean }) + | { status: 409; id: string; slug: string } + | { status: 422; message: string } +> => { + if (seed.slug === "random") { + if (!seed.startAir) { + return { + status: 422, + message: "`random` is a reserved slug. Use something else.", + }; + } + seed.slug = `random-${getYear(seed.startAir)}`; + } + + const { translations, seasons, entries, ...serie } = seed; + const nextRefresh = guessNextRefresh(serie.startAir ?? new Date()); + + const ret = await insertShow( + { + kind: "serie", + nextRefresh, + ...serie, + }, + translations, + ); + if ("status" in ret) return ret; + + const retEntries = await insertEntries(ret.pk, entries); + + return { + updated: ret.updated, + id: ret.id, + slug: ret.slug, + }; +};