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
|
||||
|
||||
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>
|
||||
|
@ -22,3 +22,74 @@ a code:hover {
|
||||
/* text-decoration: underline; */
|
||||
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",
|
||||
"leekslazylogger": "^2.0.7",
|
||||
"node-fetch": "^2.6.1",
|
||||
"sequelize": "^6.5.0",
|
||||
"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": {
|
||||
"@keyv/sqlite": "^2.0.2"
|
||||
"sqlite3": "^5.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@keyv/mongo": "^1.1.0",
|
||||
"@keyv/mysql": "^1.1.4",
|
||||
"@keyv/postgres": "^1.0.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@keyv/mongo": "^1.1.0",
|
||||
"@keyv/mysql": "^1.1.4",
|
||||
"@keyv/postgres": "^1.0.16",
|
||||
"eslint": "^7.20.0",
|
||||
"nodemon": "^2.0.7"
|
||||
"mariadb": "^2.5.2",
|
||||
"mysql2": "^2.2.5",
|
||||
"pg": "^8.5.1",
|
||||
"pg-hstore": "^2.3.3",
|
||||
"tedious": "^11.0.3"
|
||||
}
|
||||
}
|
||||
|
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 { 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('./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');
|
||||
|
||||
@ -43,7 +45,6 @@ const log = new Logger({
|
||||
});
|
||||
|
||||
|
||||
const terminalLink = require('terminal-link');
|
||||
log.report = error => {
|
||||
let report = [
|
||||
'<< Issue report >>',
|
||||
@ -57,6 +58,9 @@ log.report = error => {
|
||||
if (error) log.error(error);
|
||||
};
|
||||
|
||||
const terminalLink = require('terminal-link');
|
||||
const I18n = require('@eartharoid/i18n');
|
||||
|
||||
const { Client } = require('discord.js');
|
||||
class Bot extends Client {
|
||||
constructor() {
|
||||
@ -66,8 +70,9 @@ class Bot extends Client {
|
||||
|
||||
Object.assign(this, {
|
||||
config,
|
||||
db: require('./modules/database')(log),
|
||||
db: require('./database')(log),
|
||||
log,
|
||||
i18n: new I18n(path('./src/locales'), 'en-GB')
|
||||
});
|
||||
|
||||
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',
|
||||
type: 'WATCHING'
|
||||
}
|
||||
},
|
||||
],
|
||||
defaults: {
|
||||
prefix: '-',
|
||||
colour: '#009999',
|
||||
locale: 'en-GB'
|
||||
},
|
||||
logs: {
|
||||
enabled: true,
|
||||
|
Loading…
Reference in New Issue
Block a user