268 lines
9.9 KiB
PHP
268 lines
9.9 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers;
|
|
|
|
use App\Models\OrganizationUserModel;
|
|
use App\Models\UserModel;
|
|
use App\Models\OrganizationModel;
|
|
use App\Services\InvitationService;
|
|
use App\Services\AccessService;
|
|
|
|
class InvitationController extends BaseController
|
|
{
|
|
protected InvitationService $invitationService;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->invitationService = new InvitationService();
|
|
}
|
|
|
|
/**
|
|
* Страница принятия/отклонения приглашения
|
|
*/
|
|
public function accept(string $token)
|
|
{
|
|
$invitation = $this->invitationService->orgUserModel->findByInviteToken($token);
|
|
|
|
if (!$invitation) {
|
|
return $this->renderTwig('organizations/invitation_expired', [
|
|
'title' => 'Приглашение недействительно',
|
|
]);
|
|
}
|
|
|
|
// Получаем данные организации
|
|
$orgModel = new OrganizationModel();
|
|
$organization = $orgModel->find($invitation['organization_id']);
|
|
|
|
// Получаем данные приглашающего
|
|
$invitedByUser = null;
|
|
if ($invitation['invited_by']) {
|
|
$userModel = new UserModel();
|
|
$invitedByUser = $userModel->find($invitation['invited_by']);
|
|
}
|
|
|
|
// Определяем, авторизован ли пользователь
|
|
$currentUserId = session()->get('user_id');
|
|
$isLoggedIn = !empty($currentUserId);
|
|
|
|
// Если пользователь авторизован - проверяем, тот ли это email
|
|
$emailMatches = true;
|
|
if ($isLoggedIn && $invitation['user_id']) {
|
|
$currentUser = (new UserModel())->find($currentUserId);
|
|
// Проверяем, тот ли пользователь (по ID или email)
|
|
$emailMatches = ($currentUserId == $invitation['user_id']);
|
|
}
|
|
|
|
// Метка роли
|
|
$roleLabels = [
|
|
'owner' => 'Владелец',
|
|
'admin' => 'Администратор',
|
|
'manager' => 'Менеджер',
|
|
'guest' => 'Гость',
|
|
];
|
|
|
|
return $this->renderTwig('organizations/invitation_accept', [
|
|
'title' => 'Приглашение в ' . ($organization['name'] ?? 'организацию'),
|
|
'token' => $token,
|
|
'organization' => $organization,
|
|
'role' => $invitation['role'],
|
|
'role_label' => $roleLabels[$invitation['role']] ?? $invitation['role'],
|
|
'invited_by' => $invitedByUser,
|
|
'invited_at' => $invitation['invited_at'],
|
|
'is_logged_in' => $isLoggedIn,
|
|
'email_matches' => $emailMatches,
|
|
'current_user_id'=> $currentUserId,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Обработка принятия приглашения
|
|
*/
|
|
public function processAccept()
|
|
{
|
|
$token = $this->request->getPost('token');
|
|
$action = $this->request->getPost('action');
|
|
|
|
if ($action === 'decline') {
|
|
return $this->decline($token);
|
|
}
|
|
|
|
$userId = session()->get('user_id');
|
|
|
|
// Если пользователь не авторизован - редирект на страницу создания пароля
|
|
if (!$userId) {
|
|
return redirect()->to('/invitation/complete/' . $token);
|
|
}
|
|
|
|
// Принимаем приглашение
|
|
$result = $this->invitationService->acceptInvitation($token, $userId);
|
|
|
|
if (!$result['success']) {
|
|
session()->setFlashdata('error', $result['message']);
|
|
return redirect()->to('/invitation/accept/' . $token);
|
|
}
|
|
|
|
session()->setFlashdata('success', 'Вы приняли приглашение в организацию "' . $result['organization_name'] . '"');
|
|
|
|
// Переключаем организацию и редиректим на главную
|
|
session()->set('active_org_id', $result['organization_id']);
|
|
(new AccessService())->resetCache();
|
|
|
|
return redirect()->to('/');
|
|
}
|
|
|
|
/**
|
|
* Отклонение приглашения
|
|
*/
|
|
public function decline(string $token)
|
|
{
|
|
$result = $this->invitationService->declineInvitation($token);
|
|
|
|
if (!$result['success']) {
|
|
session()->setFlashdata('error', $result['message']);
|
|
} else {
|
|
session()->setFlashdata('info', 'Приглашение отклонено');
|
|
}
|
|
|
|
return redirect()->to('/');
|
|
}
|
|
|
|
/**
|
|
* Страница завершения регистрации (для новых пользователей)
|
|
*/
|
|
public function complete(string $token)
|
|
{
|
|
$invitation = $this->invitationService->orgUserModel->findByInviteToken($token);
|
|
|
|
if (!$invitation) {
|
|
return $this->renderTwig('organizations/invitation_expired', [
|
|
'title' => 'Приглашение недействительно',
|
|
]);
|
|
}
|
|
|
|
// Если пользователь уже авторизован и это его приглашение
|
|
$userId = session()->get('user_id');
|
|
if ($userId && $invitation['user_id'] == $userId) {
|
|
return redirect()->to('/invitation/accept/' . $token);
|
|
}
|
|
|
|
// Получаем данные организации
|
|
$orgModel = new OrganizationModel();
|
|
$organization = $orgModel->find($invitation['organization_id']);
|
|
|
|
// Метка роли
|
|
$roleLabels = [
|
|
'owner' => 'Владелец',
|
|
'admin' => 'Администратор',
|
|
'manager' => 'Менеджер',
|
|
'guest' => 'Гость',
|
|
];
|
|
|
|
return $this->renderTwig('organizations/invitation_complete', [
|
|
'title' => 'Завершение регистрации',
|
|
'token' => $token,
|
|
'email' => $invitation['user_id'] ? '' : '', // Email возьмем из теневой записи
|
|
'organization' => $organization,
|
|
'role' => $invitation['role'],
|
|
'role_label' => $roleLabels[$invitation['role']] ?? $invitation['role'],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Обработка завершения регистрации
|
|
*/
|
|
public function processComplete()
|
|
{
|
|
$token = $this->request->getPost('token');
|
|
$name = $this->request->getPost('name');
|
|
$password = $this->request->getPost('password');
|
|
$passwordConfirm = $this->request->getPost('password_confirm');
|
|
|
|
// Валидация
|
|
$errors = [];
|
|
|
|
if (empty($name) || strlen($name) < 2) {
|
|
$errors[] = 'Имя должно содержать минимум 2 символа';
|
|
}
|
|
|
|
if (empty($password) || strlen($password) < 8) {
|
|
$errors[] = 'Пароль должен содержать минимум 8 символов';
|
|
}
|
|
|
|
if ($password !== $passwordConfirm) {
|
|
$errors[] = 'Пароли не совпадают';
|
|
}
|
|
|
|
if (!empty($errors)) {
|
|
return redirect()->back()->withInput()->with('errors', $errors);
|
|
}
|
|
|
|
$invitation = $this->invitationService->orgUserModel->findByInviteToken($token);
|
|
|
|
if (!$invitation) {
|
|
return redirect()->to('/');
|
|
}
|
|
|
|
// Находим теневую запись пользователя
|
|
$userModel = new UserModel();
|
|
|
|
// Если user_id указан - обновляем существующего пользователя
|
|
if ($invitation['user_id']) {
|
|
$user = $userModel->find($invitation['user_id']);
|
|
if (!$user) {
|
|
session()->setFlashdata('error', 'Пользователь не найден');
|
|
return redirect()->to('/invitation/complete/' . $token);
|
|
}
|
|
|
|
// Обновляем профиль
|
|
$userModel->update($user['id'], [
|
|
'name' => $name,
|
|
'password' => $password,
|
|
]);
|
|
|
|
$userId = $user['id'];
|
|
} else {
|
|
// Создаем нового пользователя (теневой + реальный)
|
|
// На самом деле у нас уже есть запись в users - нужно её "активировать"
|
|
$shadowUsers = $userModel->where('email', $userModel->getFindByEmail($invitation['organization_id']))->findAll();
|
|
// Логика для теневых пользователей требует доработки
|
|
|
|
session()->setFlashdata('error', 'Ошибка регистрации');
|
|
return redirect()->to('/invitation/complete/' . $token);
|
|
}
|
|
|
|
// Авторизуем пользователя
|
|
$user = $userModel->find($userId);
|
|
$this->loginUser($user);
|
|
|
|
// Принимаем приглашение
|
|
$result = $this->invitationService->acceptInvitation($token, $userId);
|
|
|
|
if (!$result['success']) {
|
|
session()->setFlashdata('error', $result['message']);
|
|
return redirect()->to('/');
|
|
}
|
|
|
|
session()->setFlashdata('success', 'Добро пожаловать! Вы успешно зарегистрировались и приняли приглашение.');
|
|
|
|
// Переключаем организацию
|
|
session()->set('active_org_id', $result['organization_id']);
|
|
(new AccessService())->resetCache();
|
|
|
|
return redirect()->to('/');
|
|
}
|
|
|
|
/**
|
|
* Авторизация пользователя после регистрации
|
|
*/
|
|
protected function loginUser(array $user): void
|
|
{
|
|
session()->set([
|
|
'user_id' => $user['id'],
|
|
'email' => $user['email'],
|
|
'name' => $user['name'],
|
|
'logged_in' => true,
|
|
]);
|
|
}
|
|
}
|