mirror of
https://github.com/Hessenuk/DiscordTickets.git
synced 2024-12-23 00:03:09 +02:00
Database
This commit is contained in:
parent
dc902b6daf
commit
cf8dff2a5b
54
README.md
54
README.md
@ -1,57 +1,3 @@
|
|||||||
# Please download from [releases](https://github.com/eartharoid/DiscordTickets/releases) or [v2 branch](https://github.com/eartharoid/DiscordTickets/tree/v2) - master branch is currently a work in progress
|
# Please download from [releases](https://github.com/eartharoid/DiscordTickets/releases) or [v2 branch](https://github.com/eartharoid/DiscordTickets/tree/v2) - master branch is currently a work in progress
|
||||||
|
|
||||||
https://discord.com/oauth2/authorize?permissions=8&scope=applications.commands%20bot&client_id=...
|
https://discord.com/oauth2/authorize?permissions=8&scope=applications.commands%20bot&client_id=...
|
||||||
|
|
||||||
# DiscordTickets
|
|
||||||
|
|
||||||
[![Run on Repl.it](https://repl.it/badge/github/eartharoid/DiscordTickets)](https://repl.it/github/eartharoid/DiscordTickets) [![GitHub issues](https://img.shields.io/github/issues/eartharoid/DiscordTickets?style=flat-square)](https://github.com/eartharoid/DiscordTickets/issues) [![GitHub stars](https://img.shields.io/github/stars/eartharoid/DiscordTickets?style=flat-square)](https://github.com/eartharoid/DiscordTickets/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eartharoid/DiscordTickets?style=flat-square)](https://github.com/eartharoid/DiscordTickets/network) [![GitHub license](https://img.shields.io/github/license/eartharoid/DiscordTickets?style=flat-square)](https://github.com/eartharoid/DiscordTickets/blob/master/LICENSE) ![Codacy grade](https://img.shields.io/codacy/grade/14e6851c85444424b75b8bc3f93e93db?logo=codacy&style=flat-square) [![Discord support server](https://discordapp.com/api/guilds/451745464480432129/embed.png?style=shield)](https://discord.gg/pXc9vyC)
|
|
||||||
|
|
||||||
DiscordTickets is a Discord bot for managing support ticket channels, to allow you and your team to provide better and quicker assistance to your members/customers. It is a free, open-source, and self-hosted alternative to [Ticket Tool](https://tickettool.xyz/) and [TicketsBot](https://ticketsbot.net/) premium/whitelabel plans.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Highly customisable
|
|
||||||
- Ticket "panel" / "widget" (react to embed to create ticket)
|
|
||||||
- Simple commands
|
|
||||||
- Supports multiple databases: SQLite (easy, default), MySQL (recommend) storage, MariaDB, PostgreSQL and Microsoft SQL Server
|
|
||||||
- Most (all of the best) features of the premium bots, for free
|
|
||||||
- Self-hosted with your bot application, your logo and guild name
|
|
||||||
- Optional express.js server for web archives: [DiscordTickets-Portal](https://github.com/eartharoid/DiscordTickets-Portal/)
|
|
||||||
|
|
||||||
## Screenshot
|
|
||||||
|
|
||||||
*The mention and embed text are customisable. The images is randomly selected and can be changed or disabled.*
|
|
||||||
![Screenshot](https://i.imgur.com/Y1uCqJJ.gif)
|
|
||||||
|
|
||||||
## Instructions
|
|
||||||
|
|
||||||
For installation, configuration, usage, and other information, **go to the [wiki](https://github.com/Eartharoid/DiscordTickets/wiki).**
|
|
||||||
|
|
||||||
Basic installation support will be provided on Discord, however if you really don't know what you're doing, you can purchase the [premium support setup service](https://ko-fi.com/s/34ccccfbd6) and I will install the bot and portal (archives web server) for you.
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
**[Go to the wiki](https://github.com/Eartharoid/DiscordTickets/wiki)**, or ask for help in [#support](https://discordapp.com/channels/451745464480432129/475351519516950548) on [Discord](https://discord.gg/pXc9vyC).
|
|
||||||
|
|
||||||
[![Discord](https://discordapp.com/api/guilds/451745464480432129/widget.png?style=banner4)](https://discord.gg/pXc9vyC)
|
|
||||||
|
|
||||||
## Donate
|
|
||||||
|
|
||||||
[![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/eartharoid)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<a href="https://private-hosting.eu/">
|
|
||||||
<img src="https://i.imgur.com/eSXhP9C.png"/>
|
|
||||||
</a>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<b>
|
|
||||||
<a href="https://private-hosting.eu/">Sponsored by Private-Hosting</a>
|
|
||||||
</b>
|
|
||||||
<br>
|
|
||||||
<sub>
|
|
||||||
Cheap and powerful servers with 100% uptime.
|
|
||||||
</sub>
|
|
||||||
</div>
|
|
||||||
|
@ -21,4 +21,75 @@ a code:hover {
|
|||||||
color: white !important;
|
color: white !important;
|
||||||
/* text-decoration: underline; */
|
/* text-decoration: underline; */
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer.sponsorship {
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
footer.sponsorship hr {
|
||||||
|
display: inline-block;
|
||||||
|
width: 1.6rem;
|
||||||
|
margin: 0 .7rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 2px solid var(--md-default-fg-color--lighter)
|
||||||
|
}
|
||||||
|
|
||||||
|
footer.sponsorship:hover hr {
|
||||||
|
border-color: var(--md-accent-fg-color)
|
||||||
|
}
|
||||||
|
|
||||||
|
footer.sponsorship:not(:hover) .twemoji.heart-throb-hover svg {
|
||||||
|
color: var(--md-default-fg-color--lighter) !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.twemoji.heart-throb svg,
|
||||||
|
.twemoji.heart-throb-hover svg {
|
||||||
|
position: relative;
|
||||||
|
color: var(--md-heart);
|
||||||
|
animation: pulse 1.5s ease infinite
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
color: var(--md-heart-big);
|
||||||
|
transform: scale(1.3)
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
color: var(--md-heart-big);
|
||||||
|
transform: scale(1.3)
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scale(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer.sponsorship {
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
footer.sponsorship hr {
|
||||||
|
display: inline-block;
|
||||||
|
width: 1.6rem;
|
||||||
|
margin: 0 .7rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-bottom: 2px solid var(--md-default-fg-color--lighter)
|
||||||
|
}
|
||||||
|
|
||||||
|
footer.sponsorship:hover hr {
|
||||||
|
border-color: var(--md-accent-fg-color)
|
||||||
|
}
|
||||||
|
|
||||||
|
footer.sponsorship:not(:hover) .twemoji.heart-throb-hover svg {
|
||||||
|
color: var(--md-default-fg-color--lighter) !important
|
||||||
}
|
}
|
27
package.json
27
package.json
@ -34,21 +34,26 @@
|
|||||||
"keyv": "^4.0.3",
|
"keyv": "^4.0.3",
|
||||||
"leekslazylogger": "^2.0.7",
|
"leekslazylogger": "^2.0.7",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
|
"sequelize": "^6.5.0",
|
||||||
"terminal-link": "^2.1.1"
|
"terminal-link": "^2.1.1"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "^7.20.0",
|
||||||
|
"mariadb": "^2.5.2",
|
||||||
|
"mysql2": "^2.2.5",
|
||||||
|
"nodemon": "^2.0.7",
|
||||||
|
"pg": "^8.5.1",
|
||||||
|
"pg-hstore": "^2.3.3",
|
||||||
|
"tedious": "^11.0.3"
|
||||||
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@keyv/sqlite": "^2.0.2"
|
"sqlite3": "^5.0.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@keyv/mongo": "^1.1.0",
|
"mariadb": "^2.5.2",
|
||||||
"@keyv/mysql": "^1.1.4",
|
"mysql2": "^2.2.5",
|
||||||
"@keyv/postgres": "^1.0.16"
|
"pg": "^8.5.1",
|
||||||
},
|
"pg-hstore": "^2.3.3",
|
||||||
"devDependencies": {
|
"tedious": "^11.0.3"
|
||||||
"@keyv/mongo": "^1.1.0",
|
|
||||||
"@keyv/mysql": "^1.1.4",
|
|
||||||
"@keyv/postgres": "^1.0.16",
|
|
||||||
"eslint": "^7.20.0",
|
|
||||||
"nodemon": "^2.0.7"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1063
pnpm-lock.yaml
1063
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
42
src/database/dialects.js
Normal file
42
src/database/dialects.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
module.exports = {
|
||||||
|
sqlite: {
|
||||||
|
name: 'SQLite',
|
||||||
|
dialect: 'sqlite',
|
||||||
|
packages: ['sqlite3'],
|
||||||
|
},
|
||||||
|
mysql: {
|
||||||
|
name: 'MySQL',
|
||||||
|
dialect: 'mysql',
|
||||||
|
packages: ['mysql2']
|
||||||
|
},
|
||||||
|
maria: {
|
||||||
|
name: 'MariaDB',
|
||||||
|
dialect: 'mariadb',
|
||||||
|
package: ['mariadb']
|
||||||
|
},
|
||||||
|
mariadb: {
|
||||||
|
name: 'MariaDB',
|
||||||
|
dialect: 'mariadb',
|
||||||
|
package: ['mariadb']
|
||||||
|
},
|
||||||
|
postgre: {
|
||||||
|
name: 'PostgreSQL',
|
||||||
|
dialect: 'postgres',
|
||||||
|
packages: ['pg', 'pg-hstore']
|
||||||
|
},
|
||||||
|
postgres: {
|
||||||
|
name: 'PostgreSQL',
|
||||||
|
dialect: 'postgres',
|
||||||
|
packages: ['pg', 'pg-hstore']
|
||||||
|
},
|
||||||
|
postgresql: {
|
||||||
|
name: 'PostgreSQL',
|
||||||
|
dialect: 'postgres',
|
||||||
|
packages: ['pg', 'pg-hstore']
|
||||||
|
},
|
||||||
|
microsoft: {
|
||||||
|
name: 'Microsoft SQL',
|
||||||
|
dialect: 'mssql',
|
||||||
|
packages: ['tedious']
|
||||||
|
},
|
||||||
|
};
|
126
src/database/index.js
Normal file
126
src/database/index.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
const {
|
||||||
|
Sequelize,
|
||||||
|
DataTypes
|
||||||
|
} = require('sequelize');
|
||||||
|
const { path } = require('../utils/fs');
|
||||||
|
const config = require('../../user/config');
|
||||||
|
const types = require('./dialects');
|
||||||
|
const supported = Object.keys(types);
|
||||||
|
|
||||||
|
module.exports = async (log) => {
|
||||||
|
|
||||||
|
const {
|
||||||
|
DB_TYPE,
|
||||||
|
DB_HOST,
|
||||||
|
DB_USER,
|
||||||
|
DB_PASS,
|
||||||
|
DB_NAME
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
let type = (DB_TYPE || 'sqlite').toLowerCase();
|
||||||
|
|
||||||
|
if (!supported.includes(type)) {
|
||||||
|
log.report('Invalid database type');
|
||||||
|
throw new Error(`DB_TYPE (${type}) is not a valid type`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
types[type].packages.forEach(pkg => require(pkg));
|
||||||
|
} catch {
|
||||||
|
log.report('Specified database type is not installed');
|
||||||
|
let required = types[type].packages.map(i => `"${i}"`).join(' and ');
|
||||||
|
throw new Error(`Please install the package(s) for your selected database type: ${required}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let sequelize;
|
||||||
|
|
||||||
|
if (type === 'sqlite') {
|
||||||
|
log.info('Using SQLite storage');
|
||||||
|
sequelize = new Sequelize({
|
||||||
|
dialect: types[type].dialect,
|
||||||
|
storage: path('./user/database.sqlite'),
|
||||||
|
logging: log.debug
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
log.info(`Connecting to ${types[type].name} database...`);
|
||||||
|
sequelize = new Sequelize(DB_NAME, DB_USER, DB_PASS, {
|
||||||
|
dialect: types[type].dialect,
|
||||||
|
host: DB_HOST,
|
||||||
|
logging: log.debug
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await sequelize.authenticate();
|
||||||
|
log.success('Connected to database successfully');
|
||||||
|
} catch (error) {
|
||||||
|
log.warn('Unable to connect to database');
|
||||||
|
log.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* let models = {};
|
||||||
|
let files = fs.readdirSync(path('src/database/models/')).filter(file => file.endsWith('.js'));
|
||||||
|
|
||||||
|
for (let file of files) {
|
||||||
|
let table = require(`./models/${file}`);
|
||||||
|
let model = sequelize.define(table.name, table.model);
|
||||||
|
models[table.name] = model;
|
||||||
|
} */
|
||||||
|
|
||||||
|
const Guild = sequelize.define('Guild', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.CHAR(18),
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
prefix: {
|
||||||
|
type: DataTypes.STRING, // STRING(255) = VARCHAR(255)
|
||||||
|
defaultValue: config.defaults.prefix
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
defaultValue: config.defaults.locale
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
tableName: 'guilds'
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const Ticket = sequelize.define('Ticket', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.CHAR(18),
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
guild: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
references: {
|
||||||
|
model: Guild,
|
||||||
|
key: 'id'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
tableName: 'tickets'
|
||||||
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
const Message = sequelize.define('Message', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.CHAR(18),
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
ticket: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
references: {
|
||||||
|
model: Ticket,
|
||||||
|
key: 'id'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
tableName: 'messages'
|
||||||
|
});
|
||||||
|
|
||||||
|
sequelize.sync();
|
||||||
|
|
||||||
|
return sequelize.models;
|
||||||
|
};
|
13
src/index.js
13
src/index.js
@ -28,9 +28,11 @@ const { version } = require('../package.json');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { path } = require('./utils/fs');
|
const { path } = require('./utils/fs');
|
||||||
if (!fs.existsSync(path('./.env'))) return console.log('Please make a copy of \'example.env\' called \'.env\'');
|
if (!fs.existsSync(path('./.env'))) return console.log('Please make a copy of \'example.env\' called \'.env\'');
|
||||||
if (!fs.existsSync(path('./user/config.js'))) return console.log('Please make a copy of \'example.config.js\' called \'config.js\'');
|
if (!fs.existsSync(path('./user/config.js'))) return console.log('Please make a copy of \'user/example.config.js\' called \'user/config.js\'');
|
||||||
|
|
||||||
require('dotenv').config();
|
require('dotenv').config({
|
||||||
|
path: path('./.env')
|
||||||
|
});
|
||||||
|
|
||||||
const config = require('../user/config');
|
const config = require('../user/config');
|
||||||
|
|
||||||
@ -43,7 +45,6 @@ const log = new Logger({
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const terminalLink = require('terminal-link');
|
|
||||||
log.report = error => {
|
log.report = error => {
|
||||||
let report = [
|
let report = [
|
||||||
'<< Issue report >>',
|
'<< Issue report >>',
|
||||||
@ -57,6 +58,9 @@ log.report = error => {
|
|||||||
if (error) log.error(error);
|
if (error) log.error(error);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const terminalLink = require('terminal-link');
|
||||||
|
const I18n = require('@eartharoid/i18n');
|
||||||
|
|
||||||
const { Client } = require('discord.js');
|
const { Client } = require('discord.js');
|
||||||
class Bot extends Client {
|
class Bot extends Client {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -66,8 +70,9 @@ class Bot extends Client {
|
|||||||
|
|
||||||
Object.assign(this, {
|
Object.assign(this, {
|
||||||
config,
|
config,
|
||||||
db: require('./modules/database')(log),
|
db: require('./database')(log),
|
||||||
log,
|
log,
|
||||||
|
i18n: new I18n(path('./src/locales'), 'en-GB')
|
||||||
});
|
});
|
||||||
|
|
||||||
this.log.info('Connecting to Discord API');
|
this.log.info('Connecting to Discord API');
|
||||||
|
1
src/locales/en-GB.json
Normal file
1
src/locales/en-GB.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
@ -1,75 +0,0 @@
|
|||||||
const Keyv = require('keyv');
|
|
||||||
|
|
||||||
const { homepage } = require('../../package.json');
|
|
||||||
const { path } = require('../utils/fs');
|
|
||||||
|
|
||||||
const types = {
|
|
||||||
sqlite: 'sqlite',
|
|
||||||
mysql: 'mysql',
|
|
||||||
mongo: 'mongo',
|
|
||||||
mongodb: 'mongo',
|
|
||||||
postgre: 'postgres',
|
|
||||||
postgres: 'postgres',
|
|
||||||
postgresql: 'postgres',
|
|
||||||
};
|
|
||||||
|
|
||||||
const supported = Object.keys(types);
|
|
||||||
|
|
||||||
module.exports = (log) => {
|
|
||||||
|
|
||||||
let type = (process.env.DB_TYPE || 'sqlite').toLowerCase();
|
|
||||||
|
|
||||||
if (!supported.includes(type)) {
|
|
||||||
log.report('Invalid database type');
|
|
||||||
throw new Error(`DB_TYPE (${type}) is not a valid type`);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
require(`@keyv/${types[type]}`);
|
|
||||||
} catch {
|
|
||||||
log.report('Specified database type is not installed');
|
|
||||||
throw new Error(`"@keyv/${types[type]}" is not installed, please install is manually`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
DB_HOST,
|
|
||||||
DB_USER,
|
|
||||||
DB_PASS,
|
|
||||||
DB_NAME
|
|
||||||
} = process.env;
|
|
||||||
let database;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 'mysql':
|
|
||||||
database = `mysql://${DB_USER}:${DB_PASS}@${DB_HOST}/${DB_NAME}`;
|
|
||||||
log.info('Using MySQL as database backend');
|
|
||||||
break;
|
|
||||||
case 'mongo':
|
|
||||||
case 'mongodb':
|
|
||||||
database = `mongodb://${DB_USER}:${DB_PASS}@${DB_HOST}/${DB_NAME}`;
|
|
||||||
log.info('Using MongoDB as database backend');
|
|
||||||
break;
|
|
||||||
case 'postgre':
|
|
||||||
case 'postgres':
|
|
||||||
case 'postgresql':
|
|
||||||
database = `postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}/${DB_NAME}`;
|
|
||||||
log.info('Using Postgres as database backend');
|
|
||||||
break;
|
|
||||||
default: // sqlite
|
|
||||||
database = `sqlite://${path('./user/database.sqlite')}`;
|
|
||||||
log.info('Using SQLite as database backend');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
servers: new Keyv(database, {
|
|
||||||
namespace: 'servers'
|
|
||||||
}),
|
|
||||||
tickets: new Keyv(database, {
|
|
||||||
namespace: 'tickets'
|
|
||||||
}),
|
|
||||||
messages: new Keyv(database, {
|
|
||||||
namespace: 'messages'
|
|
||||||
})
|
|
||||||
};
|
|
||||||
};
|
|
@ -39,11 +39,12 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
activity: 'for new tickets | %shelp',
|
activity: 'for new tickets | %shelp',
|
||||||
type: 'WATCHING'
|
type: 'WATCHING'
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
defaults: {
|
defaults: {
|
||||||
prefix: '-',
|
prefix: '-',
|
||||||
colour: '#009999',
|
colour: '#009999',
|
||||||
|
locale: 'en-GB'
|
||||||
},
|
},
|
||||||
logs: {
|
logs: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user