added and fix some of things

Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-08-03 12:03:02 +08:00
parent 6765c1faba
commit d246c09cdd
31 changed files with 724 additions and 510 deletions
@@ -17,7 +17,10 @@
const { Op } = require('sequelize');
const R = require('../../utils/response.util');
const CourseReadingProgress = require('../../models/courses/course_reading_progress.mdl');
const { Course, Unit, Lesson, CourseUnit } = require('../../models/courses/courses.associations');
const {
Course, Unit, Lesson, CourseUnit,
UnitQuiz, CourseAssessment, QuizAttempt,
} = require('../../models/courses/courses.associations');
const mdl_Users = require('../../models/users/users.mdl');
const { countCourseLessons, getCourseUnitIds, flattenUnits } = require('../../utils/courses/hierarchy.util');
const { resolveAvatarUrl } = require('../../utils/resolveAvatar.util');
@@ -68,6 +71,42 @@ exports.getCourseReadingProgress = async (req, res) => {
});
const userMap = Object.fromEntries(users.map((u) => [u.user_id, u]));
// Quiz/assessment gating — mirrors controllers/client/course_reading_progress
// .controller.js#getMyInProgressCourses: a unit quiz or course assessment that
// exists but hasn't been passed yet is why a user with 1/1 lessons read can still
// be 'in_progress'. Batched once per course across all users in this list.
const unitQuizzes = unitIds.length
? await UnitQuiz.findAll({ where: { unit_id: unitIds, ...notDeleted }, attributes: ['quiz_id'] })
: [];
const quizIds = unitQuizzes.map((q) => q.quiz_id);
const assessment = await CourseAssessment.findOne({
where: { course_id: courseId },
attributes: ['assessment_id'],
});
const passedQuizIdsByUser = new Map();
const passedAssessmentUserIds = new Set();
if (quizIds.length || assessment) {
const passedAttempts = await QuizAttempt.findAll({
where: {
user_id: userIds,
passed: true,
[Op.or]: [
...(quizIds.length ? [{ quiz_id: quizIds }] : []),
...(assessment ? [{ assessment_id: assessment.assessment_id }] : []),
],
},
attributes: ['user_id', 'quiz_id', 'assessment_id'],
});
for (const attempt of passedAttempts) {
if (attempt.quiz_id) {
if (!passedQuizIdsByUser.has(attempt.user_id)) passedQuizIdsByUser.set(attempt.user_id, new Set());
passedQuizIdsByUser.get(attempt.user_id).add(attempt.quiz_id);
}
if (attempt.assessment_id) passedAssessmentUserIds.add(attempt.user_id);
}
}
// Build per-user summary
const summaryMap = {};
for (const row of rows) {
@@ -106,6 +145,8 @@ exports.getCourseReadingProgress = async (req, res) => {
lessons_total,
// Fall back to in_progress if the course row hasn't been written yet
course_status: entry.course_status ?? 'in_progress',
quizzes_pending: quizIds.length - (passedQuizIdsByUser.get(entry.user_id)?.size ?? 0),
assessment_pending: !!assessment && !passedAssessmentUserIds.has(entry.user_id),
};
}));