Add practice-existence flags and refresh API contracts.
Expose has_practice booleans for LMS and pre-exam hierarchy entities, wire SQL/repository mappings, and regenerate SQLC/Swagger artifacts. Also update the Resend sender display name for outbound emails. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
9da9eb77e5
commit
bc2357374b
|
|
@ -12,9 +12,18 @@ RETURNING
|
||||||
*;
|
*;
|
||||||
|
|
||||||
-- name: ExamPrepGetCatalogCourseByID :one
|
-- name: ExamPrepGetCatalogCourseByID :one
|
||||||
SELECT *
|
SELECT
|
||||||
FROM exam_prep.catalog_courses
|
c.*,
|
||||||
WHERE id = $1;
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN exam_prep.units u ON u.id = m.unit_id
|
||||||
|
WHERE u.catalog_course_id = c.id
|
||||||
|
) AS has_practice
|
||||||
|
FROM exam_prep.catalog_courses c
|
||||||
|
WHERE c.id = $1;
|
||||||
|
|
||||||
-- name: ExamPrepListCatalogCourses :many
|
-- name: ExamPrepListCatalogCourses :many
|
||||||
WITH catalog_course_counts AS (
|
WITH catalog_course_counts AS (
|
||||||
|
|
@ -38,6 +47,14 @@ SELECT
|
||||||
COALESCE(cc.units_count, 0)::BIGINT AS units_count,
|
COALESCE(cc.units_count, 0)::BIGINT AS units_count,
|
||||||
COALESCE(cc.modules_count, 0)::BIGINT AS modules_count,
|
COALESCE(cc.modules_count, 0)::BIGINT AS modules_count,
|
||||||
COALESCE(cc.lessons_count, 0)::BIGINT AS lessons_count,
|
COALESCE(cc.lessons_count, 0)::BIGINT AS lessons_count,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN exam_prep.units u ON u.id = m.unit_id
|
||||||
|
WHERE u.catalog_course_id = c.id
|
||||||
|
) AS has_practice,
|
||||||
c.created_at,
|
c.created_at,
|
||||||
c.updated_at
|
c.updated_at
|
||||||
FROM exam_prep.catalog_courses c
|
FROM exam_prep.catalog_courses c
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,15 @@ RETURNING
|
||||||
*;
|
*;
|
||||||
|
|
||||||
-- name: ExamPrepGetUnitModuleLessonByID :one
|
-- name: ExamPrepGetUnitModuleLessonByID :one
|
||||||
SELECT *
|
SELECT
|
||||||
FROM exam_prep.unit_module_lessons
|
l.*,
|
||||||
WHERE id = $1;
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
WHERE p.unit_module_lesson_id = l.id
|
||||||
|
) AS has_practice
|
||||||
|
FROM exam_prep.unit_module_lessons l
|
||||||
|
WHERE l.id = $1;
|
||||||
|
|
||||||
-- name: ExamPrepListUnitModuleLessonIDsByUnitModule :many
|
-- name: ExamPrepListUnitModuleLessonIDsByUnitModule :many
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -39,6 +45,11 @@ SELECT
|
||||||
l.thumbnail,
|
l.thumbnail,
|
||||||
l.description,
|
l.description,
|
||||||
l.sort_order,
|
l.sort_order,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
WHERE p.unit_module_lesson_id = l.id
|
||||||
|
) AS has_practice,
|
||||||
l.created_at,
|
l.created_at,
|
||||||
l.updated_at
|
l.updated_at
|
||||||
FROM exam_prep.unit_module_lessons l
|
FROM exam_prep.unit_module_lessons l
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,16 @@ RETURNING
|
||||||
*;
|
*;
|
||||||
|
|
||||||
-- name: ExamPrepGetUnitModuleByID :one
|
-- name: ExamPrepGetUnitModuleByID :one
|
||||||
SELECT *
|
SELECT
|
||||||
FROM exam_prep.unit_modules
|
m.*,
|
||||||
WHERE id = $1;
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
WHERE l.unit_module_id = m.id
|
||||||
|
) AS has_practice
|
||||||
|
FROM exam_prep.unit_modules m
|
||||||
|
WHERE m.id = $1;
|
||||||
|
|
||||||
-- name: ExamPrepListUnitModuleIDsByUnit :many
|
-- name: ExamPrepListUnitModuleIDsByUnit :many
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -51,6 +58,7 @@ SELECT
|
||||||
m.sort_order,
|
m.sort_order,
|
||||||
COALESCE(mc.lessons_count, 0)::BIGINT AS lessons_count,
|
COALESCE(mc.lessons_count, 0)::BIGINT AS lessons_count,
|
||||||
COALESCE(mc.practices_count, 0)::BIGINT AS practices_count,
|
COALESCE(mc.practices_count, 0)::BIGINT AS practices_count,
|
||||||
|
(COALESCE(mc.practices_count, 0)::BIGINT > 0) AS has_practice,
|
||||||
m.created_at,
|
m.created_at,
|
||||||
m.updated_at
|
m.updated_at
|
||||||
FROM exam_prep.unit_modules m
|
FROM exam_prep.unit_modules m
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,17 @@ RETURNING
|
||||||
*;
|
*;
|
||||||
|
|
||||||
-- name: ExamPrepGetUnitByID :one
|
-- name: ExamPrepGetUnitByID :one
|
||||||
SELECT *
|
SELECT
|
||||||
FROM exam_prep.units
|
u.*,
|
||||||
WHERE id = $1;
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
WHERE m.unit_id = u.id
|
||||||
|
) AS has_practice
|
||||||
|
FROM exam_prep.units u
|
||||||
|
WHERE u.id = $1;
|
||||||
|
|
||||||
-- name: ExamPrepListUnitIDsByCatalogCourse :many
|
-- name: ExamPrepListUnitIDsByCatalogCourse :many
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -52,6 +60,7 @@ SELECT
|
||||||
COALESCE(uc.modules_count, 0)::BIGINT AS modules_count,
|
COALESCE(uc.modules_count, 0)::BIGINT AS modules_count,
|
||||||
COALESCE(uc.lessons_count, 0)::BIGINT AS lessons_count,
|
COALESCE(uc.lessons_count, 0)::BIGINT AS lessons_count,
|
||||||
COALESCE(uc.practices_count, 0)::BIGINT AS practices_count,
|
COALESCE(uc.practices_count, 0)::BIGINT AS practices_count,
|
||||||
|
(COALESCE(uc.practices_count, 0)::BIGINT > 0) AS has_practice,
|
||||||
u.created_at,
|
u.created_at,
|
||||||
u.updated_at
|
u.updated_at
|
||||||
FROM exam_prep.units u
|
FROM exam_prep.units u
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,18 @@ RETURNING
|
||||||
*;
|
*;
|
||||||
|
|
||||||
-- name: GetCourseByID :one
|
-- name: GetCourseByID :one
|
||||||
SELECT *
|
SELECT
|
||||||
|
c.*,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.course_id = c.id
|
||||||
|
AND p.module_id IS NULL
|
||||||
|
AND p.lesson_id IS NULL
|
||||||
|
) AS has_practice
|
||||||
FROM courses
|
FROM courses
|
||||||
WHERE id = $1;
|
c
|
||||||
|
WHERE c.id = $1;
|
||||||
|
|
||||||
-- name: ListCourseIDsByProgram :many
|
-- name: ListCourseIDsByProgram :many
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -65,7 +74,14 @@ SELECT
|
||||||
WHERE
|
WHERE
|
||||||
p.course_id = c.id
|
p.course_id = c.id
|
||||||
AND p.module_id IS NULL
|
AND p.module_id IS NULL
|
||||||
AND p.lesson_id IS NULL) AS practice_count
|
AND p.lesson_id IS NULL) AS practice_count,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.course_id = c.id
|
||||||
|
AND p.module_id IS NULL
|
||||||
|
AND p.lesson_id IS NULL
|
||||||
|
) AS has_practice
|
||||||
FROM
|
FROM
|
||||||
courses c
|
courses c
|
||||||
WHERE
|
WHERE
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,16 @@ RETURNING
|
||||||
*;
|
*;
|
||||||
|
|
||||||
-- name: GetLessonByID :one
|
-- name: GetLessonByID :one
|
||||||
SELECT *
|
SELECT
|
||||||
|
l.*,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.lesson_id = l.id
|
||||||
|
) AS has_practice
|
||||||
FROM lessons
|
FROM lessons
|
||||||
WHERE id = $1;
|
l
|
||||||
|
WHERE l.id = $1;
|
||||||
|
|
||||||
-- name: ListLessonsByModuleID :many
|
-- name: ListLessonsByModuleID :many
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -31,7 +38,12 @@ SELECT
|
||||||
l.description,
|
l.description,
|
||||||
l.sort_order,
|
l.sort_order,
|
||||||
l.created_at,
|
l.created_at,
|
||||||
l.updated_at
|
l.updated_at,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.lesson_id = l.id
|
||||||
|
) AS has_practice
|
||||||
FROM
|
FROM
|
||||||
lessons l
|
lessons l
|
||||||
WHERE
|
WHERE
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,17 @@ RETURNING
|
||||||
*;
|
*;
|
||||||
|
|
||||||
-- name: GetModuleByID :one
|
-- name: GetModuleByID :one
|
||||||
SELECT *
|
SELECT
|
||||||
|
m.*,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.module_id = m.id
|
||||||
|
AND p.lesson_id IS NULL
|
||||||
|
) AS has_practice
|
||||||
FROM modules
|
FROM modules
|
||||||
WHERE id = $1;
|
m
|
||||||
|
WHERE m.id = $1;
|
||||||
|
|
||||||
-- name: ListModuleIDsByCourse :many
|
-- name: ListModuleIDsByCourse :many
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -41,7 +49,13 @@ SELECT
|
||||||
m.icon,
|
m.icon,
|
||||||
m.sort_order,
|
m.sort_order,
|
||||||
m.created_at,
|
m.created_at,
|
||||||
m.updated_at
|
m.updated_at,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.module_id = m.id
|
||||||
|
AND p.lesson_id IS NULL
|
||||||
|
) AS has_practice
|
||||||
FROM
|
FROM
|
||||||
modules m
|
modules m
|
||||||
WHERE
|
WHERE
|
||||||
|
|
|
||||||
87
docs/docs.go
87
docs/docs.go
|
|
@ -9405,6 +9405,60 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"domain.DynamicElementDefinition": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"config": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domain.DynamicElementInstance": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"value": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domain.DynamicQuestionPayload": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"response": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementInstance"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stimulus": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementInstance"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.EmploymentType": {
|
"domain.EmploymentType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
@ -9638,6 +9692,9 @@ const docTemplate = `{
|
||||||
"difficultyLevel": {
|
"difficultyLevel": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"dynamicPayload": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicQuestionPayload"
|
||||||
|
},
|
||||||
"explanation": {
|
"explanation": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -10927,6 +10984,9 @@ const docTemplate = `{
|
||||||
"difficulty_level": {
|
"difficulty_level": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"dynamic_payload": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicQuestionPayload"
|
||||||
|
},
|
||||||
"explanation": {
|
"explanation": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11046,6 +11106,12 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"response_schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementDefinition"
|
||||||
|
}
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11054,6 +11120,12 @@ const docTemplate = `{
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"stimulus_schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementDefinition"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -11409,6 +11481,9 @@ const docTemplate = `{
|
||||||
"difficulty_level": {
|
"difficulty_level": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"dynamic_payload": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicQuestionPayload"
|
||||||
|
},
|
||||||
"explanation": {
|
"explanation": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11500,6 +11575,12 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"response_schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementDefinition"
|
||||||
|
}
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11508,6 +11589,12 @@ const docTemplate = `{
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"stimulus_schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementDefinition"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9397,6 +9397,60 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"domain.DynamicElementDefinition": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"config": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domain.DynamicElementInstance": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"value": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domain.DynamicQuestionPayload": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"response": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementInstance"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stimulus": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementInstance"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.EmploymentType": {
|
"domain.EmploymentType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
@ -9630,6 +9684,9 @@
|
||||||
"difficultyLevel": {
|
"difficultyLevel": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"dynamicPayload": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicQuestionPayload"
|
||||||
|
},
|
||||||
"explanation": {
|
"explanation": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -10919,6 +10976,9 @@
|
||||||
"difficulty_level": {
|
"difficulty_level": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"dynamic_payload": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicQuestionPayload"
|
||||||
|
},
|
||||||
"explanation": {
|
"explanation": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11038,6 +11098,12 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"response_schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementDefinition"
|
||||||
|
}
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11046,6 +11112,12 @@
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"stimulus_schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementDefinition"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -11401,6 +11473,9 @@
|
||||||
"difficulty_level": {
|
"difficulty_level": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"dynamic_payload": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicQuestionPayload"
|
||||||
|
},
|
||||||
"explanation": {
|
"explanation": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11492,6 +11567,12 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"response_schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementDefinition"
|
||||||
|
}
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11500,6 +11581,12 @@
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"stimulus_schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.DynamicElementDefinition"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,42 @@ definitions:
|
||||||
- password
|
- password
|
||||||
- team_role
|
- team_role
|
||||||
type: object
|
type: object
|
||||||
|
domain.DynamicElementDefinition:
|
||||||
|
properties:
|
||||||
|
config:
|
||||||
|
additionalProperties: true
|
||||||
|
type: object
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
type: string
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
domain.DynamicElementInstance:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
additionalProperties: true
|
||||||
|
type: object
|
||||||
|
value: {}
|
||||||
|
type: object
|
||||||
|
domain.DynamicQuestionPayload:
|
||||||
|
properties:
|
||||||
|
response:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domain.DynamicElementInstance'
|
||||||
|
type: array
|
||||||
|
stimulus:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domain.DynamicElementInstance'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
domain.EmploymentType:
|
domain.EmploymentType:
|
||||||
enum:
|
enum:
|
||||||
- full_time
|
- full_time
|
||||||
|
|
@ -371,6 +407,8 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
difficultyLevel:
|
difficultyLevel:
|
||||||
type: string
|
type: string
|
||||||
|
dynamicPayload:
|
||||||
|
$ref: '#/definitions/domain.DynamicQuestionPayload'
|
||||||
explanation:
|
explanation:
|
||||||
type: string
|
type: string
|
||||||
id:
|
id:
|
||||||
|
|
@ -1240,6 +1278,8 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
difficulty_level:
|
difficulty_level:
|
||||||
type: string
|
type: string
|
||||||
|
dynamic_payload:
|
||||||
|
$ref: '#/definitions/domain.DynamicQuestionPayload'
|
||||||
explanation:
|
explanation:
|
||||||
type: string
|
type: string
|
||||||
image_url:
|
image_url:
|
||||||
|
|
@ -1320,12 +1360,20 @@ definitions:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
response_schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domain.DynamicElementDefinition'
|
||||||
|
type: array
|
||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
stimulus_component_kinds:
|
stimulus_component_kinds:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
stimulus_schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domain.DynamicElementDefinition'
|
||||||
|
type: array
|
||||||
required:
|
required:
|
||||||
- display_name
|
- display_name
|
||||||
- key
|
- key
|
||||||
|
|
@ -1567,6 +1615,8 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
difficulty_level:
|
difficulty_level:
|
||||||
type: string
|
type: string
|
||||||
|
dynamic_payload:
|
||||||
|
$ref: '#/definitions/domain.DynamicQuestionPayload'
|
||||||
explanation:
|
explanation:
|
||||||
type: string
|
type: string
|
||||||
image_url:
|
image_url:
|
||||||
|
|
@ -1627,12 +1677,20 @@ definitions:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
response_schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domain.DynamicElementDefinition'
|
||||||
|
type: array
|
||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
stimulus_component_kinds:
|
stimulus_component_kinds:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
stimulus_schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domain.DynamicElementDefinition'
|
||||||
|
type: array
|
||||||
type: object
|
type: object
|
||||||
handlers.validateQuestionTypeDefinitionReq:
|
handlers.validateQuestionTypeDefinitionReq:
|
||||||
properties:
|
properties:
|
||||||
|
|
|
||||||
|
|
@ -57,14 +57,34 @@ func (q *Queries) ExamPrepDeleteCatalogCourse(ctx context.Context, id int64) err
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExamPrepGetCatalogCourseByID = `-- name: ExamPrepGetCatalogCourseByID :one
|
const ExamPrepGetCatalogCourseByID = `-- name: ExamPrepGetCatalogCourseByID :one
|
||||||
SELECT id, name, description, thumbnail, sort_order, created_at, updated_at
|
SELECT
|
||||||
FROM exam_prep.catalog_courses
|
c.id, c.name, c.description, c.thumbnail, c.sort_order, c.created_at, c.updated_at,
|
||||||
WHERE id = $1
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN exam_prep.units u ON u.id = m.unit_id
|
||||||
|
WHERE u.catalog_course_id = c.id
|
||||||
|
) AS has_practice
|
||||||
|
FROM exam_prep.catalog_courses c
|
||||||
|
WHERE c.id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ExamPrepGetCatalogCourseByID(ctx context.Context, id int64) (ExamPrepCatalogCourse, error) {
|
type ExamPrepGetCatalogCourseByIDRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ExamPrepGetCatalogCourseByID(ctx context.Context, id int64) (ExamPrepGetCatalogCourseByIDRow, error) {
|
||||||
row := q.db.QueryRow(ctx, ExamPrepGetCatalogCourseByID, id)
|
row := q.db.QueryRow(ctx, ExamPrepGetCatalogCourseByID, id)
|
||||||
var i ExamPrepCatalogCourse
|
var i ExamPrepGetCatalogCourseByIDRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
|
|
@ -73,6 +93,7 @@ func (q *Queries) ExamPrepGetCatalogCourseByID(ctx context.Context, id int64) (E
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
&i.HasPractice,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -126,6 +147,14 @@ SELECT
|
||||||
COALESCE(cc.units_count, 0)::BIGINT AS units_count,
|
COALESCE(cc.units_count, 0)::BIGINT AS units_count,
|
||||||
COALESCE(cc.modules_count, 0)::BIGINT AS modules_count,
|
COALESCE(cc.modules_count, 0)::BIGINT AS modules_count,
|
||||||
COALESCE(cc.lessons_count, 0)::BIGINT AS lessons_count,
|
COALESCE(cc.lessons_count, 0)::BIGINT AS lessons_count,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
INNER JOIN exam_prep.units u ON u.id = m.unit_id
|
||||||
|
WHERE u.catalog_course_id = c.id
|
||||||
|
) AS has_practice,
|
||||||
c.created_at,
|
c.created_at,
|
||||||
c.updated_at
|
c.updated_at
|
||||||
FROM exam_prep.catalog_courses c
|
FROM exam_prep.catalog_courses c
|
||||||
|
|
@ -149,6 +178,7 @@ type ExamPrepListCatalogCoursesRow struct {
|
||||||
UnitsCount int64 `json:"units_count"`
|
UnitsCount int64 `json:"units_count"`
|
||||||
ModulesCount int64 `json:"modules_count"`
|
ModulesCount int64 `json:"modules_count"`
|
||||||
LessonsCount int64 `json:"lessons_count"`
|
LessonsCount int64 `json:"lessons_count"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
@ -172,6 +202,7 @@ func (q *Queries) ExamPrepListCatalogCourses(ctx context.Context, arg ExamPrepLi
|
||||||
&i.UnitsCount,
|
&i.UnitsCount,
|
||||||
&i.ModulesCount,
|
&i.ModulesCount,
|
||||||
&i.LessonsCount,
|
&i.LessonsCount,
|
||||||
|
&i.HasPractice,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -71,14 +71,33 @@ func (q *Queries) ExamPrepDeleteUnitModuleLesson(ctx context.Context, id int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExamPrepGetUnitModuleLessonByID = `-- name: ExamPrepGetUnitModuleLessonByID :one
|
const ExamPrepGetUnitModuleLessonByID = `-- name: ExamPrepGetUnitModuleLessonByID :one
|
||||||
SELECT id, unit_module_id, title, video_url, thumbnail, description, sort_order, created_at, updated_at
|
SELECT
|
||||||
FROM exam_prep.unit_module_lessons
|
l.id, l.unit_module_id, l.title, l.video_url, l.thumbnail, l.description, l.sort_order, l.created_at, l.updated_at,
|
||||||
WHERE id = $1
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
WHERE p.unit_module_lesson_id = l.id
|
||||||
|
) AS has_practice
|
||||||
|
FROM exam_prep.unit_module_lessons l
|
||||||
|
WHERE l.id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ExamPrepGetUnitModuleLessonByID(ctx context.Context, id int64) (ExamPrepUnitModuleLesson, error) {
|
type ExamPrepGetUnitModuleLessonByIDRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
UnitModuleID int64 `json:"unit_module_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
VideoUrl pgtype.Text `json:"video_url"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ExamPrepGetUnitModuleLessonByID(ctx context.Context, id int64) (ExamPrepGetUnitModuleLessonByIDRow, error) {
|
||||||
row := q.db.QueryRow(ctx, ExamPrepGetUnitModuleLessonByID, id)
|
row := q.db.QueryRow(ctx, ExamPrepGetUnitModuleLessonByID, id)
|
||||||
var i ExamPrepUnitModuleLesson
|
var i ExamPrepGetUnitModuleLessonByIDRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.UnitModuleID,
|
&i.UnitModuleID,
|
||||||
|
|
@ -89,6 +108,7 @@ func (q *Queries) ExamPrepGetUnitModuleLessonByID(ctx context.Context, id int64)
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
&i.HasPractice,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -133,6 +153,11 @@ SELECT
|
||||||
l.thumbnail,
|
l.thumbnail,
|
||||||
l.description,
|
l.description,
|
||||||
l.sort_order,
|
l.sort_order,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
WHERE p.unit_module_lesson_id = l.id
|
||||||
|
) AS has_practice,
|
||||||
l.created_at,
|
l.created_at,
|
||||||
l.updated_at
|
l.updated_at
|
||||||
FROM exam_prep.unit_module_lessons l
|
FROM exam_prep.unit_module_lessons l
|
||||||
|
|
@ -160,6 +185,7 @@ type ExamPrepListUnitModuleLessonsByUnitModuleIDRow struct {
|
||||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
SortOrder int32 `json:"sort_order"`
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +208,7 @@ func (q *Queries) ExamPrepListUnitModuleLessonsByUnitModuleID(ctx context.Contex
|
||||||
&i.Thumbnail,
|
&i.Thumbnail,
|
||||||
&i.Description,
|
&i.Description,
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
|
&i.HasPractice,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -71,14 +71,34 @@ func (q *Queries) ExamPrepDeleteUnitModule(ctx context.Context, id int64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExamPrepGetUnitModuleByID = `-- name: ExamPrepGetUnitModuleByID :one
|
const ExamPrepGetUnitModuleByID = `-- name: ExamPrepGetUnitModuleByID :one
|
||||||
SELECT id, unit_id, name, description, thumbnail, icon, sort_order, created_at, updated_at
|
SELECT
|
||||||
FROM exam_prep.unit_modules
|
m.id, m.unit_id, m.name, m.description, m.thumbnail, m.icon, m.sort_order, m.created_at, m.updated_at,
|
||||||
WHERE id = $1
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
WHERE l.unit_module_id = m.id
|
||||||
|
) AS has_practice
|
||||||
|
FROM exam_prep.unit_modules m
|
||||||
|
WHERE m.id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ExamPrepGetUnitModuleByID(ctx context.Context, id int64) (ExamPrepUnitModule, error) {
|
type ExamPrepGetUnitModuleByIDRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
UnitID int64 `json:"unit_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
Icon pgtype.Text `json:"icon"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ExamPrepGetUnitModuleByID(ctx context.Context, id int64) (ExamPrepGetUnitModuleByIDRow, error) {
|
||||||
row := q.db.QueryRow(ctx, ExamPrepGetUnitModuleByID, id)
|
row := q.db.QueryRow(ctx, ExamPrepGetUnitModuleByID, id)
|
||||||
var i ExamPrepUnitModule
|
var i ExamPrepGetUnitModuleByIDRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.UnitID,
|
&i.UnitID,
|
||||||
|
|
@ -89,6 +109,7 @@ func (q *Queries) ExamPrepGetUnitModuleByID(ctx context.Context, id int64) (Exam
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
&i.HasPractice,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -145,6 +166,7 @@ SELECT
|
||||||
m.sort_order,
|
m.sort_order,
|
||||||
COALESCE(mc.lessons_count, 0)::BIGINT AS lessons_count,
|
COALESCE(mc.lessons_count, 0)::BIGINT AS lessons_count,
|
||||||
COALESCE(mc.practices_count, 0)::BIGINT AS practices_count,
|
COALESCE(mc.practices_count, 0)::BIGINT AS practices_count,
|
||||||
|
(COALESCE(mc.practices_count, 0)::BIGINT > 0) AS has_practice,
|
||||||
m.created_at,
|
m.created_at,
|
||||||
m.updated_at
|
m.updated_at
|
||||||
FROM exam_prep.unit_modules m
|
FROM exam_prep.unit_modules m
|
||||||
|
|
@ -175,6 +197,7 @@ type ExamPrepListUnitModulesByUnitRow struct {
|
||||||
SortOrder int32 `json:"sort_order"`
|
SortOrder int32 `json:"sort_order"`
|
||||||
LessonsCount int64 `json:"lessons_count"`
|
LessonsCount int64 `json:"lessons_count"`
|
||||||
PracticesCount int64 `json:"practices_count"`
|
PracticesCount int64 `json:"practices_count"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
@ -199,6 +222,7 @@ func (q *Queries) ExamPrepListUnitModulesByUnit(ctx context.Context, arg ExamPre
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
&i.LessonsCount,
|
&i.LessonsCount,
|
||||||
&i.PracticesCount,
|
&i.PracticesCount,
|
||||||
|
&i.HasPractice,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -67,14 +67,34 @@ func (q *Queries) ExamPrepDeleteUnit(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExamPrepGetUnitByID = `-- name: ExamPrepGetUnitByID :one
|
const ExamPrepGetUnitByID = `-- name: ExamPrepGetUnitByID :one
|
||||||
SELECT id, catalog_course_id, name, description, thumbnail, sort_order, created_at, updated_at
|
SELECT
|
||||||
FROM exam_prep.units
|
u.id, u.catalog_course_id, u.name, u.description, u.thumbnail, u.sort_order, u.created_at, u.updated_at,
|
||||||
WHERE id = $1
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM exam_prep.lesson_practices p
|
||||||
|
INNER JOIN exam_prep.unit_module_lessons l ON l.id = p.unit_module_lesson_id
|
||||||
|
INNER JOIN exam_prep.unit_modules m ON m.id = l.unit_module_id
|
||||||
|
WHERE m.unit_id = u.id
|
||||||
|
) AS has_practice
|
||||||
|
FROM exam_prep.units u
|
||||||
|
WHERE u.id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ExamPrepGetUnitByID(ctx context.Context, id int64) (ExamPrepUnit, error) {
|
type ExamPrepGetUnitByIDRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
CatalogCourseID int64 `json:"catalog_course_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ExamPrepGetUnitByID(ctx context.Context, id int64) (ExamPrepGetUnitByIDRow, error) {
|
||||||
row := q.db.QueryRow(ctx, ExamPrepGetUnitByID, id)
|
row := q.db.QueryRow(ctx, ExamPrepGetUnitByID, id)
|
||||||
var i ExamPrepUnit
|
var i ExamPrepGetUnitByIDRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.CatalogCourseID,
|
&i.CatalogCourseID,
|
||||||
|
|
@ -84,6 +104,7 @@ func (q *Queries) ExamPrepGetUnitByID(ctx context.Context, id int64) (ExamPrepUn
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
&i.HasPractice,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -142,6 +163,7 @@ SELECT
|
||||||
COALESCE(uc.modules_count, 0)::BIGINT AS modules_count,
|
COALESCE(uc.modules_count, 0)::BIGINT AS modules_count,
|
||||||
COALESCE(uc.lessons_count, 0)::BIGINT AS lessons_count,
|
COALESCE(uc.lessons_count, 0)::BIGINT AS lessons_count,
|
||||||
COALESCE(uc.practices_count, 0)::BIGINT AS practices_count,
|
COALESCE(uc.practices_count, 0)::BIGINT AS practices_count,
|
||||||
|
(COALESCE(uc.practices_count, 0)::BIGINT > 0) AS has_practice,
|
||||||
u.created_at,
|
u.created_at,
|
||||||
u.updated_at
|
u.updated_at
|
||||||
FROM exam_prep.units u
|
FROM exam_prep.units u
|
||||||
|
|
@ -172,6 +194,7 @@ type ExamPrepListUnitsByCatalogCourseRow struct {
|
||||||
ModulesCount int64 `json:"modules_count"`
|
ModulesCount int64 `json:"modules_count"`
|
||||||
LessonsCount int64 `json:"lessons_count"`
|
LessonsCount int64 `json:"lessons_count"`
|
||||||
PracticesCount int64 `json:"practices_count"`
|
PracticesCount int64 `json:"practices_count"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
@ -196,6 +219,7 @@ func (q *Queries) ExamPrepListUnitsByCatalogCourse(ctx context.Context, arg Exam
|
||||||
&i.ModulesCount,
|
&i.ModulesCount,
|
||||||
&i.LessonsCount,
|
&i.LessonsCount,
|
||||||
&i.PracticesCount,
|
&i.PracticesCount,
|
||||||
|
&i.HasPractice,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -67,14 +67,35 @@ func (q *Queries) DeleteCourse(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetCourseByID = `-- name: GetCourseByID :one
|
const GetCourseByID = `-- name: GetCourseByID :one
|
||||||
SELECT id, program_id, name, description, thumbnail, created_at, updated_at, sort_order
|
SELECT
|
||||||
|
c.id, c.program_id, c.name, c.description, c.thumbnail, c.created_at, c.updated_at, c.sort_order,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.course_id = c.id
|
||||||
|
AND p.module_id IS NULL
|
||||||
|
AND p.lesson_id IS NULL
|
||||||
|
) AS has_practice
|
||||||
FROM courses
|
FROM courses
|
||||||
WHERE id = $1
|
c
|
||||||
|
WHERE c.id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetCourseByID(ctx context.Context, id int64) (Course, error) {
|
type GetCourseByIDRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
ProgramID int64 `json:"program_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetCourseByID(ctx context.Context, id int64) (GetCourseByIDRow, error) {
|
||||||
row := q.db.QueryRow(ctx, GetCourseByID, id)
|
row := q.db.QueryRow(ctx, GetCourseByID, id)
|
||||||
var i Course
|
var i GetCourseByIDRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ProgramID,
|
&i.ProgramID,
|
||||||
|
|
@ -84,6 +105,7 @@ func (q *Queries) GetCourseByID(ctx context.Context, id int64) (Course, error) {
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
|
&i.HasPractice,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +177,14 @@ SELECT
|
||||||
WHERE
|
WHERE
|
||||||
p.course_id = c.id
|
p.course_id = c.id
|
||||||
AND p.module_id IS NULL
|
AND p.module_id IS NULL
|
||||||
AND p.lesson_id IS NULL) AS practice_count
|
AND p.lesson_id IS NULL) AS practice_count,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.course_id = c.id
|
||||||
|
AND p.module_id IS NULL
|
||||||
|
AND p.lesson_id IS NULL
|
||||||
|
) AS has_practice
|
||||||
FROM
|
FROM
|
||||||
courses c
|
courses c
|
||||||
WHERE
|
WHERE
|
||||||
|
|
@ -185,6 +214,7 @@ type ListCoursesByProgramIDRow struct {
|
||||||
ModuleCount int64 `json:"module_count"`
|
ModuleCount int64 `json:"module_count"`
|
||||||
LessonCount int64 `json:"lesson_count"`
|
LessonCount int64 `json:"lesson_count"`
|
||||||
PracticeCount int64 `json:"practice_count"`
|
PracticeCount int64 `json:"practice_count"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) ListCoursesByProgramID(ctx context.Context, arg ListCoursesByProgramIDParams) ([]ListCoursesByProgramIDRow, error) {
|
func (q *Queries) ListCoursesByProgramID(ctx context.Context, arg ListCoursesByProgramIDParams) ([]ListCoursesByProgramIDRow, error) {
|
||||||
|
|
@ -209,6 +239,7 @@ func (q *Queries) ListCoursesByProgramID(ctx context.Context, arg ListCoursesByP
|
||||||
&i.ModuleCount,
|
&i.ModuleCount,
|
||||||
&i.LessonCount,
|
&i.LessonCount,
|
||||||
&i.PracticeCount,
|
&i.PracticeCount,
|
||||||
|
&i.HasPractice,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,14 +71,34 @@ func (q *Queries) DeleteLesson(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetLessonByID = `-- name: GetLessonByID :one
|
const GetLessonByID = `-- name: GetLessonByID :one
|
||||||
SELECT id, module_id, title, video_url, thumbnail, description, created_at, updated_at, sort_order
|
SELECT
|
||||||
|
l.id, l.module_id, l.title, l.video_url, l.thumbnail, l.description, l.created_at, l.updated_at, l.sort_order,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.lesson_id = l.id
|
||||||
|
) AS has_practice
|
||||||
FROM lessons
|
FROM lessons
|
||||||
WHERE id = $1
|
l
|
||||||
|
WHERE l.id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetLessonByID(ctx context.Context, id int64) (Lesson, error) {
|
type GetLessonByIDRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
ModuleID int64 `json:"module_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
VideoUrl pgtype.Text `json:"video_url"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetLessonByID(ctx context.Context, id int64) (GetLessonByIDRow, error) {
|
||||||
row := q.db.QueryRow(ctx, GetLessonByID, id)
|
row := q.db.QueryRow(ctx, GetLessonByID, id)
|
||||||
var i Lesson
|
var i GetLessonByIDRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ModuleID,
|
&i.ModuleID,
|
||||||
|
|
@ -89,6 +109,7 @@ func (q *Queries) GetLessonByID(ctx context.Context, id int64) (Lesson, error) {
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
|
&i.HasPractice,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +125,12 @@ SELECT
|
||||||
l.description,
|
l.description,
|
||||||
l.sort_order,
|
l.sort_order,
|
||||||
l.created_at,
|
l.created_at,
|
||||||
l.updated_at
|
l.updated_at,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.lesson_id = l.id
|
||||||
|
) AS has_practice
|
||||||
FROM
|
FROM
|
||||||
lessons l
|
lessons l
|
||||||
WHERE
|
WHERE
|
||||||
|
|
@ -133,6 +159,7 @@ type ListLessonsByModuleIDRow struct {
|
||||||
SortOrder int32 `json:"sort_order"`
|
SortOrder int32 `json:"sort_order"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) ListLessonsByModuleID(ctx context.Context, arg ListLessonsByModuleIDParams) ([]ListLessonsByModuleIDRow, error) {
|
func (q *Queries) ListLessonsByModuleID(ctx context.Context, arg ListLessonsByModuleIDParams) ([]ListLessonsByModuleIDRow, error) {
|
||||||
|
|
@ -155,6 +182,7 @@ func (q *Queries) ListLessonsByModuleID(ctx context.Context, arg ListLessonsByMo
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
&i.HasPractice,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,14 +71,35 @@ func (q *Queries) DeleteModule(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetModuleByID = `-- name: GetModuleByID :one
|
const GetModuleByID = `-- name: GetModuleByID :one
|
||||||
SELECT id, program_id, course_id, name, description, icon, created_at, updated_at, sort_order
|
SELECT
|
||||||
|
m.id, m.program_id, m.course_id, m.name, m.description, m.icon, m.created_at, m.updated_at, m.sort_order,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.module_id = m.id
|
||||||
|
AND p.lesson_id IS NULL
|
||||||
|
) AS has_practice
|
||||||
FROM modules
|
FROM modules
|
||||||
WHERE id = $1
|
m
|
||||||
|
WHERE m.id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetModuleByID(ctx context.Context, id int64) (Module, error) {
|
type GetModuleByIDRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
ProgramID int64 `json:"program_id"`
|
||||||
|
CourseID int64 `json:"course_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Icon pgtype.Text `json:"icon"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
SortOrder int32 `json:"sort_order"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetModuleByID(ctx context.Context, id int64) (GetModuleByIDRow, error) {
|
||||||
row := q.db.QueryRow(ctx, GetModuleByID, id)
|
row := q.db.QueryRow(ctx, GetModuleByID, id)
|
||||||
var i Module
|
var i GetModuleByIDRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ProgramID,
|
&i.ProgramID,
|
||||||
|
|
@ -89,6 +110,7 @@ func (q *Queries) GetModuleByID(ctx context.Context, id int64) (Module, error) {
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
|
&i.HasPractice,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +157,13 @@ SELECT
|
||||||
m.icon,
|
m.icon,
|
||||||
m.sort_order,
|
m.sort_order,
|
||||||
m.created_at,
|
m.created_at,
|
||||||
m.updated_at
|
m.updated_at,
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM lms_practices p
|
||||||
|
WHERE p.module_id = m.id
|
||||||
|
AND p.lesson_id IS NULL
|
||||||
|
) AS has_practice
|
||||||
FROM
|
FROM
|
||||||
modules m
|
modules m
|
||||||
WHERE
|
WHERE
|
||||||
|
|
@ -166,6 +194,7 @@ type ListModulesByProgramAndCourseRow struct {
|
||||||
SortOrder int32 `json:"sort_order"`
|
SortOrder int32 `json:"sort_order"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) ListModulesByProgramAndCourse(ctx context.Context, arg ListModulesByProgramAndCourseParams) ([]ListModulesByProgramAndCourseRow, error) {
|
func (q *Queries) ListModulesByProgramAndCourse(ctx context.Context, arg ListModulesByProgramAndCourseParams) ([]ListModulesByProgramAndCourseRow, error) {
|
||||||
|
|
@ -193,6 +222,7 @@ func (q *Queries) ListModulesByProgramAndCourse(ctx context.Context, arg ListMod
|
||||||
&i.SortOrder,
|
&i.SortOrder,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
&i.HasPractice,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ type Course struct {
|
||||||
ModuleCount int `json:"module_count"`
|
ModuleCount int `json:"module_count"`
|
||||||
LessonCount int `json:"lesson_count"`
|
LessonCount int `json:"lesson_count"`
|
||||||
PracticeCount int `json:"practice_count"`
|
PracticeCount int `json:"practice_count"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
Access *LMSEntityAccess `json:"access,omitempty"`
|
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ type ExamPrepCatalogCourse struct {
|
||||||
UnitsCount *int64 `json:"units_count,omitempty"`
|
UnitsCount *int64 `json:"units_count,omitempty"`
|
||||||
ModulesCount *int64 `json:"modules_count,omitempty"`
|
ModulesCount *int64 `json:"modules_count,omitempty"`
|
||||||
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ type ExamPrepLesson struct {
|
||||||
Thumbnail *string `json:"thumbnail,omitempty"`
|
Thumbnail *string `json:"thumbnail,omitempty"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
SortOrder int `json:"sort_order"`
|
SortOrder int `json:"sort_order"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ type ExamPrepModule struct {
|
||||||
SortOrder int `json:"sort_order"`
|
SortOrder int `json:"sort_order"`
|
||||||
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
||||||
PracticesCount *int64 `json:"practices_count,omitempty"`
|
PracticesCount *int64 `json:"practices_count,omitempty"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ type ExamPrepUnit struct {
|
||||||
ModulesCount *int64 `json:"modules_count,omitempty"`
|
ModulesCount *int64 `json:"modules_count,omitempty"`
|
||||||
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
LessonsCount *int64 `json:"lessons_count,omitempty"`
|
||||||
PracticesCount *int64 `json:"practices_count,omitempty"`
|
PracticesCount *int64 `json:"practices_count,omitempty"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ type Lesson struct {
|
||||||
Thumbnail *string `json:"thumbnail,omitempty"`
|
Thumbnail *string `json:"thumbnail,omitempty"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
SortOrder int `json:"sort_order"`
|
SortOrder int `json:"sort_order"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
Access *LMSEntityAccess `json:"access,omitempty"`
|
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ type Module struct {
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
Icon *string `json:"icon,omitempty"`
|
Icon *string `json:"icon,omitempty"`
|
||||||
SortOrder int `json:"sort_order"`
|
SortOrder int `json:"sort_order"`
|
||||||
|
HasPractice bool `json:"has_practice"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
Access *LMSEntityAccess `json:"access,omitempty"`
|
Access *LMSEntityAccess `json:"access,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,17 @@ func (s *Store) GetExamPrepCatalogCourseByID(ctx context.Context, id int64) (dom
|
||||||
}
|
}
|
||||||
return domain.ExamPrepCatalogCourse{}, err
|
return domain.ExamPrepCatalogCourse{}, err
|
||||||
}
|
}
|
||||||
return examPrepCatalogCourseToDomain(c), nil
|
out := examPrepCatalogCourseToDomain(dbgen.ExamPrepCatalogCourse{
|
||||||
|
ID: c.ID,
|
||||||
|
Name: c.Name,
|
||||||
|
Description: c.Description,
|
||||||
|
Thumbnail: c.Thumbnail,
|
||||||
|
SortOrder: c.SortOrder,
|
||||||
|
CreatedAt: c.CreatedAt,
|
||||||
|
UpdatedAt: c.UpdatedAt,
|
||||||
|
})
|
||||||
|
out.HasPractice = c.HasPractice
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ListExamPrepCatalogCourses(ctx context.Context, limit, offset int32) ([]domain.ExamPrepCatalogCourse, int64, error) {
|
func (s *Store) ListExamPrepCatalogCourses(ctx context.Context, limit, offset int32) ([]domain.ExamPrepCatalogCourse, int64, error) {
|
||||||
|
|
@ -79,6 +89,7 @@ func (s *Store) ListExamPrepCatalogCourses(ctx context.Context, limit, offset in
|
||||||
item.UnitsCount = &r.UnitsCount
|
item.UnitsCount = &r.UnitsCount
|
||||||
item.ModulesCount = &r.ModulesCount
|
item.ModulesCount = &r.ModulesCount
|
||||||
item.LessonsCount = &r.LessonsCount
|
item.LessonsCount = &r.LessonsCount
|
||||||
|
item.HasPractice = r.HasPractice
|
||||||
out = append(out, item)
|
out = append(out, item)
|
||||||
}
|
}
|
||||||
return out, total, nil
|
return out, total, nil
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,19 @@ func (s *Store) GetExamPrepUnitModuleLessonByID(ctx context.Context, id int64) (
|
||||||
}
|
}
|
||||||
return domain.ExamPrepLesson{}, err
|
return domain.ExamPrepLesson{}, err
|
||||||
}
|
}
|
||||||
return examPrepLessonToDomain(l), nil
|
out := examPrepLessonToDomain(dbgen.ExamPrepUnitModuleLesson{
|
||||||
|
ID: l.ID,
|
||||||
|
UnitModuleID: l.UnitModuleID,
|
||||||
|
Title: l.Title,
|
||||||
|
VideoUrl: l.VideoUrl,
|
||||||
|
Thumbnail: l.Thumbnail,
|
||||||
|
Description: l.Description,
|
||||||
|
SortOrder: l.SortOrder,
|
||||||
|
CreatedAt: l.CreatedAt,
|
||||||
|
UpdatedAt: l.UpdatedAt,
|
||||||
|
})
|
||||||
|
out.HasPractice = l.HasPractice
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ListExamPrepUnitModuleLessonsByUnitModuleID(ctx context.Context, unitModuleID int64, limit, offset int32) ([]domain.ExamPrepLesson, int64, error) {
|
func (s *Store) ListExamPrepUnitModuleLessonsByUnitModuleID(ctx context.Context, unitModuleID int64, limit, offset int32) ([]domain.ExamPrepLesson, int64, error) {
|
||||||
|
|
@ -72,7 +84,7 @@ func (s *Store) ListExamPrepUnitModuleLessonsByUnitModuleID(ctx context.Context,
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
total = r.TotalCount
|
total = r.TotalCount
|
||||||
}
|
}
|
||||||
out = append(out, examPrepLessonToDomain(dbgen.ExamPrepUnitModuleLesson{
|
item := examPrepLessonToDomain(dbgen.ExamPrepUnitModuleLesson{
|
||||||
ID: r.ID,
|
ID: r.ID,
|
||||||
UnitModuleID: r.UnitModuleID,
|
UnitModuleID: r.UnitModuleID,
|
||||||
Title: r.Title,
|
Title: r.Title,
|
||||||
|
|
@ -82,7 +94,9 @@ func (s *Store) ListExamPrepUnitModuleLessonsByUnitModuleID(ctx context.Context,
|
||||||
SortOrder: r.SortOrder,
|
SortOrder: r.SortOrder,
|
||||||
CreatedAt: r.CreatedAt,
|
CreatedAt: r.CreatedAt,
|
||||||
UpdatedAt: r.UpdatedAt,
|
UpdatedAt: r.UpdatedAt,
|
||||||
}))
|
})
|
||||||
|
item.HasPractice = r.HasPractice
|
||||||
|
out = append(out, item)
|
||||||
}
|
}
|
||||||
return out, total, nil
|
return out, total, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,19 @@ func (s *Store) GetExamPrepUnitModuleByID(ctx context.Context, id int64) (domain
|
||||||
}
|
}
|
||||||
return domain.ExamPrepModule{}, err
|
return domain.ExamPrepModule{}, err
|
||||||
}
|
}
|
||||||
return examPrepModuleToDomain(m), nil
|
out := examPrepModuleToDomain(dbgen.ExamPrepUnitModule{
|
||||||
|
ID: m.ID,
|
||||||
|
UnitID: m.UnitID,
|
||||||
|
Name: m.Name,
|
||||||
|
Description: m.Description,
|
||||||
|
Thumbnail: m.Thumbnail,
|
||||||
|
Icon: m.Icon,
|
||||||
|
SortOrder: m.SortOrder,
|
||||||
|
CreatedAt: m.CreatedAt,
|
||||||
|
UpdatedAt: m.UpdatedAt,
|
||||||
|
})
|
||||||
|
out.HasPractice = m.HasPractice
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ListExamPrepUnitModulesByUnit(ctx context.Context, unitID int64, limit, offset int32) ([]domain.ExamPrepModule, int64, error) {
|
func (s *Store) ListExamPrepUnitModulesByUnit(ctx context.Context, unitID int64, limit, offset int32) ([]domain.ExamPrepModule, int64, error) {
|
||||||
|
|
@ -85,6 +97,7 @@ func (s *Store) ListExamPrepUnitModulesByUnit(ctx context.Context, unitID int64,
|
||||||
})
|
})
|
||||||
item.LessonsCount = &r.LessonsCount
|
item.LessonsCount = &r.LessonsCount
|
||||||
item.PracticesCount = &r.PracticesCount
|
item.PracticesCount = &r.PracticesCount
|
||||||
|
item.HasPractice = r.HasPractice
|
||||||
out = append(out, item)
|
out = append(out, item)
|
||||||
}
|
}
|
||||||
return out, total, nil
|
return out, total, nil
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,18 @@ func (s *Store) GetExamPrepUnitByID(ctx context.Context, id int64) (domain.ExamP
|
||||||
}
|
}
|
||||||
return domain.ExamPrepUnit{}, err
|
return domain.ExamPrepUnit{}, err
|
||||||
}
|
}
|
||||||
return examPrepUnitToDomain(u), nil
|
out := examPrepUnitToDomain(dbgen.ExamPrepUnit{
|
||||||
|
ID: u.ID,
|
||||||
|
CatalogCourseID: u.CatalogCourseID,
|
||||||
|
Name: u.Name,
|
||||||
|
Description: u.Description,
|
||||||
|
Thumbnail: u.Thumbnail,
|
||||||
|
SortOrder: u.SortOrder,
|
||||||
|
CreatedAt: u.CreatedAt,
|
||||||
|
UpdatedAt: u.UpdatedAt,
|
||||||
|
})
|
||||||
|
out.HasPractice = u.HasPractice
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ListExamPrepUnitsByCatalogCourse(ctx context.Context, catalogCourseID int64, limit, offset int32) ([]domain.ExamPrepUnit, int64, error) {
|
func (s *Store) ListExamPrepUnitsByCatalogCourse(ctx context.Context, catalogCourseID int64, limit, offset int32) ([]domain.ExamPrepUnit, int64, error) {
|
||||||
|
|
@ -83,6 +94,7 @@ func (s *Store) ListExamPrepUnitsByCatalogCourse(ctx context.Context, catalogCou
|
||||||
item.ModulesCount = &r.ModulesCount
|
item.ModulesCount = &r.ModulesCount
|
||||||
item.LessonsCount = &r.LessonsCount
|
item.LessonsCount = &r.LessonsCount
|
||||||
item.PracticesCount = &r.PracticesCount
|
item.PracticesCount = &r.PracticesCount
|
||||||
|
item.HasPractice = r.HasPractice
|
||||||
out = append(out, item)
|
out = append(out, item)
|
||||||
}
|
}
|
||||||
return out, total, nil
|
return out, total, nil
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,18 @@ func (s *Store) GetCourseByID(ctx context.Context, id int64) (domain.Course, err
|
||||||
}
|
}
|
||||||
return domain.Course{}, err
|
return domain.Course{}, err
|
||||||
}
|
}
|
||||||
return courseToDomain(c), nil
|
out := courseToDomain(dbgen.Course{
|
||||||
|
ID: c.ID,
|
||||||
|
ProgramID: c.ProgramID,
|
||||||
|
Name: c.Name,
|
||||||
|
Description: c.Description,
|
||||||
|
Thumbnail: c.Thumbnail,
|
||||||
|
SortOrder: c.SortOrder,
|
||||||
|
CreatedAt: c.CreatedAt,
|
||||||
|
UpdatedAt: c.UpdatedAt,
|
||||||
|
})
|
||||||
|
out.HasPractice = c.HasPractice
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ListCoursesByProgramID(ctx context.Context, programID int64, limit, offset int32) ([]domain.Course, int64, error) {
|
func (s *Store) ListCoursesByProgramID(ctx context.Context, programID int64, limit, offset int32) ([]domain.Course, int64, error) {
|
||||||
|
|
@ -87,6 +98,7 @@ func (s *Store) ListCoursesByProgramID(ctx context.Context, programID int64, lim
|
||||||
co.ModuleCount = int(r.ModuleCount)
|
co.ModuleCount = int(r.ModuleCount)
|
||||||
co.LessonCount = int(r.LessonCount)
|
co.LessonCount = int(r.LessonCount)
|
||||||
co.PracticeCount = int(r.PracticeCount)
|
co.PracticeCount = int(r.PracticeCount)
|
||||||
|
co.HasPractice = r.HasPractice
|
||||||
out = append(out, co)
|
out = append(out, co)
|
||||||
}
|
}
|
||||||
return out, total, nil
|
return out, total, nil
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,19 @@ func (s *Store) GetLessonByID(ctx context.Context, id int64) (domain.Lesson, err
|
||||||
}
|
}
|
||||||
return domain.Lesson{}, err
|
return domain.Lesson{}, err
|
||||||
}
|
}
|
||||||
return lessonToDomain(l), nil
|
out := lessonToDomain(dbgen.Lesson{
|
||||||
|
ID: l.ID,
|
||||||
|
ModuleID: l.ModuleID,
|
||||||
|
Title: l.Title,
|
||||||
|
VideoUrl: l.VideoUrl,
|
||||||
|
Thumbnail: l.Thumbnail,
|
||||||
|
Description: l.Description,
|
||||||
|
SortOrder: l.SortOrder,
|
||||||
|
CreatedAt: l.CreatedAt,
|
||||||
|
UpdatedAt: l.UpdatedAt,
|
||||||
|
})
|
||||||
|
out.HasPractice = l.HasPractice
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ListLessonsByModuleID(ctx context.Context, moduleID int64, limit, offset int32) ([]domain.Lesson, int64, error) {
|
func (s *Store) ListLessonsByModuleID(ctx context.Context, moduleID int64, limit, offset int32) ([]domain.Lesson, int64, error) {
|
||||||
|
|
@ -72,7 +84,7 @@ func (s *Store) ListLessonsByModuleID(ctx context.Context, moduleID int64, limit
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
total = r.TotalCount
|
total = r.TotalCount
|
||||||
}
|
}
|
||||||
out = append(out, lessonToDomain(dbgen.Lesson{
|
lesson := lessonToDomain(dbgen.Lesson{
|
||||||
ID: r.ID,
|
ID: r.ID,
|
||||||
ModuleID: r.ModuleID,
|
ModuleID: r.ModuleID,
|
||||||
Title: r.Title,
|
Title: r.Title,
|
||||||
|
|
@ -82,7 +94,9 @@ func (s *Store) ListLessonsByModuleID(ctx context.Context, moduleID int64, limit
|
||||||
CreatedAt: r.CreatedAt,
|
CreatedAt: r.CreatedAt,
|
||||||
UpdatedAt: r.UpdatedAt,
|
UpdatedAt: r.UpdatedAt,
|
||||||
SortOrder: r.SortOrder,
|
SortOrder: r.SortOrder,
|
||||||
}))
|
})
|
||||||
|
lesson.HasPractice = r.HasPractice
|
||||||
|
out = append(out, lesson)
|
||||||
}
|
}
|
||||||
return out, total, nil
|
return out, total, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,19 @@ func (s *Store) GetModuleByID(ctx context.Context, id int64) (domain.Module, err
|
||||||
}
|
}
|
||||||
return domain.Module{}, err
|
return domain.Module{}, err
|
||||||
}
|
}
|
||||||
return moduleToDomain(m), nil
|
out := moduleToDomain(dbgen.Module{
|
||||||
|
ID: m.ID,
|
||||||
|
ProgramID: m.ProgramID,
|
||||||
|
CourseID: m.CourseID,
|
||||||
|
Name: m.Name,
|
||||||
|
Description: m.Description,
|
||||||
|
Icon: m.Icon,
|
||||||
|
SortOrder: m.SortOrder,
|
||||||
|
CreatedAt: m.CreatedAt,
|
||||||
|
UpdatedAt: m.UpdatedAt,
|
||||||
|
})
|
||||||
|
out.HasPractice = m.HasPractice
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ListModulesByProgramAndCourse(ctx context.Context, programID, courseID int64, limit, offset int32) ([]domain.Module, int64, error) {
|
func (s *Store) ListModulesByProgramAndCourse(ctx context.Context, programID, courseID int64, limit, offset int32) ([]domain.Module, int64, error) {
|
||||||
|
|
@ -77,7 +89,7 @@ func (s *Store) ListModulesByProgramAndCourse(ctx context.Context, programID, co
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
total = r.TotalCount
|
total = r.TotalCount
|
||||||
}
|
}
|
||||||
out = append(out, moduleToDomain(dbgen.Module{
|
mod := moduleToDomain(dbgen.Module{
|
||||||
ID: r.ID,
|
ID: r.ID,
|
||||||
ProgramID: r.ProgramID,
|
ProgramID: r.ProgramID,
|
||||||
CourseID: r.CourseID,
|
CourseID: r.CourseID,
|
||||||
|
|
@ -87,7 +99,9 @@ func (s *Store) ListModulesByProgramAndCourse(ctx context.Context, programID, co
|
||||||
CreatedAt: r.CreatedAt,
|
CreatedAt: r.CreatedAt,
|
||||||
UpdatedAt: r.UpdatedAt,
|
UpdatedAt: r.UpdatedAt,
|
||||||
SortOrder: r.SortOrder,
|
SortOrder: r.SortOrder,
|
||||||
}))
|
})
|
||||||
|
mod.HasPractice = r.HasPractice
|
||||||
|
out = append(out, mod)
|
||||||
}
|
}
|
||||||
return out, total, nil
|
return out, total, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ func (s *Service) SendEmail(ctx context.Context, receiverEmail, message string,
|
||||||
func (s *Service) SendEmailWithAttachments(ctx context.Context, receiverEmail, message string, messageHTML string, subject string, attachments []*resend.Attachment) error {
|
func (s *Service) SendEmailWithAttachments(ctx context.Context, receiverEmail, message string, messageHTML string, subject string, attachments []*resend.Attachment) error {
|
||||||
apiKey := s.config.ResendApiKey
|
apiKey := s.config.ResendApiKey
|
||||||
client := resend.NewClient(apiKey)
|
client := resend.NewClient(apiKey)
|
||||||
formattedSenderEmail := "Y <" + s.config.ResendSenderEmail + ">"
|
formattedSenderEmail := "Yimaru - Academy <" + s.config.ResendSenderEmail + ">"
|
||||||
params := &resend.SendEmailRequest{
|
params := &resend.SendEmailRequest{
|
||||||
From: formattedSenderEmail,
|
From: formattedSenderEmail,
|
||||||
To: []string{receiverEmail},
|
To: []string{receiverEmail},
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Yimaru-Backend/internal/domain"
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -132,6 +135,27 @@ func (h *Handler) CreateQuestionTypeDefinition(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actorID := c.Locals("user_id").(int64)
|
||||||
|
actorRole := string(c.Locals("role").(domain.Role))
|
||||||
|
ip := c.IP()
|
||||||
|
ua := c.Get("User-Agent")
|
||||||
|
meta, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"question_type_definition_id": def.ID,
|
||||||
|
"key": def.Key,
|
||||||
|
})
|
||||||
|
go h.activityLogSvc.RecordAction(
|
||||||
|
context.Background(),
|
||||||
|
&actorID,
|
||||||
|
&actorRole,
|
||||||
|
domain.ActionQuestionCreated,
|
||||||
|
domain.ResourceQuestion,
|
||||||
|
&def.ID,
|
||||||
|
"Created question type definition: "+def.DisplayName,
|
||||||
|
meta,
|
||||||
|
&ip,
|
||||||
|
&ua,
|
||||||
|
)
|
||||||
|
|
||||||
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
||||||
Message: "Question type definition created",
|
Message: "Question type definition created",
|
||||||
Data: def,
|
Data: def,
|
||||||
|
|
@ -251,6 +275,26 @@ func (h *Handler) UpdateQuestionTypeDefinition(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actorID := c.Locals("user_id").(int64)
|
||||||
|
actorRole := string(c.Locals("role").(domain.Role))
|
||||||
|
ip := c.IP()
|
||||||
|
ua := c.Get("User-Agent")
|
||||||
|
meta, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"question_type_definition_id": id,
|
||||||
|
})
|
||||||
|
go h.activityLogSvc.RecordAction(
|
||||||
|
context.Background(),
|
||||||
|
&actorID,
|
||||||
|
&actorRole,
|
||||||
|
domain.ActionQuestionUpdated,
|
||||||
|
domain.ResourceQuestion,
|
||||||
|
&id,
|
||||||
|
fmt.Sprintf("Updated question type definition ID: %d", id),
|
||||||
|
meta,
|
||||||
|
&ip,
|
||||||
|
&ua,
|
||||||
|
)
|
||||||
|
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Question type definition updated",
|
Message: "Question type definition updated",
|
||||||
Data: fiber.Map{"id": id},
|
Data: fiber.Map{"id": id},
|
||||||
|
|
@ -282,6 +326,26 @@ func (h *Handler) DeleteQuestionTypeDefinition(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actorID := c.Locals("user_id").(int64)
|
||||||
|
actorRole := string(c.Locals("role").(domain.Role))
|
||||||
|
ip := c.IP()
|
||||||
|
ua := c.Get("User-Agent")
|
||||||
|
meta, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"question_type_definition_id": id,
|
||||||
|
})
|
||||||
|
go h.activityLogSvc.RecordAction(
|
||||||
|
context.Background(),
|
||||||
|
&actorID,
|
||||||
|
&actorRole,
|
||||||
|
domain.ActionQuestionDeleted,
|
||||||
|
domain.ResourceQuestion,
|
||||||
|
&id,
|
||||||
|
fmt.Sprintf("Deleted question type definition ID: %d", id),
|
||||||
|
meta,
|
||||||
|
&ip,
|
||||||
|
&ua,
|
||||||
|
)
|
||||||
|
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Question type definition deleted",
|
Message: "Question type definition deleted",
|
||||||
Data: fiber.Map{"id": id},
|
Data: fiber.Map{"id": id},
|
||||||
|
|
|
||||||
|
|
@ -1299,6 +1299,17 @@ func (h *Handler) AddQuestionToSet(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actorID := c.Locals("user_id").(int64)
|
||||||
|
actorRole := string(c.Locals("role").(domain.Role))
|
||||||
|
ip := c.IP()
|
||||||
|
ua := c.Get("User-Agent")
|
||||||
|
meta, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"question_set_id": setID,
|
||||||
|
"question_id": req.QuestionID,
|
||||||
|
"display_order": req.DisplayOrder,
|
||||||
|
})
|
||||||
|
go h.activityLogSvc.RecordAction(context.Background(), &actorID, &actorRole, domain.ActionQuestionSetUpdated, domain.ResourceQuestionSet, &setID, fmt.Sprintf("Added question %d to question set %d", req.QuestionID, setID), meta, &ip, &ua)
|
||||||
|
|
||||||
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
||||||
Message: "Question added to set successfully",
|
Message: "Question added to set successfully",
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
|
|
@ -1605,6 +1616,16 @@ func (h *Handler) RemoveQuestionFromSet(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actorID := c.Locals("user_id").(int64)
|
||||||
|
actorRole := string(c.Locals("role").(domain.Role))
|
||||||
|
ip := c.IP()
|
||||||
|
ua := c.Get("User-Agent")
|
||||||
|
meta, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"question_set_id": setID,
|
||||||
|
"question_id": questionID,
|
||||||
|
})
|
||||||
|
go h.activityLogSvc.RecordAction(context.Background(), &actorID, &actorRole, domain.ActionQuestionSetUpdated, domain.ResourceQuestionSet, &setID, fmt.Sprintf("Removed question %d from question set %d", questionID, setID), meta, &ip, &ua)
|
||||||
|
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Question removed from set successfully",
|
Message: "Question removed from set successfully",
|
||||||
})
|
})
|
||||||
|
|
@ -1662,6 +1683,17 @@ func (h *Handler) UpdateQuestionOrderInSet(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actorID := c.Locals("user_id").(int64)
|
||||||
|
actorRole := string(c.Locals("role").(domain.Role))
|
||||||
|
ip := c.IP()
|
||||||
|
ua := c.Get("User-Agent")
|
||||||
|
meta, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"question_set_id": setID,
|
||||||
|
"question_id": questionID,
|
||||||
|
"display_order": req.DisplayOrder,
|
||||||
|
})
|
||||||
|
go h.activityLogSvc.RecordAction(context.Background(), &actorID, &actorRole, domain.ActionQuestionSetUpdated, domain.ResourceQuestionSet, &setID, fmt.Sprintf("Updated question %d display_order to %d in set %d", questionID, req.DisplayOrder, setID), meta, &ip, &ua)
|
||||||
|
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Question order updated successfully",
|
Message: "Question order updated successfully",
|
||||||
})
|
})
|
||||||
|
|
@ -1769,6 +1801,17 @@ func (h *Handler) AddUserPersonaToQuestionSet(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actorID := c.Locals("user_id").(int64)
|
||||||
|
actorRole := string(c.Locals("role").(domain.Role))
|
||||||
|
ip := c.IP()
|
||||||
|
ua := c.Get("User-Agent")
|
||||||
|
meta, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"question_set_id": setID,
|
||||||
|
"user_id": req.UserID,
|
||||||
|
"display_order": req.DisplayOrder,
|
||||||
|
})
|
||||||
|
go h.activityLogSvc.RecordAction(context.Background(), &actorID, &actorRole, domain.ActionQuestionSetUpdated, domain.ResourceQuestionSet, &setID, fmt.Sprintf("Added persona user %d to question set %d", req.UserID, setID), meta, &ip, &ua)
|
||||||
|
|
||||||
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
||||||
Message: "Persona added to question set successfully",
|
Message: "Persona added to question set successfully",
|
||||||
})
|
})
|
||||||
|
|
@ -1812,6 +1855,16 @@ func (h *Handler) RemoveUserPersonaFromQuestionSet(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actorID := c.Locals("user_id").(int64)
|
||||||
|
actorRole := string(c.Locals("role").(domain.Role))
|
||||||
|
ip := c.IP()
|
||||||
|
ua := c.Get("User-Agent")
|
||||||
|
meta, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"question_set_id": setID,
|
||||||
|
"user_id": userID,
|
||||||
|
})
|
||||||
|
go h.activityLogSvc.RecordAction(context.Background(), &actorID, &actorRole, domain.ActionQuestionSetUpdated, domain.ResourceQuestionSet, &setID, fmt.Sprintf("Removed persona user %d from question set %d", userID, setID), meta, &ip, &ua)
|
||||||
|
|
||||||
return c.JSON(domain.Response{
|
return c.JSON(domain.Response{
|
||||||
Message: "Persona removed from question set successfully",
|
Message: "Persona removed from question set successfully",
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,18 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Delete("/notifications", a.authMiddleware, a.RequirePermission("notifications.delete_mine"), h.DeleteUserNotifications)
|
groupV1.Delete("/notifications", a.authMiddleware, a.RequirePermission("notifications.delete_mine"), h.DeleteUserNotifications)
|
||||||
groupV1.Get("/notifications/unread", a.authMiddleware, a.RequirePermission("notifications.count_unread"), h.CountUnreadNotifications)
|
groupV1.Get("/notifications/unread", a.authMiddleware, a.RequirePermission("notifications.count_unread"), h.CountUnreadNotifications)
|
||||||
groupV1.Post("/notifications/create", a.authMiddleware, a.RequirePermission("notifications.create"), h.CreateAndSendNotification)
|
groupV1.Post("/notifications/create", a.authMiddleware, a.RequirePermission("notifications.create"), h.CreateAndSendNotification)
|
||||||
|
groupV1.Post("/notifications/test-push", a.authMiddleware, a.RequirePermission("notifications.test_push"), h.SendTestPushNotification)
|
||||||
|
|
||||||
|
// Bulk Notifications
|
||||||
|
groupV1.Post("/notifications/bulk-push", a.authMiddleware, a.RequirePermission("notifications.bulk_push"), h.SendBulkPushNotification)
|
||||||
|
groupV1.Post("/notifications/bulk-sms", a.authMiddleware, a.RequirePermission("notifications.bulk_sms"), h.SendBulkSMS)
|
||||||
|
groupV1.Post("/notifications/send-email", a.authMiddleware, a.RequirePermission("notifications.send_email"), h.SendSingleEmail)
|
||||||
|
groupV1.Post("/notifications/bulk-email", a.authMiddleware, a.RequirePermission("notifications.bulk_email"), h.SendBulkEmail)
|
||||||
|
|
||||||
|
// Scheduled Notifications
|
||||||
|
groupV1.Get("/notifications/scheduled", a.authMiddleware, a.RequirePermission("notifications_scheduled.list"), h.ListScheduledNotifications)
|
||||||
|
groupV1.Get("/notifications/scheduled/:id", a.authMiddleware, a.RequirePermission("notifications_scheduled.get"), h.GetScheduledNotification)
|
||||||
|
groupV1.Post("/notifications/scheduled/:id/cancel", a.authMiddleware, a.RequirePermission("notifications_scheduled.cancel"), h.CancelScheduledNotification)
|
||||||
|
|
||||||
// Issues
|
// Issues
|
||||||
groupV1.Post("/issues", a.authMiddleware, a.RequirePermission("issues.create"), h.CreateIssue)
|
groupV1.Post("/issues", a.authMiddleware, a.RequirePermission("issues.create"), h.CreateIssue)
|
||||||
|
|
@ -324,18 +336,6 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Post("/devices/register", a.authMiddleware, a.RequirePermission("devices.register"), h.RegisterDeviceToken)
|
groupV1.Post("/devices/register", a.authMiddleware, a.RequirePermission("devices.register"), h.RegisterDeviceToken)
|
||||||
groupV1.Post("/devices/unregister", a.authMiddleware, a.RequirePermission("devices.unregister"), h.UnregisterDeviceToken)
|
groupV1.Post("/devices/unregister", a.authMiddleware, a.RequirePermission("devices.unregister"), h.UnregisterDeviceToken)
|
||||||
|
|
||||||
// Push Notifications
|
|
||||||
groupV1.Post("/notifications/test-push", a.authMiddleware, a.RequirePermission("notifications.test_push"), h.SendTestPushNotification)
|
|
||||||
groupV1.Post("/notifications/bulk-push", a.authMiddleware, a.RequirePermission("notifications.bulk_push"), h.SendBulkPushNotification)
|
|
||||||
groupV1.Post("/notifications/bulk-sms", a.authMiddleware, a.RequirePermission("notifications.bulk_sms"), h.SendBulkSMS)
|
|
||||||
groupV1.Post("/notifications/send-email", a.authMiddleware, a.RequirePermission("notifications.send_email"), h.SendSingleEmail)
|
|
||||||
groupV1.Post("/notifications/bulk-email", a.authMiddleware, a.RequirePermission("notifications.bulk_email"), h.SendBulkEmail)
|
|
||||||
|
|
||||||
// Scheduled Notifications
|
|
||||||
groupV1.Get("/notifications/scheduled", a.authMiddleware, a.RequirePermission("notifications_scheduled.list"), h.ListScheduledNotifications)
|
|
||||||
groupV1.Get("/notifications/scheduled/:id", a.authMiddleware, a.RequirePermission("notifications_scheduled.get"), h.GetScheduledNotification)
|
|
||||||
groupV1.Post("/notifications/scheduled/:id/cancel", a.authMiddleware, a.RequirePermission("notifications_scheduled.cancel"), h.CancelScheduledNotification)
|
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
groupV1.Get("/settings", a.authMiddleware, a.RequirePermission("settings.list"), h.GetGlobalSettingList)
|
groupV1.Get("/settings", a.authMiddleware, a.RequirePermission("settings.list"), h.GetGlobalSettingList)
|
||||||
groupV1.Get("/settings/:key", a.authMiddleware, a.RequirePermission("settings.get"), h.GetGlobalSettingByKey)
|
groupV1.Get("/settings/:key", a.authMiddleware, a.RequirePermission("settings.get"), h.GetGlobalSettingByKey)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user