This commit is contained in:
Gerald Schmittinger 2025-05-12 00:59:32 +02:00
commit db92eff759
26 changed files with 9291 additions and 659 deletions

View file

@ -41,6 +41,7 @@
"loki-logger-ts": "^1.0.2",
"marked": "^15.0.7",
"mime-types": "^3.0.1",
"nanoid": "^5.1.5",
"response-time": "^2.3.3",
"swagger-ui-express": "^5.0.1",
"unzipper": "^0.12.3",

View file

@ -1,15 +1,17 @@
import { Collection, Entity, ManyToMany, PrimaryKey, Property } from '@mikro-orm/core';
import { v4 } from 'uuid';
import { Teacher } from '../users/teacher.entity.js';
import { Student } from '../users/student.entity.js';
import { ClassRepository } from '../../data/classes/class-repository.js';
import { customAlphabet } from 'nanoid';
const generateClassId = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 6);
@Entity({
repository: () => ClassRepository,
})
export class Class {
@PrimaryKey()
classId? = v4();
classId? = generateClassId();
@Property({ type: 'string' })
displayName!: string;

View file

@ -0,0 +1,47 @@
import { setupTestApp } from '../setup-tests.js';
import { describe, it, expect, beforeAll, beforeEach, vi, Mock } from 'vitest';
import { Request, Response } from 'express';
import { createClassHandler, deleteClassHandler } from '../../src/controllers/classes';
describe('Class controllers', () => {
let req: Partial<Request>;
let res: Partial<Response>;
let jsonMock: Mock;
let statusMock: Mock;
beforeAll(async () => {
await setupTestApp();
});
beforeEach(async () => {
jsonMock = vi.fn();
statusMock = vi.fn().mockReturnThis();
res = {
json: jsonMock,
status: statusMock,
};
});
it('create and delete class', async () => {
req = {
body: { displayName: 'coole_nieuwe_klas' },
};
await createClassHandler(req as Request, res as Response);
const result = jsonMock.mock.lastCall?.[0];
// Console.log('class', result.class);
expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ class: expect.anything() }));
req = {
params: { id: result.class.id },
};
await deleteClassHandler(req as Request, res as Response);
expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ class: expect.anything() }));
});
});

View file

