mirror of
https://github.com/Hessenuk/DiscordTickets.git
synced 2024-11-17 09:23:07 +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
|
# directories
|
||||||
node_modules/
|
|
||||||
dist/
|
dist/
|
||||||
|
node_modules/
|
||||||
|
prisma/
|
||||||
|
|
||||||
# files
|
# files
|
||||||
.env*
|
.env
|
||||||
version
|
*.db
|
||||||
user/config.yml
|
|
||||||
user/database.sqlite
|
|
||||||
*.log
|
*.log
|
||||||
*.lock
|
*.lock
|
||||||
*-lock.*
|
*-lock.*
|
||||||
|
user/config.yml
|
@ -1,8 +1,12 @@
|
|||||||
DISCORD_SECRET=
|
DISCORD_SECRET=
|
||||||
DISCORD_TOKEN=
|
DISCORD_TOKEN=
|
||||||
DB_CONNECTION_URL="mysql://test:password@localhost/tickets0"
|
DB_CONNECTION_URL="mysql://test:password@localhost/tickets0"
|
||||||
|
DB_PROVIDER=mysql
|
||||||
ENCRYPTION_KEY=
|
ENCRYPTION_KEY=
|
||||||
HTTP_BIND=8080
|
HTTP_BIND=8080
|
||||||
HTTP_EXTERNAL=http://localhost:8080
|
HTTP_EXTERNAL=http://localhost:8080
|
||||||
PORTAL=http://localhost:3000
|
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",
|
"contributors:generate": "all-contributors generate",
|
||||||
"keygen": "node scripts/keygen",
|
"keygen": "node scripts/keygen",
|
||||||
"lint": "eslint src scripts --ext mjs --fix",
|
"lint": "eslint src scripts --ext mjs --fix",
|
||||||
"start": "node .",
|
"prisma": "node scripts/prisma",
|
||||||
|
"start": "npm run prisma && node .",
|
||||||
"studio": "npx prisma studio",
|
"studio": "npx prisma studio",
|
||||||
"test": "echo \"There's nothing to test\" && exit 1"
|
"test": "echo \"There's nothing to test\" && exit 1"
|
||||||
},
|
},
|
||||||
@ -45,6 +46,7 @@
|
|||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"fastify": "^4.2.1",
|
"fastify": "^4.2.1",
|
||||||
"figlet": "^1.5.2",
|
"figlet": "^1.5.2",
|
||||||
|
"fs-extra": "^10.1.0",
|
||||||
"keyv": "^4.3.3",
|
"keyv": "^4.3.3",
|
||||||
"leeks.js": "^0.2.4",
|
"leeks.js": "^0.2.4",
|
||||||
"leekslazylogger": "^4.1.7",
|
"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 fs = require('fs');
|
||||||
const { join } = require('path');
|
const { join } = require('path');
|
||||||
const YAML = require('yaml');
|
const YAML = require('yaml');
|
||||||
|
const encryptionMiddleware = require('./lib/middleware/prisma-encryption');
|
||||||
|
const typesMiddleware = require('./lib/middleware/prisma-types');
|
||||||
|
|
||||||
module.exports = class Client extends FrameworkClient {
|
module.exports = class Client extends FrameworkClient {
|
||||||
constructor(config, log) {
|
constructor(config, log) {
|
||||||
@ -36,6 +38,8 @@ module.exports = class Client extends FrameworkClient {
|
|||||||
async login(token) {
|
async login(token) {
|
||||||
/** @type {PrismaClient} */
|
/** @type {PrismaClient} */
|
||||||
this.prisma = new PrismaClient();
|
this.prisma = new PrismaClient();
|
||||||
|
this.prisma.$use(encryptionMiddleware);
|
||||||
|
this.prisma.$use(typesMiddleware);
|
||||||
this.keyv = new Keyv();
|
this.keyv = new Keyv();
|
||||||
return super.login(token);
|
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: {
|
data: {
|
||||||
guild: { connect: { id: guild.id } },
|
guild: { connect: { id: guild.id } },
|
||||||
...data,
|
...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