Prevent duplicated staff members

This commit is contained in:
2025-12-04 12:48:11 +01:00
parent eb4e3217a2
commit d374193ac2
7 changed files with 85 additions and 12 deletions

View File

@@ -52,8 +52,7 @@ export const base = new Elysia({ name: "base" })
console.error(code, error); console.error(code, error);
return { return {
status: 500, status: 500,
message: "message" in error ? (error?.message ?? code) : code, message: "Internal server error",
details: error,
} as KError; } as KError;
}) })
.get("/health", () => ({ status: "healthy" }) as const, { .get("/health", () => ({ status: "healthy" }) as const, {

View File

@@ -4,6 +4,7 @@ import { roles, staff } from "~/db/schema";
import { conflictUpdateAllExcept, unnestValues } from "~/db/utils"; import { conflictUpdateAllExcept, unnestValues } from "~/db/utils";
import type { SeedStaff } from "~/models/staff"; import type { SeedStaff } from "~/models/staff";
import { record } from "~/otel"; import { record } from "~/otel";
import { uniqBy } from "~/utils";
import { enqueueOptImage, flushImageQueue, type ImageTask } from "../images"; import { enqueueOptImage, flushImageQueue, type ImageTask } from "../images";
export const insertStaff = record( export const insertStaff = record(
@@ -13,13 +14,16 @@ export const insertStaff = record(
return await db.transaction(async (tx) => { return await db.transaction(async (tx) => {
const imgQueue: ImageTask[] = []; const imgQueue: ImageTask[] = [];
const people = seed.map((x) => ({ const people = uniqBy(
...x.staff, seed.map((x) => ({
image: enqueueOptImage(imgQueue, { ...x.staff,
url: x.staff.image, image: enqueueOptImage(imgQueue, {
column: staff.image, url: x.staff.image,
}), column: staff.image,
})); }),
})),
(x) => x.slug,
);
const ret = await tx const ret = await tx
.insert(staff) .insert(staff)
.select(unnestValues(people, staff)) .select(unnestValues(people, staff))
@@ -36,7 +40,7 @@ export const insertStaff = record(
const rval = seed.map((x, i) => ({ const rval = seed.map((x, i) => ({
showPk, showPk,
staffPk: ret[i].pk, staffPk: ret.find(y => y.slug === x.staff.slug)!.pk,
kind: x.kind, kind: x.kind,
order: i, order: i,
character: { character: {

View File

@@ -831,6 +831,9 @@ export const videosWriteH = new Elysia({ prefix: "/videos", tags: ["videos"] })
.post( .post(
"", "",
async ({ body, status }) => { async ({ body, status }) => {
if (body.length === 0) {
return status(422, { status: 422, message: "No videos" });
}
return await db.transaction(async (tx) => { return await db.transaction(async (tx) => {
let vids: { pk: number; id: string; path: string; guess: Guess }[] = []; let vids: { pk: number; id: string; path: string; guess: Guess }[] = [];
try { try {
@@ -925,6 +928,7 @@ export const videosWriteH = new Elysia({ prefix: "/videos", tags: ["videos"] })
description: description:
"Invalid rendering specified. (conflicts with an existing video)", "Invalid rendering specified. (conflicts with an existing video)",
}, },
422: KError,
}, },
}, },
) )

View File

@@ -91,7 +91,7 @@ export const seasonRelations = relations(seasons, ({ one, many }) => ({
export const seasonTrRelations = relations(seasonTranslations, ({ one }) => ({ export const seasonTrRelations = relations(seasonTranslations, ({ one }) => ({
season: one(seasons, { season: one(seasons, {
relationName: "season_translation", relationName: "season_translations",
fields: [seasonTranslations.pk], fields: [seasonTranslations.pk],
references: [seasons.pk], references: [seasons.pk],
}), }),

View File

@@ -28,3 +28,13 @@ export function getFile(path: string): BunFile | S3File {
return Bun.file(path); return Bun.file(path);
} }
export function uniqBy<T>(a: T[], key: (val: T) => string) {
const seen: Record<string, boolean> = {};
return a.filter((item) => {
const k = key(item);
if (seen[k]) return false;
seen[k] = true;
return true;
});
}

View File

@@ -104,4 +104,60 @@ describe("Serie seeding", () => {
], ],
}); });
}); });
it("Can create a serie with quotes", async () => {
const [resp, body] = await createSerie({
...madeInAbyss,
slug: "quote-test",
seasons: [
{
...madeInAbyss.seasons[0],
translations: {
en: {
...madeInAbyss.seasons[0].translations.en,
name: "Season'1",
},
},
},
{
...madeInAbyss.seasons[1],
translations: {
en: {
...madeInAbyss.seasons[0].translations.en,
name: 'Season"2',
description: `This's """""quote, idk'''''`,
},
},
},
],
});
expectStatus(resp, body).toBe(201);
expect(body.id).toBeString();
expect(body.slug).toBe("quote-test");
const ret = await db.query.shows.findFirst({
where: eq(shows.id, body.id),
with: {
seasons: {
orderBy: seasons.seasonNumber,
with: { translations: true },
},
entries: {
with: {
translations: true,
evj: { with: { video: true } },
},
},
},
});
expect(ret).not.toBeNull();
expect(ret!.seasons).toBeArrayOfSize(2);
expect(ret!.seasons[0].translations[0].name).toBe("Season'1");
expect(ret!.seasons[1].translations[0].name).toBe('Season"2');
expect(ret!.entries).toBeArrayOfSize(
madeInAbyss.entries.length + madeInAbyss.extras.length,
);
});
}); });

View File

@@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2021", "target": "ES2022",
"module": "ES2022", "module": "ES2022",
"moduleResolution": "node", "moduleResolution": "node",
"esModuleInterop": true, "esModuleInterop": true,