diff --git a/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationIntro.vue b/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationIntro.vue index 6d293307..931fb4ba 100644 --- a/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationIntro.vue +++ b/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationIntro.vue @@ -58,7 +58,7 @@ async function startEvaluation() { upsertAssignmentCompletionMutation.executeMutation({ assignmentId: props.assignment.id, courseSessionId: courseSession.value.id, - assignmentUserId: props.assignmentUser.user_id, + assignmentUserId: props.assignmentUser.id, completionStatus: "EVALUATION_IN_PROGRESS", completionDataString: JSON.stringify({}), // next line used for urql diff --git a/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue b/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue index 9f29e01a..6e7a905e 100644 --- a/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue +++ b/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue @@ -75,7 +75,7 @@ async function submitEvaluation() { upsertAssignmentCompletionMutation.executeMutation({ assignmentId: props.assignment.id, courseSessionId: courseSession.value.id, - assignmentUserId: props.assignmentUser.user_id, + assignmentUserId: props.assignmentUser.id, completionStatus: "EVALUATION_SUBMITTED", completionDataString: JSON.stringify({}), evaluationPoints: userPoints.value, diff --git a/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationTask.vue b/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationTask.vue index 1ccb03e0..e6750d3b 100644 --- a/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationTask.vue +++ b/client/src/pages/cockpit/assignmentEvaluationPage/EvaluationTask.vue @@ -91,7 +91,7 @@ async function evaluateAssignmentCompletion(completionData: AssignmentCompletion upsertAssignmentCompletionMutation.executeMutation({ assignmentId: props.assignment.id, courseSessionId: courseSession.value.id, - assignmentUserId: props.assignmentUser.user_id, + assignmentUserId: props.assignmentUser.id, completionStatus: "EVALUATION_IN_PROGRESS", completionDataString: JSON.stringify(completionData), // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/server/vbv_lernwelt/assignment/graphql/mutations.py b/server/vbv_lernwelt/assignment/graphql/mutations.py index 1e6b2ac2..7071876d 100644 --- a/server/vbv_lernwelt/assignment/graphql/mutations.py +++ b/server/vbv_lernwelt/assignment/graphql/mutations.py @@ -99,7 +99,11 @@ class AssignmentCompletionMutation(graphene.Mutation): AssignmentCompletionStatus.EVALUATION_SUBMITTED, AssignmentCompletionStatus.EVALUATION_IN_PROGRESS, ): - if not can_evaluate_assignments(info.context.user, course_session_id): + if not can_evaluate_assignments( + evaluation_user=info.context.user, + assignment_user_id=assignment_user_id, + course_session_id=course_session_id, + ): raise PermissionDenied() evaluation_data = { diff --git a/server/vbv_lernwelt/assignment/graphql/types.py b/server/vbv_lernwelt/assignment/graphql/types.py index 70efc5b6..a0dfdb8a 100644 --- a/server/vbv_lernwelt/assignment/graphql/types.py +++ b/server/vbv_lernwelt/assignment/graphql/types.py @@ -109,7 +109,7 @@ def resolve_assignment_completion( assignment_user_id = info.context.user.id if str(assignment_user_id) == str(info.context.user.id) or can_evaluate_assignments( - info.context.user, course_session_id + evaluation_user=info.context.user, assignment_user_id=assignment_user_id, course_session_id=course_session_id ): course_id = CourseSession.objects.get(id=course_session_id).course_id if has_course_access(info.context.user, course_id): diff --git a/server/vbv_lernwelt/iam/permissions.py b/server/vbv_lernwelt/iam/permissions.py index e0b0fd92..01164834 100644 --- a/server/vbv_lernwelt/iam/permissions.py +++ b/server/vbv_lernwelt/iam/permissions.py @@ -18,6 +18,9 @@ def has_course_access(user, course_id): ).exists(): return True + if LearningMentor.objects.filter(course_id=course_id, mentor=user).exists(): + return True + return CourseSessionUser.objects.filter( course_session__course_id=course_id, user=user ).exists() @@ -32,6 +35,19 @@ def has_course_session_access(user, course_session_id: int): ).exists() +def is_user_mentor(mentor: User, participant_user_id: str, course_session_id: int): + csu = CourseSessionUser.objects.filter( + course_session_id=course_session_id, user_id=participant_user_id + ).first() + + if csu is None: + return False + + return LearningMentor.objects.filter( + course_id=csu.course_session.course_id, mentor=mentor, participants=csu + ).exists() + + def is_course_session_expert(user, course_session_id: int): if user.is_superuser: return True @@ -60,21 +76,29 @@ def is_course_session_member(user, course_session_id: int | None = None): ).exists() -def can_evaluate_assignments(user, course_session_id: int): - if user.is_superuser: +def can_evaluate_assignments( + evaluation_user: User, course_session_id: int, assignment_user_id: str | None = None +): + if evaluation_user.is_superuser: return True is_supervisor = CourseSessionGroup.objects.filter( - supervisor=user, course_session__id=course_session_id + supervisor=evaluation_user, course_session__id=course_session_id ).exists() is_expert = CourseSessionUser.objects.filter( course_session_id=course_session_id, - user=user, + user=evaluation_user, role=CourseSessionUser.Role.EXPERT, ).exists() - return is_supervisor or is_expert + is_mentor = is_user_mentor( + mentor=evaluation_user, + participant_user_id=assignment_user_id, + course_session_id=course_session_id, + ) + + return is_supervisor or is_expert or is_mentor def course_sessions_for_user_qs(user): diff --git a/server/vbv_lernwelt/iam/tests/test_roles.py b/server/vbv_lernwelt/iam/tests/test_roles.py index 2cb221c6..6f77888e 100644 --- a/server/vbv_lernwelt/iam/tests/test_roles.py +++ b/server/vbv_lernwelt/iam/tests/test_roles.py @@ -8,7 +8,7 @@ from vbv_lernwelt.course.creators.test_utils import ( ) from vbv_lernwelt.course.models import CourseSessionUser from vbv_lernwelt.course_session_group.models import CourseSessionGroup -from vbv_lernwelt.iam.permissions import has_role_in_course +from vbv_lernwelt.iam.permissions import has_role_in_course, is_user_mentor from vbv_lernwelt.learning_mentor.models import LearningMentor @@ -59,6 +59,58 @@ class RoleTestCase(TestCase): # THEN self.assertTrue(has_role) + def test_is_user_mentor(self): + # GIVEN + member = create_user("member") + mentor = create_user("mentor") + + course, course_page = create_course("Test Course") + course_session = create_course_session(course=course, title=":)") + + member_csu = add_course_session_user( + course_session=course_session, + user=member, + role=CourseSessionUser.Role.MEMBER, + ) + + learning_mentor = LearningMentor.objects.create( + mentor=mentor, + course=course, + ) + + learning_mentor.participants.add(member_csu) + learning_mentor.save() + + # WHEN + is_mentor = is_user_mentor( + mentor=mentor, participant_user_id=member.id, course_id=course.id + ) + + # THEN + self.assertTrue(is_mentor) + + def test_not_is_user_mentor(self): + # GIVEN + member = create_user("member") + wanna_be_mentor = create_user("wanna_be_mentor") + + course, course_page = create_course("Test Course") + course_session = create_course_session(course=course, title=":)") + + add_course_session_user( + course_session=course_session, + user=member, + role=CourseSessionUser.Role.MEMBER, + ) + + # WHEN + is_mentor = is_user_mentor( + mentor=wanna_be_mentor, participant_user_id=member.id, course_id=course.id + ) + + # THEN + self.assertFalse(is_mentor) + def test_no_role(self): # GIVEN other_course, _ = create_course("Other Test Course")