From bed95c311137fc165e52782235d82812ecb74c64 Mon Sep 17 00:00:00 2001 From: Vassili Minaev Date: Tue, 5 May 2026 20:26:54 -0600 Subject: [PATCH] Initial commit --- bot.py | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++ tickets.json | 137 +++++++++++++++++++++++++++++++++++++ 2 files changed, 323 insertions(+) create mode 100644 bot.py create mode 100644 tickets.json diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..48ecfe8 --- /dev/null +++ b/bot.py @@ -0,0 +1,186 @@ +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) \ No newline at end of file diff --git a/tickets.json b/tickets.json new file mode 100644 index 0000000..dfb69b8 --- /dev/null +++ b/tickets.json @@ -0,0 +1,137 @@ +{ + "272518615356538887": { + "email": "seifer.moringa@gmail.com", + "tickets": [ + { + "type": "golden", + "expiration": null + } + ] + }, + "928079996403212429": { + "email": "metalarms127@gmail.com", + "tickets": [ + { + "type": "golden", + "expiration": null + }, + { + "type": "golden", + "expiration": null + } + ] + }, + "526179144967520257": { + "email": "nyrvaan@gmail.com", + "tickets": [ + { + "type": "normal", + "expiration": "2026-10-28T01:04:21.726082" + }, + { + "type": "normal", + "expiration": "2026-10-28T01:05:18.289342" + } + ] + }, + "865708915924533248": { + "email": "romangraham07@gmail.com", + "tickets": [ + { + "type": "normal", + "expiration": "2026-05-30T01:40:52.106310" + }, + { + "type": "normal", + "expiration": "2027-04-07T00:09:45.822523" + } + ] + }, + "1131710863343091722": { + "email": "atomiccryo@gmail.com", + "tickets": [ + { + "type": "normal", + "expiration": "2026-05-30T01:41:46.157234" + }, + { + "type": "normal", + "expiration": "2026-11-01T20:06:20.779733" + }, + { + "type": "normal", + "expiration": "2027-04-07T00:17:19.067922" + } + ] + }, + "348204092709142538": { + "email": "micahelacostapsyd@gmail.com", + "tickets": [ + { + "type": "normal", + "expiration": "2026-06-01T05:00:16.756179" + } + ] + }, + "267100324127440907": { + "email": "mskintner@gmail.com", + "tickets": [ + { + "type": "golden", + "expiration": null + }, + { + "type": "normal", + "expiration": "2027-05-01T20:40:03.987511" + }, + { + "type": "normal", + "expiration": "2027-05-01T20:40:08.497594" + }, + { + "type": "normal", + "expiration": "2027-05-01T20:40:10.222346" + }, + { + "type": "normal", + "expiration": "2027-05-01T20:40:11.817248" + } + ] + }, + "1097655473337016481": { + "email": "spectre1kj@gmail.com", + "tickets": [ + { + "type": "normal", + "expiration": "2026-10-25T02:02:36.677040" + } + ] + }, + "265268782455324692": { + "email": "hansthelarson@gmail.com", + "tickets": [ + { + "type": "normal", + "expiration": "2026-10-28T00:46:43.282249" + } + ] + }, + "171471851590123520": { + "email": "cartmachine@gmail.com", + "tickets": [ + { + "type": "normal", + "expiration": "2026-10-29T08:30:40.170348" + } + ] + }, + "928442689874165771": { + "email": "Limdul3000@gmail.com", + "tickets": [ + { + "type": "normal", + "expiration": "2027-02-21T22:17:34.693537" + } + ] + } +} \ No newline at end of file