начало работы над сессиями и там дохуя чего ещё
This commit is contained in:
		
							
								
								
									
										107
									
								
								composer.json
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								composer.json
									
									
									
									
									
								
							| @@ -1,57 +1,56 @@ | ||||
| { | ||||
|     "name": "mirzaev/site-account", | ||||
|     "description": "API for intersite authentication", | ||||
|     "readme": "README.md", | ||||
|     "keywords": [ | ||||
|         "site", | ||||
|         "api", | ||||
|         "authentication", | ||||
|         "auth" | ||||
|     ], | ||||
|     "type": "site", | ||||
|     "homepage": "https://git.mirzaev.sexy/mirzaev/site-account", | ||||
|     "license": "WTFPL", | ||||
|     "authors": [ | ||||
|         { | ||||
|             "name": "Arsen Mirzaev Tatyano-Muradovich", | ||||
|             "email": "arsen@mirzaev.sexy", | ||||
|             "homepage": "https://mirzaev.sexy", | ||||
|             "role": "Programmer" | ||||
|         } | ||||
|     ], | ||||
|     "support": { | ||||
|         "email": "arsen@mirzaev.sexy", | ||||
|         "wiki": "https://git.mirzaev.sexy/mirzaev/site-account/wiki", | ||||
|         "issues": "https://git.mirzaev.sexy/mirzaev/site-account/issues" | ||||
|     }, | ||||
|     "funding": [ | ||||
|         { | ||||
|             "type": "funding", | ||||
|             "url": "https://fund.mirzaev.sexy" | ||||
|         } | ||||
|     ], | ||||
|     "require": { | ||||
|         "php": "~8.1", | ||||
|         "ext-sodium": "~8.1", | ||||
|         "mirzaev/minimal": "^2.0.x-dev", | ||||
|         "mirzaev/accounts": "~1.2.x-dev", | ||||
|         "mirzaev/arangodb": "^1.0.0", | ||||
|         "mirzaev/vk": "^5.0", | ||||
|         "triagens/arangodb": "~3.9.x-dev", | ||||
|         "twig/twig": "^3.4", | ||||
|         "guzzlehttp/guzzle": "^7.5" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "phpunit/phpunit": "~9.5" | ||||
|     }, | ||||
|     "autoload": { | ||||
|         "psr-4": { | ||||
|             "mirzaev\\site\\account\\": "mirzaev/site/account/system" | ||||
|         } | ||||
|     }, | ||||
|     "autoload-dev": { | ||||
|         "psr-4": { | ||||
|             "mirzaev\\site\\account\\tests\\": "mirzaev/site/account/tests" | ||||
|         } | ||||
|   "name": "mirzaev/site-account", | ||||
|   "description": "API for intersite authentication", | ||||
|   "readme": "README.md", | ||||
|   "keywords": [ | ||||
|     "site", | ||||
|     "api", | ||||
|     "authentication" | ||||
|   ], | ||||
|   "type": "site", | ||||
|   "homepage": "https://git.mirzaev.sexy/mirzaev/site-account", | ||||
|   "license": "WTFPL", | ||||
|   "authors": [ | ||||
|     { | ||||
|       "name": "Arsen Mirzaev Tatyano-Muradovich", | ||||
|       "email": "arsen@mirzaev.sexy", | ||||
|       "homepage": "https://mirzaev.sexy", | ||||
|       "role": "Programmer" | ||||
|     } | ||||
|   ], | ||||
|   "support": { | ||||
|     "email": "arsen@mirzaev.sexy", | ||||
|     "wiki": "https://git.mirzaev.sexy/mirzaev/site-account/wiki", | ||||
|     "issues": "https://git.mirzaev.sexy/mirzaev/site-account/issues" | ||||
|   }, | ||||
|   "funding": [ | ||||
|     { | ||||
|       "type": "funding", | ||||
|       "url": "https://fund.mirzaev.sexy" | ||||
|     } | ||||
|   ], | ||||
|   "require": { | ||||
|     "php": "~8.2", | ||||
|     "ext-sodium": "~8.2", | ||||
|     "mirzaev/minimal": "^2.0.x-dev", | ||||
|     "mirzaev/accounts": "~1.2.x-dev", | ||||
|     "mirzaev/arangodb": "^1.0.0", | ||||
|     "mirzaev/vk": "^5.0", | ||||
|     "triagens/arangodb": "~3.9.x-dev", | ||||
|     "twig/twig": "^3.4", | ||||
|     "guzzlehttp/guzzle": "^7.5" | ||||
|   }, | ||||
|   "require-dev": { | ||||
|     "phpunit/phpunit": "~9.5" | ||||
|   }, | ||||
|   "autoload": { | ||||
|     "psr-4": { | ||||
|       "mirzaev\\site\\account\\": "mirzaev/site/account/system" | ||||
|     } | ||||
|   }, | ||||
|   "autoload-dev": { | ||||
|     "psr-4": { | ||||
|       "mirzaev\\site\\account\\tests\\": "mirzaev/site/account/tests" | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -61,7 +61,7 @@ class core extends controller | ||||
|         $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) { | ||||
|             // Изменился хеш сессии (подразумевается, что сессия устарела) | ||||
| @@ -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) { | ||||
|             // Инициализирован аккаунт | ||||
|   | ||||
| @@ -15,71 +15,66 @@ use mirzaev\site\account\controllers\core; | ||||
|  */ | ||||
| final class index_controller extends core | ||||
| { | ||||
|     /** | ||||
|      * Главная страница | ||||
|      * | ||||
|      * @param array $parameters Параметры запроса | ||||
|      */ | ||||
|     public function index(array $parameters = []): ?string | ||||
|     { | ||||
|         // Инициализация загружаемых категорий | ||||
|         $this->variables['include'] = [ | ||||
|             'head' => ['self'], | ||||
|             'body' => ['self'] | ||||
|         ]; | ||||
|   /** | ||||
|    * Главная страница | ||||
|    * | ||||
|    * @param array $parameters Параметры запроса | ||||
|    */ | ||||
|   public function index(array $parameters = []): ?string | ||||
|   { | ||||
|     // Инициализация загружаемых категорий | ||||
|     $this->variables['include'] = [ | ||||
|       'head' => ['self'], | ||||
|       'body' => ['self'] | ||||
|     ]; | ||||
|  | ||||
|         // Инициализация бегущей строки | ||||
|         $this->variables['hotline'] = [ | ||||
|             'id' => $this->variables['request']['id'] ?? 'hotline' | ||||
|         ]; | ||||
|     // Инициализация бегущей строки | ||||
|     $this->variables['hotline'] = [ | ||||
|       'id' => $this->variables['request']['id'] ?? 'hotline' | ||||
|     ]; | ||||
|  | ||||
|         // Инициализация параметров бегущей строки | ||||
|         $this->variables['hotline']['parameters'] = [ | ||||
|             // 'step' => 2 | ||||
|         ]; | ||||
|     // Инициализация параметров бегущей строки | ||||
|     $this->variables['hotline']['parameters'] = [ | ||||
|       // 'step' => 2 | ||||
|     ]; | ||||
|  | ||||
|         // Инициализация аттрибутов бегущей строки | ||||
|         $this->variables['hotline']['attributes'] = [ | ||||
|     // Инициализация аттрибутов бегущей строки | ||||
|     $this->variables['hotline']['attributes'] = []; | ||||
|  | ||||
|         ]; | ||||
|     // Инициализация элементов бегущей строки | ||||
|     $this->variables['hotline']['elements'] = [ | ||||
|       ['content' => '1'], | ||||
|       [ | ||||
|         'tag' => 'article', | ||||
|         'content' => '2' | ||||
|       ], | ||||
|       ['content' => '3'], | ||||
|       ['content' => '4'], | ||||
|       ['content' => '5'], | ||||
|       ['content' => '6'], | ||||
|       ['content' => '7'], | ||||
|       ['content' => '8'], | ||||
|       ['content' => '9'], | ||||
|       ['content' => '10'], | ||||
|       ['content' => '11'], | ||||
|       ['content' => '12'], | ||||
|       ['content' => '13'], | ||||
|       ['content' => '14'], | ||||
|       ['content' => '15'] | ||||
|     ]; | ||||
|  | ||||
|         // Инициализация элементов бегущей строки | ||||
|         $this->variables['hotline']['elements'] = [ | ||||
|             ['content' => '1'], | ||||
|             [ | ||||
|                 'tag' => 'article', | ||||
|                 'content' => '2' | ||||
|             ], | ||||
|             ['content' => '3'], | ||||
|             ['content' => '4'], | ||||
|             ['content' => '5'], | ||||
|             ['content' => '6'], | ||||
|             ['content' => '7'], | ||||
|             ['content' => '8'], | ||||
|             ['content' => '9'], | ||||
|             ['content' => '10'], | ||||
|             ['content' => '11'], | ||||
|             ['content' => '12'], | ||||
|             ['content' => '13'], | ||||
|             ['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'] = []; | ||||
|  | ||||
|         ]; | ||||
|  | ||||
|         // Инициализация элементов бегущей строки | ||||
|         $this->variables['graph']['elements'] = [ | ||||
|         ]; | ||||
|  | ||||
|         // Генерация представления | ||||
|         return $this->view->render(DIRECTORY_SEPARATOR . 'index.html', $this->variables); | ||||
|     } | ||||
|     // Генерация представления | ||||
|     return $this->view->render(DIRECTORY_SEPARATOR . 'index.html', $this->variables); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -9,7 +9,7 @@ use mirzaev\site\account\models\account_model as account; | ||||
|  | ||||
| // Фреймворк ArangoDB | ||||
| use mirzaev\arangodb\collection, | ||||
|     mirzaev\arangodb\document; | ||||
|   mirzaev\arangodb\document; | ||||
|  | ||||
| // Библиотека для ArangoDB | ||||
| use ArangoDBClient\Document as _document; | ||||
| @@ -25,189 +25,225 @@ use exception; | ||||
|  */ | ||||
| final class session_model extends core | ||||
| { | ||||
|     /** | ||||
|      * Коллекция | ||||
|      */ | ||||
|     public const COLLECTION = 'session'; | ||||
|   /** | ||||
|    * Коллекция | ||||
|    */ | ||||
|   public const COLLECTION = 'session'; | ||||
|  | ||||
|     /** | ||||
|      * Инициализация | ||||
|      * | ||||
|      * @param ?string $hash Хеш сессии в базе данных | ||||
|      * @param ?int $expires Дата окончания работы сессии (используется при создании новой сессии) | ||||
|      * @param array &$errors Журнал ошибок | ||||
|      * | ||||
|      * @return ?_document Инстанция сессии, если удалось найти или создать | ||||
|      */ | ||||
|     public static function initialization(?string $hash = null, ?int $expires = null, array &$errors = []): ?_document | ||||
|     { | ||||
|         try { | ||||
|             if (collection::init(static::$db->session, self::COLLECTION)) { | ||||
|                 // Инициализирована коллекция | ||||
|   /** | ||||
|    * Данные сессии из базы данных  | ||||
|    */ | ||||
|   public _document $document; | ||||
|  | ||||
|                 if (isset($hash) && $session = collection::search(static::$db->session, sprintf( | ||||
|                     <<<AQL | ||||
|                         FOR d IN %s | ||||
|                         FILTER d.hash == '$hash' && d.expires > %d | ||||
|                         RETURN d | ||||
|                     AQL, | ||||
|                     self::COLLECTION, | ||||
|                     time() | ||||
|                 ))) { | ||||
|                     // Найдена сессия по хешу | ||||
|   /** | ||||
|    * Конструктор  | ||||
|    * | ||||
|    * Инициализация сессии и запись в свойство $this->document | ||||
|    * | ||||
|    * @param ?string $hash Хеш сессии в базе данных | ||||
|    * @param ?int $expires Дата окончания работы сессии (используется при создании новой сессии) | ||||
|    * @param array &$errors Журнал ошибок | ||||
|    * | ||||
|    * @return static Инстанция сессии | ||||
|    */ | ||||
|   public function __construct(?string $hash = null, ?int $expires = null, array &$errors = []) | ||||
|   { | ||||
|     try { | ||||
|       if (collection::init(static::$db->session, self::COLLECTION)) { | ||||
|         // Инициализирована коллекция | ||||
|  | ||||
|                     // Возврат сессии | ||||
|                     return $session; | ||||
|                 } else if ($session = collection::search(static::$db->session, sprintf( | ||||
|                     <<<AQL | ||||
|                         FOR d IN %s | ||||
|                         FILTER d.ip == '%s' && d.expires > %d | ||||
|                         RETURN d | ||||
|                     AQL, | ||||
|                     self::COLLECTION, | ||||
|                     $_SERVER['REMOTE_ADDR'], | ||||
|                     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 | ||||
|           AQL, | ||||
|           self::COLLECTION, | ||||
|           time() | ||||
|         ))) { | ||||
|           // Найдена сессия по хешу | ||||
|  | ||||
|                     // Возврат сессии | ||||
|                     return $session; | ||||
|                 } else { | ||||
|                     // Не найдена сессия | ||||
|           // Запись в свойство | ||||
|           $this->document = $session; | ||||
|         } else if ($session = collection::search(static::$db->session, sprintf( | ||||
|           <<<AQL | ||||
|             FOR d IN %s | ||||
|             FILTER d.ip == '%s' && d.expires > %d | ||||
|             RETURN d | ||||
|           AQL, | ||||
|           self::COLLECTION, | ||||
|           $_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 | ||||
|                             FILTER d._id == '$_id' && d.expires > %d | ||||
|                             RETURN d | ||||
|                         AQL, | ||||
|                         self::COLLECTION, | ||||
|                         time() | ||||
|                     ))) { | ||||
|                         // Найдена созданная сессия | ||||
|           // Запись сессии в базу данных | ||||
|           $_id = document::write(static::$db->session, self::COLLECTION, [ | ||||
|             'ip' => $_SERVER['REMOTE_ADDR'], | ||||
|             'expires' => $expires ?? time() + 604800 | ||||
|           ]); | ||||
|  | ||||
|                         // Запись хеша | ||||
|                         $session->hash = sodium_bin2hex(sodium_crypto_generichash($_id)); | ||||
|           if ($session = collection::search(static::$db->session, sprintf( | ||||
|             <<<AQL | ||||
|               FOR d IN %s | ||||
|               FILTER d._id == '$_id' && d.expires > %d | ||||
|               RETURN d | ||||
|             AQL, | ||||
|             self::COLLECTION, | ||||
|             time() | ||||
|           ))) { | ||||
|             // Найдена созданная сессия | ||||
|  | ||||
|                         if (document::update(static::$db->session, $session)) { | ||||
|                             // Записано обновление | ||||
|             // Запись хеша | ||||
|             $session->hash = sodium_bin2hex(sodium_crypto_generichash($_id)); | ||||
|  | ||||
|                             return $session; | ||||
|                         } else throw new exception('Не удалось записать данные сессии'); | ||||
|                     } else throw new exception('Не удалось создать или найти созданную сессию'); | ||||
|                 } | ||||
|             } else throw new exception('Не удалось инициализировать коллекцию'); | ||||
|         } catch (exception $e) { | ||||
|             // Запись в журнал ошибок | ||||
|             $errors[] = [ | ||||
|                 'text' => $e->getMessage(), | ||||
|                 'file' => $e->getFile(), | ||||
|                 'line' => $e->getLine(), | ||||
|                 'stack' => $e->getTrace() | ||||
|             ]; | ||||
|             if (document::update(static::$db->session, $session)) { | ||||
|               // Записано обновление | ||||
|  | ||||
|               // Запись в свойство | ||||
|               $this->document = $session; | ||||
|             } else throw new exception('Не удалось записать данные сессии'); | ||||
|           } else throw new exception('Не удалось создать или найти созданную сессию'); | ||||
|         } | ||||
|       } else throw new exception('Не удалось инициализировать коллекцию'); | ||||
|     } catch (exception $e) { | ||||
|       // Запись в журнал ошибок | ||||
|       $errors[] = [ | ||||
|         'text' => $e->getMessage(), | ||||
|         'file' => $e->getFile(), | ||||
|         'line' => $e->getLine(), | ||||
|         'stack' => $e->getTrace() | ||||
|       ]; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|         return null; | ||||
|   /** | ||||
|    * Связь сессии с аккаунтом | ||||
|    * | ||||
|    * @param _document $account Инстанция аккаунта | ||||
|    * @param array &$errors Журнал ошибок | ||||
|    * | ||||
|    * @return bool Статус выполнения | ||||
|    */ | ||||
|   public function connect(_document $account, array &$errors = []): bool | ||||
|   { | ||||
|     try { | ||||
|       if ( | ||||
|         collection::init(static::$db->session, self::COLLECTION) | ||||
|         && collection::init(static::$db->session, account::COLLECTION) | ||||
|         && collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true) | ||||
|       ) { | ||||
|         // Инициализирована коллекция | ||||
|  | ||||
|         if (document::write(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, [ | ||||
|           '_from' => $this->document->getId(), | ||||
|           '_to' => $account->getId() | ||||
|         ])) { | ||||
|           // Создано ребро: session -> account | ||||
|  | ||||
|           return true; | ||||
|         } else throw new exception('Не удалось создать ребро: session -> account'); | ||||
|       } else throw new exception('Не удалось инициализировать коллекцию'); | ||||
|     } catch (exception $e) { | ||||
|       // Запись в журнал ошибок | ||||
|       $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 | ||||
|     { | ||||
|         try { | ||||
|             if ( | ||||
|                 collection::init(static::$db->session, self::COLLECTION) | ||||
|                 && collection::init(static::$db->session, account::COLLECTION) | ||||
|                 && collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true) | ||||
|             ) { | ||||
|                 // Инициализирована коллекция | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|                 if (document::write(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, [ | ||||
|                     '_from' => $session->getId(), | ||||
|                     '_to' => $account->getId() | ||||
|                 ])) { | ||||
|                     // Создано ребро: session -> account | ||||
|   /** | ||||
|    * Поиск связанного аккаунта | ||||
|    * | ||||
|    * @param array &$errors Журнал ошибок | ||||
|    * | ||||
|    * @return ?_document Инстанция аккаунта, если удалось найти | ||||
|    */ | ||||
|   public function account(array &$errors = []): ?_document | ||||
|   { | ||||
|     try { | ||||
|       if ( | ||||
|         collection::init(static::$db->session, self::COLLECTION) | ||||
|         && collection::init(static::$db->session, account::COLLECTION) | ||||
|         && collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true) | ||||
|       ) { | ||||
|         // Инициализированы коллекции | ||||
|  | ||||
|                     return true; | ||||
|                 } else throw new exception('Не удалось создать ребро: session -> account'); | ||||
|             } else throw new exception('Не удалось инициализировать коллекцию'); | ||||
|         } catch (exception $e) { | ||||
|             // Запись в журнал ошибок | ||||
|             $errors[] = [ | ||||
|                 'text' => $e->getMessage(), | ||||
|                 'file' => $e->getFile(), | ||||
|                 'line' => $e->getLine(), | ||||
|                 'stack' => $e->getTrace() | ||||
|             ]; | ||||
|         } | ||||
|         if ($account = collection::search(static::$db->session, sprintf( | ||||
|           <<<AQL | ||||
|             FOR document IN %s | ||||
|             LET edge = ( | ||||
|               FOR edge IN %s | ||||
|               FILTER edge._from == '%s' | ||||
|               SORT edge._key DESC | ||||
|               LIMIT 1 | ||||
|               RETURN edge | ||||
|             ) | ||||
|             FILTER document._id == edge[0]._to | ||||
|             LIMIT 1 | ||||
|             RETURN document | ||||
|           AQL, | ||||
|           account::COLLECTION, | ||||
|           self::COLLECTION . '_edge_' . account::COLLECTION, | ||||
|           $this->document->getId() | ||||
|         ))) { | ||||
|           // Найден аккаунт | ||||
|  | ||||
|         return false; | ||||
|           return $account; | ||||
|         } else throw new exception('Не удалось найти аккаунт'); | ||||
|       } else throw new exception('Не удалось инициализировать коллекцию'); | ||||
|     } catch (exception $e) { | ||||
|       // Запись в журнал ошибок | ||||
|       $errors[] = [ | ||||
|         'text' => $e->getMessage(), | ||||
|         'file' => $e->getFile(), | ||||
|         'line' => $e->getLine(), | ||||
|         'stack' => $e->getTrace() | ||||
|       ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Поиск связанного аккаунта | ||||
|      * | ||||
|      * @param _document $session Инстанция сессии | ||||
|      * @param array &$errors Журнал ошибок | ||||
|      * | ||||
|      * @return ?_document Инстанция аккаунта, если удалось найти | ||||
|      */ | ||||
|     public static function account(_document $session, array &$errors = []): ?_document | ||||
|     { | ||||
|         try { | ||||
|             if ( | ||||
|                 collection::init(static::$db->session, self::COLLECTION) | ||||
|                 && collection::init(static::$db->session, account::COLLECTION) | ||||
|                 && collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true) | ||||
|             ) { | ||||
|                 // Инициализированы коллекции | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|                 if ($account = collection::search(static::$db->session, sprintf( | ||||
|                     <<<AQL | ||||
|                         FOR document IN %s | ||||
|                         LET edge = ( | ||||
|                             FOR edge IN %s | ||||
|                             FILTER edge._from == '%s' | ||||
|                             SORT edge._key DESC | ||||
|                             LIMIT 1 | ||||
|                             RETURN edge | ||||
|                         ) | ||||
|                         FILTER document._id == edge[0]._to | ||||
|                         LIMIT 1 | ||||
|                         RETURN document | ||||
|                     AQL, | ||||
|                     account::COLLECTION, | ||||
|                     self::COLLECTION . '_edge_' . account::COLLECTION, | ||||
|                     $session->getId() | ||||
|                 ))) { | ||||
|                     // Найден аккаунт | ||||
|   /** | ||||
|    * Записать | ||||
|    * | ||||
|    * Ищет свойство, если не находит, то ищет его в инстанции документа сессии из базы данных, | ||||
|    * затем записывает в него переданные данные. Инициализация новых свойств происходит в инстанции | ||||
|    * документа сессии из базы данных  | ||||
|    * | ||||
|    * @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; | ||||
|   } | ||||
|  | ||||
|                     return $account; | ||||
|                 } else throw new exception('Не удалось найти аккаунт'); | ||||
|             } else throw new exception('Не удалось инициализировать коллекцию'); | ||||
|         } catch (exception $e) { | ||||
|             // Запись в журнал ошибок | ||||
|             $errors[] = [ | ||||
|                 'text' => $e->getMessage(), | ||||
|                 'file' => $e->getFile(), | ||||
|                 'line' => $e->getLine(), | ||||
|                 'stack' => $e->getTrace() | ||||
|             ]; | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|   /** | ||||
|    * Прочитать | ||||
|    * | ||||
|    * Ищет свойство, если не находит, то ищет его в инстанции документа сессии из базы данных | ||||
|    * | ||||
|    * @param string $name Название | ||||
|    * | ||||
|    * @return mixed Данные свойства инстанции сессии или инстанции документа сессии из базы данных | ||||
|    */ | ||||
|   public function __get(string $name): mixed | ||||
|   { | ||||
|     return $this->{$name} ?? $this->document->{$name}; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| @import url('/fonts/comissioner.ttf'); | ||||
| @import url('/fonts/commissioner.ttf'); | ||||
|  | ||||
| @media (prefers-color-scheme: light) { | ||||
|     :root { | ||||
|   | ||||
| @@ -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,6 +1,6 @@ | ||||
| {% 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 "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 %} | ||||
|   | ||||
							
								
								
									
										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