Updated models and migrations to new spec

This commit is contained in:
2022-08-17 19:36:47 +02:00
parent bc075805e2
commit 05804cb78a
22 changed files with 336 additions and 86 deletions

View File

@@ -34,6 +34,22 @@ Completed bands reward cosmetics and XP (scaled to band size)
Band levels by collecting duplicates (?) as a long term hook
### Guild - Single guild the bot has joined
- int guildID
- int active | 0 inactive, 1 active, 2 banned/blocked
- int adminRoleId | role can configure server specific bot options
- date created
- date updated
### Core - Global bot settings
- bool maintenance
- int[] adminIDs
### User
- int userID
- int active | 0 inactive, 1 active, 2 banned/blocked
- int privacy | 0 public, 1 private
## Profile
Steal profile layout from Amaan
with more customization

View File

@@ -12,4 +12,5 @@ If ran outside the container, DB_HOST must be set to localhost or the container'
```bash
$npx sequelize db:migrate
$npx sequelize db:seed:all
```

View File

@@ -7,26 +7,19 @@ module.exports = {
.setName("collection")
.setDescription("List all cards in your collection"),
async execute(interaction) {
//fetch the user given the userID
//fetch the user given the userID and include his cards
const user = await User.findOne({
where: {
userID: interaction.member.id
}
});
//fetch all cards give the user id
const cards = await Card.findAll({
where: {
ownerID: user.id
discordId: interaction.member.id
},
include: [{
model: Character,
as: "character"
model: Card,
include: [Character]
}]
});
//if the user has no cards, tell him
if (cards.length === 0) {
if (user.Cards.length === 0) {
interaction.reply({
content: "You have no cards in your collection",
ephemeral: true
@@ -36,8 +29,14 @@ module.exports = {
//if the user has cards, list them
let message = "";
for (let i = 0; i < cards.length; i++) {
message += `${cards[i].id} - ${cards[i].characterID} ${cards[i].character.name} \n`;
for (let i = 0; i < user.Cards.length; i++) {
message += `${user.Cards[i].id} - ${user.Cards[i].characterId} \n`;
message += `Identifier: ${user.Cards[i].identifier} \n`;
message += `Name: ${user.Cards[i].Character.name} \n`;
message += `Image: ${user.Cards[i].Character.imageURL} \n`;
message += `Quality: ${user.Cards[i].quality} \n`;
message += `Print number: ${user.Cards[i].printNr} \n`;
message += `------------------------ \n`;
}
interaction.reply({
content: message,

View File

@@ -1,5 +1,6 @@
const { SlashCommandBuilder } = require("@discordjs/builders");
const { Card, User } = require("../models");
const { customAlphabet } = require("nanoid");
module.exports = {
data: new SlashCommandBuilder()
@@ -16,15 +17,25 @@ module.exports = {
//get user id from database given the userID
const user = await User.findOne({
where: {
userID: interaction.member.id
discordId: interaction.member.id
}
});
//create new card with the given character id, and the user id
const nanoid = customAlphabet('23456789ABCDEFGHJKLMNPRSTUVWXYZ',6); //Up to 887.503.681
const identifier = nanoid();
const existingCharacterCount = await Card.count({
where: {
characterId: interaction.options.getInteger("id")
}
});
const card = await Card.create({
characterID: interaction.options.getInteger("id"),
identifier: "00000",
ownerID: user.id,
characterId: interaction.options.getInteger("id"),
identifier: identifier,
quality: 1,
printNr: existingCharacterCount + 1,
userId: user.id
});
//reply with the new card id

View File

@@ -9,7 +9,7 @@ module.exports = {
async execute(interaction) {
let user = await User.findOne({
where: {
userID: interaction.user.id
discordId: interaction.user.id
}
});
if (user) {
@@ -19,9 +19,8 @@ module.exports = {
});
} else {
await User.create({
userID: interaction.user.id,
banned: false,
registredAt: new Date()
discordId: interaction.user.id,
active: 1,
});
interaction.reply({
content: "You are now registered",

View File

@@ -10,7 +10,7 @@ module.exports = {
let users = await User.findAll();
let userList = "";
for (let i = 0; i < users.length; i++) {
let username = await interaction.client.users.fetch(users[i].userID);
let username = await interaction.client.users.fetch(users[i].discordId);
userList += `${username.username}#${username.discriminator}`;
}
if (userList === "") {

View File

@@ -12,15 +12,16 @@ module.exports = {
//check if guild exists in database
let guildData = await Guild.findOne({
where: {
guildID: guild.id
guildId: guild.id
}
});
if (!guildData) {
//create guild in database
await Guild.create({
guildID: guild.id,
ownerID: guild.ownerId,
guildId: guild.id,
adminRoleId: null,
active: 1
});
//send guild registered message to the interations channel
interaction.channel.send({
@@ -32,7 +33,7 @@ module.exports = {
//check if the user exists in the database, if not tell him to use the /register command
let user = await User.findOne({
where: {
userID: interaction.member.id
discordId: interaction.member.id
}
});
if (!user && interaction.commandName !== "register") {
@@ -52,8 +53,8 @@ module.exports = {
} catch (err) {
if (err) console.log(err);
await interaction.reply({
content: "An error occured processing the command",
ephemeral: true
content: `An error occured processing the command :(\n \`\`\`${JSON.stringify(err, null, 2)}\`\`\``,
ephemeral: false
});
}
}

View File

@@ -0,0 +1,40 @@
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('Bands', {
id: {
allowNull: false,
autoIncrement: false,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
description: {
type: Sequelize.TEXT
},
imageURL: {
type: Sequelize.STRING
},
enabled: {
allowNull: false,
type: Sequelize.BOOLEAN,
defaultValue: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('Bands');
}
};

View File

@@ -8,22 +8,27 @@ module.exports = {
primaryKey: true,
type: Sequelize.INTEGER
},
guildID: {
type: Sequelize.STRING
guildId: {
type: Sequelize.BIGINT,
allowNull: false
},
adminRoleID: {
type: Sequelize.STRING
adminRoleId: {
type: Sequelize.BIGINT,
},
owderID: {
type: Sequelize.STRING
active: {
type: Sequelize.INTEGER,
allowNull: false,
defaultValue: 1
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
}
});
},

View File

@@ -8,23 +8,29 @@ module.exports = {
primaryKey: true,
type: Sequelize.INTEGER
},
userID: {
type: Sequelize.STRING,
discordId: {
type: Sequelize.BIGINT,
allowNull: false
},
banned: {
type: Sequelize.BOOLEAN
active: {
type: Sequelize.INTEGER,
allowNull: false,
defaultValue: 1
},
registredAt: {
type: Sequelize.DATE
privacy: {
type: Sequelize.INTEGER,
allowNull: false,
defaultValue: 0
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
}
});
},

View File

@@ -4,32 +4,41 @@ module.exports = {
await queryInterface.createTable('Characters', {
id: {
allowNull: false,
autoIncrement: true,
autoIncrement: false,
primaryKey: true,
type: Sequelize.INTEGER
},
bandId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Bands',
key: 'id'
}
},
name: {
type: Sequelize.STRING
},
rarity: {
type: Sequelize.INTEGER
},
description: {
type: Sequelize.STRING
type: Sequelize.TEXT
},
imageURL: {
type: Sequelize.STRING
},
imageHash: {
type: Sequelize.STRING
enabled: {
allowNull: false,
type: Sequelize.BOOLEAN,
defaultValue: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
}
});
},

View File

@@ -10,9 +10,10 @@ module.exports = {
},
identifier: {
allowNull: false,
type: Sequelize.STRING
type: Sequelize.STRING,
unique: true
},
characterID: {
characterId: {
allowNull: false,
type: Sequelize.INTEGER,
references: {
@@ -20,7 +21,11 @@ module.exports = {
key: 'id'
}
},
ownerID: {
quality: {
allowNull: false,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
@@ -28,17 +33,27 @@ module.exports = {
key: 'id'
}
},
imageHash: {
type: Sequelize.STRING
},
enabled: {
allowNull: false,
type: Sequelize.BOOLEAN
type: Sequelize.BOOLEAN,
defaultValue: true
},
printNr: {
allowNull: false,
type: Sequelize.INTEGER,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
}
});
},

View File

@@ -0,0 +1,36 @@
'use strict';
module.exports = {
async up (queryInterface, Sequelize) {
await queryInterface.createTable('Bot', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
maintenance: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
adminIDs: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
}
});
},
async down (queryInterface, Sequelize) {
await queryInterface.dropTable('Bot');
}
};

28
models/band.js Normal file
View File

@@ -0,0 +1,28 @@
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Band extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
Band.hasMany(models.Character);
}
}
Band.init({
uniqueId: DataTypes.INTEGER,
name: DataTypes.STRING,
description: DataTypes.TEXT,
imageURL: DataTypes.STRING,
enabled: DataTypes.BOOLEAN
}, {
sequelize,
modelName: 'Band',
});
return Band;
};

24
models/bot.js Normal file
View File

@@ -0,0 +1,24 @@
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Bot extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
}
Bot.init({
maintenance: DataTypes.BOOLEAN,
adminIDs: DataTypes.STRING
}, {
sequelize,
modelName: 'Guild',
});
return Bot;
};

View File

@@ -10,22 +10,18 @@ module.exports = (sequelize, DataTypes) => {
* The `models/index` file will call this method automatically.
*/
static associate(models) {
Card.belongsTo(models.Character, {
foreignKey: 'characterID',
as: 'character'
});
Card.belongsTo(models.User, {
foreignKey: 'ownerID',
key: 'userId',
as: 'owner'
});
Card.belongsTo(models.User);
Card.belongsTo(models.Character);
}
}
Card.init({
ownerID: DataTypes.STRING,
identifier: DataTypes.STRING,
characterID: DataTypes.INTEGER,
enabled: { type: DataTypes.BOOLEAN, defaultValue: true }
characterId: DataTypes.INTEGER,
quality: DataTypes.INTEGER,
userId: DataTypes.STRING,
imageHash: DataTypes.STRING,
enabled: { type: DataTypes.BOOLEAN, defaultValue: true },
printNr: DataTypes.INTEGER,
}, {
sequelize,
modelName: 'Card',

View File

@@ -10,18 +10,16 @@ module.exports = (sequelize, DataTypes) => {
* The `models/index` file will call this method automatically.
*/
static associate(models) {
Character.hasMany(models.Card, {
foreignKey: 'characterID',
as: 'cards'
});
Character.belongsToMany(models.Card, { through: 'CardCharacter' });
Character.belongsTo(models.Band, { foreignKey: 'bandId', });
}
}
Character.init({
name: DataTypes.STRING,
rarity: DataTypes.INTEGER,
description: DataTypes.STRING,
bandId: DataTypes.INTEGER,
imageURL: DataTypes.STRING,
imageHash: DataTypes.STRING
description: DataTypes.TEXT,
enabled: DataTypes.BOOLEAN
}, {
sequelize,
modelName: 'Character',

View File

@@ -14,9 +14,9 @@ module.exports = (sequelize, DataTypes) => {
}
}
Guild.init({
guildID: DataTypes.STRING,
adminRoleID: DataTypes.STRING,
owderID: DataTypes.STRING
guildId: DataTypes.BIGINT,
adminRoleId: DataTypes.BIGINT,
active: DataTypes.INTEGER,
}, {
sequelize,
modelName: 'Guild',

View File

@@ -11,12 +11,13 @@ module.exports = (sequelize, DataTypes) => {
*/
static associate(models) {
// define association here
User.hasMany(models.Card);
}
}
User.init({
userID: DataTypes.STRING,
banned: DataTypes.BOOLEAN,
registredAt: DataTypes.DATE
discordId: DataTypes.BIGINT,
active: DataTypes.INTEGER,
privacy: DataTypes.INTEGER
}, {
sequelize,
modelName: 'User',

17
package-lock.json generated
View File

@@ -14,6 +14,7 @@
"discord.js": "^13.6.0",
"dotenv": "^16.0.0",
"mysql2": "^2.3.3",
"nanoid": "^3.0.0",
"nodemon": "^2.0.15",
"sequelize": "^6.19.0",
"sequelize-cli": "^6.4.1"
@@ -1401,6 +1402,17 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
},
"node_modules/nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
@@ -3319,6 +3331,11 @@
}
}
},
"nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
},
"next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",

View File

@@ -15,6 +15,7 @@
"discord.js": "^13.6.0",
"dotenv": "^16.0.0",
"mysql2": "^2.3.3",
"nanoid": "^3.0.0",
"nodemon": "^2.0.15",
"sequelize": "^6.19.0",
"sequelize-cli": "^6.4.1"

View File

@@ -0,0 +1,47 @@
'use strict';
module.exports = {
async up (queryInterface, Sequelize) {
/**
* Add seed commands here.
*
* Example:
* await queryInterface.bulkInsert('People', [{
* name: 'John Doe',
* isBetaMember: false
* }], {});
*/
await queryInterface.bulkInsert('Bands', [{
id: 1,
name: 'BAND-MAID',
description: 'Band-Maid (stylized as BAND-MAID) is an all girl rock band from Tokyo that formed in July 2013. The band combines a rock sound with a maid image modeled on Japanese maid cafés.',
imageURL: 'https://cdn.discordapp.com/attachments/851543504831119380/1009467684490063892/unknown.png',
enabled: true
}]);
await queryInterface.bulkInsert('Characters', [{
id: 1,
bandId: 1,
name: 'Miku Kobato',
description: 'Miku Kobato is a Japanese singer, songwriter and guitarist. She is the initial founding member and main lyricist for BAND-MAID.',
imageURL: 'https://cdn.discordapp.com/attachments/851543504831119380/1009468495077048330/unknown.png',
enabled: true
},
{
id: 2,
bandId: 1,
name: 'Akane Hirose',
description: 'Akane Hirose is a Japanese drummer and founding member of BAND-MAID.',
imageURL: 'https://cdn.discordapp.com/attachments/851543504831119380/1009469985296490568/unknown.png',
enabled: true
}]);
},
async down (queryInterface, Sequelize) {
/**
* Add commands to revert seed here.
*
* Example:
* await queryInterface.bulkDelete('People', null, {});
*/
}
};