diff --git a/.eslintrc.json b/.eslintrc.json index 6276302..80ed293 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -12,6 +12,9 @@ "ecmaVersion": 12, "sourceType": "module" }, + "plugins": [ + "unused-imports" + ], "root": true, "rules": { "array-bracket-newline": [ @@ -145,6 +148,9 @@ "no-unneeded-ternary": [ "error" ], + "no-unused-expressions": [ + "error" + ], "no-var": [ "error" ], @@ -204,6 +210,16 @@ "spaced-comment": [ "error", "always" + ], + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + } ] } } \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ff369df --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +CONFIG_PATH=./user/config.yml +DISCORD_TOKEN= +DB_ENCRYPTION_KEY= +DB_CONNECTION_URL="" \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json index 40bf6bd..554aae6 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -5,7 +5,7 @@ "moduleResolution": "Node", "baseUrl": "src", "resolveJsonModule": true, - "checkJs": true, + "checkJs": false, "paths": { "@/*": ["*.mjs"], "#/*": ["*.json"] diff --git a/package.json b/package.json index 49c37ba..f024b27 100644 --- a/package.json +++ b/package.json @@ -33,9 +33,11 @@ }, "dependencies": { "@eartharoid/dtf": "^2.0.1", + "@prisma/client": "^3.11.0", "@sapphire/framework": "^2.4.1", "discord.js": "^13.6.0", - "dotenv-cra": "^3.0.2", + "dotenv": "^16.0.0", + "figlet": "^1.5.2", "leeks.js": "^0.2.4", "leekslazylogger": "^4.1.7", "semver": "^7.3.5", @@ -44,6 +46,8 @@ }, "devDependencies": { "all-contributors-cli": "^6.20.0", - "eslint": "^8.11.0" + "eslint": "^8.11.0", + "eslint-plugin-unused-imports": "^2.0.0", + "prisma": "^3.11.0" } } \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..faf775c --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,75 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "mysql" + url = env("DB_CONNECTION_URL") +} + +model Category { + id String @id @unique @db.VarChar(19) + tickets Ticket[] + + @@map("categories") +} + +model Guild { + id String @id @unique @db.VarChar(19) + archive Boolean @default(true) + errorColour String @default("RED") + primaryColour String @default("#009999") + successColour String @default("GREEN") + tags Tag[] + tickets Ticket[] + + @@map("guilds") +} + +model Tag { + content String @db.Text + guild Guild @relation(fields: [guildId], references: [id]) + guildId String @db.VarChar(19) + name String + + @@id([guildId, name]) + @@unique([guildId, name]) + @@map("tags") +} + +model Ticket { + id String @id @unique @db.VarChar(19) + category Category @relation(fields: [categoryId], references: [id]) + categoryId String @db.VarChar(19) + claimedBy User? @relation(name: "ClaimedTickets", fields: [claimedById], references: [id]) + claimedById String @db.VarChar(19) + closedBy User? @relation(name: "ClosedTickets", fields: [closedById], references: [id]) + closedById String @db.VarChar(19) + closedReason String? + createdBy User? @relation(name: "CreatedTickets", fields: [createdById], references: [id]) + createdById String @db.VarChar(19) + firstResponse DateTime? + guild Guild @relation(fields: [guildId], references: [id]) + guildId String @db.VarChar(19) + lastMessage DateTime? + number Int + open Boolean @default(true) + openingMessage String @db.VarChar(19) + pinnedMessages Json @default("[]") + topic String? + + @@unique([guildId, number]) + @@map("tickets") +} + +model User { + id String @id @unique @db.VarChar(19) + ticketsCreated Ticket[] @relation("CreatedTickets") + ticketsClosed Ticket[] @relation("ClosedTickets") + ticketsClaimed Ticket[] @relation("ClaimedTickets") + + @@map("users") +} diff --git a/scripts/keygen.mjs b/scripts/keygen.mjs index 614b775..9dd0443 100644 --- a/scripts/keygen.mjs +++ b/scripts/keygen.mjs @@ -4,5 +4,5 @@ import { short } from 'leeks.js'; console.log(short( 'Set the "DB_ENCRYPTION_KEY" environment variable to: \n&1&!f' + randomBytes(24).toString('hex') + - '&r\n\n&0&!e WARNING &r &e&lDo not lose the encryption key or most of the data in the database will be unreadable, requiring a new key and a full reset.' + '&r\n\n&0&!e WARNING &r &e&lIf you lose the encryption key, most of the data in the database will become unreadable, requiring a new key and a full reset.' )); \ No newline at end of file diff --git a/src/client.mjs b/src/client.mjs new file mode 100644 index 0000000..64645a9 --- /dev/null +++ b/src/client.mjs @@ -0,0 +1,31 @@ +import { + container, + SapphireClient +} from '@sapphire/framework'; +import { Intents } from 'discord.js'; +import prisma from '@prisma/client'; + +export default class Client extends SapphireClient { + constructor() { + super({ + defaultPrefix: 'tickets/', + intents: [ + Intents.FLAGS.GUILDS, + Intents.FLAGS.GUILD_MEMBERS, + Intents.FLAGS.GUILD_MESSAGES, + Intents.FLAGS.GUILD_MESSAGE_REACTIONS + ], + }); + } + async login(token) { + container.prisma = new prisma.PrismaClient(); + return super.login(token); + } + + async destroy() { + await container.prisma.$disconnect(); + return super.destroy(); + } + + +} \ No newline at end of file diff --git a/src/index.mjs b/src/index.mjs index ebb2379..cb52eb3 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -21,13 +21,15 @@ * @license GNU-GPLv3 */ -import dotenv from 'dotenv-cra'; +import dotenv from 'dotenv'; import fs from 'fs'; import semver from 'semver'; import { colours } from 'leeks.js'; import logger from './lib/logger.mjs'; import banner from './lib/banner.mjs'; import YAML from 'yaml'; +import { container } from '@sapphire/framework'; +import Client from './client.mjs'; process.env.NODE_ENV ??= 'development'; // make sure NODE_ENV is set dotenv.config(); // load env file @@ -36,7 +38,7 @@ const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8')); // check node version if (!semver.satisfies(process.versions.node, pkg.engines.node)) { - console.log('\x07' + colours.redBright(`Error: Discord Tickets requires Node.js version ${pkg.engines.node}; you are currently using ${process.versions.node}`)); + console.log('\x07' + colours.redBright(`Error: Your current Node.js version, ${process.versions.node}, does not meet the requirement "${pkg.engines.node}".`)); process.exit(1); } @@ -45,8 +47,6 @@ if (process.env.DB_ENCRYPTION_KEY === undefined) { process.exit(1); } -console.log(banner(pkg.version)); // print big title - process.env.CONFIG_PATH ??= './user/config.yml'; // set default config file path if (!fs.existsSync(process.env.CONFIG_PATH)) { @@ -61,10 +61,11 @@ if (!fs.existsSync(process.env.CONFIG_PATH)) { } } +console.log(banner(pkg.version)); // print big title + const config = YAML.parse(fs.readFileSync(process.env.CONFIG_PATH, 'utf8')); - const log = logger(config); - +container.log = log; process.on('unhandledRejection', error => { log.notice(`Discord Tickets v${pkg.version} on Node.js v${process.versions.node} (${process.platform})`); @@ -73,3 +74,5 @@ process.on('unhandledRejection', error => { log.error(error); }); +const client = new Client(); +client.login(); \ No newline at end of file diff --git a/src/lib/banner.mjs b/src/lib/banner.mjs index 811e9ed..2201c2f 100644 --- a/src/lib/banner.mjs +++ b/src/lib/banner.mjs @@ -1,22 +1,9 @@ import { colours } from 'leeks.js'; +import figlet from 'figlet'; import link from 'terminal-link'; -export default version => colours.cyan(` -######## #### ###### ###### ####### ######## ######## -## ## ## ## ## ## ## ## ## ## ## ## ## -## ## ## ## ## ## ## ## ## ## ## -## ## ## ###### ## ## ## ######## ## ## -## ## ## ## ## ## ## ## ## ## ## -## ## ## ## ## ## ## ## ## ## ## ## ## -######## #### ###### ###### ####### ## ## ######## -######## #### ###### ## ## ######## ######## ###### - ## ## ## ## ## ## ## ## ## ## - ## ## ## ## ## ## ## ## - ## ## ## ##### ###### ## ###### - ## ## ## ## ## ## ## ## - ## ## ## ## ## ## ## ## ## ## - ## #### ###### ## ## ######## ## ###### -`) + -colours.cyanBright(`\n${link('Discord Tickets', 'https://discordtickets.app')} bot v${version} by eartharoid`) + -colours.cyanBright('\n' + link('Sponsor this project', 'https://discordtickets.app/sponsor')) + -'\n\n'; \ No newline at end of file +export default version => colours.cyan(figlet.textSync('Discord', { font: 'Banner3' })) + + colours.cyan('\n\n' + figlet.textSync('Tickets', { font: 'Banner3' })) + + colours.cyanBright(`\n\n${link('Discord Tickets', 'https://discordtickets.app')} bot v${version} by eartharoid`) + + colours.cyanBright('\n' + link('Sponsor this project', 'https://discordtickets.app/sponsor')) + + '\n\n'; diff --git a/src/lib/constants.js b/src/lib/constants.mjs similarity index 100% rename from src/lib/constants.js rename to src/lib/constants.mjs