Done for today. Time to write some issues so I can remember where to start from tomorrow.

This commit is contained in:
Boyan 2024-02-13 20:05:42 +01:00
parent 99e356d96a
commit f0979d34e7
7 changed files with 50 additions and 36 deletions

View File

@ -5,10 +5,11 @@ from Base import Base
from Exercise import Exercise from Exercise import Exercise
from requests import Session from requests import Session
class Assignment(Base): class Assignment(Base):
def __init__(self, url:str, name:str, session:Session, parent): def __init__(self, url:str, name:str, session:Session, parent):
super().__init__() super().__init__(url, name, session, parent)
self.download = Downloadable(url, name, session, self) self.download = Downloadable(name, session, self)
def __str__(self): def __str__(self):
return f"Assignment {self.name} in course {self.parent.name}" return f"Assignment {self.name} in course {self.parent.name}"

View File

@ -33,6 +33,28 @@ class Base:
return submission return submission
# TODO: Fix
def getDownloadable(self, soup) -> list:
# Make sure we only get the ones that have a link
# We parse the cfg and check for the key "Downloads"
# Check if downloads are available
print(soup)
cfg = soup.find('div', class_='cfg-container round')
print(cfg)
cfg = self.__parseCfgBlock(cfg)
# Get the downloads
downloads = cfg.get("Downloads", None)
if downloads == None:
return []
# Get the links
links = downloads.find_all('a')
files = []
for link in links:
files.append(Base(link['href'], link.text, self.session, self))
return files
def getSubmissions(self): def getSubmissions(self):
# We change the url where course becomes stats # We change the url where course becomes stats
url = self.url.replace("course", "stats") url = self.url.replace("course", "stats")

View File

@ -6,6 +6,12 @@ import re
from Base import Base from Base import Base
from exceptions.CourseUnavailable import CourseUnavailable from exceptions.CourseUnavailable import CourseUnavailable
# PROBLEM: This implementation is bad due to inconsistencies in the website
# The way we can tell the difference between an assignment and an exercise is by the presence of an a with the class "ass-submitable"
# As opposed to folders which contain exercises which are marked with "ass-group"
# Therefore, we should take that into consideration and spawn the corresponding Exercise or Assignment class
# Naming becomes a bit inconsistent like that as well, as Assignments could be Exercises. Might opt to call the "assignments" "exerciseGroups" or some shit.
class Course(Base): class Course(Base):
# Extend the Base class init # Extend the Base class init
def __init__(self, url:str, name:str, session:Session, parent): def __init__(self, url:str, name:str, session:Session, parent):
@ -18,6 +24,7 @@ class Course(Base):
def __courseAvailable(self, r): def __courseAvailable(self, r):
# Check if we got an error # Check if we got an error
print(self.url)
if "Something went wrong" in r.text: if "Something went wrong" in r.text:
raise CourseUnavailable() raise CourseUnavailable()
@ -45,7 +52,7 @@ class Course(Base):
# Search by name # Search by name
assignment = soup.find('a', text=name) assignment = soup.find('a', text=name)
# Get the url and transform it into an assignment object # Get the url and transform it into an assignment object
return Assignment(url=assignment['href'], name=name, session=self.session, course=self) return Assignment(url=assignment['href'], name=name, session=self.session, parent=self)
def getAssignments(self) -> list[Assignment]: def getAssignments(self) -> list[Assignment]:
@ -53,13 +60,13 @@ class Course(Base):
r = self.session.get(self.url) r = self.session.get(self.url)
soup = BeautifulSoup(r.text, 'lxml') soup = BeautifulSoup(r.text, 'lxml')
# Find the big ul # Find the big ul
print(soup) # print(soup)
section = soup.find('div', class_="ass-children") section = soup.find('div', class_="ass-children")
ul = section.find('ul', class_='round') ul = section.find('ul', class_='round')
# IDEA: They sometimes put other stuff in these li's, so we have to filter them out # IDEA: They sometimes put other stuff in these li's, so we have to filter them out
print(ul) # print(ul)
print(type(ul)) # print(type(ul))
# Transform them into Assignment objects # Transform them into Assignment objects
# I want to call the __liLargeToAssignments method from the Base class # I want to call the __liLargeToAssignments method from the Base class
return self.liLargeToAssignments(ul) return self.liLargeToAssignments(ul)

