seed data clearer API
This commit is contained in:
parent
36134f32a2
commit
05cb8715f9
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE question_sets
|
||||||
|
DROP COLUMN IF EXISTS intro_video_url;
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE question_sets
|
||||||
|
ADD COLUMN intro_video_url TEXT;
|
||||||
|
|
@ -44,7 +44,7 @@ WHERE sub_course_id = $1 AND status = 'PUBLISHED'
|
||||||
ORDER BY display_order, id;
|
ORDER BY display_order, id;
|
||||||
|
|
||||||
-- name: GetSubCoursePracticesForLearningPath :many
|
-- name: GetSubCoursePracticesForLearningPath :many
|
||||||
SELECT id, title, description, persona, status,
|
SELECT id, title, description, persona, status, intro_video_url,
|
||||||
(SELECT COUNT(*) FROM question_set_items WHERE set_id = qs.id) AS question_count
|
(SELECT COUNT(*) FROM question_set_items WHERE set_id = qs.id) AS question_count
|
||||||
FROM question_sets qs
|
FROM question_sets qs
|
||||||
WHERE qs.owner_type = 'SUB_COURSE' AND qs.owner_id = $1
|
WHERE qs.owner_type = 'SUB_COURSE' AND qs.owner_id = $1
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ INSERT INTO question_sets (
|
||||||
passing_score,
|
passing_score,
|
||||||
shuffle_questions,
|
shuffle_questions,
|
||||||
status,
|
status,
|
||||||
sub_course_video_id
|
sub_course_video_id,
|
||||||
|
intro_video_url
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, COALESCE($10, false), COALESCE($11, 'DRAFT'), $12)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, COALESCE($10, false), COALESCE($11, 'DRAFT'), $12, $13)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
-- name: GetQuestionSetByID :one
|
-- name: GetQuestionSetByID :one
|
||||||
|
|
@ -59,9 +60,10 @@ SET
|
||||||
passing_score = COALESCE($6, passing_score),
|
passing_score = COALESCE($6, passing_score),
|
||||||
shuffle_questions = COALESCE($7, shuffle_questions),
|
shuffle_questions = COALESCE($7, shuffle_questions),
|
||||||
status = COALESCE($8, status),
|
status = COALESCE($8, status),
|
||||||
sub_course_video_id = COALESCE($9, sub_course_video_id),
|
intro_video_url = COALESCE($9, intro_video_url),
|
||||||
|
sub_course_video_id = COALESCE($10, sub_course_video_id),
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE id = $10;
|
WHERE id = $11;
|
||||||
|
|
||||||
-- name: ArchiveQuestionSet :exec
|
-- name: ArchiveQuestionSet :exec
|
||||||
UPDATE question_sets
|
UPDATE question_sets
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ func (q *Queries) GetFullLearningTree(ctx context.Context) ([]GetFullLearningTre
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetSubCoursePracticesForLearningPath = `-- name: GetSubCoursePracticesForLearningPath :many
|
const GetSubCoursePracticesForLearningPath = `-- name: GetSubCoursePracticesForLearningPath :many
|
||||||
SELECT id, title, description, persona, status,
|
SELECT id, title, description, persona, status, intro_video_url,
|
||||||
(SELECT COUNT(*) FROM question_set_items WHERE set_id = qs.id) AS question_count
|
(SELECT COUNT(*) FROM question_set_items WHERE set_id = qs.id) AS question_count
|
||||||
FROM question_sets qs
|
FROM question_sets qs
|
||||||
WHERE qs.owner_type = 'SUB_COURSE' AND qs.owner_id = $1
|
WHERE qs.owner_type = 'SUB_COURSE' AND qs.owner_id = $1
|
||||||
|
|
@ -160,6 +160,7 @@ type GetSubCoursePracticesForLearningPathRow struct {
|
||||||
Description pgtype.Text `json:"description"`
|
Description pgtype.Text `json:"description"`
|
||||||
Persona pgtype.Text `json:"persona"`
|
Persona pgtype.Text `json:"persona"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
|
IntroVideoUrl pgtype.Text `json:"intro_video_url"`
|
||||||
QuestionCount int64 `json:"question_count"`
|
QuestionCount int64 `json:"question_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,6 +179,7 @@ func (q *Queries) GetSubCoursePracticesForLearningPath(ctx context.Context, owne
|
||||||
&i.Description,
|
&i.Description,
|
||||||
&i.Persona,
|
&i.Persona,
|
||||||
&i.Status,
|
&i.Status,
|
||||||
|
&i.IntroVideoUrl,
|
||||||
&i.QuestionCount,
|
&i.QuestionCount,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,7 @@ type QuestionSet struct {
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
SubCourseVideoID pgtype.Int8 `json:"sub_course_video_id"`
|
SubCourseVideoID pgtype.Int8 `json:"sub_course_video_id"`
|
||||||
DisplayOrder int32 `json:"display_order"`
|
DisplayOrder int32 `json:"display_order"`
|
||||||
|
IntroVideoUrl pgtype.Text `json:"intro_video_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type QuestionSetItem struct {
|
type QuestionSetItem struct {
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ func (q *Queries) GetQuestionSetItems(ctx context.Context, setID int64) ([]GetQu
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetQuestionSetsContainingQuestion = `-- name: GetQuestionSetsContainingQuestion :many
|
const GetQuestionSetsContainingQuestion = `-- name: GetQuestionSetsContainingQuestion :many
|
||||||
SELECT qs.id, qs.title, qs.description, qs.set_type, qs.owner_type, qs.owner_id, qs.banner_image, qs.persona, qs.time_limit_minutes, qs.passing_score, qs.shuffle_questions, qs.status, qs.created_at, qs.updated_at, qs.sub_course_video_id, qs.display_order
|
SELECT qs.id, qs.title, qs.description, qs.set_type, qs.owner_type, qs.owner_id, qs.banner_image, qs.persona, qs.time_limit_minutes, qs.passing_score, qs.shuffle_questions, qs.status, qs.created_at, qs.updated_at, qs.sub_course_video_id, qs.display_order, qs.intro_video_url
|
||||||
FROM question_sets qs
|
FROM question_sets qs
|
||||||
JOIN question_set_items qsi ON qsi.set_id = qs.id
|
JOIN question_set_items qsi ON qsi.set_id = qs.id
|
||||||
WHERE qsi.question_id = $1
|
WHERE qsi.question_id = $1
|
||||||
|
|
@ -231,6 +231,7 @@ func (q *Queries) GetQuestionSetsContainingQuestion(ctx context.Context, questio
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SubCourseVideoID,
|
&i.SubCourseVideoID,
|
||||||
&i.DisplayOrder,
|
&i.DisplayOrder,
|
||||||
|
&i.IntroVideoUrl,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,11 @@ INSERT INTO question_sets (
|
||||||
passing_score,
|
passing_score,
|
||||||
shuffle_questions,
|
shuffle_questions,
|
||||||
status,
|
status,
|
||||||
sub_course_video_id
|
sub_course_video_id,
|
||||||
|
intro_video_url
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, COALESCE($10, false), COALESCE($11, 'DRAFT'), $12)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, COALESCE($10, false), COALESCE($11, 'DRAFT'), $12, $13)
|
||||||
RETURNING id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order
|
RETURNING id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order, intro_video_url
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateQuestionSetParams struct {
|
type CreateQuestionSetParams struct {
|
||||||
|
|
@ -83,6 +84,7 @@ type CreateQuestionSetParams struct {
|
||||||
Column10 interface{} `json:"column_10"`
|
Column10 interface{} `json:"column_10"`
|
||||||
Column11 interface{} `json:"column_11"`
|
Column11 interface{} `json:"column_11"`
|
||||||
SubCourseVideoID pgtype.Int8 `json:"sub_course_video_id"`
|
SubCourseVideoID pgtype.Int8 `json:"sub_course_video_id"`
|
||||||
|
IntroVideoUrl pgtype.Text `json:"intro_video_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateQuestionSet(ctx context.Context, arg CreateQuestionSetParams) (QuestionSet, error) {
|
func (q *Queries) CreateQuestionSet(ctx context.Context, arg CreateQuestionSetParams) (QuestionSet, error) {
|
||||||
|
|
@ -99,6 +101,7 @@ func (q *Queries) CreateQuestionSet(ctx context.Context, arg CreateQuestionSetPa
|
||||||
arg.Column10,
|
arg.Column10,
|
||||||
arg.Column11,
|
arg.Column11,
|
||||||
arg.SubCourseVideoID,
|
arg.SubCourseVideoID,
|
||||||
|
arg.IntroVideoUrl,
|
||||||
)
|
)
|
||||||
var i QuestionSet
|
var i QuestionSet
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
@ -118,6 +121,7 @@ func (q *Queries) CreateQuestionSet(ctx context.Context, arg CreateQuestionSetPa
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SubCourseVideoID,
|
&i.SubCourseVideoID,
|
||||||
&i.DisplayOrder,
|
&i.DisplayOrder,
|
||||||
|
&i.IntroVideoUrl,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +137,7 @@ func (q *Queries) DeleteQuestionSet(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetInitialAssessmentSet = `-- name: GetInitialAssessmentSet :one
|
const GetInitialAssessmentSet = `-- name: GetInitialAssessmentSet :one
|
||||||
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order
|
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order, intro_video_url
|
||||||
FROM question_sets
|
FROM question_sets
|
||||||
WHERE set_type = 'INITIAL_ASSESSMENT'
|
WHERE set_type = 'INITIAL_ASSESSMENT'
|
||||||
AND status = 'PUBLISHED'
|
AND status = 'PUBLISHED'
|
||||||
|
|
@ -161,12 +165,13 @@ func (q *Queries) GetInitialAssessmentSet(ctx context.Context) (QuestionSet, err
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SubCourseVideoID,
|
&i.SubCourseVideoID,
|
||||||
&i.DisplayOrder,
|
&i.DisplayOrder,
|
||||||
|
&i.IntroVideoUrl,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetPublishedQuestionSetsByOwner = `-- name: GetPublishedQuestionSetsByOwner :many
|
const GetPublishedQuestionSetsByOwner = `-- name: GetPublishedQuestionSetsByOwner :many
|
||||||
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order
|
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order, intro_video_url
|
||||||
FROM question_sets
|
FROM question_sets
|
||||||
WHERE owner_type = $1
|
WHERE owner_type = $1
|
||||||
AND owner_id = $2
|
AND owner_id = $2
|
||||||
|
|
@ -205,6 +210,7 @@ func (q *Queries) GetPublishedQuestionSetsByOwner(ctx context.Context, arg GetPu
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SubCourseVideoID,
|
&i.SubCourseVideoID,
|
||||||
&i.DisplayOrder,
|
&i.DisplayOrder,
|
||||||
|
&i.IntroVideoUrl,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -217,7 +223,7 @@ func (q *Queries) GetPublishedQuestionSetsByOwner(ctx context.Context, arg GetPu
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetQuestionSetByID = `-- name: GetQuestionSetByID :one
|
const GetQuestionSetByID = `-- name: GetQuestionSetByID :one
|
||||||
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order
|
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order, intro_video_url
|
||||||
FROM question_sets
|
FROM question_sets
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -242,12 +248,13 @@ func (q *Queries) GetQuestionSetByID(ctx context.Context, id int64) (QuestionSet
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SubCourseVideoID,
|
&i.SubCourseVideoID,
|
||||||
&i.DisplayOrder,
|
&i.DisplayOrder,
|
||||||
|
&i.IntroVideoUrl,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetQuestionSetsByOwner = `-- name: GetQuestionSetsByOwner :many
|
const GetQuestionSetsByOwner = `-- name: GetQuestionSetsByOwner :many
|
||||||
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order
|
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order, intro_video_url
|
||||||
FROM question_sets
|
FROM question_sets
|
||||||
WHERE owner_type = $1
|
WHERE owner_type = $1
|
||||||
AND owner_id = $2
|
AND owner_id = $2
|
||||||
|
|
@ -286,6 +293,7 @@ func (q *Queries) GetQuestionSetsByOwner(ctx context.Context, arg GetQuestionSet
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SubCourseVideoID,
|
&i.SubCourseVideoID,
|
||||||
&i.DisplayOrder,
|
&i.DisplayOrder,
|
||||||
|
&i.IntroVideoUrl,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +308,7 @@ func (q *Queries) GetQuestionSetsByOwner(ctx context.Context, arg GetQuestionSet
|
||||||
const GetQuestionSetsByType = `-- name: GetQuestionSetsByType :many
|
const GetQuestionSetsByType = `-- name: GetQuestionSetsByType :many
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) OVER () AS total_count,
|
COUNT(*) OVER () AS total_count,
|
||||||
qs.id, qs.title, qs.description, qs.set_type, qs.owner_type, qs.owner_id, qs.banner_image, qs.persona, qs.time_limit_minutes, qs.passing_score, qs.shuffle_questions, qs.status, qs.created_at, qs.updated_at, qs.sub_course_video_id, qs.display_order
|
qs.id, qs.title, qs.description, qs.set_type, qs.owner_type, qs.owner_id, qs.banner_image, qs.persona, qs.time_limit_minutes, qs.passing_score, qs.shuffle_questions, qs.status, qs.created_at, qs.updated_at, qs.sub_course_video_id, qs.display_order, qs.intro_video_url
|
||||||
FROM question_sets qs
|
FROM question_sets qs
|
||||||
WHERE set_type = $1
|
WHERE set_type = $1
|
||||||
AND status != 'ARCHIVED'
|
AND status != 'ARCHIVED'
|
||||||
|
|
@ -333,6 +341,7 @@ type GetQuestionSetsByTypeRow struct {
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
SubCourseVideoID pgtype.Int8 `json:"sub_course_video_id"`
|
SubCourseVideoID pgtype.Int8 `json:"sub_course_video_id"`
|
||||||
DisplayOrder int32 `json:"display_order"`
|
DisplayOrder int32 `json:"display_order"`
|
||||||
|
IntroVideoUrl pgtype.Text `json:"intro_video_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetQuestionSetsByType(ctx context.Context, arg GetQuestionSetsByTypeParams) ([]GetQuestionSetsByTypeRow, error) {
|
func (q *Queries) GetQuestionSetsByType(ctx context.Context, arg GetQuestionSetsByTypeParams) ([]GetQuestionSetsByTypeRow, error) {
|
||||||
|
|
@ -362,6 +371,7 @@ func (q *Queries) GetQuestionSetsByType(ctx context.Context, arg GetQuestionSets
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SubCourseVideoID,
|
&i.SubCourseVideoID,
|
||||||
&i.DisplayOrder,
|
&i.DisplayOrder,
|
||||||
|
&i.IntroVideoUrl,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -374,7 +384,7 @@ func (q *Queries) GetQuestionSetsByType(ctx context.Context, arg GetQuestionSets
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetSubCourseInitialAssessmentSet = `-- name: GetSubCourseInitialAssessmentSet :one
|
const GetSubCourseInitialAssessmentSet = `-- name: GetSubCourseInitialAssessmentSet :one
|
||||||
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order
|
SELECT id, title, description, set_type, owner_type, owner_id, banner_image, persona, time_limit_minutes, passing_score, shuffle_questions, status, created_at, updated_at, sub_course_video_id, display_order, intro_video_url
|
||||||
FROM question_sets
|
FROM question_sets
|
||||||
WHERE set_type = 'INITIAL_ASSESSMENT'
|
WHERE set_type = 'INITIAL_ASSESSMENT'
|
||||||
AND owner_type = 'SUB_COURSE'
|
AND owner_type = 'SUB_COURSE'
|
||||||
|
|
@ -404,6 +414,7 @@ func (q *Queries) GetSubCourseInitialAssessmentSet(ctx context.Context, ownerID
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.SubCourseVideoID,
|
&i.SubCourseVideoID,
|
||||||
&i.DisplayOrder,
|
&i.DisplayOrder,
|
||||||
|
&i.IntroVideoUrl,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -507,9 +518,10 @@ SET
|
||||||
passing_score = COALESCE($6, passing_score),
|
passing_score = COALESCE($6, passing_score),
|
||||||
shuffle_questions = COALESCE($7, shuffle_questions),
|
shuffle_questions = COALESCE($7, shuffle_questions),
|
||||||
status = COALESCE($8, status),
|
status = COALESCE($8, status),
|
||||||
sub_course_video_id = COALESCE($9, sub_course_video_id),
|
intro_video_url = COALESCE($9, intro_video_url),
|
||||||
|
sub_course_video_id = COALESCE($10, sub_course_video_id),
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE id = $10
|
WHERE id = $11
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateQuestionSetParams struct {
|
type UpdateQuestionSetParams struct {
|
||||||
|
|
@ -521,6 +533,7 @@ type UpdateQuestionSetParams struct {
|
||||||
PassingScore pgtype.Int4 `json:"passing_score"`
|
PassingScore pgtype.Int4 `json:"passing_score"`
|
||||||
ShuffleQuestions bool `json:"shuffle_questions"`
|
ShuffleQuestions bool `json:"shuffle_questions"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
|
IntroVideoUrl pgtype.Text `json:"intro_video_url"`
|
||||||
SubCourseVideoID pgtype.Int8 `json:"sub_course_video_id"`
|
SubCourseVideoID pgtype.Int8 `json:"sub_course_video_id"`
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
@ -535,6 +548,7 @@ func (q *Queries) UpdateQuestionSet(ctx context.Context, arg UpdateQuestionSetPa
|
||||||
arg.PassingScore,
|
arg.PassingScore,
|
||||||
arg.ShuffleQuestions,
|
arg.ShuffleQuestions,
|
||||||
arg.Status,
|
arg.Status,
|
||||||
|
arg.IntroVideoUrl,
|
||||||
arg.SubCourseVideoID,
|
arg.SubCourseVideoID,
|
||||||
arg.ID,
|
arg.ID,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ type LearningPathPractice struct {
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
Persona *string `json:"persona,omitempty"`
|
Persona *string `json:"persona,omitempty"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
|
IntroVideoURL *string `json:"intro_video_url,omitempty"`
|
||||||
QuestionCount int64 `json:"question_count"`
|
QuestionCount int64 `json:"question_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ type QuestionSet struct {
|
||||||
ShuffleQuestions bool
|
ShuffleQuestions bool
|
||||||
Status string
|
Status string
|
||||||
SubCourseVideoID *int64
|
SubCourseVideoID *int64
|
||||||
|
IntroVideoURL *string
|
||||||
UserPersonas []UserPersona
|
UserPersonas []UserPersona
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt *time.Time
|
UpdatedAt *time.Time
|
||||||
|
|
@ -170,6 +171,7 @@ type CreateQuestionSetInput struct {
|
||||||
ShuffleQuestions *bool
|
ShuffleQuestions *bool
|
||||||
Status *string
|
Status *string
|
||||||
SubCourseVideoID *int64
|
SubCourseVideoID *int64
|
||||||
|
IntroVideoURL *string
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserPersona represents a user acting as a persona in a practice session
|
// UserPersona represents a user acting as a persona in a practice session
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,7 @@ func (s *Store) getSubCoursePracticesForPath(ctx context.Context, subCourseID in
|
||||||
Description: ptrString(row.Description),
|
Description: ptrString(row.Description),
|
||||||
Persona: ptrString(row.Persona),
|
Persona: ptrString(row.Persona),
|
||||||
Status: row.Status,
|
Status: row.Status,
|
||||||
|
IntroVideoURL: ptrString(row.IntroVideoUrl),
|
||||||
QuestionCount: row.QuestionCount,
|
QuestionCount: row.QuestionCount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,7 @@ func questionSetToDomain(qs dbgen.QuestionSet) domain.QuestionSet {
|
||||||
ShuffleQuestions: qs.ShuffleQuestions,
|
ShuffleQuestions: qs.ShuffleQuestions,
|
||||||
Status: qs.Status,
|
Status: qs.Status,
|
||||||
SubCourseVideoID: fromPgInt8(qs.SubCourseVideoID),
|
SubCourseVideoID: fromPgInt8(qs.SubCourseVideoID),
|
||||||
|
IntroVideoURL: fromPgText(qs.IntroVideoUrl),
|
||||||
CreatedAt: qs.CreatedAt.Time,
|
CreatedAt: qs.CreatedAt.Time,
|
||||||
UpdatedAt: timePtr(qs.UpdatedAt),
|
UpdatedAt: timePtr(qs.UpdatedAt),
|
||||||
}
|
}
|
||||||
|
|
@ -542,6 +543,7 @@ func (s *Store) CreateQuestionSet(ctx context.Context, input domain.CreateQuesti
|
||||||
Column10: shuffleQuestions,
|
Column10: shuffleQuestions,
|
||||||
Column11: status,
|
Column11: status,
|
||||||
SubCourseVideoID: toPgInt8(input.SubCourseVideoID),
|
SubCourseVideoID: toPgInt8(input.SubCourseVideoID),
|
||||||
|
IntroVideoUrl: toPgText(input.IntroVideoURL),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.QuestionSet{}, err
|
return domain.QuestionSet{}, err
|
||||||
|
|
@ -603,6 +605,7 @@ func (s *Store) GetQuestionSetsByType(ctx context.Context, setType string, limit
|
||||||
ShuffleQuestions: r.ShuffleQuestions,
|
ShuffleQuestions: r.ShuffleQuestions,
|
||||||
Status: r.Status,
|
Status: r.Status,
|
||||||
SubCourseVideoID: fromPgInt8(r.SubCourseVideoID),
|
SubCourseVideoID: fromPgInt8(r.SubCourseVideoID),
|
||||||
|
IntroVideoURL: fromPgText(r.IntroVideoUrl),
|
||||||
CreatedAt: r.CreatedAt.Time,
|
CreatedAt: r.CreatedAt.Time,
|
||||||
UpdatedAt: timePtr(r.UpdatedAt),
|
UpdatedAt: timePtr(r.UpdatedAt),
|
||||||
}
|
}
|
||||||
|
|
@ -688,6 +691,7 @@ func (s *Store) UpdateQuestionSet(ctx context.Context, id int64, input domain.Cr
|
||||||
PassingScore: toPgInt4(input.PassingScore),
|
PassingScore: toPgInt4(input.PassingScore),
|
||||||
ShuffleQuestions: shuffleQuestions,
|
ShuffleQuestions: shuffleQuestions,
|
||||||
Status: status,
|
Status: status,
|
||||||
|
IntroVideoUrl: toPgText(input.IntroVideoURL),
|
||||||
SubCourseVideoID: toPgInt8(input.SubCourseVideoID),
|
SubCourseVideoID: toPgInt8(input.SubCourseVideoID),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,10 @@ type resetAndReseedReq struct {
|
||||||
Confirm string `json:"confirm"`
|
Confirm string `json:"confirm"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type clearCourseManagementReq struct {
|
||||||
|
Confirm string `json:"confirm"`
|
||||||
|
}
|
||||||
|
|
||||||
func extractInsertStatement(sqlContent string, tableName string) (string, bool) {
|
func extractInsertStatement(sqlContent string, tableName string) (string, bool) {
|
||||||
pattern := fmt.Sprintf(`(?is)INSERT\s+INTO\s+%s\b.*?;`, regexp.QuoteMeta(tableName))
|
pattern := fmt.Sprintf(`(?is)INSERT\s+INTO\s+%s\b.*?;`, regexp.QuoteMeta(tableName))
|
||||||
re := regexp.MustCompile(pattern)
|
re := regexp.MustCompile(pattern)
|
||||||
|
|
@ -191,3 +195,71 @@ func (h *Handler) ResetAndReseedDatabase(c *fiber.Ctx) error {
|
||||||
StatusCode: fiber.StatusOK,
|
StatusCode: fiber.StatusOK,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearCourseManagementData godoc
|
||||||
|
// @Summary Clear course management hierarchy data only
|
||||||
|
// @Description Truncates course_categories, courses, and sub_courses (same scope as reset-reseed) without re-inserting seed SQL.
|
||||||
|
// @Tags internal
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param X-Seed-Reset-Token header string false "Optional token when DB_RESET_RESEED_TOKEN is set"
|
||||||
|
// @Param body body clearCourseManagementReq true "Confirmation payload"
|
||||||
|
// @Success 200 {object} domain.Response
|
||||||
|
// @Failure 400 {object} domain.ErrorResponse
|
||||||
|
// @Failure 403 {object} domain.ErrorResponse
|
||||||
|
// @Failure 500 {object} domain.ErrorResponse
|
||||||
|
// @Router /api/v1/internal/db/clear-course-management [post]
|
||||||
|
func (h *Handler) ClearCourseManagementData(c *fiber.Ctx) error {
|
||||||
|
if h.Cfg == nil || !h.Cfg.DBResetReseedEnabled {
|
||||||
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Operation is disabled",
|
||||||
|
Error: "internal course management maintenance is disabled",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var req clearCourseManagementReq
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Invalid request body",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(req.Confirm) != "CLEAR_COURSE_MANAGEMENT" {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Confirmation required",
|
||||||
|
Error: `set confirm to "CLEAR_COURSE_MANAGEMENT"`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedToken := strings.TrimSpace(h.Cfg.DBResetReseedToken)
|
||||||
|
if expectedToken != "" {
|
||||||
|
providedToken := strings.TrimSpace(c.Get("X-Seed-Reset-Token"))
|
||||||
|
if subtle.ConstantTimeCompare([]byte(providedToken), []byte(expectedToken)) != 1 {
|
||||||
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Invalid reset token",
|
||||||
|
Error: "missing or invalid X-Seed-Reset-Token",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tableNames := []string{"course_categories", "courses", "sub_courses"}
|
||||||
|
sql := `BEGIN;
|
||||||
|
TRUNCATE TABLE sub_courses, courses, course_categories RESTART IDENTITY CASCADE;
|
||||||
|
COMMIT;`
|
||||||
|
|
||||||
|
if _, err := h.analyticsDB.ExecRaw(c.Context(), sql); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to clear course management data",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(domain.Response{
|
||||||
|
Message: "Course management hierarchy cleared successfully (no re-seed)",
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"tables": tableNames,
|
||||||
|
},
|
||||||
|
Success: true,
|
||||||
|
StatusCode: fiber.StatusOK,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -525,6 +525,7 @@ type createQuestionSetReq struct {
|
||||||
ShuffleQuestions *bool `json:"shuffle_questions"`
|
ShuffleQuestions *bool `json:"shuffle_questions"`
|
||||||
Status *string `json:"status"`
|
Status *string `json:"status"`
|
||||||
SubCourseVideoID *int64 `json:"sub_course_video_id"`
|
SubCourseVideoID *int64 `json:"sub_course_video_id"`
|
||||||
|
IntroVideoURL *string `json:"intro_video_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type questionSetRes struct {
|
type questionSetRes struct {
|
||||||
|
|
@ -541,6 +542,7 @@ type questionSetRes struct {
|
||||||
ShuffleQuestions bool `json:"shuffle_questions"`
|
ShuffleQuestions bool `json:"shuffle_questions"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
SubCourseVideoID *int64 `json:"sub_course_video_id,omitempty"`
|
SubCourseVideoID *int64 `json:"sub_course_video_id,omitempty"`
|
||||||
|
IntroVideoURL *string `json:"intro_video_url,omitempty"`
|
||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at"`
|
||||||
QuestionCount *int64 `json:"question_count,omitempty"`
|
QuestionCount *int64 `json:"question_count,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
@ -626,6 +628,7 @@ func (h *Handler) CreateQuestionSet(c *fiber.Ctx) error {
|
||||||
ShuffleQuestions: req.ShuffleQuestions,
|
ShuffleQuestions: req.ShuffleQuestions,
|
||||||
Status: req.Status,
|
Status: req.Status,
|
||||||
SubCourseVideoID: req.SubCourseVideoID,
|
SubCourseVideoID: req.SubCourseVideoID,
|
||||||
|
IntroVideoURL: req.IntroVideoURL,
|
||||||
}
|
}
|
||||||
|
|
||||||
set, err := h.questionsSvc.CreateQuestionSet(c.Context(), input)
|
set, err := h.questionsSvc.CreateQuestionSet(c.Context(), input)
|
||||||
|
|
@ -659,6 +662,7 @@ func (h *Handler) CreateQuestionSet(c *fiber.Ctx) error {
|
||||||
ShuffleQuestions: set.ShuffleQuestions,
|
ShuffleQuestions: set.ShuffleQuestions,
|
||||||
Status: set.Status,
|
Status: set.Status,
|
||||||
SubCourseVideoID: set.SubCourseVideoID,
|
SubCourseVideoID: set.SubCourseVideoID,
|
||||||
|
IntroVideoURL: set.IntroVideoURL,
|
||||||
CreatedAt: set.CreatedAt.String(),
|
CreatedAt: set.CreatedAt.String(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
@ -711,6 +715,7 @@ func (h *Handler) GetSubCourseEntryAssessmentSet(c *fiber.Ctx) error {
|
||||||
ShuffleQuestions: set.ShuffleQuestions,
|
ShuffleQuestions: set.ShuffleQuestions,
|
||||||
Status: set.Status,
|
Status: set.Status,
|
||||||
SubCourseVideoID: set.SubCourseVideoID,
|
SubCourseVideoID: set.SubCourseVideoID,
|
||||||
|
IntroVideoURL: set.IntroVideoURL,
|
||||||
CreatedAt: set.CreatedAt.String(),
|
CreatedAt: set.CreatedAt.String(),
|
||||||
QuestionCount: &count,
|
QuestionCount: &count,
|
||||||
},
|
},
|
||||||
|
|
@ -774,6 +779,7 @@ func (h *Handler) GetQuestionSetByID(c *fiber.Ctx) error {
|
||||||
ShuffleQuestions: set.ShuffleQuestions,
|
ShuffleQuestions: set.ShuffleQuestions,
|
||||||
Status: set.Status,
|
Status: set.Status,
|
||||||
SubCourseVideoID: set.SubCourseVideoID,
|
SubCourseVideoID: set.SubCourseVideoID,
|
||||||
|
IntroVideoURL: set.IntroVideoURL,
|
||||||
CreatedAt: set.CreatedAt.String(),
|
CreatedAt: set.CreatedAt.String(),
|
||||||
QuestionCount: &count,
|
QuestionCount: &count,
|
||||||
},
|
},
|
||||||
|
|
@ -829,6 +835,7 @@ func (h *Handler) GetQuestionSetsByType(c *fiber.Ctx) error {
|
||||||
ShuffleQuestions: s.ShuffleQuestions,
|
ShuffleQuestions: s.ShuffleQuestions,
|
||||||
Status: s.Status,
|
Status: s.Status,
|
||||||
SubCourseVideoID: s.SubCourseVideoID,
|
SubCourseVideoID: s.SubCourseVideoID,
|
||||||
|
IntroVideoURL: s.IntroVideoURL,
|
||||||
CreatedAt: s.CreatedAt.String(),
|
CreatedAt: s.CreatedAt.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -895,6 +902,7 @@ func (h *Handler) GetQuestionSetsByOwner(c *fiber.Ctx) error {
|
||||||
ShuffleQuestions: s.ShuffleQuestions,
|
ShuffleQuestions: s.ShuffleQuestions,
|
||||||
Status: s.Status,
|
Status: s.Status,
|
||||||
SubCourseVideoID: s.SubCourseVideoID,
|
SubCourseVideoID: s.SubCourseVideoID,
|
||||||
|
IntroVideoURL: s.IntroVideoURL,
|
||||||
CreatedAt: s.CreatedAt.String(),
|
CreatedAt: s.CreatedAt.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -915,6 +923,7 @@ type updateQuestionSetReq struct {
|
||||||
ShuffleQuestions *bool `json:"shuffle_questions"`
|
ShuffleQuestions *bool `json:"shuffle_questions"`
|
||||||
Status *string `json:"status"`
|
Status *string `json:"status"`
|
||||||
SubCourseVideoID *int64 `json:"sub_course_video_id"`
|
SubCourseVideoID *int64 `json:"sub_course_video_id"`
|
||||||
|
IntroVideoURL *string `json:"intro_video_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateQuestionSet godoc
|
// UpdateQuestionSet godoc
|
||||||
|
|
@ -962,6 +971,7 @@ func (h *Handler) UpdateQuestionSet(c *fiber.Ctx) error {
|
||||||
ShuffleQuestions: req.ShuffleQuestions,
|
ShuffleQuestions: req.ShuffleQuestions,
|
||||||
Status: req.Status,
|
Status: req.Status,
|
||||||
SubCourseVideoID: req.SubCourseVideoID,
|
SubCourseVideoID: req.SubCourseVideoID,
|
||||||
|
IntroVideoURL: req.IntroVideoURL,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.questionsSvc.UpdateQuestionSet(c.Context(), id, input)
|
err = h.questionsSvc.UpdateQuestionSet(c.Context(), id, input)
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,7 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Post("/user/me/deletion/cancel", a.authMiddleware, a.RequirePermission("users.cancel_delete_self"), h.CancelMyUserAccountDeletion)
|
groupV1.Post("/user/me/deletion/cancel", a.authMiddleware, a.RequirePermission("users.cancel_delete_self"), h.CancelMyUserAccountDeletion)
|
||||||
groupV1.Post("/internal/users/purge-due-deletions", a.authMiddleware, a.RequirePermission("users.purge_due_deletions"), h.PurgeDueDeletedUsers)
|
groupV1.Post("/internal/users/purge-due-deletions", a.authMiddleware, a.RequirePermission("users.purge_due_deletions"), h.PurgeDueDeletedUsers)
|
||||||
groupV1.Post("/internal/db/reset-reseed", a.authMiddleware, a.RequirePermission("internal.db.reset_reseed"), h.ResetAndReseedDatabase)
|
groupV1.Post("/internal/db/reset-reseed", a.authMiddleware, a.RequirePermission("internal.db.reset_reseed"), h.ResetAndReseedDatabase)
|
||||||
|
groupV1.Post("/internal/db/clear-course-management", a.authMiddleware, a.RequirePermission("internal.db.reset_reseed"), h.ClearCourseManagementData)
|
||||||
groupV1.Get("/user/single/:id", a.authMiddleware, a.RequirePermission("users.get"), h.GetUserByID)
|
groupV1.Get("/user/single/:id", a.authMiddleware, a.RequirePermission("users.get"), h.GetUserByID)
|
||||||
groupV1.Delete("/user/delete/:id", a.authMiddleware, a.RequirePermission("users.delete"), h.DeleteUser)
|
groupV1.Delete("/user/delete/:id", a.authMiddleware, a.RequirePermission("users.delete"), h.DeleteUser)
|
||||||
groupV1.Post("/user/search", a.authMiddleware, a.RequirePermission("users.search"), h.SearchUserByNameOrPhone)
|
groupV1.Post("/user/search", a.authMiddleware, a.RequirePermission("users.search"), h.SearchUserByNameOrPhone)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user