mirror of
https://github.com/Hessenuk/DiscordTickets.git
synced 2024-12-22 15:53:08 +02:00
Add support for SQLite and PostgreSQL. Also add/fix encryption...
...for a smaller number of fields
This commit is contained in:
parent
08e757febf
commit
3de9cd8c3a
12
.gitignore
vendored
12
.gitignore
vendored
@ -1,12 +1,12 @@
|
||||
# directories
|
||||
node_modules/
|
||||
dist/
|
||||
node_modules/
|
||||
prisma/
|
||||
|
||||
# files
|
||||
.env*
|
||||
version
|
||||
user/config.yml
|
||||
user/database.sqlite
|
||||
.env
|
||||
*.db
|
||||
*.log
|
||||
*.lock
|
||||
*-lock.*
|
||||
*-lock.*
|
||||
user/config.yml
|
@ -1,8 +1,12 @@
|
||||
DISCORD_SECRET=
|
||||
DISCORD_TOKEN=
|
||||
DB_CONNECTION_URL="mysql://test:password@localhost/tickets0"
|
||||
DB_PROVIDER=mysql
|
||||
ENCRYPTION_KEY=
|
||||
HTTP_BIND=8080
|
||||
HTTP_EXTERNAL=http://localhost:8080
|
||||
PORTAL=http://localhost:3000
|
||||
SUPER=
|
||||
SUPER=
|
||||
|
||||
|
||||
https://www.prisma.io/docs/reference/database-reference/supported-databases
|
248
db/mysql/schema.prisma
Normal file
248
db/mysql/schema.prisma
Normal file
@ -0,0 +1,248 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "mysql"
|
||||
url = env("DB_CONNECTION_URL")
|
||||
}
|
||||
|
||||
model ArchivedChannel {
|
||||
channelId String @db.VarChar(19)
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
|
||||
@@id([ticketId, channelId])
|
||||
@@unique([ticketId, channelId])
|
||||
@@map("archivedChannels")
|
||||
}
|
||||
|
||||
model ArchivedMessage {
|
||||
author ArchivedUser @relation(fields: [ticketId, authorId], references: [ticketId, userId], onDelete: Cascade)
|
||||
authorId String @db.VarChar(19)
|
||||
content String @db.Text
|
||||
createdAt DateTime @default(now())
|
||||
deleted Boolean @default(false)
|
||||
edited Boolean @default(false)
|
||||
id String @id @db.VarChar(19)
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
|
||||
@@map("archivedMessages")
|
||||
}
|
||||
|
||||
model ArchivedRole {
|
||||
archivedUsers ArchivedUser[]
|
||||
colour String @default("7289DA") @db.Char(6)
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
roleId String @db.VarChar(19)
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
|
||||
@@id([ticketId, roleId])
|
||||
@@unique([ticketId, roleId])
|
||||
@@map("archivedRoles")
|
||||
}
|
||||
|
||||
model ArchivedUser {
|
||||
archivedMessages ArchivedMessage[]
|
||||
avatar String
|
||||
bot Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
discriminator String @db.Char(4)
|
||||
displayName String @db.Text
|
||||
role ArchivedRole @relation(fields: [ticketId, roleId], references: [ticketId, roleId], onDelete: Cascade)
|
||||
roleId String @db.VarChar(19)
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
userId String @db.VarChar(19)
|
||||
username String @db.Text
|
||||
|
||||
@@id([ticketId, userId])
|
||||
@@unique([ticketId, userId])
|
||||
@@map("archivedUsers")
|
||||
}
|
||||
|
||||
model Category {
|
||||
channelName String
|
||||
claiming Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
cooldown Int?
|
||||
customTopic String?
|
||||
description String
|
||||
discordCategory String @db.VarChar(19)
|
||||
emoji String
|
||||
enableFeedback Boolean @default(false)
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String @db.VarChar(19)
|
||||
id Int @id @default(autoincrement())
|
||||
image String?
|
||||
memberLimit Int @default(1)
|
||||
name String
|
||||
openingMessage String @db.Text
|
||||
pingRoles Json @default("[]")
|
||||
questions Question[]
|
||||
ratelimit Int?
|
||||
requiredRoles Json @default("[]")
|
||||
requireTopic Boolean @default(false)
|
||||
staffRoles Json
|
||||
tickets Ticket[]
|
||||
totalLimit Int @default(-1)
|
||||
|
||||
@@map("categories")
|
||||
}
|
||||
|
||||
model Feedback {
|
||||
comment String? @db.Text
|
||||
createdAt DateTime @default(now())
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String @db.VarChar(19)
|
||||
id Int @id @default(autoincrement())
|
||||
rating Int
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id])
|
||||
ticketId String @unique @db.VarChar(19)
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
userId String? @db.VarChar(19)
|
||||
|
||||
@@map("feedback")
|
||||
}
|
||||
|
||||
model Guild {
|
||||
autoClose Int?
|
||||
autoTag Json @default("[]")
|
||||
archive Boolean @default(true)
|
||||
blocklist Json @default("[]")
|
||||
categories Category[]
|
||||
claimButton Boolean @default(false)
|
||||
closeButton Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
errorColour String @default("Red")
|
||||
feedback Feedback[]
|
||||
footer String? @default("Discord Tickets by eartharoid")
|
||||
id String @id @db.VarChar(19)
|
||||
locale String @default("en-GB")
|
||||
logChannel String? @db.VarChar(19)
|
||||
primaryColour String @default("#009999")
|
||||
staleAfter Int?
|
||||
successColour String @default("Green")
|
||||
tags Tag[]
|
||||
tickets Ticket[]
|
||||
workingHours Json @default("[\"UTC\", [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"]]")
|
||||
|
||||
@@map("guilds")
|
||||
}
|
||||
|
||||
model Question {
|
||||
answers QuestionAnswer[]
|
||||
createdAt DateTime @default(now())
|
||||
id String @id @default(uuid())
|
||||
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
|
||||
categoryId Int
|
||||
label String @db.VarChar(45)
|
||||
maxLength Int? @default(4000)
|
||||
minLength Int? @default(0)
|
||||
options Json @default("[]")
|
||||
order Int
|
||||
placeholder String? @db.VarChar(100)
|
||||
required Boolean @default(true)
|
||||
style Int @default(2)
|
||||
type QuestionType @default(TEXT)
|
||||
value String? @db.Text
|
||||
|
||||
@@map("questions")
|
||||
}
|
||||
|
||||
model QuestionAnswer {
|
||||
createdAt DateTime @default(now())
|
||||
id Int @id @default(autoincrement())
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
question Question @relation(fields: [questionId], references: [id], onDelete: Cascade)
|
||||
questionId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String @db.VarChar(19)
|
||||
value String? @db.Text
|
||||
|
||||
@@map("questionAnswers")
|
||||
}
|
||||
|
||||
model Tag {
|
||||
content String @db.Text
|
||||
createdAt DateTime @default(now())
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String @db.VarChar(19)
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
regex String?
|
||||
|
||||
@@unique([guildId, name])
|
||||
@@map("tags")
|
||||
}
|
||||
|
||||
model Ticket {
|
||||
archivedChannels ArchivedChannel[]
|
||||
archivedMessages ArchivedMessage[]
|
||||
archivedRoles ArchivedRole[]
|
||||
archivedUsers ArchivedUser[]
|
||||
category Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
|
||||
categoryId Int?
|
||||
claimedBy User @relation(name: "TicketsClaimedByUser", fields: [claimedById], references: [id])
|
||||
claimedById String @db.VarChar(19)
|
||||
closedAt DateTime?
|
||||
closedBy User @relation(name: "TicketsClosedByUser", fields: [closedById], references: [id])
|
||||
closedById String @db.VarChar(19)
|
||||
closedReason String?
|
||||
createdAt DateTime @default(now())
|
||||
createdBy User @relation(name: "TicketsCreatedByUser", fields: [createdById], references: [id])
|
||||
createdById String @db.VarChar(19)
|
||||
feedback Feedback?
|
||||
feedbackId Int?
|
||||
firstResponseAt DateTime?
|
||||
deleted Boolean @default(false)
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String @db.VarChar(19)
|
||||
id String @id @db.VarChar(19)
|
||||
lastMessageAt DateTime?
|
||||
messageCount Int?
|
||||
number Int
|
||||
open Boolean @default(true)
|
||||
openingMessage String @db.VarChar(19)
|
||||
pinnedMessages Json @default("[]")
|
||||
priority TicketPriority?
|
||||
referencedBy Ticket[] @relation("TicketsReferencedByTicket")
|
||||
referencesMessageId String @db.VarChar(19)
|
||||
referencesTicket Ticket? @relation(name: "TicketsReferencedByTicket", fields: [referencesTicketId], references: [id], onDelete: SetNull)
|
||||
referencesTicketId String? @db.VarChar(19)
|
||||
topic String?
|
||||
questionAnswers QuestionAnswer[]
|
||||
|
||||
@@unique([guildId, number])
|
||||
@@map("tickets")
|
||||
}
|
||||
|
||||
model User {
|
||||
createdAt DateTime @default(now())
|
||||
feedback Feedback[]
|
||||
id String @id @db.VarChar(19)
|
||||
messageCount Int @default(0)
|
||||
ticketsCreated Ticket[] @relation("TicketsCreatedByUser")
|
||||
ticketsClosed Ticket[] @relation("TicketsClosedByUser")
|
||||
ticketsClaimed Ticket[] @relation("TicketsClaimedByUser")
|
||||
questionAnswers QuestionAnswer[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
enum TicketPriority {
|
||||
LOW
|
||||
MEDIUM
|
||||
HIGH
|
||||
}
|
||||
|
||||
enum QuestionType {
|
||||
MENU
|
||||
TEXT
|
||||
}
|
248
db/postgresql/schema.prisma
Normal file
248
db/postgresql/schema.prisma
Normal file
@ -0,0 +1,248 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DB_CONNECTION_URL")
|
||||
}
|
||||
|
||||
model ArchivedChannel {
|
||||
channelId String @db.VarChar(19)
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
|
||||
@@id([ticketId, channelId])
|
||||
@@unique([ticketId, channelId])
|
||||
@@map("archivedChannels")
|
||||
}
|
||||
|
||||
model ArchivedMessage {
|
||||
author ArchivedUser @relation(fields: [ticketId, authorId], references: [ticketId, userId], onDelete: Cascade)
|
||||
authorId String @db.VarChar(19)
|
||||
content String @db.Text
|
||||
createdAt DateTime @default(now())
|
||||
deleted Boolean @default(false)
|
||||
edited Boolean @default(false)
|
||||
id String @id @db.VarChar(19)
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
|
||||
@@map("archivedMessages")
|
||||
}
|
||||
|
||||
model ArchivedRole {
|
||||
archivedUsers ArchivedUser[]
|
||||
colour String @default("7289DA") @db.Char(6)
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
roleId String @db.VarChar(19)
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
|
||||
@@id([ticketId, roleId])
|
||||
@@unique([ticketId, roleId])
|
||||
@@map("archivedRoles")
|
||||
}
|
||||
|
||||
model ArchivedUser {
|
||||
archivedMessages ArchivedMessage[]
|
||||
avatar String
|
||||
bot Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
discriminator String @db.Char(4)
|
||||
displayName String @db.Text
|
||||
role ArchivedRole @relation(fields: [ticketId, roleId], references: [ticketId, roleId], onDelete: Cascade)
|
||||
roleId String @db.VarChar(19)
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
userId String @db.VarChar(19)
|
||||
username String @db.Text
|
||||
|
||||
@@id([ticketId, userId])
|
||||
@@unique([ticketId, userId])
|
||||
@@map("archivedUsers")
|
||||
}
|
||||
|
||||
model Category {
|
||||
channelName String
|
||||
claiming Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
cooldown Int?
|
||||
customTopic String?
|
||||
description String
|
||||
discordCategory String @db.VarChar(19)
|
||||
emoji String
|
||||
enableFeedback Boolean @default(false)
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String @db.VarChar(19)
|
||||
id Int @id @default(autoincrement())
|
||||
image String?
|
||||
memberLimit Int @default(1)
|
||||
name String
|
||||
openingMessage String @db.Text
|
||||
pingRoles Json @default("[]")
|
||||
questions Question[]
|
||||
ratelimit Int?
|
||||
requiredRoles Json @default("[]")
|
||||
requireTopic Boolean @default(false)
|
||||
staffRoles Json
|
||||
tickets Ticket[]
|
||||
totalLimit Int @default(-1)
|
||||
|
||||
@@map("categories")
|
||||
}
|
||||
|
||||
model Feedback {
|
||||
comment String? @db.Text
|
||||
createdAt DateTime @default(now())
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String @db.VarChar(19)
|
||||
id Int @id @default(autoincrement())
|
||||
rating Int
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id])
|
||||
ticketId String @unique @db.VarChar(19)
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
userId String? @db.VarChar(19)
|
||||
|
||||
@@map("feedback")
|
||||
}
|
||||
|
||||
model Guild {
|
||||
autoClose Int?
|
||||
autoTag Json @default("[]")
|
||||
archive Boolean @default(true)
|
||||
blocklist Json @default("[]")
|
||||
categories Category[]
|
||||
claimButton Boolean @default(false)
|
||||
closeButton Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
errorColour String @default("Red")
|
||||
feedback Feedback[]
|
||||
footer String? @default("Discord Tickets by eartharoid")
|
||||
id String @id @db.VarChar(19)
|
||||
locale String @default("en-GB")
|
||||
logChannel String? @db.VarChar(19)
|
||||
primaryColour String @default("#009999")
|
||||
staleAfter Int?
|
||||
successColour String @default("Green")
|
||||
tags Tag[]
|
||||
tickets Ticket[]
|
||||
workingHours Json @default("[\"UTC\", [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"]]")
|
||||
|
||||
@@map("guilds")
|
||||
}
|
||||
|
||||
model Question {
|
||||
answers QuestionAnswer[]
|
||||
createdAt DateTime @default(now())
|
||||
id String @id @default(uuid())
|
||||
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
|
||||
categoryId Int
|
||||
label String @db.VarChar(45)
|
||||
maxLength Int? @default(4000)
|
||||
minLength Int? @default(0)
|
||||
options Json @default("[]")
|
||||
order Int
|
||||
placeholder String? @db.VarChar(100)
|
||||
required Boolean @default(true)
|
||||
style Int @default(2)
|
||||
type QuestionType @default(TEXT)
|
||||
value String? @db.Text
|
||||
|
||||
@@map("questions")
|
||||
}
|
||||
|
||||
model QuestionAnswer {
|
||||
createdAt DateTime @default(now())
|
||||
id Int @id @default(autoincrement())
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String @db.VarChar(19)
|
||||
question Question @relation(fields: [questionId], references: [id], onDelete: Cascade)
|
||||
questionId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String @db.VarChar(19)
|
||||
value String? @db.Text
|
||||
|
||||
@@map("questionAnswers")
|
||||
}
|
||||
|
||||
model Tag {
|
||||
content String @db.Text
|
||||
createdAt DateTime @default(now())
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String @db.VarChar(19)
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
regex String?
|
||||
|
||||
@@unique([guildId, name])
|
||||
@@map("tags")
|
||||
}
|
||||
|
||||
model Ticket {
|
||||
archivedChannels ArchivedChannel[]
|
||||
archivedMessages ArchivedMessage[]
|
||||
archivedRoles ArchivedRole[]
|
||||
archivedUsers ArchivedUser[]
|
||||
category Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
|
||||
categoryId Int?
|
||||
claimedBy User @relation(name: "TicketsClaimedByUser", fields: [claimedById], references: [id])
|
||||
claimedById String @db.VarChar(19)
|
||||
closedAt DateTime?
|
||||
closedBy User @relation(name: "TicketsClosedByUser", fields: [closedById], references: [id])
|
||||
closedById String @db.VarChar(19)
|
||||
closedReason String?
|
||||
createdAt DateTime @default(now())
|
||||
createdBy User @relation(name: "TicketsCreatedByUser", fields: [createdById], references: [id])
|
||||
createdById String @db.VarChar(19)
|
||||
feedback Feedback?
|
||||
feedbackId Int?
|
||||
firstResponseAt DateTime?
|
||||
deleted Boolean @default(false)
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String @db.VarChar(19)
|
||||
id String @id @db.VarChar(19)
|
||||
lastMessageAt DateTime?
|
||||
messageCount Int?
|
||||
number Int
|
||||
open Boolean @default(true)
|
||||
openingMessage String @db.VarChar(19)
|
||||
pinnedMessages Json @default("[]")
|
||||
priority TicketPriority?
|
||||
referencedBy Ticket[] @relation("TicketsReferencedByTicket")
|
||||
referencesMessageId String @db.VarChar(19)
|
||||
referencesTicket Ticket? @relation(name: "TicketsReferencedByTicket", fields: [referencesTicketId], references: [id], onDelete: SetNull)
|
||||
referencesTicketId String? @db.VarChar(19)
|
||||
topic String?
|
||||
questionAnswers QuestionAnswer[]
|
||||
|
||||
@@unique([guildId, number])
|
||||
@@map("tickets")
|
||||
}
|
||||
|
||||
model User {
|
||||
createdAt DateTime @default(now())
|
||||
feedback Feedback[]
|
||||
id String @id @db.VarChar(19)
|
||||
messageCount Int @default(0)
|
||||
ticketsCreated Ticket[] @relation("TicketsCreatedByUser")
|
||||
ticketsClosed Ticket[] @relation("TicketsClosedByUser")
|
||||
ticketsClaimed Ticket[] @relation("TicketsClaimedByUser")
|
||||
questionAnswers QuestionAnswer[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
enum TicketPriority {
|
||||
LOW
|
||||
MEDIUM
|
||||
HIGH
|
||||
}
|
||||
|
||||
enum QuestionType {
|
||||
MENU
|
||||
TEXT
|
||||
}
|
237
db/sqlite/schema.prisma
Normal file
237
db/sqlite/schema.prisma
Normal file
@ -0,0 +1,237 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = env("DB_CONNECTION_URL")
|
||||
}
|
||||
|
||||
model ArchivedChannel {
|
||||
channelId String
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String
|
||||
|
||||
@@id([ticketId, channelId])
|
||||
@@unique([ticketId, channelId])
|
||||
@@map("archivedChannels")
|
||||
}
|
||||
|
||||
model ArchivedMessage {
|
||||
author ArchivedUser @relation(fields: [ticketId, authorId], references: [ticketId, userId], onDelete: Cascade)
|
||||
authorId String
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
deleted Boolean @default(false)
|
||||
edited Boolean @default(false)
|
||||
id String @id
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String
|
||||
|
||||
@@map("archivedMessages")
|
||||
}
|
||||
|
||||
model ArchivedRole {
|
||||
archivedUsers ArchivedUser[]
|
||||
colour String @default("7289DA")
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
roleId String
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String
|
||||
|
||||
@@id([ticketId, roleId])
|
||||
@@unique([ticketId, roleId])
|
||||
@@map("archivedRoles")
|
||||
}
|
||||
|
||||
model ArchivedUser {
|
||||
archivedMessages ArchivedMessage[]
|
||||
avatar String
|
||||
bot Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
discriminator String
|
||||
displayName String
|
||||
role ArchivedRole @relation(fields: [ticketId, roleId], references: [ticketId, roleId], onDelete: Cascade)
|
||||
roleId String
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String
|
||||
userId String
|
||||
username String
|
||||
|
||||
@@id([ticketId, userId])
|
||||
@@unique([ticketId, userId])
|
||||
@@map("archivedUsers")
|
||||
}
|
||||
|
||||
model Category {
|
||||
channelName String
|
||||
claiming Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
cooldown Int?
|
||||
customTopic String?
|
||||
description String
|
||||
discordCategory String
|
||||
emoji String
|
||||
enableFeedback Boolean @default(false)
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String
|
||||
id Int @id @default(autoincrement())
|
||||
image String?
|
||||
memberLimit Int @default(1)
|
||||
name String
|
||||
openingMessage String
|
||||
pingRoles String @default("[]")
|
||||
questions Question[]
|
||||
ratelimit Int?
|
||||
requiredRoles String @default("[]")
|
||||
requireTopic Boolean @default(false)
|
||||
staffRoles String
|
||||
tickets Ticket[]
|
||||
totalLimit Int @default(-1)
|
||||
|
||||
@@map("categories")
|
||||
}
|
||||
|
||||
model Feedback {
|
||||
comment String?
|
||||
createdAt DateTime @default(now())
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String
|
||||
id Int @id @default(autoincrement())
|
||||
rating Int
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id])
|
||||
ticketId String @unique
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
userId String?
|
||||
|
||||
@@map("feedback")
|
||||
}
|
||||
|
||||
model Guild {
|
||||
autoClose Int?
|
||||
autoTag String @default("[]")
|
||||
archive Boolean @default(true)
|
||||
blocklist String @default("[]")
|
||||
categories Category[]
|
||||
claimButton Boolean @default(false)
|
||||
closeButton Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
errorColour String @default("Red")
|
||||
feedback Feedback[]
|
||||
footer String? @default("Discord Tickets by eartharoid")
|
||||
id String @id
|
||||
locale String @default("en-GB")
|
||||
logChannel String?
|
||||
primaryColour String @default("#009999")
|
||||
staleAfter Int?
|
||||
successColour String @default("Green")
|
||||
tags Tag[]
|
||||
tickets Ticket[]
|
||||
workingHours String @default("[\"UTC\", [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"], [\"00:00\",\"23:59\"]]")
|
||||
|
||||
@@map("guilds")
|
||||
}
|
||||
|
||||
model Question {
|
||||
answers QuestionAnswer[]
|
||||
createdAt DateTime @default(now())
|
||||
id String @id @default(uuid())
|
||||
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
|
||||
categoryId Int
|
||||
label String
|
||||
maxLength Int? @default(4000)
|
||||
minLength Int? @default(0)
|
||||
options String @default("[]")
|
||||
order Int
|
||||
placeholder String?
|
||||
required Boolean @default(true)
|
||||
style Int @default(2)
|
||||
type String @default("TEXT")
|
||||
value String?
|
||||
|
||||
@@map("questions")
|
||||
}
|
||||
|
||||
model QuestionAnswer {
|
||||
createdAt DateTime @default(now())
|
||||
id Int @id @default(autoincrement())
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
ticketId String
|
||||
question Question @relation(fields: [questionId], references: [id], onDelete: Cascade)
|
||||
questionId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
value String?
|
||||
|
||||
@@map("questionAnswers")
|
||||
}
|
||||
|
||||
model Tag {
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
regex String?
|
||||
|
||||
@@unique([guildId, name])
|
||||
@@map("tags")
|
||||
}
|
||||
|
||||
model Ticket {
|
||||
archivedChannels ArchivedChannel[]
|
||||
archivedMessages ArchivedMessage[]
|
||||
archivedRoles ArchivedRole[]
|
||||
archivedUsers ArchivedUser[]
|
||||
category Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
|
||||
categoryId Int?
|
||||
claimedBy User @relation(name: "TicketsClaimedByUser", fields: [claimedById], references: [id])
|
||||
claimedById String
|
||||
closedAt DateTime?
|
||||
closedBy User @relation(name: "TicketsClosedByUser", fields: [closedById], references: [id])
|
||||
closedById String
|
||||
closedReason String?
|
||||
createdAt DateTime @default(now())
|
||||
createdBy User @relation(name: "TicketsCreatedByUser", fields: [createdById], references: [id])
|
||||
createdById String
|
||||
feedback Feedback?
|
||||
feedbackId Int?
|
||||
firstResponseAt DateTime?
|
||||
deleted Boolean @default(false)
|
||||
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade)
|
||||
guildId String
|
||||
id String @id
|
||||
lastMessageAt DateTime?
|
||||
messageCount Int?
|
||||
number Int
|
||||
open Boolean @default(true)
|
||||
openingMessage String
|
||||
pinnedMessages String @default("[]")
|
||||
priority String?
|
||||
referencedBy Ticket[] @relation("TicketsReferencedByTicket")
|
||||
referencesMessageId String
|
||||
referencesTicket Ticket? @relation(name: "TicketsReferencedByTicket", fields: [referencesTicketId], references: [id], onDelete: SetNull)
|
||||
referencesTicketId String?
|
||||
topic String?
|
||||
questionAnswers QuestionAnswer[]
|
||||
|
||||
@@unique([guildId, number])
|
||||
@@map("tickets")
|
||||
}
|
||||
|
||||
model User {
|
||||
createdAt DateTime @default(now())
|
||||
feedback Feedback[]
|
||||
id String @id
|
||||
messageCount Int @default(0)
|
||||
ticketsCreated Ticket[] @relation("TicketsCreatedByUser")
|
||||
ticketsClosed Ticket[] @relation("TicketsClosedByUser")
|
||||
ticketsClaimed Ticket[] @relation("TicketsClaimedByUser")
|
||||
questionAnswers QuestionAnswer[]
|
||||
|
||||
@@map("users")
|
||||
}
|
@ -9,7 +9,8 @@
|
||||
"contributors:generate": "all-contributors generate",
|
||||
"keygen": "node scripts/keygen",
|
||||
"lint": "eslint src scripts --ext mjs --fix",
|
||||
"start": "node .",
|
||||
"prisma": "node scripts/prisma",
|
||||
"start": "npm run prisma && node .",
|
||||
"studio": "npx prisma studio",
|
||||
"test": "echo \"There's nothing to test\" && exit 1"
|
||||
},
|
||||
@ -45,6 +46,7 @@
|
||||
"dotenv": "^16.0.1",
|
||||
"fastify": "^4.2.1",
|
||||
"figlet": "^1.5.2",
|
||||
"fs-extra": "^10.1.0",
|
||||
"keyv": "^4.3.3",
|
||||
"leeks.js": "^0.2.4",
|
||||
"leekslazylogger": "^4.1.7",
|
||||
|
22
scripts/prisma.js
Normal file
22
scripts/prisma.js
Normal file
@ -0,0 +1,22 @@
|
||||
require('dotenv').config();
|
||||
const fs = require('fs-extra');
|
||||
// const { promisify } = require('util');
|
||||
// const exec = promisify(require('child_process').exec);
|
||||
const { spawnSync } = require('child_process');
|
||||
|
||||
const providers = ['mysql', 'postgresql', 'sqlite'];
|
||||
const provider = process.env.DB_PROVIDER;
|
||||
if (!providers.includes(provider)) throw new Error(`DB_PROVIDER must be one of: ${providers}`);
|
||||
|
||||
if (!fs.existsSync('./prisma')) fs.mkdirSync('./prisma');
|
||||
fs.copySync(`./db/${provider}`, './prisma'); // copy schema & migrations
|
||||
|
||||
npx('prisma generate');
|
||||
npx('prisma migrate deploy');
|
||||
|
||||
function npx(cmd) {
|
||||
const child = spawnSync('npx', cmd.split(/\s/));
|
||||
if (child.stdout) console.log(child.stdout.toString());
|
||||
if (child.stderr) console.log(child.stderr.toString());
|
||||
if (child.status) process.exit(child.status);
|
||||
}
|
@ -6,6 +6,8 @@ const I18n = require('@eartharoid/i18n');
|
||||
const fs = require('fs');
|
||||
const { join } = require('path');
|
||||
const YAML = require('yaml');
|
||||
const encryptionMiddleware = require('./lib/middleware/prisma-encryption');
|
||||
const typesMiddleware = require('./lib/middleware/prisma-types');
|
||||
|
||||
module.exports = class Client extends FrameworkClient {
|
||||
constructor(config, log) {
|
||||
@ -36,6 +38,8 @@ module.exports = class Client extends FrameworkClient {
|
||||
async login(token) {
|
||||
/** @type {PrismaClient} */
|
||||
this.prisma = new PrismaClient();
|
||||
this.prisma.$use(encryptionMiddleware);
|
||||
this.prisma.$use(typesMiddleware);
|
||||
this.keyv = new Keyv();
|
||||
return super.login(token);
|
||||
}
|
||||
|
49
src/lib/middleware/prisma-encryption.js
Normal file
49
src/lib/middleware/prisma-encryption.js
Normal file
@ -0,0 +1,49 @@
|
||||
const Cryptr = require('cryptr');
|
||||
const cryptr = new Cryptr(process.env.ENCRYPTION_KEY);
|
||||
const encryptedFields = [
|
||||
// 'name',
|
||||
'content',
|
||||
'username',
|
||||
'displayName',
|
||||
// 'channelName',
|
||||
// 'openingMessage',
|
||||
// 'description',
|
||||
'value',
|
||||
// 'placeholder',
|
||||
'closedReason',
|
||||
'topic',
|
||||
'comment',
|
||||
// 'label',
|
||||
// 'regex',
|
||||
];
|
||||
|
||||
const encrypt = obj => {
|
||||
for (const prop in obj) {
|
||||
if (typeof obj[prop] === 'string' && obj[prop].length !== 0 && encryptedFields.includes(prop)) {
|
||||
obj[prop] = cryptr.encrypt(obj[prop]);
|
||||
} else if (typeof obj[prop] === 'object') {
|
||||
obj[prop] = encrypt(obj[prop]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
const decrypt = obj => {
|
||||
for (const prop in obj) {
|
||||
if (typeof obj[prop] === 'string' && obj[prop].length !== 0 && encryptedFields.includes(prop)) {
|
||||
obj[prop] = cryptr.decrypt(obj[prop]);
|
||||
} else if (typeof obj[prop] === 'object') {
|
||||
obj[prop] = decrypt(obj[prop]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
module.exports = async (params, next) => {
|
||||
if (params.args.create) params.args.create = encrypt(params.args.create);
|
||||
if (params.args.data) params.args.data = encrypt(params.args.data);
|
||||
if (params.args.update) params.args.update = encrypt(params.args.update);
|
||||
let result = await next(params);
|
||||
if (result) result = decrypt(result);
|
||||
return result;
|
||||
};
|
35
src/lib/middleware/prisma-types.js
Normal file
35
src/lib/middleware/prisma-types.js
Normal file
@ -0,0 +1,35 @@
|
||||
const jsonFields = [
|
||||
'pingRoles',
|
||||
'requiredRoles',
|
||||
'staffRoles',
|
||||
'autoTag',
|
||||
'blocklist',
|
||||
'workingHours',
|
||||
'options',
|
||||
'pinnedMessages',
|
||||
];
|
||||
|
||||
const traverse = (obj, func) => {
|
||||
for (const prop in obj) {
|
||||
console.log(prop, typeof obj[prop], obj[prop]);
|
||||
if (jsonFields.includes(prop) && obj[prop] !== null && obj[prop] !== undefined) {
|
||||
obj[prop] = func(obj[prop]);
|
||||
} else if (typeof obj[prop] === 'object') {
|
||||
obj[prop] = traverse(obj[prop], func);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
module.exports = async (params, next) => {
|
||||
if (process.env.DB_PROVIDER === 'sqlite') {
|
||||
if (params.args.create) params.args.create = traverse(params.args.create, val => JSON.stringify(val));
|
||||
if (params.args.data) params.args.data = traverse(params.args.data, val => JSON.stringify(val));
|
||||
if (params.args.update) params.args.update = traverse(params.args.update, val => JSON.stringify(val));
|
||||
let result = await next(params);
|
||||
if (result) result = traverse(result, val => JSON.parse(val));
|
||||
return result;
|
||||
} else {
|
||||
return await next(params);
|
||||
}
|
||||
};
|
@ -78,7 +78,8 @@ module.exports.post = fastify => ({
|
||||
data: {
|
||||
guild: { connect: { id: guild.id } },
|
||||
...data,
|
||||
questions: { createMany: { data: data.questions ?? [] } },
|
||||
// questions: { createMany: { data: data.questions ?? [] } },
|
||||
questions: { create: { data: data.questions ?? [] } }, // sqlite doesn't support createMany?
|
||||
},
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user