WIP: Add Praxisbildner switch, move code to type
This commit is contained in:
parent
6edb5be093
commit
2f77bf7734
|
|
@ -0,0 +1,41 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, ref, Ref } from "vue";
|
||||||
|
import { ProgressDashboardAssignmentType } from "@/gql/graphql";
|
||||||
|
import { fetchProgressData } from "@/services/dashboard";
|
||||||
|
import AssignmentProgressSummaryBox from "@/components/dashboard/AssignmentProgressSummaryBox.vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
courseId: string;
|
||||||
|
courseSlug: string;
|
||||||
|
sessionToContinueId: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const DEFAULT_ASSIGNMENT = {
|
||||||
|
points_achieved_count: 0,
|
||||||
|
points_max_count: 0,
|
||||||
|
total_count: 0,
|
||||||
|
};
|
||||||
|
const assignment: Ref<ProgressDashboardAssignmentType> = ref(DEFAULT_ASSIGNMENT);
|
||||||
|
|
||||||
|
const competenceCertificateUrl = computed(() => {
|
||||||
|
return `/course/${props.courseSlug}/competence/certificates?courseSessionId=${props.sessionToContinueId}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const data = await fetchProgressData(props.courseId);
|
||||||
|
assignment.value = data?.assignment;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="assignment" class="mb-14 space-y-8">
|
||||||
|
<div class="flex flex-col space-y-7 bg-white p-6">
|
||||||
|
<AssignmentProgressSummaryBox
|
||||||
|
:total-assignments="assignment.total_count"
|
||||||
|
:achieved-points-count="assignment.points_achieved_count"
|
||||||
|
:max-points-count="assignment.points_max_count"
|
||||||
|
:details-link="competenceCertificateUrl"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -18,8 +18,8 @@ const competenceCriteriaUrl = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const some = await fetchProgressData(props.courseId);
|
const data = await fetchProgressData(props.courseId);
|
||||||
competence.value = some.competence;
|
competence.value = data.competence;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,18 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import type { CourseProgressType } from "@/gql/graphql";
|
import type { CourseProgressType, WidgetType } from "@/gql/graphql";
|
||||||
import { DashboardConfigType } from "@/gql/graphql";
|
import { DashboardConfigType } from "@/gql/graphql";
|
||||||
import { fetchCourseData } from "@/services/dashboard";
|
import { fetchCourseData } from "@/services/dashboard";
|
||||||
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
||||||
import CompetenceSummary from "@/components/dashboard/CompetenceSummary.vue";
|
import CompetenceSummary from "@/components/dashboard/CompetenceSummary.vue";
|
||||||
|
import AssignmentSummary from "@/components/dashboard/AssignmentSummary.vue";
|
||||||
|
|
||||||
|
const mentorWidgets = [
|
||||||
|
"MENTOR_TASKS_WIDGET",
|
||||||
|
"MENTOR_PERSON_WIDGET",
|
||||||
|
"MENTOR_COMPETENCE_WIDGET",
|
||||||
|
];
|
||||||
|
const progressWidgets = ["COMPETENCE_WIDGET", "COMPETENCE_CERTIFICATE_WIDGET"];
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseConfig: DashboardConfigType;
|
courseConfig: DashboardConfigType;
|
||||||
|
|
@ -16,6 +24,17 @@ const data = ref<CourseProgressType | null>(null);
|
||||||
|
|
||||||
const courseSlug = computed(() => props.courseConfig?.slug);
|
const courseSlug = computed(() => props.courseConfig?.slug);
|
||||||
const courseName = computed(() => props.courseConfig?.name);
|
const courseName = computed(() => props.courseConfig?.name);
|
||||||
|
const numberOfMentorWidgets = computed(() => {
|
||||||
|
return data.value?.widgets.filter((widget) => mentorWidgets.includes(widget)).length;
|
||||||
|
});
|
||||||
|
const numberOfProgressWidgets = computed(() => {
|
||||||
|
return data.value?.widgets.filter((widget) => progressWidgets.includes(widget))
|
||||||
|
.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
function hasWidget(widget: WidgetType) {
|
||||||
|
return data.value?.widgets.includes(widget);
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
data.value = await fetchCourseData(props.courseConfig.id);
|
data.value = await fetchCourseData(props.courseConfig.id);
|
||||||
|
|
@ -27,23 +46,31 @@ onMounted(async () => {
|
||||||
<div v-if="!isLoading && courseConfig" class="mb-14 space-y-8">
|
<div v-if="!isLoading && courseConfig" class="mb-14 space-y-8">
|
||||||
<div class="flex flex-col space-y-7 bg-white p-6">
|
<div class="flex flex-col space-y-7 bg-white p-6">
|
||||||
<h3>{{ courseName }}</h3>
|
<h3>{{ courseName }}</h3>
|
||||||
<div v-for="widget in data.widgets" :key="widget.id">
|
<LearningPathDiagram
|
||||||
{{ widget }}
|
v-if="hasWidget('PROGRESS_WIDGET') && data.session_to_continue_id && courseSlug"
|
||||||
<LearningPathDiagram
|
:key="courseSlug"
|
||||||
v-if="
|
:course-slug="courseSlug"
|
||||||
widget === 'PROGRESS_WIDGET' && data.session_to_continue_id && courseSlug
|
:course-session-id="data.session_to_continue_id"
|
||||||
"
|
diagram-type="horizontal"
|
||||||
:key="courseSlug"
|
></LearningPathDiagram>
|
||||||
:course-slug="courseSlug"
|
<div v-if="numberOfProgressWidgets" class="flex flex-col flex-wrap">
|
||||||
:course-session-id="data.session_to_continue_id"
|
|
||||||
diagram-type="horizontal"
|
|
||||||
></LearningPathDiagram>
|
|
||||||
<CompetenceSummary
|
<CompetenceSummary
|
||||||
v-else-if="widget === 'COMPETENCE_WIDGET'"
|
v-if="hasWidget('COMPETENCE_WIDGET')"
|
||||||
:course-slug="courseSlug"
|
:course-slug="courseSlug"
|
||||||
:session-to-continue-id="data.session_to_continue_id"
|
:session-to-continue-id="data.session_to_continue_id"
|
||||||
:course-id="courseConfig.id"
|
:course-id="courseConfig.id"
|
||||||
></CompetenceSummary>
|
></CompetenceSummary>
|
||||||
|
<AssignmentSummary
|
||||||
|
v-if="hasWidget('COMPETENCE_CERTIFICATE_WIDGET')"
|
||||||
|
:course-slug="courseSlug"
|
||||||
|
:session-to-continue-id="data.session_to_continue_id"
|
||||||
|
:course-id="courseConfig.id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="numberOfMentorWidgets > 0" class="flex flex-col flex-wrap">
|
||||||
|
<div v-if="hasWidget('MENTOR_TASKS_WIDGET')">MENTOR_TASKS_WIDGET</div>
|
||||||
|
<div v-if="hasWidget('MENTOR_PERSON_WIDGET')">MENTOR_PERSON_WIDGET</div>
|
||||||
|
<div v-if="hasWidget('MENTOR_COMPETENCE_WIDGET')">MENTOR_COMPETENCE_WIDGET</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -466,6 +466,7 @@ export type DashboardConfigType = {
|
||||||
|
|
||||||
export type DashboardType =
|
export type DashboardType =
|
||||||
| 'MENTOR_DASHBOARD'
|
| 'MENTOR_DASHBOARD'
|
||||||
|
| 'PRAXISBILDNER_DASHBOARD'
|
||||||
| 'PROGRESS_DASHBOARD'
|
| 'PROGRESS_DASHBOARD'
|
||||||
| 'SIMPLE_DASHBOARD'
|
| 'SIMPLE_DASHBOARD'
|
||||||
| 'STATISTICS_DASHBOARD';
|
| 'STATISTICS_DASHBOARD';
|
||||||
|
|
@ -908,7 +909,6 @@ export type Query = {
|
||||||
course_session_attendance_course?: Maybe<CourseSessionAttendanceCourseObjectType>;
|
course_session_attendance_course?: Maybe<CourseSessionAttendanceCourseObjectType>;
|
||||||
course_statistics?: Maybe<CourseStatisticsType>;
|
course_statistics?: Maybe<CourseStatisticsType>;
|
||||||
dashboard_config: Array<DashboardConfigType>;
|
dashboard_config: Array<DashboardConfigType>;
|
||||||
dashboard_data?: Maybe<DashboardConfigType>;
|
|
||||||
learning_content_assignment?: Maybe<LearningContentAssignmentObjectType>;
|
learning_content_assignment?: Maybe<LearningContentAssignmentObjectType>;
|
||||||
learning_content_attendance_course?: Maybe<LearningContentAttendanceCourseObjectType>;
|
learning_content_attendance_course?: Maybe<LearningContentAttendanceCourseObjectType>;
|
||||||
learning_content_document_list?: Maybe<LearningContentDocumentListObjectType>;
|
learning_content_document_list?: Maybe<LearningContentDocumentListObjectType>;
|
||||||
|
|
@ -980,11 +980,6 @@ export type QueryCourseStatisticsArgs = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export type QueryDashboardDataArgs = {
|
|
||||||
course_id: Scalars['ID']['input'];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export type QueryLearningPathArgs = {
|
export type QueryLearningPathArgs = {
|
||||||
course_id?: InputMaybe<Scalars['ID']['input']>;
|
course_id?: InputMaybe<Scalars['ID']['input']>;
|
||||||
course_slug?: InputMaybe<Scalars['String']['input']>;
|
course_slug?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
|
@ -1056,7 +1051,8 @@ export type UserObjectType = {
|
||||||
export type WidgetType =
|
export type WidgetType =
|
||||||
| 'COMPETENCE_CERTIFICATE_WIDGET'
|
| 'COMPETENCE_CERTIFICATE_WIDGET'
|
||||||
| 'COMPETENCE_WIDGET'
|
| 'COMPETENCE_WIDGET'
|
||||||
| 'MENTEE_WIDGET'
|
| 'MENTOR_COMPETENCE_WIDGET'
|
||||||
|
| 'MENTOR_PERSON_WIDGET'
|
||||||
| 'MENTOR_TASKS_WIDGET'
|
| 'MENTOR_TASKS_WIDGET'
|
||||||
| 'PROGRESS_WIDGET';
|
| 'PROGRESS_WIDGET';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ type Query {
|
||||||
course_statistics(course_id: ID!): CourseStatisticsType
|
course_statistics(course_id: ID!): CourseStatisticsType
|
||||||
course_progress(course_id: ID!): CourseProgressType
|
course_progress(course_id: ID!): CourseProgressType
|
||||||
dashboard_config: [DashboardConfigType!]!
|
dashboard_config: [DashboardConfigType!]!
|
||||||
dashboard_data(course_id: ID!): DashboardConfigType
|
|
||||||
learning_path(id: ID, slug: String, course_id: ID, course_slug: String): LearningPathObjectType
|
learning_path(id: ID, slug: String, course_id: ID, course_slug: String): LearningPathObjectType
|
||||||
course_session_attendance_course(id: ID!, assignment_user_id: ID): CourseSessionAttendanceCourseObjectType
|
course_session_attendance_course(id: ID!, assignment_user_id: ID): CourseSessionAttendanceCourseObjectType
|
||||||
course(id: ID, slug: String): CourseObjectType
|
course(id: ID, slug: String): CourseObjectType
|
||||||
|
|
@ -200,8 +199,9 @@ type ProgressDashboardAssignmentType {
|
||||||
enum WidgetType {
|
enum WidgetType {
|
||||||
PROGRESS_WIDGET
|
PROGRESS_WIDGET
|
||||||
COMPETENCE_WIDGET
|
COMPETENCE_WIDGET
|
||||||
MENTEE_WIDGET
|
|
||||||
MENTOR_TASKS_WIDGET
|
MENTOR_TASKS_WIDGET
|
||||||
|
MENTOR_PERSON_WIDGET
|
||||||
|
MENTOR_COMPETENCE_WIDGET
|
||||||
COMPETENCE_CERTIFICATE_WIDGET
|
COMPETENCE_CERTIFICATE_WIDGET
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,6 +218,7 @@ enum DashboardType {
|
||||||
PROGRESS_DASHBOARD
|
PROGRESS_DASHBOARD
|
||||||
SIMPLE_DASHBOARD
|
SIMPLE_DASHBOARD
|
||||||
MENTOR_DASHBOARD
|
MENTOR_DASHBOARD
|
||||||
|
PRAXISBILDNER_DASHBOARD
|
||||||
}
|
}
|
||||||
|
|
||||||
type CourseConfigurationObjectType {
|
type CourseConfigurationObjectType {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ const boards: Record<DashboardType, DashboardPage> = {
|
||||||
SIMPLE_DASHBOARD: { main: SimpleCoursePage, aside: SimpleDates },
|
SIMPLE_DASHBOARD: { main: SimpleCoursePage, aside: SimpleDates },
|
||||||
STATISTICS_DASHBOARD: { main: StatisticPage, aside: CourseDetailDates },
|
STATISTICS_DASHBOARD: { main: StatisticPage, aside: CourseDetailDates },
|
||||||
MENTOR_DASHBOARD: { main: MentorPage, aside: SimpleDates },
|
MENTOR_DASHBOARD: { main: MentorPage, aside: SimpleDates },
|
||||||
|
PRAXISBILDNER_DASHBOARD: { main: CoursePanel, aside: SimpleDates },
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(dashboardStore.loadDashboardDetails);
|
onMounted(dashboardStore.loadDashboardDetails);
|
||||||
|
|
@ -57,8 +58,17 @@ onMounted(dashboardStore.loadDashboardDetails);
|
||||||
<CoursePanel :course-config="config" />
|
<CoursePanel :course-config="config" />
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<!-- keep until we unify the dashboard -->
|
||||||
|
<CoursePanel
|
||||||
|
v-if="
|
||||||
|
dashboardStore.currentDashboardConfig.dashboard_type ===
|
||||||
|
'PRAXISBILDNER_DASHBOARD'
|
||||||
|
"
|
||||||
|
course-config="dashboardStore.currentDashboardConfig"
|
||||||
|
/>
|
||||||
<component
|
<component
|
||||||
:is="boards[dashboardStore.currentDashboardConfig.dashboard_type].main"
|
:is="boards[dashboardStore.currentDashboardConfig.dashboard_type].main"
|
||||||
|
v-else
|
||||||
></component>
|
></component>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ from vbv_lernwelt.dashboard.graphql.types.dashboard import (
|
||||||
CourseStatisticsType,
|
CourseStatisticsType,
|
||||||
DashboardConfigType,
|
DashboardConfigType,
|
||||||
DashboardType,
|
DashboardType,
|
||||||
|
get_widgets_for_course,
|
||||||
ProgressDashboardAssignmentType,
|
ProgressDashboardAssignmentType,
|
||||||
ProgressDashboardCompetenceType,
|
ProgressDashboardCompetenceType,
|
||||||
WidgetType,
|
|
||||||
)
|
)
|
||||||
from vbv_lernwelt.iam.permissions import (
|
from vbv_lernwelt.iam.permissions import (
|
||||||
can_view_course_session,
|
can_view_course_session,
|
||||||
|
|
@ -40,10 +40,6 @@ class DashboardQuery(graphene.ObjectType):
|
||||||
graphene.NonNull(DashboardConfigType), required=True
|
graphene.NonNull(DashboardConfigType), required=True
|
||||||
)
|
)
|
||||||
|
|
||||||
dashboard_data = graphene.Field(
|
|
||||||
DashboardConfigType, course_id=graphene.ID(required=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
def resolve_course_statistics(root, info, course_id: str): # noqa
|
def resolve_course_statistics(root, info, course_id: str): # noqa
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
course = Course.objects.get(id=course_id)
|
course = Course.objects.get(id=course_id)
|
||||||
|
|
@ -114,6 +110,8 @@ class DashboardQuery(graphene.ObjectType):
|
||||||
|
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
course = Course.objects.get(id=course_id)
|
course = Course.objects.get(id=course_id)
|
||||||
|
setattr(info.context, "course", course)
|
||||||
|
return CourseProgressType()
|
||||||
|
|
||||||
newest: CourseSession | None = None
|
newest: CourseSession | None = None
|
||||||
course_session_for_user: List[str] = []
|
course_session_for_user: List[str] = []
|
||||||
|
|
@ -169,12 +167,9 @@ class DashboardQuery(graphene.ObjectType):
|
||||||
points_max_count=int(points_max_count), # noqa
|
points_max_count=int(points_max_count), # noqa
|
||||||
points_achieved_count=int(points_achieved_count), # noqa
|
points_achieved_count=int(points_achieved_count), # noqa
|
||||||
),
|
),
|
||||||
widgets=get_widget_for_course(course_id, user), # noqa
|
widgets=get_widgets_for_course(course, user), # noqa
|
||||||
)
|
)
|
||||||
|
|
||||||
def resolve_dashboard_data(root, info, course_id: str):
|
|
||||||
return get_widget_for_course(course_id, info.context.user)
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_statistics_dashboards(user: User) -> Tuple[List[Dict[str, str]], Set[int]]:
|
def get_user_statistics_dashboards(user: User) -> Tuple[List[Dict[str, str]], Set[int]]:
|
||||||
course_ids = set()
|
course_ids = set()
|
||||||
|
|
@ -272,42 +267,3 @@ def get_user_course_session_dashboards(
|
||||||
)
|
)
|
||||||
|
|
||||||
return dashboards, course_ids
|
return dashboards, course_ids
|
||||||
|
|
||||||
|
|
||||||
def get_widget_for_course(course_id: str, user: User) -> List[WidgetType]:
|
|
||||||
widgets = []
|
|
||||||
|
|
||||||
course_sessions = CourseSession.objects.filter(course__id=course_id).prefetch_related(
|
|
||||||
"course",
|
|
||||||
"course__configuration",
|
|
||||||
)
|
|
||||||
roles_by_course: Dict[Course, Set[DashboardType]] = {}
|
|
||||||
|
|
||||||
learning_mentors = LearningMentor.objects.filter(mentor=user).values_list(
|
|
||||||
"course_session__course__id", "id"
|
|
||||||
)
|
|
||||||
mentor_course_ids = set([mentor[0] for mentor in learning_mentors])
|
|
||||||
|
|
||||||
# duplicate code
|
|
||||||
for course_session in course_sessions:
|
|
||||||
if can_view_course_session(user=user, course_session=course_session):
|
|
||||||
role = CourseSessionUser.objects.get(
|
|
||||||
course_session=course_session, user=user
|
|
||||||
).role
|
|
||||||
roles_by_course.setdefault(course_session.course, set())
|
|
||||||
roles_by_course[course_session.course].add(role)
|
|
||||||
|
|
||||||
for course, roles in roles_by_course.items():
|
|
||||||
if len(roles) == 1:
|
|
||||||
course_role = roles.pop()
|
|
||||||
|
|
||||||
# test widgets
|
|
||||||
if course_role == CourseSessionUser.Role.MEMBER:
|
|
||||||
widgets.append(WidgetType.PROGRESS_WIDGET)
|
|
||||||
widgets.append(WidgetType.COMPETENCE_WIDGET)
|
|
||||||
if course.configuration.enable_competence_certificates:
|
|
||||||
widgets.append(WidgetType.COMPETENCE_CERTIFICATE_WIDGET)
|
|
||||||
if course.id in mentor_course_ids:
|
|
||||||
widgets.append(WidgetType.MENTOR_TASKS_WIDGET)
|
|
||||||
# add KN if has KN
|
|
||||||
return widgets
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,15 @@
|
||||||
|
from typing import Dict, List, Set, Tuple
|
||||||
|
|
||||||
import graphene
|
import graphene
|
||||||
from graphene import Enum
|
from graphene import Enum
|
||||||
|
|
||||||
|
from vbv_lernwelt.assignment.models import (
|
||||||
|
AssignmentCompletion,
|
||||||
|
AssignmentCompletionStatus,
|
||||||
|
)
|
||||||
|
from vbv_lernwelt.core.models import User
|
||||||
from vbv_lernwelt.course.graphql.types import CourseConfigurationObjectType
|
from vbv_lernwelt.course.graphql.types import CourseConfigurationObjectType
|
||||||
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
|
from vbv_lernwelt.course.models import Course, CourseSession, CourseSessionUser
|
||||||
from vbv_lernwelt.dashboard.graphql.types.assignment import (
|
from vbv_lernwelt.dashboard.graphql.types.assignment import (
|
||||||
assignments,
|
assignments,
|
||||||
AssignmentsStatisticsType,
|
AssignmentsStatisticsType,
|
||||||
|
|
@ -20,6 +27,11 @@ from vbv_lernwelt.dashboard.graphql.types.feedback import (
|
||||||
feedback_responses,
|
feedback_responses,
|
||||||
FeedbackStatisticsResponsesType,
|
FeedbackStatisticsResponsesType,
|
||||||
)
|
)
|
||||||
|
from vbv_lernwelt.iam.permissions import (
|
||||||
|
can_view_course_session,
|
||||||
|
can_view_course_session_progress,
|
||||||
|
)
|
||||||
|
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||||
from vbv_lernwelt.learnpath.models import Circle
|
from vbv_lernwelt.learnpath.models import Circle
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -54,13 +66,15 @@ class DashboardType(Enum):
|
||||||
PROGRESS_DASHBOARD = "ProgressDashboard"
|
PROGRESS_DASHBOARD = "ProgressDashboard"
|
||||||
SIMPLE_DASHBOARD = "SimpleDashboard"
|
SIMPLE_DASHBOARD = "SimpleDashboard"
|
||||||
MENTOR_DASHBOARD = "MentorDashboard"
|
MENTOR_DASHBOARD = "MentorDashboard"
|
||||||
|
PRAXISBILDNER_DASHBOARD = "PraxisbildnerDashboard"
|
||||||
|
|
||||||
|
|
||||||
class WidgetType(Enum):
|
class WidgetType(Enum):
|
||||||
PROGRESS_WIDGET = "ProgressWidget"
|
PROGRESS_WIDGET = "ProgressWidget"
|
||||||
COMPETENCE_WIDGET = "CompetenceWidget"
|
COMPETENCE_WIDGET = "CompetenceWidget"
|
||||||
MENTEE_WIDGET = "MenteeWidget"
|
|
||||||
MENTOR_TASKS_WIDGET = "MentorTasksWidget"
|
MENTOR_TASKS_WIDGET = "MentorTasksWidget"
|
||||||
|
MENTOR_PERSON_WIDGET = "MentorPersonWidget"
|
||||||
|
MENTOR_COMPETENCE_WIDGET = "MentorCompetenceWidget"
|
||||||
COMPETENCE_CERTIFICATE_WIDGET = "CompetenceCertificateWidget"
|
COMPETENCE_CERTIFICATE_WIDGET = "CompetenceCertificateWidget"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -99,6 +113,86 @@ class CourseProgressType(graphene.ObjectType):
|
||||||
assignment = graphene.Field(ProgressDashboardAssignmentType, required=False)
|
assignment = graphene.Field(ProgressDashboardAssignmentType, required=False)
|
||||||
widgets = graphene.List(graphene.NonNull(WidgetType), required=True)
|
widgets = graphene.List(graphene.NonNull(WidgetType), required=True)
|
||||||
|
|
||||||
|
def resolve__id(root, info):
|
||||||
|
return info.context.course.id
|
||||||
|
|
||||||
|
def resolve_course_id(root, info):
|
||||||
|
return info.context.course.id
|
||||||
|
|
||||||
|
def resolve_session_to_continue_id(root, info):
|
||||||
|
newest, _course_session_for_user = root._get_newest_cs_and_cs_for_user(
|
||||||
|
info, info.context.course.id, info.context.user
|
||||||
|
)
|
||||||
|
return newest.id if newest else None
|
||||||
|
|
||||||
|
def resolve_assignment(root, info):
|
||||||
|
evaluation_results = AssignmentCompletion.objects.filter(
|
||||||
|
completion_status=AssignmentCompletionStatus.EVALUATION_SUBMITTED.value,
|
||||||
|
assignment_user=info.context.user,
|
||||||
|
course_session__course=info.context.course,
|
||||||
|
).values("evaluation_max_points", "evaluation_points")
|
||||||
|
|
||||||
|
evaluation_results = list(evaluation_results)
|
||||||
|
points_max_count = sum(
|
||||||
|
[result.get("evaluation_max_points", 0) for result in evaluation_results]
|
||||||
|
)
|
||||||
|
points_achieved_count = sum(
|
||||||
|
[result.get("evaluation_points", 0) for result in evaluation_results]
|
||||||
|
)
|
||||||
|
return ProgressDashboardAssignmentType( # noqa
|
||||||
|
_id=info.context.course.id, # noqa
|
||||||
|
total_count=len(evaluation_results), # noqa
|
||||||
|
points_max_count=int(points_max_count), # noqa
|
||||||
|
points_achieved_count=int(points_achieved_count), # noqa
|
||||||
|
)
|
||||||
|
|
||||||
|
def resolve_competence(root, info):
|
||||||
|
newest, course_session_for_user = root._get_newest_cs_and_cs_for_user(
|
||||||
|
info, info.context.course.id, info.context.user
|
||||||
|
)
|
||||||
|
_, success_total, fail_total = competences(
|
||||||
|
course_slug=str(info.context.course.slug),
|
||||||
|
course_session_selection_ids=course_session_for_user,
|
||||||
|
user_selection_ids=[str(info.context.user.id)],
|
||||||
|
)
|
||||||
|
|
||||||
|
return ProgressDashboardCompetenceType( # noqa
|
||||||
|
_id=info.context.course.id, # noqa
|
||||||
|
total_count=success_total + fail_total, # noqa
|
||||||
|
success_count=success_total, # noqa
|
||||||
|
fail_count=fail_total, # noqa
|
||||||
|
)
|
||||||
|
|
||||||
|
def resolve_widgets(root, info):
|
||||||
|
return get_widgets_for_course(info.context.course, info.context.user)
|
||||||
|
|
||||||
|
def _get_newest_cs_and_cs_for_user(
|
||||||
|
root, info, course_id: str, user: User
|
||||||
|
) -> Tuple[CourseSession, List[str]]:
|
||||||
|
newest: CourseSession | None = getattr(info.context, "newest", None)
|
||||||
|
course_session_for_user: List[str] = getattr(
|
||||||
|
info.context, "course_session_for_user", []
|
||||||
|
)
|
||||||
|
|
||||||
|
if newest is not None and course_session_for_user:
|
||||||
|
return newest, course_session_for_user
|
||||||
|
|
||||||
|
for course_session in CourseSession.objects.filter(course_id=course_id):
|
||||||
|
if can_view_course_session_progress(
|
||||||
|
user=user, course_session=course_session
|
||||||
|
):
|
||||||
|
course_session_for_user.append(course_session)
|
||||||
|
generation_newest = newest.generation if newest else None
|
||||||
|
if (
|
||||||
|
generation_newest is None
|
||||||
|
or course_session.generation > generation_newest
|
||||||
|
):
|
||||||
|
newest = course_session
|
||||||
|
# cache for use in other resolvers
|
||||||
|
setattr(info.context, "newest", newest)
|
||||||
|
setattr(info.context, "course_session_for_user", course_session_for_user)
|
||||||
|
return newest, course_session_for_user
|
||||||
|
|
||||||
|
|
||||||
class CourseStatisticsType(graphene.ObjectType):
|
class CourseStatisticsType(graphene.ObjectType):
|
||||||
_id = graphene.ID(required=True)
|
_id = graphene.ID(required=True)
|
||||||
|
|
@ -224,3 +318,48 @@ class CourseStatisticsType(graphene.ObjectType):
|
||||||
generations=list(generations), # noqa
|
generations=list(generations), # noqa
|
||||||
circles=circle_data, # noqa
|
circles=circle_data, # noqa
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_widgets_for_course(course: Course, user: User) -> List[WidgetType]:
|
||||||
|
widgets = []
|
||||||
|
|
||||||
|
course_sessions = CourseSession.objects.filter(
|
||||||
|
course__id=course.id, coursesessionuser__user=user
|
||||||
|
).prefetch_related(
|
||||||
|
"course",
|
||||||
|
"course__configuration",
|
||||||
|
)
|
||||||
|
|
||||||
|
roles_by_course: Dict[Course, Set[DashboardType]] = {}
|
||||||
|
|
||||||
|
learning_mentors = LearningMentor.objects.filter(
|
||||||
|
mentor=user, course_session__course__id=course.id
|
||||||
|
).values_list("course_session__course__id", "id")
|
||||||
|
mentor_course_ids = set([mentor[0] for mentor in learning_mentors])
|
||||||
|
|
||||||
|
# duplicate code
|
||||||
|
for course_session in course_sessions:
|
||||||
|
if can_view_course_session(user=user, course_session=course_session):
|
||||||
|
role = CourseSessionUser.objects.get(
|
||||||
|
course_session=course_session, user=user
|
||||||
|
).role
|
||||||
|
roles_by_course.setdefault(course_session.course, set())
|
||||||
|
roles_by_course[course_session.course].add(role)
|
||||||
|
|
||||||
|
for course, roles in roles_by_course.items():
|
||||||
|
if len(roles) == 1:
|
||||||
|
course_role = roles.pop()
|
||||||
|
|
||||||
|
# members
|
||||||
|
if course_role == CourseSessionUser.Role.MEMBER:
|
||||||
|
widgets.append(WidgetType.PROGRESS_WIDGET)
|
||||||
|
widgets.append(WidgetType.COMPETENCE_WIDGET)
|
||||||
|
if course.configuration.enable_competence_certificates:
|
||||||
|
widgets.append(WidgetType.COMPETENCE_CERTIFICATE_WIDGET)
|
||||||
|
# mentors
|
||||||
|
if course.id in mentor_course_ids:
|
||||||
|
widgets.append(WidgetType.MENTOR_TASKS_WIDGET)
|
||||||
|
widgets.append(WidgetType.MENTOR_PERSON_WIDGET)
|
||||||
|
if course.configuration.enable_competence_certificates:
|
||||||
|
widgets.append(WidgetType.MENTOR_COMPETENCE_WIDGET)
|
||||||
|
return widgets
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue