commit d1a6e3f914e1aa38cadaa8742308c3efb9f51f78 Author: Arsen Mirzaev Tatyano-Muradovich Date: Mon Jul 15 15:20:06 2024 +0700 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c26c9a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +!.gitignore +composer.phar +composer.lock +vendor diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..e007a57 --- /dev/null +++ b/LICENSE @@ -0,0 +1,11 @@ +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar + +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 +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.md b/README.md new file mode 100755 index 0000000..7e386e5 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# parser_from_rossko + diff --git a/author/project/system/controllers/core.php b/author/project/system/controllers/core.php new file mode 100644 index 0000000..3ae6699 --- /dev/null +++ b/author/project/system/controllers/core.php @@ -0,0 +1,121 @@ + + */ +class core extends controller +{ + /** + * Postfix for name of controllers files + */ + final public const POSTFIX = ''; + + /** + * Instance of a session + */ + protected readonly session session; + + /** + * Instance of an account + */ + protected readonly ?account account; + + /** + * Registry of errors + */ + protected array errors = [ + 'session' => [], + 'account' => [] + ]; + + /** + * Constructor of an instance + * + * @param bool initialize Initialize a controller? + * + * @return void + */ + public function __construct(bool initialize = true) + { + // Blocking requests from CloudFlare (better to write this blocking into nginx config file) + if (_SERVER['HTTP_USER_AGENT'] === 'nginx-ssl early hints') return; + + // For the extends system + parent::__construct(initialize); + + if (initialize) { + // Initializing is requested + + // Initializing of models core (connect to ArangoDB...) + new models(); + + // Initializing of the date until which the session will be active + expires = strtotime('+1 week'); + + // Initializing of default value of hash of the session + _COOKIE["session"] ??= null; + + // Initializing of session + this->session = new session(_COOKIE["session"], expires, this->errors['session']); + + // Handle a problems with initializing a session + if (!empty(this->errors['session'])) die; + else if (_COOKIE["session"] !== this->session->hash) { + // Hash of the session is changed (implies that the session has expired and recreated) + + // Write a new hash of the session to cookies + setcookie( + 'session', + this->session->hash, + [ + 'expires' => expires, + 'path' => '/', + 'secure' => true, + 'httponly' => true, + 'samesite' => 'strict' + ] + ); + } + + // Initializing of preprocessor of views + this->view = new templater(this->session); + } + } + + /** + * Check of initialization + * + * Checks whether a property is initialized in a document instance from ArangoDB + * + * @param string name Name of the property from ArangoDB + * + * @return bool The property is initialized? + */ + public function __isset(string name): bool + { + // Check of initialization of the property and exit (success) + return match (name) { + default => isset(this->{name}) + }; + } + +} diff --git a/author/project/system/controllers/index.php b/author/project/system/controllers/index.php new file mode 100644 index 0000000..e7e7db7 --- /dev/null +++ b/author/project/system/controllers/index.php @@ -0,0 +1,32 @@ + + */ +final class index extends core +{ + /** + * Render the main page + * + * @param array parameters Parameters of the request (POST + GET) + */ + public function index(array parameters = []): ?string + { + // Exit (success) + if (_SERVER['REQUEST_METHOD'] === 'GET') return this->view->render(DIRECTORY_SEPARATOR . 'index.html'); + else if (_SERVER['REQUEST_METHOD'] === 'POST') return main; + + // Exit (fail) + return null; + } +} diff --git a/author/project/system/models/core.php b/author/project/system/models/core.php new file mode 100644 index 0000000..9ebd96e --- /dev/null +++ b/author/project/system/models/core.php @@ -0,0 +1,289 @@ + + */ +class core extends model +{ + /** + * Postfix for name of models files + */ + final public const POSTFIX = ''; + + /** + * Path to the file with settings of connecting to the ArangoDB + */ + final public const ARANGODB = '../settings/arangodb.php'; + + /** + * Instance of the session of ArangoDB + */ + protected static arangodb arangodb; + + /** + * Name of the collection in ArangoDB + */ + public const COLLECTION = 'THIS_COLLECTION_SHOULD_NOT_EXIST_REPLACE_IT_IN_THE_MODEL'; + + /** + * Constructor of an instance + * + * @param bool initialize Initialize a model? + * @param ?arangodb arangodb Instance of a session of ArangoDB + * + * @return void + */ + public function __construct(bool initialize = true, ?arangodb arangodb = null) + { + // For the extends system + parent::__construct(initialize); + + if (initialize) { + // Initializing is requested + + if (isset(arangodb)) { + // Recieved an instance of a session of ArangoDB + + // Write an instance of a session of ArangoDB to the property + this->__set('arangodb', arangodb); + } else { + // Not recieved an instance of a session of ArangoDB + + // Initializing of an instance of a session of ArangoDB + this->__get('arangodb'); + } + } + } + + /** + * Read from ArangoDB + * + * @param string filter Expression for filtering (AQL) + * @param string sort Expression for sorting (AQL) + * @param int amount Amount of documents for collect + * @param int page Page + * @param string return Expression describing the parameters to return (AQL) + * @param array &errors The registry on errors + * + * @return _document|array|null An array of instances of documents from ArangoDB, if they are found + */ + public static function read( + string filter = '', + string sort = 'd.created DESC, d._key DESC', + int amount = 1, + int page = 1, + string return = 'd', + array &errors = [] + ): _document|array|null { + try { + if (collection::init(static::arangodb->session, static::COLLECTION)) { + // Initialized the collection + + // Read from ArangoDB and exit (success) + return collection::search( + static::arangodb->session, + sprintf( + <<<'AQL' + FOR d IN %s + %s + %s + LIMIT %d, %d + RETURN %s + AQL, + static::COLLECTION, + empty(filter) ? '' : "FILTER filter", + empty(sort) ? '' : "SORT sort", + --page <= 0 ? 0 : amount * page, + amount, + return + ) + ); + } else throw new exception('Failed to initialize the collection'); + } catch (exception e) { + // Write to the registry of errors + errors[] = [ + 'text' => e->getMessage(), + 'file' => e->getFile(), + 'line' => e->getLine(), + 'stack' => e->getTrace() + ]; + } + + // Exit (fail) + return null; + } + + /** + * Delete from ArangoDB + * + * @param _document instance Instance of the document from ArangoDB + * @param array &errors The registry on errors + * + * @return bool Deleted from ArangoDB without errors? + */ + public static function delete(_document instance, array &errors = []): bool + { + try { + if (collection::init(static::arangodb->session, static::COLLECTION)) { + // Initialized the collection + + // Delete from ArangoDB and exit (success) + return (new _document_handler(static::arangodb->session))->remove(instance); + } else throw new exception('Failed to initialize the collection'); + } catch (exception e) { + // Write to the registry of errors + errors[] = [ + 'text' => e->getMessage(), + 'file' => e->getFile(), + 'line' => e->getLine(), + 'stack' => e->getTrace() + ]; + } + + // Exit (fail) + return false; + } + + /** + * Update in ArangoDB + * + * @param _document instance Instance of the document from ArangoDB + * + * @return bool Writed to ArangoDB without errors? + */ + public static function update(_document instance): bool + { + // Update in ArangoDB and exit (success) + return document::update(static::arangodb->session, instance); + } + + /** + * Write + * + * @param string name Name of the property + * @param mixed value Value of the property + * + * @return void + */ + public function __set(string name, mixed value = null): void + { + match (name) { + 'arangodb' => (function () use (value) { + if (this->__isset('arangodb')) { + // Is alredy initialized + + // Exit (fail) + throw new exception('Forbidden to reinitialize the session of ArangoDB (this::arangodb)', 500); + } else { + // Is not already initialized + + if (value instanceof arangodb) { + // Recieved an appropriate value + + // Write the property and exit (success) + self::arangodb = value; + } else { + // Recieved an inappropriate value + + // Exit (fail) + throw new exception('Session of ArangoDB (this::arangodb) is need to be mirzaev\arangodb\connection', 500); + } + } + })(), + default => parent::__set(name, value) + }; + } + + /** + * Read + * + * @param string name Name of the property + * + * @return mixed Content of the property, if they are found + */ + public function __get(string name): mixed + { + return match (name) { + 'arangodb' => (function () { + try { + if (!this->__isset('arangodb')) { + // Is not initialized + + // Initializing of a default value from settings + this->__set('arangodb', new arangodb(require static::ARANGODB)); + } + + // Exit (success) + return self::arangodb; + } catch (exception) { + // Exit (fail) + return null; + } + })(), + default => parent::__get(name) + }; + } + + /** + * Delete + * + * @param string name Name of the property + * + * @return void + */ + public function __unset(string name): void + { + // Deleting a property and exit (success) + parent::__unset(name); + } + + /** + * Check of initialization + * + * @param string name Name of the property + * + * @return bool The property is initialized? + */ + public function __isset(string name): bool + { + // Check of initialization of the property and exit (success) + return parent::__isset(name); + } + + /** + * Call a static property or method + * + * @param string name Name of the property or the method + * @param array arguments Arguments for the method + */ + public static function __callStatic(string name, array arguments): mixed + { + match (name) { + 'arangodb' => (new static)->__get('arangodb'), + default => throw new exception("Not found: name", 500) + }; + } +} + diff --git a/author/project/system/models/session.php b/author/project/system/models/session.php new file mode 100644 index 0000000..e522a73 --- /dev/null +++ b/author/project/system/models/session.php @@ -0,0 +1,276 @@ + + */ +final class session extends core +{ + /** + * Name of the collection in ArangoDB + */ + final public const COLLECTION = 'session'; + + /** + * An instance of the ArangoDB document from ArangoDB + */ + protected readonly _document document; + + /** + * Constructor of an instance + * + * Initialize of a session and write them to the this->document property + * + * @param ?string hash Hash of the session in ArangoDB + * @param ?int expires Date of expiring of the session (used for creating a new session) + * @param array &errors Registry of errors + * + * @return static instance of the ArangoDB document of session + */ + public function __construct(?string hash = null, ?int expires = null, array &errors = []) + { + try { + if (collection::init(static::arangodb->session, self::COLLECTION)) { + // Initialized the collection + + if (this->search(hash, errors)) { + // Found an instance of the ArangoDB document of session and received a session hash + } else { + // Not found an instance of the ArangoDB document of session + + // Initializing a new session and write they into ArangoDB + _id = document::write(this::arangodb->session, self::COLLECTION, [ + 'active' => true, + 'expires' => expires ?? time() + 604800, + 'ip' => _SERVER['REMOTE_ADDR'], + 'x-forwarded-for' => _SERVER['HTTP_X_FORWARDED_FOR'] ?? null, + 'referer' => _SERVER['HTTP_REFERER'] ?? null, + 'useragent' => _SERVER['HTTP_USER_AGENT'] ?? null + ]); + + if (session = collection::search(this::arangodb->session, sprintf( + << %d && d.active == true + RETURN d + AQL, + self::COLLECTION, + _id, + time() + ))) { + // Found an instance of just created new session + + // Generate a hash and write into an instance of the ArangoDB document of session property + session->hash = sodium_bin2hex(sodium_crypto_generichash(_id)); + + if (document::update(this::arangodb->session, session)) { + // Is writed update + + // Write instance of the ArangoDB document of session into property and exit (success) + this->document = session; + } else throw new exception('Could not write the session data'); + } else throw new exception('Could not create or find just created session'); + } + } else throw new exception('Could not initialize the collection'); + } catch (exception e) { + // Write to the registry of errors + errors[] = [ + 'text' => e->getMessage(), + 'file' => e->getFile(), + 'line' => e->getLine(), + 'stack' => e->getTrace() + ]; + } + } + + /** + * Search + * + * Search for the session in ArangoDB by hash and write they into this->document property if they are found + * + * @param ?string hash Hash of the session in ArangoDB + * @param array &errors Registry of errors + * + * @return static instance of the ArangoDB document of session + */ + public function search(?string hash, array &errors = []): bool + { + try { + if (isset(hash)) { + // Recieved a hash + + // Search the session data in ArangoDB + _document = session = collection::search(this::arangodb->session, sprintf( + << %d && d.active == true + RETURN d + AQL, + self::COLLECTION, + hash, + time() + )); + + if (_document instanceof _document) { + // An instance of the ArangoDB document of session is found + + // Write the session data to the property + this->document = _document; + + // Exit (success) + return true; + } + } + } catch (exception e) { + // Write to the registry of errors + errors[] = [ + 'text' => e->getMessage(), + 'file' => e->getFile(), + 'line' => e->getLine(), + 'stack' => e->getTrace() + ]; + } + + // Exit (fail) + return false; + } + + /** + * Write to buffer of the session + * + * @param array data Data for merging + * @param array &errors Registry of errors + * + * @return bool Is data has written into the session buffer? + */ + public function write(array data, array &errors = []): bool + { + try { + if (collection::init(this::arangodb->session, self::COLLECTION)) { + // Initialized the collection + + // An instance of the ArangoDB document of session is initialized? + if (!isset(this->document)) throw new exception('An instance of the ArangoDB document of session is not initialized'); + + // Write data into buffwer of an instance of the ArangoDB document of session + this->document->buffer = array_replace_recursive( + this->document->buffer ?? [], + [_SERVER['INTERFACE'] => array_replace_recursive(this->document->buffer[_SERVER['INTERFACE']] ?? [], data)] + ); + + // Write to ArangoDB and exit (success) + return document::update(this::arangodb->session, this->document) ? true : throw new exception('Не удалось записать данные в буфер сессии'); + } else throw new exception('Could not initialize the collection'); + } catch (exception e) { + // Write to the registry of errors + errors[] = [ + 'text' => e->getMessage(), + 'file' => e->getFile(), + 'line' => e->getLine(), + 'stack' => e->getTrace() + ]; + } + + return false; + } + + /** + * Write + * + * Write a property into an instance of the ArangoDB document + * + * @param string name Name of the property + * @param mixed value Content of the property + * + * @return void + */ + public function __set(string name, mixed value = null): void + { + // Write to the property into an instance of the ArangoDB document and exit (success) + this->document->{name} = value; + } + + /** + * Read + * + * Read a property from an instance of the ArangoDB docuemnt + * + * @param string name Name of the property + * + * @return mixed Content of the property + */ + public function __get(string name): mixed + { + // Read a property from an instance of the ArangoDB document and exit (success) + return match (name) { + 'arangodb' => this::arangodb, + default => this->document->{name} + }; + } + + /** + * Delete + * + * Deinitialize the property in an instance of the ArangoDB document + * + * @param string name Name of the property + * + * @return void + */ + public function __unset(string name): void + { + // Delete the property in an instance of the ArangoDB document and exit (success) + unset(this->document->{name}); + } + + /** + * Check of initialization + * + * Check of initialization of the property into an instance of the ArangoDB document + * + * @param string name Name of the property + * + * @return bool The property is initialized? + */ + public function __isset(string name): bool + { + // Check of initializatio nof the property and exit (success) + return isset(this->document->{name}); + } + + /** + * Execute a method + * + * Execute a method from an instance of the ArangoDB document + * + * @param string name Name of the method + * @param array arguments Arguments for the method + * + * @return mixed Result of execution of the method + */ + public function __call(string name, array arguments = []): mixed + { + // Execute the method and exit (success) + if (method_exists(this->document, name)) return this->document->{name}(arguments); + } +} diff --git a/author/project/system/models/traits/status.php b/author/project/system/models/traits/status.php new file mode 100644 index 0000000..faa7e79 --- /dev/null +++ b/author/project/system/models/traits/status.php @@ -0,0 +1,45 @@ + + */ +trait status +{ + /** + * Initialize of a status + * + * @param array &errors Registry of errors + * + * @return ?bool Status, if they are found + */ + public function status(array &errors = []): ?bool + { + try { + // Read from ArangoDB and exit (success) + return this->document->active ?? false; + } catch (exception e) { + // Write to the registry of errors + errors[] = [ + 'text' => e->getMessage(), + 'file' => e->getFile(), + 'line' => e->getLine(), + 'stack' => e->getTrace() + ]; + } + + // Exit (fail) + return null; + } +} + diff --git a/author/project/system/public/css/themes/default/main.css b/author/project/system/public/css/themes/default/main.css new file mode 100644 index 0000000..ff80335 --- /dev/null +++ b/author/project/system/public/css/themes/default/main.css @@ -0,0 +1,47 @@ +@charset "UTF-8"; + +* { + text-decoration: none; + outline: none; + border: none; + /* font-family: , system-ui, sans-serif; */ + font-family: "dejavu"; + transition: 0.1s ease-out; +} + +body { + margin: 0; + min-height: 100vh; + padding: 0; + display: flex; + flex-direction: column; + background-color: var(--background, #fafafa); +} + + +aside { +} + +header { +} + +main { + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + transition: 0s; +} + +footer { +} + +.unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + diff --git a/author/project/system/public/index.php b/author/project/system/public/index.php new file mode 100644 index 0000000..9b019bd --- /dev/null +++ b/author/project/system/public/index.php @@ -0,0 +1,32 @@ +write('/', 'index', 'index'); + +// Инициализация ядра +core = new core(namespace: __NAMESPACE__, router: router); + +// Обработка запроса +echo core->start(); + diff --git a/author/project/system/settings/.gitignore b/author/project/system/settings/.gitignore new file mode 100644 index 0000000..2027072 --- /dev/null +++ b/author/project/system/settings/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!*.sample diff --git a/author/project/system/settings/arangodb.php.sample b/author/project/system/settings/arangodb.php.sample new file mode 100644 index 0000000..8b517a4 --- /dev/null +++ b/author/project/system/settings/arangodb.php.sample @@ -0,0 +1,8 @@ + 'unix:///var/run/arangodb3/arango.sock', + 'database' => 'parser_from_rossko', + 'name' => 'parser_from_rossko', + 'password' => '' +]; diff --git a/author/project/system/views/templater.php b/author/project/system/views/templater.php new file mode 100644 index 0000000..9c785a8 --- /dev/null +++ b/author/project/system/views/templater.php @@ -0,0 +1,202 @@ + + */ +final class templater extends controller implements ArrayAccess +{ + /** + * Registry of global variables of view + */ + public array variables = []; + + /** + * Instance of twig templater + */ + readonly public twig twig; + + /** + * Constructor of an instance + * + * @param ?session session Instance of the session of ArangoDB + * + * @return void + */ + public function __construct(?session &session = null): void + { + // Initializing of an instance of twig + this->twig = new twig(new FilesystemLoader(VIEWS)); + + // Initializing of global variables + this->twig->addGlobal('theme', 'default'); + this->twig->addGlobal('server', _SERVER); + this->twig->addGlobal('cookies', _COOKIE); + if (!empty(session->status())) { + this->twig->addGlobal('session', session); + } + + // Initializing of twig extensions + this->twig->addExtension(new intl()); + } + + /** + * Render a HTML-document + * + * @param string file Related path to a HTML-document + * @param ?array variables Registry of variables to push into registry of global variables + * + * @return ?string HTML-документ + */ + public function render(string file, ?array variables = null): ?string + { + // Generation and exit (success) + return this->twig->render('themes' . DIRECTORY_SEPARATOR . this->twig->getGlobal('theme') . DIRECTORY_SEPARATOR . file, variables + this->variables); + } + + /** + * Write + * + * Write a variable into registry of global variables + * + * @param string name Name of the variable + * @param mixed value Value of the variable + * + * @return void + */ + public function __set(string name, mixed value = null): void + { + // Write the variable and exit (success) + this->variables[name] = value; + } + + /** + * Read + * + * Read a variable from registry of global variables + * + * @param string name Name of the variable + * + * @return mixed Content of the variable, if they are found + */ + public function __get(string name): mixed + { + // Read the variable and exit (success) + return this->variables[name]; + } + + /** + * Delete + * + * Delete a variable from the registry of global variables + * + * @param string name Name of the variable + * + * @return void + */ + public function __unset(string name): void + { + // Delete the variable and exit (success) + unset(this->variables[name]); + } + + /** + * Check of initialization + * + * Check of initialization in registry of global variables + * + * @param string name Name of the variable + * + * @return bool The variable is initialized? + */ + public function __isset(string name): bool + { + // Check of initialization of the variable and exit (success) + return isset(this->variables[name]); + } + + /** + * Write + * + * Write a variable into registry of global variables + * + * @param mixed name Name of an offset of the variable + * @param mixed value Value of the variable + * + * @return void + */ + public function offsetSet(mixed name, mixed value): void + { + // Write the variable and exit (success) + this->variables[name] = value; + } + + /** + * Read + * + * Read a variable from registry of global variables + * + * @param mixed name Name of the variable + * + * @return mixed Content of the variable, if they are found + */ + public function offsetGet(mixed name): mixed + { + // Read the variable and exit (success) + return this->variables[name]; + } + + /** + * Delete + * + * Delete a variable from the registry of global variables + * + * @param mixed name Name of the variable + * + * @return void + */ + public function offsetUnset(mixed name): void + { + // Delete the variable and exit (success) + unset(this->variables[name]); + } + + /** + * Check of initialization + * + * Check of initialization in registry of global variables + * + * @param mixed name Name of the variable + * + * @return bool The variable is initialized? + */ + public function offsetExists(mixed name): bool + { + // Check of initialization of the variable and exit (success) + return isset(this->variables[name]); + } +} + diff --git a/author/project/system/views/themes/default/core.html b/author/project/system/views/themes/default/core.html new file mode 100644 index 0000000..fd92488 --- /dev/null +++ b/author/project/system/views/themes/default/core.html @@ -0,0 +1,31 @@ + + + + + + {% use 'head.html' with title as head_title, meta as head_meta, css as head_css %} + + {% block title %} + {{ block('head_title') }} + {% endblock %} + + {% block meta %} + {{ block('head_meta') }} + {% endblock %} + + {{ block('head_css') }} + {% block css %} + {% endblock %} + + + + {% block body %} + {% endblock %} + + {% include 'js.html' %} + {% block js %} + {% endblock %} + + + + diff --git a/author/project/system/views/themes/default/footer.html b/author/project/system/views/themes/default/footer.html new file mode 100644 index 0000000..8322f33 --- /dev/null +++ b/author/project/system/views/themes/default/footer.html @@ -0,0 +1,10 @@ +{% block css %} +{% endblock %} + +{% block body %} +
+
+{% endblock %} + +{% block js %} +{% endblock %} diff --git a/author/project/system/views/themes/default/head.html b/author/project/system/views/themes/default/head.html new file mode 100644 index 0000000..1785b3d --- /dev/null +++ b/author/project/system/views/themes/default/head.html @@ -0,0 +1,15 @@ +{% block title %} +{% if head.title != empty %}{{head.title}}{% else %}parser_from_rossko by mirzaev{% endif %} +{% endblock %} + +{% block meta %} + + +{% for meta in head.metas %} + +{% endfor %} +{% endblock %} + +{% block css %} + +{% endblock %} diff --git a/author/project/system/views/themes/default/header.html b/author/project/system/views/themes/default/header.html new file mode 100644 index 0000000..430650a --- /dev/null +++ b/author/project/system/views/themes/default/header.html @@ -0,0 +1,10 @@ +{% block css %} +{% endblock %} + +{% block body %} +
+
+{% endblock %} + +{% block js %} +{% endblock %} diff --git a/author/project/system/views/themes/default/index.html b/author/project/system/views/themes/default/index.html new file mode 100644 index 0000000..85ad9c7 --- /dev/null +++ b/author/project/system/views/themes/default/index.html @@ -0,0 +1,27 @@ +{% extends "core.html" %} + +{% use "core.html" with css as core_css, body as core, js as core_js %} +{% use "header.html" with css as header_css, body as header, js as header_js %} +{% use "footer.html" with css as footer_css, body as footer, js as footer_js %} + +{% block css %} +{{ block('core_css') }} +{{ block('header_css') }} +{{ block('footer_css') }} +{% endblock %} + +{% block body %} +{{ block('header') }} +
+ {% block main %} + {{ main|raw }} + {% endblock %} +
+{{ block('footer') }} +{% endblock %} + +{% block js %} +{{ block('footer_js') }} +{{ block('header_js') }} +{{ block('core_js') }} +{% endblock %} diff --git a/author/project/system/views/themes/default/js.html b/author/project/system/views/themes/default/js.html new file mode 100644 index 0000000..47c8fd2 --- /dev/null +++ b/author/project/system/views/themes/default/js.html @@ -0,0 +1,2 @@ +{% block js %} +{% endblock %} diff --git a/composer.json b/composer.json new file mode 100755 index 0000000..92b2b5f --- /dev/null +++ b/composer.json @@ -0,0 +1,46 @@ +{ + "name": "mirzaev/parser_from_rossko", + "description": "", + "readme": "README.md", + "keywords": [], + "type": "site", + "homepage": "https://git.mirzaev.sexy/mirzaev/parser_from_rossko", + "license": "WTFPL", + "authors": [ + { + "name": "mirzaev", + "email": "mirzaev@gmail.com", + "homepage": "https://mirzaev.page", + "role": "Programmer" + } + ], + "support": { + "docs": "https://git.mirzaev.sexy/mirzaev/parser_from_rossko/manual", + "issues": "https://git.mirzaev.sexy/mirzaev/parser_from_rossko/issues" + }, + "require": { + "php": "~8.3", + "ext-sodium": "~8.3", + "mirzaev/minimal": "^2.2.0", + "mirzaev/accounts": "~1.2.x-dev", + "mirzaev/arangodb": "^1.0.0", + "triagens/arangodb": "~3.9.x-dev", + "twig/twig": "^3.4" + }, + "require-dev": { + "phpunit/phpunit": "~9.5" + }, + "autoload": { + "psr-4": { + "mirzaev\\parser_from_rossko\\": "mirzaev/parser_from_rossko/system" + } + }, + "autoload-dev": { + "psr-4": { + "mirzaev\\parser_from_rossko\\tests\\": "mirzaev/parser_from_rossko/tests" + } + }, + "scripts": { + "pre-update-cmd": "./install.sh" + } +} diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..904cdb9 --- /dev/null +++ b/install.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +if [ -d author/project ]; then + mv author/project author/parser_from_rossko +fi + +if [ -d author ]; then + mv author mirzaev +fi +