feat: add schema for admin content modules
This commit is contained in:
1 parent
9ead82bbca
commit
b9525c8e6b
3 files changed
+314
No files matched your search
@@ -0,0 +1,136 @@
|
||||
CREATE TABLE IF NOT EXISTS `website_event_types` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`slug` VARCHAR(100) NOT NULL,
|
||||
`description` VARCHAR(500) NOT NULL DEFAULT '',
|
||||
`color` VARCHAR(20) NOT NULL DEFAULT '#3b82f6',
|
||||
`icon` VARCHAR(50) NOT NULL DEFAULT 'calendar',
|
||||
`is_active` INTEGER NOT NULL DEFAULT 1,
|
||||
`min_rank` INTEGER NOT NULL DEFAULT 0,
|
||||
UNIQUE INDEX `website_event_types_slug_key`(`slug`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `website_events` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`title` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT NOT NULL,
|
||||
`type_id` INTEGER NOT NULL,
|
||||
`host_user_id` INTEGER NOT NULL,
|
||||
`room_id` INTEGER NULL,
|
||||
`starts_at` DATETIME(3) NOT NULL,
|
||||
`ends_at` DATETIME(3) NULL,
|
||||
`max_players` INTEGER NULL,
|
||||
`is_recurring` INTEGER NOT NULL DEFAULT 0,
|
||||
`recurrence_rule` VARCHAR(255) NULL,
|
||||
`status` VARCHAR(20) NOT NULL DEFAULT 'draft',
|
||||
`image` VARCHAR(500) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
INDEX `website_events_type_id_idx`(`type_id`),
|
||||
INDEX `website_events_host_user_id_idx`(`host_user_id`),
|
||||
INDEX `website_events_starts_at_idx`(`starts_at`),
|
||||
INDEX `website_events_status_idx`(`status`),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `website_events_type_id_fkey` FOREIGN KEY (`type_id`) REFERENCES `website_event_types`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `website_event_registrations` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`event_id` INTEGER NOT NULL,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
INDEX `website_event_registrations_user_id_idx`(`user_id`),
|
||||
UNIQUE INDEX `website_event_registrations_event_id_user_id_key`(`event_id`, `user_id`),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `website_event_registrations_event_id_fkey` FOREIGN KEY (`event_id`) REFERENCES `website_events`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `website_event_prizes` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`event_id` INTEGER NOT NULL,
|
||||
`position` INTEGER NOT NULL DEFAULT 1,
|
||||
`prize_type` VARCHAR(20) NOT NULL DEFAULT 'badge',
|
||||
`badge_code` VARCHAR(50) NULL,
|
||||
`credits` INTEGER NOT NULL DEFAULT 0,
|
||||
`pixels` INTEGER NOT NULL DEFAULT 0,
|
||||
`points` INTEGER NOT NULL DEFAULT 0,
|
||||
`item_id` INTEGER NULL,
|
||||
`description` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
INDEX `website_event_prizes_event_id_idx`(`event_id`),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `website_event_prizes_event_id_fkey` FOREIGN KEY (`event_id`) REFERENCES `website_events`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `website_event_winners` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`event_id` INTEGER NOT NULL,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`position` INTEGER NOT NULL DEFAULT 1,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
INDEX `website_event_winners_user_id_idx`(`user_id`),
|
||||
UNIQUE INDEX `website_event_winners_event_id_user_id_key`(`event_id`, `user_id`),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `website_event_winners_event_id_fkey` FOREIGN KEY (`event_id`) REFERENCES `website_events`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `website_polls` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`title` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`status` VARCHAR(20) NOT NULL DEFAULT 'draft',
|
||||
`show_results` INTEGER NOT NULL DEFAULT 1,
|
||||
`multiple_choice` INTEGER NOT NULL DEFAULT 0,
|
||||
`starts_at` DATETIME(3) NULL,
|
||||
`ends_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
INDEX `website_polls_status_idx`(`status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `website_poll_questions` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`poll_id` INTEGER NOT NULL,
|
||||
`question` VARCHAR(500) NOT NULL,
|
||||
`type` VARCHAR(20) NOT NULL DEFAULT 'single',
|
||||
`sort_order` INTEGER NOT NULL DEFAULT 0,
|
||||
`options` TEXT NOT NULL,
|
||||
INDEX `website_poll_questions_poll_id_idx`(`poll_id`),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `website_poll_questions_poll_id_fkey` FOREIGN KEY (`poll_id`) REFERENCES `website_polls`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `website_poll_votes` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`question_id` INTEGER NOT NULL,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`answer` VARCHAR(500) NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
INDEX `website_poll_votes_user_id_idx`(`user_id`),
|
||||
UNIQUE INDEX `website_poll_votes_question_id_user_id_key`(`question_id`, `user_id`),
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `website_poll_votes_question_id_fkey` FOREIGN KEY (`question_id`) REFERENCES `website_poll_questions`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `website_banners` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`title` VARCHAR(255) NOT NULL DEFAULT '', `subtitle` VARCHAR(500) NOT NULL DEFAULT '',
|
||||
`image` VARCHAR(500) NOT NULL DEFAULT '', `link` VARCHAR(500) NOT NULL DEFAULT '',
|
||||
`color` VARCHAR(20) NOT NULL DEFAULT '', `is_active` INT NOT NULL DEFAULT 1,
|
||||
`sort_order` INT NOT NULL DEFAULT 0, `start_date` VARCHAR(50) NULL, `end_date` VARCHAR(50) NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `custom_prefixes` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT, `user_id` INT NOT NULL, `text` VARCHAR(50) NOT NULL,
|
||||
`color` VARCHAR(255) NOT NULL DEFAULT '#FFFFFF', `icon` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`effect` VARCHAR(50) NOT NULL DEFAULT '', `active` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`), INDEX `idx_custom_prefix_user` (`user_id`, `active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
CREATE TABLE IF NOT EXISTS `custom_prefix_blacklist` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT, `word` VARCHAR(100) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uq_prefix_word` (`word`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
CREATE TABLE IF NOT EXISTS `custom_prefix_settings` (
|
||||
`key` VARCHAR(100) NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY (`key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
@@ -2606,3 +2606,153 @@ model RadioAutoDjPlaylist {
|
||||
|
||||
@@map("radio_auto_dj_playlist")
|
||||
}
|
||||
|
||||
model WebsiteBanner {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @default("")
|
||||
subtitle String @default("")
|
||||
image String @default("") @db.VarChar(500)
|
||||
link String @default("") @db.VarChar(500)
|
||||
color String @default("") @db.VarChar(20)
|
||||
isActive Int @default(1) @map("is_active")
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
startDate String? @map("start_date") @db.VarChar(50)
|
||||
endDate String? @map("end_date") @db.VarChar(50)
|
||||
|
||||
@@map("website_banners")
|
||||
}
|
||||
|
||||
model WebsiteEventType {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(100)
|
||||
slug String @unique @db.VarChar(100)
|
||||
description String @default("") @db.VarChar(500)
|
||||
color String @default("#3b82f6") @db.VarChar(20)
|
||||
icon String @default("calendar") @db.VarChar(50)
|
||||
isActive Int @default(1) @map("is_active")
|
||||
minRank Int @default(0) @map("min_rank")
|
||||
events WebsiteEvent[]
|
||||
|
||||
@@map("website_event_types")
|
||||
}
|
||||
|
||||
model WebsiteEvent {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @db.VarChar(255)
|
||||
description String @db.Text
|
||||
typeId Int @map("type_id")
|
||||
hostUserId Int @map("host_user_id")
|
||||
roomId Int? @map("room_id")
|
||||
startsAt DateTime @map("starts_at")
|
||||
endsAt DateTime? @map("ends_at")
|
||||
maxPlayers Int? @map("max_players")
|
||||
isRecurring Int @default(0) @map("is_recurring")
|
||||
recurrenceRule String? @map("recurrence_rule") @db.VarChar(255)
|
||||
status String @default("draft") @db.VarChar(20)
|
||||
image String? @db.VarChar(500)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
type WebsiteEventType @relation(fields: [typeId], references: [id])
|
||||
registrations WebsiteEventRegistration[]
|
||||
prizes WebsiteEventPrize[]
|
||||
winners WebsiteEventWinner[]
|
||||
|
||||
@@index([typeId])
|
||||
@@index([hostUserId])
|
||||
@@index([startsAt])
|
||||
@@index([status])
|
||||
@@map("website_events")
|
||||
}
|
||||
|
||||
model WebsiteEventRegistration {
|
||||
id Int @id @default(autoincrement())
|
||||
eventId Int @map("event_id")
|
||||
userId Int @map("user_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
event WebsiteEvent @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([eventId, userId])
|
||||
@@index([userId])
|
||||
@@map("website_event_registrations")
|
||||
}
|
||||
|
||||
model WebsiteEventPrize {
|
||||
id Int @id @default(autoincrement())
|
||||
eventId Int @map("event_id")
|
||||
position Int @default(1)
|
||||
prizeType String @default("badge") @map("prize_type") @db.VarChar(20)
|
||||
badgeCode String? @map("badge_code") @db.VarChar(50)
|
||||
credits Int @default(0)
|
||||
pixels Int @default(0)
|
||||
points Int @default(0)
|
||||
itemId Int? @map("item_id")
|
||||
description String @default("") @db.VarChar(255)
|
||||
|
||||
event WebsiteEvent @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([eventId])
|
||||
@@map("website_event_prizes")
|
||||
}
|
||||
|
||||
model WebsiteEventWinner {
|
||||
id Int @id @default(autoincrement())
|
||||
eventId Int @map("event_id")
|
||||
userId Int @map("user_id")
|
||||
position Int @default(1)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
event WebsiteEvent @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([eventId, userId])
|
||||
@@index([userId])
|
||||
@@map("website_event_winners")
|
||||
}
|
||||
|
||||
model WebsitePoll {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @db.VarChar(255)
|
||||
description String? @db.Text
|
||||
status String @default("draft") @db.VarChar(20)
|
||||
showResults Int @default(1) @map("show_results")
|
||||
multipleChoice Int @default(0) @map("multiple_choice")
|
||||
startsAt DateTime? @map("starts_at")
|
||||
endsAt DateTime? @map("ends_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
questions WebsitePollQuestion[]
|
||||
|
||||
@@index([status])
|
||||
@@map("website_polls")
|
||||
}
|
||||
|
||||
model WebsitePollQuestion {
|
||||
id Int @id @default(autoincrement())
|
||||
pollId Int @map("poll_id")
|
||||
question String @db.VarChar(500)
|
||||
type String @default("single") @db.VarChar(20)
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
options String @db.Text
|
||||
|
||||
poll WebsitePoll @relation(fields: [pollId], references: [id], onDelete: Cascade)
|
||||
votes WebsitePollVote[]
|
||||
|
||||
@@index([pollId])
|
||||
@@map("website_poll_questions")
|
||||
}
|
||||
|
||||
model WebsitePollVote {
|
||||
id Int @id @default(autoincrement())
|
||||
questionId Int @map("question_id")
|
||||
userId Int @map("user_id")
|
||||
answer String @db.VarChar(500)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
question WebsitePollQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([questionId, userId])
|
||||
@@index([userId])
|
||||
@@map("website_poll_votes")
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const tables = [
|
||||
"website_event_types", "website_events", "website_event_registrations",
|
||||
"website_event_prizes", "website_event_winners", "website_polls",
|
||||
"website_poll_questions", "website_poll_votes", "website_banners",
|
||||
"custom_prefixes", "custom_prefix_blacklist", "custom_prefix_settings",
|
||||
];
|
||||
|
||||
describe("admin content module port", () => {
|
||||
it("owns every required table through schema and migration contracts", () => {
|
||||
const schema = readFileSync(resolve("prisma/schema.prisma"), "utf8");
|
||||
const migration = readFileSync(resolve("prisma/migrations/0013_admin_events_polls_banners_prefixes.sql"), "utf8");
|
||||
for (const table of tables) {
|
||||
expect(migration).toContain(`CREATE TABLE IF NOT EXISTS \`${table}\``);
|
||||
if (!table.startsWith("custom_prefix")) expect(schema).toContain(`@@map("${table}")`);
|
||||
}
|
||||
});
|
||||
|
||||
it("provides locale-free routes and matching server actions", () => {
|
||||
for (const module of ["events", "polls", "banners", "prefixes"]) {
|
||||
expect(existsSync(resolve(`src/app/admin/${module}/page.tsx`))).toBe(true);
|
||||
expect(existsSync(resolve(`src/actions/${module}.ts`))).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user