Remember uploaded images
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `UserLoginLinks` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "public"."UserLoginLinks" DROP CONSTRAINT "UserLoginLinks_userId_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."User" ADD COLUMN "password" TEXT NOT NULL DEFAULT '',
|
||||
ALTER COLUMN "role" SET DEFAULT 'USER';
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "public"."UserLoginLinks";
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `picture` on the `QuestAnswer` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."QuestAnswer" DROP COLUMN "picture",
|
||||
ADD COLUMN "pictureId" INTEGER;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."File" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"uuid" TEXT NOT NULL,
|
||||
"creatorId" INTEGER NOT NULL,
|
||||
"huntId" INTEGER,
|
||||
"questId" INTEGER,
|
||||
"answerId" INTEGER,
|
||||
"createdAt" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "File_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "File_uuid_key" ON "public"."File"("uuid");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."File" ADD CONSTRAINT "File_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "public"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."File" ADD CONSTRAINT "File_huntId_fkey" FOREIGN KEY ("huntId") REFERENCES "public"."Hunt"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."File" ADD CONSTRAINT "File_questId_fkey" FOREIGN KEY ("questId") REFERENCES "public"."HuntQuest"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."File" ADD CONSTRAINT "File_answerId_fkey" FOREIGN KEY ("answerId") REFERENCES "public"."QuestAnswer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."QuestAnswer" ADD CONSTRAINT "QuestAnswer_pictureId_fkey" FOREIGN KEY ("pictureId") REFERENCES "public"."File"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `image` on the `HuntQuest` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."Hunt" ADD COLUMN "pictureId" INTEGER;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."HuntQuest" DROP COLUMN "image",
|
||||
ADD COLUMN "pictureId" INTEGER;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Hunt" ADD CONSTRAINT "Hunt_pictureId_fkey" FOREIGN KEY ("pictureId") REFERENCES "public"."File"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."HuntQuest" ADD CONSTRAINT "HuntQuest_pictureId_fkey" FOREIGN KEY ("pictureId") REFERENCES "public"."File"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[url]` on the table `File` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `url` to the `File` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."File" ADD COLUMN "url" TEXT NOT NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "File_url_key" ON "public"."File"("url");
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `revealPictures` on the `Hunt` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "public"."Hunt" DROP COLUMN "revealPictures",
|
||||
ADD COLUMN "revealQuests" BOOLEAN NOT NULL DEFAULT false;
|
||||
+46
-20
@@ -8,15 +8,14 @@ datasource db {
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
email String @unique
|
||||
name String
|
||||
role UserRole
|
||||
id Int @id @default(autoincrement())
|
||||
email String @unique
|
||||
password String @default("")
|
||||
name String
|
||||
role UserRole @default(USER)
|
||||
|
||||
emailConfirmedAt DateTime? @db.Timestamptz(3)
|
||||
|
||||
loginLinks UserLoginLinks[]
|
||||
|
||||
deactivated Boolean @default(false)
|
||||
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(3)
|
||||
@@ -30,6 +29,8 @@ model User {
|
||||
teamsMember TeamMember[]
|
||||
answers QuestAnswer[] @relation("AnswerMember")
|
||||
reviews QuestAnswer[] @relation("AnswerReview")
|
||||
|
||||
uploaded_files File[]
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
@@ -38,16 +39,28 @@ enum UserRole {
|
||||
ADMIN
|
||||
}
|
||||
|
||||
model UserLoginLinks {
|
||||
id Int @id @default(autoincrement())
|
||||
model File {
|
||||
id Int @id @default(autoincrement())
|
||||
uuid String @unique
|
||||
url String @unique
|
||||
|
||||
secret String
|
||||
used Boolean @default(false)
|
||||
creator User @relation(fields: [creatorId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
creatorId Int
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
userId Int
|
||||
hunt Hunt? @relation(name: "OldHuntFiles", fields: [huntId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
huntId Int?
|
||||
|
||||
quest HuntQuest? @relation(name: "OldQuestFiles", fields: [questId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
questId Int?
|
||||
|
||||
answer QuestAnswer? @relation(name: "OldAnswerFiles", fields: [answerId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
answerId Int?
|
||||
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(3)
|
||||
|
||||
answers QuestAnswer[]
|
||||
quests HuntQuest[]
|
||||
hunts Hunt[]
|
||||
}
|
||||
|
||||
model Hunt {
|
||||
@@ -55,16 +68,19 @@ model Hunt {
|
||||
name String
|
||||
description String
|
||||
|
||||
virtual Boolean @default(false)
|
||||
start DateTime? @db.Timestamptz(3)
|
||||
end DateTime? @db.Timestamptz(3)
|
||||
allowJoin Boolean @default(false)
|
||||
revealPictures Boolean @default(false)
|
||||
revealAnswers Boolean @default(false)
|
||||
virtual Boolean @default(false)
|
||||
start DateTime? @db.Timestamptz(3)
|
||||
end DateTime? @db.Timestamptz(3)
|
||||
allowJoin Boolean @default(false)
|
||||
revealQuests Boolean @default(false)
|
||||
revealAnswers Boolean @default(false)
|
||||
|
||||
creator User @relation(fields: [creatorId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
creatorId Int
|
||||
|
||||
picture File? @relation(fields: [pictureId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
pictureId Int?
|
||||
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(3)
|
||||
deletedAt DateTime? @db.Timestamptz(3)
|
||||
@@ -74,6 +90,8 @@ model Hunt {
|
||||
|
||||
quests HuntQuest[]
|
||||
|
||||
old_files File[] @relation("OldHuntFiles")
|
||||
|
||||
@@index([creatorId])
|
||||
}
|
||||
|
||||
@@ -140,10 +158,12 @@ model HuntQuest {
|
||||
title String
|
||||
description String @default("")
|
||||
question String?
|
||||
image String?
|
||||
location String?
|
||||
locationLink String?
|
||||
|
||||
picture File? @relation(fields: [pictureId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
pictureId Int?
|
||||
|
||||
order Int @default(0)
|
||||
optional Boolean @default(true)
|
||||
pictureRequired Boolean @default(false)
|
||||
@@ -161,13 +181,14 @@ model HuntQuest {
|
||||
|
||||
answers QuestAnswer[]
|
||||
|
||||
old_files File[] @relation("OldQuestFiles")
|
||||
|
||||
@@index([huntId])
|
||||
}
|
||||
|
||||
model QuestAnswer {
|
||||
id Int @id @default(autoincrement())
|
||||
text String?
|
||||
picture String?
|
||||
location String?
|
||||
lat Decimal? @db.Decimal(10, 8)
|
||||
lon Decimal? @db.Decimal(10, 8)
|
||||
@@ -181,6 +202,9 @@ model QuestAnswer {
|
||||
quest HuntQuest @relation(fields: [questId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
questId Int
|
||||
|
||||
picture File? @relation(fields: [pictureId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
pictureId Int?
|
||||
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(3)
|
||||
|
||||
@@ -190,6 +214,8 @@ model QuestAnswer {
|
||||
score Int? @db.SmallInt
|
||||
review String?
|
||||
|
||||
old_files File[] @relation("OldAnswerFiles")
|
||||
|
||||
@@index([teamId])
|
||||
@@index([memberId])
|
||||
@@index([questId])
|
||||
|
||||
+188
-167
@@ -1,182 +1,203 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
// region Users
|
||||
const admin = await prisma.user.upsert({
|
||||
where: { email: 'admin@mail.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'admin@mail.com',
|
||||
name: 'Admin user',
|
||||
role: 'ADMIN',
|
||||
emailConfirmedAt: new Date()
|
||||
}
|
||||
});
|
||||
const huntMember = await prisma.user.upsert({
|
||||
where: { email: 'team@mail.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'team@mail.com',
|
||||
name: 'Hunt member',
|
||||
role: 'ADMIN',
|
||||
emailConfirmedAt: new Date()
|
||||
}
|
||||
});
|
||||
await prisma.$transaction(async (tx) => {
|
||||
// region Users
|
||||
const admin = await tx.user.upsert({
|
||||
where: { email: 'admin@mail.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'admin@mail.com',
|
||||
name: 'Admin user',
|
||||
role: 'ADMIN',
|
||||
emailConfirmedAt: new Date()
|
||||
}
|
||||
});
|
||||
const huntMember = await tx.user.upsert({
|
||||
where: { email: 'team@mail.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'team@mail.com',
|
||||
name: 'Hunt member',
|
||||
role: 'ADMIN',
|
||||
emailConfirmedAt: new Date()
|
||||
}
|
||||
});
|
||||
|
||||
const user = await prisma.user.upsert({
|
||||
where: { email: 'user@mail.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'user@mail.com',
|
||||
name: 'User',
|
||||
role: 'USER',
|
||||
emailConfirmedAt: new Date()
|
||||
}
|
||||
});
|
||||
const teamMember = await prisma.user.upsert({
|
||||
where: { email: 'member@mail.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'member@mail.com',
|
||||
name: 'Team Member',
|
||||
role: 'USER',
|
||||
emailConfirmedAt: new Date()
|
||||
}
|
||||
});
|
||||
// endregion
|
||||
const user = await tx.user.upsert({
|
||||
where: { email: 'user@mail.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'user@mail.com',
|
||||
name: 'User',
|
||||
role: 'USER',
|
||||
emailConfirmedAt: new Date()
|
||||
}
|
||||
});
|
||||
const teamMember = await tx.user.upsert({
|
||||
where: { email: 'member@mail.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'member@mail.com',
|
||||
name: 'Team Member',
|
||||
role: 'USER',
|
||||
emailConfirmedAt: new Date()
|
||||
}
|
||||
});
|
||||
// endregion
|
||||
|
||||
const hunt = await prisma.hunt.create({
|
||||
include: {
|
||||
teams: true,
|
||||
quests: {
|
||||
orderBy: {
|
||||
order: 'asc'
|
||||
const hunt = await tx.hunt.create({
|
||||
include: {
|
||||
teams: true,
|
||||
quests: {
|
||||
orderBy: {
|
||||
order: 'asc'
|
||||
}
|
||||
}
|
||||
},
|
||||
data: {
|
||||
name: 'Bremer Stadtrallye!',
|
||||
description: 'DIE Rallye durch Bremen!',
|
||||
start: new Date('2025-08-23T10:00:00.000Z'),
|
||||
end: new Date('2025-08-30T10:00:00.000Z'),
|
||||
allowJoin: true,
|
||||
revealQuests: true,
|
||||
revealAnswers: false,
|
||||
quests: {
|
||||
create: [
|
||||
{
|
||||
title: 'MOIN!',
|
||||
description: 'Finde das größte MOIN',
|
||||
question: 'Wo steht es?',
|
||||
order: 0,
|
||||
optional: false,
|
||||
pictureRequired: true,
|
||||
textRequired: false,
|
||||
textType: 'TEXT',
|
||||
textSolution: 'Am Herdentor',
|
||||
points: 10
|
||||
},
|
||||
{
|
||||
title: 'Die Musikanten',
|
||||
description:
|
||||
'Dort wo die vier Bremer Tiere musizieren, müsst ihr ihre Beine anfassen!',
|
||||
question: 'Wie viele Beine haben die Musikanten zusammen?',
|
||||
extraText:
|
||||
'Mehr Punkte, je mehr unterschiedliche Beine ihre berührt!',
|
||||
points: 10,
|
||||
extraPoints: 5,
|
||||
pictureRequired: true,
|
||||
optional: false,
|
||||
textRequired: true,
|
||||
textType: 'INTEGER',
|
||||
textSolution: '14',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
title: 'Tolle Aussicht',
|
||||
description:
|
||||
'Mache ein Bild aus einem Gebäude der Hochschule, von so weit oben wie möglich!',
|
||||
points: 10,
|
||||
extraPoints: 10,
|
||||
extraText:
|
||||
'Wenn ihr das einzige Team in diesem Gebäude/Standort oder die Höchsten wart!',
|
||||
optional: false,
|
||||
pictureRequired: true,
|
||||
textRequired: false,
|
||||
question: 'In welchem Gebäude und Stockwerk wart ihr?',
|
||||
textType: 'TEXT',
|
||||
order: 2
|
||||
}
|
||||
]
|
||||
},
|
||||
creatorId: admin.id,
|
||||
members: {
|
||||
create: [
|
||||
{
|
||||
memberId: huntMember.id
|
||||
}
|
||||
]
|
||||
},
|
||||
teams: {
|
||||
create: [
|
||||
{
|
||||
ownerId: user.id,
|
||||
name: 'Team 1',
|
||||
description: 'Das beste Informatik Team!',
|
||||
password: 'top secret',
|
||||
members: {
|
||||
create: [
|
||||
{
|
||||
memberId: teamMember.id
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
data: {
|
||||
name: 'Bremer Stadtrallye!',
|
||||
description: 'DIE Rallye durch Bremen!',
|
||||
start: new Date('2025-08-23T10:00:00.000Z'),
|
||||
end: new Date('2025-08-30T10:00:00.000Z'),
|
||||
});
|
||||
|
||||
quests: {
|
||||
create: [
|
||||
{
|
||||
title: 'MOIN!',
|
||||
description: 'Finde das größte MOIN',
|
||||
question: 'Wo steht es?',
|
||||
order: 0,
|
||||
optional: false,
|
||||
pictureRequired: true,
|
||||
textRequired: false,
|
||||
textType: 'TEXT',
|
||||
textSolution: 'Am Herdentor',
|
||||
points: 10
|
||||
},
|
||||
{
|
||||
title: 'Die Musikanten',
|
||||
description:
|
||||
'Dort wo die vier Bremer Tiere musizieren, müsst ihr ihre Beine anfassen!',
|
||||
question: 'Wie viele Beine haben die Musikanten zusammen?',
|
||||
extraText:
|
||||
'Mehr Punkte, je mehr unterschiedliche Beine ihre berührt!',
|
||||
points: 10,
|
||||
extraPoints: 5,
|
||||
pictureRequired: true,
|
||||
optional: false,
|
||||
textRequired: true,
|
||||
textType: 'INTEGER',
|
||||
textSolution: '14',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
title: 'Tolle Aussicht',
|
||||
description:
|
||||
'Mache ein Bild aus einem Gebäude der Hochschule, von so weit oben wie möglich!',
|
||||
points: 10,
|
||||
extraPoints: 10,
|
||||
extraText:
|
||||
'Wenn ihr das einzige Team in diesem Gebäude/Standort oder die Höchsten wart!',
|
||||
optional: false,
|
||||
pictureRequired: true,
|
||||
textRequired: false,
|
||||
question: 'In welchem Gebäude und Stockwerk wart ihr?',
|
||||
textType: 'TEXT',
|
||||
order: 2
|
||||
const team = hunt.teams[0];
|
||||
|
||||
const images = [
|
||||
'/img/dummy/moin1.jpeg',
|
||||
'/img/dummy/musikanten1.jpg',
|
||||
'/img/dummy/aussicht1.jpeg'
|
||||
];
|
||||
const answers = await tx.questAnswer.createManyAndReturn({
|
||||
data: [
|
||||
{
|
||||
teamId: team.id,
|
||||
memberId: user.id,
|
||||
questId: hunt.quests[0].id,
|
||||
text: 'Am Herdentor',
|
||||
location: 'An der Haltestelle Herdentor',
|
||||
lat: 53.079138,
|
||||
lon: 8.809734,
|
||||
reviewerId: admin.id,
|
||||
score: 10,
|
||||
review: 'Schönes Bild!'
|
||||
},
|
||||
{
|
||||
teamId: team.id,
|
||||
memberId: teamMember.id,
|
||||
questId: hunt.quests[1].id,
|
||||
text: '14',
|
||||
location: 'Marktplatz',
|
||||
score: 10
|
||||
},
|
||||
{
|
||||
teamId: team.id,
|
||||
memberId: teamMember.id,
|
||||
questId: hunt.quests[2].id,
|
||||
text: 'Neustadtswall AB-Gebäude Etage 10',
|
||||
score: 17,
|
||||
reviewerId: huntMember.id,
|
||||
review: 'Höchstes Team, aber leider gabs andere im AB!'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
answers.map((a, i) =>
|
||||
tx.file.create({
|
||||
data: {
|
||||
url: images[i],
|
||||
creatorId: a.memberId,
|
||||
uuid: randomUUID(),
|
||||
answers: { connect: { id: a.id } },
|
||||
answerId: a.id
|
||||
}
|
||||
]
|
||||
},
|
||||
creatorId: admin.id,
|
||||
members: {
|
||||
create: [
|
||||
{
|
||||
memberId: huntMember.id
|
||||
}
|
||||
]
|
||||
},
|
||||
teams: {
|
||||
create: [
|
||||
{
|
||||
ownerId: user.id,
|
||||
name: 'Team 1',
|
||||
description: 'Das beste Informatik Team!',
|
||||
password: 'top secret',
|
||||
members: {
|
||||
create: [
|
||||
{
|
||||
memberId: teamMember.id
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
console.log(JSON.stringify(hunt, null, 2));
|
||||
});
|
||||
|
||||
const team = hunt.teams[0];
|
||||
|
||||
const answers = await prisma.questAnswer.createManyAndReturn({
|
||||
data: [
|
||||
{
|
||||
teamId: team.id,
|
||||
memberId: user.id,
|
||||
questId: hunt.quests[0].id,
|
||||
text: 'Am Herdentor',
|
||||
picture: '/img/dummy/moin1.jpeg',
|
||||
location: 'An der Haltestelle Herdentor',
|
||||
lat: 53.079138,
|
||||
lon: 8.809734,
|
||||
reviewerId: admin.id,
|
||||
score: 10,
|
||||
review: 'Schönes Bild!'
|
||||
},
|
||||
{
|
||||
teamId: team.id,
|
||||
memberId: teamMember.id,
|
||||
questId: hunt.quests[1].id,
|
||||
text: '14',
|
||||
picture: '/img/dummy/musikanten1.jpg',
|
||||
location: 'Marktplatz',
|
||||
score: 10
|
||||
},
|
||||
{
|
||||
teamId: team.id,
|
||||
memberId: teamMember.id,
|
||||
questId: hunt.quests[2].id,
|
||||
picture: '/img/dummy/aussicht1.jpeg',
|
||||
text: 'Neustadtswall AB-Gebäude Etage 10',
|
||||
score: 17,
|
||||
reviewerId: huntMember.id,
|
||||
review: 'Höchstes Team, aber leider gabs andere im AB!'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
console.log(JSON.stringify(hunt, null, 2));
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user