начало работы над сессиями и там дохуя чего ещё

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2023-02-25 15:06:59 +10:00
parent ed5756d065
commit b2a78519e4
39 changed files with 3692 additions and 3609 deletions

6
.gitignore vendored
View File

@ -1,3 +1,3 @@
!.gitignore !.gitignore
composer.phar composer.phar
vendor vendor

22
LICENSE
View File

@ -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.

View File

@ -1,3 +1,3 @@
# site-account # site-account
Site for intersite authentication Site for intersite authentication

View File

@ -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" }
} }
} }
}

View File

@ -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);
} }
} }

View File

@ -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) {
// Инициализирован аккаунт // Инициализирован аккаунт

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
}
}

View File

@ -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;
} }
} }

View File

@ -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)
}; };
} }
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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%);
} }

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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)
} }

View File

@ -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;
} }

View File

@ -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

View File

@ -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();
} }

View File

@ -1 +1 @@
arangodb.php arangodb.php

View File

@ -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' => ''
]; ];

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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>

View File

@ -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>

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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

View 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 %}

View 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 %}