first commit
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"pubkey" TEXT NOT NULL,
|
||||
"role" TEXT NOT NULL DEFAULT 'USER',
|
||||
"displayName" TEXT,
|
||||
"username" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Meetup" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"date" TEXT NOT NULL,
|
||||
"time" TEXT NOT NULL,
|
||||
"location" TEXT NOT NULL,
|
||||
"link" TEXT,
|
||||
"imageId" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'UPCOMING',
|
||||
"featured" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Media" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"slug" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"mimeType" TEXT NOT NULL,
|
||||
"size" INTEGER NOT NULL,
|
||||
"originalFilename" TEXT NOT NULL,
|
||||
"uploadedBy" TEXT NOT NULL,
|
||||
"title" TEXT,
|
||||
"description" TEXT,
|
||||
"altText" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Post" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"nostrEventId" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"excerpt" TEXT,
|
||||
"authorPubkey" TEXT NOT NULL,
|
||||
"authorName" TEXT,
|
||||
"featured" BOOLEAN NOT NULL DEFAULT false,
|
||||
"visible" BOOLEAN NOT NULL DEFAULT true,
|
||||
"publishedAt" DATETIME NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Category" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PostCategory" (
|
||||
"postId" TEXT NOT NULL,
|
||||
"categoryId" TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY ("postId", "categoryId"),
|
||||
CONSTRAINT "PostCategory_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "PostCategory_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "Category" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "HiddenContent" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"nostrEventId" TEXT NOT NULL,
|
||||
"reason" TEXT,
|
||||
"hiddenBy" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BlockedPubkey" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"pubkey" TEXT NOT NULL,
|
||||
"reason" TEXT,
|
||||
"blockedBy" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Relay" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"url" TEXT NOT NULL,
|
||||
"priority" INTEGER NOT NULL DEFAULT 0,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Setting" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"key" TEXT NOT NULL,
|
||||
"value" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "NostrEventCache" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"eventId" TEXT NOT NULL,
|
||||
"kind" INTEGER NOT NULL,
|
||||
"pubkey" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"tags" TEXT NOT NULL,
|
||||
"createdAt" INTEGER NOT NULL,
|
||||
"cachedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Submission" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"eventId" TEXT,
|
||||
"naddr" TEXT,
|
||||
"title" TEXT NOT NULL,
|
||||
"authorPubkey" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'PENDING',
|
||||
"reviewedBy" TEXT,
|
||||
"reviewNote" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Faq" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"question" TEXT NOT NULL,
|
||||
"answer" TEXT NOT NULL,
|
||||
"order" INTEGER NOT NULL DEFAULT 0,
|
||||
"showOnHomepage" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_pubkey_key" ON "User"("pubkey");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Post_nostrEventId_key" ON "Post"("nostrEventId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Post_slug_key" ON "Post"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Category_slug_key" ON "Category"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Relay_url_key" ON "Relay"("url");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Setting_key_key" ON "Setting"("key");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "NostrEventCache_eventId_key" ON "NostrEventCache"("eventId");
|
||||
@@ -0,0 +1,23 @@
|
||||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Meetup" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"date" TEXT NOT NULL,
|
||||
"time" TEXT NOT NULL,
|
||||
"location" TEXT NOT NULL,
|
||||
"link" TEXT,
|
||||
"imageId" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'UPCOMING',
|
||||
"featured" BOOLEAN NOT NULL DEFAULT false,
|
||||
"visibility" TEXT NOT NULL DEFAULT 'PUBLIC',
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
INSERT INTO "new_Meetup" ("createdAt", "date", "description", "featured", "id", "imageId", "link", "location", "status", "time", "title", "updatedAt") SELECT "createdAt", "date", "description", "featured", "id", "imageId", "link", "location", "status", "time", "title", "updatedAt" FROM "Meetup";
|
||||
DROP TABLE "Meetup";
|
||||
ALTER TABLE "new_Meetup" RENAME TO "Meetup";
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
@@ -0,0 +1,23 @@
|
||||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Meetup" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"date" TEXT NOT NULL,
|
||||
"time" TEXT NOT NULL,
|
||||
"location" TEXT NOT NULL,
|
||||
"link" TEXT,
|
||||
"imageId" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'DRAFT',
|
||||
"featured" BOOLEAN NOT NULL DEFAULT false,
|
||||
"visibility" TEXT NOT NULL DEFAULT 'PUBLIC',
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
INSERT INTO "new_Meetup" ("createdAt", "date", "description", "featured", "id", "imageId", "link", "location", "status", "time", "title", "updatedAt", "visibility") SELECT "createdAt", "date", "description", "featured", "id", "imageId", "link", "location", "status", "time", "title", "updatedAt", "visibility" FROM "Meetup";
|
||||
DROP TABLE "Meetup";
|
||||
ALTER TABLE "new_Meetup" RENAME TO "Meetup";
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
3
backend/prisma/migrations/migration_lock.toml
Normal file
3
backend/prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "sqlite"
|
||||
149
backend/prisma/schema.prisma
Normal file
149
backend/prisma/schema.prisma
Normal file
@@ -0,0 +1,149 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
pubkey String @unique
|
||||
role String @default("USER") // USER, MODERATOR, ADMIN
|
||||
displayName String?
|
||||
username String? @unique
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Meetup {
|
||||
id String @id @default(uuid())
|
||||
title String
|
||||
description String
|
||||
date String
|
||||
time String
|
||||
location String
|
||||
link String?
|
||||
imageId String?
|
||||
status String @default("DRAFT") // DRAFT, PUBLISHED, CANCELLED (Upcoming/Past derived from date)
|
||||
featured Boolean @default(false)
|
||||
visibility String @default("PUBLIC") // PUBLIC, HIDDEN
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Media {
|
||||
id String @id // ULID, not auto-generated
|
||||
slug String
|
||||
type String // "image" | "video"
|
||||
mimeType String
|
||||
size Int
|
||||
originalFilename String
|
||||
uploadedBy String
|
||||
title String?
|
||||
description String?
|
||||
altText String?
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model Post {
|
||||
id String @id @default(uuid())
|
||||
nostrEventId String @unique
|
||||
title String
|
||||
slug String @unique
|
||||
content String
|
||||
excerpt String?
|
||||
authorPubkey String
|
||||
authorName String?
|
||||
featured Boolean @default(false)
|
||||
visible Boolean @default(true)
|
||||
publishedAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
categories PostCategory[]
|
||||
}
|
||||
|
||||
model Category {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
slug String @unique
|
||||
sortOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
posts PostCategory[]
|
||||
}
|
||||
|
||||
model PostCategory {
|
||||
postId String
|
||||
categoryId String
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([postId, categoryId])
|
||||
}
|
||||
|
||||
model HiddenContent {
|
||||
id String @id @default(uuid())
|
||||
nostrEventId String
|
||||
reason String?
|
||||
hiddenBy String
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model BlockedPubkey {
|
||||
id String @id @default(uuid())
|
||||
pubkey String
|
||||
reason String?
|
||||
blockedBy String
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model Relay {
|
||||
id String @id @default(uuid())
|
||||
url String @unique
|
||||
priority Int @default(0)
|
||||
active Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model Setting {
|
||||
id String @id @default(uuid())
|
||||
key String @unique
|
||||
value String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model NostrEventCache {
|
||||
id String @id @default(uuid())
|
||||
eventId String @unique
|
||||
kind Int
|
||||
pubkey String
|
||||
content String
|
||||
tags String // JSON string
|
||||
createdAt Int // event timestamp
|
||||
cachedAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model Submission {
|
||||
id String @id @default(uuid())
|
||||
eventId String?
|
||||
naddr String?
|
||||
title String
|
||||
authorPubkey String
|
||||
status String @default("PENDING") // PENDING, APPROVED, REJECTED
|
||||
reviewedBy String?
|
||||
reviewNote String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Faq {
|
||||
id String @id @default(uuid())
|
||||
question String
|
||||
answer String
|
||||
order Int @default(0)
|
||||
showOnHomepage Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
85
backend/prisma/seed.ts
Normal file
85
backend/prisma/seed.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
const relays = [
|
||||
{ url: 'wss://relay.damus.io', priority: 1 },
|
||||
{ url: 'wss://nos.lol', priority: 2 },
|
||||
{ url: 'wss://relay.nostr.band', priority: 3 },
|
||||
];
|
||||
|
||||
for (const relay of relays) {
|
||||
await prisma.relay.upsert({
|
||||
where: { url: relay.url },
|
||||
update: {},
|
||||
create: relay,
|
||||
});
|
||||
}
|
||||
|
||||
const settings = [
|
||||
{ key: 'site_title', value: 'Belgian Bitcoin Embassy' },
|
||||
{ key: 'site_tagline', value: 'Your gateway to Bitcoin in Belgium' },
|
||||
{ key: 'telegram_link', value: 'https://t.me/belgianbitcoinembassy' },
|
||||
{ key: 'nostr_link', value: '' },
|
||||
{ key: 'x_link', value: '' },
|
||||
{ key: 'youtube_link', value: '' },
|
||||
{ key: 'discord_link', value: '' },
|
||||
{ key: 'linkedin_link', value: '' },
|
||||
];
|
||||
|
||||
for (const setting of settings) {
|
||||
await prisma.setting.upsert({
|
||||
where: { key: setting.key },
|
||||
update: {},
|
||||
create: setting,
|
||||
});
|
||||
}
|
||||
|
||||
const categories = [
|
||||
{ name: 'Bitcoin', slug: 'bitcoin', sortOrder: 1 },
|
||||
{ name: 'Lightning', slug: 'lightning', sortOrder: 2 },
|
||||
{ name: 'Privacy', slug: 'privacy', sortOrder: 3 },
|
||||
{ name: 'Education', slug: 'education', sortOrder: 4 },
|
||||
{ name: 'Community', slug: 'community', sortOrder: 5 },
|
||||
];
|
||||
|
||||
for (const category of categories) {
|
||||
await prisma.category.upsert({
|
||||
where: { slug: category.slug },
|
||||
update: {},
|
||||
create: category,
|
||||
});
|
||||
}
|
||||
|
||||
const existingMeetup = await prisma.meetup.findFirst({
|
||||
where: { title: 'Monthly Bitcoin Meetup' },
|
||||
});
|
||||
|
||||
if (!existingMeetup) {
|
||||
await prisma.meetup.create({
|
||||
data: {
|
||||
title: 'Monthly Bitcoin Meetup',
|
||||
description:
|
||||
'Join us for our monthly Bitcoin meetup! We discuss the latest developments, share knowledge, and connect with fellow Bitcoiners in Belgium.',
|
||||
date: '2025-02-15',
|
||||
time: '19:00',
|
||||
location: 'Brussels, Belgium',
|
||||
link: 'https://meetup.com/example',
|
||||
status: 'UPCOMING',
|
||||
featured: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Seed completed successfully.');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user