Discord License Management Bot

This Python bot manages licenses for a Discord server, featuring a NoSQL database backend (via JSON files) to store user data and payment information. It includes admin commands for user management and general commands for key generation and payment checks.

Setup Tutorial

Follow these steps to set up your Discord License Management Bot:

  1. Create a Discord Bot:
    • Visit the Discord Developer Portal.
    • Click "New Application" and give it a name.
    • Go to the "Bot" tab and click "Add Bot".
    • Copy the bot token and keep it secure.
  2. Invite the Bot to Your Server:
    • In the Developer Portal, go to the "OAuth2" tab.
    • Under "Scopes", select "bot".
    • Choose permissions (e.g., Send Messages, Manage Roles).
    • Copy the invite link and open it to add the bot.
  3. Set Up the Required Files:
    • Create database.json with:
      {"ids": []}
    • Ensure successful_payments.json exists or is handled.
  4. Install Dependencies:
    • Ensure Python 3.8+ is installed.
    • Install packages:
      pip install discord.py requests
  5. Run the Bot:
    • Replace [redacted] with your admin ID, token, and API URLs.
    • Save as bot.py and run:
      python bot.py

Notes:

  • Ensure bot permissions are set in your server.
  • Test with $help after running.
  • Keep your token secure.

1. Importing Modules

These modules provide functionality for Discord integration, file handling, asynchronous operations, and more.


import discord
from discord.ext import commands
import time
import random
import requests
import subprocess
import socket
import threading
import json
import asyncio
import os
from datetime import datetime
            

2. Constants and Variables

Defines the bot's configuration, including admin ID, token, intents, and file paths. Sensitive data is redacted for this showcase.


whitelisted_admin = [redacted]  # Admin user ID
token = "[redacted]"           # Bot token
intents = discord.Intents.default()
intents.message_content = True
client = commands.Bot(command_prefix="$", intents=intents)
rgb_color = (0, 0, 0)          # Embed color in RGB
hex_color = f'#{rgb_color[0]:02x}{rgb_color[1]:02x}{rgb_color[2]:02x}'
payments_file = 'successful_payments.json'  # File for payment data
            

3. Helper Functions

Utility functions for managing payment data and user permissions.


# Loads successful payments from JSON file
def load_successful_payments():
    if os.path.exists(payments_file):
        with open(payments_file, 'r') as file:
            return json.load(file)
    return {}

# Saves updated payment data to JSON file
def save_successful_payments(payments):
    with open(payments_file, 'w') as file:
        json.dump(payments, file, indent=4)

# Checks if a user is in the allowed list
def is_allowed(user_id):
    with open("users.txt", "r") as file:
        allowed_users = file.read().splitlines()
    return str(user_id) in allowed_users
            

4. Bot Setup and Presence

Sets up the bot's online presence and initializes it when ready.


# Updates bot presence every 1.5 seconds
async def send_ppx():
    await client.wait_until_ready()
    while not client.is_closed():
        await client.change_presence(
            status=discord.Status.online,
            activity=discord.Game(name="$help")
        )
        await asyncio.sleep(1.5)

# Triggered when bot is fully connected
@client.event
async def on_ready():
    threading.Thread(
        target=lambda: client.loop.create_task(send_ppx())
    ).start()
    print("Bot initialized")
            

5. Message Event Handler

Handles all incoming messages and processes commands. Comments within denote each command's purpose.


