package training import ( "context" "time" "github.com/google/uuid" "github.com/jackc/pgx/v5" ) // CreateModuleContent creates new content for a module func (s *Store) CreateModuleContent(ctx context.Context, content *ModuleContent) error { content.ID = uuid.New() content.CreatedAt = time.Now().UTC() content.UpdatedAt = content.CreatedAt // Auto-increment version var maxVersion int s.pool.QueryRow(ctx, "SELECT COALESCE(MAX(version), 0) FROM training_module_content WHERE module_id = $1", content.ModuleID).Scan(&maxVersion) content.Version = maxVersion + 1 _, err := s.pool.Exec(ctx, ` INSERT INTO training_module_content ( id, module_id, version, content_format, content_body, summary, generated_by, llm_model, is_published, reviewed_by, reviewed_at, created_at, updated_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) `, content.ID, content.ModuleID, content.Version, string(content.ContentFormat), content.ContentBody, content.Summary, content.GeneratedBy, content.LLMModel, content.IsPublished, content.ReviewedBy, content.ReviewedAt, content.CreatedAt, content.UpdatedAt, ) return err } // GetPublishedContent retrieves the published content for a module func (s *Store) GetPublishedContent(ctx context.Context, moduleID uuid.UUID) (*ModuleContent, error) { var content ModuleContent var contentFormat string err := s.pool.QueryRow(ctx, ` SELECT id, module_id, version, content_format, content_body, summary, generated_by, llm_model, is_published, reviewed_by, reviewed_at, created_at, updated_at FROM training_module_content WHERE module_id = $1 AND is_published = true ORDER BY version DESC LIMIT 1 `, moduleID).Scan( &content.ID, &content.ModuleID, &content.Version, &contentFormat, &content.ContentBody, &content.Summary, &content.GeneratedBy, &content.LLMModel, &content.IsPublished, &content.ReviewedBy, &content.ReviewedAt, &content.CreatedAt, &content.UpdatedAt, ) if err == pgx.ErrNoRows { return nil, nil } if err != nil { return nil, err } content.ContentFormat = ContentFormat(contentFormat) return &content, nil } // GetLatestContent retrieves the latest content (published or not) for a module func (s *Store) GetLatestContent(ctx context.Context, moduleID uuid.UUID) (*ModuleContent, error) { var content ModuleContent var contentFormat string err := s.pool.QueryRow(ctx, ` SELECT id, module_id, version, content_format, content_body, summary, generated_by, llm_model, is_published, reviewed_by, reviewed_at, created_at, updated_at FROM training_module_content WHERE module_id = $1 ORDER BY version DESC LIMIT 1 `, moduleID).Scan( &content.ID, &content.ModuleID, &content.Version, &contentFormat, &content.ContentBody, &content.Summary, &content.GeneratedBy, &content.LLMModel, &content.IsPublished, &content.ReviewedBy, &content.ReviewedAt, &content.CreatedAt, &content.UpdatedAt, ) if err == pgx.ErrNoRows { return nil, nil } if err != nil { return nil, err } content.ContentFormat = ContentFormat(contentFormat) return &content, nil } // PublishContent marks a content version as published (unpublishes all others for that module) func (s *Store) PublishContent(ctx context.Context, contentID uuid.UUID, reviewedBy uuid.UUID) error { now := time.Now().UTC() // Get module_id for this content var moduleID uuid.UUID err := s.pool.QueryRow(ctx, "SELECT module_id FROM training_module_content WHERE id = $1", contentID).Scan(&moduleID) if err != nil { return err } // Unpublish all existing content for this module _, err = s.pool.Exec(ctx, "UPDATE training_module_content SET is_published = false WHERE module_id = $1", moduleID) if err != nil { return err } // Publish the specified content _, err = s.pool.Exec(ctx, ` UPDATE training_module_content SET is_published = true, reviewed_by = $2, reviewed_at = $3, updated_at = $3 WHERE id = $1 `, contentID, reviewedBy, now) return err }