Introduce lms_personas table, repoint practice persona_id FKs off users, validate persona refs on LMS and exam-prep practice flows, personas.* RBAC permissions, and OpenAPI docs. Co-authored-by: Cursor <cursoragent@cursor.com>
85 lines
3.6 KiB
Go
85 lines
3.6 KiB
Go
package domain
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ParentKind identifies which hierarchy entity owns a practice (exactly one).
|
|
type ParentKind string
|
|
|
|
const (
|
|
ParentKindCourse ParentKind = "COURSE"
|
|
ParentKindModule ParentKind = "MODULE"
|
|
ParentKindLesson ParentKind = "LESSON"
|
|
)
|
|
|
|
// PracticePublishStatus controls learner visibility for a practice shell (independent of question_set.status).
|
|
type PracticePublishStatus string
|
|
|
|
const (
|
|
PracticePublishDraft PracticePublishStatus = "DRAFT"
|
|
PracticePublishPublished PracticePublishStatus = "PUBLISHED"
|
|
)
|
|
|
|
// ParsePracticePublishStatusInput maps API input. Empty or unknown values default to PUBLISHED for backward compatibility.
|
|
func ParsePracticePublishStatusInput(raw string) PracticePublishStatus {
|
|
switch strings.TrimSpace(strings.ToUpper(raw)) {
|
|
case string(PracticePublishDraft):
|
|
return PracticePublishDraft
|
|
case string(PracticePublishPublished):
|
|
return PracticePublishPublished
|
|
default:
|
|
return PracticePublishPublished
|
|
}
|
|
}
|
|
|
|
// PracticePublishStatusFromDB maps persisted values into the domain type.
|
|
func PracticePublishStatusFromDB(raw string) PracticePublishStatus {
|
|
return ParsePracticePublishStatusInput(raw)
|
|
}
|
|
|
|
// Practice is question-set content (story, persona, tips) scoped to a course, module, or lesson.
|
|
type Practice struct {
|
|
ID int64 `json:"id"`
|
|
ParentKind ParentKind `json:"parent_kind"`
|
|
ParentID int64 `json:"parent_id"`
|
|
Title string `json:"title"`
|
|
StoryDescription *string `json:"story_description,omitempty"`
|
|
StoryImage *string `json:"story_image,omitempty"`
|
|
PersonaID *int64 `json:"persona_id,omitempty"` // lms_personas.id when set
|
|
QuestionSetID int64 `json:"question_set_id"`
|
|
PublishStatus PracticePublishStatus `json:"publish_status"`
|
|
QuickTips *string `json:"quick_tips,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
|
}
|
|
|
|
// VisibleToLearners is true when the practice shell should appear in subscribed learner catalogs and progression.
|
|
func (p Practice) VisibleToLearners() bool {
|
|
return p.PublishStatus == PracticePublishPublished
|
|
}
|
|
|
|
type CreatePracticeInput struct {
|
|
ParentKind ParentKind `json:"parent_kind" validate:"required,oneof=COURSE MODULE LESSON"`
|
|
ParentID int64 `json:"parent_id" validate:"required,gt=0"`
|
|
Title *string `json:"title,omitempty"`
|
|
StoryDescription *string `json:"story_description,omitempty"`
|
|
StoryImage *string `json:"story_image,omitempty"`
|
|
PersonaID *int64 `json:"persona_id,omitempty"`
|
|
QuestionSetID int64 `json:"question_set_id" validate:"required,gt=0"`
|
|
QuickTips *string `json:"quick_tips,omitempty"`
|
|
// Omit or empty for backward compatibility defaults to PUBLISHED; set DRAFT to save hidden from learners until published.
|
|
PublishStatus string `json:"publish_status,omitempty" validate:"omitempty,oneof=DRAFT draft PUBLISHED published"`
|
|
}
|
|
|
|
type UpdatePracticeInput struct {
|
|
Title *string `json:"title,omitempty"`
|
|
StoryDescription *string `json:"story_description,omitempty"`
|
|
StoryImage *string `json:"story_image,omitempty"`
|
|
PersonaID *int64 `json:"persona_id,omitempty"`
|
|
QuestionSetID *int64 `json:"question_set_id,omitempty"`
|
|
QuickTips *string `json:"quick_tips,omitempty"`
|
|
PublishStatus *string `json:"publish_status,omitempty" validate:"omitempty,oneof=DRAFT draft PUBLISHED published"`
|
|
}
|