Compare commits
3 Commits
1026354c24
...
7ff0b639cf
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ff0b639cf | |||
| c5d3935062 | |||
| 518c3ee751 |
|
|
@ -0,0 +1,18 @@
|
||||||
|
-- Restores legacy lesson columns. Rows will have NULL question_set_id until repopulated.
|
||||||
|
|
||||||
|
ALTER TABLE sub_module_lessons
|
||||||
|
ADD COLUMN IF NOT EXISTS question_set_id BIGINT REFERENCES question_sets(id) ON DELETE CASCADE,
|
||||||
|
ADD COLUMN IF NOT EXISTS intro_video_url TEXT;
|
||||||
|
|
||||||
|
UPDATE sub_module_lessons
|
||||||
|
SET intro_video_url = teaching_video_url
|
||||||
|
WHERE teaching_video_url IS NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE sub_module_lessons
|
||||||
|
DROP COLUMN IF EXISTS title,
|
||||||
|
DROP COLUMN IF EXISTS description,
|
||||||
|
DROP COLUMN IF EXISTS thumbnail,
|
||||||
|
DROP COLUMN IF EXISTS teaching_text,
|
||||||
|
DROP COLUMN IF EXISTS teaching_image_url,
|
||||||
|
DROP COLUMN IF EXISTS teaching_audio_url,
|
||||||
|
DROP COLUMN IF EXISTS teaching_video_url;
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
-- Lessons are teaching content only (text, images, audio, video, thumbnail).
|
||||||
|
-- Question sets remain linked to practices, not lessons.
|
||||||
|
|
||||||
|
ALTER TABLE sub_module_lessons
|
||||||
|
ADD COLUMN IF NOT EXISTS title VARCHAR(255),
|
||||||
|
ADD COLUMN IF NOT EXISTS description TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS thumbnail TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS teaching_text TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS teaching_image_url TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS teaching_audio_url TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS teaching_video_url TEXT;
|
||||||
|
|
||||||
|
UPDATE sub_module_lessons sml
|
||||||
|
SET
|
||||||
|
title = qs.title,
|
||||||
|
description = qs.description
|
||||||
|
FROM question_sets qs
|
||||||
|
WHERE sml.question_set_id IS NOT NULL
|
||||||
|
AND qs.id = sml.question_set_id;
|
||||||
|
|
||||||
|
UPDATE sub_module_lessons
|
||||||
|
SET title = 'Lesson'
|
||||||
|
WHERE title IS NULL OR trim(title) = '';
|
||||||
|
|
||||||
|
UPDATE sub_module_lessons
|
||||||
|
SET teaching_video_url = intro_video_url
|
||||||
|
WHERE intro_video_url IS NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE sub_module_lessons DROP CONSTRAINT IF EXISTS sub_module_lessons_question_set_id_fkey;
|
||||||
|
ALTER TABLE sub_module_lessons DROP CONSTRAINT IF EXISTS sub_module_lessons_question_set_id_key;
|
||||||
|
|
||||||
|
ALTER TABLE sub_module_lessons DROP COLUMN IF EXISTS question_set_id;
|
||||||
|
ALTER TABLE sub_module_lessons DROP COLUMN IF EXISTS intro_video_url;
|
||||||
|
|
||||||
|
ALTER TABLE sub_module_lessons
|
||||||
|
ALTER COLUMN title SET NOT NULL,
|
||||||
|
ALTER COLUMN title SET DEFAULT 'Lesson';
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE levels
|
||||||
|
DROP COLUMN IF EXISTS title,
|
||||||
|
DROP COLUMN IF EXISTS description,
|
||||||
|
DROP COLUMN IF EXISTS thumbnail;
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
ALTER TABLE levels
|
||||||
|
ADD COLUMN IF NOT EXISTS title VARCHAR(255),
|
||||||
|
ADD COLUMN IF NOT EXISTS description TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS thumbnail TEXT;
|
||||||
|
|
||||||
|
UPDATE levels
|
||||||
|
SET title = cefr_level
|
||||||
|
WHERE title IS NULL OR trim(title) = '';
|
||||||
|
|
||||||
|
ALTER TABLE levels
|
||||||
|
ALTER COLUMN title SET NOT NULL;
|
||||||
12
db/migrations/000035_sub_module_capstones.down.sql
Normal file
12
db/migrations/000035_sub_module_capstones.down.sql
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
DROP INDEX IF EXISTS idx_sub_module_capstones_sub_module_id;
|
||||||
|
DROP TABLE IF EXISTS sub_module_capstones;
|
||||||
|
|
||||||
|
ALTER TABLE question_sets DROP CONSTRAINT IF EXISTS question_sets_set_type_check;
|
||||||
|
ALTER TABLE question_sets ADD CONSTRAINT question_sets_set_type_check
|
||||||
|
CHECK (set_type IN (
|
||||||
|
'PRACTICE',
|
||||||
|
'INITIAL_ASSESSMENT',
|
||||||
|
'QUIZ',
|
||||||
|
'EXAM',
|
||||||
|
'SURVEY'
|
||||||
|
));
|
||||||
29
db/migrations/000035_sub_module_capstones.up.sql
Normal file
29
db/migrations/000035_sub_module_capstones.up.sql
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
-- Capstone assessments: sub-module scoped, backed by question_sets (type CAPSTONE).
|
||||||
|
|
||||||
|
ALTER TABLE question_sets DROP CONSTRAINT IF EXISTS question_sets_set_type_check;
|
||||||
|
ALTER TABLE question_sets ADD CONSTRAINT question_sets_set_type_check
|
||||||
|
CHECK (set_type IN (
|
||||||
|
'PRACTICE',
|
||||||
|
'INITIAL_ASSESSMENT',
|
||||||
|
'QUIZ',
|
||||||
|
'EXAM',
|
||||||
|
'SURVEY',
|
||||||
|
'CAPSTONE'
|
||||||
|
));
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS sub_module_capstones (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
sub_module_id BIGINT NOT NULL REFERENCES sub_modules(id) ON DELETE CASCADE,
|
||||||
|
title VARCHAR(255) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
tips TEXT,
|
||||||
|
thumbnail TEXT,
|
||||||
|
question_set_id BIGINT NOT NULL REFERENCES question_sets(id) ON DELETE CASCADE,
|
||||||
|
display_order INT NOT NULL DEFAULT 0,
|
||||||
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE (question_set_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_sub_module_capstones_sub_module_id
|
||||||
|
ON sub_module_capstones (sub_module_id);
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
DROP INDEX IF EXISTS idx_module_capstones_module_id;
|
||||||
|
DROP TABLE IF EXISTS module_capstones;
|
||||||
|
|
||||||
|
ALTER TABLE modules DROP COLUMN IF EXISTS icon_url;
|
||||||
19
db/migrations/000036_module_icon_and_module_capstones.up.sql
Normal file
19
db/migrations/000036_module_icon_and_module_capstones.up.sql
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
ALTER TABLE modules
|
||||||
|
ADD COLUMN IF NOT EXISTS icon_url TEXT;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS module_capstones (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
module_id BIGINT NOT NULL REFERENCES modules(id) ON DELETE CASCADE,
|
||||||
|
title VARCHAR(255) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
tips TEXT,
|
||||||
|
thumbnail TEXT,
|
||||||
|
question_set_id BIGINT NOT NULL REFERENCES question_sets(id) ON DELETE CASCADE,
|
||||||
|
display_order INT NOT NULL DEFAULT 0,
|
||||||
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE (question_set_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_module_capstones_module_id
|
||||||
|
ON module_capstones (module_id);
|
||||||
3
db/migrations/000037_sub_modules_thumbnail_tips.down.sql
Normal file
3
db/migrations/000037_sub_modules_thumbnail_tips.down.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE sub_modules
|
||||||
|
DROP COLUMN IF EXISTS tips,
|
||||||
|
DROP COLUMN IF EXISTS thumbnail;
|
||||||
3
db/migrations/000037_sub_modules_thumbnail_tips.up.sql
Normal file
3
db/migrations/000037_sub_modules_thumbnail_tips.up.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE sub_modules
|
||||||
|
ADD COLUMN IF NOT EXISTS thumbnail TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS tips TEXT;
|
||||||
|
|
@ -83,43 +83,17 @@ WHERE sub_module_id = $1
|
||||||
ORDER BY display_order ASC, id ASC;
|
ORDER BY display_order ASC, id ASC;
|
||||||
|
|
||||||
-- name: GetSubModuleLessons :many
|
-- name: GetSubModuleLessons :many
|
||||||
SELECT
|
SELECT *
|
||||||
smp.id,
|
FROM sub_module_lessons
|
||||||
smp.sub_module_id,
|
WHERE sub_module_id = $1
|
||||||
smp.question_set_id,
|
AND is_active = TRUE
|
||||||
smp.intro_video_url,
|
ORDER BY display_order ASC, id ASC;
|
||||||
smp.display_order,
|
|
||||||
smp.is_active,
|
|
||||||
qs.title,
|
|
||||||
qs.description,
|
|
||||||
qs.status,
|
|
||||||
qs.set_type,
|
|
||||||
(SELECT COUNT(*) FROM question_set_items qsi WHERE qsi.set_id = qs.id) AS question_count
|
|
||||||
FROM sub_module_lessons smp
|
|
||||||
JOIN question_sets qs ON qs.id = smp.question_set_id
|
|
||||||
WHERE smp.sub_module_id = $1
|
|
||||||
AND smp.is_active = TRUE
|
|
||||||
AND qs.set_type = 'QUIZ'
|
|
||||||
ORDER BY smp.display_order ASC, smp.id ASC;
|
|
||||||
|
|
||||||
-- name: GetSubModuleLessonByID :one
|
-- name: GetSubModuleLessonByID :one
|
||||||
SELECT
|
SELECT *
|
||||||
smp.id,
|
FROM sub_module_lessons
|
||||||
smp.sub_module_id,
|
WHERE id = $1
|
||||||
smp.question_set_id,
|
AND is_active = TRUE;
|
||||||
smp.intro_video_url,
|
|
||||||
smp.display_order,
|
|
||||||
smp.is_active,
|
|
||||||
qs.title,
|
|
||||||
qs.description,
|
|
||||||
qs.status,
|
|
||||||
qs.set_type,
|
|
||||||
(SELECT COUNT(*) FROM question_set_items qsi WHERE qsi.set_id = qs.id) AS question_count
|
|
||||||
FROM sub_module_lessons smp
|
|
||||||
JOIN question_sets qs ON qs.id = smp.question_set_id
|
|
||||||
WHERE smp.id = $1
|
|
||||||
AND smp.is_active = TRUE
|
|
||||||
AND qs.set_type = 'QUIZ';
|
|
||||||
|
|
||||||
-- name: GetSubModulePractices :many
|
-- name: GetSubModulePractices :many
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -162,16 +136,71 @@ WHERE smp.id = $1
|
||||||
AND smp.is_active = TRUE
|
AND smp.is_active = TRUE
|
||||||
AND qs.set_type = 'PRACTICE';
|
AND qs.set_type = 'PRACTICE';
|
||||||
|
|
||||||
|
-- name: GetSubModuleCapstones :many
|
||||||
|
SELECT
|
||||||
|
smc.id,
|
||||||
|
smc.sub_module_id,
|
||||||
|
smc.title,
|
||||||
|
smc.description,
|
||||||
|
smc.tips,
|
||||||
|
smc.thumbnail,
|
||||||
|
smc.question_set_id,
|
||||||
|
smc.display_order,
|
||||||
|
smc.is_active,
|
||||||
|
qs.status,
|
||||||
|
qs.set_type,
|
||||||
|
qs.time_limit_minutes,
|
||||||
|
qs.passing_score,
|
||||||
|
qs.shuffle_questions,
|
||||||
|
(SELECT COUNT(*) FROM question_set_items qsi WHERE qsi.set_id = qs.id) AS question_count
|
||||||
|
FROM sub_module_capstones smc
|
||||||
|
JOIN question_sets qs ON qs.id = smc.question_set_id
|
||||||
|
WHERE smc.sub_module_id = $1
|
||||||
|
AND smc.is_active = TRUE
|
||||||
|
AND qs.set_type = 'CAPSTONE'
|
||||||
|
ORDER BY smc.display_order ASC, smc.id ASC;
|
||||||
|
|
||||||
|
-- name: GetSubModuleCapstoneByID :one
|
||||||
|
SELECT
|
||||||
|
smc.id,
|
||||||
|
smc.sub_module_id,
|
||||||
|
smc.title,
|
||||||
|
smc.description,
|
||||||
|
smc.tips,
|
||||||
|
smc.thumbnail,
|
||||||
|
smc.question_set_id,
|
||||||
|
smc.display_order,
|
||||||
|
smc.is_active,
|
||||||
|
qs.status,
|
||||||
|
qs.set_type,
|
||||||
|
qs.time_limit_minutes,
|
||||||
|
qs.passing_score,
|
||||||
|
qs.shuffle_questions,
|
||||||
|
(SELECT COUNT(*) FROM question_set_items qsi WHERE qsi.set_id = qs.id) AS question_count
|
||||||
|
FROM sub_module_capstones smc
|
||||||
|
JOIN question_sets qs ON qs.id = smc.question_set_id
|
||||||
|
WHERE smc.id = $1
|
||||||
|
AND smc.is_active = TRUE
|
||||||
|
AND qs.set_type = 'CAPSTONE';
|
||||||
|
|
||||||
-- name: GetFullHierarchyByCourseID :many
|
-- name: GetFullHierarchyByCourseID :many
|
||||||
SELECT
|
SELECT
|
||||||
c.id AS course_id,
|
c.id AS course_id,
|
||||||
c.title AS course_title,
|
c.title AS course_title,
|
||||||
l.id AS level_id,
|
l.id AS level_id,
|
||||||
l.cefr_level,
|
l.cefr_level,
|
||||||
|
l.title AS level_title,
|
||||||
|
l.description AS level_description,
|
||||||
|
l.thumbnail AS level_thumbnail,
|
||||||
m.id AS module_id,
|
m.id AS module_id,
|
||||||
m.title AS module_title,
|
m.title AS module_title,
|
||||||
|
m.icon_url AS module_icon_url,
|
||||||
sm.id AS sub_module_id,
|
sm.id AS sub_module_id,
|
||||||
sm.title AS sub_module_title
|
sm.title AS sub_module_title,
|
||||||
|
sm.description AS sub_module_description,
|
||||||
|
sm.thumbnail AS sub_module_thumbnail,
|
||||||
|
sm.tips AS sub_module_tips,
|
||||||
|
sm.display_order AS sub_module_display_order
|
||||||
FROM courses c
|
FROM courses c
|
||||||
LEFT JOIN levels l ON l.course_id = c.id AND l.is_active = TRUE
|
LEFT JOIN levels l ON l.course_id = c.id AND l.is_active = TRUE
|
||||||
LEFT JOIN modules m ON m.level_id = l.id AND m.is_active = TRUE
|
LEFT JOIN modules m ON m.level_id = l.id AND m.is_active = TRUE
|
||||||
|
|
@ -232,10 +261,24 @@ OFFSET sqlc.narg('offset')::INT;
|
||||||
INSERT INTO levels (
|
INSERT INTO levels (
|
||||||
course_id,
|
course_id,
|
||||||
cefr_level,
|
cefr_level,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail,
|
||||||
display_order,
|
display_order,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, COALESCE($3, 0), COALESCE($4, TRUE))
|
VALUES ($1, $2, $3, $4, $5, COALESCE($6, 0), COALESCE($7, TRUE))
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateLevel :one
|
||||||
|
UPDATE levels
|
||||||
|
SET
|
||||||
|
title = $1,
|
||||||
|
description = $2,
|
||||||
|
thumbnail = $3,
|
||||||
|
display_order = $4,
|
||||||
|
is_active = $5
|
||||||
|
WHERE id = $6
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: CreateModule :one
|
-- name: CreateModule :one
|
||||||
|
|
@ -243,10 +286,22 @@ INSERT INTO modules (
|
||||||
level_id,
|
level_id,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
icon_url,
|
||||||
display_order,
|
display_order,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, COALESCE($4, 0), COALESCE($5, TRUE))
|
VALUES ($1, $2, $3, $4, COALESCE($5, 0), COALESCE($6, TRUE))
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateModule :one
|
||||||
|
UPDATE modules
|
||||||
|
SET
|
||||||
|
title = $1,
|
||||||
|
description = $2,
|
||||||
|
icon_url = $3,
|
||||||
|
display_order = $4,
|
||||||
|
is_active = $5
|
||||||
|
WHERE id = $6
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: CreateSubModule :one
|
-- name: CreateSubModule :one
|
||||||
|
|
@ -254,10 +309,24 @@ INSERT INTO sub_modules (
|
||||||
module_id,
|
module_id,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
thumbnail,
|
||||||
|
tips,
|
||||||
display_order,
|
display_order,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, COALESCE($4, 0), COALESCE($5, TRUE))
|
VALUES ($1, $2, $3, $4, $5, COALESCE($6, 0), COALESCE($7, TRUE))
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateSubModule :one
|
||||||
|
UPDATE sub_modules
|
||||||
|
SET
|
||||||
|
title = $1,
|
||||||
|
description = $2,
|
||||||
|
thumbnail = $3,
|
||||||
|
tips = $4,
|
||||||
|
display_order = $5,
|
||||||
|
is_active = $6
|
||||||
|
WHERE id = $7
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: CreateSubModuleVideo :one
|
-- name: CreateSubModuleVideo :one
|
||||||
|
|
@ -289,26 +358,47 @@ VALUES (
|
||||||
)
|
)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: AttachQuestionSetLessonToSubModule :one
|
-- name: CreateSubModuleLesson :one
|
||||||
INSERT INTO sub_module_lessons (
|
INSERT INTO sub_module_lessons (
|
||||||
sub_module_id,
|
sub_module_id,
|
||||||
question_set_id,
|
title,
|
||||||
intro_video_url,
|
description,
|
||||||
|
thumbnail,
|
||||||
|
teaching_text,
|
||||||
|
teaching_image_url,
|
||||||
|
teaching_audio_url,
|
||||||
|
teaching_video_url,
|
||||||
display_order,
|
display_order,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, COALESCE($4, 0), COALESCE($5, TRUE))
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7,
|
||||||
|
$8,
|
||||||
|
COALESCE($9, 0),
|
||||||
|
COALESCE($10, TRUE)
|
||||||
|
)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: UpdateSubModuleLesson :one
|
-- name: UpdateSubModuleLesson :one
|
||||||
UPDATE sub_module_lessons
|
UPDATE sub_module_lessons
|
||||||
SET
|
SET
|
||||||
sub_module_id = $1,
|
sub_module_id = $1,
|
||||||
question_set_id = $2,
|
title = $2,
|
||||||
intro_video_url = $3,
|
description = $3,
|
||||||
display_order = $4,
|
thumbnail = $4,
|
||||||
is_active = $5
|
teaching_text = $5,
|
||||||
WHERE id = $6
|
teaching_image_url = $6,
|
||||||
|
teaching_audio_url = $7,
|
||||||
|
teaching_video_url = $8,
|
||||||
|
display_order = $9,
|
||||||
|
is_active = $10
|
||||||
|
WHERE id = $11
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: CreateSubModulePractice :one
|
-- name: CreateSubModulePractice :one
|
||||||
|
|
@ -325,3 +415,102 @@ INSERT INTO sub_module_practices (
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, 0), COALESCE($8, TRUE))
|
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, 0), COALESCE($8, TRUE))
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: CreateSubModuleCapstone :one
|
||||||
|
INSERT INTO sub_module_capstones (
|
||||||
|
sub_module_id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
tips,
|
||||||
|
thumbnail,
|
||||||
|
question_set_id,
|
||||||
|
display_order,
|
||||||
|
is_active
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, 0), COALESCE($8, TRUE))
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateSubModuleCapstone :one
|
||||||
|
UPDATE sub_module_capstones
|
||||||
|
SET
|
||||||
|
title = $1,
|
||||||
|
description = $2,
|
||||||
|
tips = $3,
|
||||||
|
thumbnail = $4,
|
||||||
|
display_order = $5,
|
||||||
|
is_active = $6
|
||||||
|
WHERE id = $7
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetModuleCapstones :many
|
||||||
|
SELECT
|
||||||
|
mc.id,
|
||||||
|
mc.module_id,
|
||||||
|
mc.title,
|
||||||
|
mc.description,
|
||||||
|
mc.tips,
|
||||||
|
mc.thumbnail,
|
||||||
|
mc.question_set_id,
|
||||||
|
mc.display_order,
|
||||||
|
mc.is_active,
|
||||||
|
qs.status,
|
||||||
|
qs.set_type,
|
||||||
|
qs.time_limit_minutes,
|
||||||
|
qs.passing_score,
|
||||||
|
qs.shuffle_questions,
|
||||||
|
(SELECT COUNT(*) FROM question_set_items qsi WHERE qsi.set_id = qs.id) AS question_count
|
||||||
|
FROM module_capstones mc
|
||||||
|
JOIN question_sets qs ON qs.id = mc.question_set_id
|
||||||
|
WHERE mc.module_id = $1
|
||||||
|
AND mc.is_active = TRUE
|
||||||
|
AND qs.set_type = 'CAPSTONE'
|
||||||
|
ORDER BY mc.display_order ASC, mc.id ASC;
|
||||||
|
|
||||||
|
-- name: GetModuleCapstoneByID :one
|
||||||
|
SELECT
|
||||||
|
mc.id,
|
||||||
|
mc.module_id,
|
||||||
|
mc.title,
|
||||||
|
mc.description,
|
||||||
|
mc.tips,
|
||||||
|
mc.thumbnail,
|
||||||
|
mc.question_set_id,
|
||||||
|
mc.display_order,
|
||||||
|
mc.is_active,
|
||||||
|
qs.status,
|
||||||
|
qs.set_type,
|
||||||
|
qs.time_limit_minutes,
|
||||||
|
qs.passing_score,
|
||||||
|
qs.shuffle_questions,
|
||||||
|
(SELECT COUNT(*) FROM question_set_items qsi WHERE qsi.set_id = qs.id) AS question_count
|
||||||
|
FROM module_capstones mc
|
||||||
|
JOIN question_sets qs ON qs.id = mc.question_set_id
|
||||||
|
WHERE mc.id = $1
|
||||||
|
AND mc.is_active = TRUE
|
||||||
|
AND qs.set_type = 'CAPSTONE';
|
||||||
|
|
||||||
|
-- name: CreateModuleCapstone :one
|
||||||
|
INSERT INTO module_capstones (
|
||||||
|
module_id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
tips,
|
||||||
|
thumbnail,
|
||||||
|
question_set_id,
|
||||||
|
display_order,
|
||||||
|
is_active
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, 0), COALESCE($8, TRUE))
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateModuleCapstone :one
|
||||||
|
UPDATE module_capstones
|
||||||
|
SET
|
||||||
|
title = $1,
|
||||||
|
description = $2,
|
||||||
|
tips = $3,
|
||||||
|
thumbnail = $4,
|
||||||
|
display_order = $5,
|
||||||
|
is_active = $6
|
||||||
|
WHERE id = $7
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
|
|
||||||
1803
docs/docs.go
1803
docs/docs.go
File diff suppressed because it is too large
Load Diff
1803
docs/swagger.json
1803
docs/swagger.json
File diff suppressed because it is too large
Load Diff
1211
docs/swagger.yaml
1211
docs/swagger.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
func (q *Queries) GetSubModuleByIDCompat(ctx context.Context, id int64) (SubModule, error) {
|
func (q *Queries) GetSubModuleByIDCompat(ctx context.Context, id int64) (SubModule, error) {
|
||||||
row := q.db.QueryRow(ctx, `
|
row := q.db.QueryRow(ctx, `
|
||||||
SELECT id, module_id, title, description, display_order, is_active, created_at, legacy_sub_course_id
|
SELECT id, module_id, title, description, display_order, is_active, created_at, legacy_sub_course_id, thumbnail, tips
|
||||||
FROM sub_modules
|
FROM sub_modules
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`, id)
|
`, id)
|
||||||
|
|
@ -22,19 +22,24 @@ WHERE id = $1
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.LegacySubCourseID,
|
&i.LegacySubCourseID,
|
||||||
|
&i.Thumbnail,
|
||||||
|
&i.Tips,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateSubModuleCompat(ctx context.Context, id int64, title string, description string, isActive bool) error {
|
func (q *Queries) UpdateSubModuleCompat(ctx context.Context, id int64, title string, description string, thumbnail string, tips string, displayOrder int32, isActive bool) error {
|
||||||
_, err := q.db.Exec(ctx, `
|
_, err := q.db.Exec(ctx, `
|
||||||
UPDATE sub_modules
|
UPDATE sub_modules
|
||||||
SET
|
SET
|
||||||
title = $1,
|
title = $1,
|
||||||
description = NULLIF($2, ''),
|
description = NULLIF($2, ''),
|
||||||
is_active = $3
|
thumbnail = NULLIF($3, ''),
|
||||||
WHERE id = $4
|
tips = NULLIF($4, ''),
|
||||||
`, title, description, isActive, id)
|
display_order = $5,
|
||||||
|
is_active = $6
|
||||||
|
WHERE id = $7
|
||||||
|
`, title, description, thumbnail, tips, displayOrder, isActive, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,6 +124,24 @@ func (q *Queries) DeletePracticeCompat(ctx context.Context, id int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteCapstoneCompat removes the backing question set (and cascades sub_module_capstones).
|
||||||
|
func (q *Queries) DeleteCapstoneCompat(ctx context.Context, capstoneID int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, `
|
||||||
|
DELETE FROM question_sets
|
||||||
|
WHERE id = (SELECT question_set_id FROM sub_module_capstones WHERE id = $1)
|
||||||
|
`, capstoneID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteModuleCapstoneCompat removes the backing question set (and cascades module_capstones).
|
||||||
|
func (q *Queries) DeleteModuleCapstoneCompat(ctx context.Context, capstoneID int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, `
|
||||||
|
DELETE FROM question_sets
|
||||||
|
WHERE id = (SELECT question_set_id FROM module_capstones WHERE id = $1)
|
||||||
|
`, capstoneID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateCourseCompat(
|
func (q *Queries) CreateCourseCompat(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
categoryID int64,
|
categoryID int64,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -76,6 +76,9 @@ type Level struct {
|
||||||
DisplayOrder int32 `json:"display_order"`
|
DisplayOrder int32 `json:"display_order"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LevelToSubCourse struct {
|
type LevelToSubCourse struct {
|
||||||
|
|
@ -91,6 +94,20 @@ type Module struct {
|
||||||
DisplayOrder int32 `json:"display_order"`
|
DisplayOrder int32 `json:"display_order"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
IconUrl pgtype.Text `json:"icon_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModuleCapstone struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
ModuleID int64 `json:"module_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Tips pgtype.Text `json:"tips"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
QuestionSetID int64 `json:"question_set_id"`
|
||||||
|
DisplayOrder int32 `json:"display_order"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModuleToSubCourse struct {
|
type ModuleToSubCourse struct {
|
||||||
|
|
@ -353,18 +370,38 @@ type SubModule struct {
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
LegacySubCourseID pgtype.Int8 `json:"legacy_sub_course_id"`
|
LegacySubCourseID pgtype.Int8 `json:"legacy_sub_course_id"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
Tips pgtype.Text `json:"tips"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubModuleLesson struct {
|
type SubModuleCapstone struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
SubModuleID int64 `json:"sub_module_id"`
|
SubModuleID int64 `json:"sub_module_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Tips pgtype.Text `json:"tips"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
QuestionSetID int64 `json:"question_set_id"`
|
QuestionSetID int64 `json:"question_set_id"`
|
||||||
IntroVideoUrl pgtype.Text `json:"intro_video_url"`
|
|
||||||
DisplayOrder int32 `json:"display_order"`
|
DisplayOrder int32 `json:"display_order"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SubModuleLesson struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
SubModuleID int64 `json:"sub_module_id"`
|
||||||
|
DisplayOrder int32 `json:"display_order"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
TeachingText pgtype.Text `json:"teaching_text"`
|
||||||
|
TeachingImageUrl pgtype.Text `json:"teaching_image_url"`
|
||||||
|
TeachingAudioUrl pgtype.Text `json:"teaching_audio_url"`
|
||||||
|
TeachingVideoUrl pgtype.Text `json:"teaching_video_url"`
|
||||||
|
}
|
||||||
|
|
||||||
type SubModulePractice struct {
|
type SubModulePractice struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
SubModuleID int64 `json:"sub_module_id"`
|
SubModuleID int64 `json:"sub_module_id"`
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ type LearningPathSubCourse struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
Thumbnail *string `json:"thumbnail,omitempty"`
|
Thumbnail *string `json:"thumbnail,omitempty"`
|
||||||
|
Tips *string `json:"tips,omitempty"`
|
||||||
DisplayOrder int32 `json:"display_order"`
|
DisplayOrder int32 `json:"display_order"`
|
||||||
Level string `json:"level"`
|
Level string `json:"level"`
|
||||||
SubLevel string `json:"sub_level"`
|
SubLevel string `json:"sub_level"`
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ const (
|
||||||
QuestionSetTypeQuiz QuestionSetType = "QUIZ"
|
QuestionSetTypeQuiz QuestionSetType = "QUIZ"
|
||||||
QuestionSetTypeExam QuestionSetType = "EXAM"
|
QuestionSetTypeExam QuestionSetType = "EXAM"
|
||||||
QuestionSetTypeSurvey QuestionSetType = "SURVEY"
|
QuestionSetTypeSurvey QuestionSetType = "SURVEY"
|
||||||
|
QuestionSetTypeCapstone QuestionSetType = "CAPSTONE"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PracticeAccessBlock struct {
|
type PracticeAccessBlock struct {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -515,7 +515,7 @@ func (h *Handler) DeleteQuestion(c *fiber.Ctx) error {
|
||||||
type createQuestionSetReq struct {
|
type createQuestionSetReq struct {
|
||||||
Title string `json:"title" validate:"required"`
|
Title string `json:"title" validate:"required"`
|
||||||
Description *string `json:"description"`
|
Description *string `json:"description"`
|
||||||
SetType string `json:"set_type" validate:"required,oneof=PRACTICE INITIAL_ASSESSMENT QUIZ EXAM SURVEY"`
|
SetType string `json:"set_type" validate:"required,oneof=PRACTICE INITIAL_ASSESSMENT QUIZ EXAM SURVEY CAPSTONE"`
|
||||||
OwnerType *string `json:"owner_type"`
|
OwnerType *string `json:"owner_type"`
|
||||||
OwnerID *int64 `json:"owner_id"`
|
OwnerID *int64 `json:"owner_id"`
|
||||||
BannerImage *string `json:"banner_image"`
|
BannerImage *string `json:"banner_image"`
|
||||||
|
|
@ -791,7 +791,7 @@ func (h *Handler) GetQuestionSetByID(c *fiber.Ctx) error {
|
||||||
// @Description Returns a paginated list of question sets filtered by type
|
// @Description Returns a paginated list of question sets filtered by type
|
||||||
// @Tags question-sets
|
// @Tags question-sets
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param set_type query string true "Set type (PRACTICE, INITIAL_ASSESSMENT, QUIZ, EXAM, SURVEY)"
|
// @Param set_type query string true "Set type (PRACTICE, INITIAL_ASSESSMENT, QUIZ, EXAM, SURVEY, CAPSTONE)"
|
||||||
// @Param limit query int false "Limit" default(10)
|
// @Param limit query int false "Limit" default(10)
|
||||||
// @Param offset query int false "Offset" default(0)
|
// @Param offset query int false "Offset" default(0)
|
||||||
// @Success 200 {object} domain.Response
|
// @Success 200 {object} domain.Response
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,9 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Post("/course-management/sub-categories", a.authMiddleware, a.RequirePermission("course_categories.create"), h.CreateCourseSubCategory)
|
groupV1.Post("/course-management/sub-categories", a.authMiddleware, a.RequirePermission("course_categories.create"), h.CreateCourseSubCategory)
|
||||||
groupV1.Delete("/course-management/sub-categories/:subCategoryId", a.authMiddleware, a.RequirePermission("course_categories.delete"), h.DeleteCourseSubCategory)
|
groupV1.Delete("/course-management/sub-categories/:subCategoryId", a.authMiddleware, a.RequirePermission("course_categories.delete"), h.DeleteCourseSubCategory)
|
||||||
groupV1.Post("/course-management/levels", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateLevel)
|
groupV1.Post("/course-management/levels", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateLevel)
|
||||||
|
groupV1.Put("/course-management/levels/:levelId", a.authMiddleware, a.RequirePermission("subcourses.update"), h.UpdateLevel)
|
||||||
groupV1.Post("/course-management/modules", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateModule)
|
groupV1.Post("/course-management/modules", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateModule)
|
||||||
|
groupV1.Put("/course-management/modules/:moduleId", a.authMiddleware, a.RequirePermission("subcourses.update"), h.UpdateModule)
|
||||||
groupV1.Delete("/course-management/modules/:moduleId", a.authMiddleware, a.RequirePermission("subcourses.delete"), h.DeleteModule)
|
groupV1.Delete("/course-management/modules/:moduleId", a.authMiddleware, a.RequirePermission("subcourses.delete"), h.DeleteModule)
|
||||||
groupV1.Post("/course-management/sub-modules", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateSubModule)
|
groupV1.Post("/course-management/sub-modules", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateSubModule)
|
||||||
groupV1.Put("/course-management/sub-modules/:subModuleId", a.authMiddleware, a.RequirePermission("subcourses.update"), h.UpdateSubModule)
|
groupV1.Put("/course-management/sub-modules/:subModuleId", a.authMiddleware, a.RequirePermission("subcourses.update"), h.UpdateSubModule)
|
||||||
|
|
@ -116,15 +118,25 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Post("/course-management/sub-module-videos", a.authMiddleware, a.RequirePermission("videos.create"), h.CreateSubModuleVideo)
|
groupV1.Post("/course-management/sub-module-videos", a.authMiddleware, a.RequirePermission("videos.create"), h.CreateSubModuleVideo)
|
||||||
groupV1.Put("/course-management/sub-module-videos/:videoId", a.authMiddleware, a.RequirePermission("videos.update"), h.UpdateSubModuleVideo)
|
groupV1.Put("/course-management/sub-module-videos/:videoId", a.authMiddleware, a.RequirePermission("videos.update"), h.UpdateSubModuleVideo)
|
||||||
groupV1.Delete("/course-management/sub-module-videos/:videoId", a.authMiddleware, a.RequirePermission("videos.delete"), h.DeleteSubModuleVideo)
|
groupV1.Delete("/course-management/sub-module-videos/:videoId", a.authMiddleware, a.RequirePermission("videos.delete"), h.DeleteSubModuleVideo)
|
||||||
groupV1.Get("/course-management/sub-modules/:subModuleId/lessons", a.authMiddleware, a.RequirePermission("question_sets.list"), h.GetSubModuleLessons)
|
groupV1.Get("/course-management/sub-modules/:subModuleId/lessons", a.authMiddleware, a.RequirePermission("learning_tree.get"), h.GetSubModuleLessons)
|
||||||
groupV1.Get("/course-management/sub-module-lessons/:lessonId", a.authMiddleware, a.RequirePermission("question_sets.get"), h.GetSubModuleLessonByID)
|
groupV1.Get("/course-management/sub-module-lessons/:lessonId", a.authMiddleware, a.RequirePermission("learning_tree.get"), h.GetSubModuleLessonByID)
|
||||||
groupV1.Put("/course-management/sub-module-lessons/:lessonId", a.authMiddleware, a.RequirePermission("question_sets.update"), h.UpdateSubModuleLesson)
|
groupV1.Put("/course-management/sub-module-lessons/:lessonId", a.authMiddleware, a.RequirePermission("subcourses.update"), h.UpdateSubModuleLesson)
|
||||||
groupV1.Post("/course-management/sub-module-lessons", a.authMiddleware, a.RequirePermission("question_sets.update"), h.AttachSubModuleLesson)
|
groupV1.Post("/course-management/sub-module-lessons", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateSubModuleLesson)
|
||||||
groupV1.Get("/course-management/sub-modules/:subModuleId/practices", a.authMiddleware, a.RequirePermission("question_sets.list"), h.GetSubModulePractices)
|
groupV1.Get("/course-management/sub-modules/:subModuleId/practices", a.authMiddleware, a.RequirePermission("question_sets.list"), h.GetSubModulePractices)
|
||||||
groupV1.Get("/course-management/practices/:practiceId", a.authMiddleware, a.RequirePermission("question_sets.get"), h.GetSubModulePracticeByID)
|
groupV1.Get("/course-management/practices/:practiceId", a.authMiddleware, a.RequirePermission("question_sets.get"), h.GetSubModulePracticeByID)
|
||||||
groupV1.Post("/course-management/sub-module-practices", a.authMiddleware, a.RequirePermission("question_sets.update"), h.CreateSubModulePractice)
|
groupV1.Post("/course-management/sub-module-practices", a.authMiddleware, a.RequirePermission("question_sets.update"), h.CreateSubModulePractice)
|
||||||
groupV1.Put("/course-management/practices/:practiceId", a.authMiddleware, a.RequirePermission("question_sets.update"), h.UpdatePractice)
|
groupV1.Put("/course-management/practices/:practiceId", a.authMiddleware, a.RequirePermission("question_sets.update"), h.UpdatePractice)
|
||||||
groupV1.Delete("/course-management/practices/:practiceId", a.authMiddleware, a.RequirePermission("question_sets.delete"), h.DeletePractice)
|
groupV1.Delete("/course-management/practices/:practiceId", a.authMiddleware, a.RequirePermission("question_sets.delete"), h.DeletePractice)
|
||||||
|
groupV1.Get("/course-management/sub-modules/:subModuleId/capstones", a.authMiddleware, a.RequirePermission("question_sets.list"), h.GetSubModuleCapstones)
|
||||||
|
groupV1.Get("/course-management/capstones/:capstoneId", a.authMiddleware, a.RequirePermission("question_sets.get"), h.GetSubModuleCapstoneByID)
|
||||||
|
groupV1.Post("/course-management/sub-module-capstones", a.authMiddleware, a.RequirePermission("question_sets.update"), h.CreateSubModuleCapstone)
|
||||||
|
groupV1.Put("/course-management/capstones/:capstoneId", a.authMiddleware, a.RequirePermission("question_sets.update"), h.UpdateSubModuleCapstone)
|
||||||
|
groupV1.Delete("/course-management/capstones/:capstoneId", a.authMiddleware, a.RequirePermission("question_sets.delete"), h.DeleteCapstone)
|
||||||
|
groupV1.Get("/course-management/modules/:moduleId/capstones", a.authMiddleware, a.RequirePermission("question_sets.list"), h.GetModuleCapstones)
|
||||||
|
groupV1.Get("/course-management/module-capstones/:moduleCapstoneId", a.authMiddleware, a.RequirePermission("question_sets.get"), h.GetModuleCapstoneByID)
|
||||||
|
groupV1.Post("/course-management/module-capstones", a.authMiddleware, a.RequirePermission("question_sets.update"), h.CreateModuleCapstone)
|
||||||
|
groupV1.Put("/course-management/module-capstones/:moduleCapstoneId", a.authMiddleware, a.RequirePermission("question_sets.update"), h.UpdateModuleCapstone)
|
||||||
|
groupV1.Delete("/course-management/module-capstones/:moduleCapstoneId", a.authMiddleware, a.RequirePermission("question_sets.delete"), h.DeleteModuleCapstone)
|
||||||
|
|
||||||
// Questions
|
// Questions
|
||||||
groupV1.Post("/questions", a.authMiddleware, a.RequirePermission("questions.create"), h.CreateQuestion)
|
groupV1.Post("/questions", a.authMiddleware, a.RequirePermission("questions.create"), h.CreateQuestion)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user