Fix LMS sequential gating when sort_order has gaps.
Resolve the immediate predecessor by sort_order (and id) instead of requiring sort_order - 1, so learners cannot skip locked programs, courses, or modules when ordering numbers are non-consecutive. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
fbad083ca4
commit
c00ab684c5
|
|
@ -1,11 +1,23 @@
|
||||||
-- name: GetPreviousProgram :one
|
-- name: GetPreviousProgram :one
|
||||||
|
-- Immediate predecessor by sort_order within the same category (gaps in sort_order are allowed).
|
||||||
SELECT
|
SELECT
|
||||||
p2.*
|
p2.*
|
||||||
FROM
|
FROM
|
||||||
programs AS p1
|
programs AS p1
|
||||||
INNER JOIN programs AS p2 ON p2.sort_order = p1.sort_order - 1
|
INNER JOIN programs AS p2 ON p2.category = p1.category
|
||||||
|
AND (
|
||||||
|
p2.sort_order < p1.sort_order
|
||||||
|
OR (
|
||||||
|
p2.sort_order = p1.sort_order
|
||||||
|
AND p2.id < p1.id
|
||||||
|
)
|
||||||
|
)
|
||||||
WHERE
|
WHERE
|
||||||
p1.id = $1;
|
p1.id = $1
|
||||||
|
ORDER BY
|
||||||
|
p2.sort_order DESC,
|
||||||
|
p2.id DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
-- name: GetPreviousCourseInProgram :one
|
-- name: GetPreviousCourseInProgram :one
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -13,9 +25,19 @@ SELECT
|
||||||
FROM
|
FROM
|
||||||
courses AS c1
|
courses AS c1
|
||||||
INNER JOIN courses AS c2 ON c2.program_id = c1.program_id
|
INNER JOIN courses AS c2 ON c2.program_id = c1.program_id
|
||||||
AND c2.sort_order = c1.sort_order - 1
|
AND (
|
||||||
|
c2.sort_order < c1.sort_order
|
||||||
|
OR (
|
||||||
|
c2.sort_order = c1.sort_order
|
||||||
|
AND c2.id < c1.id
|
||||||
|
)
|
||||||
|
)
|
||||||
WHERE
|
WHERE
|
||||||
c1.id = $1;
|
c1.id = $1
|
||||||
|
ORDER BY
|
||||||
|
c2.sort_order DESC,
|
||||||
|
c2.id DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
-- name: GetPreviousModuleInCourse :one
|
-- name: GetPreviousModuleInCourse :one
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -23,9 +45,19 @@ SELECT
|
||||||
FROM
|
FROM
|
||||||
modules AS m1
|
modules AS m1
|
||||||
INNER JOIN modules AS m2 ON m2.course_id = m1.course_id
|
INNER JOIN modules AS m2 ON m2.course_id = m1.course_id
|
||||||
AND m2.sort_order = m1.sort_order - 1
|
AND (
|
||||||
|
m2.sort_order < m1.sort_order
|
||||||
|
OR (
|
||||||
|
m2.sort_order = m1.sort_order
|
||||||
|
AND m2.id < m1.id
|
||||||
|
)
|
||||||
|
)
|
||||||
WHERE
|
WHERE
|
||||||
m1.id = $1;
|
m1.id = $1
|
||||||
|
ORDER BY
|
||||||
|
m2.sort_order DESC,
|
||||||
|
m2.id DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
-- name: GetPreviousLessonInModule :one
|
-- name: GetPreviousLessonInModule :one
|
||||||
SELECT
|
SELECT
|
||||||
|
|
|
||||||
|
|
@ -647,9 +647,19 @@ SELECT
|
||||||
FROM
|
FROM
|
||||||
courses AS c1
|
courses AS c1
|
||||||
INNER JOIN courses AS c2 ON c2.program_id = c1.program_id
|
INNER JOIN courses AS c2 ON c2.program_id = c1.program_id
|
||||||
AND c2.sort_order = c1.sort_order - 1
|
AND (
|
||||||
|
c2.sort_order < c1.sort_order
|
||||||
|
OR (
|
||||||
|
c2.sort_order = c1.sort_order
|
||||||
|
AND c2.id < c1.id
|
||||||
|
)
|
||||||
|
)
|
||||||
WHERE
|
WHERE
|
||||||
c1.id = $1
|
c1.id = $1
|
||||||
|
ORDER BY
|
||||||
|
c2.sort_order DESC,
|
||||||
|
c2.id DESC
|
||||||
|
LIMIT 1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetPreviousCourseInProgram(ctx context.Context, id int64) (Course, error) {
|
func (q *Queries) GetPreviousCourseInProgram(ctx context.Context, id int64) (Course, error) {
|
||||||
|
|
@ -715,9 +725,19 @@ SELECT
|
||||||
FROM
|
FROM
|
||||||
modules AS m1
|
modules AS m1
|
||||||
INNER JOIN modules AS m2 ON m2.course_id = m1.course_id
|
INNER JOIN modules AS m2 ON m2.course_id = m1.course_id
|
||||||
AND m2.sort_order = m1.sort_order - 1
|
AND (
|
||||||
|
m2.sort_order < m1.sort_order
|
||||||
|
OR (
|
||||||
|
m2.sort_order = m1.sort_order
|
||||||
|
AND m2.id < m1.id
|
||||||
|
)
|
||||||
|
)
|
||||||
WHERE
|
WHERE
|
||||||
m1.id = $1
|
m1.id = $1
|
||||||
|
ORDER BY
|
||||||
|
m2.sort_order DESC,
|
||||||
|
m2.id DESC
|
||||||
|
LIMIT 1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetPreviousModuleInCourse(ctx context.Context, id int64) (Module, error) {
|
func (q *Queries) GetPreviousModuleInCourse(ctx context.Context, id int64) (Module, error) {
|
||||||
|
|
@ -742,11 +762,23 @@ SELECT
|
||||||
p2.id, p2.name, p2.description, p2.thumbnail, p2.created_at, p2.updated_at, p2.sort_order, p2.category
|
p2.id, p2.name, p2.description, p2.thumbnail, p2.created_at, p2.updated_at, p2.sort_order, p2.category
|
||||||
FROM
|
FROM
|
||||||
programs AS p1
|
programs AS p1
|
||||||
INNER JOIN programs AS p2 ON p2.sort_order = p1.sort_order - 1
|
INNER JOIN programs AS p2 ON p2.category = p1.category
|
||||||
|
AND (
|
||||||
|
p2.sort_order < p1.sort_order
|
||||||
|
OR (
|
||||||
|
p2.sort_order = p1.sort_order
|
||||||
|
AND p2.id < p1.id
|
||||||
|
)
|
||||||
|
)
|
||||||
WHERE
|
WHERE
|
||||||
p1.id = $1
|
p1.id = $1
|
||||||
|
ORDER BY
|
||||||
|
p2.sort_order DESC,
|
||||||
|
p2.id DESC
|
||||||
|
LIMIT 1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// Immediate predecessor by sort_order within the same category (gaps in sort_order are allowed).
|
||||||
func (q *Queries) GetPreviousProgram(ctx context.Context, id int64) (Program, error) {
|
func (q *Queries) GetPreviousProgram(ctx context.Context, id int64) (Program, error) {
|
||||||
row := q.db.QueryRow(ctx, GetPreviousProgram, id)
|
row := q.db.QueryRow(ctx, GetPreviousProgram, id)
|
||||||
var i Program
|
var i Program
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user