import discord from discord.ext import commands from discord import app_commands import json import os MISC_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "misc")) ROLES_JSON_PATH = os.path.join(MISC_DIR, "roles.json") AUTHORIZED_USER_ID = 966338171958886420 # List of available roles AVAILABLE_ROLES = [ "Management", "Owner", "Overseer", "Manager", "Staff Manager", "Tester Manager", "Senior Moderator", "Moderator", "Senior Tester", "Verified Tester", "Helper", "Staff Team", "Administrator" ] def load_roles(): """Load roles from roles.json""" try: os.makedirs(MISC_DIR, exist_ok=True) if os.path.isfile(ROLES_JSON_PATH): with open(ROLES_JSON_PATH, "r", encoding="utf-8") as f: return json.load(f) except Exception as e: print(f"Error loading roles.json: {e}") return {} def save_roles(roles_data): """Save roles to roles.json""" try: os.makedirs(MISC_DIR, exist_ok=True) with open(ROLES_JSON_PATH, "w", encoding="utf-8") as f: json.dump(roles_data, f, ensure_ascii=False, indent=2) except Exception as e: print(f"Error saving roles.json: {e}") class Miscellaneous(commands.Cog): def __init__(self, bot): self.bot = bot self.backup_service = None self._initialize_backup() def _initialize_backup(self): """Initialize backup service""" try: import config from google_drive_backup import GoogleDriveBackup oauth_credentials = os.path.join( os.path.dirname(os.path.dirname(__file__)), "oauth_credentials.json" ) if os.path.exists(oauth_credentials) and hasattr(config, 'GOOGLE_DRIVE_BACKUP_FOLDER_ID'): self.backup_service = GoogleDriveBackup( oauth_credentials, config.GOOGLE_DRIVE_BACKUP_FOLDER_ID ) print("[MISC] [OK] Backup service initialized") else: if not os.path.exists(oauth_credentials): print("[MISC] [!] oauth_credentials.json not found - Google Drive backup disabled") elif not hasattr(config, 'GOOGLE_DRIVE_BACKUP_FOLDER_ID'): print("[MISC] [!] GOOGLE_DRIVE_BACKUP_FOLDER_ID not in config.py") else: print("[MISC] [!] Backup service not configured") except Exception as e: print(f"[MISC] [ERROR] Error initializing backup: {str(e)}") @app_commands.command(name="save", description="Manually backup all bot data to Google Drive (Forced Backup)") async def save_backup(self, interaction: discord.Interaction): """ Create a forced backup of all bot data and code to Google Drive Only authorized users can execute this """ print(f"[SAVE] Command started by {interaction.user.name} ({interaction.user.id})") # Check if user is authorized if interaction.user.id != AUTHORIZED_USER_ID: print(f"[SAVE] [!] Permission denied - {interaction.user.name} is not authorized") await interaction.response.send_message( "āŒ You don't have permission to use this command.", ephemeral=True ) return # Check if backup service is available if not self.backup_service: print(f"[SAVE] [ERROR] Backup service not initialized") await interaction.response.send_message( "āŒ Backup service is not properly configured. Contact admin.", ephemeral=True ) return try: # Defer response as backup may take time await interaction.response.defer() # Get or create backup-logs channel backup_logs_channel = await self._get_or_create_backup_logs_channel(interaction.guild) print(f"[SAVE] [BACKUP] Starting forced backup by {interaction.user.name}") # Perform backup result = self.backup_service.backup_bot_data(backup_type="forced") if result.get("success"): success_msg = f"āœ… **FORCED BACKUP COMPLETED**\n\nšŸ“ Folder: `{result['folder_name']}`\nā° Time: {result['timestamp']}\nšŸ‘¤ User: {interaction.user.mention}" print(f"[SAVE] [OK] Backup successful: {result['folder_name']}") # Send confirmation in Discord await interaction.followup.send( success_msg, ephemeral=True ) # Log in backup-logs channel if backup_logs_channel: embed = discord.Embed( title="āœ… Forced Backup Created", description=f"**Folder:** `{result['folder_name']}`", color=discord.Color.green(), timestamp=discord.utils.utcnow() ) embed.add_field(name="Triggered By", value=interaction.user.mention, inline=True) embed.add_field(name="Type", value="Forced Backup", inline=True) embed.set_footer(text="Backup System") await backup_logs_channel.send(embed=embed) else: error_msg = f"āŒ **BACKUP FAILED**\n\nError: {result.get('error', 'Unknown error')}" print(f"[SAVE] [ERROR] Backup failed: {result.get('error')}") await interaction.followup.send( error_msg, ephemeral=True ) # Log error in backup-logs channel if backup_logs_channel: embed = discord.Embed( title="āŒ Backup Failed", description=f"**Error:** {result.get('error', 'Unknown error')}", color=discord.Color.red(), timestamp=discord.utils.utcnow() ) embed.add_field(name="Triggered By", value=interaction.user.mention, inline=True) embed.set_footer(text="Backup System") await backup_logs_channel.send(embed=embed) except Exception as e: error_msg = f"[SAVE] āŒ Unexpected error: {str(e)}" print(error_msg) await interaction.followup.send( f"āŒ Error: {str(e)}", ephemeral=True ) async def _get_or_create_backup_logs_channel(self, guild: discord.Guild) -> discord.TextChannel: """Get or create backup-logs channel""" try: channel = discord.utils.get(guild.text_channels, name="backup-logs") if not channel: print("[SAVE] [DIR] Creating backup-logs channel...") channel = await guild.create_text_channel( "backup-logs", topic="šŸ”„ Automated backup logs - View all backup operations here" ) print("[SAVE] [OK] Created backup-logs channel") return channel except Exception as e: print(f"[SAVE] [ERROR] Error with backup-logs channel: {str(e)}") return None # Deprecated: Use /setuproles command instead (from queue_system.py) @app_commands.command(name="stop", description="Safely shut down the bot (Owner only)") async def stop_bot(self, interaction: discord.Interaction): """ Safely turns off the bot. Only accessible by authorized user ID. """ # Check if user is authorized if interaction.user.id != AUTHORIZED_USER_ID: await interaction.response.send_message( "āŒ You don't have permission to use this command.", ephemeral=True ) return await interaction.response.send_message( "šŸ›‘ Bot is shutting down safely...", ephemeral=True ) print(f"Bot shutdown initiated by {interaction.user} ({interaction.user.id})") await self.bot.close() async def setup(bot: commands.Bot): await bot.add_cog(Miscellaneous(bot))