Merged in feature/VBV-297-trainer-landet-direkt-in-cockpit (pull request #99)

Trainer landet direkt in cockpit

Approved-by: Daniel Egger
This commit is contained in:
Elia Bieri 2023-05-26 07:58:21 +00:00 committed by Daniel Egger
commit c75c9d0b40
11 changed files with 46 additions and 19 deletions

View File

@ -16,10 +16,6 @@ echo "$BRANCH_NAME_SLUG"
DEFAULT_APP_NAME="vbv-$BRANCH_NAME_SLUG" DEFAULT_APP_NAME="vbv-$BRANCH_NAME_SLUG"
APP_NAME=${1:-$DEFAULT_APP_NAME} APP_NAME=${1:-$DEFAULT_APP_NAME}
# remove multiple dashes and make sure it does not end with a dash
APP_NAME=$(echo "$APP_NAME" | sed -E 's/-+/-/g')
APP_NAME=$(echo "$APP_NAME" | sed 's/-\+$//')
# shorten APP_NAME to 32 characters # shorten APP_NAME to 32 characters
# app names with more character seem to fail in some steps in CapRover # app names with more character seem to fail in some steps in CapRover
# CapRover generates longer names out from the app name and there # CapRover generates longer names out from the app name and there
@ -29,6 +25,10 @@ if (( ${#APP_NAME} > 32 )); then
APP_NAME=$(echo -n "${APP_NAME:0:28}-${hash}") APP_NAME=$(echo -n "${APP_NAME:0:28}-${hash}")
fi fi
# remove multiple dashes and make sure it does not end with a dash
APP_NAME=$(echo "$APP_NAME" | sed -E 's/-+/-/g')
APP_NAME=$(echo "$APP_NAME" | sed 's/-\+$//')
echo "Deploy to $APP_NAME" echo "Deploy to $APP_NAME"
VITE_GRAPHQL_URL="/server/graphql/" VITE_GRAPHQL_URL="/server/graphql/"

View File

@ -106,7 +106,7 @@ onMounted(() => {
v-if=" v-if="
inCourse() && inCourse() &&
courseSessionsStore.currentCourseSession && courseSessionsStore.currentCourseSession &&
courseSessionsStore.hasCockpit courseSessionsStore.currentCourseSessionHasCockpit
" "
:to="`${courseSessionsStore.currentCourseSession.course_url}/cockpit`" :to="`${courseSessionsStore.currentCourseSession.course_url}/cockpit`"
class="nav-item" class="nav-item"

View File

@ -2,8 +2,9 @@
import LearningPathDiagramSmall from "@/components/learningPath/LearningPathDiagramSmall.vue"; import LearningPathDiagramSmall from "@/components/learningPath/LearningPathDiagramSmall.vue";
import { useCourseSessionsStore } from "@/stores/courseSessions"; import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import type { CourseSession } from "@/types";
import log from "loglevel"; import log from "loglevel";
import { onMounted } from "vue"; import { computed, onMounted } from "vue";
log.debug("DashboardPage created"); log.debug("DashboardPage created");
@ -13,6 +14,15 @@ const courseSessionsStore = useCourseSessionsStore();
onMounted(async () => { onMounted(async () => {
log.debug("DashboardPage mounted"); log.debug("DashboardPage mounted");
}); });
const getNextStepLink = (courseSession: CourseSession) => {
return computed(() => {
if (courseSessionsStore.hasCockpit(courseSession)) {
return courseSession.cockpit_url;
}
return courseSession.learning_path_url;
});
};
</script> </script>
<template> <template>
@ -44,7 +54,7 @@ onMounted(async () => {
<div> <div>
<router-link <router-link
class="btn-blue" class="btn-blue"
:to="courseSession.learning_path_url" :to="getNextStepLink(courseSession).value"
:data-cy="`continue-course-${courseSession.course.id}`" :data-cy="`continue-course-${courseSession.course.id}`"
> >
{{ $t("general.nextStep") }} {{ $t("general.nextStep") }}

View File

@ -17,7 +17,7 @@ describe("Guards", () => {
it("cannot route to cockpit", () => { it("cannot route to cockpit", () => {
vi.spyOn(courseSessions, "useCourseSessionsStore").mockReturnValue({ vi.spyOn(courseSessions, "useCourseSessionsStore").mockReturnValue({
hasCockpit: false, currentCourseSessionHasCockpit: false,
}); });
const slug = "test"; const slug = "test";
expect(expertRequired({ params: { courseSlug: "test" } })).toEqual( expect(expertRequired({ params: { courseSlug: "test" } })).toEqual(
@ -27,7 +27,7 @@ describe("Guards", () => {
it("can route to cockpit", () => { it("can route to cockpit", () => {
vi.spyOn(courseSessions, "useCourseSessionsStore").mockReturnValue({ vi.spyOn(courseSessions, "useCourseSessionsStore").mockReturnValue({
hasCockpit: true, currentCourseSessionHasCockpit: true,
}); });
const to = { const to = {
params: { params: {

View File

@ -36,7 +36,7 @@ const loginRequired = (to: RouteLocationNormalized) => {
export const expertRequired: NavigationGuard = (to: RouteLocationNormalized) => { export const expertRequired: NavigationGuard = (to: RouteLocationNormalized) => {
const courseSessionsStore = useCourseSessionsStore(); const courseSessionsStore = useCourseSessionsStore();
if (courseSessionsStore.hasCockpit) { if (courseSessionsStore.currentCourseSessionHasCockpit) {
return true; return true;
} else { } else {
const courseSlug = to.params.courseSlug as string; const courseSlug = to.params.courseSlug as string;

View File

@ -66,7 +66,7 @@ describe("CourseSession Store", () => {
courseSessionsStore._currentCourseSlug = "test-course"; courseSessionsStore._currentCourseSlug = "test-course";
courseSessionsStore.allCourseSessions = courseSessions; courseSessionsStore.allCourseSessions = courseSessions;
expect(courseSessionsStore.hasCockpit).toBeFalsy(); expect(courseSessionsStore.currentCourseSessionHasCockpit).toBeFalsy();
}); });
it("superuser has cockpit", () => { it("superuser has cockpit", () => {
@ -77,7 +77,7 @@ describe("CourseSession Store", () => {
courseSessionsStore._currentCourseSlug = "test-course"; courseSessionsStore._currentCourseSlug = "test-course";
courseSessionsStore.allCourseSessions = courseSessions; courseSessionsStore.allCourseSessions = courseSessions;
expect(courseSessionsStore.hasCockpit).toBeTruthy(); expect(courseSessionsStore.currentCourseSessionHasCockpit).toBeTruthy();
}); });
it("expert has cockpit", () => { it("expert has cockpit", () => {
@ -90,6 +90,6 @@ describe("CourseSession Store", () => {
courseSessionsStore._currentCourseSlug = "test-course"; courseSessionsStore._currentCourseSlug = "test-course";
courseSessionsStore.allCourseSessions = courseSessions; courseSessionsStore.allCourseSessions = courseSessions;
expect(courseSessionsStore.hasCockpit).toBeTruthy(); expect(courseSessionsStore.currentCourseSessionHasCockpit).toBeTruthy();
}); });
}); });

View File

@ -124,13 +124,9 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
return allCourseSessionsForCourse(_currentCourseSlug.value); return allCourseSessionsForCourse(_currentCourseSlug.value);
}); });
const hasCockpit = computed(() => { const currentCourseSessionHasCockpit = computed(() => {
if (currentCourseSession.value) { if (currentCourseSession.value) {
const userStore = useUserStore(); return hasCockpit(currentCourseSession.value);
return (
userStore.course_session_experts.includes(currentCourseSession.value.id) ||
userStore.is_superuser
);
} }
return false; return false;
@ -182,6 +178,14 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
); );
}); });
function hasCockpit(couseSession: CourseSession) {
const userStore = useUserStore();
return (
userStore.course_session_experts.includes(couseSession.id) ||
userStore.is_superuser
);
}
function addDocument(document: CircleDocument) { function addDocument(document: CircleDocument) {
currentCourseSession.value?.documents.push(document); currentCourseSession.value?.documents.push(document);
} }
@ -232,6 +236,7 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
courseSessionForCourse, courseSessionForCourse,
switchCourseSession, switchCourseSession,
hasCockpit, hasCockpit,
currentCourseSessionHasCockpit,
canUploadCircleDocuments, canUploadCircleDocuments,
circleDocuments, circleDocuments,
circleExperts, circleExperts,

View File

@ -417,6 +417,7 @@ export interface CourseSession {
start_date: string; start_date: string;
end_date: string; end_date: string;
learning_path_url: string; learning_path_url: string;
cockpit_url: string;
competence_url: string; competence_url: string;
course_url: string; course_url: string;
media_library_url: string; media_library_url: string;

View File

@ -35,6 +35,9 @@ class Course(models.Model):
def get_learning_path_url(self): def get_learning_path_url(self):
return self.get_learning_path().get_frontend_url() return self.get_learning_path().get_frontend_url()
def get_cockpit_url(self):
return self.get_learning_path().get_cockpit_url()
def get_competence_url(self): def get_competence_url(self):
from vbv_lernwelt.competence.models import CompetenceProfilePage from vbv_lernwelt.competence.models import CompetenceProfilePage

View File

@ -46,6 +46,7 @@ class CourseSessionSerializer(serializers.ModelSerializer):
course = serializers.SerializerMethodField() course = serializers.SerializerMethodField()
course_url = serializers.SerializerMethodField() course_url = serializers.SerializerMethodField()
learning_path_url = serializers.SerializerMethodField() learning_path_url = serializers.SerializerMethodField()
cockpit_url = serializers.SerializerMethodField()
competence_url = serializers.SerializerMethodField() competence_url = serializers.SerializerMethodField()
media_library_url = serializers.SerializerMethodField() media_library_url = serializers.SerializerMethodField()
documents = serializers.SerializerMethodField() documents = serializers.SerializerMethodField()
@ -59,6 +60,9 @@ class CourseSessionSerializer(serializers.ModelSerializer):
def get_learning_path_url(self, obj): def get_learning_path_url(self, obj):
return obj.course.get_learning_path_url() return obj.course.get_learning_path_url()
def get_cockpit_url(self, obj):
return obj.course.get_cockpit_url()
def get_media_library_url(self, obj): def get_media_library_url(self, obj):
return obj.course.get_media_library_url() return obj.course.get_media_library_url()
@ -85,6 +89,7 @@ class CourseSessionSerializer(serializers.ModelSerializer):
"attendance_courses", "attendance_courses",
"assignment_details_list", "assignment_details_list",
"learning_path_url", "learning_path_url",
"cockpit_url",
"competence_url", "competence_url",
"media_library_url", "media_library_url",
"course_url", "course_url",

View File

@ -34,6 +34,9 @@ class LearningPath(CourseBasePage):
def get_frontend_url(self): def get_frontend_url(self):
return f"/course/{self.slug.replace('-lp', '')}/learn" return f"/course/{self.slug.replace('-lp', '')}/learn"
def get_cockpit_url(self):
return f"/course/{self.slug.replace('-lp', '')}/cockpit"
class Topic(CourseBasePage): class Topic(CourseBasePage):
serialize_field_names = ["is_visible"] serialize_field_names = ["is_visible"]