diff --git a/app/Libraries/Twig/TwigGlobalsExtension.php b/app/Libraries/Twig/TwigGlobalsExtension.php
index 5db223c..fdc77f2 100644
--- a/app/Libraries/Twig/TwigGlobalsExtension.php
+++ b/app/Libraries/Twig/TwigGlobalsExtension.php
@@ -51,9 +51,14 @@ class TwigGlobalsExtension extends AbstractExtension
// Module subscription functions
new TwigFunction('is_module_active', [$this, 'isModuleActive'], ['is_safe' => ['html']]),
new TwigFunction('is_module_available', [$this, 'isModuleAvailable'], ['is_safe' => ['html']]),
+ new TwigFunction('csrf_meta', [$this, 'csrf_meta'], ['is_safe' => ['html']]),
];
}
+ public function csrf_meta()
+ {
+ return csrf_meta();
+ }
// ========================================
// Access Functions для Twig
// ========================================
diff --git a/app/Modules/CRM/Controllers/ContactsController.php b/app/Modules/CRM/Controllers/ContactsController.php
index 0c389a7..7142360 100644
--- a/app/Modules/CRM/Controllers/ContactsController.php
+++ b/app/Modules/CRM/Controllers/ContactsController.php
@@ -249,11 +249,14 @@ class ContactsController extends BaseController
];
}, $contacts);
- return $this->response->setJSON([
- 'success' => true,
- 'items' => $items,
- 'total' => count($items),
- ]);
+ return $this->response
+ ->setHeader('X-CSRF-TOKEN', csrf_hash())
+ ->setHeader('X-CSRF-HASH', csrf_token())
+ ->setJSON([
+ 'success' => true,
+ 'items' => $items,
+ 'total' => count($items),
+ ]);
}
/**
@@ -263,7 +266,12 @@ class ContactsController extends BaseController
public function ajaxStore()
{
$organizationId = $this->requireActiveOrg();
- $customerId = $this->request->getPost('customer_id');
+
+ // Поддержка JSON и form-urlencoded данных
+ $jsonData = $this->request->getJSON(true);
+ $rawInput = $jsonData ?? $this->request->getPost();
+
+ $customerId = $rawInput['customer_id'] ?? null;
// Проверяем клиента если указан
if ($customerId) {
@@ -279,10 +287,10 @@ class ContactsController extends BaseController
$data = [
'organization_id' => $organizationId,
'customer_id' => $customerId ?: null,
- 'name' => $this->request->getPost('name'),
- 'email' => $this->request->getPost('email') ?: null,
- 'phone' => $this->request->getPost('phone') ?: null,
- 'position' => $this->request->getPost('position') ?: null,
+ 'name' => $rawInput['name'] ?? '',
+ 'email' => $rawInput['email'] ?? null,
+ 'phone' => $rawInput['phone'] ?? null,
+ 'position' => $rawInput['position'] ?? null,
];
// Валидация
@@ -304,17 +312,20 @@ class ContactsController extends BaseController
])->setStatusCode(422);
}
- return $this->response->setJSON([
- 'success' => true,
- 'message' => 'Контакт создан',
- 'item' => [
- 'id' => $contactId,
- 'name' => $data['name'],
- 'email' => $data['email'],
- 'phone' => $data['phone'],
- 'position' => $data['position'],
- ],
- ]);
+ return $this->response
+ ->setHeader('X-CSRF-TOKEN', csrf_hash())
+ ->setHeader('X-CSRF-HASH', csrf_token())
+ ->setJSON([
+ 'success' => true,
+ 'message' => 'Контакт создан',
+ 'item' => [
+ 'id' => $contactId,
+ 'name' => $data['name'],
+ 'email' => $data['email'],
+ 'phone' => $data['phone'],
+ 'position' => $data['position'],
+ ],
+ ]);
}
/**
@@ -334,11 +345,15 @@ class ContactsController extends BaseController
])->setStatusCode(404);
}
+ // Поддержка JSON и form-urlencoded данных
+ $jsonData = $this->request->getJSON(true);
+ $rawInput = $jsonData ?? $this->request->getPost();
+
$data = [
- 'name' => $this->request->getPost('name'),
- 'email' => $this->request->getPost('email') ?: null,
- 'phone' => $this->request->getPost('phone') ?: null,
- 'position' => $this->request->getPost('position') ?: null,
+ 'name' => $rawInput['name'] ?? '',
+ 'email' => $rawInput['email'] ?? null,
+ 'phone' => $rawInput['phone'] ?? null,
+ 'position' => $rawInput['position'] ?? null,
];
// Валидация
@@ -360,17 +375,20 @@ class ContactsController extends BaseController
])->setStatusCode(422);
}
- return $this->response->setJSON([
- 'success' => true,
- 'message' => 'Контакт обновлён',
- 'item' => [
- 'id' => $id,
- 'name' => $data['name'],
- 'email' => $data['email'],
- 'phone' => $data['phone'],
- 'position' => $data['position'],
- ],
- ]);
+ return $this->response
+ ->setHeader('X-CSRF-TOKEN', csrf_hash())
+ ->setHeader('X-CSRF-HASH', csrf_token())
+ ->setJSON([
+ 'success' => true,
+ 'message' => 'Контакт обновлён',
+ 'item' => [
+ 'id' => $id,
+ 'name' => $data['name'],
+ 'email' => $data['email'],
+ 'phone' => $data['phone'],
+ 'position' => $data['position'],
+ ],
+ ]);
}
/**
@@ -392,9 +410,12 @@ class ContactsController extends BaseController
$this->contactModel->delete($id);
- return $this->response->setJSON([
- 'success' => true,
- 'message' => 'Контакт удалён',
- ]);
+ return $this->response
+ ->setHeader('X-CSRF-TOKEN', csrf_hash())
+ ->setHeader('X-CSRF-HASH', csrf_token())
+ ->setJSON([
+ 'success' => true,
+ 'message' => 'Контакт удалён',
+ ]);
}
}
diff --git a/app/Views/layouts/base.twig b/app/Views/layouts/base.twig
index 104f0ed..2932a02 100644
--- a/app/Views/layouts/base.twig
+++ b/app/Views/layouts/base.twig
@@ -7,6 +7,7 @@
diff --git a/dump.sql b/dump.sql
deleted file mode 100644
index 78db8c2..0000000
--- a/dump.sql
+++ /dev/null
@@ -1,587 +0,0 @@
-/*M!999999\- enable the sandbox mode */
--- MariaDB dump 10.19-11.8.3-MariaDB, for debian-linux-gnu (x86_64)
---
--- Host: localhost Database: bp_mirv_db
--- ------------------------------------------------------
--- Server version 11.8.3-MariaDB-0+deb13u1 from Debian
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8mb4 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*M!100616 SET @OLD_NOTE_VERBOSITY=@@NOTE_VERBOSITY, NOTE_VERBOSITY=0 */;
-
---
--- Table structure for table `ci_sessions`
---
-
-DROP TABLE IF EXISTS `ci_sessions`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `ci_sessions` (
- `id` varchar(128) NOT NULL,
- `ip_address` varchar(45) NOT NULL,
- `timestamp` int(10) unsigned NOT NULL DEFAULT 0,
- `data` blob DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `timestamp` (`timestamp`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `ci_sessions`
---
-
-LOCK TABLES `ci_sessions` WRITE;
-/*!40000 ALTER TABLE `ci_sessions` DISABLE KEYS */;
-set autocommit=0;
-/*!40000 ALTER TABLE `ci_sessions` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `contacts`
---
-
-DROP TABLE IF EXISTS `contacts`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `contacts` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `organization_id` int(11) unsigned NOT NULL,
- `customer_id` int(11) unsigned NOT NULL COMMENT 'Ссылка на клиента (компанию)',
- `name` varchar(255) NOT NULL COMMENT 'Имя контакта',
- `email` varchar(255) DEFAULT NULL,
- `phone` varchar(50) DEFAULT NULL,
- `position` varchar(255) DEFAULT NULL COMMENT 'Должность',
- `is_primary` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'Основной контакт',
- `notes` text DEFAULT NULL,
- `created_at` datetime DEFAULT NULL,
- `updated_at` datetime DEFAULT NULL,
- `deleted_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `organization_id` (`organization_id`),
- KEY `customer_id` (`customer_id`),
- CONSTRAINT `contacts_customer_id_foreign` FOREIGN KEY (`customer_id`) REFERENCES `organizations_clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT `contacts_organization_id_foreign` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `contacts`
---
-
-LOCK TABLES `contacts` WRITE;
-/*!40000 ALTER TABLE `contacts` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `contacts` VALUES
-(1,12,1,'Петров',NULL,'+79999999955','Вахтер',0,NULL,'2026-01-15 02:50:50','2026-01-15 02:50:50',NULL);
-/*!40000 ALTER TABLE `contacts` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `deal_history`
---
-
-DROP TABLE IF EXISTS `deal_history`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `deal_history` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `deal_id` bigint(20) unsigned NOT NULL,
- `user_id` int(11) unsigned NOT NULL,
- `action` varchar(50) NOT NULL,
- `field_name` varchar(50) DEFAULT NULL,
- `old_value` text DEFAULT NULL,
- `new_value` text DEFAULT NULL,
- `created_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `deal_id` (`deal_id`),
- KEY `user_id` (`user_id`),
- CONSTRAINT `deal_history_deal_id_foreign` FOREIGN KEY (`deal_id`) REFERENCES `deals` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT `deal_history_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `deal_history`
---
-
-LOCK TABLES `deal_history` WRITE;
-/*!40000 ALTER TABLE `deal_history` DISABLE KEYS */;
-set autocommit=0;
-/*!40000 ALTER TABLE `deal_history` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `deal_stages`
---
-
-DROP TABLE IF EXISTS `deal_stages`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `deal_stages` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `organization_id` int(11) unsigned NOT NULL,
- `name` varchar(255) NOT NULL,
- `color` varchar(7) NOT NULL DEFAULT '#6B7280',
- `order_index` int(11) NOT NULL DEFAULT 0,
- `type` enum('progress','won','lost') NOT NULL DEFAULT 'progress',
- `probability` int(3) unsigned NOT NULL DEFAULT 0,
- `created_at` datetime DEFAULT NULL,
- `updated_at` datetime DEFAULT NULL,
- `deleted_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `organization_id` (`organization_id`),
- CONSTRAINT `deal_stages_organization_id_foreign` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `deal_stages`
---
-
-LOCK TABLES `deal_stages` WRITE;
-/*!40000 ALTER TABLE `deal_stages` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `deal_stages` VALUES
-(1,12,'Первый контакт','#6b7280',1,'progress',1,NULL,NULL,NULL),
-(2,12,'Второй контакт','#9a9996',2,'progress',5,NULL,NULL,NULL),
-(3,12,'Переговоры по договору','#c061cb',3,'progress',10,NULL,NULL,NULL);
-/*!40000 ALTER TABLE `deal_stages` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `deals`
---
-
-DROP TABLE IF EXISTS `deals`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `deals` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `organization_id` int(11) unsigned NOT NULL,
- `contact_id` int(11) unsigned DEFAULT NULL,
- `company_id` int(11) unsigned DEFAULT NULL,
- `title` varchar(255) NOT NULL,
- `description` text DEFAULT NULL,
- `amount` decimal(15,2) NOT NULL DEFAULT 0.00,
- `currency` char(3) NOT NULL DEFAULT 'RUB',
- `stage_id` int(11) unsigned NOT NULL,
- `assigned_user_id` int(11) unsigned DEFAULT NULL,
- `expected_close_date` date DEFAULT NULL,
- `created_by` int(11) unsigned NOT NULL,
- `created_at` datetime DEFAULT NULL,
- `updated_at` datetime DEFAULT NULL,
- `deleted_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `organization_id` (`organization_id`),
- KEY `stage_id` (`stage_id`),
- KEY `assigned_user_id` (`assigned_user_id`),
- CONSTRAINT `deals_assigned_user_id_foreign` FOREIGN KEY (`assigned_user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE SET NULL,
- CONSTRAINT `deals_organization_id_foreign` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT `deals_stage_id_foreign` FOREIGN KEY (`stage_id`) REFERENCES `deal_stages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `deals`
---
-
-LOCK TABLES `deals` WRITE;
-/*!40000 ALTER TABLE `deals` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `deals` VALUES
-(1,12,1,1,'Раскрутка сайта','',1000.00,'RUB',3,NULL,NULL,11,'2026-01-15 03:07:32','2026-01-15 03:07:32',NULL),
-(2,12,NULL,1,'Пупупу','',15000.00,'RUB',1,11,'2026-02-28',11,'2026-01-15 03:45:08','2026-01-15 07:43:07',NULL);
-/*!40000 ALTER TABLE `deals` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `migrations`
---
-
-DROP TABLE IF EXISTS `migrations`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `migrations` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
- `version` varchar(255) NOT NULL,
- `class` varchar(255) NOT NULL,
- `group` varchar(255) NOT NULL,
- `namespace` varchar(255) NOT NULL,
- `time` int(11) NOT NULL,
- `batch` int(11) unsigned NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `migrations`
---
-
-LOCK TABLES `migrations` WRITE;
-/*!40000 ALTER TABLE `migrations` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `migrations` VALUES
-(1,'2026-01-07-053357','App\\Database\\Migrations\\CreateUsersTable','default','App',1767769689,1),
-(2,'2026-01-07-053401','App\\Database\\Migrations\\CreateOrganizationsTable','default','App',1767769689,1),
-(3,'2026-01-07-053407','App\\Database\\Migrations\\CreateOrganizationUsersTable','default','App',1767769689,1),
-(4,'2026-01-07-053412','App\\Database\\Migrations\\CreateOrganizationSubscriptionsTable','default','App',1767769689,1),
-(5,'2026-01-07-053413','App\\Database\\Migrations\\CreateOrganizationSubscriptionsTable','default','App',1767769974,2),
-(6,'2026-01-08-000001','App\\Database\\Migrations\\AddEmailVerificationToUsers','default','App',1767870811,3),
-(7,'2026-01-08-200001','App\\Database\\Migrations\\CreateOrganizationsClientsTable','default','App',1767878430,4),
-(8,'2026-01-12-000001','App\\Database\\Migrations\\AddInviteFieldsToOrganizationUsers','default','App',1768267451,5),
-(9,'2026-01-13-000001','App\\Database\\Migrations\\CreateRememberTokensTable','default','App',1768267451,5),
-(10,'2026-01-13-163701','App\\Database\\Migrations\\AddTrialEndsAtToSubscriptions','default','App',1768295204,6),
-(11,'2026-01-13-200001','App\\Database\\Migrations\\CreateCiSessionsTable','default','App',1768313545,7),
-(12,'2026-01-13-200002','App\\Database\\Migrations\\AddPasswordResetFieldsToUsers','default','App',1768313545,7),
-(13,'2026-01-14-000001','App\\Database\\Migrations\\AddSystemRoleToUsers','default','App',1768317531,8),
-(14,'2026-01-15-000001','App\\Database\\Migrations\\AddPlansTable','default','App',1768317531,8),
-(15,'2026-01-15-000002','App\\Database\\Migrations\\CreateOrganizationPlanSubscriptionsTable','default','App',1768320790,9),
-(16,'2026-01-15-000003','App\\Database\\Migrations\\AddTokenExpiresToUsers','default','App',1768372597,10),
-(17,'2026-01-15-000004','App\\Database\\Migrations\\AddInviteExpiresToOrganizationUsers','default','App',1768372597,10),
-(18,'2026-01-15-000005','App\\Database\\Migrations\\AddStatusToOrganizations','default','App',1768376017,11),
-(19,'2026-01-15-000006','App\\Database\\Migrations\\CreateDealsTables','default','App',1768439721,12),
-(21,'2026-01-15-000007','App\\Database\\Migrations\\CreateContactsTable','default','App',1768440786,13),
-(22,'2026-01-16-210001','App\\Database\\Migrations\\DropOrganizationPlanSubscriptionsTable','default','App',1768572350,14),
-(23,'2026-01-16-220001','App\\Database\\Migrations\\CreateModuleSettingsTable','default','App',1768573190,15);
-/*!40000 ALTER TABLE `migrations` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `module_settings`
---
-
-DROP TABLE IF EXISTS `module_settings`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `module_settings` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `module_code` varchar(50) NOT NULL,
- `name` varchar(100) NOT NULL,
- `description` varchar(255) NOT NULL,
- `price_monthly` int(11) NOT NULL DEFAULT 0,
- `price_yearly` int(11) NOT NULL DEFAULT 0,
- `trial_days` int(11) NOT NULL DEFAULT 0,
- `is_active` tinyint(1) NOT NULL DEFAULT 1,
- `created_at` datetime DEFAULT NULL,
- `updated_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `module_code` (`module_code`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `module_settings`
---
-
-LOCK TABLES `module_settings` WRITE;
-/*!40000 ALTER TABLE `module_settings` DISABLE KEYS */;
-set autocommit=0;
-/*!40000 ALTER TABLE `module_settings` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `organization_subscriptions`
---
-
-DROP TABLE IF EXISTS `organization_subscriptions`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `organization_subscriptions` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `organization_id` int(11) unsigned NOT NULL,
- `module_code` varchar(50) NOT NULL,
- `status` enum('trial','active','expired','cancelled') NOT NULL DEFAULT 'trial',
- `trial_ends_at` datetime DEFAULT NULL COMMENT 'Дата окончания триального периода',
- `expires_at` datetime DEFAULT NULL,
- `created_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `organization_id_module_code` (`organization_id`,`module_code`),
- CONSTRAINT `organization_subscriptions_organization_id_foreign` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `organization_subscriptions`
---
-
-LOCK TABLES `organization_subscriptions` WRITE;
-/*!40000 ALTER TABLE `organization_subscriptions` DISABLE KEYS */;
-set autocommit=0;
-/*!40000 ALTER TABLE `organization_subscriptions` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `organization_users`
---
-
-DROP TABLE IF EXISTS `organization_users`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `organization_users` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `organization_id` int(11) unsigned NOT NULL,
- `user_id` int(11) unsigned NOT NULL,
- `role` enum('owner','admin','manager','guest') NOT NULL DEFAULT 'manager',
- `invite_token` varchar(64) DEFAULT NULL,
- `invited_by` int(10) unsigned DEFAULT NULL,
- `invited_at` datetime DEFAULT NULL,
- `invite_expires_at` datetime DEFAULT NULL,
- `status` enum('active','pending','invited','blocked') NOT NULL DEFAULT 'pending',
- `joined_at` datetime DEFAULT NULL,
- `created_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `organization_id_user_id` (`organization_id`,`user_id`),
- KEY `organization_users_user_id_foreign` (`user_id`),
- KEY `idx_org_users_token` (`invite_token`),
- CONSTRAINT `organization_users_organization_id_foreign` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT `organization_users_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `organization_users`
---
-
-LOCK TABLES `organization_users` WRITE;
-/*!40000 ALTER TABLE `organization_users` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `organization_users` VALUES
-(12,12,11,'owner',NULL,NULL,NULL,NULL,'active','2026-01-08 12:48:27',NULL),
-(13,13,11,'owner',NULL,NULL,NULL,NULL,'active','2026-01-08 15:29:08',NULL);
-/*!40000 ALTER TABLE `organization_users` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `organizations`
---
-
-DROP TABLE IF EXISTS `organizations`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `organizations` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `owner_id` int(11) unsigned NOT NULL,
- `name` varchar(255) NOT NULL,
- `type` enum('business','personal') NOT NULL DEFAULT 'business',
- `logo` varchar(255) DEFAULT NULL,
- `requisites` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`requisites`)),
- `trial_ends_at` datetime DEFAULT NULL,
- `settings` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`settings`)),
- `status` enum('active','blocked') NOT NULL DEFAULT 'active',
- `created_at` datetime DEFAULT NULL,
- `updated_at` datetime DEFAULT NULL,
- `deleted_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `organizations_owner_id_foreign` (`owner_id`),
- CONSTRAINT `organizations_owner_id_foreign` FOREIGN KEY (`owner_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `organizations`
---
-
-LOCK TABLES `organizations` WRITE;
-/*!40000 ALTER TABLE `organizations` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `organizations` VALUES
-(12,11,'Личное пространство','personal',NULL,NULL,NULL,NULL,'active','2026-01-08 12:48:27','2026-01-08 12:48:27',NULL),
-(13,11,'Редька','business',NULL,'{\"inn\":\"1112223334\",\"ogrn\":\"1231231231230\",\"kpp\":\"\",\"legal_address\":\"\\u041f\\u0438\\u0442\\u0435\\u0440, \\u041c\\u043e\\u0439\\u043a\\u0430 13\",\"actual_address\":\"\",\"phone\":\"\",\"email\":\"\",\"website\":\"\",\"bank_name\":\"\",\"bank_bik\":\"\",\"checking_account\":\"\",\"correspondent_account\":\"\"}',NULL,'[]','active','2026-01-08 15:29:08','2026-01-14 07:34:02',NULL);
-/*!40000 ALTER TABLE `organizations` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `organizations_clients`
---
-
-DROP TABLE IF EXISTS `organizations_clients`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `organizations_clients` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `organization_id` int(11) unsigned NOT NULL,
- `name` varchar(255) NOT NULL,
- `email` varchar(255) DEFAULT NULL,
- `phone` varchar(50) DEFAULT NULL,
- `notes` text DEFAULT NULL,
- `created_at` datetime DEFAULT NULL,
- `updated_at` datetime DEFAULT NULL,
- `deleted_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `organization_id` (`organization_id`),
- CONSTRAINT `organizations_clients_organization_id_foreign` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `organizations_clients`
---
-
-LOCK TABLES `organizations_clients` WRITE;
-/*!40000 ALTER TABLE `organizations_clients` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `organizations_clients` VALUES
-(1,12,'РогаКопыта','','','Текст','2026-01-08 13:40:47','2026-01-11 15:52:48',NULL),
-(2,12,'Третий','ttt@ttt.com','','','2026-01-08 14:15:49','2026-01-08 14:15:49',NULL),
-(3,12,'ыва','ddd@ddd.com','','','2026-01-08 21:34:38','2026-01-08 21:34:38',NULL),
-(4,12,'ппп','','','','2026-01-12 01:22:38','2026-01-12 01:22:38',NULL),
-(5,12,'ккк','','','','2026-01-12 01:22:43','2026-01-12 01:22:43',NULL),
-(6,12,'еее','','','','2026-01-12 01:22:49','2026-01-12 01:22:49',NULL),
-(7,12,'ннн','','','','2026-01-12 01:22:53','2026-01-12 01:22:53',NULL),
-(8,12,'ггг','test3@test.com','','Вот такие вот заметки ','2026-01-12 01:22:56','2026-01-15 03:51:00',NULL),
-(9,12,'шшш','','','','2026-01-12 01:22:59','2026-01-12 01:22:59',NULL),
-(10,12,'щщщ','','','','2026-01-12 01:23:04','2026-01-12 01:23:04',NULL),
-(11,12,'ффф','','','','2026-01-12 01:23:08','2026-01-12 01:23:08',NULL),
-(12,13,'Супер','','','','2026-01-12 02:56:33','2026-01-12 02:56:33',NULL),
-(13,13,'Супер222','','','','2026-01-12 09:04:04','2026-01-12 09:04:16',NULL);
-/*!40000 ALTER TABLE `organizations_clients` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `plans`
---
-
-DROP TABLE IF EXISTS `plans`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `plans` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `name` varchar(100) NOT NULL,
- `description` text DEFAULT NULL,
- `price` decimal(10,2) NOT NULL DEFAULT 0.00,
- `currency` varchar(3) NOT NULL DEFAULT 'RUB',
- `billing_period` enum('monthly','yearly','quarterly') NOT NULL DEFAULT 'monthly',
- `max_users` int(11) NOT NULL DEFAULT 5,
- `max_clients` int(11) NOT NULL DEFAULT 100,
- `max_storage` int(11) NOT NULL DEFAULT 10,
- `features` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`features`)),
- `is_active` tinyint(4) NOT NULL DEFAULT 1,
- `is_default` tinyint(4) NOT NULL DEFAULT 0,
- `created_at` datetime NOT NULL,
- `updated_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `name` (`name`)
-) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `plans`
---
-
-LOCK TABLES `plans` WRITE;
-/*!40000 ALTER TABLE `plans` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `plans` VALUES
-(1,'Бесплатный','Базовый тариф для небольших команд',0.00,'RUB','monthly',3,50,5,'[\"\\u0411\\u0430\\u0437\\u043e\\u0432\\u044b\\u0435 \\u043c\\u043e\\u0434\\u0443\\u043b\\u0438\",\"Email \\u043f\\u043e\\u0434\\u0434\\u0435\\u0440\\u0436\\u043a\\u0430\",\"\\u042d\\u043a\\u0441\\u043f\\u043e\\u0440\\u0442 \\u0432 CSV\"]',1,1,'2026-01-13 15:18:51',NULL),
-(2,'Старт','Тариф для растущих компаний',990.00,'RUB','monthly',10,500,50,'[\"\\u0412\\u0441\\u0435 \\u043c\\u043e\\u0434\\u0443\\u043b\\u0438\",\"\\u041f\\u0440\\u0438\\u043e\\u0440\\u0438\\u0442\\u0435\\u0442\\u043d\\u0430\\u044f \\u043f\\u043e\\u0434\\u0434\\u0435\\u0440\\u0436\\u043a\\u0430\",\"\\u042d\\u043a\\u0441\\u043f\\u043e\\u0440\\u0442 \\u0432 PDF \\u0438 Excel\",\"API \\u0434\\u043e\\u0441\\u0442\\u0443\\u043f\"]',1,0,'2026-01-13 15:18:51',NULL),
-(3,'Бизнес','Полный функционал для крупных компаний',4990.00,'RUB','monthly',50,5000,500,'[\"\\u0412\\u0441\\u0435 \\u043c\\u043e\\u0434\\u0443\\u043b\\u0438\",\"\\u041f\\u0435\\u0440\\u0441\\u043e\\u043d\\u0430\\u043b\\u044c\\u043d\\u044b\\u0439 \\u043c\\u0435\\u043d\\u0435\\u0434\\u0436\\u0435\\u0440\",\"\\u042d\\u043a\\u0441\\u043f\\u043e\\u0440\\u0442 \\u0432 PDF \\u0438 Excel\",\"\\u041f\\u043e\\u043b\\u043d\\u044b\\u0439 API \\u0434\\u043e\\u0441\\u0442\\u0443\\u043f\",\"\\u0418\\u043d\\u0442\\u0435\\u0433\\u0440\\u0430\\u0446\\u0438\\u0438\",\"\\u0411\\u0440\\u0435\\u043d\\u0434\\u0438\\u043d\\u0433\"]',1,0,'2026-01-13 15:18:51',NULL);
-/*!40000 ALTER TABLE `plans` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `remember_tokens`
---
-
-DROP TABLE IF EXISTS `remember_tokens`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `remember_tokens` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `user_id` int(11) unsigned NOT NULL,
- `selector` varchar(64) NOT NULL,
- `token_hash` varchar(128) NOT NULL,
- `expires_at` datetime NOT NULL,
- `created_at` datetime DEFAULT NULL,
- `user_agent` varchar(500) DEFAULT NULL,
- `ip_address` varchar(45) DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `user_id` (`user_id`),
- KEY `selector` (`selector`),
- KEY `expires_at` (`expires_at`),
- CONSTRAINT `remember_tokens_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
-) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `remember_tokens`
---
-
-LOCK TABLES `remember_tokens` WRITE;
-/*!40000 ALTER TABLE `remember_tokens` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `remember_tokens` VALUES
-(4,11,'508781e7a1d7bfb7b15c4ed38a71e205','dc94c9825eed3efd9d960fdefb9e9048203a2b837d8168e1c78ce1cc3e38f90d','2026-02-13 07:17:58','2026-01-14 07:17:58','Mozilla/5.0 (X11; Linux x86_64; rv:146.0) Gecko/20100101 Firefox/146.0','91.234.172.241');
-/*!40000 ALTER TABLE `remember_tokens` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-
---
--- Table structure for table `users`
---
-
-DROP TABLE IF EXISTS `users`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8mb4 */;
-CREATE TABLE `users` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `email` varchar(255) NOT NULL,
- `password` varchar(255) NOT NULL,
- `system_role` enum('user','admin','superadmin') DEFAULT 'user',
- `name` varchar(100) NOT NULL,
- `phone` varchar(20) DEFAULT NULL,
- `avatar` varchar(255) DEFAULT NULL,
- `created_at` datetime DEFAULT NULL,
- `updated_at` datetime DEFAULT NULL,
- `verification_token` varchar(255) DEFAULT NULL COMMENT 'Токен для подтверждения email',
- `token_expires_at` datetime DEFAULT NULL,
- `email_verified` tinyint(1) DEFAULT 0 COMMENT 'Статус подтверждения email (0 - не подтвержден, 1 - подтвержден)',
- `verified_at` datetime DEFAULT NULL COMMENT 'Дата и время подтверждения email',
- `reset_token` varchar(255) DEFAULT NULL,
- `reset_expires_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `email` (`email`)
-) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `users`
---
-
-LOCK TABLES `users` WRITE;
-/*!40000 ALTER TABLE `users` DISABLE KEYS */;
-set autocommit=0;
-INSERT INTO `users` VALUES
-(11,'mirvtop@yandex.ru','$2y$12$lPkp/tIPEgltYiyIw5ZWuukNPrMdGzfzerRG1oSXbKuBSpVbBmhhu','superadmin','Mirivlad',NULL,'avatar_11_1768273671.jpg','2026-01-08 12:48:27','2026-01-13 15:29:21',NULL,NULL,1,'2026-01-08 12:48:38',NULL,NULL);
-/*!40000 ALTER TABLE `users` ENABLE KEYS */;
-UNLOCK TABLES;
-commit;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*M!100616 SET NOTE_VERBOSITY=@OLD_NOTE_VERBOSITY */;
-
--- Dump completed on 2026-01-16 17:43:45
diff --git a/public/assets/js/base.js b/public/assets/js/base.js
index 7fbcbb4..2b881de 100644
--- a/public/assets/js/base.js
+++ b/public/assets/js/base.js
@@ -5,7 +5,7 @@ document.addEventListener("DOMContentLoaded", function () {
const body = document.body;
// Базовая функция для получения base URL (объявляем ДО использования)
- const baseUrl = '{{ base_url("/") }}'.replace(/\/+$/, '');
+ const baseUrl = '/'.replace(/\/+$/, '');
if (sidebarToggle) {
// Обработчик клика
diff --git a/public/assets/js/modules/contacts.js b/public/assets/js/modules/contacts.js
index 39ad58c..257be27 100644
--- a/public/assets/js/modules/contacts.js
+++ b/public/assets/js/modules/contacts.js
@@ -24,6 +24,16 @@ class ContactsManager {
this.loadContacts();
}
+ /**
+ * Получить заголовки запроса
+ */
+ getHeaders() {
+ return {
+ 'Content-Type': 'application/json',
+ 'X-Requested-With': 'XMLHttpRequest'
+ };
+ }
+
/**
* Загрузить список контактов
*/
@@ -31,9 +41,8 @@ class ContactsManager {
try {
const response = await fetch(`${this.apiUrl}/list/${this.clientId}`, {
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
+ credentials: 'same-origin',
+ headers: this.getHeaders(),
body: JSON.stringify({})
});
@@ -106,6 +115,7 @@ class ContactsManager {
* Отобразить одну строку контакта
*/
renderRow(contact) {
+ const escapedId = this.escapeJs(contact.id);
return `
|
@@ -129,29 +139,27 @@ class ContactsManager {
value="${this.escapeHtml(contact.position || '')}" style="display: none;" placeholder="Должность">
|
- |
-
- `;
+ `;
}
/**
@@ -225,18 +233,16 @@ class ContactsManager {
// Создание нового
response = await fetch(`${this.apiUrl}/store`, {
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
+ credentials: 'same-origin',
+ headers: this.getHeaders(),
body: JSON.stringify(data)
});
} else {
// Обновление существующего
response = await fetch(`${this.apiUrl}/update/${contactId}`, {
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
+ credentials: 'same-origin',
+ headers: this.getHeaders(),
body: JSON.stringify(data)
});
}
@@ -245,13 +251,15 @@ class ContactsManager {
if (result.success) {
// Обновляем локальный массив
- const index = this.contacts.findIndex(c => c.id === contactId);
+ // contactId может быть строкой из data-id, а c.id - числом из БД
+ const contactIdStr = String(contactId);
+ const index = this.contacts.findIndex(c => String(c.id) === contactIdStr);
if (index !== -1) {
if (result.item) {
// Обновляем с реальным ID от сервера
this.contacts[index] = { ...data, id: result.item.id };
} else {
- this.contacts[index] = data;
+ this.contacts[index] = { ...data, id: contactId };
}
}
@@ -270,9 +278,10 @@ class ContactsManager {
* Отменить редактирование
*/
cancel(contactId) {
- if (contactId.toString().startsWith('new_')) {
+ const contactIdStr = String(contactId);
+ if (contactIdStr.startsWith('new_')) {
// Удаляем новую строку
- this.contacts = this.contacts.filter(c => c.id !== contactId);
+ this.contacts = this.contacts.filter(c => String(c.id) !== contactIdStr);
this.render();
} else {
// Перезагружаем данные
@@ -291,16 +300,17 @@ class ContactsManager {
try {
const response = await fetch(`${this.apiUrl}/delete/${contactId}`, {
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
+ credentials: 'same-origin',
+ headers: this.getHeaders(),
body: JSON.stringify({})
});
const result = await response.json();
if (result.success) {
- this.contacts = this.contacts.filter(c => c.id !== contactId);
+ // contactId может быть строкой, а c.id - числом
+ const contactIdStr = String(contactId);
+ this.contacts = this.contacts.filter(c => String(c.id) !== contactIdStr);
this.render();
this.showSuccess(result.message || 'Контакт удалён');
} else {
@@ -361,6 +371,23 @@ class ContactsManager {
div.textContent = text;
return div.innerHTML;
}
+
+ /**
+ * Экранирование для JavaScript строки
+ */
+ escapeJs(text) {
+ if (!text) return '';
+ // Приводим к строке, так как id может быть числом
+ const str = String(text);
+ return str
+ .replace(/\\/g, '\\\\')
+ .replace(/'/g, "\\'")
+ .replace(/"/g, '\\"')
+ .replace(/\n/g, '\\n')
+ .replace(/\r/g, '\\r')
+ .replace(//g, '\\x3e');
+ }
}
// Инициализация при загрузке страницы