Merge pull request #4 from stijndcl/remind

Remind command + Les
pull/5/head
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 100644
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

24
data/remind.py 100644
View File

@ -0,0 +1,24 @@
from functions import les
from functions.database import remind
class Reminders:
def __init__(self):
rows = remind.getAllRows()
self._nightlyUsers = [int(user[0]) for user in rows if user[1]]
self._nightlyMessages = ["Dagelijkse herinnering om Didier Nightly te doen.", "Vrees niet, Nightly-streak-liefhebber! 't Zenne kik, Didier, me ne reminder!"]
self.nightly = {"users": self._nightlyUsers, "messages": self._nightlyMessages}
self._les = [int(user[0]) for user in rows if user[2]]
self._lesMessages = ["Lessenrooster voor vandaag:"]
self.les = {"users": self._les, "messages": self._lesMessages, "embed": self.lesEmbed()}
self.categories = [self.nightly, self.les]
def lesEmbed(self):
day, dayDatetime, semester, year = les.parseArgs([])[1:]
schedule = les.getSchedule(semester, year)
return les.createEmbed(day, dayDatetime, semester, year, schedule)

View File

@ -140,6 +140,14 @@ Used in dinks.py - Prison commands. Contains information on who is in prison.
2 days: integer | The remaining days this user has to spend in prison
3 daily: numeric | The amount of Didier Dinks that [daily] decreases by every day
### remind
Used in tasks.py - sendReminders task.
0 userid: bigint, unique, primary key | The user's Discord id
1 nightly: boolean, default false | A boolean indicating whether or not the user wants Nightly reminders
2 les: boolean, default false | A boolean indicating whether or not the user wants Les reminders
### store
Used in store.py - Store commands. Contains info on items that are available for purchase.

View File

@ -9,8 +9,8 @@ load_dotenv(verbose=True)
# All possible prefixes
# When_mentioned_or doesn't count for spaces so can't use that
prefixes = ["didier ", "Didier ", "DIDIER ", "big d ", "<@!680510935164911730> ",
"didier", "Didier", "DIDIER", "big d", "<@!680510935164911730>"]
prefixes = ["didier ", "Didier ", "DIDIER ", "big d ", "Big d ", "Big D ", "BIG D ", "<@!680510935164911730> ",
"didier", "Didier", "DIDIER", "big d", "Big d", "Big D", "BIG D", "<@!680510935164911730>"]
# Configure intents (1.5.0)
intents = discord.Intents.default()

View File

@ -86,7 +86,9 @@
"releases": "Lijst van de games die in de volgende 30 dagen uitkomen.\nGeef een getal op om volgende/vorige pagina's te bekijken (standaard pagina 1).",
"releases info": "Geeft gedetailleerde informatie over de game met de opgegeven id.",
"reload": "Verwijdert [Cog] & voegt hem daarna terug toe.",
"remind": "Krijg een dagelijkse herinnering om Didier Nightly te doen.\nMeer categorieën en usages komen later:tm:.",
"remind": "Krijg een lijst van categorieën waaraan je dagelijks herinnerd kan worden.\nOm deze herinneringen niet langer te krijgen, kan je opnieuw Didier Remind [Categorie] doen.",
"remind les": "Krijg dagelijks het lessenrooster voor die dag toegestuurd.",
"remind nightly": "Krijg dagelijks een herinnering om Didier Nightly te doen.",
"reverse": "Returnt tekst achterstevoren.",
"rhyme": "Stuurt de 15 beste suggesties voor woorden die rijmen op [Woord].",
"rob": "Probeer Didier Dinks te stelen van [Persoon].",

View File

