refactor: enum voor account types
This commit is contained in:
parent
f9fc19d8a6
commit
fc0d3b5c84
20 changed files with 77 additions and 5870 deletions
|
@ -5,6 +5,7 @@ import { envVars, getEnvVar } from '../util/envVars.js';
|
|||
import { createOrUpdateStudent } from '../services/students.js';
|
||||
import { Request, Response } from 'express';
|
||||
import { createOrUpdateTeacher } from '../services/teachers.js';
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
interface FrontendIdpConfig {
|
||||
authority: string;
|
||||
|
@ -55,7 +56,7 @@ export async function postHelloHandler(req: AuthenticatedRequest, res: Response)
|
|||
firstName: auth.firstName ?? '',
|
||||
lastName: auth.lastName ?? '',
|
||||
};
|
||||
if (auth.accountType === 'student') {
|
||||
if (auth.accountType === AccountType.Student) {
|
||||
await createOrUpdateStudent(userData);
|
||||
logger.debug(`Synchronized student ${userData.username} with IDP`);
|
||||
} else {
|
||||
|
|
|
@ -2,6 +2,7 @@ import { authorize } from './auth-checks.js';
|
|||
import { fetchClass } from '../../../services/classes.js';
|
||||
import { fetchAllGroups } from '../../../services/groups.js';
|
||||
import { mapToUsername } from '../../../interfaces/user.js';
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
/**
|
||||
* Expects the path to contain the path parameters 'classId' and 'id' (meaning the ID of the assignment).
|
||||
|
@ -11,7 +12,7 @@ import { mapToUsername } from '../../../interfaces/user.js';
|
|||
*/
|
||||
export const onlyAllowIfHasAccessToAssignment = authorize(async (auth, req) => {
|
||||
const { classid: classId, id: assignmentId } = req.params as { classid: string; id: number };
|
||||
if (auth.accountType === 'teacher') {
|
||||
if (auth.accountType === AccountType.Teacher) {
|
||||
const clazz = await fetchClass(classId);
|
||||
return clazz.teachers.map(mapToUsername).includes(auth.username);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import * as express from 'express';
|
|||
import { RequestHandler } from 'express';
|
||||
import { UnauthorizedException } from '../../../exceptions/unauthorized-exception.js';
|
||||
import { ForbiddenException } from '../../../exceptions/forbidden-exception.js';
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
/**
|
||||
* Middleware which rejects unauthenticated users (with HTTP 401) and authenticated users which do not fulfill
|
||||
|
@ -36,11 +37,11 @@ export const authenticatedOnly = authorize((_) => true);
|
|||
/**
|
||||
* Middleware which rejects requests from unauthenticated users or users that aren't students.
|
||||
*/
|
||||
export const studentsOnly = authorize((auth) => auth.accountType === 'student');
|
||||
export const studentsOnly = authorize((auth) => auth.accountType === AccountType.Student);
|
||||
/**
|
||||
* Middleware which rejects requests from unauthenticated users or users that aren't teachers.
|
||||
*/
|
||||
export const teachersOnly = authorize((auth) => auth.accountType === 'teacher');
|
||||
export const teachersOnly = authorize((auth) => auth.accountType === AccountType.Teacher);
|
||||
/**
|
||||
* Middleware which is to be used on requests no normal user should be able to execute.
|
||||
* Since there is no concept of administrator accounts yet, currently, those requests will always be blocked.
|
||||
|
|
|
@ -4,6 +4,7 @@ import { AuthenticatedRequest } from '../authenticated-request.js';
|
|||
import { fetchClass } from '../../../services/classes.js';
|
||||
import { mapToUsername } from '../../../interfaces/user.js';
|
||||
import {getAllInvitations} from "../../../services/teacher-invitations";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
async function teaches(teacherUsername: string, classId: string): Promise<boolean> {
|
||||
const clazz = await fetchClass(classId);
|
||||
|
@ -18,7 +19,7 @@ async function teaches(teacherUsername: string, classId: string): Promise<boolea
|
|||
export const onlyAllowStudentHimselfAndTeachersOfClass = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => {
|
||||
if (req.params.username === auth.username) {
|
||||
return true;
|
||||
} else if (auth.accountType === 'teacher') {
|
||||
} else if (auth.accountType === AccountType.Teacher) {
|
||||
return teaches(auth.username, req.params.classId);
|
||||
}
|
||||
return false;
|
||||
|
@ -39,7 +40,7 @@ export const onlyAllowTeacherOfClass = authorize(
|
|||
export const onlyAllowIfInClass = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => {
|
||||
const classId = req.params.classId ?? req.params.classid ?? req.params.id;
|
||||
const clazz = await fetchClass(classId);
|
||||
if (auth.accountType === 'teacher') {
|
||||
if (auth.accountType === AccountType.Teacher) {
|
||||
return clazz.teachers.map(mapToUsername).includes(auth.username);
|
||||
}
|
||||
return clazz.students.map(mapToUsername).includes(auth.username);
|
||||
|
@ -48,7 +49,7 @@ export const onlyAllowIfInClass = authorize(async (auth: AuthenticationInfo, req
|
|||
export const onlyAllowIfInClassOrInvited = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => {
|
||||
const classId = req.params.classId ?? req.params.classid ?? req.params.id;
|
||||
const clazz = await fetchClass(classId);
|
||||
if (auth.accountType === 'teacher') {
|
||||
if (auth.accountType === AccountType.Teacher) {
|
||||
const invitations = await getAllInvitations(auth.username, false);
|
||||
return clazz.teachers.map(mapToUsername).includes(auth.username) || invitations.some(invitation => invitation.classId === classId);
|
||||
}
|
||||
|
@ -62,7 +63,7 @@ export const onlyAllowOwnClassInBody = authorize(async (auth, req) => {
|
|||
const classId = (req.body as { class: string })?.class;
|
||||
const clazz = await fetchClass(classId);
|
||||
|
||||
if (auth.accountType === 'teacher') {
|
||||
if (auth.accountType === AccountType.Teacher) {
|
||||
return clazz.teachers.map(mapToUsername).includes(auth.username);
|
||||
}
|
||||
return clazz.students.map(mapToUsername).includes(auth.username);
|
||||
|
|
|
@ -2,6 +2,7 @@ import { authorize } from './auth-checks.js';
|
|||
import { fetchClass } from '../../../services/classes.js';
|
||||
import { fetchGroup } from '../../../services/groups.js';
|
||||
import { mapToUsername } from '../../../interfaces/user.js';
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
/**
|
||||
* Expects the path to contain the path parameters 'classid', 'assignmentid' and 'groupid'.
|
||||
|
@ -16,7 +17,7 @@ export const onlyAllowIfHasAccessToGroup = authorize(async (auth, req) => {
|
|||
groupid: groupId,
|
||||
} = req.params as { classid: string; assignmentid: number; groupid: number };
|
||||
|
||||
if (auth.accountType === 'teacher') {
|
||||
if (auth.accountType === AccountType.Teacher) {
|
||||
const clazz = await fetchClass(classId);
|
||||
return clazz.teachers.map(mapToUsername).includes(auth.username);
|
||||
} // User is student
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { authorize } from './auth-checks';
|
||||
import { AuthenticationInfo } from '../authentication-info';
|
||||
import { AuthenticatedRequest } from '../authenticated-request';
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
/**
|
||||
* Only allows requests whose learning path personalization query parameters ('forGroup' / 'assignmentNo' / 'classId')
|
||||
|
@ -11,7 +12,7 @@ import { AuthenticatedRequest } from '../authenticated-request';
|
|||
*/
|
||||
export const onlyAllowPersonalizationForOwnGroup = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => {
|
||||
const { forGroup, assignmentNo, classId } = req.params;
|
||||
if (auth.accountType === 'student' && forGroup && assignmentNo && classId) {
|
||||
if (auth.accountType === AccountType.Student && forGroup && assignmentNo && classId) {
|
||||
// TODO: groupNumber?
|
||||
// Const group = await fetchGroup(Number(classId), Number(assignmentNo), )
|
||||
return false;
|
||||
|
|
|
@ -7,6 +7,7 @@ import { fetchQuestion } from '../../../services/questions.js';
|
|||
import { FALLBACK_SEQ_NUM } from '../../../config.js';
|
||||
import { fetchAnswer } from '../../../services/answers.js';
|
||||
import { mapToUsername } from '../../../interfaces/user.js';
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
export const onlyAllowAuthor = authorize(
|
||||
(auth: AuthenticationInfo, req: AuthenticatedRequest) => (req.body as { author: string }).author === auth.username
|
||||
|
@ -57,7 +58,7 @@ export const onlyAllowIfHasAccessToQuestion = authorize(async (auth: Authenticat
|
|||
const question = await fetchQuestion(questionId);
|
||||
const group = question.inGroup;
|
||||
|
||||
if (auth.accountType === 'teacher') {
|
||||
if (auth.accountType === AccountType.Teacher) {
|
||||
const cls = group.assignment.within; // TODO check if contains full objects
|
||||
return cls.teachers.map(mapToUsername).includes(auth.username);
|
||||
} // User is student
|
||||
|
|
|
@ -6,6 +6,7 @@ import { AuthenticationInfo } from '../authentication-info.js';
|
|||
import { authorize } from './auth-checks.js';
|
||||
import { FALLBACK_LANG } from '../../../config.js';
|
||||
import { mapToUsername } from '../../../interfaces/user.js';
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
export const onlyAllowSubmitter = authorize(
|
||||
(auth: AuthenticationInfo, req: AuthenticatedRequest) => (req.body as { submitter: string }).submitter === auth.username
|
||||
|
@ -18,7 +19,7 @@ export const onlyAllowIfHasAccessToSubmission = authorize(async (auth: Authentic
|
|||
const loId = new LearningObjectIdentifier(lohruid, languageMap[lang as string] ?? FALLBACK_LANG, Number(version));
|
||||
const submission = await fetchSubmission(loId, Number(submissionNumber));
|
||||
|
||||
if (auth.accountType === 'teacher') {
|
||||
if (auth.accountType === AccountType.Teacher) {
|
||||
// Dit kan niet werken om dat al deze objecten niet gepopulate zijn.
|
||||
return submission.onBehalfOf.assignment.within.teachers.map(mapToUsername).includes(auth.username);
|
||||
}
|
||||
|
|
4
common/src/util/account-types.ts
Normal file
4
common/src/util/account-types.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export enum AccountType {
|
||||
Student = 'student',
|
||||
Teacher = 'teacher'
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
"test:e2e": "playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dwengo-1/common": "^0.2.0",
|
||||
"@tanstack/react-query": "^5.69.0",
|
||||
"@tanstack/vue-query": "^5.69.0",
|
||||
"@vueuse/core": "^13.1.0",
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import type { AnswersResponse } from "@/controllers/answers";
|
||||
import type { AnswerData, AnswerDTO } from "@dwengo-1/common/interfaces/answer";
|
||||
import authService from "@/services/auth/auth-service";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
const props = defineProps<{
|
||||
question: QuestionDTO;
|
||||
|
@ -80,7 +81,7 @@
|
|||
{{ question.content }}
|
||||
</div>
|
||||
<div
|
||||
v-if="authService.authState.activeRole === 'teacher'"
|
||||
v-if="authService.authState.activeRole === AccountType.Teacher"
|
||||
class="answer-input-container"
|
||||
>
|
||||
<input
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg";
|
||||
import auth from "@/services/auth/auth-service.ts";
|
||||
import { watch } from "vue";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
@ -17,11 +18,11 @@
|
|||
);
|
||||
|
||||
async function loginAsStudent(): Promise<void> {
|
||||
await auth.loginAs("student");
|
||||
await auth.loginAs(AccountType.Student);
|
||||
}
|
||||
|
||||
async function loginAsTeacher(): Promise<void> {
|
||||
await auth.loginAs("teacher");
|
||||
await auth.loginAs(AccountType.Teacher);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
import type { AssignmentDTO } from "@dwengo-1/common/interfaces/assignment";
|
||||
import { useCreateAssignmentMutation } from "@/queries/assignments.ts";
|
||||
import { useRoute } from "vue-router";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
@ -23,7 +24,7 @@
|
|||
|
||||
onMounted(async () => {
|
||||
// Redirect student
|
||||
if (role.value === "student") {
|
||||
if (role.value === AccountType.Student) {
|
||||
await router.push("/user");
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
import { useGetLearningPathQuery } from "@/queries/learning-paths.ts";
|
||||
import type { LearningPath } from "@/data-objects/learning-paths/learning-path.ts";
|
||||
import type { GroupDTO } from "@dwengo-1/common/interfaces/group";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
const role = auth.authState.activeRole;
|
||||
const isTeacher = computed(() => role === "teacher");
|
||||
const isTeacher = computed(() => role === AccountType.Teacher);
|
||||
|
||||
const route = useRoute();
|
||||
const classId = ref<string>(route.params.classId as string);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import type { ClassDTO } from "@dwengo-1/common/interfaces/class";
|
||||
import { asyncComputed } from "@vueuse/core";
|
||||
import { useDeleteAssignmentMutation } from "@/queries/assignments.ts";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
@ -16,7 +17,7 @@
|
|||
const role = ref(auth.authState.activeRole);
|
||||
const username = ref<string>("");
|
||||
|
||||
const isTeacher = computed(() => role.value === "teacher");
|
||||
const isTeacher = computed(() => role.value === AccountType.Teacher);
|
||||
|
||||
// Fetch and store all the teacher's classes
|
||||
let classesQueryResults = undefined;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import authState from "@/services/auth/auth-service.ts";
|
||||
import TeacherClasses from "./TeacherClasses.vue";
|
||||
import StudentClasses from "./StudentClasses.vue";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
// Determine if role is student or teacher to render correct view
|
||||
const role: string = authState.authState.activeRole!;
|
||||
|
@ -9,7 +10,7 @@
|
|||
|
||||
<template>
|
||||
<main>
|
||||
<TeacherClasses v-if="role === 'teacher'"></TeacherClasses>
|
||||
<TeacherClasses v-if="role === AccountType.Teacher"></TeacherClasses>
|
||||
<StudentClasses v-else></StudentClasses>
|
||||
</main>
|
||||
</template>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
import type { AssignmentDTO } from "@dwengo-1/common/interfaces/assignment";
|
||||
import type { GroupDTO } from "@dwengo-1/common/interfaces/group";
|
||||
import QuestionNotification from "@/components/QuestionNotification.vue";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
@ -235,8 +236,8 @@
|
|||
</p>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
v-if="query.classId && query.assignmentNo && authService.authState.activeRole === 'teacher'"
|
||||
<v-list-itemF
|
||||
v-if="query.classId && query.assignmentNo && authService.authState.activeRole === AccountType.Teacher"
|
||||
>
|
||||
<template v-slot:default>
|
||||
<learning-path-group-selector
|
||||
|
@ -245,7 +246,7 @@
|
|||
v-model="forGroupQueryParam"
|
||||
/>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list-itemF>
|
||||
<v-divider></v-divider>
|
||||
<div v-if="props.learningObjectHruid">
|
||||
<using-query-result
|
||||
|
@ -259,7 +260,7 @@
|
|||
:title="node.title"
|
||||
:active="node.key === props.learningObjectHruid"
|
||||
:key="node.key"
|
||||
v-if="!node.teacherExclusive || authService.authState.activeRole === 'teacher'"
|
||||
v-if="!node.teacherExclusive || authService.authState.activeRole === AccountType.Teacher"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon
|
||||
|
@ -283,7 +284,7 @@
|
|||
</using-query-result>
|
||||
</div>
|
||||
<v-spacer></v-spacer>
|
||||
<v-list-item v-if="authService.authState.activeRole === 'teacher'">
|
||||
<v-list-item v-if="authService.authState.activeRole === AccountType.Teacher">
|
||||
<template v-slot:default>
|
||||
<v-btn
|
||||
class="button-in-nav"
|
||||
|
@ -296,7 +297,7 @@
|
|||
</v-list-item>
|
||||
<v-list-item>
|
||||
<div
|
||||
v-if="authService.authState.activeRole === 'student' && pathIsAssignment"
|
||||
v-if="authService.authState.activeRole === AccountType.Student && pathIsAssignment"
|
||||
class="assignment-indicator"
|
||||
>
|
||||
{{ t("assignmentIndicator") }}
|
||||
|
@ -325,7 +326,7 @@
|
|||
></learning-object-view>
|
||||
</div>
|
||||
<div
|
||||
v-if="authService.authState.activeRole === 'student' && pathIsAssignment"
|
||||
v-if="authService.authState.activeRole === AccountType.Student && pathIsAssignment"
|
||||
class="question-box"
|
||||
>
|
||||
<div class="input-wrapper">
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
import type { SubmissionData } from "@/views/learning-paths/learning-object/submission-data";
|
||||
import LearningObjectContentView from "@/views/learning-paths/learning-object/content/LearningObjectContentView.vue";
|
||||
import LearningObjectSubmissionsView from "@/views/learning-paths/learning-object/submissions/LearningObjectSubmissionsView.vue";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
const _isStudent = computed(() => authService.authState.activeRole === "student");
|
||||
const _isStudent = computed(() => authService.authState.activeRole === AccountType.Student);
|
||||
|
||||
const props = defineProps<{
|
||||
hruid: string;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
import type { StudentDTO } from "@dwengo-1/common/interfaces/student";
|
||||
import type { GroupDTO } from "@dwengo-1/common/interfaces/group";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import {AccountType} from "@dwengo-1/common/util/account-types";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -31,7 +32,7 @@
|
|||
mutate: submitSolution,
|
||||
} = useCreateSubmissionMutation();
|
||||
|
||||
const isStudent = computed(() => authService.authState.activeRole === "student");
|
||||
const isStudent = computed(() => authService.authState.activeRole === AccountType.Student);
|
||||
|
||||
const isSubmitDisabled = computed(() => {
|
||||
if (!props.submissionData || props.submissions === undefined) {
|
||||
|
|
5869
package-lock.json
generated
5869
package-lock.json
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue