mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Add /studios/:id
This commit is contained in:
parent
03d071acb4
commit
44658ce6b0
@ -1,8 +1,16 @@
|
|||||||
import { and, eq, exists } from "drizzle-orm";
|
import { and, eq, exists, sql } from "drizzle-orm";
|
||||||
import Elysia, { t } from "elysia";
|
import Elysia, { t } from "elysia";
|
||||||
import { db } from "~/db";
|
import { db } from "~/db";
|
||||||
import { showStudioJoin, shows, studios } from "~/db/schema";
|
import {
|
||||||
|
showStudioJoin,
|
||||||
|
shows,
|
||||||
|
studioTranslations,
|
||||||
|
studios,
|
||||||
|
} from "~/db/schema";
|
||||||
|
import { sqlarr } from "~/db/utils";
|
||||||
import { KError } from "~/models/error";
|
import { KError } from "~/models/error";
|
||||||
|
import { Movie } from "~/models/movie";
|
||||||
|
import { Serie } from "~/models/serie";
|
||||||
import { Show } from "~/models/show";
|
import { Show } from "~/models/show";
|
||||||
import { Studio, StudioTranslation } from "~/models/studio";
|
import { Studio, StudioTranslation } from "~/models/studio";
|
||||||
import {
|
import {
|
||||||
@ -15,14 +23,94 @@ import {
|
|||||||
} from "~/models/utils";
|
} from "~/models/utils";
|
||||||
import { desc } from "~/models/utils/descriptions";
|
import { desc } from "~/models/utils/descriptions";
|
||||||
import { getShows, showFilters, showSort } from "./shows/logic";
|
import { getShows, showFilters, showSort } from "./shows/logic";
|
||||||
import { Serie } from "~/models/serie";
|
|
||||||
import { Movie } from "~/models/movie";
|
|
||||||
|
|
||||||
export const studiosH = new Elysia({ tags: ["studios"] })
|
export const studiosH = new Elysia({ prefix: "/studios", tags: ["studios"] })
|
||||||
.model({
|
.model({
|
||||||
studio: Studio,
|
studio: Studio,
|
||||||
"studio-translation": StudioTranslation,
|
"studio-translation": StudioTranslation,
|
||||||
})
|
})
|
||||||
|
.get(
|
||||||
|
"/:id",
|
||||||
|
async ({
|
||||||
|
params: { id },
|
||||||
|
headers: { "accept-language": languages },
|
||||||
|
query: { with: relations },
|
||||||
|
error,
|
||||||
|
set,
|
||||||
|
}) => {
|
||||||
|
const langs = processLanguages(languages);
|
||||||
|
const ret = await db.query.studios.findFirst({
|
||||||
|
where: isUuid(id) ? eq(studios.id, id) : eq(studios.slug, id),
|
||||||
|
with: {
|
||||||
|
selectedTranslation: {
|
||||||
|
columns: { pk: false },
|
||||||
|
where: !languages.includes("*")
|
||||||
|
? eq(studioTranslations.language, sql`any(${sqlarr(langs)})`)
|
||||||
|
: undefined,
|
||||||
|
orderBy: [
|
||||||
|
sql`array_position(${sqlarr(langs)}, ${studioTranslations.language})`,
|
||||||
|
],
|
||||||
|
limit: 1,
|
||||||
|
},
|
||||||
|
...(relations.includes("translations") && {
|
||||||
|
translations: {
|
||||||
|
columns: {
|
||||||
|
pk: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!ret) {
|
||||||
|
return error(404, {
|
||||||
|
status: 404,
|
||||||
|
message: `No studio with the id or slug: '${id}'`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const tr = ret.selectedTranslation[0];
|
||||||
|
set.headers["content-language"] = tr.language;
|
||||||
|
return {
|
||||||
|
...ret,
|
||||||
|
...tr,
|
||||||
|
...(ret.translations && {
|
||||||
|
translations: Object.fromEntries(
|
||||||
|
ret.translations.map(
|
||||||
|
({ language, ...translation }) =>
|
||||||
|
[language, translation] as const,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
detail: {
|
||||||
|
description: "Get a studio by id or slug",
|
||||||
|
},
|
||||||
|
params: t.Object({
|
||||||
|
id: t.String({
|
||||||
|
description: "The id or slug of the collection to retrieve.",
|
||||||
|
example: "mappa",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
query: t.Object({
|
||||||
|
with: t.Array(t.UnionEnum(["translations"]), {
|
||||||
|
default: [],
|
||||||
|
description: "Include related resources in the response.",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
headers: t.Object({
|
||||||
|
"accept-language": AcceptLanguage(),
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: { ...Studio, description: "Found" },
|
||||||
|
404: {
|
||||||
|
...KError,
|
||||||
|
description: "No collection found with the given id or slug.",
|
||||||
|
},
|
||||||
|
422: KError,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
.guard({
|
.guard({
|
||||||
params: t.Object({
|
params: t.Object({
|
||||||
id: t.String({
|
id: t.String({
|
||||||
@ -52,7 +140,7 @@ export const studiosH = new Elysia({ tags: ["studios"] })
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.get(
|
.get(
|
||||||
"/studios/:id/shows",
|
"/:id/shows",
|
||||||
async ({
|
async ({
|
||||||
params: { id },
|
params: { id },
|
||||||
query: { limit, after, query, sort, filter, preferOriginal },
|
query: { limit, after, query, sort, filter, preferOriginal },
|
||||||
@ -111,7 +199,7 @@ export const studiosH = new Elysia({ tags: ["studios"] })
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.get(
|
.get(
|
||||||
"/studios/:id/movies",
|
"/:id/movies",
|
||||||
async ({
|
async ({
|
||||||
params: { id },
|
params: { id },
|
||||||
query: { limit, after, query, sort, filter, preferOriginal },
|
query: { limit, after, query, sort, filter, preferOriginal },
|
||||||
@ -171,7 +259,7 @@ export const studiosH = new Elysia({ tags: ["studios"] })
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.get(
|
.get(
|
||||||
"/studios/:id/series",
|
"/:id/series",
|
||||||
async ({
|
async ({
|
||||||
params: { id },
|
params: { id },
|
||||||
query: { limit, after, query, sort, filter, preferOriginal },
|
query: { limit, after, query, sort, filter, preferOriginal },
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { sql } from "drizzle-orm";
|
import { relations, sql } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
index,
|
index,
|
||||||
integer,
|
integer,
|
||||||
@ -53,3 +53,37 @@ export const showStudioJoin = schema.table(
|
|||||||
},
|
},
|
||||||
(t) => [primaryKey({ columns: [t.show, t.studio] })],
|
(t) => [primaryKey({ columns: [t.show, t.studio] })],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const studioRelations = relations(studios, ({ many }) => ({
|
||||||
|
translations: many(studioTranslations, {
|
||||||
|
relationName: "studio_translations",
|
||||||
|
}),
|
||||||
|
selectedTranslation: many(studioTranslations, {
|
||||||
|
relationName: "studio_selected_translation",
|
||||||
|
}),
|
||||||
|
showsJoin: many(showStudioJoin, { relationName: "show_studios" }),
|
||||||
|
}));
|
||||||
|
export const studioTrRelations = relations(studioTranslations, ({ one }) => ({
|
||||||
|
studio: one(studios, {
|
||||||
|
relationName: "studio_translations",
|
||||||
|
fields: [studioTranslations.pk],
|
||||||
|
references: [studios.pk],
|
||||||
|
}),
|
||||||
|
selectedTranslation: one(studios, {
|
||||||
|
relationName: "studio_selected_translation",
|
||||||
|
fields: [studioTranslations.pk],
|
||||||
|
references: [studios.pk],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
export const ssjRelations = relations(showStudioJoin, ({ one }) => ({
|
||||||
|
show: one(shows, {
|
||||||
|
relationName: "ssj_show",
|
||||||
|
fields: [showStudioJoin.show],
|
||||||
|
references: [shows.pk],
|
||||||
|
}),
|
||||||
|
studio: one(studios, {
|
||||||
|
relationName: "ssj_studio",
|
||||||
|
fields: [showStudioJoin.studio],
|
||||||
|
references: [studios.pk],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
export * from "./movies-helper";
|
export * from "./movies-helper";
|
||||||
export * from "./series-helper";
|
export * from "./series-helper";
|
||||||
|
export * from "./studio-helper";
|
||||||
export * from "./videos-helper";
|
export * from "./videos-helper";
|
||||||
|
|
||||||
export * from "~/elysia";
|
export * from "~/elysia";
|
||||||
|
@ -1,6 +1,24 @@
|
|||||||
import { buildUrl } from "tests/utils";
|
import { buildUrl } from "tests/utils";
|
||||||
import { app } from "~/elysia";
|
import { app } from "~/elysia";
|
||||||
|
|
||||||
|
export const getStudio = async (
|
||||||
|
id: string,
|
||||||
|
{ langs, ...query }: { langs?: string; preferOriginal?: boolean },
|
||||||
|
) => {
|
||||||
|
const resp = await app.handle(
|
||||||
|
new Request(buildUrl(`studios/${id}`, query), {
|
||||||
|
method: "GET",
|
||||||
|
headers: langs
|
||||||
|
? {
|
||||||
|
"Accept-Language": langs,
|
||||||
|
}
|
||||||
|
: {},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const body = await resp.json();
|
||||||
|
return [resp, body] as const;
|
||||||
|
};
|
||||||
|
|
||||||
export const getShowsByStudio = async (
|
export const getShowsByStudio = async (
|
||||||
studio: string,
|
studio: string,
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { beforeAll, describe, expect, it } from "bun:test";
|
import { beforeAll, describe, expect, it } from "bun:test";
|
||||||
import { getShowsByStudio } from "tests/helpers/studio-helper";
|
import { getShowsByStudio, getStudio } from "tests/helpers";
|
||||||
import { expectStatus } from "tests/utils";
|
import { expectStatus } from "tests/utils";
|
||||||
import { seedSerie } from "~/controllers/seed/series";
|
import { seedSerie } from "~/controllers/seed/series";
|
||||||
import { madeInAbyss } from "~/models/examples";
|
import { madeInAbyss } from "~/models/examples";
|
||||||
@ -28,3 +28,22 @@ describe("Get by studio", () => {
|
|||||||
expect(body.items[0].slug).toBe(madeInAbyss.slug);
|
expect(body.items[0].slug).toBe(madeInAbyss.slug);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Get a studio", () => {
|
||||||
|
it("Invalid slug", async () => {
|
||||||
|
const [resp, body] = await getStudio("sotneuhn", { langs: "en" });
|
||||||
|
|
||||||
|
expectStatus(resp, body).toBe(404);
|
||||||
|
expect(body).toMatchObject({
|
||||||
|
status: 404,
|
||||||
|
message: expect.any(String),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Get by id", async () => {
|
||||||
|
const slug = madeInAbyss.studios[0].slug;
|
||||||
|
const [resp, body] = await getStudio(slug, { langs: "en" });
|
||||||
|
|
||||||
|
expectStatus(resp, body).toBe(200);
|
||||||
|
expect(body.slug).toBe(slug);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user