Merge pull request #199 from SELab-2/feat/class-functionality-fix-bugs
fix: teacher invitation en andere bugs in class functionality
This commit is contained in:
commit
e31c6a060d
12 changed files with 166 additions and 48 deletions
|
@ -1,6 +1,6 @@
|
|||
import { Request, Response } from 'express';
|
||||
import { requireFields } from './error-helper';
|
||||
import { createInvitation, deleteInvitation, getAllInvitations, getInvitation, updateInvitation } from '../services/teacher-invitations';
|
||||
import { requireFields } from './error-helper.js';
|
||||
import { createInvitation, deleteInvitation, getAllInvitations, getInvitation, updateInvitation } from '../services/teacher-invitations.js';
|
||||
import { TeacherInvitationData } from '@dwengo-1/common/interfaces/teacher-invitation';
|
||||
|
||||
export async function getAllInvitationsHandler(req: Request, res: Response): Promise<void> {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { getGroupRepository } from '../data/repositories.js';
|
|||
import { AssignmentDTO } from '@dwengo-1/common/interfaces/assignment';
|
||||
import { Class } from '../entities/classes/class.entity.js';
|
||||
import { StudentDTO } from '@dwengo-1/common/interfaces/student';
|
||||
import { mapToClassDTO } from './class';
|
||||
import { mapToClassDTO } from './class.js';
|
||||
|
||||
export function mapToGroup(groupDto: GroupDTO, clazz: Class): Group {
|
||||
const assignmentDto = groupDto.assignment as AssignmentDTO;
|
||||
|
|
|
@ -2,9 +2,9 @@ import { Submission } from '../entities/assignments/submission.entity.js';
|
|||
import { mapToGroupDTO } from './group.js';
|
||||
import { mapToStudentDTO } from './student.js';
|
||||
import { SubmissionDTO, SubmissionDTOId } from '@dwengo-1/common/interfaces/submission';
|
||||
import { getSubmissionRepository } from '../data/repositories';
|
||||
import { Student } from '../entities/users/student.entity';
|
||||
import { Group } from '../entities/assignments/group.entity';
|
||||
import { getSubmissionRepository } from '../data/repositories.js';
|
||||
import { Student } from '../entities/users/student.entity.js';
|
||||
import { Group } from '../entities/assignments/group.entity.js';
|
||||
|
||||
export function mapToSubmissionDTO(submission: Submission): SubmissionDTO {
|
||||
return {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { TeacherInvitation } from '../entities/classes/teacher-invitation.entity.js';
|
||||
import { mapToUserDTO } from './user.js';
|
||||
import { TeacherInvitationDTO } from '@dwengo-1/common/interfaces/teacher-invitation';
|
||||
import { getTeacherInvitationRepository } from '../data/repositories';
|
||||
import { Teacher } from '../entities/users/teacher.entity';
|
||||
import { Class } from '../entities/classes/class.entity';
|
||||
import { getTeacherInvitationRepository } from '../data/repositories.js';
|
||||
import { Teacher } from '../entities/users/teacher.entity.js';
|
||||
import { Class } from '../entities/classes/class.entity.js';
|
||||
import { ClassStatus } from '@dwengo-1/common/util/class-join-request';
|
||||
|
||||
export function mapToTeacherInvitationDTO(invitation: TeacherInvitation): TeacherInvitationDTO {
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
getAllInvitationsHandler,
|
||||
getInvitationHandler,
|
||||
updateInvitationHandler,
|
||||
} from '../controllers/teacher-invitations';
|
||||
} from '../controllers/teacher-invitations.js';
|
||||
|
||||
const router = express.Router({ mergeParams: true });
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import { AnswerDTO, AnswerId } from '@dwengo-1/common/interfaces/answer';
|
|||
import { mapToAssignment } from '../interfaces/assignment.js';
|
||||
import { AssignmentDTO } from '@dwengo-1/common/interfaces/assignment';
|
||||
import { fetchStudent } from './students.js';
|
||||
import { NotFoundException } from '../exceptions/not-found-exception';
|
||||
import { NotFoundException } from '../exceptions/not-found-exception.js';
|
||||
import { FALLBACK_VERSION_NUM } from '../config.js';
|
||||
|
||||
export async function getQuestionsAboutLearningObjectInAssignment(
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { fetchTeacher } from './teachers';
|
||||
import { getTeacherInvitationRepository } from '../data/repositories';
|
||||
import { mapToInvitation, mapToTeacherInvitationDTO } from '../interfaces/teacher-invitation';
|
||||
import { addClassTeacher, fetchClass } from './classes';
|
||||
import { fetchTeacher } from './teachers.js';
|
||||
import { getTeacherInvitationRepository } from '../data/repositories.js';
|
||||
import { mapToInvitation, mapToTeacherInvitationDTO } from '../interfaces/teacher-invitation.js';
|
||||
import { addClassTeacher, fetchClass } from './classes.js';
|
||||
import { TeacherInvitationData, TeacherInvitationDTO } from '@dwengo-1/common/interfaces/teacher-invitation';
|
||||
import { ConflictException } from '../exceptions/conflict-exception';
|
||||
import { NotFoundException } from '../exceptions/not-found-exception';
|
||||
import { TeacherInvitation } from '../entities/classes/teacher-invitation.entity';
|
||||
import { ConflictException } from '../exceptions/conflict-exception.js';
|
||||
import { NotFoundException } from '../exceptions/not-found-exception.js';
|
||||
import { TeacherInvitation } from '../entities/classes/teacher-invitation.entity.js';
|
||||
import { ClassStatus } from '@dwengo-1/common/util/class-join-request';
|
||||
|
||||
export async function getAllInvitations(username: string, sent: boolean): Promise<TeacherInvitationDTO[]> {
|
||||
|
|
|
@ -11,10 +11,11 @@ export interface TeacherInvitationResponse {
|
|||
|
||||
export class TeacherInvitationController extends BaseController {
|
||||
constructor() {
|
||||
super("teachers/invitations");
|
||||
super("teacher/invitations");
|
||||
}
|
||||
|
||||
async getAll(username: string, sent: boolean): Promise<TeacherInvitationsResponse> {
|
||||
async getAll(username: string, s: boolean): Promise<TeacherInvitationsResponse> {
|
||||
const sent = s.toString();
|
||||
return this.get<TeacherInvitationsResponse>(`/${username}`, { sent });
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,35 @@
|
|||
import type { QuestionId } from "@dwengo-1/common/dist/interfaces/question.ts";
|
||||
import { type MaybeRefOrGetter, toValue } from "vue";
|
||||
import { useMutation, type UseMutationReturnType, useQuery, type UseQueryReturnType } from "@tanstack/vue-query";
|
||||
import { AnswerController, type AnswerResponse, type AnswersResponse } from "@/controllers/answers.ts";
|
||||
import type { AnswerData } from "@dwengo-1/common/dist/interfaces/answer.ts";
|
||||
import {computed, type MaybeRefOrGetter, toValue} from "vue";
|
||||
import {
|
||||
useMutation,
|
||||
type UseMutationReturnType,
|
||||
useQuery,
|
||||
type UseQueryReturnType,
|
||||
useQueryClient,
|
||||
} from "@tanstack/vue-query";
|
||||
import {
|
||||
AnswerController,
|
||||
type AnswerResponse,
|
||||
type AnswersResponse,
|
||||
} from "@/controllers/answers.ts";
|
||||
import type { AnswerData } from "@dwengo-1/common/interfaces/answer";
|
||||
import type {QuestionId} from "@dwengo-1/common/interfaces/question";
|
||||
|
||||
// TODO caching
|
||||
/** 🔑 Query keys */
|
||||
export function answersQueryKey(questionId: QuestionId, full: boolean): [string, string, number, string, number, boolean] {
|
||||
const loId = questionId.learningObjectIdentifier;
|
||||
return ["answers", loId.hruid, loId.version!, loId.language, questionId.sequenceNumber, full];
|
||||
}
|
||||
export function answerQueryKey(questionId: QuestionId, sequenceNumber: number): [string, string, number, string, number, number] {
|
||||
const loId = questionId.learningObjectIdentifier;
|
||||
return ["answer", loId.hruid, loId.version!, loId.language, questionId.sequenceNumber, sequenceNumber];
|
||||
}
|
||||
|
||||
export function useAnswersQuery(
|
||||
questionId: MaybeRefOrGetter<QuestionId>,
|
||||
full: MaybeRefOrGetter<boolean> = true,
|
||||
): UseQueryReturnType<AnswersResponse, Error> {
|
||||
return useQuery({
|
||||
queryKey: computed(() => answersQueryKey(toValue(questionId), toValue(full))),
|
||||
queryFn: async () => new AnswerController(toValue(questionId)).getAll(toValue(full)),
|
||||
enabled: () => Boolean(toValue(questionId)),
|
||||
});
|
||||
|
@ -21,31 +40,69 @@ export function useAnswerQuery(
|
|||
sequenceNumber: MaybeRefOrGetter<number>,
|
||||
): UseQueryReturnType<AnswerResponse, Error> {
|
||||
return useQuery({
|
||||
queryKey: computed(() => answerQueryKey(toValue(questionId), toValue(sequenceNumber))),
|
||||
queryFn: async () => new AnswerController(toValue(questionId)).getBy(toValue(sequenceNumber)),
|
||||
enabled: () => Boolean(toValue(questionId)),
|
||||
enabled: () => Boolean(toValue(questionId)) && Boolean(toValue(sequenceNumber)),
|
||||
});
|
||||
}
|
||||
|
||||
export function useCreateAnswerMutation(
|
||||
questionId: MaybeRefOrGetter<QuestionId>,
|
||||
): UseMutationReturnType<AnswerResponse, Error, AnswerData, unknown> {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data) => new AnswerController(toValue(questionId)).create(data),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: answersQueryKey(toValue(questionId), true),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: answersQueryKey(toValue(questionId), false),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteAnswerMutation(
|
||||
questionId: MaybeRefOrGetter<QuestionId>,
|
||||
): UseMutationReturnType<AnswerResponse, Error, number, unknown> {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (seq) => new AnswerController(toValue(questionId)).remove(seq),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: answersQueryKey(toValue(questionId), true),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: answersQueryKey(toValue(questionId), false),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateAnswerMutation(
|
||||
questionId: MaybeRefOrGetter<QuestionId>,
|
||||
): UseMutationReturnType<AnswerResponse, Error, { answerData: AnswerData; seq: number }, unknown> {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data, seq) => new AnswerController(toValue(questionId)).update(seq, data),
|
||||
mutationFn: async ({ answerData, seq }) =>
|
||||
new AnswerController(toValue(questionId)).update(seq, answerData),
|
||||
onSuccess: async (_, { seq }) => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: answerQueryKey(toValue(questionId), seq),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: answersQueryKey(toValue(questionId), true),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: answersQueryKey(toValue(questionId), true),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: answersQueryKey(toValue(questionId), false),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@ export function questionsQueryKey(
|
|||
loId: LearningObjectIdentifierDTO,
|
||||
full: boolean,
|
||||
): [string, string, number, string, boolean] {
|
||||
return ["questions", loId.hruid, loId.version, loId.language, full];
|
||||
return ["questions", loId.hruid, loId.version!, loId.language, full];
|
||||
}
|
||||
|
||||
export function questionQueryKey(questionId: QuestionId): [string, string, number, string, number] {
|
||||
const loId = questionId.learningObjectIdentifier;
|
||||
return ["question", loId.hruid, loId.version, loId.language, questionId.sequenceNumber];
|
||||
return ["question", loId.hruid, loId.version!, loId.language, questionId.sequenceNumber];
|
||||
}
|
||||
|
||||
export function useQuestionsQuery(
|
||||
|
@ -39,7 +39,7 @@ export function useQuestionQuery(
|
|||
const loId = toValue(questionId).learningObjectIdentifier;
|
||||
const sequenceNumber = toValue(questionId).sequenceNumber;
|
||||
return useQuery({
|
||||
queryKey: computed(() => questionQueryKey(loId, sequenceNumber)),
|
||||
queryKey: computed(() => questionQueryKey(toValue(questionId))),
|
||||
queryFn: async () => new QuestionController(loId).getBy(sequenceNumber),
|
||||
enabled: () => Boolean(toValue(questionId)),
|
||||
});
|
||||
|
@ -55,6 +55,7 @@ export function useCreateQuestionMutation(
|
|||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), true) });
|
||||
await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), false) });
|
||||
await queryClient.invalidateQueries({ queryKey: ["answers"] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -88,6 +89,8 @@ export function useDeleteQuestionMutation(
|
|||
await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), true) });
|
||||
await queryClient.invalidateQueries({ queryKey: questionsQueryKey(toValue(loId), false) });
|
||||
await queryClient.invalidateQueries({ queryKey: questionQueryKey(toValue(questionId)) });
|
||||
await queryClient.invalidateQueries({ queryKey: ["answers"] });
|
||||
await queryClient.invalidateQueries({ queryKey: ["answer"] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,36 +1,56 @@
|
|||
import { useMutation, useQuery, type UseMutationReturnType, type UseQueryReturnType } from "@tanstack/vue-query";
|
||||
import { computed, toValue } from "vue";
|
||||
import {
|
||||
useMutation,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
type UseMutationReturnType,
|
||||
type UseQueryReturnType,
|
||||
} from "@tanstack/vue-query";
|
||||
import { toValue } from "vue";
|
||||
import type { MaybeRefOrGetter } from "vue";
|
||||
import {
|
||||
TeacherInvitationController,
|
||||
type TeacherInvitationResponse,
|
||||
type TeacherInvitationsResponse,
|
||||
} from "@/controllers/teacher-invitations.ts";
|
||||
} from "@/controllers/teacher-invitations";
|
||||
import type { TeacherInvitationData } from "@dwengo-1/common/interfaces/teacher-invitation";
|
||||
import type { TeacherDTO } from "@dwengo-1/common/interfaces/teacher";
|
||||
|
||||
const controller = new TeacherInvitationController();
|
||||
|
||||
/** 🔑 Query keys */
|
||||
export function teacherInvitationsSentQueryKey(username: string): [string, string, string] {
|
||||
return ["teacher-invitations", "sent", username];
|
||||
}
|
||||
|
||||
export function teacherInvitationsReceivedQueryKey(username: string): [string, string, string] {
|
||||
return ["teacher-invitations", "received", username ];
|
||||
}
|
||||
|
||||
export function teacherInvitationQueryKey(data: TeacherInvitationData): [string, string, string, string] {
|
||||
return ["teacher-invitation", data.sender, data.receiver, data.class];
|
||||
}
|
||||
|
||||
/**
|
||||
All the invitations the teacher sent
|
||||
**/
|
||||
* All the invitations the teacher sent
|
||||
*/
|
||||
export function useTeacherInvitationsSentQuery(
|
||||
username: MaybeRefOrGetter<string | undefined>,
|
||||
): UseQueryReturnType<TeacherInvitationsResponse, Error> {
|
||||
return useQuery({
|
||||
queryFn: computed(async () => controller.getAll(toValue(username), true)),
|
||||
queryKey: teacherInvitationsSentQueryKey(toValue(username)!),
|
||||
queryFn: async () => controller.getAll(toValue(username)!, true),
|
||||
enabled: () => Boolean(toValue(username)),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
All the pending invitations sent to this teacher
|
||||
* All the pending invitations sent to this teacher
|
||||
*/
|
||||
export function useTeacherInvitationsReceivedQuery(
|
||||
username: MaybeRefOrGetter<string | undefined>,
|
||||
): UseQueryReturnType<TeacherInvitationsResponse, Error> {
|
||||
return useQuery({
|
||||
queryFn: computed(async () => controller.getAll(toValue(username), false)),
|
||||
queryKey: teacherInvitationsReceivedQueryKey(toValue(username)!),
|
||||
queryFn: async () => controller.getAll(toValue(username)!, false),
|
||||
enabled: () => Boolean(toValue(username)),
|
||||
});
|
||||
}
|
||||
|
@ -39,7 +59,8 @@ export function useTeacherInvitationQuery(
|
|||
data: MaybeRefOrGetter<TeacherInvitationData | undefined>,
|
||||
): UseQueryReturnType<TeacherInvitationResponse, Error> {
|
||||
return useQuery({
|
||||
queryFn: computed(async () => controller.getBy(toValue(data))),
|
||||
queryKey: teacherInvitationQueryKey(toValue(data)!),
|
||||
queryFn: async () => controller.getBy(toValue(data)!),
|
||||
enabled: () => Boolean(toValue(data)),
|
||||
});
|
||||
}
|
||||
|
@ -47,32 +68,68 @@ export function useTeacherInvitationQuery(
|
|||
export function useCreateTeacherInvitationMutation(): UseMutationReturnType<
|
||||
TeacherInvitationResponse,
|
||||
Error,
|
||||
TeacherDTO,
|
||||
TeacherInvitationData,
|
||||
unknown
|
||||
> {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: TeacherInvitationData) => controller.create(data),
|
||||
mutationFn: async (data) => controller.create(data),
|
||||
onSuccess: async (_, data) => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: teacherInvitationsSentQueryKey(data.sender),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: teacherInvitationsReceivedQueryKey(data.receiver),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useRespondTeacherInvitationMutation(): UseMutationReturnType<
|
||||
TeacherInvitationResponse,
|
||||
Error,
|
||||
TeacherDTO,
|
||||
TeacherInvitationData,
|
||||
unknown
|
||||
> {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: TeacherInvitationData) => controller.respond(data),
|
||||
mutationFn: async (data) => controller.respond(data),
|
||||
onSuccess: async (_, data) => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: teacherInvitationsSentQueryKey(data.sender),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: teacherInvitationsReceivedQueryKey(data.receiver),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: teacherInvitationQueryKey(data),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteTeacherInvitationMutation(): UseMutationReturnType<
|
||||
TeacherInvitationResponse,
|
||||
Error,
|
||||
TeacherDTO,
|
||||
TeacherInvitationData,
|
||||
unknown
|
||||
> {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: TeacherInvitationData) => controller.remove(data),
|
||||
mutationFn: async (data) => controller.remove(data),
|
||||
onSuccess: async (_, data) => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: teacherInvitationsSentQueryKey(data.sender),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: teacherInvitationsReceivedQueryKey(data.receiver),
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: teacherInvitationQueryKey(data),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useQuery, type UseQueryReturnType } from "@tanstack/vue-query";
|
||||
import { type MaybeRefOrGetter, toValue } from "vue";
|
||||
import type { Theme } from "@dwengo-1/interfaces/theme";
|
||||
import { getThemeController } from "@/controllers/controllers.ts";
|
||||
import type {Theme} from "@dwengo-1/common/interfaces/theme";
|
||||
|
||||
const themeController = getThemeController();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue