Divent/divent/bot.py

145 lines
3.9 KiB
Python
Raw Normal View History

2022-06-23 13:27:13 +00:00
import json
2022-07-26 13:39:00 +00:00
import logging
2022-06-08 21:02:14 +00:00
from datetime import datetime, timedelta
2022-06-23 13:27:13 +00:00
from os import environ, path
2022-09-07 17:36:18 +00:00
from typing import Optional
2022-05-08 14:02:19 +00:00
2022-05-30 06:30:11 +00:00
from disnake import Client, Guild
2022-05-08 14:02:19 +00:00
from dotenv import load_dotenv
from ics import Calendar, Event # type: ignore
from ics.alarm.display import DisplayAlarm # type: ignore
2022-09-07 17:36:18 +00:00
from quart import Quart, redirect, render_template, request, url_for
2022-09-01 19:06:40 +00:00
import sentry_sdk
2022-08-29 14:14:56 +00:00
from sentry_sdk.integrations.quart import QuartIntegration
2022-05-08 14:02:19 +00:00
load_dotenv()
2022-07-26 13:39:00 +00:00
QUART_DEBUG = environ.get("QUART_DEBUG", False)
2022-05-08 14:02:19 +00:00
DISCORD_TOKEN = environ.get("DISCORD_TOKEN")
2022-09-07 17:36:18 +00:00
if not DISCORD_TOKEN:
raise Exception("Missing DISCORD_TOKEN")
2022-05-08 14:02:19 +00:00
2022-07-26 13:39:00 +00:00
if QUART_DEBUG:
logging.basicConfig(level=logging.DEBUG)
2022-08-29 14:14:56 +00:00
SENTRY_DSN = environ.get("SENTRY_DSN")
if SENTRY_DSN:
sentry_sdk.init(SENTRY_DSN, integrations=[QuartIntegration()])
2022-05-08 14:02:19 +00:00
class Discord(Client):
async def on_ready(self):
print(f"Logged on as {self.user}!")
client = Discord()
app = Quart(__name__)
2022-05-30 15:31:33 +00:00
def get_guild_by_id(guild_id: str) -> Optional[Guild]:
2022-09-07 17:36:18 +00:00
if guild_id:
for guild in client.guilds:
if str(guild.id) == guild_id or guild.vanity_url_code == guild_id:
return guild
2022-05-08 14:02:19 +00:00
return None
2022-06-23 13:27:13 +00:00
CATALOG_CACHE = {}
2022-07-26 13:39:00 +00:00
@app.errorhandler(500)
async def errorhandler(error: Exception):
print(f"\33[31m{error}\33[m")
return await render_template("error.html.j2", error=str(error)), 500
@app.errorhandler(404)
async def not_found(error: Exception):
return await render_template("error.html.j2", error=str(error)), 404
2022-06-23 13:27:13 +00:00
def i18n(str: str) -> str:
lang = request.accept_languages.best_match(["en", "fr"])
if lang not in CATALOG_CACHE:
catalog_file = f"{path.dirname(__file__)}/translations/{lang}.json"
if path.exists(catalog_file):
with open(catalog_file) as catalog_json:
catalog = json.load(catalog_json)
CATALOG_CACHE[lang] = catalog
if lang in CATALOG_CACHE and str in CATALOG_CACHE[lang]:
return CATALOG_CACHE[lang][str]
return str
2022-09-07 21:11:11 +00:00
def days_before_failure() -> int:
2022-06-08 21:02:14 +00:00
nextYear = datetime.today().year + 5 - ((datetime.today().year + 5) % 5)
nextDate = datetime(year=nextYear, month=6, day=3)
nextDelta = nextDate - datetime.now()
2022-06-23 13:27:13 +00:00
return nextDelta.days
@app.context_processor
def context_processor():
2022-09-07 17:36:18 +00:00
return dict(_=i18n, client=client, days_before_failure=days_before_failure())
2022-06-08 21:02:14 +00:00
2022-05-30 15:31:33 +00:00
@app.route("/")
async def index():
2022-09-07 17:36:18 +00:00
guild_id = request.args.get("guild")
guild = get_guild_by_id(guild_id)
2022-07-05 16:23:05 +00:00
2022-09-07 17:36:18 +00:00
if guild:
2022-09-07 21:11:11 +00:00
return redirect(url_for(".subscribe", guild_id=guild_id))
2022-06-08 21:02:14 +00:00
2022-09-07 17:36:18 +00:00
return await render_template("index.html.j2")
2022-09-07 21:11:11 +00:00
@app.route("/subscribe/<guild_id>")
async def subscribe(guild_id: str):
guild = get_guild_by_id(guild_id)
return await render_template("subscribe.html.j2", guild=guild)
2022-05-08 14:02:19 +00:00
@app.route("/<guild_id>.ics")
2022-07-05 16:23:05 +00:00
async def ical(guild_id: str):
2022-05-08 14:02:19 +00:00
guild = get_guild_by_id(guild_id)
if guild is None:
2022-09-07 17:36:18 +00:00
return redirect(url_for(".index"))
2022-05-08 14:02:19 +00:00
calendar = Calendar()
for scheduled_event in guild.scheduled_events:
event = Event()
event.name = scheduled_event.name
event.begin = scheduled_event.scheduled_start_time
2022-05-30 06:30:11 +00:00
event.end = (
scheduled_event.scheduled_end_time
or scheduled_event.scheduled_start_time + timedelta(hours=2)
)
2022-05-08 14:02:19 +00:00
event.uid = str(scheduled_event.id)
event.description = scheduled_event.description
2022-05-30 06:30:11 +00:00
event.url = f"https://discord.com/events/{guild_id}/{scheduled_event.id}"
2022-05-08 14:02:19 +00:00
event.location = (
scheduled_event.entity_metadata.location
if scheduled_event.entity_metadata
else None
)
alarm = DisplayAlarm()
alarm.trigger = timedelta(hours=1)
event.alarms.append(alarm)
calendar.events.add(event)
return str(calendar)
2022-08-22 21:44:02 +00:00
quart_task = client.loop.create_task(app.run_task())
quart_task.add_done_callback(lambda f: client.loop.stop())
client.run(DISCORD_TOKEN)