fix: DSA sheet progress never persists — accept object completedTopics shape - #1729
fix: DSA sheet progress never persists — accept object completedTopics shape#1729vedant7007 wants to merge 1 commit into
Conversation
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
📝 WalkthroughWalkthroughThe progress controller now accepts ChangesProgress validation
Estimated code review effort: 1 (Trivial) | ~5 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (1)
backend/controllers/userSheetProgressController.js
| 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", |
There was a problem hiding this comment.
🗄️ 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.
|
@vedant7007 address the coderabbit suggestions |
Closes #1727
Problem
saveProgressrejected the real payload with400:The frontend sends
completedTopicsas 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({...})istrue, so every save returned 400 and the frontend.catchswallowed it — progress lived only in localStorage and was lost across devices / on cache clear.Fix
Validate
completedTopicsas a plain object (reject arrays/null) to match the rest of the system.Testing
node --checkon the changed controller.Contributing as part of Elite Coders Summer of Code (ECSoC 2026).
Summary
saveProgressvalidation forcompletedTopics.{ "0-0-0": true }.nullvalues.node --check.