diff --git a/bun.lock b/bun.lock index 59a4a2d..3d50db7 100644 --- a/bun.lock +++ b/bun.lock @@ -5,8 +5,8 @@ "": { "name": "admin.gaertan.art", "dependencies": { - "@aws-sdk/client-s3": "^3.958.0", - "@aws-sdk/s3-request-presigner": "^3.958.0", + "@aws-sdk/client-s3": "^3.962.0", + "@aws-sdk/s3-request-presigner": "^3.962.0", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@hookform/resolvers": "^5.2.2", @@ -63,7 +63,7 @@ "zod": "^4.3.4", }, "devDependencies": { - "@biomejs/biome": "2.2.0", + "@biomejs/biome": "2.3.11", "@tailwindcss/postcss": "^4.1.18", "@types/archiver": "^7.0.0", "@types/culori": "^4.0.1", @@ -180,23 +180,23 @@ "@better-fetch/fetch": ["@better-fetch/fetch@1.1.21", "", {}, "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A=="], - "@biomejs/biome": ["@biomejs/biome@2.2.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.2.0", "@biomejs/cli-darwin-x64": "2.2.0", "@biomejs/cli-linux-arm64": "2.2.0", "@biomejs/cli-linux-arm64-musl": "2.2.0", "@biomejs/cli-linux-x64": "2.2.0", "@biomejs/cli-linux-x64-musl": "2.2.0", "@biomejs/cli-win32-arm64": "2.2.0", "@biomejs/cli-win32-x64": "2.2.0" }, "bin": { "biome": "bin/biome" } }, "sha512-3On3RSYLsX+n9KnoSgfoYlckYBoU6VRM22cw1gB4Y0OuUVSYd/O/2saOJMrA4HFfA1Ff0eacOvMN1yAAvHtzIw=="], + "@biomejs/biome": ["@biomejs/biome@2.3.11", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.11", "@biomejs/cli-darwin-x64": "2.3.11", "@biomejs/cli-linux-arm64": "2.3.11", "@biomejs/cli-linux-arm64-musl": "2.3.11", "@biomejs/cli-linux-x64": "2.3.11", "@biomejs/cli-linux-x64-musl": "2.3.11", "@biomejs/cli-win32-arm64": "2.3.11", "@biomejs/cli-win32-x64": "2.3.11" }, "bin": { "biome": "bin/biome" } }, "sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zKbwUUh+9uFmWfS8IFxmVD6XwqFcENjZvEyfOxHs1epjdH3wyyMQG80FGDsmauPwS2r5kXdEM0v/+dTIA9FXAg=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-+OmT4dsX2eTfhD5crUOPw3RPhaR+SKVspvGVmSdZ9y9O/AgL8pla6T4hOn1q+VAFBHuHhsdxDRJgFCSC7RaMOw=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-fh7nnvbweDPm2xEmFjfmq7zSUiox88plgdHF9OIW4i99WnXrAC3o2P3ag9judoUMv8FCSUnlwJCM1B64nO5Fbg=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-egKpOa+4FL9YO+SMUMLUvf543cprjevNc3CAgDNFLcjknuNMcZ0GLJYa3EGTCR2xIkIUJDVneBV3O9OcIlCEZQ=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-XPSQ+XIPZMLaZ6zveQdwNjbX+QdROEd1zPgMwD47zvHV+tCGB88VH+aynyGxAHdzL+Tm/+DtKST5SECs4iwCLg=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.2.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Nawu5nHjP/zPKTIryh2AavzTc/KEg4um/MxWdXW0A6P/RZOyIpa7+QSjeXwAwX/utJGaCoXRPWtF3m5U/bB3Ww=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg=="], "@chevrotain/cst-dts-gen": ["@chevrotain/cst-dts-gen@10.5.0", "", { "dependencies": { "@chevrotain/gast": "10.5.0", "@chevrotain/types": "10.5.0", "lodash": "4.17.21" } }, "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw=="], diff --git a/package.json b/package.json index bbaedc9..c3e9064 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "zod": "^4.3.4" }, "devDependencies": { - "@biomejs/biome": "2.2.0", + "@biomejs/biome": "2.3.11", "@tailwindcss/postcss": "^4.1.18", "@types/archiver": "^7.0.0", "@types/culori": "^4.0.1", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9b87d63..b17667d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -13,6 +13,8 @@ datasource db { provider = "postgresql" } + +/** Artworks **/ model Artwork { id String @id @default(cuid()) createdAt DateTime @default(now()) @@ -231,6 +233,7 @@ model FileVariant { @@unique([artworkId, type]) } +/** Commissions **/ model Commission { id String @id @default(cuid()) createdAt DateTime @default(now()) @@ -411,6 +414,39 @@ model TermsOfService { version Int @default(autoincrement()) } +/** Voting **/ +model Animal { + id String @id @default(cuid()) + name String + slug String @unique + description String? + imageUrl String? + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + votes Vote[] +} + +model Vote { + id String @id @default(cuid()) + animalId String + voterId String? // Twitch user ID (nullable for anon) + source VoteSource + createdAt DateTime @default(now()) + + animal Animal @relation(fields: [animalId], references: [id]) + + @@index([animalId]) +} + +enum VoteSource { + TWITCH_CHAT + CHANNEL_POINTS + ADMIN +} + +/** User management **/ model User { id String @id name String diff --git a/prisma/seed.ts b/prisma/seed.ts index a9f71af..a7be4cf 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,77 +1,77 @@ -import { PrismaClient } from "@/generated/prisma/client"; -import { PrismaPg } from "@prisma/adapter-pg"; -import { hashPassword } from "better-auth/crypto"; +// import { PrismaClient } from "@/generated/prisma/client"; +// import { PrismaPg } from "@prisma/adapter-pg"; +// import { hashPassword } from "better-auth/crypto"; -const connectionString = `${process.env.DATABASE_URL}` +// const connectionString = `${process.env.DATABASE_URL}` -const adapter = new PrismaPg({ connectionString }) -const prisma = new PrismaClient({ adapter }) +// const adapter = new PrismaPg({ connectionString }) +// const prisma = new PrismaClient({ adapter }) -function uid() { - return crypto.randomUUID(); -} +// function uid() { +// return crypto.randomUUID(); +// } -async function main() { - const email = "admin@gaertan.art"; - const name = "Admin"; - const password = "037Ikk7qmCamW5iYBimcwiPXNELzktIRG9ndiIkA3u"; +// async function main() { +// const email = "admin@gaertan.art"; +// const name = "Admin"; +// const password = "037Ikk7qmCamW5iYBimcwiPXNELzktIRG9ndiIkA3u"; - const passwordHash = await hashPassword(password); +// const passwordHash = await hashPassword(password); - // 1) Ensure user exists (your User.id has no default, so we must set it) - const user = await prisma.user.upsert({ - where: { email }, - update: { - name, - // optional: mark verified for initial admin - emailVerified: true, - }, - create: { - id: uid(), - email, - name, - emailVerified: true, - }, - }); +// // 1) Ensure user exists (your User.id has no default, so we must set it) +// const user = await prisma.user.upsert({ +// where: { email }, +// update: { +// name, +// // optional: mark verified for initial admin +// emailVerified: true, +// }, +// create: { +// id: uid(), +// email, +// name, +// emailVerified: true, +// }, +// }); - // 2) Ensure credential account exists for this user - // Better Auth expects providerId="credential" and accountId=userId for credential accounts. :contentReference[oaicite:2]{index=2} - const existingCredential = await prisma.account.findFirst({ - where: { - userId: user.id, - providerId: "credential", - accountId: user.id, - }, - }); +// // 2) Ensure credential account exists for this user +// // Better Auth expects providerId="credential" and accountId=userId for credential accounts. :contentReference[oaicite:2]{index=2} +// const existingCredential = await prisma.account.findFirst({ +// where: { +// userId: user.id, +// providerId: "credential", +// accountId: user.id, +// }, +// }); - if (!existingCredential) { - await prisma.account.create({ - data: { - id: uid(), - userId: user.id, - providerId: "credential", - accountId: user.id, - password: passwordHash, - }, - }); - } else { - // If it exists, keep it consistent (optionally reset password on seed) - await prisma.account.update({ - where: { id: existingCredential.id }, - data: { password: passwordHash }, - }); - } +// if (!existingCredential) { +// await prisma.account.create({ +// data: { +// id: uid(), +// userId: user.id, +// providerId: "credential", +// accountId: user.id, +// password: passwordHash, +// }, +// }); +// } else { +// // If it exists, keep it consistent (optionally reset password on seed) +// await prisma.account.update({ +// where: { id: existingCredential.id }, +// data: { password: passwordHash }, +// }); +// } - console.log("Seeded/updated admin user:"); - console.log(" email:", email); - console.log(" password:", password); -} +// console.log("Seeded/updated admin user:"); +// console.log(" email:", email); +// console.log(" password:", password); +// } -main() - .catch((err) => { - console.error("Seed failed:", err); - process.exit(1); - }) - .finally(async () => { - await prisma.$disconnect(); - }); +// main() +// .catch((err) => { +// console.error("Seed failed:", err); +// process.exit(1); +// }) +// .finally(async () => { +// await prisma.$disconnect(); +// });