v0.7.1: in-app password change, custom labels, always-on folders
- Settings -> Account: change your own password (current + new), session
preserved via update_session_auth_hash.
- Custom labels: per-user palette in Settings -> Labels; apply/remove from a
message's ... menu (menu stays open, checkmark = applied). Labels are unified
with tags; chip colours sync to the global TagColor. New Label model +
migration 0017; POST /a/{id}/label (session, owner-scoped, palette-validated).
- Sidebar Keep/Deleted folders are now always shown; count badge only when
non-empty. Updates the stale 'hide when empty' note in CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
fcd7da853f
commit
c2a354809a
14 changed files with 562 additions and 23 deletions
54
tests/views/test_settings_account.py
Normal file
54
tests/views/test_settings_account.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class ChangePasswordViewTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(username="alice", password="oldpassword")
|
||||
self.client.force_login(self.user)
|
||||
|
||||
def _post(self, old, new1, new2):
|
||||
return self.client.post(
|
||||
reverse("settings-account"),
|
||||
{"old_password": old, "new_password1": new1, "new_password2": new2},
|
||||
)
|
||||
|
||||
def test_get_renders_form(self):
|
||||
response = self.client.get(reverse("settings-account"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Change password")
|
||||
self.assertContains(response, "old_password")
|
||||
|
||||
def test_requires_login(self):
|
||||
self.client.logout()
|
||||
response = self.client.get(reverse("settings-account"))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
def test_valid_change_updates_password(self):
|
||||
response = self._post("oldpassword", "brandnewpass", "brandnewpass")
|
||||
self.assertRedirects(response, reverse("settings-account"))
|
||||
self.user.refresh_from_db()
|
||||
self.assertTrue(self.user.check_password("brandnewpass"))
|
||||
self.assertFalse(self.user.check_password("oldpassword"))
|
||||
|
||||
def test_valid_change_keeps_session(self):
|
||||
self._post("oldpassword", "brandnewpass", "brandnewpass")
|
||||
# Session must survive the password change (update_session_auth_hash),
|
||||
# so a follow-up authenticated request still succeeds.
|
||||
response = self.client.get(reverse("settings-account"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_wrong_current_password_rejected(self):
|
||||
response = self._post("WRONG", "brandnewpass", "brandnewpass")
|
||||
self.assertEqual(response.status_code, 200) # re-render with errors, no redirect
|
||||
self.user.refresh_from_db()
|
||||
self.assertTrue(self.user.check_password("oldpassword"))
|
||||
|
||||
def test_mismatched_new_password_rejected(self):
|
||||
response = self._post("oldpassword", "brandnewpass", "different")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.user.refresh_from_db()
|
||||
self.assertTrue(self.user.check_password("oldpassword"))
|
||||
Loading…
Add table
Add a link
Reference in a new issue