View File

@ -5,7 +5,8 @@ from bs4 import BeautifulSoup
from Base import Base from Base import Base
class Downloadable(Base): class Downloadable(Base):
def __init__(self, session:Session, parent): def __init__(self, name, session:Session, parent):
self.name = name
self.session = session self.session = session
self.parent = parent self.parent = parent
@ -21,23 +22,9 @@ class Downloadable(Base):
def files(self) -> list: def files(self) -> list:
# Create a list of files # Create a list of files
# They are all links in a span with class "cfg-val" # They are all links in a span with class "cfg-val"
r = self.session.get(self.url) r = self.session.get("https://themis.housing.rug.nl" + self.parent.url)
soup = BeautifulSoup(r.text, 'lxml') soup = BeautifulSoup(r.text, 'lxml')
# Make sure we only get the ones that have a link return self.getDownloadable(soup)
# We parse the cfg and check for the key "Downloads"
cfg = soup.find('div', class_='cfg-container round')
cfg = self.__parseCfgBlock(cfg)
# Get the downloads
downloads = cfg.get("Downloads", None)
if downloads == None:
return []
# Get the links
links = downloads.find_all('a')
files = []
for link in links:
files.append(File(link['href'], link.text, self.session, self))
return files
def download(self, filename:str) -> str: def download(self, filename:str) -> str:
# Download the file # Download the file

View File

@ -13,6 +13,8 @@ class Exercise(Base):
def __str__(self): def __str__(self):
return f"Exercise {self.name} in assignment {self.parent.name}" return f"Exercise {self.name} in assignment {self.parent.name}"
# IDEA: Implement test case downloading
# IDEA : Make this async, so we don't have to wait for the whole output to load # IDEA : Make this async, so we don't have to wait for the whole output to load
def submit(self, file:str, comment:str) -> str: def submit(self, file:str, comment:str) -> str:
# Submit a file # Submit a file

View File

@ -59,12 +59,4 @@ class Themis:
year = li.a.text.split("-") year = li.a.text.split("-")
years.append(Year(self.session, self, int(year[0]), int(year[1]))) years.append(Year(self.session, self, int(year[0]), int(year[1])))
return years # Return a list of year objects return years # Return a list of year objects
# This is the main file, so we have to run the main function
def main():
themis = Themis()
year = themis.getYear(2019, 2020)
print(year.getCourses())

View File

@ -5,6 +5,7 @@ from Course import Course
from requests import Session from requests import Session
from exceptions.CourseUnavailable import CourseUnavailable from exceptions.CourseUnavailable import CourseUnavailable
# Works
class Year: class Year:
def __init__(self, session:Session, parent, start_year:int, end_year:int): def __init__(self, session:Session, parent, start_year:int, end_year:int):
self.start = start_year self.start = start_year
@ -25,9 +26,10 @@ class Year:
courses = [] courses = []
for li in lis: for li in lis:
try: try:
suffix = (li.a['href'].replace(f"course/{self.start}-{self.year}", ""))
courses.append( courses.append(
Course( Course(
self.url + li.a['href'], self.url + suffix,
li.a.text, li.a.text,
self.session, self.session,
self self
@ -37,7 +39,8 @@ class Year:
if errors: if errors:
raise CourseUnavailable(f"Course {li.a.text} in year {self.start}-{self.year} is not available") raise CourseUnavailable(f"Course {li.a.text} in year {self.start}-{self.year} is not available")
else: else:
pass print("error with course", li.a.text)
continue
return courses return courses
@ -47,6 +50,6 @@ class Year:
r = self.session.get(self.url) r = self.session.get(self.url)
soup = BeautifulSoup(r.text, 'lxml') soup = BeautifulSoup(r.text, 'lxml')
# Search by name # Search by name
course = soup.find('a', text=name) course = self.url + soup.find('a', text=name)['href'].replace(f"course/{self.start}-{self.year}", "")
# Get the url and transform it into a course object # Get the url and transform it into a course object
return Course(url=course['href'], name=name, session=self.session, year=self) return Course(url=course, name=name, session=self.session, parent=self)