@ -6,16 +6,10 @@
"slots": [
{
"online": "Bongo Virtual Classroom",
"campus": "Sterre",
"building": "S8",
"room": "LES 3.1",
"time": ["maandag", 1000, 1230]
},
{
"online": "ZOOM",
"campus": "Sterre",
"building": "S8",
"room": "LES 2.4",
"time": ["vrijdag", 1300, 1530]
}
]
@ -24,34 +18,14 @@
"course": "Systeemprogrammeren",
"bongo": "https://ufora.ugent.be/d2l/ext/rp/222035/lti/framedlaunch/7f4120b3-8827-44ad-8b02-a79066c396cf",
"slots": [
{
"campus": "Sterre",
"building": "S8",
"room": "LES 2.1",
"time": ["donderdag", 1430, 1700]
},
{
"online": "Bongo Virtual Classroom",
"weeks": [1],
"group": 1,
"campus": "Sterre",
"building": "S4",
"room": "LES 0.1",
"time": ["maandag", 1430, 1700]
},
{
"online": "Bongo Virtual Classroom",
"weeks": [1],
"time": ["donderdag", 1430, 1700]
},
{
"weeks": [2],
"group": 2,
"campus": "Sterre",
"building": "S4",
"room": "LES 0.1",
"time": ["maandag", 1430, 1700]
},
{
"weeks": [3],
"canceled": true,
@ -73,94 +47,92 @@
}
],
"time": ["maandag", 1430, 1700]
},
{
"weeks": [5],
"group": 1,
"locations": [
{
"campus": "Sterre",
"building": "S8",
"room": "LES 0.1 Victor Van Straelen"
},
{
"campus": "Sterre",
"building": "S9",
"room": "3.1 Konrad Zuse"
}
],
"time": ["maandag", 1430, 1700]
}
]
},
{
"course": "AD 2",
"bongo": "https://ufora.ugent.be/d2l/ext/rp/222018/lti/framedlaunch/7f4120b3-8827-44ad-8b02-a79066c396cf",
"msteams": "https://teams.microsoft.com/_?culture=nl-nl&country=NL&lm=deeplink&lmsrc=homePageWeb&cmpid=WebSignIn#/conversations/19:8ee7593d50924201a43ed9373dd6b05d@thread.v2?ctx=chat",
"zoom": "https://ufora.ugent.be/d2l/ext/rp/222018/lti/framedlaunch/556e197e-e87b-4c27-be5d-53adc7a41826",
"slots": [
{
"online": "Bongo Virtual Classroom",
"campus": "Sterre",
"building": "S9",
"room": "A3",
"time": ["dinsdag", 1300, 1530]
"time": ["dinsdag", 1300, 1400]
},
{
"online": "ZOOM",
"campus": "Sterre",
"building": "S9",
"room": "A3",
"time": ["dinsdag", 1430, 1530]
},
{
"online": "Bongo Virtual Classroom",
"campus": "Sterre",
"building": "S9",
"room": "A3",
"time": ["vrijdag", 830, 930]
},
{
"locations": [
{
"campus": "Sterre",
"building": "S8",
"room": "Victor Van Straelen"
},
{
"campus": "Sterre",
"building": "S9",
"room": "3.1 Konrad Zuse"
}
],
"online": "MS Teams",
"campus": "Sterre",
"building": "S9",
"room": "3.1 Kondrad Zuse",
"time": ["vrijdag", 1000, 1100]
},
{
"weeks": [6, 7, 8, 9, 10, 11, 12],
"online": "Bongo Virtual Classroom",
"time": ["dinsdag", 1300, 1400]
},
{
"weeks": [6, 7, 8, 9, 10, 11, 12],
"online": "ZOOM",
"time": ["dinsdag", 1430, 1530]
},
{
"weeks": [6, 7, 8, 9, 10, 11, 12],
"online": "Bongo Virtual Classroom",
"time": ["vrijdag", 830, 930]
},
{
"weeks": [6, 7, 8, 9, 10, 11, 12],
"online": "MS Teams",
"time": ["vrijdag", 1000, 1100]
}
]
},
{
"course": "Communicatienetwerken",
"zoom": "https://ufora.ugent.be/d2l/ext/rp/221184/lti/framedlaunch/556e197e-e87b-4c27-be5d-53adc7a41826",
"slots": [
{
"online": "ZOOM",
"campus": "Ardoyen",
"building": "Locus",
"room": "Resto Locus",
"time": ["woensdag", 1000, 1230]
"time": ["woensdag", 1100, 1200]
},
{
"online": "ZOOM",
"campus": "Ardoyen",
"building": "Locus",
"room": "Resto Locus",
"time": ["woensdag", 1430, 1700]
"time": ["woensdag", 1430, 1600]
},
{
"weeks": [4, 7],
"locations": [
{
"campus": "Ardoyen",
"building": "iGent",
"room": "0.1"
},
{
"campus": "Ardoyen",
"building": "iGent",
"room": "0.1 PRA"
},
{
"campus": "Ardoyen",
"building": "iGent",
"room": "0.2"
}
],
"time": ["woensdag", 1430, 1700]
"weeks": [6, 7, 8, 9, 10, 11, 12],
"online": "ZOOM",
"time": ["woensdag", 1100, 1200]
},
{
"weeks": [6, 7, 8, 9, 10, 11, 12],
"online": "ZOOM",
"time": ["woensdag", 1430, 1600]
}
]
},
@ -170,32 +142,14 @@
"slots": [
{
"online": "Bongo Virtual Classroom",
"campus": "Sterre",
"building": "S12",
"room": "Auditorium 1",
"time": ["dinsdag", 1600, 1700]
},
{
"locations": [
{
"campus": "Sterre",
"building": "S9",
"room": "1.1 Alan Turing"
},
{
"campus": "Sterre",
"building": "S9",
"room": "3.1 Konrad Zuse"
}
],
"online": "Bongo Virtual Classroom",
"time": ["donderdag", 830, 1100]
},
{
"online": "Bongo Virtual Classroom",
"campus": "Sterre",
"building": "S9",
"room": "A2",
"time": ["donderdag", 1300, 1400]
}
]