@client.event
async def on_message(message):
    user_id = message.author.id
    if message.author == client.user:
        return

    # Load database
    try:
        with open('database.json') as fw:
            data_amp = json.load(fw)
    except FileNotFoundError:
        print("File 'database.json' not found.")
        exit(1)
    except Exception as e:
        print("An error occurred:", e)
        exit(1)

    auth = user_id

    # Forward DMs to admin
    if isinstance(message.channel, discord.DMChannel):
        target_user = await client.fetch_user(whitelisted_admin)
        if target_user:
            await target_user.send(
                f"`[{datetime.now()}] Received DM from {message.author}`\n```{message.content}```"
            )

    # Command: $dmuser - Sends DM to a user (admin only)
    if message.content.startswith("$dmuser"):
        if message.author.id == whitelisted_admin:
            args = message.content.split()[1:]
            if len(args) >= 2:
                id_, msg = args[0], ' '.join(args[1:])
                target_user = await client.fetch_user(int(id_))
                await target_user.send(f"{msg}")
                await message.reply("Sent message to user.")
            else:
                await message.reply("Provide user ID and message.")
        else:
            embed = discord.Embed(
                title="__Information__",
                description="`You do not have access to this command.`",
                color=int(hex_color[1:], 16)
            )
            embed.set_thumbnail(url="[redacted]")
            await message.reply(embed=embed)

    # Command: $remove - Removes user from whitelist (admin only)
    if message.content.startswith("$remove"):
        if message.author.id == whitelisted_admin:
            text = message.content[len('$remove'):].strip()
            with open("database.json", 'r') as file:
                data = json.load(file)
            removed = False
            for idx, entry in enumerate(data["ids"]):
                if entry["id"] == int(text):
                    del data["ids"][idx]
                    removed = True
                    break
            if removed:
                with open("database.json", 'w') as file:
                    json.dump(data, file, indent=4)
                embed = discord.Embed(
                    title="__Information__",
                    description=f"`Successfully removed {text} from whitelist.`",
                    color=int(hex_color[1:], 16)
                )
                embed.set_thumbnail(url="[redacted]")
                await message.reply(embed=embed)
            else:
                embed = discord.Embed(
                    title="__Information__",
                    description=f"`ID {text} not found.`",
                    color=int(hex_color[1:], 16)
                )
                embed.set_thumbnail(url="[redacted]")
                await message.reply(embed=embed)
        else:
            embed = discord.Embed(
                title="__Information__",
                description="`You do not have access to this command.`",
                color=int(hex_color[1:], 16)
            )
            embed.set_thumbnail(url="[redacted]")
            await message.reply(embed=embed)

    # Command: $credsadd - Adds credits to a user (admin only)
    if message.content.startswith("$credsadd"):
        if message.author.id == whitelisted_admin:
            args = message.content.split()[1:]
            if len(args) == 2:
                id_user, credits = args
                with open('database.json', 'r') as file:
                    data = json.load(file)
                for entry in data['ids']:
                    if entry['id'] == int(id_user):
                        entry['credits'] += int(credits)
                        with open('database.json', 'w') as file:
                            json.dump(data, file, indent=4)
                        embed = discord.Embed(
                            title="__Information__",
                            description=f"```Added {credits} credits to {id_user}.```",
                            color=int(hex_color[1:], 16)
                        )
                        embed.set_thumbnail(url="[redacted]")
                        await message.reply(embed=embed)
                        break
                else:
                    embed = discord.Embed(
                        title="__Information__",
                        description="`User not found.`",
                        color=int(hex_color[1:], 16)
                    )
                    embed.set_thumbnail(url="[redacted]")
                    await message.reply(embed=embed)
            else:
                embed = discord.Embed(
                    title="__Information__",
                    description="`Incorrect arguments.`",
                    color=int(hex_color[1:], 16)
                )
                embed.set_thumbnail(url="[redacted]")
                await message.reply(embed=embed)
        else:
            embed = discord.Embed(
                title="__Information__",
                description="`You do not have access to this command.`",
                color=int(hex_color[1:], 16)
            )
            embed.set_thumbnail(url="[redacted]")
            await message.reply(embed=embed)

    # Command: $add - Adds a new user with credits (admin only)
    if message.content.startswith("$add"):
        if message.author.id == whitelisted_admin:
            args = message.content.split()[1:]
            if len(args) == 2:
                ida, credits = args
                new_id = {"id": int(ida), "credits": int(credits)}
                with open("database.json", "r") as json_file:
                    data = json.load(json_file)
                data["ids"].append(new_id)
                with open("database.json", "w") as json_file:
                    json.dump(data, json_file, indent=4)
                guild = message.guild
                member = await guild.fetch_member(int(ida))
                if member:
                    pro_role = discord.utils.get(guild.roles, name="pro")
                    customer_role = discord.utils.get(guild.roles, name="customer")
                    if pro_role:
                        await member.add_roles(pro_role)
                    if customer_role:
                        await member.add_roles(customer_role)
                    embed = discord.Embed(
                        title="__Information__",
                        description=f"```Added {member} as customer.\nCredits: {credits}```",
                        color=int(hex_color[1:], 16)
                    )
                    embed.set_thumbnail(url="[redacted]")
                    await message.reply(embed=embed)
                else:
                    await message.reply("User not found in guild.")
            else:
                embed = discord.Embed(
                    title="__Information__",
                    description="`Incorrect arguments.`",
                    color=int(hex_color[1:], 16)
                )
                embed.set_thumbnail(url="[redacted]")
                await message.reply(embed=embed)
        else:
            embed = discord.Embed(
                title="__Information__",
                description="`You do not have access to this command.`",
                color=int(hex_color[1:], 16)
            )
            embed.set_thumbnail(url="[redacted]")
            await message.reply(embed=embed)

    # Command: $show - Displays whitelisted users (admin only)
    if message.content == "$show":
        if message.author.id == whitelisted_admin:
            with open("database.json", "r") as filae:
                datawa = json.load(filae)
            stra = ""
            for item in datawa["ids"]:
                stra += f"ID: {item['id']}\nCredits: {item['credits']}\n\n"
            embed = discord.Embed(
                title="__Whitelisted Users__",
                description=f"```{stra}```",
                color=int(hex_color[1:], 16)
            )
            embed.set_thumbnail(url="[redacted]")
            await message.reply(embed=embed)
        else:
            embed = discord.Embed(
                title="__Information__",
                description="`You do not have access to this command.`",
                color=int(hex_color[1:], 16)
            )
            embed.set_thumbnail(url="[redacted]")
            await message.reply(embed=embed)

    # Command: $pay - Shows payment methods
    if message.content == "$pay":
        embed = discord.Embed(
            title="__Payment Methods__",
            description="[redacted]\nMAKE SURE TO FILL IN YOUR DISCORD USERNAME!",
            color=int(hex_color[1:], 16)
        )
        embed.set_thumbnail(url="[redacted]")
        await message.reply(embed=embed)

    # Command: $admin - Displays admin commands (admin only)
    if message.content == "$admin":
        if auth == whitelisted_admin:
            embed = discord.Embed(title="__Admin Menu__", color=int(hex_color[1:], 16))
            embed.add_field(name="$add `id` `credits`", value="Adds user to whitelist", inline=False)
            embed.add_field(name="$remove `id`", value="Removes user from whitelist", inline=False)
            embed.add_field(name="$dmuser `id` `message`", value="DMs a user", inline=False)
            embed.add_field(name="$show", value="Shows whitelisted users", inline=False)
            embed.set_thumbnail(url="[redacted]")
            await message.reply(embed=embed)
        else:
            embed = discord.Embed(
                title="__Information__",
                description="`You do not have access to this command.`",
                color=int(hex_color[1:], 16)
            )
            embed.set_thumbnail(url="[redacted]")
            await message.reply(embed=embed)

    # Command: $help - Displays user commands
    if message.content == "$help":
        embed = discord.Embed(title="__Help__", color=int(hex_color[1:], 16))
        embed.add_field(name="$pay", value="Sends payment link.", inline=False)
        embed.add_field(name="$check", value="Redeems payment for a token.", inline=False)
        embed.add_field(name="$generate_key", value="Generates a key using a token.", inline=False)
        embed.set_thumbnail(url="[redacted]")
        await message.reply(embed=embed)

    # Command: $generate_key - Generates a key if user has credits
    if message.content == "$generate_key":
        pro_role = discord.utils.get(message.author.roles, name="pro")
        if pro_role:
            user_found = False
            for entry in data_amp['ids']:
                if entry['id'] == user_id:
                    user_found = True
                    if entry['credits'] > 0:
                        entry['credits'] -= 1
                        with open('database.json', 'w') as file:
                            json.dump(data_amp, file, indent=4)
                        guild = message.guild
                        member = await guild.fetch_member(int(user_id))
                        api_url = "[redacted]"
                        response = requests.get(api_url)
                        if response.status_code == 200:
                            embed = discord.Embed(
                                title="__Information__",
                                description=f"```Generated key for {member}.\nCheck DM.```",
                                color=int(hex_color[1:], 16)
                            )
                            embed.set_thumbnail(url="[redacted]")
                            await message.reply(embed=embed)
                            key = response.text.strip()
                            await message.author.send(
                                f"Your key: `{key}`\nCredits left: {entry['credits']}"
                            )
                        else:
                            await message.author.send("Failed to generate key.")
                    else:
                        await message.reply("Not enough credits.")
                    break
            if not user_found:
                await message.reply("You do not have access.")
        else:
            await message.reply("You do not have access.")

    # Command: $check - Verifies payment and adds credits
    if message.content.startswith("$check"):
        successful_payments = load_successful_payments()
        username = message.author.name
        if username in successful_payments:
            user_entry = next(
                (entry for entry in data_amp['ids'] if entry['id'] == user_id), None
            )
            if user_entry:
                user_entry['credits'] += 1
            else:
                new_entry = {"id": user_id, "credits": 1}
                data_amp['ids'].append(new_entry)
            with open('database.json', 'w') as file:
                json.dump(data_amp, file, indent=4)
            await message.reply(f"Added a token to {message.author.mention}!")
            guild = message.guild
            member = message.author
            if member:
                pro_role = discord.utils.get(guild.roles, name="pro")
                customer_role = discord.utils.get(guild.roles, name="customer")
                if pro_role:
                    await member.add_roles(pro_role)
                if customer_role:
                    await member.add_roles(customer_role)
                embed = discord.Embed(
                    title="__Information__",
                    description="```Successfully redeemed!```",
                    color=int(hex_color[1:], 16)
                )
                embed.set_thumbnail(url="[redacted]")
                await message.reply(embed=embed)
            del successful_payments[username]
            save_successful_payments(successful_payments)
        else:
            await message.reply("Payment not found.")

# Start the bot
client.run(token)