начало работы над сессиями и там дохуя чего ещё
This commit is contained in:
		
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,3 @@ | |||||||
| !.gitignore | !.gitignore | ||||||
| composer.phar | composer.phar | ||||||
| vendor | vendor | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								LICENSE
									
									
									
									
									
								
							| @@ -1,11 +1,11 @@ | |||||||
| DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | ||||||
| Version 2, December 2004 | Version 2, December 2004 | ||||||
|  |  | ||||||
| Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> | Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> | ||||||
|  |  | ||||||
| Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. | Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. | ||||||
|  |  | ||||||
| DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | ||||||
| TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||||
|  |  | ||||||
|   0. You just DO WHAT THE FUCK YOU WANT TO. |   0. You just DO WHAT THE FUCK YOU WANT TO. | ||||||
|   | |||||||
| @@ -1,3 +1,3 @@ | |||||||
| # site-account | # site-account | ||||||
|  |  | ||||||
| Site for intersite authentication | Site for intersite authentication | ||||||
							
								
								
									
										113
									
								
								composer.json
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								composer.json
									
									
									
									
									
								
							| @@ -1,57 +1,56 @@ | |||||||
| { | { | ||||||
|     "name": "mirzaev/site-account", |   "name": "mirzaev/site-account", | ||||||
|     "description": "API for intersite authentication", |   "description": "API for intersite authentication", | ||||||
|     "readme": "README.md", |   "readme": "README.md", | ||||||
|     "keywords": [ |   "keywords": [ | ||||||
|         "site", |     "site", | ||||||
|         "api", |     "api", | ||||||
|         "authentication", |     "authentication" | ||||||
|         "auth" |   ], | ||||||
|     ], |   "type": "site", | ||||||
|     "type": "site", |   "homepage": "https://git.mirzaev.sexy/mirzaev/site-account", | ||||||
|     "homepage": "https://git.mirzaev.sexy/mirzaev/site-account", |   "license": "WTFPL", | ||||||
|     "license": "WTFPL", |   "authors": [ | ||||||
|     "authors": [ |     { | ||||||
|         { |       "name": "Arsen Mirzaev Tatyano-Muradovich", | ||||||
|             "name": "Arsen Mirzaev Tatyano-Muradovich", |       "email": "arsen@mirzaev.sexy", | ||||||
|             "email": "arsen@mirzaev.sexy", |       "homepage": "https://mirzaev.sexy", | ||||||
|             "homepage": "https://mirzaev.sexy", |       "role": "Programmer" | ||||||
|             "role": "Programmer" |     } | ||||||
|         } |   ], | ||||||
|     ], |   "support": { | ||||||
|     "support": { |     "email": "arsen@mirzaev.sexy", | ||||||
|         "email": "arsen@mirzaev.sexy", |     "wiki": "https://git.mirzaev.sexy/mirzaev/site-account/wiki", | ||||||
|         "wiki": "https://git.mirzaev.sexy/mirzaev/site-account/wiki", |     "issues": "https://git.mirzaev.sexy/mirzaev/site-account/issues" | ||||||
|         "issues": "https://git.mirzaev.sexy/mirzaev/site-account/issues" |   }, | ||||||
|     }, |   "funding": [ | ||||||
|     "funding": [ |     { | ||||||
|         { |       "type": "funding", | ||||||
|             "type": "funding", |       "url": "https://fund.mirzaev.sexy" | ||||||
|             "url": "https://fund.mirzaev.sexy" |     } | ||||||
|         } |   ], | ||||||
|     ], |   "require": { | ||||||
|     "require": { |     "php": "~8.2", | ||||||
|         "php": "~8.1", |     "ext-sodium": "~8.2", | ||||||
|         "ext-sodium": "~8.1", |     "mirzaev/minimal": "^2.0.x-dev", | ||||||
|         "mirzaev/minimal": "^2.0.x-dev", |     "mirzaev/accounts": "~1.2.x-dev", | ||||||
|         "mirzaev/accounts": "~1.2.x-dev", |     "mirzaev/arangodb": "^1.0.0", | ||||||
|         "mirzaev/arangodb": "^1.0.0", |     "mirzaev/vk": "^5.0", | ||||||
|         "mirzaev/vk": "^5.0", |     "triagens/arangodb": "~3.9.x-dev", | ||||||
|         "triagens/arangodb": "~3.9.x-dev", |     "twig/twig": "^3.4", | ||||||
|         "twig/twig": "^3.4", |     "guzzlehttp/guzzle": "^7.5" | ||||||
|         "guzzlehttp/guzzle": "^7.5" |   }, | ||||||
|     }, |   "require-dev": { | ||||||
|     "require-dev": { |     "phpunit/phpunit": "~9.5" | ||||||
|         "phpunit/phpunit": "~9.5" |   }, | ||||||
|     }, |   "autoload": { | ||||||
|     "autoload": { |     "psr-4": { | ||||||
|         "psr-4": { |       "mirzaev\\site\\account\\": "mirzaev/site/account/system" | ||||||
|             "mirzaev\\site\\account\\": "mirzaev/site/account/system" |     } | ||||||
|         } |   }, | ||||||
|     }, |   "autoload-dev": { | ||||||
|     "autoload-dev": { |     "psr-4": { | ||||||
|         "psr-4": { |       "mirzaev\\site\\account\\tests\\": "mirzaev/site/account/tests" | ||||||
|             "mirzaev\\site\\account\\tests\\": "mirzaev/site/account/tests" |     } | ||||||
|         } |   } | ||||||
|     } | } | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,146 +1,146 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| declare(strict_types=1); | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace mirzaev\site\account\controllers; | namespace mirzaev\site\account\controllers; | ||||||
|  |  | ||||||
| // Файлы проекта | // Файлы проекта | ||||||
| use mirzaev\site\account\controllers\core; | use mirzaev\site\account\controllers\core; | ||||||
| use mirzaev\site\account\models\account_model as account; | use mirzaev\site\account\models\account_model as account; | ||||||
| use mirzaev\site\account\models\session_model as session; | use mirzaev\site\account\models\session_model as session; | ||||||
| use mirzaev\site\account\models\vk_model as vk; | use mirzaev\site\account\models\vk_model as vk; | ||||||
|  |  | ||||||
| // Библиотека для ArangoDB | // Библиотека для ArangoDB | ||||||
| use ArangoDBClient\Document as _document; | use ArangoDBClient\Document as _document; | ||||||
| use stdClass; | use stdClass; | ||||||
|  |  | ||||||
| // Фреймворк для ВКонтакте | // Фреймворк для ВКонтакте | ||||||
| use mirzaev\vk\core as api; | use mirzaev\vk\core as api; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Контроллер аккаунтов |  * Контроллер аккаунтов | ||||||
|  * |  * | ||||||
|  * @package mirzaev\site\account\controllers |  * @package mirzaev\site\account\controllers | ||||||
|  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> |  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> | ||||||
|  */ |  */ | ||||||
| final class account_controller extends core | final class account_controller extends core | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * Страница профиля |      * Страница профиля | ||||||
|      * |      * | ||||||
|      * @param array $parameters Параметры запроса |      * @param array $parameters Параметры запроса | ||||||
|      */ |      */ | ||||||
|     public function index(array $parameters = []): ?string |     public function index(array $parameters = []): ?string | ||||||
|     { |     { | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Инициализация |      * Инициализация | ||||||
|      * |      * | ||||||
|      * @param array $parameters Параметры запроса |      * @param array $parameters Параметры запроса | ||||||
|      */ |      */ | ||||||
|     public function initialization(array $parameters = []): ?string |     public function initialization(array $parameters = []): ?string | ||||||
|     { |     { | ||||||
|         if ($this->variables['account'] instanceof _document) { |         if ($this->variables['account'] instanceof _document) { | ||||||
|             // Найден аккаунт |             // Найден аккаунт | ||||||
|  |  | ||||||
|             if ($this->variables['vk'] instanceof _document) { |             if ($this->variables['vk'] instanceof _document) { | ||||||
|                 // Найден аккаунт ВКонтакте |                 // Найден аккаунт ВКонтакте | ||||||
|  |  | ||||||
|                 // Инициализация данных аккаунта ВКонтакте |                 // Инициализация данных аккаунта ВКонтакте | ||||||
|                 vk::parse($this->variables['vk'], $this->variables['errors']['vk']); |                 vk::parse($this->variables['vk'], $this->variables['errors']['vk']); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Запись кода ответа |             // Запись кода ответа | ||||||
|             http_response_code(200); |             http_response_code(200); | ||||||
|  |  | ||||||
|             return null; |             return null; | ||||||
|         } else { |         } else { | ||||||
|             // Не найден аккаунт |             // Не найден аккаунт | ||||||
|  |  | ||||||
|             // Запись кода ответа |             // Запись кода ответа | ||||||
|             http_response_code(401); |             http_response_code(401); | ||||||
|  |  | ||||||
|             // Запись заголовка ответа с ключом аккаунта |             // Запись заголовка ответа с ключом аккаунта | ||||||
|             header('session: ' . $this->variables['session']->hash); |             header('session: ' . $this->variables['session']->hash); | ||||||
|  |  | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Запись кода ответа |         // Запись кода ответа | ||||||
|         http_response_code(500); |         http_response_code(500); | ||||||
|  |  | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Связь аккаунта с аккаунтом ВКонтакте |      * Связь аккаунта с аккаунтом ВКонтакте | ||||||
|      * |      * | ||||||
|      * @param array $parameters Параметры запроса |      * @param array $parameters Параметры запроса | ||||||
|      */ |      */ | ||||||
|     public function connect(array $parameters = []): ?string |     public function connect(array $parameters = []): ?string | ||||||
|     { |     { | ||||||
|         if ($this->variables['session']->hash === $parameters['state']) { |         if ($this->variables['session']->hash === $parameters['state']) { | ||||||
|             // Совпадает хеш сессии с полученным хешем из ответа ВКонтакте |             // Совпадает хеш сессии с полученным хешем из ответа ВКонтакте | ||||||
|  |  | ||||||
|             if (!empty($response = vk::key($parameters['code'], $this->variables['errors']['vk']))) { |             if (!empty($response = vk::key($parameters['code'], $this->variables['errors']['vk']))) { | ||||||
|                 // Получены данные аккаунта ВКонтакте |                 // Получены данные аккаунта ВКонтакте | ||||||
|  |  | ||||||
|                 if (($this->variables['vk'] = vk::initialization($response, $this->variables['errors']['vk'])) instanceof _document) { |                 if (($this->variables['vk'] = vk::initialization($response, $this->variables['errors']['vk'])) instanceof _document) { | ||||||
|                     // Инициализирован аккаунт ВКонтакте |                     // Инициализирован аккаунт ВКонтакте | ||||||
|  |  | ||||||
|                     if (($this->variables['account'] = vk::account($this->variables['vk'])) instanceof _document) { |                     if (($this->variables['account'] = vk::account($this->variables['vk'])) instanceof _document) { | ||||||
|                         // Найден аккаунт (существующий) |                         // Найден аккаунт (существующий) | ||||||
|  |  | ||||||
|                         if (session::connect($this->variables['session'], $this->variables['account'], $this->variables['errors']['session'])) { |                         if (session::connect($this->variables['session'], $this->variables['account'], $this->variables['errors']['session'])) { | ||||||
|                             // Связана сессия с аккаунтом |                             // Связана сессия с аккаунтом | ||||||
|                         } |                         } | ||||||
|                     } else if (($this->variables['account'] = account::create($this->variables['errors']['account'])) instanceof _document) { |                     } else if (($this->variables['account'] = account::create($this->variables['errors']['account'])) instanceof _document) { | ||||||
|                         // Найден аккаунт (создан новый) |                         // Найден аккаунт (создан новый) | ||||||
|  |  | ||||||
|                         if (session::connect($this->variables['session'], $this->variables['account'], $this->variables['errors']['session'])) { |                         if (session::connect($this->variables['session'], $this->variables['account'], $this->variables['errors']['session'])) { | ||||||
|                             // Связана сессия с аккаунтом |                             // Связана сессия с аккаунтом | ||||||
|  |  | ||||||
|                             if (account::connect($this->variables['account'], $this->variables['vk'], $this->variables['errors']['account'])) { |                             if (account::connect($this->variables['account'], $this->variables['vk'], $this->variables['errors']['account'])) { | ||||||
|                                 // Связан аккаунт с аккаунтом ВКонтакте |                                 // Связан аккаунт с аккаунтом ВКонтакте | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     // Инициализация робота для аккаунта ВКонтакте |                     // Инициализация робота для аккаунта ВКонтакте | ||||||
|                     $this->vk = api::init()->user(key: $this->variables['vk']->access['key']); |                     $this->vk = api::init()->user(key: $this->variables['vk']->access['key']); | ||||||
|  |  | ||||||
|                     if ($this->variables['vk'] instanceof _document) { |                     if ($this->variables['vk'] instanceof _document) { | ||||||
|                         // Инициализирован робот для аккаунта ВКонтакте |                         // Инициализирован робот для аккаунта ВКонтакте | ||||||
|  |  | ||||||
|                         // Инициализация данных аккаунта ВКонтакте |                         // Инициализация данных аккаунта ВКонтакте | ||||||
|                         $data = vk::parse($this->vk, $this->variables['errors']['vk']); |                         $data = vk::parse($this->vk, $this->variables['errors']['vk']); | ||||||
|                         var_dump($data); die; |                         var_dump($data); die; | ||||||
|  |  | ||||||
|                         if ($data instanceof stdClass) { |                         if ($data instanceof stdClass) { | ||||||
|                             // Получены данные ВКонтакте |                             // Получены данные ВКонтакте | ||||||
|  |  | ||||||
|                             // Запись в базу данных |                             // Запись в базу данных | ||||||
|                             vk::update($this->variables['vk'], $data, $this->variables['errors']['vk']); |                             vk::update($this->variables['vk'], $data, $this->variables['errors']['vk']); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Генерация представления |         // Генерация представления | ||||||
|         return $this->view->render(DIRECTORY_SEPARATOR . 'account' . DIRECTORY_SEPARATOR . 'vk.html', $this->variables); |         return $this->view->render(DIRECTORY_SEPARATOR . 'account' . DIRECTORY_SEPARATOR . 'vk.html', $this->variables); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Генерация панели аккаунта |      * Генерация панели аккаунта | ||||||
|      * |      * | ||||||
|      * @param array $parameters Параметры запроса |      * @param array $parameters Параметры запроса | ||||||
|      */ |      */ | ||||||
|     public function panel(array $parameters = []): ?string |     public function panel(array $parameters = []): ?string | ||||||
|     { |     { | ||||||
|         // Генерация представления |         // Генерация представления | ||||||
|         return $this->view->render(DIRECTORY_SEPARATOR . 'account' . DIRECTORY_SEPARATOR . 'panel.html', $this->variables); |         return $this->view->render(DIRECTORY_SEPARATOR . 'account' . DIRECTORY_SEPARATOR . 'panel.html', $this->variables); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -61,7 +61,7 @@ class core extends controller | |||||||
|         $expires = time() + 604800; |         $expires = time() + 604800; | ||||||
|  |  | ||||||
|         // Инициализация сессии (без журналирования) |         // Инициализация сессии (без журналирования) | ||||||
|         $this->variables['session'] = session::initialization($_COOKIE["session"] ?? null, $expires) ?? header('Location: https://mirzaev.sexy/error?code=500&text=Не+удалось+инициализировать+сессию'); |         $this->variables['session'] = new session($_COOKIE["session"] ?? null, $expires) ?? header('Location: https://mirzaev.sexy/error?code=500&text=Не+удалось+инициализировать+сессию'); | ||||||
|  |  | ||||||
|         if ($_COOKIE["session"] ?? null !== $this->variables['session']->hash) { |         if ($_COOKIE["session"] ?? null !== $this->variables['session']->hash) { | ||||||
|             // Изменился хеш сессии (подразумевается, что сессия устарела) |             // Изменился хеш сессии (подразумевается, что сессия устарела) | ||||||
| @@ -78,7 +78,7 @@ class core extends controller | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Инициализация аккаунта (без журналирования) |         // Инициализация аккаунта (без журналирования) | ||||||
|         $this->variables['account'] = session::account($this->variables['session']); |         $this->variables['account'] = $this->variables['session']->account(); | ||||||
|  |  | ||||||
|         if ($this->variables['account'] instanceof _document) { |         if ($this->variables['account'] instanceof _document) { | ||||||
|             // Инициализирован аккаунт |             // Инициализирован аккаунт | ||||||
|   | |||||||
| @@ -1,44 +1,44 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| declare(strict_types=1); | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace mirzaev\site\account\controllers; | namespace mirzaev\site\account\controllers; | ||||||
|  |  | ||||||
| // Файлы проекта | // Файлы проекта | ||||||
| use mirzaev\site\account\controllers\core; | use mirzaev\site\account\controllers\core; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Контроллер ошибок |  * Контроллер ошибок | ||||||
|  * |  * | ||||||
|  * @package mirzaev\site\account\controllers |  * @package mirzaev\site\account\controllers | ||||||
|  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> |  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> | ||||||
|  */ |  */ | ||||||
| final class error_controller extends core | final class error_controller extends core | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * Страница с ошибкой |      * Страница с ошибкой | ||||||
|      * |      * | ||||||
|      * @param array $parameters |      * @param array $parameters | ||||||
|      */ |      */ | ||||||
|     public function index(array $parameters = []): ?string |     public function index(array $parameters = []): ?string | ||||||
|     { |     { | ||||||
|         // Запись текста ошибки в переменную окружения |         // Запись текста ошибки в переменную окружения | ||||||
|         $this->variables['text'] = $parameters['text'] ?? null; |         $this->variables['text'] = $parameters['text'] ?? null; | ||||||
|  |  | ||||||
|         if (isset($parameters['code'])) { |         if (isset($parameters['code'])) { | ||||||
|             // Получен код ошибки |             // Получен код ошибки | ||||||
|  |  | ||||||
|             // Запись кода ошибки в переменную окружения |             // Запись кода ошибки в переменную окружения | ||||||
|             $this->variables['code'] = $parameters['code']; |             $this->variables['code'] = $parameters['code']; | ||||||
|  |  | ||||||
|             // Запись кода ответа |             // Запись кода ответа | ||||||
|             http_response_code($parameters['code']); |             http_response_code($parameters['code']); | ||||||
|  |  | ||||||
|             // Генерация представления |             // Генерация представления | ||||||
|             return $this->view->render(DIRECTORY_SEPARATOR . 'errors' . DIRECTORY_SEPARATOR . 'index.html', $this->variables); |             return $this->view->render(DIRECTORY_SEPARATOR . 'errors' . DIRECTORY_SEPARATOR . 'index.html', $this->variables); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Генерация представления |         // Генерация представления | ||||||
|         return $this->view->render(DIRECTORY_SEPARATOR . 'errors' . DIRECTORY_SEPARATOR . ($parameters['code'] ?? 'index') . '.html', $this->variables); |         return $this->view->render(DIRECTORY_SEPARATOR . 'errors' . DIRECTORY_SEPARATOR . ($parameters['code'] ?? 'index') . '.html', $this->variables); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,59 +1,59 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| declare(strict_types=1); | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace mirzaev\site\account\controllers; | namespace mirzaev\site\account\controllers; | ||||||
|  |  | ||||||
| // Файлы проекта | // Файлы проекта | ||||||
| use mirzaev\site\account\controllers\core; | use mirzaev\site\account\controllers\core; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Контроллер графика |  * Контроллер графика | ||||||
|  * |  * | ||||||
|  * @package mirzaev\site\account\controllers |  * @package mirzaev\site\account\controllers | ||||||
|  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> |  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> | ||||||
|  */ |  */ | ||||||
| final class graph_controller extends core | final class graph_controller extends core | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * Страница с графиком |      * Страница с графиком | ||||||
|      * |      * | ||||||
|      * Можно использовать совместно с элементом <iframe> для изоляции |      * Можно использовать совместно с элементом <iframe> для изоляции | ||||||
|      * содержимого бегущей строки от поисковых роботов |      * содержимого бегущей строки от поисковых роботов | ||||||
|      * |      * | ||||||
|      * @param array $parameters |      * @param array $parameters | ||||||
|      */ |      */ | ||||||
|     public function index(array $parameters = []): ?string |     public function index(array $parameters = []): ?string | ||||||
|     { |     { | ||||||
|         // Инициализация элементов для генерации в головном элементе |         // Инициализация элементов для генерации в головном элементе | ||||||
|         $this->variables['head'] = [ |         $this->variables['head'] = [ | ||||||
|             'title' => 'Бегущая строка', |             'title' => 'Бегущая строка', | ||||||
|             'metas' => [ |             'metas' => [ | ||||||
|                 [ |                 [ | ||||||
|                     'attributes' => [ |                     'attributes' => [ | ||||||
|                         'name' => 'robots', |                         'name' => 'robots', | ||||||
|                         'content' => 'nofollow' |                         'content' => 'nofollow' | ||||||
|                     ] |                     ] | ||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         // Инициализация бегущей строки |         // Инициализация бегущей строки | ||||||
|         $this->variables['graph'] = [ |         $this->variables['graph'] = [ | ||||||
|             'id' => $this->variables['request']['id'] ?? 'graph' |             'id' => $this->variables['request']['id'] ?? 'graph' | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         // Инициализация аттрибутов бегущей строки |         // Инициализация аттрибутов бегущей строки | ||||||
|         $this->variables['graph']['attributes'] = [ |         $this->variables['graph']['attributes'] = [ | ||||||
|  |  | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         // Инициализация элементов бегущей строки |         // Инициализация элементов бегущей строки | ||||||
|         $this->variables['graph']['elements'] = [ |         $this->variables['graph']['elements'] = [ | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         // Генерация представления |         // Генерация представления | ||||||
|         return $this->view->render(DIRECTORY_SEPARATOR . 'graph' . DIRECTORY_SEPARATOR . 'index.html', $this->variables); |         return $this->view->render(DIRECTORY_SEPARATOR . 'graph' . DIRECTORY_SEPARATOR . 'index.html', $this->variables); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,82 +1,82 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| declare(strict_types=1); | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace mirzaev\site\account\controllers; | namespace mirzaev\site\account\controllers; | ||||||
|  |  | ||||||
| // Файлы проекта | // Файлы проекта | ||||||
| use mirzaev\site\account\controllers\core; | use mirzaev\site\account\controllers\core; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Контроллер бегущей строки |  * Контроллер бегущей строки | ||||||
|  * |  * | ||||||
|  * @package mirzaev\site\account\controllers |  * @package mirzaev\site\account\controllers | ||||||
|  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> |  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> | ||||||
|  */ |  */ | ||||||
| final class hotline_controller extends core | final class hotline_controller extends core | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * Страница с бегущей строкой |      * Страница с бегущей строкой | ||||||
|      * |      * | ||||||
|      * Можно использовать совместно с элементом <iframe> для изоляции |      * Можно использовать совместно с элементом <iframe> для изоляции | ||||||
|      * содержимого бегущей строки от поисковых роботов |      * содержимого бегущей строки от поисковых роботов | ||||||
|      * |      * | ||||||
|      * @param array $parameters |      * @param array $parameters | ||||||
|      */ |      */ | ||||||
|     public function index(array $parameters = []): ?string |     public function index(array $parameters = []): ?string | ||||||
|     { |     { | ||||||
|         // Инициализация элементов для генерации в головном элементе |         // Инициализация элементов для генерации в головном элементе | ||||||
|         $this->variables['head'] = [ |         $this->variables['head'] = [ | ||||||
|             'title' => 'Бегущая строка', |             'title' => 'Бегущая строка', | ||||||
|             'metas' => [ |             'metas' => [ | ||||||
|                 [ |                 [ | ||||||
|                     'attributes' => [ |                     'attributes' => [ | ||||||
|                         'name' => 'robots', |                         'name' => 'robots', | ||||||
|                         'content' => 'nofollow' |                         'content' => 'nofollow' | ||||||
|                     ] |                     ] | ||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         // Инициализация бегущей строки |         // Инициализация бегущей строки | ||||||
|         $this->variables['hotline'] = [ |         $this->variables['hotline'] = [ | ||||||
|             'id' => $this->variables['request']['id'] ?? 'hotline' |             'id' => $this->variables['request']['id'] ?? 'hotline' | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         // Инициализация параметров бегущей строки |         // Инициализация параметров бегущей строки | ||||||
|         $this->variables['hotline']['parameters'] = [ |         $this->variables['hotline']['parameters'] = [ | ||||||
|             // 'step' => 2 |             // 'step' => 2 | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         // Инициализация аттрибутов бегущей строки |         // Инициализация аттрибутов бегущей строки | ||||||
|         $this->variables['hotline']['attributes'] = [ |         $this->variables['hotline']['attributes'] = [ | ||||||
|  |  | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         // Инициализация элементов бегущей строки |         // Инициализация элементов бегущей строки | ||||||
|         $this->variables['hotline']['elements'] = [ |         $this->variables['hotline']['elements'] = [ | ||||||
|             ['content' => '1'], |             ['content' => '1'], | ||||||
|             [ |             [ | ||||||
|                 'tag' => 'article', |                 'tag' => 'article', | ||||||
|                 'content' => '2' |                 'content' => '2' | ||||||
|             ], |             ], | ||||||
|             ['content' => '3'], |             ['content' => '3'], | ||||||
|             ['content' => '4'], |             ['content' => '4'], | ||||||
|             ['content' => '5'], |             ['content' => '5'], | ||||||
|             ['content' => '6'], |             ['content' => '6'], | ||||||
|             ['content' => '7'], |             ['content' => '7'], | ||||||
|             ['content' => '8'], |             ['content' => '8'], | ||||||
|             ['content' => '9'], |             ['content' => '9'], | ||||||
|             ['content' => '10'], |             ['content' => '10'], | ||||||
|             ['content' => '11'], |             ['content' => '11'], | ||||||
|             ['content' => '12'], |             ['content' => '12'], | ||||||
|             ['content' => '13'], |             ['content' => '13'], | ||||||
|             ['content' => '14'], |             ['content' => '14'], | ||||||
|             ['content' => '15'] |             ['content' => '15'] | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         // Генерация представления |         // Генерация представления | ||||||
|         return $this->view->render(DIRECTORY_SEPARATOR . 'hotline' . DIRECTORY_SEPARATOR . 'index.html', $this->variables); |         return $this->view->render(DIRECTORY_SEPARATOR . 'hotline' . DIRECTORY_SEPARATOR . 'index.html', $this->variables); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,85 +1,80 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| declare(strict_types=1); | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace mirzaev\site\account\controllers; | namespace mirzaev\site\account\controllers; | ||||||
|  |  | ||||||
| // Файлы проекта | // Файлы проекта | ||||||
| use mirzaev\site\account\controllers\core; | use mirzaev\site\account\controllers\core; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Контроллер основной страницы |  * Контроллер основной страницы | ||||||
|  * |  * | ||||||
|  * @package mirzaev\site\account\controllers |  * @package mirzaev\site\account\controllers | ||||||
|  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> |  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> | ||||||
|  */ |  */ | ||||||
| final class index_controller extends core | final class index_controller extends core | ||||||
| { | { | ||||||
|     /** |   /** | ||||||
|      * Главная страница |    * Главная страница | ||||||
|      * |    * | ||||||
|      * @param array $parameters Параметры запроса |    * @param array $parameters Параметры запроса | ||||||
|      */ |    */ | ||||||
|     public function index(array $parameters = []): ?string |   public function index(array $parameters = []): ?string | ||||||
|     { |   { | ||||||
|         // Инициализация загружаемых категорий |     // Инициализация загружаемых категорий | ||||||
|         $this->variables['include'] = [ |     $this->variables['include'] = [ | ||||||
|             'head' => ['self'], |       'head' => ['self'], | ||||||
|             'body' => ['self'] |       'body' => ['self'] | ||||||
|         ]; |     ]; | ||||||
|  |  | ||||||
|         // Инициализация бегущей строки |     // Инициализация бегущей строки | ||||||
|         $this->variables['hotline'] = [ |     $this->variables['hotline'] = [ | ||||||
|             'id' => $this->variables['request']['id'] ?? 'hotline' |       'id' => $this->variables['request']['id'] ?? 'hotline' | ||||||
|         ]; |     ]; | ||||||
|  |  | ||||||
|         // Инициализация параметров бегущей строки |     // Инициализация параметров бегущей строки | ||||||
|         $this->variables['hotline']['parameters'] = [ |     $this->variables['hotline']['parameters'] = [ | ||||||
|             // 'step' => 2 |       // 'step' => 2 | ||||||
|         ]; |     ]; | ||||||
|  |  | ||||||
|         // Инициализация аттрибутов бегущей строки |     // Инициализация аттрибутов бегущей строки | ||||||
|         $this->variables['hotline']['attributes'] = [ |     $this->variables['hotline']['attributes'] = []; | ||||||
|  |  | ||||||
|         ]; |     // Инициализация элементов бегущей строки | ||||||
|  |     $this->variables['hotline']['elements'] = [ | ||||||
|         // Инициализация элементов бегущей строки |       ['content' => '1'], | ||||||
|         $this->variables['hotline']['elements'] = [ |       [ | ||||||
|             ['content' => '1'], |         'tag' => 'article', | ||||||
|             [ |         'content' => '2' | ||||||
|                 'tag' => 'article', |       ], | ||||||
|                 'content' => '2' |       ['content' => '3'], | ||||||
|             ], |       ['content' => '4'], | ||||||
|             ['content' => '3'], |       ['content' => '5'], | ||||||
|             ['content' => '4'], |       ['content' => '6'], | ||||||
|             ['content' => '5'], |       ['content' => '7'], | ||||||
|             ['content' => '6'], |       ['content' => '8'], | ||||||
|             ['content' => '7'], |       ['content' => '9'], | ||||||
|             ['content' => '8'], |       ['content' => '10'], | ||||||
|             ['content' => '9'], |       ['content' => '11'], | ||||||
|             ['content' => '10'], |       ['content' => '12'], | ||||||
|             ['content' => '11'], |       ['content' => '13'], | ||||||
|             ['content' => '12'], |       ['content' => '14'], | ||||||
|             ['content' => '13'], |       ['content' => '15'] | ||||||
|             ['content' => '14'], |     ]; | ||||||
|             ['content' => '15'] |  | ||||||
|         ]; |     // Инициализация бегущей строки | ||||||
|  |     $this->variables['graph'] = [ | ||||||
|         // Инициализация бегущей строки |       'id' => $this->variables['request']['id'] ?? 'graph' | ||||||
|         $this->variables['graph'] = [ |     ]; | ||||||
|             'id' => $this->variables['request']['id'] ?? 'graph' |  | ||||||
|         ]; |     // Инициализация аттрибутов бегущей строки | ||||||
|  |     $this->variables['graph']['attributes'] = []; | ||||||
|         // Инициализация аттрибутов бегущей строки |  | ||||||
|         $this->variables['graph']['attributes'] = [ |     // Инициализация элементов бегущей строки | ||||||
|  |     $this->variables['graph']['elements'] = []; | ||||||
|         ]; |  | ||||||
|  |     // Генерация представления | ||||||
|         // Инициализация элементов бегущей строки |     return $this->view->render(DIRECTORY_SEPARATOR . 'index.html', $this->variables); | ||||||
|         $this->variables['graph']['elements'] = [ |   } | ||||||
|         ]; | } | ||||||
|  |  | ||||||
|         // Генерация представления |  | ||||||
|         return $this->view->render(DIRECTORY_SEPARATOR . 'index.html', $this->variables); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,169 +1,169 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| declare(strict_types=1); | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace mirzaev\site\account\models; | namespace mirzaev\site\account\models; | ||||||
|  |  | ||||||
| // Файлы проекта | // Файлы проекта | ||||||
| use mirzaev\site\account\models\vk_model as vk; | use mirzaev\site\account\models\vk_model as vk; | ||||||
|  |  | ||||||
| // Фреймворк ArangoDB | // Фреймворк ArangoDB | ||||||
| use mirzaev\arangodb\collection, | use mirzaev\arangodb\collection, | ||||||
|     mirzaev\arangodb\document; |     mirzaev\arangodb\document; | ||||||
|  |  | ||||||
| // Библиотека для ArangoDB | // Библиотека для ArangoDB | ||||||
| use ArangoDBClient\Document as _document; | use ArangoDBClient\Document as _document; | ||||||
|  |  | ||||||
| // Встроенные библиотеки | // Встроенные библиотеки | ||||||
| use exception; | use exception; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Модель регистрации, аутентификации и авторизации |  * Модель регистрации, аутентификации и авторизации | ||||||
|  * |  * | ||||||
|  * @package mirzaev\site\account\models |  * @package mirzaev\site\account\models | ||||||
|  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> |  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> | ||||||
|  */ |  */ | ||||||
| final class account_model extends core | final class account_model extends core | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * Коллекция |      * Коллекция | ||||||
|      */ |      */ | ||||||
|     public const COLLECTION = 'account'; |     public const COLLECTION = 'account'; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Создать |      * Создать | ||||||
|      * |      * | ||||||
|      * @param array &$errors Журнал ошибок |      * @param array &$errors Журнал ошибок | ||||||
|      * |      * | ||||||
|      * @return ?_document Инстанция аккаунта, если удалось создать |      * @return ?_document Инстанция аккаунта, если удалось создать | ||||||
|      */ |      */ | ||||||
|     public static function create(array &$errors = []): ?_document |     public static function create(array &$errors = []): ?_document | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             if (collection::init(static::$db->session, self::COLLECTION)) { |             if (collection::init(static::$db->session, self::COLLECTION)) { | ||||||
|                 // Инициализирована коллекция |                 // Инициализирована коллекция | ||||||
|  |  | ||||||
|                 // Запись аккаунта в базу данных |                 // Запись аккаунта в базу данных | ||||||
|                 $_id = document::write(static::$db->session, self::COLLECTION); |                 $_id = document::write(static::$db->session, self::COLLECTION); | ||||||
|  |  | ||||||
|                 if ($account = collection::search(static::$db->session, sprintf( |                 if ($account = collection::search(static::$db->session, sprintf( | ||||||
|                     <<<AQL |                     <<<AQL | ||||||
|                             FOR d IN %s |                             FOR d IN %s | ||||||
|                             FILTER d._id == '$_id' |                             FILTER d._id == '$_id' | ||||||
|                             RETURN d |                             RETURN d | ||||||
|                         AQL, |                         AQL, | ||||||
|                     self::COLLECTION |                     self::COLLECTION | ||||||
|                 ))) { |                 ))) { | ||||||
|                     // Найден созданный аккаунт |                     // Найден созданный аккаунт | ||||||
|  |  | ||||||
|                     return $account; |                     return $account; | ||||||
|                 } else throw new exception('Не удалось создать аккаунт'); |                 } else throw new exception('Не удалось создать аккаунт'); | ||||||
|             } else throw new exception('Не удалось инициализировать коллекцию'); |             } else throw new exception('Не удалось инициализировать коллекцию'); | ||||||
|         } catch (exception $e) { |         } catch (exception $e) { | ||||||
|             // Запись в журнал ошибок |             // Запись в журнал ошибок | ||||||
|             $errors[] = [ |             $errors[] = [ | ||||||
|                 'text' => $e->getMessage(), |                 'text' => $e->getMessage(), | ||||||
|                 'file' => $e->getFile(), |                 'file' => $e->getFile(), | ||||||
|                 'line' => $e->getLine(), |                 'line' => $e->getLine(), | ||||||
|                 'stack' => $e->getTrace() |                 'stack' => $e->getTrace() | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Связь аккаунта с аккаунтом ВКонтакте |      * Связь аккаунта с аккаунтом ВКонтакте | ||||||
|      * |      * | ||||||
|      * @param _document $account Инстанция аккаунта |      * @param _document $account Инстанция аккаунта | ||||||
|      * @param _document $vk Инстанция аккаунта ВКонтакте |      * @param _document $vk Инстанция аккаунта ВКонтакте | ||||||
|      * @param array &$errors Журнал ошибок |      * @param array &$errors Журнал ошибок | ||||||
|      * |      * | ||||||
|      * @return bool Статус выполнения |      * @return bool Статус выполнения | ||||||
|      */ |      */ | ||||||
|     public static function connect(_document $account, _document $vk, array &$errors = []): bool |     public static function connect(_document $account, _document $vk, array &$errors = []): bool | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             if ( |             if ( | ||||||
|                 collection::init(static::$db->session, self::COLLECTION) |                 collection::init(static::$db->session, self::COLLECTION) | ||||||
|                 && collection::init(static::$db->session, vk::COLLECTION) |                 && collection::init(static::$db->session, vk::COLLECTION) | ||||||
|                 && collection::init(static::$db->session, self::COLLECTION . '_edge_' . vk::COLLECTION, true) |                 && collection::init(static::$db->session, self::COLLECTION . '_edge_' . vk::COLLECTION, true) | ||||||
|             ) { |             ) { | ||||||
|                 // Инициализированы коллекции |                 // Инициализированы коллекции | ||||||
|  |  | ||||||
|                 if (document::write(static::$db->session, self::COLLECTION . '_edge_' . vk::COLLECTION, [ |                 if (document::write(static::$db->session, self::COLLECTION . '_edge_' . vk::COLLECTION, [ | ||||||
|                     '_from' => $account->getId(), |                     '_from' => $account->getId(), | ||||||
|                     '_to' => $vk->getId() |                     '_to' => $vk->getId() | ||||||
|                 ])) { |                 ])) { | ||||||
|                     // Создано ребро: account -> vk |                     // Создано ребро: account -> vk | ||||||
|  |  | ||||||
|                     return true; |                     return true; | ||||||
|                 } else throw new exception('Не удалось создать ребро: account -> vk'); |                 } else throw new exception('Не удалось создать ребро: account -> vk'); | ||||||
|             } else throw new exception('Не удалось инициализировать коллекцию'); |             } else throw new exception('Не удалось инициализировать коллекцию'); | ||||||
|         } catch (exception $e) { |         } catch (exception $e) { | ||||||
|             // Запись в журнал ошибок |             // Запись в журнал ошибок | ||||||
|             $errors[] = [ |             $errors[] = [ | ||||||
|                 'text' => $e->getMessage(), |                 'text' => $e->getMessage(), | ||||||
|                 'file' => $e->getFile(), |                 'file' => $e->getFile(), | ||||||
|                 'line' => $e->getLine(), |                 'line' => $e->getLine(), | ||||||
|                 'stack' => $e->getTrace() |                 'stack' => $e->getTrace() | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Поиск связанного аккаунта ВКонтакте |      * Поиск связанного аккаунта ВКонтакте | ||||||
|      * |      * | ||||||
|      * @param _document $account Инстанция аккаунта |      * @param _document $account Инстанция аккаунта | ||||||
|      * @param array &$errors Журнал ошибок |      * @param array &$errors Журнал ошибок | ||||||
|      * |      * | ||||||
|      * @return ?_document Инстанция аккаунта, если удалось найти |      * @return ?_document Инстанция аккаунта, если удалось найти | ||||||
|      */ |      */ | ||||||
|     public static function vk(_document $account, array &$errors = []): ?_document |     public static function vk(_document $account, array &$errors = []): ?_document | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             if ( |             if ( | ||||||
|                 collection::init(static::$db->session, self::COLLECTION) |                 collection::init(static::$db->session, self::COLLECTION) | ||||||
|                 && collection::init(static::$db->session, vk::COLLECTION) |                 && collection::init(static::$db->session, vk::COLLECTION) | ||||||
|                 && collection::init(static::$db->session, self::COLLECTION . '_edge_' . vk::COLLECTION, true) |                 && collection::init(static::$db->session, self::COLLECTION . '_edge_' . vk::COLLECTION, true) | ||||||
|             ) { |             ) { | ||||||
|                 // Инициализирована коллекция |                 // Инициализирована коллекция | ||||||
|  |  | ||||||
|                 if ($vk = collection::search(static::$db->session, sprintf( |                 if ($vk = collection::search(static::$db->session, sprintf( | ||||||
|                     <<<AQL |                     <<<AQL | ||||||
|                         FOR document IN %s |                         FOR document IN %s | ||||||
|                         LET edge = ( |                         LET edge = ( | ||||||
|                             FOR edge IN %s |                             FOR edge IN %s | ||||||
|                             FILTER edge._from == '%s' |                             FILTER edge._from == '%s' | ||||||
|                             SORT edge._key DESC |                             SORT edge._key DESC | ||||||
|                             LIMIT 1 |                             LIMIT 1 | ||||||
|                             RETURN edge |                             RETURN edge | ||||||
|                         ) |                         ) | ||||||
|                         FILTER document._id == edge[0]._to |                         FILTER document._id == edge[0]._to | ||||||
|                         LIMIT 1 |                         LIMIT 1 | ||||||
|                         RETURN document |                         RETURN document | ||||||
|                     AQL, |                     AQL, | ||||||
|                     vk::COLLECTION, |                     vk::COLLECTION, | ||||||
|                     self::COLLECTION . '_edge_' . vk::COLLECTION, |                     self::COLLECTION . '_edge_' . vk::COLLECTION, | ||||||
|                     $account->getId() |                     $account->getId() | ||||||
|                 ))) { |                 ))) { | ||||||
|                     // Найден аккаунт ВКонтакте |                     // Найден аккаунт ВКонтакте | ||||||
|  |  | ||||||
|                     return $vk; |                     return $vk; | ||||||
|                 } else throw new exception('Не удалось найти аккаунт ВКонтакте'); |                 } else throw new exception('Не удалось найти аккаунт ВКонтакте'); | ||||||
|             } else throw new exception('Не удалось инициализировать коллекцию'); |             } else throw new exception('Не удалось инициализировать коллекцию'); | ||||||
|         } catch (exception $e) { |         } catch (exception $e) { | ||||||
|             // Запись в журнал ошибок |             // Запись в журнал ошибок | ||||||
|             $errors[] = [ |             $errors[] = [ | ||||||
|                 'text' => $e->getMessage(), |                 'text' => $e->getMessage(), | ||||||
|                 'file' => $e->getFile(), |                 'file' => $e->getFile(), | ||||||
|                 'line' => $e->getLine(), |                 'line' => $e->getLine(), | ||||||
|                 'stack' => $e->getTrace() |                 'stack' => $e->getTrace() | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,143 +1,143 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| declare(strict_types=1); | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace mirzaev\site\account\models; | namespace mirzaev\site\account\models; | ||||||
|  |  | ||||||
| use mirzaev\minimal\model; | use mirzaev\minimal\model; | ||||||
|  |  | ||||||
| use mirzaev\arangodb\connection; | use mirzaev\arangodb\connection; | ||||||
|  |  | ||||||
| use exception; | use exception; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Ядро моделей |  * Ядро моделей | ||||||
|  * |  * | ||||||
|  * @package mirzaev\site\account\models |  * @package mirzaev\site\account\models | ||||||
|  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> |  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> | ||||||
|  */ |  */ | ||||||
| class core extends model | class core extends model | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * Коллекция в которой хранятся аккаунты |      * Коллекция в которой хранятся аккаунты | ||||||
|      */ |      */ | ||||||
|     public const SETTINGS = '../settings/arangodb.php'; |     public const SETTINGS = '../settings/arangodb.php'; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Соединение с базой данных |      * Соединение с базой данных | ||||||
|      */ |      */ | ||||||
|     protected static connection $db; |     protected static connection $db; | ||||||
|  |  | ||||||
|     public function __construct(connection $db = null) |     public function __construct(connection $db = null) | ||||||
|     { |     { | ||||||
|         if (isset($db)) { |         if (isset($db)) { | ||||||
|             // Получена инстанция соединения с базой данных |             // Получена инстанция соединения с базой данных | ||||||
|  |  | ||||||
|             // Запись и инициализация соединения с базой данных |             // Запись и инициализация соединения с базой данных | ||||||
|             $this->__set('db', $db); |             $this->__set('db', $db); | ||||||
|         } else { |         } else { | ||||||
|             // Не получена инстанция соединения с базой данных |             // Не получена инстанция соединения с базой данных | ||||||
|  |  | ||||||
|             // Инициализация соединения с базой данных по умолчанию |             // Инициализация соединения с базой данных по умолчанию | ||||||
|             $this->__get('db'); |             $this->__get('db'); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Записать свойство |      * Записать свойство | ||||||
|      * |      * | ||||||
|      * @param string $name Название |      * @param string $name Название | ||||||
|      * @param mixed $value Значение |      * @param mixed $value Значение | ||||||
|      */ |      */ | ||||||
|     public function __set(string $name, mixed $value = null): void |     public function __set(string $name, mixed $value = null): void | ||||||
|     { |     { | ||||||
|         match ($name) { |         match ($name) { | ||||||
|             'db' => (function () use ($value) { |             'db' => (function () use ($value) { | ||||||
|                 if ($this->__isset('db')) { |                 if ($this->__isset('db')) { | ||||||
|                     // Свойство уже было инициализировано |                     // Свойство уже было инициализировано | ||||||
|  |  | ||||||
|                     // Выброс исключения (неудача) |                     // Выброс исключения (неудача) | ||||||
|                     throw new exception('Запрещено реинициализировать соединение с базой данных ($this->db)', 500); |                     throw new exception('Запрещено реинициализировать соединение с базой данных ($this->db)', 500); | ||||||
|                 } else { |                 } else { | ||||||
|                     // Свойство ещё не было инициализировано |                     // Свойство ещё не было инициализировано | ||||||
|  |  | ||||||
|                     if ($value instanceof connection) { |                     if ($value instanceof connection) { | ||||||
|                         // Передано подходящее значение |                         // Передано подходящее значение | ||||||
|  |  | ||||||
|                         // Запись свойства (успех) |                         // Запись свойства (успех) | ||||||
|                         self::$db = $value; |                         self::$db = $value; | ||||||
|                     } else { |                     } else { | ||||||
|                         // Передано неподходящее значение |                         // Передано неподходящее значение | ||||||
|  |  | ||||||
|                         // Выброс исключения (неудача) |                         // Выброс исключения (неудача) | ||||||
|                         throw new exception('Соединение с базой данных ($this->db) должен быть инстанцией mirzaev\arangodb\connection', 500); |                         throw new exception('Соединение с базой данных ($this->db) должен быть инстанцией mirzaev\arangodb\connection', 500); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             })(), |             })(), | ||||||
|             default => parent::__set($name, $value) |             default => parent::__set($name, $value) | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Прочитать свойство |      * Прочитать свойство | ||||||
|      * |      * | ||||||
|      * @param string $name Название |      * @param string $name Название | ||||||
|      * |      * | ||||||
|      * @return mixed Содержимое |      * @return mixed Содержимое | ||||||
|      */ |      */ | ||||||
|     public function __get(string $name): mixed |     public function __get(string $name): mixed | ||||||
|     { |     { | ||||||
|         return match ($name) { |         return match ($name) { | ||||||
|             'db' => (function () { |             'db' => (function () { | ||||||
|                 if (!$this->__isset('db')) { |                 if (!$this->__isset('db')) { | ||||||
|                     // Свойство не инициализировано |                     // Свойство не инициализировано | ||||||
|  |  | ||||||
|                     // Инициализация значения по умолчанию исходя из настроек |                     // Инициализация значения по умолчанию исходя из настроек | ||||||
|                     $this->__set('db', new connection(require static::SETTINGS)); |                     $this->__set('db', new connection(require static::SETTINGS)); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 return self::$db; |                 return self::$db; | ||||||
|             })(), |             })(), | ||||||
|             default => parent::__get($name) |             default => parent::__get($name) | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Проверить свойство на инициализированность |      * Проверить свойство на инициализированность | ||||||
|      * |      * | ||||||
|      * @param string $name Название |      * @param string $name Название | ||||||
|      */ |      */ | ||||||
|     public function __isset(string $name): bool |     public function __isset(string $name): bool | ||||||
|     { |     { | ||||||
|         return match ($name) { |         return match ($name) { | ||||||
|             default => parent::__isset($name) |             default => parent::__isset($name) | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Удалить свойство |      * Удалить свойство | ||||||
|      * |      * | ||||||
|      * @param string $name Название |      * @param string $name Название | ||||||
|      */ |      */ | ||||||
|     public function __unset(string $name): void |     public function __unset(string $name): void | ||||||
|     { |     { | ||||||
|         match ($name) { |         match ($name) { | ||||||
|             default => parent::__isset($name) |             default => parent::__isset($name) | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Статический вызов |      * Статический вызов | ||||||
|      * |      * | ||||||
|      * @param string $name Название |      * @param string $name Название | ||||||
|      * @param array $arguments Параметры |      * @param array $arguments Параметры | ||||||
|      */ |      */ | ||||||
|     public static function __callStatic(string $name, array $arguments): mixed |     public static function __callStatic(string $name, array $arguments): mixed | ||||||
|     { |     { | ||||||
|         match ($name) { |         match ($name) { | ||||||
|             'db' => (new static)->__get('db'), |             'db' => (new static)->__get('db'), | ||||||
|             default => throw new exception("Не найдено свойство или функция: $name", 500) |             default => throw new exception("Не найдено свойство или функция: $name", 500) | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,213 +1,249 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| declare(strict_types=1); | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace mirzaev\site\account\models; | namespace mirzaev\site\account\models; | ||||||
|  |  | ||||||
| // Файлы проекта | // Файлы проекта | ||||||
| use mirzaev\site\account\models\account_model as account; | use mirzaev\site\account\models\account_model as account; | ||||||
|  |  | ||||||
| // Фреймворк ArangoDB | // Фреймворк ArangoDB | ||||||
| use mirzaev\arangodb\collection, | use mirzaev\arangodb\collection, | ||||||
|     mirzaev\arangodb\document; |   mirzaev\arangodb\document; | ||||||
|  |  | ||||||
| // Библиотека для ArangoDB | // Библиотека для ArangoDB | ||||||
| use ArangoDBClient\Document as _document; | use ArangoDBClient\Document as _document; | ||||||
|  |  | ||||||
| // Встроенные библиотеки | // Встроенные библиотеки | ||||||
| use exception; | use exception; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Модель сессий |  * Модель сессий | ||||||
|  * |  * | ||||||
|  * @package mirzaev\site\account\models |  * @package mirzaev\site\account\models | ||||||
|  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> |  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> | ||||||
|  */ |  */ | ||||||
| final class session_model extends core | final class session_model extends core | ||||||
| { | { | ||||||
|     /** |   /** | ||||||
|      * Коллекция |    * Коллекция | ||||||
|      */ |    */ | ||||||
|     public const COLLECTION = 'session'; |   public const COLLECTION = 'session'; | ||||||
|  |  | ||||||
|     /** |   /** | ||||||
|      * Инициализация |    * Данные сессии из базы данных  | ||||||
|      * |    */ | ||||||
|      * @param ?string $hash Хеш сессии в базе данных |   public _document $document; | ||||||
|      * @param ?int $expires Дата окончания работы сессии (используется при создании новой сессии) |  | ||||||
|      * @param array &$errors Журнал ошибок |   /** | ||||||
|      * |    * Конструктор  | ||||||
|      * @return ?_document Инстанция сессии, если удалось найти или создать |    * | ||||||
|      */ |    * Инициализация сессии и запись в свойство $this->document | ||||||
|     public static function initialization(?string $hash = null, ?int $expires = null, array &$errors = []): ?_document |    * | ||||||
|     { |    * @param ?string $hash Хеш сессии в базе данных | ||||||
|         try { |    * @param ?int $expires Дата окончания работы сессии (используется при создании новой сессии) | ||||||
|             if (collection::init(static::$db->session, self::COLLECTION)) { |    * @param array &$errors Журнал ошибок | ||||||
|                 // Инициализирована коллекция |    * | ||||||
|  |    * @return static Инстанция сессии | ||||||
|                 if (isset($hash) && $session = collection::search(static::$db->session, sprintf( |    */ | ||||||
|                     <<<AQL |   public function __construct(?string $hash = null, ?int $expires = null, array &$errors = []) | ||||||
|                         FOR d IN %s |   { | ||||||
|                         FILTER d.hash == '$hash' && d.expires > %d |     try { | ||||||
|                         RETURN d |       if (collection::init(static::$db->session, self::COLLECTION)) { | ||||||
|                     AQL, |         // Инициализирована коллекция | ||||||
|                     self::COLLECTION, |  | ||||||
|                     time() |         if (isset($hash) && $session = collection::search(static::$db->session, sprintf( | ||||||
|                 ))) { |           <<<AQL | ||||||
|                     // Найдена сессия по хешу |             FOR d IN %s | ||||||
|  |             FILTER d.hash == '$hash' && d.expires > %d | ||||||
|                     // Возврат сессии |             RETURN d | ||||||
|                     return $session; |           AQL, | ||||||
|                 } else if ($session = collection::search(static::$db->session, sprintf( |           self::COLLECTION, | ||||||
|                     <<<AQL |           time() | ||||||
|                         FOR d IN %s |         ))) { | ||||||
|                         FILTER d.ip == '%s' && d.expires > %d |           // Найдена сессия по хешу | ||||||
|                         RETURN d |  | ||||||
|                     AQL, |           // Запись в свойство | ||||||
|                     self::COLLECTION, |           $this->document = $session; | ||||||
|                     $_SERVER['REMOTE_ADDR'], |         } else if ($session = collection::search(static::$db->session, sprintf( | ||||||
|                     time() |           <<<AQL | ||||||
|                 ))) { |             FOR d IN %s | ||||||
|                     // Найдена сессия по данным пользователя |             FILTER d.ip == '%s' && d.expires > %d | ||||||
|  |             RETURN d | ||||||
|                     // Возврат сессии |           AQL, | ||||||
|                     return $session; |           self::COLLECTION, | ||||||
|                 } else { |           $_SERVER['REMOTE_ADDR'], | ||||||
|                     // Не найдена сессия |           time() | ||||||
|  |         ))) { | ||||||
|                     // Запись сессии в базу данных |           // Найдена сессия по данным пользователя | ||||||
|                     $_id = document::write(static::$db->session, self::COLLECTION, [ |  | ||||||
|                         'ip' => $_SERVER['REMOTE_ADDR'], |           // Запись в свойство | ||||||
|                         'expires' => $expires ?? time() + 604800 |           $this->document = $session; | ||||||
|                     ]); |         } else { | ||||||
|  |           // Не найдена сессия | ||||||
|                     if ($session = collection::search(static::$db->session, sprintf( |  | ||||||
|                         <<<AQL |           // Запись сессии в базу данных | ||||||
|                             FOR d IN %s |           $_id = document::write(static::$db->session, self::COLLECTION, [ | ||||||
|                             FILTER d._id == '$_id' && d.expires > %d |             'ip' => $_SERVER['REMOTE_ADDR'], | ||||||
|                             RETURN d |             'expires' => $expires ?? time() + 604800 | ||||||
|                         AQL, |           ]); | ||||||
|                         self::COLLECTION, |  | ||||||
|                         time() |           if ($session = collection::search(static::$db->session, sprintf( | ||||||
|                     ))) { |             <<<AQL | ||||||
|                         // Найдена созданная сессия |               FOR d IN %s | ||||||
|  |               FILTER d._id == '$_id' && d.expires > %d | ||||||
|                         // Запись хеша |               RETURN d | ||||||
|                         $session->hash = sodium_bin2hex(sodium_crypto_generichash($_id)); |             AQL, | ||||||
|  |             self::COLLECTION, | ||||||
|                         if (document::update(static::$db->session, $session)) { |             time() | ||||||
|                             // Записано обновление |           ))) { | ||||||
|  |             // Найдена созданная сессия | ||||||
|                             return $session; |  | ||||||
|                         } else throw new exception('Не удалось записать данные сессии'); |             // Запись хеша | ||||||
|                     } else throw new exception('Не удалось создать или найти созданную сессию'); |             $session->hash = sodium_bin2hex(sodium_crypto_generichash($_id)); | ||||||
|                 } |  | ||||||
|             } else throw new exception('Не удалось инициализировать коллекцию'); |             if (document::update(static::$db->session, $session)) { | ||||||
|         } catch (exception $e) { |               // Записано обновление | ||||||
|             // Запись в журнал ошибок |  | ||||||
|             $errors[] = [ |               // Запись в свойство | ||||||
|                 'text' => $e->getMessage(), |               $this->document = $session; | ||||||
|                 'file' => $e->getFile(), |             } else throw new exception('Не удалось записать данные сессии'); | ||||||
|                 'line' => $e->getLine(), |           } else throw new exception('Не удалось создать или найти созданную сессию'); | ||||||
|                 'stack' => $e->getTrace() |         } | ||||||
|             ]; |       } else throw new exception('Не удалось инициализировать коллекцию'); | ||||||
|         } |     } catch (exception $e) { | ||||||
|  |       // Запись в журнал ошибок | ||||||
|         return null; |       $errors[] = [ | ||||||
|     } |         'text' => $e->getMessage(), | ||||||
|  |         'file' => $e->getFile(), | ||||||
|     /** |         'line' => $e->getLine(), | ||||||
|      * Связь сессии с аккаунтом |         'stack' => $e->getTrace() | ||||||
|      * |       ]; | ||||||
|      * @param _document $session Инстанция сессии |     } | ||||||
|      * @param _document $account Инстанция аккаунта |   } | ||||||
|      * @param array &$errors Журнал ошибок |  | ||||||
|      * |   /** | ||||||
|      * @return bool Статус выполнения |    * Связь сессии с аккаунтом | ||||||
|      */ |    * | ||||||
|     public static function connect(_document $session, _document $account, array &$errors = []): bool |    * @param _document $account Инстанция аккаунта | ||||||
|     { |    * @param array &$errors Журнал ошибок | ||||||
|         try { |    * | ||||||
|             if ( |    * @return bool Статус выполнения | ||||||
|                 collection::init(static::$db->session, self::COLLECTION) |    */ | ||||||
|                 && collection::init(static::$db->session, account::COLLECTION) |   public function connect(_document $account, array &$errors = []): bool | ||||||
|                 && collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true) |   { | ||||||
|             ) { |     try { | ||||||
|                 // Инициализирована коллекция |       if ( | ||||||
|  |         collection::init(static::$db->session, self::COLLECTION) | ||||||
|                 if (document::write(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, [ |         && collection::init(static::$db->session, account::COLLECTION) | ||||||
|                     '_from' => $session->getId(), |         && collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true) | ||||||
|                     '_to' => $account->getId() |       ) { | ||||||
|                 ])) { |         // Инициализирована коллекция | ||||||
|                     // Создано ребро: session -> account |  | ||||||
|  |         if (document::write(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, [ | ||||||
|                     return true; |           '_from' => $this->document->getId(), | ||||||
|                 } else throw new exception('Не удалось создать ребро: session -> account'); |           '_to' => $account->getId() | ||||||
|             } else throw new exception('Не удалось инициализировать коллекцию'); |         ])) { | ||||||
|         } catch (exception $e) { |           // Создано ребро: session -> account | ||||||
|             // Запись в журнал ошибок |  | ||||||
|             $errors[] = [ |           return true; | ||||||
|                 'text' => $e->getMessage(), |         } else throw new exception('Не удалось создать ребро: session -> account'); | ||||||
|                 'file' => $e->getFile(), |       } else throw new exception('Не удалось инициализировать коллекцию'); | ||||||
|                 'line' => $e->getLine(), |     } catch (exception $e) { | ||||||
|                 'stack' => $e->getTrace() |       // Запись в журнал ошибок | ||||||
|             ]; |       $errors[] = [ | ||||||
|         } |         'text' => $e->getMessage(), | ||||||
|  |         'file' => $e->getFile(), | ||||||
|         return false; |         'line' => $e->getLine(), | ||||||
|     } |         'stack' => $e->getTrace() | ||||||
|  |       ]; | ||||||
|     /** |     } | ||||||
|      * Поиск связанного аккаунта |  | ||||||
|      * |     return false; | ||||||
|      * @param _document $session Инстанция сессии |   } | ||||||
|      * @param array &$errors Журнал ошибок |  | ||||||
|      * |   /** | ||||||
|      * @return ?_document Инстанция аккаунта, если удалось найти |    * Поиск связанного аккаунта | ||||||
|      */ |    * | ||||||
|     public static function account(_document $session, array &$errors = []): ?_document |    * @param array &$errors Журнал ошибок | ||||||
|     { |    * | ||||||
|         try { |    * @return ?_document Инстанция аккаунта, если удалось найти | ||||||
|             if ( |    */ | ||||||
|                 collection::init(static::$db->session, self::COLLECTION) |   public function account(array &$errors = []): ?_document | ||||||
|                 && collection::init(static::$db->session, account::COLLECTION) |   { | ||||||
|                 && collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true) |     try { | ||||||
|             ) { |       if ( | ||||||
|                 // Инициализированы коллекции |         collection::init(static::$db->session, self::COLLECTION) | ||||||
|  |         && collection::init(static::$db->session, account::COLLECTION) | ||||||
|                 if ($account = collection::search(static::$db->session, sprintf( |         && collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true) | ||||||
|                     <<<AQL |       ) { | ||||||
|                         FOR document IN %s |         // Инициализированы коллекции | ||||||
|                         LET edge = ( |  | ||||||
|                             FOR edge IN %s |         if ($account = collection::search(static::$db->session, sprintf( | ||||||
|                             FILTER edge._from == '%s' |           <<<AQL | ||||||
|                             SORT edge._key DESC |             FOR document IN %s | ||||||
|                             LIMIT 1 |             LET edge = ( | ||||||
|                             RETURN edge |               FOR edge IN %s | ||||||
|                         ) |               FILTER edge._from == '%s' | ||||||
|                         FILTER document._id == edge[0]._to |               SORT edge._key DESC | ||||||
|                         LIMIT 1 |               LIMIT 1 | ||||||
|                         RETURN document |               RETURN edge | ||||||
|                     AQL, |             ) | ||||||
|                     account::COLLECTION, |             FILTER document._id == edge[0]._to | ||||||
|                     self::COLLECTION . '_edge_' . account::COLLECTION, |             LIMIT 1 | ||||||
|                     $session->getId() |             RETURN document | ||||||
|                 ))) { |           AQL, | ||||||
|                     // Найден аккаунт |           account::COLLECTION, | ||||||
|  |           self::COLLECTION . '_edge_' . account::COLLECTION, | ||||||
|                     return $account; |           $this->document->getId() | ||||||
|                 } else throw new exception('Не удалось найти аккаунт'); |         ))) { | ||||||
|             } else throw new exception('Не удалось инициализировать коллекцию'); |           // Найден аккаунт | ||||||
|         } catch (exception $e) { |  | ||||||
|             // Запись в журнал ошибок |           return $account; | ||||||
|             $errors[] = [ |         } else throw new exception('Не удалось найти аккаунт'); | ||||||
|                 'text' => $e->getMessage(), |       } else throw new exception('Не удалось инициализировать коллекцию'); | ||||||
|                 'file' => $e->getFile(), |     } catch (exception $e) { | ||||||
|                 'line' => $e->getLine(), |       // Запись в журнал ошибок | ||||||
|                 'stack' => $e->getTrace() |       $errors[] = [ | ||||||
|             ]; |         'text' => $e->getMessage(), | ||||||
|         } |         'file' => $e->getFile(), | ||||||
|  |         'line' => $e->getLine(), | ||||||
|         return null; |         'stack' => $e->getTrace() | ||||||
|     } |       ]; | ||||||
| } |     } | ||||||
|  |  | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Записать | ||||||
|  |    * | ||||||
|  |    * Ищет свойство, если не находит, то ищет его в инстанции документа сессии из базы данных, | ||||||
|  |    * затем записывает в него переданные данные. Инициализация новых свойств происходит в инстанции | ||||||
|  |    * документа сессии из базы данных  | ||||||
|  |    * | ||||||
|  |    * @param string $name Название | ||||||
|  |    * @param mixed $value Содержимое | ||||||
|  |    * | ||||||
|  |    * @return void | ||||||
|  |    */ | ||||||
|  |   public function __set(string $name, mixed $value = null): void | ||||||
|  |   { | ||||||
|  |     if (isset($this->{$name})) $this->{$name} = $value; | ||||||
|  |     else $this->document->{$name} = $value; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Прочитать | ||||||
|  |    * | ||||||
|  |    * Ищет свойство, если не находит, то ищет его в инстанции документа сессии из базы данных | ||||||
|  |    * | ||||||
|  |    * @param string $name Название | ||||||
|  |    * | ||||||
|  |    * @return mixed Данные свойства инстанции сессии или инстанции документа сессии из базы данных | ||||||
|  |    */ | ||||||
|  |   public function __get(string $name): mixed | ||||||
|  |   { | ||||||
|  |     return $this->{$name} ?? $this->document->{$name}; | ||||||
|  |   } | ||||||
|  | } | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,182 +1,182 @@ | |||||||
| @keyframes glare { | @keyframes glare { | ||||||
|  |  | ||||||
|     2%, |     2%, | ||||||
|     100% { |     100% { | ||||||
|         left   : 130%; |         left   : 130%; | ||||||
|         bottom : -200%; |         bottom : -200%; | ||||||
|         width  : 120px; |         width  : 120px; | ||||||
|         opacity: 0.7; |         opacity: 0.7; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication { | section#authentication { | ||||||
|     z-index       : 1000; |     z-index       : 1000; | ||||||
|     width         : 400px; |     width         : 400px; | ||||||
|     position      : relative; |     position      : relative; | ||||||
|     margin        : 25vh auto; |     margin        : 25vh auto; | ||||||
|     display       : flex; |     display       : flex; | ||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.header { | section#authentication>section.header { | ||||||
|     z-index           : 1000; |     z-index           : 1000; | ||||||
|     height            : 100px; |     height            : 100px; | ||||||
|     margin-left       : -50px; |     margin-left       : -50px; | ||||||
|     padding           : 30px 0; |     padding           : 30px 0; | ||||||
|     display           : flex; |     display           : flex; | ||||||
|     clip-path         : url(#authentication-header-mask); |     clip-path         : url(#authentication-header-mask); | ||||||
|     border-radius     : 3px 3px 0 0; |     border-radius     : 3px 3px 0 0; | ||||||
|     animation-duration: 120s; |     animation-duration: 120s; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.header>img.avatar { | section#authentication>section.header>img.avatar { | ||||||
|     z-index           : 1500; |     z-index           : 1500; | ||||||
|     left              : 6px; |     left              : 6px; | ||||||
|     top               : 36px; |     top               : 36px; | ||||||
|     width             : 88px; |     width             : 88px; | ||||||
|     height            : 88px; |     height            : 88px; | ||||||
|     position          : absolute; |     position          : absolute; | ||||||
|     margin            : auto; |     margin            : auto; | ||||||
|     object-fit        : cover; |     object-fit        : cover; | ||||||
|     border-radius     : 100%; |     border-radius     : 100%; | ||||||
|     cursor            : pointer; |     cursor            : pointer; | ||||||
|     image-rendering   : smooth; |     image-rendering   : smooth; | ||||||
|     box-shadow        : 0px 0px 12px 0px rgba(0, 0, 0, 0.5); |     box-shadow        : 0px 0px 12px 0px rgba(0, 0, 0, 0.5); | ||||||
|     -webkit-box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.5); |     -webkit-box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.5); | ||||||
|     -moz-box-shadow   : 0px 0px 12px 0px rgba(0, 0, 0, 0.5); |     -moz-box-shadow   : 0px 0px 12px 0px rgba(0, 0, 0, 0.5); | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.header>img.avatar:hover { | section#authentication>section.header>img.avatar:hover { | ||||||
|     left              : 0; |     left              : 0; | ||||||
|     top               : 30px; |     top               : 30px; | ||||||
|     width             : 100px; |     width             : 100px; | ||||||
|     height            : 100px; |     height            : 100px; | ||||||
|     box-shadow        : 0px 0px 8px 0px rgba(0, 0, 0, 0.3); |     box-shadow        : 0px 0px 8px 0px rgba(0, 0, 0, 0.3); | ||||||
|     -webkit-box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.3); |     -webkit-box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.3); | ||||||
|     -moz-box-shadow   : 0px 0px 8px 0px rgba(0, 0, 0, 0.3); |     -moz-box-shadow   : 0px 0px 8px 0px rgba(0, 0, 0, 0.3); | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.header>img.cover { | section#authentication>section.header>img.cover { | ||||||
|     z-index        : -5000; |     z-index        : -5000; | ||||||
|     left           : -50px; |     left           : -50px; | ||||||
|     top            : 0; |     top            : 0; | ||||||
|     position       : absolute; |     position       : absolute; | ||||||
|     width          : calc(100% + 100px); |     width          : calc(100% + 100px); | ||||||
|     height         : 100%; |     height         : 100%; | ||||||
|     object-position: 0px 30%; |     object-position: 0px 30%; | ||||||
|     object-fit     : cover; |     object-fit     : cover; | ||||||
|     clip-path      : polygon(50px 0, calc(100% - 50px) 0, calc(100% - 50px) 100%, 50px 100%); |     clip-path      : polygon(50px 0, calc(100% - 50px) 0, calc(100% - 50px) 100%, 50px 100%); | ||||||
|     border-radius  : 0 0 3px 3px; |     border-radius  : 0 0 3px 3px; | ||||||
|     background     : var(--background-above); |     background     : var(--background-above); | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.header>div.glare { | section#authentication>section.header>div.glare { | ||||||
|     z-index                  : 3000; |     z-index                  : 3000; | ||||||
|     left                     : -30px; |     left                     : -30px; | ||||||
|     top                      : -300px; |     top                      : -300px; | ||||||
|     width                    : 30px; |     width                    : 30px; | ||||||
|     height                   : 400%; |     height                   : 400%; | ||||||
|     position                 : absolute; |     position                 : absolute; | ||||||
|     rotate                   : 25deg; |     rotate                   : 25deg; | ||||||
|     opacity                  : 0.2; |     opacity                  : 0.2; | ||||||
|     filter                   : unset; |     filter                   : unset; | ||||||
|     pointer-events           : none; |     pointer-events           : none; | ||||||
|     animation-name           : glare; |     animation-name           : glare; | ||||||
|     animation-duration       : 32s; |     animation-duration       : 32s; | ||||||
|     animation-delay          : 2s; |     animation-delay          : 2s; | ||||||
|     animation-fill-mode      : forwards; |     animation-fill-mode      : forwards; | ||||||
|     animation-timing-function: linear; |     animation-timing-function: linear; | ||||||
|     background-color         : #fff; |     background-color         : #fff; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.header>div { | section#authentication>section.header>div { | ||||||
|     animation-duration: 80s; |     animation-duration: 80s; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.header>a { | section#authentication>section.header>a { | ||||||
|     margin        : auto; |     margin        : auto; | ||||||
|     width         : 100%; |     width         : 100%; | ||||||
|     margin-left   : 110px; |     margin-left   : 110px; | ||||||
|     padding-bottom: 0.5ex; |     padding-bottom: 0.5ex; | ||||||
|     white-space   : nowrap; |     white-space   : nowrap; | ||||||
|     overflow-x    : hidden; |     overflow-x    : hidden; | ||||||
|     text-overflow : ellipsis; |     text-overflow : ellipsis; | ||||||
|     font-size     : 1.3em; |     font-size     : 1.3em; | ||||||
|     font-weight   : bold; |     font-weight   : bold; | ||||||
|     color         : var(--text-inverse); |     color         : var(--text-inverse); | ||||||
|     text-shadow   : 0 0 8px #00000080; |     text-shadow   : 0 0 8px #00000080; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| section#authentication>section.body { | section#authentication>section.body { | ||||||
|     margin-top           : -160px; |     margin-top           : -160px; | ||||||
|     padding              : 180px 30px 20px 30px; |     padding              : 180px 30px 20px 30px; | ||||||
|     gap                  : 3ex; |     gap                  : 3ex; | ||||||
|     display              : flex; |     display              : flex; | ||||||
|     flex-direction       : column; |     flex-direction       : column; | ||||||
|     border-radius        : 3px; |     border-radius        : 3px; | ||||||
|     background-color     : var(--background-above); |     background-color     : var(--background-above); | ||||||
|     /* background-image  : radial-gradient(circle at 70% 20%, #000000A0 0%, var(--background-above) 75%); */ |     /* background-image  : radial-gradient(circle at 70% 20%, #000000A0 0%, var(--background-above) 75%); */ | ||||||
|     box-shadow           : 0px 0px 8px 0px rgba(0, 0, 0, 0.2); |     box-shadow           : 0px 0px 8px 0px rgba(0, 0, 0, 0.2); | ||||||
|     -webkit-box-shadow   : 0px 0px 8px 0px rgba(0, 0, 0, 0.2); |     -webkit-box-shadow   : 0px 0px 8px 0px rgba(0, 0, 0, 0.2); | ||||||
|     -moz-box-shadow      : 0px 0px 8px 0px rgba(0, 0, 0, 0.2); |     -moz-box-shadow      : 0px 0px 8px 0px rgba(0, 0, 0, 0.2); | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body>ul { | section#authentication>section.body>ul { | ||||||
|     margin       : unset; |     margin       : unset; | ||||||
|     margin-left  : 10%; |     margin-left  : 10%; | ||||||
|     margin-bottom: 1ex; |     margin-bottom: 1ex; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body ul ul { | section#authentication>section.body ul ul { | ||||||
|     padding-top: 1ex; |     padding-top: 1ex; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body ul li:not(:last-child) { | section#authentication>section.body ul li:not(:last-child) { | ||||||
|     margin-bottom: 1ex; |     margin-bottom: 1ex; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body div.buttons { | section#authentication>section.body div.buttons { | ||||||
|     display: flex; |     display: flex; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body div.buttons>button { | section#authentication>section.body div.buttons>button { | ||||||
|     padding         : 1ex 2ex; |     padding         : 1ex 2ex; | ||||||
|     cursor          : pointer; |     cursor          : pointer; | ||||||
|     border-radius   : 3px; |     border-radius   : 3px; | ||||||
|     font-size       : 0.9em; |     font-size       : 0.9em; | ||||||
|     background-color: unset; |     background-color: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body div.buttons>button:hover { | section#authentication>section.body div.buttons>button:hover { | ||||||
|     color: var(--text-hover); |     color: var(--text-hover); | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body div.buttons>button:active { | section#authentication>section.body div.buttons>button:active { | ||||||
|     color     : var(--text-active); |     color     : var(--text-active); | ||||||
|     transition: unset; |     transition: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body div.buttons>button:first-of-type { | section#authentication>section.body div.buttons>button:first-of-type { | ||||||
|     margin-left : auto; |     margin-left : auto; | ||||||
|     margin-right: 5%; |     margin-right: 5%; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body div.buttons>button:last-of-type { | section#authentication>section.body div.buttons>button:last-of-type { | ||||||
|     margin-right: auto; |     margin-right: auto; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body div.buttons>button.accept { | section#authentication>section.body div.buttons>button.accept { | ||||||
|     padding         : 1ex 5ex; |     padding         : 1ex 5ex; | ||||||
|     color           : var(--text-inverse); |     color           : var(--text-inverse); | ||||||
|     background-color: #63954d; |     background-color: #63954d; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body div.buttons>button.accept:hover { | section#authentication>section.body div.buttons>button.accept:hover { | ||||||
|     color           : var(--text-inverse-above); |     color           : var(--text-inverse-above); | ||||||
|     background-color: #6fa259; |     background-color: #6fa259; | ||||||
| } | } | ||||||
|  |  | ||||||
| section#authentication>section.body div.buttons>button.accept:active { | section#authentication>section.body div.buttons>button.accept:active { | ||||||
|     background-color: #63954d; |     background-color: #63954d; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,134 +1,134 @@ | |||||||
| @keyframes red { | @keyframes red { | ||||||
|     25% { |     25% { | ||||||
|         left: -240%; |         left: -240%; | ||||||
|         top : -130%; |         top : -130%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     50% { |     50% { | ||||||
|         left: -100%; |         left: -100%; | ||||||
|         top : -120%; |         top : -120%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     75% { |     75% { | ||||||
|         left: -160%; |         left: -160%; | ||||||
|         top : -230%; |         top : -230%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     100% { |     100% { | ||||||
|         left: -250%; |         left: -250%; | ||||||
|         top : -300%; |         top : -300%; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @keyframes blue { | @keyframes blue { | ||||||
|     25% { |     25% { | ||||||
|         left: -180%; |         left: -180%; | ||||||
|         top : -100%; |         top : -100%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     50% { |     50% { | ||||||
|         left: -120%; |         left: -120%; | ||||||
|         top : -250%; |         top : -250%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     75% { |     75% { | ||||||
|         left: -250%; |         left: -250%; | ||||||
|         top : -300%; |         top : -300%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     100% { |     100% { | ||||||
|         left: -280%; |         left: -280%; | ||||||
|         top : -80%; |         top : -80%; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @keyframes green { | @keyframes green { | ||||||
|     25% { |     25% { | ||||||
|         left: -120%; |         left: -120%; | ||||||
|         top : -250%; |         top : -250%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     50% { |     50% { | ||||||
|         left: -250%; |         left: -250%; | ||||||
|         top : -300%; |         top : -300%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     75% { |     75% { | ||||||
|         left: -280%; |         left: -280%; | ||||||
|         top : -80%; |         top : -80%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     100% { |     100% { | ||||||
|         left: -180%; |         left: -180%; | ||||||
|         top : -100%; |         top : -100%; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @keyframes wrap-background { | @keyframes wrap-background { | ||||||
|     25% { |     25% { | ||||||
|         background-color: #9395ff; |         background-color: #9395ff; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     50% { |     50% { | ||||||
|         background-color: #fff393; |         background-color: #fff393; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     75% { |     75% { | ||||||
|         background-color: #534eff; |         background-color: #534eff; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     100% { |     100% { | ||||||
|         background-color: #ff5c5c; |         background-color: #ff5c5c; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| :is(div, section).gradient { | :is(div, section).gradient { | ||||||
|     position                 : relative; |     position                 : relative; | ||||||
|     overflow                 : hidden; |     overflow                 : hidden; | ||||||
|     animation-duration       : 30s; |     animation-duration       : 30s; | ||||||
|     animation-name           : wrap-background; |     animation-name           : wrap-background; | ||||||
|     animation-iteration-count: infinite; |     animation-iteration-count: infinite; | ||||||
|     background-repeat        : no-repeat; |     background-repeat        : no-repeat; | ||||||
|     animation-timing-function: ease-in-out; |     animation-timing-function: ease-in-out; | ||||||
|     background-color         : #ff5c5c; |     background-color         : #ff5c5c; | ||||||
| } | } | ||||||
|  |  | ||||||
| :is(div, section).gradient>div:not(.gradient) { | :is(div, section).gradient>div:not(.gradient) { | ||||||
|     z-index                  : -1000; |     z-index                  : -1000; | ||||||
|     width                    : 500%; |     width                    : 500%; | ||||||
|     height                   : 500%; |     height                   : 500%; | ||||||
|     position                 : absolute; |     position                 : absolute; | ||||||
|     pointer-events           : none; |     pointer-events           : none; | ||||||
|     filter                   : blur(200px); |     filter                   : blur(200px); | ||||||
|     animation-duration       : 12s; |     animation-duration       : 12s; | ||||||
|     background-repeat        : no-repeat; |     background-repeat        : no-repeat; | ||||||
|     animation-timing-function: ease-in-out; |     animation-timing-function: ease-in-out; | ||||||
|     animation-iteration-count: infinite; |     animation-iteration-count: infinite; | ||||||
| } | } | ||||||
|  |  | ||||||
| :is(div, section).gradient>div.red { | :is(div, section).gradient>div.red { | ||||||
|     left          : -250%; |     left          : -250%; | ||||||
|     top           : -300%; |     top           : -300%; | ||||||
|     animation-name: red; |     animation-name: red; | ||||||
|     background-image: radial-gradient(circle, |     background-image: radial-gradient(circle, | ||||||
|             rgba(255, 25, 25, 1) 0%, |             rgba(255, 25, 25, 1) 0%, | ||||||
|             rgba(0, 0, 0, 0) 35%); |             rgba(0, 0, 0, 0) 35%); | ||||||
| } | } | ||||||
|  |  | ||||||
| :is(div, section).gradient>div.blue { | :is(div, section).gradient>div.blue { | ||||||
|     left          : -280%; |     left          : -280%; | ||||||
|     top           : -80%; |     top           : -80%; | ||||||
|     animation-name: blue; |     animation-name: blue; | ||||||
|     background-image: radial-gradient(circle, |     background-image: radial-gradient(circle, | ||||||
|             rgba(25, 25, 255, 0.6) 0%, |             rgba(25, 25, 255, 0.6) 0%, | ||||||
|             rgba(0, 0, 0, 0) 35%); |             rgba(0, 0, 0, 0) 35%); | ||||||
| } | } | ||||||
|  |  | ||||||
| :is(div, section).gradient>div.green { | :is(div, section).gradient>div.green { | ||||||
|     left          : -180%; |     left          : -180%; | ||||||
|     top           : -100%; |     top           : -100%; | ||||||
|     animation-name: green; |     animation-name: green; | ||||||
|     background-image: radial-gradient(circle, |     background-image: radial-gradient(circle, | ||||||
|             rgba(25, 255, 25, 1) 0%, |             rgba(25, 255, 25, 1) 0%, | ||||||
|             rgba(0, 0, 0, 0) 35%); |             rgba(0, 0, 0, 0) 35%); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,245 +1,245 @@ | |||||||
| @keyframes node-select { | @keyframes node-select { | ||||||
|     from { |     from { | ||||||
|         outline-offset: 0px; |         outline-offset: 0px; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     to { |     to { | ||||||
|         outline       : 2px solid var(--grey-light); |         outline       : 2px solid var(--grey-light); | ||||||
|         outline-offset: 10px; |         outline-offset: 10px; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @keyframes node-select-revert { | @keyframes node-select-revert { | ||||||
|     from { |     from { | ||||||
|         outline       : 2px solid var(--grey-light); |         outline       : 2px solid var(--grey-light); | ||||||
|         outline-offset: 10px; |         outline-offset: 10px; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     to { |     to { | ||||||
|         outline-offset: 0px; |         outline-offset: 0px; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @keyframes description-select { | @keyframes description-select { | ||||||
|     from { |     from { | ||||||
|         outline-offset: 0px; |         outline-offset: 0px; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     to { |     to { | ||||||
|         outline       : 2px solid var(--grey); |         outline       : 2px solid var(--grey); | ||||||
|         outline-offset: 10px; |         outline-offset: 10px; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @keyframes description-select-revert { | @keyframes description-select-revert { | ||||||
|     from { |     from { | ||||||
|         outline       : 2px solid var(--grey); |         outline       : 2px solid var(--grey); | ||||||
|         outline-offset: 10px; |         outline-offset: 10px; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     to { |     to { | ||||||
|         outline-offset: 0px; |         outline-offset: 0px; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph { | section.graph { | ||||||
|     z-index   : 0; |     z-index   : 0; | ||||||
|     width     : 100vw; |     width     : 100vw; | ||||||
|     height    : 100vh; |     height    : 100vh; | ||||||
|     position  : absolute; |     position  : absolute; | ||||||
|     transition: unset; |     transition: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph * { | section.graph * { | ||||||
|     transition: unset; |     transition: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph:active { | section.graph:active { | ||||||
|     cursor: move; |     cursor: move; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node { | section.graph article.node { | ||||||
|     z-index                  : 500; |     z-index                  : 500; | ||||||
|     position                 : absolute; |     position                 : absolute; | ||||||
|     display                  : flex; |     display                  : flex; | ||||||
|     cursor                   : grab; |     cursor                   : grab; | ||||||
|     border-radius            : 100%; |     border-radius            : 100%; | ||||||
|     background-color         : var(--node-background); |     background-color         : var(--node-background); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node.animated { | section.graph article.node.animated { | ||||||
|     animation-duration       : 0.1s; |     animation-duration       : 0.1s; | ||||||
|     animation-name           : node-select-revert; |     animation-name           : node-select-revert; | ||||||
|     animation-fill-mode      : forwards; |     animation-fill-mode      : forwards; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node.animated:hover { | section.graph article.node.animated:hover { | ||||||
|     animation-duration       : 0.1s; |     animation-duration       : 0.1s; | ||||||
|     animation-name           : node-select; |     animation-name           : node-select; | ||||||
|     animation-fill-mode      : forwards; |     animation-fill-mode      : forwards; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node:active { | section.graph article.node:active { | ||||||
|     cursor          : grabbing; |     cursor          : grabbing; | ||||||
|     background-color: var(--node-background-important); |     background-color: var(--node-background-important); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>h4.title { | section.graph article.node>h4.title { | ||||||
|     margin    : auto; |     margin    : auto; | ||||||
|     text-align: center; |     text-align: center; | ||||||
|     cursor    : pointer; |     cursor    : pointer; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description { | section.graph article.node>div.description { | ||||||
|     z-index         : 1000; |     z-index         : 1000; | ||||||
|     position        : absolute; |     position        : absolute; | ||||||
|     text-align      : justify; |     text-align      : justify; | ||||||
|     text-align-last : center; |     text-align-last : center; | ||||||
|     border-radius   : 100%; |     border-radius   : 100%; | ||||||
|     overflow        : hidden; |     overflow        : hidden; | ||||||
|     background-color: var(--node-background-completed); |     background-color: var(--node-background-completed); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* section.graph article.node>div.description.animated { | /* section.graph article.node>div.description.animated { | ||||||
|     animation-duration       : 0.1s; |     animation-duration       : 0.1s; | ||||||
|     animation-name           : description-select-revert; |     animation-name           : description-select-revert; | ||||||
|     animation-fill-mode      : forwards; |     animation-fill-mode      : forwards; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description.animated:hover { | section.graph article.node>div.description.animated:hover { | ||||||
|     animation-duration       : 0.1s; |     animation-duration       : 0.1s; | ||||||
|     animation-name           : description-select; |     animation-name           : description-select; | ||||||
|     animation-fill-mode      : forwards; |     animation-fill-mode      : forwards; | ||||||
| } */ | } */ | ||||||
|  |  | ||||||
| section.graph article.node * { | section.graph article.node * { | ||||||
|     transition: 0.1s ease-in; |     transition: 0.1s ease-in; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description>span.wrapper { | section.graph article.node>div.description>span.wrapper { | ||||||
|     width       : 50%; |     width       : 50%; | ||||||
|     height      : 100%; |     height      : 100%; | ||||||
|     shape-margin: 15px; |     shape-margin: 15px; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description>span.left.wrapper { | section.graph article.node>div.description>span.left.wrapper { | ||||||
|     float        : left; |     float        : left; | ||||||
|     shape-outside: polygon(100% 0%, 0% 0%, 0% 100%, 100% 100%, 68% 98%, 38% 90%, 10% 72%, 0% 50%, 10% 28%, 20% 20%, 100% 20%); |     shape-outside: polygon(100% 0%, 0% 0%, 0% 100%, 100% 100%, 68% 98%, 38% 90%, 10% 72%, 0% 50%, 10% 28%, 20% 20%, 100% 20%); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description>span.right.wrapper { | section.graph article.node>div.description>span.right.wrapper { | ||||||
|     float        : right; |     float        : right; | ||||||
|     shape-outside: polygon(0% 100%, 100% 100%, 100% 0%, 0% 0%, 0% 20%, 82% 20%, 90% 28%, 100% 50%, 90% 72%, 60% 90%, 32% 98%); |     shape-outside: polygon(0% 100%, 100% 100%, 100% 0%, 0% 0%, 0% 20%, 82% 20%, 90% 28%, 100% 50%, 90% 72%, 60% 90%, 32% 98%); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description>p { | section.graph article.node>div.description>p { | ||||||
|     z-index   : 1500; |     z-index   : 1500; | ||||||
|     position  : relative; |     position  : relative; | ||||||
|     margin    : 0; |     margin    : 0; | ||||||
|     opacity   : 0; |     opacity   : 0; | ||||||
|     word-break: break-all; |     word-break: break-all; | ||||||
|     color     : var(--text-inverse); |     color     : var(--text-inverse); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description:hover>p { | section.graph article.node>div.description:hover>p { | ||||||
|     opacity: 1; |     opacity: 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description>a.source { | section.graph article.node>div.description>a.source { | ||||||
|     z-index    : 2000; |     z-index    : 2000; | ||||||
|     top        : calc(20% - 1.3em + (1em - 1.3ex)); |     top        : calc(20% - 1.3em + (1em - 1.3ex)); | ||||||
|     left       : 0; |     left       : 0; | ||||||
|     position   : absolute; |     position   : absolute; | ||||||
|     font-weight: bold; |     font-weight: bold; | ||||||
|     font-size  : 1.3em; |     font-size  : 1.3em; | ||||||
|     opacity    : 0; |     opacity    : 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node.white>div.description>a.source { | section.graph article.node.white>div.description>a.source { | ||||||
|     color: var(--text-inverse); |     color: var(--text-inverse); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node.white>div.description>a.source:active { | section.graph article.node.white>div.description>a.source:active { | ||||||
|     color: var(--text-inverse-active); |     color: var(--text-inverse-active); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node.white>div.description>a.source:hover { | section.graph article.node.white>div.description>a.source:hover { | ||||||
|     color: var(--text-inverse-hover); |     color: var(--text-inverse-hover); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node.red>div.description>a.source { | section.graph article.node.red>div.description>a.source { | ||||||
|     color: var(--text-red); |     color: var(--text-red); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node.red>div.description>a.source:active { | section.graph article.node.red>div.description>a.source:active { | ||||||
|     color: var(--text-red-active); |     color: var(--text-red-active); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node.red>div.description>a.source:hover { | section.graph article.node.red>div.description>a.source:hover { | ||||||
|     color: var(--text-red-hover); |     color: var(--text-red-hover); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description>a.source.red:active { | section.graph article.node>div.description>a.source.red:active { | ||||||
|     color: var(--text-red-active); |     color: var(--text-red-active); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description:hover>a.source { | section.graph article.node>div.description:hover>a.source { | ||||||
|     opacity: 1; |     opacity: 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description>a.source:visited ::after { | section.graph article.node>div.description>a.source:visited ::after { | ||||||
|     content         : ''; |     content         : ''; | ||||||
|     width           : 100%; |     width           : 100%; | ||||||
|     height          : 100%; |     height          : 100%; | ||||||
|     background-color: var(--node-background-completed); |     background-color: var(--node-background-completed); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description>img.cover { | section.graph article.node>div.description>img.cover { | ||||||
|     left          : 0; |     left          : 0; | ||||||
|     top           : 0; |     top           : 0; | ||||||
|     position      : absolute; |     position      : absolute; | ||||||
|     width         : 100%; |     width         : 100%; | ||||||
|     height        : 100%; |     height        : 100%; | ||||||
|     object-fit    : cover; |     object-fit    : cover; | ||||||
|     pointer-events: none; |     pointer-events: none; | ||||||
|     filter        : unset; |     filter        : unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>div.description:hover>img.cover { | section.graph article.node>div.description:hover>img.cover { | ||||||
|     filter: blur(5px) brightness(0.5); |     filter: blur(5px) brightness(0.5); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>i.close { | section.graph article.node>i.close { | ||||||
|     z-index   : -2000; |     z-index   : -2000; | ||||||
|     top       : -10%; |     top       : -10%; | ||||||
|     right     : -10%; |     right     : -10%; | ||||||
|     position  : absolute; |     position  : absolute; | ||||||
|     scale     : 0; |     scale     : 0; | ||||||
|     opacity   : 0; |     opacity   : 0; | ||||||
|     cursor    : pointer; |     cursor    : pointer; | ||||||
|     color     : var(--text); |     color     : var(--text); | ||||||
|     transition: 0.2s ease-out; |     transition: 0.2s ease-out; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>i.close:hover { | section.graph article.node>i.close:hover { | ||||||
|     scale     : 1.4 !important; |     scale     : 1.4 !important; | ||||||
|     color     : var(--text-hover); |     color     : var(--text-hover); | ||||||
|     transition: 0.1s ease-in; |     transition: 0.1s ease-in; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph article.node>i.close:active { | section.graph article.node>i.close:active { | ||||||
|     scale     : 1.2 !important; |     scale     : 1.2 !important; | ||||||
|     color     : var(--text-active); |     color     : var(--text-active); | ||||||
|     transition: unset; |     transition: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph svg.connection { | section.graph svg.connection { | ||||||
|     z-index : -500; |     z-index : -500; | ||||||
|     position: absolute; |     position: absolute; | ||||||
|     width   : 100%; |     width   : 100%; | ||||||
|     height  : 100%; |     height  : 100%; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.graph svg.connection>line { | section.graph svg.connection>line { | ||||||
|     stroke: var(--connection); |     stroke: var(--connection); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,31 +1,31 @@ | |||||||
| section.hotline { | section.hotline { | ||||||
|     display: inline-flex; |     display: inline-flex; | ||||||
|     height : 100%; |     height : 100%; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.hotline * { | section.hotline * { | ||||||
|     transition: unset; |     transition: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.hotline:last-child { | section.hotline:last-child { | ||||||
|     margin-bottom: unset; |     margin-bottom: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.hotline>article { | section.hotline>article { | ||||||
|     margin-right    : 18px; |     margin-right    : 18px; | ||||||
|     width           : 140px; |     width           : 140px; | ||||||
|     height          : 190px; |     height          : 190px; | ||||||
|     display         : flex; |     display         : flex; | ||||||
|     align-self      : flex-end; |     align-self      : flex-end; | ||||||
|     border-radius   : 3px; |     border-radius   : 3px; | ||||||
|     background-color: var(--background-light-1); |     background-color: var(--background-light-1); | ||||||
|     box-shadow      : 0px -6px 6px rgba(0, 0, 0, 0.3); |     box-shadow      : 0px -6px 6px rgba(0, 0, 0, 0.3); | ||||||
| } | } | ||||||
|  |  | ||||||
| section.hotline>article:last-child { | section.hotline>article:last-child { | ||||||
|     margin-right: unset; |     margin-right: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| section.hotline>article>* { | section.hotline>article>* { | ||||||
|     margin: auto; |     margin: auto; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,29 +1,29 @@ | |||||||
| .icon.close { | .icon.close { | ||||||
|     box-sizing   : border-box; |     box-sizing   : border-box; | ||||||
|     position     : relative; |     position     : relative; | ||||||
|     display      : block; |     display      : block; | ||||||
|     transform    : scale(var(--ggs, 1)); |     transform    : scale(var(--ggs, 1)); | ||||||
|     width        : 22px; |     width        : 22px; | ||||||
|     height       : 22px; |     height       : 22px; | ||||||
|     border       : 2px solid transparent; |     border       : 2px solid transparent; | ||||||
|     border-radius: 40px |     border-radius: 40px | ||||||
| } | } | ||||||
|  |  | ||||||
| .icon.close::after, | .icon.close::after, | ||||||
| .icon.close::before { | .icon.close::before { | ||||||
|     content      : ""; |     content      : ""; | ||||||
|     display      : block; |     display      : block; | ||||||
|     box-sizing   : border-box; |     box-sizing   : border-box; | ||||||
|     position     : absolute; |     position     : absolute; | ||||||
|     width        : 16px; |     width        : 16px; | ||||||
|     height       : 2px; |     height       : 2px; | ||||||
|     background   : currentColor; |     background   : currentColor; | ||||||
|     transform    : rotate(45deg); |     transform    : rotate(45deg); | ||||||
|     border-radius: 5px; |     border-radius: 5px; | ||||||
|     top          : 8px; |     top          : 8px; | ||||||
|     left         : 1px |     left         : 1px | ||||||
| } | } | ||||||
|  |  | ||||||
| .icon.close::after { | .icon.close::after { | ||||||
|     transform: rotate(-45deg) |     transform: rotate(-45deg) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,225 +1,225 @@ | |||||||
| @import url('/fonts/comissioner.ttf'); | @import url('/fonts/commissioner.ttf'); | ||||||
|  |  | ||||||
| @media (prefers-color-scheme: light) { | @media (prefers-color-scheme: light) { | ||||||
|     :root { |     :root { | ||||||
|         --background-above-1       : #fff; |         --background-above-1       : #fff; | ||||||
|         --background-above         : #fff6f6; |         --background-above         : #fff6f6; | ||||||
|         --background               : #e8dada; |         --background               : #e8dada; | ||||||
|         --background-below         : #d7c5c5; |         --background-below         : #d7c5c5; | ||||||
|         --background-inverse       : #221e1e; |         --background-inverse       : #221e1e; | ||||||
|         --background-inverse-dark  : #120f0f; |         --background-inverse-dark  : #120f0f; | ||||||
|         --node-background-important: #c3eac3; |         --node-background-important: #c3eac3; | ||||||
|         --node-background-completed: #b0c0b0; |         --node-background-completed: #b0c0b0; | ||||||
|         --node-background          : #bdb; |         --node-background          : #bdb; | ||||||
|         --connection               : #b2b7b2; |         --connection               : #b2b7b2; | ||||||
|         --connection-completed     : #d1d1d1; |         --connection-completed     : #d1d1d1; | ||||||
|         --text                     : #151313; |         --text                     : #151313; | ||||||
|         --text-hover               : #463e3e; |         --text-hover               : #463e3e; | ||||||
|         --text-active              : #0e0e0e; |         --text-active              : #0e0e0e; | ||||||
|         --text-inverse-above       : #fff; |         --text-inverse-above       : #fff; | ||||||
|         --text-inverse             : #efefef; |         --text-inverse             : #efefef; | ||||||
|         --text-inverse-below       : #d0d0d0; |         --text-inverse-below       : #d0d0d0; | ||||||
|         --text-red                 : #f8a2a2; |         --text-red                 : #f8a2a2; | ||||||
|         --text-red-hover           : #ffbcbc; |         --text-red-hover           : #ffbcbc; | ||||||
|         --text-red-active          : #e69191; |         --text-red-active          : #e69191; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @media (prefers-color-scheme: dark) { | @media (prefers-color-scheme: dark) { | ||||||
|     :root { |     :root { | ||||||
|         --background-above-1: #322d2d; |         --background-above-1: #322d2d; | ||||||
|         --background-above  : #2b2525; |         --background-above  : #2b2525; | ||||||
|         --background        : #221e1e; |         --background        : #221e1e; | ||||||
|         --background-below  : #121010; |         --background-below  : #121010; | ||||||
|         --node-background   : #221e1e; |         --node-background   : #221e1e; | ||||||
|         --text              : #e6e6e6; |         --text              : #e6e6e6; | ||||||
|         --text-hover        : #fff; |         --text-hover        : #fff; | ||||||
|         --text-active       : #d0d0d0; |         --text-active       : #d0d0d0; | ||||||
|         --text-inverse      : 'dark'; |         --text-inverse      : 'dark'; | ||||||
|         --red-light-1       : #dc4343; |         --red-light-1       : #dc4343; | ||||||
|         --red-light         : #bf3737; |         --red-light         : #bf3737; | ||||||
|         --red               : #a43333; |         --red               : #a43333; | ||||||
|         --red-dark          : #8d2a2a; |         --red-dark          : #8d2a2a; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @keyframes page-background-gradient { | @keyframes page-background-gradient { | ||||||
|     25% { |     25% { | ||||||
|         left: -350%; |         left: -350%; | ||||||
|         top : 0%; |         top : 0%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     50% { |     50% { | ||||||
|         left: 0%; |         left: 0%; | ||||||
|         top : 0%; |         top : 0%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     75% { |     75% { | ||||||
|         left: 0%; |         left: 0%; | ||||||
|         top : -350%; |         top : -350%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     to { |     to { | ||||||
|         left: -350%; |         left: -350%; | ||||||
|         top : -350%; |         top : -350%; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| :root { | :root { | ||||||
|     --link       : #3c76ff; |     --link       : #3c76ff; | ||||||
|     --link-hover : #6594ff; |     --link-hover : #6594ff; | ||||||
|     --link-active: #3064dd; |     --link-active: #3064dd; | ||||||
| } | } | ||||||
|  |  | ||||||
| * { | * { | ||||||
|     text-decoration: none; |     text-decoration: none; | ||||||
|     outline        : none; |     outline        : none; | ||||||
|     border         : none; |     border         : none; | ||||||
|     color          : var(--text); |     color          : var(--text); | ||||||
|     font-family    : 'Commissioner', sans-serif; |     font-family    : 'Commissioner', sans-serif; | ||||||
|     transition     : 0.1s ease-out; |     transition     : 0.1s ease-out; | ||||||
| } | } | ||||||
|  |  | ||||||
| .unselectable { | .unselectable { | ||||||
|     -webkit-touch-callout: none; |     -webkit-touch-callout: none; | ||||||
|     -webkit-user-select  : none; |     -webkit-user-select  : none; | ||||||
|     -khtml-user-select   : none; |     -khtml-user-select   : none; | ||||||
|     -moz-user-select     : none; |     -moz-user-select     : none; | ||||||
|     -ms-user-select      : none; |     -ms-user-select      : none; | ||||||
|     user-select          : none; |     user-select          : none; | ||||||
| } | } | ||||||
|  |  | ||||||
| a { | a { | ||||||
|     color: var(--link); |     color: var(--link); | ||||||
| } | } | ||||||
|  |  | ||||||
| a:hover { | a:hover { | ||||||
|     color: var(--link-hover); |     color: var(--link-hover); | ||||||
| } | } | ||||||
|  |  | ||||||
| a:active { | a:active { | ||||||
|     color     : var(--link-active); |     color     : var(--link-active); | ||||||
|     transition: unset; |     transition: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| body { | body { | ||||||
|     height          : 100vh; |     height          : 100vh; | ||||||
|     margin          : 0; |     margin          : 0; | ||||||
|     overflow        : hidden; |     overflow        : hidden; | ||||||
|     background-color: var(--background); |     background-color: var(--background); | ||||||
| } | } | ||||||
|  |  | ||||||
| body>div.background { | body>div.background { | ||||||
|     z-index                  : -50000; |     z-index                  : -50000; | ||||||
|     left                     : -350%; |     left                     : -350%; | ||||||
|     top                      : -350%; |     top                      : -350%; | ||||||
|     width                    : 500%; |     width                    : 500%; | ||||||
|     height                   : 500%; |     height                   : 500%; | ||||||
|     position                 : absolute; |     position                 : absolute; | ||||||
|     filter                   : blur(200px); |     filter                   : blur(200px); | ||||||
|     animation-duration       : 15s; |     animation-duration       : 15s; | ||||||
|     animation-name           : page-background-gradient; |     animation-name           : page-background-gradient; | ||||||
|     animation-iteration-count: infinite; |     animation-iteration-count: infinite; | ||||||
|     background-repeat        : no-repeat; |     background-repeat        : no-repeat; | ||||||
|     animation-timing-function: linear; |     animation-timing-function: linear; | ||||||
|     background-image         : radial-gradient(circle, var(--background-above) 0%, rgba(0, 0, 0, 0) 100%); |     background-image         : radial-gradient(circle, var(--background-above) 0%, rgba(0, 0, 0, 0) 100%); | ||||||
| } | } | ||||||
|  |  | ||||||
| aside { | aside { | ||||||
|     z-index    : 500; |     z-index    : 500; | ||||||
|     grid-column: 1/ 4; |     grid-column: 1/ 4; | ||||||
|     grid-row   : 2; |     grid-row   : 2; | ||||||
|     overflow   : hidden; |     overflow   : hidden; | ||||||
| } | } | ||||||
|  |  | ||||||
| header { | header { | ||||||
|     z-index       : 5000; |     z-index       : 5000; | ||||||
|     position      : absolute; |     position      : absolute; | ||||||
|     display       : flex; |     display       : flex; | ||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
|     box-shadow    : 2px 0 5px rgba(0, 0, 0, 0.3); |     box-shadow    : 2px 0 5px rgba(0, 0, 0, 0.3); | ||||||
| } | } | ||||||
|  |  | ||||||
| header>menu { | header>menu { | ||||||
|     margin          : unset; |     margin          : unset; | ||||||
|     padding         : 20px; |     padding         : 20px; | ||||||
|     display         : flex; |     display         : flex; | ||||||
|     flex-direction  : column; |     flex-direction  : column; | ||||||
|     flex-grow       : 1; |     flex-grow       : 1; | ||||||
|     background-color: var(--background-light-1); |     background-color: var(--background-light-1); | ||||||
| } | } | ||||||
|  |  | ||||||
| header>#account>button#login { | header>#account>button#login { | ||||||
|     z-index: 1500; |     z-index: 1500; | ||||||
| } | } | ||||||
|  |  | ||||||
| header>menu a { | header>menu a { | ||||||
|     margin-bottom: 8px; |     margin-bottom: 8px; | ||||||
|     display      : flex; |     display      : flex; | ||||||
|     align-items  : center; |     align-items  : center; | ||||||
| } | } | ||||||
|  |  | ||||||
| header>menu a:last-child { | header>menu a:last-child { | ||||||
|     margin-bottom: unset; |     margin-bottom: unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| header>menu a svg { | header>menu a svg { | ||||||
|     margin-right: 8px; |     margin-right: 8px; | ||||||
|     height      : 1.2rem; |     height      : 1.2rem; | ||||||
|     position    : relative; |     position    : relative; | ||||||
| } | } | ||||||
|  |  | ||||||
| header>menu a:hover svg { | header>menu a:hover svg { | ||||||
|     margin-left : -5px; |     margin-left : -5px; | ||||||
|     margin-right: 13px; |     margin-right: 13px; | ||||||
| } | } | ||||||
|  |  | ||||||
| header>menu a svg path { | header>menu a svg path { | ||||||
|     fill: var(--text); |     fill: var(--text); | ||||||
| } | } | ||||||
|  |  | ||||||
| header>section { | header>section { | ||||||
|     background-color: var(--background-light-1); |     background-color: var(--background-light-1); | ||||||
| } | } | ||||||
|  |  | ||||||
| header :is(button, a[type="button"]) { | header :is(button, a[type="button"]) { | ||||||
|     width           : 100%; |     width           : 100%; | ||||||
|     height          : 40px; |     height          : 40px; | ||||||
|     display         : flex; |     display         : flex; | ||||||
|     justify-content : center; |     justify-content : center; | ||||||
|     align-items     : center; |     align-items     : center; | ||||||
|     cursor          : pointer; |     cursor          : pointer; | ||||||
|     background-color: var(--red); |     background-color: var(--red); | ||||||
|     transition      : unset; |     transition      : unset; | ||||||
| } | } | ||||||
|  |  | ||||||
| header button { | header button { | ||||||
|     font-weight   : bold; |     font-weight   : bold; | ||||||
|     text-transform: uppercase; |     text-transform: uppercase; | ||||||
| } | } | ||||||
|  |  | ||||||
| header :is(button, a[type="button"]):hover { | header :is(button, a[type="button"]):hover { | ||||||
|     background-color: var(--red-light); |     background-color: var(--red-light); | ||||||
| } | } | ||||||
|  |  | ||||||
| header :is(button, a[type="button"]):active { | header :is(button, a[type="button"]):active { | ||||||
|     background-color: var(--red-dark); |     background-color: var(--red-dark); | ||||||
| } | } | ||||||
|  |  | ||||||
| header>nav { | header>nav { | ||||||
|     margin-top    : auto; |     margin-top    : auto; | ||||||
|     display       : flex; |     display       : flex; | ||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
| } | } | ||||||
|  |  | ||||||
| main { | main { | ||||||
|     z-index       : 1000; |     z-index       : 1000; | ||||||
|     height        : 100%; |     height        : 100%; | ||||||
|     display       : flex; |     display       : flex; | ||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
| } | } | ||||||
|  |  | ||||||
| footer { | footer { | ||||||
|     z-index : 3000; |     z-index : 3000; | ||||||
|     position: absolute; |     position: absolute; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,26 +1,26 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
|  |  | ||||||
| class account { | class account { | ||||||
|     static async initialization() { |     static async initialization() { | ||||||
|         // Запрос |         // Запрос | ||||||
|         return fetch('https://auth.mirzaev.sexy/account/initialization', { |         return fetch('https://auth.mirzaev.sexy/account/initialization', { | ||||||
|             method: 'GET' |             method: 'GET' | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static authentication() { |     static authentication() { | ||||||
|         // Инициализация аккаунта |         // Инициализация аккаунта | ||||||
|         alert(1); |         alert(1); | ||||||
|         this.initialization() |         this.initialization() | ||||||
|             .then( |             .then( | ||||||
|                 (response) => { |                 (response) => { | ||||||
|                     alert(2); |                     alert(2); | ||||||
|                 } |                 } | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static deauthentication() { |     static deauthentication() { | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,127 +1,127 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
|  |  | ||||||
| class troller { | class troller { | ||||||
|     static what = { |     static what = { | ||||||
|         enable() { |         enable() { | ||||||
|             document.body.onmouseleave = function () { |             document.body.onmouseleave = function () { | ||||||
|                 // if (Math.random() > 0.90) { |                 // if (Math.random() > 0.90) { | ||||||
|                 // 10% |                 // 10% | ||||||
|  |  | ||||||
|                 troller.what.start(); |                 troller.what.start(); | ||||||
|                 // } |                 // } | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             document.body.onmouseenter = function () { |             document.body.onmouseenter = function () { | ||||||
|                 troller.what.end(); |                 troller.what.end(); | ||||||
|             }; |             }; | ||||||
|         }, |         }, | ||||||
|         disable() { |         disable() { | ||||||
|             document.body.onmouseleave = document.body.onmouseenter = undefined; |             document.body.onmouseleave = document.body.onmouseenter = undefined; | ||||||
|         }, |         }, | ||||||
|         start() { |         start() { | ||||||
|             // Отображение изображения |             // Отображение изображения | ||||||
|             document.getElementById('what_image').classList.add('active'); |             document.getElementById('what_image').classList.add('active'); | ||||||
|  |  | ||||||
|             // Инициализация элемента со звуком |             // Инициализация элемента со звуком | ||||||
|             const what_sound = document.getElementById('what_sound'); |             const what_sound = document.getElementById('what_sound'); | ||||||
|  |  | ||||||
|             // Воспроизведение звука |             // Воспроизведение звука | ||||||
|             what_sound.currentTime = 0; |             what_sound.currentTime = 0; | ||||||
|             what_sound.play(); |             what_sound.play(); | ||||||
|         }, |         }, | ||||||
|         end() { |         end() { | ||||||
|             // Сокрытие изображения |             // Сокрытие изображения | ||||||
|             document.getElementById('what_image').classList.remove('active'); |             document.getElementById('what_image').classList.remove('active'); | ||||||
|  |  | ||||||
|             // Остановка звука |             // Остановка звука | ||||||
|             document.getElementById('what_sound').pause(); |             document.getElementById('what_sound').pause(); | ||||||
|         }, |         }, | ||||||
|         single(event = 'onmouseleave') { |         single(event = 'onmouseleave') { | ||||||
|             if (typeof event === 'string') { |             if (typeof event === 'string') { | ||||||
|                 // Получены обязательные входные параметры |                 // Получены обязательные входные параметры | ||||||
|                 // Отображение изображения |                 // Отображение изображения | ||||||
|                 document.getElementById('what_image').classList.add('active'); |                 document.getElementById('what_image').classList.add('active'); | ||||||
|  |  | ||||||
|                 // Инициализация элемента со звуком |                 // Инициализация элемента со звуком | ||||||
|                 const what_sound = document.getElementById('what_sound'); |                 const what_sound = document.getElementById('what_sound'); | ||||||
|  |  | ||||||
|                 // Воспроизведение звука |                 // Воспроизведение звука | ||||||
|                 what_sound.currentTime = 0; |                 what_sound.currentTime = 0; | ||||||
|                 what_sound.play(); |                 what_sound.play(); | ||||||
|  |  | ||||||
|                 document.body[event] = function () { |                 document.body[event] = function () { | ||||||
|                     troller.what.end(); |                     troller.what.end(); | ||||||
|  |  | ||||||
|                     document.body[event] = undefined; |                     document.body[event] = undefined; | ||||||
|                 }; |                 }; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static vk() { |     static vk() { | ||||||
|         setInterval(function () { |         setInterval(function () { | ||||||
|             const sound = document.getElementById('sound_vk'); |             const sound = document.getElementById('sound_vk'); | ||||||
|  |  | ||||||
|             if (Math.random() > 0.95) { |             if (Math.random() > 0.95) { | ||||||
|                 // 5% |                 // 5% | ||||||
|  |  | ||||||
|                 // Воспроизведение звука |                 // Воспроизведение звука | ||||||
|                 sound.currentTime = 0; |                 sound.currentTime = 0; | ||||||
|                 sound.play(); |                 sound.play(); | ||||||
|             } |             } | ||||||
|         }, 85000); |         }, 85000); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static whatsapp() { |     static whatsapp() { | ||||||
|         setInterval(function () { |         setInterval(function () { | ||||||
|             const sound = document.getElementById('sound_whatsup'); |             const sound = document.getElementById('sound_whatsup'); | ||||||
|  |  | ||||||
|             if (Math.random() > 0.97) { |             if (Math.random() > 0.97) { | ||||||
|                 // 3% |                 // 3% | ||||||
|  |  | ||||||
|                 // Воспроизведение звука |                 // Воспроизведение звука | ||||||
|                 sound.currentTime = 0; |                 sound.currentTime = 0; | ||||||
|                 sound.play(); |                 sound.play(); | ||||||
|             } |             } | ||||||
|         }, 125000); |         }, 125000); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static iphone() { |     static iphone() { | ||||||
|         setInterval(function () { |         setInterval(function () { | ||||||
|             const sound = document.getElementById('sound_iphone'); |             const sound = document.getElementById('sound_iphone'); | ||||||
|  |  | ||||||
|             if (Math.random() > 0.98) { |             if (Math.random() > 0.98) { | ||||||
|                 // 2% |                 // 2% | ||||||
|  |  | ||||||
|                 // Воспроизведение звука |                 // Воспроизведение звука | ||||||
|                 sound.currentTime = 0; |                 sound.currentTime = 0; | ||||||
|                 sound.play(); |                 sound.play(); | ||||||
|             } |             } | ||||||
|         }, 265000); |         }, 265000); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| if (Math.random() > 0.90) { | if (Math.random() > 0.90) { | ||||||
|     // 10% |     // 10% | ||||||
|  |  | ||||||
|     troller.what.enable(); |     troller.what.enable(); | ||||||
| } | } | ||||||
|  |  | ||||||
| if (Math.random() > 0.90) { | if (Math.random() > 0.90) { | ||||||
|     // 10% |     // 10% | ||||||
|  |  | ||||||
|     troller.vk(); |     troller.vk(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| if (Math.random() > 0.90) { | if (Math.random() > 0.90) { | ||||||
|     // 10% |     // 10% | ||||||
|  |  | ||||||
|     troller.whatsapp(); |     troller.whatsapp(); | ||||||
| } | } | ||||||
|  |  | ||||||
| if (Math.random() > 0.90) { | if (Math.random() > 0.90) { | ||||||
|     // 10% |     // 10% | ||||||
|  |  | ||||||
|     troller.iphone(); |     troller.iphone(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| arangodb.php | arangodb.php | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return [ | return [ | ||||||
|     'endpoint' => 'unix:///var/run/arangodb3/arango.sock', |     'endpoint' => 'unix:///var/run/arangodb3/arango.sock', | ||||||
|     'database' => '', |     'database' => '', | ||||||
|     'name' => '', |     'name' => '', | ||||||
|     'password' => '' |     'password' => '' | ||||||
| ]; | ]; | ||||||
|   | |||||||
| @@ -1,53 +0,0 @@ | |||||||
| {% block css %} |  | ||||||
| <link type="text/css" rel="stylesheet" href="/css/account.css"> |  | ||||||
| <link type="text/css" rel="stylesheet" href="/css/gradient.css"> |  | ||||||
| {% endblock %} |  | ||||||
|  |  | ||||||
| {% block body %} |  | ||||||
| <section id="authentication"> |  | ||||||
|     {% if account %} |  | ||||||
|     {{ account.getKey() }} |  | ||||||
|     {% if vk %} |  | ||||||
|     {{ vk.mail }} |  | ||||||
|     {% endif %} |  | ||||||
|     {% else %} |  | ||||||
|     <section class="header gradient unselectable"> |  | ||||||
|         <div class="glare"></div> |  | ||||||
|         <img class="avatar unselectable" src="/images/what.png" alt="Пользователь" draggable="false"> |  | ||||||
|         <a href="https://mirzaev.sexy">Нейрожурнал Мирзаева</a> |  | ||||||
|         <div class="red"></div> |  | ||||||
|         <div class="green"></div> |  | ||||||
|         <div class="blue"></div> |  | ||||||
|         <img class="cover unselectable" src="/images/heh.gif" alt="Нейрожурнал Мирзаева" draggable="false"></img> |  | ||||||
|     </section> |  | ||||||
|     <section class="body"> |  | ||||||
|         <ul> |  | ||||||
|             <li>Подпункт 2.1.</li> |  | ||||||
|             <li>Подпункт 2.2. |  | ||||||
|                 <ul> |  | ||||||
|                     <li>Подпункт 2.2.1.</li> |  | ||||||
|                     <li>Подпункт 2.2.2.</li> |  | ||||||
|                 </ul> |  | ||||||
|             </li> |  | ||||||
|             <li>Подпункт 2.3.</li> |  | ||||||
|         </ul> |  | ||||||
|         <div class="buttons"> |  | ||||||
|             <button class="accept">Разрешить</button> |  | ||||||
|             <button>Запретить</button> |  | ||||||
|         </div> |  | ||||||
|     </section> |  | ||||||
|     {% endif %} |  | ||||||
|     <svg width="0" height="0"> |  | ||||||
|         <defs> |  | ||||||
|             <clipPath id="authentication-header-mask"> |  | ||||||
|                 <path |  | ||||||
|                     d="M50,160 L50,130 C22,130 0,107.612 0,80 C0,52 22,30 50,30 L50,3 C50,1.3 51.3,0 53,0 L447,0 C448,0 450,1.5 450,3 L450,160 L50,160 Z" /> |  | ||||||
|             </clipPath> |  | ||||||
|         </defs> |  | ||||||
|     </svg> |  | ||||||
| </section> |  | ||||||
| {% endblock %} |  | ||||||
|  |  | ||||||
| {% block js %} |  | ||||||
| <script type="text/javascript" src="/js/account.js"></script> |  | ||||||
| {% endblock %} |  | ||||||
| @@ -1,14 +1,14 @@ | |||||||
|  |  | ||||||
| {% block css %} | {% block css %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block body %} | {% block body %} | ||||||
| <aside> | <aside> | ||||||
| </aside> | </aside> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js %} | {% block js %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js_init %} | {% block js_init %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -1,33 +1,33 @@ | |||||||
| <!doctype html> | <!doctype html> | ||||||
|  |  | ||||||
| <html lang="ru"> | <html lang="ru"> | ||||||
|  |  | ||||||
| <head> | <head> | ||||||
| 	{% use 'head.html' with title as head_title, meta as head_meta, css as head_css %} | 	{% use 'head.html' with title as head_title, meta as head_meta, css as head_css %} | ||||||
|  |  | ||||||
| 	{% block title %} | 	{% block title %} | ||||||
| 	{{ block('head_title') }} | 	{{ block('head_title') }} | ||||||
| 	{% endblock %} | 	{% endblock %} | ||||||
|  |  | ||||||
| 	{% block meta %} | 	{% block meta %} | ||||||
| 	{{ block('head_meta') }} | 	{{ block('head_meta') }} | ||||||
| 	{% endblock %} | 	{% endblock %} | ||||||
|  |  | ||||||
| 	{% block css %} | 	{% block css %} | ||||||
| 	{{ block('head_css') }} | 	{{ block('head_css') }} | ||||||
| 	{% endblock %} | 	{% endblock %} | ||||||
| </head> | </head> | ||||||
|  |  | ||||||
| <body> | <body> | ||||||
| 	{% block body %} | 	{% block body %} | ||||||
| 	{% endblock %} | 	{% endblock %} | ||||||
|  |  | ||||||
| 	{% block js %} | 	{% block js %} | ||||||
| 	{% include 'js.html' %} | 	{% include 'js.html' %} | ||||||
| 	{% endblock %} | 	{% endblock %} | ||||||
|  |  | ||||||
| 	{% block js_init %} | 	{% block js_init %} | ||||||
| 	{% endblock %} | 	{% endblock %} | ||||||
| </body> | </body> | ||||||
|  |  | ||||||
| </html> | </html> | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| <footer> | <footer> | ||||||
|     <!-- <p><a href="http://www.anybrowser.org/campaign/"><img src="/img/logos/any_browser.gif" width="278" height="44" alt="Доступно на любом браузере" /></a></p> --> |     <!-- <p><a href="http://www.anybrowser.org/campaign/"><img src="/img/logos/any_browser.gif" width="278" height="44" alt="Доступно на любом браузере" /></a></p> --> | ||||||
|     <!-- <p><a href="/browsers"><img src="/img/logos/any_browser.gif" width="278" height="44" alt="Доступно на любом браузере" /></a></p> --> |     <!-- <p><a href="/browsers"><img src="/img/logos/any_browser.gif" width="278" height="44" alt="Доступно на любом браузере" /></a></p> --> | ||||||
| </footer> | </footer> | ||||||
|   | |||||||
| @@ -1,86 +1,86 @@ | |||||||
| {% block css %} | {% block css %} | ||||||
| <link type="text/css" rel="stylesheet" href="/css/graph.css"> | <link type="text/css" rel="stylesheet" href="/css/graph.css"> | ||||||
| <link type="text/css" rel="stylesheet" href="/css/icon_close.css" /> | <link type="text/css" rel="stylesheet" href="/css/icon_close.css" /> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block body %} | {% block body %} | ||||||
| {% if graph.id != empty %} | {% if graph.id != empty %} | ||||||
| <section id="{{ graph.id }}" class="graph unselectable" {% for name, value in graph.attributes %} {{ name }}="{{value}}" | <section id="{{ graph.id }}" class="graph unselectable" {% for name, value in graph.attributes %} {{ name }}="{{value}}" | ||||||
|     {% endfor %}> |     {% endfor %}> | ||||||
|     {% for element in graph.elements %} |     {% for element in graph.elements %} | ||||||
|     <{{element.tag??'article'}}>{{ element.content }}</{{element.tag??'article'}}> |     <{{element.tag??'article'}}>{{ element.content }}</{{element.tag??'article'}}> | ||||||
|     {% endfor %} |     {% endfor %} | ||||||
| </section> | </section> | ||||||
| {% endif %} | {% endif %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js %} | {% block js %} | ||||||
| <script type="module" src="/js/victor.js" defer></script> | <script type="module" src="/js/victor.js" defer></script> | ||||||
| <script type="module" src="/js/graph.js" defer></script> | <script type="module" src="/js/graph.js" defer></script> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js_init %} | {% block js_init %} | ||||||
| <script> | <script> | ||||||
|     document.addEventListener('graph.loaded', function (e) { |     document.addEventListener('graph.loaded', function (e) { | ||||||
|         // Инициализация графика |         // Инициализация графика | ||||||
|         {% if graph.id != empty %} |         {% if graph.id != empty %} | ||||||
|         const core = new e.detail.graph(document.getElementById('{{ graph.id }}')); |         const core = new e.detail.graph(document.getElementById('{{ graph.id }}')); | ||||||
|  |  | ||||||
|         core.write({ |         core.write({ | ||||||
|             title: 'бебра' |             title: 'бебра' | ||||||
|         }); |         }); | ||||||
|         const mirzaev = core.write({ |         const mirzaev = core.write({ | ||||||
|             title: 'Арсен Мирзаев', |             title: 'Арсен Мирзаев', | ||||||
|             description: ' абабабаба абабабабаабабабабаабабабабаабабабаба абабабаба абабабаба абабабабаабабабаба абабабаба абабабаба абабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабаба', |             description: ' абабабаба абабабабаабабабабаабабабабаабабабаба абабабаба абабабаба абабабабаабабабаба абабабаба абабабаба абабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабабабабаба абабабабаабабаба', | ||||||
|             cover: 'https://sun9-east.userapi.com/sun9-27/s/v1/ig2/qOBvWvsDwPmMjOTqQbl0TuGHaoMwWQhhd81nxD847v32dT-pyYa9kxw2MY7moQBVBoN4iVLnUZx6WmE4x4HnIwAu.jpg?size=810x1080&quality=95&type=album', |             cover: 'https://sun9-east.userapi.com/sun9-27/s/v1/ig2/qOBvWvsDwPmMjOTqQbl0TuGHaoMwWQhhd81nxD847v32dT-pyYa9kxw2MY7moQBVBoN4iVLnUZx6WmE4x4HnIwAu.jpg?size=810x1080&quality=95&type=album', | ||||||
|             link: { |             link: { | ||||||
|                 name: 'Арсен Мирзаев', |                 name: 'Арсен Мирзаев', | ||||||
|                 title: 'Читать статью полностью', |                 title: 'Читать статью полностью', | ||||||
|                 href: 'https://google.com', |                 href: 'https://google.com', | ||||||
|                 class: ['source'] |                 class: ['source'] | ||||||
|             }, |             }, | ||||||
|             popup: 'Для подробной информации читайте статью полностью', |             popup: 'Для подробной информации читайте статью полностью', | ||||||
|             color: 'red' |             color: 'red' | ||||||
|         }); |         }); | ||||||
|         const berbi = core.write({ |         const berbi = core.write({ | ||||||
|             title: 'берби' |             title: 'берби' | ||||||
|         }); |         }); | ||||||
|         const anarchy = core.write({ |         const anarchy = core.write({ | ||||||
|             title: 'анархия' |             title: 'анархия' | ||||||
|         }); |         }); | ||||||
|         core.connect( |         core.connect( | ||||||
|             berbi, |             berbi, | ||||||
|             mirzaev); |             mirzaev); | ||||||
|         core.connect( |         core.connect( | ||||||
|             anarchy, |             anarchy, | ||||||
|             mirzaev); |             mirzaev); | ||||||
|         core.connect( |         core.connect( | ||||||
|             core.write({ |             core.write({ | ||||||
|                 title: 'бабы' |                 title: 'бабы' | ||||||
|             }), |             }), | ||||||
|             mirzaev); |             mirzaev); | ||||||
|         core.connect( |         core.connect( | ||||||
|             core.write({ |             core.write({ | ||||||
|                 title: 'Ксения Велькович', |                 title: 'Ксения Велькович', | ||||||
|                 description: 'А меня вписать в кружочек?', |                 description: 'А меня вписать в кружочек?', | ||||||
|                 cover: 'https://storage.mirzaev.sexy/2022/mirzaev.sexy/nodes/ksenia_velkovich.jpg', |                 cover: 'https://storage.mirzaev.sexy/2022/mirzaev.sexy/nodes/ksenia_velkovich.jpg', | ||||||
|                 link: { |                 link: { | ||||||
|                     name: 'Ксения Велькович', |                     name: 'Ксения Велькович', | ||||||
|                     title: 'Страница ВКонтакте', |                     title: 'Страница ВКонтакте', | ||||||
|                     href: 'https://vk.com/id720261644', |                     href: 'https://vk.com/id720261644', | ||||||
|                     class: ['source'] |                     class: ['source'] | ||||||
|                 } |                 } | ||||||
|             }), |             }), | ||||||
|             mirzaev); |             mirzaev); | ||||||
|         core.connect( |         core.connect( | ||||||
|             core.write({ |             core.write({ | ||||||
|                 title: 'чокопайки' |                 title: 'чокопайки' | ||||||
|             }), |             }), | ||||||
|             mirzaev); |             mirzaev); | ||||||
|         core.connect( |         core.connect( | ||||||
|             anarchy, |             anarchy, | ||||||
|             berbi); |             berbi); | ||||||
|         {% endif %} |         {% endif %} | ||||||
|     }); |     }); | ||||||
| </script> | </script> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -1,15 +1,15 @@ | |||||||
| {% block title %} | {% block title %} | ||||||
| <title>{% if head.title != empty %}{{head.title}}{% else %}Управление аккаунтом{% endif %}</title> | <title>{% if head.title != empty %}{{head.title}}{% else %}Управление аккаунтом{% endif %}</title> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block meta %} | {% block meta %} | ||||||
| <meta charset="utf-8"> | <meta charset="utf-8"> | ||||||
| <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||||||
| {% for meta in head.metas %} | {% for meta in head.metas %} | ||||||
| <meta {% for name, value in meta.attributes %}{{name}}="{{value}}" {% endfor %}> | <meta {% for name, value in meta.attributes %}{{name}}="{{value}}" {% endfor %}> | ||||||
| {% endfor %} | {% endfor %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block css %} | {% block css %} | ||||||
| <link type="text/css" rel="stylesheet" href="/css/main.css" /> | <link type="text/css" rel="stylesheet" href="/css/main.css" /> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -1,13 +1,13 @@ | |||||||
| {% block css %} | {% block css %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block body %} | {% block body %} | ||||||
| <header> | <header> | ||||||
| </header> | </header> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js %} | {% block js %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js_init %} | {% block js_init %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -1,28 +1,28 @@ | |||||||
| {% block css %} | {% block css %} | ||||||
| <link type="text/css" rel="stylesheet" href="/css/hotline.css"> | <link type="text/css" rel="stylesheet" href="/css/hotline.css"> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block body %} | {% block body %} | ||||||
| {% if hotline.id != empty %} | {% if hotline.id != empty %} | ||||||
| <section id="{{ hotline.id }}" class="hotline unselectable" data-hotline="true" {% for name, value in hotline.parameters | <section id="{{ hotline.id }}" class="hotline unselectable" data-hotline="true" {% for name, value in hotline.parameters | ||||||
|     %} data-hotline-{{ name }}="{{value}}" {% endfor %} {% for name, value in hotline.attributes %} {{ name |     %} data-hotline-{{ name }}="{{value}}" {% endfor %} {% for name, value in hotline.attributes %} {{ name | ||||||
|     }}="{{value}}" {% endfor %}> |     }}="{{value}}" {% endfor %}> | ||||||
|     {% for element in hotline.elements %} |     {% for element in hotline.elements %} | ||||||
|     <{{element.tag??'article'}}>{{ element.content }}</{{element.tag??'article'}}> |     <{{element.tag??'article'}}>{{ element.content }}</{{element.tag??'article'}}> | ||||||
|     {% endfor %} |     {% endfor %} | ||||||
| </section> | </section> | ||||||
| {% endif %} | {% endif %} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js %} | {% block js %} | ||||||
| <script type="text/javascript" src="/js/hotline.js" defer></script> | <script type="text/javascript" src="/js/hotline.js" defer></script> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js_init %} | {% block js_init %} | ||||||
| <script> | <script> | ||||||
|     document.addEventListener('hotline.loaded', function (e) { |     document.addEventListener('hotline.loaded', function (e) { | ||||||
|         // Запуск препроцессора бегущих строк |         // Запуск препроцессора бегущих строк | ||||||
|         e.detail.hotline.preprocessing(); |         e.detail.hotline.preprocessing(); | ||||||
|     }); |     }); | ||||||
| </script> | </script> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -1,47 +1,47 @@ | |||||||
| {% extends "core.html" %} | {% extends "core.html" %} | ||||||
|  |  | ||||||
| {% use 'account/element.html' with css as account_css, body as account_body, js as account_js %} | {% use 'nodes/account.html' with css as account_css, body as account_body, js as account_js %} | ||||||
| {% use "core.html" with css as core_css, body as core_body, js as core_js, js_init as core_js_init %} | {% use "core.html" with css as core_css, body as core_body, js as core_js, js_init as core_js_init %} | ||||||
| {% use "header.html" with css as header_css, body as header_body, js as header_js, js_init as header_js_init %} | {% use "header.html" with css as header_css, body as header_body, js as header_js, js_init as header_js_init %} | ||||||
| {% use "aside.html" with css as aside_css, body as aside_body, js as aside_js, js_init as aside_js_init %} | {% use "aside.html" with css as aside_css, body as aside_body, js as aside_js, js_init as aside_js_init %} | ||||||
| {% use 'graph/index.html' with css as graph_css, body as graph_body, js as graph_js, js_init as graph_js_init %} | {% use 'graph/index.html' with css as graph_css, body as graph_body, js as graph_js, js_init as graph_js_init %} | ||||||
|  |  | ||||||
| {% block css %} | {% block css %} | ||||||
| {{ block('core_css') }} | {{ block('core_css') }} | ||||||
| {{ block('header_css') }} | {{ block('header_css') }} | ||||||
| {{ block('aside_css') }} | {{ block('aside_css') }} | ||||||
| {{ block('graph_css') }} | {{ block('graph_css') }} | ||||||
| {{ block('account_css') }} | {{ block('account_css') }} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block body %} | {% block body %} | ||||||
| {{ block('core_body') }} | {{ block('core_body') }} | ||||||
| {{ block('aside_body') }} | {{ block('aside_body') }} | ||||||
| {{ block('header_body') }} | {{ block('header_body') }} | ||||||
|  |  | ||||||
| <main> | <main> | ||||||
| 	<noscript>К сожалению мой сайт ещё пока не готов для работы без javascript</noscript> | 	<noscript>К сожалению мой сайт ещё пока не готов для работы без javascript</noscript> | ||||||
| 	{% block main %} | 	{% block main %} | ||||||
| 	{{ block('account_body') }} | 	{{ block('account_body') }} | ||||||
| 	{% endblock %} | 	{% endblock %} | ||||||
| 	{{ block('graph_body') }} | 	{{ block('graph_body') }} | ||||||
| </main> | </main> | ||||||
|  |  | ||||||
| {# {% include 'footer.html' %} #} | {# {% include 'footer.html' %} #} | ||||||
| {# <div class="background"></div> #} | {# <div class="background"></div> #} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js %} | {% block js %} | ||||||
| {{ block('core_js') }} | {{ block('core_js') }} | ||||||
| {{ block('header_js') }} | {{ block('header_js') }} | ||||||
| {{ block('aside_js') }} | {{ block('aside_js') }} | ||||||
| {{ block('graph_js') }} | {{ block('graph_js') }} | ||||||
| {{ block('account_js') }} | {{ block('account_js') }} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block js_init %} | {% block js_init %} | ||||||
| {{ block('core_js_init') }} | {{ block('core_js_init') }} | ||||||
| {{ block('header_js_init') }} | {{ block('header_js_init') }} | ||||||
| {{ block('aside_js_init') }} | {{ block('aside_js_init') }} | ||||||
| {{ block('graph_js_init') }} | {{ block('graph_js_init') }} | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -1,3 +1,3 @@ | |||||||
| {% block js %} | {% block js %} | ||||||
| <script type="text/javascript" src="/js/js.cookie.min.js" defer></script> | <script type="text/javascript" src="/js/js.cookie.min.js" defer></script> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -1,25 +1,25 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| declare(strict_types=1); | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace mirzaev\site\account\views; | namespace mirzaev\site\account\views; | ||||||
|  |  | ||||||
| use mirzaev\minimal\controller; | use mirzaev\minimal\controller; | ||||||
|  |  | ||||||
| use Twig\Loader\FilesystemLoader; | use Twig\Loader\FilesystemLoader; | ||||||
| use Twig\Environment as view; | use Twig\Environment as view; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Менеджер представлений |  * Менеджер представлений | ||||||
|  * |  * | ||||||
|  * @package mirzaev\site\account\controllers |  * @package mirzaev\site\account\controllers | ||||||
|  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> |  * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> | ||||||
|  */ |  */ | ||||||
| final class manager extends controller | final class manager extends controller | ||||||
| { | { | ||||||
|     public function render(string $file, array $vars = []): ?string |     public function render(string $file, array $vars = []): ?string | ||||||
|     { |     { | ||||||
|         // Генерация представления |         // Генерация представления | ||||||
|         return (new view(new FilesystemLoader(VIEWS)))->render($file, $vars); |         return (new view(new FilesystemLoader(VIEWS)))->render($file, $vars); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										53
									
								
								mirzaev/site/account/system/views/nodes/account.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								mirzaev/site/account/system/views/nodes/account.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | {% block css %} | ||||||
|  | <link type="text/css" rel="stylesheet" href="/css/account.css"> | ||||||
|  | <link type="text/css" rel="stylesheet" href="/css/gradient.css"> | ||||||
|  | {% endblock %} | ||||||
|  |  | ||||||
|  | {% block body %} | ||||||
|  | <section id="authentication"> | ||||||
|  |   {% if account %} | ||||||
|  |   {{ account.getKey() }} | ||||||
|  |   {% if vk %} | ||||||
|  |   {{ vk.mail }} | ||||||
|  |   {% endif %} | ||||||
|  |   {% else %} | ||||||
|  |   <section class="header gradient unselectable"> | ||||||
|  |     <div class="glare"></div> | ||||||
|  |     <img class="avatar unselectable" src="/images/what.png" alt="Пользователь" draggable="false"> | ||||||
|  |     <a href="https://mirzaev.sexy">{{ name ?? session.ip ?? session.hash ?? 'Ты кто?'}}</a> | ||||||
|  |     <div class="red"></div> | ||||||
|  |     <div class="green"></div> | ||||||
|  |     <div class="blue"></div> | ||||||
|  |     <img class="cover unselectable" src="/images/heh.gif" alt="Нейрожурнал Мирзаева" draggable="false"></img> | ||||||
|  |   </section> | ||||||
|  |   <section class="body"> | ||||||
|  |     <ul> | ||||||
|  |       <li>Подпункт 2.1.</li> | ||||||
|  |       <li>Подпункт 2.2. | ||||||
|  |         <ul> | ||||||
|  |           <li>Подпункт 2.2.1.</li> | ||||||
|  |           <li>Подпункт 2.2.2.</li> | ||||||
|  |         </ul> | ||||||
|  |       </li> | ||||||
|  |       <li>Подпункт 2.3.</li> | ||||||
|  |     </ul> | ||||||
|  |     <div class="buttons"> | ||||||
|  |       <button class="accept">Разрешить</button> | ||||||
|  |       <button>Запретить</button> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  |   {% endif %} | ||||||
|  |   <svg width="0" height="0"> | ||||||
|  |     <defs> | ||||||
|  |       <clipPath id="authentication-header-mask"> | ||||||
|  |         <path | ||||||
|  |           d="M50,160 L50,130 C22,130 0,107.612 0,80 C0,52 22,30 50,30 L50,3 C50,1.3 51.3,0 53,0 L447,0 C448,0 450,1.5 450,3 L450,160 L50,160 Z" /> | ||||||
|  |       </clipPath> | ||||||
|  |     </defs> | ||||||
|  |   </svg> | ||||||
|  | </section> | ||||||
|  | {% endblock %} | ||||||
|  |  | ||||||
|  | {% block js %} | ||||||
|  | <script type="text/javascript" src="/js/account.js"></script> | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										53
									
								
								mirzaev/site/account/system/views/nodes/connect.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								mirzaev/site/account/system/views/nodes/connect.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | {% block css %} | ||||||
|  | <link type="text/css" rel="stylesheet" href="/css/account.css"> | ||||||
|  | <link type="text/css" rel="stylesheet" href="/css/gradient.css"> | ||||||
|  | {% endblock %} | ||||||
|  |  | ||||||
|  | {% block body %} | ||||||
|  | <section id="authentication"> | ||||||
|  |   {% if account %} | ||||||
|  |   {{ account.getKey() }} | ||||||
|  |   {% if vk %} | ||||||
|  |   {{ vk.mail }} | ||||||
|  |   {% endif %} | ||||||
|  |   {% else %} | ||||||
|  |   <section class="header gradient unselectable"> | ||||||
|  |     <div class="glare"></div> | ||||||
|  |     <img class="avatar unselectable" src="/images/what.png" alt="Пользователь" draggable="false"> | ||||||
|  |     <a href="https://mirzaev.sexy">Нейрожурнал Мирзаева</a> | ||||||
|  |     <div class="red"></div> | ||||||
|  |     <div class="green"></div> | ||||||
|  |     <div class="blue"></div> | ||||||
|  |     <img class="cover unselectable" src="/images/heh.gif" alt="Нейрожурнал Мирзаева" draggable="false"></img> | ||||||
|  |   </section> | ||||||
|  |   <section class="body"> | ||||||
|  |     <ul> | ||||||
|  |       <li>Подпункт 2.1.</li> | ||||||
|  |       <li>Подпункт 2.2. | ||||||
|  |         <ul> | ||||||
|  |           <li>Подпункт 2.2.1.</li> | ||||||
|  |           <li>Подпункт 2.2.2.</li> | ||||||
|  |         </ul> | ||||||
|  |       </li> | ||||||
|  |       <li>Подпункт 2.3.</li> | ||||||
|  |     </ul> | ||||||
|  |     <div class="buttons"> | ||||||
|  |       <button class="accept">Разрешить</button> | ||||||
|  |       <button>Запретить</button> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  |   {% endif %} | ||||||
|  |   <svg width="0" height="0"> | ||||||
|  |     <defs> | ||||||
|  |       <clipPath id="authentication-header-mask"> | ||||||
|  |         <path | ||||||
|  |           d="M50,160 L50,130 C22,130 0,107.612 0,80 C0,52 22,30 50,30 L50,3 C50,1.3 51.3,0 53,0 L447,0 C448,0 450,1.5 450,3 L450,160 L50,160 Z" /> | ||||||
|  |       </clipPath> | ||||||
|  |     </defs> | ||||||
|  |   </svg> | ||||||
|  | </section> | ||||||
|  | {% endblock %} | ||||||
|  |  | ||||||
|  | {% block js %} | ||||||
|  | <script type="text/javascript" src="/js/account.js"></script> | ||||||
|  | {% endblock %} | ||||||
		Reference in New Issue
	
	Block a user