diff --git a/uqcsbot/__main__.py b/uqcsbot/__main__.py index 93e7591..ee84876 100644 --- a/uqcsbot/__main__.py +++ b/uqcsbot/__main__.py @@ -43,6 +43,7 @@ async def main(): "basic", "cat", "cowsay", + "course_ecp", "dominos_coupons", "error_handler", "events", diff --git a/uqcsbot/course_ecp.py b/uqcsbot/course_ecp.py new file mode 100644 index 0000000..e00643b --- /dev/null +++ b/uqcsbot/course_ecp.py @@ -0,0 +1,110 @@ +from typing import Optional +import logging +from datetime import datetime +import discord +from discord import app_commands +from discord.ext import commands + +from uqcsbot.utils.uq_course_utils import ( + Offering, + HttpException, + CourseNotFoundException, + ProfileNotFoundException, + get_course_profile_url, +) +from uqcsbot.yelling import yelling_exemptor + + +class CourseECP(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + @app_commands.command() + @app_commands.describe( + course1="The course to find an ECP for.", + course2="The second course to find an ECP for.", + course3="The third course to find an ECP for.", + course4="The fourth course to find an ECP for.", + year="The year to find the course ECP for. Defaults to what UQCSbot believes is the current year.", + semester="The semester to find the course ECP for. Defaults to what UQCSbot believes is the current semester.", + campus="The campus the course is held at. Defaults to St Lucia. Defaults to St Lucia. Note that many external courses are 'hosted' at St Lucia.", + mode="The mode of the course. Defaults to Internal.", + ) + @yelling_exemptor(input_args=["course1, course2, course3, course4"]) + async def courseecp( + self, + interaction: discord.Interaction, + course1: str, + course2: Optional[str], + course3: Optional[str], + course4: Optional[str], + year: Optional[int] = None, + semester: Optional[Offering.SemesterType] = None, + campus: Offering.CampusType = "St Lucia", + mode: Offering.ModeType = "Internal", + ): + """ + Returns the URL of the ECPs for course codes given. Assumes the same semester and year for the course codes given. + + """ + await interaction.response.defer(thinking=True) + + possible_courses = [course1, course2, course3, course4] + course_names = [c.upper() for c in possible_courses if c != None] + course_name_urls: dict[str, str] = {} + offering = Offering(semester=semester, campus=campus, mode=mode) + + try: + for course in course_names: + course_name_urls.update( + {course: get_course_profile_url(course, offering, year)} + ) + except HttpException as exception: + logging.warning( + f"Received a HTTP response code {exception.status_code} when trying find the course url using get_course_profile_url in course_ecp.py . Error information: {exception.message}" + ) + await interaction.edit_original_response( + content=f"Could not contact UQ, please try again." + ) + return + except (CourseNotFoundException, ProfileNotFoundException) as exception: + await interaction.edit_original_response(content=exception.message) + return + + # If year is none assign it the current year + if not year: + year = datetime.today().year + + # If semester is none assign it the current estimated semester + if not semester: + semester = Offering.estimate_current_semester() + + # Create the embedded message with the course names and details + embed = discord.Embed( + title=f"Course ECP: {', '.join(course_names)}", + description=f"For Semester {semester} {year}, {mode}, {campus}", + ) + + # Add the ECP urls to the embedded message + if course_name_urls: + for course in course_name_urls: + embed.add_field( + name=f"", + value=f"[{course}]({course_name_urls.get(course)}) ", + inline=False, + ) + else: + await interaction.edit_original_response( + content=f"No ECP could be found for the courses: {course_names}. The ECP(s) might not be available." + ) + return + + embed.set_footer( + text="The course ECP might be out of date, be sure to check the course on BlackBoard." + ) + await interaction.edit_original_response(embed=embed) + return + + +async def setup(bot: commands.Bot): + await bot.add_cog(CourseECP(bot)) diff --git a/uqcsbot/utils/uq_course_utils.py b/uqcsbot/utils/uq_course_utils.py index 9343222..f879d79 100644 --- a/uqcsbot/utils/uq_course_utils.py +++ b/uqcsbot/utils/uq_course_utils.py @@ -14,8 +14,10 @@ "student_section_report.php?report=assessment&profileIds=" ) BASE_CALENDAR_URL = "http://www.uq.edu.au/events/calendar_view.php?category_id=16&year=" -OFFERING_PARAMETER = "offer" BASE_PAST_EXAMS_URL = "https://api.library.uq.edu.au/v1/exams/search/" +# Parameters for the course page +OFFERING_PARAMETER = "offer" +YEAR_PARAMETER = "year" class Offering: @@ -59,7 +61,7 @@ def __init__( if semester is not None: self.semester = semester else: - self.semester = self._estimate_current_semester() + self.semester = self.estimate_current_semester() self.semester self.campus = campus self.mode = mode @@ -93,7 +95,7 @@ def get_offering_code(self) -> str: return offering_code_text.encode("utf-8").hex() @staticmethod - def _estimate_current_semester() -> SemesterType: + def estimate_current_semester() -> SemesterType: """ Returns an estimate of the current semester (represented by an integer) based on the current month. 3 represents summer semester. """ @@ -256,23 +258,19 @@ def get_uq_request( def get_course_profile_url( - course_name: str, offering: Optional[Offering] = None + course_name: str, + offering: Optional[Offering] = None, + year: Optional[int] = None, ) -> str: """ - Returns the URL to the course profile for the given course for a given offering. - If no offering is give, will return the first course profile on the course page. + Returns the URL to the course profile (ECP) for the given course for a given offering. + If no offering or year are given, the first course profile on the course page will be returned. """ - if offering is None: - course_url = BASE_COURSE_URL + course_name - else: - course_url = ( - BASE_COURSE_URL - + course_name - + "&" - + OFFERING_PARAMETER - + "=" - + offering.get_offering_code() - ) + course_url = BASE_COURSE_URL + course_name + if offering: + course_url += "&" + OFFERING_PARAMETER + "=" + offering.get_offering_code() + if year: + course_url += "&" + YEAR_PARAMETER + "=" + str(year) http_response = get_uq_request(course_url) if http_response.status_code != requests.codes.ok: