ребрендинг + строка пакостей
|
@ -1,16 +1,15 @@
|
|||
{
|
||||
"name": "mirzaev/site-virus",
|
||||
"description": "Site with viruses and scary pictures",
|
||||
"name": "mirzaev/site-ff",
|
||||
"description": "our FUCKING.FORUM",
|
||||
"readme": "README.md",
|
||||
"keywords": [
|
||||
"virus",
|
||||
"download",
|
||||
"forum",
|
||||
"Evil Alliance",
|
||||
"imageboard",
|
||||
"site"
|
||||
],
|
||||
"type": "site",
|
||||
"homepage": "https://git.mirzaev.sexy/mirzaev/site-virus",
|
||||
"homepage": "https://git.mirzaev.sexy/mirzaev/site-ff",
|
||||
"license": "WTFPL",
|
||||
"authors": [
|
||||
{
|
||||
|
@ -21,31 +20,31 @@
|
|||
}
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://git.mirzaev.sexy/mirzaev/site-virus/manual",
|
||||
"issues": "https://git.mirzaev.sexy/mirzaev/site-virus/issues"
|
||||
"docs": "https://git.mirzaev.sexy/mirzaev/site-ff/manual",
|
||||
"issues": "https://git.mirzaev.sexy/mirzaev/site-ff/issues"
|
||||
},
|
||||
"require": {
|
||||
"php": "~8.1",
|
||||
"ext-sodium": "~8.1",
|
||||
"mirzaev/minimal": "^2.0.x-dev",
|
||||
"php": "~8.2",
|
||||
"ext-sodium": "~8.2",
|
||||
"mirzaev/accounts": "~1.2.x-dev",
|
||||
"mirzaev/arangodb": "^1.0.0",
|
||||
"mirzaev/vk": "^4.0",
|
||||
"triagens/arangodb": "~3.9.x-dev",
|
||||
"twig/twig": "^3.4",
|
||||
"guzzlehttp/guzzle": "^7.5"
|
||||
"guzzlehttp/guzzle": "^7.5",
|
||||
"mirzaev/minimal": "^2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~9.5"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"mirzaev\\site\\virus\\": "mirzaev/site/virus/system"
|
||||
"mirzaev\\site\\ff\\": "mirzaev/site/ff/system"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"mirzaev\\site\\virus\\tests\\": "mirzaev/site/virus/tests"
|
||||
"mirzaev\\site\\ff\\tests\\": "mirzaev/site/ff/tests"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace mirzaev\site\virus\controllers;
|
||||
namespace mirzaev\site\ff\controllers;
|
||||
|
||||
// Файлы проекта
|
||||
use mirzaev\site\virus\controllers\core;
|
||||
use mirzaev\site\virus\models\account_model as account;
|
||||
use mirzaev\site\virus\models\session_model as session;
|
||||
use mirzaev\site\virus\models\vk_model as vk;
|
||||
use mirzaev\site\ff\controllers\core;
|
||||
use mirzaev\site\ff\models\account_model as account;
|
||||
use mirzaev\site\ff\models\session_model as session;
|
||||
use mirzaev\site\ff\models\vk_model as vk;
|
||||
|
||||
// Библиотека для ArangoDB
|
||||
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>
|
||||
*/
|
||||
final class account_controller extends core
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace mirzaev\site\virus\controllers;
|
||||
namespace mirzaev\site\ff\controllers;
|
||||
|
||||
// Файлы проекта
|
||||
use mirzaev\site\virus\views\manager;
|
||||
use mirzaev\site\virus\models\core as models;
|
||||
use mirzaev\site\virus\models\account_model as account;
|
||||
use mirzaev\site\virus\models\session_model as session;
|
||||
use mirzaev\site\ff\views\manager;
|
||||
use mirzaev\site\ff\models\core as models;
|
||||
use mirzaev\site\ff\models\account_model as account;
|
||||
use mirzaev\site\ff\models\session_model as session;
|
||||
|
||||
// Библиотека для ArangoDB
|
||||
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>
|
||||
*/
|
||||
class core extends controller
|
||||
|
@ -69,7 +69,7 @@ class core extends controller
|
|||
// Запись хеша новой сессии
|
||||
setcookie('session', $this->variables['session']->hash, [
|
||||
'expires' => $expires,
|
||||
'domain' => 'virus.mirzaev.sexy',
|
||||
'domain' => 'ff.mirzaev.sexy',
|
||||
'path' => '/',
|
||||
'secure' => true,
|
||||
'httponly' => true,
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
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>
|
||||
*/
|
||||
final class error_controller extends core
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
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>
|
||||
*/
|
||||
final class hotline_controller extends core
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
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
|
||||
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>
|
||||
*/
|
||||
final class account_model extends core
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace mirzaev\site\virus\models;
|
||||
namespace mirzaev\site\ff\models;
|
||||
|
||||
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>
|
||||
*/
|
||||
class core extends model
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
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
|
||||
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>
|
||||
*/
|
||||
final class vk_model extends core
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Before Width: | Height: | Size: 552 B After Width: | Height: | Size: 552 B |
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 328 B |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 537 B |
Before Width: | Height: | Size: 825 B After Width: | Height: | Size: 825 B |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 397 KiB After Width: | Height: | Size: 397 KiB |
Before Width: | Height: | Size: 295 KiB After Width: | Height: | Size: 295 KiB |
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace mirzaev\site\virus;
|
||||
namespace mirzaev\site\ff;
|
||||
|
||||
use mirzaev\minimal\core;
|
||||
use mirzaev\minimal\router;
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
@ -2,6 +2,7 @@
|
|||
|
||||
{% block css %}
|
||||
{# {{ block('hotline_css') }} #}
|
||||
<link type="text/css" rel="stylesheet" href="/css/trash.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
|
@ -8,7 +8,7 @@
|
|||
%} data-hotline-{{ name }}="{{value}}" {% endfor %} {% for name, value in hotline.attributes %} {{ name
|
||||
}}="{{value}}" {% endfor %}>
|
||||
{% 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 %}
|
||||
</section>
|
||||
{% endif %}
|
|
@ -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>
|
|
@ -19,7 +19,7 @@
|
|||
{{ block('header_body') }}
|
||||
|
||||
<main>
|
||||
<noscript>К сожалению мой сайт ещё пока не готов для работы без javascript</noscript>
|
||||
<noscript>Весь код на JavaScript выполняется из соглашения по твоему выбору через popup-окно (cookies), смело включай</noscript>
|
||||
{% block main %}
|
||||
{% endblock %}
|
||||
</main>
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace mirzaev\site\virus\views;
|
||||
namespace mirzaev\site\ff\views;
|
||||
|
||||
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>
|
||||
*/
|
||||
final class manager extends controller
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|