first commit
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
<?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('/');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use App\Models\OrganizationModel;
|
||||
|
||||
/**
|
||||
* BaseController provides a convenient place for loading components
|
||||
* and performing functions that are needed by all your controllers.
|
||||
*
|
||||
* Extend this class in any new controllers:
|
||||
* ```
|
||||
* class Home extends BaseController
|
||||
* ```
|
||||
*
|
||||
* For security, be sure to declare any new methods as protected or private.
|
||||
*/
|
||||
abstract class BaseController extends Controller
|
||||
{
|
||||
/**
|
||||
* Be sure to declare properties for any property fetch you initialized.
|
||||
* The creation of dynamic property is deprecated in PHP 8.2.
|
||||
*/
|
||||
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
|
||||
{
|
||||
// Load here all helpers you want to be available in your controllers that extend BaseController.
|
||||
// Caution: Do not put the this below the parent::initController() call below.
|
||||
// $this->helpers = ['form', 'url'];
|
||||
|
||||
// Caution: Do not edit this line.
|
||||
parent::initController($request, $response, $logger);
|
||||
|
||||
// Preload any models, libraries, etc, here.
|
||||
$this->session = service('session');
|
||||
}
|
||||
|
||||
public function renderTwig($template, $data = [])
|
||||
{
|
||||
helper('csrf');
|
||||
|
||||
$twig = \Config\Services::twig();
|
||||
|
||||
// oldInput из сессии добавляется в данные шаблона
|
||||
// Расширение TwigGlobalsExtension автоматически добавляет session, alerts, old, currentOrg
|
||||
$oldInput = $this->session->get('_ci_old_input') ?? [];
|
||||
$data['old'] = $data['old'] ?? $oldInput;
|
||||
|
||||
ob_start();
|
||||
$twig->display($template, $data);
|
||||
$content = ob_get_clean();
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Методы для универсальных таблиц
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Конфигурация таблицы - переопределяется в каждом контроллере
|
||||
*/
|
||||
protected function getTableConfig(): array
|
||||
{
|
||||
return [
|
||||
'model' => null,
|
||||
'columns' => [],
|
||||
'searchable' => [],
|
||||
'sortable' => [],
|
||||
'defaultSort' => 'id',
|
||||
'order' => 'asc',
|
||||
'viewPath' => '',
|
||||
'partialPath' => '',
|
||||
'itemsKey' => 'items',
|
||||
'scope' => null, // callable($builder) для дополнительных модификаций
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка AJAX запроса
|
||||
*/
|
||||
protected function isAjax(): bool
|
||||
{
|
||||
$header = $this->request->header('X-Requested-With');
|
||||
$value = $header ? $header->getValue() : '';
|
||||
return strtolower($value) === 'xmlhttprequest';
|
||||
}
|
||||
|
||||
/**
|
||||
* Подготовка данных таблицы (общая логика для всех таблиц)
|
||||
*/
|
||||
protected function prepareTableData(?array $config = null): array
|
||||
{
|
||||
$config = array_merge($this->getTableConfig(), $config ?? []);
|
||||
$page = (int) ($this->request->getGet('page') ?? 1);
|
||||
$perPage = (int) ($this->request->getGet('perPage') ?? 10);
|
||||
$sort = $this->request->getGet('sort') ?? $config['defaultSort'];
|
||||
$order = $this->request->getGet('order') ?? $config['order'];
|
||||
|
||||
// Исправление: получаем фильтры из параметра filters[]
|
||||
$filters = [];
|
||||
$rawFilters = $this->request->getGet('filters');
|
||||
|
||||
if ($rawFilters) {
|
||||
if (is_array($rawFilters)) {
|
||||
$filters = $rawFilters;
|
||||
} else {
|
||||
// Для обратной совместимости, если фильтры пришли в строке
|
||||
parse_str($rawFilters, $filters);
|
||||
if (isset($filters['filters'])) {
|
||||
$filters = $filters['filters'];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Старый способ извлечения фильтров для совместимости
|
||||
foreach ($this->request->getGet() as $key => $value) {
|
||||
if (str_starts_with($key, 'filters[') && str_ends_with($key, ']')) {
|
||||
$field = substr($key, 8, -1); // Исправлено: было 9, должно быть 8
|
||||
$filters[$field] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$model = $config['model'];
|
||||
$builder = $model->builder();
|
||||
|
||||
// Сбрасываем все предыдущие условия
|
||||
$builder->resetQuery();
|
||||
|
||||
if (isset($config['scope']) && is_callable($config['scope'])) {
|
||||
$config['scope']($builder);
|
||||
}
|
||||
|
||||
// Применяем фильтры
|
||||
foreach ($filters as $field => $value) {
|
||||
if ($value !== '' && in_array($field, $config['searchable'])) {
|
||||
$builder->like($field, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// Сортировка
|
||||
if ($sort && in_array($sort, $config['sortable'])) {
|
||||
$builder->orderBy($sort, $order);
|
||||
}
|
||||
|
||||
// Исправлено: countAllResults(false) вместо countAll()
|
||||
// Сохраняем текущее состояние builder для подсчета
|
||||
$countBuilder = clone $builder;
|
||||
$total = $countBuilder->countAllResults(false);
|
||||
|
||||
// Получаем данные с пагинацией
|
||||
$builder->select('*');
|
||||
$items = $builder->limit($perPage, ($page - 1) * $perPage)->get()->getResult();
|
||||
|
||||
$from = ($page - 1) * $perPage + 1;
|
||||
$to = min($page * $perPage, $total);
|
||||
|
||||
$pagerData = [
|
||||
'currentPage' => $page,
|
||||
'pageCount' => $total > 0 ? (int) ceil($total / $perPage) : 1,
|
||||
'total' => $total,
|
||||
'perPage' => $perPage,
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
];
|
||||
|
||||
$pagerStub = new class($pagerData) {
|
||||
private $data;
|
||||
public function __construct(array $data)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
public function getCurrentPage(): int
|
||||
{
|
||||
return $this->data['currentPage'] ?? 1;
|
||||
}
|
||||
public function getPageCount(): int
|
||||
{
|
||||
return $this->data['pageCount'] ?? 1;
|
||||
}
|
||||
public function getTotal(): int
|
||||
{
|
||||
return $this->data['total'] ?? 0;
|
||||
}
|
||||
public function getDetails(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
};
|
||||
|
||||
$data = [
|
||||
$config['itemsKey'] => $items,
|
||||
'pager' => $pagerStub,
|
||||
'pagerDetails' => $pagerData,
|
||||
'perPage' => $perPage,
|
||||
'sort' => $sort,
|
||||
'order' => $order,
|
||||
'filters' => $filters,
|
||||
'columns' => $config['columns'],
|
||||
];
|
||||
|
||||
// В конце prepareTableData, перед return
|
||||
log_message('debug', 'Total records calculated: ' . $total);
|
||||
log_message('debug', 'Organization ID: ' . session()->get('active_org_id'));
|
||||
log_message('debug', 'SQL Query: ' . $countBuilder->getCompiledSelect());
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX endpoint для таблицы - возвращает partial (tbody + tfoot)
|
||||
*/
|
||||
public function table()
|
||||
{
|
||||
$config = $this->getTableConfig();
|
||||
$data = $this->prepareTableData($config);
|
||||
|
||||
if (!$this->isAjax()) {
|
||||
return redirect()->to('/');
|
||||
}
|
||||
|
||||
return $this->renderTwig($config['partialPath'], $data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\OrganizationModel;
|
||||
use App\Models\OrganizationUserModel;
|
||||
|
||||
class Home extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
//log_message('debug', '[HOME INDEX] START: active_org_id = ' . (session()->get('active_org_id') ?? 'NULL'));
|
||||
|
||||
if (!session()->get('isLoggedIn')) {
|
||||
return $this->renderTwig('landing/index');
|
||||
}
|
||||
// Получаем текущую организацию из сессии
|
||||
$orgId = session()->get('active_org_id');
|
||||
if (empty($orgId)){
|
||||
session()->remove('active_org_id');
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
// Загружаем данные организации для шапки (имя, логотип)
|
||||
// $orgModel = new OrganizationModel();
|
||||
// $currentOrg = $orgModel->find($orgId);
|
||||
// // print_r($currentOrg);
|
||||
// // die();
|
||||
// // Если организации нет (сессия слетела), кидаем на выбор
|
||||
// if (!$currentOrg) {
|
||||
// session()->remove('active_org_id');
|
||||
// return redirect()->to('/organizations');
|
||||
// }
|
||||
|
||||
// Передаем данные в шаблон
|
||||
$data = [
|
||||
'title' => 'Рабочий стол',
|
||||
//'currentOrg' => $currentOrg,
|
||||
];
|
||||
|
||||
return $this->renderTwig('dashboard/index', $data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
class Landing extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
// Если пользователь уже залогинен, редиректим его сразу на выбор орги
|
||||
if (session()->get('isLoggedIn')) {
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
|
||||
return $this->renderTwig('landing/index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\OrganizationModel;
|
||||
use App\Models\OrganizationUserModel;
|
||||
|
||||
class Organizations extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$orgModel = new OrganizationModel();
|
||||
$orgUserModel = new OrganizationUserModel();
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
// Получаем организации пользователя через связующую таблицу
|
||||
$userOrgLinks = $orgUserModel->where('user_id', $userId)->findAll();
|
||||
|
||||
// Нам нужно получить сами данные организаций
|
||||
$orgIds = array_column($userOrgLinks, 'organization_id');
|
||||
$organizations = [];
|
||||
|
||||
if (!empty($orgIds)) {
|
||||
$organizations = $orgModel->whereIn('id', $orgIds)->findAll();
|
||||
}
|
||||
|
||||
// Логика автоперехода (как в Auth)
|
||||
// if (count($organizations) === 1) {
|
||||
// session()->set('active_org_id', $organizations[0]['id']);
|
||||
// return redirect()->to('/');
|
||||
// }
|
||||
|
||||
// Если больше 1 или 0, показываем список
|
||||
return $this->renderTwig('organizations/index', [
|
||||
'organizations' => $organizations,
|
||||
'count' => count($organizations)
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
if ($this->request->getMethod() === 'POST') {
|
||||
$orgModel = new OrganizationModel();
|
||||
$orgUserModel = new OrganizationUserModel();
|
||||
|
||||
$rules = [
|
||||
'name' => 'required|min_length[2]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
// Собираем реквизиты в JSON
|
||||
$requisites = [
|
||||
'inn' => trim($this->request->getPost('inn') ?? ''),
|
||||
'ogrn' => trim($this->request->getPost('ogrn') ?? ''),
|
||||
'kpp' => trim($this->request->getPost('kpp') ?? ''),
|
||||
'legal_address' => trim($this->request->getPost('legal_address') ?? ''),
|
||||
'actual_address' => trim($this->request->getPost('actual_address') ?? ''),
|
||||
'phone' => trim($this->request->getPost('phone') ?? ''),
|
||||
'email' => trim($this->request->getPost('email') ?? ''),
|
||||
'website' => trim($this->request->getPost('website') ?? ''),
|
||||
'bank_name' => trim($this->request->getPost('bank_name') ?? ''),
|
||||
'bank_bik' => trim($this->request->getPost('bank_bik') ?? ''),
|
||||
'checking_account' => trim($this->request->getPost('checking_account') ?? ''),
|
||||
'correspondent_account' => trim($this->request->getPost('correspondent_account') ?? ''),
|
||||
];
|
||||
|
||||
// Создаем организацию
|
||||
$orgId = $orgModel->insert([
|
||||
'owner_id' => session()->get('user_id'),
|
||||
'name' => $this->request->getPost('name'),
|
||||
'type' => 'business',
|
||||
'requisites' => json_encode($requisites),
|
||||
'settings' => json_encode([]),
|
||||
]);
|
||||
|
||||
// Привязываем владельца
|
||||
$orgUserModel->insert([
|
||||
'organization_id' => $orgId,
|
||||
'user_id' => session()->get('user_id'),
|
||||
'role' => 'owner',
|
||||
'status' => 'active',
|
||||
'joined_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
// Сразу переключаемся на неё
|
||||
session()->set('active_org_id', $orgId);
|
||||
session()->setFlashdata('success', 'Организация успешно создана!');
|
||||
|
||||
return redirect()->to('/');
|
||||
}
|
||||
|
||||
// GET запрос - форму создания
|
||||
return $this->renderTwig('organizations/create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Редактирование организации
|
||||
*/
|
||||
public function edit($orgId)
|
||||
{
|
||||
$orgModel = new OrganizationModel();
|
||||
$orgUserModel = new OrganizationUserModel();
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
// Проверяем: имеет ли пользователь доступ к этой организации?
|
||||
$membership = $orgUserModel->where('organization_id', $orgId)
|
||||
->where('user_id', $userId)
|
||||
->first();
|
||||
|
||||
if (!$membership) {
|
||||
session()->setFlashdata('error', 'Доступ запрещен');
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
|
||||
// Получаем организацию
|
||||
$organization = $orgModel->find($orgId);
|
||||
if (!$organization) {
|
||||
session()->setFlashdata('error', 'Организация не найдена');
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
|
||||
// Декодируем requisites для формы
|
||||
$requisites = json_decode($organization['requisites'] ?? '{}', true);
|
||||
|
||||
// Если это POST запрос — обновляем данные
|
||||
if ($this->request->getMethod() === 'POST') {
|
||||
$rules = [
|
||||
'name' => 'required|min_length[2]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
// Собираем обновлённые реквизиты
|
||||
$newRequisites = [
|
||||
'inn' => trim($this->request->getPost('inn') ?? ''),
|
||||
'ogrn' => trim($this->request->getPost('ogrn') ?? ''),
|
||||
'kpp' => trim($this->request->getPost('kpp') ?? ''),
|
||||
'legal_address' => trim($this->request->getPost('legal_address') ?? ''),
|
||||
'actual_address' => trim($this->request->getPost('actual_address') ?? ''),
|
||||
'phone' => trim($this->request->getPost('phone') ?? ''),
|
||||
'email' => trim($this->request->getPost('email') ?? ''),
|
||||
'website' => trim($this->request->getPost('website') ?? ''),
|
||||
'bank_name' => trim($this->request->getPost('bank_name') ?? ''),
|
||||
'bank_bik' => trim($this->request->getPost('bank_bik') ?? ''),
|
||||
'checking_account' => trim($this->request->getPost('checking_account') ?? ''),
|
||||
'correspondent_account' => trim($this->request->getPost('correspondent_account') ?? ''),
|
||||
];
|
||||
|
||||
// Обновляем организацию
|
||||
$orgModel->update($orgId, [
|
||||
'name' => $this->request->getPost('name'),
|
||||
'requisites' => json_encode($newRequisites),
|
||||
]);
|
||||
|
||||
session()->setFlashdata('success', 'Организация успешно обновлена!');
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
|
||||
// GET запрос — форма редактирования
|
||||
return $this->renderTwig('organizations/edit', [
|
||||
'organization' => $organization,
|
||||
'requisites' => $requisites
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаление организации
|
||||
*/
|
||||
public function delete($orgId)
|
||||
{
|
||||
$orgModel = new OrganizationModel();
|
||||
$orgUserModel = new OrganizationUserModel();
|
||||
$userId = session()->get('user_id');
|
||||
|
||||
// Проверяем: имеет ли пользователь доступ к этой организации?
|
||||
$membership = $orgUserModel->where('organization_id', $orgId)
|
||||
->where('user_id', $userId)
|
||||
->first();
|
||||
|
||||
if (!$membership) {
|
||||
session()->setFlashdata('error', 'Доступ запрещен');
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
|
||||
// Проверяем, что пользователь — владелец
|
||||
if ($membership['role'] !== 'owner') {
|
||||
session()->setFlashdata('error', 'Только владелец может удалить организацию');
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
|
||||
// Получаем организацию
|
||||
$organization = $orgModel->find($orgId);
|
||||
if (!$organization) {
|
||||
session()->setFlashdata('error', 'Организация не найдена');
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
|
||||
// Если это POST с подтверждением — удаляем
|
||||
if ($this->request->getMethod() === 'POST') {
|
||||
// Удаляем связи с пользователями
|
||||
$orgUserModel->where('organization_id', $orgId)->delete();
|
||||
|
||||
// Мягкое удаление организации
|
||||
$orgModel->delete($orgId);
|
||||
|
||||
// Если удаляли активную организацию — очищаем
|
||||
if (session()->get('active_org_id') == $orgId) {
|
||||
session()->remove('active_org_id');
|
||||
}
|
||||
|
||||
session()->setFlashdata('success', 'Организация "' . $organization['name'] . '" удалена');
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
|
||||
// GET запрос — страница подтверждения удаления
|
||||
return $this->renderTwig('organizations/delete', [
|
||||
'organization' => $organization
|
||||
]);
|
||||
}
|
||||
|
||||
public function switch($orgId)
|
||||
{
|
||||
$userId = session()->get('user_id');
|
||||
$orgUserModel = new OrganizationUserModel();
|
||||
|
||||
// Проверяем: имеет ли пользователь доступ к этой организации?
|
||||
$membership = $orgUserModel->where('organization_id', $orgId)
|
||||
->where('user_id', $userId)
|
||||
->first();
|
||||
|
||||
if ($membership) {
|
||||
session()->set('active_org_id', $orgId);
|
||||
session()->setFlashdata('success', 'Организация изменена');
|
||||
return redirect()->to('/');
|
||||
} else {
|
||||
session()->setFlashdata('error', 'Доступ запрещен');
|
||||
return redirect()->to('/organizations');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user