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
|
||||
SELECT
|
||||
lp.module_id
|
||||
FROM
|
||||
lms_practices AS lp
|
||||
scoped.module_id
|
||||
FROM (
|
||||
SELECT
|
||||
m.id AS module_id,
|
||||
lp.question_set_id
|
||||
FROM
|
||||
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
|
||||
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.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
|
||||
scoped.module_id
|
||||
HAVING
|
||||
count(DISTINCT lp.question_set_id) > 0
|
||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
||||
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,
|
||||
lp.module_id ASC;
|
||||
scoped.module_id ASC;
|
||||
|
||||
-- name: ListLMSCompletedCourseIDsByUser :many
|
||||
SELECT
|
||||
lp.course_id
|
||||
FROM
|
||||
lms_practices AS lp
|
||||
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
|
||||
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.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
|
||||
scoped.course_id
|
||||
HAVING
|
||||
count(DISTINCT lp.question_set_id) > 0
|
||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
||||
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,
|
||||
lp.course_id ASC;
|
||||
scoped.course_id ASC;
|
||||
|
||||
-- name: ListLMSCompletedProgramIDsByUser :many
|
||||
SELECT
|
||||
c.program_id
|
||||
FROM
|
||||
lms_practices AS lp
|
||||
INNER JOIN courses c ON c.id = lp.course_id
|
||||
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
|
||||
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'
|
||||
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
|
||||
c.program_id
|
||||
scoped.program_id
|
||||
HAVING
|
||||
count(DISTINCT lp.question_set_id) > 0
|
||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
||||
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,
|
||||
c.program_id ASC;
|
||||
scoped.program_id ASC;
|
||||
|
||||
-- Lesson-based progress within a course (all modules).
|
||||
-- name: CountLessonsInCourse :one
|
||||
|
|
@ -340,7 +392,7 @@ WHERE
|
|||
AND ulp.user_id = $2
|
||||
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
|
||||
SELECT
|
||||
count(*)::int AS n
|
||||
|
|
@ -348,7 +400,15 @@ FROM
|
|||
lms_practices lp
|
||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||
WHERE
|
||||
(
|
||||
lp.module_id = $1
|
||||
OR lp.lesson_id IN (
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
lessons
|
||||
WHERE
|
||||
module_id = $1))
|
||||
AND qs.set_type = 'PRACTICE'
|
||||
AND qs.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 user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||
WHERE
|
||||
(
|
||||
lp.module_id = $1
|
||||
OR lp.lesson_id IN (
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
lessons
|
||||
WHERE
|
||||
module_id = $1))
|
||||
AND upp.user_id = $2
|
||||
AND upp.completed_at IS NOT NULL
|
||||
AND qs.set_type = 'PRACTICE'
|
||||
|
|
@ -375,7 +443,23 @@ FROM
|
|||
lms_practices lp
|
||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||
WHERE
|
||||
(
|
||||
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.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 user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||
WHERE
|
||||
(
|
||||
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.completed_at IS NOT NULL
|
||||
AND qs.set_type = 'PRACTICE'
|
||||
AND qs.status = 'PUBLISHED';
|
||||
AND qs.status = 'PUBLISHED'
|
||||
AND lp.publish_status = 'PUBLISHED';
|
||||
|
||||
-- name: CountPublishedPracticesInProgram :one
|
||||
SELECT
|
||||
count(*)::int AS n
|
||||
FROM
|
||||
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
|
||||
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.status = 'PUBLISHED'
|
||||
AND lp.publish_status = 'PUBLISHED';
|
||||
|
|
@ -412,11 +536,34 @@ SELECT
|
|||
count(*)::int AS n
|
||||
FROM
|
||||
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 user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||
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.completed_at IS NOT NULL
|
||||
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
|
||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||
WHERE
|
||||
(
|
||||
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.status = 'PUBLISHED'
|
||||
AND lp.publish_status = 'PUBLISHED'
|
||||
|
|
@ -146,13 +162,21 @@ FROM
|
|||
lms_practices lp
|
||||
INNER JOIN question_sets qs ON qs.id = lp.question_set_id
|
||||
WHERE
|
||||
(
|
||||
lp.module_id = $1
|
||||
OR lp.lesson_id IN (
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
lessons
|
||||
WHERE
|
||||
module_id = $1))
|
||||
AND qs.set_type = 'PRACTICE'
|
||||
AND qs.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) {
|
||||
row := q.db.QueryRow(ctx, CountPublishedPracticesInModule, moduleID)
|
||||
var n int32
|
||||
|
|
@ -165,10 +189,33 @@ SELECT
|
|||
count(*)::int AS n
|
||||
FROM
|
||||
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
|
||||
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.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 user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||
WHERE
|
||||
(
|
||||
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.completed_at IS NOT NULL
|
||||
AND qs.set_type = 'PRACTICE'
|
||||
AND qs.status = 'PUBLISHED'
|
||||
AND lp.publish_status = 'PUBLISHED'
|
||||
`
|
||||
|
||||
type CountUserCompletedPublishedPracticesInCourseParams struct {
|
||||
|
|
@ -365,7 +429,15 @@ FROM
|
|||
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
|
||||
WHERE
|
||||
(
|
||||
lp.module_id = $1
|
||||
OR lp.lesson_id IN (
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
lessons
|
||||
WHERE
|
||||
module_id = $1))
|
||||
AND upp.user_id = $2
|
||||
AND upp.completed_at IS NOT NULL
|
||||
AND qs.set_type = 'PRACTICE'
|
||||
|
|
@ -390,11 +462,34 @@ SELECT
|
|||
count(*)::int AS n
|
||||
FROM
|
||||
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 user_practice_progress upp ON upp.question_set_id = lp.question_set_id
|
||||
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.completed_at IS NOT NULL
|
||||
AND qs.set_type = 'PRACTICE'
|
||||
|
|
@ -640,37 +735,57 @@ func (q *Queries) InsertUserProgramProgress(ctx context.Context, arg InsertUserP
|
|||
|
||||
const ListLMSCompletedCourseIDsByUser = `-- name: ListLMSCompletedCourseIDsByUser :many
|
||||
SELECT
|
||||
lp.course_id
|
||||
FROM
|
||||
lms_practices AS lp
|
||||
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
|
||||
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.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
|
||||
scoped.course_id
|
||||
HAVING
|
||||
count(DISTINCT lp.question_set_id) > 0
|
||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
||||
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,
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []pgtype.Int8
|
||||
var items []int64
|
||||
for rows.Next() {
|
||||
var course_id pgtype.Int8
|
||||
var course_id int64
|
||||
if err := rows.Scan(&course_id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -728,37 +843,49 @@ func (q *Queries) ListLMSCompletedLessonIDsByUser(ctx context.Context, userID in
|
|||
|
||||
const ListLMSCompletedModuleIDsByUser = `-- name: ListLMSCompletedModuleIDsByUser :many
|
||||
SELECT
|
||||
lp.module_id
|
||||
FROM
|
||||
lms_practices AS lp
|
||||
scoped.module_id
|
||||
FROM (
|
||||
SELECT
|
||||
m.id AS module_id,
|
||||
lp.question_set_id
|
||||
FROM
|
||||
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
|
||||
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.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
|
||||
scoped.module_id
|
||||
HAVING
|
||||
count(DISTINCT lp.question_set_id) > 0
|
||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
||||
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,
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []pgtype.Int8
|
||||
var items []int64
|
||||
for rows.Next() {
|
||||
var module_id pgtype.Int8
|
||||
var module_id int64
|
||||
if err := rows.Scan(&module_id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -772,26 +899,46 @@ func (q *Queries) ListLMSCompletedModuleIDsByUser(ctx context.Context, userID in
|
|||
|
||||
const ListLMSCompletedProgramIDsByUser = `-- name: ListLMSCompletedProgramIDsByUser :many
|
||||
SELECT
|
||||
c.program_id
|
||||
FROM
|
||||
lms_practices AS lp
|
||||
INNER JOIN courses c ON c.id = lp.course_id
|
||||
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
|
||||
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'
|
||||
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
|
||||
c.program_id
|
||||
scoped.program_id
|
||||
HAVING
|
||||
count(DISTINCT lp.question_set_id) > 0
|
||||
AND count(DISTINCT upp.question_set_id) >= count(DISTINCT lp.question_set_id)
|
||||
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,
|
||||
c.program_id ASC
|
||||
scoped.program_id ASC
|
||||
`
|
||||
|
||||
func (q *Queries) ListLMSCompletedProgramIDsByUser(ctx context.Context, userID int64) ([]int64, error) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ type ExamPrepCatalogCourse struct {
|
|||
ModulesCount *int64 `json:"modules_count,omitempty"`
|
||||
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
||||
HasPractice bool `json:"has_practice"`
|
||||
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ type ExamPrepLesson struct {
|
|||
Description *string `json:"description,omitempty"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
HasPractice bool `json:"has_practice"`
|
||||
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ type ExamPrepModule struct {
|
|||
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
||||
PracticesCount *int64 `json:"practices_count,omitempty"`
|
||||
HasPractice bool `json:"has_practice"`
|
||||
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ type ExamPrepUnit struct {
|
|||
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
||||
PracticesCount *int64 `json:"practices_count,omitempty"`
|
||||
HasPractice bool `json:"has_practice"`
|
||||
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
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 (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
// 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)
|
||||
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
|
||||
}
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ func (s *Store) GetLMSUserProgressSnapshot(ctx context.Context, userID int64) (d
|
|||
}
|
||||
return domain.LMSUserProgress{
|
||||
LessonIDs: pgInt8IDsToInt64(lessons),
|
||||
ModuleIDs: pgInt8IDsToInt64(mods),
|
||||
CourseIDs: pgInt8IDsToInt64(courses),
|
||||
ModuleIDs: int64IDsOrEmpty(mods),
|
||||
CourseIDs: int64IDsOrEmpty(courses),
|
||||
ProgramIDs: int64IDsOrEmpty(programs),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,6 +234,66 @@ func (s *Service) ApplyAccessLesson(ctx context.Context, role domain.Role, userI
|
|||
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 {
|
||||
return total > 0 && completed >= total
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,10 +116,18 @@ func (h *Handler) ListExamPrepCatalogCourses(c *fiber.Ctx) error {
|
|||
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{
|
||||
Message: "Catalog courses retrieved successfully",
|
||||
Data: fiber.Map{
|
||||
"catalog_courses": filtered[start:end],
|
||||
"catalog_courses": page,
|
||||
"total_count": total,
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
|
|
@ -136,6 +144,12 @@ func (h *Handler) ListExamPrepCatalogCourses(c *fiber.Ctx) 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{
|
||||
Message: "Catalog courses retrieved successfully",
|
||||
Data: fiber.Map{
|
||||
|
|
@ -218,6 +232,12 @@ func (h *Handler) GetExamPrepCatalogCourseByID(c *fiber.Ctx) 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{
|
||||
Message: "Catalog course retrieved successfully",
|
||||
Data: out,
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@ func (h *Handler) ListExamPrepLessonsByUnitModule(c *fiber.Ctx) 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{
|
||||
Message: "Lessons retrieved successfully",
|
||||
Data: fiber.Map{
|
||||
|
|
@ -175,6 +181,12 @@ func (h *Handler) GetExamPrepLessonByID(c *fiber.Ctx) 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{
|
||||
Message: "Lesson retrieved successfully",
|
||||
Data: les,
|
||||
|
|
|
|||
|
|
@ -85,6 +85,12 @@ func (h *Handler) ListExamPrepModulesByUnit(c *fiber.Ctx) 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{
|
||||
Message: "Modules retrieved successfully",
|
||||
Data: fiber.Map{
|
||||
|
|
@ -175,6 +181,12 @@ func (h *Handler) GetExamPrepModuleByID(c *fiber.Ctx) 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{
|
||||
Message: "Module retrieved successfully",
|
||||
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(),
|
||||
})
|
||||
}
|
||||
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{
|
||||
Message: "Units retrieved successfully",
|
||||
Data: fiber.Map{
|
||||
|
|
@ -183,6 +189,12 @@ func (h *Handler) GetExamPrepUnitByID(c *fiber.Ctx) 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{
|
||||
Message: "Unit retrieved successfully",
|
||||
Data: out,
|
||||
|
|
|
|||
|
|
@ -1573,6 +1573,14 @@ func (h *Handler) CompletePractice(c *fiber.Ctx) error {
|
|||
})
|
||||
}
|
||||
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 {
|
||||
// Backward compatibility: also accept question_set.id directly.
|
||||
set, setErr = h.questionsSvc.GetQuestionSetByID(c.Context(), id)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user