Multiple form validation fixes

This commit is contained in:
Jorge Vargas 2025-03-10 22:22:52 -06:00
parent 20dd61881c
commit 0e6e08beb2
5 changed files with 55 additions and 55 deletions

View file

@ -0,0 +1,10 @@
/*
Warnings:
- You are about to drop the column `createdAt` on the `links` table. All the data in the column will be lost.
- You are about to drop the column `updatedAt` on the `links` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE `links` DROP COLUMN `createdAt`,
DROP COLUMN `updatedAt`;

View file

@ -275,8 +275,6 @@ model links {
directUrl String? @db.VarChar(255)
provider String? @db.VarChar(255)
custom String? @db.VarChar(255)
createdAt DateTime @db.DateTime(0)
updatedAt DateTime @db.DateTime(0)
downloadId Int
url2 String? @db.VarChar(255)
download downloads? @relation(fields: [downloadId], references: [id], map: "links_ibfk_1")

View file

@ -1,34 +1,12 @@
import type { APIRoute } from 'astro'
import * as s from 'superstruct'
import { AlbumStatus } from '@prisma/client'
import prismaClient from 'utils/prisma-client'
import { Status, formToObject, slug } from 'utils/form'
import { AlbumStatus } from '@prisma/client'
import { Status, slug } from 'utils/form'
import { writeImg, getImgColor } from 'utils/img'
import { handleComplete } from 'integrations/requestCat'
import { DownloadInput } from 'schemas/album'
const CreateAlbum = s.object({
cover: s.instance(File),
title: s.optional(s.string()),
subTitle: s.optional(s.string()),
releaseDate: s.optional(s.string()),
label: s.optional(s.string()),
vgmdb: s.optional(s.string()),
description: s.optional(s.string()),
status: s.defaulted(s.enums(Object.values(AlbumStatus)), AlbumStatus.HIDDEN),
animations: s.defaulted(s.array(s.integer()), []),
artists: s.defaulted(s.array(s.string()), []),
categories: s.defaulted(s.array(s.string()), []),
classifications: s.defaulted(s.array(s.string()), []),
games: s.defaulted(s.array(s.string()), []),
platforms: s.defaulted(s.array(s.integer()), []),
discs: s.defaulted(s.array(s.object({ number: s.integer(), body: s.string() })), []),
downloads: s.defaulted(s.array(DownloadInput), []),
related: s.defaulted(s.array(s.number()), []),
stores: s.defaulted(s.array(s.object({ provider: s.string(), url: s.string() })), []),
request: s.optional(s.integer())
})
import { CreateAlbum } from 'schemas/album'
export const POST: APIRoute = async ({ request, locals }) => {
const { session, permissions, user } = locals
@ -39,7 +17,10 @@ export const POST: APIRoute = async ({ request, locals }) => {
let body
try {
const formData = await request.formData()
body = s.create(formToObject(formData), CreateAlbum)
const data = formData.get('data') as string
const cover = formData.get('cover')
const formObject = { cover, ...JSON.parse(data) }
body = s.create(formObject, CreateAlbum)
} catch (err) {
return Status(422, (err as Error).message)
}
@ -52,7 +33,7 @@ export const POST: APIRoute = async ({ request, locals }) => {
data: {
title: body.title,
subTitle: body.subTitle,
releaseDate: body.releaseDate,
releaseDate: body.releaseDate ? new Date(body.releaseDate) : null,
label: body.label,
vgmdb: body.vgmdb,
description: body.description,
@ -89,14 +70,18 @@ export const POST: APIRoute = async ({ request, locals }) => {
await Promise.all([
handleCover(),
tx.downloads.createMany({
data: body.downloads.map((d) => ({
title: d.title,
small: d.small,
albumId: albumRow.id,
links: { create: d.links }
}))
})
Promise.all(
body.downloads.map((d) =>
tx.downloads.create({
data: {
title: d.title,
small: d.small,
albumId: albumRow.id,
links: { create: d.links }
}
})
)
)
])
return albumRow
@ -106,6 +91,7 @@ export const POST: APIRoute = async ({ request, locals }) => {
return Status(200, albumRow.id.toString())
} catch (err) {
console.error(err)
return Status(500, (err as Error).message)
}
}

View file

@ -1,4 +1,5 @@
import * as s from 'superstruct'
import { AlbumStatus } from '@prisma/client'
const LinkInput = s.object({
provider: s.string(),
@ -13,3 +14,25 @@ export const DownloadInput = s.object({
small: s.defaulted(s.boolean(), false),
links: s.defaulted(s.array(LinkInput), [])
})
export const CreateAlbum = s.object({
cover: s.instance(File),
title: s.optional(s.string()),
subTitle: s.optional(s.string()),
releaseDate: s.optional(s.string()),
label: s.optional(s.string()),
vgmdb: s.optional(s.string()),
description: s.optional(s.string()),
status: s.defaulted(s.enums(Object.values(AlbumStatus)), AlbumStatus.HIDDEN),
animations: s.defaulted(s.array(s.integer()), []),
artists: s.defaulted(s.array(s.string()), []),
categories: s.defaulted(s.array(s.string()), []),
classifications: s.defaulted(s.array(s.string()), []),
games: s.defaulted(s.array(s.string()), []),
platforms: s.defaulted(s.array(s.integer()), []),
discs: s.defaulted(s.array(s.object({ number: s.integer(), body: s.string() })), []),
downloads: s.defaulted(s.array(DownloadInput), []),
related: s.defaulted(s.array(s.number()), []),
stores: s.defaulted(s.array(s.object({ provider: s.string(), url: s.string() })), []),
request: s.optional(s.integer())
})

View file

@ -2,20 +2,3 @@ import slugify from 'slugify'
export const Status = (status: number, statusText?: string) => new Response(null, { status, statusText })
export const slug = (text: string) => slugify(text, { lower: true, strict: true })
export function formToObject(formData: FormData) {
const object: Record<string, any> = {}
formData.forEach((value, key) => {
// Reflect.has in favor of: object.hasOwnProperty(key)
if (!Reflect.has(object, key)) {
object[key] = value
return
}
if (!Array.isArray(object[key])) {
object[key] = [object[key]]
}
object[key].push(value)
})
return object
}