ребрендинг + строка пакостей

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2023-11-18 07:57:41 +07:00
parent 494a8dc41c
commit 5288bba8ca
68 changed files with 3670 additions and 3580 deletions

View File

@ -1,16 +1,15 @@
{ {
"name": "mirzaev/site-virus", "name": "mirzaev/site-ff",
"description": "Site with viruses and scary pictures", "description": "our FUCKING.FORUM",
"readme": "README.md", "readme": "README.md",
"keywords": [ "keywords": [
"virus", "forum",
"download",
"Evil Alliance", "Evil Alliance",
"imageboard", "imageboard",
"site" "site"
], ],
"type": "site", "type": "site",
"homepage": "https://git.mirzaev.sexy/mirzaev/site-virus", "homepage": "https://git.mirzaev.sexy/mirzaev/site-ff",
"license": "WTFPL", "license": "WTFPL",
"authors": [ "authors": [
{ {
@ -21,31 +20,31 @@
} }
], ],
"support": { "support": {
"docs": "https://git.mirzaev.sexy/mirzaev/site-virus/manual", "docs": "https://git.mirzaev.sexy/mirzaev/site-ff/manual",
"issues": "https://git.mirzaev.sexy/mirzaev/site-virus/issues" "issues": "https://git.mirzaev.sexy/mirzaev/site-ff/issues"
}, },
"require": { "require": {
"php": "~8.1", "php": "~8.2",
"ext-sodium": "~8.1", "ext-sodium": "~8.2",
"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": "^4.0", "mirzaev/vk": "^4.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",
"mirzaev/minimal": "^2.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "~9.5" "phpunit/phpunit": "~9.5"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"mirzaev\\site\\virus\\": "mirzaev/site/virus/system" "mirzaev\\site\\ff\\": "mirzaev/site/ff/system"
} }
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"mirzaev\\site\\virus\\tests\\": "mirzaev/site/virus/tests" "mirzaev\\site\\ff\\tests\\": "mirzaev/site/ff/tests"
} }
} }
} }

