Merge pull request #4 from stijndcl/remind

Remind command + Les
This commit is contained in:
Stijn De Clercq 2020-10-24 00:01:32 +02:00 committed by GitHub
commit 76e317169d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 592 additions and 335 deletions

53
cogs/remind.py Normal file
View file

@ -0,0 +1,53 @@
import discord
from discord.ext import commands
from decorators import help
from enums.help_categories import Category
from functions.database import remind
class Remind(commands.Cog):
def __init__(self, client):
self.client = client
# Don't allow any commands to work when locked
def cog_check(self, ctx):
return not self.client.locked
@commands.group(name="Remind", aliases=["Remindme"], usage="[Categorie]", case_insensitive=True, invoke_without_command=True)
@help.Category(Category.Other)
async def remind(self, ctx):
"""
Command group to remind the user of a certain thing every day.
:param ctx: Discord Context
"""
categories = ["Les", "Nightly"]
embed = discord.Embed(colour=discord.Colour.blue())
embed.set_author(name="Remind Categorieën")
embed.description = "\n".join(sorted(categories))
await ctx.send(embed=embed)
@remind.command(name="Nightly")
async def nightly(self, ctx):
"""
Command to get a daily Nightly reminder
"""
if remind.switchReminder(ctx.author.id, "nightly"):
await ctx.send("Vanaf nu wordt je er dagelijks aan herinnerd om Didier Nightly te doen.")
else:
await ctx.send("Je zal er niet langer aan herinnerd worden om Didier Nightly te doen.")
@remind.command(name="Les", aliases=["Class", "Classes", "Sched", "Schedule"])
async def les(self, ctx):
"""
Command to get a daily reminder with an embed of your schedule
"""
if remind.switchReminder(ctx.author.id, "les"):
await ctx.send("Vanaf nu krijg je dagelijks je lessenrooster toegestuurd.")
else:
await ctx.send("Je zal je lessenrooster niet langer toegestuurd krijgen.")
def setup(client):
client.add_cog(Remind(client))

View file

