diff --git a/data/les.py b/data/les.py new file mode 100644 index 0000000..d2b6472 --- /dev/null +++ b/data/les.py @@ -0,0 +1,143 @@ +from enums.platforms import Platforms +from functions.timeFormatters import timeFromInt + + +# A container class for schedules +class Schedule: + def __init__(self, schedule: dict): + self.courses = [Course(course) for course in schedule] + self.customs = [] # Courses that only the person that called the schedule has + self.extra = [] # Courses that need special attention (canceled, online, ...) + + def addCustom(self, course): + """ + Function that adds a course into the list of courses, + useful for adding a user's custom courses + """ + self.customs.append(Course(course)) + + +# A container class for courses +class Course: + # Initialize a course from the dict that the JSON contains + def __init__(self, courseInfo: dict): + self.courseInfo = courseInfo + self.name = courseInfo["course"] + + self.slots = [] + self.initSlots() + + self.platforms = {} + self.initPlatforms() + + def initSlots(self): + """ + Function that creates Slot instances & adds them to the list + """ + for slot in self.courseInfo["slots"]: + self.slots.append(Slot(self, slot)) + + def initPlatforms(self): + """ + Function that creates Platform instances & adds them into the dict + """ + for platform in Platforms: + if platform["rep"] in self.courseInfo: + self.platforms[platform["rep"]] = Platform(platform["name"], self.courseInfo[platform["rep"]]) + + def getSlotsOnDay(self, day: str, week: int): + """ + Function that returns a list of all slots of this course + on a given day of the week + + This list then has duplicate days filtered out depending on + whether or not there is a special class on this day + """ + slots = [] + specials = [] + + for slot in self.slots: + # Skip slots on other days + if slot.day != day: + continue + + # This is a special slot that should only be added + # if the week corresponds + if slot.weeks and week not in slot.weeks: + continue + + if slot.special: + specials.append(slot) + else: + slots.append(slot) + +# Filter doubles out (special classes, ...) + for special in specials: + for slot in slots: + if slot.start == special.start and slot.end == special.end: + slots.remove(slot) + + return slots, specials + + +# TODO add an is_online field to the JSON to allow toggling +# temporary online classes easier +# A slot in a course +class Slot: + def __init__(self, course: Course, slot: dict): + self.course = course + self.day = slot["time"][0] + self.start = timeFromInt(slot["time"][1]) + self.end = timeFromInt(slot["time"][2]) + self.weeks = [] if "weeks" not in slot else slot["weeks"] + self.canceled = "canceled" in slot # Boolean indicating whether or not this class has been canceled + self.special = "weeks" in slot or self.canceled # Boolean indicating if this class is special or generic + + # TODO check if on-campus, else None + self.locations = self.setLocations(slot) + self.platform = self.course.platforms[slot["online"]] + + def setLocations(self, slot: dict): + """ + Function that creates a list of Location instances + """ + locations = [] + + # Slot has multiple locations + if "locations" in slot: + for location in slot["locations"]: + locations.append(Location(location)) + else: + # Slot has only one location + locations.append(Location(slot)) + + return locations + + def getLocations(self): + """ + Function that creates a string representation for this + slot's locations + """ + if self.locations is None: + return "" + + def getOnline(self): + pass + + +# A location where a course might take place +class Location: + def __init__(self, slot: dict): + self.campus = slot["campus"] + self.building = slot["building"] + self.room = slot["room"] + + def __str__(self): + return " ".join([self.campus, self.building, self.room]) + + +# A streaming platform +class Platform: + def __init__(self, name, url): + self.name = name + self.url = url diff --git a/data/schedule.py b/data/schedule.py deleted file mode 100644 index 45cdcd2..0000000 --- a/data/schedule.py +++ /dev/null @@ -1,128 +0,0 @@ -import json -from dacite import from_dict -from dataclasses import dataclass, field -from datetime import datetime, timedelta -from enums.platforms import Platforms -from functions.config import get -from typing import Dict, Optional, List - -from functions.timeFormatters import fromArray - - -@dataclass -class Holiday: - start_list: List[int] - end_list: List[int] - start_date: datetime = field(init=False) - end_date: datetime = field(init=False) - duration: timedelta = field(init=False) - - def __post_init__(self): - self.start_date = fromArray(self.start_list) - self.end_date = fromArray(self.end_list) - self.duration = self.end_date - self.start_date - - def has_passed(self, current_day: datetime) -> bool: - """ - Check if a holiday has passed already - """ - return current_day > self.end_date - - -@dataclass -class Course: - day: str - week: int - course_dict: Dict - - -@dataclass -class Location: - campus: str - building: str - room: str - - -@dataclass -class Timeslot: - course: Course - start_time: int - end_time: int - canceled: bool = False - is_special: bool = False - location: Optional[Location] = None - online_link: Optional[str] = None - online_platform: Optional[Platforms] = None - - -@dataclass -class Schedule: - day: datetime - schedule_dict: Dict = field(init=False) - start_date: datetime - end_date: datetime - semester_over: bool = False - holiday_offset: int = 0 - current_holiday: Optional[Holiday] = None - - def __post_init__(self): - self.schedule_dict: Dict = self.load_schedule_file() - self.start_date = fromArray(self.schedule_dict["semester_start"]) - self.end_date = fromArray(self.schedule_dict["semester_end"]) - - # Semester is over - if self.end_date <= self.day: - self.semester_over = True - return - - self.check_holidays() - - # Show schedule for after holidays - if self.current_holiday is not None: - self.day = self.current_holiday.end_date + timedelta(days=1) - - def check_holidays(self): - """ - Do all holiday-related stuff here to avoid multiple loops - """ - for hol_entry in self.schedule_dict.get("holidays", []): - holiday: Holiday = from_dict(Holiday, hol_entry) - - # Hasn't happened yet, don't care - if holiday.start_date > self.day: - continue - - # In the past: add the offset - if holiday.has_passed(self.day): - self.holiday_offset += (self.day - holiday.end_date) // 7 - elif holiday.start_date <= self.day <= holiday.end_date: - self.current_holiday = holiday - - def load_schedule_file(self) -> Dict: - """ - Load the schedule from the JSON file - """ - semester = get("semester") - year = get("year") - - with open(f"files/{year}{semester}.json", "r") as fp: - return json.load(fp) - - def get_week(self) -> int: - """ - Get the current week of the semester - """ - diff: timedelta = self.day - self.start_date - - # Hasn't started yet, show week 1 - if diff.days < 0: - return 1 - - # Add +1 at the end because week 1 would be 0 as it's not over yet - return (diff.days // 7) + self.holiday_offset + 1 - - def create_schedule(self): - """ - Create the schedule for the current week - """ - week: int = self.get_week() diff --git a/functions/les_rework.py b/functions/les_rework.py deleted file mode 100644 index 6646a4a..0000000 --- a/functions/les_rework.py +++ /dev/null @@ -1,58 +0,0 @@ -from datetime import datetime, timedelta -from timeFormatters import dateTimeNow, weekdayToInt -from typing import Optional - - -def find_target_date(arg: Optional[str]) -> datetime: - """ - Find the requested date out of the user's arguments - """ - # Start at current date - day: datetime = dateTimeNow() - - # If no offset was provided, check the time - # otherwise the argument overrides it - if arg is None: - # When the command is used after 6 pm, show schedule - # for the next day instead - if day.hour > 18: - day += timedelta(days=1) - elif 0 <= (weekday := weekdayToInt(arg)) <= 4: # Weekday provided - day = forward_to_weekday(day, weekday) - elif arg.lower() == "morgen": # Tomorrow's schedule - day += timedelta(days=1) - elif arg.lower() == "overmorgen": # Day after tomorrow's schedule - day += timedelta(days=2) - - # Don't land on a weekend - day = skip_weekends(day) - - return day - - -def skip_weekends(day: datetime) -> datetime: - """ - Increment the current date if it's not a weekday - """ - weekday = day.weekday() - - # Friday is weekday 4 - if weekday > 4: - return day + timedelta(days=(7 - weekday)) - - return day - - -def forward_to_weekday(day: datetime, weekday: int) -> datetime: - """ - Increment a date until the weekday is the same as the one provided - Finds the "next" [weekday] - """ - current = day.weekday() - - # This avoids negative numbers below, and shows - # next week in case the days are the same - if weekday >= current: - weekday += 7 - - return day + timedelta(days=(weekday - current)) diff --git a/functions/timeFormatters.py b/functions/timeFormatters.py index 58e6712..b79dd74 100644 --- a/functions/timeFormatters.py +++ b/functions/timeFormatters.py @@ -1,12 +1,8 @@ import datetime -from typing import List - import dateutil.relativedelta import pytz import time -from functions import stringFormatters - def epochToDate(epochTimeStamp, strFormat="%d/%m/%Y om %H:%M:%S"): now = dateTimeNow() @@ -138,12 +134,8 @@ def getPlural(amount, unit): return dic[unit.lower()]["s" if amount == 1 else "p"] -def weekdayToInt(day) -> int: +def weekdayToInt(day): days = {"maandag": 0, "dinsdag": 1, "woensdag": 2, "donderdag": 3, "vrijdag": 4, "zaterdag": 5, "zondag": 6} - - if day.lower() not in days: - return -1 - return days[day.lower()] @@ -151,16 +143,8 @@ def intToWeekday(day): return ["Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"][day] -def fromString(timeString: str, formatString="%d/%m/%Y", tzinfo=pytz.timezone("Europe/Brussels")): +def fromString(timeString: str, formatString="%d/%m/%Y"): """ Constructs a datetime object from an input string """ - return datetime.datetime.strptime(timeString, formatString).replace(tzinfo=tzinfo) - - -def fromArray(data: List[int]) -> datetime: - day = stringFormatters.leadingZero(str(data[0])) - month = stringFormatters.leadingZero(str(data[1])) - year = str(data[2]) - - return fromString(f"{day}/{month}/{year}") + return datetime.datetime.strptime(timeString, formatString) diff --git a/requirements.txt b/requirements.txt index 083a9f5..77d3ae8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,6 +14,4 @@ yarl==1.4.2 feedparser==6.0.2 googletrans==4.0.0rc1 quart==0.15.1 -Quart-CORS==0.5.0 -attrs~=21.2.0 -dacite~=1.6.0 \ No newline at end of file +Quart-CORS==0.5.0 \ No newline at end of file