diff --git a/README.md b/README.md index 30af309..5450016 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,23 @@ # DiscordKeyBot -Distribute game or license keys via Discord \ No newline at end of file +DiscordKeyBot is a bot designed to securely distribute Steam game keys to users in your Discord server. Admins can upload lists of keys, set a logging channel for bot warnings, and post an official registration message for users to claim their keys. The bot tracks which users have claimed keys, enforces eligibility based on server join date, and provides admin tools for key management. Warnings are sent to the logging channel when keys run low or if users encounter issues. + +## How to setup bot + +1. Run `npm install` to install dependencies. +2. Run `npm run register` to register the bot's slash commands globally. +3. Run `npm start` to launch the bot. + +## How to use the bot + +- **Set the logging channel:** + Before using the registration feature, run `/keys logging` and select the channel where you want bot warnings and notifications to be sent. +- **Upload keys:** + Use `/keys load` and upload a text file with one Steam key per line. The bot will send a confirmation message saying how many keys are in the file. Confirm the upload to add keys to the vault. +- **Post registration message:** + Run `/register` to send an official message with a "Claim Key" button. Users who are eligible can click the button to receive a key via DM. + +### Manually get users' keys + +Admins can use `/keys get` and select a user to view their registered key. +To check how many keys are left, use `/keys check`. \ No newline at end of file diff --git a/index.js b/index.js index 25cebe7..3e43257 100644 --- a/index.js +++ b/index.js @@ -83,10 +83,6 @@ client.once(Events.ClientReady, async () => { client.on(Events.InteractionCreate, async interaction => { // Slash command: /register if (interaction.isChatInputCommand() && interaction.commandName === 'register') { - if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) { - return interaction.reply({ content: 'You must be an administrator.', ephemeral: true }); - } - // Check if loggingChannel is set if (!data.loggingChannel) { return interaction.reply({ @@ -117,10 +113,6 @@ client.on(Events.InteractionCreate, async interaction => { // Slash command: /key if (interaction.isChatInputCommand() && interaction.commandName === 'keys') { - if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) { - return interaction.reply({ content: 'You must be an administrator.', ephemeral: true }); - } - const sub = interaction.options.getSubcommand(); // /key load @@ -178,9 +170,6 @@ client.on(Events.InteractionCreate, async interaction => { // /keys logging if (sub === 'logging') { - if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) { - return interaction.reply({ content: 'You must be an administrator.', ephemeral: true }); - } const channel = interaction.options.getChannel('channel'); if (!channel) { return interaction.reply({ content: 'Invalid channel.', ephemeral: true }); @@ -195,9 +184,6 @@ client.on(Events.InteractionCreate, async interaction => { // Handle key load confirmation buttons if (interaction.isButton() && (interaction.customId === 'key_load_yes' || interaction.customId === 'key_load_no')) { - if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) { - return interaction.reply({ content: 'You must be an administrator.', ephemeral: true }); - } if (!client.tempKeyLoads || !client.tempKeyLoads[interaction.user.id]) { return interaction.reply({ content: 'No pending key load found.', ephemeral: true }); } @@ -283,40 +269,6 @@ client.on(Events.InteractionCreate, async interaction => { return interaction.reply({ content: 'Unable to send DM. Please change your privacy settings or reach out to <@404872989188816906> in <#580122303342313473> for support!', ephemeral: true }); } } - - // Slash command: /setlogging - if (interaction.isChatInputCommand() && interaction.commandName === 'setlogging') { - if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) { - return interaction.reply({ content: 'You must be an administrator.', ephemeral: true }); - } - const channel = interaction.options.getChannel('channel'); - if (!channel) { - return interaction.reply({ content: 'Invalid channel.', ephemeral: true }); - } - data = loadData(); - data.loggingChannel = channel.id; - saveData(data); - await channel.send(`Successfully set logging channel for all Swordcery Key Bot-related messages to <#${channel.id}>.`); - return interaction.reply({ content: `Logging channel set to <#${channel.id}>.`, ephemeral: true }); - } - - // Slash command: /getkey - if (interaction.isChatInputCommand() && interaction.commandName === 'getkey') { - if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) { - return interaction.reply({ content: 'You must be an administrator.', ephemeral: true }); - } - const user = interaction.options.getUser('user'); - if (!user) { - return interaction.reply({ content: 'Invalid user.', ephemeral: true }); - } - data = loadData(); - const found = data.users.find(u => u.id === user.id); - if (found && found.key) { - return interaction.reply({ content: `User <@${user.id}> has registered key: \`${found.key}\``, ephemeral: true }); - } else { - return interaction.reply({ content: `User <@${user.id}> does not have a registered key.`, ephemeral: true }); - } - } }); client.login(TOKEN); diff --git a/register.js b/register.js index 972d8c6..6ad9cb9 100644 --- a/register.js +++ b/register.js @@ -1,9 +1,9 @@ import 'dotenv/config'; -import { REST, Routes } from 'discord.js'; +import { REST, Routes, PermissionsBitField } from 'discord.js'; const TOKEN = process.env.DISCORD_TOKEN; const CLIENT_ID = process.env.DISCORD_CLIENT_ID; -const ADMIN_PERM = 0x00000008; +const ADMIN_PERM = PermissionsBitField.Flags.ManageGuild | PermissionsBitField.Flags.BanMembers; const commands = [ {