UNPKG

@defikitdotnet/education-module-ai

Version:
716 lines (701 loc) 39 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.StudentController = void 0; var controller_1 = require("../decorators/controller"); var bcrypt_1 = __importDefault(require("bcrypt")); var SqliteAdapter_1 = require("../database/SqliteAdapter"); var StudentRepository_1 = require("../repositories/StudentRepository"); var auth_1 = require("../middleware/auth"); var QuizService_1 = require("../services/QuizService"); var QuizQuestionService_1 = require("../services/QuizQuestionService"); var QuizSubmissionService_1 = require("../services/QuizSubmissionService"); var errorHandler_1 = require("../middleware/errorHandler"); var jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); /** * Student Controller - Handles student access, PROFILE management, and LOGIN */ var StudentController = /** @class */ (function () { function StudentController(mainDatabaseAdapter, quizService, quizQuestionService, quizSubmissionService, studentRepository) { this.quizService = quizService; this.quizQuestionService = quizQuestionService; this.quizSubmissionService = quizSubmissionService; this.educationModuleAdapter = null; // Define path for BaseController implementation this.path = "/api/student"; this.mainDatabaseAdapter = mainDatabaseAdapter; this.studentRepository = studentRepository; console.log("StudentController initialized with required services and StudentRepository"); } StudentController.prototype.setEducationModuleAdapter = function (adapter) { this.educationModuleAdapter = adapter; console.log("EducationModuleAdapter set in StudentController"); }; // Required for BaseController implementation StudentController.prototype.initRoutes = function () { // Routes are initialized through decorators }; /** * Register a new student profile */ StudentController.prototype.registerStudent = function (req, res, next) { return __awaiter(this, void 0, void 0, function () { var _a, name, email, password, tempDbAdapter, existingStudent, createdStudent, _b, passwordHash, safeStudent, error_1; return __generator(this, function (_c) { switch (_c.label) { case 0: _a = req.body, name = _a.name, email = _a.email, password = _a.password; if (!name || !email || !password) { return [2 /*return*/, next(new errorHandler_1.ApiError("Missing required fields: name, email, password", 400))]; } tempDbAdapter = null; _c.label = 1; case 1: _c.trys.push([1, 4, 5, 6]); return [4 /*yield*/, this.studentRepository.findByEmail(email)]; case 2: existingStudent = _c.sent(); if (existingStudent) { return [2 /*return*/, next(new errorHandler_1.ApiError("Email already in use", 409))]; // Use error handler middleware } return [4 /*yield*/, this.studentRepository.create({ // id: studentId, // Removed - Repository likely generates ID name: name, email: email, password: password, // Pass the raw password // passwordHash, // Removed - Repository likely handles hashing createdAt: new Date(), // Add createdAt back as repository expects it })]; case 3: createdStudent = _c.sent(); _b = createdStudent || {}, passwordHash = _b.passwordHash, safeStudent = __rest(_b, ["passwordHash"]); // Use default empty object {} if createdStudent is unexpectedly null/undefined // Check if student creation actually succeeded (repository might return null on failure) if (!createdStudent) { console.error("[StudentController] StudentRepository.create returned null/undefined for email ".concat(email)); return [2 /*return*/, next(new errorHandler_1.ApiError("Failed to create student record.", 500))]; } res.status(201).json({ message: "Student registered successfully", student: safeStudent, // Return the created student data (without hash) }); return [3 /*break*/, 6]; case 4: error_1 = _c.sent(); console.error("[StudentController] Error registering student ".concat(email, ":"), error_1); next(error_1); // Pass error to the centralized handler return [3 /*break*/, 6]; case 5: return [7 /*endfinally*/]; case 6: return [2 /*return*/]; } }); }); }; /** * Get published content for students */ StudentController.prototype.getPublishedContent = function (req, res) { return __awaiter(this, void 0, void 0, function () { var _a, subject_1, level_1, publishedContent, contentList, contentStore, error_2; return __generator(this, function (_b) { switch (_b.label) { case 0: _b.trys.push([0, 4, , 5]); _a = req.query, subject_1 = _a.subject, level_1 = _a.level; publishedContent = []; if (!this.educationModuleAdapter) return [3 /*break*/, 2]; return [4 /*yield*/, this.educationModuleAdapter.getEducationalContents()]; case 1: contentList = _b.sent(); // Filter to only published content - safely check if property exists publishedContent = contentList.filter(function (c) { return "isPublished" in c && c.isPublished === true; }); // Apply additional filters if specified if (subject_1) { publishedContent = publishedContent.filter(function (c) { return c.subject === subject_1; }); } if (level_1) { publishedContent = publishedContent.filter(function (c) { return c.level === level_1; }); } return [3 /*break*/, 3]; case 2: contentStore = {}; publishedContent = Object.values(contentStore).filter(function (c) { return "isPublished" in c && c.isPublished === true; }); if (subject_1) { publishedContent = publishedContent.filter(function (c) { return c.subject === subject_1; }); } if (level_1) { publishedContent = publishedContent.filter(function (c) { return c.level === level_1; }); } _b.label = 3; case 3: res.status(200).json({ data: publishedContent }); return [3 /*break*/, 5]; case 4: error_2 = _b.sent(); console.error("Error retrieving published content:", error_2); res.status(500).json({ error: "Failed to retrieve published content" }); return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }); }; /** * Get specific content by ID */ StudentController.prototype.getContentById = function (req, res) { return __awaiter(this, void 0, void 0, function () { var contentId, studentId, content, contentStore, error_3; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 4, , 5]); contentId = req.params.contentId; studentId = req.query.studentId || "anonymous"; content = void 0; if (!this.educationModuleAdapter) return [3 /*break*/, 2]; return [4 /*yield*/, this.educationModuleAdapter.getEducationalContent(contentId)]; case 1: content = _a.sent(); return [3 /*break*/, 3]; case 2: contentStore = {}; content = contentStore[contentId]; _a.label = 3; case 3: if (!content) { res.status(404).json({ error: "Content not found" }); return [2 /*return*/]; } // Safely check if property exists before comparing if ("isPublished" in content && content.isPublished === false) { res .status(403) .json({ error: "This content is not available for students" }); return [2 /*return*/]; } // Record student access // await pluginManager.notifyStudentAccessed(contentId, studentId); res.status(200).json({ data: content }); return [3 /*break*/, 5]; case 4: error_3 = _a.sent(); console.error("Error retrieving content:", error_3); res.status(500).json({ error: "Failed to retrieve content" }); return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }); }; /** * Submit assessment/quiz answers (Old endpoint - likely unused) */ StudentController.prototype.submitAssessment = function (req, res) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { /* // Entire method body commented out as it references unused/removed types try { const { contentId } = req.params; const { studentId, answers } = req.body; if (!studentId) { res.status(400).json({ error: "Student ID is required" }); return; } if (!answers || !Array.isArray(answers)) { res.status(400).json({ error: "Answers must be provided as an array" }); return; } // Get the content to check answers against let content; if (this.educationModuleAdapter) { content = await this.educationModuleAdapter.getEducationalContent(contentId); } else { // In-memory implementation (would be empty in a real scenario) const contentStore: Record<string, EducationalContentResource> = {}; content = contentStore[contentId]; } if (!content) { res.status(404).json({ error: "Content not found" }); return; } // Safely check if property exists before comparing if ('isPublished' in content && content.isPublished === false) { res.status(403).json({ error: "This content is not available for students" }); return; } // Process the answers const contentHasQuestions = hasQuestions(content); const results = { contentId, studentId, timestamp: new Date(), score: 0, totalQuestions: contentHasQuestions ? (content as ContentWithQuestions).questions.length : 0, correctAnswers: 0, answerDetails: [] as Array<{ questionIndex: number, correct: boolean, studentAnswer: string, correctAnswer?: string, explanation?: string }> }; // Check answers if content has questions if (contentHasQuestions) { // Calculate score const contentWithQuestions = content as ContentWithQuestions; answers.forEach((answer: any, index: number) => { const question = contentWithQuestions.questions[index]; if (!question) return; let isCorrect = false; if (question.type === 'multiple_choice' || question.type === 'true_false') { isCorrect = question.correctAnswer === answer.answer; } else { // For essay or other types, we would need AI evaluation here // Just mark as pending for now isCorrect = false; // Requires teacher grading } results.answerDetails.push({ questionIndex: index, correct: isCorrect, studentAnswer: answer.answer, correctAnswer: question.correctAnswer, explanation: question.type !== 'essay' ? 'Auto-graded' : 'Requires teacher evaluation' }); if (isCorrect) { results.correctAnswers += 1; } }); // Calculate percentage score results.score = results.totalQuestions > 0 ? Math.round((results.correctAnswers / results.totalQuestions) * 100) : 0; } // Notify plugins that student completed content await pluginManager.notifyStudentCompleted(contentId, studentId, results); res.status(200).json({ data: results, message: "Assessment submitted successfully" }); } catch (error) { console.error("Error submitting assessment:", error); res.status(500).json({ error: "Failed to submit assessment" }); } */ res .status(501) .json({ error: "This endpoint is deprecated. Use /api/student/quizzes/:quizId/submit instead.", }); // Return Not Implemented return [2 /*return*/]; }); }); }; /** * Get feedback on submitted assessment */ StudentController.prototype.getAssessmentFeedback = function (req, res) { return __awaiter(this, void 0, void 0, function () { var contentId, studentId, feedback; return __generator(this, function (_a) { try { contentId = req.params.contentId; studentId = req.query.studentId; if (!studentId) { res.status(400).json({ error: "Student ID is required" }); return [2 /*return*/]; } feedback = { contentId: contentId, studentId: studentId, score: 85, feedback: "Good work! You've demonstrated a solid understanding of the key concepts.", recommendedResources: [ "Review Chapter 3 for more practice", "Watch the supplementary video on topic X", ], teacherComments: "I was particularly impressed with your answer to question 4.", }; res.status(200).json({ data: feedback }); } catch (error) { console.error("Error retrieving feedback:", error); res.status(500).json({ error: "Failed to retrieve feedback" }); } return [2 /*return*/]; }); }); }; /** * Submit answers for a specific Quiz identified by quizId */ StudentController.prototype.submitQuiz = function (req, res) { return __awaiter(this, void 0, void 0, function () { var quizId, _a, studentId, answers, quiz, questions, questionIds_1, submittedQuestionIds, correctCount, answerMap, answerDetails, _i, questions_1, question, studentAnswer, correctAnswer, isCorrect, score, submissionData, savedSubmission, result, error_4; return __generator(this, function (_b) { switch (_b.label) { case 0: quizId = req.params.quizId; _a = req.body, studentId = _a.studentId, answers = _a.answers; if (!studentId) { // Or check req.student.id if using auth middleware throw new errorHandler_1.ApiError("Student ID is required.", 400); } if (!quizId) { throw new errorHandler_1.ApiError("Quiz ID is required.", 400); } if (!answers || !Array.isArray(answers) || answers.length === 0) { throw new errorHandler_1.ApiError("Valid answers array is required.", 400); } _b.label = 1; case 1: _b.trys.push([1, 5, , 6]); return [4 /*yield*/, this.quizService.getQuiz(quizId)]; case 2: quiz = _b.sent(); if (!quiz) { throw new errorHandler_1.ApiError("Quiz with ID ".concat(quizId, " not found."), 404); } return [4 /*yield*/, this.quizQuestionService.getQuestionsByQuizId(quizId)]; case 3: questions = _b.sent(); if (!questions || questions.length === 0) { throw new errorHandler_1.ApiError("No questions found for quiz ".concat(quizId, ". Cannot submit."), 400); } questionIds_1 = new Set(questions.map(function (q) { return q.id; })); submittedQuestionIds = new Set(answers.map(function (a) { return a.questionId; })); if (answers.length !== questions.length || !answers.every(function (a) { return questionIds_1.has(a.questionId); })) { throw new errorHandler_1.ApiError("Submitted answers do not match the questions for quiz ".concat(quizId, "."), 400); } correctCount = 0; answerMap = new Map(answers.map(function (a) { return [a.questionId, a.answer]; })); answerDetails = []; for (_i = 0, questions_1 = questions; _i < questions_1.length; _i++) { question = questions_1[_i]; studentAnswer = answerMap.get(question.id); correctAnswer = question.answer; isCorrect = false; // Check if the student provided an answer for this question if (studentAnswer !== undefined) { // Simple comparison (adjust for case sensitivity or trimming if needed) isCorrect = String(studentAnswer) === String(correctAnswer); } // else: student didn't answer, isCorrect remains false if (isCorrect) { correctCount++; } // Add details for this question answerDetails.push({ questionId: question.id, questionText: question.question, // Add the question text studentAnswer: studentAnswer !== null && studentAnswer !== void 0 ? studentAnswer : "Not Answered", // Handle undefined answer correctAnswer: correctAnswer, explanation: question.explanation, // Include explanation if available correct: isCorrect, }); } score = questions.length > 0 ? Math.round((correctCount / questions.length) * 100) : 0; submissionData = { studentId: studentId, quizId: quizId, score: score, answers: JSON.stringify(answers), // Store submitted answers as JSON submittedAt: new Date(), }; return [4 /*yield*/, this.quizSubmissionService.createSubmission(submissionData)]; case 4: savedSubmission = _b.sent(); result = { submissionId: savedSubmission.id, quizId: quizId, studentId: studentId, score: score, totalQuestions: questions.length, correctAnswers: correctCount, feedback: "You answered ".concat(correctCount, " out of ").concat(questions.length, " questions correctly."), submittedAt: savedSubmission.submittedAt, answerDetails: answerDetails, // Include the generated details }; res.status(201).json({ message: "Quiz submitted successfully.", data: result, }); return [3 /*break*/, 6]; case 5: error_4 = _b.sent(); // Log the error for debugging console.error("Error submitting quiz ".concat(quizId, " for student ").concat(studentId, ":"), error_4); // Rethrow ApiError or wrap other errors if (error_4 instanceof errorHandler_1.ApiError) { throw error_4; } else { // Use a generic error for unexpected issues throw new errorHandler_1.ApiError("An unexpected error occurred while submitting the quiz.", 500); } return [3 /*break*/, 6]; case 6: return [2 /*return*/]; } }); }); }; /** * Get courses for a specific teacher * Requires student authentication */ StudentController.prototype.getCoursesByTeacherId = function (req, res) { return __awaiter(this, void 0, void 0, function () { var student, teacherId, tempDbAdapter, teacher, courses, error_5, closeError_1; return __generator(this, function (_a) { switch (_a.label) { case 0: student = req.student; if (!student) { // This check might be redundant if middleware guarantees req.student res.status(401).json({ message: "Authentication required" }); return [2 /*return*/]; } teacherId = req.params.teacherId; if (!teacherId) { res.status(400).json({ message: "Teacher ID is required in the URL path" }); return [2 /*return*/]; } tempDbAdapter = null; _a.label = 1; case 1: _a.trys.push([1, 4, 5, 10]); // Create a temporary adapter instance for this request scope // TODO: Replace with proper dependency injection tempDbAdapter = new SqliteAdapter_1.SqliteAdapter(); return [4 /*yield*/, tempDbAdapter.findTeacherById(teacherId)]; case 2: teacher = _a.sent(); if (!teacher) { // tempDbAdapter.close(); // Close before throwing/sending response res .status(404) .json({ message: "Teacher profile not found for the provided link.", }); return [2 /*return*/]; } return [4 /*yield*/, tempDbAdapter.findCoursesByTeacherId(teacherId)]; case 3: courses = _a.sent(); // tempDbAdapter.close(); // Close after successful fetch res.status(200).json({ courses: courses || [] }); return [3 /*break*/, 10]; case 4: error_5 = _a.sent(); console.error("Error fetching courses for teacher ".concat(teacherId, " for student ").concat(student.id, ":"), error_5); // Use centralized error handler if available res.status(500).json({ message: "Failed to retrieve courses" }); return [3 /*break*/, 10]; case 5: if (!(tempDbAdapter && typeof tempDbAdapter.close === "function")) return [3 /*break*/, 9]; _a.label = 6; case 6: _a.trys.push([6, 8, , 9]); return [4 /*yield*/, tempDbAdapter.close()]; case 7: _a.sent(); return [3 /*break*/, 9]; case 8: closeError_1 = _a.sent(); console.error("Error closing DB adapter:", closeError_1); return [3 /*break*/, 9]; case 9: return [7 /*endfinally*/]; case 10: return [2 /*return*/]; } }); }); }; /** * Login a student using email and password (Moved from AuthController) */ StudentController.prototype.loginStudent = function (req, res, next) { return __awaiter(this, void 0, void 0, function () { var _a, email, password, secret, student, isPasswordValid, tokenPayload, token, error_6; return __generator(this, function (_b) { switch (_b.label) { case 0: _a = req.body, email = _a.email, password = _a.password; secret = process.env.JWT_SECRET; if (!email || !password) { return [2 /*return*/, next(new errorHandler_1.ApiError("Email and password are required", 400))]; } if (!secret) { console.error("JWT_SECRET is not set in environment variables"); return [2 /*return*/, next(new errorHandler_1.ApiError("Server configuration error", 500))]; } _b.label = 1; case 1: _b.trys.push([1, 4, , 5]); return [4 /*yield*/, this.studentRepository.findByEmail(email)]; case 2: student = _b.sent(); if (!student) { // Use next() to pass error to centralized handler return [2 /*return*/, next(new errorHandler_1.ApiError("Invalid credentials", 401))]; } // Ensure student.passwordHash is available and is a string if (typeof student.passwordHash !== 'string' || student.passwordHash.length === 0) { console.error("[StudentController.login] Missing or invalid password hash for student ".concat(email)); return [2 /*return*/, next(new errorHandler_1.ApiError("Authentication error - invalid user data.", 500))]; } return [4 /*yield*/, bcrypt_1.default.compare(password, student.passwordHash)]; case 3: isPasswordValid = _b.sent(); if (!isPasswordValid) { return [2 /*return*/, next(new errorHandler_1.ApiError("Invalid credentials", 401))]; } tokenPayload = { studentId: student.id }; token = jsonwebtoken_1.default.sign(tokenPayload, secret, { expiresIn: "1h" }); // Set HTTP-only cookie res.cookie("studentAuthToken", token, { httpOnly: true, // Prevent client-side JS access secure: process.env.NODE_ENV === "production", // Use secure cookies in production sameSite: "lax", // Adjust as needed for your cross-origin setup ('none' requires secure) maxAge: 3600000, // 1 hour in milliseconds }); // Send success response with student ID and basic info res.status(200).json({ message: "Login successful", student: { id: student.id, // Send the correct UUID email: student.email, name: student.name, }, }); return [3 /*break*/, 5]; case 4: error_6 = _b.sent(); console.error("[StudentController] Student login error for ".concat(email, ":"), error_6); next(error_6); // Pass error to the centralized handler return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }); }; __decorate([ (0, controller_1.Post)("/register"), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object, Function]), __metadata("design:returntype", Promise) ], StudentController.prototype, "registerStudent", null); __decorate([ (0, controller_1.Get)("/content"), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], StudentController.prototype, "getPublishedContent", null); __decorate([ (0, controller_1.Get)("/content/:contentId"), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], StudentController.prototype, "getContentById", null); __decorate([ (0, controller_1.Post)("/submit/:contentId"), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], StudentController.prototype, "submitAssessment", null); __decorate([ (0, controller_1.Get)("/feedback/:contentId"), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], StudentController.prototype, "getAssessmentFeedback", null); __decorate([ (0, controller_1.Post)("/quizzes/:quizId/submit"), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], StudentController.prototype, "submitQuiz", null); __decorate([ (0, controller_1.Use)(auth_1.authenticateStudent), (0, controller_1.Get)("/courses/:teacherId"), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], StudentController.prototype, "getCoursesByTeacherId", null); __decorate([ (0, controller_1.Post)("/login"), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object, Function]), __metadata("design:returntype", Promise) ], StudentController.prototype, "loginStudent", null); StudentController = __decorate([ (0, controller_1.Controller)("/api/student"), __metadata("design:paramtypes", [Object, QuizService_1.QuizService, QuizQuestionService_1.QuizQuestionService, QuizSubmissionService_1.QuizSubmissionService, StudentRepository_1.StudentRepository]) ], StudentController); return StudentController; }()); exports.StudentController = StudentController;