Add support for SQLite and PostgreSQL. Also add/fix encryption...

...for a smaller number of fields
This commit is contained in:
Isaac 2022-07-23 01:44:03 +01:00
parent 08e757febf
commit 3de9cd8c3a
No known key found for this signature in database
GPG Key ID: F4EAABEB0FFCC06A
11 changed files with 859 additions and 9 deletions

10
.gitignore vendored
View File

@ -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.*
user/config.yml

View File

@ -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=
https://www.prisma.io/docs/reference/database-reference/supported-databases

248
db/mysql/schema.prisma Normal file
View 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
View 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
View 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")
}

View File

@ -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
View 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);
}

View File

@ -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);
}

View 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;
};

View 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);
}
};

View File

@ -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?
},
});