From 0821a3a9e7303eeb1adfa7d75271f4530d117082 Mon Sep 17 00:00:00 2001 From: frostyfan109 Date: Mon, 26 Aug 2024 13:43:31 -0400 Subject: [PATCH 1/2] Add student notebook upload --- eduhelx_jupyterlab_student/handlers.py | 15 +++++++----- eduhelx_jupyterlab_student/student_repo.py | 28 +++++++++++++++++++--- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/eduhelx_jupyterlab_student/handlers.py b/eduhelx_jupyterlab_student/handlers.py index c53075e..db22162 100644 --- a/eduhelx_jupyterlab_student/handlers.py +++ b/eduhelx_jupyterlab_student/handlers.py @@ -247,20 +247,22 @@ async def post(self): })) return - current_assignment_path = student_repo.get_assignment_path(student_repo.current_assignment) + student_notebook_path = student_repo.current_assignment_path / student_repo.current_assignment["student_notebook_path"] + with open(student_notebook_path, "r") as f: + student_notebook_content = f.read() rollback_id = get_head_commit_id(path=student_repo.repo_root) - stage_files(".", path=current_assignment_path) + stage_files(".", path=student_repo.current_assignment_path) try: commit_id = commit( submission_summary, submission_description if submission_description else None, - path=current_assignment_path + path=student_repo.current_assignment_path ) except Exception as e: # If the commit fails then unstage the assignment files. - git_reset(".", path=current_assignment_path) + git_reset(".", path=student_repo.current_assignment_path) self.set_status(500) self.finish(str(e)) return @@ -268,7 +270,8 @@ async def post(self): try: await self.api.create_submission( student_repo.current_assignment["id"], - commit_id + commit_id, + student_notebook_content ) except Exception as e: # If the submission fails create in the API, rollback the local commit to the previous head. @@ -281,7 +284,7 @@ async def post(self): # so that we don't push the stages changes without actually creating a submission for the user # (which would be very misleading) try: - push(StudentClassRepo.ORIGIN_REMOTE_NAME, StudentClassRepo.MAIN_BRANCH_NAME, path=current_assignment_path) + push(StudentClassRepo.ORIGIN_REMOTE_NAME, StudentClassRepo.MAIN_BRANCH_NAME, path=student_repo.current_assignment_path) self.finish() except Exception as e: # Need to rollback the commit if push failed too. diff --git a/eduhelx_jupyterlab_student/student_repo.py b/eduhelx_jupyterlab_student/student_repo.py index 0f46dcf..c0140c0 100644 --- a/eduhelx_jupyterlab_student/student_repo.py +++ b/eduhelx_jupyterlab_student/student_repo.py @@ -6,6 +6,9 @@ class NotStudentClassRepositoryException(Exception): pass +class NotInAnAssignmentException(Exception): + pass + """ Note: this class is naive to the fixed repo path. It is designed for relative interaction with class repository filepaths WHILE inside the repository. """ @@ -28,9 +31,14 @@ def __init__(self, course, assignments, current_path): self.repo_root = self._compute_repo_root(self.course["name"], self.current_path) self.current_assignment = self._compute_current_assignment(self.assignments, self.repo_root, self.current_path) + + @property + def current_assignment_path(self) -> Path | None: + if self.current_assignment is None: return None + return self.get_assignment_path(self.current_assignment) def get_assignment_path(self, assignment): - return os.path.join(self.repo_root, assignment["directory_path"]) + return self.repo_root / assignment["directory_path"] def get_protected_file_paths(self, assignment) -> list[Path]: files = [] @@ -38,8 +46,6 @@ def get_protected_file_paths(self, assignment) -> list[Path]: files += self.get_assignment_path(assignment).glob(glob_pattern) return files - - @classmethod def _compute_repo_root(cls, course_name, current_path: str | None = None): """ Validates that user is in the repository root if current_path is provided """ @@ -65,3 +71,19 @@ def _compute_current_assignment(assignments, repo_root, current_path): break return current_assignment + + @classmethod + def from_assignment_no_path(cls, course, assignments, assignment_id: int): + try: + assignment = [a for a in assignments if a["id"] == assignment_id][0] + except IndexError: + raise NotInAnAssignmentException + + repo_root = cls._compute_repo_root(course["name"]).resolve() + assignment_path = repo_root / assignment["directory_path"] + + return cls( + course=course, + assignments=assignments, + current_path=assignment_path + ) \ No newline at end of file From a052dec087bdd7bc8ce9c013a5a659b0b02b8abf Mon Sep 17 00:00:00 2001 From: frostyfan109 Date: Tue, 27 Aug 2024 12:19:06 -0400 Subject: [PATCH 2/2] sort assn alphanum if due date tied --- .../assignments-list/assignments-list.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/assignment-panel/assignments-list/assignments-list.tsx b/src/components/assignment-panel/assignments-list/assignments-list.tsx index b61de66..778b10e 100644 --- a/src/components/assignment-panel/assignments-list/assignments-list.tsx +++ b/src/components/assignment-panel/assignments-list/assignments-list.tsx @@ -127,9 +127,14 @@ const AssignmentsBucket = ({ }: AssignmentsBucketProps) => { const [expanded, setExpanded] = useState(defaultExpanded) - const assignmentsSource = useMemo(() => ( - assignments?.sort((a, b) => (a.adjustedDueDate?.getTime() ?? 0) - (b.adjustedDueDate?.getTime() ?? 0)) - ), [assignments]) + const assignmentsSource = useMemo(() => assignments?.sort((a, b) => { + const aDue = a.adjustedDueDate?.getTime() ?? Infinity + const bDue = b.adjustedDueDate?.getTime() ?? Infinity + // Sort by date, or name if same date. + if (aDue > bDue) return 1 + if (aDue < bDue) return -1 + return a.name.localeCompare(b.name, undefined, { numeric: true }) + }), [assignments]) const isEmpty = useMemo(() => !assignmentsSource || assignmentsSource.length === 0, [assignmentsSource])