diff --git a/.vscode/settings.json b/.vscode/settings.json index e076ad2..5a47d7e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,5 +24,8 @@ ], "editor.fontFamily": "Cascadia Code", "editor.fontLigatures": true, - "git.enableCommitSigning": true + "git.enableCommitSigning": true, + "files.associations": { + "*.yaml": "home-assistant" + } } diff --git a/package.json b/package.json index e83225d..471f10c 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "dotenv": "^16.0.0", "i18next": "^21.6.13", "mongoose": "^6.2.3", + "node-schedule": "^2.1.0", "pino": "^7.0.0-rc.9", "quick.db": "^7.1.3", "uuid": "^8.3.2" diff --git a/src/commands/shop/addons/roles.js b/src/commands/shop/addons/roles.js new file mode 100644 index 0000000..ee14e2d --- /dev/null +++ b/src/commands/shop/addons/roles.js @@ -0,0 +1,24 @@ +const { v4: uuidv4 } = require('uuid'); +const axios = require('axios'); +const config = require('../../../../config.json'); +const logger = require('../../../handlers/logger'); + +const { credits, apis } = require('../../../helpers/database/models'); +const creditNoun = require('../../../helpers/creditNoun'); + +module.exports = async (interaction) => { + const name = interaction.options.getString('name'); + + guild.roles + .create({ + data: { + name, + color: 'BLUE', + }, + reason: `${interaction.member.id} bought from shop`, + }) + .then(console.log) + .catch(console.error); + + interaction.editReply({ content: 'Roles' }); +}; diff --git a/src/commands/shop/index.js b/src/commands/shop/index.js index 9fe4319..e36e30b 100644 --- a/src/commands/shop/index.js +++ b/src/commands/shop/index.js @@ -4,6 +4,7 @@ const { Permissions } = require('discord.js'); const guilds = require('../../helpers/database/models/guildSchema'); const pterodactyl = require('./addons/pterodactyl'); +const roles = require('./roles'); module.exports = { data: new SlashCommandBuilder() @@ -18,6 +19,31 @@ module.exports = { .setName('amount') .setDescription('How much credits you want to withdraw.') ) + ) + .addSubcommandGroup((group) => + group + .setName('roles') + .setDescription('Manage custom roles.') + .addSubcommand((command) => + command + .setName('buy') + .setDescription('Buy a custom role') + .addStringOption((option) => + option + .setName('name') + .setDescription('Name of the role you wish to purchase.') + ) + ) + .addSubcommand((command) => + command + .setName('cancel') + .setDescription('Cancel a custom role') + .addStringOption((option) => + option + .setName('name') + .setDescription('Name of the role you wish to cancel.') + ) + ) ), async execute(interaction) { // If subcommand is pterodactyl @@ -25,5 +51,11 @@ module.exports = { // Execute pterodactyl addon await pterodactyl(interaction); } + + // If subcommand group is roles + else if (interaction.options.getSubcommandGroup() === 'roles') { + // Execute roles addon + await roles(interaction); + } }, }; diff --git a/src/commands/shop/roles/addons/buy.js b/src/commands/shop/roles/addons/buy.js new file mode 100644 index 0000000..05bf353 --- /dev/null +++ b/src/commands/shop/roles/addons/buy.js @@ -0,0 +1,53 @@ +const { v4: uuidv4 } = require('uuid'); +const axios = require('axios'); +const config = require('../../../../../config.json'); +const logger = require('../../../../handlers/logger'); + +const { + credits, + apis, + shopRoles, + guilds, +} = require('../../../../helpers/database/models'); +const creditNoun = require('../../../../helpers/creditNoun'); + +module.exports = async (interaction) => { + const { member } = interaction; + + const name = await interaction.options.getString('name'); + + await interaction.guild.roles + .create({ + name, + color: 'RED', + reason: `${interaction.member.id} bought from shop`, + }) + .then(async (data) => { + // Get guild object + const guild = await guilds.findOne({ + guildId: interaction.member.guild.id, + }); + + const userObject = await credits.findOne({ + userId: member.id, + guildId: interaction.member.guild.id, + }); + const pricePerHour = guild.shop.roles.pricePerHour; + + userObject.balance -= pricePerHour; + + shopRoles.create({ + roleId: data.id, + userId: member.id, + guildId: member.guild.id, + pricePerHour, + lastPayed: new Date(), + }); + + interaction.member.roles.add(data.id); + shopRoles.find().then((data) => console.log(data)); + }) + .catch(console.error); + + await interaction.editReply({ content: 'Roles bought' }); +}; diff --git a/src/commands/shop/roles/addons/cancel.js b/src/commands/shop/roles/addons/cancel.js new file mode 100644 index 0000000..55fb7df --- /dev/null +++ b/src/commands/shop/roles/addons/cancel.js @@ -0,0 +1,13 @@ +const { v4: uuidv4 } = require('uuid'); +const axios = require('axios'); +const config = require('../../../../../config.json'); +const logger = require('../../../../handlers/logger'); + +const { credits, apis } = require('../../../../helpers/database/models'); +const creditNoun = require('../../../../helpers/creditNoun'); + +module.exports = async (interaction) => { + const name = interaction.options.getString('name'); + + interaction.editReply({ content: 'Roles canceled' }); +}; diff --git a/src/commands/shop/roles/addons/index.js b/src/commands/shop/roles/addons/index.js new file mode 100644 index 0000000..61e5b68 --- /dev/null +++ b/src/commands/shop/roles/addons/index.js @@ -0,0 +1,4 @@ +const buy = require('./buy'); +const cancel = require('./cancel'); + +module.exports = { buy, cancel }; diff --git a/src/commands/shop/roles/index.js b/src/commands/shop/roles/index.js new file mode 100644 index 0000000..b41e1de --- /dev/null +++ b/src/commands/shop/roles/index.js @@ -0,0 +1,29 @@ +const { Permissions } = require('discord.js'); +const config = require('../../../../config.json'); +const logger = require('../../../handlers/logger'); + +const { buy, cancel } = require('./addons'); + +module.exports = async (interaction) => { + // Destructure member + const { member } = interaction; + + // If subcommand is buy + if (interaction.options.getSubcommand() === 'buy') { + // Execute buy addon + await buy(interaction); + } + + // If subcommand is cancel + if (interaction.options.getSubcommand() === 'cancel') { + // Execute cancel addon + await cancel(interaction); + } + + // Send debug message + await logger.debug( + `Guild: ${member.guild.id} User: ${member.id} executed /${ + interaction.commandName + } ${interaction.options.getSubcommandGroup()} ${interaction.options.getSubcommand()}` + ); +}; diff --git a/src/events/guildCreate.js b/src/events/guildCreate.js index 1aa28f3..febf749 100644 --- a/src/events/guildCreate.js +++ b/src/events/guildCreate.js @@ -7,7 +7,10 @@ module.exports = { const { client } = guild; // Create guild object if not already created - await guilds.findOne({ guildId: guild.id }, { new: true, upsert: true }); + const guildExist = await guilds.findOne({ guildId: guild.id }); + if (!guildExist) { + await guilds.create({ guildId: guild.id }); + } // Set client status await client.user.setPresence({ diff --git a/src/handlers/index.js b/src/handlers/index.js index ab4a615..318fa71 100644 --- a/src/handlers/index.js +++ b/src/handlers/index.js @@ -1,5 +1,6 @@ const events = require('./events'); const commands = require('./commands'); const locale = require('./locale'); +const schedules = require('./schedules'); -module.exports = { events, commands, locale }; +module.exports = { events, commands, locale, schedules }; diff --git a/src/handlers/schedules.js b/src/handlers/schedules.js new file mode 100644 index 0000000..2e28287 --- /dev/null +++ b/src/handlers/schedules.js @@ -0,0 +1,52 @@ +const schedule = require('node-schedule'); +const { shopRoles, credits, guilds } = require('../helpers/database/models'); +const logger = require('./logger'); + +module.exports = async (client) => { + // schedule.scheduleJob('*/1 * * *', function () { + // console.log('The answer to life, the universe, and everything!'); + // }); + + schedule.scheduleJob('*/30 * * * *', async () => { + shopRoles.find().then(async (data) => { + data.map(async (role) => { + var payed = new Date(role.lastPayed); + + oneHourAfterPayed = payed.setHours(payed.getHours() + 1); + + if (new Date() > oneHourAfterPayed) { + // Get guild object + const guild = await guilds.findOne({ + guildId: role.guildId, + }); + + const userObject = await credits.findOne({ + userId: role.userId, + guildId: role.guildId, + }); + const pricePerHour = guild.shop.roles.pricePerHour; + + if (userObject.balance < pricePerHour) { + const rGuild = await client.guilds.cache.get(`${role.guildId}`); + let rMember = await rGuild.members.fetch(`${role.userId}`); + + await rMember.roles + .remove(`${role.roleId}`) + .then(console.log) + .catch(console.error); //Removes all roles + } + + role.lastPayed = new Date(); + role.save(); + userObject.balance -= pricePerHour; + userObject.save(); + await logger.debug( + `${role.roleId} was payed one hour later. BEFORE: ${payed} AFTER: ${oneHourAfterPayed} UPDATED: ${role.updatedAt} CREATED: ${role.createdAt}` + ); + } + }); + }); + + await logger.debug('Checking schedules! (Every 30 minutes)'); + }); +}; diff --git a/src/helpers/database/models/guildSchema.js b/src/helpers/database/models/guildSchema.js index ca8c5c2..c55f867 100644 --- a/src/helpers/database/models/guildSchema.js +++ b/src/helpers/database/models/guildSchema.js @@ -40,6 +40,14 @@ const guildSchema = new mongoose.Schema( default: 900000, }, }, + shop: { + roles: { + pricePerHour: { + type: mongoose.SchemaTypes.Number, + default: 5, + }, + }, + }, points: { status: { type: mongoose.SchemaTypes.Boolean, diff --git a/src/helpers/database/models/index.js b/src/helpers/database/models/index.js index 564c89d..c0bfca4 100644 --- a/src/helpers/database/models/index.js +++ b/src/helpers/database/models/index.js @@ -5,6 +5,7 @@ const guilds = require('./guildSchema'); const apis = require('./apiSchema'); const timeouts = require('./timeoutSchema'); const counters = require('./counterSchema'); +const shopRoles = require('./shopRolesSchema'); module.exports = { credits, @@ -14,4 +15,5 @@ module.exports = { apis, timeouts, counters, + shopRoles, }; diff --git a/src/helpers/database/models/shopRolesSchema.js b/src/helpers/database/models/shopRolesSchema.js new file mode 100644 index 0000000..6a8ff36 --- /dev/null +++ b/src/helpers/database/models/shopRolesSchema.js @@ -0,0 +1,39 @@ +const mongoose = require('mongoose'); + +const shopRoleSchema = new mongoose.Schema( + { + roleId: { + type: mongoose.SchemaTypes.Decimal128, + required: true, + unique: false, + index: true, + }, + userId: { + type: mongoose.SchemaTypes.Decimal128, + required: true, + unique: false, + index: true, + }, + guildId: { + type: mongoose.SchemaTypes.Decimal128, + required: true, + unique: false, + index: true, + }, + pricePerHour: { + type: mongoose.SchemaTypes.Number, + required: true, + unique: false, + index: true, + default: 5, + }, + lastPayed: { + type: mongoose.SchemaTypes.Date, + unique: false, + index: true, + }, + }, + { timestamps: true } +); + +module.exports = mongoose.model('shopRole', shopRoleSchema); diff --git a/src/index.js b/src/index.js index e5c563c..a4e037c 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,7 @@ const { Client, Intents } = require('discord.js'); // discord.js const { database } = require('./helpers'); // helpers -const { events, commands, locale } = require('./handlers'); // handlers +const { events, commands, locale, schedules } = require('./handlers'); // handlers const config = require('../config.json'); // config.json @@ -16,6 +16,7 @@ const config = require('../config.json'); // config.json await locale(); await events(client); await commands(client); + await schedules(client); await client.login(config.bot.token); })();