bp/app/Views/profile/security.twig

267 lines
10 KiB
Twig
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends 'layouts/base.twig' %}
{% block title %}{{ title }}{% endblock %}
{% block styles %}
<style>
.profile-header {
text-align: center;
padding: 2rem 0;
}
.avatar-container {
position: relative;
width: 120px;
height: 120px;
margin: 0 auto 1rem;
}
.avatar-img {
width: 120px;
height: 120px;
border-radius: 50%;
object-fit: cover;
border: 4px solid #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.avatar-placeholder {
width: 120px;
height: 120px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
font-size: 48px;
color: white;
border: 4px solid #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.nav-pills .nav-link {
color: #495057;
border-radius: 0.5rem;
padding: 0.75rem 1.5rem;
margin-bottom: 0.5rem;
}
.nav-pills .nav-link.active {
background-color: #0d6efd;
color: white;
}
.nav-pills .nav-link:hover:not(.active) {
background-color: #e9ecef;
}
.form-label {
font-weight: 500;
margin-bottom: 0.5rem;
}
.session-item {
padding: 1rem;
border: 1px solid #e9ecef;
border-radius: 0.5rem;
margin-bottom: 0.75rem;
background: #fafafa;
}
.session-item:last-child {
margin-bottom: 0;
}
.session-device {
font-weight: 500;
color: #333;
}
.session-meta {
font-size: 0.875rem;
color: #6c757d;
margin-top: 0.25rem;
}
.session-current {
border-color: #198754;
background: #f0fff4;
}
.session-current .badge {
background: #198754;
}
.session-badge {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
}
.empty-sessions {
text-align: center;
padding: 2rem;
color: #6c757d;
}
.empty-sessions i {
font-size: 3rem;
margin-bottom: 1rem;
opacity: 0.5;
}
</style>
{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-3">
<!-- Боковая панель навигации -->
<div class="card mb-4">
<div class="card-body">
<div class="profile-header">
<div class="avatar-container">
{% if user.avatar %}
<img src="{{ base_url('/uploads/avatars/' ~ user.avatar) }}" alt="Аватар" class="avatar-img">
{% else %}
<div class="avatar-placeholder">
{{ user.name|first|upper }}
</div>
{% endif %}
</div>
<h5 class="mb-1">{{ user.name }}</h5>
<p class="text-muted mb-0">{{ user.email }}</p>
</div>
<hr>
<nav class="nav-pills flex-column">
<a href="{{ base_url('/profile') }}" class="nav-link {{ active_tab == 'general' ? 'active' : '' }}">
<i class="fa-solid fa-user me-2"></i> Основное
</a>
<a href="{{ base_url('/profile/organizations') }}" class="nav-link {{ active_tab == 'organizations' ? 'active' : '' }}">
<i class="fa-solid fa-building me-2"></i> Мои организации
</a>
<a href="{{ base_url('/profile/security') }}" class="nav-link {{ active_tab == 'security' ? 'active' : '' }}">
<i class="fa-solid fa-shield-halved me-2"></i> Безопасность
</a>
</nav>
</div>
</div>
</div>
<div class="col-md-9">
<!-- Смена пароля -->
<div class="card mb-4">
<div class="card-header bg-white">
<h4 class="mb-0"><i class="fa-solid fa-key me-2"></i>Смена пароля</h4>
</div>
<div class="card-body">
<form action="{{ base_url('/profile/change-password') }}" method="post">
{{ csrf_field()|raw }}
<div class="mb-3">
<label for="current_password" class="form-label">Текущий пароль</label>
<input type="password" class="form-control" id="current_password" name="current_password" required>
</div>
<div class="mb-3">
<label for="new_password" class="form-label">Новый пароль</label>
<input type="password" class="form-control" id="new_password" name="new_password" required minlength="6">
<div class="form-text">Минимум 6 символов</div>
</div>
<div class="mb-3">
<label for="confirm_password" class="form-label">Подтвердите новый пароль</label>
<input type="password" class="form-control" id="confirm_password" name="confirm_password" required>
</div>
<div class="alert alert-info">
<i class="fa-solid fa-info-circle me-2"></i>
После смены пароля вы будете автоматически разлогинены на всех устройствах для безопасности.
</div>
<button type="submit" class="btn btn-primary">
<i class="fa-solid fa-check me-1"></i> Изменить пароль
</button>
</form>
</div>
</div>
<!-- Активные сессии и устройства -->
<div class="card mb-4">
<div class="card-header bg-white d-flex justify-content-between align-items-center">
<h4 class="mb-0"><i class="fa-solid fa-desktop me-2"></i>Активные сессии</h4>
{% if sessions|length > 0 %}
<form action="{{ base_url('/profile/sessions/revoke-all') }}" method="post" onsubmit="return confirm('Вы уверены? Это завершит сессии на всех устройствах, кроме текущего.');">
{{ csrf_field()|raw }}
<button type="submit" class="btn btn-outline-danger btn-sm">
<i class="fa-solid fa-times me-1"></i>Завершить все
</button>
</form>
{% endif %}
</div>
<div class="card-body">
{% if sessions|length > 0 %}
{% for session in sessions %}
<div class="session-item{% if session.is_current %} session-current{% endif %}">
<div class="d-flex justify-content-between align-items-start">
<div>
<div class="session-device">
<i class="fa-solid fa-desktop me-2"></i>{{ session.device }}
{% if session.is_current %}
<span class="badge session-badge ms-2">Текущая сессия</span>
{% endif %}
</div>
<div class="session-meta">
<i class="fa-solid fa-globe me-1"></i>{{ session.ip_address }}
{% if session.expires_at %}
&nbsp;|&nbsp;
<i class="fa-solid fa-clock me-1"></i>истекает {{ session.expires_at|date('d.m.Y H:i') }}
{% endif %}
</div>
</div>
{% if not session.is_current %}
<form action="{{ base_url('/profile/session/revoke') }}" method="post">
{{ csrf_field()|raw }}
<input type="hidden" name="session_id" value="{{ session.id }}">
<button type="submit" class="btn btn-outline-danger btn-sm" onclick="return confirm('Завершить эту сессию?');">
<i class="fa-solid fa-times"></i>
</button>
</form>
{% endif %}
</div>
</div>
{% endfor %}
<div class="alert alert-info mt-3 mb-0">
<i class="fa-solid fa-info-circle me-2"></i>
<strong>Запомненные устройства:</strong> Если вы отметили "Запомнить меня" при входе, устройство будет автоматически авторизовано в течение 30 дней. Вы можете завершить эти сессии вручную.
</div>
{% else %}
<div class="empty-sessions">
<i class="fa-solid fa-shield-check"></i>
<p>Нет активных сессий на других устройствах</p>
</div>
{% endif %}
</div>
</div>
<!-- Информация о безопасности -->
<div class="card">
<div class="card-header bg-white">
<h4 class="mb-0"><i class="fa-solid fa-shield-halved me-2"></i>Рекомендации по безопасности</h4>
</div>
<div class="card-body">
<ul class="mb-0">
<li class="mb-2">Используйте пароль длиной не менее 8 символов</li>
<li class="mb-2">Комбинируйте буквы, цифры и специальные символы</li>
<li class="mb-2">Не используйте один и тот же пароль для разных сервисов</li>
<li class="mb-2">Регулярно меняйте пароль</li>
<li>Не сообщайте пароль третьим лицам</li>
</ul>
</div>
</div>
</div>
</div>
{% endblock %}