diff --git a/eduhelx_jupyterlab_student/handlers.py b/eduhelx_jupyterlab_student/handlers.py index ecb6312..b223ec7 100644 --- a/eduhelx_jupyterlab_student/handlers.py +++ b/eduhelx_jupyterlab_student/handlers.py @@ -247,30 +247,26 @@ async def post(self): })) return - current_assignment_path = student_repo.get_assignment_path(student_repo.current_assignment) - student_notebook_path = current_assignment_path / student_repo.current_assignment["student_notebook_path"] - + student_notebook_path = student_repo.current_assignment_path / student_repo.current_assignment["student_notebook_path"] if not student_notebook_path.exists(): self.set_status(400) self.finish(json.dumps({ - "message": "Student notebook file does not exist" + "message": "Student notebook does not exist" })) - return - student_notebook_content = student_notebook_path.read_text() - + student_notebook_content = student_notebook_path.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 @@ -278,8 +274,8 @@ async def post(self): try: await self.api.create_submission( student_repo.current_assignment["id"], - commit_id=commit_id, - student_notebook_content=student_notebook_content + 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. @@ -292,7 +288,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 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])