feat(core): add secure recipe APIs, precise scaling and versioned imports
This commit is contained in:
commit
5d71d32e20
31 files changed
+6293
No files matched your search
@@ -0,0 +1,58 @@
|
||||
import { eq, desc, and } from 'drizzle-orm';
|
||||
import { db } from '@/db';
|
||||
import { recipes } from '@/db/schema';
|
||||
import type { Recipe, SavedRecipe } from './recipe';
|
||||
import { ApiError } from './server';
|
||||
export function serialize(row: typeof recipes.$inferSelect): SavedRecipe {
|
||||
return {
|
||||
...row.data,
|
||||
id: row.id,
|
||||
title: row.title,
|
||||
published: row.published,
|
||||
createdAt: row.createdAt.toISOString(),
|
||||
updatedAt: row.updatedAt.toISOString(),
|
||||
};
|
||||
}
|
||||
export async function listRecipes(isAdmin = false) {
|
||||
return (
|
||||
await db
|
||||
.select()
|
||||
.from(recipes)
|
||||
.where(isAdmin ? undefined : eq(recipes.published, true))
|
||||
.orderBy(desc(recipes.createdAt))
|
||||
).map(serialize);
|
||||
}
|
||||
export async function getRecipe(id: string, isAdmin = false) {
|
||||
if (!/^[0-9a-f-]{36}$/i.test(id)) return null;
|
||||
const [row] = await db
|
||||
.select()
|
||||
.from(recipes)
|
||||
.where(and(eq(recipes.id, id), isAdmin ? undefined : eq(recipes.published, true)));
|
||||
return row ? serialize(row) : null;
|
||||
}
|
||||
export const titleKey = (title: string) => title.normalize('NFKC').trim().toLocaleLowerCase('de');
|
||||
export async function saveRecipe(data: Recipe, id?: string, expected?: string) {
|
||||
const values = {
|
||||
title: data.title,
|
||||
titleKey: titleKey(data.title),
|
||||
published: data.published,
|
||||
data,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
if (id) {
|
||||
if (!expected) throw new ApiError(428, 'Versionsstand zum Speichern fehlt.');
|
||||
const [row] = await db
|
||||
.update(recipes)
|
||||
.set(values)
|
||||
.where(and(eq(recipes.id, id), eq(recipes.updatedAt, new Date(expected))))
|
||||
.returning();
|
||||
if (!row)
|
||||
throw new ApiError(
|
||||
409,
|
||||
'Das Rezept wurde zwischenzeitlich verändert. Entwurf sichern und Seite neu laden.',
|
||||
);
|
||||
return serialize(row);
|
||||
}
|
||||
const [row] = await db.insert(recipes).values(values).returning();
|
||||
return serialize(row);
|
||||
}
|
||||
Reference in new issue
Block a user