Skip to content

feat(egh): add createEggheadLessonVersion function and integrate egghead lesson versioning in post updates #481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 3, 2025

Conversation

zacjones93
Copy link
Contributor

@zacjones93 zacjones93 commented May 28, 2025

lesson progress was not working properly for users because we weren't creating lesson versions in rails. This adds lesson versions so that when a lesson is created or updated in builder it will push a lesson version to rails as well.

I also updated the affected (~140) lessons with proper lesson versions as well as added lesson version ids to the lesson views users completed on those 140 lessons (~7.5k records)

gif

#EGG-406

Summary by CodeRabbit

  • New Features
    • Added version tracking for Egghead lessons, allowing creation of new lesson versions with notes when posts are created or updated.
  • Improvements
    • Lesson publishing status is now explicitly tracked and updated.

…ead lesson versioning in post updates
Copy link

vercel bot commented May 28, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
ai-hero ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm
astro-party ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm
course-builder-egghead ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm
course-builder-poc ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm
craft-of-ui ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm
cursor-pro ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm
epic-react-builder ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm
epic-web-builder ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm
epicai-pro ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm
go-local-first ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 3, 2025 6:12pm

Copy link
Contributor

coderabbitai bot commented May 28, 2025

Walkthrough

This change introduces explicit version tracking for Egghead lessons by adding a function to create lesson version records and updating relevant workflows to call it. The update also extends the lesson update logic to include a published field, ensuring the lesson's published state is stored and tracked in the database.

Changes

File(s) Change Summary
apps/egghead/src/lib/egghead/lesson.ts Removed unused imports; updated updateEggheadLesson to accept and store published; added createEggheadLessonVersion for lesson versioning.
apps/egghead/src/lib/posts-new-query.ts Imported and called createEggheadLessonVersion when creating a new post with an Egghead lesson.
apps/egghead/src/lib/posts/write.ts Integrated createEggheadLessonVersion into post update flow; updated lesson with new published flag.

Sequence Diagram(s)

Loading
sequenceDiagram
    participant User
    participant PostService
    participant LessonService
    participant Database

    User->>PostService: Create or update post (with Egghead lesson)
    PostService->>LessonService: updateEggheadLesson(..., published)
    LessonService->>Database: Update lessons table (set published)
    alt New post or content hash changed
        PostService->>LessonService: createEggheadLessonVersion(lessonId, note)
        LessonService->>Database: Insert lesson_versions row
        LessonService->>Database: Update lessons.current_lesson_version_id
    end
    PostService->>User: Return result

Possibly related PRs

Suggested reviewers

  • joelhooks

Poem

In the warren of lessons, a version appears,
Each hop a new record, dispelling old fears.
With published now tracked, and notes in the log,
The database hums through the digital fog.
Oh, what a delight for a code-loving bunny—
Versioned and published, both crisp and sunny! 🥕

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

Scope: all 3 workspace projects
 WARN  Ignoring not compatible lockfile at /tmp/eslint/pnpm-lock.yaml
Progress: resolved 1, reused 0, downloaded 0, added 0
 WARN  deprecated [email protected]: This version is no longer supported. Please see https://eslint.org/version-support for other options.
/tmp/eslint/packages/config/eslint-config:
 ERR_PNPM_WORKSPACE_PKG_NOT_FOUND  In packages/config/eslint-config: "@coursebuilder/eslint-plugin@workspace:*" is in the dependencies but no package named "@coursebuilder/eslint-plugin" is present in the workspace

This error happened while installing a direct dependency of /tmp/eslint/packages/config/eslint-config

Packages found in the workspace:

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Sorry, something went wrong.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cacd740 and e28a593.