@ -21,6 +21,7 @@ import { BadRequestException } from '../../src/exceptions/bad-request-exception.
import { ConflictException } from '../../src/exceptions/conflict-exception.js';
import { EntityAlreadyExistsException } from '../../src/exceptions/entity-already-exists-exception.js';
import { StudentDTO } from '@dwengo-1/common/interfaces/student';
import { getClass02 } from '../test_assets/classes/classes.testdata';
describe('Student controllers', () => {
let req: Partial<Request>;
@ -186,7 +187,7 @@ describe('Student controllers', () => {
it('Get join request by student and class', async () => {
req = {
params: { username: 'PinkFloyd', classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89' },
params: { username: 'PinkFloyd', classId: getClass02().classId },
};
await getStudentRequestHandler(req as Request, res as Response);
@ -201,7 +202,7 @@ describe('Student controllers', () => {
it('Create and delete join request', async () => {
req = {
params: { username: 'TheDoors' },
body: { classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89' },
body: { classId: getClass02().classId },
};
await createStudentRequestHandler(req as Request, res as Response);
@ -209,7 +210,7 @@ describe('Student controllers', () => {
expect(jsonMock).toHaveBeenCalledWith(expect.objectContaining({ request: expect.anything() }));
req = {
params: { username: 'TheDoors', classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89' },
params: { username: 'TheDoors', classId: getClass02().classId },
};
await deleteClassJoinRequestHandler(req as Request, res as Response);
@ -222,7 +223,7 @@ describe('Student controllers', () => {
it('Create join request student already in class error', async () => {
req = {
params: { username: 'Noordkaap' },
body: { classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89' },
body: { classId: getClass02().classId },
};
await expect(async () => createStudentRequestHandler(req as Request, res as Response)).rejects.toThrow(ConflictException);
@ -231,7 +232,7 @@ describe('Student controllers', () => {
it('Create join request duplicate', async () => {
req = {
params: { username: 'Tool' },
body: { classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89' },
body: { classId: getClass02().classId },
};
await expect(async () => createStudentRequestHandler(req as Request, res as Response)).rejects.toThrow(ConflictException);

View file

@ -12,6 +12,7 @@ import { TeacherInvitationData } from '@dwengo-1/common/interfaces/teacher-invit
import { getClassHandler } from '../../src/controllers/classes';
import { BadRequestException } from '../../src/exceptions/bad-request-exception';
import { ClassStatus } from '@dwengo-1/common/util/class-join-request';
import { getClass02 } from '../test_assets/classes/classes.testdata';
describe('Teacher controllers', () => {
let req: Partial<Request>;
@ -57,7 +58,7 @@ describe('Teacher controllers', () => {
const body = {
sender: 'LimpBizkit',
receiver: 'testleerkracht1',
class: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89',
class: getClass02().classId,
} as TeacherInvitationData;
req = { body };
@ -67,7 +68,7 @@ describe('Teacher controllers', () => {
params: {
sender: 'LimpBizkit',
receiver: 'testleerkracht1',
classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89',
classId: getClass02().classId,
},
body: { accepted: 'false' },
};
@ -80,7 +81,7 @@ describe('Teacher controllers', () => {
params: {
sender: 'LimpBizkit',
receiver: 'FooFighters',
classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89',
classId: getClass02().classId,
},
};
await getInvitationHandler(req as Request, res as Response);
@ -100,7 +101,7 @@ describe('Teacher controllers', () => {
const body = {
sender: 'LimpBizkit',
receiver: 'FooFighters',
class: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89',
class: getClass02().classId,
} as TeacherInvitationData;
req = { body };
@ -111,7 +112,7 @@ describe('Teacher controllers', () => {
req = {
params: {
id: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89',
id: getClass02().classId,
},
};

View file

@ -17,6 +17,7 @@ import { EntityAlreadyExistsException } from '../../src/exceptions/entity-alread
import { getStudentRequestsHandler } from '../../src/controllers/students.js';
import { TeacherDTO } from '@dwengo-1/common/interfaces/teacher';
import { getClassHandler } from '../../src/controllers/classes';
import { getClass02 } from '../test_assets/classes/classes.testdata';
describe('Teacher controllers', () => {
let req: Partial<Request>;
@ -169,7 +170,7 @@ describe('Teacher controllers', () => {
it('Get join requests by class', async () => {
req = {
params: { classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89' },
params: { classId: getClass02().classId },
};
await getStudentJoinRequestHandler(req as Request, res as Response);
@ -183,7 +184,7 @@ describe('Teacher controllers', () => {
it('Update join request status', async () => {
req = {
params: { classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89', studentUsername: 'PinkFloyd' },
params: { classId: getClass02().classId, studentUsername: 'PinkFloyd' },
body: { accepted: 'true' },
};
@ -201,7 +202,7 @@ describe('Teacher controllers', () => {
expect(status).toBeTruthy();
req = {
params: { id: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89' },
params: { id: getClass02().classId },
};
await getClassHandler(req as Request, res as Response);

View file

@ -3,6 +3,7 @@ import { setupTestApp } from '../../setup-tests';
import { AssignmentRepository } from '../../../src/data/assignments/assignment-repository';
import { getAssignmentRepository, getClassRepository } from '../../../src/data/repositories';
import { ClassRepository } from '../../../src/data/classes/class-repository';
import { getClass02 } from '../../test_assets/classes/classes.testdata';
describe('AssignmentRepository', () => {
let assignmentRepository: AssignmentRepository;
@ -15,7 +16,7 @@ describe('AssignmentRepository', () => {
});
it('should return the requested assignment', async () => {
const class_ = await classRepository.findById('34d484a1-295f-4e9f-bfdc-3e7a23d86a89');
const class_ = await classRepository.findById(getClass02().classId);
const assignment = await assignmentRepository.findByClassAndId(class_!, 21001);
expect(assignment).toBeTruthy();
@ -23,7 +24,7 @@ describe('AssignmentRepository', () => {
});
it('should return all assignments for a class', async () => {
const class_ = await classRepository.findById('34d484a1-295f-4e9f-bfdc-3e7a23d86a89');
const class_ = await classRepository.findById(getClass02().classId);
const assignments = await assignmentRepository.findAllAssignmentsInClass(class_!);
expect(assignments).toBeTruthy();

View file

@ -4,6 +4,7 @@ import { GroupRepository } from '../../../src/data/assignments/group-repository'
import { getAssignmentRepository, getClassRepository, getGroupRepository } from '../../../src/data/repositories';
import { AssignmentRepository } from '../../../src/data/assignments/assignment-repository';
import { ClassRepository } from '../../../src/data/classes/class-repository';
import { getClass01, getClass02 } from '../../test_assets/classes/classes.testdata';
describe('GroupRepository', () => {
let groupRepository: GroupRepository;
@ -18,7 +19,8 @@ describe('GroupRepository', () => {
});
it('should return the requested group', async () => {
const class_ = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9');
const id = getClass01().classId;
const class_ = await classRepository.findById(id);
const assignment = await assignmentRepository.findByClassAndId(class_!, 21000);
const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 21001);
@ -27,7 +29,7 @@ describe('GroupRepository', () => {
});
it('should return all groups for assignment', async () => {
const class_ = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9');
const class_ = await classRepository.findById(getClass01().classId);
const assignment = await assignmentRepository.findByClassAndId(class_!, 21000);
const groups = await groupRepository.findAllGroupsForAssignment(assignment!);
@ -37,7 +39,7 @@ describe('GroupRepository', () => {
});
it('should not find removed group', async () => {
const class_ = await classRepository.findById('34d484a1-295f-4e9f-bfdc-3e7a23d86a89');
const class_ = await classRepository.findById(getClass02().classId);
const assignment = await assignmentRepository.findByClassAndId(class_!, 21001);
await groupRepository.deleteByAssignmentAndGroupNumber(assignment!, 21001);

View file

@ -18,6 +18,7 @@ import { Submission } from '../../../src/entities/assignments/submission.entity'
import { Class } from '../../../src/entities/classes/class.entity';
import { Assignment } from '../../../src/entities/assignments/assignment.entity';
import { testLearningObject01 } from '../../test_assets/content/learning-objects.testdata';
import { getClass01 } from '../../test_assets/classes/classes.testdata';
describe('SubmissionRepository', () => {
let submissionRepository: SubmissionRepository;
@ -54,7 +55,7 @@ describe('SubmissionRepository', () => {
it('should find the most recent submission for a group', async () => {
const id = new LearningObjectIdentifier('id03', Language.English, 1);
const class_ = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9');
const class_ = await classRepository.findById(getClass01().classId);
const assignment = await assignmentRepository.findByClassAndId(class_!, 21000);
const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 21001);
const submission = await submissionRepository.findMostRecentSubmissionForGroup(id, group!);
@ -67,7 +68,7 @@ describe('SubmissionRepository', () => {
let assignment: Assignment | null;
let loId: LearningObjectIdentifier;
it('should find all submissions for a certain learning object and assignment', async () => {
clazz = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9');
clazz = await classRepository.findById(getClass01().classId);
assignment = await assignmentRepository.findByClassAndId(clazz!, 21000);
loId = {
hruid: 'id02',

View file

@ -4,6 +4,7 @@ import { ClassJoinRequestRepository } from '../../../src/data/classes/class-join
import { getClassJoinRequestRepository, getClassRepository, getStudentRepository } from '../../../src/data/repositories';
import { StudentRepository } from '../../../src/data/users/student-repository';
import { ClassRepository } from '../../../src/data/classes/class-repository';
import { getClass02, getClass03 } from '../../test_assets/classes/classes.testdata';
describe('ClassJoinRequestRepository', () => {
let classJoinRequestRepository: ClassJoinRequestRepository;
@ -26,7 +27,7 @@ describe('ClassJoinRequestRepository', () => {
});
it('should list all requests to a single class', async () => {
const class_ = await cassRepository.findById('34d484a1-295f-4e9f-bfdc-3e7a23d86a89');
const class_ = await cassRepository.findById(getClass02().classId);
const requests = await classJoinRequestRepository.findAllOpenRequestsTo(class_!);
expect(requests).toBeTruthy();
@ -35,7 +36,7 @@ describe('ClassJoinRequestRepository', () => {
it('should not find a removed request', async () => {
const student = await studentRepository.findByUsername('SmashingPumpkins');
const class_ = await cassRepository.findById('80dcc3e0-1811-4091-9361-42c0eee91cfa');
const class_ = await cassRepository.findById(getClass03().classId);
await classJoinRequestRepository.deleteBy(student!, class_!);
const request = await classJoinRequestRepository.findAllRequestsBy(student!);

View file

@ -2,6 +2,7 @@ import { beforeAll, describe, expect, it } from 'vitest';
import { ClassRepository } from '../../../src/data/classes/class-repository';
import { setupTestApp } from '../../setup-tests';
import { getClassRepository } from '../../../src/data/repositories';
import { getClass01, getClass04 } from '../../test_assets/classes/classes.testdata';
describe('ClassRepository', () => {
let classRepository: ClassRepository;
@ -18,16 +19,16 @@ describe('ClassRepository', () => {
});
it('should return requested class', async () => {
const classVar = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9');
const classVar = await classRepository.findById(getClass01().classId);
expect(classVar).toBeTruthy();
expect(classVar?.displayName).toBe('class01');
});
it('class should be gone after deletion', async () => {
await classRepository.deleteById('33d03536-83b8-4880-9982-9bbf2f908ddf');
await classRepository.deleteById(getClass04().classId);
const classVar = await classRepository.findById('33d03536-83b8-4880-9982-9bbf2f908ddf');
const classVar = await classRepository.findById(getClass04().classId);
expect(classVar).toBeNull();
});

View file

@ -4,6 +4,7 @@ import { getClassRepository, getTeacherInvitationRepository, getTeacherRepositor
import { TeacherInvitationRepository } from '../../../src/data/classes/teacher-invitation-repository';
import { TeacherRepository } from '../../../src/data/users/teacher-repository';
import { ClassRepository } from '../../../src/data/classes/class-repository';
import { getClass01, getClass02 } from '../../test_assets/classes/classes.testdata';
describe('ClassRepository', () => {
let teacherInvitationRepository: TeacherInvitationRepository;
@ -34,7 +35,7 @@ describe('ClassRepository', () => {
});
it('should return all invitations for a class', async () => {
const class_ = await classRepository.findById('34d484a1-295f-4e9f-bfdc-3e7a23d86a89');
const class_ = await classRepository.findById(getClass02().classId);
const invitations = await teacherInvitationRepository.findAllInvitationsForClass(class_!);
expect(invitations).toBeTruthy();
@ -42,7 +43,7 @@ describe('ClassRepository', () => {
});
it('should not find a removed invitation', async () => {
const class_ = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9');
const class_ = await classRepository.findById(getClass01().classId);
const sender = await teacherRepository.findByUsername('FooFighters');
const receiver = await teacherRepository.findByUsername('LimpBizkit');
await teacherInvitationRepository.deleteBy(class_!, sender!, receiver!);

View file

@ -14,6 +14,7 @@ import { Language } from '@dwengo-1/common/util/language';
import { Question } from '../../../src/entities/questions/question.entity';
import { Class } from '../../../src/entities/classes/class.entity';
import { Assignment } from '../../../src/entities/assignments/assignment.entity';
import { getClass01 } from '../../test_assets/classes/classes.testdata';
describe('QuestionRepository', () => {
let questionRepository: QuestionRepository;
@ -37,7 +38,7 @@ describe('QuestionRepository', () => {
const id = new LearningObjectIdentifier('id03', Language.English, 1);
const student = await studentRepository.findByUsername('Noordkaap');
const clazz = await getClassRepository().findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9');
const clazz = await getClassRepository().findById(getClass01().classId);
const assignment = await getAssignmentRepository().findByClassAndId(clazz!, 21000);
const group = await getGroupRepository().findByAssignmentAndGroupNumber(assignment!, 21001);
await questionRepository.createQuestion({
@ -56,7 +57,7 @@ describe('QuestionRepository', () => {
let assignment: Assignment | null;
let loId: LearningObjectIdentifier;
it('should find all questions for a certain learning object and assignment', async () => {
clazz = await getClassRepository().findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9');
clazz = await getClassRepository().findById(getClass01().classId);
assignment = await getAssignmentRepository().findByClassAndId(clazz!, 21000);
loId = {
hruid: 'id05',

View file

@ -10,7 +10,7 @@ export function makeTestClasses(em: EntityManager, students: Student[], teachers
const teacherClass01: Teacher[] = teachers.slice(4, 5);
class01 = em.create(Class, {
classId: '8764b861-90a6-42e5-9732-c0d9eb2f55f9',
classId: 'X2J9QT', // 8764b861-90a6-42e5-9732-c0d9eb2f55f9
displayName: 'class01',
teachers: teacherClass01,
students: studentsClass01,
@ -20,7 +20,7 @@ export function makeTestClasses(em: EntityManager, students: Student[], teachers
const teacherClass02: Teacher[] = teachers.slice(1, 2);
class02 = em.create(Class, {
classId: '34d484a1-295f-4e9f-bfdc-3e7a23d86a89',
classId: '7KLPMA', // 34d484a1-295f-4e9f-bfdc-3e7a23d86a89
displayName: 'class02',
teachers: teacherClass02,
students: studentsClass02,
@ -30,7 +30,7 @@ export function makeTestClasses(em: EntityManager, students: Student[], teachers
const teacherClass03: Teacher[] = teachers.slice(2, 3);
class03 = em.create(Class, {
classId: '80dcc3e0-1811-4091-9361-42c0eee91cfa',
classId: 'R0D3UZ', // 80dcc3e0-1811-4091-9361-42c0eee91cfa
displayName: 'class03',
teachers: teacherClass03,
students: studentsClass03,
@ -40,14 +40,14 @@ export function makeTestClasses(em: EntityManager, students: Student[], teachers
const teacherClass04: Teacher[] = teachers.slice(2, 3);
class04 = em.create(Class, {
classId: '33d03536-83b8-4880-9982-9bbf2f908ddf',
classId: 'Q8N5YC', // 33d03536-83b8-4880-9982-9bbf2f908ddf
displayName: 'class04',
teachers: teacherClass04,
students: studentsClass04,
});
classWithTestleerlingAndTestleerkracht = em.create(Class, {
classId: 'a75298b5-18aa-471d-8eeb-5d77eb989393',
classId: 'ZAV71B', // Was a75298b5-18aa-471d-8eeb-5d77eb989393
displayName: 'Testklasse',
teachers: [getTestleerkracht1()],
students: [getTestleerling1()],

View file

@ -14,6 +14,7 @@
const _router = useRouter(); // Zonder '_' gaf dit een linter error voor unused variable
const name: string = auth.authState.user!.profile.name!;
const email = auth.authState.user!.profile.email;
const initials: string = name
.split(" ")
.map((n) => n[0])
@ -90,31 +91,34 @@
<!-- >-->
<!-- {{ t("discussions") }}-->
<!-- </v-btn>-->
<v-menu open-on-hover>
<template v-slot:activator="{ props }">
<v-btn
v-bind="props"
icon
variant="text"
>
<v-icon
icon="mdi-translate"
size="small"
color="#0e6942"
></v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(language, index) in languages"
:key="index"
@click="changeLanguage(language.code)"
>
<v-list-item-title>{{ language.name }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-toolbar-items>
<v-menu
open-on-hover
open-on-click
>
<template v-slot:activator="{ props }">
<v-btn
v-bind="props"
icon
variant="text"
>
<v-icon
icon="mdi-translate"
size="small"
color="#0e6942"
></v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="(language, index) in languages"
:key="index"
@click="changeLanguage(language.code)"
>
<v-list-item-title>{{ language.name }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-spacer></v-spacer>
<v-dialog max-width="500">
<template v-slot:activator="{ props: activatorProps }">
@ -158,12 +162,43 @@
</v-card>
</template>
</v-dialog>
<v-avatar
size="large"
color="#0e6942"
class="user-button"
>{{ initials }}</v-avatar
>
<v-menu min-width="200px">
<template v-slot:activator="{ props }">
<v-btn
icon
v-bind="props"
>
<v-avatar
color="#0e6942"
size="large"
class="user-button"
>
<span>{{ initials }}</span>
</v-avatar>
</v-btn>
</template>
<v-card>
<v-card-text>
<div class="mx-auto text-center">
<v-avatar color="#0e6942">
<span class="text-h5">{{ initials }}</span>
</v-avatar>
<h3>{{ name }}</h3>
<p class="text-caption mt-1">{{ email }}</p>
<v-divider class="my-3"></v-divider>
<v-btn
variant="text"
rounded
append-icon="mdi-logout"
@click="performLogout"
to="/login"
>{{ t("logout") }}</v-btn
>
<v-divider class="my-3"></v-divider>
</div>
</v-card-text>
</v-card>
</v-menu>
</v-app-bar>
<v-navigation-drawer
v-model="drawer"
@ -248,6 +283,12 @@
text-transform: none;
}
.translate-button {
z-index: 1;
position: relative;
margin-left: 10px;
}
@media (max-width: 700px) {
.menu {
display: none;

View file

@ -84,7 +84,10 @@
</div>
</div>
<div class="container_right">
<v-menu open-on-hover>
<v-menu
open-on-hover
open-on-click
>
<template v-slot:activator="{ props }">
<v-btn
v-bind="props"

View file

@ -1,6 +1,20 @@
<script setup lang="ts">
import { useRouter } from "vue-router";
import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg";
import auth from "@/services/auth/auth-service.ts";
import { watch } from "vue";
const router = useRouter();
watch(
() => auth.isLoggedIn.value,
async (newVal) => {
if (newVal) {
await router.push("/user");
}
},
{ immediate: true },
);
async function loginAsStudent(): Promise<void> {
await auth.loginAs("student");
@ -9,10 +23,6 @@
async function loginAsTeacher(): Promise<void> {
await auth.loginAs("teacher");
}
async function performLogout(): Promise<void> {
await auth.logout();
}
</script>
<template>
@ -65,13 +75,6 @@
</div>
</ul>
</div>
<div v-if="auth.isLoggedIn.value">
<p>
You are currently logged in as {{ auth.authState.user!.profile.name }} ({{ auth.authState.activeRole }})
</p>
<v-btn @click="performLogout">Logout</v-btn>
<v-btn to="/user">home</v-btn>
</div>
</main>
</template>

View file

@ -22,8 +22,7 @@
) => { groupProgressMap: Map<number, number> };
}>();
const { t, locale } = useI18n();
const language = ref<Language>(locale.value as Language);
const { t } = useI18n();
const learningPath = ref();
// Get the user's username/id
const username = asyncComputed(async () => {
@ -38,7 +37,7 @@
const lpQueryResult = useGetLearningPathQuery(
computed(() => assignmentQueryResult.data.value?.assignment?.learningPath ?? ""),
computed(() => language.value),
computed(() => assignmentQueryResult.data.value?.assignment.language as Language),
);
const groupsQueryResult = useGroupsQuery(props.classId, props.assignmentId, true);
@ -100,7 +99,7 @@ language
>
<v-btn
v-if="lpData"
:to="`/learningPath/${lpData.hruid}/${language}/${lpData.startNode.learningobjectHruid}?forGroup=${group?.groupNumber}&assignmentNo=${assignmentId}&classId=${classId}`"
:to="`/learningPath/${lpData.hruid}/${assignmentQueryResult.data.value?.assignment.language}/${lpData.startNode.learningobjectHruid}?forGroup=${group?.groupNumber}&assignmentNo=${assignmentId}&classId=${classId}`"
variant="tonal"
color="primary"
>

View file

@ -19,8 +19,7 @@
) => { groupProgressMap: Map<number, number> };
}>();
const { t, locale } = useI18n();
const language = computed(() => locale.value);
const { t } = useI18n();
const groups = ref();
const learningPath = ref();
@ -29,7 +28,7 @@
// Get learning path object
const lpQueryResult = useGetLearningPathQuery(
computed(() => assignmentQueryResult.data.value?.assignment?.learningPath ?? ""),
computed(() => language.value as Language),
computed(() => assignmentQueryResult.data.value?.assignment.language as Language),
);
// Get all the groups withing the assignment
@ -38,9 +37,9 @@
/* Crashes right now cause api data has inexistent hruid TODO: uncomment later and use it in progress bar
Const {groupProgressMap} = props.useGroupsWithProgress(
groups,
learningPath,
language
groups,
learningPath,
language
);
*/
@ -121,7 +120,7 @@ Const {groupProgressMap} = props.useGroupsWithProgress(
>
<v-btn
v-if="lpData"
:to="`/learningPath/${lpData.hruid}/${language}/${lpData.startNode.learningobjectHruid}?assignmentNo=${assignmentId}&classId=${classId}`"
:to="`/learningPath/${lpData.hruid}/${assignmentQueryResult.data.value?.assignment.language}/${lpData.startNode.learningobjectHruid}?assignmentNo=${assignmentId}&classId=${classId}`"
variant="tonal"
color="primary"
>
@ -203,8 +202,8 @@ Const {groupProgressMap} = props.useGroupsWithProgress(
<v-btn
color="primary"
@click="dialog = false"
>Close</v-btn
>
>Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>

View file

@ -143,6 +143,13 @@
box-sizing: border-box;
}
h1 {
color: #0e6942;
text-transform: uppercase;
font-weight: bolder;
font-size: 50px;
}
.center-btn {
display: block;
margin-left: auto;

View file

@ -95,6 +95,13 @@
justify-content: center;
}
h1 {
color: #0e6942;
text-transform: uppercase;
font-weight: bolder;
font-size: 50px;
}
.dropdowns {
display: flex;
justify-content: space-between;

View file

@ -287,6 +287,8 @@
<template v-slot:default>
<v-btn
class="button-in-nav"
width="100%"
:color="COLORS.teacherExclusive"
@click="assign()"
>{{ t("assignLearningPath") }}</v-btn
>

View file

@ -5,7 +5,7 @@ describe("AssignmentController Tests", () => {
let controller: AssignmentController;
beforeEach(() => {
controller = new AssignmentController("8764b861-90a6-42e5-9732-c0d9eb2f55f9"); // Example class ID
controller = new AssignmentController("X2J9QT"); // Example class ID (class01)
});
it("should fetch all assignments", async () => {

View file

@ -3,7 +3,7 @@ import { GroupController } from "../../src/controllers/groups";
describe("Test controller groups", () => {
it("Get groups", async () => {
const classId = "8764b861-90a6-42e5-9732-c0d9eb2f55f9";
const classId = "X2J9QT"; // Class01
const assignmentNumber = 21000;
const controller = new GroupController(classId, assignmentNumber);

View file

@ -5,7 +5,7 @@ import { Language } from "../../src/data-objects/language";
describe("Test controller submissions", () => {
it("Get submission by number", async () => {
const hruid = "id03";
const classId = "8764b861-90a6-42e5-9732-c0d9eb2f55f9";
const classId = "X2J9QT"; // Class01
const controller = new SubmissionController(hruid);
const data = await controller.getByNumber(Language.English, 1, classId, 1, 1, 1);

9640
package-lock.json generated

File diff suppressed because it is too large Load diff