Skip to content

Commit

Permalink
feat(api): convert last few routes to use token instead of old models (
Browse files Browse the repository at this point in the history
…#1195)

* fix: change eslint rules so frontend can compile with unused variables

* wip: created mirrored prepareUserPayload backend helper and converted

* fix: tokenified the  route

* fix: coursesUnlockedWhenTaken and getAllUnlocked tests now use tokens

* remove prepareUserPayload from frontend

* feat: created  function, and finally removed old UserData model

* fix: unselect tests now use token

* added note into unselectCourse route

* fix: aligned mark mappings to the WAM spec

* wip: move out convert_to_planner_data

* feat: removed  model and reworked  route

* fix: convert ctf to fully use user Storage

* feat: convert /validateTermPlanner to no longer use old models

* fix: update frontend mark parsing to match backend

* fix: re-enable circular imports pylint and remove type keyword

* fix: remove potentially bad load_dotenv

* fix: remove unused props for CourseDescriptionPanel and CourseMenu after tokenifying last routes
  • Loading branch information
ollibowers authored Sep 12, 2024
1 parent 0305c75 commit 72801cf
Show file tree
Hide file tree
Showing 25 changed files with 597 additions and 458 deletions.
2 changes: 0 additions & 2 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ disable=import-error, # allow import from folder.file instea
missing-module-docstring, # allow for missing module docstrings, democratially ignored
missing-function-docstring, # TODO: be much more selective with these, and docstring most functions
missing-class-docstring, #
import-outside-toplevel, # allow non-top level imports. used to prevent circular dependencies
cyclic-import, # TODO: remove these when utility refactor + old user storage dicts removal
# parameter-unpacking,
# unpacking-in-except,
# old-raise-syntax,
Expand Down
21 changes: 14 additions & 7 deletions backend/algorithms/objects/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import json
import re
from itertools import chain
from typing import List, Literal, Optional, Tuple
from typing import List, Literal, Optional, Tuple, TypedDict

from algorithms.cache.cache_config import CACHED_EQUIVALENTS_FILE, CACHED_EXCLUSIONS_FILE
from algorithms.objects.categories import AnyCategory, Category
Expand All @@ -20,6 +20,13 @@
with open(CACHED_EXCLUSIONS_FILE, "r", encoding="utf8") as f:
CACHED_EXCLUSIONS: dict[str, dict[str, Literal[1]]] = json.load(f)

class UserJSON(TypedDict, total=False):
courses: dict[str, tuple[int, Optional[int]]]
program: Optional[str]
specialisations: list[str]
year: int
core_courses: list[str]

class User:
""" A user and their data which will be used to determine if they can take a course """
# pylint: disable=too-many-public-methods
Expand Down Expand Up @@ -119,18 +126,18 @@ def in_specialisation(self, specialisation: str):
for spec in self.specialisations
)

def load_json(self, data):
def load_json(self, data: UserJSON):
""" Given the user data, correctly loads it into this user class """

if "program" in data.keys():
if "program" in data:
self.program = copy.deepcopy(data["program"])
if "specialisations" in data.keys():
if "specialisations" in data:
self.specialisations = copy.deepcopy(data["specialisations"])
if "courses" in data.keys():
if "courses" in data:
self.courses = copy.deepcopy(data["courses"])
if "year" in data.keys():
if "year" in data:
self.year = copy.deepcopy(data["year"])
if "core_courses" in data.keys():
if "core_courses" in data:
self.core_courses = copy.deepcopy(data["core_courses"])

def get_grade(self, course: str):
Expand Down
12 changes: 6 additions & 6 deletions backend/algorithms/tests/test_autoplanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from algorithms.autoplanning import autoplan, terms_between
from algorithms.objects.course import Course
from algorithms.objects.user import User
from algorithms.validate_term_planner import validate_terms
from algorithms.validate_term_planner import RawUserPlan, validate_terms
from pytest import raises
from server.routers.model import CONDITIONS, ValidPlannerData
from server.routers.model import CONDITIONS


