Initial commit
This commit is contained in:
commit
bed95c3111
2 changed files with 323 additions and 0 deletions
186
bot.py
Normal file
186
bot.py
Normal file
|
|
@ -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)
|
||||||
137
tickets.json
Normal file
137
tickets.json
Normal file
|
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue