diff --git a/backend/src/controllers/teachers.ts b/backend/src/controllers/teachers.ts index 2ef63b65..d3b6a4db 100644 --- a/backend/src/controllers/teachers.ts +++ b/backend/src/controllers/teachers.ts @@ -2,15 +2,16 @@ import { Request, Response } from 'express'; import { createTeacher, deleteTeacher, - fetchTeacherByUsername, + getTeacherByUsername, getClassesByTeacher, getClassIdsByTeacher, getAllTeachers, - getAllTeachersIds, getStudentsByTeacher, getStudentIdsByTeacher + getAllTeachersIds, getStudentsByTeacher, getStudentIdsByTeacher, getQuestionsByTeacher, getQuestionIdsByTeacher } from '../services/teachers.js'; import {TeacherDTO} from "../interfaces/teacher"; import {ClassDTO} from "../interfaces/class"; import {StudentDTO} from "../interfaces/student"; +import {QuestionDTO, QuestionId} from "../interfaces/question"; export async function getTeacherHandler(req: Request, res: Response): Promise { try { @@ -18,7 +19,7 @@ export async function getTeacherHandler(req: Request, res: Response): Promise { + try { + const username = req.params.username as string; + const full = req.query.full === 'true'; + + if (!username) { + res.status(400).json({ error: 'Missing required field: username' }); + return; + } + + let questions: QuestionDTO[] | QuestionId[]; + + if (full) questions = await getQuestionsByTeacher(username); + else questions = await getQuestionIdsByTeacher(username); + + res.status(201).json(questions); + } catch (error) { + console.error('Error fetching questions by teacher:', error); + res.status(500).json({ error: 'Internal server error' }); + } +} + + diff --git a/backend/src/data/content/learning-object-repository.ts b/backend/src/data/content/learning-object-repository.ts index 5d30b956..d8b07943 100644 --- a/backend/src/data/content/learning-object-repository.ts +++ b/backend/src/data/content/learning-object-repository.ts @@ -1,6 +1,7 @@ import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; import { LearningObject } from '../../entities/content/learning-object.entity.js'; import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js'; +import {Teacher} from "../../entities/users/teacher.entity"; export class LearningObjectRepository extends DwengoEntityRepository { public findByIdentifier( @@ -13,4 +14,11 @@ export class LearningObjectRepository extends DwengoEntityRepository { + return this.find( + { admins: teacher }, + { populate: ['admins'] } // Make sure to load admin relations + ); + } } diff --git a/backend/src/data/questions/question-repository.ts b/backend/src/data/questions/question-repository.ts index 517305f1..05430ddd 100644 --- a/backend/src/data/questions/question-repository.ts +++ b/backend/src/data/questions/question-repository.ts @@ -2,6 +2,7 @@ import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; import { Question } from '../../entities/questions/question.entity.js'; import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js'; import { Student } from '../../entities/users/student.entity.js'; +import {LearningObject} from "../../entities/content/learning-object.entity"; export class QuestionRepository extends DwengoEntityRepository { public createQuestion(question: { @@ -42,4 +43,17 @@ export class QuestionRepository extends DwengoEntityRepository { sequenceNumber: sequenceNumber, }); } + + public async findAllByLearningObjects(learningObjects: LearningObject[]): Promise { + const objectIdentifiers = learningObjects.map(lo => ({ + learningObjectHruid: lo.hruid, + learningObjectLanguage: lo.language, + learningObjectVersion: lo.version + })); + + return this.findAll({ + where: { $or: objectIdentifiers }, + orderBy: { timestamp: 'ASC' }, + }); + } } diff --git a/backend/src/interfaces/question.ts b/backend/src/interfaces/question.ts new file mode 100644 index 00000000..1a8c914a --- /dev/null +++ b/backend/src/interfaces/question.ts @@ -0,0 +1,41 @@ +import {Question} from "../entities/questions/question.entity"; +import {Enum, PrimaryKey} from "@mikro-orm/core"; +import {Language} from "../entities/content/language"; + +export interface QuestionDTO { + learningObjectHruid: string; + learningObjectLanguage: string; + learningObjectVersion: string; + sequenceNumber: number; + authorUsername: string; + timestamp: string; + content: string; + endpoints?: { + classes: string; + questions: string; + invitations: string; + groups: string; + }; +} + +/** + * Convert a Question entity to a DTO format. + */ +export function mapToQuestionDTO(question: Question): QuestionDTO { + return { + learningObjectHruid: question.learningObjectHruid, + learningObjectLanguage: question.learningObjectLanguage, + learningObjectVersion: question.learningObjectVersion, + sequenceNumber: question.sequenceNumber, + authorUsername: question.author.username, + timestamp: question.timestamp.toISOString(), + content: question.content, + }; +} + +export interface QuestionId { + learningObjectHruid: string, + learningObjectLanguage: Language, + learningObjectVersion: string, + sequenceNumber: number +} diff --git a/backend/src/routes/teachers.ts b/backend/src/routes/teachers.ts index 338ac0b8..2a29897b 100644 --- a/backend/src/routes/teachers.ts +++ b/backend/src/routes/teachers.ts @@ -3,7 +3,7 @@ import { createTeacherHandler, deleteTeacherHandler, getTeacherClassHandler, - getTeacherHandler, getTeacherStudentHandler + getTeacherHandler, getTeacherQuestionHandler, getTeacherStudentHandler } from "../controllers/teachers.js"; const router = express.Router(); @@ -18,14 +18,7 @@ router.get('/:username/classes', getTeacherClassHandler); router.get('/:username/students', getTeacherStudentHandler); -// the questions students asked a teacher -router.get('/:id/questions', (req, res) => { - res.json({ - questions: [ - '0' - ], - }); -}); +router.get('/:username/questions', getTeacherQuestionHandler); // invitations to other classes a teacher received router.get('/:id/invitations', (req, res) => { @@ -36,14 +29,6 @@ router.get('/:id/invitations', (req, res) => { }); }); -// a list with ids of classes a teacher is in -router.get('/:id/classes', (req, res) => { - res.json({ - classes: [ - '0' - ], - }); -}); export default router diff --git a/backend/src/services/teachers.ts b/backend/src/services/teachers.ts index 8382e4b3..4b8affc5 100644 --- a/backend/src/services/teachers.ts +++ b/backend/src/services/teachers.ts @@ -1,9 +1,15 @@ -import {getClassRepository, getTeacherRepository} from "../data/repositories.js"; +import { + getClassRepository, + getLearningObjectRepository, + getQuestionRepository, + getTeacherRepository +} from "../data/repositories.js"; import {mapToTeacher, mapToTeacherDTO, TeacherDTO} from "../interfaces/teacher.js"; import { Teacher } from "../entities/users/teacher.entity"; import {ClassDTO, mapToClassDTO} from "../interfaces/class"; import {getClassStudents, getClassStudentsIds} from "./class"; import {StudentDTO} from "../interfaces/student"; +import {mapToQuestionDTO, QuestionDTO, QuestionId} from "../interfaces/question"; async function fetchAllTeachers(): Promise { @@ -29,7 +35,7 @@ export async function createTeacher(teacherData: TeacherDTO): Promise { return newTeacher; } -export async function fetchTeacherByUsername(username: string): Promise { +export async function getTeacherByUsername(username: string): Promise { const teacherRepository = getTeacherRepository(); const teacher = await teacherRepository.findByUsername(username); @@ -84,5 +90,42 @@ export async function getStudentIdsByTeacher(): Promise { return await fetchStudentsByTeacher(username).map((student) => student.username); } +async function fetchTeacherQuestions(username: string): Promise { + const learningObjectRepository = getLearningObjectRepository(); + const questionRepository = getQuestionRepository(); + + const teacher = getTeacherByUsername(username); + if (!teacher) { + throw new Error(`Teacher with username '${username}' not found.`); + } + + // Find all learning objects that this teacher manages + const learningObjects = await learningObjectRepository.findAllByTeacher(teacher); + + // Fetch all questions related to these learning objects + const questions = await questionRepository.findAllByLearningObjects(learningObjects); + + return questions.map(mapToQuestionDTO); +} + +export async function getQuestionsByTeacher(username: string): Promise { + return await fetchTeacherQuestions(username); +} + +export async function getQuestionIdsByTeacher(username: string): Promise { + const questions = await fetchTeacherQuestions(username); + + return questions.map((question) => ({ + learningObjectHruid: question.learningObjectHruid, + learningObjectLanguage: question.learningObjectLanguage, + learningObjectVersion: question.learningObjectVersion, + sequenceNumber: question.sequenceNumber + })); +} + + + + +