def get_uoc(course_name: str, courses: list[Course]):
Expand Down Expand Up @@ -132,11 +132,11 @@ def assert_autoplanning_guarantees(uoc_max: list[int], courses: list[Course], pr
course_names = [course[0] for course in res if terms_between((2020, 0), course[1]) == index]
assert number >= sum(get_uoc(course_name, courses) for course_name in course_names)
# all courses valid
plan: list[list[dict[str, tuple[int, Optional[int]]]]] = [[{}, {}, {}, {}] for _ in range(2023-2020)]
plan: RawUserPlan = [[{}, {}, {}, {}] for _ in range(2023-2020)]
for course_name, (course_year, course_term) in res:
plan[course_year - 2020][course_term][course_name] = (get_uoc(course_name, courses), get_mark(course_name, courses))
assert all(course_state['is_accurate'] for course_state in validate_terms(ValidPlannerData(
assert all(course_state.is_accurate for course_state in validate_terms(
programCode="3778",
specialisations=["COMPA1"],
specs=["COMPA1"],
plan=plan
)).values())
).values())
29 changes: 17 additions & 12 deletions backend/algorithms/validate_term_planner.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
from typing import Optional
from algorithms.objects.user import User
from server.routers.model import CACHED_HANDBOOK_NOTE, CONDITIONS, ValidPlannerData
from server.routers.model import CACHED_HANDBOOK_NOTE, CONDITIONS, CourseState


def validate_terms(data: ValidPlannerData):
RawUserPlan = list[list[dict[str, tuple[int, Optional[int]]]]]

def validate_terms(programCode: str, specs: list[str], plan: RawUserPlan) -> dict[str, CourseState]:
"""Validates the term planner, returning all warnings."""
emptyUserData = {
"program": data.programCode,
"specialisations": data.specialisations,
"program": programCode,
"specialisations": specs[:],
"courses": {}, # Start off the user with an empty year
}
user = User(emptyUserData)
# State of courses on the term planner
coursesState = {}
coursesState: dict[str, CourseState] = {}

for year in data.plan:
for year in plan:
# Go through all the years
for term in year:
user.add_current_courses(term)
Expand All @@ -24,12 +28,13 @@ def validate_terms(data: ValidPlannerData):
if is_answer_accurate
else (True, [])
)
coursesState[course] = {
"is_accurate": is_answer_accurate,
"handbook_note": CACHED_HANDBOOK_NOTE.get(course, ""),
"unlocked": unlocked,
"warnings": warnings
}
coursesState[course] = CourseState(
is_accurate=is_answer_accurate,
handbook_note=CACHED_HANDBOOK_NOTE.get(course, ""),
unlocked=unlocked,
warnings=warnings
)

# Add all these courses to the user in preparation for the next term
user.empty_current_courses()
user.add_courses(term)
Expand Down
136 changes: 136 additions & 0 deletions backend/server/example_input/example_local_storage_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,5 +185,141 @@
"isSummerEnabled": false,
"lockedTerms": {}
}
},
"sample_user_1": {
"degree": {
"programCode": "3778",
"specs": [
"COMPA1",
"ACCTA2"
]
},
"planner": {
"years": [ {
"T0": [],
"T1": ["COMP1511"],
"T2": ["COMP1521"],
"T3": []
},
{
"T0": [],
"T1": [],
"T2": [],
"T3": []
},
{
"T0": [],
"T1": [],
"T2": [],
"T3": []
}
],
"unplanned": [],
"startYear": 2020,
"isSummerEnabled": false,
"lockedTerms": {}
}
},
"sample_user_2": {
"degree": {
"programCode": "3789",
"specs": [
"COMPJ1",
"FOODH1"
]
},
"planner": {
"years": [ {
"T0": [],
"T1": ["COMP1511"],
"T2": ["COMP1521", "COMP1531"],
"T3": ["COMP2521"]
},
{
"T0": [],
"T1": ["COMP3231"],
"T2": ["COMP9242"],
"T3": []
},
{
"T0": [],
"T1": [],
"T2": [],
"T3": []
}
],
"unplanned": [],
"startYear": 2020,
"isSummerEnabled": false,
"lockedTerms": {}
}
},
"sample_user_one_math": {
"degree": {
"programCode": "3707",
"specs": [
"COMPA1",
"ACCTA2"
]
},
"planner": {
"years": [ {
"T0": [],
"T1": ["MATH1131"],
"T2": [],
"T3": []
},
{
"T0": [],
"T1": [],
"T2": [],
"T3": []
},
{
"T0": [],
"T1": [],
"T2": [],
"T3": []
}
],
"unplanned": [],
"startYear": 2020,
"isSummerEnabled": false,
"lockedTerms": {}
}
},
"sample_user_no_courses": {
"degree": {
"programCode": "3707",
"specs": [
"COMPA1",
"ACCTA2"
]
},
"planner": {
"years": [ {
"T0": [],
"T1": [],
"T2": [],
"T3": []
},
{
"T0": [],
"T1": [],
"T2": [],
"T3": []
},
{
"T0": [],
"T1": [],
"T2": [],
"T3": []
}
],
"unplanned": [],
"startYear": 2020,
"isSummerEnabled": false,
"lockedTerms": {}
}
}
}
Loading

0 comments on commit 72801cf

Please sign in to comment.