@ -1,12 +1,10 @@
from data import constants
import datetime
from decorators import help
import discord
from discord.ext import commands
from enums.courses import years
from enums.help_categories import Category
from functions import checks, eten, timeFormatters, config, stringFormatters
from functions.numbers import clamp
from functions import checks, eten, les
import json
@ -23,7 +21,7 @@ class School(commands.Cog):
@commands.check(checks.allowedChannels)
@help.Category(category=Category.School)
async def eten(self, ctx, *day):
day = self.getWeekDay(None if len(day) == 0 else day)[1]
day = les.getWeekDay(None if len(day) == 0 else day)[1]
# Create embed
menu = eten.etenScript(day)
@ -41,250 +39,37 @@ class School(commands.Cog):
embed.set_footer(text="Omwille van de coronamaatregelen is er een beperkter aanbod, en kan je enkel nog eten afhalen. Ter plaatse eten is niet meer mogelijk.")
await ctx.send(embed=embed)
@commands.command(name="Les", aliases=["Sched", "Schedule", "Class"], usage="[Jaargang]* [Dag]*")
@commands.command(name="Les", aliases=["Class", "Classes", "Sched", "Schedule"], usage="[Jaargang]* [Dag]*")
@commands.check(checks.allowedChannels)
@help.Category(category=Category.School)
async def les(self, ctx, *day):
semester = int(config.get("semester"))
year = int(config.get("year"))
years_counter = int(config.get("years"))
# Check if a schedule or a day was called
if len(day) == 0:
day = []
else:
# Only either of them was passed
if len(day) == 1:
# Called a schedule
if day[0].isdigit():
if 0 < int(day[0]) < years_counter + 1:
year = int(day[0])
day = []
else:
return await ctx.send("Dit is geen geldige jaargang.")
# elif: calling a weekday is automatically handled below,
# so checking is obsolete
else:
# Both were passed
if day[0].isdigit():
if 0 < int(day[0]) < years_counter + 1:
year = int(day[0])
day = []
else:
return await ctx.send("Dit is geen geldige jaargang.")
# Cut the schedule from the string
day = day[1:]
parsed = les.parseArgs(day)
day = self.getWeekDay(None if len(day) == 0 else day)[1]
dayDatetime = self.findDate(timeFormatters.weekdayToInt(day))
# Invalid arguments
if not parsed[0]:
return await ctx.send(parsed[1])
day, dayDatetime, semester, year = parsed[1:]
# Customize the user's schedule
schedule = self.customizeSchedule(ctx, year, semester)
# Create a date object to check the current week
startDate = 1600041600
currentTime = dayDatetime.timestamp()
week = clamp(timeFormatters.timeIn(currentTime - startDate, "weeks")[0], 1, 13)
# Create the embed
embed = les.createEmbed(day, dayDatetime, semester, year, schedule)
title, week = self.getTitle(day, dayDatetime, week)
# Add all courses & their corresponding times + locations of today
courses, extras, prev, online = self.getCourses(schedule, day, week)
embed = discord.Embed(colour=discord.Colour.blue(), title=title)
embed.set_author(name="Lessenrooster voor {}{} Bachelor".format(year, "ste" if year == 1 else "de"))
if len(courses) == 0:
embed.add_field(name="Geen Les", value="Geen Les", inline=False)
else:
courseString = self.createCourseString(courses)
courseString += "\nGroep {} heeft vandaag online les.".format(1 if week % 2 == 0 else 2)
embed.description = courseString
if prev:
embed.add_field(name="Vakken uit vorige jaren", value=self.createCourseString(prev), inline=False)
if extras:
embed.add_field(name="Extra", value="\n".join(self.getExtras(extra) for extra in extras), inline=False)
# Add online links if not commnet
if online:
embed.add_field(name="Online Links", value="\n".join(self.getLink(onlineClass) for onlineClass in online))
embed.set_footer(text="Semester {} | Lesweek {}".format(semester, round(week)))
await ctx.send(embed=embed)
def getLink(self, onlineClass):
return "{}: **[{}]({})**".format(onlineClass["course"], onlineClass["online"], onlineClass["link"])
def createCourseString(self, courses):
courseString = ""
for course in sorted(courses, key=lambda item: item["slot"]["time"][1]):
# Add a ":" to the hour + add a leading "0" if needed
start = timeFormatters.timeFromInt(course["slot"]["time"][1])
end = timeFormatters.timeFromInt(course["slot"]["time"][2])
courseString += "{} - {}: {} {}\n".format(start, end,
str(course["course"]), self.getLocation(course["slot"]))
return courseString
# Returns the day of the week, while keeping track of weekends
def getWeekDay(self, day=None):
weekDays = ["maandag", "dinsdag", "woensdag", "donderdag", "vrijdag"]
# Get current day of the week
dayNumber = datetime.datetime.today().weekday()
# If a day or a modifier was passed, show that day instead
if day is not None:
if day[0] == "morgen":
dayNumber += 1
elif day[0] == "overmorgen":
dayNumber += 2
else:
for i in range(5):
if weekDays[i].startswith(day):
dayNumber = i
# Weekends should be skipped
dayNumber = dayNumber % 7
if dayNumber > 4:
dayNumber = 0
# Get daystring
return dayNumber, weekDays[dayNumber]
def getLocation(self, slot):
if "canceled" in slot:
return None
if "online" in slot:
return "online @ **[{}]({})**".format(slot["online"], slot["zoom"] if slot["online"] == "ZOOM" else slot["bongo"])
# Check for courses in multiple locations
if "locations" in slot:
# Language - 'en' for the last one
return ", ".join(self.getLocation(location) for location in slot["locations"][:-1]) \
+ " en " + self.getLocation(slot["locations"][-1])
return "in {} {} {}".format(slot["campus"], slot["building"], slot["room"])
def getCourses(self, schedule, day, week):
# Add all courses & their corresponding times + locations of today
courses = []
extras = []
prev = []
onlineLinks = []
for course in schedule:
for slot in course["slots"]:
if day in slot["time"]:
classDic = {"course": course["course"], "slot": slot}
# Class was canceled
if "canceled" in slot and "weeks" in slot and week in slot["weeks"]:
extras.append(classDic)
continue
# Add online links for those at home
if not any(el["course"] == course["course"] for el in onlineLinks):
if "bongo" in course:
onlineDic = {"course": course["course"], "online": "Bongo Virtual Classroom", "link": course["bongo"]}
onlineLinks.append(onlineDic)
elif "zoom" in course:
onlineDic = {"course": course["course"], "online": "Zoom", "link": course["zoom"]}
onlineLinks.append(onlineDic)
# Add this class' bongo & zoom links
if "bongo" in course:
classDic["slot"]["bongo"] = course["bongo"]
if "zoom" in course:
classDic["slot"]["zoom"] = course["zoom"]
if "custom" in course:
prev.append(classDic)
# Check for special classes
if "weeks" in slot and "online" not in slot:
if week in slot["weeks"]:
if "custom" not in course:
courses.append(classDic)
extras.append(classDic)
elif "weeks" in slot and "online" in slot and "group" not in slot:
if week in slot["weeks"]:
if "custom" not in course:
courses.append(classDic)
extras.append(classDic)
else:
if "custom" not in course:
courses.append(classDic)
# Filter out normal courses that are replaced with special courses
for extra in extras:
for course in courses:
if course["slot"]["time"] == extra["slot"]["time"] and course != extra:
courses.remove(course)
break
# Sort online links alphabetically
onlineLinks.sort(key=lambda x: x["course"])
# Remove links of canceled classes
for element in onlineLinks:
if not any(c["course"] == element["course"] for c in courses):
onlineLinks.remove(element)
return courses, extras, prev, onlineLinks
def getTitle(self, day, dayDT, week):
# now = timeFormatters.dateTimeNow()
# if timeFormatters.weekdayToInt(day) < now.weekday():
# week += 1
day = day[0].upper() + day[1:].lower()
titleString = "{} {}/{}/{}".format(day, stringFormatters.leadingZero(dayDT.day),
stringFormatters.leadingZero(dayDT.month), dayDT.year)
return titleString, week
def getExtras(self, extra):
start = timeFormatters.timeFromInt(extra["slot"]["time"][1])
end = timeFormatters.timeFromInt(extra["slot"]["time"][2])
location = self.getLocation(extra["slot"])
if "canceled" in extra["slot"]:
return "De les **{}** van **{}** tot **{}** gaat vandaag uitzonderlijk **niet** door.".format(
extra["course"], start, end
)
if "group" in extra["slot"]:
return "**Groep {}** heeft vandaag uitzonderlijk **{}** **{}** van **{} tot {}**.".format(
extra["slot"]["group"], extra["course"], location,
start, end
)
elif "online" in extra["slot"]:
return "**{}** gaat vandaag uitzonderlijk online door {} van **{} tot {}**.".format(
extra["course"], location[7:],
start, end
)
else:
return "**{}** vindt vandaag uitzonderlijk plaats **{}** van **{} tot {}**.".format(
extra["course"], location,
start, end
)
def findDate(self, targetWeekday):
now = timeFormatters.dateTimeNow()
while now.weekday() != targetWeekday:
now = now + datetime.timedelta(days=1)
return now
# Add all the user's courses
def customizeSchedule(self, ctx, year, semester):
with open("files/schedules/{}{}.json".format(year, semester), "r") as fp:
schedule = json.load(fp)
return schedule
member = self.client.get_guild(int(constants.CallOfCode)).get_member(ctx.author.id)
schedule = les.getSchedule(semester, year)
COC = self.client.get_guild(int(constants.CallOfCode))
if COC is None:
return schedule
member = COC.get_member(ctx.author.id)
for role in member.roles:
for univYear in years:
for course in univYear:

