progress precentage fix
This commit is contained in:
parent
d3225ca61a
commit
a1c6b3c15a
119
db/query/exam_prep_progress.sql
Normal file
119
db/query/exam_prep_progress.sql
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
-- name: CountPublishedExamPrepPracticesInLesson :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
p.unit_module_lesson_id = $1
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED';
|
||||||
|
|
||||||
|
-- name: CountUserCompletedPublishedExamPrepPracticesInLesson :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
p.unit_module_lesson_id = $1
|
||||||
|
AND upp.user_id = $2
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED';
|
||||||
|
|
||||||
|
-- name: CountPublishedExamPrepPracticesInModule :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
l.unit_module_id = $1
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED';
|
||||||
|
|
||||||
|
-- name: CountUserCompletedPublishedExamPrepPracticesInModule :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
l.unit_module_id = $1
|
||||||
|
AND upp.user_id = $2
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED';
|
||||||
|
|
||||||
|
-- name: CountPublishedExamPrepPracticesInUnit :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
m.unit_id = $1
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED';
|
||||||
|
|
||||||
|
-- name: CountUserCompletedPublishedExamPrepPracticesInUnit :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
m.unit_id = $1
|
||||||
|
AND upp.user_id = $2
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED';
|
||||||
|
|
||||||
|
-- name: CountPublishedExamPrepPracticesInCatalogCourse :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN exam_prep.units u ON u.id = m.unit_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
u.catalog_course_id = $1
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED';
|
||||||
|
|
||||||
|
-- name: CountUserCompletedPublishedExamPrepPracticesInCatalogCourse :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN exam_prep.units u ON u.id = m.unit_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
u.catalog_course_id = $1
|
||||||
|
AND upp.user_id = $2
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED';
|
||||||
|
|
@ -225,72 +225,124 @@ ORDER BY
|
||||||
|
|
||||||
-- name: ListLMSCompletedModuleIDsByUser :many
|
-- name: ListLMSCompletedModuleIDsByUser :many
|
||||||
SELECT
|
SELECT
|
||||||
lp.module_id
|
scoped.module_id
|
||||||
FROM
|
FROM (
|
||||||
lms_practices AS lp
|
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
|
||||||
LEFT JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
|
||||||
AND upp.user_id = $1
|
|
||||||
AND upp.completed_at IS NOT NULL
|
|
||||||
WHERE
|
|
||||||
lp.module_id IS NOT NULL
|
|
||||||
AND qs.set_type = 'PRACTICE'
|
|
||||||
AND qs.status = 'PUBLISHED'
|
|
||||||
AND lp.publish_status = 'PUBLISHED'
|
|
||||||
GROUP BY
|
|
||||||
lp.module_id
|
|
||||||
HAVING
|
|
||||||
count(DISTINCT lp.question_set_id) > 0
|
|
||||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
|
||||||
ORDER BY
|
|
||||||
max(upp.completed_at) ASC,
|
|
||||||
lp.module_id ASC;
|
|
||||||
|
|
||||||
-- name: ListLMSCompletedCourseIDsByUser :many
|
|
||||||
SELECT
|
SELECT
|
||||||
lp.course_id
|
m.id AS module_id,
|
||||||
|
lp.question_set_id
|
||||||
FROM
|
FROM
|
||||||
lms_practices AS lp
|
modules m
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN lms_practices lp ON (
|
||||||
LEFT JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
lp.module_id = m.id
|
||||||
AND upp.user_id = $1
|
OR lp.lesson_id IN (
|
||||||
AND upp.completed_at IS NOT NULL
|
|
||||||
WHERE
|
|
||||||
lp.course_id IS NOT NULL
|
|
||||||
AND qs.set_type = 'PRACTICE'
|
|
||||||
AND qs.status = 'PUBLISHED'
|
|
||||||
AND lp.publish_status = 'PUBLISHED'
|
|
||||||
GROUP BY
|
|
||||||
lp.course_id
|
|
||||||
HAVING
|
|
||||||
count(DISTINCT lp.question_set_id) > 0
|
|
||||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
|
||||||
ORDER BY
|
|
||||||
max(upp.completed_at) ASC,
|
|
||||||
lp.course_id ASC;
|
|
||||||
|
|
||||||
-- name: ListLMSCompletedProgramIDsByUser :many
|
|
||||||
SELECT
|
SELECT
|
||||||
c.program_id
|
id
|
||||||
FROM
|
FROM
|
||||||
lms_practices AS lp
|
lessons
|
||||||
INNER JOIN courses c ON c.id = lp.course_id
|
WHERE
|
||||||
|
module_id = m.id))
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
LEFT JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
|
||||||
AND upp.user_id = $1
|
|
||||||
AND upp.completed_at IS NOT NULL
|
|
||||||
WHERE
|
WHERE
|
||||||
qs.set_type = 'PRACTICE'
|
qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED'
|
AND qs.status = 'PUBLISHED'
|
||||||
AND lp.publish_status = 'PUBLISHED'
|
AND lp.publish_status = 'PUBLISHED') scoped
|
||||||
|
LEFT JOIN user_practice_progress upp ON upp.question_set_id = scoped.question_set_id
|
||||||
|
AND upp.user_id = $1
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
GROUP BY
|
GROUP BY
|
||||||
c.program_id
|
scoped.module_id
|
||||||
HAVING
|
HAVING
|
||||||
count(DISTINCT lp.question_set_id) > 0
|
count(DISTINCT scoped.question_set_id) > 0
|
||||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT scoped.question_set_id)
|
||||||
ORDER BY
|
ORDER BY
|
||||||
max(upp.completed_at) ASC,
|
max(upp.completed_at) ASC,
|
||||||
c.program_id ASC;
|
scoped.module_id ASC;
|
||||||
|
|
||||||
|
-- name: ListLMSCompletedCourseIDsByUser :many
|
||||||
|
SELECT
|
||||||
|
scoped.course_id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
c.id AS course_id,
|
||||||
|
lp.question_set_id
|
||||||
|
FROM
|
||||||
|
courses c
|
||||||
|
INNER JOIN lms_practices lp ON (
|
||||||
|
lp.course_id = c.id
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
modules
|
||||||
|
WHERE
|
||||||
|
course_id = c.id)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
WHERE
|
||||||
|
m.course_id = c.id))
|
||||||
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
|
WHERE
|
||||||
|
qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND lp.publish_status = 'PUBLISHED') scoped
|
||||||
|
LEFT JOIN user_practice_progress upp ON upp.question_set_id = scoped.question_set_id
|
||||||
|
AND upp.user_id = $1
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
GROUP BY
|
||||||
|
scoped.course_id
|
||||||
|
HAVING
|
||||||
|
count(DISTINCT scoped.question_set_id) > 0
|
||||||
|
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT scoped.question_set_id)
|
||||||
|
ORDER BY
|
||||||
|
max(upp.completed_at) ASC,
|
||||||
|
scoped.course_id ASC;
|
||||||
|
|
||||||
|
-- name: ListLMSCompletedProgramIDsByUser :many
|
||||||
|
SELECT
|
||||||
|
scoped.program_id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
c.program_id,
|
||||||
|
lp.question_set_id
|
||||||
|
FROM
|
||||||
|
courses c
|
||||||
|
INNER JOIN lms_practices lp ON (
|
||||||
|
lp.course_id = c.id
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
m.id
|
||||||
|
FROM
|
||||||
|
modules m
|
||||||
|
WHERE
|
||||||
|
m.course_id = c.id)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
WHERE
|
||||||
|
m.course_id = c.id))
|
||||||
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
|
WHERE
|
||||||
|
qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND lp.publish_status = 'PUBLISHED') scoped
|
||||||
|
LEFT JOIN user_practice_progress upp ON upp.question_set_id = scoped.question_set_id
|
||||||
|
AND upp.user_id = $1
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
GROUP BY
|
||||||
|
scoped.program_id
|
||||||
|
HAVING
|
||||||
|
count(DISTINCT scoped.question_set_id) > 0
|
||||||
|
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT scoped.question_set_id)
|
||||||
|
ORDER BY
|
||||||
|
max(upp.completed_at) ASC,
|
||||||
|
scoped.program_id ASC;
|
||||||
|
|
||||||
-- Lesson-based progress within a course (all modules).
|
-- Lesson-based progress within a course (all modules).
|
||||||
-- name: CountLessonsInCourse :one
|
-- name: CountLessonsInCourse :one
|
||||||
|
|
@ -340,7 +392,7 @@ WHERE
|
||||||
AND ulp.user_id = $2
|
AND ulp.user_id = $2
|
||||||
AND l.publish_status = 'PUBLISHED';
|
AND l.publish_status = 'PUBLISHED';
|
||||||
|
|
||||||
-- Published practices in a module (module-level and lesson-level practices should carry module_id).
|
-- Published practices in a module (direct module practices and practices on lessons in the module).
|
||||||
-- name: CountPublishedPracticesInModule :one
|
-- name: CountPublishedPracticesInModule :one
|
||||||
SELECT
|
SELECT
|
||||||
count(*)::int AS n
|
count(*)::int AS n
|
||||||
|
|
@ -348,7 +400,15 @@ FROM
|
||||||
lms_practices lp
|
lms_practices lp
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
|
(
|
||||||
lp.module_id = $1
|
lp.module_id = $1
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
lessons
|
||||||
|
WHERE
|
||||||
|
module_id = $1))
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED'
|
AND qs.status = 'PUBLISHED'
|
||||||
AND lp.publish_status = 'PUBLISHED';
|
AND lp.publish_status = 'PUBLISHED';
|
||||||
|
|
@ -361,7 +421,15 @@ FROM
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
|
(
|
||||||
lp.module_id = $1
|
lp.module_id = $1
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
lessons
|
||||||
|
WHERE
|
||||||
|
module_id = $1))
|
||||||
AND upp.user_id = $2
|
AND upp.user_id = $2
|
||||||
AND upp.completed_at IS NOT NULL
|
AND upp.completed_at IS NOT NULL
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
|
@ -375,7 +443,23 @@ FROM
|
||||||
lms_practices lp
|
lms_practices lp
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
|
(
|
||||||
lp.course_id = $1
|
lp.course_id = $1
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
modules
|
||||||
|
WHERE
|
||||||
|
course_id = $1)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
WHERE
|
||||||
|
m.course_id = $1))
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED'
|
AND qs.status = 'PUBLISHED'
|
||||||
AND lp.publish_status = 'PUBLISHED';
|
AND lp.publish_status = 'PUBLISHED';
|
||||||
|
|
@ -388,21 +472,61 @@ FROM
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
|
(
|
||||||
lp.course_id = $1
|
lp.course_id = $1
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
modules
|
||||||
|
WHERE
|
||||||
|
course_id = $1)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
WHERE
|
||||||
|
m.course_id = $1))
|
||||||
AND upp.user_id = $2
|
AND upp.user_id = $2
|
||||||
AND upp.completed_at IS NOT NULL
|
AND upp.completed_at IS NOT NULL
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED';
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND lp.publish_status = 'PUBLISHED';
|
||||||
|
|
||||||
-- name: CountPublishedPracticesInProgram :one
|
-- name: CountPublishedPracticesInProgram :one
|
||||||
SELECT
|
SELECT
|
||||||
count(*)::int AS n
|
count(*)::int AS n
|
||||||
FROM
|
FROM
|
||||||
lms_practices lp
|
lms_practices lp
|
||||||
INNER JOIN courses c ON c.id = lp.course_id
|
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
c.program_id = $1
|
(
|
||||||
|
lp.course_id IN (
|
||||||
|
SELECT
|
||||||
|
c.id
|
||||||
|
FROM
|
||||||
|
courses c
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1)
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
m.id
|
||||||
|
FROM
|
||||||
|
modules m
|
||||||
|
INNER JOIN courses c ON c.id = m.course_id
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
INNER JOIN courses c ON c.id = m.course_id
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1))
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED'
|
AND qs.status = 'PUBLISHED'
|
||||||
AND lp.publish_status = 'PUBLISHED';
|
AND lp.publish_status = 'PUBLISHED';
|
||||||
|
|
@ -412,11 +536,34 @@ SELECT
|
||||||
count(*)::int AS n
|
count(*)::int AS n
|
||||||
FROM
|
FROM
|
||||||
lms_practices lp
|
lms_practices lp
|
||||||
INNER JOIN courses c ON c.id = lp.course_id
|
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
c.program_id = $1
|
(
|
||||||
|
lp.course_id IN (
|
||||||
|
SELECT
|
||||||
|
c.id
|
||||||
|
FROM
|
||||||
|
courses c
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1)
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
m.id
|
||||||
|
FROM
|
||||||
|
modules m
|
||||||
|
INNER JOIN courses c ON c.id = m.course_id
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
INNER JOIN courses c ON c.id = m.course_id
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1))
|
||||||
AND upp.user_id = $2
|
AND upp.user_id = $2
|
||||||
AND upp.completed_at IS NOT NULL
|
AND upp.completed_at IS NOT NULL
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
|
|
||||||
214
gen/db/exam_prep_progress.sql.go
Normal file
214
gen/db/exam_prep_progress.sql.go
Normal file
|
|
@ -0,0 +1,214 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.30.0
|
||||||
|
// source: exam_prep_progress.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CountPublishedExamPrepPracticesInCatalogCourse = `-- name: CountPublishedExamPrepPracticesInCatalogCourse :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN exam_prep.units u ON u.id = m.unit_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
u.catalog_course_id = $1
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED'
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CountPublishedExamPrepPracticesInCatalogCourse(ctx context.Context, catalogCourseID int64) (int32, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountPublishedExamPrepPracticesInCatalogCourse, catalogCourseID)
|
||||||
|
var n int32
|
||||||
|
err := row.Scan(&n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CountPublishedExamPrepPracticesInLesson = `-- name: CountPublishedExamPrepPracticesInLesson :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
p.unit_module_lesson_id = $1
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED'
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CountPublishedExamPrepPracticesInLesson(ctx context.Context, unitModuleLessonID int64) (int32, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountPublishedExamPrepPracticesInLesson, unitModuleLessonID)
|
||||||
|
var n int32
|
||||||
|
err := row.Scan(&n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CountPublishedExamPrepPracticesInModule = `-- name: CountPublishedExamPrepPracticesInModule :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
l.unit_module_id = $1
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED'
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CountPublishedExamPrepPracticesInModule(ctx context.Context, unitModuleID int64) (int32, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountPublishedExamPrepPracticesInModule, unitModuleID)
|
||||||
|
var n int32
|
||||||
|
err := row.Scan(&n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CountPublishedExamPrepPracticesInUnit = `-- name: CountPublishedExamPrepPracticesInUnit :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
m.unit_id = $1
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED'
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CountPublishedExamPrepPracticesInUnit(ctx context.Context, unitID int64) (int32, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountPublishedExamPrepPracticesInUnit, unitID)
|
||||||
|
var n int32
|
||||||
|
err := row.Scan(&n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CountUserCompletedPublishedExamPrepPracticesInCatalogCourse = `-- name: CountUserCompletedPublishedExamPrepPracticesInCatalogCourse :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN exam_prep.units u ON u.id = m.unit_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
u.catalog_course_id = $1
|
||||||
|
AND upp.user_id = $2
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED'
|
||||||
|
`
|
||||||
|
|
||||||
|
type CountUserCompletedPublishedExamPrepPracticesInCatalogCourseParams struct {
|
||||||
|
CatalogCourseID int64 `json:"catalog_course_id"`
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CountUserCompletedPublishedExamPrepPracticesInCatalogCourse(ctx context.Context, arg CountUserCompletedPublishedExamPrepPracticesInCatalogCourseParams) (int32, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountUserCompletedPublishedExamPrepPracticesInCatalogCourse, arg.CatalogCourseID, arg.UserID)
|
||||||
|
var n int32
|
||||||
|
err := row.Scan(&n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CountUserCompletedPublishedExamPrepPracticesInLesson = `-- name: CountUserCompletedPublishedExamPrepPracticesInLesson :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
p.unit_module_lesson_id = $1
|
||||||
|
AND upp.user_id = $2
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED'
|
||||||
|
`
|
||||||
|
|
||||||
|
type CountUserCompletedPublishedExamPrepPracticesInLessonParams struct {
|
||||||
|
UnitModuleLessonID int64 `json:"unit_module_lesson_id"`
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CountUserCompletedPublishedExamPrepPracticesInLesson(ctx context.Context, arg CountUserCompletedPublishedExamPrepPracticesInLessonParams) (int32, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountUserCompletedPublishedExamPrepPracticesInLesson, arg.UnitModuleLessonID, arg.UserID)
|
||||||
|
var n int32
|
||||||
|
err := row.Scan(&n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CountUserCompletedPublishedExamPrepPracticesInModule = `-- name: CountUserCompletedPublishedExamPrepPracticesInModule :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
l.unit_module_id = $1
|
||||||
|
AND upp.user_id = $2
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED'
|
||||||
|
`
|
||||||
|
|
||||||
|
type CountUserCompletedPublishedExamPrepPracticesInModuleParams struct {
|
||||||
|
UnitModuleID int64 `json:"unit_module_id"`
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CountUserCompletedPublishedExamPrepPracticesInModule(ctx context.Context, arg CountUserCompletedPublishedExamPrepPracticesInModuleParams) (int32, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountUserCompletedPublishedExamPrepPracticesInModule, arg.UnitModuleID, arg.UserID)
|
||||||
|
var n int32
|
||||||
|
err := row.Scan(&n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CountUserCompletedPublishedExamPrepPracticesInUnit = `-- name: CountUserCompletedPublishedExamPrepPracticesInUnit :one
|
||||||
|
SELECT
|
||||||
|
count(*)::int AS n
|
||||||
|
FROM
|
||||||
|
exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN question_sets qs ON qs.id = p.question_set_id
|
||||||
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = p.question_set_id
|
||||||
|
WHERE
|
||||||
|
m.unit_id = $1
|
||||||
|
AND upp.user_id = $2
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND p.publish_status = 'PUBLISHED'
|
||||||
|
`
|
||||||
|
|
||||||
|
type CountUserCompletedPublishedExamPrepPracticesInUnitParams struct {
|
||||||
|
UnitID int64 `json:"unit_id"`
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CountUserCompletedPublishedExamPrepPracticesInUnit(ctx context.Context, arg CountUserCompletedPublishedExamPrepPracticesInUnitParams) (int32, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountUserCompletedPublishedExamPrepPracticesInUnit, arg.UnitID, arg.UserID)
|
||||||
|
var n int32
|
||||||
|
err := row.Scan(&n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
@ -106,7 +106,23 @@ FROM
|
||||||
lms_practices lp
|
lms_practices lp
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
|
(
|
||||||
lp.course_id = $1
|
lp.course_id = $1
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
modules
|
||||||
|
WHERE
|
||||||
|
course_id = $1)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
WHERE
|
||||||
|
m.course_id = $1))
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED'
|
AND qs.status = 'PUBLISHED'
|
||||||
AND lp.publish_status = 'PUBLISHED'
|
AND lp.publish_status = 'PUBLISHED'
|
||||||
|
|
@ -146,13 +162,21 @@ FROM
|
||||||
lms_practices lp
|
lms_practices lp
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
|
(
|
||||||
lp.module_id = $1
|
lp.module_id = $1
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
lessons
|
||||||
|
WHERE
|
||||||
|
module_id = $1))
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED'
|
AND qs.status = 'PUBLISHED'
|
||||||
AND lp.publish_status = 'PUBLISHED'
|
AND lp.publish_status = 'PUBLISHED'
|
||||||
`
|
`
|
||||||
|
|
||||||
// Published practices in a module (module-level and lesson-level practices should carry module_id).
|
// Published practices in a module (direct module practices and practices on lessons in the module).
|
||||||
func (q *Queries) CountPublishedPracticesInModule(ctx context.Context, moduleID pgtype.Int8) (int32, error) {
|
func (q *Queries) CountPublishedPracticesInModule(ctx context.Context, moduleID pgtype.Int8) (int32, error) {
|
||||||
row := q.db.QueryRow(ctx, CountPublishedPracticesInModule, moduleID)
|
row := q.db.QueryRow(ctx, CountPublishedPracticesInModule, moduleID)
|
||||||
var n int32
|
var n int32
|
||||||
|
|
@ -165,10 +189,33 @@ SELECT
|
||||||
count(*)::int AS n
|
count(*)::int AS n
|
||||||
FROM
|
FROM
|
||||||
lms_practices lp
|
lms_practices lp
|
||||||
INNER JOIN courses c ON c.id = lp.course_id
|
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
c.program_id = $1
|
(
|
||||||
|
lp.course_id IN (
|
||||||
|
SELECT
|
||||||
|
c.id
|
||||||
|
FROM
|
||||||
|
courses c
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1)
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
m.id
|
||||||
|
FROM
|
||||||
|
modules m
|
||||||
|
INNER JOIN courses c ON c.id = m.course_id
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
INNER JOIN courses c ON c.id = m.course_id
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1))
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED'
|
AND qs.status = 'PUBLISHED'
|
||||||
AND lp.publish_status = 'PUBLISHED'
|
AND lp.publish_status = 'PUBLISHED'
|
||||||
|
|
@ -310,11 +357,28 @@ FROM
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
|
(
|
||||||
lp.course_id = $1
|
lp.course_id = $1
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
modules
|
||||||
|
WHERE
|
||||||
|
course_id = $1)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
WHERE
|
||||||
|
m.course_id = $1))
|
||||||
AND upp.user_id = $2
|
AND upp.user_id = $2
|
||||||
AND upp.completed_at IS NOT NULL
|
AND upp.completed_at IS NOT NULL
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED'
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND lp.publish_status = 'PUBLISHED'
|
||||||
`
|
`
|
||||||
|
|
||||||
type CountUserCompletedPublishedPracticesInCourseParams struct {
|
type CountUserCompletedPublishedPracticesInCourseParams struct {
|
||||||
|
|
@ -365,7 +429,15 @@ FROM
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
|
(
|
||||||
lp.module_id = $1
|
lp.module_id = $1
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
lessons
|
||||||
|
WHERE
|
||||||
|
module_id = $1))
|
||||||
AND upp.user_id = $2
|
AND upp.user_id = $2
|
||||||
AND upp.completed_at IS NOT NULL
|
AND upp.completed_at IS NOT NULL
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
|
@ -390,11 +462,34 @@ SELECT
|
||||||
count(*)::int AS n
|
count(*)::int AS n
|
||||||
FROM
|
FROM
|
||||||
lms_practices lp
|
lms_practices lp
|
||||||
INNER JOIN courses c ON c.id = lp.course_id
|
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
INNER JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||||
WHERE
|
WHERE
|
||||||
c.program_id = $1
|
(
|
||||||
|
lp.course_id IN (
|
||||||
|
SELECT
|
||||||
|
c.id
|
||||||
|
FROM
|
||||||
|
courses c
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1)
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
m.id
|
||||||
|
FROM
|
||||||
|
modules m
|
||||||
|
INNER JOIN courses c ON c.id = m.course_id
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
INNER JOIN courses c ON c.id = m.course_id
|
||||||
|
WHERE
|
||||||
|
c.program_id = $1))
|
||||||
AND upp.user_id = $2
|
AND upp.user_id = $2
|
||||||
AND upp.completed_at IS NOT NULL
|
AND upp.completed_at IS NOT NULL
|
||||||
AND qs.set_type = 'PRACTICE'
|
AND qs.set_type = 'PRACTICE'
|
||||||
|
|
@ -640,37 +735,57 @@ func (q *Queries) InsertUserProgramProgress(ctx context.Context, arg InsertUserP
|
||||||
|
|
||||||
const ListLMSCompletedCourseIDsByUser = `-- name: ListLMSCompletedCourseIDsByUser :many
|
const ListLMSCompletedCourseIDsByUser = `-- name: ListLMSCompletedCourseIDsByUser :many
|
||||||
SELECT
|
SELECT
|
||||||
lp.course_id
|
scoped.course_id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
c.id AS course_id,
|
||||||
|
lp.question_set_id
|
||||||
FROM
|
FROM
|
||||||
lms_practices AS lp
|
courses c
|
||||||
|
INNER JOIN lms_practices lp ON (
|
||||||
|
lp.course_id = c.id
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
modules
|
||||||
|
WHERE
|
||||||
|
course_id = c.id)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
WHERE
|
||||||
|
m.course_id = c.id))
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
LEFT JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
WHERE
|
||||||
|
qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND lp.publish_status = 'PUBLISHED') scoped
|
||||||
|
LEFT JOIN user_practice_progress upp ON upp.question_set_id = scoped.question_set_id
|
||||||
AND upp.user_id = $1
|
AND upp.user_id = $1
|
||||||
AND upp.completed_at IS NOT NULL
|
AND upp.completed_at IS NOT NULL
|
||||||
WHERE
|
|
||||||
lp.course_id IS NOT NULL
|
|
||||||
AND qs.set_type = 'PRACTICE'
|
|
||||||
AND qs.status = 'PUBLISHED'
|
|
||||||
AND lp.publish_status = 'PUBLISHED'
|
|
||||||
GROUP BY
|
GROUP BY
|
||||||
lp.course_id
|
scoped.course_id
|
||||||
HAVING
|
HAVING
|
||||||
count(DISTINCT lp.question_set_id) > 0
|
count(DISTINCT scoped.question_set_id) > 0
|
||||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT scoped.question_set_id)
|
||||||
ORDER BY
|
ORDER BY
|
||||||
max(upp.completed_at) ASC,
|
max(upp.completed_at) ASC,
|
||||||
lp.course_id ASC
|
scoped.course_id ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListLMSCompletedCourseIDsByUser(ctx context.Context, userID int64) ([]pgtype.Int8, error) {
|
func (q *Queries) ListLMSCompletedCourseIDsByUser(ctx context.Context, userID int64) ([]int64, error) {
|
||||||
rows, err := q.db.Query(ctx, ListLMSCompletedCourseIDsByUser, userID)
|
rows, err := q.db.Query(ctx, ListLMSCompletedCourseIDsByUser, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []pgtype.Int8
|
var items []int64
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var course_id pgtype.Int8
|
var course_id int64
|
||||||
if err := rows.Scan(&course_id); err != nil {
|
if err := rows.Scan(&course_id); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -728,37 +843,49 @@ func (q *Queries) ListLMSCompletedLessonIDsByUser(ctx context.Context, userID in
|
||||||
|
|
||||||
const ListLMSCompletedModuleIDsByUser = `-- name: ListLMSCompletedModuleIDsByUser :many
|
const ListLMSCompletedModuleIDsByUser = `-- name: ListLMSCompletedModuleIDsByUser :many
|
||||||
SELECT
|
SELECT
|
||||||
lp.module_id
|
scoped.module_id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
m.id AS module_id,
|
||||||
|
lp.question_set_id
|
||||||
FROM
|
FROM
|
||||||
lms_practices AS lp
|
modules m
|
||||||
|
INNER JOIN lms_practices lp ON (
|
||||||
|
lp.module_id = m.id
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
lessons
|
||||||
|
WHERE
|
||||||
|
module_id = m.id))
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
LEFT JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
WHERE
|
||||||
|
qs.set_type = 'PRACTICE'
|
||||||
|
AND qs.status = 'PUBLISHED'
|
||||||
|
AND lp.publish_status = 'PUBLISHED') scoped
|
||||||
|
LEFT JOIN user_practice_progress upp ON upp.question_set_id = scoped.question_set_id
|
||||||
AND upp.user_id = $1
|
AND upp.user_id = $1
|
||||||
AND upp.completed_at IS NOT NULL
|
AND upp.completed_at IS NOT NULL
|
||||||
WHERE
|
|
||||||
lp.module_id IS NOT NULL
|
|
||||||
AND qs.set_type = 'PRACTICE'
|
|
||||||
AND qs.status = 'PUBLISHED'
|
|
||||||
AND lp.publish_status = 'PUBLISHED'
|
|
||||||
GROUP BY
|
GROUP BY
|
||||||
lp.module_id
|
scoped.module_id
|
||||||
HAVING
|
HAVING
|
||||||
count(DISTINCT lp.question_set_id) > 0
|
count(DISTINCT scoped.question_set_id) > 0
|
||||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT scoped.question_set_id)
|
||||||
ORDER BY
|
ORDER BY
|
||||||
max(upp.completed_at) ASC,
|
max(upp.completed_at) ASC,
|
||||||
lp.module_id ASC
|
scoped.module_id ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListLMSCompletedModuleIDsByUser(ctx context.Context, userID int64) ([]pgtype.Int8, error) {
|
func (q *Queries) ListLMSCompletedModuleIDsByUser(ctx context.Context, userID int64) ([]int64, error) {
|
||||||
rows, err := q.db.Query(ctx, ListLMSCompletedModuleIDsByUser, userID)
|
rows, err := q.db.Query(ctx, ListLMSCompletedModuleIDsByUser, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []pgtype.Int8
|
var items []int64
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var module_id pgtype.Int8
|
var module_id int64
|
||||||
if err := rows.Scan(&module_id); err != nil {
|
if err := rows.Scan(&module_id); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -772,26 +899,46 @@ func (q *Queries) ListLMSCompletedModuleIDsByUser(ctx context.Context, userID in
|
||||||
|
|
||||||
const ListLMSCompletedProgramIDsByUser = `-- name: ListLMSCompletedProgramIDsByUser :many
|
const ListLMSCompletedProgramIDsByUser = `-- name: ListLMSCompletedProgramIDsByUser :many
|
||||||
SELECT
|
SELECT
|
||||||
c.program_id
|
scoped.program_id
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
c.program_id,
|
||||||
|
lp.question_set_id
|
||||||
FROM
|
FROM
|
||||||
lms_practices AS lp
|
courses c
|
||||||
INNER JOIN courses c ON c.id = lp.course_id
|
INNER JOIN lms_practices lp ON (
|
||||||
|
lp.course_id = c.id
|
||||||
|
OR lp.module_id IN (
|
||||||
|
SELECT
|
||||||
|
m.id
|
||||||
|
FROM
|
||||||
|
modules m
|
||||||
|
WHERE
|
||||||
|
m.course_id = c.id)
|
||||||
|
OR lp.lesson_id IN (
|
||||||
|
SELECT
|
||||||
|
l.id
|
||||||
|
FROM
|
||||||
|
lessons l
|
||||||
|
INNER JOIN modules m ON m.id = l.module_id
|
||||||
|
WHERE
|
||||||
|
m.course_id = c.id))
|
||||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||||
LEFT JOIN user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
|
||||||
AND upp.user_id = $1
|
|
||||||
AND upp.completed_at IS NOT NULL
|
|
||||||
WHERE
|
WHERE
|
||||||
qs.set_type = 'PRACTICE'
|
qs.set_type = 'PRACTICE'
|
||||||
AND qs.status = 'PUBLISHED'
|
AND qs.status = 'PUBLISHED'
|
||||||
AND lp.publish_status = 'PUBLISHED'
|
AND lp.publish_status = 'PUBLISHED') scoped
|
||||||
|
LEFT JOIN user_practice_progress upp ON upp.question_set_id = scoped.question_set_id
|
||||||
|
AND upp.user_id = $1
|
||||||
|
AND upp.completed_at IS NOT NULL
|
||||||
GROUP BY
|
GROUP BY
|
||||||
c.program_id
|
scoped.program_id
|
||||||
HAVING
|
HAVING
|
||||||
count(DISTINCT lp.question_set_id) > 0
|
count(DISTINCT scoped.question_set_id) > 0
|
||||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT scoped.question_set_id)
|
||||||
ORDER BY
|
ORDER BY
|
||||||
max(upp.completed_at) ASC,
|
max(upp.completed_at) ASC,
|
||||||
c.program_id ASC
|
scoped.program_id ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListLMSCompletedProgramIDsByUser(ctx context.Context, userID int64) ([]int64, error) {
|
func (q *Queries) ListLMSCompletedProgramIDsByUser(ctx context.Context, userID int64) ([]int64, error) {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ type ExamPrepCatalogCourse struct {
|
||||||
ModulesCount *int64 `json:"modules_count,omitempty"`
|
ModulesCount *int64 `json:"modules_count,omitempty"`
|
||||||
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
||||||
HasPractice bool `json:"has_practice"`
|
HasPractice bool `json:"has_practice"`
|
||||||
|
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ type ExamPrepLesson struct {
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
SortOrder int `json:"sort_order"`
|
SortOrder int `json:"sort_order"`
|
||||||
HasPractice bool `json:"has_practice"`
|
HasPractice bool `json:"has_practice"`
|
||||||
|
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ type ExamPrepModule struct {
|
||||||
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
||||||
PracticesCount *int64 `json:"practices_count,omitempty"`
|
PracticesCount *int64 `json:"practices_count,omitempty"`
|
||||||
HasPractice bool `json:"has_practice"`
|
HasPractice bool `json:"has_practice"`
|
||||||
|
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ type ExamPrepUnit struct {
|
||||||
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
||||||
PracticesCount *int64 `json:"practices_count,omitempty"`
|
PracticesCount *int64 `json:"practices_count,omitempty"`
|
||||||
HasPractice bool `json:"has_practice"`
|
HasPractice bool `json:"has_practice"`
|
||||||
|
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
71
internal/repository/exam_prep_progress.go
Normal file
71
internal/repository/exam_prep_progress.go
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExamPrepUserPracticeProgressInLesson returns published practice completion counts scoped to an exam-prep lesson.
|
||||||
|
func (s *Store) ExamPrepUserPracticeProgressInLesson(ctx context.Context, userID, lessonID int64) (completed, total int32, err error) {
|
||||||
|
total, err = s.queries.CountPublishedExamPrepPracticesInLesson(ctx, lessonID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
completed, err = s.queries.CountUserCompletedPublishedExamPrepPracticesInLesson(ctx, dbgen.CountUserCompletedPublishedExamPrepPracticesInLessonParams{
|
||||||
|
UnitModuleLessonID: lessonID,
|
||||||
|
UserID: userID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
return completed, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExamPrepUserPracticeProgressInModule returns published practice completion counts in an exam-prep module.
|
||||||
|
func (s *Store) ExamPrepUserPracticeProgressInModule(ctx context.Context, userID, moduleID int64) (completed, total int32, err error) {
|
||||||
|
total, err = s.queries.CountPublishedExamPrepPracticesInModule(ctx, moduleID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
completed, err = s.queries.CountUserCompletedPublishedExamPrepPracticesInModule(ctx, dbgen.CountUserCompletedPublishedExamPrepPracticesInModuleParams{
|
||||||
|
UnitModuleID: moduleID,
|
||||||
|
UserID: userID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
return completed, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExamPrepUserPracticeProgressInUnit returns published practice completion counts in an exam-prep unit.
|
||||||
|
func (s *Store) ExamPrepUserPracticeProgressInUnit(ctx context.Context, userID, unitID int64) (completed, total int32, err error) {
|
||||||
|
total, err = s.queries.CountPublishedExamPrepPracticesInUnit(ctx, unitID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
completed, err = s.queries.CountUserCompletedPublishedExamPrepPracticesInUnit(ctx, dbgen.CountUserCompletedPublishedExamPrepPracticesInUnitParams{
|
||||||
|
UnitID: unitID,
|
||||||
|
UserID: userID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
return completed, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExamPrepUserPracticeProgressInCatalogCourse returns published practice completion counts in a catalog course.
|
||||||
|
func (s *Store) ExamPrepUserPracticeProgressInCatalogCourse(ctx context.Context, userID, catalogCourseID int64) (completed, total int32, err error) {
|
||||||
|
total, err = s.queries.CountPublishedExamPrepPracticesInCatalogCourse(ctx, catalogCourseID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
completed, err = s.queries.CountUserCompletedPublishedExamPrepPracticesInCatalogCourse(ctx, dbgen.CountUserCompletedPublishedExamPrepPracticesInCatalogCourseParams{
|
||||||
|
CatalogCourseID: catalogCourseID,
|
||||||
|
UserID: userID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
return completed, total, nil
|
||||||
|
}
|
||||||
|
|
@ -2,9 +2,11 @@ package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
dbgen "Yimaru-Backend/gen/db"
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CompleteLessonForUser records lesson completion for sequential lesson gating and
|
// CompleteLessonForUser records lesson completion for sequential lesson gating and
|
||||||
|
|
@ -60,6 +62,13 @@ func (s *Store) CompletePracticeForUser(ctx context.Context, userID, questionSet
|
||||||
|
|
||||||
scope, err := q.GetPracticeScopeByQuestionSetID(ctx, questionSetID)
|
scope, err := q.GetPracticeScopeByQuestionSetID(ctx, questionSetID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
// Exam-prep practices are not in lms_practices; completion is tracked in user_practice_progress only.
|
||||||
|
if err := tx.Commit(ctx); err != nil {
|
||||||
|
return fmt.Errorf("commit: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ func (s *Store) GetLMSUserProgressSnapshot(ctx context.Context, userID int64) (d
|
||||||
}
|
}
|
||||||
return domain.LMSUserProgress{
|
return domain.LMSUserProgress{
|
||||||
LessonIDs: pgInt8IDsToInt64(lessons),
|
LessonIDs: pgInt8IDsToInt64(lessons),
|
||||||
ModuleIDs: pgInt8IDsToInt64(mods),
|
ModuleIDs: int64IDsOrEmpty(mods),
|
||||||
CourseIDs: pgInt8IDsToInt64(courses),
|
CourseIDs: int64IDsOrEmpty(courses),
|
||||||
ProgramIDs: int64IDsOrEmpty(programs),
|
ProgramIDs: int64IDsOrEmpty(programs),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,66 @@ func (s *Service) ApplyAccessLesson(ctx context.Context, role domain.Role, userI
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplyExamPrepAccessCatalogCourse sets progress on an exam-prep catalog course for learner roles.
|
||||||
|
func (s *Service) ApplyExamPrepAccessCatalogCourse(ctx context.Context, role domain.Role, userID int64, cc *domain.ExamPrepCatalogCourse) error {
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
cc.Access = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
comp, tot, err := s.store.ExamPrepUserPracticeProgressInCatalogCourse(ctx, userID, cc.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
done := lmsProgressComplete(comp, tot)
|
||||||
|
cc.Access = buildLMSEntityAccess(true, "", done, comp, tot)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyExamPrepAccessUnit sets progress on an exam-prep unit for learner roles.
|
||||||
|
func (s *Service) ApplyExamPrepAccessUnit(ctx context.Context, role domain.Role, userID int64, u *domain.ExamPrepUnit) error {
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
u.Access = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
comp, tot, err := s.store.ExamPrepUserPracticeProgressInUnit(ctx, userID, u.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
done := lmsProgressComplete(comp, tot)
|
||||||
|
u.Access = buildLMSEntityAccess(true, "", done, comp, tot)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyExamPrepAccessModule sets progress on an exam-prep module for learner roles.
|
||||||
|
func (s *Service) ApplyExamPrepAccessModule(ctx context.Context, role domain.Role, userID int64, m *domain.ExamPrepModule) error {
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
m.Access = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
comp, tot, err := s.store.ExamPrepUserPracticeProgressInModule(ctx, userID, m.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
done := lmsProgressComplete(comp, tot)
|
||||||
|
m.Access = buildLMSEntityAccess(true, "", done, comp, tot)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyExamPrepAccessLesson sets progress on an exam-prep lesson for learner roles.
|
||||||
|
func (s *Service) ApplyExamPrepAccessLesson(ctx context.Context, role domain.Role, userID int64, les *domain.ExamPrepLesson) error {
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
les.Access = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
comp, tot, err := s.store.ExamPrepUserPracticeProgressInLesson(ctx, userID, les.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
done := lmsProgressComplete(comp, tot)
|
||||||
|
les.Access = buildLMSEntityAccess(true, "", done, comp, tot)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func lmsProgressComplete(completed, total int32) bool {
|
func lmsProgressComplete(completed, total int32) bool {
|
||||||
return total > 0 && completed >= total
|
return total > 0 && completed >= total
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,10 +116,18 @@ func (h *Handler) ListExamPrepCatalogCourses(c *fiber.Ctx) error {
|
||||||
end = total
|
end = total
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page := filtered[start:end]
|
||||||
|
if err := h.applyExamPrepAccessCatalogCourses(c.Context(), c, page); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to build catalog course list",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Catalog courses retrieved successfully",
|
Message: "Catalog courses retrieved successfully",
|
||||||
Data: fiber.Map{
|
Data: fiber.Map{
|
||||||
"catalog_courses": filtered[start:end],
|
"catalog_courses": page,
|
||||||
"total_count": total,
|
"total_count": total,
|
||||||
"limit": limit,
|
"limit": limit,
|
||||||
"offset": offset,
|
"offset": offset,
|
||||||
|
|
@ -136,6 +144,12 @@ func (h *Handler) ListExamPrepCatalogCourses(c *fiber.Ctx) error {
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := h.applyExamPrepAccessCatalogCourses(c.Context(), c, items); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to build catalog course list",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Catalog courses retrieved successfully",
|
Message: "Catalog courses retrieved successfully",
|
||||||
Data: fiber.Map{
|
Data: fiber.Map{
|
||||||
|
|
@ -218,6 +232,12 @@ func (h *Handler) GetExamPrepCatalogCourseByID(c *fiber.Ctx) error {
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := h.applyExamPrepAccessCatalogCourse(c.Context(), c, &out); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to build catalog course",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Catalog course retrieved successfully",
|
Message: "Catalog course retrieved successfully",
|
||||||
Data: out,
|
Data: out,
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,12 @@ func (h *Handler) ListExamPrepLessonsByUnitModule(c *fiber.Ctx) error {
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := h.applyExamPrepAccessLessons(c.Context(), c, items); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to build lesson list",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Lessons retrieved successfully",
|
Message: "Lessons retrieved successfully",
|
||||||
Data: fiber.Map{
|
Data: fiber.Map{
|
||||||
|
|
@ -175,6 +181,12 @@ func (h *Handler) GetExamPrepLessonByID(c *fiber.Ctx) error {
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := h.applyExamPrepAccessLesson(c.Context(), c, &les); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to build lesson",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Lesson retrieved successfully",
|
Message: "Lesson retrieved successfully",
|
||||||
Data: les,
|
Data: les,
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,12 @@ func (h *Handler) ListExamPrepModulesByUnit(c *fiber.Ctx) error {
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := h.applyExamPrepAccessModules(c.Context(), c, items); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to build module list",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Modules retrieved successfully",
|
Message: "Modules retrieved successfully",
|
||||||
Data: fiber.Map{
|
Data: fiber.Map{
|
||||||
|
|
@ -175,6 +181,12 @@ func (h *Handler) GetExamPrepModuleByID(c *fiber.Ctx) error {
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := h.applyExamPrepAccessModule(c.Context(), c, &out); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to build module",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Module retrieved successfully",
|
Message: "Module retrieved successfully",
|
||||||
Data: out,
|
Data: out,
|
||||||
|
|
|
||||||
125
internal/web_server/handlers/exam_prep_progress_helper.go
Normal file
125
internal/web_server/handlers/exam_prep_progress_helper.go
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Handler) applyExamPrepAccessCatalogCourses(ctx context.Context, c *fiber.Ctx, items []domain.ExamPrepCatalogCourse) error {
|
||||||
|
role, _ := c.Locals("role").(domain.Role)
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
|
if !ok || userID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := range items {
|
||||||
|
if err := h.lmsProgressSvc.ApplyExamPrepAccessCatalogCourse(ctx, role, userID, &items[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) applyExamPrepAccessCatalogCourse(ctx context.Context, c *fiber.Ctx, item *domain.ExamPrepCatalogCourse) error {
|
||||||
|
role, _ := c.Locals("role").(domain.Role)
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
|
if !ok || userID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return h.lmsProgressSvc.ApplyExamPrepAccessCatalogCourse(ctx, role, userID, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) applyExamPrepAccessUnits(ctx context.Context, c *fiber.Ctx, items []domain.ExamPrepUnit) error {
|
||||||
|
role, _ := c.Locals("role").(domain.Role)
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
|
if !ok || userID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := range items {
|
||||||
|
if err := h.lmsProgressSvc.ApplyExamPrepAccessUnit(ctx, role, userID, &items[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) applyExamPrepAccessUnit(ctx context.Context, c *fiber.Ctx, item *domain.ExamPrepUnit) error {
|
||||||
|
role, _ := c.Locals("role").(domain.Role)
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
|
if !ok || userID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return h.lmsProgressSvc.ApplyExamPrepAccessUnit(ctx, role, userID, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) applyExamPrepAccessModules(ctx context.Context, c *fiber.Ctx, items []domain.ExamPrepModule) error {
|
||||||
|
role, _ := c.Locals("role").(domain.Role)
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
|
if !ok || userID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := range items {
|
||||||
|
if err := h.lmsProgressSvc.ApplyExamPrepAccessModule(ctx, role, userID, &items[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) applyExamPrepAccessModule(ctx context.Context, c *fiber.Ctx, item *domain.ExamPrepModule) error {
|
||||||
|
role, _ := c.Locals("role").(domain.Role)
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
|
if !ok || userID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return h.lmsProgressSvc.ApplyExamPrepAccessModule(ctx, role, userID, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) applyExamPrepAccessLessons(ctx context.Context, c *fiber.Ctx, items []domain.ExamPrepLesson) error {
|
||||||
|
role, _ := c.Locals("role").(domain.Role)
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
|
if !ok || userID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := range items {
|
||||||
|
if err := h.lmsProgressSvc.ApplyExamPrepAccessLesson(ctx, role, userID, &items[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) applyExamPrepAccessLesson(ctx context.Context, c *fiber.Ctx, item *domain.ExamPrepLesson) error {
|
||||||
|
role, _ := c.Locals("role").(domain.Role)
|
||||||
|
if !role.IsCustomerLearnerRole() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
|
if !ok || userID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return h.lmsProgressSvc.ApplyExamPrepAccessLesson(ctx, role, userID, item)
|
||||||
|
}
|
||||||
|
|
@ -92,6 +92,12 @@ func (h *Handler) ListExamPrepUnitsByCatalogCourse(c *fiber.Ctx) error {
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := h.applyExamPrepAccessUnits(c.Context(), c, items); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to build unit list",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Units retrieved successfully",
|
Message: "Units retrieved successfully",
|
||||||
Data: fiber.Map{
|
Data: fiber.Map{
|
||||||
|
|
@ -183,6 +189,12 @@ func (h *Handler) GetExamPrepUnitByID(c *fiber.Ctx) error {
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err := h.applyExamPrepAccessUnit(c.Context(), c, &out); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to build unit",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Unit retrieved successfully",
|
Message: "Unit retrieved successfully",
|
||||||
Data: out,
|
Data: out,
|
||||||
|
|
|
||||||
|
|
@ -1573,6 +1573,14 @@ func (h *Handler) CompletePractice(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
set, setErr = h.questionsSvc.GetQuestionSetByID(c.Context(), practice.QuestionSetID)
|
set, setErr = h.questionsSvc.GetQuestionSetByID(c.Context(), practice.QuestionSetID)
|
||||||
|
} else if examPractice, examPracticeErr := h.examPrepSvc.GetExamPrepPracticeByID(c.Context(), id); examPracticeErr == nil {
|
||||||
|
if !examPractice.VisibleToLearners() {
|
||||||
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Only published practices can be completed",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
set, setErr = h.questionsSvc.GetQuestionSetByID(c.Context(), examPractice.QuestionSetID)
|
||||||
|
practiceErr = nil
|
||||||
} else {
|
} else {
|
||||||
// Backward compatibility: also accept question_set.id directly.
|
// Backward compatibility: also accept question_set.id directly.
|
||||||
set, setErr = h.questionsSvc.GetQuestionSetByID(c.Context(), id)
|
set, setErr = h.questionsSvc.GetQuestionSetByID(c.Context(), id)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user