feat: praxis assigment evaluation user

This commit is contained in:
Reto Aebersold 2023-12-14 11:03:04 +01:00
parent 712d6d2868
commit 6479683ad8
14 changed files with 110 additions and 58 deletions

View File

@ -47,9 +47,6 @@ const onSubmit = async () => {
learningContentId: props.learningContentId,
completionDataString: JSON.stringify({}),
completionStatus: "SUBMITTED",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id: props.assignmentCompletion?.id,
});
bustItGetCache(
`/api/course/completion/${props.courseSessionId}/${useUserStore().id}/`

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import ItButton from "@/components/ui/ItButton.vue";
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import { computed, ref } from "vue";
import { ref } from "vue";
import { bustItGetCache, useCSRFFetch } from "@/fetchHelpers";
import { useUserStore } from "@/stores/user";
import eventBus from "@/utils/eventBus";
@ -10,12 +10,14 @@ import dayjs from "dayjs";
import { useMutation } from "@urql/vue";
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
import type { CourseSessionUserObjectsType } from "@/gql/graphql";
import type { Assignment } from "@/types";
import DateEmbedding from "@/components/dueDates/DateEmbedding.vue";
import { useCurrentCourseSession } from "@/composables";
const currentCourseSession = useCurrentCourseSession();
const props = defineProps<{
submissionDeadlineStart?: string | null;
circleExpert?: CourseSessionUserObjectsType;
courseSessionId: string;
assignment: Assignment;
learningContentId: string;
@ -27,14 +29,12 @@ const upsertAssignmentCompletionMutation = useMutation(
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
);
const circleExpertName = computed(() => {
return `${props.circleExpert?.first_name} ${props.circleExpert?.last_name}`;
});
const { data: learningMentors } = useCSRFFetch(
`/api/mentor/${props.courseSessionId}/mentors`
).json();
const selectedLearningMentor = ref();
const onSubmit = async () => {
try {
await upsertAssignmentCompletionMutation.executeMutation({
@ -43,9 +43,7 @@ const onSubmit = async () => {
learningContentId: props.learningContentId,
completionDataString: JSON.stringify({}),
completionStatus: "SUBMITTED",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id: props.assignmentCompletion?.id,
evaluationUserId: selectedLearningMentor.value,
});
bustItGetCache(
`/api/course/completion/${props.courseSessionId}/${useUserStore().id}/`
@ -62,27 +60,53 @@ const onSubmit = async () => {
<template>
<div class="w-full border-b border-gray-400">
<ItCheckbox
class="py-6"
:checkbox-item="{
label: $t('a.confirmSubmitPersonPraxisAssignment'),
value: 'value',
checked: confirmPerson,
}"
data-cy="confirm-submit-person"
@toggle="confirmPerson = !confirmPerson"
></ItCheckbox>
<div v-if="circleExpert" class="flex flex-row items-center pb-6 pl-[49px]">
<img
alt="Notification icon"
class="mr-2 h-[45px] min-w-[45px] rounded-full"
:src="circleExpert.avatar_url"
/>
<p class="text-base font-bold">
{{ circleExpertName }}
</p>
<div v-if="learningMentors?.length" class="my-6">
<ItCheckbox
class="py-6"
:checkbox-item="{
label: $t('a.confirmSubmitPersonPraxisAssignment'),
value: 'value',
checked: confirmPerson,
}"
data-cy="confirm-submit-person"
@toggle="confirmPerson = !confirmPerson"
></ItCheckbox>
<div>
<select v-model="selectedLearningMentor">
<option
:value="learningMentor.mentor.id"
v-for="learningMentor in learningMentors"
:key="learningMentor.id"
>
{{ learningMentor.mentor.first_name }} {{ learningMentor.mentor.last_name }}
</option>
</select>
</div>
</div>
<div v-else class="my-6">
<div class="flex space-x-2 bg-sky-200 p-4">
<it-icon-info class="it-icon h-6 w-6 text-sky-700" />
<div>
<div class="mb-4">
{{
$t(
"a.Aktuell hast du noch keine Person als Lernbegleitung eingeladen. Lade jetzt jemanden ein."
)
}}
</div>
<router-link
:to="{
name: 'learningMentorManagement',
params: { courseSlug: currentCourseSession.course.slug },
}"
class="btn-blue px-4 py-2 font-bold"
>
{{ $t("a.Lernbegleitung einladen") }}
</router-link>
</div>
</div>
</div>
{{ learningMentors }}
</div>
<p v-if="props.submissionDeadlineStart" class="pt-6">
{{ $t("assignment.dueDateSubmission") }}
@ -90,12 +114,12 @@ const onSubmit = async () => {
</p>
<ItButton
class="mt-6"
variant="blue"
variant="primary"
size="large"
:disabled="!confirmPerson"
:disabled="!confirmPerson || !selectedLearningMentor"
data-cy="submit-assignment"
@click="onSubmit"
>
<p>{{ $t("assignment.submitAssignment") }}</p>
<p>{{ $t("a.Ergebnisse teilen") }}</p>
</ItButton>
</template>

View File

@ -30,9 +30,6 @@ const onSubmit = async () => {
learningContentId: props.learningContentId,
completionDataString: JSON.stringify({}),
completionStatus: "SUBMITTED",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id: props.assignmentCompletion?.id,
});
bustItGetCache(
`/api/course/completion/${props.courseSessionId}/${useUserStore().id}/`

View File

@ -14,7 +14,7 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
*/
const documents = {
"\n mutation AttendanceCheckMutation(\n $attendanceCourseId: ID!\n $attendanceUserList: [AttendanceUserInputType]!\n ) {\n update_course_session_attendance_course_users(\n id: $attendanceCourseId\n attendance_user_list: $attendanceUserList\n ) {\n course_session_attendance_course {\n id\n attendance_user_list {\n user_id\n first_name\n last_name\n email\n status\n }\n }\n }\n }\n": types.AttendanceCheckMutationDocument,
"\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_points\n completion_data\n task_completion_data\n }\n }\n }\n": types.UpsertAssignmentCompletionDocument,
"\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n $evaluationUserId: ID\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n evaluation_user_id: $evaluationUserId\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_points\n completion_data\n task_completion_data\n }\n }\n }\n": types.UpsertAssignmentCompletionDocument,
"\n fragment CoursePageFields on CoursePageInterface {\n title\n id\n slug\n content_type\n frontend_url\n }\n": types.CoursePageFieldsFragmentDoc,
"\n query attendanceCheckQuery($courseSessionId: ID!) {\n course_session_attendance_course(id: $courseSessionId) {\n id\n attendance_user_list {\n user_id\n status\n }\n }\n }\n": types.AttendanceCheckQueryDocument,
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n needs_expert_evaluation\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n solution_sample {\n id\n url\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_points\n evaluation_max_points\n evaluation_passed\n edoniq_extended_time_flag\n completion_data\n task_completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
@ -48,7 +48,7 @@ export function graphql(source: "\n mutation AttendanceCheckMutation(\n $att
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_points\n completion_data\n task_completion_data\n }\n }\n }\n"): (typeof documents)["\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_points\n completion_data\n task_completion_data\n }\n }\n }\n"];
export function graphql(source: "\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n $evaluationUserId: ID\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n evaluation_user_id: $evaluationUserId\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_points\n completion_data\n task_completion_data\n }\n }\n }\n"): (typeof documents)["\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n $evaluationUserId: ID\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n evaluation_user_id: $evaluationUserId\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_points\n completion_data\n task_completion_data\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/

File diff suppressed because one or more lines are too long

View File

@ -863,7 +863,7 @@ type CompetenceCertificateListObjectType implements CoursePageInterface {
type Mutation {
send_feedback(course_session_id: ID!, data: GenericScalar, learning_content_page_id: ID!, learning_content_type: String!, submitted: Boolean = false): SendFeedbackMutation
update_course_session_attendance_course_users(attendance_user_list: [AttendanceUserInputType]!, id: ID!): AttendanceCourseUserMutation
upsert_assignment_completion(assignment_id: ID!, assignment_user_id: UUID, completion_data_string: String, completion_status: AssignmentCompletionStatus, course_session_id: ID!, evaluation_passed: Boolean, evaluation_points: Float, initialize_completion: Boolean, learning_content_page_id: ID): AssignmentCompletionMutation
upsert_assignment_completion(assignment_id: ID!, assignment_user_id: UUID, completion_data_string: String, completion_status: AssignmentCompletionStatus, course_session_id: ID!, evaluation_passed: Boolean, evaluation_points: Float, evaluation_user_id: ID, initialize_completion: Boolean, learning_content_page_id: ID): AssignmentCompletionMutation
}
type SendFeedbackMutation {
@ -903,4 +903,4 @@ enum AssignmentCompletionStatus {
SUBMITTED
EVALUATION_IN_PROGRESS
EVALUATION_SUBMITTED
}
}

View File

@ -33,6 +33,7 @@ export const UPSERT_ASSIGNMENT_COMPLETION_MUTATION = graphql(`
$completionDataString: String!
$evaluationPoints: Float
$initializeCompletion: Boolean
$evaluationUserId: ID
) {
upsert_assignment_completion(
assignment_id: $assignmentId
@ -43,6 +44,7 @@ export const UPSERT_ASSIGNMENT_COMPLETION_MUTATION = graphql(`
completion_data_string: $completionDataString
evaluation_points: $evaluationPoints
initialize_completion: $initializeCompletion
evaluation_user_id: $evaluationUserId
) {
assignment_completion {
id

View File

@ -90,7 +90,12 @@ const openSolutionSample = () => {
<template>
<div class="w-full border border-gray-400 p-8" data-cy="confirm-container">
<h3 class="heading-3 border-b border-gray-400 pb-6">
{{ $t("assignment.submitAssignment") }}
<template v-if="isPraxisAssignment">
{{ $t("a.Ergebnisse teilen") }}
</template>
<template v-else>
{{ $t("assignment.submitAssignment") }}
</template>
</h3>
<div v-if="completionStatus === 'IN_PROGRESS'">
@ -109,7 +114,6 @@ const openSolutionSample = () => {
:course-session-id="courseSessionId"
:assignment="assignment"
:learning-content-id="learningContentId"
:circle-expert="circleExpert"
:submission-deadline-start="submissionDeadlineStart"
/>

View File

@ -125,6 +125,7 @@ const router = createRouter({
path: "/course/:courseSlug/mentor",
component: () => import("@/pages/learningMentor/MentorManagementPage.vue"),
props: true,
name: "learningMentorManagement",
},
{
path: "/lernbegleitung/:courseId/invitation/:invitationId",

View File

@ -31,6 +31,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
evaluation_points = graphene.Float()
evaluation_passed = graphene.Boolean()
evaluation_user_id = graphene.ID(required=False)
initialize_completion = graphene.Boolean(required=False)
@classmethod
@ -46,6 +47,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
completion_data_string="{}",
evaluation_points=None,
evaluation_passed=None,
evaluation_user_id=None,
initialize_completion=False,
):
if assignment_user_id is None:
@ -78,13 +80,18 @@ class AssignmentCompletionMutation(graphene.Mutation):
}
if completion_status == AssignmentCompletionStatus.SUBMITTED:
# TODO: determine proper way to assign evaluation user
experts = CourseSessionUser.objects.filter(
course_session=course_session, role="EXPERT"
)
if not experts:
raise PermissionDenied()
assignment_data["evaluation_user"] = experts[0].user
if evaluation_user_id:
assignment_data["evaluation_user"] = User.objects.get(
id=evaluation_user_id
)
else:
# TODO: determine proper way to assign evaluation user
experts = CourseSessionUser.objects.filter(
course_session=course_session, role="EXPERT"
)
if not experts:
raise PermissionDenied()
assignment_data["evaluation_user"] = experts[0].user
evaluation_data = {}

View File

@ -17,12 +17,16 @@ from vbv_lernwelt.learning_mentor.entities import (
def get_assignment_completions(
course_session: CourseSession, assignment: Assignment, participants: List[User]
course_session: CourseSession,
assignment: Assignment,
participants: List[User],
evaluation_user: User,
) -> List[PraxisAssignmentCompletion]:
evaluation_results = AssignmentCompletion.objects.filter(
assignment_user__in=participants,
course_session=course_session,
assignment=assignment,
evaluation_user=evaluation_user,
).values("completion_status", "assignment_user__last_name", "assignment_user")
user_status_map = {}
@ -73,7 +77,7 @@ def get_assignment_completions(
def get_praxis_assignments(
course_session: CourseSession, participants: List[User]
course_session: CourseSession, participants: List[User], evaluation_user: User
) -> Tuple[List[PraxisAssignmentStatus], Set[int]]:
records = []
circle_ids = set()
@ -93,6 +97,7 @@ def get_praxis_assignments(
course_session=course_session,
assignment=learning_content.content_assignment,
participants=participants,
evaluation_user=evaluation_user,
)
submitted_count = len(

View File

@ -23,6 +23,7 @@ from vbv_lernwelt.learning_mentor.entities import CompletionStatus
class AttendanceServicesTestCase(TestCase):
def setUp(self):
self.mentor = create_user("Mentor")
self.user1 = create_user("Alpha")
self.user2 = create_user("Beta")
self.user3 = create_user("Kappa")
@ -41,18 +42,21 @@ class AttendanceServicesTestCase(TestCase):
course_session=self.course_session,
assignment=self.assignment,
completion_status=AssignmentCompletionStatus.EVALUATION_SUBMITTED.value,
evaluation_user=self.mentor,
)
AssignmentCompletion.objects.create(
assignment_user=self.user2,
course_session=self.course_session,
assignment=self.assignment,
completion_status=AssignmentCompletionStatus.SUBMITTED.value,
evaluation_user=self.mentor,
)
AssignmentCompletion.objects.create(
assignment_user=self.user3,
course_session=self.course_session,
assignment=self.assignment,
completion_status=AssignmentCompletionStatus.IN_PROGRESS.value,
evaluation_user=self.mentor,
)
def test_assignment_completions(self):
@ -61,7 +65,10 @@ class AttendanceServicesTestCase(TestCase):
# WHEN
results = get_assignment_completions(
self.course_session, self.assignment, participants
course_session=self.course_session,
assignment=self.assignment,
participants=participants,
evaluation_user=self.mentor,
)
# THEN
@ -88,7 +95,9 @@ class AttendanceServicesTestCase(TestCase):
# WHEN
assignments, circle_ids = get_praxis_assignments(
self.course_session, participants
course_session=self.course_session,
participants=participants,
evaluation_user=self.mentor,
)
# THEN

View File

@ -125,6 +125,7 @@ class LearningMentorAPITest(APITestCase):
course_session=self.course_session,
assignment=self.assignment,
completion_status=AssignmentCompletionStatus.EVALUATION_SUBMITTED.value,
evaluation_user=self.mentor,
)
AssignmentCompletion.objects.create(
@ -132,6 +133,7 @@ class LearningMentorAPITest(APITestCase):
course_session=self.course_session,
assignment=self.assignment,
completion_status=AssignmentCompletionStatus.SUBMITTED.value,
evaluation_user=self.mentor,
)
# WHEN

View File

@ -34,7 +34,9 @@ def mentor_summary(request, course_session_id: int):
participants = mentor.participants.filter(course_session=course_session)
users = [p.user for p in participants]
praxis_assignments, circle_ids = get_praxis_assignments(course_session, users)
praxis_assignments, circle_ids = get_praxis_assignments(
course_session=course_session, participants=users, evaluation_user=request.user
)
circles = Circle.objects.filter(id__in=circle_ids).values("id", "title")