commit 680a9659e3c54e4c2e779a6e1c7f467675653d2e Author: garden <> Date: Wed Jan 7 13:05:12 2026 +0500 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1dda020 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +!.gitignore +composer.phar +vendor diff --git a/LICENSE b/LICENSE new file mode 100644 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 100644 index 0000000..3a2c9d8 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# campanula +Receive and send messages through Gammu server and Telegram messenger interface diff --git a/author/project/system/controllers/core.php b/author/project/system/controllers/core.php new file mode 100644 index 0000000..d963ac3 --- /dev/null +++ b/author/project/system/controllers/core.php @@ -0,0 +1,83 @@ + + */ +class core extends controller +{ + /** + * Language + * + * @var language $language Language + */ + protected language $language = language::en; + + /** + * Response + * + * @see https://wiki.php.net/rfc/property-hooks (find a table about backed and virtual hooks) + * + * @var response $response Response + */ + protected response $response { + // Read + get => $this->response ??= $this->request->response(); + } + + /** + * Errors + * + * @var array $errors Registry of errors + */ + protected array $errors = [ + 'system' => [] + ]; + + /** + * Constructor + * + * @param minimal $core Instance of the MINIMAL + * @param bool $initialize Initialize a controller? + * + * @return void + */ + public function __construct(minimal $core) + { + // Blocking requests from CloudFlare (better to write this blocking into nginx config file) + if (isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] === 'nginx-ssl early hints') return status::bruh->label; + + // Initializing the view template engine instance + $this->view = new templater(); + + // For the extends system + parent::__construct(core: $core); + } +} diff --git a/author/project/system/controllers/index.php b/author/project/system/controllers/index.php new file mode 100644 index 0000000..1924a62 --- /dev/null +++ b/author/project/system/controllers/index.php @@ -0,0 +1,70 @@ + + */ +final class index extends core +{ + /** + * Errors + * + * @var array $errors Registry of errors + */ + protected array $errors = [ + 'system' => [] + ]; + + /** + * Main page + * + * @return null + */ + public function index(): null + { + if (str_contains($this->request->headers['accept'] ?? '', content::html->value)) { + // Request for HTML response + + // Render page + $page = $this->view->render('index.html'); + + // Sending response + $this->response + ->start() + ->clean() + ->sse() + ->write($page) + ->validate($this->request) + ?->body() + ->end(); + + // Deinitializing rendered page + unset($page); + + // Exit (success) + return null; + } + + // Exit (fail) + return null; + } +} diff --git a/author/project/system/databases/.gitignore b/author/project/system/databases/.gitignore new file mode 100644 index 0000000..94d59c2 --- /dev/null +++ b/author/project/system/databases/.gitignore @@ -0,0 +1,3 @@ +!.gitignore +!*.php +*.baza diff --git a/author/project/system/databases/scripts/account.php b/author/project/system/databases/scripts/account.php new file mode 100644 index 0000000..2bb0f31 --- /dev/null +++ b/author/project/system/databases/scripts/account.php @@ -0,0 +1,71 @@ +database->read( + filter: fn(record $record) => $record->domain === 'buddy_volkodav', + amount: 1, + offset: 0 +)[0] ?? null; + +var_dump($account); + +// Initializing the account authorizations model +$authorizations_model = new authorizations(); + +// Searching for the account authorizations +$authorizations = $authorizations_model->database->read( + filter: fn(record $record) => $record->account === $account->identifier, + amount: 1, + offset: 0 +)[0] ?? null; + +var_dump($authorizations); + diff --git a/author/project/system/localizations/english.php b/author/project/system/localizations/english.php new file mode 100644 index 0000000..cc96c97 --- /dev/null +++ b/author/project/system/localizations/english.php @@ -0,0 +1,42 @@ + 'Empty', + 'yes' => 'Yes', + 'no' => 'No', + + // Main menu + 'menu_title' => 'Main menu', + + // Account + 'account_title' => 'Account', + 'account_authorized_system' => 'Access to the system', + 'account_authorized_settings' => 'Access to settings', + 'account_authorized_system_settings' => 'System access to the system settings', + + // Language setting + 'settings_select_language_title' => 'Select language', + 'settings_select_language_description' => 'The selected language will be writed in your account settings', + 'settings_language_update_success' => 'Language replaced:', + 'settings_language_update_fail' => 'Failed to replace language', + + // Language selection + 'select_language_title' => 'Select language', + 'select_language_description' => 'The selected language will be used in the current process', + 'select_language_button_add' => 'Add a language', + + // Authorization + 'not_authorized_system' => 'You do not have access to the system', + 'not_authorized_settings' => 'You do not have access to the settings', + 'not_authorized_system_settings' => 'You do not have access to the system settings', + + // Messages + 'message_initialization_fail' => 'Не удалось инициализировать сообщение Телеграм', + 'message_text_initialization_fail' => 'Не удалось инициализировать текст сообщения Телеграм', + + // Other + 'why_so_shroomious' => 'why so shroomious' +]; + diff --git a/author/project/system/localizations/russian.php b/author/project/system/localizations/russian.php new file mode 100644 index 0000000..ca1553f --- /dev/null +++ b/author/project/system/localizations/russian.php @@ -0,0 +1,41 @@ + 'Пусто', + 'yes' => 'Да', + 'no' => 'Нет', + + // Главное меню + 'menu_title' => 'Главное меню', + + // Аккаунт + 'account_title' => 'Аккаунт', + 'account_authorized_system' => 'Доступ к системе', + 'account_authorized_settings' => 'Доступ к изменению настроек', + 'account_authorized_system_settings' => 'Системный доступ к системным настройкам', + + // Настройки языка + 'settings_select_language_title' => 'Выбери язык', + 'settings_select_language_description' => 'Выбранный язык будет записан в настройки аккаунта', + 'settings_language_update_success' => 'Язык заменён:', + 'settings_language_update_fail' => 'Не удалось заменить язык', + + // Выбор языка + 'select_language_title' => 'Выбери язык', + 'select_language_description' => 'Выбранный язык будет использован в текущем процессе', + 'select_language_button_add' => 'Добавить язык', + + // Авторизация + 'not_authorized_system' => 'У тебя нет доступа к системе', + 'not_authorized_settings' => 'У тебя нет доступа к настройкам', + 'not_authorized_system_settings' => 'У тебя нет доступа к системным настройкам', + + // Сообщения + 'message_initialization_fail' => 'Не удалось инициализировать сообщение Телеграм', + 'message_text_initialization_fail' => 'Не удалось инициализировать текст сообщения Телеграм', + + // Прочее + 'why_so_shroomious' => 'почему такой грибъёзный' +]; diff --git a/author/project/system/models/account.php b/author/project/system/models/account.php new file mode 100644 index 0000000..3a6b0c0 --- /dev/null +++ b/author/project/system/models/account.php @@ -0,0 +1,377 @@ + + */ +final class account extends core implements record_interface +{ + use record_trait; + + /** + * File + * + * @var string $database Path to the database file + */ + protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'accounts.baza'; + + /** + * Database + * + * @var database $database The database + */ + public protected(set) database $database; + + /** + * Constructor + * + * @method record|null $record The record + * + * @return void + */ + public function __construct(?record $record = null) + { + // Initializing the database + $this->database = new database() + ->encoding(encoding::utf8) + ->columns( + new column('identifier', type::long_long_unsigned), + new column('identifier_telegram', type::long_long_unsigned), + new column('domain', type::string, ['length' => 32]), + new column('name_first', type::string, ['length' => 64]), + new column('name_second', type::string, ['length' => 64]), + new column('language', type::string, ['length' => 2]), + new column('robot', type::char), + /* new column('', type::), */ + new column('updated', type::integer_unsigned), + new column('created', type::integer_unsigned) + ) + ->connect($this->file); + + // Initializing the record + $record instanceof record and $this->record = $record; + } + + /** + * Initialize + * + * @param telegram_user $telegram The telegram account + * + * @throws exception_runtime if update the account record in the database by the telegram account values + * @throws exception_runtime if failed to find the registered account + * @throws exception_runtime if failed to registrate the account + * + * @return static|null The account, if found, updated or created + */ + public function initialize(telegram_user $telegram): ?static + { + // Searching for the account in the database + $account = $this->database->read(filter: fn(record $record) => $record->identifier_telegram === $telegram->getId(), amount: 1)[0] ?? null; + + if ($account instanceof record) { + // Found the account record + + if ( + $account->domain !== (string) $telegram->getUsername() || + $account->name_first !== (string) $telegram->getFirstName() || + $account->name_second !== (string) $telegram->getLastName() || + $account->language !== (string) $telegram->getLanguageCode() + ) { + // The telegram account was updated + + // Updating the account in the database + $updated = $this->database->read( + filter: fn(record $record) => $record->identifier_telegram === $telegram->getId(), + update: function (record &$record) use ($telegram) { + // Writing new values into the record + $record->domain = (string) $telegram->getUsername(); + $record->name_first = (string) $telegram->getFirstName(); + $record->name_second = (string) $telegram->getLastName(); + $record->language = (string) $telegram->getLanguageCode(); + $record->updated = svoboda::timestamp(); + }, + amount: 1 + )[0] ?? null; + + if ($updated instanceof record && $updated->values() !== $account->values()) { + // Updated the account in the database + + // Writing the updated record into the account object + $this->record = $updated; + + // Deserializing parameters + $this->deserialize(); + + // Exit (success) + return $this; + } else { + // Not updated the account in the database + + // Exit (fail) + throw new exception_runtime('Failed to update the account record in the database by the telegram account values'); + } + } + + // Writing the found record into the account object + $this->record = $account; + + // Deserializing parameters + $this->deserialize(); + + // Exit (success) + return $this; + } else { + // Not found the account record + + if ($this->registrate($telegram)) { + // Registered the account + + // Searching for the registered account in the database + $registered = $this->database->read(filter: fn(record $record) => $record->identifier_telegram === $telegram->getId(), amount: 1)[0] ?? null; + + if ($registered instanceof record) { + // Found the registered account + + // Writing the registered record into the account object + $this->record = $registered; + + // Deserializing parameters + $this->deserialize(); + + // Exit (success) + return $this; + } else { + // Not found the registered account + + // Exit (fail) + throw new exception_runtime('Failed to find the registered account'); + } + } else { + // Not registered the account + + // Exit (fail) + throw new exception_runtime('Failed to registrate the account'); + } + } + } + + /** + * Registrate + * + * Create the account by the telegram account data + * + * @param telegram_user $telegram The telegram account + * + * @return record|false The record, if created + */ + public function registrate(telegram_user $telegram): record|false + { + // Creating the record + $record = $this->write( + telegram_identifier: (int) $telegram->getId(), + name_first: (string) $telegram->getFirstName(), + name_last: (string) $telegram->getLastName(), + domain: (string) $telegram->getUsername(), + language: (string) $telegram->getLanguageCode(), + robot: (bool) $telegram->isBot() + ); + + if ($record instanceof record) { + // The record was writed into the database + + // Initializing the authorizations model + $authorizations = new authorizations(); + + // Creating the authorizations record + $authorizations->write(account: $record->identifier); + + // Initializing the settings model + $settings = new settings(); + + // Creating the account settings + $settings->write(account: $record->identifier); + + // Initializing the chat model + $chat = new chat(); + + // Creating the account chat + $record->chat = $chat->write(account: $record->identifier, network: NETWORK_DEFAULT); + + // Initializing the tariff model + $tariff = new tariff(); + + // Creating the tariff record + $record->tariff = $tariff->write(account: $record->identifier, invoice: 0, active: 1, type: TARIFF_DEFAULT ?? tariff_type::free); + + // Writing the record into the database + $record = $this->database->read( + filter: fn(record $_record) => $_record->identifier === $record->identifier, + update: fn(record &$_record) => $_record = $record, + amount: 1 + )[0] ?? null; + + // Exit (success) + return $record; + } + + // Exit (fail) + return false; + } + + /** + * Write + * + * @param int $telegram_identifier The telegram account identifier + * @param string $name_first + * @param string $name_last + * @param string $domain + * @param language|string $language + * @param bool $robot Is a robot? + * + * @return record|false The record, if created + */ + public function write( + int $telegram_identifier, + string $domain = '', + string $name_first = '', + string $name_last = '', + language|string $language = LANGUAGE_DEFAULT ?? language::en, + bool $robot = false, + ): record|false { + // Initializing the record + $record = $this->database->record( + $this->database->count() + 1, + (int) $telegram_identifier, + $domain, + $name_first, + $name_last, + $language instanceof language ? $language->name : (string) $language, + (int) $robot, + /* */ + svoboda::timestamp(), + svoboda::timestamp() + ); + + // Writing the record into the database + $created = $this->database->write($record); + + // Exit (success) + return $created ? $record : false; + } + + /** + * Serialize + * + * @return self The instance from which the method was called (fluent interface) + */ + public function serialize(): self + { + // Serializing the record parameters + $this->record->language = $this->record->language->name; + + // Exit (success) + return $this; + } + + /** + * Deserialize + * + * @return self The instance from which the method was called (fluent interface) + */ + public function deserialize(): self + { + // Deserializing the record parameters + $this->record->language = language::{$this->record->language} ?? LANGUAGE_DEFAULT ?? language::en; + + // Exit (success) + return $this; + } + + /** + * Authorizations + * + * Search for the account authorizations + * + * @return authorizations|null The account authorizations + */ + public function authorizations(): ?authorizations + { + // Search for the account authorizations + $authorizations = new authorizations()->read(filter: fn(record $record) => $record->active === 1 && $record->account === $this->identifier); + + if ($authorizations instanceof authorizations) { + // Found the account authorizations + + // Exit (success) + return $authorizations; + } + + // Exit (fail) + return null; + } + + /** + * Settings + * + * Search for the account settings + * + * @return settings|null The account settings + */ + public function settings(): ?settings + { + // Search for the account settings + $settings = new settings()->read(filter: fn(record $record) => $record->active === 1 && $record->account === $this->identifier); + + if ($settings instanceof settings) { + // Found the account settings + + // Exit (success) + return $settings; + } + + // Exit (fail) + return null; + } +} + diff --git a/author/project/system/models/authorizations.php b/author/project/system/models/authorizations.php new file mode 100644 index 0000000..4a3c032 --- /dev/null +++ b/author/project/system/models/authorizations.php @@ -0,0 +1,120 @@ + + */ +final class authorizations extends core implements record_interface +{ + use record_trait; + + /** + * File + * + * @var string $database Path to the database file + */ + protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'authorizations.baza'; + + /** + * Database + * + * @var database $database The database + */ + public protected(set) database $database; + + /** + * Constructor + * + * @method record|null $record The record + * + * @return void + */ + public function __construct(?record $record = null) + { + // Initializing the database + $this->database = new database() + ->encoding(encoding::utf8) + ->columns( + new column('identifier', type::long_long_unsigned), + new column('account', type::long_long_unsigned), + new column('system', type::char), + new column('settings', type::char), + new column('chat', type::char), + /* new column('', type::char), */ + new column('system_settings', type::char), + new column('updated', type::integer_unsigned), + new column('created', type::integer_unsigned) + ) + ->connect($this->file); + + // Initializing the record + $record instanceof record and $this->record = $record; + } + + /** + * Write + * + * @param int $account The account identifier + * @param int $system + * @param int $settings + * @param int $system_settings + * + * @return int|false The record identifier, if created + */ + public function write( + int $account, + int $system = 1, + int $settings = 1, + int $system_settings = 0, + ): int|false + { + $record = $this->database->record( + $this->database->count() + 1, + $account, + $system, + $settings, + $system_settings, + svoboda::timestamp(), + svoboda::timestamp() + ); + + // Writing the record into the database + $created = $this->database->write($record); + + // Exit (success) + return $created ? $record->identifier : false; + } +} + diff --git a/author/project/system/models/core.php b/author/project/system/models/core.php new file mode 100644 index 0000000..01fb947 --- /dev/null +++ b/author/project/system/models/core.php @@ -0,0 +1,44 @@ + + */ +class core extends model +{ + /** + * File + * + * @var string database Path to the database file + */ + protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'example.baza'; + + /** + * Constructor + * + * Initialize the database + * + * @return void + */ + public function __construct() + { + } +} + diff --git a/author/project/system/models/settings.php b/author/project/system/models/settings.php new file mode 100644 index 0000000..ab9d32f --- /dev/null +++ b/author/project/system/models/settings.php @@ -0,0 +1,106 @@ + + */ +final class settings extends core implements record_interface +{ + use record_trait; + + /** + * File + * + * @var string $database Path to the database file + */ + protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'settings.baza'; + + /** + * Database + * + * @var database $database The database + */ + public protected(set) database $database; + + /** + * Constructor + * + * @method record|null $record The record + * + * @return void + */ + public function __construct(?record $record = null) + { + // Initializing the database + $this->database = new database() + ->encoding(encoding::utf8) + ->columns( + new column('identifier', type::long_long_unsigned), + new column('account', type::long_long_unsigned), + /* new column('', type::), */ + new column('updated', type::integer_unsigned), + new column('created', type::integer_unsigned) + ) + ->connect($this->file); + + // Initializing the record + $record instanceof record and $this->record = $record; + } + + /** + * Write + * + * @param int $account The account identifier (0 for disable) + * + * @return int|false The record identifier, if created + */ + public function write( + int $account = 0, + ): int|false { + $record = $this->database->record( + $this->database->count() + 1, + $account, + svoboda::timestamp(), + svoboda::timestamp() + ); + + // Writing the record into the database + $created = $this->database->write($record); + + // Exit (success) + return $created ? $record->identifier : false; + } +} + diff --git a/author/project/system/models/telegram/commands.php b/author/project/system/models/telegram/commands.php new file mode 100644 index 0000000..bbae4f9 --- /dev/null +++ b/author/project/system/models/telegram/commands.php @@ -0,0 +1,393 @@ + + */ +final class commands extends core +{ + /** + * Start + * + * Responce for command: "/start" + * + * @param context $context Request data from Telegram + * + * @return void + */ + public static function start(context $context): void + { + static::menu($context); + } + + /** + * Menu + * + * Responce for command: '/menu' + * + * @param context $context Request data from Telegram + * + * @return void + */ + public static function menu(context $context): void + { + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof account) { + // Initialized the account + + // Initializing the language + $language = $context->get('language'); + + if ($language instanceof language) { + // Initialized the language + + // Initializing localization + $localization = $context->get('localization'); + + if ($localization) { + // Initialized localization + + // Initializing the title + $title = '📋 *' . $localization['menu_title'] . '*'; + + // Initializing accounts + /* $accounts_message = '*' . $localization['menu_accounts'] . ':* ' . ((new account)->database->count() ?? 0); */ + + // Initializing the account tariff + $tariff = $account->tariff(); + + // Declaring the tariff button + $tariff_button = []; + + if ($tariff instanceof tariff) { + // Initialized the account tariff + + // Initializing the tariff button + $tariff_button = [ + 'text' => '🔐 ' . $tariff->type->label($language) . ' (' . $tariff->used . '/' . $tariff->tokens . ')', + 'callback_data' => 'tariffs' + ]; + } else { + + // Initialized the account tariff + + // Initializing the tariff button + $tariff_button = [ + 'text' => '⚠️ ' . $localization['menu_tariff_empty'], + 'callback_data' => 'tariffs' + ]; + } + + // Initializing the account chat + $chat = $account->chat(); + + // Initializing the chto text + $howto = $localization['menu_howto']; + + // Sending the message + $context->sendMessage( + << [ + 'inline_keyboard' => [ + /* [ + [ + 'text' => '⚙️ ' . $localization[''], + 'callback_data' => '' + ] + ] */ + ], + 'disable_notification' => true, + 'remove_keyboard' => true + ], + ] + )->then(function (message $message) use ($context) { + // Sended the message + + }); + } else { + // Not initialized localization + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize localization*') + ->then(function (message $message) use ($context) { + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized language + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize language*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Ending the conversation process + $context->endConversation(); + }); + } + } + + /** + * Account + * + * Responce for the command: "/account" + * + * Sends information about account with menu + * + * @param context $context Request data from Telegram + * + * @return void + */ + public static function account(context $context): void + { + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof account) { + // Initialized the account + + // Initializing localization + $localization = $context->get('localization'); + + if ($localization) { + // Initialized localization + + // Initializing title for the message + $title = '🫵 ' . $localization['account_title']; + + // Declaring buufer of rows about authorizations + $authorizations = ''; + + // Initializing rows about authorization + foreach ($account->values() as $key => $value) { + // Iterating over account parameters + + if (str_starts_with($key, 'authorized_')) { + // Iterating over account authorizations + + // Skipping system authorizations + if (str_starts_with($key, 'authorized_system_')) continue; + + // Writing into buffer of rows about authorizations + $authorizations .= ($value ? '✅' : '❎') . ' *' . ($localization["account_$key"] ?? $key) . ':* ' . ($value ? $localization['yes'] : $localization['no']) . "\n"; + } + } + + // Trimming the last line break character + $authorizations = trim($authorizations, "\n"); + + // Sending the message + $context->sendMessage( + << [ + 'remove_keyboard' => true, + 'disable_notification' => true + ], + 'link_preview_options' => [ + 'is_disabled' => true + ] + ] + ); + } else { + // Not initialized localization + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize localization*') + ->then(function (message $message) use ($context) { + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Ending the conversation process + $context->endConversation(); + }); + } + } + + /** + * Language + * + * Responce for the command: "/language" + * + * Send the language selection menu + * + * @param context $context Request data from Telegram + * + * @return void + */ + public static function language(context $context): void + { + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof account) { + // Initialized the account + + // Initializing language + $language = $context->get('language'); + + if ($language instanceof language) { + // Initialized language + + // Initializing localization + $localization = $context->get('localization'); + + if ($localization) { + // Initialized localization + + // Sending the language selection + process_language_select::menu( + context: $context, + prefix: 'settings_language_', + title: '🌏 *' . $localization['settings_select_language_title'] . '*', + description: '🌏 *' . $localization['settings_select_language_description'] . '*' + ); + } else { + // Not initialized localization + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize localization*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized language + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize language*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } + + /** + * Society + * + * Responce for the command: "/society" + * + * Sends the "mushroom" image and the localized text "why so shroomious" + * + * @param context $context Request data from Telegram + * + * @return void + */ + public static function society(context $context): void + { + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof account) { + // Initialized the account + + // Initializing localization + $localization = $context->get('localization'); + + if ($localization) { + // Initialized localization + + // Sending the message + $context->sendPhoto( + new file_input(STORAGE . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'mushroom.jpg'), + [ + 'caption' => $localization['why_so_shroomious'], + 'disable_notification' => true + ] + ); + } else { + // Not initialized localization + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize localization*') + ->then(function (message $message) use ($context) { + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Ending the conversation process + $context->endConversation(); + }); + } + } +} + diff --git a/author/project/system/models/telegram/middlewares.php b/author/project/system/models/telegram/middlewares.php new file mode 100644 index 0000000..ef90146 --- /dev/null +++ b/author/project/system/models/telegram/middlewares.php @@ -0,0 +1,469 @@ + + */ +final class middlewares extends core +{ + /** + * Account (middleware) + * + * Initialize or registrate the account and write it into the `account` variable inside the `$context` + * + * @param context $context + * @param node $next + * + * @return void + */ + public static function account(context $context, node $next): void + { + // Is the process stopped? + if ($context->get('stop')) return; + + // Initializing the telegram account + $telegram = $context->getEffectiveUser(); + + // Initializing the account + $account = new account()->initialize($telegram); + + if ($account instanceof account) { + // Initialized the account + + // Writing the account into the context variable + $context->set('account', $account); + + // Continuation of the process + $next($context); + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } + + /** + * Authorizations (middleware) + * + * Initialize the account authorizations and write them into the `authorizations` variable inside the `$context` + * + * @param context $context + * @param node $next + * + * @return void + */ + public static function authorizations(context $context, node $next): void + { + // Is the process stopped? + if ($context->get('stop')) return; + + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof account) { + // Initialized the account + + // Initializing the account authorizations + $authorizations = $account->authorizations(); + + if ($authorizations instanceof authorizations) { + // Initialized the account authorizations + + // Writing the account authorizations into the context variable + $context->set('authorizations', $authorizations); + + // Continuation of the process + $next($context); + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account authorizations*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } + + /** + * Language (middleware) + * + * Implement the account language + * + * @param context $context + * @param node $next + * + * @return void + */ + public static function language(context $context, node $next): void + { + // Is the process stopped? + if ($context->get('stop')) return; + + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof account) { + // Initialized the account + + if ($account->language instanceof language) { + // Initialized the language parameter + + try { + // Writing the account language into the context variable + $context->set('language', $account->language); + } catch (error $error) { + // Not initialized the language + + // Writing the default language into the context variable + $context->set('language', LANGUAGE_DEFAULT ?? language::en); + } + } else { + // Not initialized the language parameter + + // Writing the default language into the context variable + $context->set('language', LANGUAGE_DEFAULT ?? language::en); + } + + // Continuation of the process + $next($context); + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } + + /** + * Localization (middleware) + * + * Implement the account language and initialize the localization file + * + * @param context $context + * @param node $next + * + * @return void + */ + public static function localization(context $context, node $next): void + { + // Is the process stopped? + if ($context->get('stop')) return; + + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof account) { + // Initialized the account + + // Initializing the language + $language = $context->get('language'); + + if ($language instanceof language) { + // Initialized the language + + // Initializing path to the localization file + $file = LOCALIZATIONS . DIRECTORY_SEPARATOR . strtolower($language->label()) . '.php'; + + if (file_exists($file) && is_readable($file)) { + // Found the localization file + + // Initializing localization + $localization = require($file); + + if (is_array($localization)) { + // Initialized the localization + + // Writing localization into the context variable + $context->set('localization', $localization); + + // Continuation of the process + $next($context); + } else { + // Not initialized the localization + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize localization*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not found the localization file + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize the localization file*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized language + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize language*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } + + /** + * Settings (middleware) + * + * Check the account for access to the settings + * + * @param context $context + * @param node $next + * + * @return void + */ + public static function settings(context $context, node $next): void + { + // Is the process stopped? + if ($context->get('stop')) return; + + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof account) { + // Initialized the account + + // Initializing the account authorizations + $authorizations = $context->get('authorizations'); + + if ($authorizations instanceof authorizations) { + // Initialized the account authorizations + + if ($authorizations->settings) { + // Authorized the account to the settings + + // Continuation of the process + $next($context); + } else { + // Not authorized the account to the settings + + // Initializing localization + $localization = $context->get('localization'); + + if ($localization) { + // Initialized localization + + // Sending the message + $context->sendMessage('⛔ *' . $localization['not_authorized_settings'] . '*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + + // Stopping the process + $context->set('stop', true); + } else { + // Not initialized localization + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize localization*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } + } else { + // Not initialized the account authorizations + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account authorizations*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } + + /** + * System settings (middleware) + * + * Check the account for access to the system settings + * + * @param context $context + * @param node $next + * + * @return void + */ + public static function system_settings(context $context, node $next): void + { + // Is the process stopped? + if ($context->get('stop')) return; + + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof account) { + // Initialized the account + + // Initializing the account authorizations + $authorizations = $context->get('authorizations'); + + if ($authorizations instanceof authorizations) { + // Initialized the account authorizations + + if ($authorizations->system_settings) { + // Authorized the account to the system settings + + // Continuation of the process + $next($context); + } else { + // Not authorized the account to the system settings + + // Initializing localization + $localization = $context->get('localization'); + + if ($localization) { + // Initialized localization + + // Sending the message + $context->sendMessage('⛔ *' . $localization['not_authorized_system_settings'] . '*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + + // Stopping the process + $context->set('stop', true); + } else { + // Not initialized localization + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize localization*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account authorizations*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } +} + diff --git a/author/project/system/models/telegram/processes/language/select.php b/author/project/system/models/telegram/processes/language/select.php new file mode 100644 index 0000000..be577ca --- /dev/null +++ b/author/project/system/models/telegram/processes/language/select.php @@ -0,0 +1,152 @@ + + */ +final class select extends core +{ + /** + * Language + * + * Send the language choose menu + * + * @param context $context Request data from Telegram + * @param string $prefix Prefix for 'callback_data' (`$prefix . $language->name`) + * @param string $title Title of the message + * @param string $description Description of the message + * @param array $exclude Languages that will be excluded ['ru', 'en'...] + * + * @return void + */ + public static function menu(context $context, string $prefix, string $title, string $description, array $exclude = []): void + { + // Initializing the account + $account = $context->get('account'); + + if ($account instanceof record) { + // Initialized the account + + // Initializing language + $language = $context->get('language'); + + if ($language) { + // Initialized language + + // Initializing localization + $localization = $context->get('localization'); + + if ($localization) { + // Initialized localization + + // Declaring the buffer of generated keyboard with languages + $keyboard = []; + + // Initializing the iterator of rows + $row = 0; + + // Initializing buffer of languages + $languages = language::cases(); + + // Deleting the actual language from buffer of languages + unset($languages[array_search($language, $languages, strict: true)]); + + // Sorting buffer of languages by the actual language + $languages = [$language, ...$languages]; + + foreach ($languages as $language) { + // Iterating over languages + + // Skipping excluded languages + if (array_search($language->name, $exclude, strict: true) !== false) continue; + + // Initializing the row + $keyboard[$row] ??= []; + + // Writing the language choose button into the buffer of generated keyboard with languages + $keyboard[$row][] = [ + 'text' => ($language->flag() ? $language->flag() . ' ' : '') . $language->label($language), + 'callback_data' => $prefix . $language->name + ]; + + // When reaching 4 buttons in a row, move to the next row + if (count($keyboard[$row]) === 4) ++$row; + } + + // Writing the button for helping lozalizing + $keyboard[$row === 0 && empty($keyboard[0]) ? 0 : ++$row] = [ + [ + 'text' => '🗂 ' . $localization['select_language_button_add'], + 'url' => 'https://git.svoboda.works/garden\campanula/src/branch/stable/kodorvan/neurobot/system/localizations' + ] + ]; + + // Sending the message + $context->sendMessage( + $title ?? '🌏 *' . $localization['select_language_title'] . "*\n" . ($description ?? $localization['select_language_description']), + [ + 'reply_markup' => [ + 'inline_keyboard' => $keyboard, + 'disable_notification' => true + ], + ] + ); + } else { + // Not initialized localization + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize localization*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized language + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize language*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } else { + // Not initialized the account + + // Sending the message + $context->sendMessage('⚠️ *Failed to initialize your Telegram account*') + ->then(function (message $message) use ($context) { + // Sended the message + + // Ending the conversation process + $context->endConversation(); + }); + } + } +} diff --git a/author/project/system/public/css/fonts/dejavu.css b/author/project/system/public/css/fonts/dejavu.css new file mode 100644 index 0000000..5012ff4 --- /dev/null +++ b/author/project/system/public/css/fonts/dejavu.css @@ -0,0 +1,34 @@ +@font-face { + font-family: 'DejaVu'; + src: url("/fonts/dejavu/DejaVuLGCSans-ExtraLight.ttf"); + font-weight: 200; + font-style: normal; +} + +@font-face { + font-family: 'DejaVu'; + src: url("/fonts/dejavu/DejaVuLGCSans.ttf"); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'DejaVu'; + src: url("/fonts/dejavu/DejaVuLGCSans-Oblique.ttf"); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'DejaVu'; + src: url("/fonts/dejavu/DejaVuLGCSans-Bold.ttf"); + font-weight: 500; + font-style: normal; +} + +@font-face { + font-family: 'DejaVu'; + src: url("/fonts/dejavu/DejaVuLGCSans-BoldOblique.ttf"); + font-weight: 500; + font-style: italic; +} diff --git a/author/project/system/public/css/fonts/fira.css b/author/project/system/public/css/fonts/fira.css new file mode 100644 index 0000000..074cfc0 --- /dev/null +++ b/author/project/system/public/css/fonts/fira.css @@ -0,0 +1,139 @@ +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-Hair.woff2') format('woff2'), url('/fonts/fira/FiraSans-Hair.woff') format('woff'); + font-weight: 100; + font-style: normal; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-HairItalic.woff2') format('woff2'), url('/fonts/fira/FiraSans-HairItalic.woff') format('woff'); + font-weight: 100; + font-style: italic; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-UltraLight.woff2') format('woff2'), url('/fonts/fira/FiraSans-UltraLight.woff') format('woff'); + font-weight: 200; + font-style: normal; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-UltraLightItalic.woff2') format('woff2'), url('/fonts/fira/FiraSans-UltraLightItalic.woff') format('woff'); + font-weight: 200; + font-style: italic; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-Light.woff2') format('woff2'), url('/fonts/fira/FiraSans-Light.woff') format('woff'); + font-weight: 300; + font-style: normal; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-LightItalic.woff2') format('woff2'), url('/fonts/fira/FiraSans-LightItalic.woff') format('woff'); + font-weight: 300; + font-style: italic; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-Regular.woff2') format('woff2'), url('/fonts/fira/FiraSans-Regular.woff') format('woff'); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-Italic.woff2') format('woff2'), url('/fonts/fira/FiraSans-Italic.woff') format('woff'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraMono-Medium.woff2') format('woff2'), url('/fonts/fira/FiraMono-Medium.woff') format('woff'); + font-weight: 500; + font-style: normal; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-MediumItalic.woff2') format('woff2'), url('/fonts/fira/FiraSans-MediumItalic.woff') format('woff'); + font-weight: 500; + font-style: italic; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-SemiBold.woff2') format('woff2'), url('/fonts/fira/FiraSans-SemiBold.woff') format('woff'); + font-weight: 600; + font-style: normal; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-SemiBoldItalic.woff2') format('woff2'), url('/fonts/fira/FiraSans-SemiBoldItalic.woff') format('woff'); + font-weight: 600; + font-style: italic; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-Bold.woff2') format('woff2'), url('/fonts/fira/FiraSans-Bold.woff') format('woff'); + font-weight: 700; + font-style: normal; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-BoldItalic.woff2') format('woff2'), url('/fonts/fira/FiraSans-BoldItalic.woff') format('woff'); + font-weight: 700; + font-style: italic; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-ExtraBold.woff2') format('woff2'), url('/fonts/fira/FiraSans-ExtraBold.woff') format('woff'); + font-weight: 800; + font-style: normal; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-ExtraBoldItalic.woff2') format('woff2'), url('/fonts/fira/FiraSans-ExtraBoldItalic.woff') format('woff'); + font-weight: 800; + font-style: italic; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-Heavy.woff2') format('woff2'), url('/fonts/fira/FiraSans-Heavy.woff') format('woff'); + font-weight: 900; + font-style: normal; +} + +@font-face { + font-family: 'Fira'; + src: url('/fonts/fira/FiraSans-HeavyItalic.woff2') format('woff2'), url('/fonts/fira/FiraSans-HeavyItalic.woff') format('woff'); + font-weight: 900; + font-style: italic; +} + +@font-face { + font-family: 'Fira' Mono; + src: url('/fonts/fira/FiraMono-Regular.woff2') format('woff2'), url('/fonts/fira/FiraMono-Regular.woff') format('woff'); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'Fira' Mono; + src: url('/fonts/fira/FiraMono-Bold.woff2') format('woff2'), url('/fonts/fira/FiraMono-Bold.woff') format('woff'); + font-weight: 600; + font-style: normal; +} diff --git a/author/project/system/public/css/fonts/hack.css b/author/project/system/public/css/fonts/hack.css new file mode 100644 index 0000000..ea1ca63 --- /dev/null +++ b/author/project/system/public/css/fonts/hack.css @@ -0,0 +1,31 @@ +@font-face { + font-family: 'Hack'; + src: url('/fonts/hack/hack-regular.woff2?sha=3114f1256') format('woff2'), url('/fonts/hack/hack-regular.woff?sha=3114f1256') format('woff'); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Hack'; + src: url('/fonts/hack/hack-bold.woff2?sha=3114f1256') format('woff2'), url('/fonts/hack/hack-bold.woff?sha=3114f1256') format('woff'); + font-weight: 700; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Hack'; + src: url('/fonts/hack/hack-italic.woff2?sha=3114f1256') format('woff2'), url('/fonts/hack/hack-italic.woff?sha=3114f1256') format('woff'); + font-weight: 400; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: 'Hack'; + src: url('/fonts/hack/hack-bolditalic.woff2?sha=3114f1256') format('woff2'), url('/fonts/hack/hack-bolditalic.woff?sha=3114f1256') format('woff'); + font-weight: 700; + font-style: italic; + font-display: swap; +} diff --git a/author/project/system/public/fonts/commissioner.ttf b/author/project/system/public/fonts/commissioner.ttf new file mode 100644 index 0000000..5072c39 Binary files /dev/null and b/author/project/system/public/fonts/commissioner.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSans-Bold.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSans-Bold.ttf new file mode 100644 index 0000000..78584c4 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSans-Bold.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSans-BoldOblique.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSans-BoldOblique.ttf new file mode 100644 index 0000000..a013892 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSans-BoldOblique.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSans-ExtraLight.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSans-ExtraLight.ttf new file mode 100644 index 0000000..60dd47e Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSans-ExtraLight.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSans-Oblique.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSans-Oblique.ttf new file mode 100644 index 0000000..37e6daf Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSans-Oblique.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSans.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSans.ttf new file mode 100644 index 0000000..6060dfb Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSans.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed-Bold.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed-Bold.ttf new file mode 100644 index 0000000..68908d7 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed-Bold.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed-BoldOblique.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed-BoldOblique.ttf new file mode 100644 index 0000000..1a2d58d Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed-BoldOblique.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed-Oblique.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed-Oblique.ttf new file mode 100644 index 0000000..6d25e67 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed-Oblique.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed.ttf new file mode 100644 index 0000000..95aaba6 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSansCondensed.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono-Bold.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono-Bold.ttf new file mode 100644 index 0000000..c2465b3 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono-Bold.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono-BoldOblique.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono-BoldOblique.ttf new file mode 100644 index 0000000..303202f Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono-BoldOblique.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono-Oblique.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono-Oblique.ttf new file mode 100644 index 0000000..1df5133 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono-Oblique.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono.ttf new file mode 100644 index 0000000..3206a82 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSansMono.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSerif-Bold.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSerif-Bold.ttf new file mode 100644 index 0000000..2be31a1 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSerif-Bold.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSerif-BoldItalic.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSerif-BoldItalic.ttf new file mode 100644 index 0000000..2c6daba Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSerif-BoldItalic.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSerif-Italic.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSerif-Italic.ttf new file mode 100644 index 0000000..c52d49f Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSerif-Italic.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSerif.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSerif.ttf new file mode 100644 index 0000000..046c102 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSerif.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed-Bold.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed-Bold.ttf new file mode 100644 index 0000000..fc164c7 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed-Bold.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed-BoldItalic.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed-BoldItalic.ttf new file mode 100644 index 0000000..f01089d Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed-BoldItalic.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed-Italic.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed-Italic.ttf new file mode 100644 index 0000000..6254c8b Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed-Italic.ttf differ diff --git a/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed.ttf b/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed.ttf new file mode 100644 index 0000000..6e42557 Binary files /dev/null and b/author/project/system/public/fonts/dejavu/DejaVuLGCSerifCondensed.ttf differ diff --git a/author/project/system/public/fonts/fira/FiraMono-Bold.woff b/author/project/system/public/fonts/fira/FiraMono-Bold.woff new file mode 100644 index 0000000..e7da594 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraMono-Bold.woff differ diff --git a/author/project/system/public/fonts/fira/FiraMono-Bold.woff2 b/author/project/system/public/fonts/fira/FiraMono-Bold.woff2 new file mode 100644 index 0000000..7a3a102 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraMono-Bold.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraMono-Medium.woff b/author/project/system/public/fonts/fira/FiraMono-Medium.woff new file mode 100644 index 0000000..f08fde9 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraMono-Medium.woff differ diff --git a/author/project/system/public/fonts/fira/FiraMono-Medium.woff2 b/author/project/system/public/fonts/fira/FiraMono-Medium.woff2 new file mode 100644 index 0000000..3c9553d Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraMono-Medium.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraMono-Regular.woff b/author/project/system/public/fonts/fira/FiraMono-Regular.woff new file mode 100644 index 0000000..64e33d3 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraMono-Regular.woff differ diff --git a/author/project/system/public/fonts/fira/FiraMono-Regular.woff2 b/author/project/system/public/fonts/fira/FiraMono-Regular.woff2 new file mode 100644 index 0000000..bb452d4 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraMono-Regular.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Bold.woff b/author/project/system/public/fonts/fira/FiraSans-Bold.woff new file mode 100644 index 0000000..8001b79 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Bold.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Bold.woff2 b/author/project/system/public/fonts/fira/FiraSans-Bold.woff2 new file mode 100644 index 0000000..ce8013e Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Bold.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-BoldItalic.woff b/author/project/system/public/fonts/fira/FiraSans-BoldItalic.woff new file mode 100644 index 0000000..9c1da3a Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-BoldItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-BoldItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-BoldItalic.woff2 new file mode 100644 index 0000000..cf90d9a Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-BoldItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Book.woff b/author/project/system/public/fonts/fira/FiraSans-Book.woff new file mode 100644 index 0000000..299c884 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Book.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Book.woff2 b/author/project/system/public/fonts/fira/FiraSans-Book.woff2 new file mode 100644 index 0000000..6f9e54d Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Book.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-BookItalic.woff b/author/project/system/public/fonts/fira/FiraSans-BookItalic.woff new file mode 100644 index 0000000..cc29ba7 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-BookItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-BookItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-BookItalic.woff2 new file mode 100644 index 0000000..1275913 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-BookItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Eight.woff b/author/project/system/public/fonts/fira/FiraSans-Eight.woff new file mode 100644 index 0000000..9261a69 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Eight.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Eight.woff2 b/author/project/system/public/fonts/fira/FiraSans-Eight.woff2 new file mode 100644 index 0000000..729ba54 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Eight.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-EightItalic.woff b/author/project/system/public/fonts/fira/FiraSans-EightItalic.woff new file mode 100644 index 0000000..000003c Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-EightItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-EightItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-EightItalic.woff2 new file mode 100644 index 0000000..e651af6 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-EightItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ExtraBold.woff b/author/project/system/public/fonts/fira/FiraSans-ExtraBold.woff new file mode 100644 index 0000000..8289f9f Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ExtraBold.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ExtraBold.woff2 b/author/project/system/public/fonts/fira/FiraSans-ExtraBold.woff2 new file mode 100644 index 0000000..a14dbce Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ExtraBold.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ExtraBoldItalic.woff b/author/project/system/public/fonts/fira/FiraSans-ExtraBoldItalic.woff new file mode 100644 index 0000000..5dfa8da Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ExtraBoldItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ExtraBoldItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-ExtraBoldItalic.woff2 new file mode 100644 index 0000000..828a57d Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ExtraBoldItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ExtraLight.woff b/author/project/system/public/fonts/fira/FiraSans-ExtraLight.woff new file mode 100644 index 0000000..16ec788 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ExtraLight.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ExtraLight.woff2 b/author/project/system/public/fonts/fira/FiraSans-ExtraLight.woff2 new file mode 100644 index 0000000..8e98c42 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ExtraLight.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ExtraLightItalic.woff b/author/project/system/public/fonts/fira/FiraSans-ExtraLightItalic.woff new file mode 100644 index 0000000..99ce8e5 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ExtraLightItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ExtraLightItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-ExtraLightItalic.woff2 new file mode 100644 index 0000000..2ea8212 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ExtraLightItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Four.woff b/author/project/system/public/fonts/fira/FiraSans-Four.woff new file mode 100644 index 0000000..518fd5f Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Four.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Four.woff2 b/author/project/system/public/fonts/fira/FiraSans-Four.woff2 new file mode 100644 index 0000000..33473a6 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Four.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-FourItalic.woff b/author/project/system/public/fonts/fira/FiraSans-FourItalic.woff new file mode 100644 index 0000000..b407c43 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-FourItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-FourItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-FourItalic.woff2 new file mode 100644 index 0000000..0e64a9c Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-FourItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Hair.woff b/author/project/system/public/fonts/fira/FiraSans-Hair.woff new file mode 100644 index 0000000..ce65bcc Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Hair.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Hair.woff2 b/author/project/system/public/fonts/fira/FiraSans-Hair.woff2 new file mode 100644 index 0000000..64cef84 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Hair.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-HairItalic.woff b/author/project/system/public/fonts/fira/FiraSans-HairItalic.woff new file mode 100644 index 0000000..08abd3a Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-HairItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-HairItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-HairItalic.woff2 new file mode 100644 index 0000000..b063e87 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-HairItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Heavy.woff b/author/project/system/public/fonts/fira/FiraSans-Heavy.woff new file mode 100644 index 0000000..ff18652 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Heavy.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Heavy.woff2 b/author/project/system/public/fonts/fira/FiraSans-Heavy.woff2 new file mode 100644 index 0000000..0cafdba Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Heavy.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-HeavyItalic.woff b/author/project/system/public/fonts/fira/FiraSans-HeavyItalic.woff new file mode 100644 index 0000000..77c1d55 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-HeavyItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-HeavyItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-HeavyItalic.woff2 new file mode 100644 index 0000000..8d48a7f Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-HeavyItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Italic.woff b/author/project/system/public/fonts/fira/FiraSans-Italic.woff new file mode 100644 index 0000000..d200976 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Italic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Italic.woff2 b/author/project/system/public/fonts/fira/FiraSans-Italic.woff2 new file mode 100644 index 0000000..f7857e9 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Italic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Light.woff b/author/project/system/public/fonts/fira/FiraSans-Light.woff new file mode 100644 index 0000000..309ecf2 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Light.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Light.woff2 b/author/project/system/public/fonts/fira/FiraSans-Light.woff2 new file mode 100644 index 0000000..24e6444 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Light.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-LightItalic.woff b/author/project/system/public/fonts/fira/FiraSans-LightItalic.woff new file mode 100644 index 0000000..9f3c250 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-LightItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-LightItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-LightItalic.woff2 new file mode 100644 index 0000000..f456ca5 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-LightItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Medium.woff b/author/project/system/public/fonts/fira/FiraSans-Medium.woff new file mode 100644 index 0000000..1701b41 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Medium.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Medium.woff2 b/author/project/system/public/fonts/fira/FiraSans-Medium.woff2 new file mode 100644 index 0000000..71d8ed5 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Medium.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-MediumItalic.woff b/author/project/system/public/fonts/fira/FiraSans-MediumItalic.woff new file mode 100644 index 0000000..029099b Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-MediumItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-MediumItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-MediumItalic.woff2 new file mode 100644 index 0000000..97b96c6 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-MediumItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Regular.woff b/author/project/system/public/fonts/fira/FiraSans-Regular.woff new file mode 100644 index 0000000..10c41a7 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Regular.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Regular.woff2 b/author/project/system/public/fonts/fira/FiraSans-Regular.woff2 new file mode 100644 index 0000000..f77c427 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Regular.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-SemiBold.woff b/author/project/system/public/fonts/fira/FiraSans-SemiBold.woff new file mode 100644 index 0000000..3ccdeb4 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-SemiBold.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-SemiBold.woff2 b/author/project/system/public/fonts/fira/FiraSans-SemiBold.woff2 new file mode 100644 index 0000000..29ef538 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-SemiBold.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-SemiBoldItalic.woff b/author/project/system/public/fonts/fira/FiraSans-SemiBoldItalic.woff new file mode 100644 index 0000000..378fde9 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-SemiBoldItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-SemiBoldItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-SemiBoldItalic.woff2 new file mode 100644 index 0000000..91182a7 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-SemiBoldItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Thin.woff b/author/project/system/public/fonts/fira/FiraSans-Thin.woff new file mode 100644 index 0000000..21e509d Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Thin.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Thin.woff2 b/author/project/system/public/fonts/fira/FiraSans-Thin.woff2 new file mode 100644 index 0000000..c494caa Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Thin.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ThinItalic.woff b/author/project/system/public/fonts/fira/FiraSans-ThinItalic.woff new file mode 100644 index 0000000..a75b761 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ThinItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-ThinItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-ThinItalic.woff2 new file mode 100644 index 0000000..4f432d6 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-ThinItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Two.woff b/author/project/system/public/fonts/fira/FiraSans-Two.woff new file mode 100644 index 0000000..3b77a84 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Two.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Two.woff2 b/author/project/system/public/fonts/fira/FiraSans-Two.woff2 new file mode 100644 index 0000000..6842f0c Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Two.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-TwoItalic.woff b/author/project/system/public/fonts/fira/FiraSans-TwoItalic.woff new file mode 100644 index 0000000..c2a549d Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-TwoItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-TwoItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-TwoItalic.woff2 new file mode 100644 index 0000000..6b176c7 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-TwoItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Ultra.woff b/author/project/system/public/fonts/fira/FiraSans-Ultra.woff new file mode 100644 index 0000000..705346e Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Ultra.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-Ultra.woff2 b/author/project/system/public/fonts/fira/FiraSans-Ultra.woff2 new file mode 100644 index 0000000..25e5e6a Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-Ultra.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-UltraItalic.woff b/author/project/system/public/fonts/fira/FiraSans-UltraItalic.woff new file mode 100644 index 0000000..1790a76 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-UltraItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-UltraItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-UltraItalic.woff2 new file mode 100644 index 0000000..7b9b43b Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-UltraItalic.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-UltraLight.woff b/author/project/system/public/fonts/fira/FiraSans-UltraLight.woff new file mode 100644 index 0000000..cbc1f31 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-UltraLight.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-UltraLight.woff2 b/author/project/system/public/fonts/fira/FiraSans-UltraLight.woff2 new file mode 100644 index 0000000..82046b1 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-UltraLight.woff2 differ diff --git a/author/project/system/public/fonts/fira/FiraSans-UltraLightItalic.woff b/author/project/system/public/fonts/fira/FiraSans-UltraLightItalic.woff new file mode 100644 index 0000000..5f0ef24 Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-UltraLightItalic.woff differ diff --git a/author/project/system/public/fonts/fira/FiraSans-UltraLightItalic.woff2 b/author/project/system/public/fonts/fira/FiraSans-UltraLightItalic.woff2 new file mode 100644 index 0000000..a50a5df Binary files /dev/null and b/author/project/system/public/fonts/fira/FiraSans-UltraLightItalic.woff2 differ diff --git a/author/project/system/public/fonts/hack/hack-bold-subset.woff b/author/project/system/public/fonts/hack/hack-bold-subset.woff new file mode 100644 index 0000000..99e9e7b Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-bold-subset.woff differ diff --git a/author/project/system/public/fonts/hack/hack-bold-subset.woff2 b/author/project/system/public/fonts/hack/hack-bold-subset.woff2 new file mode 100644 index 0000000..ae3694f Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-bold-subset.woff2 differ diff --git a/author/project/system/public/fonts/hack/hack-bold.woff b/author/project/system/public/fonts/hack/hack-bold.woff new file mode 100644 index 0000000..7a64513 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-bold.woff differ diff --git a/author/project/system/public/fonts/hack/hack-bold.woff2 b/author/project/system/public/fonts/hack/hack-bold.woff2 new file mode 100644 index 0000000..a25b27d Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-bold.woff2 differ diff --git a/author/project/system/public/fonts/hack/hack-bolditalic-subset.woff b/author/project/system/public/fonts/hack/hack-bolditalic-subset.woff new file mode 100644 index 0000000..91399f9 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-bolditalic-subset.woff differ diff --git a/author/project/system/public/fonts/hack/hack-bolditalic-subset.woff2 b/author/project/system/public/fonts/hack/hack-bolditalic-subset.woff2 new file mode 100644 index 0000000..55d67b8 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-bolditalic-subset.woff2 differ diff --git a/author/project/system/public/fonts/hack/hack-bolditalic.woff b/author/project/system/public/fonts/hack/hack-bolditalic.woff new file mode 100644 index 0000000..993d05a Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-bolditalic.woff differ diff --git a/author/project/system/public/fonts/hack/hack-bolditalic.woff2 b/author/project/system/public/fonts/hack/hack-bolditalic.woff2 new file mode 100644 index 0000000..5415871 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-bolditalic.woff2 differ diff --git a/author/project/system/public/fonts/hack/hack-italic-subset.woff b/author/project/system/public/fonts/hack/hack-italic-subset.woff new file mode 100644 index 0000000..4d747c7 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-italic-subset.woff differ diff --git a/author/project/system/public/fonts/hack/hack-italic-subset.woff2 b/author/project/system/public/fonts/hack/hack-italic-subset.woff2 new file mode 100644 index 0000000..bbb6240 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-italic-subset.woff2 differ diff --git a/author/project/system/public/fonts/hack/hack-italic.woff b/author/project/system/public/fonts/hack/hack-italic.woff new file mode 100644 index 0000000..b79f9e4 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-italic.woff differ diff --git a/author/project/system/public/fonts/hack/hack-italic.woff2 b/author/project/system/public/fonts/hack/hack-italic.woff2 new file mode 100644 index 0000000..40522cc Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-italic.woff2 differ diff --git a/author/project/system/public/fonts/hack/hack-regular-subset.woff b/author/project/system/public/fonts/hack/hack-regular-subset.woff new file mode 100644 index 0000000..65a07e4 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-regular-subset.woff differ diff --git a/author/project/system/public/fonts/hack/hack-regular-subset.woff2 b/author/project/system/public/fonts/hack/hack-regular-subset.woff2 new file mode 100644 index 0000000..ae9eca7 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-regular-subset.woff2 differ diff --git a/author/project/system/public/fonts/hack/hack-regular.woff b/author/project/system/public/fonts/hack/hack-regular.woff new file mode 100644 index 0000000..07d1b32 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-regular.woff differ diff --git a/author/project/system/public/fonts/hack/hack-regular.woff2 b/author/project/system/public/fonts/hack/hack-regular.woff2 new file mode 100644 index 0000000..cc862c7 Binary files /dev/null and b/author/project/system/public/fonts/hack/hack-regular.woff2 differ diff --git a/author/project/system/public/index.php b/author/project/system/public/index.php new file mode 100644 index 0000000..9c886de --- /dev/null +++ b/author/project/system/public/index.php @@ -0,0 +1,52 @@ +router + ->write('/', new route('index', 'index'), 'GET') +; + +// Handling request +$core->start(); diff --git a/author/project/system/public/telegram.php b/author/project/system/public/telegram.php new file mode 100644 index 0000000..d4873e3 --- /dev/null +++ b/author/project/system/public/telegram.php @@ -0,0 +1,101 @@ +setParseMode(config::PARSE_MODE_MARKDOWN); +$config->useReactFileSystem(true); + +// Initializing the robot +$robot = new Zanzara(ROBOT['key'], $config); + +// Initializing the updates listener +$robot->onUpdate(function (context $context): void {}); + +// Initializing the robot middlewares +$robot->middleware([middlewares::class, 'account']); +$robot->middleware([middlewares::class, 'language']); +$robot->middleware([middlewares::class, 'localization']); +$robot->middleware([middlewares::class, 'authorizations']); +$robot->middleware([middlewares::class, 'welcome']); + +// Initializing the robot commands handlers +$robot->onCommand('start', [commands::class, 'start']); +$robot->onCommand('menu', [commands::class, 'menu']); +$robot->onCommand('language', [commands::class, 'language'])->middleware([middlewares::class, 'settings']); +$robot->onCommand('society', [commands::class, 'society']); + +// Initializing the robot settings language buttons handlers +foreach (language::cases() as $language) { + // Iterating over languages + + // Initializing language buttons + $robot->onCbQueryData(["settings_language_$language->name"], fn(context $context) => settings::language($context, $language)); +}; + +// Starting chat-robot +$robot->run(); diff --git a/author/project/system/public/themes/default/css/aside.css b/author/project/system/public/themes/default/css/aside.css new file mode 100644 index 0000000..7ba2c94 --- /dev/null +++ b/author/project/system/public/themes/default/css/aside.css @@ -0,0 +1,7 @@ +@charset "UTF-8"; + +aside { + &:not(:has(*)) { + display: none; + } +} diff --git a/author/project/system/public/themes/default/css/colorscheme.css b/author/project/system/public/themes/default/css/colorscheme.css new file mode 100644 index 0000000..49b480d --- /dev/null +++ b/author/project/system/public/themes/default/css/colorscheme.css @@ -0,0 +1,45 @@ +@charset "UTF-8"; + +@media (prefers-color-scheme: dark) { + :root { + --text-color: #fff; + --text-color-inverted: #000; + --button-background-color-inverted: #fff; + --button-background-color: #000; + --section-background-color-inverted: #fff; + --section-background-color: #000; + --background-color: #000; + --background-color-inverted: #fff; + + --interface-top-background-color: var(--background-color, #000); + --interface-background-color: var(--background-color, #000); + --interface-bottom-background-color: var(--background-color, #000); + + --red: red; + --white: #fff; + + --paper: var(--white); + } +} + +@media (prefers-color-scheme: light) { + :root { + --text-color: #fff; + --text-color-inverted: #000; + --button-background-color-inverted: #fff; + --button-background-color: #000; + --section-background-color-inverted: #fff; + --section-background-color: #000; + --background-color: #000; + --background-color-inverted: #fff; + + --interface-top-background-color: var(--background-color, #000); + --interface-background-color: var(--background-color, #000); + --interface-bottom-background-color: var(--background-color, #000); + + --red: red; + --white: #fff; + + --paper: var(--white); + } +} diff --git a/author/project/system/public/themes/default/css/fonts.css b/author/project/system/public/themes/default/css/fonts.css new file mode 100644 index 0000000..84f16b4 --- /dev/null +++ b/author/project/system/public/themes/default/css/fonts.css @@ -0,0 +1,9 @@ +@import url('/css/fonts/fira.css'); +@import url('/css/fonts/hack.css'); +@import url('/css/fonts/dejavu.css'); + +@font-face { + font-family: 'Commissioner'; + src: url('/fonts/commissioner.ttf'); + font-weight: 400; +} diff --git a/author/project/system/public/themes/default/css/footer.css b/author/project/system/public/themes/default/css/footer.css new file mode 100644 index 0000000..5e5e484 --- /dev/null +++ b/author/project/system/public/themes/default/css/footer.css @@ -0,0 +1,7 @@ +@charset "UTF-8"; + +footer { + &:not(:has(*)) { + display: none; + } +} \ No newline at end of file diff --git a/author/project/system/public/themes/default/css/header.css b/author/project/system/public/themes/default/css/header.css new file mode 100644 index 0000000..514eb63 --- /dev/null +++ b/author/project/system/public/themes/default/css/header.css @@ -0,0 +1,7 @@ +@charset "UTF-8"; + +header { + &:not(:has(*)) { + display: none; + } +} diff --git a/author/project/system/public/themes/default/css/main.css b/author/project/system/public/themes/default/css/main.css new file mode 100644 index 0000000..f1b3243 --- /dev/null +++ b/author/project/system/public/themes/default/css/main.css @@ -0,0 +1,14 @@ +@charset "UTF-8"; + +body { + margin: unset; +} + +main { + flex-grow: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: var(--gap); + transition: 0s; +} \ No newline at end of file diff --git a/author/project/system/public/themes/default/css/system.css b/author/project/system/public/themes/default/css/system.css new file mode 100644 index 0000000..1137f56 --- /dev/null +++ b/author/project/system/public/themes/default/css/system.css @@ -0,0 +1,34 @@ +@charset "UTF-8"; + +:root { + --gap: min(12px, 1rem); + + /* font-family: , system-ui, sans-serif; */ + font-family: "dejavu"; + text-decoration: none; + outline: none; + border: none; + transition: 0.1s ease-out; +} + +/* Selection */ +::selection { + color: var(--text-selected-color); + background: var(--text-selected-background-color); +} + +::-moz-selection { + color: var(--text-selected-color); + background: var(--text-selected-background-color); +} + + +.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/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/system.php.sample b/author/project/system/settings/system.php.sample new file mode 100644 index 0000000..549fb63 --- /dev/null +++ b/author/project/system/settings/system.php.sample @@ -0,0 +1,13 @@ + null, + 'key' => '' +]); diff --git a/author/project/system/storage/images/mushroom.jpg b/author/project/system/storage/images/mushroom.jpg new file mode 100644 index 0000000..5d8741d Binary files /dev/null and b/author/project/system/storage/images/mushroom.jpg differ diff --git a/author/project/system/views/templater.php b/author/project/system/views/templater.php new file mode 100644 index 0000000..3a85b4b --- /dev/null +++ b/author/project/system/views/templater.php @@ -0,0 +1,210 @@ + + */ +final class templater extends controller implements array_access +{ + /** + * Twig + * + * @var twig $twig Instance of the twig templater + */ + readonly public twig $twig; + + /** + * Variables + * + * @var array $variables Registry of view global variables + */ + public array $variables = []; + + /** + * Constructor of an instance + * + * @return void + */ + public function __construct() + { + // Initializing the Twig instance + $this->twig = new twig(new FilesystemLoader(VIEWS)); + + // Initializing global variables + $this->twig->addGlobal('theme', 'default'); + $this->twig->addGlobal('server', $_SERVER); + $this->twig->addGlobal('cookies', $_COOKIE); + $this->twig->addGlobal('language', $language = $session?->buffer['language'] ?? language::en); + } + + /** + * Render + * + * Render the 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-document + */ + public function render(string $file, array $variables = []): ?string + { + // Generation and exit (success) + return $this->twig->render('themes' . DIRECTORY_SEPARATOR . $this->twig->getGlobals()['theme'] . DIRECTORY_SEPARATOR . $file, $variables + $this->variables); + + } + + /** + * Write + * + * Write the variable into the registry of the view 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 the variable from the registry of the view 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 the variable from the registry of the view 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 the registry of the view 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 the variable into the registry of the view 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 the variable from the registry of the view 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 the variable from the registry of the view 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 the registry of the view 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/aside.html b/author/project/system/views/themes/default/aside.html new file mode 100644 index 0000000..afb2aa1 --- /dev/null +++ b/author/project/system/views/themes/default/aside.html @@ -0,0 +1,10 @@ +{% block css %} +{% endblock %} + +{% block body %} + +{% endblock %} + +{% block js %} +{% endblock %} \ No newline at end of file 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..1bb43a7 --- /dev/null +++ b/author/project/system/views/themes/default/core.html @@ -0,0 +1,31 @@ + + + + + + {% use '/themes/default/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 '/themes/default/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..dbc5cdc --- /dev/null +++ b/author/project/system/views/themes/default/head.html @@ -0,0 +1,26 @@ +{% block title %} +{% if head.title != empty %}{{ head.title }}{% else %}campanula by garden{% endif %} +{% endblock %} + +{% block meta %} + + +{% for meta in head.metas %} + +{% endfor %} +{% endblock %} + +{% block css %} +{% for element in css %} + +{% endfor %} + + + + + + + +{% 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..be72f70 --- /dev/null +++ b/author/project/system/views/themes/default/index.html @@ -0,0 +1,31 @@ +{% extends "/themes/default/core.html" %} + +{% use "/themes/default/header.html" with css as header_css, body as header, js as header_js %} +{% use "/themes/default/aside.html" with css as aside_css, body as aside, js as aside_js %} +{% use "/themes/default/footer.html" with css as footer_css, body as footer, js as footer_js %} + +{% block css %} + {{ block('header_css') }} + {{ block('aside_css') }} + {{ block('footer_css') }} +{% endblock %} + +{% block body %} + {{ block('header') }} + + {{ block('aside') }} + +
+ {% block main %} + {{ main|raw }} + {% endblock %} +
+ + {{ block('footer') }} +{% endblock %} + +{% block js %} + {{ block('header_js') }} + {{ block('aside_js') }} + {{ block('footer_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..784e58d --- /dev/null +++ b/author/project/system/views/themes/default/js.html @@ -0,0 +1,5 @@ +{% block js %} +{% for element in js %} + +{% endfor %} +{% endblock %} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..c6040bc --- /dev/null +++ b/composer.json @@ -0,0 +1,56 @@ +{ + "name": "garden/campanula", + "description": "Receive and send messages through Gammu server and Telegram messenger interface", + "homepage": "https://git.svoboda.works/garden/campanula", + "type": "site", + "keywords": [ + "minimal", + "baza" + ], + "readme": "README.md", + "license": "WTFPL", + "authors": [ + { + "name": "garden", + "email": "garden@gmail.com", + "homepage": "https://garden.page", + "role": "Programmer" + } + ], + "support": { + "wiki": "https://git.svoboda.works/garden/campanula/wiki", + "issues": "https://git.svoboda.works/garden/campanula/issues" + }, + "require": { + "php": "^8.5", + "mirzaev/minimal": "^3.7", + "mirzaev/baza": "^3.3", + "mirzaev/record": "^1.0", + "mirzaev/languages": "^1.0", + "mirzaev/currencies": "^2.0", + "mirzaev/unmarkdown": "^1.0", + "svoboda/time": "^1.0", + "badfarm/zanzara": "^0.9.1", + "twig/twig": "^3.2", + "twig/extra-bundle": "^3.7", + "twig/intl-extra": "^3.10" + }, + "suggest": { + "mirzaev/files": "Easy working with files", + "mirzaev/currencies": "Easy currencies integration" + + }, + "autoload": { + "psr-4": { + "garden\\campanula\\": "garden/campanula/system" + } + }, + "autoload-dev": { + "psr-4": { + "garden\\campanula\\tests\\": "garden/campanula/tests" + } + }, + "scripts": { + "pre-update-cmd": "./install.sh" + } +} diff --git a/examples/systemd/telegram.service b/examples/systemd/telegram.service new file mode 100644 index 0000000..d71d31f --- /dev/null +++ b/examples/systemd/telegram.service @@ -0,0 +1,16 @@ +[Unit] +Description=Telegram chat-robot: @robot_bot + +Wants=network.target +After=syslog.target network-online.target + +[Service] +ExecStart=sudo -u www-data /usr/bin/php /var/www/campanula/garden/campanula/system/public/telegram.php +PIDFile=/var/run/php/telegram.pid +RemainAfterExit=no +RuntimeMaxSec=3600s +Restart=always +RestartSec=5s + +[Install] +WantedBy=multi-user.target diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..049975d --- /dev/null +++ b/install.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ -d author/project ]; then + mv author/project author/campanula +fi + +if [ -d author ]; then + mv author garden +fi + +for i in garden/campanula/system/settings/*.sample; do + echo $i; + if [ ! -f "${i/.sample/}" ]; then + cp "$i" "${i/.sample/}"; + echo ${i/.sample/}; + fi +done \ No newline at end of file