View file

@ -1,9 +1,11 @@
from data import constants
from data.remind import Reminders
from discord.ext import commands, tasks
from enums.numbers import Numbers
from functions import timeFormatters
from functions.database import currency, poke, prison, birthdays, stats
import json
import random
import requests
import time
@ -18,9 +20,13 @@ class Tasks(commands.Cog):
# self.resetPoke.start()
self.checkBirthdays.start()
self.updateMessageCounts.start()
self.sendReminders.start()
@tasks.loop(hours=1.0)
async def bankInterest(self):
"""
Task that gives daily interest
"""
# Don't do it multiple times a day if bot dc's, ...
with open("files/lastTasks.json", "r") as fp:
lastTasks = json.load(fp)
@ -58,6 +64,9 @@ class Tasks(commands.Cog):
@tasks.loop(hours=1.0)
async def resetLost(self):
"""
Task that resets Lost Today
"""
# Don't do it multiple times a day if bot dc's, ...
with open("files/lastTasks.json", "r") as fp:
lastTasks = json.load(fp)
@ -79,6 +88,9 @@ class Tasks(commands.Cog):
@tasks.loop(hours=6.0)
async def resetPoke(self):
"""
Task that resets Poke
"""
if int(time.time()) - int(poke.get()[1]) > 259200:
await self.client.get_guild(int(self.client.constants.CallOfCode))\
.get_channel(int(self.client.constants.DidierPosting))\
@ -90,6 +102,9 @@ class Tasks(commands.Cog):
@tasks.loop(hours=1.0)
async def resetPrison(self):
"""
Task that lowers prison time daily
"""
# Don't do it multiple times a day if bot dc's, ...
with open("files/lastTasks.json", "r") as fp:
lastTasks = json.load(fp)
@ -107,6 +122,9 @@ class Tasks(commands.Cog):
@tasks.loop(hours=1.0)
async def checkBirthdays(self):
"""
Task that wishes people a happy birthday
"""
# Don't do it multiple times a day if bot dc's, ...
with open("files/lastTasks.json", "r") as fp:
lastTasks = json.load(fp)
@ -138,6 +156,9 @@ class Tasks(commands.Cog):
@tasks.loop(hours=1.0)
async def updateMessageCounts(self):
"""
Task that updates the activity counter for channels
"""
# Don't do it multiple times a day if bot dc's, ...
with open("files/lastTasks.json", "r") as fp:
lastTasks = json.load(fp)
@ -154,6 +175,39 @@ class Tasks(commands.Cog):
async def beforeupdateMessageCounts(self):
await self.client.wait_until_ready()
@tasks.loop(hours=1.0)
async def sendReminders(self):
"""
Task that sends people daily reminders
"""
# Don't do it multiple times a day if bot dc's, ...
with open("files/lastTasks.json", "r") as fp:
lastTasks = json.load(fp)
if int(self.getCurrentHour()) == 7 and int(time.time()) - int(lastTasks["remind"]) > 10000:
reminders = Reminders()
for category in reminders.categories:
for user in category["users"]:
userInstance = await self.client.fetch_user(user)
# User can't be fetched for whatever reason, ignore instead of crashing
if userInstance is None:
continue
# Check if a special embed has to be attached for this reminder
if "embed" not in category:
await userInstance.send(random.choice(category["messages"]))
else:
await userInstance.send(random.choice(category["messages"]), embed=category["embed"])
with open("files/lastTasks.json", "w") as fp:
lastTasks["remind"] = round(time.time())
json.dump(lastTasks, fp)
@sendReminders.before_loop
async def beforeSendReminders(self):
await self.client.wait_until_ready()
def getCurrentHour(self):
return timeFormatters.dateTimeNow().hour