Merged in feature/hide-cockpit (pull request #26)
Prevent normal users from navigating to the cockpit Approved-by: Elia Bieri
This commit is contained in:
commit
2d580cad18
|
|
@ -0,0 +1,39 @@
|
|||
import { createPinia, setActivePinia } from "pinia";
|
||||
import { beforeEach, describe, expect, vi } from "vitest";
|
||||
import * as courseSessions from "../../stores/courseSessions";
|
||||
import { expertRequired } from "../guards";
|
||||
|
||||
describe("Guards", () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// creates a fresh pinia and make it active so it's automatically picked
|
||||
// up by any useStore() call without having to pass it to it:
|
||||
// `useStore(pinia)`
|
||||
setActivePinia(createPinia());
|
||||
});
|
||||
|
||||
it("cannot route to cockpit", () => {
|
||||
vi.spyOn(courseSessions, "useCourseSessionsStore").mockReturnValue({
|
||||
hasCockpit: false,
|
||||
});
|
||||
const slug = "test";
|
||||
expect(expertRequired({ params: { courseSlug: "test" } })).toEqual(
|
||||
`/course/${slug}/learn`
|
||||
);
|
||||
});
|
||||
|
||||
it("can route to cockpit", () => {
|
||||
vi.spyOn(courseSessions, "useCourseSessionsStore").mockReturnValue({
|
||||
hasCockpit: true,
|
||||
});
|
||||
const to = {
|
||||
params: {
|
||||
courseSlug: "test",
|
||||
},
|
||||
};
|
||||
expect(expertRequired(to)).toEqual(to);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import type { NavigationGuardWithThis, RouteLocationNormalized } from "vue-router";
|
||||
import type { NavigationGuard, RouteLocationNormalized } from "vue-router";
|
||||
|
||||
export const updateLoggedIn: NavigationGuardWithThis<undefined> = async () => {
|
||||
export const updateLoggedIn: NavigationGuard = async () => {
|
||||
const loggedIn = getCookieValue("loginStatus") === "true";
|
||||
const userStore = useUserStore();
|
||||
|
||||
|
|
@ -11,7 +12,7 @@ export const updateLoggedIn: NavigationGuardWithThis<undefined> = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
export const redirectToLoginIfRequired: NavigationGuardWithThis<undefined> = (to) => {
|
||||
export const redirectToLoginIfRequired: NavigationGuard = (to) => {
|
||||
const userStore = useUserStore();
|
||||
if (loginRequired(to) && !userStore.loggedIn) {
|
||||
return `/login?next=${to.fullPath}`;
|
||||
|
|
@ -32,3 +33,13 @@ export const getCookieValue = (cookieName: string): string => {
|
|||
const loginRequired = (to: RouteLocationNormalized) => {
|
||||
return !to.meta?.public;
|
||||
};
|
||||
|
||||
export const expertRequired: NavigationGuard = (to: RouteLocationNormalized) => {
|
||||
const courseSessionsStore = useCourseSessionsStore();
|
||||
if (courseSessionsStore.hasCockpit) {
|
||||
return to;
|
||||
} else {
|
||||
const courseSlug = to.params.courseSlug as string;
|
||||
return `/course/${courseSlug}/learn`;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import DashboardPage from "@/pages/DashboardPage.vue";
|
||||
import LoginPage from "@/pages/LoginPage.vue";
|
||||
import { redirectToLoginIfRequired, updateLoggedIn } from "@/router/guards";
|
||||
import {
|
||||
expertRequired,
|
||||
redirectToLoginIfRequired,
|
||||
updateLoggedIn,
|
||||
} from "@/router/guards";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
|
||||
|
|
@ -103,6 +107,7 @@ const router = createRouter({
|
|||
path: "/course/:courseSlug/cockpit",
|
||||
props: true,
|
||||
component: () => import("@/pages/cockpit/CockpitParentPage.vue"),
|
||||
beforeEnter: [expertRequired],
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
import { itGetCached, itPost } from "@/fetchHelpers";
|
||||
import type { CourseSession } from "@/types";
|
||||
import { createPinia, setActivePinia } from "pinia";
|
||||
import { beforeEach, describe, expect, vi } from "vitest";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useCourseSessionsStore } from "../courseSessions";
|
||||
import { useUserStore } from "../user";
|
||||
|
||||
let user = {};
|
||||
let courseSessions: CourseSession[] = [];
|
||||
|
||||
describe("CourseSession Store", () => {
|
||||
vi.mock("vue-router", () => ({
|
||||
useRoute: () => ({
|
||||
path: "/course/test-course/learn/",
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@/fetchHelpers", () => {
|
||||
const itGetCached = () => Promise.resolve([]);
|
||||
const itPost = () => Promise.resolve([]);
|
||||
|
||||
return {
|
||||
itGetCached,
|
||||
itPost,
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// creates a fresh pinia and make it active so it's automatically picked
|
||||
// up by any useStore() call without having to pass it to it:
|
||||
// `useStore(pinia)`
|
||||
setActivePinia(createPinia());
|
||||
user = {
|
||||
is_superuser: false,
|
||||
course_session_expert: [],
|
||||
};
|
||||
courseSessions = [
|
||||
{
|
||||
id: 1,
|
||||
created_at: "2021-05-11T10:00:00.000000Z",
|
||||
updated_at: "2023-05-11T10:00:00.000000Z",
|
||||
course: {
|
||||
id: 1,
|
||||
title: "Test Course",
|
||||
category_name: "Test Category",
|
||||
slug: "test-course",
|
||||
},
|
||||
title: "Test Course Session",
|
||||
start_date: "2022-05-11T10:00:00.000000Z",
|
||||
end_date: "2023-05-11T10:00:00.000000Z",
|
||||
learning_path_url: "/course/test-course/learn/",
|
||||
competence_url: "/course/test-course/competence/",
|
||||
course_url: "/course/test-course/",
|
||||
media_library_url: "/course/test-course/media/",
|
||||
additional_json_data: {},
|
||||
documents: [],
|
||||
users: [],
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
it("normal user has no cockpit", () => {
|
||||
const userStore = useUserStore();
|
||||
const courseSessionsStore = useCourseSessionsStore();
|
||||
userStore.$patch(user);
|
||||
courseSessionsStore.$patch({ courseSessions });
|
||||
|
||||
expect(courseSessionsStore.hasCockpit).toBeFalsy();
|
||||
});
|
||||
|
||||
it("superuser has cockpit", () => {
|
||||
const userStore = useUserStore();
|
||||
const courseSessionsStore = useCourseSessionsStore();
|
||||
userStore.$patch(Object.assign(user, { is_superuser: true }));
|
||||
courseSessionsStore.$patch({ courseSessions });
|
||||
|
||||
expect(courseSessionsStore.hasCockpit).toBeTruthy();
|
||||
});
|
||||
|
||||
it("expert has cockpit", () => {
|
||||
const userStore = useUserStore();
|
||||
const courseSessionsStore = useCourseSessionsStore();
|
||||
userStore.$patch(
|
||||
Object.assign(user, { course_session_experts: [courseSessions[0].id] })
|
||||
);
|
||||
courseSessionsStore.$patch({ courseSessions });
|
||||
|
||||
expect(courseSessionsStore.hasCockpit).toBeTruthy();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue