added more structure to submodules
This commit is contained in:
parent
c5d3935062
commit
7ff0b639cf
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;
|
||||
|
|
@ -136,6 +136,53 @@ WHERE smp.id = $1
|
|||
AND smp.is_active = TRUE
|
||||
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
|
||||
SELECT
|
||||
c.id AS course_id,
|
||||
|
|
@ -147,8 +194,13 @@ SELECT
|
|||
l.thumbnail AS level_thumbnail,
|
||||
m.id AS module_id,
|
||||
m.title AS module_title,
|
||||
m.icon_url AS module_icon_url,
|
||||
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
|
||||
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
|
||||
|
|
@ -234,10 +286,22 @@ INSERT INTO modules (
|
|||
level_id,
|
||||
title,
|
||||
description,
|
||||
icon_url,
|
||||
display_order,
|
||||
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 *;
|
||||
|
||||
-- name: CreateSubModule :one
|
||||
|
|
@ -245,10 +309,24 @@ INSERT INTO sub_modules (
|
|||
module_id,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
tips,
|
||||
display_order,
|
||||
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 *;
|
||||
|
||||
-- name: CreateSubModuleVideo :one
|
||||
|
|
@ -337,3 +415,102 @@ INSERT INTO sub_module_practices (
|
|||
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, 0), COALESCE($8, TRUE))
|
||||
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 *;
|
||||
|
||||
|
|
|
|||
736
docs/docs.go
736
docs/docs.go
|
|
@ -713,6 +713,149 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/capstones/{capstoneId}": {
|
||||
"get": {
|
||||
"description": "Returns one capstone with question-set fields and the ordered question list",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Get capstone detail",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Capstone ID",
|
||||
"name": "capstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Updates capstone content, question-set assessment settings, and optionally replaces the question list",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Update capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Capstone ID",
|
||||
"name": "capstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Update capstone payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.updateSubModuleCapstoneReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Deletes the capstone and its backing question set (and question items)",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Delete capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Capstone ID",
|
||||
"name": "capstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/categories": {
|
||||
"get": {
|
||||
"description": "Legacy-compatible endpoint for listing course categories",
|
||||
|
|
@ -1568,6 +1711,195 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/module-capstones": {
|
||||
"post": {
|
||||
"description": "Creates a module-level capstone with a new CAPSTONE question set and ordered questions",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Create module capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Create module capstone payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.createModuleCapstoneReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/module-capstones/{moduleCapstoneId}": {
|
||||
"get": {
|
||||
"description": "Returns one module capstone with question-set fields and the ordered question list",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Get module capstone detail",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module capstone ID",
|
||||
"name": "moduleCapstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Updates module capstone content, question-set assessment settings, and optionally replaces the question list",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Update module capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module capstone ID",
|
||||
"name": "moduleCapstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Update module capstone payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.updateModuleCapstoneReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Deletes the module capstone and its backing question set",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Delete module capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module capstone ID",
|
||||
"name": "moduleCapstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/modules": {
|
||||
"get": {
|
||||
"description": "Returns all modules with pagination",
|
||||
|
|
@ -1608,7 +1940,7 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Creates a module under a level",
|
||||
"description": "Creates a module under a level; optional icon_url stores a module icon image URL",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
|
@ -1697,6 +2029,104 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Updates module title, description, icon URL, display order, and active flag",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Update module",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module ID",
|
||||
"name": "moduleId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Update module payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.updateModuleReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/modules/{moduleId}/capstones": {
|
||||
"get": {
|
||||
"description": "Returns active module capstones with question-set settings and question counts",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "List capstones under module",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module ID",
|
||||
"name": "moduleId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/modules/{moduleId}/sub-modules": {
|
||||
|
|
@ -1927,6 +2357,52 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/sub-module-capstones": {
|
||||
"post": {
|
||||
"description": "Creates a capstone assessment with a new CAPSTONE question set, metadata, and ordered questions",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Create capstone under sub-module",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Create capstone payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.createSubModuleCapstoneReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/sub-module-lessons": {
|
||||
"post": {
|
||||
"description": "Creates a sub-module lesson with teaching content (text, image, audio, video URLs) and optional thumbnail",
|
||||
|
|
@ -2212,7 +2688,7 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Creates a sub-module under a module",
|
||||
"description": "Creates a sub-module under a module; optional thumbnail (image URL) and tips text",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
|
@ -2303,6 +2779,47 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/sub-modules/{subModuleId}/capstones": {
|
||||
"get": {
|
||||
"description": "Returns active capstones for a sub-module with question-set settings and question counts",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "List capstones under sub-module",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Sub-module ID",
|
||||
"name": "subModuleId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/sub-modules/{subModuleId}/lessons": {
|
||||
"get": {
|
||||
"description": "Returns all active lessons for a sub-module (teaching content metadata)",
|
||||
|
|
@ -4040,7 +4557,7 @@ const docTemplate = `{
|
|||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Set type (PRACTICE, INITIAL_ASSESSMENT, QUIZ, EXAM, SURVEY)",
|
||||
"description": "Set type (PRACTICE, INITIAL_ASSESSMENT, QUIZ, EXAM, SURVEY, CAPSTONE)",
|
||||
"name": "set_type",
|
||||
"in": "query",
|
||||
"required": true
|
||||
|
|
@ -10300,6 +10817,17 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.capstoneQuestionItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"question_id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.changePasswordReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
@ -10432,6 +10960,50 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.createModuleCapstoneReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"module_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"passing_score": {
|
||||
"type": "integer"
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.capstoneQuestionItem"
|
||||
}
|
||||
},
|
||||
"shuffle_questions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"time_limit_minutes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.createModuleReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -10441,6 +11013,9 @@ const docTemplate = `{
|
|||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"icon_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -10588,7 +11163,8 @@ const docTemplate = `{
|
|||
"INITIAL_ASSESSMENT",
|
||||
"QUIZ",
|
||||
"EXAM",
|
||||
"SURVEY"
|
||||
"SURVEY",
|
||||
"CAPSTONE"
|
||||
]
|
||||
},
|
||||
"shuffle_questions": {
|
||||
|
|
@ -10608,6 +11184,50 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.createSubModuleCapstoneReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"passing_score": {
|
||||
"type": "integer"
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.capstoneQuestionItem"
|
||||
}
|
||||
},
|
||||
"shuffle_questions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"sub_module_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"time_limit_minutes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.createSubModuleLessonReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -10687,6 +11307,12 @@ const docTemplate = `{
|
|||
"module_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
|
|
@ -11073,6 +11699,67 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.updateModuleCapstoneReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"passing_score": {
|
||||
"type": "integer"
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.capstoneQuestionItem"
|
||||
}
|
||||
},
|
||||
"shuffle_questions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"time_limit_minutes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.updateModuleReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"icon_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.updatePlanReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -11195,6 +11882,47 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.updateSubModuleCapstoneReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"passing_score": {
|
||||
"type": "integer"
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.capstoneQuestionItem"
|
||||
}
|
||||
},
|
||||
"shuffle_questions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"time_limit_minutes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.updateSubModuleLessonReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
|
|
@ -705,6 +705,149 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/capstones/{capstoneId}": {
|
||||
"get": {
|
||||
"description": "Returns one capstone with question-set fields and the ordered question list",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Get capstone detail",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Capstone ID",
|
||||
"name": "capstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Updates capstone content, question-set assessment settings, and optionally replaces the question list",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Update capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Capstone ID",
|
||||
"name": "capstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Update capstone payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.updateSubModuleCapstoneReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Deletes the capstone and its backing question set (and question items)",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Delete capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Capstone ID",
|
||||
"name": "capstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/categories": {
|
||||
"get": {
|
||||
"description": "Legacy-compatible endpoint for listing course categories",
|
||||
|
|
@ -1560,6 +1703,195 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/module-capstones": {
|
||||
"post": {
|
||||
"description": "Creates a module-level capstone with a new CAPSTONE question set and ordered questions",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Create module capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Create module capstone payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.createModuleCapstoneReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/module-capstones/{moduleCapstoneId}": {
|
||||
"get": {
|
||||
"description": "Returns one module capstone with question-set fields and the ordered question list",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Get module capstone detail",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module capstone ID",
|
||||
"name": "moduleCapstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Updates module capstone content, question-set assessment settings, and optionally replaces the question list",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Update module capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module capstone ID",
|
||||
"name": "moduleCapstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Update module capstone payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.updateModuleCapstoneReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Deletes the module capstone and its backing question set",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Delete module capstone",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module capstone ID",
|
||||
"name": "moduleCapstoneId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/modules": {
|
||||
"get": {
|
||||
"description": "Returns all modules with pagination",
|
||||
|
|
@ -1600,7 +1932,7 @@
|
|||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Creates a module under a level",
|
||||
"description": "Creates a module under a level; optional icon_url stores a module icon image URL",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
|
@ -1689,6 +2021,104 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Updates module title, description, icon URL, display order, and active flag",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Update module",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module ID",
|
||||
"name": "moduleId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Update module payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.updateModuleReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/modules/{moduleId}/capstones": {
|
||||
"get": {
|
||||
"description": "Returns active module capstones with question-set settings and question counts",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "List capstones under module",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Module ID",
|
||||
"name": "moduleId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/modules/{moduleId}/sub-modules": {
|
||||
|
|
@ -1919,6 +2349,52 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/sub-module-capstones": {
|
||||
"post": {
|
||||
"description": "Creates a capstone assessment with a new CAPSTONE question set, metadata, and ordered questions",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "Create capstone under sub-module",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Create capstone payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.createSubModuleCapstoneReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/sub-module-lessons": {
|
||||
"post": {
|
||||
"description": "Creates a sub-module lesson with teaching content (text, image, audio, video URLs) and optional thumbnail",
|
||||
|
|
@ -2204,7 +2680,7 @@
|
|||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Creates a sub-module under a module",
|
||||
"description": "Creates a sub-module under a module; optional thumbnail (image URL) and tips text",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
|
@ -2295,6 +2771,47 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/sub-modules/{subModuleId}/capstones": {
|
||||
"get": {
|
||||
"description": "Returns active capstones for a sub-module with question-set settings and question counts",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"course-management"
|
||||
],
|
||||
"summary": "List capstones under sub-module",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Sub-module ID",
|
||||
"name": "subModuleId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/course-management/sub-modules/{subModuleId}/lessons": {
|
||||
"get": {
|
||||
"description": "Returns all active lessons for a sub-module (teaching content metadata)",
|
||||
|
|
@ -4032,7 +4549,7 @@
|
|||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Set type (PRACTICE, INITIAL_ASSESSMENT, QUIZ, EXAM, SURVEY)",
|
||||
"description": "Set type (PRACTICE, INITIAL_ASSESSMENT, QUIZ, EXAM, SURVEY, CAPSTONE)",
|
||||
"name": "set_type",
|
||||
"in": "query",
|
||||
"required": true
|
||||
|
|
@ -10292,6 +10809,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.capstoneQuestionItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"question_id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.changePasswordReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
@ -10424,6 +10952,50 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.createModuleCapstoneReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"module_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"passing_score": {
|
||||
"type": "integer"
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.capstoneQuestionItem"
|
||||
}
|
||||
},
|
||||
"shuffle_questions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"time_limit_minutes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.createModuleReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -10433,6 +11005,9 @@
|
|||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"icon_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -10580,7 +11155,8 @@
|
|||
"INITIAL_ASSESSMENT",
|
||||
"QUIZ",
|
||||
"EXAM",
|
||||
"SURVEY"
|
||||
"SURVEY",
|
||||
"CAPSTONE"
|
||||
]
|
||||
},
|
||||
"shuffle_questions": {
|
||||
|
|
@ -10600,6 +11176,50 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.createSubModuleCapstoneReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"passing_score": {
|
||||
"type": "integer"
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.capstoneQuestionItem"
|
||||
}
|
||||
},
|
||||
"shuffle_questions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"sub_module_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"time_limit_minutes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.createSubModuleLessonReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -10679,6 +11299,12 @@
|
|||
"module_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
|
|
@ -11065,6 +11691,67 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.updateModuleCapstoneReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"passing_score": {
|
||||
"type": "integer"
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.capstoneQuestionItem"
|
||||
}
|
||||
},
|
||||
"shuffle_questions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"time_limit_minutes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.updateModuleReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"icon_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.updatePlanReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -11187,6 +11874,47 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"handlers.updateSubModuleCapstoneReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"passing_score": {
|
||||
"type": "integer"
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.capstoneQuestionItem"
|
||||
}
|
||||
},
|
||||
"shuffle_questions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
},
|
||||
"time_limit_minutes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tips": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.updateSubModuleLessonReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
|
|
@ -916,6 +916,13 @@ definitions:
|
|||
auto_renew:
|
||||
type: boolean
|
||||
type: object
|
||||
handlers.capstoneQuestionItem:
|
||||
properties:
|
||||
display_order:
|
||||
type: integer
|
||||
question_id:
|
||||
type: integer
|
||||
type: object
|
||||
handlers.changePasswordReq:
|
||||
properties:
|
||||
current_password:
|
||||
|
|
@ -1004,12 +1011,43 @@ definitions:
|
|||
title:
|
||||
type: string
|
||||
type: object
|
||||
handlers.createModuleCapstoneReq:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
display_order:
|
||||
type: integer
|
||||
is_active:
|
||||
type: boolean
|
||||
module_id:
|
||||
type: integer
|
||||
passing_score:
|
||||
type: integer
|
||||
questions:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.capstoneQuestionItem'
|
||||
type: array
|
||||
shuffle_questions:
|
||||
type: boolean
|
||||
status:
|
||||
type: string
|
||||
thumbnail:
|
||||
type: string
|
||||
time_limit_minutes:
|
||||
type: integer
|
||||
tips:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
type: object
|
||||
handlers.createModuleReq:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
display_order:
|
||||
type: integer
|
||||
icon_url:
|
||||
type: string
|
||||
is_active:
|
||||
type: boolean
|
||||
level_id:
|
||||
|
|
@ -1111,6 +1149,7 @@ definitions:
|
|||
- QUIZ
|
||||
- EXAM
|
||||
- SURVEY
|
||||
- CAPSTONE
|
||||
type: string
|
||||
shuffle_questions:
|
||||
type: boolean
|
||||
|
|
@ -1126,6 +1165,35 @@ definitions:
|
|||
- set_type
|
||||
- title
|
||||
type: object
|
||||
handlers.createSubModuleCapstoneReq:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
display_order:
|
||||
type: integer
|
||||
is_active:
|
||||
type: boolean
|
||||
passing_score:
|
||||
type: integer
|
||||
questions:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.capstoneQuestionItem'
|
||||
type: array
|
||||
shuffle_questions:
|
||||
type: boolean
|
||||
status:
|
||||
type: string
|
||||
sub_module_id:
|
||||
type: integer
|
||||
thumbnail:
|
||||
type: string
|
||||
time_limit_minutes:
|
||||
type: integer
|
||||
tips:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
type: object
|
||||
handlers.createSubModuleLessonReq:
|
||||
properties:
|
||||
description:
|
||||
|
|
@ -1178,6 +1246,10 @@ definitions:
|
|||
type: boolean
|
||||
module_id:
|
||||
type: integer
|
||||
thumbnail:
|
||||
type: string
|
||||
tips:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
type: object
|
||||
|
|
@ -1437,6 +1509,46 @@ definitions:
|
|||
title:
|
||||
type: string
|
||||
type: object
|
||||
handlers.updateModuleCapstoneReq:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
display_order:
|
||||
type: integer
|
||||
is_active:
|
||||
type: boolean
|
||||
passing_score:
|
||||
type: integer
|
||||
questions:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.capstoneQuestionItem'
|
||||
type: array
|
||||
shuffle_questions:
|
||||
type: boolean
|
||||
status:
|
||||
type: string
|
||||
thumbnail:
|
||||
type: string
|
||||
time_limit_minutes:
|
||||
type: integer
|
||||
tips:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
type: object
|
||||
handlers.updateModuleReq:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
display_order:
|
||||
type: integer
|
||||
icon_url:
|
||||
type: string
|
||||
is_active:
|
||||
type: boolean
|
||||
title:
|
||||
type: string
|
||||
type: object
|
||||
handlers.updatePlanReq:
|
||||
properties:
|
||||
currency:
|
||||
|
|
@ -1517,6 +1629,33 @@ definitions:
|
|||
title:
|
||||
type: string
|
||||
type: object
|
||||
handlers.updateSubModuleCapstoneReq:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
display_order:
|
||||
type: integer
|
||||
is_active:
|
||||
type: boolean
|
||||
passing_score:
|
||||
type: integer
|
||||
questions:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.capstoneQuestionItem'
|
||||
type: array
|
||||
shuffle_questions:
|
||||
type: boolean
|
||||
status:
|
||||
type: string
|
||||
thumbnail:
|
||||
type: string
|
||||
time_limit_minutes:
|
||||
type: integer
|
||||
tips:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
type: object
|
||||
handlers.updateSubModuleLessonReq:
|
||||
properties:
|
||||
description:
|
||||
|
|
@ -2417,6 +2556,104 @@ paths:
|
|||
summary: Refresh token
|
||||
tags:
|
||||
- auth
|
||||
/api/v1/course-management/capstones/{capstoneId}:
|
||||
delete:
|
||||
description: Deletes the capstone and its backing question set (and question
|
||||
items)
|
||||
parameters:
|
||||
- description: Capstone ID
|
||||
in: path
|
||||
name: capstoneId
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Delete capstone
|
||||
tags:
|
||||
- course-management
|
||||
get:
|
||||
description: Returns one capstone with question-set fields and the ordered question
|
||||
list
|
||||
parameters:
|
||||
- description: Capstone ID
|
||||
in: path
|
||||
name: capstoneId
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Get capstone detail
|
||||
tags:
|
||||
- course-management
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Updates capstone content, question-set assessment settings, and
|
||||
optionally replaces the question list
|
||||
parameters:
|
||||
- description: Capstone ID
|
||||
in: path
|
||||
name: capstoneId
|
||||
required: true
|
||||
type: integer
|
||||
- description: Update capstone payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/handlers.updateSubModuleCapstoneReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Update capstone
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/categories:
|
||||
get:
|
||||
description: Legacy-compatible endpoint for listing course categories
|
||||
|
|
@ -2982,6 +3219,134 @@ paths:
|
|||
summary: List modules by level
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/module-capstones:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Creates a module-level capstone with a new CAPSTONE question set
|
||||
and ordered questions
|
||||
parameters:
|
||||
- description: Create module capstone payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/handlers.createModuleCapstoneReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Create module capstone
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/module-capstones/{moduleCapstoneId}:
|
||||
delete:
|
||||
description: Deletes the module capstone and its backing question set
|
||||
parameters:
|
||||
- description: Module capstone ID
|
||||
in: path
|
||||
name: moduleCapstoneId
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Delete module capstone
|
||||
tags:
|
||||
- course-management
|
||||
get:
|
||||
description: Returns one module capstone with question-set fields and the ordered
|
||||
question list
|
||||
parameters:
|
||||
- description: Module capstone ID
|
||||
in: path
|
||||
name: moduleCapstoneId
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Get module capstone detail
|
||||
tags:
|
||||
- course-management
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Updates module capstone content, question-set assessment settings,
|
||||
and optionally replaces the question list
|
||||
parameters:
|
||||
- description: Module capstone ID
|
||||
in: path
|
||||
name: moduleCapstoneId
|
||||
required: true
|
||||
type: integer
|
||||
- description: Update module capstone payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/handlers.updateModuleCapstoneReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Update module capstone
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/modules:
|
||||
get:
|
||||
description: Returns all modules with pagination
|
||||
|
|
@ -3011,7 +3376,8 @@ paths:
|
|||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Creates a module under a level
|
||||
description: Creates a module under a level; optional icon_url stores a module
|
||||
icon image URL
|
||||
parameters:
|
||||
- description: Create module payload
|
||||
in: body
|
||||
|
|
@ -3068,6 +3434,73 @@ paths:
|
|||
summary: Get module detail
|
||||
tags:
|
||||
- course-management
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Updates module title, description, icon URL, display order, and
|
||||
active flag
|
||||
parameters:
|
||||
- description: Module ID
|
||||
in: path
|
||||
name: moduleId
|
||||
required: true
|
||||
type: integer
|
||||
- description: Update module payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/handlers.updateModuleReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Update module
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/modules/{moduleId}/capstones:
|
||||
get:
|
||||
description: Returns active module capstones with question-set settings and
|
||||
question counts
|
||||
parameters:
|
||||
- description: Module ID
|
||||
in: path
|
||||
name: moduleId
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: List capstones under module
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/modules/{moduleId}/sub-modules:
|
||||
get:
|
||||
description: Returns all active sub-modules for one module
|
||||
|
|
@ -3218,6 +3651,37 @@ paths:
|
|||
summary: List courses by sub-category
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/sub-module-capstones:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Creates a capstone assessment with a new CAPSTONE question set,
|
||||
metadata, and ordered questions
|
||||
parameters:
|
||||
- description: Create capstone payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/handlers.createSubModuleCapstoneReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Create capstone under sub-module
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/sub-module-lessons:
|
||||
post:
|
||||
consumes:
|
||||
|
|
@ -3411,7 +3875,8 @@ paths:
|
|||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Creates a sub-module under a module
|
||||
description: Creates a sub-module under a module; optional thumbnail (image
|
||||
URL) and tips text
|
||||
parameters:
|
||||
- description: Create sub-module payload
|
||||
in: body
|
||||
|
|
@ -3468,6 +3933,34 @@ paths:
|
|||
summary: Get sub-module detail
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/sub-modules/{subModuleId}/capstones:
|
||||
get:
|
||||
description: Returns active capstones for a sub-module with question-set settings
|
||||
and question counts
|
||||
parameters:
|
||||
- description: Sub-module ID
|
||||
in: path
|
||||
name: subModuleId
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/domain.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: List capstones under sub-module
|
||||
tags:
|
||||
- course-management
|
||||
/api/v1/course-management/sub-modules/{subModuleId}/lessons:
|
||||
get:
|
||||
consumes:
|
||||
|
|
@ -4597,7 +5090,7 @@ paths:
|
|||
get:
|
||||
description: Returns a paginated list of question sets filtered by type
|
||||
parameters:
|
||||
- description: Set type (PRACTICE, INITIAL_ASSESSMENT, QUIZ, EXAM, SURVEY)
|
||||
- description: Set type (PRACTICE, INITIAL_ASSESSMENT, QUIZ, EXAM, SURVEY, CAPSTONE)
|
||||
in: query
|
||||
name: set_type
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
func (q *Queries) GetSubModuleByIDCompat(ctx context.Context, id int64) (SubModule, error) {
|
||||
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
|
||||
WHERE id = $1
|
||||
`, id)
|
||||
|
|
@ -22,19 +22,24 @@ WHERE id = $1
|
|||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.LegacySubCourseID,
|
||||
&i.Thumbnail,
|
||||
&i.Tips,
|
||||
)
|
||||
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, `
|
||||
UPDATE sub_modules
|
||||
SET
|
||||
title = $1,
|
||||
description = NULLIF($2, ''),
|
||||
is_active = $3
|
||||
WHERE id = $4
|
||||
`, title, description, isActive, id)
|
||||
thumbnail = NULLIF($3, ''),
|
||||
tips = NULLIF($4, ''),
|
||||
display_order = $5,
|
||||
is_active = $6
|
||||
WHERE id = $7
|
||||
`, title, description, thumbnail, tips, displayOrder, isActive, id)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -119,6 +124,24 @@ func (q *Queries) DeletePracticeCompat(ctx context.Context, id int64) error {
|
|||
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(
|
||||
ctx context.Context,
|
||||
categoryID int64,
|
||||
|
|
|
|||
|
|
@ -106,19 +106,21 @@ INSERT INTO modules (
|
|||
level_id,
|
||||
title,
|
||||
description,
|
||||
icon_url,
|
||||
display_order,
|
||||
is_active
|
||||
)
|
||||
VALUES ($1, $2, $3, COALESCE($4, 0), COALESCE($5, TRUE))
|
||||
RETURNING id, level_id, title, description, display_order, is_active, created_at
|
||||
VALUES ($1, $2, $3, $4, COALESCE($5, 0), COALESCE($6, TRUE))
|
||||
RETURNING id, level_id, title, description, display_order, is_active, created_at, icon_url
|
||||
`
|
||||
|
||||
type CreateModuleParams struct {
|
||||
LevelID int64 `json:"level_id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
Column4 interface{} `json:"column_4"`
|
||||
IconUrl pgtype.Text `json:"icon_url"`
|
||||
Column5 interface{} `json:"column_5"`
|
||||
Column6 interface{} `json:"column_6"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Module, error) {
|
||||
|
|
@ -126,8 +128,9 @@ func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Mod
|
|||
arg.LevelID,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.Column4,
|
||||
arg.IconUrl,
|
||||
arg.Column5,
|
||||
arg.Column6,
|
||||
)
|
||||
var i Module
|
||||
err := row.Scan(
|
||||
|
|
@ -138,6 +141,60 @@ func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Mod
|
|||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.IconUrl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const CreateModuleCapstone = `-- 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 id, module_id, title, description, tips, thumbnail, question_set_id, display_order, is_active, created_at
|
||||
`
|
||||
|
||||
type CreateModuleCapstoneParams struct {
|
||||
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"`
|
||||
Column7 interface{} `json:"column_7"`
|
||||
Column8 interface{} `json:"column_8"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateModuleCapstone(ctx context.Context, arg CreateModuleCapstoneParams) (ModuleCapstone, error) {
|
||||
row := q.db.QueryRow(ctx, CreateModuleCapstone,
|
||||
arg.ModuleID,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.Tips,
|
||||
arg.Thumbnail,
|
||||
arg.QuestionSetID,
|
||||
arg.Column7,
|
||||
arg.Column8,
|
||||
)
|
||||
var i ModuleCapstone
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Tips,
|
||||
&i.Thumbnail,
|
||||
&i.QuestionSetID,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
@ -147,19 +204,23 @@ INSERT INTO sub_modules (
|
|||
module_id,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
tips,
|
||||
display_order,
|
||||
is_active
|
||||
)
|
||||
VALUES ($1, $2, $3, COALESCE($4, 0), COALESCE($5, TRUE))
|
||||
RETURNING id, module_id, title, description, display_order, is_active, created_at, legacy_sub_course_id
|
||||
VALUES ($1, $2, $3, $4, $5, COALESCE($6, 0), COALESCE($7, TRUE))
|
||||
RETURNING id, module_id, title, description, display_order, is_active, created_at, legacy_sub_course_id, thumbnail, tips
|
||||
`
|
||||
|
||||
type CreateSubModuleParams struct {
|
||||
ModuleID int64 `json:"module_id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
Column4 interface{} `json:"column_4"`
|
||||
Column5 interface{} `json:"column_5"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
Tips pgtype.Text `json:"tips"`
|
||||
Column6 interface{} `json:"column_6"`
|
||||
Column7 interface{} `json:"column_7"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateSubModule(ctx context.Context, arg CreateSubModuleParams) (SubModule, error) {
|
||||
|
|
@ -167,8 +228,10 @@ func (q *Queries) CreateSubModule(ctx context.Context, arg CreateSubModuleParams
|
|||
arg.ModuleID,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.Column4,
|
||||
arg.Column5,
|
||||
arg.Thumbnail,
|
||||
arg.Tips,
|
||||
arg.Column6,
|
||||
arg.Column7,
|
||||
)
|
||||
var i SubModule
|
||||
err := row.Scan(
|
||||
|
|
@ -180,6 +243,61 @@ func (q *Queries) CreateSubModule(ctx context.Context, arg CreateSubModuleParams
|
|||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.LegacySubCourseID,
|
||||
&i.Thumbnail,
|
||||
&i.Tips,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const CreateSubModuleCapstone = `-- 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 id, sub_module_id, title, description, tips, thumbnail, question_set_id, display_order, is_active, created_at
|
||||
`
|
||||
|
||||
type CreateSubModuleCapstoneParams struct {
|
||||
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"`
|
||||
Column7 interface{} `json:"column_7"`
|
||||
Column8 interface{} `json:"column_8"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateSubModuleCapstone(ctx context.Context, arg CreateSubModuleCapstoneParams) (SubModuleCapstone, error) {
|
||||
row := q.db.QueryRow(ctx, CreateSubModuleCapstone,
|
||||
arg.SubModuleID,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.Tips,
|
||||
arg.Thumbnail,
|
||||
arg.QuestionSetID,
|
||||
arg.Column7,
|
||||
arg.Column8,
|
||||
)
|
||||
var i SubModuleCapstone
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.SubModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Tips,
|
||||
&i.Thumbnail,
|
||||
&i.QuestionSetID,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
@ -469,7 +587,7 @@ func (q *Queries) GetAllLevels(ctx context.Context, arg GetAllLevelsParams) ([]G
|
|||
const GetAllModules = `-- name: GetAllModules :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
m.id, m.level_id, m.title, m.description, m.display_order, m.is_active, m.created_at
|
||||
m.id, m.level_id, m.title, m.description, m.display_order, m.is_active, m.created_at, m.icon_url
|
||||
FROM modules m
|
||||
ORDER BY m.display_order ASC, m.id ASC
|
||||
LIMIT $2::INT
|
||||
|
|
@ -490,6 +608,7 @@ type GetAllModulesRow struct {
|
|||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
IconUrl pgtype.Text `json:"icon_url"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllModules(ctx context.Context, arg GetAllModulesParams) ([]GetAllModulesRow, error) {
|
||||
|
|
@ -510,6 +629,7 @@ func (q *Queries) GetAllModules(ctx context.Context, arg GetAllModulesParams) ([
|
|||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.IconUrl,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -524,7 +644,7 @@ func (q *Queries) GetAllModules(ctx context.Context, arg GetAllModulesParams) ([
|
|||
const GetAllSubModules = `-- name: GetAllSubModules :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
sm.id, sm.module_id, sm.title, sm.description, sm.display_order, sm.is_active, sm.created_at, sm.legacy_sub_course_id
|
||||
sm.id, sm.module_id, sm.title, sm.description, sm.display_order, sm.is_active, sm.created_at, sm.legacy_sub_course_id, sm.thumbnail, sm.tips
|
||||
FROM sub_modules sm
|
||||
ORDER BY sm.display_order ASC, sm.id ASC
|
||||
LIMIT $2::INT
|
||||
|
|
@ -546,6 +666,8 @@ type GetAllSubModulesRow struct {
|
|||
IsActive bool `json:"is_active"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
LegacySubCourseID pgtype.Int8 `json:"legacy_sub_course_id"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
Tips pgtype.Text `json:"tips"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllSubModules(ctx context.Context, arg GetAllSubModulesParams) ([]GetAllSubModulesRow, error) {
|
||||
|
|
@ -567,6 +689,8 @@ func (q *Queries) GetAllSubModules(ctx context.Context, arg GetAllSubModulesPara
|
|||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.LegacySubCourseID,
|
||||
&i.Thumbnail,
|
||||
&i.Tips,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -706,8 +830,13 @@ SELECT
|
|||
l.thumbnail AS level_thumbnail,
|
||||
m.id AS module_id,
|
||||
m.title AS module_title,
|
||||
m.icon_url AS module_icon_url,
|
||||
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
|
||||
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
|
||||
|
|
@ -726,8 +855,13 @@ type GetFullHierarchyByCourseIDRow struct {
|
|||
LevelThumbnail pgtype.Text `json:"level_thumbnail"`
|
||||
ModuleID pgtype.Int8 `json:"module_id"`
|
||||
ModuleTitle pgtype.Text `json:"module_title"`
|
||||
ModuleIconUrl pgtype.Text `json:"module_icon_url"`
|
||||
SubModuleID pgtype.Int8 `json:"sub_module_id"`
|
||||
SubModuleTitle pgtype.Text `json:"sub_module_title"`
|
||||
SubModuleDescription pgtype.Text `json:"sub_module_description"`
|
||||
SubModuleThumbnail pgtype.Text `json:"sub_module_thumbnail"`
|
||||
SubModuleTips pgtype.Text `json:"sub_module_tips"`
|
||||
SubModuleDisplayOrder pgtype.Int4 `json:"sub_module_display_order"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetFullHierarchyByCourseID(ctx context.Context, id int64) ([]GetFullHierarchyByCourseIDRow, error) {
|
||||
|
|
@ -749,8 +883,13 @@ func (q *Queries) GetFullHierarchyByCourseID(ctx context.Context, id int64) ([]G
|
|||
&i.LevelThumbnail,
|
||||
&i.ModuleID,
|
||||
&i.ModuleTitle,
|
||||
&i.ModuleIconUrl,
|
||||
&i.SubModuleID,
|
||||
&i.SubModuleTitle,
|
||||
&i.SubModuleDescription,
|
||||
&i.SubModuleThumbnail,
|
||||
&i.SubModuleTips,
|
||||
&i.SubModuleDisplayOrder,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -892,7 +1031,7 @@ func (q *Queries) GetLevelsByCourseID(ctx context.Context, courseID int64) ([]Le
|
|||
}
|
||||
|
||||
const GetModuleByID = `-- name: GetModuleByID :one
|
||||
SELECT id, level_id, title, description, display_order, is_active, created_at
|
||||
SELECT id, level_id, title, description, display_order, is_active, created_at, icon_url
|
||||
FROM modules
|
||||
WHERE id = $1
|
||||
`
|
||||
|
|
@ -908,12 +1047,157 @@ func (q *Queries) GetModuleByID(ctx context.Context, id int64) (Module, error) {
|
|||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.IconUrl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetModuleCapstoneByID = `-- 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'
|
||||
`
|
||||
|
||||
type GetModuleCapstoneByIDRow 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"`
|
||||
Status string `json:"status"`
|
||||
SetType string `json:"set_type"`
|
||||
TimeLimitMinutes pgtype.Int4 `json:"time_limit_minutes"`
|
||||
PassingScore pgtype.Int4 `json:"passing_score"`
|
||||
ShuffleQuestions bool `json:"shuffle_questions"`
|
||||
QuestionCount int64 `json:"question_count"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetModuleCapstoneByID(ctx context.Context, id int64) (GetModuleCapstoneByIDRow, error) {
|
||||
row := q.db.QueryRow(ctx, GetModuleCapstoneByID, id)
|
||||
var i GetModuleCapstoneByIDRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Tips,
|
||||
&i.Thumbnail,
|
||||
&i.QuestionSetID,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.SetType,
|
||||
&i.TimeLimitMinutes,
|
||||
&i.PassingScore,
|
||||
&i.ShuffleQuestions,
|
||||
&i.QuestionCount,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetModuleCapstones = `-- 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
|
||||
`
|
||||
|
||||
type GetModuleCapstonesRow 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"`
|
||||
Status string `json:"status"`
|
||||
SetType string `json:"set_type"`
|
||||
TimeLimitMinutes pgtype.Int4 `json:"time_limit_minutes"`
|
||||
PassingScore pgtype.Int4 `json:"passing_score"`
|
||||
ShuffleQuestions bool `json:"shuffle_questions"`
|
||||
QuestionCount int64 `json:"question_count"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetModuleCapstones(ctx context.Context, moduleID int64) ([]GetModuleCapstonesRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetModuleCapstones, moduleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetModuleCapstonesRow
|
||||
for rows.Next() {
|
||||
var i GetModuleCapstonesRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Tips,
|
||||
&i.Thumbnail,
|
||||
&i.QuestionSetID,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.SetType,
|
||||
&i.TimeLimitMinutes,
|
||||
&i.PassingScore,
|
||||
&i.ShuffleQuestions,
|
||||
&i.QuestionCount,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetModulesByLevelID = `-- name: GetModulesByLevelID :many
|
||||
SELECT id, level_id, title, description, display_order, is_active, created_at
|
||||
SELECT id, level_id, title, description, display_order, is_active, created_at, icon_url
|
||||
FROM modules
|
||||
WHERE level_id = $1
|
||||
AND is_active = TRUE
|
||||
|
|
@ -937,6 +1221,7 @@ func (q *Queries) GetModulesByLevelID(ctx context.Context, levelID int64) ([]Mod
|
|||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.IconUrl,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -949,7 +1234,7 @@ func (q *Queries) GetModulesByLevelID(ctx context.Context, levelID int64) ([]Mod
|
|||
}
|
||||
|
||||
const GetSubModuleByID = `-- name: GetSubModuleByID :one
|
||||
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
|
||||
WHERE id = $1
|
||||
`
|
||||
|
|
@ -966,10 +1251,156 @@ func (q *Queries) GetSubModuleByID(ctx context.Context, id int64) (SubModule, er
|
|||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.LegacySubCourseID,
|
||||
&i.Thumbnail,
|
||||
&i.Tips,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetSubModuleCapstoneByID = `-- 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'
|
||||
`
|
||||
|
||||
type GetSubModuleCapstoneByIDRow struct {
|
||||
ID int64 `json:"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"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Status string `json:"status"`
|
||||
SetType string `json:"set_type"`
|
||||
TimeLimitMinutes pgtype.Int4 `json:"time_limit_minutes"`
|
||||
PassingScore pgtype.Int4 `json:"passing_score"`
|
||||
ShuffleQuestions bool `json:"shuffle_questions"`
|
||||
QuestionCount int64 `json:"question_count"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetSubModuleCapstoneByID(ctx context.Context, id int64) (GetSubModuleCapstoneByIDRow, error) {
|
||||
row := q.db.QueryRow(ctx, GetSubModuleCapstoneByID, id)
|
||||
var i GetSubModuleCapstoneByIDRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.SubModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Tips,
|
||||
&i.Thumbnail,
|
||||
&i.QuestionSetID,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.SetType,
|
||||
&i.TimeLimitMinutes,
|
||||
&i.PassingScore,
|
||||
&i.ShuffleQuestions,
|
||||
&i.QuestionCount,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetSubModuleCapstones = `-- 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
|
||||
`
|
||||
|
||||
type GetSubModuleCapstonesRow struct {
|
||||
ID int64 `json:"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"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Status string `json:"status"`
|
||||
SetType string `json:"set_type"`
|
||||
TimeLimitMinutes pgtype.Int4 `json:"time_limit_minutes"`
|
||||
PassingScore pgtype.Int4 `json:"passing_score"`
|
||||
ShuffleQuestions bool `json:"shuffle_questions"`
|
||||
QuestionCount int64 `json:"question_count"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetSubModuleCapstones(ctx context.Context, subModuleID int64) ([]GetSubModuleCapstonesRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetSubModuleCapstones, subModuleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetSubModuleCapstonesRow
|
||||
for rows.Next() {
|
||||
var i GetSubModuleCapstonesRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.SubModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Tips,
|
||||
&i.Thumbnail,
|
||||
&i.QuestionSetID,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.SetType,
|
||||
&i.TimeLimitMinutes,
|
||||
&i.PassingScore,
|
||||
&i.ShuffleQuestions,
|
||||
&i.QuestionCount,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetSubModuleLessonByID = `-- name: GetSubModuleLessonByID :one
|
||||
SELECT id, sub_module_id, display_order, is_active, created_at, title, description, thumbnail, teaching_text, teaching_image_url, teaching_audio_url, teaching_video_url
|
||||
FROM sub_module_lessons
|
||||
|
|
@ -1214,7 +1645,7 @@ func (q *Queries) GetSubModuleVideos(ctx context.Context, subModuleID int64) ([]
|
|||
}
|
||||
|
||||
const GetSubModulesByModuleID = `-- name: GetSubModulesByModuleID :many
|
||||
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
|
||||
WHERE module_id = $1
|
||||
AND is_active = TRUE
|
||||
|
|
@ -1239,6 +1670,8 @@ func (q *Queries) GetSubModulesByModuleID(ctx context.Context, moduleID int64) (
|
|||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.LegacySubCourseID,
|
||||
&i.Thumbnail,
|
||||
&i.Tips,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1295,6 +1728,197 @@ func (q *Queries) UpdateLevel(ctx context.Context, arg UpdateLevelParams) (Level
|
|||
return i, err
|
||||
}
|
||||
|
||||
const UpdateModule = `-- name: UpdateModule :one
|
||||
UPDATE modules
|
||||
SET
|
||||
title = $1,
|
||||
description = $2,
|
||||
icon_url = $3,
|
||||
display_order = $4,
|
||||
is_active = $5
|
||||
WHERE id = $6
|
||||
RETURNING id, level_id, title, description, display_order, is_active, created_at, icon_url
|
||||
`
|
||||
|
||||
type UpdateModuleParams struct {
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
IconUrl pgtype.Text `json:"icon_url"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateModule(ctx context.Context, arg UpdateModuleParams) (Module, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateModule,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.IconUrl,
|
||||
arg.DisplayOrder,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
var i Module
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.LevelID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.IconUrl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const UpdateModuleCapstone = `-- 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 id, module_id, title, description, tips, thumbnail, question_set_id, display_order, is_active, created_at
|
||||
`
|
||||
|
||||
type UpdateModuleCapstoneParams struct {
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
Tips pgtype.Text `json:"tips"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateModuleCapstone(ctx context.Context, arg UpdateModuleCapstoneParams) (ModuleCapstone, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateModuleCapstone,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.Tips,
|
||||
arg.Thumbnail,
|
||||
arg.DisplayOrder,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
var i ModuleCapstone
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Tips,
|
||||
&i.Thumbnail,
|
||||
&i.QuestionSetID,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const UpdateSubModule = `-- 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 id, module_id, title, description, display_order, is_active, created_at, legacy_sub_course_id, thumbnail, tips
|
||||
`
|
||||
|
||||
type UpdateSubModuleParams struct {
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
Tips pgtype.Text `json:"tips"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateSubModule(ctx context.Context, arg UpdateSubModuleParams) (SubModule, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateSubModule,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.Thumbnail,
|
||||
arg.Tips,
|
||||
arg.DisplayOrder,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
var i SubModule
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.LegacySubCourseID,
|
||||
&i.Thumbnail,
|
||||
&i.Tips,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const UpdateSubModuleCapstone = `-- 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 id, sub_module_id, title, description, tips, thumbnail, question_set_id, display_order, is_active, created_at
|
||||
`
|
||||
|
||||
type UpdateSubModuleCapstoneParams struct {
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
Tips pgtype.Text `json:"tips"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateSubModuleCapstone(ctx context.Context, arg UpdateSubModuleCapstoneParams) (SubModuleCapstone, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateSubModuleCapstone,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.Tips,
|
||||
arg.Thumbnail,
|
||||
arg.DisplayOrder,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
var i SubModuleCapstone
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.SubModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Tips,
|
||||
&i.Thumbnail,
|
||||
&i.QuestionSetID,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const UpdateSubModuleLesson = `-- name: UpdateSubModuleLesson :one
|
||||
UPDATE sub_module_lessons
|
||||
SET
|
||||
|
|
|
|||
|
|
@ -94,6 +94,20 @@ type Module struct {
|
|||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
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 {
|
||||
|
|
@ -356,6 +370,21 @@ type SubModule struct {
|
|||
IsActive bool `json:"is_active"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
LegacySubCourseID pgtype.Int8 `json:"legacy_sub_course_id"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
Tips pgtype.Text `json:"tips"`
|
||||
}
|
||||
|
||||
type SubModuleCapstone struct {
|
||||
ID int64 `json:"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"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
}
|
||||
|
||||
type SubModuleLesson struct {
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ type LearningPathSubCourse struct {
|
|||
Title string `json:"title"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Thumbnail *string `json:"thumbnail,omitempty"`
|
||||
Tips *string `json:"tips,omitempty"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
Level string `json:"level"`
|
||||
SubLevel string `json:"sub_level"`
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ const (
|
|||
QuestionSetTypeQuiz QuestionSetType = "QUIZ"
|
||||
QuestionSetTypeExam QuestionSetType = "EXAM"
|
||||
QuestionSetTypeSurvey QuestionSetType = "SURVEY"
|
||||
QuestionSetTypeCapstone QuestionSetType = "CAPSTONE"
|
||||
)
|
||||
|
||||
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 {
|
||||
Title string `json:"title" validate:"required"`
|
||||
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"`
|
||||
OwnerID *int64 `json:"owner_id"`
|
||||
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
|
||||
// @Tags question-sets
|
||||
// @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 offset query int false "Offset" default(0)
|
||||
// @Success 200 {object} domain.Response
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ func (a *App) initAppRoutes() {
|
|||
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.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.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)
|
||||
|
|
@ -126,6 +127,16 @@ func (a *App) initAppRoutes() {
|
|||
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.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
|
||||
groupV1.Post("/questions", a.authMiddleware, a.RequirePermission("questions.create"), h.CreateQuestion)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user