import discord from discord.ext import commands, tasks from datetime import datetime, timedelta import json import pytz import os from dotenv import load_dotenv # Load environment variables from .env file load_dotenv() # Retrieve the bot token from the environment variable TOKEN = os.getenv('DISCORD_BOT_TOKEN') # Set up intents intents = discord.Intents.default() intents.members = True intents.message_content = True bot = commands.Bot(command_prefix='/tp ', intents=intents) # File path for tickets data TICKETS_FILE = 'tickets.json' # Load or initialize tickets data def load_tickets_data(): if os.path.exists(TICKETS_FILE): with open(TICKETS_FILE, 'r') as f: try: data = json.load(f) print("Loaded tickets data:", data) # Debug log return data except json.JSONDecodeError as e: print(f"Error loading JSON data: {e}") return {} return {} tickets_data = load_tickets_data() # Helper function to save tickets data def save_tickets_data(): with open(TICKETS_FILE, 'w') as f: json.dump(tickets_data, f, indent=4) print("Saved tickets data:", tickets_data) # Debug log # Helper function to reload tickets data from the file def reload_tickets_data(): global tickets_data tickets_data = load_tickets_data() # Command to assign a ticket @bot.command() @commands.has_permissions(administrator=True) async def assign_ticket(ctx, member: discord.Member, email: str, ticket_type: str = "normal"): if ticket_type not in ["normal", "golden"]: await ctx.send("Invalid ticket type. Use 'normal' or 'golden'.") return member_id = str(member.id) # Ensure ID is a string if member_id not in tickets_data: tickets_data[member_id] = {"email": email, "tickets": []} if ticket_type == "normal": # Assign an individual expiration date for the normal ticket expiration_date = datetime.utcnow() + timedelta(days=365) tickets_data[member_id]["tickets"].append({ "type": "normal", "expiration": expiration_date.isoformat() }) expiration_message = f", which expires on {expiration_date.strftime('%Y-%m-%d %H:%M:%S')} UTC." else: # Golden tickets do not expire tickets_data[member_id]["tickets"].append({ "type": "golden", "expiration": None }) expiration_message = "" save_tickets_data() reload_tickets_data() # Reload the tickets data to ensure consistency await ctx.send(f"Assigned a {ticket_type} ticket to {member.mention}{expiration_message}.") # Command to redeem a ticket @bot.command() @commands.has_permissions(administrator=True) async def redeem_ticket(ctx, member: discord.Member, ticket_type: str): if ticket_type not in ["normal", "golden"]: await ctx.send("Invalid ticket type. Use 'normal' or 'golden'.") return member_id = str(member.id) # Ensure ID is a string if member_id not in tickets_data or not tickets_data[member_id]["tickets"]: await ctx.send(f"{member.mention} does not have any tickets.") return for i, ticket in enumerate(tickets_data[member_id]["tickets"]): if ticket["type"] == ticket_type: del tickets_data[member_id]["tickets"][i] save_tickets_data() reload_tickets_data() # Reload the tickets data to ensure consistency await ctx.send(f"Redeemed a {ticket_type} ticket for {member.mention}.") return await ctx.send(f"{member.mention} does not have any {ticket_type} tickets to redeem.") # Command to check a user's tickets (admins only) @bot.command() @commands.has_permissions(administrator=True) async def check_ticket(ctx, member: discord.Member): member_id = str(member.id) # Ensure ID is a string if member_id not in tickets_data or not tickets_data[member_id]["tickets"]: await ctx.send(f"{member.mention} does not have any tickets.") return ticket_info = tickets_data[member_id]["tickets"] normal_tickets = [t for t in ticket_info if t["type"] == "normal"] golden_tickets = [t for t in ticket_info if t["type"] == "golden"] # Timezone definitions tz_utc = pytz.UTC tz_mst = pytz.timezone('America/Edmonton') normal_message = f"{member.mention} has {len(normal_tickets)} normal tickets:\n" for ticket in normal_tickets: expiration_date_utc = datetime.fromisoformat(ticket["expiration"]).astimezone(tz_utc) expiration_date_mst = expiration_date_utc.astimezone(tz_mst) normal_message += f"- Expires on {expiration_date_utc.strftime('%Y-%m-%d %H:%M:%S')} UTC / {expiration_date_mst.strftime('%Y-%m-%d %H:%M:%S')} MST\n" golden_message = f"{member.mention} has {len(golden_tickets)} golden tickets." await ctx.send(f"{normal_message}{golden_message}") # Command to check your own tickets (all users) @bot.command() async def tickets(ctx): member_id = str(ctx.author.id) # Ensure ID is a string if member_id not in tickets_data or not tickets_data[member_id]["tickets"]: # Send a DM if no tickets are found await ctx.author.send("You do not have any tickets.") await ctx.send("I have sent you a DM with your ticket information.") return ticket_info = tickets_data[member_id]["tickets"] normal_tickets = [t for t in ticket_info if t["type"] == "normal"] golden_tickets = [t for t in ticket_info if t["type"] == "golden"] normal_message = f"You have {len(normal_tickets)} normal tickets:\n" for ticket in normal_tickets: expiration_date = datetime.fromisoformat(ticket["expiration"]) normal_message += f"- Expires on {expiration_date.strftime('%Y-%m-%d %H:%M:%S')} UTC\n" golden_message = f"You have {len(golden_tickets)} golden tickets." # Send the result to the user via DM await ctx.author.send(f"{normal_message}\n{golden_message}") await ctx.send("I have sent you a DM with your ticket information.") # Background task to check and remove expired tickets @tasks.loop(hours=24) async def check_expired_tickets(): tz = pytz.UTC current_time = datetime.now(tz) to_remove = [] for member_id, ticket_info in tickets_data.items(): tickets_data[member_id]["tickets"] = [ ticket for ticket in ticket_info["tickets"] if ticket["type"] == "golden" or current_time < datetime.fromisoformat(ticket["expiration"]).astimezone(tz) ] # Remove the member if they have no tickets left if not tickets_data[member_id]["tickets"]: to_remove.append(member_id) for member_id in to_remove: print(f"Removing expired tickets for user ID: {member_id}") # Debug log del tickets_data[member_id] save_tickets_data() @bot.event async def on_ready(): print(f'Logged in as {bot.user.name}') check_expired_tickets.start() # Run the bot bot.run(TOKEN)