userModel = new UserModel(); $this->orgModel = new OrganizationModel(); } /** * Главная страница профиля */ public function index() { $userId = $this->getCurrentUserId(); $user = $this->userModel->find($userId); return $this->renderTwig('profile/index', [ 'title' => 'Профиль', 'user' => $user, 'active_tab' => 'general', ]); } /** * Вкладка "Организации" */ public function organizations() { $userId = $this->getCurrentUserId(); $user = $this->userModel->find($userId); $currentOrgId = $this->session->get('active_org_id'); // Получаем все организации пользователя $orgUserModel = $this->getOrgUserModel(); $memberships = $orgUserModel->where('user_id', $userId)->findAll(); $orgIds = array_column($memberships, 'organization_id'); $organizations = []; if (!empty($orgIds)) { $organizations = $this->orgModel->whereIn('id', $orgIds)->findAll(); } // Объединяем данные $orgList = []; foreach ($organizations as $org) { // Находим соответствующий membership $membership = null; foreach ($memberships as $m) { if ($m['organization_id'] == $org['id']) { $membership = $m; break; } } $orgList[] = [ 'id' => $org['id'], 'name' => $org['name'], 'type' => $org['type'], 'role' => $membership['role'] ?? 'guest', 'status' => $membership['status'] ?? 'active', 'joined_at' => $membership['joined_at'] ?? null, 'is_owner' => ($membership['role'] ?? '') === 'owner', 'is_current_org' => ((int) $org['id'] === (int) $currentOrgId), ]; } return $this->renderTwig('profile/organizations', [ 'title' => 'Мои организации', 'user' => $user, 'organizations' => $orgList, 'active_tab' => 'organizations', ]); } /** * Вкладка "Безопасность" */ public function security() { $userId = $this->getCurrentUserId(); $user = $this->userModel->find($userId); return $this->renderTwig('profile/security', [ 'title' => 'Безопасность', 'user' => $user, 'active_tab' => 'security', ]); } /** * Обновление имени пользователя */ public function updateName() { $userId = $this->getCurrentUserId(); $name = trim($this->request->getPost('name')); if (empty($name)) { $this->session->setFlashdata('error', 'Имя обязательно для заполнения'); return redirect()->to('/profile'); } if (strlen($name) < 3) { $this->session->setFlashdata('error', 'Имя должно содержать минимум 3 символа'); return redirect()->to('/profile'); } $this->userModel->update($userId, ['name' => $name]); $this->session->set('name', $name); $this->session->setFlashdata('success', 'Имя успешно обновлено'); return redirect()->to('/profile'); } /** * Загрузка аватара */ public function uploadAvatar() { $userId = $this->getCurrentUserId(); $file = $this->request->getFile('avatar'); if (!$file || !$file->isValid()) { $this->session->setFlashdata('error', 'Ошибка загрузки файла'); return redirect()->to('/profile'); } // Валидация $allowedTypes = ['image/jpeg', 'image/png', 'image/gif']; $maxSize = 2 * 1024 * 1024; // 2MB if (!in_array($file->getMimeType(), $allowedTypes)) { $this->session->setFlashdata('error', 'Разрешены только файлы JPG, PNG и GIF'); return redirect()->to('/profile'); } if ($file->getSize() > $maxSize) { $this->session->setFlashdata('error', 'Максимальный размер файла - 2 МБ'); return redirect()->to('/profile'); } // Создаём директорию для аватаров если нет $uploadPath = ROOTPATH . 'public/uploads/avatars'; if (!is_dir($uploadPath)) { mkdir($uploadPath, 0755, true); } // Генерируем уникальное имя файла $extension = $file->getClientExtension(); $newFileName = 'avatar_' . $userId . '_' . time() . '.' . $extension; // Перемещаем файл $file->move($uploadPath, $newFileName); // Удаляем старый аватар если был $user = $this->userModel->find($userId); if (!empty($user['avatar']) && file_exists($uploadPath . '/' . $user['avatar'])) { @unlink($uploadPath . '/' . $user['avatar']); } // Обновляем путь к аватару в базе $this->userModel->update($userId, ['avatar' => $newFileName]); $this->session->setFlashdata('success', 'Аватар успешно загружен'); return redirect()->to('/profile'); } /** * Смена пароля */ public function changePassword() { $userId = $this->getCurrentUserId(); $user = $this->userModel->find($userId); $currentPassword = $this->request->getPost('current_password'); $newPassword = $this->request->getPost('new_password'); $confirmPassword = $this->request->getPost('confirm_password'); // Валидация if (empty($currentPassword)) { $this->session->setFlashdata('error', 'Введите текущий пароль'); return redirect()->to('/profile/security'); } if (empty($newPassword)) { $this->session->setFlashdata('error', 'Введите новый пароль'); return redirect()->to('/profile/security'); } if (strlen($newPassword) < 6) { $this->session->setFlashdata('error', 'Новый пароль должен содержать минимум 6 символов'); return redirect()->to('/profile/security'); } if ($newPassword !== $confirmPassword) { $this->session->setFlashdata('error', 'Пароли не совпадают'); return redirect()->to('/profile/security'); } // Проверяем текущий пароль if (!password_verify($currentPassword, $user['password'])) { $this->session->setFlashdata('error', 'Неверный текущий пароль'); return redirect()->to('/profile/security'); } // Обновляем пароль $this->userModel->update($userId, ['password' => $newPassword]); // Завершаем все сессии пользователя (кроме текущей) $this->endAllUserSessions($userId); $this->session->setFlashdata('success', 'Пароль успешно изменён. Для безопасности вы будете разлогинены на всех устройствах.'); return redirect()->to('/logout'); } /** * Завершение всех сессий пользователя */ private function endAllUserSessions(int $userId): void { // Удаляем все remember-токены пользователя $db = \Config\Database::connect(); $db->table('remember_tokens')->where('user_id', $userId)->delete(); // Регенерируем ID текущей сессии $this->session->regenerate(true); } }