Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/gradescopeapi/classes/_helpers/_assignment_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import dateutil.parser
import requests

from bs4 import BeautifulSoup

from gradescopeapi import DEFAULT_GRADESCOPE_BASE_URL
from gradescopeapi.classes.assignments import Assignment, Deadlines

Expand Down Expand Up @@ -32,7 +34,7 @@ def check_page_auth(session, endpoint):
return submissions_resp


def get_assignments_instructor_view(coursepage_soup):
def get_assignments_instructor_view(coursepage_soup: BeautifulSoup):
assignments_list = []
sections_dict = {}
element_with_props = coursepage_soup.find(
Expand Down Expand Up @@ -102,6 +104,7 @@ def get_assignments_instructor_view(coursepage_soup):
dateutil.parser.parse(late_due_date) if late_due_date else late_due_date
)

course_id = assignment["url"].split("/")[-3]
assignment_id = assignment["url"].split("/")[-1]

# Check if assignment has section management enabled
Expand All @@ -110,6 +113,7 @@ def get_assignments_instructor_view(coursepage_soup):
sections = sections_dict[assignment_id]

assignment_obj = Assignment(
course_id=course_id,
assignment_id=assignment_id,
name=assignment["title"],
deadlines=Deadlines(
Expand All @@ -128,7 +132,11 @@ def get_assignments_instructor_view(coursepage_soup):
return assignments_list


def get_assignments_student_view(coursepage_soup):
def get_assignments_student_view(coursepage_soup: BeautifulSoup):
# Extract course ID
course_id_header = coursepage_soup.find("div", class_="courseHeader--courseID")
course_id = course_id_header.text

# parse into list of lists: Assignments[row_elements[]]
assignment_table = []
for assignment_row in coursepage_soup.find_all("tr", role="row")[
Expand Down Expand Up @@ -196,6 +204,7 @@ def get_assignments_student_view(coursepage_soup):

# Store the extracted information in a dictionary
assignment_obj = Assignment(
course_id=course_id,
assignment_id=assignment_id,
name=name,
deadlines=Deadlines(
Expand Down
59 changes: 54 additions & 5 deletions src/gradescopeapi/classes/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def __init__(
):
self.session = session
self.gradescope_base_url = gradescope_base_url
self.courses: dict[str, dict[str, Course]] = {}
self.assignments: list[Assignment] = []
self.users: list[Member] = []

def get_courses(self) -> dict[str, dict[str, Course]]:
"""
Expand All @@ -54,6 +57,10 @@ def get_courses(self) -> dict[str, dict[str, Course]]:
RuntimeError: If request to account page fails.
"""

# check if courses were already retrieved
if self.courses != {}:
return self.courses

endpoint = f"{self.gradescope_base_url}/account"

# get main page
Expand All @@ -67,7 +74,8 @@ def get_courses(self) -> dict[str, dict[str, Course]]:
soup = BeautifulSoup(response.text, "html.parser")

# see if user is solely a student or instructor
return get_courses_info(soup)
self.courses = get_courses_info(soup)
return self.courses

def get_course_users(self, course_id: str) -> list[Member]:
"""
Expand All @@ -80,14 +88,18 @@ def get_course_users(self, course_id: str) -> list[Member]:
"You must be logged in to access this page.": if no user is logged in
"""

membership_endpoint = (
f"{self.gradescope_base_url}/courses/{course_id}/memberships"
)

# check that course_id is valid (not empty)
if not course_id:
raise Exception("Invalid Course ID")

# check if users were already retrieved
if self.users != []:
return self.users

membership_endpoint = (
f"{self.gradescope_base_url}/courses/{course_id}/memberships"
)

session = self.session

try:
Expand All @@ -98,6 +110,8 @@ def get_course_users(self, course_id: str) -> list[Member]:
# get all users in the course
users = get_course_members(membership_soup, course_id)

self.users = users

return users
except Exception:
return None
Expand All @@ -118,6 +132,10 @@ def get_assignments(self, course_id: str) -> list[Assignment]:
raise Exception("Invalid Course ID")
session = self.session

# check if assignments were already retrieved
if self.assignments != []:
return self.assignments

# scrape page
try:
# this endpoint is only available if the user is a staff of the course
Expand All @@ -137,8 +155,39 @@ def get_assignments(self, course_id: str) -> list[Assignment]:
if not assignment_info_list:
assignment_info_list = get_assignments_student_view(coursepage_soup)

self.assignments = assignment_info_list

return assignment_info_list

def get_assignment(self, course_id: str, assignment_id: str) -> Assignment:
"""
Get detailed information on a single assignment for a course
Returns:
Assignment: An Assignment object
Raises:
Exceptions:
"One or more invalid parameters": if course_id or assignment_id is null or empty value
"You are not authorized to access this page.": if logged in user is unable to access submissions
"You must be logged in to access this page.": if no user is logged in
"""
# check that course_id is valid (not empty)
if not course_id:
raise Exception("Invalid Course ID")

# check if assignments were not retrieved
if self.assignments == []:
self.get_assignments(course_id=course_id)

assignment: Assignment = next(
(
assignment
for assignment in self.assignments
if assignment.assignment_id == assignment_id
)
)

return assignment

def get_assignment_submissions(
self, course_id: str, assignment_id: str
) -> dict[str, list[str]]:
Expand Down
Loading