460
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\site\virus\controllers; namespace mirzaev\site\ff\controllers;
// Файлы проекта // Файлы проекта
use mirzaev\site\virus\controllers\core; use mirzaev\site\ff\controllers\core;
use mirzaev\site\virus\models\account_model as account; use mirzaev\site\ff\models\account_model as account;
use mirzaev\site\virus\models\session_model as session; use mirzaev\site\ff\models\session_model as session;
use mirzaev\site\virus\models\vk_model as vk; use mirzaev\site\ff\models\vk_model as vk;
// Библиотека для ArangoDB // Библиотека для ArangoDB
use ArangoDBClient\Document as _document; use ArangoDBClient\Document as _document;
@ -21,7 +21,7 @@ use mirzaev\vk\core as api;
/** /**
* Контроллер аккаунтов * Контроллер аккаунтов
* *
* @package mirzaev\site\virus\controllers * @package mirzaev\site\ff\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

View File

@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\site\virus\controllers; namespace mirzaev\site\ff\controllers;
// Файлы проекта // Файлы проекта
use mirzaev\site\virus\views\manager; use mirzaev\site\ff\views\manager;
use mirzaev\site\virus\models\core as models; use mirzaev\site\ff\models\core as models;
use mirzaev\site\virus\models\account_model as account; use mirzaev\site\ff\models\account_model as account;
use mirzaev\site\virus\models\session_model as session; use mirzaev\site\ff\models\session_model as session;
// Библиотека для ArangoDB // Библиотека для ArangoDB
use ArangoDBClient\Document as _document; use ArangoDBClient\Document as _document;
@ -23,7 +23,7 @@ use mirzaev\vk\robots\user as robot;
/** /**
* Ядро контроллеров * Ядро контроллеров
* *
* @package mirzaev\site\virus\controllers * @package mirzaev\site\ff\controllers
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/ */
class core extends controller class core extends controller
@ -69,7 +69,7 @@ class core extends controller
// Запись хеша новой сессии // Запись хеша новой сессии
setcookie('session', $this->variables['session']->hash, [ setcookie('session', $this->variables['session']->hash, [
'expires' => $expires, 'expires' => $expires,
'domain' => 'virus.mirzaev.sexy', 'domain' => 'ff.mirzaev.sexy',
'path' => '/', 'path' => '/',
'secure' => true, 'secure' => true,
'httponly' => true, 'httponly' => true,

View File

@ -2,15 +2,15 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\site\virus\controllers; namespace mirzaev\site\ff\controllers;
// Файлы проекта // Файлы проекта
use mirzaev\site\virus\controllers\core; use mirzaev\site\ff\controllers\core;
/** /**
* Контроллер ошибок * Контроллер ошибок
* *
* @package mirzaev\site\virus\controllers * @package mirzaev\site\ff\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

View File

@ -2,15 +2,15 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\site\virus\controllers; namespace mirzaev\site\ff\controllers;
// Файлы проекта // Файлы проекта
use mirzaev\site\virus\controllers\core; use mirzaev\site\ff\controllers\core;
/** /**
* Контроллер бегущей строки * Контроллер бегущей строки
* *
* @package mirzaev\site\virus\controllers * @package mirzaev\site\ff\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

View File

@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
namespace mirzaev\site\ff\controllers;
// Файлы проекта
use mirzaev\site\ff\controllers\core;
/**
* Контроллер основной страницы
*
* @package mirzaev\site\ff\controllers
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class index_controller extends core
{
/**
* Главная страница
*
* @param array $parameters Параметры запроса
*/
public function index(array $parameters = []): ?string
{
// Инициализация загружаемых категорий
$this->variables['include'] = [
'head' => ['self'],
'body' => ['self']
];
// Инициализация бегущей строки
$this->variables['hotline'] = [
'id' => $this->variables['request']['id'] ?? 'hotline'
];
// Инициализация параметров бегущей строки
$this->variables['hotline']['parameters'] = [
'step' => '0.3'
];
// Инициализация аттрибутов бегущей строки
$this->variables['hotline']['attributes'] = [];
// Инициализация элементов бегущей строки
$this->variables['hotline']['elements'] = [
['html' => '1'],
[
'tag' => 'article',
'attributes' => [
'class' => 'trash'
],
'html' => $this->view->render(DIRECTORY_SEPARATOR . 'hotline' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . 'trash.html', [
'id' => 'trash_1',
'title' => 'Linoleum',
'main' => '<p>Do you really like the rotting smell, dull sound and disgusting greasy shine of parquet-like fake pattern on a polymer toxic film? <b>Are you fucking insane?</b></p>',
'image' => [
'src' => '/images/trash/linoleum.png',
'alt' => 'Linoleum'
]
])
],
['html' => '3'],
['html' => '4'],
['html' => '5'],
['html' => '6'],
['html' => '7'],
['html' => '8'],
['html' => '9'],
['html' => '10'],
['html' => '11'],
['html' => '12'],
['html' => '13'],
['html' => '14'],
['html' => '15']
];
// Генерация представления
return $this->view->render(DIRECTORY_SEPARATOR . 'index.html', $this->variables);
}
}

View File

@ -2,10 +2,10 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\site\virus\models; namespace mirzaev\site\ff\models;
// Файлы проекта // Файлы проекта
use mirzaev\site\virus\models\vk_model as vk; use mirzaev\site\ff\models\vk_model as vk;
// Фреймворк ArangoDB // Фреймворк ArangoDB
use mirzaev\arangodb\collection, use mirzaev\arangodb\collection,
@ -20,7 +20,7 @@ use exception;
/** /**
* Модель регистрации, аутентификации и авторизации * Модель регистрации, аутентификации и авторизации
* *
* @package mirzaev\site\virus\models * @package mirzaev\site\ff\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

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\site\virus\models; namespace mirzaev\site\ff\models;
use mirzaev\minimal\model; use mirzaev\minimal\model;
@ -13,7 +13,7 @@ use exception;
/** /**
* Ядро моделей * Ядро моделей
* *
* @package mirzaev\site\virus\models * @package mirzaev\site\ff\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

View File

@ -0,0 +1,216 @@
<?php
declare(strict_types=1);
namespace mirzaev\site\ff\models;
// Файлы проекта
use mirzaev\site\ff\models\account_model as account;
// Фреймворк ArangoDB
use mirzaev\arangodb\collection,
mirzaev\arangodb\document;
// Библиотека для ArangoDB
use ArangoDBClient\Document as _document;
// Встроенные библиотеки
use exception;
/**
* Модель сессий
*
* @package mirzaev\site\ff\models
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class session_model extends core
{
/**
* Коллекция
*/
public const COLLECTION = 'session';
/**
* Инициализация
*
* @param ?string $hash Хеш сессии в базе данных
* @param ?int $expires Дата окончания работы сессии (используется при создании новой сессии)
* @param array &$errors Журнал ошибок
*
* @return ?_document Инстанция сессии, если удалось найти или создать
*/
public static function initialization(?string $hash = null, ?int $expires = null, array &$errors = []): ?_document
{
$a = new _document();
$a->hash = 'dolboeb227';
return $a;
try {
if (collection::init(static::$db->session, self::COLLECTION)) {
// Инициализирована коллекция
if (isset($hash) && $session = collection::search(static::$db->session, sprintf(
<<<AQL
FOR d IN %s
FILTER d.hash == '$hash' && d.expires > %d
RETURN d
AQL,
self::COLLECTION,
time()
))) {
// Найдена сессия по хешу
// Возврат сессии
return $session;
} else if ($session = collection::search(static::$db->session, sprintf(
<<<AQL
FOR d IN %s
FILTER d.ip == '%s' && d.expires > %d
RETURN d
AQL,
self::COLLECTION,
$_SERVER['REMOTE_ADDR'],
time()
))) {
// Найдена сессия по данным пользователя
// Возврат сессии
return $session;
} else {
// Не найдена сессия
// Запись сессии в базу данных
$_id = document::write(static::$db->session, self::COLLECTION, [
'ip' => $_SERVER['REMOTE_ADDR'],
'expires' => $expires ?? time() + 604800
]);
if ($session = collection::search(static::$db->session, sprintf(
<<<AQL
FOR d IN %s
FILTER d._id == '$_id' && d.expires > %d
RETURN d
AQL,
self::COLLECTION,
time()
))) {
// Найдена созданная сессия
// Запись хеша
$session->hash = sodium_bin2hex(sodium_crypto_generichash($_id));
if (document::update(static::$db->session, $session)) {
// Записано обновление
return $session;
} else throw new exception('Не удалось записать данные сессии');
} else throw new exception('Не удалось создать или найти созданную сессию');
}
} else throw new exception('Не удалось инициализировать коллекцию');
} catch (exception $e) {
// Запись в журнал ошибок
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
return null;
}
/**
* Связь сессии с аккаунтом
*
* @param _document $session Инстанция сессии
* @param _document $account Инстанция аккаунта
* @param array &$errors Журнал ошибок
*
* @return bool Статус выполнения
*/
public static function connect(_document $session, _document $account, array &$errors = []): bool
{
try {
if (
collection::init(static::$db->session, self::COLLECTION)
&& collection::init(static::$db->session, account::COLLECTION)
&& collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true)
) {
// Инициализирована коллекция
if (document::write(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, [
'_from' => $session->getId(),
'_to' => $account->getId()
])) {
// Создано ребро: session -> account
return true;
} else throw new exception('Не удалось создать ребро: session -> account');
} else throw new exception('Не удалось инициализировать коллекцию');
} catch (exception $e) {
// Запись в журнал ошибок
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
return false;
}
/**
* Поиск связанного аккаунта
*
* @param _document $session Инстанция сессии
* @param array &$errors Журнал ошибок
*
* @return ?_document Инстанция аккаунта, если удалось найти
*/
public static function account(_document $session, array &$errors = []): ?_document
{
try {
if (
collection::init(static::$db->session, self::COLLECTION)
&& collection::init(static::$db->session, account::COLLECTION)
&& collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true)
) {
// Инициализированы коллекции
if ($account = collection::search(static::$db->session, sprintf(
<<<AQL
FOR document IN %s
LET edge = (
FOR edge IN %s
FILTER edge._from == '%s'
SORT edge._key DESC
LIMIT 1
RETURN edge
)
FILTER document._id == edge[0]._to
LIMIT 1
RETURN document
AQL,
account::COLLECTION,
self::COLLECTION . '_edge_' . account::COLLECTION,
$session->getId()
))) {
// Найден аккаунт
return $account;
} else throw new exception('Не удалось найти аккаунт');
} else throw new exception('Не удалось инициализировать коллекцию');
} catch (exception $e) {
// Запись в журнал ошибок
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
return null;
}
}

View File

@ -2,10 +2,10 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\site\virus\models; namespace mirzaev\site\ff\models;
// Файлы проекта // Файлы проекта
use mirzaev\site\virus\models\account_model as account; use mirzaev\site\ff\models\account_model as account;
// Фреймворк ArangoDB // Фреймворк ArangoDB
use mirzaev\arangodb\collection, use mirzaev\arangodb\collection,
@ -27,7 +27,7 @@ use stdClass;
/** /**
* Модель аккаунта ВКонтакте * Модель аккаунта ВКонтакте
* *
* @package mirzaev\site\virus\models * @package mirzaev\site\ff\models
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/ */
final class vk_model extends core final class vk_model extends core

View File

@ -0,0 +1,37 @@
section.hotline {
display: inline-flex;
height: 100%;
transition: unset;
/* gap нельзя */
}
section.hotline * {
transition: unset;
}
section.hotline:last-child {
margin-bottom: unset;
}
section.hotline > article {
position: relative;
margin-right: 18px;
width: calc(140px - var(--padding, 0px) * 2);
height: calc(190px - var(--padding, 0px) * 2);
padding: var(--padding, 0px);
display: flex;
align-self: flex-end;
overflow: clip;
border-radius: 3px;
background-color: var(--background-light-1);
box-shadow: 0px -6px 6px rgba(0, 0, 0, 0.3);
}
section.hotline>article:last-child {
margin-right: unset;
}
section.hotline > article > * {
margin: auto;
}

View File

@ -0,0 +1,49 @@
section.hotline > article.trash {
--padding: 12px;
flex-direction: column;
align-items: center;
gap: 7px;
cursor: zoom-in;
}
section.hotline > article.trash > h1 {
z-index: 10;
margin-top: 10px;
flex-grow: 4;
font-size: 0.9rem;
}
section.hotline > article.trash :is(p, b) {
z-index: 10;
flex-grow: 1;
font-size: 0.6rem;
text-align: justify;
}
section.hotline > article.trash small {
z-index: 10;
flex-grow: 1;
font-size: 0.5rem;
}
section.hotline > article.trash > img {
z-index: 5;
position: absolute;
left: -5%;
top: -5%;
width: 110%;
height: 110%;
object-position: center;
object-fit: cover;
filter: blur(2px) saturate(30%) brightness(40%);
transition: 0.2s ease-in;
}
section.hotline > article.trash:is(:hover, :active) > img {
left: -20%;
top: -20%;
width: 140%;
height: 140%;
filter: blur(3px) saturate(0) brightness(60%) contrast(150%);
transition: 0.1s ease-out;
}

View File

Before

Width:  |  Height:  |  Size: 552 B

After

Width:  |  Height:  |  Size: 552 B

View File

Before

Width:  |  Height:  |  Size: 328 B

After

Width:  |  Height:  |  Size: 328 B

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

View File

Before

Width:  |  Height:  |  Size: 825 B

After

Width:  |  Height:  |  Size: 825 B

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 397 KiB

After

Width:  |  Height:  |  Size: 397 KiB

View File

Before

Width:  |  Height:  |  Size: 295 KiB

After

Width:  |  Height:  |  Size: 295 KiB

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\site\virus; namespace mirzaev\site\ff;
use mirzaev\minimal\core; use mirzaev\minimal\core;
use mirzaev\minimal\router; use mirzaev\minimal\router;

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -2,6 +2,7 @@
{% block css %} {% block css %}
{# {{ block('hotline_css') }} #} {# {{ block('hotline_css') }} #}
<link type="text/css" rel="stylesheet" href="/css/trash.css">
{% endblock %} {% endblock %}
{% block body %} {% block body %}

View File

@ -8,7 +8,7 @@
%} 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'}} {% for attribute, value in element.attributes %}{{ attribute }}="{{ value }}"{% endfor %}>{{ element.html|raw }}</{{element.tag??'article'}}>
{% endfor %} {% endfor %}
</section> </section>
{% endif %} {% endif %}

View File

@ -0,0 +1,15 @@
<h1>{{ title }}</h1>
{{ main|raw }}
{% if image is not null %}<img src="{{ image.src }}" alt="{{ image.alt }}">{% endif %}
<script>
// Initialization of the element
const element = document.getElementById('{{ id }}');
if (element instanceof HTMLElement) {
// Found the element
element.addEventListener('mouseenter', () => {
console.log('{{ id }}');
});
}
</script>

View File

@ -19,7 +19,7 @@
{{ block('header_body') }} {{ block('header_body') }}
<main> <main>
<noscript>К сожалению мой сайт ещё пока не готов для работы без javascript</noscript> <noscript>Весь код на JavaScript выполняется из соглашения по твоему выбору через popup-окно (cookies), смело включай</noscript>
{% block main %} {% block main %}
{% endblock %} {% endblock %}
</main> </main>

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace mirzaev\site\virus\views; namespace mirzaev\site\ff\views;
use mirzaev\minimal\controller; use mirzaev\minimal\controller;
@ -12,7 +12,7 @@ use Twig\Environment as view;
/** /**
* Менеджер представлений * Менеджер представлений
* *
* @package mirzaev\site\virus\controllers * @package mirzaev\site\ff\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

View File

@ -1,71 +0,0 @@
<?php
declare(strict_types=1);
namespace mirzaev\site\virus\controllers;
// Файлы проекта
use mirzaev\site\virus\controllers\core;
/**
* Контроллер основной страницы
*
* @package mirzaev\site\virus\controllers
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class index_controller extends core
{
/**
* Главная страница
*
* @param array $parameters Параметры запроса
*/
public function index(array $parameters = []): ?string
{
// Инициализация загружаемых категорий
$this->variables['include'] = [
'head' => ['self'],
'body' => ['self']
];
// Инициализация бегущей строки
$this->variables['hotline'] = [
'id' => $this->variables['request']['id'] ?? 'hotline'
];
// Инициализация параметров бегущей строки
$this->variables['hotline']['parameters'] = [
// 'step' => 2
];
// Инициализация аттрибутов бегущей строки
$this->variables['hotline']['attributes'] = [
];
// Инициализация элементов бегущей строки
$this->variables['hotline']['elements'] = [
['content' => '1'],
[
'tag' => 'article',
'content' => '2'
],
['content' => '3'],
['content' => '4'],
['content' => '5'],
['content' => '6'],
['content' => '7'],
['content' => '8'],
['content' => '9'],
['content' => '10'],
['content' => '11'],
['content' => '12'],
['content' => '13'],
['content' => '14'],
['content' => '15']
];
// Генерация представления
return $this->view->render(DIRECTORY_SEPARATOR . 'index.html', $this->variables);
}
}

View File

@ -1,213 +0,0 @@
<?php
declare(strict_types=1);
namespace mirzaev\site\virus\models;
// Файлы проекта
use mirzaev\site\virus\models\account_model as account;
// Фреймворк ArangoDB
use mirzaev\arangodb\collection,
mirzaev\arangodb\document;
// Библиотека для ArangoDB
use ArangoDBClient\Document as _document;
// Встроенные библиотеки
use exception;
/**
* Модель сессий
*
* @package mirzaev\site\virus\models
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class session_model extends core
{
/**
* Коллекция
*/
public const COLLECTION = 'session';
/**
* Инициализация
*
* @param ?string $hash Хеш сессии в базе данных
* @param ?int $expires Дата окончания работы сессии (используется при создании новой сессии)
* @param array &$errors Журнал ошибок
*
* @return ?_document Инстанция сессии, если удалось найти или создать
*/
public static function initialization(?string $hash = null, ?int $expires = null, array &$errors = []): ?_document
{
try {
if (collection::init(static::$db->session, self::COLLECTION)) {
// Инициализирована коллекция
if (isset($hash) && $session = collection::search(static::$db->session, sprintf(
<<<AQL
FOR d IN %s
FILTER d.hash == '$hash' && d.expires > %d
RETURN d
AQL,
self::COLLECTION,
time()
))) {
// Найдена сессия по хешу
// Возврат сессии
return $session;
} else if ($session = collection::search(static::$db->session, sprintf(
<<<AQL
FOR d IN %s
FILTER d.ip == '%s' && d.expires > %d
RETURN d
AQL,
self::COLLECTION,
$_SERVER['REMOTE_ADDR'],
time()
))) {
// Найдена сессия по данным пользователя
// Возврат сессии
return $session;
} else {
// Не найдена сессия
// Запись сессии в базу данных
$_id = document::write(static::$db->session, self::COLLECTION, [
'ip' => $_SERVER['REMOTE_ADDR'],
'expires' => $expires ?? time() + 604800
]);
if ($session = collection::search(static::$db->session, sprintf(
<<<AQL
FOR d IN %s
FILTER d._id == '$_id' && d.expires > %d
RETURN d
AQL,
self::COLLECTION,
time()
))) {
// Найдена созданная сессия
// Запись хеша
$session->hash = sodium_bin2hex(sodium_crypto_generichash($_id));
if (document::update(static::$db->session, $session)) {
// Записано обновление
return $session;
} else throw new exception('Не удалось записать данные сессии');
} else throw new exception('Не удалось создать или найти созданную сессию');
}
} else throw new exception('Не удалось инициализировать коллекцию');
} catch (exception $e) {
// Запись в журнал ошибок
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
return null;
}
/**
* Связь сессии с аккаунтом
*
* @param _document $session Инстанция сессии
* @param _document $account Инстанция аккаунта
* @param array &$errors Журнал ошибок
*
* @return bool Статус выполнения
*/
public static function connect(_document $session, _document $account, array &$errors = []): bool
{
try {
if (
collection::init(static::$db->session, self::COLLECTION)
&& collection::init(static::$db->session, account::COLLECTION)
&& collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true)
) {
// Инициализирована коллекция
if (document::write(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, [
'_from' => $session->getId(),
'_to' => $account->getId()
])) {
// Создано ребро: session -> account
return true;
} else throw new exception('Не удалось создать ребро: session -> account');
} else throw new exception('Не удалось инициализировать коллекцию');
} catch (exception $e) {
// Запись в журнал ошибок
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
return false;
}
/**
* Поиск связанного аккаунта
*
* @param _document $session Инстанция сессии
* @param array &$errors Журнал ошибок
*
* @return ?_document Инстанция аккаунта, если удалось найти
*/
public static function account(_document $session, array &$errors = []): ?_document
{
try {
if (
collection::init(static::$db->session, self::COLLECTION)
&& collection::init(static::$db->session, account::COLLECTION)
&& collection::init(static::$db->session, self::COLLECTION . '_edge_' . account::COLLECTION, true)
) {
// Инициализированы коллекции
if ($account = collection::search(static::$db->session, sprintf(
<<<AQL
FOR document IN %s
LET edge = (
FOR edge IN %s
FILTER edge._from == '%s'
SORT edge._key DESC
LIMIT 1
RETURN edge
)
FILTER document._id == edge[0]._to
LIMIT 1
RETURN document
AQL,
account::COLLECTION,
self::COLLECTION . '_edge_' . account::COLLECTION,
$session->getId()
))) {
// Найден аккаунт
return $account;
} else throw new exception('Не удалось найти аккаунт');
} else throw new exception('Не удалось инициализировать коллекцию');
} catch (exception $e) {
// Запись в журнал ошибок
$errors[] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
return null;
}
}

View File

@ -1,31 +0,0 @@
section.hotline {
display: inline-flex;
height : 100%;
}
section.hotline * {
transition: unset;
}
section.hotline:last-child {
margin-bottom: unset;
}
section.hotline>article {
margin-right : 18px;
width : 140px;
height : 190px;
display : flex;
align-self : flex-end;
border-radius : 3px;
background-color: var(--background-light-1);
box-shadow : 0px -6px 6px rgba(0, 0, 0, 0.3);
}
section.hotline>article:last-child {
margin-right: unset;
}
section.hotline>article>* {
margin: auto;
}