bp/app/Controllers/Auth.php

271 lines
11 KiB
PHP
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.

<?php
namespace App\Controllers;
use App\Models\UserModel;
use App\Models\OrganizationModel;
use App\Models\OrganizationUserModel;
use App\Libraries\EmailLibrary;
class Auth extends BaseController
{
protected $emailLibrary;
public function __construct()
{
$this->emailLibrary = new EmailLibrary();
}
public function register()
{
if ($this->request->getMethod() === 'POST') {
log_message('debug', 'POST запрос получен: ' . print_r($this->request->getPost(), true));
// Валидация (упрощенная для примера)
$rules = [
'name' => 'required|min_length[3]',
'email' => 'required|valid_email|is_unique[users.email]',
'password' => 'required|min_length[6]',
];
if (!$this->validate($rules)) {
return redirect()->back()->with('error', 'Ошибка регистрации');
}
$userModel = new UserModel();
$orgModel = new OrganizationModel();
$orgUserModel = new OrganizationUserModel();
// Генерируем токен для подтверждения email
$verificationToken = bin2hex(random_bytes(32));
// 1. Создаем пользователя с токеном верификации
$userData = [
'name' => $this->request->getPost('name'),
'email' => $this->request->getPost('email'),
'password' => $this->request->getPost('password'), // Хешируется в модели
'verification_token' => $verificationToken,
'email_verified' => 0,
];
log_message('debug', 'Registration userData: ' . print_r($userData, true));
$userId = $userModel->insert($userData);
log_message('debug', 'Insert result, userId: ' . $userId);
// 2. Создаем "Личную организацию" (п. 5.2.1 ТЗ)
$orgData = [
'owner_id' => $userId,
'name' => 'Личное пространство',
'type' => 'personal',
];
$orgId = $orgModel->insert($orgData);
// 3. Привязываем пользователя к этой организации (роль owner)
$orgUserModel->insert([
'organization_id' => $orgId,
'user_id' => $userId,
'role' => 'owner',
'status' => 'active',
'joined_at' => date('Y-m-d H:i:s'),
]);
// 4. Отправляем письмо для подтверждения email
$this->emailLibrary->sendVerificationEmail(
$userData['email'],
$userData['name'],
$verificationToken
);
// 5. Показываем сообщение о необходимости подтверждения
session()->setFlashdata('success', 'Регистрация успешна! Пожалуйста, проверьте вашу почту и подтвердите email.');
return redirect()->to('/register/success');
}
return $this->renderTwig('auth/register');
}
/**
* Страница после успешной регистрации
*/
public function registerSuccess()
{
return $this->renderTwig('auth/register_success');
}
/**
* Подтверждение email по токену
*/
public function verify($token)
{
log_message('debug', 'Verify called with token: ' . $token);
if (empty($token)) {
return $this->renderTwig('auth/verify_error', [
'message' => 'Отсутствует токен подтверждения.'
]);
}
$userModel = new UserModel();
// Ищем пользователя по токену
$user = $userModel->where('verification_token', $token)->first();
log_message('debug', 'User found: ' . ($user ? 'yes' : 'no'));
if ($user) {
log_message('debug', 'User email_verified: ' . $user['email_verified']);
}
if (!$user) {
return $this->renderTwig('auth/verify_error', [
'message' => 'Недействительная ссылка для подтверждения. Возможно, ссылка уже была использована или истек срок её действия.'
]);
}
if ($user['email_verified']) {
return $this->renderTwig('auth/verify_error', [
'message' => 'Email уже подтверждён. Вы можете войти в систему.'
]);
}
// Подтверждаем email
$updateData = [
'email_verified' => 1,
'verified_at' => date('Y-m-d H:i:s'),
'verification_token' => null, // Удаляем токен после использования
];
$result = $userModel->update($user['id'], $updateData);
log_message('debug', 'Update result: ' . ($result ? 'success' : 'failed'));
log_message('debug', 'Update data: ' . print_r($updateData, true));
if (!$result) {
log_message('error', 'Update errors: ' . print_r($userModel->errors(), true));
}
// Отправляем приветственное письмо
$this->emailLibrary->sendWelcomeEmail($user['email'], $user['name']);
return $this->renderTwig('auth/verify_success', [
'name' => $user['name']
]);
}
/**
* Повторная отправка письма для подтверждения
*/
public function resendVerification()
{
if ($this->request->getMethod() === 'POST') {
$email = $this->request->getPost('email');
if (empty($email)) {
return redirect()->back()->with('error', 'Введите email');
}
$userModel = new UserModel();
$user = $userModel->where('email', $email)->first();
if (!$user) {
return redirect()->back()->with('error', 'Пользователь с таким email не найден');
}
if ($user['email_verified']) {
return redirect()->to('/login')->with('info', 'Email уже подтверждён. Вы можете войти.');
}
// Генерируем новый токен
$newToken = bin2hex(random_bytes(32));
$userModel->update($user['id'], [
'verification_token' => $newToken
]);
// Отправляем письмо повторно
$this->emailLibrary->sendVerificationEmail(
$user['email'],
$user['name'],
$newToken
);
return redirect()->back()->with('success', 'Письмо для подтверждения отправлено повторно. Проверьте почту.');
}
return $this->renderTwig('auth/resend_verification');
}
public function login()
{
if ($this->request->getMethod() === 'POST') {
$userModel = new \App\Models\UserModel();
$orgUserModel = new \App\Models\OrganizationUserModel();
$email = $this->request->getPost('email');
$password = $this->request->getPost('password');
$user = $userModel->where('email', $email)->first();
if ($user && password_verify($password, $user['password'])) {
// Проверяем, подтвержден ли email
if (!$user['email_verified']) {
session()->setFlashdata('warning', 'Email не подтверждён. Проверьте почту или <a href="/auth/resend-verification">запросите письмо повторно</a>.');
return redirect()->to('/login');
}
// Получаем организации пользователя
$userOrgs = $orgUserModel->where('user_id', $user['id'])->findAll();
if (empty($userOrgs)) {
// Экстремальный случай: если по какой-то причине у пользователя нет организаций
session()->setFlashdata('error', 'Ваш аккаунт не привязан ни к одной организации. Обратитесь к поддержке.');
return redirect()->to('/login');
}
// Базовые данные сессии (пользователь авторизован)
$sessionData = [
'user_id' => $user['id'],
'email' => $user['email'],
'name' => $user['name'],
'isLoggedIn' => true
];
// АВТОМАТИЧЕСКИЙ ВЫБОР ОРГАНИЗАЦИИ
if (count($userOrgs) === 1) {
// Если одна организация — заходим автоматически для удобства
$sessionData['active_org_id'] = $userOrgs[0]['organization_id'];
session()->set($sessionData);
return redirect()->to('/');
}
// ОЧИЩАЕМ active_org_id если несколько организаций
session()->remove('active_org_id');
// Если несколько организаций — отправляем на страницу выбора
session()->set($sessionData);
// (Опционально) Записываем информацию, что пользователь залогинен, но орга не выбрана,
// чтобы страница /organizations не редиректнула его обратно (см. Organizations::index)
session()->setFlashdata('info', 'Выберите пространство для работы');
return redirect()->to('/organizations');
//}
} else {
return redirect()->back()->with('error', 'Неверный логин или пароль');
}
}
return $this->renderTwig('auth/login');
}
public function logout()
{
session()->destroy();
session()->remove('active_org_id');
return redirect()->to('/');
}
}