From 161c4022ae4d952601ea26ffd95ba5d473cafd04 Mon Sep 17 00:00:00 2001 From: Jorge Vargas Date: Fri, 14 Mar 2025 21:27:27 -0600 Subject: [PATCH] Amaterasu runner file --- .forgejo/workflows/build.yaml | 16 ++++++ src/pages/api/album/create.ts | 2 +- src/pages/api/album/update.ts | 93 ++++++++++++++++++++++++++++++++ src/pages/api/platform/create.ts | 90 +++++++++++++++++++++++++++++++ src/pages/api/platform/update.ts | 93 ++++++++++++++++++++++++++++++++ src/schemas/album.ts | 2 +- 6 files changed, 294 insertions(+), 2 deletions(-) create mode 100644 .forgejo/workflows/build.yaml create mode 100644 src/pages/api/album/update.ts create mode 100644 src/pages/api/platform/create.ts create mode 100644 src/pages/api/platform/update.ts diff --git a/.forgejo/workflows/build.yaml b/.forgejo/workflows/build.yaml new file mode 100644 index 0000000..62d0cb4 --- /dev/null +++ b/.forgejo/workflows/build.yaml @@ -0,0 +1,16 @@ +on: + workflow_dispatch: + push: + +jobs: + build: + runs-on: docker + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@latest + with: + node-version: 'latest' + check-latest: true + cache: 'yarn' + - run: | + yarn build diff --git a/src/pages/api/album/create.ts b/src/pages/api/album/create.ts index c43d5fe..5bce3e9 100644 --- a/src/pages/api/album/create.ts +++ b/src/pages/api/album/create.ts @@ -6,7 +6,7 @@ import { AlbumStatus } from '@prisma/client' import { Status, parseForm, slug } from 'utils/form' import { writeImg, getImgColor } from 'utils/img' import { handleComplete } from 'integrations/requestCat' -import { CreateAlbum } from 'schemas/album' +import { AlbumSchema } from 'schemas/album' export const POST: APIRoute = async ({ request, locals }) => { const { session, permissions, user } = locals diff --git a/src/pages/api/album/update.ts b/src/pages/api/album/update.ts new file mode 100644 index 0000000..5d3797f --- /dev/null +++ b/src/pages/api/album/update.ts @@ -0,0 +1,93 @@ +import type { APIRoute } from 'astro' +import * as s from 'superstruct' + +import { AlbumStatus } from '@prisma/client' +import prismaClient from 'utils/prisma-client' + +import { Status, parseForm, slug } from 'utils/form' +import { writeImg, getImgColor } from 'utils/img' +import { handleComplete } from 'integrations/requestCat' +import { AlbumSchema } from 'schemas/album' + +const UpdateAlbum = s.assign(s.partial(AlbumSchema), s.object({ albumId: s.number() })) + +export const POST: APIRoute = async ({ request, locals }) => { + const { session, permissions, user } = locals + + if (!session || !user) return Status(401) + if (!permissions.includes('UPDATE')) return Status(403) + + let body + try { + const formData = await parseForm(request) + body = s.create(formData, UpdateAlbum) + } catch (err) { + return Status(422, (err as Error).message) + } + + try { + const albumRow = await prismaClient.$transaction(async (tx) => { + const artistRows = body.artists.map((name: string) => ({ slug: slug(name), name })) + + const albumRow = await tx.albums.update({ + where: {id: body.albumId} + data: { + title: body.title, + subTitle: body.subTitle, + releaseDate: body.releaseDate, + label: body.label, + vgmdb: body.vgmdb, + description: body.description, + createdBy: user.name, + status: body.status, + animations: { create: body.animations.map((id) => ({ animation: { connect: { id } } })) }, + artists: { + set: artistRows.map((a) => ({ + artist: { + connectOrCreate: { + create: a, + where: { slug: a.slug } + } + } + })) + }, + categories: { create: body.categories.map((c) => ({ category: { connect: { name: c } } })) }, + classifications: { create: body.classifications.map((name) => ({ classification: { connect: { name } } })) }, + games: { create: body.games.map((slug) => ({ game: { connect: { slug } } })) }, + platforms: { create: body.platforms.map((id) => ({ platform: { connect: { id } } })) }, + // albumHistories + discs: { createMany: { data: body.discs } }, + relatedAlbums: { create: body.related.map((id) => ({ relatedAlbum: { connect: { id } } })) } + }, + include: { artists: { include: { artist: { select: { name: true } } } } } + }) + + const handleCover = async () => { + const coverPath = await writeImg(body.cover, 'album', albumRow.id) + const headerColor = await getImgColor(coverPath) + await tx.albums.update({ where: { id: albumRow.id }, data: { headerColor } }) + albumRow.headerColor = headerColor + } + + 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 } + })) + }) + ]) + + return albumRow + }) + + if (albumRow.status === AlbumStatus.SHOW) await handleComplete(albumRow, body.request) + + return Status(200, albumRow.id.toString()) + } catch (err) { + return Status(500, (err as Error).message) + } +} diff --git a/src/pages/api/platform/create.ts b/src/pages/api/platform/create.ts new file mode 100644 index 0000000..ad60f79 --- /dev/null +++ b/src/pages/api/platform/create.ts @@ -0,0 +1,90 @@ +import type { APIRoute } from 'astro' +import * as s from 'superstruct' + +import prismaClient from 'utils/prisma-client' +import { AlbumStatus } from '@prisma/client' + +import { Status, formToObject, slug } from 'utils/form' +import { writeImg, getImgColor } from 'utils/img' +import { handleComplete } from 'integrations/requestCat' +import { AlbumSchema } from 'schemas/album' + +export const POST: APIRoute = async ({ request, locals }) => { + const { session, permissions, user } = locals + + if (!session || !user) return Status(401) + if (!permissions.includes('UPDATE')) return Status(403) + + let body + try { + const formData = await request.formData() + body = s.create(formToObject(formData), AlbumSchema) + } catch (err) { + return Status(422, (err as Error).message) + } + + try { + const albumRow = await prismaClient.$transaction(async (tx) => { + const artistRows = body.artists.map((name: string) => ({ slug: slug(name), name })) + + const albumRow = await tx.albums.create({ + data: { + title: body.title, + subTitle: body.subTitle, + releaseDate: body.releaseDate, + label: body.label, + vgmdb: body.vgmdb, + description: body.description, + createdBy: user.name, + status: body.status, + animations: { create: body.animations.map((id) => ({ animation: { connect: { id } } })) }, + artists: { + create: artistRows.map((a) => ({ + artist: { + connectOrCreate: { + create: a, + where: { slug: a.slug } + } + } + })) + }, + categories: { create: body.categories.map((c) => ({ category: { connect: { name: c } } })) }, + classifications: { create: body.classifications.map((name) => ({ classification: { connect: { name } } })) }, + games: { create: body.games.map((slug) => ({ game: { connect: { slug } } })) }, + platforms: { create: body.platforms.map((id) => ({ platform: { connect: { id } } })) }, + // albumHistories + discs: { createMany: { data: body.discs } }, + relatedAlbums: { create: body.related.map((id) => ({ relatedAlbum: { connect: { id } } })) } + }, + include: { artists: { include: { artist: { select: { name: true } } } } } + }) + + const handleCover = async () => { + const coverPath = await writeImg(body.cover, 'album', albumRow.id) + const headerColor = await getImgColor(coverPath) + await tx.albums.update({ where: { id: albumRow.id }, data: { headerColor } }) + albumRow.headerColor = headerColor + } + + 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 } + })) + }) + ]) + + return albumRow + }) + + if (albumRow.status === AlbumStatus.SHOW) await handleComplete(albumRow, body.request) + + return Status(200, albumRow.id.toString()) + } catch (err) { + return Status(500, (err as Error).message) + } +} diff --git a/src/pages/api/platform/update.ts b/src/pages/api/platform/update.ts new file mode 100644 index 0000000..6edf0a3 --- /dev/null +++ b/src/pages/api/platform/update.ts @@ -0,0 +1,93 @@ +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 { writeImg, getImgColor } from 'utils/img' +import { handleComplete } from 'integrations/requestCat' +import { AlbumSchema } from 'schemas/album' + +const UpdateAlbum = s.assign(s.partial(AlbumSchema), s.object({ albumId: s.number() })) + +export const POST: APIRoute = async ({ request, locals }) => { + const { session, permissions, user } = locals + + if (!session || !user) return Status(401) + if (!permissions.includes('UPDATE')) return Status(403) + + let body + try { + const formData = await request.formData() + body = s.create(formToObject(formData), UpdateAlbum) + } catch (err) { + return Status(422, (err as Error).message) + } + + try { + const albumRow = await prismaClient.$transaction(async (tx) => { + const artistRows = body.artists.map((name: string) => ({ slug: slug(name), name })) + + const albumRow = await tx.albums.update({ + where: {id: body.albumId} + data: { + title: body.title, + subTitle: body.subTitle, + releaseDate: body.releaseDate, + label: body.label, + vgmdb: body.vgmdb, + description: body.description, + createdBy: user.name, + status: body.status, + animations: { create: body.animations.map((id) => ({ animation: { connect: { id } } })) }, + artists: { + set: artistRows.map((a) => ({ + artist: { + connectOrCreate: { + create: a, + where: { slug: a.slug } + } + } + })) + }, + categories: { create: body.categories.map((c) => ({ category: { connect: { name: c } } })) }, + classifications: { create: body.classifications.map((name) => ({ classification: { connect: { name } } })) }, + games: { create: body.games.map((slug) => ({ game: { connect: { slug } } })) }, + platforms: { create: body.platforms.map((id) => ({ platform: { connect: { id } } })) }, + // albumHistories + discs: { createMany: { data: body.discs } }, + relatedAlbums: { create: body.related.map((id) => ({ relatedAlbum: { connect: { id } } })) } + }, + include: { artists: { include: { artist: { select: { name: true } } } } } + }) + + const handleCover = async () => { + const coverPath = await writeImg(body.cover, 'album', albumRow.id) + const headerColor = await getImgColor(coverPath) + await tx.albums.update({ where: { id: albumRow.id }, data: { headerColor } }) + albumRow.headerColor = headerColor + } + + 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 } + })) + }) + ]) + + return albumRow + }) + + if (albumRow.status === AlbumStatus.SHOW) await handleComplete(albumRow, body.request) + + return Status(200, albumRow.id.toString()) + } catch (err) { + return Status(500, (err as Error).message) + } +} diff --git a/src/schemas/album.ts b/src/schemas/album.ts index 7102683..f9ef39b 100644 --- a/src/schemas/album.ts +++ b/src/schemas/album.ts @@ -15,7 +15,7 @@ export const DownloadInput = s.object({ links: s.defaulted(s.array(LinkInput), []) }) -export const CreateAlbum = s.object({ +export const AlbumSchema = s.object({ cover: s.instance(File), title: s.optional(s.string()), subTitle: s.optional(s.string()),