Fix practice completion roll-up for non-module scopes.

Resolve practice hierarchy using module, lesson, or course linkage and only run module-level cascade when module context exists.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Yared Yemane 2026-05-13 03:58:39 -07:00
parent 4ada908555
commit 8bba318372

View File

@ -32,7 +32,7 @@ func (s *Store) CompleteLessonForUser(ctx context.Context, userID, lessonID int6
return err return err
} }
if err := s.cascadeLMSCompletion(ctx, q, userID, mod.ID, crs.ID, crs.ProgramID); err != nil { if err := s.cascadeLMSCompletion(ctx, q, userID, &mod.ID, crs.ID, crs.ProgramID); err != nil {
return err return err
} }
@ -62,21 +62,43 @@ func (s *Store) CompletePracticeForUser(ctx context.Context, userID, questionSet
if err != nil { if err != nil {
return err return err
} }
if !scope.ModuleID.Valid { var (
return fmt.Errorf("practice %d is not linked to a module", questionSetID) moduleID *int64
courseID int64
)
switch {
case scope.ModuleID.Valid:
mid := scope.ModuleID.Int64
moduleID = &mid
mod, err := q.GetModuleByID(ctx, mid)
if err != nil {
return err
}
courseID = mod.CourseID
case scope.LessonID.Valid:
lesson, err := q.GetLessonByID(ctx, scope.LessonID.Int64)
if err != nil {
return err
}
mid := lesson.ModuleID
moduleID = &mid
mod, err := q.GetModuleByID(ctx, mid)
if err != nil {
return err
}
courseID = mod.CourseID
case scope.CourseID.Valid:
courseID = scope.CourseID.Int64
default:
return fmt.Errorf("practice %d is not linked to lesson/module/course", questionSetID)
} }
mod, err := q.GetModuleByID(ctx, scope.ModuleID.Int64) crs, err := q.GetCourseByID(ctx, courseID)
if err != nil { if err != nil {
return err return err
} }
crs, err := q.GetCourseByID(ctx, mod.CourseID) if err := s.cascadeLMSCompletion(ctx, q, userID, moduleID, crs.ID, crs.ProgramID); err != nil {
if err != nil {
return err
}
if err := s.cascadeLMSCompletion(ctx, q, userID, mod.ID, crs.ID, crs.ProgramID); err != nil {
return err return err
} }
@ -86,38 +108,40 @@ func (s *Store) CompletePracticeForUser(ctx context.Context, userID, questionSet
return nil return nil
} }
func (s *Store) cascadeLMSCompletion(ctx context.Context, q *dbgen.Queries, userID, moduleID, courseID, programID int64) error { func (s *Store) cascadeLMSCompletion(ctx context.Context, q *dbgen.Queries, userID int64, moduleID *int64, courseID, programID int64) error {
moduleLessonsTotal, err := q.CountLessonsInModule(ctx, moduleID) if moduleID != nil {
if err != nil { moduleLessonsTotal, err := q.CountLessonsInModule(ctx, *moduleID)
return err if err != nil {
} return err
moduleLessonsDone, err := q.CountUserCompletedLessonsInModule(ctx, dbgen.CountUserCompletedLessonsInModuleParams{ }
ModuleID: moduleID, moduleLessonsDone, err := q.CountUserCompletedLessonsInModule(ctx, dbgen.CountUserCompletedLessonsInModuleParams{
UserID: userID, ModuleID: *moduleID,
}) UserID: userID,
if err != nil { })
return err if err != nil {
} return err
modulePracticesTotal, err := q.CountPublishedPracticesInModule(ctx, toPgInt8(&moduleID)) }
if err != nil { modulePracticesTotal, err := q.CountPublishedPracticesInModule(ctx, toPgInt8(moduleID))
return err if err != nil {
} return err
modulePracticesDone, err := q.CountUserCompletedPublishedPracticesInModule(ctx, dbgen.CountUserCompletedPublishedPracticesInModuleParams{ }
ModuleID: toPgInt8(&moduleID), modulePracticesDone, err := q.CountUserCompletedPublishedPracticesInModule(ctx, dbgen.CountUserCompletedPublishedPracticesInModuleParams{
UserID: userID, ModuleID: toPgInt8(moduleID),
}) UserID: userID,
if err != nil { })
return err if err != nil {
} return err
}
moduleLessonsComplete := moduleLessonsTotal > 0 && moduleLessonsDone >= moduleLessonsTotal moduleLessonsComplete := moduleLessonsTotal > 0 && moduleLessonsDone >= moduleLessonsTotal
modulePracticesComplete := modulePracticesDone >= modulePracticesTotal modulePracticesComplete := modulePracticesDone >= modulePracticesTotal
if !moduleLessonsComplete || !modulePracticesComplete { if !moduleLessonsComplete || !modulePracticesComplete {
return nil return nil
} }
if err := q.InsertUserModuleProgress(ctx, dbgen.InsertUserModuleProgressParams{UserID: userID, ModuleID: moduleID}); err != nil { if err := q.InsertUserModuleProgress(ctx, dbgen.InsertUserModuleProgressParams{UserID: userID, ModuleID: *moduleID}); err != nil {
return err return err
}
} }
nMods, err := q.CountModulesInCourse(ctx, courseID) nMods, err := q.CountModulesInCourse(ctx, courseID)