woodburn-bot/bot.py

644 lines
26 KiB
Python
Raw Normal View History

2023-08-11 15:55:44 +10:00
import os
from dotenv import load_dotenv
import discord
from discord import app_commands
2023-08-11 16:35:36 +10:00
import requests
2023-08-11 17:24:11 +10:00
import dns.resolver
2023-08-12 22:39:36 +10:00
import markdownify
2023-09-27 17:27:06 +10:00
import subprocess
import tempfile
import re
2023-09-27 17:44:07 +10:00
import binascii
2023-09-27 18:29:09 +10:00
from cryptography import x509
from cryptography.hazmat.backends import default_backend
2023-10-01 13:21:13 +11:00
import datetime
2023-11-13 20:16:01 +11:00
import chatai
2023-11-14 14:01:29 +11:00
import tools
from tools import parse_time, read_reminders, store_reminder, write_reminders
2023-11-14 13:05:41 +11:00
import asyncio
2023-11-14 13:56:55 +11:00
from discord.ext import tasks, commands
2024-02-07 23:24:31 +11:00
from discord.ext.commands import has_permissions, MissingPermissions
import support
2023-10-01 22:38:31 +11:00
2023-09-27 18:25:58 +10:00
2023-08-11 15:55:44 +10:00
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
2023-08-12 17:14:55 +10:00
ADMINID = 0
2023-08-12 16:52:01 +10:00
KUTT_APIKEY=os.getenv('LINK_API_KEY')
KUTT_URL=os.getenv('LINK_URL')
2023-08-12 17:05:35 +10:00
LOG_CHANNEL = int(os.getenv('LOG_CHANNEL'))
2023-08-11 15:55:44 +10:00
intents = discord.Intents.default()
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)
2023-08-11 16:35:36 +10:00
activityMessage="over the server"
statusType="watching"
2023-08-12 16:52:01 +10:00
2023-08-11 15:55:44 +10:00
# Commands
@tree.command(name="ping", description="Check bot connection")
async def ping(ctx):
await ctx.response.send_message("Pong!",ephemeral=True)
2023-08-11 16:35:36 +10:00
@tree.command(name="shortlink", description="Shorten a link")
async def shortlink(ctx, link: str, name: str = None):
2023-08-12 16:52:01 +10:00
if (ctx.user.id != ADMINID):
2023-08-11 16:55:18 +10:00
await log("User: " + str(ctx.user.name) + " tried to use the shortlink command")
2023-08-11 16:35:36 +10:00
await ctx.response.send_message("You don't have permission to use this command",ephemeral=True)
else:
2023-08-12 17:05:35 +10:00
url=f"{KUTT_URL}/api/v2/links"
2023-08-12 16:52:01 +10:00
headers = {'X-API-KEY' : KUTT_APIKEY}
2023-08-11 16:35:36 +10:00
data = {'target' : link, 'customurl' : name}
if (name == None):
data = {'target' : link}
x = requests.post(url, data = data, headers = headers)
if (x.status_code != 200 and x.status_code != 201):
await ctx.response.send_message("ERROR: " + x.text,ephemeral=True)
link=x.json()['link']
await ctx.response.send_message("Link: " + link,ephemeral=False)
@tree.command(name="botstatus", description="Set the bot status")
async def botstatus(ctx, message: str, statusmethod: str = None):
2023-08-12 16:52:01 +10:00
if (ctx.user.id != ADMINID):
2023-08-11 16:55:18 +10:00
await log("User: " + str(ctx.user.name) + " tried to use the botstatus command")
2023-08-11 16:35:36 +10:00
await ctx.response.send_message("You don't have permission to use this command",ephemeral=True)
else:
global activityMessage
activityMessage=message
global statusType
if (statusmethod == None):
statusmethod="watching"
else:
statusType=statusmethod.lower()
updateStatus()
await ctx.response.send_message("Status updated",ephemeral=True)
2023-08-11 15:55:44 +10:00
2023-08-11 17:24:11 +10:00
@tree.command(name="dig", description="Dig a dns record")
async def dig(ctx, domain: str, record_type: str = "A"):
record_type = record_type.upper()
resolver = dns.resolver.Resolver()
resolver.nameservers = ["10.2.1.15"]
2023-11-08 18:09:50 +11:00
resolver.port = 5350
2023-08-11 17:24:11 +10:00
try:
# Query the DNS record
2023-08-11 17:30:07 +10:00
response = resolver.resolve(domain, record_type)
2023-08-11 17:24:11 +10:00
records = ""
for record in response:
records = records + "\n" + str(record)
# Send the result to the Discord channel
await ctx.response.send_message(f"DNS records for {domain} ({record_type}):{records}")
except dns.resolver.NXDOMAIN:
await ctx.response.send_message(f"Domain {domain} not found.")
except dns.exception.DNSException as e:
await ctx.response.send_message(f"An error occurred: {e}")
2023-08-12 15:18:21 +10:00
@tree.command(name="curl", description="HTTP request")
async def curl(ctx, url: str):
try:
proxyURL = "https://proxy.hnsproxy.au"
response = requests.get(url, proxies={"http": proxyURL, "https": proxyURL},verify=False)
output = response.text
2023-08-12 22:39:36 +10:00
# Get BODY only
output = output.split("<body")[1]
output = output.split("</body>")[0]
output = output.split(">", 1)[1]
# Replace any relative links with absolute links
output = output.replace('href="/', 'href="' + url + '/')
parsed = markdownify.markdownify(output, heading_style="ATX")
# Delete any empty lines
parsed = "\n".join([s for s in parsed.splitlines() if s.strip()])
output = response.text
# Get title
if (output.find("<title>") != -1):
title = output.split("<title>")[1]
title = title.split("</title>")[0]
else:
title = url
if (len(parsed) > 4096):
parsed = parsed[:4096]
# Delete any incomplete lines
parsed = "\n".join(parsed.splitlines()[:-1])
parsed = parsed + "\n..."
# if url is a tld only replace it with the url https://hns.au (due to Discord not allowing tld only links)
if (url.find(".") == -1):
url = "https://hns.au"
# Create an embed
embed = discord.Embed(title=title, url=url, description=parsed)
embed.set_footer(text="Parsed by HNSProxy",icon_url="https://hns.au/assets/img/favicon.png")
embed.timestamp = discord.utils.utcnow()
await ctx.response.send_message(embed=embed)
2023-08-12 15:18:21 +10:00
except requests.exceptions.RequestException as e:
await ctx.response.send_message(f"An error occurred: {e}")
2023-08-12 22:39:36 +10:00
except Exception as e:
await ctx.response.send_message(f"An error occurred: {e}")
2023-09-27 17:27:06 +10:00
@tree.command(name="ssl", description="Check SSL certificate")
2023-10-01 22:38:31 +11:00
async def ssl(ctx, domain: str, showcert: bool = False, notifymeonexpiry: bool = False):
# Verify that the domain is valid
if not domain:
await ctx.response.send_message("Please provide a domain to check")
return
2023-09-27 17:27:06 +10:00
regexmatch = re.match(r"^([a-z0-9]+(-[a-z0-9]+)*\.)*([a-z0-9]+(-[a-z0-9]+)*)$", domain)
if not regexmatch:
await ctx.response.send_message("Please provide a valid domain to check")
return
2023-09-27 17:27:06 +10:00
2023-09-27 18:18:35 +10:00
await ctx.response.send_message(f"Checking SSL certificate for {domain}...")
2023-09-27 17:27:06 +10:00
message = ""
resolver = dns.resolver.Resolver()
resolver.nameservers = ["10.2.1.15"]
2023-11-08 18:09:50 +11:00
resolver.port = 5350
2023-09-27 18:34:24 +10:00
domain_check = False
2023-09-27 17:27:06 +10:00
try:
# Query the DNS record
response = resolver.resolve(domain, "A")
records = []
message = "## A records:\n"
for record in response:
records.append(str(record))
message = message + "- " +str(record) + "\n"
2023-09-27 17:36:22 +10:00
if not records:
2023-09-27 18:14:34 +10:00
await ctx.channel.send(f"No A record found for {domain}")
2023-09-27 17:27:06 +10:00
return
# Get the first A record
ip = records[0]
# Run the openssl s_client command
2023-09-27 17:31:22 +10:00
s_client_command = ["openssl","s_client","-showcerts","-connect",f"{ip}:443","-servername",domain,]
2023-09-27 17:27:06 +10:00
2023-09-27 17:31:22 +10:00
s_client_process = subprocess.Popen(s_client_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
s_client_output, _ = s_client_process.communicate(input=b"\n")
2023-09-27 18:35:27 +10:00
2023-09-27 17:27:06 +10:00
certificates = []
current_cert = ""
for line in s_client_output.split(b"\n"):
current_cert += line.decode("utf-8") + "\n"
if "-----END CERTIFICATE-----" in line.decode("utf-8"):
certificates.append(current_cert)
current_cert = ""
2023-09-27 17:38:56 +10:00
# Remove anything before -----BEGIN CERTIFICATE-----
certificates = [cert[cert.find("-----BEGIN CERTIFICATE-----"):] for cert in certificates]
2023-09-27 17:27:06 +10:00
if certificates:
cert = certificates[0]
2023-10-01 13:32:19 +11:00
if showcert:
message = message + "\n## Website Certificate:\n```\n" + cert + "\n```\n"
2023-09-27 17:27:06 +10:00
with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_cert_file:
temp_cert_file.write(cert)
temp_cert_file.seek(0) # Move back to the beginning of the temporary file
2023-09-27 17:44:07 +10:00
tlsa_command = ["openssl","x509","-in",temp_cert_file.name,"-pubkey","-noout","|","openssl","pkey","-pubin","-outform","der","|","openssl","dgst","-sha256","-binary",]
2023-09-27 17:27:06 +10:00
tlsa_process = subprocess.Popen(" ".join(tlsa_command), shell=True, stdout=subprocess.PIPE)
tlsa_output, _ = tlsa_process.communicate()
2023-09-27 17:44:07 +10:00
2023-09-27 18:03:53 +10:00
tlsa_server = "3 1 1 " + binascii.hexlify(tlsa_output).decode("utf-8")
2023-09-27 17:44:07 +10:00
2023-09-27 18:03:53 +10:00
message = message + "\n## TLSA Record from webserver:\n`" + tlsa_server + "`\n"
2023-09-27 18:25:58 +10:00
# Get domains
2023-09-27 18:29:09 +10:00
cert_obj = x509.load_pem_x509_certificate(cert.encode("utf-8"), default_backend())
2023-09-27 18:25:58 +10:00
domains = []
2023-09-27 18:29:09 +10:00
for ext in cert_obj.extensions:
if ext.oid == x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME:
san_list = ext.value.get_values_for_type(x509.DNSName)
domains.extend(san_list)
# Extract the common name (CN) from the subject
common_name = cert_obj.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
if common_name:
2023-09-27 18:34:24 +10:00
if common_name[0].value not in domains:
domains.append(common_name[0].value)
2023-09-27 18:29:09 +10:00
2023-09-27 18:25:58 +10:00
if domains:
message = message + "\n## SSL Domains:\n"
2023-09-27 18:37:48 +10:00
for cn in domains:
message = message + "- " + cn + "\n"
2023-09-27 18:34:24 +10:00
if domain in domains:
domain_check = True
2023-09-27 18:25:58 +10:00
2023-10-01 13:13:55 +11:00
expiry_date = cert_obj.not_valid_after
2023-10-01 13:20:04 +11:00
# Check if expiry date is past
2024-02-07 23:24:31 +11:00
if expiry_date < datetime.datetime.utcnow():
2023-10-01 13:20:04 +11:00
message = message + "\n## Expiry Date:\n:x: Certificate has expired\n"
2024-02-07 23:24:31 +11:00
elif expiry_date < datetime.datetime.utcnow() + datetime.timedelta(days=7):
2023-10-01 13:20:04 +11:00
message = message + "\n## Expiry Date:\n:warning: Certificate expires soon\n"
else:
message = message + "\n## Expiry Date:\n:white_check_mark: Certificate is valid\n"
message = message + expiry_date.strftime("%d %B %Y %H:%M:%S") + "\n"
2023-10-01 13:13:55 +11:00
2023-09-27 18:25:58 +10:00
2023-09-27 18:11:27 +10:00
else:
message = message + "\n## Website Certificate:\n:x: No certificate found\n"
message = message + "\n## TLSA Record from webserver:\n:x: No certificate found\n"
2023-09-27 17:47:57 +10:00
2023-09-27 18:11:27 +10:00
try:
2023-09-27 17:47:57 +10:00
# Check for TLSA record
response = resolver.resolve("_443._tcp."+domain, "TLSA")
tlsa_records = []
message = message + "\n## TLSA Records from DNS:\n"
2023-09-27 17:47:57 +10:00
for record in response:
tlsa_records.append(str(record))
message = message + "- " +str(record) + "\n"
if not tlsa_records:
2023-09-27 17:57:45 +10:00
message = message + "\n## Result:\n:x: No TLSA record found\n"
else:
if tlsa_server == tlsa_records[0]:
2023-09-27 18:34:24 +10:00
if domain_check:
message = message + "\n## Result:\n:white_check_mark: TLSA record matches certificate\n"
else:
message = message + "\n## Result:\n:x: TLSA record matches certificate but domain does not match\n"
2023-09-27 17:57:45 +10:00
else:
message = message + "\n## Result:\n:x: TLSA record does not match certificate\n"
2023-09-27 18:11:27 +10:00
except:
message = message + "\n## TLSA Records from DNS:\n:x: No TLSA record found\n"
message = message + "\n## Result:\n:x: No TLSA record found\n"
# If message is too long, send it in 2 messages
if (len(message) > 2000):
# Split on the last line under 2000 characters
message1 = message[:2000]
message1 = message1[:message1.rfind("\n")]
message2 = message[len(message1):]
2023-09-27 18:14:34 +10:00
await ctx.channel.send(message1)
2023-09-27 18:11:27 +10:00
await ctx.channel.send(message2)
2023-09-27 17:27:06 +10:00
else:
2023-09-27 18:14:34 +10:00
await ctx.channel.send(message)
2023-10-01 22:38:31 +11:00
if (notifymeonexpiry):
with open("/mnt/sslnotify.txt", "a") as file:
file.write(str(ctx.user.id) + "," + domain + "\n")
2023-09-27 17:27:06 +10:00
# Catch all exceptions
except Exception as e:
2023-09-27 18:14:34 +10:00
await ctx.channel.send(f"An error occurred: {e}")
2023-09-27 17:27:06 +10:00
2023-08-11 17:24:11 +10:00
2023-08-12 15:38:32 +10:00
@tree.command(name="invite", description="Invite me to your server")
async def invite(ctx):
await ctx.response.send_message("https://discord.com/api/oauth2/authorize?client_id=1006128164218621972&permissions=0&scope=bot",ephemeral=True)
2023-08-11 17:24:11 +10:00
2023-08-11 16:55:18 +10:00
async def log(message):
2023-08-12 16:52:01 +10:00
channel=client.get_channel(LOG_CHANNEL)
2023-08-11 16:55:18 +10:00
await channel.send(message)
2023-08-11 15:55:44 +10:00
def updateStatus():
2023-08-11 16:35:36 +10:00
global activityMessage
global statusType
if (statusType == "watching"):
activity=discord.Activity(type=discord.ActivityType.watching, name=activityMessage)
elif (statusType == "playing"):
activity=discord.Activity(type=discord.ActivityType.playing, name=activityMessage)
elif (statusType == "listening"):
activity=discord.Activity(type=discord.ActivityType.listening, name=activityMessage)
elif (statusType == "competing"):
activity=discord.Activity(type=discord.ActivityType.competing, name=activityMessage)
else:
activity=discord.Activity(type=discord.ActivityType.watching, name=activityMessage)
2023-08-11 15:55:44 +10:00
client.loop.create_task(client.change_presence(activity=activity))
2023-11-14 13:56:55 +11:00
@tasks.loop(hours=24)
2023-10-01 22:53:54 +11:00
async def checkForSSLExpiry():
2023-10-01 22:38:31 +11:00
with open("/mnt/sslnotify.txt", "r") as file:
lines = file.readlines()
for line in lines:
line = line.strip()
if not line:
2023-10-01 23:12:09 +11:00
print("No line", flush=True)
2023-10-01 22:38:31 +11:00
continue
userid, domain = line.split(",")
2023-10-01 23:12:09 +11:00
print(f"Checking SSL certificate for {domain}...", flush=True)
2023-10-01 22:38:31 +11:00
resolver = dns.resolver.Resolver()
2023-11-08 18:09:50 +11:00
resolver.nameservers = ["10.2.1.15"]
resolver.port = 5350
2023-10-01 22:38:31 +11:00
try:
# Query the DNS record
response = resolver.resolve(domain, "A")
records = []
for record in response:
records.append(str(record))
if not records:
2023-10-01 23:08:01 +11:00
print(f"No A record found for {domain}", flush=True)
2023-10-01 22:38:31 +11:00
continue
# Get the first A record
ip = records[0]
# Run the openssl s_client command
s_client_command = ["openssl","s_client","-showcerts","-connect",f"{ip}:443","-servername",domain,]
s_client_process = subprocess.Popen(s_client_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
s_client_output, _ = s_client_process.communicate(input=b"\n")
certificates = []
current_cert = ""
for line in s_client_output.split(b"\n"):
current_cert += line.decode("utf-8") + "\n"
if "-----END CERTIFICATE-----" in line.decode("utf-8"):
certificates.append(current_cert)
current_cert = ""
# Remove anything before -----BEGIN CERTIFICATE-----
certificates = [cert[cert.find("-----BEGIN CERTIFICATE-----"):] for cert in certificates]
if certificates:
cert = certificates[0]
# Get expiry date
cert_obj = x509.load_pem_x509_certificate(cert.encode("utf-8"), default_backend())
expiry_date = cert_obj.not_valid_after
2024-02-07 23:24:31 +11:00
if expiry_date < datetime.datetime.utcnow() + datetime.timedelta(days=7):
2023-10-01 23:22:45 +11:00
user = await client.fetch_user(int(userid))
2023-10-01 22:38:31 +11:00
if user:
2023-10-01 22:53:54 +11:00
await user.send(f"SSL certificate for {domain} expires soon")
2023-10-01 23:03:01 +11:00
print(f"SSL certificate for {domain} expires soon", flush=True)
2023-10-01 23:14:37 +11:00
else:
2023-10-01 23:28:11 +11:00
await log(f"User {userid} not found")
2023-10-01 23:08:01 +11:00
else:
print(f"No certificate found for {domain}", flush=True)
await user.send(f"No certificate found for {domain}")
continue
2023-10-01 22:47:23 +11:00
except Exception as e:
print(e, flush=True)
2023-10-01 23:28:11 +11:00
await log(e)
2023-10-01 22:38:31 +11:00
continue
2023-10-01 22:47:23 +11:00
print("SSL check complete", flush=True)
2023-10-01 22:38:31 +11:00
@tree.command(name="ssldomains", description="List domains with SSL certificates")
async def ssldomains(ctx):
# Get user id
userid = str(ctx.user.id)
# Get all domains for user
domains = []
with open("/mnt/sslnotify.txt", "r") as file:
lines = file.readlines()
for line in lines:
line = line.strip()
if not line:
continue
if line.startswith(userid):
_, domain = line.split(",")
domains.append(domain)
if not domains:
await ctx.response.send_message("You have no domains in the SSL expiry notification list",ephemeral=True)
return
await ctx.response.send_message("Domains in the SSL expiry notification list:\n" + "\n".join(domains),ephemeral=True)
2023-10-01 22:59:40 +11:00
@tree.command(name="sslremove", description="Remove a domain from the SSL expiry notification list")
async def sslremove(ctx, domain: str):
# Get user id
userid = str(ctx.user.id)
# Get all domains for user
domains = []
with open("/mnt/sslnotify.txt", "r") as file:
lines = file.readlines()
for line in lines:
line = line.strip()
if not line:
continue
if line.startswith(userid):
_, dom = line.split(",")
domains.append(dom)
if not domains:
await ctx.response.send_message("You have no domains in the SSL expiry notification list",ephemeral=True)
return
if domain not in domains:
await ctx.response.send_message("Domain not found in the SSL expiry notification list",ephemeral=True)
return
with open("/mnt/sslnotify.txt", "w") as file:
for line in lines:
line = line.strip()
if not line:
continue
if not line.startswith(userid):
file.write(line + "\n")
for dom in domains:
if domain != dom:
file.write(userid + "," + dom + "\n")
await ctx.response.send_message("Domain removed from the SSL expiry notification list",ephemeral=True)
2023-10-01 22:38:31 +11:00
2023-10-01 22:59:40 +11:00
@tree.command(name="manualsslcheck", description="Manually check SSL certificate")
async def manualsslcheck(ctx):
if (ctx.user.id != ADMINID):
await log("User: " + str(ctx.user.name) + " tried to use the manualsslcheck command")
await ctx.response.send_message("You don't have permission to use this command",ephemeral=True)
2023-10-01 22:38:31 +11:00
2023-10-01 22:59:40 +11:00
await ctx.response.send_message("SSL checking",ephemeral=True)
await checkForSSLExpiry()
2023-10-01 23:06:55 +11:00
await ctx.channel.send("SSL check complete",ephemeral=True)
2023-10-01 22:59:40 +11:00
2023-11-13 20:11:49 +11:00
@tree.command(name="ai", description="AI Chat")
async def ai(ctx, message: str):
prompt = "Name: " + str(ctx.user.name) + "\n"
prompt = prompt + "Message: " + message + "\n"
2023-11-13 20:16:01 +11:00
await ctx.response.send_message(chatai.chat(prompt))
2023-10-01 22:38:31 +11:00
2023-11-14 13:05:41 +11:00
@tree.command(name="remindme", description="Remind me")
2023-11-14 13:15:56 +11:00
async def remindme(ctx, when: str, reminder: str):
2023-11-14 13:05:41 +11:00
time_delta = parse_time(when)
if time_delta is not None:
# Schedule the reminder
2023-11-14 13:15:56 +11:00
reminder_time = datetime.datetime.now() + time_delta
2023-11-14 13:19:25 +11:00
store_reminder(ctx.user.id, reminder_time, reminder)
2023-11-14 13:15:56 +11:00
await ctx.response.send_message("I've set a reminder for you in " + when + ".\n" + reminder,ephemeral=True)
2023-11-14 13:05:41 +11:00
else:
await ctx.response.send_message("Invalid time format. Please use something like `1d 3h` or `4hr`.",ephemeral=True)
2023-11-14 14:05:39 +11:00
@tree.command(name="reminders", description="List reminders")
async def reminders(ctx):
reminders = read_reminders()
if len(reminders) == 0:
await ctx.response.send_message("You have no reminders.",ephemeral=True)
else:
user_reminders = []
for reminder in reminders:
# Only show reminders for the user who requested them
if reminder['user_id'] == str(ctx.user.id):
user_reminders.append(reminder)
if len(user_reminders) == 0:
await ctx.response.send_message("You have no reminders.",ephemeral=True)
else:
message = "Reminders:\n"
for reminder in user_reminders:
time = datetime.datetime.strptime(reminder['time'], "%Y-%m-%d %H:%M:%S")
2023-11-14 14:18:01 +11:00
time = tools.timestamp_relative(time)
2023-11-14 14:05:39 +11:00
message += f"{time}: {reminder['text']}\n"
await ctx.response.send_message(message,ephemeral=True)
2023-11-18 15:20:30 +11:00
@tree.command(name="timestamp", description="Convert timestamp")
async def timestamp(ctx, when: str):
when = when.strip()
time_delta = parse_time(when)
if time_delta is not None:
# Schedule the reminder
time = datetime.datetime.now() + time_delta
if when.endswith("ago"):
time = datetime.datetime.now() - time_delta
time = tools.timestamp_all_raw(time)
await ctx.response.send_message(time,ephemeral=True)
else:
await ctx.response.send_message("Invalid time format. Please use something like `1d 3h` or `4hr`. End with `ago` to convert to past time",ephemeral=True)
2024-02-07 23:24:31 +11:00
#region Tickets
@tree.command(name="ticket", description="Create a ticket")
async def ticket(ctx):
if (ctx.guild == None):
await ctx.response.send_message("This command can only be used in a server",ephemeral=True)
return
server = ctx.guild.id
if not support.is_server_valid(str(server)):
await ctx.response.send_message("This server is not registered",ephemeral=True)
return
await ctx.response.send_message("Creating ticket...",ephemeral=True)
await support.create_ticket(str(ctx.user.id), str(ctx.guild.id))
@tree.command(name="ticketaddserver", description="Add a server to the ticket system")
@commands.has_permissions(administrator=True)
async def ticketaddserver(ctx, category: str, modrole: discord.Role, closedcategory: str):
if (ctx.user.id != ADMINID):
await log("User: " + str(ctx.user.name) + " tried to use the ticketAddServer command")
await ctx.response.send_message("You don't have permission to use this command",ephemeral=True)
else:
await ctx.response.send_message("Adding server to ticket system",ephemeral=True)
result = await support.ticketAddServer(ctx.guild.id, category, modrole.id,closedcategory)
await ctx.channel.send(result)
@tree.command(name="adduser", description="Add a user to a ticket")
async def adduser(ctx, user: discord.User):
if (ctx.guild == None):
await ctx.response.send_message("This command can only be used in a server",ephemeral=True)
return
server = ctx.guild.id
if not support.is_server_valid(str(server)):
await ctx.response.send_message("This server is not registered",ephemeral=True)
return
result = await support.addMemberToTicket(user,str(ctx.channel.id), str(ctx.guild.id))
await ctx.response.send_message(result,ephemeral=True)
@tree.command(name="removeuser", description="Remove a user from a ticket")
async def removeuser(ctx, user: discord.User):
if (ctx.guild == None):
await ctx.response.send_message("This command can only be used in a server",ephemeral=True)
return
server = ctx.guild.id
if not support.is_server_valid(str(server)):
await ctx.response.send_message("This server is not registered",ephemeral=True)
return
result = await support.removeMemberFromTicket(user,str(ctx.channel.id), str(ctx.guild.id))
await ctx.response.send_message(result,ephemeral=True)
@tree.command(name="closeticket", description="Close a ticket")
async def closeticket(ctx):
if (ctx.guild == None):
await ctx.response.send_message("This command can only be used in a server",ephemeral=True)
return
server = ctx.guild.id
if not support.is_server_valid(str(server)):
await ctx.response.send_message("This server is not registered",ephemeral=True)
return
await ctx.response.send_message("Closing ticket",ephemeral=True)
await support.close_ticket(str(ctx.user.id),str(ctx.channel.id), str(ctx.guild.id))
@tree.command(name="reopenticket", description="Reopen a ticket")
async def reopenticket(ctx):
if (ctx.guild == None):
await ctx.response.send_message("This command can only be used in a server",ephemeral=True)
return
server = ctx.guild.id
if not support.is_server_valid(str(server)):
await ctx.response.send_message("This server is not registered",ephemeral=True)
return
await ctx.response.send_message("Reopening ticket",ephemeral=True)
await support.reopen_ticket(str(ctx.user.id),str(ctx.channel.id), str(ctx.guild.id))
@tree.command(name="renameticket", description="Rename a ticket")
async def renameticket(ctx, name: str):
if (ctx.guild == None):
await ctx.response.send_message("This command can only be used in a server",ephemeral=True)
return
server = ctx.guild.id
if not support.is_server_valid(str(server)):
await ctx.response.send_message("This server is not registered",ephemeral=True)
return
result = await support.rename_ticket(str(ctx.user.id),str(ctx.channel.id), str(ctx.guild.id),name)
await ctx.response.send_message(result,ephemeral=True)
#endregion
2023-11-14 13:56:55 +11:00
@tasks.loop(seconds=10)
2023-11-14 13:15:56 +11:00
async def check_reminders():
now = datetime.datetime.now()
reminders = read_reminders()
for reminder in reminders[:]:
reminder_time = datetime.datetime.strptime(reminder['time'], "%Y-%m-%d %H:%M:%S")
if reminder_time <= now:
user = await client.fetch_user(int(reminder['user_id']))
2023-11-14 13:56:55 +11:00
2023-11-14 14:01:29 +11:00
await user.send(embed=tools.embed("Reminder", reminder['text']))
2023-11-14 13:56:55 +11:00
print("Reminder sent for "+str(reminder), flush=True)
2023-11-14 13:15:56 +11:00
reminders.remove(reminder)
write_reminders(reminders)
2023-08-11 15:55:44 +10:00
# When the bot is ready
@client.event
async def on_ready():
2023-08-12 17:14:55 +10:00
global ADMINID
ADMINID = client.application.owner.id
2024-02-07 23:24:31 +11:00
support.set_client(client)
2023-08-11 15:55:44 +10:00
await tree.sync()
updateStatus()
2023-11-14 13:56:55 +11:00
check_reminders.start()
checkForSSLExpiry.start()
2023-08-11 15:55:44 +10:00
2023-11-14 13:56:55 +11:00
client.run(TOKEN)
2023-10-01 22:38:31 +11:00
2023-10-01 22:45:21 +11:00
2024-02-07 23:24:31 +11:00