Make practice title optional on create.
POST /practices and exam-prep practice create accept missing or null title; persist as empty string. Refresh OpenAPI and document the behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
bd1767d2a6
commit
71bc09a638
|
|
@ -415,6 +415,8 @@ This creates the practice record scoped to lesson.
|
||||||
|
|
||||||
### Request
|
### Request
|
||||||
|
|
||||||
|
`title` is optional; omit it or use an empty string to create a practice without a display title (stored as empty).
|
||||||
|
|
||||||
Include `publish_status`: `DRAFT` to hide the practice from subscribed learners until you set it to `PUBLISHED` (via create or `PUT /practices/:id`). Omit the field or send `PUBLISHED` to go live immediately (backward compatible).
|
Include `publish_status`: `DRAFT` to hide the practice from subscribed learners until you set it to `PUBLISHED` (via create or `PUT /practices/:id`). Omit the field or send `PUBLISHED` to go live immediately (backward compatible).
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|
|
||||||
71
docs/docs.go
71
docs/docs.go
|
|
@ -10434,13 +10434,21 @@ const docTemplate = `{
|
||||||
"domain.CreateExamPrepPracticeInput": {
|
"domain.CreateExamPrepPracticeInput": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"question_set_id",
|
"question_set_id"
|
||||||
"title"
|
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"persona_id": {
|
"persona_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"publish_status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
|
},
|
||||||
"question_set_id": {
|
"question_set_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
@ -10485,11 +10493,19 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"publish_status": {
|
"publish_status": {
|
||||||
"description": "Omit or DRAFT (default) for drafts; PUBLISHED for learner-visible lessons.",
|
"description": "Omit or empty defaults to DRAFT; set PUBLISHED to make visible to learners immediately.",
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"sort_order": {
|
"sort_order": {
|
||||||
"type": "integer"
|
"description": "SortOrder within the module when set; omit to append after current max within module_id.",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
},
|
},
|
||||||
"thumbnail": {
|
"thumbnail": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|
@ -10516,6 +10532,11 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sort_order": {
|
||||||
|
"description": "SortOrder within the course when set; omit to append after current max within course_id (uniqueness is per-course).",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -10524,8 +10545,7 @@ const docTemplate = `{
|
||||||
"required": [
|
"required": [
|
||||||
"parent_id",
|
"parent_id",
|
||||||
"parent_kind",
|
"parent_kind",
|
||||||
"question_set_id",
|
"question_set_id"
|
||||||
"title"
|
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"parent_id": {
|
"parent_id": {
|
||||||
|
|
@ -10546,6 +10566,16 @@ const docTemplate = `{
|
||||||
"persona_id": {
|
"persona_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"publish_status": {
|
||||||
|
"description": "Omit or empty for backward compatibility defaults to PUBLISHED; set DRAFT to save hidden from learners until published.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
|
},
|
||||||
"question_set_id": {
|
"question_set_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
@ -11327,6 +11357,15 @@ const docTemplate = `{
|
||||||
"persona_id": {
|
"persona_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"publish_status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
|
},
|
||||||
"question_set_id": {
|
"question_set_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
@ -11380,8 +11419,13 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"publish_status": {
|
"publish_status": {
|
||||||
"description": "DRAFT or PUBLISHED",
|
"type": "string",
|
||||||
"type": "string"
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"sort_order": {
|
"sort_order": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
|
@ -11420,6 +11464,15 @@ const docTemplate = `{
|
||||||
"persona_id": {
|
"persona_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"publish_status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
|
},
|
||||||
"question_set_id": {
|
"question_set_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -10426,13 +10426,21 @@
|
||||||
"domain.CreateExamPrepPracticeInput": {
|
"domain.CreateExamPrepPracticeInput": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"question_set_id",
|
"question_set_id"
|
||||||
"title"
|
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"persona_id": {
|
"persona_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"publish_status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
|
},
|
||||||
"question_set_id": {
|
"question_set_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
@ -10477,11 +10485,19 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"publish_status": {
|
"publish_status": {
|
||||||
"description": "Omit or DRAFT (default) for drafts; PUBLISHED for learner-visible lessons.",
|
"description": "Omit or empty defaults to DRAFT; set PUBLISHED to make visible to learners immediately.",
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"sort_order": {
|
"sort_order": {
|
||||||
"type": "integer"
|
"description": "SortOrder within the module when set; omit to append after current max within module_id.",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
},
|
},
|
||||||
"thumbnail": {
|
"thumbnail": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|
@ -10508,6 +10524,11 @@
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sort_order": {
|
||||||
|
"description": "SortOrder within the course when set; omit to append after current max within course_id (uniqueness is per-course).",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -10516,8 +10537,7 @@
|
||||||
"required": [
|
"required": [
|
||||||
"parent_id",
|
"parent_id",
|
||||||
"parent_kind",
|
"parent_kind",
|
||||||
"question_set_id",
|
"question_set_id"
|
||||||
"title"
|
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"parent_id": {
|
"parent_id": {
|
||||||
|
|
@ -10538,6 +10558,16 @@
|
||||||
"persona_id": {
|
"persona_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"publish_status": {
|
||||||
|
"description": "Omit or empty for backward compatibility defaults to PUBLISHED; set DRAFT to save hidden from learners until published.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
|
},
|
||||||
"question_set_id": {
|
"question_set_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
@ -11319,6 +11349,15 @@
|
||||||
"persona_id": {
|
"persona_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"publish_status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
|
},
|
||||||
"question_set_id": {
|
"question_set_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
@ -11372,8 +11411,13 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"publish_status": {
|
"publish_status": {
|
||||||
"description": "DRAFT or PUBLISHED",
|
"type": "string",
|
||||||
"type": "string"
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"sort_order": {
|
"sort_order": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
|
@ -11412,6 +11456,15 @@
|
||||||
"persona_id": {
|
"persona_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"publish_status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"DRAFT",
|
||||||
|
"draft",
|
||||||
|
"PUBLISHED",
|
||||||
|
"published"
|
||||||
|
]
|
||||||
|
},
|
||||||
"question_set_id": {
|
"question_set_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,13 @@ definitions:
|
||||||
properties:
|
properties:
|
||||||
persona_id:
|
persona_id:
|
||||||
type: integer
|
type: integer
|
||||||
|
publish_status:
|
||||||
|
enum:
|
||||||
|
- DRAFT
|
||||||
|
- draft
|
||||||
|
- PUBLISHED
|
||||||
|
- published
|
||||||
|
type: string
|
||||||
question_set_id:
|
question_set_id:
|
||||||
type: integer
|
type: integer
|
||||||
quick_tips:
|
quick_tips:
|
||||||
|
|
@ -401,7 +408,6 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- question_set_id
|
- question_set_id
|
||||||
- title
|
|
||||||
type: object
|
type: object
|
||||||
domain.CreateExamPrepUnitInput:
|
domain.CreateExamPrepUnitInput:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -419,9 +425,18 @@ definitions:
|
||||||
description:
|
description:
|
||||||
type: string
|
type: string
|
||||||
publish_status:
|
publish_status:
|
||||||
description: Omit or DRAFT (default) for drafts; PUBLISHED for learner-visible lessons.
|
description: Omit or empty defaults to DRAFT; set PUBLISHED to make visible
|
||||||
|
to learners immediately.
|
||||||
|
enum:
|
||||||
|
- DRAFT
|
||||||
|
- draft
|
||||||
|
- PUBLISHED
|
||||||
|
- published
|
||||||
type: string
|
type: string
|
||||||
sort_order:
|
sort_order:
|
||||||
|
description: SortOrder within the module when set; omit to append after current
|
||||||
|
max within module_id.
|
||||||
|
minimum: 0
|
||||||
type: integer
|
type: integer
|
||||||
thumbnail:
|
thumbnail:
|
||||||
type: string
|
type: string
|
||||||
|
|
@ -440,6 +455,11 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
|
sort_order:
|
||||||
|
description: SortOrder within the course when set; omit to append after current
|
||||||
|
max within course_id (uniqueness is per-course).
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
|
|
@ -456,6 +476,15 @@ definitions:
|
||||||
- LESSON
|
- LESSON
|
||||||
persona_id:
|
persona_id:
|
||||||
type: integer
|
type: integer
|
||||||
|
publish_status:
|
||||||
|
description: Omit or empty for backward compatibility defaults to PUBLISHED;
|
||||||
|
set DRAFT to save hidden from learners until published.
|
||||||
|
enum:
|
||||||
|
- DRAFT
|
||||||
|
- draft
|
||||||
|
- PUBLISHED
|
||||||
|
- published
|
||||||
|
type: string
|
||||||
question_set_id:
|
question_set_id:
|
||||||
type: integer
|
type: integer
|
||||||
quick_tips:
|
quick_tips:
|
||||||
|
|
@ -470,7 +499,6 @@ definitions:
|
||||||
- parent_id
|
- parent_id
|
||||||
- parent_kind
|
- parent_kind
|
||||||
- question_set_id
|
- question_set_id
|
||||||
- title
|
|
||||||
type: object
|
type: object
|
||||||
domain.CreateProgramInput:
|
domain.CreateProgramInput:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -996,6 +1024,13 @@ definitions:
|
||||||
properties:
|
properties:
|
||||||
persona_id:
|
persona_id:
|
||||||
type: integer
|
type: integer
|
||||||
|
publish_status:
|
||||||
|
enum:
|
||||||
|
- DRAFT
|
||||||
|
- draft
|
||||||
|
- PUBLISHED
|
||||||
|
- published
|
||||||
|
type: string
|
||||||
question_set_id:
|
question_set_id:
|
||||||
type: integer
|
type: integer
|
||||||
quick_tips:
|
quick_tips:
|
||||||
|
|
@ -1031,7 +1066,11 @@ definitions:
|
||||||
description:
|
description:
|
||||||
type: string
|
type: string
|
||||||
publish_status:
|
publish_status:
|
||||||
description: DRAFT or PUBLISHED
|
enum:
|
||||||
|
- DRAFT
|
||||||
|
- draft
|
||||||
|
- PUBLISHED
|
||||||
|
- published
|
||||||
type: string
|
type: string
|
||||||
sort_order:
|
sort_order:
|
||||||
type: integer
|
type: integer
|
||||||
|
|
@ -1057,6 +1096,13 @@ definitions:
|
||||||
properties:
|
properties:
|
||||||
persona_id:
|
persona_id:
|
||||||
type: integer
|
type: integer
|
||||||
|
publish_status:
|
||||||
|
enum:
|
||||||
|
- DRAFT
|
||||||
|
- draft
|
||||||
|
- PUBLISHED
|
||||||
|
- published
|
||||||
|
type: string
|
||||||
question_set_id:
|
question_set_id:
|
||||||
type: integer
|
type: integer
|
||||||
quick_tips:
|
quick_tips:
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ func (p ExamPrepPractice) VisibleToLearners() bool {
|
||||||
|
|
||||||
// CreateExamPrepPracticeInput is the body for POST .../exam-prep/lessons/{lessonId}/practices (lesson from path).
|
// CreateExamPrepPracticeInput is the body for POST .../exam-prep/lessons/{lessonId}/practices (lesson from path).
|
||||||
type CreateExamPrepPracticeInput struct {
|
type CreateExamPrepPracticeInput struct {
|
||||||
Title string `json:"title" validate:"required"`
|
Title *string `json:"title,omitempty"`
|
||||||
StoryDescription *string `json:"story_description,omitempty"`
|
StoryDescription *string `json:"story_description,omitempty"`
|
||||||
StoryImage *string `json:"story_image,omitempty"`
|
StoryImage *string `json:"story_image,omitempty"`
|
||||||
PersonaID *int64 `json:"persona_id,omitempty"`
|
PersonaID *int64 `json:"persona_id,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ func (p Practice) VisibleToLearners() bool {
|
||||||
type CreatePracticeInput struct {
|
type CreatePracticeInput struct {
|
||||||
ParentKind ParentKind `json:"parent_kind" validate:"required,oneof=COURSE MODULE LESSON"`
|
ParentKind ParentKind `json:"parent_kind" validate:"required,oneof=COURSE MODULE LESSON"`
|
||||||
ParentID int64 `json:"parent_id" validate:"required,gt=0"`
|
ParentID int64 `json:"parent_id" validate:"required,gt=0"`
|
||||||
Title string `json:"title" validate:"required"`
|
Title *string `json:"title,omitempty"`
|
||||||
StoryDescription *string `json:"story_description,omitempty"`
|
StoryDescription *string `json:"story_description,omitempty"`
|
||||||
StoryImage *string `json:"story_image,omitempty"`
|
StoryImage *string `json:"story_image,omitempty"`
|
||||||
PersonaID *int64 `json:"persona_id,omitempty"`
|
PersonaID *int64 `json:"persona_id,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ func (s *Store) CreateExamPrepLessonPractice(ctx context.Context, lessonID int64
|
||||||
ps := domain.ParsePracticePublishStatusInput(in.PublishStatus)
|
ps := domain.ParsePracticePublishStatusInput(in.PublishStatus)
|
||||||
p, err := s.queries.ExamPrepCreateLessonPractice(ctx, dbgen.ExamPrepCreateLessonPracticeParams{
|
p, err := s.queries.ExamPrepCreateLessonPractice(ctx, dbgen.ExamPrepCreateLessonPracticeParams{
|
||||||
UnitModuleLessonID: lessonID,
|
UnitModuleLessonID: lessonID,
|
||||||
Title: in.Title,
|
Title: derefString(in.Title),
|
||||||
StoryDescription: toPgText(in.StoryDescription),
|
StoryDescription: toPgText(in.StoryDescription),
|
||||||
StoryImage: toPgText(in.StoryImage),
|
StoryImage: toPgText(in.StoryImage),
|
||||||
PersonaID: int64PtrToPg8(in.PersonaID),
|
PersonaID: int64PtrToPg8(in.PersonaID),
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,13 @@ func optionalInt8UpdateID(val *int64) pgtype.Int8 {
|
||||||
return pgtype.Int8{Int64: *val, Valid: true}
|
return pgtype.Int8{Int64: *val, Valid: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func derefString(p *string) string {
|
||||||
|
if p == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *p
|
||||||
|
}
|
||||||
|
|
||||||
func lmsPracticeToDomain(p dbgen.LmsPractice) domain.Practice {
|
func lmsPracticeToDomain(p dbgen.LmsPractice) domain.Practice {
|
||||||
out := domain.Practice{
|
out := domain.Practice{
|
||||||
ID: p.ID,
|
ID: p.ID,
|
||||||
|
|
@ -98,7 +105,7 @@ func (s *Store) CreateLmsPractice(
|
||||||
CourseID: int64PtrToPg8(courseID),
|
CourseID: int64PtrToPg8(courseID),
|
||||||
ModuleID: int64PtrToPg8(moduleID),
|
ModuleID: int64PtrToPg8(moduleID),
|
||||||
LessonID: int64PtrToPg8(lessonID),
|
LessonID: int64PtrToPg8(lessonID),
|
||||||
Title: in.Title,
|
Title: derefString(in.Title),
|
||||||
StoryDescription: toPgText(in.StoryDescription),
|
StoryDescription: toPgText(in.StoryDescription),
|
||||||
StoryImage: toPgText(in.StoryImage),
|
StoryImage: toPgText(in.StoryImage),
|
||||||
PersonaID: int64PtrToPg8(in.PersonaID),
|
PersonaID: int64PtrToPg8(in.PersonaID),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user