Skip to content

fix: DSA sheet progress never persists — accept object completedTopics shape - #1729

Open
vedant7007 wants to merge 1 commit into
Canopus-Labs:mainfrom
vedant7007:fix/sheet-progress-object-shape
Open

fix: DSA sheet progress never persists — accept object completedTopics shape#1729
vedant7007 wants to merge 1 commit into
Canopus-Labs:mainfrom
vedant7007:fix/sheet-progress-object-shape

Conversation

@vedant7007

@vedant7007 vedant7007 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Closes #1727

Problem

saveProgress rejected the real payload with 400:

if (completedTopics !== undefined && !Array.isArray(completedTopics)) { /* 400 "must be an array" */ }

The frontend sends completedTopics as an object/map ({ "0-0-0": true }), and so do the Zod validator (z.record(z.string(), z.boolean())), the Mongoose schema ({ type: Object }), resetProgress ({}), and the import util. !Array.isArray({...}) is true, so every save returned 400 and the frontend .catch swallowed it — progress lived only in localStorage and was lost across devices / on cache clear.

Fix

Validate completedTopics as a plain object (reject arrays/null) to match the rest of the system.

Testing

  • node --check on the changed controller.

Contributing as part of Elite Coders Summer of Code (ECSoC 2026).

Summary

  • Fixed saveProgress validation for completedTopics.
  • The controller now accepts non-null plain objects, such as { "0-0-0": true }.
  • The controller rejects arrays and null values.
  • Updated the validation error message.
  • Verified syntax with node --check.

The controller required completedTopics to be an Array, but the frontend,
the Zod validator (z.record), the Mongoose schema ({ type: Object }), the
import util, and resetProgress all use an object/map — so every save hit
!Array.isArray({...}) and returned 400, and progress was silently lost
(kept only in localStorage). Validate it as a plain object instead.

Fixes Canopus-Labs#1727
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The progress controller now accepts completedTopics object maps instead of arrays. It rejects null values and arrays, and updates the validation error message.

Changes

Progress validation

Layer / File(s) Summary
Completed topics validation
backend/controllers/userSheetProgressController.js
saveProgress now accepts non-null, non-array objects for completedTopics and returns an object-specific validation error for invalid values.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Suggested labels: good-backend, level:beginner

Suggested reviewers: karanunique

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the completedTopics shape correction that fixes DSA sheet progress persistence.
Linked Issues check ✅ Passed The change aligns controller validation with issue #1727 by accepting object completedTopics values and rejecting null or array values.
Out of Scope Changes check ✅ Passed The changes are limited to completedTopics validation and its error message, which directly supports issue #1727.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/controllers/userSheetProgressController.js`:
- Around line 63-71: Strengthen the completedTopics validation in the user sheet
progress controller to require a plain object and boolean values for every
property, matching the contract enforced by ValidateUserSheetProgress. Reject
non-plain objects and any entry whose value is not boolean before persisting the
record, while preserving the existing 400 response.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f3981c68-c780-418a-ac3b-4a331ec7ad11

📥 Commits

Reviewing files that changed from the base of the PR and between a8a7be0 and e2d6a03.

📒 Files selected for processing (1)
  • backend/controllers/userSheetProgressController.js

Comment on lines +63 to +71
if (
completedTopics !== undefined &&
(typeof completedTopics !== "object" ||
completedTopics === null ||
Array.isArray(completedTopics))
) {
return res.status(400).json({
success: false,
error: "Invalid completedTopics field, must be an array",
error: "Invalid completedTopics field, must be an object",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Validate completedTopics values against the record contract.

This check accepts any non-null, non-array object. For example, { "0-0-0": "true" } passes validation, but backend/Input_validators/ValidateUserSheetProgress.js:5-10 requires string keys with boolean values. Validate that the value is a plain object and that every property value is boolean before persisting it.

Proposed fix
   if (
     completedTopics !== undefined &&
-    (typeof completedTopics !== "object" ||
-      completedTopics === null ||
-      Array.isArray(completedTopics))
+    (completedTopics === null ||
+      typeof completedTopics !== "object" ||
+      Array.isArray(completedTopics) ||
+      Object.values(completedTopics).some(
+        (value) => typeof value !== "boolean"
+      ))
   ) {
     return res.status(400).json({
       success: false,
-      error: "Invalid completedTopics field, must be an object",
+      error: "Invalid completedTopics field, must be an object with boolean values",
     });
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/controllers/userSheetProgressController.js` around lines 63 - 71,
Strengthen the completedTopics validation in the user sheet progress controller
to require a plain object and boolean values for every property, matching the
contract enforced by ValidateUserSheetProgress. Reject non-plain objects and any
entry whose value is not boolean before persisting the record, while preserving
the existing 400 response.

@github-actions github-actions Bot added the merge ready PR is mergeable and has no conflicts label Aug 9, 2026
@KaranUnique

Copy link
Copy Markdown
Contributor

@vedant7007 address the coderabbit suggestions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge ready PR is mergeable and has no conflicts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] DSA sheet progress never persists — saveProgress rejects the object completedTopics shape with 400

2 participants