View File

@ -0,0 +1,43 @@
from functions.database import utils
def getAllRows():
connection = utils.connect()
cursor = connection.cursor()
cursor.execute("SELECT * FROM remind")
return cursor.fetchall()
def getOrAddUser(userid):
connection = utils.connect()
cursor = connection.cursor()
cursor.execute("SELECT * FROM remind WHERE userid = %s", (int(userid),))
res = cursor.fetchall()
if not res:
cursor.execute("INSERT INTO remind(userid) VALUES(%s)", (int(userid),))
connection.commit()
return getOrAddUser(userid)
return res[0]
def switchReminder(userid, column):
connection = utils.connect()
cursor = connection.cursor()
columns = ["id", "nightly", "les"]
res = getOrAddUser(userid)
# Switch the column value
to = not (res[columns.index(column)])
cursor.execute("UPDATE remind SET {} = %s WHERE userid = %s".format(column), (to, int(userid),))
connection.commit()
return to

333
functions/les.py 100644
View File

@ -0,0 +1,333 @@
import datetime
import discord
from functions import config, timeFormatters, stringFormatters
from functions.numbers import clamp
import json
# TODO use constants & enums instead of hardcoding platform names
# also make the naming in the jsons more consistent
def createCourseString(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"]), getLocation(course["slot"]))
return courseString
def createEmbed(day, dayDatetime, semester, year, schedule):
# Create a date object to check the current week
startDate = 1600041600
currentTime = dayDatetime.timestamp()
week = clamp(timeFormatters.timeIn(currentTime - startDate, "weeks")[0], 1, 13)
title, week = getTitle(day, dayDatetime, week)
# Add all courses & their corresponding times + locations of today
courses, extras, prev, online = 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 = createCourseString(courses)
# TODO uncomment this when covid rules slow down
# 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=createCourseString(prev), inline=False)
if extras:
embed.add_field(name="Extra", value="\n".join(getExtras(extra) for extra in extras), inline=False)
# TODO uncomment this when covid rules slow down
# Add online links - temporarily removed because everything is online right now
# if online:
# uniqueLinks: dict = getUniqueLinks(online)
# embed.add_field(name="Online Links", value="\n".join(
# sorted(getLinks(onlineClass, links) for onlineClass, links in uniqueLinks.items())))
embed.set_footer(text="Semester {} | Lesweek {}".format(semester, round(week)))
return embed
def findDate(targetWeekday):
"""
Function that finds the datetime object that corresponds to
the next occurence of [targetWeekday].
:param targetWeekday: The weekday to find
"""
now = timeFormatters.dateTimeNow()
while now.weekday() != targetWeekday:
now = now + datetime.timedelta(days=1)
return now
def getCourses(schedule, day, week):
"""
Function that creates a list of all courses of this day,
a list of all online links, and extra information for these courses.
:param schedule: A user's (customized) schedule
:param day: The current weekday
:param week: The current 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"]:
# Basic dict containing the course name & the class' time slot
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
# Check if link hasn't been added yet
if not any(el["course"] == course["course"] and
# Avoid KeyErrors: if either of these don't have an online link yet,
# add it as well
("online" not in el or "online" not in slot or el["online"] == slot["online"])
for el in onlineLinks):
# Some courses have multiple links on the same day,
# add all of them
if "bongo" in slot["online"].lower():
onlineDic = {"course": course["course"], "online": "Bongo Virtual Classroom",
"link": course["bongo"]}
onlineLinks.append(onlineDic)
if "zoom" in slot["online"].lower():
onlineDic = {"course": course["course"], "online": "ZOOM", "link": course["zoom"]}
onlineLinks.append(onlineDic)
if "teams" in slot["online"].lower():
onlineDic = {"course": course["course"], "online": "MS Teams", "link": course["msteams"]}
onlineLinks.append(onlineDic)
# Add this class' bongo, msteams & zoom links
if "bongo" in course:
classDic["slot"]["bongo"] = course["bongo"]
if "msteams" in course:
classDic["slot"]["msteams"] = course["msteams"]
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:
# This class is only online for this week
if week in slot["weeks"]:
if "custom" not in course:
courses.append(classDic)
extras.append(classDic)
else:
# Nothing special happening, just add it to the list of courses
# in case this is a course for everyone in this year
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 getExtras(extra):
"""
Function that returns a formatted string giving clear info
when a course is happening somewhere else (or canceled).
"""
start = timeFormatters.timeFromInt(extra["slot"]["time"][1])
end = timeFormatters.timeFromInt(extra["slot"]["time"][2])
location = 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 getUniqueLinks(onlineClasses):
"""
Function that returns a dict of all online unique online links for every class
in case some classes have multiple links on the same day.
"""
# Create a list of all unique course names
courseNames = list(set(oc["course"] for oc in onlineClasses))
uniqueLinks: dict = {}
# Add every link of every class into the dict
for name in courseNames:
uniqueLinks[name] = {}
for oc in onlineClasses:
if oc["course"] == name:
# Add the link for this platform
uniqueLinks[name][oc["online"]] = oc["link"]
return uniqueLinks
def getLinks(onlineClass, links):
"""
Function that returns a formatted string giving a hyperlink
to every online link for this class today.
"""
return "{}: {}".format(onlineClass,
" | ".join(
["**[{}]({})**".format(platform, url) for platform, url in
links.items()])
)
def getLocation(slot):
"""
Function that returns a formatted string indicating where this course
is happening.
"""
if "canceled" in slot:
return None
# TODO fix this because it's ugly
if "online" in slot:
return "online @ **[{}]({})**".format(slot["online"],
slot["zoom"] if slot["online"] == "ZOOM" else slot["msteams"] if slot[
"online"] == "MS Teams" else
slot["bongo"])
# Check for courses in multiple locations
if "locations" in slot:
# Language - 'en' for the last one
return ", ".join(getLocation(location) for location in slot["locations"][:-1]) \
+ " en " + getLocation(slot["locations"][-1])
return "in {} {} {}".format(slot["campus"], slot["building"], slot["room"])
def getSchedule(semester, year):
with open("files/schedules/{}{}.json".format(year, semester), "r") as fp:
schedule = json.load(fp)
return schedule
def getTitle(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
# Returns the day of the week, while keeping track of weekends
def getWeekDay(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 parseArgs(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 [False, "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 [False, "Dit is geen geldige jaargang."]
# Cut the schedule from the string
day = day[1:]
day = getWeekDay(None if len(day) == 0 else day)[1]
dayDatetime = findDate(timeFormatters.weekdayToInt(day))
return [True, day, dayDatetime, semester, year]

View File

@ -48,7 +48,8 @@ Contains timestamps for when every `task` in `cogs/tasks.py` ran for the last ti
"interest": 0,
"lost": 0,
"prison": 0,
"poke": 0
"poke": 0,
"remind": 0
}
```