From 8d82dfe5b5933cc95daf3aca650f98a58abd4195 Mon Sep 17 00:00:00 2001 From: Isaac Beh Date: Fri, 4 Aug 2023 12:01:47 +1000 Subject: [PATCH] Whatsdue: Added weeks_to_show to reduce output --- uqcsbot/utils/uq_course_utils.py | 26 ++++++++++++++++++++++---- uqcsbot/whatsdue.py | 16 ++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/uqcsbot/utils/uq_course_utils.py b/uqcsbot/utils/uq_course_utils.py index af24fed..0ef8654 100644 --- a/uqcsbot/utils/uq_course_utils.py +++ b/uqcsbot/utils/uq_course_utils.py @@ -3,7 +3,7 @@ from datetime import datetime from dateutil import parser from bs4 import BeautifulSoup, element -from typing import List, Dict, Optional, Literal +from typing import List, Dict, Optional, Literal, Tuple from dataclasses import dataclass import json import re @@ -148,6 +148,20 @@ def is_after(self, cutoff: datetime): return True return end_datetime >= cutoff if end_datetime else start_datetime >= cutoff + def is_before(self, cutoff: datetime): + """ + Returns whether the assessment occurs before the given cutoff. + """ + try: + start_datetime, _ = self.get_parsed_due_date() + except DateSyntaxException: + # TODO bot.logger.error(e.message) + # If we can't parse a date, we're better off keeping it just in case. + # TODO(mitch): Keep track of these instances to attempt to accurately + # parse them in future. Will require manual detection + parsing. + return True + return start_datetime <= cutoff + def get_weight_as_int(self): """ Trys to get the weight percentage of an assessment as a percentage. Will return None @@ -339,7 +353,7 @@ def get_course_assessment_page( def get_course_assessment( course_names: List[str], - cutoff: Optional[datetime] = None, + cutoff: Tuple[Optional[datetime], Optional[datetime]] = (None, None), assessment_url: Optional[str] = None, offering: Optional[Offering] = None, ) -> List[AssessmentItem]: @@ -362,8 +376,12 @@ def get_course_assessment( assessment = assessment_table.findAll("tr")[1:] parsed_assessment = map(get_parsed_assessment_item, assessment) # If no cutoff is specified, set cutoff to UNIX epoch (i.e. filter nothing). - cutoff = cutoff or datetime.min - filtered_assessment = filter(lambda item: item.is_after(cutoff), parsed_assessment) + cutoff_min = cutoff[0] or datetime.min + cutoff_max = cutoff[1] or datetime.max + filtered_assessment = filter( + lambda item: item.is_after(cutoff_min) and item.is_before(cutoff_max), + parsed_assessment, + ) return list(filtered_assessment) diff --git a/uqcsbot/whatsdue.py b/uqcsbot/whatsdue.py index 2bbbb43..98528c1 100644 --- a/uqcsbot/whatsdue.py +++ b/uqcsbot/whatsdue.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timedelta import logging from typing import Optional, Callable, Literal, Dict @@ -16,7 +16,6 @@ get_course_assessment, get_course_assessment_page, get_course_profile_id, - get_current_exam_period, ) AssessmentSortType = Literal["Date", "Course Name", "Weight"] @@ -30,7 +29,7 @@ def sort_by_date(item: AssessmentItem): try: return item.get_parsed_due_date()[0] except DateSyntaxException: - return get_current_exam_period()[0] + return datetime.max SORT_METHODS: Dict[ @@ -50,6 +49,7 @@ def __init__(self, bot: commands.Bot): @app_commands.describe( fulloutput="Display the full list of assessment. Defaults to False, which only " + "shows assessment due from today onwards.", + weeks_to_show="Only show assessment due within this number of weeks. If 0 (default), show all assessment.", semester="The semester to get assessment for. Defaults to what UQCSbot believes is the current semester.", campus="The campus the course is held at. Defaults to St Lucia. Note that many external courses are 'hosted' at St Lucia.", mode="The mode of the course. Defaults to Internal.", @@ -63,6 +63,7 @@ async def whatsdue( interaction: discord.Interaction, courses: str, fulloutput: bool = False, + weeks_to_show: int = 0, semester: Optional[Offering.SemesterType] = None, campus: Offering.CampusType = "St Lucia", mode: Offering.ModeType = "Internal", @@ -81,7 +82,12 @@ async def whatsdue( offering = Offering(semester=semester, campus=campus, mode=mode) # If full output is not specified, set the cutoff to today's date. - cutoff = None if fulloutput else datetime.today() + cutoff = ( + None if fulloutput else datetime.today(), + datetime.today() + timedelta(weeks=weeks_to_show) + if weeks_to_show > 0 + else None, + ) try: assessment_page = get_course_assessment_page(course_names, offering) assessment = get_course_assessment(course_names, cutoff, assessment_page) @@ -128,7 +134,9 @@ async def whatsdue( name=f"Potential ECP {'Link' if len(course_names) == 1 else 'Links'}", value=" ".join(ecp_links) + "\nNote that these may not be the correct ECPs. Check the year and offering type.", + inline=False, ) + if not fulloutput: embed.set_footer( text="Note: This may not be the full assessment list. Set fulloutput to True to see a potentially more complete list, or check your ECP for a true list of assessment."