2023-11-06 02:57:00 +01:00
import { defineEventHandler , readBody , setResponseStatus } from "h3" ;
2023-05-24 09:40:45 +02:00
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" ;
2023-11-06 02:57:00 +01:00
import { createError } from "#imports" ;
2023-05-24 09:40:45 +02:00
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 ) ;
} ) ;