feat: password change + split account/household settings UI
CI / test-and-package (push) Successful in 43s
CI / build-android (push) Successful in 1m10s

- New /change-password route: validates current password,
  enforces min 4 chars, requires confirmation match
- update_password() helper in models.py
- Dashboard UI split into two collapsible sections:
  👤 Account Settings (password, ntfy, delete account)
  🏠 Household Settings (admin only: public link, timezone,
     delete household)
- 14 new i18n keys with fr/de translations
- Restored accidentally dropped 'Delete My Account' key
This commit is contained in:
agentbox
2026-08-01 12:23:30 +00:00
parent 4abbbecce6
commit bda54eda3a
4 changed files with 114 additions and 21 deletions
+24 -12
View File
@@ -85,15 +85,14 @@
<div class="manage-section">
<details class="manage-details">
<summary>{{ t(' Account Settings') }}</summary>
<summary>{{ t('👤 Account Settings') }}</summary>
<div class="manage-forms">
<form method="POST" action="{{ url_for('meals.delete_account') }}"
onsubmit="return confirm(this.dataset.confirmMsg);"
data-confirm-msg="{{ t('Delete YOUR account? This cannot be undone.') }}"
class="manage-form">
<h4>{{ t('Delete My Account') }}</h4>
<input type="password" name="password" placeholder="{{ t('Enter your password to confirm') }}" required>
<button class="btn btn-danger">{{ t('Delete My Account') }}</button>
<form method="POST" action="{{ url_for('meals.change_password') }}" class="manage-form">
<h4>🔑 {{ t('Change Password') }}</h4>
<input type="password" name="current_password" placeholder="{{ t('Current password') }}" required>
<input type="password" name="new_password" placeholder="{{ t('New password') }}" required style="margin-top: 8px;">
<input type="password" name="confirm_password" placeholder="{{ t('Confirm new password') }}" required style="margin-top: 8px;">
<button type="submit" class="btn btn-primary btn-sm" style="margin-top: 8px;">{{ t('Change Password') }}</button>
</form>
<form method="POST" action="{{ url_for('meals.ntfy_settings') }}" class="manage-form">
@@ -113,7 +112,22 @@
</div>
</form>
{% if is_admin %}
<form method="POST" action="{{ url_for('meals.delete_account') }}"
onsubmit="return confirm(this.dataset.confirmMsg);"
data-confirm-msg="{{ t('Delete YOUR account? This cannot be undone.') }}"
class="manage-form">
<h4>{{ t('Delete My Account') }}</h4>
<p class="hint">{{ t('This will permanently delete your account and all your responses.') }}</p>
<input type="password" name="password" placeholder="{{ t('Enter your password to confirm') }}" required>
<button class="btn btn-danger">{{ t('Delete My Account') }}</button>
</form>
</div>
</details>
{% if is_admin %}
<details class="manage-details" style="margin-top: 8px;">
<summary>{{ t('🏠 Household Settings') }}</summary>
<div class="manage-forms">
<form method="POST" action="{{ url_for('meals.admin_public_link') }}" class="manage-form">
<h4>🔗 {{ t('Public Sharing Link') }}</h4>
<p class="hint">{{ t('Share a read-only view of your household\'s meal status. The link is hard to guess — only people with it can see the data.') }}</p>
@@ -150,9 +164,7 @@
</select>
<button type="submit" class="btn btn-primary btn-sm" style="margin-top: 8px;">{{ t('Save') }}</button>
</form>
{% endif %}
{% if is_admin %}
<form method="POST" action="{{ url_for('meals.admin_delete_household') }}"
onsubmit="return confirm(this.dataset.confirmMsg);"
data-confirm-msg="{{ t('Delete the ENTIRE household and ALL members? This cannot be undone.') }}"
@@ -162,9 +174,9 @@
<input type="password" name="password" placeholder="{{ t('Enter your password to confirm') }}" required>
<button class="btn btn-danger">{{ t('Delete Household') }}</button>
</form>
{% endif %}
</div>
</details>
{% endif %}
</div>
<script>