Wroclaw
eebf25198d
also I updated packages, and properly typed api input a lot of time was spent, I don't remeber what really I did x3 but everything was related to replacing mysql2 with prisma
191 lines
6.6 KiB
TypeScript
191 lines
6.6 KiB
TypeScript
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
|
import * as Prisma from "@prisma/client";
|
|
|
|
import { createValidationError, handleRecursedValidationError } from "../utils/validation";
|
|
import { database } from "../utils/database";
|
|
import getRequestingUser from "../utils/getRequestingUser";
|
|
import { getOrder } from "./orders/[id].get";
|
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
|
import Snowflake from "~/utils/snowflake";
|
|
|
|
import { createError } from "#imports";
|
|
|
|
type importedProduct<inOrder extends boolean = boolean> = {
|
|
orderId: inOrder extends true ? never : string,
|
|
name: string | null,
|
|
link: string,
|
|
price_imported: number,
|
|
price: number,
|
|
}
|
|
|
|
type work<inOrder extends boolean = boolean> = {
|
|
orderId: inOrder extends true ? never : string,
|
|
offerId: string,
|
|
price: number,
|
|
notes: string | null,
|
|
fulfilled: boolean,
|
|
}
|
|
|
|
type order = {
|
|
clientId: string,
|
|
// userId: string,
|
|
draft: boolean,
|
|
imported_products: Array<importedProduct<true>>,
|
|
work: Array<work<true>>,
|
|
};
|
|
|
|
export function checkIsWork<Patch extends boolean = boolean, inOrder extends boolean = boolean>(
|
|
value: any,
|
|
patch: Patch,
|
|
needsOrderId: inOrder,
|
|
): value is Patch extends true ? Partial<work<inOrder>> : work<inOrder> {
|
|
const errors = new Map<string, string>();
|
|
|
|
if (typeof value !== "object") {
|
|
throw createError({
|
|
message: "Invalid body",
|
|
statusCode: 400,
|
|
});
|
|
}
|
|
|
|
if (!(typeof value.orderId === "string" || (patch && value.orderId === undefined) || !needsOrderId)) errors.set("orderId", "is not string");
|
|
if (!(typeof value.offerId === "string" || (patch && value.offerId === undefined))) errors.set("offerId", "is not string");
|
|
if (!(typeof value.price === "number" || (patch && value.price === undefined))) errors.set("price", "is not price");
|
|
if (!(typeof value.notes === "string" || value.notes === null || (patch && value.notes === undefined))) errors.set("notes", "is not string or null");
|
|
if (!(typeof value.is_fulfilled === "boolean" || (patch && value.is_fulfilled === undefined))) errors.set("is_fulfilled", "is not boolean");
|
|
|
|
// TODO: Excessive property checking
|
|
// Excessive properties should be checked and an error should be thrown if there is one
|
|
|
|
if (errors.size !== 0) throw createValidationError(errors);
|
|
return true;
|
|
}
|
|
|
|
export function checkIsImportedProduct<Patch extends boolean = boolean, inOrder extends boolean = boolean>(
|
|
value: any,
|
|
patch: Patch,
|
|
needsOrderId: inOrder,
|
|
): value is Patch extends true ? Partial<importedProduct<inOrder>> : importedProduct<inOrder> {
|
|
const errors = new Map<string, string>();
|
|
|
|
if (typeof value !== "object") {
|
|
throw createError({
|
|
message: "Invalid body",
|
|
statusCode: 400,
|
|
});
|
|
}
|
|
|
|
if (!(typeof value.orderId === "string" || (patch && value.orderId === undefined) || !needsOrderId)) errors.set("orderId", "is not string");
|
|
if (!(typeof value.name === "string" || value.name === null || (patch && value.name === undefined))) errors.set("name", "is not string or null");
|
|
if (!(typeof value.link === "string" || (patch && value.name === undefined))) errors.set("link", "is not string");
|
|
if (!(typeof value.price_imported === "number" || (patch && value.name === undefined))) errors.set("price_imported", "is not number");
|
|
if (!(typeof value.price === "number" || (patch && value.price === undefined))) errors.set("price", "is not number");
|
|
|
|
// TODO: Excessive property checking
|
|
// Excessive properties should be checked and an error should be thrown if there is one
|
|
|
|
if (errors.size !== 0) throw createValidationError(errors);
|
|
|
|
return true;
|
|
}
|
|
|
|
export function checkIsOrder<Patch extends boolean = boolean>(
|
|
value: any,
|
|
patch: Patch,
|
|
): value is Patch extends true ? Partial<Omit<order, "imported_products" | "work">> : order {
|
|
const errors = new Map<string, string>();
|
|
|
|
if (typeof value !== "object") {
|
|
throw createError({
|
|
message: "Invalid body",
|
|
statusCode: 400,
|
|
});
|
|
}
|
|
|
|
if (!(typeof value.clientId === "string" || (patch && value.clientId === undefined))) errors.set("clientId", "is not string");
|
|
if (!(typeof value.draft === "boolean" || (patch && value.is_draft === undefined))) errors.set("draft", "is not boolean");
|
|
if (!(value.imported_products instanceof Array)) errors.set("imported_products", "is not array");
|
|
else if (patch && value.imported_products !== undefined) errors.set("imported_products", "cannot patch from order");
|
|
if (!(value.work instanceof Array)) errors.set("work", "is not array");
|
|
else if (patch && value.work !== undefined) errors.set("work", "cannot patch from order");
|
|
|
|
// TODO: Excessive property checking
|
|
// Excessive properties should be checked and an error should be thrown if there is one
|
|
|
|
if (!patch) {
|
|
const importedProducts = value.imported_products;
|
|
if (importedProducts instanceof Array) {
|
|
for (const i in importedProducts) {
|
|
try {
|
|
checkIsImportedProduct(importedProducts[i], patch, false);
|
|
} catch (e) {
|
|
handleRecursedValidationError(e, errors, `imported_products[${i}]`);
|
|
}
|
|
}
|
|
}
|
|
|
|
const work = value.work;
|
|
if (work instanceof Array) {
|
|
for (const i in work) {
|
|
try {
|
|
checkIsWork(work[i], patch, false);
|
|
} catch (e) {
|
|
handleRecursedValidationError(e, errors, `work[${i}]`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (errors.size !== 0) throw createValidationError(errors);
|
|
|
|
return true;
|
|
}
|
|
|
|
export default defineEventHandler(async (e) => {
|
|
const body = await readBody(e);
|
|
const id = new Snowflake().state;
|
|
const user = await getRequestingUser(e);
|
|
|
|
if (!checkIsOrder(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
|
|
|
await database.order.create({
|
|
data: {
|
|
clientId: BigInt(body.clientId),
|
|
draft: body.draft,
|
|
imported_products: {
|
|
createMany: {
|
|
data: body.imported_products.reduce(
|
|
(pV, cV) => {
|
|
pV.push({
|
|
...cV,
|
|
id: new Snowflake().state,
|
|
});
|
|
return pV;
|
|
},
|
|
[] as Array<Omit<Prisma.Prisma.ImportedProductCreateManyOrderInput, "orderId">>,
|
|
),
|
|
},
|
|
},
|
|
work: {
|
|
createMany: {
|
|
data: body.work.reduce(
|
|
(pV, cV) => {
|
|
pV.push({
|
|
...cV,
|
|
id: new Snowflake().state,
|
|
offerId: BigInt(cV.offerId),
|
|
});
|
|
return pV;
|
|
},
|
|
[] as Array<Omit<Prisma.Prisma.WorkCreateManyOrderInput, "orderId">>,
|
|
),
|
|
},
|
|
},
|
|
id,
|
|
userId: user.id,
|
|
},
|
|
});
|
|
|
|
setResponseStatus(e, 201);
|
|
return getOrder(id).then(prismaToWeb);
|
|
});
|