Release v2.1: GDPR, passkeys, session management, admin redesign
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,13 +6,13 @@
|
||||
<section class="page-header">
|
||||
<div class="container">
|
||||
<h1 class="page-header__title">Настройки профиля</h1>
|
||||
<p class="page-header__subtitle">Измените email или пароль</p>
|
||||
<p class="page-header__subtitle">Безопасность, passkey, сессии и GDPR</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="auth-section">
|
||||
<div class="container auth-container">
|
||||
<div class="auth-card auth-card--wide">
|
||||
<section class="auth-section profile-section">
|
||||
<div class="container profile-grid">
|
||||
<div class="auth-card auth-card--wide profile-card">
|
||||
{% include "partials/alerts.html" %}
|
||||
|
||||
<div class="profile-info">
|
||||
@@ -30,7 +30,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="profile-card__title">Email и пароль</h2>
|
||||
<form method="post" class="auth-form">
|
||||
<input type="hidden" name="action" value="save">
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="email" required value="{{ current_user.email }}">
|
||||
@@ -41,19 +43,111 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password">Новый пароль (необязательно)</label>
|
||||
<input type="password" id="new_password" name="new_password" minlength="6" placeholder="оставьте пустым, если не меняете">
|
||||
<input type="password" id="new_password" name="new_password" minlength="6">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password2">Подтверждение нового пароля</label>
|
||||
<input type="password" id="new_password2" name="new_password2" minlength="6">
|
||||
</div>
|
||||
<button type="submit" class="btn btn--primary btn--full">Сохранить</button>
|
||||
<button type="submit" class="btn btn--primary">Сохранить</button>
|
||||
</form>
|
||||
|
||||
<p class="auth-card__footer">
|
||||
<a href="{{ url_for('cabinet.index') }}">← Вернуться в кабинет</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="auth-card auth-card--wide profile-card">
|
||||
<h2 class="profile-card__title">Passkey</h2>
|
||||
<p class="profile-card__hint">Вход без пароля через Face ID, Touch ID, Windows Hello или ключ безопасности.</p>
|
||||
|
||||
{% if passkeys %}
|
||||
<ul class="session-list">
|
||||
{% for passkey in passkeys %}
|
||||
<li class="session-item">
|
||||
<div>
|
||||
<strong>{{ passkey.name }}</strong>
|
||||
<span class="session-item__meta">Добавлен {{ passkey.created_at.strftime('%d.%m.%Y') }}</span>
|
||||
</div>
|
||||
<form method="post">
|
||||
<input type="hidden" name="action" value="delete_passkey">
|
||||
<input type="hidden" name="passkey_id" value="{{ passkey.id }}">
|
||||
<button type="submit" class="btn btn--danger btn--sm">Удалить</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="profile-card__empty">Passkey не настроен</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="form-group" style="margin-top:16px">
|
||||
<label for="passkeyName">Название устройства</label>
|
||||
<input type="text" id="passkeyName" value="Моё устройство" maxlength="120">
|
||||
</div>
|
||||
<button type="button" class="btn btn--ghost" id="addPasskeyBtn">Добавить passkey</button>
|
||||
</div>
|
||||
|
||||
<div class="auth-card auth-card--wide profile-card">
|
||||
<h2 class="profile-card__title">Активные сессии</h2>
|
||||
<p class="profile-card__hint">Все устройства, где выполнен вход в ваш аккаунт.</p>
|
||||
|
||||
{% if sessions %}
|
||||
<ul class="session-list">
|
||||
{% for item in sessions %}
|
||||
<li class="session-item {% if item.session_key == current_sid %}session-item--current{% endif %}">
|
||||
<div>
|
||||
<strong>{{ item.device_label }}</strong>
|
||||
{% if item.session_key == current_sid %}<span class="badge badge--success">текущая</span>{% endif %}
|
||||
<span class="session-item__meta">
|
||||
{{ item.ip_address or 'IP неизвестен' }} ·
|
||||
{{ item.last_seen_at.strftime('%d.%m.%Y %H:%M') }}
|
||||
</span>
|
||||
</div>
|
||||
{% if item.session_key != current_sid %}
|
||||
<form method="post">
|
||||
<input type="hidden" name="action" value="revoke_session">
|
||||
<input type="hidden" name="session_id" value="{{ item.id }}">
|
||||
<button type="submit" class="btn btn--ghost btn--sm">Завершить</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<form method="post" style="margin-top:16px">
|
||||
<input type="hidden" name="action" value="revoke_all_sessions">
|
||||
<button type="submit" class="btn btn--danger btn--sm" onclick="return confirm('Завершить все сессии кроме текущей?');">
|
||||
Выйти на всех устройствах
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<p class="profile-card__empty">Нет активных сессий</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="auth-card auth-card--wide profile-card">
|
||||
<h2 class="profile-card__title">GDPR и данные</h2>
|
||||
<p class="profile-card__hint">
|
||||
Вы можете скачать копию своих данных или удалить аккаунт.
|
||||
<a href="{{ url_for('legal.gdpr') }}">Подробнее о правах</a>
|
||||
</p>
|
||||
<div class="profile-actions">
|
||||
<a href="{{ url_for('cabinet.export_profile') }}" class="btn btn--ghost">Скачать мои данные (JSON)</a>
|
||||
</div>
|
||||
|
||||
<form method="post" class="profile-delete-form" onsubmit="return confirm('Удалить аккаунт без возможности восстановления?');">
|
||||
<input type="hidden" name="action" value="delete_account">
|
||||
<div class="form-group">
|
||||
<label for="delete_password">Пароль для удаления аккаунта</label>
|
||||
<input type="password" id="delete_password" name="delete_password" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn--danger">Удалить аккаунт</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p class="auth-card__footer profile-footer">
|
||||
<a href="{{ url_for('cabinet.index') }}">← Вернуться в кабинет</a>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/passkey.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user