[Eng-445 ] refact: user change password py to pydantic#3667
[Eng-445 ] refact: user change password py to pydantic#3667nandkishorr wants to merge 3 commits into
Conversation
📝 WalkthroughWalkthroughThis PR replaces the DRF Serializer-based password-change flow with a Pydantic ChangesPassword Change Validation Refactor
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly Related PRs
Suggested Reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR refactors the change-password endpoint from a DRF
Confidence Score: 3/5The change-password endpoint now returns 500 for requests with missing fields and silently changes its error response format for password policy violations — both are regressions from the old serializer behaviour. Two concrete regressions exist in the changed view: missing-field payloads now crash with an unhandled Pydantic exception, and password-validation failures return a different JSON shape than before. The test suite does not catch either because it never sends a malformed request and uses assertContains (text-anywhere check) rather than asserting the specific field key in the error body. care/users/api/viewsets/change_password.py needs the most attention — both regressions live there. Important Files Changed
Reviews (1): Last reviewed commit: "refact:updted the tests" | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 `@care/users/api/viewsets/change_password.py`:
- Around line 18-22: The top-level request=ChangePasswordSpec on
extend_schema_view won't apply to per-operation docs; move the
request=ChangePasswordSpec into each per-method extend_schema call so the PUT
and PATCH operations get the ChangePasswordSpec request body. Update the
extend_schema_view usage so extend_schema(tags=["users"],
request=ChangePasswordSpec) is applied for the put and patch entries (i.e.,
put=extend_schema(tags=["users"], request=ChangePasswordSpec) and
patch=extend_schema(tags=["users"], request=ChangePasswordSpec)), referencing
extend_schema_view, extend_schema, put, patch, and ChangePasswordSpec.
- Line 32: Wrap the construction of ChangePasswordSpec(**request.data) in a
try/except that catches pydantic.ValidationError in the change password view
(change_password.py) and translate it to a DRF 400 response by raising
rest_framework.exceptions.ValidationError (or returning Response with status=400
and the validation details); reference the ChangePasswordSpec symbol and the
view's handler where request.data is parsed. Also add a new test
test_change_password_missing_fields in care/users/tests/test_change_password.py
that POSTs with missing/invalid old_password or new_password and asserts HTTP
400 plus the returned validation error details.
In `@care/users/tests/test_change_password.py`:
- Around line 44-49: The test test_change_password_invalid_password currently
sets self.payload["new_password"] to the same value as the current password, so
the final assertion self.user.check_password("password123") is meaningless;
change the test to record the current password (or use its known value) as
original_password, set self.payload["new_password"] to a distinct invalid value
(e.g. "invalid_new_pwd"), call self.client.put(self.url, self.payload,
format="json") as before, refresh the user with self.user.refresh_from_db(), and
assert that self.user.check_password(original_password) is still True to prove
the password was not changed.
- Around line 10-15: The test uses hardcoded passwords
(password123/newpassword456) in care/users/tests/test_change_password.py via
create_user_with_password and payload which will trigger Ruff bandit rules
S105/S106; either add "S105,S106" to
tool.ruff.lint.per-file-ignores["**/tests/**"] in ruff.toml so tests are exempt,
or change the test to generate non-literal passwords (e.g., derive them at
runtime via secrets or a test factory) and assign them to the same variables
used (self.create_user_with_password call and
self.payload["old_password"/"new_password"]) to avoid hardcoded string literals.
🪄 Autofix (Beta)
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
Run ID: 89f9cbab-0607-4c27-bfe2-4ce029b0d1ba
📒 Files selected for processing (3)
care/users/api/viewsets/change_password.pycare/users/tests/__init__.pycare/users/tests/test_change_password.py
There was a problem hiding this comment.
🧹 Nitpick comments (1)
care/users/tests/test_change_password.py (1)
51-91: ⚡ Quick winWhitespace coverage only exercises
old_password;new_passwordstripping is left untested.These three tests thoroughly cover stripping on
old_password, which is nice. However,ChangePasswordSpec.strip_passwordsalso stripsnew_password— meaning a user submitting"newpassword456 "would silently get a different stored password than they typed. That behavior currently has no test guarding it. Consider adding a case that submits anew_passwordwith surrounding whitespace and asserts the stripped value is what's persisted.💚 Suggested additional test
def test_change_password_strips_new_password_whitespace(self): self.payload["new_password"] = " newpassword456 " response = self.client.put(self.url, self.payload, format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) self.user.refresh_from_db() self.assertTrue(self.user.check_password("newpassword456")) self.assertFalse(self.user.check_password(" newpassword456 "))🤖 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 `@care/users/tests/test_change_password.py` around lines 51 - 91, The tests exercise stripping of old_password but miss asserting that new_password is stripped before being stored; add a test in care/users/tests/test_change_password.py (e.g., test_change_password_strips_new_password_whitespace) that sets self.payload["new_password"] to a value with surrounding whitespace, sends the PUT to self.url, asserts a 200 response, refreshes self.user (self.user.refresh_from_db()) and then asserts the stored password matches the stripped value (self.user.check_password("newpassword456")) and not the unstripped value; this verifies ChangePasswordSpec.strip_passwords correctly strips new_password as well.
🤖 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.
Nitpick comments:
In `@care/users/tests/test_change_password.py`:
- Around line 51-91: The tests exercise stripping of old_password but miss
asserting that new_password is stripped before being stored; add a test in
care/users/tests/test_change_password.py (e.g.,
test_change_password_strips_new_password_whitespace) that sets
self.payload["new_password"] to a value with surrounding whitespace, sends the
PUT to self.url, asserts a 200 response, refreshes self.user
(self.user.refresh_from_db()) and then asserts the stored password matches the
stripped value (self.user.check_password("newpassword456")) and not the
unstripped value; this verifies ChangePasswordSpec.strip_passwords correctly
strips new_password as well.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d62a9170-ec83-4e85-b589-77ef178d2a0a
📒 Files selected for processing (3)
care/emr/tests/test_reset_password_api.pycare/users/api/viewsets/change_password.pycare/users/tests/test_change_password.py
💤 Files with no reviewable changes (1)
- care/emr/tests/test_reset_password_api.py
🚧 Files skipped from review as they are similar to previous changes (1)
- care/users/api/viewsets/change_password.py
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #3667 +/- ##
========================================
Coverage 75.85% 75.85%
========================================
Files 479 479
Lines 23043 23043
Branches 2380 2380
========================================
Hits 17480 17480
Misses 4990 4990
Partials 573 573 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Proposed Changes
Associated Issue
Merge Checklist
/docsOnly PR's with test cases included and passing lint and test pipelines will be reviewed
@ohcnetwork/care-backend-maintainers @ohcnetwork/care-backend-admins
Summary by CodeRabbit
Bug Fixes
Tests