forked from Wroclaw/WorkshopTasker
173 lines
5.5 KiB
TypeScript
173 lines
5.5 KiB
TypeScript
|
/* global defineEventHandler, createError, readBody, setResponseStatus */
|
||
|
|
||
|
import { createValidationError, handleRecursedValidationError } from "../utils/validation";
|
||
|
import { database as db } from "../utils/database";
|
||
|
import getRequestingUser from "../utils/getRequestingUser";
|
||
|
import { getOrder } from "./orders/[id].get";
|
||
|
import Snowflake from "~/utils/snowflake";
|
||
|
|
||
|
type importedProduct = {
|
||
|
name: string | null,
|
||
|
link: string,
|
||
|
price_imported: number,
|
||
|
price: number,
|
||
|
}
|
||
|
|
||
|
type work = {
|
||
|
offer: string,
|
||
|
price: number,
|
||
|
notes: string | null,
|
||
|
is_fulfilled: boolean | 0 | 1,
|
||
|
}
|
||
|
|
||
|
type order = {
|
||
|
client: string,
|
||
|
// user: string,
|
||
|
is_draft: boolean | 0 | 1,
|
||
|
imported_products: Array<importedProduct>,
|
||
|
work: Array<work>,
|
||
|
};
|
||
|
|
||
|
export function checkIsWork<Patch extends boolean = boolean>(
|
||
|
value: any,
|
||
|
patch: Patch,
|
||
|
): value is Patch extends true ? Partial<work> : work {
|
||
|
const errors = new Map<string, string>();
|
||
|
|
||
|
if (typeof value !== "object") {
|
||
|
throw createError({
|
||
|
message: "Invalid body",
|
||
|
statusCode: 400,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (!(typeof value.offer === "string" || (patch && value.offer === undefined))) errors.set("offer", "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" || value.is_fulfilled === 0 || value.is_fulfilled === 1 || (patch && value.is_fulfilled === undefined))) errors.set("is_fulfilled", "is not boolean");
|
||
|
|
||
|
if (errors.size !== 0) throw createValidationError(errors);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
export function checkIsImportedProduct<Patch extends boolean = boolean>(
|
||
|
value: any,
|
||
|
patch: Patch,
|
||
|
): value is Patch extends true ? Partial<importedProduct> : importedProduct {
|
||
|
const errors = new Map<string, string>();
|
||
|
|
||
|
if (typeof value !== "object") {
|
||
|
throw createError({
|
||
|
message: "Invalid body",
|
||
|
statusCode: 400,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
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 || (patch && value.price === undefined))) errors.set("price", "is not number");
|
||
|
|
||
|
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<Pick<order, "client" | "is_draft">> : order {
|
||
|
const errors = new Map<string, string>();
|
||
|
|
||
|
if (typeof value !== "object") {
|
||
|
throw createError({
|
||
|
message: "Invalid body",
|
||
|
statusCode: 400,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (!(typeof value.client === "string" || (patch && value.client === undefined))) errors.set("client", "is not string");
|
||
|
if (!(typeof value.is_draft === "boolean" || value.is_draft === 0 || value.is_draft === 1 || (patch && value.is_draft === undefined))) errors.set("is_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");
|
||
|
|
||
|
if (!patch) {
|
||
|
const importedProducts = value.imported_products;
|
||
|
if (importedProducts instanceof Array) {
|
||
|
for (const i in importedProducts) {
|
||
|
try {
|
||
|
checkIsImportedProduct(importedProducts[i], patch);
|
||
|
} 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);
|
||
|
} 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().toString();
|
||
|
const user = await getRequestingUser(e);
|
||
|
|
||
|
if (!checkIsOrder(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||
|
|
||
|
const database = await db.new();
|
||
|
await database.beginTransaction();
|
||
|
|
||
|
await database.query(
|
||
|
["INSERT INTO",
|
||
|
"`orders`",
|
||
|
"VALUES",
|
||
|
"(?, ?, ?, ?)",
|
||
|
].join(" "),
|
||
|
[id, body.client, user.id, body.is_draft],
|
||
|
);
|
||
|
|
||
|
const promises: Array<Promise<any>> = [];
|
||
|
for (const i of body.imported_products) {
|
||
|
promises.push(database.query(
|
||
|
["INSERT INTO",
|
||
|
"`imported_products`",
|
||
|
"VALUES",
|
||
|
"(?, ?, ?, ?, ?, ?)",
|
||
|
].join(" "),
|
||
|
[new Snowflake().toString(), id, i.name, i.link, i.price_imported, i.price],
|
||
|
));
|
||
|
}
|
||
|
|
||
|
for (const i of body.work) {
|
||
|
promises.push(database.query(
|
||
|
["INSERT INTO",
|
||
|
"`work`",
|
||
|
"VALUES",
|
||
|
"(?, ?, ?, ?, ?, ?)",
|
||
|
].join(" "),
|
||
|
[new Snowflake().toString(), id, i.offer, i.price, i.notes, i.is_fulfilled],
|
||
|
));
|
||
|
}
|
||
|
|
||
|
await Promise.all(promises);
|
||
|
await database.commit();
|
||
|
|
||
|
setResponseStatus(e, 201);
|
||
|
return getOrder(id);
|
||
|
});
|