Merge branch 'develop' into feature/VBV-621-teilnehmer-profil
This commit is contained in:
commit
0e487cd7d0
|
|
@ -17,7 +17,7 @@ const 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": 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,
|
||||
"\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 first_name\n last_name\n }\n assignment_user {\n avatar_url\n first_name\n last_name\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,
|
||||
"\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument,
|
||||
"\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n enable_circle_documents\n circle_contact_type\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n": types.CourseSessionDetailDocument,
|
||||
"\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n enable_circle_documents\n circle_contact_type\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.CourseQueryDocument,
|
||||
|
|
@ -60,7 +60,7 @@ export function graphql(source: "\n query attendanceCheckQuery($courseSessionId
|
|||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\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"): (typeof documents)["\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"];
|
||||
export function graphql(source: "\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 first_name\n last_name\n }\n assignment_user {\n avatar_url\n first_name\n last_name\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"): (typeof documents)["\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 first_name\n last_name\n }\n assignment_user {\n avatar_url\n first_name\n last_name\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"];
|
||||
/**
|
||||
* 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
|
|
@ -66,8 +66,13 @@ export const ASSIGNMENT_COMPLETION_QUERY = graphql(`
|
|||
evaluation_submitted_at
|
||||
evaluation_user {
|
||||
id
|
||||
first_name
|
||||
last_name
|
||||
}
|
||||
assignment_user {
|
||||
avatar_url
|
||||
first_name
|
||||
last_name
|
||||
id
|
||||
}
|
||||
evaluation_points
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
||||
import EvaluationContainer from "@/pages/cockpit/assignmentEvaluationPage/EvaluationContainer.vue";
|
||||
import AssignmentSubmissionResponses from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionResponses.vue";
|
||||
import type { Assignment, AssignmentCompletion } from "@/types";
|
||||
import type { Assignment, AssignmentCompletion, CourseSessionUser } from "@/types";
|
||||
import { useQuery } from "@urql/vue";
|
||||
import log from "loglevel";
|
||||
import { computed, onMounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { getPreviousRoute } from "@/router/history";
|
||||
import { getAssignmentTypeTitle } from "../../../utils/utils";
|
||||
import { useExpertCockpitPageData } from "@/pages/cockpit/cockpitPage/composables";
|
||||
|
||||
const props = defineProps<{
|
||||
courseSlug: string;
|
||||
|
|
@ -20,7 +19,6 @@ const props = defineProps<{
|
|||
|
||||
log.debug("AssignmentEvaluationPage created", props.assignmentId, props.userId);
|
||||
|
||||
const { loading } = useExpertCockpitPageData(props.courseSlug);
|
||||
const courseSession = useCurrentCourseSession();
|
||||
const router = useRouter();
|
||||
|
||||
|
|
@ -38,9 +36,6 @@ onMounted(async () => {
|
|||
log.debug("AssignmentView mounted", props.assignmentId, props.userId);
|
||||
});
|
||||
|
||||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
const assignmentUser = computed(() => courseSessionDetailResult.findUser(props.userId));
|
||||
|
||||
const previousRoute = getPreviousRoute();
|
||||
|
||||
function close() {
|
||||
|
|
@ -58,13 +53,17 @@ const assignmentCompletion = computed(
|
|||
queryResult.data.value?.assignment_completion as AssignmentCompletion | undefined
|
||||
);
|
||||
|
||||
const assignmentUser = computed(
|
||||
() => assignmentCompletion.value?.assignment_user as CourseSessionUser | undefined
|
||||
);
|
||||
|
||||
const assignment = computed(
|
||||
() => queryResult.data.value?.assignment as Assignment | undefined
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!loading" class="absolute bottom-0 top-0 z-10 w-full bg-white">
|
||||
<div class="absolute bottom-0 top-0 z-10 w-full bg-white">
|
||||
<div v-if="queryResult.fetching.value"></div>
|
||||
<div v-else-if="queryResult.error.value">{{ queryResult.error.value }}</div>
|
||||
<div v-else>
|
||||
|
|
@ -101,12 +100,12 @@ const assignment = computed(
|
|||
|
||||
<div class="my-6 flex items-center">
|
||||
<img
|
||||
:src="assignmentUser?.avatar_url"
|
||||
:src="assignmentUser.avatar_url"
|
||||
class="mr-4 h-11 w-11 rounded-full"
|
||||
/>
|
||||
<div class="font-bold">
|
||||
{{ assignmentUser?.first_name }}
|
||||
{{ assignmentUser?.last_name }}
|
||||
{{ assignmentUser.first_name }}
|
||||
{{ assignmentUser.last_name }}
|
||||
</div>
|
||||
</div>
|
||||
<AssignmentSubmissionResponses
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
|
||||
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||
import {
|
||||
maxAssignmentPoints,
|
||||
|
|
@ -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,
|
||||
|
|
@ -110,26 +110,19 @@ const maxPoints = computed(() => maxAssignmentPoints(props.assignment));
|
|||
const userPoints = computed(() =>
|
||||
userAssignmentPoints(props.assignment, props.assignmentCompletion)
|
||||
);
|
||||
|
||||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
const evaluationUser = computed(() => {
|
||||
if (props.assignmentCompletion.evaluation_user) {
|
||||
return courseSessionDetailResult.findUser(
|
||||
props.assignmentCompletion.evaluation_user?.id
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<div>
|
||||
<h3 v-if="evaluationUser && props.showEvaluationUser" class="mb-6">
|
||||
<h3
|
||||
v-if="assignmentCompletion.evaluation_user && props.showEvaluationUser"
|
||||
class="mb-6"
|
||||
>
|
||||
{{
|
||||
$t(text.evaluationFromUser, {
|
||||
x: evaluationUser?.first_name,
|
||||
y: evaluationUser?.last_name,
|
||||
x: assignmentCompletion.evaluation_user.first_name,
|
||||
y: assignmentCompletion.evaluation_user.last_name,
|
||||
})
|
||||
}}
|
||||
</h3>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import type { Participant, PraxisAssignment } from "@/services/mentorCockpit";
|
||||
import { useMentorCockpit } from "@/services/mentorCockpit";
|
||||
import { computed, type Ref } from "vue";
|
||||
import { computed, onMounted, type Ref } from "vue";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
import log from "loglevel";
|
||||
|
||||
const props = defineProps<{
|
||||
praxisAssignmentId: string;
|
||||
|
|
@ -11,19 +12,19 @@ const props = defineProps<{
|
|||
const courseSession = useCurrentCourseSession();
|
||||
const mentorCockpitStore = useMentorCockpit(courseSession.value.id);
|
||||
|
||||
const participants = computed(() => mentorCockpitStore.summary.value?.participants);
|
||||
const praxisAssignment: Ref<PraxisAssignment | null> = computed(() =>
|
||||
mentorCockpitStore.getPraxisAssignmentById(props.praxisAssignmentId)
|
||||
);
|
||||
|
||||
const getParticipantById = (id: string): Participant | null => {
|
||||
if (mentorCockpitStore.summary.value?.participants) {
|
||||
const found = mentorCockpitStore.summary.value.participants.find(
|
||||
(item) => item.id === id
|
||||
);
|
||||
return found || null;
|
||||
}
|
||||
return null;
|
||||
return participants.value?.find((participant) => participant.id === id) || null;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
log.debug("MentorPraxisAssignment mounted");
|
||||
mentorCockpitStore.fetchData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -96,7 +97,22 @@ const getParticipantById = (id: string): Participant | null => {
|
|||
</template>
|
||||
</div>
|
||||
<!-- Right -->
|
||||
<div></div>
|
||||
<div>
|
||||
<router-link
|
||||
v-if="item.status == 'SUBMITTED'"
|
||||
class="btn-primary"
|
||||
:to="item.url"
|
||||
>
|
||||
{{ $t("a.Ergebnis bewerten") }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-else-if="item.status == 'EVALUATED'"
|
||||
class="underline"
|
||||
:to="item.url"
|
||||
>
|
||||
{{ $t("a.Bewertung ansehen") }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ import { useRouteQuery } from "@vueuse/router";
|
|||
import * as log from "loglevel";
|
||||
import { computed, onMounted, ref, watchEffect } from "vue";
|
||||
import { useTranslation } from "i18next-vue";
|
||||
import { bustItGetCache } from "@/fetchHelpers";
|
||||
import { learningContentTypeData } from "@/utils/typeMaps";
|
||||
import EvaluationSummary from "@/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue";
|
||||
import { bustItGetCache } from "@/fetchHelpers";
|
||||
|
||||
const { t } = useTranslation();
|
||||
const courseSession = useCurrentCourseSession();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { itGetCached } from "@/fetchHelpers";
|
||||
import { itGet } from "@/fetchHelpers";
|
||||
import type { Ref } from "vue";
|
||||
import { ref, watchEffect } from "vue";
|
||||
|
||||
|
|
@ -27,6 +27,7 @@ interface Completion {
|
|||
status: CompletionStatus;
|
||||
user_id: string;
|
||||
last_name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface PraxisAssignment {
|
||||
|
|
@ -73,7 +74,7 @@ export const useMentorCockpit = (
|
|||
summary.value = null;
|
||||
error.value = null;
|
||||
|
||||
itGetCached(`/api/mentor/${courseSessionId}/summary`)
|
||||
itGet(`/api/mentor/${courseSessionId}/summary`)
|
||||
.then((response) => {
|
||||
summary.value = response;
|
||||
})
|
||||
|
|
@ -93,5 +94,6 @@ export const useMentorCockpit = (
|
|||
error,
|
||||
getCircleTitleById,
|
||||
getPraxisAssignmentById,
|
||||
fetchData,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -109,7 +109,9 @@ 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):
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class Course(models.Model):
|
|||
return f"/course/{self.slug}"
|
||||
|
||||
def get_cockpit_url(self):
|
||||
return f"/{self.get_course_url()}/cockpit"
|
||||
return f"{self.get_course_url()}/cockpit"
|
||||
|
||||
def get_learning_path(self):
|
||||
from vbv_lernwelt.learnpath.models import LearningPath
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -67,21 +83,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):
|
||||
|
|
|
|||
|
|
@ -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,62 @@ 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_session_id=course_session.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_session_id=course_session.id,
|
||||
)
|
||||
|
||||
# THEN
|
||||
self.assertFalse(is_mentor)
|
||||
|
||||
def test_no_role(self):
|
||||
# GIVEN
|
||||
other_course, _ = create_course("Other Test Course")
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ def get_assignment_completions(
|
|||
)[0],
|
||||
user_id=user.id,
|
||||
last_name=user.last_name,
|
||||
url=f"/course/{course_session.course.slug}/cockpit/assignment/{assignment.id}/{user.id}",
|
||||
)
|
||||
for user in sorted_participants
|
||||
]
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class PraxisAssignmentCompletion:
|
|||
status: CompletionStatus
|
||||
user_id: str
|
||||
last_name: str
|
||||
url: str
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ class PraxisAssignmentCompletionSerializer(serializers.Serializer):
|
|||
status = serializers.SerializerMethodField()
|
||||
user_id = serializers.CharField()
|
||||
last_name = serializers.CharField()
|
||||
url = serializers.CharField()
|
||||
|
||||
@staticmethod
|
||||
def get_status(obj):
|
||||
|
|
|
|||
|
|
@ -84,6 +84,10 @@ class AttendanceServicesTestCase(TestCase):
|
|||
for i, result in enumerate(results):
|
||||
self.assertEqual(result.last_name, expected_order[i])
|
||||
self.assertEqual(result.status, expected_statuses[result.last_name])
|
||||
self.assertEqual(
|
||||
result.url,
|
||||
f"/course/test-lehrgang/cockpit/assignment/{self.assignment.id}/{result.user_id}",
|
||||
)
|
||||
|
||||
def test_praxis_assignment_status(self):
|
||||
# GIVEN
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from vbv_lernwelt.course_session.models import (
|
|||
CourseSessionAssignment,
|
||||
CourseSessionEdoniqTest,
|
||||
)
|
||||
from vbv_lernwelt.learnpath.models import Circle
|
||||
from vbv_lernwelt.notify.services import NotificationService
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
|
@ -63,9 +64,12 @@ def send_assignment_reminder_notifications():
|
|||
AssignmentType.CASEWORK.value,
|
||||
],
|
||||
):
|
||||
circle_page = assignment.learning_content.get_parent_circle()
|
||||
circle = Circle.objects.get(page_ptr=circle_page.id)
|
||||
for expert in CourseSessionUser.objects.filter(
|
||||
course_session_id=assignment.course_session.id,
|
||||
role=CourseSessionUser.Role.EXPERT,
|
||||
expert=circle,
|
||||
):
|
||||
sent.append(
|
||||
NotificationService.send_casework_expert_evaluation_reminder(
|
||||
|
|
|
|||
Loading…
Reference in New Issue