course management and course data seed implementations
This commit is contained in:
parent
aae54e928a
commit
64c25699e9
|
|
@ -287,3 +287,93 @@ VALUES
|
||||||
(16, 'The speaker is promising to arrive on time.', 2, TRUE),
|
(16, 'The speaker is promising to arrive on time.', 2, TRUE),
|
||||||
(16, 'The speaker might arrive late.', 3, FALSE),
|
(16, 'The speaker might arrive late.', 3, FALSE),
|
||||||
(16, 'The speaker has already arrived.', 4, FALSE);
|
(16, 'The speaker has already arrived.', 4, FALSE);
|
||||||
|
|
||||||
|
-- ======================================================
|
||||||
|
-- Course Management Seed Data
|
||||||
|
-- ======================================================
|
||||||
|
|
||||||
|
-- Course Categories
|
||||||
|
INSERT INTO course_categories (name, is_active, created_at) VALUES
|
||||||
|
('Programming', TRUE, CURRENT_TIMESTAMP),
|
||||||
|
('Data Science', TRUE, CURRENT_TIMESTAMP),
|
||||||
|
('Web Development', TRUE, CURRENT_TIMESTAMP);
|
||||||
|
|
||||||
|
-- Courses
|
||||||
|
INSERT INTO courses (category_id, title, description, is_active) VALUES
|
||||||
|
(1, 'Python Programming Fundamentals', 'Learn Python from basics to advanced concepts', TRUE),
|
||||||
|
(1, 'JavaScript for Beginners', 'Master JavaScript programming language', TRUE),
|
||||||
|
(1, 'Advanced Java Development', 'Deep dive into Java enterprise development', TRUE),
|
||||||
|
(2, 'Data Analysis with Python', 'Learn data manipulation and analysis using pandas', TRUE),
|
||||||
|
(2, 'Machine Learning Basics', 'Introduction to machine learning algorithms', TRUE),
|
||||||
|
(3, 'Full Stack Web Development', 'Complete guide to modern web development', TRUE),
|
||||||
|
(3, 'React.js Masterclass', 'Build dynamic user interfaces with React', TRUE);
|
||||||
|
|
||||||
|
-- Programs
|
||||||
|
INSERT INTO programs (course_id, title, description, thumbnail, display_order, is_active) VALUES
|
||||||
|
(1, 'Python Basics', 'Fundamental concepts of Python programming', NULL, 1, TRUE),
|
||||||
|
(1, 'Python Intermediate', 'Object-oriented programming and data structures', NULL, 2, TRUE),
|
||||||
|
(1, 'Python Advanced', 'Advanced Python concepts and best practices', NULL, 3, TRUE),
|
||||||
|
(2, 'JavaScript Fundamentals', 'Core JavaScript concepts and syntax', NULL, 1, TRUE),
|
||||||
|
(2, 'DOM Manipulation', 'Working with the Document Object Model', NULL, 2, TRUE),
|
||||||
|
(3, 'Java Core Concepts', 'Essential Java programming principles', NULL, 1, TRUE),
|
||||||
|
(3, 'Spring Framework', 'Building enterprise applications with Spring', NULL, 2, TRUE);
|
||||||
|
|
||||||
|
-- Levels
|
||||||
|
INSERT INTO levels (program_id, title, description, level_index, is_active) VALUES
|
||||||
|
(1, 'Getting Started', 'Introduction to Python and basic syntax', 1, TRUE),
|
||||||
|
(1, 'Data Types & Variables', 'Understanding Python data types and variables', 2, TRUE),
|
||||||
|
(1, 'Control Flow', 'Conditional statements and loops', 3, TRUE),
|
||||||
|
|
||||||
|
(2, 'Functions', 'Writing and using functions in Python', 1, TRUE),
|
||||||
|
(2, 'Lists & Dictionaries', 'Working with Python collections', 2, TRUE),
|
||||||
|
(2, 'File Operations', 'Reading and writing files', 3, TRUE);
|
||||||
|
|
||||||
|
-- Modules
|
||||||
|
INSERT INTO modules (level_id, title, content, display_order, is_active) VALUES
|
||||||
|
(1, 'Installing Python', 'Setting up Python development environment', 1, TRUE),
|
||||||
|
(1, 'Your First Python Program', 'Writing and running your first Python script', 2, TRUE),
|
||||||
|
(2, 'Numbers and Strings', 'Working with numeric and text data types', 1, TRUE),
|
||||||
|
(2, 'Variables and Assignment', 'Understanding variables and assignment operators', 2, TRUE),
|
||||||
|
(3, 'Conditional Statements', 'Using if, elif, and else statements', 1, TRUE),
|
||||||
|
(3, 'Loops in Python', 'For and while loops with examples', 2, TRUE);
|
||||||
|
|
||||||
|
-- Module Videos
|
||||||
|
INSERT INTO module_videos (
|
||||||
|
module_id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
video_url,
|
||||||
|
duration,
|
||||||
|
resolution,
|
||||||
|
visibility,
|
||||||
|
is_active
|
||||||
|
) VALUES
|
||||||
|
(1, 'Python Installation Guide', 'Installing Python', 'https://example.com/python-install.mp4', 900, '1080p', 'public', TRUE),
|
||||||
|
(2, 'Hello World in Python', 'First Python program', 'https://example.com/python-hello.mp4', 1200, '1080p', 'public', TRUE),
|
||||||
|
(3, 'Numbers and Math', 'Numeric types in Python', 'https://example.com/python-numbers.mp4', 1500, '720p', 'public', TRUE);
|
||||||
|
|
||||||
|
-- Practices
|
||||||
|
INSERT INTO practices (
|
||||||
|
owner_type,
|
||||||
|
owner_id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
persona,
|
||||||
|
is_active
|
||||||
|
) VALUES
|
||||||
|
('LEVEL', 1, 'Python Basics Assessment', 'Test Python basics', 'beginner', TRUE),
|
||||||
|
('LEVEL', 2, 'Data Types Practice', 'Practice Python data types', 'beginner', TRUE),
|
||||||
|
('MODULE', 3, 'Control Flow Quiz', 'Assess control flow knowledge', 'beginner', TRUE);
|
||||||
|
|
||||||
|
-- Practice Questions
|
||||||
|
INSERT INTO practice_questions (
|
||||||
|
practice_id,
|
||||||
|
question,
|
||||||
|
sample_answer,
|
||||||
|
tips,
|
||||||
|
type
|
||||||
|
) VALUES
|
||||||
|
(1, 'What is the correct way to print "Hello World" in Python?', 'print("Hello World")', 'Use print()', 'MCQ'),
|
||||||
|
(1, 'Which is a valid Python variable name?', 'my_variable', 'Variables cannot start with numbers', 'MCQ'),
|
||||||
|
(2, 'How do you convert "123" to an integer?', 'int("123")', 'Use int()', 'MCQ'),
|
||||||
|
(3, 'How many times does range(3) loop run?', '3', 'Starts from zero', 'MCQ');
|
||||||
|
|
|
||||||
|
|
@ -78,3 +78,59 @@ SELECT setval(
|
||||||
COALESCE((SELECT MAX(id) FROM reported_issues), 1),
|
COALESCE((SELECT MAX(id) FROM reported_issues), 1),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- course_categories.id (BIGSERIAL)
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('course_categories', 'id'),
|
||||||
|
COALESCE((SELECT MAX(id) FROM course_categories), 1),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
-- courses.id (BIGSERIAL)
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('courses', 'id'),
|
||||||
|
COALESCE((SELECT MAX(id) FROM courses), 1),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
-- programs.id (BIGSERIAL)
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('programs', 'id'),
|
||||||
|
COALESCE((SELECT MAX(id) FROM programs), 1),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
-- levels.id (BIGSERIAL)
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('levels', 'id'),
|
||||||
|
COALESCE((SELECT MAX(id) FROM levels), 1),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
-- modules.id (BIGSERIAL)
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('modules', 'id'),
|
||||||
|
COALESCE((SELECT MAX(id) FROM modules), 1),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
-- module_videos.id (BIGSERIAL)
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('module_videos', 'id'),
|
||||||
|
COALESCE((SELECT MAX(id) FROM module_videos), 1),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
-- practices.id (BIGSERIAL)
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('practices', 'id'),
|
||||||
|
COALESCE((SELECT MAX(id) FROM practices), 1),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
-- practice_questions.id (BIGSERIAL)
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('practice_questions', 'id'),
|
||||||
|
COALESCE((SELECT MAX(id) FROM practice_questions), 1),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,50 +3,37 @@ INSERT INTO course_categories (
|
||||||
name,
|
name,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, COALESCE($2, true))
|
||||||
$1, -- name
|
RETURNING *;
|
||||||
$2 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
is_active,
|
|
||||||
created_at;
|
|
||||||
|
|
||||||
-- name: GetCourseCategoryByID :one
|
-- name: GetCourseCategoryByID :one
|
||||||
SELECT
|
SELECT *
|
||||||
id,
|
|
||||||
name,
|
|
||||||
is_active,
|
|
||||||
created_at
|
|
||||||
FROM course_categories
|
FROM course_categories
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
-- name: ListActiveCourseCategories :many
|
|
||||||
|
-- name: GetAllCourseCategories :many
|
||||||
SELECT
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
is_active,
|
is_active,
|
||||||
created_at
|
created_at
|
||||||
FROM course_categories
|
FROM course_categories
|
||||||
WHERE is_active = TRUE
|
ORDER BY created_at DESC
|
||||||
ORDER BY created_at DESC;
|
LIMIT sqlc.narg('limit')::INT
|
||||||
|
OFFSET sqlc.narg('offset')::INT;
|
||||||
|
|
||||||
-- name: UpdateCourseCategory :one
|
|
||||||
|
-- name: UpdateCourseCategory :exec
|
||||||
UPDATE course_categories
|
UPDATE course_categories
|
||||||
SET
|
SET
|
||||||
name = $2,
|
name = COALESCE($1, name),
|
||||||
is_active = $3
|
is_active = COALESCE($2, is_active)
|
||||||
WHERE id = $1
|
WHERE id = $3;
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
is_active,
|
|
||||||
created_at;
|
|
||||||
|
|
||||||
-- name: DeactivateCourseCategory :exec
|
|
||||||
UPDATE course_categories
|
-- name: DeleteCourseCategory :exec
|
||||||
SET is_active = FALSE
|
DELETE FROM course_categories
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,37 @@ INSERT INTO programs (
|
||||||
display_order,
|
display_order,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, $4, COALESCE($5, 0), COALESCE($6, true))
|
||||||
$1, -- course_id
|
RETURNING *;
|
||||||
$2, -- title
|
|
||||||
$3, -- description
|
|
||||||
$4, -- thumbnail
|
-- name: GetProgramsByCourse :many
|
||||||
$5, -- display_order
|
SELECT
|
||||||
$6 -- is_active
|
COUNT(*) OVER () AS total_count,
|
||||||
)
|
id,
|
||||||
|
course_id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail,
|
||||||
|
display_order,
|
||||||
|
is_active
|
||||||
|
FROM programs
|
||||||
|
WHERE course_id = $1
|
||||||
|
ORDER BY display_order ASC;
|
||||||
|
|
||||||
|
-- name: UpdateProgramPartial :exec
|
||||||
|
UPDATE programs
|
||||||
|
SET
|
||||||
|
title = COALESCE($1, title),
|
||||||
|
description = COALESCE($2, description),
|
||||||
|
thumbnail = COALESCE($3, thumbnail),
|
||||||
|
display_order = COALESCE($4, display_order),
|
||||||
|
is_active = COALESCE($5, is_active)
|
||||||
|
WHERE id = $6;
|
||||||
|
|
||||||
|
-- name: DeleteProgram :one
|
||||||
|
DELETE FROM programs
|
||||||
|
WHERE id = $1
|
||||||
RETURNING
|
RETURNING
|
||||||
id,
|
id,
|
||||||
course_id,
|
course_id,
|
||||||
|
|
@ -24,6 +47,7 @@ RETURNING
|
||||||
display_order,
|
display_order,
|
||||||
is_active;
|
is_active;
|
||||||
|
|
||||||
|
|
||||||
-- name: GetProgramByID :one
|
-- name: GetProgramByID :one
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
|
|
@ -63,7 +87,7 @@ FROM programs
|
||||||
WHERE is_active = TRUE
|
WHERE is_active = TRUE
|
||||||
ORDER BY display_order ASC;
|
ORDER BY display_order ASC;
|
||||||
|
|
||||||
-- name: UpdateProgram :one
|
-- name: UpdateProgramFull :one
|
||||||
UPDATE programs
|
UPDATE programs
|
||||||
SET
|
SET
|
||||||
course_id = $2,
|
course_id = $2,
|
||||||
|
|
@ -82,6 +106,7 @@ RETURNING
|
||||||
display_order,
|
display_order,
|
||||||
is_active;
|
is_active;
|
||||||
|
|
||||||
|
|
||||||
-- name: DeactivateProgram :exec
|
-- name: DeactivateProgram :exec
|
||||||
UPDATE programs
|
UPDATE programs
|
||||||
SET is_active = FALSE
|
SET is_active = FALSE
|
||||||
|
|
|
||||||
|
|
@ -5,31 +5,19 @@ INSERT INTO courses (
|
||||||
description,
|
description,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, COALESCE($4, true))
|
||||||
$1, -- category_id
|
RETURNING *;
|
||||||
$2, -- title
|
|
||||||
$3, -- description
|
|
||||||
$4 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
category_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: GetCourseByID :one
|
-- name: GetCourseByID :one
|
||||||
SELECT
|
SELECT *
|
||||||
id,
|
|
||||||
category_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
is_active
|
|
||||||
FROM courses
|
FROM courses
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
-- name: ListCoursesByCategory :many
|
|
||||||
|
-- name: GetCoursesByCategory :many
|
||||||
SELECT
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
id,
|
id,
|
||||||
category_id,
|
category_id,
|
||||||
title,
|
title,
|
||||||
|
|
@ -37,37 +25,20 @@ SELECT
|
||||||
is_active
|
is_active
|
||||||
FROM courses
|
FROM courses
|
||||||
WHERE category_id = $1
|
WHERE category_id = $1
|
||||||
AND is_active = TRUE
|
ORDER BY id DESC
|
||||||
ORDER BY id DESC;
|
LIMIT sqlc.narg('limit')::INT
|
||||||
|
OFFSET sqlc.narg('offset')::INT;
|
||||||
|
|
||||||
-- name: ListActiveCourses :many
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
category_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
is_active
|
|
||||||
FROM courses
|
|
||||||
WHERE is_active = TRUE
|
|
||||||
ORDER BY id DESC;
|
|
||||||
|
|
||||||
-- name: UpdateCourse :one
|
-- name: UpdateCourse :exec
|
||||||
UPDATE courses
|
UPDATE courses
|
||||||
SET
|
SET
|
||||||
category_id = $2,
|
title = COALESCE($1, title),
|
||||||
title = $3,
|
description = COALESCE($2, description),
|
||||||
description = $4,
|
is_active = COALESCE($3, is_active)
|
||||||
is_active = $5
|
WHERE id = $4;
|
||||||
WHERE id = $1
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
category_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: DeactivateCourse :exec
|
|
||||||
UPDATE courses
|
-- name: DeleteCourse :exec
|
||||||
SET is_active = FALSE
|
DELETE FROM courses
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
|
|
|
||||||
16
db/query/learning_tree.sql
Normal file
16
db/query/learning_tree.sql
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
-- name: GetFullLearningTree :many
|
||||||
|
SELECT
|
||||||
|
c.id AS course_id,
|
||||||
|
c.title AS course_title,
|
||||||
|
p.id AS program_id,
|
||||||
|
p.title AS program_title,
|
||||||
|
l.id AS level_id,
|
||||||
|
l.title AS level_title,
|
||||||
|
m.id AS module_id,
|
||||||
|
m.title AS module_title
|
||||||
|
FROM courses c
|
||||||
|
JOIN programs p ON p.course_id = c.id
|
||||||
|
JOIN levels l ON l.program_id = p.id
|
||||||
|
LEFT JOIN modules m ON m.level_id = l.id
|
||||||
|
WHERE c.is_active = true
|
||||||
|
ORDER BY p.display_order, l.level_index, m.display_order;
|
||||||
|
|
@ -6,34 +6,13 @@ INSERT INTO modules (
|
||||||
display_order,
|
display_order,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, COALESCE($4, 0), COALESCE($5, true))
|
||||||
$1, -- level_id
|
RETURNING *;
|
||||||
$2, -- title
|
|
||||||
$3, -- content
|
|
||||||
$4, -- display_order
|
|
||||||
$5 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
level_id,
|
|
||||||
title,
|
|
||||||
content,
|
|
||||||
display_order,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: GetModuleByID :one
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
level_id,
|
|
||||||
title,
|
|
||||||
content,
|
|
||||||
display_order,
|
|
||||||
is_active
|
|
||||||
FROM modules
|
|
||||||
WHERE id = $1;
|
|
||||||
|
|
||||||
-- name: ListModulesByLevel :many
|
-- name: GetModulesByLevel :many
|
||||||
SELECT
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
id,
|
id,
|
||||||
level_id,
|
level_id,
|
||||||
title,
|
title,
|
||||||
|
|
@ -42,26 +21,19 @@ SELECT
|
||||||
is_active
|
is_active
|
||||||
FROM modules
|
FROM modules
|
||||||
WHERE level_id = $1
|
WHERE level_id = $1
|
||||||
AND is_active = TRUE
|
ORDER BY display_order ASC;
|
||||||
ORDER BY display_order ASC, id ASC;
|
|
||||||
|
|
||||||
-- name: UpdateModule :one
|
|
||||||
|
-- name: UpdateModule :exec
|
||||||
UPDATE modules
|
UPDATE modules
|
||||||
SET
|
SET
|
||||||
title = $2,
|
title = COALESCE($1, title),
|
||||||
content = $3,
|
content = COALESCE($2, content),
|
||||||
display_order = $4,
|
display_order = COALESCE($3, display_order),
|
||||||
is_active = $5
|
is_active = COALESCE($4, is_active)
|
||||||
WHERE id = $1
|
WHERE id = $5;
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
level_id,
|
|
||||||
title,
|
|
||||||
content,
|
|
||||||
display_order,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: DeactivateModule :exec
|
|
||||||
UPDATE modules
|
-- name: DeleteModule :exec
|
||||||
SET is_active = FALSE
|
DELETE FROM modules
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
|
||||||
|
|
@ -6,136 +6,50 @@ INSERT INTO module_videos (
|
||||||
video_url,
|
video_url,
|
||||||
duration,
|
duration,
|
||||||
resolution,
|
resolution,
|
||||||
|
|
||||||
is_published,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
|
|
||||||
instructor_id,
|
instructor_id,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
|
visibility,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
$1, -- module_id
|
$1, $2, $3, $4, $5, $6,
|
||||||
$2, -- title
|
$7, $8, $9,
|
||||||
$3, -- description
|
COALESCE($10, true)
|
||||||
$4, -- video_url
|
|
||||||
$5, -- duration
|
|
||||||
$6, -- resolution
|
|
||||||
|
|
||||||
$7, -- is_published
|
|
||||||
$8, -- publish_date
|
|
||||||
$9, -- visibility
|
|
||||||
|
|
||||||
$10, -- instructor_id
|
|
||||||
$11, -- thumbnail
|
|
||||||
$12 -- is_active
|
|
||||||
)
|
)
|
||||||
RETURNING
|
RETURNING *;
|
||||||
id,
|
|
||||||
module_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
video_url,
|
|
||||||
duration,
|
|
||||||
resolution,
|
|
||||||
is_published,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
instructor_id,
|
|
||||||
thumbnail,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: GetModuleVideoByID :one
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
module_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
video_url,
|
|
||||||
duration,
|
|
||||||
resolution,
|
|
||||||
is_published,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
instructor_id,
|
|
||||||
thumbnail,
|
|
||||||
is_active
|
|
||||||
FROM module_videos
|
|
||||||
WHERE id = $1;
|
|
||||||
|
|
||||||
-- name: ListPublishedVideosByModule :many
|
-- name: PublishModuleVideo :exec
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
module_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
video_url,
|
|
||||||
duration,
|
|
||||||
resolution,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
instructor_id,
|
|
||||||
thumbnail
|
|
||||||
FROM module_videos
|
|
||||||
WHERE module_id = $1
|
|
||||||
AND is_active = TRUE
|
|
||||||
AND is_published = TRUE
|
|
||||||
ORDER BY publish_date ASC, id ASC;
|
|
||||||
|
|
||||||
-- name: ListAllVideosByModule :many
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
module_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
video_url,
|
|
||||||
duration,
|
|
||||||
resolution,
|
|
||||||
is_published,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
instructor_id,
|
|
||||||
thumbnail,
|
|
||||||
is_active
|
|
||||||
FROM module_videos
|
|
||||||
WHERE module_id = $1
|
|
||||||
ORDER BY id ASC;
|
|
||||||
|
|
||||||
-- name: UpdateModuleVideo :one
|
|
||||||
UPDATE module_videos
|
UPDATE module_videos
|
||||||
SET
|
SET
|
||||||
title = $2,
|
is_published = true,
|
||||||
description = $3,
|
publish_date = CURRENT_TIMESTAMP
|
||||||
video_url = $4,
|
|
||||||
duration = $5,
|
|
||||||
resolution = $6,
|
|
||||||
|
|
||||||
is_published = $7,
|
|
||||||
publish_date = $8,
|
|
||||||
visibility = $9,
|
|
||||||
|
|
||||||
instructor_id = $10,
|
|
||||||
thumbnail = $11,
|
|
||||||
is_active = $12
|
|
||||||
WHERE id = $1
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
module_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
video_url,
|
|
||||||
duration,
|
|
||||||
resolution,
|
|
||||||
is_published,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
instructor_id,
|
|
||||||
thumbnail,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: DeactivateModuleVideo :exec
|
|
||||||
UPDATE module_videos
|
|
||||||
SET is_active = FALSE
|
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
|
|
||||||
|
-- name: GetPublishedVideosByModule :many
|
||||||
|
SELECT *
|
||||||
|
FROM module_videos
|
||||||
|
WHERE module_id = $1
|
||||||
|
AND is_published = true
|
||||||
|
AND is_active = true
|
||||||
|
ORDER BY publish_date ASC;
|
||||||
|
|
||||||
|
|
||||||
|
-- name: UpdateModuleVideo :exec
|
||||||
|
UPDATE module_videos
|
||||||
|
SET
|
||||||
|
title = COALESCE($1, title),
|
||||||
|
description = COALESCE($2, description),
|
||||||
|
video_url = COALESCE($3, video_url),
|
||||||
|
duration = COALESCE($4, duration),
|
||||||
|
resolution = COALESCE($5, resolution),
|
||||||
|
visibility = COALESCE($6, visibility),
|
||||||
|
thumbnail = COALESCE($7, thumbnail),
|
||||||
|
is_active = COALESCE($8, is_active)
|
||||||
|
WHERE id = $9;
|
||||||
|
|
||||||
|
|
||||||
|
-- name: DeleteModuleVideo :exec
|
||||||
|
DELETE FROM module_videos
|
||||||
|
WHERE id = $1;
|
||||||
|
|
|
||||||
|
|
@ -8,71 +8,26 @@ INSERT INTO practice_questions (
|
||||||
tips,
|
tips,
|
||||||
type
|
type
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||||
$1, -- practice_id
|
RETURNING *;
|
||||||
$2, -- question
|
|
||||||
$3, -- question_voice_prompt
|
|
||||||
$4, -- sample_answer_voice_prompt
|
|
||||||
$5, -- sample_answer
|
|
||||||
$6, -- tips
|
|
||||||
$7 -- type (MCQ, TRUE_FALSE, SHORT)
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
practice_id,
|
|
||||||
question,
|
|
||||||
question_voice_prompt,
|
|
||||||
sample_answer_voice_prompt,
|
|
||||||
sample_answer,
|
|
||||||
tips,
|
|
||||||
type;
|
|
||||||
|
|
||||||
-- name: GetPracticeQuestionByID :one
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
practice_id,
|
|
||||||
question,
|
|
||||||
question_voice_prompt,
|
|
||||||
sample_answer_voice_prompt,
|
|
||||||
sample_answer,
|
|
||||||
tips,
|
|
||||||
type
|
|
||||||
FROM practice_questions
|
|
||||||
WHERE id = $1;
|
|
||||||
|
|
||||||
-- name: ListPracticeQuestions :many
|
-- name: GetQuestionsByPractice :many
|
||||||
SELECT
|
SELECT *
|
||||||
id,
|
|
||||||
practice_id,
|
|
||||||
question,
|
|
||||||
question_voice_prompt,
|
|
||||||
sample_answer_voice_prompt,
|
|
||||||
sample_answer,
|
|
||||||
tips,
|
|
||||||
type
|
|
||||||
FROM practice_questions
|
FROM practice_questions
|
||||||
WHERE practice_id = $1
|
WHERE practice_id = $1
|
||||||
ORDER BY id ASC;
|
ORDER BY id ASC;
|
||||||
|
|
||||||
-- name: UpdatePracticeQuestion :one
|
|
||||||
|
-- name: UpdatePracticeQuestion :exec
|
||||||
UPDATE practice_questions
|
UPDATE practice_questions
|
||||||
SET
|
SET
|
||||||
question = $2,
|
question = COALESCE($1, question),
|
||||||
question_voice_prompt = $3,
|
sample_answer = COALESCE($2, sample_answer),
|
||||||
sample_answer_voice_prompt = $4,
|
tips = COALESCE($3, tips),
|
||||||
sample_answer = $5,
|
type = COALESCE($4, type)
|
||||||
tips = $6,
|
WHERE id = $5;
|
||||||
type = $7
|
|
||||||
WHERE id = $1
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
practice_id,
|
|
||||||
question,
|
|
||||||
question_voice_prompt,
|
|
||||||
sample_answer_voice_prompt,
|
|
||||||
sample_answer,
|
|
||||||
tips,
|
|
||||||
type;
|
|
||||||
|
|
||||||
-- name: DeletePracticeQuestion :exec
|
-- name: DeletePracticeQuestion :exec
|
||||||
DELETE FROM practice_questions
|
DELETE FROM practice_questions
|
||||||
|
|
|
||||||
|
|
@ -8,74 +8,29 @@ INSERT INTO practices (
|
||||||
persona,
|
persona,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, true))
|
||||||
$1, -- owner_type (LEVEL | MODULE)
|
RETURNING *;
|
||||||
$2, -- owner_id
|
|
||||||
$3, -- title
|
|
||||||
$4, -- description
|
|
||||||
$5, -- banner_image
|
|
||||||
$6, -- persona
|
|
||||||
$7 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
owner_type,
|
|
||||||
owner_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
banner_image,
|
|
||||||
persona,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: GetPracticeByID :one
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
owner_type,
|
|
||||||
owner_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
banner_image,
|
|
||||||
persona,
|
|
||||||
is_active
|
|
||||||
FROM practices
|
|
||||||
WHERE id = $1;
|
|
||||||
|
|
||||||
-- name: ListPracticesByOwner :many
|
-- name: GetPracticesByOwner :many
|
||||||
SELECT
|
SELECT *
|
||||||
id,
|
|
||||||
owner_type,
|
|
||||||
owner_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
banner_image,
|
|
||||||
persona,
|
|
||||||
is_active
|
|
||||||
FROM practices
|
FROM practices
|
||||||
WHERE owner_type = $1
|
WHERE owner_type = $1
|
||||||
AND owner_id = $2
|
AND owner_id = $2
|
||||||
AND is_active = TRUE
|
AND is_active = true;
|
||||||
ORDER BY id ASC;
|
|
||||||
|
|
||||||
-- name: UpdatePractice :one
|
|
||||||
|
-- name: UpdatePractice :exec
|
||||||
UPDATE practices
|
UPDATE practices
|
||||||
SET
|
SET
|
||||||
title = $2,
|
title = COALESCE($1, title),
|
||||||
description = $3,
|
description = COALESCE($2, description),
|
||||||
banner_image = $4,
|
banner_image = COALESCE($3, banner_image),
|
||||||
persona = $5,
|
persona = COALESCE($4, persona),
|
||||||
is_active = $6
|
is_active = COALESCE($5, is_active)
|
||||||
WHERE id = $1
|
WHERE id = $6;
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
owner_type,
|
|
||||||
owner_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
banner_image,
|
|
||||||
persona,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: DeactivatePractice :exec
|
|
||||||
UPDATE practices
|
-- name: DeletePractice :exec
|
||||||
SET is_active = FALSE
|
DELETE FROM practices
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
|
||||||
|
|
@ -4,48 +4,15 @@ INSERT INTO levels (
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
level_index,
|
level_index,
|
||||||
number_of_modules,
|
|
||||||
number_of_practices,
|
|
||||||
number_of_videos,
|
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, $4, COALESCE($5, true))
|
||||||
$1, -- program_id
|
RETURNING *;
|
||||||
$2, -- title
|
|
||||||
$3, -- description
|
|
||||||
$4, -- level_index
|
|
||||||
$5, -- number_of_modules
|
|
||||||
$6, -- number_of_practices
|
|
||||||
$7, -- number_of_videos
|
|
||||||
$8 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
program_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
level_index,
|
|
||||||
number_of_modules,
|
|
||||||
number_of_practices,
|
|
||||||
number_of_videos,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: GetLevelByID :one
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
program_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
level_index,
|
|
||||||
number_of_modules,
|
|
||||||
number_of_practices,
|
|
||||||
number_of_videos,
|
|
||||||
is_active
|
|
||||||
FROM levels
|
|
||||||
WHERE id = $1;
|
|
||||||
|
|
||||||
-- name: ListLevelsByProgram :many
|
-- name: GetLevelsByProgram :many
|
||||||
SELECT
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
id,
|
id,
|
||||||
program_id,
|
program_id,
|
||||||
title,
|
title,
|
||||||
|
|
@ -57,32 +24,37 @@ SELECT
|
||||||
is_active
|
is_active
|
||||||
FROM levels
|
FROM levels
|
||||||
WHERE program_id = $1
|
WHERE program_id = $1
|
||||||
AND is_active = TRUE
|
|
||||||
ORDER BY level_index ASC;
|
ORDER BY level_index ASC;
|
||||||
|
|
||||||
-- name: UpdateLevel :one
|
|
||||||
|
-- name: UpdateLevel :exec
|
||||||
UPDATE levels
|
UPDATE levels
|
||||||
SET
|
SET
|
||||||
title = $2,
|
title = COALESCE($1, title),
|
||||||
description = $3,
|
description = COALESCE($2, description),
|
||||||
level_index = $4,
|
level_index = COALESCE($3, level_index),
|
||||||
number_of_modules = $5,
|
is_active = COALESCE($4, is_active)
|
||||||
number_of_practices = $6,
|
WHERE id = $5;
|
||||||
number_of_videos = $7,
|
|
||||||
is_active = $8
|
|
||||||
WHERE id = $1
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
program_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
level_index,
|
|
||||||
number_of_modules,
|
|
||||||
number_of_practices,
|
|
||||||
number_of_videos,
|
|
||||||
is_active;
|
|
||||||
|
|
||||||
-- name: DeactivateLevel :exec
|
|
||||||
|
-- name: IncrementLevelModuleCount :exec
|
||||||
UPDATE levels
|
UPDATE levels
|
||||||
SET is_active = FALSE
|
SET number_of_modules = number_of_modules + 1
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
|
||||||
|
-- name: IncrementLevelPracticeCount :exec
|
||||||
|
UPDATE levels
|
||||||
|
SET number_of_practices = number_of_practices + 1
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
|
||||||
|
-- name: IncrementLevelVideoCount :exec
|
||||||
|
UPDATE levels
|
||||||
|
SET number_of_videos = number_of_videos + 1
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
|
||||||
|
-- name: DeleteLevel :exec
|
||||||
|
DELETE FROM levels
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ services:
|
||||||
image: dpage/pgadmin4:latest
|
image: dpage/pgadmin4:latest
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "5050:80"
|
- "5051:80"
|
||||||
environment:
|
environment:
|
||||||
PGADMIN_DEFAULT_EMAIL: admin@local.dev
|
PGADMIN_DEFAULT_EMAIL: admin@local.dev
|
||||||
PGADMIN_DEFAULT_PASSWORD: admin
|
PGADMIN_DEFAULT_PASSWORD: admin
|
||||||
|
|
|
||||||
2546
docs/docs.go
2546
docs/docs.go
File diff suppressed because it is too large
Load Diff
2546
docs/swagger.json
2546
docs/swagger.json
File diff suppressed because it is too large
Load Diff
1919
docs/swagger.yaml
1919
docs/swagger.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -7,6 +7,8 @@ package dbgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
const CreateCourseCategory = `-- name: CreateCourseCategory :one
|
const CreateCourseCategory = `-- name: CreateCourseCategory :one
|
||||||
|
|
@ -14,24 +16,17 @@ INSERT INTO course_categories (
|
||||||
name,
|
name,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, COALESCE($2, true))
|
||||||
$1, -- name
|
RETURNING id, name, is_active, created_at
|
||||||
$2 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
is_active,
|
|
||||||
created_at
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateCourseCategoryParams struct {
|
type CreateCourseCategoryParams struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
IsActive bool `json:"is_active"`
|
Column2 interface{} `json:"column_2"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateCourseCategory(ctx context.Context, arg CreateCourseCategoryParams) (CourseCategory, error) {
|
func (q *Queries) CreateCourseCategory(ctx context.Context, arg CreateCourseCategoryParams) (CourseCategory, error) {
|
||||||
row := q.db.QueryRow(ctx, CreateCourseCategory, arg.Name, arg.IsActive)
|
row := q.db.QueryRow(ctx, CreateCourseCategory, arg.Name, arg.Column2)
|
||||||
var i CourseCategory
|
var i CourseCategory
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
|
|
@ -42,24 +37,71 @@ func (q *Queries) CreateCourseCategory(ctx context.Context, arg CreateCourseCate
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeactivateCourseCategory = `-- name: DeactivateCourseCategory :exec
|
const DeleteCourseCategory = `-- name: DeleteCourseCategory :exec
|
||||||
UPDATE course_categories
|
DELETE FROM course_categories
|
||||||
SET is_active = FALSE
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeactivateCourseCategory(ctx context.Context, id int64) error {
|
func (q *Queries) DeleteCourseCategory(ctx context.Context, id int64) error {
|
||||||
_, err := q.db.Exec(ctx, DeactivateCourseCategory, id)
|
_, err := q.db.Exec(ctx, DeleteCourseCategory, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetCourseCategoryByID = `-- name: GetCourseCategoryByID :one
|
const GetAllCourseCategories = `-- name: GetAllCourseCategories :many
|
||||||
SELECT
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
is_active,
|
is_active,
|
||||||
created_at
|
created_at
|
||||||
FROM course_categories
|
FROM course_categories
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT $2::INT
|
||||||
|
OFFSET $1::INT
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetAllCourseCategoriesParams struct {
|
||||||
|
Offset pgtype.Int4 `json:"offset"`
|
||||||
|
Limit pgtype.Int4 `json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetAllCourseCategoriesRow struct {
|
||||||
|
TotalCount int64 `json:"total_count"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetAllCourseCategories(ctx context.Context, arg GetAllCourseCategoriesParams) ([]GetAllCourseCategoriesRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllCourseCategories, arg.Offset, arg.Limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetAllCourseCategoriesRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetAllCourseCategoriesRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.TotalCount,
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.IsActive,
|
||||||
|
&i.CreatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetCourseCategoryByID = `-- name: GetCourseCategoryByID :one
|
||||||
|
SELECT id, name, is_active, created_at
|
||||||
|
FROM course_categories
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -75,69 +117,21 @@ func (q *Queries) GetCourseCategoryByID(ctx context.Context, id int64) (CourseCa
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListActiveCourseCategories = `-- name: ListActiveCourseCategories :many
|
const UpdateCourseCategory = `-- name: UpdateCourseCategory :exec
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
is_active,
|
|
||||||
created_at
|
|
||||||
FROM course_categories
|
|
||||||
WHERE is_active = TRUE
|
|
||||||
ORDER BY created_at DESC
|
|
||||||
`
|
|
||||||
|
|
||||||
func (q *Queries) ListActiveCourseCategories(ctx context.Context) ([]CourseCategory, error) {
|
|
||||||
rows, err := q.db.Query(ctx, ListActiveCourseCategories)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
var items []CourseCategory
|
|
||||||
for rows.Next() {
|
|
||||||
var i CourseCategory
|
|
||||||
if err := rows.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.Name,
|
|
||||||
&i.IsActive,
|
|
||||||
&i.CreatedAt,
|
|
||||||
); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
items = append(items, i)
|
|
||||||
}
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return items, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const UpdateCourseCategory = `-- name: UpdateCourseCategory :one
|
|
||||||
UPDATE course_categories
|
UPDATE course_categories
|
||||||
SET
|
SET
|
||||||
name = $2,
|
name = COALESCE($1, name),
|
||||||
is_active = $3
|
is_active = COALESCE($2, is_active)
|
||||||
WHERE id = $1
|
WHERE id = $3
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
is_active,
|
|
||||||
created_at
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateCourseCategoryParams struct {
|
type UpdateCourseCategoryParams struct {
|
||||||
ID int64 `json:"id"`
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateCourseCategory(ctx context.Context, arg UpdateCourseCategoryParams) (CourseCategory, error) {
|
func (q *Queries) UpdateCourseCategory(ctx context.Context, arg UpdateCourseCategoryParams) error {
|
||||||
row := q.db.QueryRow(ctx, UpdateCourseCategory, arg.ID, arg.Name, arg.IsActive)
|
_, err := q.db.Exec(ctx, UpdateCourseCategory, arg.Name, arg.IsActive, arg.ID)
|
||||||
var i CourseCategory
|
return err
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.Name,
|
|
||||||
&i.IsActive,
|
|
||||||
&i.CreatedAt,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,22 +20,8 @@ INSERT INTO programs (
|
||||||
display_order,
|
display_order,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, $4, COALESCE($5, 0), COALESCE($6, true))
|
||||||
$1, -- course_id
|
RETURNING id, course_id, title, description, thumbnail, display_order, is_active
|
||||||
$2, -- title
|
|
||||||
$3, -- description
|
|
||||||
$4, -- thumbnail
|
|
||||||
$5, -- display_order
|
|
||||||
$6 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
course_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
thumbnail,
|
|
||||||
display_order,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateProgramParams struct {
|
type CreateProgramParams struct {
|
||||||
|
|
@ -43,8 +29,8 @@ type CreateProgramParams struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
DisplayOrder int32 `json:"display_order"`
|
Column5 interface{} `json:"column_5"`
|
||||||
IsActive bool `json:"is_active"`
|
Column6 interface{} `json:"column_6"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateProgram(ctx context.Context, arg CreateProgramParams) (Program, error) {
|
func (q *Queries) CreateProgram(ctx context.Context, arg CreateProgramParams) (Program, error) {
|
||||||
|
|
@ -53,8 +39,8 @@ func (q *Queries) CreateProgram(ctx context.Context, arg CreateProgramParams) (P
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Description,
|
arg.Description,
|
||||||
arg.Thumbnail,
|
arg.Thumbnail,
|
||||||
arg.DisplayOrder,
|
arg.Column5,
|
||||||
arg.IsActive,
|
arg.Column6,
|
||||||
)
|
)
|
||||||
var i Program
|
var i Program
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
@ -80,6 +66,34 @@ func (q *Queries) DeactivateProgram(ctx context.Context, id int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DeleteProgram = `-- name: DeleteProgram :one
|
||||||
|
DELETE FROM programs
|
||||||
|
WHERE id = $1
|
||||||
|
RETURNING
|
||||||
|
id,
|
||||||
|
course_id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail,
|
||||||
|
display_order,
|
||||||
|
is_active
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteProgram(ctx context.Context, id int64) (Program, error) {
|
||||||
|
row := q.db.QueryRow(ctx, DeleteProgram, id)
|
||||||
|
var i Program
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.CourseID,
|
||||||
|
&i.Title,
|
||||||
|
&i.Description,
|
||||||
|
&i.Thumbnail,
|
||||||
|
&i.DisplayOrder,
|
||||||
|
&i.IsActive,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const GetProgramByID = `-- name: GetProgramByID :one
|
const GetProgramByID = `-- name: GetProgramByID :one
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
|
|
@ -108,6 +122,61 @@ func (q *Queries) GetProgramByID(ctx context.Context, id int64) (Program, error)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetProgramsByCourse = `-- name: GetProgramsByCourse :many
|
||||||
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
|
id,
|
||||||
|
course_id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
thumbnail,
|
||||||
|
display_order,
|
||||||
|
is_active
|
||||||
|
FROM programs
|
||||||
|
WHERE course_id = $1
|
||||||
|
ORDER BY display_order ASC
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetProgramsByCourseRow struct {
|
||||||
|
TotalCount int64 `json:"total_count"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
CourseID int64 `json:"course_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
DisplayOrder int32 `json:"display_order"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetProgramsByCourse(ctx context.Context, courseID int64) ([]GetProgramsByCourseRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetProgramsByCourse, courseID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetProgramsByCourseRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetProgramsByCourseRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.TotalCount,
|
||||||
|
&i.ID,
|
||||||
|
&i.CourseID,
|
||||||
|
&i.Title,
|
||||||
|
&i.Description,
|
||||||
|
&i.Thumbnail,
|
||||||
|
&i.DisplayOrder,
|
||||||
|
&i.IsActive,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const ListActivePrograms = `-- name: ListActivePrograms :many
|
const ListActivePrograms = `-- name: ListActivePrograms :many
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
|
|
@ -193,7 +262,7 @@ func (q *Queries) ListProgramsByCourse(ctx context.Context, courseID int64) ([]P
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdateProgram = `-- name: UpdateProgram :one
|
const UpdateProgramFull = `-- name: UpdateProgramFull :one
|
||||||
UPDATE programs
|
UPDATE programs
|
||||||
SET
|
SET
|
||||||
course_id = $2,
|
course_id = $2,
|
||||||
|
|
@ -213,7 +282,7 @@ RETURNING
|
||||||
is_active
|
is_active
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateProgramParams struct {
|
type UpdateProgramFullParams struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
CourseID int64 `json:"course_id"`
|
CourseID int64 `json:"course_id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
|
|
@ -223,8 +292,8 @@ type UpdateProgramParams struct {
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateProgram(ctx context.Context, arg UpdateProgramParams) (Program, error) {
|
func (q *Queries) UpdateProgramFull(ctx context.Context, arg UpdateProgramFullParams) (Program, error) {
|
||||||
row := q.db.QueryRow(ctx, UpdateProgram,
|
row := q.db.QueryRow(ctx, UpdateProgramFull,
|
||||||
arg.ID,
|
arg.ID,
|
||||||
arg.CourseID,
|
arg.CourseID,
|
||||||
arg.Title,
|
arg.Title,
|
||||||
|
|
@ -245,3 +314,35 @@ func (q *Queries) UpdateProgram(ctx context.Context, arg UpdateProgramParams) (P
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UpdateProgramPartial = `-- name: UpdateProgramPartial :exec
|
||||||
|
UPDATE programs
|
||||||
|
SET
|
||||||
|
title = COALESCE($1, title),
|
||||||
|
description = COALESCE($2, description),
|
||||||
|
thumbnail = COALESCE($3, thumbnail),
|
||||||
|
display_order = COALESCE($4, display_order),
|
||||||
|
is_active = COALESCE($5, is_active)
|
||||||
|
WHERE id = $6
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateProgramPartialParams struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
DisplayOrder int32 `json:"display_order"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateProgramPartial(ctx context.Context, arg UpdateProgramPartialParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateProgramPartial,
|
||||||
|
arg.Title,
|
||||||
|
arg.Description,
|
||||||
|
arg.Thumbnail,
|
||||||
|
arg.DisplayOrder,
|
||||||
|
arg.IsActive,
|
||||||
|
arg.ID,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,25 +18,15 @@ INSERT INTO courses (
|
||||||
description,
|
description,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, COALESCE($4, true))
|
||||||
$1, -- category_id
|
RETURNING id, category_id, title, description, is_active
|
||||||
$2, -- title
|
|
||||||
$3, -- description
|
|
||||||
$4 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
category_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateCourseParams struct {
|
type CreateCourseParams struct {
|
||||||
CategoryID int64 `json:"category_id"`
|
CategoryID int64 `json:"category_id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
IsActive bool `json:"is_active"`
|
Column4 interface{} `json:"column_4"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateCourse(ctx context.Context, arg CreateCourseParams) (Course, error) {
|
func (q *Queries) CreateCourse(ctx context.Context, arg CreateCourseParams) (Course, error) {
|
||||||
|
|
@ -44,7 +34,7 @@ func (q *Queries) CreateCourse(ctx context.Context, arg CreateCourseParams) (Cou
|
||||||
arg.CategoryID,
|
arg.CategoryID,
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Description,
|
arg.Description,
|
||||||
arg.IsActive,
|
arg.Column4,
|
||||||
)
|
)
|
||||||
var i Course
|
var i Course
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
@ -57,24 +47,18 @@ func (q *Queries) CreateCourse(ctx context.Context, arg CreateCourseParams) (Cou
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeactivateCourse = `-- name: DeactivateCourse :exec
|
const DeleteCourse = `-- name: DeleteCourse :exec
|
||||||
UPDATE courses
|
DELETE FROM courses
|
||||||
SET is_active = FALSE
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeactivateCourse(ctx context.Context, id int64) error {
|
func (q *Queries) DeleteCourse(ctx context.Context, id int64) error {
|
||||||
_, err := q.db.Exec(ctx, DeactivateCourse, id)
|
_, err := q.db.Exec(ctx, DeleteCourse, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetCourseByID = `-- name: GetCourseByID :one
|
const GetCourseByID = `-- name: GetCourseByID :one
|
||||||
SELECT
|
SELECT id, category_id, title, description, is_active
|
||||||
id,
|
|
||||||
category_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
is_active
|
|
||||||
FROM courses
|
FROM courses
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -92,46 +76,9 @@ func (q *Queries) GetCourseByID(ctx context.Context, id int64) (Course, error) {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListActiveCourses = `-- name: ListActiveCourses :many
|
const GetCoursesByCategory = `-- name: GetCoursesByCategory :many
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
category_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
is_active
|
|
||||||
FROM courses
|
|
||||||
WHERE is_active = TRUE
|
|
||||||
ORDER BY id DESC
|
|
||||||
`
|
|
||||||
|
|
||||||
func (q *Queries) ListActiveCourses(ctx context.Context) ([]Course, error) {
|
|
||||||
rows, err := q.db.Query(ctx, ListActiveCourses)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
var items []Course
|
|
||||||
for rows.Next() {
|
|
||||||
var i Course
|
|
||||||
if err := rows.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.CategoryID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Description,
|
|
||||||
&i.IsActive,
|
|
||||||
); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
items = append(items, i)
|
|
||||||
}
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return items, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const ListCoursesByCategory = `-- name: ListCoursesByCategory :many
|
|
||||||
SELECT
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
id,
|
id,
|
||||||
category_id,
|
category_id,
|
||||||
title,
|
title,
|
||||||
|
|
@ -139,20 +86,37 @@ SELECT
|
||||||
is_active
|
is_active
|
||||||
FROM courses
|
FROM courses
|
||||||
WHERE category_id = $1
|
WHERE category_id = $1
|
||||||
AND is_active = TRUE
|
|
||||||
ORDER BY id DESC
|
ORDER BY id DESC
|
||||||
|
LIMIT $3::INT
|
||||||
|
OFFSET $2::INT
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListCoursesByCategory(ctx context.Context, categoryID int64) ([]Course, error) {
|
type GetCoursesByCategoryParams struct {
|
||||||
rows, err := q.db.Query(ctx, ListCoursesByCategory, categoryID)
|
CategoryID int64 `json:"category_id"`
|
||||||
|
Offset pgtype.Int4 `json:"offset"`
|
||||||
|
Limit pgtype.Int4 `json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetCoursesByCategoryRow struct {
|
||||||
|
TotalCount int64 `json:"total_count"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
CategoryID int64 `json:"category_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetCoursesByCategory(ctx context.Context, arg GetCoursesByCategoryParams) ([]GetCoursesByCategoryRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetCoursesByCategory, arg.CategoryID, arg.Offset, arg.Limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []Course
|
var items []GetCoursesByCategoryRow
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i Course
|
var i GetCoursesByCategoryRow
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
|
&i.TotalCount,
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.CategoryID,
|
&i.CategoryID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
|
|
@ -169,45 +133,28 @@ func (q *Queries) ListCoursesByCategory(ctx context.Context, categoryID int64) (
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdateCourse = `-- name: UpdateCourse :one
|
const UpdateCourse = `-- name: UpdateCourse :exec
|
||||||
UPDATE courses
|
UPDATE courses
|
||||||
SET
|
SET
|
||||||
category_id = $2,
|
title = COALESCE($1, title),
|
||||||
title = $3,
|
description = COALESCE($2, description),
|
||||||
description = $4,
|
is_active = COALESCE($3, is_active)
|
||||||
is_active = $5
|
WHERE id = $4
|
||||||
WHERE id = $1
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
category_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateCourseParams struct {
|
type UpdateCourseParams struct {
|
||||||
ID int64 `json:"id"`
|
|
||||||
CategoryID int64 `json:"category_id"`
|
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateCourse(ctx context.Context, arg UpdateCourseParams) (Course, error) {
|
func (q *Queries) UpdateCourse(ctx context.Context, arg UpdateCourseParams) error {
|
||||||
row := q.db.QueryRow(ctx, UpdateCourse,
|
_, err := q.db.Exec(ctx, UpdateCourse,
|
||||||
arg.ID,
|
|
||||||
arg.CategoryID,
|
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Description,
|
arg.Description,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
|
arg.ID,
|
||||||
)
|
)
|
||||||
var i Course
|
return err
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.CategoryID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Description,
|
|
||||||
&i.IsActive,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
70
gen/db/learning_tree.sql.go
Normal file
70
gen/db/learning_tree.sql.go
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.30.0
|
||||||
|
// source: learning_tree.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GetFullLearningTree = `-- name: GetFullLearningTree :many
|
||||||
|
SELECT
|
||||||
|
c.id AS course_id,
|
||||||
|
c.title AS course_title,
|
||||||
|
p.id AS program_id,
|
||||||
|
p.title AS program_title,
|
||||||
|
l.id AS level_id,
|
||||||
|
l.title AS level_title,
|
||||||
|
m.id AS module_id,
|
||||||
|
m.title AS module_title
|
||||||
|
FROM courses c
|
||||||
|
JOIN programs p ON p.course_id = c.id
|
||||||
|
JOIN levels l ON l.program_id = p.id
|
||||||
|
LEFT JOIN modules m ON m.level_id = l.id
|
||||||
|
WHERE c.is_active = true
|
||||||
|
ORDER BY p.display_order, l.level_index, m.display_order
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetFullLearningTreeRow struct {
|
||||||
|
CourseID int64 `json:"course_id"`
|
||||||
|
CourseTitle string `json:"course_title"`
|
||||||
|
ProgramID int64 `json:"program_id"`
|
||||||
|
ProgramTitle string `json:"program_title"`
|
||||||
|
LevelID int64 `json:"level_id"`
|
||||||
|
LevelTitle string `json:"level_title"`
|
||||||
|
ModuleID pgtype.Int8 `json:"module_id"`
|
||||||
|
ModuleTitle pgtype.Text `json:"module_title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetFullLearningTree(ctx context.Context) ([]GetFullLearningTreeRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetFullLearningTree)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetFullLearningTreeRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetFullLearningTreeRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.CourseID,
|
||||||
|
&i.CourseTitle,
|
||||||
|
&i.ProgramID,
|
||||||
|
&i.ProgramTitle,
|
||||||
|
&i.LevelID,
|
||||||
|
&i.LevelTitle,
|
||||||
|
&i.ModuleID,
|
||||||
|
&i.ModuleTitle,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
@ -19,28 +19,16 @@ INSERT INTO modules (
|
||||||
display_order,
|
display_order,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, COALESCE($4, 0), COALESCE($5, true))
|
||||||
$1, -- level_id
|
RETURNING id, level_id, title, content, display_order, is_active
|
||||||
$2, -- title
|
|
||||||
$3, -- content
|
|
||||||
$4, -- display_order
|
|
||||||
$5 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
level_id,
|
|
||||||
title,
|
|
||||||
content,
|
|
||||||
display_order,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateModuleParams struct {
|
type CreateModuleParams struct {
|
||||||
LevelID int64 `json:"level_id"`
|
LevelID int64 `json:"level_id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Content pgtype.Text `json:"content"`
|
Content pgtype.Text `json:"content"`
|
||||||
DisplayOrder int32 `json:"display_order"`
|
Column4 interface{} `json:"column_4"`
|
||||||
IsActive bool `json:"is_active"`
|
Column5 interface{} `json:"column_5"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Module, error) {
|
func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Module, error) {
|
||||||
|
|
@ -48,8 +36,8 @@ func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Mod
|
||||||
arg.LevelID,
|
arg.LevelID,
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Content,
|
arg.Content,
|
||||||
arg.DisplayOrder,
|
arg.Column4,
|
||||||
arg.IsActive,
|
arg.Column5,
|
||||||
)
|
)
|
||||||
var i Module
|
var i Module
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
@ -63,45 +51,19 @@ func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Mod
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeactivateModule = `-- name: DeactivateModule :exec
|
const DeleteModule = `-- name: DeleteModule :exec
|
||||||
UPDATE modules
|
DELETE FROM modules
|
||||||
SET is_active = FALSE
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeactivateModule(ctx context.Context, id int64) error {
|
func (q *Queries) DeleteModule(ctx context.Context, id int64) error {
|
||||||
_, err := q.db.Exec(ctx, DeactivateModule, id)
|
_, err := q.db.Exec(ctx, DeleteModule, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetModuleByID = `-- name: GetModuleByID :one
|
const GetModulesByLevel = `-- name: GetModulesByLevel :many
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
level_id,
|
|
||||||
title,
|
|
||||||
content,
|
|
||||||
display_order,
|
|
||||||
is_active
|
|
||||||
FROM modules
|
|
||||||
WHERE id = $1
|
|
||||||
`
|
|
||||||
|
|
||||||
func (q *Queries) GetModuleByID(ctx context.Context, id int64) (Module, error) {
|
|
||||||
row := q.db.QueryRow(ctx, GetModuleByID, id)
|
|
||||||
var i Module
|
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.LevelID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Content,
|
|
||||||
&i.DisplayOrder,
|
|
||||||
&i.IsActive,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
|
|
||||||
const ListModulesByLevel = `-- name: ListModulesByLevel :many
|
|
||||||
SELECT
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
id,
|
id,
|
||||||
level_id,
|
level_id,
|
||||||
title,
|
title,
|
||||||
|
|
@ -110,20 +72,30 @@ SELECT
|
||||||
is_active
|
is_active
|
||||||
FROM modules
|
FROM modules
|
||||||
WHERE level_id = $1
|
WHERE level_id = $1
|
||||||
AND is_active = TRUE
|
ORDER BY display_order ASC
|
||||||
ORDER BY display_order ASC, id ASC
|
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListModulesByLevel(ctx context.Context, levelID int64) ([]Module, error) {
|
type GetModulesByLevelRow struct {
|
||||||
rows, err := q.db.Query(ctx, ListModulesByLevel, levelID)
|
TotalCount int64 `json:"total_count"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
LevelID int64 `json:"level_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Content pgtype.Text `json:"content"`
|
||||||
|
DisplayOrder int32 `json:"display_order"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetModulesByLevel(ctx context.Context, levelID int64) ([]GetModulesByLevelRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetModulesByLevel, levelID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []Module
|
var items []GetModulesByLevelRow
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i Module
|
var i GetModulesByLevelRow
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
|
&i.TotalCount,
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.LevelID,
|
&i.LevelID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
|
|
@ -141,47 +113,31 @@ func (q *Queries) ListModulesByLevel(ctx context.Context, levelID int64) ([]Modu
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdateModule = `-- name: UpdateModule :one
|
const UpdateModule = `-- name: UpdateModule :exec
|
||||||
UPDATE modules
|
UPDATE modules
|
||||||
SET
|
SET
|
||||||
title = $2,
|
title = COALESCE($1, title),
|
||||||
content = $3,
|
content = COALESCE($2, content),
|
||||||
display_order = $4,
|
display_order = COALESCE($3, display_order),
|
||||||
is_active = $5
|
is_active = COALESCE($4, is_active)
|
||||||
WHERE id = $1
|
WHERE id = $5
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
level_id,
|
|
||||||
title,
|
|
||||||
content,
|
|
||||||
display_order,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateModuleParams struct {
|
type UpdateModuleParams struct {
|
||||||
ID int64 `json:"id"`
|
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Content pgtype.Text `json:"content"`
|
Content pgtype.Text `json:"content"`
|
||||||
DisplayOrder int32 `json:"display_order"`
|
DisplayOrder int32 `json:"display_order"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateModule(ctx context.Context, arg UpdateModuleParams) (Module, error) {
|
func (q *Queries) UpdateModule(ctx context.Context, arg UpdateModuleParams) error {
|
||||||
row := q.db.QueryRow(ctx, UpdateModule,
|
_, err := q.db.Exec(ctx, UpdateModule,
|
||||||
arg.ID,
|
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Content,
|
arg.Content,
|
||||||
arg.DisplayOrder,
|
arg.DisplayOrder,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
|
arg.ID,
|
||||||
)
|
)
|
||||||
var i Module
|
return err
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.LevelID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Content,
|
|
||||||
&i.DisplayOrder,
|
|
||||||
&i.IsActive,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,45 +19,17 @@ INSERT INTO module_videos (
|
||||||
video_url,
|
video_url,
|
||||||
duration,
|
duration,
|
||||||
resolution,
|
resolution,
|
||||||
|
|
||||||
is_published,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
|
|
||||||
instructor_id,
|
instructor_id,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
|
visibility,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
$1, -- module_id
|
$1, $2, $3, $4, $5, $6,
|
||||||
$2, -- title
|
$7, $8, $9,
|
||||||
$3, -- description
|
COALESCE($10, true)
|
||||||
$4, -- video_url
|
|
||||||
$5, -- duration
|
|
||||||
$6, -- resolution
|
|
||||||
|
|
||||||
$7, -- is_published
|
|
||||||
$8, -- publish_date
|
|
||||||
$9, -- visibility
|
|
||||||
|
|
||||||
$10, -- instructor_id
|
|
||||||
$11, -- thumbnail
|
|
||||||
$12 -- is_active
|
|
||||||
)
|
)
|
||||||
RETURNING
|
RETURNING id, module_id, title, description, video_url, duration, resolution, is_published, publish_date, visibility, instructor_id, thumbnail, is_active
|
||||||
id,
|
|
||||||
module_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
video_url,
|
|
||||||
duration,
|
|
||||||
resolution,
|
|
||||||
is_published,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
instructor_id,
|
|
||||||
thumbnail,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateModuleVideoParams struct {
|
type CreateModuleVideoParams struct {
|
||||||
|
|
@ -67,12 +39,10 @@ type CreateModuleVideoParams struct {
|
||||||
VideoUrl string `json:"video_url"`
|
VideoUrl string `json:"video_url"`
|
||||||
Duration int32 `json:"duration"`
|
Duration int32 `json:"duration"`
|
||||||
Resolution pgtype.Text `json:"resolution"`
|
Resolution pgtype.Text `json:"resolution"`
|
||||||
IsPublished bool `json:"is_published"`
|
|
||||||
PublishDate pgtype.Timestamptz `json:"publish_date"`
|
|
||||||
Visibility pgtype.Text `json:"visibility"`
|
|
||||||
InstructorID pgtype.Text `json:"instructor_id"`
|
InstructorID pgtype.Text `json:"instructor_id"`
|
||||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
IsActive bool `json:"is_active"`
|
Visibility pgtype.Text `json:"visibility"`
|
||||||
|
Column10 interface{} `json:"column_10"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateModuleVideo(ctx context.Context, arg CreateModuleVideoParams) (ModuleVideo, error) {
|
func (q *Queries) CreateModuleVideo(ctx context.Context, arg CreateModuleVideoParams) (ModuleVideo, error) {
|
||||||
|
|
@ -83,12 +53,10 @@ func (q *Queries) CreateModuleVideo(ctx context.Context, arg CreateModuleVideoPa
|
||||||
arg.VideoUrl,
|
arg.VideoUrl,
|
||||||
arg.Duration,
|
arg.Duration,
|
||||||
arg.Resolution,
|
arg.Resolution,
|
||||||
arg.IsPublished,
|
|
||||||
arg.PublishDate,
|
|
||||||
arg.Visibility,
|
|
||||||
arg.InstructorID,
|
arg.InstructorID,
|
||||||
arg.Thumbnail,
|
arg.Thumbnail,
|
||||||
arg.IsActive,
|
arg.Visibility,
|
||||||
|
arg.Column10,
|
||||||
)
|
)
|
||||||
var i ModuleVideo
|
var i ModuleVideo
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
@ -109,79 +77,27 @@ func (q *Queries) CreateModuleVideo(ctx context.Context, arg CreateModuleVideoPa
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeactivateModuleVideo = `-- name: DeactivateModuleVideo :exec
|
const DeleteModuleVideo = `-- name: DeleteModuleVideo :exec
|
||||||
UPDATE module_videos
|
DELETE FROM module_videos
|
||||||
SET is_active = FALSE
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeactivateModuleVideo(ctx context.Context, id int64) error {
|
func (q *Queries) DeleteModuleVideo(ctx context.Context, id int64) error {
|
||||||
_, err := q.db.Exec(ctx, DeactivateModuleVideo, id)
|
_, err := q.db.Exec(ctx, DeleteModuleVideo, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetModuleVideoByID = `-- name: GetModuleVideoByID :one
|
const GetPublishedVideosByModule = `-- name: GetPublishedVideosByModule :many
|
||||||
SELECT
|
SELECT id, module_id, title, description, video_url, duration, resolution, is_published, publish_date, visibility, instructor_id, thumbnail, is_active
|
||||||
id,
|
|
||||||
module_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
video_url,
|
|
||||||
duration,
|
|
||||||
resolution,
|
|
||||||
is_published,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
instructor_id,
|
|
||||||
thumbnail,
|
|
||||||
is_active
|
|
||||||
FROM module_videos
|
|
||||||
WHERE id = $1
|
|
||||||
`
|
|
||||||
|
|
||||||
func (q *Queries) GetModuleVideoByID(ctx context.Context, id int64) (ModuleVideo, error) {
|
|
||||||
row := q.db.QueryRow(ctx, GetModuleVideoByID, id)
|
|
||||||
var i ModuleVideo
|
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.ModuleID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Description,
|
|
||||||
&i.VideoUrl,
|
|
||||||
&i.Duration,
|
|
||||||
&i.Resolution,
|
|
||||||
&i.IsPublished,
|
|
||||||
&i.PublishDate,
|
|
||||||
&i.Visibility,
|
|
||||||
&i.InstructorID,
|
|
||||||
&i.Thumbnail,
|
|
||||||
&i.IsActive,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
|
|
||||||
const ListAllVideosByModule = `-- name: ListAllVideosByModule :many
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
module_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
video_url,
|
|
||||||
duration,
|
|
||||||
resolution,
|
|
||||||
is_published,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
instructor_id,
|
|
||||||
thumbnail,
|
|
||||||
is_active
|
|
||||||
FROM module_videos
|
FROM module_videos
|
||||||
WHERE module_id = $1
|
WHERE module_id = $1
|
||||||
ORDER BY id ASC
|
AND is_published = true
|
||||||
|
AND is_active = true
|
||||||
|
ORDER BY publish_date ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListAllVideosByModule(ctx context.Context, moduleID int64) ([]ModuleVideo, error) {
|
func (q *Queries) GetPublishedVideosByModule(ctx context.Context, moduleID int64) ([]ModuleVideo, error) {
|
||||||
rows, err := q.db.Query(ctx, ListAllVideosByModule, moduleID)
|
rows, err := q.db.Query(ctx, GetPublishedVideosByModule, moduleID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -214,150 +130,56 @@ func (q *Queries) ListAllVideosByModule(ctx context.Context, moduleID int64) ([]
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListPublishedVideosByModule = `-- name: ListPublishedVideosByModule :many
|
const PublishModuleVideo = `-- name: PublishModuleVideo :exec
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
module_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
video_url,
|
|
||||||
duration,
|
|
||||||
resolution,
|
|
||||||
publish_date,
|
|
||||||
visibility,
|
|
||||||
instructor_id,
|
|
||||||
thumbnail
|
|
||||||
FROM module_videos
|
|
||||||
WHERE module_id = $1
|
|
||||||
AND is_active = TRUE
|
|
||||||
AND is_published = TRUE
|
|
||||||
ORDER BY publish_date ASC, id ASC
|
|
||||||
`
|
|
||||||
|
|
||||||
type ListPublishedVideosByModuleRow struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
ModuleID int64 `json:"module_id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description pgtype.Text `json:"description"`
|
|
||||||
VideoUrl string `json:"video_url"`
|
|
||||||
Duration int32 `json:"duration"`
|
|
||||||
Resolution pgtype.Text `json:"resolution"`
|
|
||||||
PublishDate pgtype.Timestamptz `json:"publish_date"`
|
|
||||||
Visibility pgtype.Text `json:"visibility"`
|
|
||||||
InstructorID pgtype.Text `json:"instructor_id"`
|
|
||||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queries) ListPublishedVideosByModule(ctx context.Context, moduleID int64) ([]ListPublishedVideosByModuleRow, error) {
|
|
||||||
rows, err := q.db.Query(ctx, ListPublishedVideosByModule, moduleID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
var items []ListPublishedVideosByModuleRow
|
|
||||||
for rows.Next() {
|
|
||||||
var i ListPublishedVideosByModuleRow
|
|
||||||
if err := rows.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.ModuleID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Description,
|
|
||||||
&i.VideoUrl,
|
|
||||||
&i.Duration,
|
|
||||||
&i.Resolution,
|
|
||||||
&i.PublishDate,
|
|
||||||
&i.Visibility,
|
|
||||||
&i.InstructorID,
|
|
||||||
&i.Thumbnail,
|
|
||||||
); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
items = append(items, i)
|
|
||||||
}
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return items, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const UpdateModuleVideo = `-- name: UpdateModuleVideo :one
|
|
||||||
UPDATE module_videos
|
UPDATE module_videos
|
||||||
SET
|
SET
|
||||||
title = $2,
|
is_published = true,
|
||||||
description = $3,
|
publish_date = CURRENT_TIMESTAMP
|
||||||
video_url = $4,
|
|
||||||
duration = $5,
|
|
||||||
resolution = $6,
|
|
||||||
|
|
||||||
is_published = $7,
|
|
||||||
publish_date = $8,
|
|
||||||
visibility = $9,
|
|
||||||
|
|
||||||
instructor_id = $10,
|
|
||||||
thumbnail = $11,
|
|
||||||
is_active = $12
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING
|
`
|
||||||
id,
|
|
||||||
module_id,
|
func (q *Queries) PublishModuleVideo(ctx context.Context, id int64) error {
|
||||||
title,
|
_, err := q.db.Exec(ctx, PublishModuleVideo, id)
|
||||||
description,
|
return err
|
||||||
video_url,
|
}
|
||||||
duration,
|
|
||||||
resolution,
|
const UpdateModuleVideo = `-- name: UpdateModuleVideo :exec
|
||||||
is_published,
|
UPDATE module_videos
|
||||||
publish_date,
|
SET
|
||||||
visibility,
|
title = COALESCE($1, title),
|
||||||
instructor_id,
|
description = COALESCE($2, description),
|
||||||
thumbnail,
|
video_url = COALESCE($3, video_url),
|
||||||
is_active
|
duration = COALESCE($4, duration),
|
||||||
|
resolution = COALESCE($5, resolution),
|
||||||
|
visibility = COALESCE($6, visibility),
|
||||||
|
thumbnail = COALESCE($7, thumbnail),
|
||||||
|
is_active = COALESCE($8, is_active)
|
||||||
|
WHERE id = $9
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateModuleVideoParams struct {
|
type UpdateModuleVideoParams struct {
|
||||||
ID int64 `json:"id"`
|
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
VideoUrl string `json:"video_url"`
|
VideoUrl string `json:"video_url"`
|
||||||
Duration int32 `json:"duration"`
|
Duration int32 `json:"duration"`
|
||||||
Resolution pgtype.Text `json:"resolution"`
|
Resolution pgtype.Text `json:"resolution"`
|
||||||
IsPublished bool `json:"is_published"`
|
|
||||||
PublishDate pgtype.Timestamptz `json:"publish_date"`
|
|
||||||
Visibility pgtype.Text `json:"visibility"`
|
Visibility pgtype.Text `json:"visibility"`
|
||||||
InstructorID pgtype.Text `json:"instructor_id"`
|
|
||||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateModuleVideo(ctx context.Context, arg UpdateModuleVideoParams) (ModuleVideo, error) {
|
func (q *Queries) UpdateModuleVideo(ctx context.Context, arg UpdateModuleVideoParams) error {
|
||||||
row := q.db.QueryRow(ctx, UpdateModuleVideo,
|
_, err := q.db.Exec(ctx, UpdateModuleVideo,
|
||||||
arg.ID,
|
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Description,
|
arg.Description,
|
||||||
arg.VideoUrl,
|
arg.VideoUrl,
|
||||||
arg.Duration,
|
arg.Duration,
|
||||||
arg.Resolution,
|
arg.Resolution,
|
||||||
arg.IsPublished,
|
|
||||||
arg.PublishDate,
|
|
||||||
arg.Visibility,
|
arg.Visibility,
|
||||||
arg.InstructorID,
|
|
||||||
arg.Thumbnail,
|
arg.Thumbnail,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
|
arg.ID,
|
||||||
)
|
)
|
||||||
var i ModuleVideo
|
return err
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.ModuleID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Description,
|
|
||||||
&i.VideoUrl,
|
|
||||||
&i.Duration,
|
|
||||||
&i.Resolution,
|
|
||||||
&i.IsPublished,
|
|
||||||
&i.PublishDate,
|
|
||||||
&i.Visibility,
|
|
||||||
&i.InstructorID,
|
|
||||||
&i.Thumbnail,
|
|
||||||
&i.IsActive,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,24 +21,8 @@ INSERT INTO practice_questions (
|
||||||
tips,
|
tips,
|
||||||
type
|
type
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||||
$1, -- practice_id
|
RETURNING id, practice_id, question, question_voice_prompt, sample_answer_voice_prompt, sample_answer, tips, type
|
||||||
$2, -- question
|
|
||||||
$3, -- question_voice_prompt
|
|
||||||
$4, -- sample_answer_voice_prompt
|
|
||||||
$5, -- sample_answer
|
|
||||||
$6, -- tips
|
|
||||||
$7 -- type (MCQ, TRUE_FALSE, SHORT)
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
practice_id,
|
|
||||||
question,
|
|
||||||
question_voice_prompt,
|
|
||||||
sample_answer_voice_prompt,
|
|
||||||
sample_answer,
|
|
||||||
tips,
|
|
||||||
type
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreatePracticeQuestionParams struct {
|
type CreatePracticeQuestionParams struct {
|
||||||
|
|
@ -85,53 +69,15 @@ func (q *Queries) DeletePracticeQuestion(ctx context.Context, id int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetPracticeQuestionByID = `-- name: GetPracticeQuestionByID :one
|
const GetQuestionsByPractice = `-- name: GetQuestionsByPractice :many
|
||||||
SELECT
|
SELECT id, practice_id, question, question_voice_prompt, sample_answer_voice_prompt, sample_answer, tips, type
|
||||||
id,
|
|
||||||
practice_id,
|
|
||||||
question,
|
|
||||||
question_voice_prompt,
|
|
||||||
sample_answer_voice_prompt,
|
|
||||||
sample_answer,
|
|
||||||
tips,
|
|
||||||
type
|
|
||||||
FROM practice_questions
|
|
||||||
WHERE id = $1
|
|
||||||
`
|
|
||||||
|
|
||||||
func (q *Queries) GetPracticeQuestionByID(ctx context.Context, id int64) (PracticeQuestion, error) {
|
|
||||||
row := q.db.QueryRow(ctx, GetPracticeQuestionByID, id)
|
|
||||||
var i PracticeQuestion
|
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.PracticeID,
|
|
||||||
&i.Question,
|
|
||||||
&i.QuestionVoicePrompt,
|
|
||||||
&i.SampleAnswerVoicePrompt,
|
|
||||||
&i.SampleAnswer,
|
|
||||||
&i.Tips,
|
|
||||||
&i.Type,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
|
|
||||||
const ListPracticeQuestions = `-- name: ListPracticeQuestions :many
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
practice_id,
|
|
||||||
question,
|
|
||||||
question_voice_prompt,
|
|
||||||
sample_answer_voice_prompt,
|
|
||||||
sample_answer,
|
|
||||||
tips,
|
|
||||||
type
|
|
||||||
FROM practice_questions
|
FROM practice_questions
|
||||||
WHERE practice_id = $1
|
WHERE practice_id = $1
|
||||||
ORDER BY id ASC
|
ORDER BY id ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListPracticeQuestions(ctx context.Context, practiceID int64) ([]PracticeQuestion, error) {
|
func (q *Queries) GetQuestionsByPractice(ctx context.Context, practiceID int64) ([]PracticeQuestion, error) {
|
||||||
rows, err := q.db.Query(ctx, ListPracticeQuestions, practiceID)
|
rows, err := q.db.Query(ctx, GetQuestionsByPractice, practiceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -159,57 +105,31 @@ func (q *Queries) ListPracticeQuestions(ctx context.Context, practiceID int64) (
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdatePracticeQuestion = `-- name: UpdatePracticeQuestion :one
|
const UpdatePracticeQuestion = `-- name: UpdatePracticeQuestion :exec
|
||||||
UPDATE practice_questions
|
UPDATE practice_questions
|
||||||
SET
|
SET
|
||||||
question = $2,
|
question = COALESCE($1, question),
|
||||||
question_voice_prompt = $3,
|
sample_answer = COALESCE($2, sample_answer),
|
||||||
sample_answer_voice_prompt = $4,
|
tips = COALESCE($3, tips),
|
||||||
sample_answer = $5,
|
type = COALESCE($4, type)
|
||||||
tips = $6,
|
WHERE id = $5
|
||||||
type = $7
|
|
||||||
WHERE id = $1
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
practice_id,
|
|
||||||
question,
|
|
||||||
question_voice_prompt,
|
|
||||||
sample_answer_voice_prompt,
|
|
||||||
sample_answer,
|
|
||||||
tips,
|
|
||||||
type
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdatePracticeQuestionParams struct {
|
type UpdatePracticeQuestionParams struct {
|
||||||
ID int64 `json:"id"`
|
|
||||||
Question string `json:"question"`
|
Question string `json:"question"`
|
||||||
QuestionVoicePrompt pgtype.Text `json:"question_voice_prompt"`
|
|
||||||
SampleAnswerVoicePrompt pgtype.Text `json:"sample_answer_voice_prompt"`
|
|
||||||
SampleAnswer pgtype.Text `json:"sample_answer"`
|
SampleAnswer pgtype.Text `json:"sample_answer"`
|
||||||
Tips pgtype.Text `json:"tips"`
|
Tips pgtype.Text `json:"tips"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdatePracticeQuestion(ctx context.Context, arg UpdatePracticeQuestionParams) (PracticeQuestion, error) {
|
func (q *Queries) UpdatePracticeQuestion(ctx context.Context, arg UpdatePracticeQuestionParams) error {
|
||||||
row := q.db.QueryRow(ctx, UpdatePracticeQuestion,
|
_, err := q.db.Exec(ctx, UpdatePracticeQuestion,
|
||||||
arg.ID,
|
|
||||||
arg.Question,
|
arg.Question,
|
||||||
arg.QuestionVoicePrompt,
|
|
||||||
arg.SampleAnswerVoicePrompt,
|
|
||||||
arg.SampleAnswer,
|
arg.SampleAnswer,
|
||||||
arg.Tips,
|
arg.Tips,
|
||||||
arg.Type,
|
arg.Type,
|
||||||
|
arg.ID,
|
||||||
)
|
)
|
||||||
var i PracticeQuestion
|
return err
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.PracticeID,
|
|
||||||
&i.Question,
|
|
||||||
&i.QuestionVoicePrompt,
|
|
||||||
&i.SampleAnswerVoicePrompt,
|
|
||||||
&i.SampleAnswer,
|
|
||||||
&i.Tips,
|
|
||||||
&i.Type,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,24 +21,8 @@ INSERT INTO practices (
|
||||||
persona,
|
persona,
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, true))
|
||||||
$1, -- owner_type (LEVEL | MODULE)
|
RETURNING id, owner_type, owner_id, title, description, banner_image, persona, is_active
|
||||||
$2, -- owner_id
|
|
||||||
$3, -- title
|
|
||||||
$4, -- description
|
|
||||||
$5, -- banner_image
|
|
||||||
$6, -- persona
|
|
||||||
$7 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
owner_type,
|
|
||||||
owner_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
banner_image,
|
|
||||||
persona,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreatePracticeParams struct {
|
type CreatePracticeParams struct {
|
||||||
|
|
@ -48,7 +32,7 @@ type CreatePracticeParams struct {
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
BannerImage pgtype.Text `json:"banner_image"`
|
BannerImage pgtype.Text `json:"banner_image"`
|
||||||
Persona pgtype.Text `json:"persona"`
|
Persona pgtype.Text `json:"persona"`
|
||||||
IsActive bool `json:"is_active"`
|
Column7 interface{} `json:"column_7"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreatePractice(ctx context.Context, arg CreatePracticeParams) (Practice, error) {
|
func (q *Queries) CreatePractice(ctx context.Context, arg CreatePracticeParams) (Practice, error) {
|
||||||
|
|
@ -59,7 +43,7 @@ func (q *Queries) CreatePractice(ctx context.Context, arg CreatePracticeParams)
|
||||||
arg.Description,
|
arg.Description,
|
||||||
arg.BannerImage,
|
arg.BannerImage,
|
||||||
arg.Persona,
|
arg.Persona,
|
||||||
arg.IsActive,
|
arg.Column7,
|
||||||
)
|
)
|
||||||
var i Practice
|
var i Practice
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
@ -75,71 +59,31 @@ func (q *Queries) CreatePractice(ctx context.Context, arg CreatePracticeParams)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeactivatePractice = `-- name: DeactivatePractice :exec
|
const DeletePractice = `-- name: DeletePractice :exec
|
||||||
UPDATE practices
|
DELETE FROM practices
|
||||||
SET is_active = FALSE
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeactivatePractice(ctx context.Context, id int64) error {
|
func (q *Queries) DeletePractice(ctx context.Context, id int64) error {
|
||||||
_, err := q.db.Exec(ctx, DeactivatePractice, id)
|
_, err := q.db.Exec(ctx, DeletePractice, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetPracticeByID = `-- name: GetPracticeByID :one
|
const GetPracticesByOwner = `-- name: GetPracticesByOwner :many
|
||||||
SELECT
|
SELECT id, owner_type, owner_id, title, description, banner_image, persona, is_active
|
||||||
id,
|
|
||||||
owner_type,
|
|
||||||
owner_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
banner_image,
|
|
||||||
persona,
|
|
||||||
is_active
|
|
||||||
FROM practices
|
|
||||||
WHERE id = $1
|
|
||||||
`
|
|
||||||
|
|
||||||
func (q *Queries) GetPracticeByID(ctx context.Context, id int64) (Practice, error) {
|
|
||||||
row := q.db.QueryRow(ctx, GetPracticeByID, id)
|
|
||||||
var i Practice
|
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.OwnerType,
|
|
||||||
&i.OwnerID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Description,
|
|
||||||
&i.BannerImage,
|
|
||||||
&i.Persona,
|
|
||||||
&i.IsActive,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
|
|
||||||
const ListPracticesByOwner = `-- name: ListPracticesByOwner :many
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
owner_type,
|
|
||||||
owner_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
banner_image,
|
|
||||||
persona,
|
|
||||||
is_active
|
|
||||||
FROM practices
|
FROM practices
|
||||||
WHERE owner_type = $1
|
WHERE owner_type = $1
|
||||||
AND owner_id = $2
|
AND owner_id = $2
|
||||||
AND is_active = TRUE
|
AND is_active = true
|
||||||
ORDER BY id ASC
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type ListPracticesByOwnerParams struct {
|
type GetPracticesByOwnerParams struct {
|
||||||
OwnerType string `json:"owner_type"`
|
OwnerType string `json:"owner_type"`
|
||||||
OwnerID int64 `json:"owner_id"`
|
OwnerID int64 `json:"owner_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) ListPracticesByOwner(ctx context.Context, arg ListPracticesByOwnerParams) ([]Practice, error) {
|
func (q *Queries) GetPracticesByOwner(ctx context.Context, arg GetPracticesByOwnerParams) ([]Practice, error) {
|
||||||
rows, err := q.db.Query(ctx, ListPracticesByOwner, arg.OwnerType, arg.OwnerID)
|
rows, err := q.db.Query(ctx, GetPracticesByOwner, arg.OwnerType, arg.OwnerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -167,54 +111,34 @@ func (q *Queries) ListPracticesByOwner(ctx context.Context, arg ListPracticesByO
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdatePractice = `-- name: UpdatePractice :one
|
const UpdatePractice = `-- name: UpdatePractice :exec
|
||||||
UPDATE practices
|
UPDATE practices
|
||||||
SET
|
SET
|
||||||
title = $2,
|
title = COALESCE($1, title),
|
||||||
description = $3,
|
description = COALESCE($2, description),
|
||||||
banner_image = $4,
|
banner_image = COALESCE($3, banner_image),
|
||||||
persona = $5,
|
persona = COALESCE($4, persona),
|
||||||
is_active = $6
|
is_active = COALESCE($5, is_active)
|
||||||
WHERE id = $1
|
WHERE id = $6
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
owner_type,
|
|
||||||
owner_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
banner_image,
|
|
||||||
persona,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdatePracticeParams struct {
|
type UpdatePracticeParams struct {
|
||||||
ID int64 `json:"id"`
|
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
BannerImage pgtype.Text `json:"banner_image"`
|
BannerImage pgtype.Text `json:"banner_image"`
|
||||||
Persona pgtype.Text `json:"persona"`
|
Persona pgtype.Text `json:"persona"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdatePractice(ctx context.Context, arg UpdatePracticeParams) (Practice, error) {
|
func (q *Queries) UpdatePractice(ctx context.Context, arg UpdatePracticeParams) error {
|
||||||
row := q.db.QueryRow(ctx, UpdatePractice,
|
_, err := q.db.Exec(ctx, UpdatePractice,
|
||||||
arg.ID,
|
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Description,
|
arg.Description,
|
||||||
arg.BannerImage,
|
arg.BannerImage,
|
||||||
arg.Persona,
|
arg.Persona,
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
|
arg.ID,
|
||||||
)
|
)
|
||||||
var i Practice
|
return err
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.OwnerType,
|
|
||||||
&i.OwnerID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Description,
|
|
||||||
&i.BannerImage,
|
|
||||||
&i.Persona,
|
|
||||||
&i.IsActive,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,31 +17,10 @@ INSERT INTO levels (
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
level_index,
|
level_index,
|
||||||
number_of_modules,
|
|
||||||
number_of_practices,
|
|
||||||
number_of_videos,
|
|
||||||
is_active
|
is_active
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES ($1, $2, $3, $4, COALESCE($5, true))
|
||||||
$1, -- program_id
|
RETURNING id, program_id, title, description, level_index, number_of_modules, number_of_practices, number_of_videos, is_active
|
||||||
$2, -- title
|
|
||||||
$3, -- description
|
|
||||||
$4, -- level_index
|
|
||||||
$5, -- number_of_modules
|
|
||||||
$6, -- number_of_practices
|
|
||||||
$7, -- number_of_videos
|
|
||||||
$8 -- is_active
|
|
||||||
)
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
program_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
level_index,
|
|
||||||
number_of_modules,
|
|
||||||
number_of_practices,
|
|
||||||
number_of_videos,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateLevelParams struct {
|
type CreateLevelParams struct {
|
||||||
|
|
@ -49,10 +28,7 @@ type CreateLevelParams struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
LevelIndex int32 `json:"level_index"`
|
LevelIndex int32 `json:"level_index"`
|
||||||
NumberOfModules int32 `json:"number_of_modules"`
|
Column5 interface{} `json:"column_5"`
|
||||||
NumberOfPractices int32 `json:"number_of_practices"`
|
|
||||||
NumberOfVideos int32 `json:"number_of_videos"`
|
|
||||||
IsActive bool `json:"is_active"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateLevel(ctx context.Context, arg CreateLevelParams) (Level, error) {
|
func (q *Queries) CreateLevel(ctx context.Context, arg CreateLevelParams) (Level, error) {
|
||||||
|
|
@ -61,10 +37,7 @@ func (q *Queries) CreateLevel(ctx context.Context, arg CreateLevelParams) (Level
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Description,
|
arg.Description,
|
||||||
arg.LevelIndex,
|
arg.LevelIndex,
|
||||||
arg.NumberOfModules,
|
arg.Column5,
|
||||||
arg.NumberOfPractices,
|
|
||||||
arg.NumberOfVideos,
|
|
||||||
arg.IsActive,
|
|
||||||
)
|
)
|
||||||
var i Level
|
var i Level
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
@ -81,51 +54,19 @@ func (q *Queries) CreateLevel(ctx context.Context, arg CreateLevelParams) (Level
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeactivateLevel = `-- name: DeactivateLevel :exec
|
const DeleteLevel = `-- name: DeleteLevel :exec
|
||||||
UPDATE levels
|
DELETE FROM levels
|
||||||
SET is_active = FALSE
|
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeactivateLevel(ctx context.Context, id int64) error {
|
func (q *Queries) DeleteLevel(ctx context.Context, id int64) error {
|
||||||
_, err := q.db.Exec(ctx, DeactivateLevel, id)
|
_, err := q.db.Exec(ctx, DeleteLevel, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetLevelByID = `-- name: GetLevelByID :one
|
const GetLevelsByProgram = `-- name: GetLevelsByProgram :many
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
program_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
level_index,
|
|
||||||
number_of_modules,
|
|
||||||
number_of_practices,
|
|
||||||
number_of_videos,
|
|
||||||
is_active
|
|
||||||
FROM levels
|
|
||||||
WHERE id = $1
|
|
||||||
`
|
|
||||||
|
|
||||||
func (q *Queries) GetLevelByID(ctx context.Context, id int64) (Level, error) {
|
|
||||||
row := q.db.QueryRow(ctx, GetLevelByID, id)
|
|
||||||
var i Level
|
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.ProgramID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Description,
|
|
||||||
&i.LevelIndex,
|
|
||||||
&i.NumberOfModules,
|
|
||||||
&i.NumberOfPractices,
|
|
||||||
&i.NumberOfVideos,
|
|
||||||
&i.IsActive,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
|
|
||||||
const ListLevelsByProgram = `-- name: ListLevelsByProgram :many
|
|
||||||
SELECT
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
id,
|
id,
|
||||||
program_id,
|
program_id,
|
||||||
title,
|
title,
|
||||||
|
|
@ -137,20 +78,33 @@ SELECT
|
||||||
is_active
|
is_active
|
||||||
FROM levels
|
FROM levels
|
||||||
WHERE program_id = $1
|
WHERE program_id = $1
|
||||||
AND is_active = TRUE
|
|
||||||
ORDER BY level_index ASC
|
ORDER BY level_index ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListLevelsByProgram(ctx context.Context, programID int64) ([]Level, error) {
|
type GetLevelsByProgramRow struct {
|
||||||
rows, err := q.db.Query(ctx, ListLevelsByProgram, programID)
|
TotalCount int64 `json:"total_count"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
ProgramID int64 `json:"program_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Description pgtype.Text `json:"description"`
|
||||||
|
LevelIndex int32 `json:"level_index"`
|
||||||
|
NumberOfModules int32 `json:"number_of_modules"`
|
||||||
|
NumberOfPractices int32 `json:"number_of_practices"`
|
||||||
|
NumberOfVideos int32 `json:"number_of_videos"`
|
||||||
|
IsActive bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetLevelsByProgram(ctx context.Context, programID int64) ([]GetLevelsByProgramRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetLevelsByProgram, programID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []Level
|
var items []GetLevelsByProgramRow
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i Level
|
var i GetLevelsByProgramRow
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
|
&i.TotalCount,
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ProgramID,
|
&i.ProgramID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
|
|
@ -171,62 +125,64 @@ func (q *Queries) ListLevelsByProgram(ctx context.Context, programID int64) ([]L
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdateLevel = `-- name: UpdateLevel :one
|
const IncrementLevelModuleCount = `-- name: IncrementLevelModuleCount :exec
|
||||||
|
UPDATE levels
|
||||||
|
SET number_of_modules = number_of_modules + 1
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) IncrementLevelModuleCount(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, IncrementLevelModuleCount, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const IncrementLevelPracticeCount = `-- name: IncrementLevelPracticeCount :exec
|
||||||
|
UPDATE levels
|
||||||
|
SET number_of_practices = number_of_practices + 1
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) IncrementLevelPracticeCount(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, IncrementLevelPracticeCount, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const IncrementLevelVideoCount = `-- name: IncrementLevelVideoCount :exec
|
||||||
|
UPDATE levels
|
||||||
|
SET number_of_videos = number_of_videos + 1
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) IncrementLevelVideoCount(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, IncrementLevelVideoCount, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateLevel = `-- name: UpdateLevel :exec
|
||||||
UPDATE levels
|
UPDATE levels
|
||||||
SET
|
SET
|
||||||
title = $2,
|
title = COALESCE($1, title),
|
||||||
description = $3,
|
description = COALESCE($2, description),
|
||||||
level_index = $4,
|
level_index = COALESCE($3, level_index),
|
||||||
number_of_modules = $5,
|
is_active = COALESCE($4, is_active)
|
||||||
number_of_practices = $6,
|
WHERE id = $5
|
||||||
number_of_videos = $7,
|
|
||||||
is_active = $8
|
|
||||||
WHERE id = $1
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
program_id,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
level_index,
|
|
||||||
number_of_modules,
|
|
||||||
number_of_practices,
|
|
||||||
number_of_videos,
|
|
||||||
is_active
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateLevelParams struct {
|
type UpdateLevelParams struct {
|
||||||
ID int64 `json:"id"`
|
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
LevelIndex int32 `json:"level_index"`
|
LevelIndex int32 `json:"level_index"`
|
||||||
NumberOfModules int32 `json:"number_of_modules"`
|
|
||||||
NumberOfPractices int32 `json:"number_of_practices"`
|
|
||||||
NumberOfVideos int32 `json:"number_of_videos"`
|
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateLevel(ctx context.Context, arg UpdateLevelParams) (Level, error) {
|
func (q *Queries) UpdateLevel(ctx context.Context, arg UpdateLevelParams) error {
|
||||||
row := q.db.QueryRow(ctx, UpdateLevel,
|
_, err := q.db.Exec(ctx, UpdateLevel,
|
||||||
arg.ID,
|
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Description,
|
arg.Description,
|
||||||
arg.LevelIndex,
|
arg.LevelIndex,
|
||||||
arg.NumberOfModules,
|
|
||||||
arg.NumberOfPractices,
|
|
||||||
arg.NumberOfVideos,
|
|
||||||
arg.IsActive,
|
arg.IsActive,
|
||||||
|
arg.ID,
|
||||||
)
|
)
|
||||||
var i Level
|
return err
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.ProgramID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Description,
|
|
||||||
&i.LevelIndex,
|
|
||||||
&i.NumberOfModules,
|
|
||||||
&i.NumberOfPractices,
|
|
||||||
&i.NumberOfVideos,
|
|
||||||
&i.IsActive,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
110
internal/domain/course_management.go
Normal file
110
internal/domain/course_management.go
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type TreeModule struct {
|
||||||
|
ID int64
|
||||||
|
Title string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TreeLevel struct {
|
||||||
|
ID int64
|
||||||
|
Title string
|
||||||
|
Modules []TreeModule
|
||||||
|
}
|
||||||
|
|
||||||
|
type TreeProgram struct {
|
||||||
|
ID int64
|
||||||
|
Title string
|
||||||
|
Levels []TreeLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
type TreeCourse struct {
|
||||||
|
ID int64
|
||||||
|
Title string
|
||||||
|
Programs []TreeProgram
|
||||||
|
}
|
||||||
|
|
||||||
|
type CourseCategory struct {
|
||||||
|
ID int64
|
||||||
|
Name string
|
||||||
|
IsActive bool
|
||||||
|
CreatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type Program struct {
|
||||||
|
ID int64
|
||||||
|
CourseID int64
|
||||||
|
Title string
|
||||||
|
Description *string
|
||||||
|
Thumbnail *string
|
||||||
|
DisplayOrder int32
|
||||||
|
IsActive bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Course struct {
|
||||||
|
ID int64
|
||||||
|
CategoryID int64
|
||||||
|
Title string
|
||||||
|
Description *string
|
||||||
|
IsActive bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Module struct {
|
||||||
|
ID int64
|
||||||
|
LevelID int64
|
||||||
|
Title string
|
||||||
|
Content *string
|
||||||
|
DisplayOrder int32
|
||||||
|
IsActive bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModuleVideo struct {
|
||||||
|
ID int64
|
||||||
|
ModuleID int64
|
||||||
|
Title string
|
||||||
|
Description *string
|
||||||
|
VideoURL string
|
||||||
|
Duration int32
|
||||||
|
Resolution *string
|
||||||
|
InstructorID *string
|
||||||
|
Thumbnail *string
|
||||||
|
Visibility *string
|
||||||
|
IsPublished bool
|
||||||
|
PublishDate *time.Time
|
||||||
|
IsActive bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type PracticeQuestion struct {
|
||||||
|
ID int64
|
||||||
|
PracticeID int64
|
||||||
|
Question string
|
||||||
|
QuestionVoicePrompt *string
|
||||||
|
SampleAnswerVoicePrompt *string
|
||||||
|
SampleAnswer *string
|
||||||
|
Tips *string
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Practice struct {
|
||||||
|
ID int64
|
||||||
|
OwnerType string
|
||||||
|
OwnerID int64
|
||||||
|
Title string
|
||||||
|
Description *string
|
||||||
|
BannerImage *string
|
||||||
|
Persona *string
|
||||||
|
IsActive bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Level struct {
|
||||||
|
ID int64
|
||||||
|
ProgramID int64
|
||||||
|
Title string
|
||||||
|
Description *string
|
||||||
|
LevelIndex int
|
||||||
|
NumberOfModules int
|
||||||
|
NumberOfPractices int
|
||||||
|
NumberOfVideos int
|
||||||
|
IsActive bool
|
||||||
|
}
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
package domain
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type CourseCategory struct {
|
|
||||||
ID int64
|
|
||||||
Name string // "Learning English", "Other Courses"
|
|
||||||
IsActive bool
|
|
||||||
CreatedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type Course struct {
|
|
||||||
ID int64
|
|
||||||
CategoryID int64
|
|
||||||
Title string
|
|
||||||
Description string
|
|
||||||
IsActive bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Program struct {
|
|
||||||
ID int64
|
|
||||||
CourseID int64
|
|
||||||
Title string
|
|
||||||
Description string
|
|
||||||
Thumbnail string
|
|
||||||
Order int // ordering inside course
|
|
||||||
IsActive bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Level struct {
|
|
||||||
ID int64
|
|
||||||
ProgramID int64
|
|
||||||
Title string // "Beginner", "Level 1"
|
|
||||||
Description string
|
|
||||||
LevelIndex int // 1,2,3...
|
|
||||||
NumberOfModules int
|
|
||||||
NumberOfPractices int
|
|
||||||
NumberOfVideos int
|
|
||||||
IsActive bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Module struct {
|
|
||||||
ID int64
|
|
||||||
LevelID int64
|
|
||||||
Title string
|
|
||||||
Content string
|
|
||||||
Order int
|
|
||||||
IsActive bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type ModuleVideo struct {
|
|
||||||
ID int64
|
|
||||||
ModuleID int64
|
|
||||||
Title string
|
|
||||||
Description string
|
|
||||||
VideoURL string
|
|
||||||
Duration int // seconds
|
|
||||||
Resolution string // "720p", "1080p"
|
|
||||||
PublishSettings PublishSettings
|
|
||||||
IsActive bool
|
|
||||||
InstructorId string
|
|
||||||
Thumbnail string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PublishSettings struct {
|
|
||||||
IsPublished bool
|
|
||||||
PublishDate time.Time
|
|
||||||
Visibility string // "public", "private", "unlisted"
|
|
||||||
}
|
|
||||||
|
|
||||||
type Practice struct {
|
|
||||||
ID int64
|
|
||||||
OwnerType string // "LEVEL" | "MODULE"
|
|
||||||
OwnerID int64
|
|
||||||
Title string
|
|
||||||
Description string
|
|
||||||
BannerImage string
|
|
||||||
Persona string
|
|
||||||
IsActive bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type PracticeQuestion struct {
|
|
||||||
ID int64
|
|
||||||
PracticeID int64
|
|
||||||
Question string
|
|
||||||
QuestionVoicePrompt string
|
|
||||||
SampleAnswerVoicePrompt string
|
|
||||||
SampleAnswer string
|
|
||||||
Tips string
|
|
||||||
Type string // MCQ, TRUE_FALSE, SHORT
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +1,253 @@
|
||||||
package ports
|
package ports
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"Yimaru-Backend/internal/domain"
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CourseStore interface {
|
type CourseStore interface {
|
||||||
CreateCourseCategory(ctx context.Context, name string) (domain.CourseCategory, error)
|
CreateCourseCategory(
|
||||||
GetCourseCategoryByID(ctx context.Context, Id int64) (domain.CourseCategory, error)
|
ctx context.Context,
|
||||||
ListActiveCourseCategories(ctx context.Context) ([]domain.CourseCategory, error)
|
name string,
|
||||||
UpdateCourseCategory(ctx context.Context, id int64, name string, isActive bool) (domain.CourseCategory, error)
|
) (domain.CourseCategory, error)
|
||||||
DeactivateCourseCategory(ctx context.Context, id int64) error
|
GetCourseCategoryByID(
|
||||||
|
ctx context.Context,
|
||||||
CreateCourse(ctx context.Context, c domain.Course) (domain.Course, error)
|
id int64,
|
||||||
GetCourseByID(ctx context.Context, id int64) (domain.Course, error)
|
) (domain.CourseCategory, error)
|
||||||
ListCoursesByCategory(ctx context.Context, categoryID int64) ([]domain.Course, error)
|
GetAllCourseCategories(
|
||||||
ListActiveCourses(ctx context.Context) ([]domain.Course, error)
|
ctx context.Context,
|
||||||
UpdateCourse(ctx context.Context, c domain.Course) (domain.Course, error)
|
limit int32,
|
||||||
DeactivateCourse(ctx context.Context, id int64) error
|
offset int32,
|
||||||
|
) ([]domain.CourseCategory, int64, error)
|
||||||
CreateProgram(ctx context.Context, p domain.Program) (domain.Program, error)
|
UpdateCourseCategory(
|
||||||
GetProgramByID(ctx context.Context, id int64) (domain.Program, error)
|
ctx context.Context,
|
||||||
ListProgramsByCourse(ctx context.Context, courseID int64) ([]domain.Program, error)
|
id int64,
|
||||||
ListActivePrograms(ctx context.Context) ([]domain.Program, error)
|
name *string,
|
||||||
UpdateProgram(ctx context.Context, p domain.Program) (domain.Program, error)
|
isActive *bool,
|
||||||
DeactivateProgram(ctx context.Context, id int64) error
|
) error
|
||||||
|
DeleteCourseCategory(
|
||||||
CreateModule(ctx context.Context, m domain.Module) (domain.Module, error)
|
ctx context.Context,
|
||||||
GetModuleByID(ctx context.Context, id int64) (domain.Module, error)
|
id int64,
|
||||||
ListModulesByLevel(ctx context.Context, levelID int64) ([]domain.Module, error)
|
) error
|
||||||
UpdateModule(ctx context.Context, m domain.Module) (domain.Module, error)
|
CreateProgram(
|
||||||
DeactivateModule(ctx context.Context, id int64) error
|
ctx context.Context,
|
||||||
|
courseID int64,
|
||||||
CreateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error)
|
title string,
|
||||||
GetModuleVideoByID(ctx context.Context, id int64) (domain.ModuleVideo, error)
|
description *string,
|
||||||
ListAllVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error)
|
thumbnail *string,
|
||||||
ListPublishedVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error)
|
displayOrder *int32,
|
||||||
UpdateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error)
|
) (domain.Program, error)
|
||||||
DeactivateModuleVideo(ctx context.Context, id int64) error
|
GetProgramByID(
|
||||||
|
ctx context.Context,
|
||||||
CreatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error)
|
id int64,
|
||||||
GetPracticeByID(ctx context.Context, id int64) (domain.Practice, error)
|
) (domain.Program, error)
|
||||||
ListPracticesByOwner(ctx context.Context, ownerType string, ownerID int64) ([]domain.Practice, error)
|
GetProgramsByCourse(
|
||||||
UpdatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error)
|
ctx context.Context,
|
||||||
DeactivatePractice(ctx context.Context, id int64) error
|
courseID int64,
|
||||||
|
) ([]domain.Program, int64, error)
|
||||||
CreatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error)
|
ListProgramsByCourse(
|
||||||
GetPracticeQuestionByID(ctx context.Context, id int64) (domain.PracticeQuestion, error)
|
ctx context.Context,
|
||||||
ListPracticeQuestions(ctx context.Context, practiceID int64) ([]domain.PracticeQuestion, error)
|
courseID int64,
|
||||||
UpdatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error)
|
) ([]domain.Program, error)
|
||||||
DeletePracticeQuestion(ctx context.Context, id int64) error
|
ListActivePrograms(
|
||||||
|
ctx context.Context,
|
||||||
CreateLevel(ctx context.Context, l domain.Level) (domain.Level, error)
|
) ([]domain.Program, error)
|
||||||
GetLevelByID(ctx context.Context, id int64) (domain.Level, error)
|
UpdateProgramPartial(
|
||||||
ListLevelsByProgram(ctx context.Context, programID int64) ([]domain.Level, error)
|
ctx context.Context,
|
||||||
UpdateLevel(ctx context.Context, l domain.Level) (domain.Level, error)
|
id int64,
|
||||||
DeactivateLevel(ctx context.Context, id int64) error
|
title *string,
|
||||||
|
description *string,
|
||||||
|
thumbnail *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
isActive *bool,
|
||||||
|
) error
|
||||||
|
UpdateProgramFull(
|
||||||
|
ctx context.Context,
|
||||||
|
program domain.Program,
|
||||||
|
) (domain.Program, error)
|
||||||
|
DeactivateProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error
|
||||||
|
DeleteProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) (domain.Program, error)
|
||||||
|
CreateCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
categoryID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
) (domain.Course, error)
|
||||||
|
GetCourseByID(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) (domain.Course, error)
|
||||||
|
GetCoursesByCategory(
|
||||||
|
ctx context.Context,
|
||||||
|
categoryID int64,
|
||||||
|
limit int32,
|
||||||
|
offset int32,
|
||||||
|
) ([]domain.Course, int64, error)
|
||||||
|
UpdateCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error
|
||||||
|
DeleteCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error
|
||||||
|
CreateModule(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
title string,
|
||||||
|
content *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
) (domain.Module, error)
|
||||||
|
GetModulesByLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) ([]domain.Module, int64, error)
|
||||||
|
UpdateModule(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
content *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
isActive *bool,
|
||||||
|
) error
|
||||||
|
DeleteModule(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error
|
||||||
|
CreateModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
moduleID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
videoURL string,
|
||||||
|
duration int32,
|
||||||
|
resolution *string,
|
||||||
|
instructorID *string,
|
||||||
|
thumbnail *string,
|
||||||
|
visibility *string,
|
||||||
|
) (domain.ModuleVideo, error)
|
||||||
|
PublishModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
videoID int64,
|
||||||
|
) error
|
||||||
|
GetPublishedVideosByModule(
|
||||||
|
ctx context.Context,
|
||||||
|
moduleID int64,
|
||||||
|
) ([]domain.ModuleVideo, error)
|
||||||
|
UpdateModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
videoURL *string,
|
||||||
|
duration *int32,
|
||||||
|
resolution *string,
|
||||||
|
visibility *string,
|
||||||
|
thumbnail *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error
|
||||||
|
DeleteModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error
|
||||||
|
CreatePracticeQuestion(
|
||||||
|
ctx context.Context,
|
||||||
|
practiceID int64,
|
||||||
|
question string,
|
||||||
|
questionVoicePrompt *string,
|
||||||
|
sampleAnswerVoicePrompt *string,
|
||||||
|
sampleAnswer *string,
|
||||||
|
tips *string,
|
||||||
|
qType string,
|
||||||
|
) (domain.PracticeQuestion, error)
|
||||||
|
GetQuestionsByPractice(
|
||||||
|
ctx context.Context,
|
||||||
|
practiceID int64,
|
||||||
|
) ([]domain.PracticeQuestion, error)
|
||||||
|
UpdatePracticeQuestion(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
question *string,
|
||||||
|
sampleAnswer *string,
|
||||||
|
tips *string,
|
||||||
|
qType *string,
|
||||||
|
) error
|
||||||
|
DeletePracticeQuestion(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error
|
||||||
|
CreatePractice(
|
||||||
|
ctx context.Context,
|
||||||
|
ownerType string,
|
||||||
|
ownerID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
bannerImage *string,
|
||||||
|
persona *string,
|
||||||
|
isActive *bool,
|
||||||
|
) (domain.Practice, error)
|
||||||
|
GetPracticesByOwner(
|
||||||
|
ctx context.Context,
|
||||||
|
ownerType string,
|
||||||
|
ownerID int64,
|
||||||
|
) ([]domain.Practice, error)
|
||||||
|
UpdatePractice(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
bannerImage *string,
|
||||||
|
persona *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error
|
||||||
|
DeletePractice(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error
|
||||||
|
CreateLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
programID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
levelIndex int,
|
||||||
|
isActive *bool,
|
||||||
|
) (domain.Level, error)
|
||||||
|
GetLevelsByProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
programID int64,
|
||||||
|
) ([]domain.Level, error)
|
||||||
|
UpdateLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
levelIndex *int,
|
||||||
|
isActive *bool,
|
||||||
|
) error
|
||||||
|
IncrementLevelModuleCount(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error
|
||||||
|
IncrementLevelPracticeCount(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error
|
||||||
|
IncrementLevelVideoCount(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error
|
||||||
|
DeleteLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error
|
||||||
|
GetFullLearningTree(ctx context.Context) ([]domain.TreeCourse, error)
|
||||||
}
|
}
|
||||||
|
|
@ -11,65 +11,14 @@ import (
|
||||||
|
|
||||||
func NewCourseStore(s *Store) ports.CourseStore { return s }
|
func NewCourseStore(s *Store) ports.CourseStore { return s }
|
||||||
|
|
||||||
func (s *Store) CreateCourseCategory(ctx context.Context, name string) (domain.CourseCategory, error) {
|
func (s *Store) CreateCourseCategory(
|
||||||
tempCategory, err := s.queries.CreateCourseCategory(ctx, dbgen.CreateCourseCategoryParams{
|
ctx context.Context,
|
||||||
|
name string,
|
||||||
|
) (domain.CourseCategory, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.CreateCourseCategory(ctx, dbgen.CreateCourseCategoryParams{
|
||||||
Name: name,
|
Name: name,
|
||||||
IsActive: true,
|
Column2: true,
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.CourseCategory{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
category := domain.CourseCategory{
|
|
||||||
ID: tempCategory.ID,
|
|
||||||
Name: tempCategory.Name,
|
|
||||||
IsActive: tempCategory.IsActive,
|
|
||||||
CreatedAt: tempCategory.CreatedAt.Time,
|
|
||||||
}
|
|
||||||
|
|
||||||
return category, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) GetCourseCategoryByID(ctx context.Context, Id int64) (domain.CourseCategory, error) {
|
|
||||||
tempCategory, err := s.queries.GetCourseCategoryByID(ctx, Id)
|
|
||||||
if err != nil {
|
|
||||||
return domain.CourseCategory{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
category := domain.CourseCategory{
|
|
||||||
ID: tempCategory.ID,
|
|
||||||
Name: tempCategory.Name,
|
|
||||||
IsActive: tempCategory.IsActive,
|
|
||||||
CreatedAt: tempCategory.CreatedAt.Time,
|
|
||||||
}
|
|
||||||
|
|
||||||
return category, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListActiveCourseCategories(ctx context.Context) ([]domain.CourseCategory, error) {
|
|
||||||
rows, err := s.queries.ListActiveCourseCategories(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make([]domain.CourseCategory, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
result = append(result, domain.CourseCategory{
|
|
||||||
ID: r.ID,
|
|
||||||
Name: r.Name,
|
|
||||||
IsActive: r.IsActive,
|
|
||||||
CreatedAt: r.CreatedAt.Time,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) UpdateCourseCategory(ctx context.Context, id int64, name string, isActive bool) (domain.CourseCategory, error) {
|
|
||||||
row, err := s.queries.UpdateCourseCategory(ctx, dbgen.UpdateCourseCategoryParams{
|
|
||||||
ID: id,
|
|
||||||
Name: name,
|
|
||||||
IsActive: isActive,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.CourseCategory{}, err
|
return domain.CourseCategory{}, err
|
||||||
|
|
@ -83,752 +32,90 @@ func (s *Store) UpdateCourseCategory(ctx context.Context, id int64, name string,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) DeactivateCourseCategory(ctx context.Context, id int64) error {
|
func (s *Store) GetCourseCategoryByID(
|
||||||
return s.queries.DeactivateCourseCategory(ctx, id)
|
ctx context.Context,
|
||||||
}
|
id int64,
|
||||||
|
) (domain.CourseCategory, error) {
|
||||||
|
|
||||||
// Course related methods
|
row, err := s.queries.GetCourseCategoryByID(ctx, id)
|
||||||
func (s *Store) CreateCourse(ctx context.Context, c domain.Course) (domain.Course, error) {
|
|
||||||
row, err := s.queries.CreateCourse(ctx, dbgen.CreateCourseParams{
|
|
||||||
CategoryID: c.CategoryID,
|
|
||||||
Title: c.Title,
|
|
||||||
Description: pgtype.Text{String: c.Description, Valid: c.Description != ""},
|
|
||||||
IsActive: c.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.Course{}, err
|
return domain.CourseCategory{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return domain.Course{
|
return domain.CourseCategory{
|
||||||
ID: row.ID,
|
ID: row.ID,
|
||||||
CategoryID: row.CategoryID,
|
Name: row.Name,
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
IsActive: row.IsActive,
|
IsActive: row.IsActive,
|
||||||
|
CreatedAt: row.CreatedAt.Time,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetCourseByID(ctx context.Context, id int64) (domain.Course, error) {
|
func (s *Store) GetAllCourseCategories(
|
||||||
row, err := s.queries.GetCourseByID(ctx, id)
|
ctx context.Context,
|
||||||
|
limit int32,
|
||||||
|
offset int32,
|
||||||
|
) ([]domain.CourseCategory, int64, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.GetAllCourseCategories(ctx, dbgen.GetAllCourseCategoriesParams{
|
||||||
|
Limit: pgtype.Int4{Int32: limit},
|
||||||
|
Offset: pgtype.Int4{Int32: offset},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.Course{}, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return domain.Course{
|
var (
|
||||||
|
categories []domain.CourseCategory
|
||||||
|
totalCount int64
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, row := range rows {
|
||||||
|
if i == 0 {
|
||||||
|
totalCount = row.TotalCount
|
||||||
|
}
|
||||||
|
|
||||||
|
categories = append(categories, domain.CourseCategory{
|
||||||
ID: row.ID,
|
ID: row.ID,
|
||||||
CategoryID: row.CategoryID,
|
Name: row.Name,
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
IsActive: row.IsActive,
|
IsActive: row.IsActive,
|
||||||
}, nil
|
CreatedAt: row.CreatedAt.Time,
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListCoursesByCategory(ctx context.Context, categoryID int64) ([]domain.Course, error) {
|
|
||||||
rows, err := s.queries.ListCoursesByCategory(ctx, categoryID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]domain.Course, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
res = append(res, domain.Course{
|
|
||||||
ID: r.ID,
|
|
||||||
CategoryID: r.CategoryID,
|
|
||||||
Title: r.Title,
|
|
||||||
Description: r.Description.String,
|
|
||||||
IsActive: r.IsActive,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return res, nil
|
|
||||||
|
return categories, totalCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) ListActiveCourses(ctx context.Context) ([]domain.Course, error) {
|
func (s *Store) UpdateCourseCategory(
|
||||||
rows, err := s.queries.ListActiveCourses(ctx)
|
ctx context.Context,
|
||||||
if err != nil {
|
id int64,
|
||||||
return nil, err
|
name *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
var (
|
||||||
|
nameVal string
|
||||||
|
isActiveVal bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if name != nil {
|
||||||
|
nameVal = *name
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]domain.Course, 0, len(rows))
|
if isActive != nil {
|
||||||
for _, r := range rows {
|
isActiveVal = *isActive
|
||||||
res = append(res, domain.Course{
|
}
|
||||||
ID: r.ID,
|
|
||||||
CategoryID: r.CategoryID,
|
return s.queries.UpdateCourseCategory(ctx, dbgen.UpdateCourseCategoryParams{
|
||||||
Title: r.Title,
|
Name: nameVal,
|
||||||
Description: r.Description.String,
|
IsActive: isActiveVal,
|
||||||
IsActive: r.IsActive,
|
ID: id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) UpdateCourse(ctx context.Context, c domain.Course) (domain.Course, error) {
|
func (s *Store) DeleteCourseCategory(
|
||||||
row, err := s.queries.UpdateCourse(ctx, dbgen.UpdateCourseParams{
|
ctx context.Context,
|
||||||
ID: c.ID,
|
id int64,
|
||||||
CategoryID: c.CategoryID,
|
) error {
|
||||||
Title: c.Title,
|
|
||||||
Description: pgtype.Text{String: c.Description, Valid: c.Description != ""},
|
|
||||||
IsActive: c.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.Course{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.Course{
|
return s.queries.DeleteCourseCategory(ctx, id)
|
||||||
ID: row.ID,
|
|
||||||
CategoryID: row.CategoryID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) DeactivateCourse(ctx context.Context, id int64) error {
|
|
||||||
return s.queries.DeactivateCourse(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Program methods
|
|
||||||
func (s *Store) CreateProgram(ctx context.Context, p domain.Program) (domain.Program, error) {
|
|
||||||
row, err := s.queries.CreateProgram(ctx, dbgen.CreateProgramParams{
|
|
||||||
CourseID: p.CourseID,
|
|
||||||
Title: p.Title,
|
|
||||||
Description: pgtype.Text{String: p.Description, Valid: p.Description != ""},
|
|
||||||
Thumbnail: pgtype.Text{String: p.Thumbnail, Valid: p.Thumbnail != ""},
|
|
||||||
DisplayOrder: int32(p.Order),
|
|
||||||
IsActive: p.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.Program{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.Program{
|
|
||||||
ID: row.ID,
|
|
||||||
CourseID: row.CourseID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
Thumbnail: row.Thumbnail.String,
|
|
||||||
Order: int(row.DisplayOrder),
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) GetProgramByID(ctx context.Context, id int64) (domain.Program, error) {
|
|
||||||
row, err := s.queries.GetProgramByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return domain.Program{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.Program{
|
|
||||||
ID: row.ID,
|
|
||||||
CourseID: row.CourseID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
Thumbnail: row.Thumbnail.String,
|
|
||||||
Order: int(row.DisplayOrder),
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListProgramsByCourse(ctx context.Context, courseID int64) ([]domain.Program, error) {
|
|
||||||
rows, err := s.queries.ListProgramsByCourse(ctx, courseID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]domain.Program, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
res = append(res, domain.Program{
|
|
||||||
ID: r.ID,
|
|
||||||
CourseID: r.CourseID,
|
|
||||||
Title: r.Title,
|
|
||||||
Description: r.Description.String,
|
|
||||||
Thumbnail: r.Thumbnail.String,
|
|
||||||
Order: int(r.DisplayOrder),
|
|
||||||
IsActive: r.IsActive,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListActivePrograms(ctx context.Context) ([]domain.Program, error) {
|
|
||||||
rows, err := s.queries.ListActivePrograms(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]domain.Program, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
res = append(res, domain.Program{
|
|
||||||
ID: r.ID,
|
|
||||||
CourseID: r.CourseID,
|
|
||||||
Title: r.Title,
|
|
||||||
Description: r.Description.String,
|
|
||||||
Thumbnail: r.Thumbnail.String,
|
|
||||||
Order: int(r.DisplayOrder),
|
|
||||||
IsActive: r.IsActive,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) UpdateProgram(ctx context.Context, p domain.Program) (domain.Program, error) {
|
|
||||||
row, err := s.queries.UpdateProgram(ctx, dbgen.UpdateProgramParams{
|
|
||||||
ID: p.ID,
|
|
||||||
CourseID: p.CourseID,
|
|
||||||
Title: p.Title,
|
|
||||||
Description: pgtype.Text{String: p.Description, Valid: p.Description != ""},
|
|
||||||
Thumbnail: pgtype.Text{String: p.Thumbnail, Valid: p.Thumbnail != ""},
|
|
||||||
DisplayOrder: int32(p.Order),
|
|
||||||
IsActive: p.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.Program{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.Program{
|
|
||||||
ID: row.ID,
|
|
||||||
CourseID: row.CourseID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
Thumbnail: row.Thumbnail.String,
|
|
||||||
Order: int(row.DisplayOrder),
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) DeactivateProgram(ctx context.Context, id int64) error {
|
|
||||||
return s.queries.DeactivateProgram(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module methods
|
|
||||||
func (s *Store) CreateModule(ctx context.Context, m domain.Module) (domain.Module, error) {
|
|
||||||
row, err := s.queries.CreateModule(ctx, dbgen.CreateModuleParams{
|
|
||||||
LevelID: m.LevelID,
|
|
||||||
Title: m.Title,
|
|
||||||
Content: pgtype.Text{String: m.Content, Valid: m.Content != ""},
|
|
||||||
DisplayOrder: int32(m.Order),
|
|
||||||
IsActive: m.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.Module{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.Module{
|
|
||||||
ID: row.ID,
|
|
||||||
LevelID: row.LevelID,
|
|
||||||
Title: row.Title,
|
|
||||||
Content: row.Content.String,
|
|
||||||
Order: int(row.DisplayOrder),
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) GetModuleByID(ctx context.Context, id int64) (domain.Module, error) {
|
|
||||||
row, err := s.queries.GetModuleByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return domain.Module{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.Module{
|
|
||||||
ID: row.ID,
|
|
||||||
LevelID: row.LevelID,
|
|
||||||
Title: row.Title,
|
|
||||||
Content: row.Content.String,
|
|
||||||
Order: int(row.DisplayOrder),
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListModulesByLevel(ctx context.Context, levelID int64) ([]domain.Module, error) {
|
|
||||||
rows, err := s.queries.ListModulesByLevel(ctx, levelID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]domain.Module, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
res = append(res, domain.Module{
|
|
||||||
ID: r.ID,
|
|
||||||
LevelID: r.LevelID,
|
|
||||||
Title: r.Title,
|
|
||||||
Content: r.Content.String,
|
|
||||||
Order: int(r.DisplayOrder),
|
|
||||||
IsActive: r.IsActive,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) UpdateModule(ctx context.Context, m domain.Module) (domain.Module, error) {
|
|
||||||
row, err := s.queries.UpdateModule(ctx, dbgen.UpdateModuleParams{
|
|
||||||
ID: m.ID,
|
|
||||||
Title: m.Title,
|
|
||||||
Content: pgtype.Text{String: m.Content, Valid: m.Content != ""},
|
|
||||||
DisplayOrder: int32(m.Order),
|
|
||||||
IsActive: m.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.Module{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.Module{
|
|
||||||
ID: row.ID,
|
|
||||||
LevelID: row.LevelID,
|
|
||||||
Title: row.Title,
|
|
||||||
Content: row.Content.String,
|
|
||||||
Order: int(row.DisplayOrder),
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) DeactivateModule(ctx context.Context, id int64) error {
|
|
||||||
return s.queries.DeactivateModule(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module video methods
|
|
||||||
func (s *Store) CreateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error) {
|
|
||||||
row, err := s.queries.CreateModuleVideo(ctx, dbgen.CreateModuleVideoParams{
|
|
||||||
ModuleID: v.ModuleID,
|
|
||||||
Title: v.Title,
|
|
||||||
Description: pgtype.Text{String: v.Description, Valid: v.Description != ""},
|
|
||||||
VideoUrl: v.VideoURL,
|
|
||||||
Duration: int32(v.Duration),
|
|
||||||
Resolution: pgtype.Text{String: v.Resolution, Valid: v.Resolution != ""},
|
|
||||||
IsPublished: v.PublishSettings.IsPublished,
|
|
||||||
PublishDate: pgtype.Timestamptz{Time: v.PublishSettings.PublishDate, Valid: !v.PublishSettings.PublishDate.IsZero()},
|
|
||||||
Visibility: pgtype.Text{String: v.PublishSettings.Visibility, Valid: v.PublishSettings.Visibility != ""},
|
|
||||||
InstructorID: pgtype.Text{String: v.InstructorId, Valid: v.InstructorId != ""},
|
|
||||||
Thumbnail: pgtype.Text{String: v.Thumbnail, Valid: v.Thumbnail != ""},
|
|
||||||
IsActive: v.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.ModuleVideo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.ModuleVideo{
|
|
||||||
ID: row.ID,
|
|
||||||
ModuleID: row.ModuleID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
VideoURL: row.VideoUrl,
|
|
||||||
Duration: int(row.Duration),
|
|
||||||
Resolution: row.Resolution.String,
|
|
||||||
PublishSettings: domain.PublishSettings{
|
|
||||||
IsPublished: row.IsPublished,
|
|
||||||
PublishDate: row.PublishDate.Time,
|
|
||||||
Visibility: row.Visibility.String,
|
|
||||||
},
|
|
||||||
InstructorId: row.InstructorID.String,
|
|
||||||
Thumbnail: row.Thumbnail.String,
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) GetModuleVideoByID(ctx context.Context, id int64) (domain.ModuleVideo, error) {
|
|
||||||
row, err := s.queries.GetModuleVideoByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return domain.ModuleVideo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.ModuleVideo{
|
|
||||||
ID: row.ID,
|
|
||||||
ModuleID: row.ModuleID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
VideoURL: row.VideoUrl,
|
|
||||||
Duration: int(row.Duration),
|
|
||||||
Resolution: row.Resolution.String,
|
|
||||||
PublishSettings: domain.PublishSettings{
|
|
||||||
IsPublished: row.IsPublished,
|
|
||||||
PublishDate: row.PublishDate.Time,
|
|
||||||
Visibility: row.Visibility.String,
|
|
||||||
},
|
|
||||||
InstructorId: row.InstructorID.String,
|
|
||||||
Thumbnail: row.Thumbnail.String,
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListAllVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error) {
|
|
||||||
rows, err := s.queries.ListAllVideosByModule(ctx, moduleID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]domain.ModuleVideo, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
res = append(res, domain.ModuleVideo{
|
|
||||||
ID: r.ID,
|
|
||||||
ModuleID: r.ModuleID,
|
|
||||||
Title: r.Title,
|
|
||||||
Description: r.Description.String,
|
|
||||||
VideoURL: r.VideoUrl,
|
|
||||||
Duration: int(r.Duration),
|
|
||||||
Resolution: r.Resolution.String,
|
|
||||||
PublishSettings: domain.PublishSettings{
|
|
||||||
IsPublished: r.IsPublished,
|
|
||||||
PublishDate: r.PublishDate.Time,
|
|
||||||
Visibility: r.Visibility.String,
|
|
||||||
},
|
|
||||||
InstructorId: r.InstructorID.String,
|
|
||||||
Thumbnail: r.Thumbnail.String,
|
|
||||||
IsActive: r.IsActive,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListPublishedVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error) {
|
|
||||||
rows, err := s.queries.ListPublishedVideosByModule(ctx, moduleID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]domain.ModuleVideo, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
res = append(res, domain.ModuleVideo{
|
|
||||||
ID: r.ID,
|
|
||||||
ModuleID: r.ModuleID,
|
|
||||||
Title: r.Title,
|
|
||||||
Description: r.Description.String,
|
|
||||||
VideoURL: r.VideoUrl,
|
|
||||||
Duration: int(r.Duration),
|
|
||||||
Resolution: r.Resolution.String,
|
|
||||||
PublishSettings: domain.PublishSettings{
|
|
||||||
IsPublished: true,
|
|
||||||
PublishDate: r.PublishDate.Time,
|
|
||||||
Visibility: r.Visibility.String,
|
|
||||||
},
|
|
||||||
InstructorId: r.InstructorID.String,
|
|
||||||
Thumbnail: r.Thumbnail.String,
|
|
||||||
IsActive: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) UpdateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error) {
|
|
||||||
row, err := s.queries.UpdateModuleVideo(ctx, dbgen.UpdateModuleVideoParams{
|
|
||||||
ID: v.ID,
|
|
||||||
Title: v.Title,
|
|
||||||
Description: pgtype.Text{String: v.Description, Valid: v.Description != ""},
|
|
||||||
VideoUrl: v.VideoURL,
|
|
||||||
Duration: int32(v.Duration),
|
|
||||||
Resolution: pgtype.Text{String: v.Resolution, Valid: v.Resolution != ""},
|
|
||||||
IsPublished: v.PublishSettings.IsPublished,
|
|
||||||
PublishDate: pgtype.Timestamptz{Time: v.PublishSettings.PublishDate, Valid: !v.PublishSettings.PublishDate.IsZero()},
|
|
||||||
Visibility: pgtype.Text{String: v.PublishSettings.Visibility, Valid: v.PublishSettings.Visibility != ""},
|
|
||||||
InstructorID: pgtype.Text{String: v.InstructorId, Valid: v.InstructorId != ""},
|
|
||||||
Thumbnail: pgtype.Text{String: v.Thumbnail, Valid: v.Thumbnail != ""},
|
|
||||||
IsActive: v.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.ModuleVideo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.ModuleVideo{
|
|
||||||
ID: row.ID,
|
|
||||||
ModuleID: row.ModuleID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
VideoURL: row.VideoUrl,
|
|
||||||
Duration: int(row.Duration),
|
|
||||||
Resolution: row.Resolution.String,
|
|
||||||
PublishSettings: domain.PublishSettings{
|
|
||||||
IsPublished: row.IsPublished,
|
|
||||||
PublishDate: row.PublishDate.Time,
|
|
||||||
Visibility: row.Visibility.String,
|
|
||||||
},
|
|
||||||
InstructorId: row.InstructorID.String,
|
|
||||||
Thumbnail: row.Thumbnail.String,
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) DeactivateModuleVideo(ctx context.Context, id int64) error {
|
|
||||||
return s.queries.DeactivateModuleVideo(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Practices and practice question methods
|
|
||||||
func (s *Store) CreatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error) {
|
|
||||||
row, err := s.queries.CreatePractice(ctx, dbgen.CreatePracticeParams{
|
|
||||||
OwnerType: p.OwnerType,
|
|
||||||
OwnerID: p.OwnerID,
|
|
||||||
Title: p.Title,
|
|
||||||
Description: pgtype.Text{String: p.Description, Valid: p.Description != ""},
|
|
||||||
BannerImage: pgtype.Text{String: p.BannerImage, Valid: p.BannerImage != ""},
|
|
||||||
Persona: pgtype.Text{String: p.Persona, Valid: p.Persona != ""},
|
|
||||||
IsActive: p.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.Practice{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain.Practice{
|
|
||||||
ID: row.ID,
|
|
||||||
OwnerType: row.OwnerType,
|
|
||||||
OwnerID: row.OwnerID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
BannerImage: row.BannerImage.String,
|
|
||||||
Persona: row.Persona.String,
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) GetPracticeByID(ctx context.Context, id int64) (domain.Practice, error) {
|
|
||||||
row, err := s.queries.GetPracticeByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return domain.Practice{}, err
|
|
||||||
}
|
|
||||||
return domain.Practice{
|
|
||||||
ID: row.ID,
|
|
||||||
OwnerType: row.OwnerType,
|
|
||||||
OwnerID: row.OwnerID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
BannerImage: row.BannerImage.String,
|
|
||||||
Persona: row.Persona.String,
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListPracticesByOwner(ctx context.Context, ownerType string, ownerID int64) ([]domain.Practice, error) {
|
|
||||||
rows, err := s.queries.ListPracticesByOwner(ctx, dbgen.ListPracticesByOwnerParams{OwnerType: ownerType, OwnerID: ownerID})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res := make([]domain.Practice, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
res = append(res, domain.Practice{
|
|
||||||
ID: r.ID,
|
|
||||||
OwnerType: r.OwnerType,
|
|
||||||
OwnerID: r.OwnerID,
|
|
||||||
Title: r.Title,
|
|
||||||
Description: r.Description.String,
|
|
||||||
BannerImage: r.BannerImage.String,
|
|
||||||
Persona: r.Persona.String,
|
|
||||||
IsActive: r.IsActive,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) UpdatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error) {
|
|
||||||
row, err := s.queries.UpdatePractice(ctx, dbgen.UpdatePracticeParams{
|
|
||||||
ID: p.ID,
|
|
||||||
Title: p.Title,
|
|
||||||
Description: pgtype.Text{String: p.Description, Valid: p.Description != ""},
|
|
||||||
BannerImage: pgtype.Text{String: p.BannerImage, Valid: p.BannerImage != ""},
|
|
||||||
Persona: pgtype.Text{String: p.Persona, Valid: p.Persona != ""},
|
|
||||||
IsActive: p.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.Practice{}, err
|
|
||||||
}
|
|
||||||
return domain.Practice{
|
|
||||||
ID: row.ID,
|
|
||||||
OwnerType: row.OwnerType,
|
|
||||||
OwnerID: row.OwnerID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
BannerImage: row.BannerImage.String,
|
|
||||||
Persona: row.Persona.String,
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) DeactivatePractice(ctx context.Context, id int64) error {
|
|
||||||
return s.queries.DeactivatePractice(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Practice question methods
|
|
||||||
func (s *Store) CreatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error) {
|
|
||||||
row, err := s.queries.CreatePracticeQuestion(ctx, dbgen.CreatePracticeQuestionParams{
|
|
||||||
PracticeID: qn.PracticeID,
|
|
||||||
Question: qn.Question,
|
|
||||||
QuestionVoicePrompt: pgtype.Text{String: qn.QuestionVoicePrompt, Valid: qn.QuestionVoicePrompt != ""},
|
|
||||||
SampleAnswerVoicePrompt: pgtype.Text{String: qn.SampleAnswerVoicePrompt, Valid: qn.SampleAnswerVoicePrompt != ""},
|
|
||||||
SampleAnswer: pgtype.Text{String: qn.SampleAnswer, Valid: qn.SampleAnswer != ""},
|
|
||||||
Tips: pgtype.Text{String: qn.Tips, Valid: qn.Tips != ""},
|
|
||||||
Type: qn.Type,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.PracticeQuestion{}, err
|
|
||||||
}
|
|
||||||
return domain.PracticeQuestion{
|
|
||||||
ID: row.ID,
|
|
||||||
PracticeID: row.PracticeID,
|
|
||||||
Question: row.Question,
|
|
||||||
QuestionVoicePrompt: row.QuestionVoicePrompt.String,
|
|
||||||
SampleAnswerVoicePrompt: row.SampleAnswerVoicePrompt.String,
|
|
||||||
SampleAnswer: row.SampleAnswer.String,
|
|
||||||
Tips: row.Tips.String,
|
|
||||||
Type: row.Type,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) GetPracticeQuestionByID(ctx context.Context, id int64) (domain.PracticeQuestion, error) {
|
|
||||||
row, err := s.queries.GetPracticeQuestionByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return domain.PracticeQuestion{}, err
|
|
||||||
}
|
|
||||||
return domain.PracticeQuestion{
|
|
||||||
ID: row.ID,
|
|
||||||
PracticeID: row.PracticeID,
|
|
||||||
Question: row.Question,
|
|
||||||
QuestionVoicePrompt: row.QuestionVoicePrompt.String,
|
|
||||||
SampleAnswerVoicePrompt: row.SampleAnswerVoicePrompt.String,
|
|
||||||
SampleAnswer: row.SampleAnswer.String,
|
|
||||||
Tips: row.Tips.String,
|
|
||||||
Type: row.Type,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListPracticeQuestions(ctx context.Context, practiceID int64) ([]domain.PracticeQuestion, error) {
|
|
||||||
rows, err := s.queries.ListPracticeQuestions(ctx, practiceID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res := make([]domain.PracticeQuestion, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
res = append(res, domain.PracticeQuestion{
|
|
||||||
ID: r.ID,
|
|
||||||
PracticeID: r.PracticeID,
|
|
||||||
Question: r.Question,
|
|
||||||
QuestionVoicePrompt: r.QuestionVoicePrompt.String,
|
|
||||||
SampleAnswerVoicePrompt: r.SampleAnswerVoicePrompt.String,
|
|
||||||
SampleAnswer: r.SampleAnswer.String,
|
|
||||||
Tips: r.Tips.String,
|
|
||||||
Type: r.Type,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) UpdatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error) {
|
|
||||||
row, err := s.queries.UpdatePracticeQuestion(ctx, dbgen.UpdatePracticeQuestionParams{
|
|
||||||
ID: qn.ID,
|
|
||||||
Question: qn.Question,
|
|
||||||
QuestionVoicePrompt: pgtype.Text{String: qn.QuestionVoicePrompt, Valid: qn.QuestionVoicePrompt != ""},
|
|
||||||
SampleAnswerVoicePrompt: pgtype.Text{String: qn.SampleAnswerVoicePrompt, Valid: qn.SampleAnswerVoicePrompt != ""},
|
|
||||||
SampleAnswer: pgtype.Text{String: qn.SampleAnswer, Valid: qn.SampleAnswer != ""},
|
|
||||||
Tips: pgtype.Text{String: qn.Tips, Valid: qn.Tips != ""},
|
|
||||||
Type: qn.Type,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.PracticeQuestion{}, err
|
|
||||||
}
|
|
||||||
return domain.PracticeQuestion{
|
|
||||||
ID: row.ID,
|
|
||||||
PracticeID: row.PracticeID,
|
|
||||||
Question: row.Question,
|
|
||||||
QuestionVoicePrompt: row.QuestionVoicePrompt.String,
|
|
||||||
SampleAnswerVoicePrompt: row.SampleAnswerVoicePrompt.String,
|
|
||||||
SampleAnswer: row.SampleAnswer.String,
|
|
||||||
Tips: row.Tips.String,
|
|
||||||
Type: row.Type,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) DeletePracticeQuestion(ctx context.Context, id int64) error {
|
|
||||||
return s.queries.DeletePracticeQuestion(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Level (program level) methods
|
|
||||||
func (s *Store) CreateLevel(ctx context.Context, l domain.Level) (domain.Level, error) {
|
|
||||||
row, err := s.queries.CreateLevel(ctx, dbgen.CreateLevelParams{
|
|
||||||
ProgramID: l.ProgramID,
|
|
||||||
Title: l.Title,
|
|
||||||
Description: pgtype.Text{String: l.Description, Valid: l.Description != ""},
|
|
||||||
LevelIndex: int32(l.LevelIndex),
|
|
||||||
NumberOfModules: int32(l.NumberOfModules),
|
|
||||||
NumberOfPractices: int32(l.NumberOfPractices),
|
|
||||||
NumberOfVideos: int32(l.NumberOfVideos),
|
|
||||||
IsActive: l.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.Level{}, err
|
|
||||||
}
|
|
||||||
return domain.Level{
|
|
||||||
ID: row.ID,
|
|
||||||
ProgramID: row.ProgramID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
LevelIndex: int(row.LevelIndex),
|
|
||||||
NumberOfModules: int(row.NumberOfModules),
|
|
||||||
NumberOfPractices: int(row.NumberOfPractices),
|
|
||||||
NumberOfVideos: int(row.NumberOfVideos),
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) GetLevelByID(ctx context.Context, id int64) (domain.Level, error) {
|
|
||||||
row, err := s.queries.GetLevelByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return domain.Level{}, err
|
|
||||||
}
|
|
||||||
return domain.Level{
|
|
||||||
ID: row.ID,
|
|
||||||
ProgramID: row.ProgramID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
LevelIndex: int(row.LevelIndex),
|
|
||||||
NumberOfModules: int(row.NumberOfModules),
|
|
||||||
NumberOfPractices: int(row.NumberOfPractices),
|
|
||||||
NumberOfVideos: int(row.NumberOfVideos),
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) ListLevelsByProgram(ctx context.Context, programID int64) ([]domain.Level, error) {
|
|
||||||
rows, err := s.queries.ListLevelsByProgram(ctx, programID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res := make([]domain.Level, 0, len(rows))
|
|
||||||
for _, r := range rows {
|
|
||||||
res = append(res, domain.Level{
|
|
||||||
ID: r.ID,
|
|
||||||
ProgramID: r.ProgramID,
|
|
||||||
Title: r.Title,
|
|
||||||
Description: r.Description.String,
|
|
||||||
LevelIndex: int(r.LevelIndex),
|
|
||||||
NumberOfModules: int(r.NumberOfModules),
|
|
||||||
NumberOfPractices: int(r.NumberOfPractices),
|
|
||||||
NumberOfVideos: int(r.NumberOfVideos),
|
|
||||||
IsActive: r.IsActive,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) UpdateLevel(ctx context.Context, l domain.Level) (domain.Level, error) {
|
|
||||||
row, err := s.queries.UpdateLevel(ctx, dbgen.UpdateLevelParams{
|
|
||||||
ID: l.ID,
|
|
||||||
Title: l.Title,
|
|
||||||
Description: pgtype.Text{String: l.Description, Valid: l.Description != ""},
|
|
||||||
LevelIndex: int32(l.LevelIndex),
|
|
||||||
NumberOfModules: int32(l.NumberOfModules),
|
|
||||||
NumberOfPractices: int32(l.NumberOfPractices),
|
|
||||||
NumberOfVideos: int32(l.NumberOfVideos),
|
|
||||||
IsActive: l.IsActive,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return domain.Level{}, err
|
|
||||||
}
|
|
||||||
return domain.Level{
|
|
||||||
ID: row.ID,
|
|
||||||
ProgramID: row.ProgramID,
|
|
||||||
Title: row.Title,
|
|
||||||
Description: row.Description.String,
|
|
||||||
LevelIndex: int(row.LevelIndex),
|
|
||||||
NumberOfModules: int(row.NumberOfModules),
|
|
||||||
NumberOfPractices: int(row.NumberOfPractices),
|
|
||||||
NumberOfVideos: int(row.NumberOfVideos),
|
|
||||||
IsActive: row.IsActive,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) DeactivateLevel(ctx context.Context, id int64) error {
|
|
||||||
return s.queries.DeactivateLevel(ctx, id)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
240
internal/repository/course_programs.go
Normal file
240
internal/repository/course_programs.go
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) CreateProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
courseID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
thumbnail *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
) (domain.Program, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.CreateProgram(ctx, dbgen.CreateProgramParams{
|
||||||
|
CourseID: courseID,
|
||||||
|
Title: title,
|
||||||
|
Description: pgtype.Text{String: *description},
|
||||||
|
Thumbnail: pgtype.Text{String: *thumbnail},
|
||||||
|
Column5: displayOrder,
|
||||||
|
Column6: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.Program{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Program{
|
||||||
|
ID: row.ID,
|
||||||
|
CourseID: row.CourseID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
Thumbnail: &row.Thumbnail.String,
|
||||||
|
DisplayOrder: row.DisplayOrder,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetProgramByID(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) (domain.Program, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.GetProgramByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Program{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Program{
|
||||||
|
ID: row.ID,
|
||||||
|
CourseID: row.CourseID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
Thumbnail: &row.Thumbnail.String,
|
||||||
|
DisplayOrder: row.DisplayOrder,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetProgramsByCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
courseID int64,
|
||||||
|
) ([]domain.Program, int64, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.GetProgramsByCourse(ctx, courseID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
programs []domain.Program
|
||||||
|
totalCount int64
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, row := range rows {
|
||||||
|
if i == 0 {
|
||||||
|
totalCount = row.TotalCount
|
||||||
|
}
|
||||||
|
|
||||||
|
programs = append(programs, domain.Program{
|
||||||
|
ID: row.ID,
|
||||||
|
CourseID: row.CourseID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
Thumbnail: &row.Thumbnail.String,
|
||||||
|
DisplayOrder: row.DisplayOrder,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return programs, totalCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) ListProgramsByCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
courseID int64,
|
||||||
|
) ([]domain.Program, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.ListProgramsByCourse(ctx, courseID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
programs := make([]domain.Program, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
programs = append(programs, domain.Program{
|
||||||
|
ID: row.ID,
|
||||||
|
CourseID: row.CourseID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
Thumbnail: &row.Thumbnail.String,
|
||||||
|
DisplayOrder: row.DisplayOrder,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return programs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) ListActivePrograms(
|
||||||
|
ctx context.Context,
|
||||||
|
) ([]domain.Program, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.ListActivePrograms(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
programs := make([]domain.Program, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
programs = append(programs, domain.Program{
|
||||||
|
ID: row.ID,
|
||||||
|
CourseID: row.CourseID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
Thumbnail: &row.Thumbnail.String,
|
||||||
|
DisplayOrder: row.DisplayOrder,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return programs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateProgramPartial(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
thumbnail *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.UpdateProgramPartial(ctx, dbgen.UpdateProgramPartialParams{
|
||||||
|
Title: func() string {
|
||||||
|
if title != nil {
|
||||||
|
return *title
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}(),
|
||||||
|
Description: pgtype.Text{String: *description},
|
||||||
|
Thumbnail: pgtype.Text{String: *thumbnail},
|
||||||
|
DisplayOrder: func() int32 {
|
||||||
|
if displayOrder != nil {
|
||||||
|
return *displayOrder
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}(),
|
||||||
|
IsActive: func() bool {
|
||||||
|
if isActive != nil {
|
||||||
|
return *isActive
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}(),
|
||||||
|
ID: id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateProgramFull(
|
||||||
|
ctx context.Context,
|
||||||
|
program domain.Program,
|
||||||
|
) (domain.Program, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.UpdateProgramFull(ctx, dbgen.UpdateProgramFullParams{
|
||||||
|
ID: program.ID,
|
||||||
|
CourseID: program.CourseID,
|
||||||
|
Title: program.Title,
|
||||||
|
Description: pgtype.Text{String: *program.Description},
|
||||||
|
Thumbnail: pgtype.Text{String: *program.Thumbnail},
|
||||||
|
DisplayOrder: program.DisplayOrder,
|
||||||
|
IsActive: program.IsActive,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.Program{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Program{
|
||||||
|
ID: row.ID,
|
||||||
|
CourseID: row.CourseID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
Thumbnail: &row.Thumbnail.String,
|
||||||
|
DisplayOrder: row.DisplayOrder,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeactivateProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.DeactivateProgram(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) (domain.Program, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.DeleteProgram(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Program{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Program{
|
||||||
|
ID: row.ID,
|
||||||
|
CourseID: row.CourseID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
Thumbnail: &row.Thumbnail.String,
|
||||||
|
DisplayOrder: row.DisplayOrder,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
132
internal/repository/courses.go
Normal file
132
internal/repository/courses.go
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) CreateCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
categoryID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
) (domain.Course, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.CreateCourse(ctx, dbgen.CreateCourseParams{
|
||||||
|
CategoryID: categoryID,
|
||||||
|
Title: title,
|
||||||
|
Description: pgtype.Text{String: *description},
|
||||||
|
Column4: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.Course{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Course{
|
||||||
|
ID: row.ID,
|
||||||
|
CategoryID: row.CategoryID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetCourseByID(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) (domain.Course, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.GetCourseByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Course{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Course{
|
||||||
|
ID: row.ID,
|
||||||
|
CategoryID: row.CategoryID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetCoursesByCategory(
|
||||||
|
ctx context.Context,
|
||||||
|
categoryID int64,
|
||||||
|
limit int32,
|
||||||
|
offset int32,
|
||||||
|
) ([]domain.Course, int64, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.GetCoursesByCategory(ctx, dbgen.GetCoursesByCategoryParams{
|
||||||
|
CategoryID: categoryID,
|
||||||
|
Limit: pgtype.Int4{Int32: limit},
|
||||||
|
Offset: pgtype.Int4{Int32: offset},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
courses []domain.Course
|
||||||
|
totalCount int64
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, row := range rows {
|
||||||
|
if i == 0 {
|
||||||
|
totalCount = row.TotalCount
|
||||||
|
}
|
||||||
|
|
||||||
|
courses = append(courses, domain.Course{
|
||||||
|
ID: row.ID,
|
||||||
|
CategoryID: row.CategoryID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return courses, totalCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
var (
|
||||||
|
titleVal string
|
||||||
|
descriptionVal string
|
||||||
|
isActiveVal bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if title != nil {
|
||||||
|
titleVal = *title
|
||||||
|
}
|
||||||
|
if description != nil {
|
||||||
|
descriptionVal = *description
|
||||||
|
}
|
||||||
|
if isActive != nil {
|
||||||
|
isActiveVal = *isActive
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.queries.UpdateCourse(ctx, dbgen.UpdateCourseParams{
|
||||||
|
Title: titleVal,
|
||||||
|
Description: pgtype.Text{String: descriptionVal},
|
||||||
|
IsActive: isActiveVal,
|
||||||
|
ID: id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.DeleteCourse(ctx, id)
|
||||||
|
}
|
||||||
90
internal/repository/learning_tree.go
Normal file
90
internal/repository/learning_tree.go
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) GetFullLearningTree(ctx context.Context) ([]domain.TreeCourse, error) {
|
||||||
|
rows, err := s.queries.GetFullLearningTree(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
coursesMap := make(map[int64]*domain.TreeCourse)
|
||||||
|
programsMap := make(map[int64]*domain.TreeProgram)
|
||||||
|
levelsMap := make(map[int64]*domain.TreeLevel)
|
||||||
|
|
||||||
|
for _, row := range rows {
|
||||||
|
// COURSE
|
||||||
|
course, ok := coursesMap[row.CourseID]
|
||||||
|
if !ok {
|
||||||
|
course = &domain.TreeCourse{
|
||||||
|
ID: row.CourseID,
|
||||||
|
Title: row.CourseTitle,
|
||||||
|
Programs: []domain.TreeProgram{},
|
||||||
|
}
|
||||||
|
coursesMap[row.CourseID] = course
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROGRAM
|
||||||
|
program, ok := programsMap[row.ProgramID]
|
||||||
|
if !ok {
|
||||||
|
program = &domain.TreeProgram{
|
||||||
|
ID: row.ProgramID,
|
||||||
|
Title: row.ProgramTitle,
|
||||||
|
Levels: []domain.TreeLevel{},
|
||||||
|
}
|
||||||
|
programsMap[row.ProgramID] = program
|
||||||
|
course.Programs = append(course.Programs, *program)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LEVEL
|
||||||
|
level, ok := levelsMap[row.LevelID]
|
||||||
|
if !ok {
|
||||||
|
level = &domain.TreeLevel{
|
||||||
|
ID: row.LevelID,
|
||||||
|
Title: row.LevelTitle,
|
||||||
|
Modules: []domain.TreeModule{},
|
||||||
|
}
|
||||||
|
levelsMap[row.LevelID] = level
|
||||||
|
|
||||||
|
// Append level to its program
|
||||||
|
for i := range course.Programs {
|
||||||
|
if course.Programs[i].ID == row.ProgramID {
|
||||||
|
course.Programs[i].Levels = append(course.Programs[i].Levels, *level)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE (may be nil)
|
||||||
|
if row.ModuleID.Valid {
|
||||||
|
module := domain.TreeModule{
|
||||||
|
ID: row.ModuleID.Int64,
|
||||||
|
Title: row.ModuleTitle.String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append module to its level
|
||||||
|
for i := range course.Programs {
|
||||||
|
if course.Programs[i].ID == row.ProgramID {
|
||||||
|
for j := range course.Programs[i].Levels {
|
||||||
|
if course.Programs[i].Levels[j].ID == row.LevelID {
|
||||||
|
course.Programs[i].Levels[j].Modules = append(course.Programs[i].Levels[j].Modules, module)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten map to slice
|
||||||
|
courses := make([]domain.TreeCourse, 0, len(coursesMap))
|
||||||
|
for _, course := range coursesMap {
|
||||||
|
courses = append(courses, *course)
|
||||||
|
}
|
||||||
|
|
||||||
|
return courses, nil
|
||||||
|
}
|
||||||
112
internal/repository/level_modules.go
Normal file
112
internal/repository/level_modules.go
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) CreateModule(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
title string,
|
||||||
|
content *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
) (domain.Module, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.CreateModule(ctx, dbgen.CreateModuleParams{
|
||||||
|
LevelID: levelID,
|
||||||
|
Title: title,
|
||||||
|
Content: pgtype.Text{String: *content},
|
||||||
|
Column4: displayOrder,
|
||||||
|
Column5: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.Module{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Module{
|
||||||
|
ID: row.ID,
|
||||||
|
LevelID: row.LevelID,
|
||||||
|
Title: row.Title,
|
||||||
|
Content: &row.Content.String,
|
||||||
|
DisplayOrder: row.DisplayOrder,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetModulesByLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) ([]domain.Module, int64, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.GetModulesByLevel(ctx, levelID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modules []domain.Module
|
||||||
|
totalCount int64
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, row := range rows {
|
||||||
|
if i == 0 {
|
||||||
|
totalCount = row.TotalCount
|
||||||
|
}
|
||||||
|
|
||||||
|
modules = append(modules, domain.Module{
|
||||||
|
ID: row.ID,
|
||||||
|
LevelID: row.LevelID,
|
||||||
|
Title: row.Title,
|
||||||
|
Content: &row.Content.String,
|
||||||
|
DisplayOrder: row.DisplayOrder,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return modules, totalCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateModule(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
content *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
titleVal := ""
|
||||||
|
if title != nil {
|
||||||
|
titleVal = *title
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayOrderVal int32
|
||||||
|
if displayOrder != nil {
|
||||||
|
displayOrderVal = *displayOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
var isActiveVal bool
|
||||||
|
if isActive != nil {
|
||||||
|
isActiveVal = *isActive
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.queries.UpdateModule(ctx, dbgen.UpdateModuleParams{
|
||||||
|
Title: titleVal,
|
||||||
|
Content: pgtype.Text{String: *content},
|
||||||
|
DisplayOrder: displayOrderVal,
|
||||||
|
IsActive: isActiveVal,
|
||||||
|
ID: id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteModule(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.DeleteModule(ctx, id)
|
||||||
|
}
|
||||||
161
internal/repository/module_videos.go
Normal file
161
internal/repository/module_videos.go
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) CreateModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
moduleID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
videoURL string,
|
||||||
|
duration int32,
|
||||||
|
resolution *string,
|
||||||
|
instructorID *string,
|
||||||
|
thumbnail *string,
|
||||||
|
visibility *string,
|
||||||
|
) (domain.ModuleVideo, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.CreateModuleVideo(ctx, dbgen.CreateModuleVideoParams{
|
||||||
|
ModuleID: moduleID,
|
||||||
|
Title: title,
|
||||||
|
Description: pgtype.Text{String: *description},
|
||||||
|
VideoUrl: videoURL,
|
||||||
|
Duration: duration,
|
||||||
|
Resolution: pgtype.Text{String: *resolution},
|
||||||
|
InstructorID: pgtype.Text{String: *instructorID},
|
||||||
|
Thumbnail: pgtype.Text{String: *thumbnail},
|
||||||
|
Visibility: pgtype.Text{String: *visibility},
|
||||||
|
Column10: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.ModuleVideo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var publishDate *time.Time
|
||||||
|
if row.PublishDate.Valid {
|
||||||
|
publishDate = &row.PublishDate.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.ModuleVideo{
|
||||||
|
ID: row.ID,
|
||||||
|
ModuleID: row.ModuleID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
VideoURL: row.VideoUrl,
|
||||||
|
Duration: row.Duration,
|
||||||
|
Resolution: &row.Resolution.String,
|
||||||
|
InstructorID: &row.InstructorID.String,
|
||||||
|
Thumbnail: &row.Thumbnail.String,
|
||||||
|
Visibility: &row.Visibility.String,
|
||||||
|
IsPublished: row.IsPublished,
|
||||||
|
PublishDate: publishDate,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) PublishModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
videoID int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.PublishModuleVideo(ctx, videoID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetPublishedVideosByModule(
|
||||||
|
ctx context.Context,
|
||||||
|
moduleID int64,
|
||||||
|
) ([]domain.ModuleVideo, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.GetPublishedVideosByModule(ctx, moduleID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
videos := make([]domain.ModuleVideo, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
|
||||||
|
var publishDate *time.Time
|
||||||
|
if row.PublishDate.Valid {
|
||||||
|
publishDate = &row.PublishDate.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
videos = append(videos, domain.ModuleVideo{
|
||||||
|
ID: row.ID,
|
||||||
|
ModuleID: row.ModuleID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
VideoURL: row.VideoUrl,
|
||||||
|
Duration: row.Duration,
|
||||||
|
Resolution: &row.Resolution.String,
|
||||||
|
InstructorID: &row.InstructorID.String,
|
||||||
|
Thumbnail: &row.Thumbnail.String,
|
||||||
|
Visibility: &row.Visibility.String,
|
||||||
|
IsPublished: row.IsPublished,
|
||||||
|
PublishDate: publishDate,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return videos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
videoURL *string,
|
||||||
|
duration *int32,
|
||||||
|
resolution *string,
|
||||||
|
visibility *string,
|
||||||
|
thumbnail *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.UpdateModuleVideo(ctx, dbgen.UpdateModuleVideoParams{
|
||||||
|
Title: func() string {
|
||||||
|
if title != nil {
|
||||||
|
return *title
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}(),
|
||||||
|
Description: pgtype.Text{String: *description},
|
||||||
|
VideoUrl: func() string {
|
||||||
|
if videoURL != nil {
|
||||||
|
return *videoURL
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}(),
|
||||||
|
Duration: func() int32 {
|
||||||
|
if duration != nil {
|
||||||
|
return *duration
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}(),
|
||||||
|
Resolution: pgtype.Text{String: *resolution},
|
||||||
|
Visibility: pgtype.Text{String: *visibility},
|
||||||
|
Thumbnail: pgtype.Text{String: *thumbnail},
|
||||||
|
IsActive: func() bool {
|
||||||
|
if isActive != nil {
|
||||||
|
return *isActive
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}(),
|
||||||
|
ID: id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.DeleteModuleVideo(ctx, id)
|
||||||
|
}
|
||||||
108
internal/repository/practice_questions.go
Normal file
108
internal/repository/practice_questions.go
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) CreatePracticeQuestion(
|
||||||
|
ctx context.Context,
|
||||||
|
practiceID int64,
|
||||||
|
question string,
|
||||||
|
questionVoicePrompt *string,
|
||||||
|
sampleAnswerVoicePrompt *string,
|
||||||
|
sampleAnswer *string,
|
||||||
|
tips *string,
|
||||||
|
qType string,
|
||||||
|
) (domain.PracticeQuestion, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.CreatePracticeQuestion(ctx, dbgen.CreatePracticeQuestionParams{
|
||||||
|
PracticeID: practiceID,
|
||||||
|
Question: question,
|
||||||
|
QuestionVoicePrompt: pgtype.Text{String: *questionVoicePrompt},
|
||||||
|
SampleAnswerVoicePrompt: pgtype.Text{String: *sampleAnswerVoicePrompt},
|
||||||
|
SampleAnswer: pgtype.Text{String: *sampleAnswer},
|
||||||
|
Tips: pgtype.Text{String: *tips},
|
||||||
|
Type: qType,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.PracticeQuestion{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.PracticeQuestion{
|
||||||
|
ID: row.ID,
|
||||||
|
PracticeID: row.PracticeID,
|
||||||
|
Question: row.Question,
|
||||||
|
QuestionVoicePrompt: &row.QuestionVoicePrompt.String,
|
||||||
|
SampleAnswerVoicePrompt: &row.SampleAnswerVoicePrompt.String,
|
||||||
|
SampleAnswer: &row.SampleAnswer.String,
|
||||||
|
Tips: &row.Tips.String,
|
||||||
|
Type: row.Type,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetQuestionsByPractice(
|
||||||
|
ctx context.Context,
|
||||||
|
practiceID int64,
|
||||||
|
) ([]domain.PracticeQuestion, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.GetQuestionsByPractice(ctx, practiceID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
questions := make([]domain.PracticeQuestion, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
questions = append(questions, domain.PracticeQuestion{
|
||||||
|
ID: row.ID,
|
||||||
|
PracticeID: row.PracticeID,
|
||||||
|
Question: row.Question,
|
||||||
|
QuestionVoicePrompt: &row.QuestionVoicePrompt.String,
|
||||||
|
SampleAnswerVoicePrompt: &row.SampleAnswerVoicePrompt.String,
|
||||||
|
SampleAnswer: &row.SampleAnswer.String,
|
||||||
|
Tips: &row.Tips.String,
|
||||||
|
Type: row.Type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return questions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdatePracticeQuestion(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
question *string,
|
||||||
|
sampleAnswer *string,
|
||||||
|
tips *string,
|
||||||
|
qType *string,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.UpdatePracticeQuestion(ctx, dbgen.UpdatePracticeQuestionParams{
|
||||||
|
Question: func() string {
|
||||||
|
if question != nil {
|
||||||
|
return *question
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}(),
|
||||||
|
SampleAnswer: pgtype.Text{String: *sampleAnswer},
|
||||||
|
Tips: pgtype.Text{String: *tips},
|
||||||
|
Type: func() string {
|
||||||
|
if qType != nil {
|
||||||
|
return *qType
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}(),
|
||||||
|
ID: id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeletePracticeQuestion(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.DeletePracticeQuestion(ctx, id)
|
||||||
|
}
|
||||||
114
internal/repository/practices.go
Normal file
114
internal/repository/practices.go
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) CreatePractice(
|
||||||
|
ctx context.Context,
|
||||||
|
ownerType string,
|
||||||
|
ownerID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
bannerImage *string,
|
||||||
|
persona *string,
|
||||||
|
isActive *bool,
|
||||||
|
) (domain.Practice, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.CreatePractice(ctx, dbgen.CreatePracticeParams{
|
||||||
|
OwnerType: ownerType,
|
||||||
|
OwnerID: ownerID,
|
||||||
|
Title: title,
|
||||||
|
Description: pgtype.Text{String: *description},
|
||||||
|
BannerImage: pgtype.Text{String: *bannerImage},
|
||||||
|
Persona: pgtype.Text{String: *persona},
|
||||||
|
Column7: isActive,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.Practice{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Practice{
|
||||||
|
ID: row.ID,
|
||||||
|
OwnerType: row.OwnerType,
|
||||||
|
OwnerID: row.OwnerID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
BannerImage: &row.BannerImage.String,
|
||||||
|
Persona: &row.Persona.String,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetPracticesByOwner(
|
||||||
|
ctx context.Context,
|
||||||
|
ownerType string,
|
||||||
|
ownerID int64,
|
||||||
|
) ([]domain.Practice, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.GetPracticesByOwner(ctx, dbgen.GetPracticesByOwnerParams{
|
||||||
|
OwnerType: ownerType,
|
||||||
|
OwnerID: ownerID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
practices := make([]domain.Practice, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
practices = append(practices, domain.Practice{
|
||||||
|
ID: row.ID,
|
||||||
|
OwnerType: row.OwnerType,
|
||||||
|
OwnerID: row.OwnerID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
BannerImage: &row.BannerImage.String,
|
||||||
|
Persona: &row.Persona.String,
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return practices, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdatePractice(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
bannerImage *string,
|
||||||
|
persona *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.UpdatePractice(ctx, dbgen.UpdatePracticeParams{
|
||||||
|
Title: func() string {
|
||||||
|
if title != nil {
|
||||||
|
return *title
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}(),
|
||||||
|
Description: pgtype.Text{String: *description},
|
||||||
|
BannerImage: pgtype.Text{String: *bannerImage},
|
||||||
|
Persona: pgtype.Text{String: *persona},
|
||||||
|
IsActive: func() bool {
|
||||||
|
if isActive != nil {
|
||||||
|
return *isActive
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}(),
|
||||||
|
ID: id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeletePractice(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.DeletePractice(ctx, id)
|
||||||
|
}
|
||||||
125
internal/repository/program_levels.go
Normal file
125
internal/repository/program_levels.go
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) CreateLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
programID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
levelIndex int,
|
||||||
|
isActive *bool,
|
||||||
|
) (domain.Level, error) {
|
||||||
|
|
||||||
|
row, err := s.queries.CreateLevel(ctx, dbgen.CreateLevelParams{
|
||||||
|
ProgramID: programID,
|
||||||
|
Title: title,
|
||||||
|
Description: pgtype.Text{String: *description},
|
||||||
|
LevelIndex: int32(levelIndex),
|
||||||
|
Column5: isActive,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.Level{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Level{
|
||||||
|
ID: row.ID,
|
||||||
|
ProgramID: row.ProgramID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
LevelIndex: int(row.LevelIndex),
|
||||||
|
NumberOfModules: int(row.NumberOfModules),
|
||||||
|
NumberOfPractices: int(row.NumberOfPractices),
|
||||||
|
NumberOfVideos: int(row.NumberOfVideos),
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetLevelsByProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
programID int64,
|
||||||
|
) ([]domain.Level, error) {
|
||||||
|
|
||||||
|
rows, err := s.queries.GetLevelsByProgram(ctx, programID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
levels := make([]domain.Level, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
levels = append(levels, domain.Level{
|
||||||
|
ID: row.ID,
|
||||||
|
ProgramID: row.ProgramID,
|
||||||
|
Title: row.Title,
|
||||||
|
Description: &row.Description.String,
|
||||||
|
LevelIndex: int(row.LevelIndex),
|
||||||
|
NumberOfModules: int(row.NumberOfModules),
|
||||||
|
NumberOfPractices: int(row.NumberOfPractices),
|
||||||
|
NumberOfVideos: int(row.NumberOfVideos),
|
||||||
|
IsActive: row.IsActive,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return levels, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
levelIndex *int,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.UpdateLevel(ctx, dbgen.UpdateLevelParams{
|
||||||
|
Title: func() string {
|
||||||
|
if title != nil {
|
||||||
|
return *title
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}(),
|
||||||
|
Description: pgtype.Text{String: *description},
|
||||||
|
LevelIndex: int32(*levelIndex),
|
||||||
|
IsActive: *isActive,
|
||||||
|
ID: id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) IncrementLevelModuleCount(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.IncrementLevelModuleCount(ctx, levelID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) IncrementLevelPracticeCount(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.IncrementLevelPracticeCount(ctx, levelID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) IncrementLevelVideoCount(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.IncrementLevelVideoCount(ctx, levelID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DeleteLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
return s.queries.DeleteLevel(ctx, levelID)
|
||||||
|
}
|
||||||
44
internal/services/course_management/course_catagories.go
Normal file
44
internal/services/course_management/course_catagories.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package course_management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreateCourseCategory(
|
||||||
|
ctx context.Context,
|
||||||
|
name string,
|
||||||
|
) (domain.CourseCategory, error) {
|
||||||
|
return s.courseStore.CreateCourseCategory(ctx, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetCourseCategoryByID(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) (domain.CourseCategory, error) {
|
||||||
|
return s.courseStore.GetCourseCategoryByID(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetAllCourseCategories(
|
||||||
|
ctx context.Context,
|
||||||
|
limit int32,
|
||||||
|
offset int32,
|
||||||
|
) ([]domain.CourseCategory, int64, error) {
|
||||||
|
return s.courseStore.GetAllCourseCategories(ctx, limit, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateCourseCategory(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
name *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.UpdateCourseCategory(ctx, id, name, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteCourseCategory(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.DeleteCourseCategory(ctx, id)
|
||||||
|
}
|
||||||
77
internal/services/course_management/course_programs.go
Normal file
77
internal/services/course_management/course_programs.go
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
package course_management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreateProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
courseID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
thumbnail *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
) (domain.Program, error) {
|
||||||
|
return s.courseStore.CreateProgram(ctx, courseID, title, description, thumbnail, displayOrder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetProgramByID(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) (domain.Program, error) {
|
||||||
|
return s.courseStore.GetProgramByID(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetProgramsByCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
courseID int64,
|
||||||
|
) ([]domain.Program, int64, error) {
|
||||||
|
return s.courseStore.GetProgramsByCourse(ctx, courseID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ListProgramsByCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
courseID int64,
|
||||||
|
) ([]domain.Program, error) {
|
||||||
|
return s.courseStore.ListProgramsByCourse(ctx, courseID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ListActivePrograms(
|
||||||
|
ctx context.Context,
|
||||||
|
) ([]domain.Program, error) {
|
||||||
|
return s.courseStore.ListActivePrograms(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateProgramPartial(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
thumbnail *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.UpdateProgramPartial(ctx, id, title, description, thumbnail, displayOrder, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateProgramFull(
|
||||||
|
ctx context.Context,
|
||||||
|
program domain.Program,
|
||||||
|
) (domain.Program, error) {
|
||||||
|
return s.courseStore.UpdateProgramFull(ctx, program)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeactivateProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.DeactivateProgram(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) (domain.Program, error) {
|
||||||
|
return s.courseStore.DeleteProgram(ctx, id)
|
||||||
|
}
|
||||||
48
internal/services/course_management/courses.go
Normal file
48
internal/services/course_management/courses.go
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
package course_management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreateCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
categoryID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
) (domain.Course, error) {
|
||||||
|
return s.courseStore.CreateCourse(ctx, categoryID, title, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetCourseByID(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) (domain.Course, error) {
|
||||||
|
return s.courseStore.GetCourseByID(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetCoursesByCategory(
|
||||||
|
ctx context.Context,
|
||||||
|
categoryID int64,
|
||||||
|
limit int32,
|
||||||
|
offset int32,
|
||||||
|
) ([]domain.Course, int64, error) {
|
||||||
|
return s.courseStore.GetCoursesByCategory(ctx, categoryID, limit, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.UpdateCourse(ctx, id, title, description, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteCourse(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.DeleteCourse(ctx, id)
|
||||||
|
}
|
||||||
10
internal/services/course_management/learning_tree.go
Normal file
10
internal/services/course_management/learning_tree.go
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
package course_management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) GetFullLearningTree(ctx context.Context) ([]domain.TreeCourse, error) {
|
||||||
|
return s.courseStore.GetFullLearningTree(ctx)
|
||||||
|
}
|
||||||
41
internal/services/course_management/level_modules.go
Normal file
41
internal/services/course_management/level_modules.go
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
package course_management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreateModule(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
title string,
|
||||||
|
content *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
) (domain.Module, error) {
|
||||||
|
return s.courseStore.CreateModule(ctx, levelID, title, content, displayOrder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetModulesByLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) ([]domain.Module, int64, error) {
|
||||||
|
return s.courseStore.GetModulesByLevel(ctx, levelID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateModule(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
content *string,
|
||||||
|
displayOrder *int32,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.UpdateModule(ctx, id, title, content, displayOrder, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteModule(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.DeleteModule(ctx, id)
|
||||||
|
}
|
||||||
57
internal/services/course_management/module_videos.go
Normal file
57
internal/services/course_management/module_videos.go
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
package course_management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreateModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
moduleID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
videoURL string,
|
||||||
|
duration int32,
|
||||||
|
resolution *string,
|
||||||
|
instructorID *string,
|
||||||
|
thumbnail *string,
|
||||||
|
visibility *string,
|
||||||
|
) (domain.ModuleVideo, error) {
|
||||||
|
return s.courseStore.CreateModuleVideo(ctx, moduleID, title, description, videoURL, duration, resolution, instructorID, thumbnail, visibility)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) PublishModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
videoID int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.PublishModuleVideo(ctx, videoID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetPublishedVideosByModule(
|
||||||
|
ctx context.Context,
|
||||||
|
moduleID int64,
|
||||||
|
) ([]domain.ModuleVideo, error) {
|
||||||
|
return s.courseStore.GetPublishedVideosByModule(ctx, moduleID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
videoURL *string,
|
||||||
|
duration *int32,
|
||||||
|
resolution *string,
|
||||||
|
visibility *string,
|
||||||
|
thumbnail *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.UpdateModuleVideo(ctx, id, title, description, videoURL, duration, resolution, visibility, thumbnail, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteModuleVideo(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.DeleteModuleVideo(ctx, id)
|
||||||
|
}
|
||||||
44
internal/services/course_management/practice_questions.go
Normal file
44
internal/services/course_management/practice_questions.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package course_management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreatePracticeQuestion(
|
||||||
|
ctx context.Context,
|
||||||
|
practiceID int64,
|
||||||
|
question string,
|
||||||
|
questionVoicePrompt *string,
|
||||||
|
sampleAnswerVoicePrompt *string,
|
||||||
|
sampleAnswer *string,
|
||||||
|
tips *string,
|
||||||
|
qType string,
|
||||||
|
) (domain.PracticeQuestion, error) {
|
||||||
|
return s.courseStore.CreatePracticeQuestion(ctx, practiceID, question, questionVoicePrompt, sampleAnswerVoicePrompt, sampleAnswer, tips, qType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetQuestionsByPractice(
|
||||||
|
ctx context.Context,
|
||||||
|
practiceID int64,
|
||||||
|
) ([]domain.PracticeQuestion, error) {
|
||||||
|
return s.courseStore.GetQuestionsByPractice(ctx, practiceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdatePracticeQuestion(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
question *string,
|
||||||
|
sampleAnswer *string,
|
||||||
|
tips *string,
|
||||||
|
qType *string,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.UpdatePracticeQuestion(ctx, id, question, sampleAnswer, tips, qType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeletePracticeQuestion(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.DeletePracticeQuestion(ctx, id)
|
||||||
|
}
|
||||||
46
internal/services/course_management/practices.go
Normal file
46
internal/services/course_management/practices.go
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package course_management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreatePractice(
|
||||||
|
ctx context.Context,
|
||||||
|
ownerType string,
|
||||||
|
ownerID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
bannerImage *string,
|
||||||
|
persona *string,
|
||||||
|
isActive *bool,
|
||||||
|
) (domain.Practice, error) {
|
||||||
|
return s.courseStore.CreatePractice(ctx, ownerType, ownerID, title, description, bannerImage, persona, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetPracticesByOwner(
|
||||||
|
ctx context.Context,
|
||||||
|
ownerType string,
|
||||||
|
ownerID int64,
|
||||||
|
) ([]domain.Practice, error) {
|
||||||
|
return s.courseStore.GetPracticesByOwner(ctx, ownerType, ownerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdatePractice(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
bannerImage *string,
|
||||||
|
persona *string,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.UpdatePractice(ctx, id, title, description, bannerImage, persona, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeletePractice(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.DeletePractice(ctx, id)
|
||||||
|
}
|
||||||
63
internal/services/course_management/program_levels.go
Normal file
63
internal/services/course_management/program_levels.go
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package course_management
|
||||||
|
|
||||||
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) CreateLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
programID int64,
|
||||||
|
title string,
|
||||||
|
description *string,
|
||||||
|
levelIndex int,
|
||||||
|
isActive *bool,
|
||||||
|
) (domain.Level, error) {
|
||||||
|
return s.courseStore.CreateLevel(ctx, programID, title, description, levelIndex, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetLevelsByProgram(
|
||||||
|
ctx context.Context,
|
||||||
|
programID int64,
|
||||||
|
) ([]domain.Level, error) {
|
||||||
|
return s.courseStore.GetLevelsByProgram(ctx, programID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
id int64,
|
||||||
|
title *string,
|
||||||
|
description *string,
|
||||||
|
levelIndex *int,
|
||||||
|
isActive *bool,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.UpdateLevel(ctx, id, title, description, levelIndex, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) IncrementLevelModuleCount(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.IncrementLevelModuleCount(ctx, levelID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) IncrementLevelPracticeCount(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.IncrementLevelPracticeCount(ctx, levelID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) IncrementLevelVideoCount(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.IncrementLevelVideoCount(ctx, levelID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteLevel(
|
||||||
|
ctx context.Context,
|
||||||
|
levelID int64,
|
||||||
|
) error {
|
||||||
|
return s.courseStore.DeleteLevel(ctx, levelID)
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
package course_management
|
package course_management
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"Yimaru-Backend/internal/config"
|
"Yimaru-Backend/internal/config"
|
||||||
"Yimaru-Backend/internal/domain"
|
|
||||||
"Yimaru-Backend/internal/ports"
|
"Yimaru-Backend/internal/ports"
|
||||||
notificationservice "Yimaru-Backend/internal/services/notification"
|
notificationservice "Yimaru-Backend/internal/services/notification"
|
||||||
)
|
)
|
||||||
|
|
@ -32,183 +29,3 @@ func NewService(
|
||||||
config: cfg,
|
config: cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Course category methods
|
|
||||||
func (s *Service) CreateCourseCategory(ctx context.Context, name string) (domain.CourseCategory, error) {
|
|
||||||
return s.courseStore.CreateCourseCategory(ctx, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetCourseCategoryByID(ctx context.Context, id int64) (domain.CourseCategory, error) {
|
|
||||||
return s.courseStore.GetCourseCategoryByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListActiveCourseCategories(ctx context.Context) ([]domain.CourseCategory, error) {
|
|
||||||
return s.courseStore.ListActiveCourseCategories(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateCourseCategory(ctx context.Context, id int64, name string, isActive bool) (domain.CourseCategory, error) {
|
|
||||||
return s.courseStore.UpdateCourseCategory(ctx, id, name, isActive)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) DeactivateCourseCategory(ctx context.Context, id int64) error {
|
|
||||||
return s.courseStore.DeactivateCourseCategory(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Courses
|
|
||||||
func (s *Service) CreateCourse(ctx context.Context, c domain.Course) (domain.Course, error) {
|
|
||||||
return s.courseStore.CreateCourse(ctx, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetCourseByID(ctx context.Context, id int64) (domain.Course, error) {
|
|
||||||
return s.courseStore.GetCourseByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListCoursesByCategory(ctx context.Context, categoryID int64) ([]domain.Course, error) {
|
|
||||||
return s.courseStore.ListCoursesByCategory(ctx, categoryID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListActiveCourses(ctx context.Context) ([]domain.Course, error) {
|
|
||||||
return s.courseStore.ListActiveCourses(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateCourse(ctx context.Context, c domain.Course) (domain.Course, error) {
|
|
||||||
return s.courseStore.UpdateCourse(ctx, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) DeactivateCourse(ctx context.Context, id int64) error {
|
|
||||||
return s.courseStore.DeactivateCourse(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Programs
|
|
||||||
func (s *Service) CreateProgram(ctx context.Context, p domain.Program) (domain.Program, error) {
|
|
||||||
return s.courseStore.CreateProgram(ctx, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetProgramByID(ctx context.Context, id int64) (domain.Program, error) {
|
|
||||||
return s.courseStore.GetProgramByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListProgramsByCourse(ctx context.Context, courseID int64) ([]domain.Program, error) {
|
|
||||||
return s.courseStore.ListProgramsByCourse(ctx, courseID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListActivePrograms(ctx context.Context) ([]domain.Program, error) {
|
|
||||||
return s.courseStore.ListActivePrograms(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateProgram(ctx context.Context, p domain.Program) (domain.Program, error) {
|
|
||||||
return s.courseStore.UpdateProgram(ctx, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) DeactivateProgram(ctx context.Context, id int64) error {
|
|
||||||
return s.courseStore.DeactivateProgram(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modules
|
|
||||||
func (s *Service) CreateModule(ctx context.Context, m domain.Module) (domain.Module, error) {
|
|
||||||
return s.courseStore.CreateModule(ctx, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetModuleByID(ctx context.Context, id int64) (domain.Module, error) {
|
|
||||||
return s.courseStore.GetModuleByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListModulesByLevel(ctx context.Context, levelID int64) ([]domain.Module, error) {
|
|
||||||
return s.courseStore.ListModulesByLevel(ctx, levelID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateModule(ctx context.Context, m domain.Module) (domain.Module, error) {
|
|
||||||
return s.courseStore.UpdateModule(ctx, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) DeactivateModule(ctx context.Context, id int64) error {
|
|
||||||
return s.courseStore.DeactivateModule(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module videos
|
|
||||||
func (s *Service) CreateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error) {
|
|
||||||
return s.courseStore.CreateModuleVideo(ctx, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetModuleVideoByID(ctx context.Context, id int64) (domain.ModuleVideo, error) {
|
|
||||||
return s.courseStore.GetModuleVideoByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListAllVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error) {
|
|
||||||
return s.courseStore.ListAllVideosByModule(ctx, moduleID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListPublishedVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error) {
|
|
||||||
return s.courseStore.ListPublishedVideosByModule(ctx, moduleID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error) {
|
|
||||||
return s.courseStore.UpdateModuleVideo(ctx, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) DeactivateModuleVideo(ctx context.Context, id int64) error {
|
|
||||||
return s.courseStore.DeactivateModuleVideo(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Practices
|
|
||||||
func (s *Service) CreatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error) {
|
|
||||||
return s.courseStore.CreatePractice(ctx, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetPracticeByID(ctx context.Context, id int64) (domain.Practice, error) {
|
|
||||||
return s.courseStore.GetPracticeByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListPracticesByOwner(ctx context.Context, ownerType string, ownerID int64) ([]domain.Practice, error) {
|
|
||||||
return s.courseStore.ListPracticesByOwner(ctx, ownerType, ownerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error) {
|
|
||||||
return s.courseStore.UpdatePractice(ctx, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) DeactivatePractice(ctx context.Context, id int64) error {
|
|
||||||
return s.courseStore.DeactivatePractice(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Practice questions
|
|
||||||
func (s *Service) CreatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error) {
|
|
||||||
return s.courseStore.CreatePracticeQuestion(ctx, qn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetPracticeQuestionByID(ctx context.Context, id int64) (domain.PracticeQuestion, error) {
|
|
||||||
return s.courseStore.GetPracticeQuestionByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListPracticeQuestions(ctx context.Context, practiceID int64) ([]domain.PracticeQuestion, error) {
|
|
||||||
return s.courseStore.ListPracticeQuestions(ctx, practiceID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error) {
|
|
||||||
return s.courseStore.UpdatePracticeQuestion(ctx, qn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) DeletePracticeQuestion(ctx context.Context, id int64) error {
|
|
||||||
return s.courseStore.DeletePracticeQuestion(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Levels
|
|
||||||
func (s *Service) CreateLevel(ctx context.Context, l domain.Level) (domain.Level, error) {
|
|
||||||
return s.courseStore.CreateLevel(ctx, l)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetLevelByID(ctx context.Context, id int64) (domain.Level, error) {
|
|
||||||
return s.courseStore.GetLevelByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ListLevelsByProgram(ctx context.Context, programID int64) ([]domain.Level, error) {
|
|
||||||
return s.courseStore.ListLevelsByProgram(ctx, programID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateLevel(ctx context.Context, l domain.Level) (domain.Level, error) {
|
|
||||||
return s.courseStore.UpdateLevel(ctx, l)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) DeactivateLevel(ctx context.Context, id int64) error {
|
|
||||||
return s.courseStore.DeactivateLevel(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -125,31 +125,68 @@ func (a *App) initAppRoutes() {
|
||||||
// )
|
// )
|
||||||
|
|
||||||
// Course Management Routes
|
// Course Management Routes
|
||||||
groupV1.Post("/course-categories", h.CreateCourseCategory)
|
|
||||||
groupV1.Get("/course-categories", h.ListActiveCourseCategories)
|
|
||||||
groupV1.Get("/course-categories/:id", h.GetCourseCategoryByID)
|
|
||||||
groupV1.Put("/course-categories/:id", h.UpdateCourseCategory)
|
|
||||||
groupV1.Post("/course-categories/:id/deactivate", h.DeactivateCourseCategory)
|
|
||||||
|
|
||||||
groupV1.Post("/courses", h.CreateCourse)
|
// Course Categories
|
||||||
groupV1.Get("/courses", h.ListActiveCourses)
|
groupV1.Post("/course-management/categories", a.authMiddleware, h.CreateCourseCategory)
|
||||||
groupV1.Get("/courses/:id", h.GetCourseByID)
|
groupV1.Get("/course-management/categories", a.authMiddleware, h.GetAllCourseCategories)
|
||||||
groupV1.Put("/courses/:id", h.UpdateCourse)
|
groupV1.Get("/course-management/categories/:id", a.authMiddleware, h.GetCourseCategoryByID)
|
||||||
groupV1.Post("/courses/:id/deactivate", h.DeactivateCourse)
|
groupV1.Put("/course-management/categories/:id", a.authMiddleware, h.UpdateCourseCategory)
|
||||||
groupV1.Get("/course-categories/:category_id/courses", h.ListCoursesByCategory)
|
groupV1.Delete("/course-management/categories/:id", a.authMiddleware, h.DeleteCourseCategory)
|
||||||
|
|
||||||
groupV1.Post("/courses/:course_id/programs", h.CreateProgram)
|
// Courses
|
||||||
groupV1.Get("/courses/:course_id/programs", h.ListProgramsByCourse)
|
groupV1.Post("/course-management/courses", a.authMiddleware, h.CreateCourse)
|
||||||
|
groupV1.Get("/course-management/courses/:id", a.authMiddleware, h.GetCourseByID)
|
||||||
|
groupV1.Get("/course-management/categories/:categoryId/courses", a.authMiddleware, h.GetCoursesByCategory)
|
||||||
|
groupV1.Put("/course-management/courses/:id", a.authMiddleware, h.UpdateCourse)
|
||||||
|
groupV1.Delete("/course-management/courses/:id", a.authMiddleware, h.DeleteCourse)
|
||||||
|
|
||||||
groupV1.Post("/modules", h.CreateModule)
|
// Programs
|
||||||
groupV1.Get("/levels/:level_id/modules", h.ListModulesByLevel)
|
groupV1.Post("/course-management/programs", a.authMiddleware, h.CreateProgram)
|
||||||
|
groupV1.Get("/course-management/programs/:id", a.authMiddleware, h.GetProgramByID)
|
||||||
|
groupV1.Get("/course-management/courses/:courseId/programs", a.authMiddleware, h.GetProgramsByCourse)
|
||||||
|
groupV1.Get("/course-management/courses/:courseId/programs/list", a.authMiddleware, h.ListProgramsByCourse)
|
||||||
|
groupV1.Get("/course-management/programs/active", a.authMiddleware, h.ListActivePrograms)
|
||||||
|
groupV1.Patch("/course-management/programs/:id", a.authMiddleware, h.UpdateProgramPartial)
|
||||||
|
groupV1.Put("/course-management/programs/:id/full", a.authMiddleware, h.UpdateProgramFull)
|
||||||
|
groupV1.Put("/course-management/programs/:id/deactivate", a.authMiddleware, h.DeactivateProgram)
|
||||||
|
groupV1.Delete("/course-management/programs/:id", a.authMiddleware, h.DeleteProgram)
|
||||||
|
|
||||||
groupV1.Post("/module-videos", h.CreateModuleVideo)
|
// Levels
|
||||||
|
groupV1.Post("/course-management/levels", a.authMiddleware, h.CreateLevel)
|
||||||
|
groupV1.Get("/course-management/programs/:programId/levels", a.authMiddleware, h.GetLevelsByProgram)
|
||||||
|
groupV1.Put("/course-management/levels/:id", a.authMiddleware, h.UpdateLevel)
|
||||||
|
groupV1.Put("/course-management/levels/:levelId/increment-module", a.authMiddleware, h.IncrementLevelModuleCount)
|
||||||
|
groupV1.Put("/course-management/levels/:levelId/increment-practice", a.authMiddleware, h.IncrementLevelPracticeCount)
|
||||||
|
groupV1.Put("/course-management/levels/:levelId/increment-video", a.authMiddleware, h.IncrementLevelVideoCount)
|
||||||
|
groupV1.Delete("/course-management/levels/:levelId", a.authMiddleware, h.DeleteLevel)
|
||||||
|
|
||||||
groupV1.Post("/practices", h.CreatePractice)
|
// Modules
|
||||||
groupV1.Post("/practice-questions", h.CreatePracticeQuestion)
|
groupV1.Post("/course-management/modules", a.authMiddleware, h.CreateModule)
|
||||||
|
groupV1.Get("/course-management/levels/:levelId/modules", a.authMiddleware, h.GetModulesByLevel)
|
||||||
|
groupV1.Put("/course-management/modules/:id", a.authMiddleware, h.UpdateModule)
|
||||||
|
groupV1.Delete("/course-management/modules/:id", a.authMiddleware, h.DeleteModule)
|
||||||
|
|
||||||
groupV1.Post("/levels", h.CreateLevel)
|
// Module Videos
|
||||||
|
groupV1.Post("/course-management/videos", a.authMiddleware, h.CreateModuleVideo)
|
||||||
|
groupV1.Put("/course-management/videos/:videoId/publish", a.authMiddleware, h.PublishModuleVideo)
|
||||||
|
groupV1.Get("/course-management/modules/:moduleId/videos/published", a.authMiddleware, h.GetPublishedVideosByModule)
|
||||||
|
groupV1.Put("/course-management/videos/:id", a.authMiddleware, h.UpdateModuleVideo)
|
||||||
|
groupV1.Delete("/course-management/videos/:id", a.authMiddleware, h.DeleteModuleVideo)
|
||||||
|
|
||||||
|
// Practices
|
||||||
|
groupV1.Post("/course-management/practices", a.authMiddleware, h.CreatePractice)
|
||||||
|
groupV1.Get("/course-management/owners/:ownerType/:ownerId/practices", a.authMiddleware, h.GetPracticesByOwner)
|
||||||
|
groupV1.Put("/course-management/practices/:id", a.authMiddleware, h.UpdatePractice)
|
||||||
|
groupV1.Delete("/course-management/practices/:id", a.authMiddleware, h.DeletePractice)
|
||||||
|
|
||||||
|
// Practice Questions
|
||||||
|
groupV1.Post("/course-management/questions", a.authMiddleware, h.CreatePracticeQuestion)
|
||||||
|
groupV1.Get("/course-management/practices/:practiceId/questions", a.authMiddleware, h.GetQuestionsByPractice)
|
||||||
|
groupV1.Put("/course-management/questions/:id", a.authMiddleware, h.UpdatePracticeQuestion)
|
||||||
|
groupV1.Delete("/course-management/questions/:id", a.authMiddleware, h.DeletePracticeQuestion)
|
||||||
|
|
||||||
|
// Learning Tree
|
||||||
|
groupV1.Get("/course-management/learning-tree", a.authMiddleware, h.GetFullLearningTree)
|
||||||
|
|
||||||
// Auth Routes
|
// Auth Routes
|
||||||
groupV1.Post("/auth/google/android", h.GoogleAndroidLogin)
|
groupV1.Post("/auth/google/android", h.GoogleAndroidLogin)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user