tickets-please/bot.py
2026-05-05 20:26:54 -06:00

186 lines
No EOL
7 KiB
Python

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)