.  
 What it handled was: 
- Roblox account verifications (Verify users with over 100k / 1m / 25k in limiteds and role them) 
- Alt detection (If someone tries to verify with the same account, it'll deny their report and send an embed with buttons below to either approve or deny them in a private channel) 
- Send out embeds for the other types of verifications
- Handle self roles to give them out to other users
- Purge specific channels (deleting them, recreating them with the channels old permissions) the chatting channels get purged every hour. 
- Sends out reaction emojis to posts being made under specific channels. 
- Auto moderates channels where people are supposed to ping a specific role. If they send a message without pinging that specific role, their message gets deleted and they get a warning dm with a strike role given to them. If they get all 3 strike roles and they break another rule. The 4th strike would be them getting blacklisted (with all their stocker roles being removed)  **(You'll be sent the whole source code for the old bot)**
 
One of the problems is, my server keeps getting false banned by discord and it takes a long time to set everything up:
- I wanted to recreate the bot into setting up all the channels, roles, and restoring the roles of all our members with what they had before. Our current database only supports roles that was given out by the bot, not ones that was given out manually (which is 80% of all the roles) I also want the bot to save and resend all of our embeds that are sent to specific channels. 

New additions: 
- Scam report form (similar to HD) It asks for user id / what happened / proof media to drop images + videos. Once the form is submitted, it sends an embed of the report / with the proof below. The report has 2 buttons. 
If approved, it'll show another prompt which gives them the option to  role them "Scammer" "Blacklisted"  or both. If blacklisted is chosen, it'll take away all their stocker roles (ill give you the list of those roles) and role them blacklisted, when it's approved it'll also make the report public by posting it in the scam alerts channel and ping @Scam Alerts.
 If denied, the embed just gets edited with status "Denied" and the embed turning red (in the staff channel without getting posted in public) 
- Notes database: Our staff uses dyno notes to assign to members depending on the rules they broke or how many strikes theyve had. Scammer reports are also noted via the notes feature. Since our server keeps getting deleted, we would like to have our own notes feature on our own bot with it being saved on a database
- Temp blacklist commands: We want application commands where staff can assign temporary blacklists to users who broke the rules which gives them a temporary blacklist. The staff has the option to blacklist them for 1 day, 3 days, 7 days, or 14 days. Once the timer is up, their blacklist role will be removed automatically with their stocker roles being applied again
- Revamp of our application process (will give more info after)

# bot.py

import os
import io
import asyncio
from datetime import datetime, timedelta

import nextcord
from nextcord.ext import commands, tasks
from nextcord import Interaction, SlashOption, ChannelType, Permissions
from nextcord.ui import Modal, TextInput, Button, View, Select
from nextcord.utils import get
from dotenv import load_dotenv
import motor.motor_asyncio
import aiohttp
import urllib.parse

# Load environment variables
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
MONGO_URI = os.getenv('MONGO_URI')
ROLIMONS_API_KEY = os.getenv('ROLIMONS_API_KEY')

# MongoDB setup
mongo_client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_URI)
db = mongo_client['discord_bot']

# Discord Intents
intents = nextcord.Intents.all()
intents.members = True  # Subscribe to the privileged members intent.
intents.message_content = True  # Message content intent required for reading message content.

# Bot setup
bot = commands.Bot(command_prefix='!', intents=intents)

# Replace with your actual IDs
YOUR_GUILD_ID = 123456789012345678  # Replace with your server's ID
YOUR_STAFF_CHANNEL_ID = 123456789012345678  # Replace with your staff channel ID
BLACKLIST_ROLE_ID = 123456789012345678  # Replace with your blacklist role ID
SCAMMER_ROLE_ID = 123456789012345678  # Replace with your scammer role ID
ROLE_ID_FOR_1M = 123456789012345678  # Replace with your role ID for 1M+
ROLE_ID_FOR_100K = 123456789012345678  # Replace with your role ID for 100K+
ROLE_ID_FOR_25K = 123456789012345678  # Replace with your role ID for 25K+

# -------------------------------------------------
# Utility Functions
# -------------------------------------------------


async def get_total_value(roblox_id):
    total_value = 0
    async with aiohttp.ClientSession() as session:
        # Get the player's inventory
        async with session.get(f'https://www.rolimons.com/playerapi/player/{roblox_id}') as resp:
            if resp.status != 200:
                return None
            data = await resp.json()
            # Check if the player is banned or private
            if not data.get('success', False):
                return None

            inventory_items = data.get('player', {}).get('item_values', {})
            # Get item details from Rolimons API
            async with session.get('https://www.rolimons.com/itemapi/itemdetails') as items_resp:
                if items_resp.status != 200:
                    return None
                items_data = await items_resp.json()
                item_details = items_data.get('items', {})

            # Sum up the values of the items in the player's inventory
            for item_id_str, item_count in inventory_items.items():
                item_id = int(item_id_str)
                item_info = item_details.get(item_id_str)
                if item_info:
                    item_value = item_info[3]  # Index 3 corresponds to the RAP or Value
                    total_value += item_value * item_count

    return total_value


async def download_attachment(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            if resp.status == 200:
                data = await resp.read()
                return nextcord.File(io.BytesIO(data), filename=url.split('/')[-1])
    return None

# -------------------------------------------------
# Event Handlers
# -------------------------------------------------


@bot.event
async def on_ready():
    print(f'Logged in as {bot.user} (ID: {bot.user.id})')
    print('------')
    check_blacklists.start()  # Start the background task
    check_purges.start()
    backup_database.start()
    print("Background tasks started.")


@bot.event
async def on_member_update(before, after):
    if before.roles != after.roles:
        await track_roles(after)


@bot.event
async def on_member_join(member):
    await restore_member_roles(member)

# -------------------------------------------------
# Commands and Features
# -------------------------------------------------

# Server Snapshot and Restoration
@bot.slash_command(name='snapshot', description='Take a snapshot of the server structure and configuration.')
@commands.has_permissions(administrator=True)
async def snapshot(interaction: Interaction):
    await interaction.response.defer(ephemeral=True)
    guild = interaction.guild

    # Capture roles
    roles = []
    for role in guild.roles:
        roles.append({
            'id': role.id,
            'name': role.name,
            'permissions': role.permissions.value,
            'color': role.color.value,
            'hoist': role.hoist,
            'position': role.position,
            'mentionable': role.mentionable,
            'managed': role.managed
        })

    # Capture channels
    channels = []
    for channel in guild.channels:
        overwrites = []
        for target, overwrite in channel.overwrites.items():
            target_id = target.id if isinstance(target, (nextcord.Role, nextcord.Member)) else target
            overwrites.append({
                'id': target_id,
                'type': 'role' if isinstance(target, nextcord.Role) else 'member',
                'allow': overwrite.pair()[0].value,
                'deny': overwrite.pair()[1].value
            })

        channels.append({
            'id': channel.id,
            'name': channel.name,
            'type': str(channel.type),
            'position': channel.position,
            'category_id': channel.category_id,
            'overwrites': overwrites
        })

    # Capture messages from important channels (e.g., announcements)
    messages = []
    important_channels = ['announcements', 'rules']  # Add your important channel names
    for channel_name in important_channels:
        channel = get(guild.channels, name=channel_name)
        if channel:
            async for message in channel.history(limit=100):  # Adjust limit as needed
                messages.append({
                    'channel_id': channel.id,
                    'content': message.content,
                    'embeds': [embed.to_dict() for embed in message.embeds],
                    'attachments': [attachment.url for attachment in message.attachments],
                    'author_id': message.author.id,
                    'timestamp': message.created_at.isoformat()
                })

    # Save snapshot to database
    snapshot_data = {
        'guild_id': guild.id,
        'timestamp': datetime.utcnow(),
        'roles': roles,
        'channels': channels,
        'messages': messages
        # Add more data if needed
    }
    await db.snapshots.insert_one(snapshot_data)
    await interaction.followup.send('Server snapshot has been taken.', ephemeral=True)


@bot.slash_command(name='restore', description='Restore the server from the latest snapshot.')
@commands.has_permissions(administrator=True)
async def restore(interaction: Interaction):
    await interaction.response.defer(ephemeral=True)
    guild = interaction.guild

    # Fetch the latest snapshot
    snapshot = await db.snapshots.find_one({'guild_id': guild.id}, sort=[('timestamp', -1)])
    if not snapshot:
        await interaction.followup.send('No snapshot available to restore.', ephemeral=True)
        return

    # Restore roles
    existing_roles = {role.name: role for role in guild.roles}
    role_mapping = {}  # Map old role IDs to new role IDs

    for role_data in snapshot['roles']:
        if role_data['name'] in existing_roles:
            role = existing_roles[role_data['name']]
            await role.edit(
                permissions=nextcord.Permissions(role_data['permissions']),
                color=nextcord.Color(role_data['color']),
                hoist=role_data['hoist'],
                mentionable=role_data['mentionable']
            )
        else:
            role = await guild.create_role(
                name=role_data['name'],
                permissions=nextcord.Permissions(role_data['permissions']),
                color=nextcord.Color(role_data['color']),
                hoist=role_data['hoist'],
                mentionable=role_data['mentionable']
            )
        role_mapping[role_data['id']] = role.id

    # Restore channels
    existing_channels = {channel.name: channel for channel in guild.channels}
    channel_mapping = {}  # Map old channel IDs to new channel IDs

    for channel_data in snapshot['channels']:
        # Resolve category
        category = None
        if channel_data['category_id']:
            category_id = channel_mapping.get(channel_data['category_id'], channel_data['category_id'])
            category = guild.get_channel(category_id)

        # Prepare overwrites
        overwrites = {}
        for overwrite_data in channel_data['overwrites']:
            target = None
            if overwrite_data['type'] == 'role':
                target = guild.get_role(role_mapping.get(overwrite_data['id'], overwrite_data['id']))
            else:
                target = guild.get_member(overwrite_data['id'])
            if target:
                overwrite = nextcord.PermissionOverwrite.from_pair(
                    nextcord.Permissions(overwrite_data['allow']),
                    nextcord.Permissions(overwrite_data['deny'])
                )
                overwrites[target] = overwrite

        # Recreate channels
        if channel_data['type'] == 'ChannelType.category':
            channel = await guild.create_category(
                name=channel_data['name'],
                overwrites=overwrites,
                position=channel_data['position']
            )
        elif channel_data['type'] == 'ChannelType.voice':
            channel = await guild.create_voice_channel(
                name=channel_data['name'],
                overwrites=overwrites,
                position=channel_data['position'],
                category=category
            )
        else:
            channel = await guild.create_text_channel(
                name=channel_data['name'],
                overwrites=overwrites,
                position=channel_data['position'],
                category=category
            )
        channel_mapping[channel_data['id']] = channel.id

    # Repost important messages
    for message_data in snapshot.get('messages', []):
        channel = guild.get_channel(channel_mapping.get(message_data['channel_id']))
        if channel:
            files = []
            for url in message_data['attachments']:
                file = await download_attachment(url)
                if file:
                    files.append(file)
            await channel.send(
                content=message_data['content'],
                embeds=[nextcord.Embed.from_dict(embed) for embed in message_data['embeds']],
                files=files
            )

    await interaction.followup.send('Server restoration completed.', ephemeral=True)


# Enhanced Role Management
async def track_roles(member):
    role_ids = [role.id for role in member.roles if role != member.guild.default_role]
    role_data = {
        'user_id': member.id,
        'guild_id': member.guild.id,
        'roles': role_ids,
        'timestamp': datetime.utcnow()
    }
    await db.user_roles.update_one(
        {'user_id': member.id, 'guild_id': member.guild.id},
        {'$set': role_data},
        upsert=True
    )


async def restore_member_roles(member):
    data = await db.user_roles.find_one({'user_id': member.id, 'guild_id': member.guild.id})
    if data:
        role_ids = data.get('roles', [])
        roles = [member.guild.get_role(role_id) for role_id in role_ids if member.guild.get_role(role_id)]
        await member.add_roles(*roles)
        print(f"Restored roles for {member}")


# User Verification and Account Management
@bot.slash_command(name='verify', description='Verify your Roblox account.')
async def verify(interaction: Interaction):
    await interaction.response.defer(ephemeral=True)

    async def message_check(msg):
        return msg.author == interaction.user and isinstance(msg.channel, nextcord.DMChannel)

    try:
        await interaction.user.send('Please enter your Roblox username:')
        username_msg = await bot.wait_for('message', check=message_check, timeout=60)
        username = username_msg.content.strip()

        # Fetch Roblox User ID
        async with aiohttp.ClientSession() as session:
            async with session.get(f'https://api.roblox.com/users/get-by-username?username={urllib.parse.quote(username)}') as resp:
                data = await resp.json()
                if 'Id' not in data or data['Id'] == 0:
                    await interaction.user.send('Invalid Roblox username.')
                    return
                roblox_id = data['Id']

            # Generate a verification code and instruct the user to set it in their status
            code_phrase = f"Discord Verification Code: {interaction.user.id}"
            await interaction.user.send(f"Please set the following phrase in your Roblox status and reply 'done' when finished:\n\n{code_phrase}")
            response_msg = await bot.wait_for('message', check=message_check, timeout=300)
            if response_msg.content.lower() != 'done':
                await interaction.user.send('Verification cancelled.')
                return

            # Check if the code_phrase is present in their status
            async with session.get(f'https://users.roblox.com/v1/users/{roblox_id}/status') as status_resp:
                if status_resp.status != 200:
                    await interaction.user.send('Failed to retrieve your Roblox status.')
                    return
                status_data = await status_resp.json()
                status = status_data.get('status', '')
                if code_phrase not in status:
                    await interaction.user.send('Verification phrase not found in your Roblox status.')
                    return

            # Alt account detection
            existing_verification = await db.verifications.find_one({'roblox_id': roblox_id})
            if existing_verification and existing_verification['discord_id'] != interaction.user.id:
                # Notify staff
                staff_channel = bot.get_channel(YOUR_STAFF_CHANNEL_ID)
                if staff_channel:
                    embed = nextcord.Embed(title='Alt Account Detected', color=nextcord.Color.red())
                    embed.add_field(name='Discord User', value=interaction.user.mention)
                    embed.add_field(name='Roblox Username', value=username)
                    embed.add_field(name='Roblox ID', value=roblox_id)
                    await staff_channel.send(embed=embed)
                await interaction.user.send('Your verification requires manual approval due to potential alt account detection.')
                return

            # Verify limited values using Rolimons API
            total_value = await get_total_value(roblox_id)
            if total_value is None:
                await interaction.user.send('Failed to retrieve your limited values.')
                return

            # Assign roles based on total_value
            guild = bot.get_guild(YOUR_GUILD_ID)
            member = guild.get_member(interaction.user.id)

            assigned_role = None
            if total_value >= 1_000_000:
                assigned_role = guild.get_role(ROLE_ID_FOR_1M)
            elif total_value >= 100_000:
                assigned_role = guild.get_role(ROLE_ID_FOR_100K)
            elif total_value >= 25_000:
                assigned_role = guild.get_role(ROLE_ID_FOR_25K)

            if assigned_role:
                await member.add_roles(assigned_role)
                await interaction.user.send(f'Verification successful! You have been assigned the {assigned_role.name} role.')
                await db.verifications.update_one(
                    {'discord_id': interaction.user.id},
                    {'$set': {'roblox_id': roblox_id, 'total_value': total_value}},
                    upsert=True
                )
            else:
                await interaction.user.send('You do not meet the value requirements for any role.')

    except asyncio.TimeoutError:
        await interaction.user.send('Verification timed out.')
    except Exception as e:
        print(f'Error during verification: {e}')
        await interaction.user.send('An error occurred during verification.')

# Advanced Moderation Tools
@bot.slash_command(name='report', description='Report a scammer or rule violator.')
async def report(interaction: Interaction):
    modal = Modal(title='Scam Report')

    user_id_input = TextInput(label='User ID', placeholder='Enter the User ID', required=True)
    description_input = TextInput(label='Description', style=nextcord.TextInputStyle.paragraph, required=True)
    proof_input = TextInput(label='Proof (URL)', placeholder='Provide proof URL', required=True)

    modal.add_item(user_id_input)
    modal.add_item(description_input)
    modal.add_item(proof_input)

    async def modal_callback(modal_interaction):
        user_id = user_id_input.value
        description = description_input.value
        proof = proof_input.value

        embed = nextcord.Embed(title='New Scam Report', color=nextcord.Color.orange())
        embed.add_field(name='User ID', value=user_id)
        embed.add_field(name='Description', value=description)
        embed.add_field(name='Proof', value=proof)
        embed.set_footer(text=f'Reported by {interaction.user}', icon_url=interaction.user.avatar.url)
        embed.timestamp = datetime.utcnow()

        staff_channel = bot.get_channel(YOUR_STAFF_CHANNEL_ID)
        if staff_channel:
            # Create approval buttons
            approve_button = Button(label='Approve', style=nextcord.ButtonStyle.green)
            deny_button = Button(label='Deny', style=nextcord.ButtonStyle.red)

            async def approve_callback(button_interaction):
                # Implement role assignment or other actions
                # For example, assign a "Scammer" role to the reported user
                try:
                    reported_user = bot.get_user(int(user_id))
                    if reported_user:
                        member = interaction.guild.get_member(reported_user.id)
                        if member:
                            scammer_role = interaction.guild.get_role(SCAMMER_ROLE_ID)  # Replace with your role ID
                            if scammer_role:
                                await member.add_roles(scammer_role)
                                await member.send('You have been flagged as a scammer by the server staff.')
                    await button_interaction.response.send_message('Report approved and actions taken.', ephemeral=True)
                except Exception as e:
                    print(f'Error handling scam report: {e}')
                    await button_interaction.response.send_message('An error occurred while processing the report.', ephemeral=True)

            async def deny_callback(button_interaction):
                await button_interaction.response.send_message('Report denied.', ephemeral=True)

            approve_button.callback = approve_callback
            deny_button.callback = deny_callback

            view = View()
            view.add_item(approve_button)
            view.add_item(deny_button)

            await staff_channel.send(embed=embed, view=view)
            await modal_interaction.response.send_message('Your report has been submitted.', ephemeral=True)
        else:
            await modal_interaction.response.send_message('Failed to submit report. Please contact staff.', ephemeral=True)

    modal.callback = modal_callback
    await interaction.response.send_modal(modal)


@bot.slash_command(name='blacklist', description='Temporarily blacklist a user.')
@commands.has_permissions(manage_roles=True)
async def blacklist(
    interaction: Interaction,
    member: nextcord.Member,
    duration: int = SlashOption(description='Duration in days', min_value=1),
    reason: str = SlashOption(description='Reason for blacklisting', required=False)
):
    blacklist_role = interaction.guild.get_role(BLACKLIST_ROLE_ID)
    if not blacklist_role:
        await interaction.response.send_message('Blacklist role not found.', ephemeral=True)
        return

    await member.add_roles(blacklist_role)
    unblacklist_time = datetime.utcnow() + timedelta(days=duration)
    await db.blacklists.insert_one({
        'user_id': member.id,
        'guild_id': interaction.guild.id,
        'unblacklist_time': unblacklist_time,
        'reason': reason
    })
    await interaction.response.send_message(f'{member.mention} has been blacklisted for {duration} day(s). Reason: {reason}', ephemeral=True)


@tasks.loop(minutes=1)
async def check_blacklists():
    now = datetime.utcnow()
    blacklists = await db.blacklists.find({'unblacklist_time': {'$lte': now}}).to_list(length=100)
    for entry in blacklists:
        guild = bot.get_guild(entry['guild_id'])
        member = guild.get_member(entry['user_id'])
        if member:
            blacklist_role = guild.get_role(BLACKLIST_ROLE_ID)
            if blacklist_role and blacklist_role in member.roles:
                await member.remove_roles(blacklist_role)
        await db.blacklists.delete_one({'_id': entry['_id']})
        print(f"Unblacklisted user {member}")


# Channel Management and Auto-Moderation
@bot.slash_command(name='schedule_purge', description='Schedule a channel to be purged.')
@commands.has_permissions(manage_channels=True)
async def schedule_purge(interaction: Interaction, channel: nextcord.TextChannel, delay: int = SlashOption(description='Delay in minutes', min_value=1)):
    purge_time = datetime.utcnow() + timedelta(minutes=delay)
    await db.channel_purges.insert_one({
        'channel_id': channel.id,
        'purge_time': purge_time
    })
    await interaction.response.send_message(f'Channel {channel.mention} will be purged in {delay} minute(s).', ephemeral=True)


@tasks.loop(minutes=1)
async def check_purges():
    now = datetime.utcnow()
    purges = await db.channel_purges.find({'purge_time': {'$lte': now}}).to_list(length=100)
    for entry in purges:
        channel = bot.get_channel(entry['channel_id'])
        if channel:
            await channel.purge(limit=None)
            print(f"Purged channel {channel.name}")
        await db.channel_purges.delete_one({'_id': entry['_id']})


# Reaction Emoji Automation and Auto-Moderation
@bot.event
async def on_message(message):
    if message.author.bot:
        return

    # Auto-moderation for role-ping channels
    if message.channel.name == 'role-ping-channel':  # Replace with your channel name
        # Implement your auto-moderation rules
        # Example: Delete messages containing certain words
        disallowed_words = ['spam', 'badword']
        if any(word in message.content.lower() for word in disallowed_words):
            await message.delete()
            await message.channel.send(f"{message.author.mention}, your message was removed due to disallowed content.", delete_after=5)

    # Reaction emoji automation
    if message.channel.name == 'reaction-emoji-channel':  # Replace with your channel name
        await message.add_reaction('👍')
        await message.add_reaction('👎')

    await bot.process_commands(message)


# Application Process
@bot.slash_command(name='apply', description='Apply for a specific role.')
async def apply(interaction: Interaction):
    # Present a dropdown menu
    roles = {
        'Top Stocker': 'top_stocker',
        'Stocker': 'stocker',
        'Small Stocker': 'small_stocker',
        'In-game Stocker': 'in_game_stocker',
        'Robux Stocker': 'robux_stocker',
        'Exchanger': 'exchanger'
    }

    options = [nextcord.SelectOption(label=role, value=value) for role, value in roles.items()]
    select = Select(placeholder='Choose a role to apply for', options=options)

    async def select_callback(select_interaction):
        selected_role = select.values[0]
        await handle_application(select_interaction, selected_role)

    select.callback = select_callback
    view = View()
    view.add_item(select)
    await interaction.response.send_message('Select the role you wish to apply for:', view=view, ephemeral=True)


async def handle_application(interaction, role_type):
    # Create a private channel for the application process
    category = nextcord.utils.get(interaction.guild.categories, name='Applications')  # Make sure you have an 'Applications' category
    if not category:
        category = await interaction.guild.create_category('Applications')

    channel = await interaction.guild.create_text_channel(
        name=f'application-{interaction.user.name}',
        overwrites={
            interaction.guild.default_role: nextcord.PermissionOverwrite(read_messages=False),
            interaction.user: nextcord.PermissionOverwrite(read_messages=True)
        },
        category=category
    )

    questions = [
        "Please provide a brief introduction about yourself.",
        "What previous experience do you have related to this role?",
        "Why do you want to apply for this role?",
        "Do you meet the minimum requirements? Please provide proof."
    ]

    await channel.send(f'{interaction.user.mention}, thank you for applying for the **{role_type.replace("_", " ").title()}** role!')
    await channel.send('Please answer the following questions:')

    answers = {}

    def check(m):
        return m.author == interaction.user and m.channel == channel

    for question in questions:
        await channel.send(question)
        try:
            msg = await bot.wait_for('message', check=check, timeout=300)
            answers[question] = msg.content
        except asyncio.TimeoutError:
            await channel.send('Application timed out due to inactivity.')
            await interaction.followup.send(f'Your application has been cancelled due to inactivity.', ephemeral=True)
            return

    # Save application to database
    application_data = {
        'user_id': interaction.user.id,
        'role_type': role_type,
        'answers': answers,
        'timestamp': datetime.utcnow()
    }
    await db.applications.insert_one(application_data)

    # Notify staff
    staff_channel = bot.get_channel(YOUR_STAFF_CHANNEL_ID)
    if staff_channel:
        embed = nextcord.Embed(title='New Application', color=nextcord.Color.blue())
        embed.set_author(name=interaction.user, icon_url=interaction.user.avatar.url)
        embed.add_field(name='Role Applied', value=role_type.replace("_", " ").title())
        embed.add_field(name='User', value=f'{interaction.user} ({interaction.user.id})')
        embed.timestamp = datetime.utcnow()
        await staff_channel.send(embed=embed)

    await channel.send('Thank you for your application! Our staff team will review it and get back to you soon.')
    await interaction.followup.send(f'Your application has been submitted and a private channel has been created: {channel.mention}', ephemeral=True)


# Regular Automated Backups
@tasks.loop(hours=24)
async def backup_database():
    try:
        # Implement your database backup logic here
        # For example, dumping the database to a file and storing it securely
        # This is a placeholder implementation
        backup_time = datetime.utcnow().strftime('%Y%m%d_%H%M%S')
        backup_file = f'db_backup_{backup_time}.bson'

        # Use mongodump to create a backup (make sure mongodump is installed)
        os.system(f"mongodump --uri='{MONGO_URI}' --archive='{backup_file}'")

        # Optionally, upload the backup to cloud storage or move it to a secure location
        print('Database backup completed.')
    except Exception as e:
        print(f'Error during database backup: {e}')


# Error Handling
@bot.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.MissingPermissions):
        await ctx.send('You do not have permission to use this command.', ephemeral=True)
    elif isinstance(error, commands.BotMissingPermissions):
        await ctx.send('I do not have the required permissions to execute this command.', ephemeral=True)
    elif isinstance(error, commands.CommandOnCooldown):
        await ctx.send(f'This command is on cooldown. Please try again after {round(error.retry_after)} seconds.', ephemeral=True)
    elif isinstance(error, commands.CommandNotFound):
        pass  # Ignore invalid commands
    else:
        await ctx.send('An error occurred while processing the command.', ephemeral=True)
        print(f'Error: {error}')

# -------------------------------------------------
# Run the Bot
# -------------------------------------------------

bot.run(TOKEN)   Give the whole code with out anything only code all working perfectly match description use embeds buttons Alan’s commands etc