📒 Files selected for processing (3)
  • apps/egghead/src/lib/egghead/lesson.ts (5 hunks)
  • apps/egghead/src/lib/posts-new-query.ts (2 hunks)
  • apps/egghead/src/lib/posts/write.ts (4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/egghead/src/lib/posts-new-query.ts (1)
apps/egghead/src/lib/egghead/lesson.ts (1)
  • createEggheadLessonVersion (264-304)
apps/egghead/src/lib/posts/write.ts (1)
apps/egghead/src/lib/egghead/lesson.ts (1)
  • createEggheadLessonVersion (264-304)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: format
  • GitHub Check: build
  • GitHub Check: e2e-node (course-builder-web)
🔇 Additional comments (8)
apps/egghead/src/lib/egghead/lesson.ts (2)

98-98: LGTM: Function signature updated correctly.

The addition of the published: boolean parameter to updateEggheadLesson aligns with the PR objective to track lesson published state. The parameter is properly destructured and used in the SQL query.

Also applies to: 108-108, 145-145


132-132: LGTM: SQL query properly updated with published field.

The SQL query correctly adds the published column update using parameterized queries, maintaining security best practices.

Also applies to: 145-145

apps/egghead/src/lib/posts-new-query.ts (2)

15-19: LGTM: Import added correctly.

The import of createEggheadLessonVersion is properly added to the existing import statement.


135-137: LGTM: Lesson version creation properly integrated.

The conditional call to createEggheadLessonVersion is correctly placed after post version creation and uses an appropriate note "Initial version" for new lessons. The conditional check ensures it only runs when an egghead lesson exists.

apps/egghead/src/lib/posts/write.ts (4)

40-40: LGTM: Import added correctly.

The import of createEggheadLessonVersion is properly added to the existing import statement from the egghead module.


358-358: LGTM: Published state correctly derived.

The isPublished boolean is correctly derived from the post state comparison, providing a clear and readable way to determine the published status.


391-391: LGTM: Published parameter correctly passed.

The published parameter is correctly passed to the updateEggheadLesson function using the derived isPublished value, integrating well with the updated function signature.


471-476: LGTM: Lesson versioning correctly integrated into update workflow.

The conditional call to createEggheadLessonVersion is properly placed after content hash change detection and new post version creation. This ensures lesson versions are created only when actual content changes occur, with an appropriate note "Post metadata updated".

Comment on lines +264 to +304
export async function createEggheadLessonVersion(
eggheadLessonId: number,
versionNote: string,
) {
const { ability, session } = await getServerAuthSession()

if (!session?.user?.id || ability.cannot('manage', 'all')) {
throw new Error('Unauthorized')
}

const eggheadUser = await getEggheadUserProfile(session?.user?.id)

const columns = ['lesson_id', 'notes', 'user_id', 'created_at']

const values = [eggheadLessonId, versionNote, eggheadUser.id, new Date()]

const placeholders = columns.map((_, index) => `$${index + 1}`).join(', ')

const query = `
INSERT INTO lesson_versions (${columns.join(', ')})
VALUES (${placeholders})
RETURNING id
`
const eggheadLessonVersionResult = await eggheadPgQuery(query, values)

const eggheadLessonVersionId = eggheadLessonVersionResult.rows[0].id

console.log('[createEggheadLessonVersion]', {
eggheadLessonVersionId,
eggheadLessonId,
})

await eggheadPgQuery(
`UPDATE lessons SET
current_lesson_version_id = $1
WHERE id = $2`,
[eggheadLessonVersionId, eggheadLessonId],
)

return eggheadLessonVersionId
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Address error handling and remove debug logging.

The createEggheadLessonVersion function implementation looks good overall, but has a few concerns:

  1. Potential null reference: Line 274 could throw if getEggheadUserProfile returns null/undefined, but there's no validation.
  2. Debug logging: Lines 291-294 contain console.log statements that should be replaced with proper logging or removed.

Apply this diff to improve error handling:

 	const eggheadUser = await getEggheadUserProfile(session?.user?.id)
+
+	if (!eggheadUser?.id) {
+		throw new Error('Egghead user profile not found')
+	}

Apply this diff to replace debug logging:

-	console.log('[createEggheadLessonVersion]', {
-		eggheadLessonVersionId,
-		eggheadLessonId,
-	})

Consider using a proper logging library instead of console.log for production code.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function createEggheadLessonVersion(
eggheadLessonId: number,
versionNote: string,
) {
const { ability, session } = await getServerAuthSession()
if (!session?.user?.id || ability.cannot('manage', 'all')) {
throw new Error('Unauthorized')
}
const eggheadUser = await getEggheadUserProfile(session?.user?.id)
const columns = ['lesson_id', 'notes', 'user_id', 'created_at']
const values = [eggheadLessonId, versionNote, eggheadUser.id, new Date()]
const placeholders = columns.map((_, index) => `$${index + 1}`).join(', ')
const query = `
INSERT INTO lesson_versions (${columns.join(', ')})
VALUES (${placeholders})
RETURNING id
`
const eggheadLessonVersionResult = await eggheadPgQuery(query, values)
const eggheadLessonVersionId = eggheadLessonVersionResult.rows[0].id
console.log('[createEggheadLessonVersion]', {
eggheadLessonVersionId,
eggheadLessonId,
})
await eggheadPgQuery(
`UPDATE lessons SET
current_lesson_version_id = $1
WHERE id = $2`,
[eggheadLessonVersionId, eggheadLessonId],
)
return eggheadLessonVersionId
}
export async function createEggheadLessonVersion(
eggheadLessonId: number,
versionNote: string,
) {
const { ability, session } = await getServerAuthSession()
if (!session?.user?.id || ability.cannot('manage', 'all')) {
throw new Error('Unauthorized')
}
const eggheadUser = await getEggheadUserProfile(session?.user?.id)
if (!eggheadUser?.id) {
throw new Error('Egghead user profile not found')
}
const columns = ['lesson_id', 'notes', 'user_id', 'created_at']
const values = [eggheadLessonId, versionNote, eggheadUser.id, new Date()]
const placeholders = columns.map((_, index) => `$${index + 1}`).join(', ')
const query = `
INSERT INTO lesson_versions (${columns.join(', ')})
VALUES (${placeholders})
RETURNING id
`
const eggheadLessonVersionResult = await eggheadPgQuery(query, values)
const eggheadLessonVersionId = eggheadLessonVersionResult.rows[0].id
await eggheadPgQuery(
`UPDATE lessons SET
current_lesson_version_id = $1
WHERE id = $2`,
[eggheadLessonVersionId, eggheadLessonId],
)
return eggheadLessonVersionId
}
🤖 Prompt for AI Agents
In apps/egghead/src/lib/egghead/lesson.ts between lines 264 and 304, add a check
after calling getEggheadUserProfile to verify that eggheadUser is not null or
undefined and throw an appropriate error if it is, to prevent potential null
reference errors. Also, remove the console.log debug statements around lines
291-294 and replace them with calls to a proper logging library or remove them
entirely if logging is not needed.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant