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
17 changes: 16 additions & 1 deletion frontend/src/components/Requirements.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,15 @@ export default function Requirements({ onChange, requirements, schedule }) {
if (requirement['count'] === 0 && requirement['min_needed'] === 0)
finished = 'req-neutral';

const isOrGroup =
'req_list' in requirement &&
requirement['min_needed'] === 1 &&
requirement['req_list'].length > 1;

let tag = '';
if (requirement['min_needed'] === 0) tag = requirement['count'];
else tag = requirement['count'] + '/' + requirement['min_needed'];
if (isOrGroup && finished !== 'req-done') tag += ' (any 1)';

let popoverContent =
'<button type="button" class="btn btn-light btn-sm btn-block searchByReq"><i class="fa fa-search"></i>Find Satisfying Courses</button>';
Expand All @@ -193,9 +199,18 @@ export default function Requirements({ onChange, requirements, schedule }) {
);

if ('req_list' in requirement) {
let childTree = requirement;
if (isOrGroup && finished === 'req-done') {
const satisfiedChildren = requirement['req_list'].filter(
(r) => r['count'] >= r['min_needed']
);
if (satisfiedChildren.length > 0) {
childTree = { ...requirement, req_list: satisfiedChildren };
}
}
return (
<TreeView key={index} nodeLabel={reqLabel} itemClassName={finished}>
{populateReqTree(requirement)}
{populateReqTree(childTree)}
</TreeView>
);
} else {
Expand Down
26 changes: 8 additions & 18 deletions tigerpath/majors_and_certificates/scripts/verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,15 @@

# Allow overriding the data repo base via env var for easy testing
# Must end with a trailing slash and point to a raw.githubusercontent.com base
REMOTE_DATA_REPO_URL = os.getenv(
"DEPT_DATA_URL",
"https://raw.githubusercontent.com/TigerAppsOrg/Princeton-Departmental-Data/old/",
)

# connect/read timeouts so requests never hang workers indefinitely
_HTTP_TIMEOUT = (3.05, 7)
import pathlib

_LOCAL_DATA_DIR = pathlib.Path(__file__).resolve().parent.parent.parent / "requirements_data"

@lru_cache(maxsize=256)
def _fetch_remote_yaml(path: str):
"""
Fetch and parse YAML from the remote requirements repository with a timeout.

Results are cached in-process to avoid repeated network requests on hot paths.
"""
resp = requests.get(REMOTE_DATA_REPO_URL + path, timeout=_HTTP_TIMEOUT)
resp.raise_for_status()
return yaml.safe_load(resp.text)
def _load_yaml(path: str):
"""Load and parse YAML from the local requirements data directory."""
filepath = _LOCAL_DATA_DIR / path
return yaml.safe_load(filepath.read_text())


MAJORS_LOCATION = "majors/" # relative path to folder containing the major requirements JSONs
Expand Down Expand Up @@ -149,7 +139,7 @@ def check_requirements(req_file, courses, year):
:returns: A simplified json with info about how much of each requirement is satisfied
:rtype: (bool, dict, dict)
"""
req = _fetch_remote_yaml(req_file)
req = _load_yaml(req_file)
courses = _init_courses(courses, req, year)
req = _init_req(req, year)
_mark_possible_reqs(req, courses)
Expand Down Expand Up @@ -205,7 +195,7 @@ def get_courses_by_path(path):
req_filepath = os.path.join(DEGREES_LOCATION, filename)
else:
raise ValueError("Path malformatted.")
req = _fetch_remote_yaml(req_filepath)
req = _load_yaml(req_filepath)
_init_year_switch(req, year)
subreq = _get_req_by_path(req, path, year)
if not subreq:
Expand Down
Loading
Loading