diff --git a/.env.example b/.env.example
index a9a285c..ffddf4b 100644
--- a/.env.example
+++ b/.env.example
@@ -1,13 +1,23 @@
+APP_NAME="It Guild Micro Framework"
+
DB_HOST=localhost
-DB_USER=root
+DB_USER={db_user}
DB_DRIVER=mysql
-DB_PASSWORD=123edsaqw
-DB_NAME=mfw
-DB_CHARSET=utf8
-DB_COLLATION=utf8_unicode_ci
+DB_PASSWORD={db_password}
+DB_NAME={db_name}
+DB_CHARSET=utf8mb4
+DB_COLLATION=utf8mb4_unicode_ci
DB_PREFIX=''
VIEWS_PATH=/views
VIEWS_CACHE_PATH=/views_cache
+MAIL_SMTP_HOST=smtp.mail.ru
+MAIL_SMTP_PORT=587
+MAIL_SMTP_USERNAME=username@mail.ru
+MAIL_SMTP_PASSWORD=somepassword
+
+MODULE_SHOP_URL='http://igfs.loc'
+MODULE_SHOP_TOKEN='your token'
+
SECRET_KEY=''
\ No newline at end of file
diff --git a/bootstrap/secure.php b/bootstrap/secure.php
index a800dda..714beb3 100644
--- a/bootstrap/secure.php
+++ b/bootstrap/secure.php
@@ -1,7 +1,8 @@
'JWT', // random_bytes, md5, crypt, hash, JWT
+ 'web_auth_type' => 'email_code', // login_password, email_code
+ 'token_type' => 'crypt', // random_bytes, md5, crypt, hash, JWT
'token_expired_time' => "+30 days", // +1 day
];
diff --git a/composer.json b/composer.json
index 00bbe7e..ecf8197 100644
--- a/composer.json
+++ b/composer.json
@@ -18,7 +18,8 @@
"josantonius/session": "^2.0",
"firebase/php-jwt": "^6.10",
"k-adam/env-editor": "^2.0",
- "guzzlehttp/guzzle": "^7.9"
+ "guzzlehttp/guzzle": "^7.9",
+ "phpmailer/phpmailer": "^6.9"
},
"autoload": {
"psr-4": {
diff --git a/composer.lock b/composer.lock
index ca65c63..36ff005 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "9b8653e1a4f451d6e125cb1732ffdeef",
+ "content-hash": "18fbb67ed0b66029e924b0a6d32f646f",
"packages": [
{
"name": "brick/math",
@@ -275,16 +275,16 @@
},
{
"name": "firebase/php-jwt",
- "version": "v6.10.1",
+ "version": "v6.10.2",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
- "reference": "500501c2ce893c824c801da135d02661199f60c5"
+ "reference": "30c19ed0f3264cb660ea496895cfb6ef7ee3653b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/firebase/php-jwt/zipball/500501c2ce893c824c801da135d02661199f60c5",
- "reference": "500501c2ce893c824c801da135d02661199f60c5",
+ "url": "https://api.github.com/repos/firebase/php-jwt/zipball/30c19ed0f3264cb660ea496895cfb6ef7ee3653b",
+ "reference": "30c19ed0f3264cb660ea496895cfb6ef7ee3653b",
"shasum": ""
},
"require": {
@@ -332,9 +332,9 @@
],
"support": {
"issues": "https://github.com/firebase/php-jwt/issues",
- "source": "https://github.com/firebase/php-jwt/tree/v6.10.1"
+ "source": "https://github.com/firebase/php-jwt/tree/v6.10.2"
},
- "time": "2024-05-18T18:05:11+00:00"
+ "time": "2024-11-24T11:22:49+00:00"
},
{
"name": "graham-campbell/result-type",
@@ -725,16 +725,16 @@
},
{
"name": "illuminate/collections",
- "version": "v11.32.0",
+ "version": "v11.34.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/collections.git",
- "reference": "a01a9d0799700bf34ab3797988fdd5f420d42bfe"
+ "reference": "fd2103ddc121449a7926fc34a9d220e5b88183c1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/collections/zipball/a01a9d0799700bf34ab3797988fdd5f420d42bfe",
- "reference": "a01a9d0799700bf34ab3797988fdd5f420d42bfe",
+ "url": "https://api.github.com/repos/illuminate/collections/zipball/fd2103ddc121449a7926fc34a9d220e5b88183c1",
+ "reference": "fd2103ddc121449a7926fc34a9d220e5b88183c1",
"shasum": ""
},
"require": {
@@ -776,20 +776,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2024-11-15T15:43:48+00:00"
+ "time": "2024-11-27T14:51:56+00:00"
},
{
"name": "illuminate/conditionable",
- "version": "v11.32.0",
+ "version": "v11.34.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/conditionable.git",
- "reference": "362dd761b9920367bca1427a902158225e9e3a23"
+ "reference": "911df1bda950a3b799cf80671764e34eede131c6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/conditionable/zipball/362dd761b9920367bca1427a902158225e9e3a23",
- "reference": "362dd761b9920367bca1427a902158225e9e3a23",
+ "url": "https://api.github.com/repos/illuminate/conditionable/zipball/911df1bda950a3b799cf80671764e34eede131c6",
+ "reference": "911df1bda950a3b799cf80671764e34eede131c6",
"shasum": ""
},
"require": {
@@ -822,20 +822,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2024-06-28T20:10:30+00:00"
+ "time": "2024-11-21T16:28:56+00:00"
},
{
"name": "illuminate/container",
- "version": "v11.32.0",
+ "version": "v11.34.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
- "reference": "6e31eb49e9c9e68356a55cd8f18fb8830b8158cd"
+ "reference": "b057b0bbb38d7c7524df1ca5c38e7318f4c64d26"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/container/zipball/6e31eb49e9c9e68356a55cd8f18fb8830b8158cd",
- "reference": "6e31eb49e9c9e68356a55cd8f18fb8830b8158cd",
+ "url": "https://api.github.com/repos/illuminate/container/zipball/b057b0bbb38d7c7524df1ca5c38e7318f4c64d26",
+ "reference": "b057b0bbb38d7c7524df1ca5c38e7318f4c64d26",
"shasum": ""
},
"require": {
@@ -873,20 +873,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2024-11-14T15:31:35+00:00"
+ "time": "2024-11-21T20:07:31+00:00"
},
{
"name": "illuminate/contracts",
- "version": "v11.32.0",
+ "version": "v11.34.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
- "reference": "44c15aec6ea0d997e0885aa5b04876fe8a141433"
+ "reference": "184317f701ba20ca265e36808ed54b75b115972d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/contracts/zipball/44c15aec6ea0d997e0885aa5b04876fe8a141433",
- "reference": "44c15aec6ea0d997e0885aa5b04876fe8a141433",
+ "url": "https://api.github.com/repos/illuminate/contracts/zipball/184317f701ba20ca265e36808ed54b75b115972d",
+ "reference": "184317f701ba20ca265e36808ed54b75b115972d",
"shasum": ""
},
"require": {
@@ -921,7 +921,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2024-11-15T15:40:33+00:00"
+ "time": "2024-11-25T15:33:38+00:00"
},
{
"name": "illuminate/database",
@@ -1060,7 +1060,7 @@
},
{
"name": "illuminate/macroable",
- "version": "v11.32.0",
+ "version": "v11.34.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/macroable.git",
@@ -1106,16 +1106,16 @@
},
{
"name": "illuminate/support",
- "version": "v11.32.0",
+ "version": "v11.34.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
- "reference": "213bc04ed2a75dac441e602df4568154c36a3670"
+ "reference": "2b718a86571baed50fdc5d5748a846c2e58e07eb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/support/zipball/213bc04ed2a75dac441e602df4568154c36a3670",
- "reference": "213bc04ed2a75dac441e602df4568154c36a3670",
+ "url": "https://api.github.com/repos/illuminate/support/zipball/2b718a86571baed50fdc5d5748a846c2e58e07eb",
+ "reference": "2b718a86571baed50fdc5d5748a846c2e58e07eb",
"shasum": ""
},
"require": {
@@ -1127,9 +1127,9 @@
"illuminate/conditionable": "^11.0",
"illuminate/contracts": "^11.0",
"illuminate/macroable": "^11.0",
- "nesbot/carbon": "^2.72.2|^3.0",
+ "nesbot/carbon": "^2.72.2|^3.4",
"php": "^8.2",
- "voku/portable-ascii": "^2.0"
+ "voku/portable-ascii": "^2.0.2"
},
"conflict": {
"tightenco/collect": "<5.5.33"
@@ -1145,7 +1145,7 @@
"symfony/process": "Required to use the composer class (^7.0).",
"symfony/uid": "Required to use Str::ulid() (^7.0).",
"symfony/var-dumper": "Required to use the dd function (^7.0).",
- "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.4.1)."
+ "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.6.1)."
},
"type": "library",
"extra": {
@@ -1178,7 +1178,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2024-11-14T16:30:16+00:00"
+ "time": "2024-11-27T14:58:17+00:00"
},
{
"name": "itguild/eloquent-table",
@@ -1217,11 +1217,11 @@
},
{
"name": "itguild/forms",
- "version": "0.1.4",
+ "version": "0.1.5",
"source": {
"type": "git",
"url": "https://git.itguild.info/ItGuild/forms_bundle.git",
- "reference": "ddb17cc47360910b3875b88e10e14f91fcd875be"
+ "reference": "45e57367d3f9571fde2b82fa2fd8126469ba6db6"
},
"require": {
"itguild/php-cg-select-v2": "^0.1.0",
@@ -1245,7 +1245,7 @@
"email": "apuc06@mail.ru"
}
],
- "time": "2024-09-10T08:41:16+00:00"
+ "time": "2024-11-28T10:18:58+00:00"
},
{
"name": "itguild/php-cg-select-v2",
@@ -1276,11 +1276,11 @@
},
{
"name": "itguild/tables",
- "version": "1.0.8",
+ "version": "1.0.9",
"source": {
"type": "git",
"url": "https://git.itguild.info/ItGuild/tables",
- "reference": "5f46431d4562d2b4d8bff43b446fef82ecf73b83"
+ "reference": "5effacf12fd68d31181304562deb7331cf42c1db"
},
"type": "library",
"autoload": {
@@ -1298,7 +1298,7 @@
"email": "apuc06@mail.ru"
}
],
- "time": "2024-10-11T13:31:11+00:00"
+ "time": "2024-11-28T08:57:17+00:00"
},
{
"name": "josantonius/session",
@@ -1607,6 +1607,87 @@
],
"time": "2024-11-07T17:46:48+00:00"
},
+ {
+ "name": "phpmailer/phpmailer",
+ "version": "v6.9.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHPMailer/PHPMailer.git",
+ "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e",
+ "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "ext-filter": "*",
+ "ext-hash": "*",
+ "php": ">=5.5.0"
+ },
+ "require-dev": {
+ "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
+ "doctrine/annotations": "^1.2.6 || ^1.13.3",
+ "php-parallel-lint/php-console-highlighter": "^1.0.0",
+ "php-parallel-lint/php-parallel-lint": "^1.3.2",
+ "phpcompatibility/php-compatibility": "^9.3.5",
+ "roave/security-advisories": "dev-latest",
+ "squizlabs/php_codesniffer": "^3.7.2",
+ "yoast/phpunit-polyfills": "^1.0.4"
+ },
+ "suggest": {
+ "decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
+ "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
+ "ext-openssl": "Needed for secure SMTP sending and DKIM signing",
+ "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
+ "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
+ "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
+ "psr/log": "For optional PSR-3 debug logging",
+ "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
+ "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "PHPMailer\\PHPMailer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "LGPL-2.1-only"
+ ],
+ "authors": [
+ {
+ "name": "Marcus Bointon",
+ "email": "phpmailer@synchromedia.co.uk"
+ },
+ {
+ "name": "Jim Jagielski",
+ "email": "jimjag@gmail.com"
+ },
+ {
+ "name": "Andy Prevost",
+ "email": "codeworxtech@users.sourceforge.net"
+ },
+ {
+ "name": "Brent R. Matzelle"
+ }
+ ],
+ "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
+ "support": {
+ "issues": "https://github.com/PHPMailer/PHPMailer/issues",
+ "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/Synchro",
+ "type": "github"
+ }
+ ],
+ "time": "2024-11-24T18:04:13+00:00"
+ },
{
"name": "phpoption/phpoption",
"version": "1.9.3",
@@ -2139,16 +2220,16 @@
},
{
"name": "symfony/clock",
- "version": "v7.1.6",
+ "version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/clock.git",
- "reference": "97bebc53548684c17ed696bc8af016880f0f098d"
+ "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/clock/zipball/97bebc53548684c17ed696bc8af016880f0f098d",
- "reference": "97bebc53548684c17ed696bc8af016880f0f098d",
+ "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
+ "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
"shasum": ""
},
"require": {
@@ -2193,7 +2274,7 @@
"time"
],
"support": {
- "source": "https://github.com/symfony/clock/tree/v7.1.6"
+ "source": "https://github.com/symfony/clock/tree/v7.2.0"
},
"funding": [
{
@@ -2209,20 +2290,20 @@
"type": "tidelift"
}
],
- "time": "2024-09-25T14:20:29+00:00"
+ "time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.5.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"shasum": ""
},
"require": {
@@ -2260,7 +2341,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -2276,20 +2357,20 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/finder",
- "version": "v7.1.6",
+ "version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "2cb89664897be33f78c65d3d2845954c8d7a43b8"
+ "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/2cb89664897be33f78c65d3d2845954c8d7a43b8",
- "reference": "2cb89664897be33f78c65d3d2845954c8d7a43b8",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/6de263e5868b9a137602dd1e33e4d48bfae99c49",
+ "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49",
"shasum": ""
},
"require": {
@@ -2324,7 +2405,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.1.6"
+ "source": "https://github.com/symfony/finder/tree/v7.2.0"
},
"funding": [
{
@@ -2340,7 +2421,7 @@
"type": "tidelift"
}
],
- "time": "2024-10-01T08:31:23+00:00"
+ "time": "2024-10-23T06:56:12+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -2735,20 +2816,21 @@
},
{
"name": "symfony/translation",
- "version": "v7.1.6",
+ "version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "b9f72ab14efdb6b772f85041fa12f820dee8d55f"
+ "reference": "dc89e16b44048ceecc879054e5b7f38326ab6cc5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/b9f72ab14efdb6b772f85041fa12f820dee8d55f",
- "reference": "b9f72ab14efdb6b772f85041fa12f820dee8d55f",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/dc89e16b44048ceecc879054e5b7f38326ab6cc5",
+ "reference": "dc89e16b44048ceecc879054e5b7f38326ab6cc5",
"shasum": ""
},
"require": {
"php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/translation-contracts": "^2.5|^3.0"
},
@@ -2809,7 +2891,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/translation/tree/v7.1.6"
+ "source": "https://github.com/symfony/translation/tree/v7.2.0"
},
"funding": [
{
@@ -2825,20 +2907,20 @@
"type": "tidelift"
}
],
- "time": "2024-09-28T12:35:13+00:00"
+ "time": "2024-11-12T20:47:56+00:00"
},
{
"name": "symfony/translation-contracts",
- "version": "v3.5.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
- "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a"
+ "reference": "4667ff3bd513750603a09c8dedbea942487fb07c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
- "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
+ "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c",
+ "reference": "4667ff3bd513750603a09c8dedbea942487fb07c",
"shasum": ""
},
"require": {
@@ -2887,7 +2969,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -2903,7 +2985,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "twbs/bootstrap",
@@ -2957,16 +3039,16 @@
},
{
"name": "twig/twig",
- "version": "v3.15.0",
+ "version": "v3.16.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
- "reference": "2d5b3964cc21d0188633d7ddce732dc8e874db02"
+ "reference": "475ad2dc97d65d8631393e721e7e44fb544f0561"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/2d5b3964cc21d0188633d7ddce732dc8e874db02",
- "reference": "2d5b3964cc21d0188633d7ddce732dc8e874db02",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/475ad2dc97d65d8631393e721e7e44fb544f0561",
+ "reference": "475ad2dc97d65d8631393e721e7e44fb544f0561",
"shasum": ""
},
"require": {
@@ -2977,6 +3059,7 @@
"symfony/polyfill-php81": "^1.29"
},
"require-dev": {
+ "phpstan/phpstan": "^2.0",
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
},
@@ -3020,7 +3103,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
- "source": "https://github.com/twigphp/Twig/tree/v3.15.0"
+ "source": "https://github.com/twigphp/Twig/tree/v3.16.0"
},
"funding": [
{
@@ -3032,7 +3115,7 @@
"type": "tidelift"
}
],
- "time": "2024-11-17T15:59:19+00:00"
+ "time": "2024-11-29T08:27:05+00:00"
},
{
"name": "vlucas/phpdotenv",
@@ -3120,16 +3203,16 @@
},
{
"name": "voku/portable-ascii",
- "version": "2.0.1",
+ "version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/voku/portable-ascii.git",
- "reference": "b56450eed252f6801410d810c8e1727224ae0743"
+ "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743",
- "reference": "b56450eed252f6801410d810c8e1727224ae0743",
+ "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
+ "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
"shasum": ""
},
"require": {
@@ -3154,7 +3237,7 @@
"authors": [
{
"name": "Lars Moelleken",
- "homepage": "http://www.moelleken.org/"
+ "homepage": "https://www.moelleken.org/"
}
],
"description": "Portable ASCII library - performance optimized (ascii) string functions for php.",
@@ -3166,7 +3249,7 @@
],
"support": {
"issues": "https://github.com/voku/portable-ascii/issues",
- "source": "https://github.com/voku/portable-ascii/tree/2.0.1"
+ "source": "https://github.com/voku/portable-ascii/tree/2.0.3"
},
"funding": [
{
@@ -3190,7 +3273,7 @@
"type": "tidelift"
}
],
- "time": "2022-03-08T17:03:00+00:00"
+ "time": "2024-11-21T01:49:47+00:00"
}
],
"packages-dev": [],
@@ -3205,5 +3288,5 @@
"ext-zip": "*"
},
"platform-dev": [],
- "plugin-api-version": "2.6.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/kernel/EntityRelation.php b/kernel/EntityRelation.php
new file mode 100644
index 0000000..6050f20
--- /dev/null
+++ b/kernel/EntityRelation.php
@@ -0,0 +1,279 @@
+moduleService = new ModuleService();
+ }
+
+
+ public static function getEntityList(): array
+ {
+ $list = [];
+ $moduleService = new ModuleService();
+ $activeModules = $moduleService->getActiveModules();
+ foreach ($activeModules as $module) {
+ if (isset($module['type']) and $module['type'] === "entity") {
+ $list[$module['slug']] = $module['slug'];
+ }
+ }
+
+ return $list;
+ }
+
+ public function getAdditionalPropertyList(): array
+ {
+ $list = [];
+ $activeModules = $this->moduleService->getActiveModules();
+ foreach ($activeModules as $module) {
+ if (isset($module['type']) and $module['type'] === "additional_property") {
+ $list[] = $module['slug'];
+ }
+ }
+
+ return $list;
+ }
+
+ public static function getEntitiesRelations(): array|bool
+ {
+ $entity_relations = OptionService::getItem("entity_relations");
+ if ($entity_relations) {
+ return json_decode($entity_relations, true);
+ }
+
+ return false;
+ }
+
+ public static function removePropertyFromEntityRelations(string $entity, string $property): bool
+ {
+ $entity_relations_info = Option::where("key", "entity_relations")->first();
+ if ($entity_relations_info) {
+ $entity_relations = json_decode($entity_relations_info->value, true);
+ if ($entity_relations[$entity]) {
+ $propertyKey = array_search($property, $entity_relations[$entity]);
+ if ($entity_relations[$entity][$propertyKey] === $property) {
+ unset($entity_relations[$entity][$propertyKey]);
+ $entity_relations[$entity] = array_values($entity_relations[$entity]);
+ if (empty($entity_relations[$entity])) {
+ unset($entity_relations[$entity]);
+ }
+ $entity_relations_info->value = json_encode($entity_relations, JSON_UNESCAPED_UNICODE);
+ $entity_relations_info->save();
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public static function removePropertyRelation(string $property): bool
+ {
+ $entity_relations_info = Option::where("key", "entity_relations")->first();
+ if ($entity_relations_info) {
+ $entity_relations = json_decode($entity_relations_info->value, true);
+ foreach ($entity_relations as $entity => $entity_relation) {
+ if (in_array($property, $entity_relation)) {
+ $index = array_search($property, $entity_relation);
+ unset($entity_relations[$entity][$index]);
+ }
+ }
+ $entity_relations_info->value = json_encode($entity_relations, JSON_UNESCAPED_UNICODE);
+ $entity_relations_info->save();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public static function removeEntityRelation(string $entity): bool
+ {
+ $entity_relations_info = Option::where("key", "entity_relations")->first();
+ if ($entity_relations_info) {
+ $entity_relations = json_decode($entity_relations_info->value, true);
+ if (isset($entity_relations[$entity])) {
+ unset($entity_relations[$entity]);
+ $entity_relations_info->value = json_encode($entity_relations, JSON_UNESCAPED_UNICODE);
+ $entity_relations_info->save();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function getEntityRelationsBySlug(string $slug)
+ {
+ $entityRelations = $this->getEntitiesRelations();
+ if ($entityRelations) {
+ if (isset($entityRelations[$slug])) {
+ return $entityRelations[$slug];
+ }
+ }
+
+ return [];
+ }
+
+ public static function addEntityRelation(string $entity, string $property): bool
+ {
+ $entity_relations_info = Option::where("key", "entity_relations")->first();
+ if ($entity_relations_info) {
+ $entity_relations = json_decode($entity_relations_info->value, true);
+ if (isset($entity_relations[$entity])) {
+ $entity_relations[$entity][] = $property;
+ } else {
+ $entity_relations[$entity][] = $property;
+ }
+ $entity_relations_info->value = json_encode($entity_relations, JSON_UNESCAPED_UNICODE);
+ $entity_relations_info->save();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public function getAdditionalPropertyClassBySlug(string $slug)
+ {
+ $module = $this->moduleService->getModuleInfoBySlug($slug);
+ if (isset($module['module_class'])) {
+ return new $module['module_class']();
+ }
+
+ return false;
+ }
+
+ public function renderFormInputsBySlug(string $entity, string $slug, Model $model): void
+ {
+ $moduleClass = $this->getAdditionalPropertyClassBySlug($slug);
+ if ($moduleClass and method_exists($moduleClass, "formInputs")) {
+ $moduleClass->formInputs($entity, $model);
+ }
+ }
+
+ public function renderEntityAdditionalPropertyFormBySlug(string $entity, Model $model = null): void
+ {
+ $relations = $this->getEntityRelationsBySlug($entity);
+ if ($relations) {
+ foreach ($relations as $relation) {
+ $this->renderFormInputsBySlug($entity, $relation, $model);
+ }
+ }
+ }
+
+ public function saveEntityRelationBySlug(string $slug, string $entity, Model $model, Request $request): void
+ {
+ $moduleClass = $this->getAdditionalPropertyClassBySlug($slug);
+ if ($moduleClass and method_exists($moduleClass, "saveInputs")) {
+ $moduleClass->saveInputs($entity, $model, $request);
+ }
+ }
+
+ public function saveEntityRelation(string $entity, Model $model, Request $request): void
+ {
+ $relations = $this->getEntityRelationsBySlug($entity);
+ if ($relations) {
+ foreach ($relations as $relation) {
+ $this->saveEntityRelationBySlug($relation, $entity, $model, $request);
+ }
+ }
+ }
+
+ public function getEntityAdditionalProperty(string $entity, Model $model): array
+ {
+ $relations = $this->getEntityRelationsBySlug($entity);
+ if ($relations) {
+ $relationsArr = [];
+ foreach ($relations as $relation) {
+ $moduleClass = $this->getAdditionalPropertyClassBySlug($relation);
+ if ($moduleClass and method_exists($moduleClass, "getItems")) {
+ $relationsArr[$relation] = $moduleClass->getItems($entity, $model);
+ }
+ }
+
+ return $relationsArr;
+ }
+
+ return [];
+ }
+
+ public function getAdditionalPropertyByEntityId(string $entity, string $entity_id, string $additionalPropertySlug): string
+ {
+ $moduleClass = $this->getAdditionalPropertyClassBySlug($additionalPropertySlug);
+ if ($moduleClass and method_exists($moduleClass, "getItem")) {
+ return $moduleClass->getItem($entity, $entity_id);
+ }
+
+ return "";
+ }
+
+ public function deleteEntityRelationBySlug(string $slug, string $entity, Model $model): void
+ {
+ $moduleClass = $this->getAdditionalPropertyClassBySlug($slug);
+ if ($moduleClass and method_exists($moduleClass, "deleteItems")) {
+ $moduleClass->deleteItems($entity, $model);
+ }
+ }
+
+ public function deleteEntityRelation(string $entity, Model $model): void
+ {
+ $relations = $this->getEntityRelationsBySlug($entity);
+ if ($relations) {
+ foreach ($relations as $relation) {
+ $this->deleteEntityRelationBySlug($relation, $entity, $model);
+ }
+ }
+ }
+
+ public static function getEntityByProperty(string $data): array
+ {
+ $entityRelations = self::getEntitiesRelations();
+ $entities = [];
+ foreach ($entityRelations as $entity => $property) {
+ if (in_array($data, $property)) {
+ $entities[] = $entity;
+ }
+ }
+
+ return $entities;
+ }
+
+ public static function configurationEntitiesByProperty(array|null $entities, string $property): void
+ {
+ $entityRelations = self::getEntitiesRelations();
+ if (isset($entities)) {
+ foreach ($entities as $entity) {
+ if (!isset($entityRelations[$entity])) {
+ EntityRelation::addEntityRelation($entity, $property);
+ }
+ }
+ foreach ($entityRelations as $entity => $additionalProperty) {
+ if (in_array($entity, $entities)) {
+ if (!in_array($property, $additionalProperty)) {
+ EntityRelation::addEntityRelation($entity, $property);
+ }
+ } else {
+ if (in_array($property, $additionalProperty)) {
+ EntityRelation::removePropertyFromEntityRelations($entity, $property);
+ }
+ }
+ }
+ } else {
+ foreach ($entityRelations as $entity => $additionalProperty) {
+ EntityRelation::removePropertyFromEntityRelations($entity, $property);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/kernel/FormModel.php b/kernel/FormModel.php
index 998d13b..92bc880 100644
--- a/kernel/FormModel.php
+++ b/kernel/FormModel.php
@@ -59,6 +59,16 @@ class FormModel
return false;
}
+ public function validateForUpdate(): bool
+ {
+ $res = $this->validator->validate($this->data, $this->rulesForUpdate());
+ if (!$res) {
+ return true;
+ }
+
+ return false;
+ }
+
public function getErrors(): array
{
return $this->validator->getProcessedErrors();
diff --git a/kernel/Mailing.php b/kernel/Mailing.php
new file mode 100644
index 0000000..05b341c
--- /dev/null
+++ b/kernel/Mailing.php
@@ -0,0 +1,50 @@
+cgView = new CgView();
+ $this->cgView->viewPath = KERNEL_DIR . "/views/mailing/";
+
+ $this->data = $data;
+
+ $this->SMTP = new SMTP();
+
+ $this->init();
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function send_html(string $tpl, array $tplParams, array $mailParams): ?false
+ {
+ $mailParams['body'] = $this->cgView->fetch($tpl, $tplParams);
+ return $this->SMTP->send_html($mailParams);
+ }
+
+ public function run()
+ {
+ }
+
+ public static function create(array $data = []): static
+ {
+ return new static($data);
+ }
+
+ protected function init()
+ {
+ }
+
+}
\ No newline at end of file
diff --git a/kernel/Widget.php b/kernel/Widget.php
index 3ecbad8..07a1327 100644
--- a/kernel/Widget.php
+++ b/kernel/Widget.php
@@ -11,7 +11,7 @@ class Widget
public function __construct(array $data = [])
{
$this->cgView = new CgView();
- $this->cgView->viewPath = ROOT_DIR . "/views/widgets";
+ $this->cgView->viewPath = KERNEL_DIR . "/views/widgets";
$this->data = $data;
diff --git a/kernel/admin_themes/simple/layout/main.php b/kernel/admin_themes/simple/layout/main.php
index c1f7972..217dd6c 100644
--- a/kernel/admin_themes/simple/layout/main.php
+++ b/kernel/admin_themes/simple/layout/main.php
@@ -13,7 +13,7 @@
-
+
diff --git a/kernel/console/controllers/AdminConsoleController.php b/kernel/console/controllers/AdminConsoleController.php
index 4b1bce3..0af6f7b 100644
--- a/kernel/console/controllers/AdminConsoleController.php
+++ b/kernel/console/controllers/AdminConsoleController.php
@@ -46,6 +46,9 @@ class AdminConsoleController extends ConsoleController
$out = $this->migrationService->runAtPath("kernel/modules/post/migrations");
$this->out->r("create post table", "green");
+ $out = $this->migrationService->runAtPath("kernel/modules/secure/migrations");
+ $this->out->r("create secret_code table", "green");
+
$this->optionService->createFromParams(
key: "admin_theme_paths",
value: "{\"paths\": [\"{KERNEL_ADMIN_THEMES}\", \"{APP}/admin_themes\"]}",
@@ -69,11 +72,18 @@ class AdminConsoleController extends ConsoleController
$this->optionService->createFromParams(
key: "active_modules",
- value: "{\"modules\":[\"admin_themes\", \"secure\", \"user\", \"menu\"]}",
+ value: "{\"modules\":[\"admin_themes\", \"secure\", \"user\", \"menu\", \"post\", \"option\"]}",
label: "Активные модули"
);
$this->out->r("create option active_modules", "green");
+ $this->optionService->createFromParams(
+ key: "entity_relations",
+ value: "{}",
+ label: "Свойства сущностей"
+ );
+ $this->out->r("create option entity_relations", "green");
+
$this->menuService->createItem([
"label" => "Модули",
"url" => "/admin",
@@ -101,6 +111,13 @@ class AdminConsoleController extends ConsoleController
]);
$this->out->r("create item menu user", "green");
+ $this->menuService->createItem([
+ "label" => "Посты",
+ "url" => "/admin/post",
+ "slug" => "post",
+ ]);
+ $this->out->r("create item menu post", "green");
+
$this->menuService->createItem([
"label" => "Настройки",
"url" => "#",
@@ -116,6 +133,21 @@ class AdminConsoleController extends ConsoleController
]);
$this->out->r("create item menu admin-themes", "green");
+ $this->menuService->createItem([
+ "label" => "Меню",
+ "url" => "/admin/settings/menu",
+ "slug" => "menu",
+ "parent_slug" => "settings"
+ ]);
+ $this->out->r("create item menu menu", "green");
+
+ $this->menuService->createItem([
+ "label" => "Опции",
+ "url" => "/admin/option",
+ "slug" => "option"
+ ]);
+ $this->out->r("create item menu option", "green");
+
$user = new CreateUserForm();
$user->load([
'username' => 'admin',
diff --git a/kernel/controllers/ModuleController.php b/kernel/controllers/ModuleController.php
index 3e2bb18..ea08cd4 100644
--- a/kernel/controllers/ModuleController.php
+++ b/kernel/controllers/ModuleController.php
@@ -6,6 +6,7 @@ use DirectoryIterator;
use JetBrains\PhpStorm\NoReturn;
use Josantonius\Session\Facades\Session;
use kernel\AdminController;
+use kernel\EntityRelation;
use kernel\helpers\Debug;
use kernel\models\Option;
use kernel\modules\module_shop_client\services\ModuleShopClientService;
diff --git a/kernel/helpers/Html.php b/kernel/helpers/Html.php
new file mode 100644
index 0000000..369290f
--- /dev/null
+++ b/kernel/helpers/Html.php
@@ -0,0 +1,42 @@
+";
+ }
+
+ public static function h(string|int $type = 1, string $title = '', array $params = [])
+ {
+ $paramsStr = self::createParams($params);
+ return "$title ";
+ }
+
+ public static function a(string $link, array $params = []): string
+ {
+ $paramsStr = self::createParams($params);
+ return "";
+ }
+
+ /**
+ * @param array $data
+ * @return string
+ */
+ public static function createParams(array $data = []): string
+ {
+ $paramsString = "";
+ foreach($data as $key => $param){
+ if(is_string($param)){
+ $paramsString .= $key . "='" . $param . "'";
+ }
+ }
+
+ return $paramsString;
+ }
+
+}
\ No newline at end of file
diff --git a/kernel/helpers/RESTClient.php b/kernel/helpers/RESTClient.php
index ecc3ede..c77cf1b 100644
--- a/kernel/helpers/RESTClient.php
+++ b/kernel/helpers/RESTClient.php
@@ -22,4 +22,31 @@ class RESTClient
]);
}
+ /**
+ * @throws GuzzleException
+ */
+ public static function request_without_auth(string $url, string $method = 'GET'): \Psr\Http\Message\ResponseInterface
+ {
+ $client = new \GuzzleHttp\Client();
+ return $client->request($method, $url);
+ }
+
+ /**
+ * @throws GuzzleException
+ */
+ public static function post(string $url, array $data = [], bool $auth = true): \Psr\Http\Message\ResponseInterface
+ {
+ $headers = [];
+ if ($auth){
+ $headers = [
+ 'Authorization' => 'Bearer ' . $_ENV['MODULE_SHOP_TOKEN']
+ ];
+ }
+ $client = new \GuzzleHttp\Client();
+ return $client->request("POST", $url, [
+ 'form_params' => $data,
+ 'headers' => $headers,
+ ]);
+ }
+
}
\ No newline at end of file
diff --git a/kernel/helpers/SMTP.php b/kernel/helpers/SMTP.php
new file mode 100644
index 0000000..0f6d5e6
--- /dev/null
+++ b/kernel/helpers/SMTP.php
@@ -0,0 +1,40 @@
+mail = new PHPMailer(true);
+ $this->mail->CharSet = 'UTF-8';
+ $this->mail->isSMTP();
+ $this->mail->SMTPAuth = true;
+ $this->mail->SMTPDebug = 0;
+ $this->mail->Host = $_ENV['MAIL_SMTP_HOST'];
+ $this->mail->Port = $_ENV['MAIL_SMTP_PORT'];
+ $this->mail->Username = $_ENV['MAIL_SMTP_USERNAME'];
+ $this->mail->Password = $_ENV['MAIL_SMTP_PASSWORD'];
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function send_html(array $params)
+ {
+ if (!isset($params['address'])){
+ return false;
+ }
+ $this->mail->setFrom($this->mail->Username, $params['from_name'] ?? $this->mail->Host);
+ $this->mail->addAddress($params['address']);
+ $this->mail->Subject = $params['subject'] ?? 'Без темы';
+ $body = $params['body'] ?? 'Нет информации';
+ $this->mail->msgHTML($body);
+
+ $this->mail->send();
+ }
+}
\ No newline at end of file
diff --git a/kernel/modules/admin_themes/views/index.php b/kernel/modules/admin_themes/views/index.php
index 50d728e..9a2ab7e 100644
--- a/kernel/modules/admin_themes/views/index.php
+++ b/kernel/modules/admin_themes/views/index.php
@@ -3,8 +3,6 @@
* @var $json string
*/
-use kernel\models\Option;
-
$table = new \Itguild\Tables\ListJsonTable($json);
$table->columns([
@@ -13,14 +11,15 @@ $table->columns([
}
]);
$table->addAction(function ($row, $url){
- $path = $row['path'];
$active_admin_theme = \kernel\modules\option\service\OptionService::getItem('active_admin_theme');
- $btn = " Активировать ";
- if ($path === $active_admin_theme){
- $btn = "Активна";
- }
- return $btn;
+ if ($row['path'] === $active_admin_theme){
+ return "Активна";
+ } else {
+ $url = "$url/activate/?p=" . $row['path'];
+
+ return \kernel\widgets\IconBtn\IconBtnActivateWidget::create(['url' => $url])->run();
+ }
});
$table->create();
$table->render();
\ No newline at end of file
diff --git a/kernel/modules/admin_themes/views/view.php b/kernel/modules/admin_themes/views/view.php
index 2f535b2..e6e0c3e 100644
--- a/kernel/modules/admin_themes/views/view.php
+++ b/kernel/modules/admin_themes/views/view.php
@@ -23,8 +23,7 @@ $table->rows([
}
]);
$table->beforePrint(function () {
- $btn = PrimaryBtn::create("Список", "/admin/settings/admin-themes")->fetch();
- return $btn;
+ return \kernel\widgets\IconBtn\IconBtnListWidget::create(['url' => '/admin/settings/admin-themes'])->run();
});
$table->create();
$table->render();
\ No newline at end of file
diff --git a/kernel/modules/menu/views/index.php b/kernel/modules/menu/views/index.php
index 4f445df..0cad83d 100644
--- a/kernel/modules/menu/views/index.php
+++ b/kernel/modules/menu/views/index.php
@@ -6,11 +6,11 @@
use Itguild\EloquentTable\EloquentDataProvider;
use Itguild\EloquentTable\ListEloquentTable;
-use kernel\IGTabel\action_column\DeleteActionColumn;
-use kernel\IGTabel\action_column\EditActionColumn;
-use kernel\IGTabel\action_column\ViewActionColumn;
-use kernel\IGTabel\btn\PrimaryBtn;
use kernel\models\Menu;
+use kernel\widgets\IconBtn\IconBtnCreateWidget;
+use kernel\widgets\IconBtn\IconBtnDeleteWidget;
+use kernel\widgets\IconBtn\IconBtnEditWidget;
+use kernel\widgets\IconBtn\IconBtnViewWidget;
$table = new ListEloquentTable(new EloquentDataProvider(Menu::class, [
'currentPage' => $page_number,
@@ -23,13 +23,22 @@ $table->columns([
if ($data == 0) return null;
return Menu::find($data)->label;
}),
+ 'icon_file' => function ($data) {
+ return $data ? " " : "";
+ }
]);
$table->beforePrint(function () {
- return PrimaryBtn::create("Создать", "/admin/settings/menu/create")->fetch();
- //return (new PrimaryBtn("Создать", "/admin/user/create"))->fetch();
+ return IconBtnCreateWidget::create(['url' => '/admin/settings/menu/create'])->run();
+});
+
+$table->addAction(function($row) {
+ return IconBtnViewWidget::create(['url' => '/admin/settings/menu/view/' . $row['id']])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnEditWidget::create(['url' => '/admin/settings/menu/update/' . $row['id']])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnDeleteWidget::create(['url' => '/admin/settings/menu/delete/' . $row['id']])->run();
});
-$table->addAction(ViewActionColumn::class);
-$table->addAction(EditActionColumn::class);
-$table->addAction(DeleteActionColumn::class);
$table->create();
$table->render();
\ No newline at end of file
diff --git a/kernel/modules/menu/views/view.php b/kernel/modules/menu/views/view.php
index 5e73c57..ecd3104 100644
--- a/kernel/modules/menu/views/view.php
+++ b/kernel/modules/menu/views/view.php
@@ -6,10 +6,10 @@
use Itguild\EloquentTable\ViewEloquentTable;
use Itguild\EloquentTable\ViewJsonTableEloquentModel;
-use kernel\IGTabel\btn\DangerBtn;
-use kernel\IGTabel\btn\PrimaryBtn;
-use kernel\IGTabel\btn\SuccessBtn;
use kernel\models\Menu;
+use kernel\widgets\IconBtn\IconBtnDeleteWidget;
+use kernel\widgets\IconBtn\IconBtnEditWidget;
+use kernel\widgets\IconBtn\IconBtnListWidget;
$table = new ViewEloquentTable(new ViewJsonTableEloquentModel($menu, [
'params' => ["class" => "table table-bordered", "border" => "2"],
@@ -17,16 +17,19 @@ $table = new ViewEloquentTable(new ViewJsonTableEloquentModel($menu, [
]));
$table->beforePrint(function () use ($menu) {
- $btn = PrimaryBtn::create("Список", "/admin/settings/menu")->fetch();
- $btn .= SuccessBtn::create("Редактировать", "/admin/settings/menu/update/" . $menu->id)->fetch();
- $btn .= DangerBtn::create("Удалить", "/admin/settings/menu/delete/" . $menu->id)->fetch();
+ $btn = IconBtnListWidget::create(['url' => '/admin/settings/menu'])->run();
+ $btn .= IconBtnEditWidget::create(['url' => '/admin/settings/menu/update/' . $menu->id])->run();
+ $btn .= IconBtnDeleteWidget::create(['url' => '/admin/settings/menu/delete/' . $menu->id])->run();
return $btn;
});
$table->rows([
'parent_id' => (function ($data) {
if ($data == 0) return null;
return Menu::find($data)->label;
- })
+ }),
+ 'icon_file' => function ($data) {
+ return $data ? " " : "";
+ }
]);
$table->create();
$table->render();
\ No newline at end of file
diff --git a/kernel/modules/module_shop_client/controllers/ModuleShopClientController.php b/kernel/modules/module_shop_client/controllers/ModuleShopClientController.php
index 6e7846b..a83f465 100644
--- a/kernel/modules/module_shop_client/controllers/ModuleShopClientController.php
+++ b/kernel/modules/module_shop_client/controllers/ModuleShopClientController.php
@@ -10,9 +10,14 @@ use kernel\Flash;
use kernel\helpers\Debug;
use kernel\helpers\Files;
use kernel\helpers\RESTClient;
+use kernel\helpers\SMTP;
+use kernel\Mailing;
use kernel\modules\module_shop_client\services\ModuleShopClientService;
use kernel\Request;
use kernel\services\ModuleService;
+use kernel\services\ModuleShopService;
+use kernel\services\TokenService;
+use PHPMailer\PHPMailer\Exception;
class ModuleShopClientController extends AdminController
{
@@ -34,18 +39,30 @@ class ModuleShopClientController extends AdminController
*/
public function actionIndex(int $page_number = 1): void
{
- $per_page = 8;
- $modules_info = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
- $modules_info = json_decode($modules_info->getBody()->getContents(), true);
- $module_count = count($modules_info);
- $modules_info = array_slice($modules_info, $per_page*($page_number-1), $per_page);
- $this->cgView->render("index.php", [
- 'modules_info' => $modules_info,
- 'moduleService' => $this->moduleService,
- 'page_number' => $page_number,
- 'module_count' => $module_count,
- 'per_page' => $per_page,
- ]);
+
+ if ($this->moduleService->issetModuleShopToken()) {
+ if ($this->moduleService->isServerAvailable()) {
+
+ $per_page = 8;
+ $modules_info = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
+ $modules_info = json_decode($modules_info->getBody()->getContents(), true);
+ $module_count = count($modules_info);
+ $modules_info = array_slice($modules_info, $per_page * ($page_number - 1), $per_page);
+
+ $this->cgView->render("index.php", [
+ 'modules_info' => $modules_info,
+ 'moduleService' => $this->moduleService,
+ 'page_number' => $page_number,
+ 'module_count' => $module_count,
+ 'per_page' => $per_page,
+ ]);
+ } else {
+ $this->cgView->render("module_shop_error_connection.php");
+ }
+
+ } else {
+ $this->cgView->render("login_at_module_shop.php");
+ }
}
public function actionView(int $id): void
@@ -106,4 +123,58 @@ class ModuleShopClientController extends AdminController
$this->redirect('/admin/module_shop_client', 302);
}
+ /**
+ * @throws Exception
+ */
+ public function actionAuth(): void
+ {
+ $request = new Request();
+ $address = $request->post("email");
+
+// $mailing = new Mailing();
+// $mailing->send_html("login_by_code.php", ['code' => mt_rand(100000, 999999)], [
+// 'address' => $address,
+// 'subject' => "Код авторизации",
+// "from_name" => $_ENV['APP_NAME']
+// ]);
+
+ $moduleShopService = new ModuleShopService();
+ $result = $moduleShopService->email_auth($address);
+
+ if ($result['status'] == 'success'){
+ $this->cgView->render('enter_code.php', ['email' => $address]);
+ }
+
+ $this->cgView->render('module_shop_error_connection.php', ['email' => $address]);
+ }
+
+ public function actionCodeCheck(): void
+ {
+ $request = new Request();
+ $code = $request->post("code");
+
+// $mailing = new Mailing();
+// $mailing->send_html("login_by_code.php", ['code' => mt_rand(100000, 999999)], [
+// 'address' => $address,
+// 'subject' => "Код авторизации",
+// "from_name" => $_ENV['APP_NAME']
+// ]);
+
+ $moduleShopService = new ModuleShopService();
+ $result = $moduleShopService->code_check($code);
+
+ if (isset($result['access_token'])){
+
+ $envFile = \EnvEditor\EnvFile::loadFrom(ROOT_DIR . "/.env");
+
+ $envFile->setValue("MODULE_SHOP_TOKEN", $result['access_token']);
+
+ $envFile->saveTo(ROOT_DIR . "/.env");
+
+ $this->cgView->render('success_login.php');
+ }
+
+ $this->cgView->render('module_shop_error_connection.php');
+ }
+
}
\ No newline at end of file
diff --git a/kernel/modules/module_shop_client/routs/module_shop_client.php b/kernel/modules/module_shop_client/routs/module_shop_client.php
index 416831c..5004486 100644
--- a/kernel/modules/module_shop_client/routs/module_shop_client.php
+++ b/kernel/modules/module_shop_client/routs/module_shop_client.php
@@ -15,6 +15,8 @@ App::$collector->group(["prefix" => "admin"], function (RouteCollector $router){
App::$collector->get('/view/{id}', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionView']);
App::$collector->get('/delete', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionDelete']);
App::$collector->get('/update', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionUpdate']);
+ App::$collector->post('/auth', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionAuth']);
+ App::$collector->post('/code_check', [\kernel\modules\module_shop_client\controllers\ModuleShopClientController::class, 'actionCodeCheck']);
});
});
});
\ No newline at end of file
diff --git a/kernel/modules/module_shop_client/views/enter_code.php b/kernel/modules/module_shop_client/views/enter_code.php
new file mode 100644
index 0000000..7befe28
--- /dev/null
+++ b/kernel/modules/module_shop_client/views/enter_code.php
@@ -0,0 +1,36 @@
+run();
+
+echo \kernel\helpers\Html::h(2, "Введите код подтверждения отправленный на почту \"$email\"");
+
+$form = new ActiveForm();
+$form->beginForm("/admin/module_shop_client/code_check/");
+
+$form->field(\itguild\forms\inputs\TextInput::class, 'code', [
+ 'class' => "form-control",
+ 'placeholder' => 'Код',
+])
+ ->setLabel("Код")
+ ->render();
+?>
+
+
+
+ field(\itguild\forms\inputs\Button::class, name: "btn-submit", params: [
+ 'class' => "btn btn-primary ",
+ 'value' => 'Отправить',
+ 'typeInput' => 'submit'
+ ])
+ ->render();
+ ?>
+
+
+
+endForm();
\ No newline at end of file
diff --git a/kernel/modules/module_shop_client/views/index.php b/kernel/modules/module_shop_client/views/index.php
index ab0199c..bfe766d 100644
--- a/kernel/modules/module_shop_client/views/index.php
+++ b/kernel/modules/module_shop_client/views/index.php
@@ -8,6 +8,7 @@
*/
use Itguild\Tables\ListJsonTable;
+use kernel\widgets\ActionButtonWidget;
$meta = [];
$meta['columns'] = [
@@ -29,40 +30,39 @@ $info_to_table['data'] = $modules_info;
$table = new ListJsonTable(json_encode($info_to_table, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
-$table->addAction(\kernel\IGTabel\action_column\ViewActionColumn::class);
+$table->addAction(function ($row, $url) use ($moduleService) {
+ $url = "$url/view/" . $row['id'];
+
+ return \kernel\widgets\IconBtn\IconBtnViewWidget::create(['url' => $url])->run();
+});
$table->addAction(function ($row, $url) use ($moduleService){
- $slug = $row['slug'];
- $id = $row['id'];
- if ($moduleService->isInstall($slug)){
- $label = "Удалить";
- $btn_type = "danger";
- $btn = "$label ";
+ if ($moduleService->isInstall($row['slug'])){
+ $url = "$url/delete/?slug=" . $row['slug'];
+
+ return \kernel\widgets\IconBtn\IconBtnDeleteWidget::create(['url' => $url])->run();
}
else {
- $label = "Установить";
- $btn_type = "success";
- $btn = "$label ";
- }
+ $url = "$url/install/?id=" . $row['id'];
- return $btn;
+ return \kernel\widgets\IconBtn\IconBtnInstallWidget::create(['url' => $url])->run();
+ }
});
$table->addAction(function ($row, $url) use ($moduleService){
$slug = $row['slug'];
if ($moduleService->isInstall($slug)){
if (!$moduleService->isLastVersion($slug)) {
- $label = "Обновить";
- $btn_type = "info";
- return "$label ";
+ $url = "$url/update/?slug=" . $slug;
+
+ return \kernel\widgets\IconBtn\IconBtnUpdateWidget::create(['url' => $url])->run();
}
}
return false;
});
+\kernel\widgets\ModuleTabsWidget::create()->run();
$table->create();
-
-\kernel\widgets\ModuleTabsWidget::create()->run();
$table->render();
diff --git a/kernel/modules/module_shop_client/views/login_at_module_shop.php b/kernel/modules/module_shop_client/views/login_at_module_shop.php
new file mode 100644
index 0000000..b635740
--- /dev/null
+++ b/kernel/modules/module_shop_client/views/login_at_module_shop.php
@@ -0,0 +1,34 @@
+run();
+
+echo \kernel\helpers\Html::h(2, "Форма авторизации/регистрации");
+
+$form = new ActiveForm();
+$form->beginForm("/admin/module_shop_client/auth/");
+
+$form->field(\itguild\forms\inputs\TextInput::class, 'email', [
+ 'class' => "form-control",
+ 'placeholder' => 'Email',
+])
+ ->setLabel("Email")
+ ->render();
+?>
+
+
+
+ field(\itguild\forms\inputs\Button::class, name: "btn-submit", params: [
+ 'class' => "btn btn-primary ",
+ 'value' => 'Отправить',
+ 'typeInput' => 'submit'
+ ])
+ ->render();
+ ?>
+
+
+
+endForm();
\ No newline at end of file
diff --git a/kernel/modules/module_shop_client/views/module_shop_error_connection.php b/kernel/modules/module_shop_client/views/module_shop_error_connection.php
new file mode 100644
index 0000000..bf31edd
--- /dev/null
+++ b/kernel/modules/module_shop_client/views/module_shop_error_connection.php
@@ -0,0 +1,6 @@
+run();
+?>
+
+Ошибка подключения к сервису
+
diff --git a/kernel/modules/module_shop_client/views/success_login.php b/kernel/modules/module_shop_client/views/success_login.php
new file mode 100644
index 0000000..927f680
--- /dev/null
+++ b/kernel/modules/module_shop_client/views/success_login.php
@@ -0,0 +1,9 @@
+run();
+
+echo \kernel\helpers\Html::h(2, "Авторизация прошла успешно");
+echo \kernel\helpers\Html::a("/admin", ['class' => 'btm btm-primary']);
+
diff --git a/kernel/modules/module_shop_client/views/view.php b/kernel/modules/module_shop_client/views/view.php
index 05bcc51..6cd40ec 100644
--- a/kernel/modules/module_shop_client/views/view.php
+++ b/kernel/modules/module_shop_client/views/view.php
@@ -25,8 +25,7 @@ $table_info = [
$table = new \Itguild\Tables\ViewJsonTable(json_encode($table_info, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
$table->beforePrint(function () {
- $btn = PrimaryBtn::create("Список", "/admin/module_shop_client")->fetch();
- return $btn;
+ return \kernel\widgets\IconBtn\IconBtnListWidget::create(['url' => '/admin/module_shop_client'])->run();
});
$table->create();
$table->render();
\ No newline at end of file
diff --git a/kernel/modules/option/service/OptionService.php b/kernel/modules/option/service/OptionService.php
index 139d0fb..15eb5a5 100644
--- a/kernel/modules/option/service/OptionService.php
+++ b/kernel/modules/option/service/OptionService.php
@@ -35,7 +35,7 @@ class OptionService
return false;
}
- public function createFromParams(string $key, string $value, string $label): false|Option
+ public static function createFromParams(string $key, string $value, string $label): false|Option
{
$model = new Option();
$model->key = $key;
@@ -63,6 +63,17 @@ class OptionService
return false;
}
+ public static function removeOptionByKey(string $key): bool
+ {
+ $option = Option::where("key", $key)->first();
+ if (!$option){
+ return false;
+ }
+
+ $option->delete();
+ return true;
+ }
+
// public function createOptionArr(): array
// {
// foreach (Option::all()->toArray() as $option) {
diff --git a/kernel/modules/option/views/index.php b/kernel/modules/option/views/index.php
index 00ad1fc..2523f35 100644
--- a/kernel/modules/option/views/index.php
+++ b/kernel/modules/option/views/index.php
@@ -11,6 +11,10 @@ use kernel\IGTabel\action_column\EditActionColumn;
use kernel\IGTabel\action_column\ViewActionColumn;
use kernel\IGTabel\btn\PrimaryBtn;
use kernel\modules\option\models\Option;
+use kernel\widgets\IconBtn\IconBtnCreateWidget;
+use kernel\widgets\IconBtn\IconBtnDeleteWidget;
+use kernel\widgets\IconBtn\IconBtnEditWidget;
+use kernel\widgets\IconBtn\IconBtnViewWidget;
$table = new ListEloquentTable(new EloquentDataProvider(Option::class, [
'current_page' => $page_number,
@@ -20,8 +24,7 @@ $table = new ListEloquentTable(new EloquentDataProvider(Option::class, [
]));
$table->beforePrint(function () {
- return PrimaryBtn::create("Создать", "/admin/option/create")->fetch();
- //return (new PrimaryBtn("Создать", "/admin/user/create"))->fetch();
+ return IconBtnCreateWidget::create(['url' => '/admin/option/create'])->run();
});
$table->columns([
@@ -31,8 +34,15 @@ $table->columns([
}]
]);
-$table->addAction(ViewActionColumn::class);
-$table->addAction(EditActionColumn::class);
-$table->addAction(DeleteActionColumn::class);
+$table->addAction(function($row) {
+ return IconBtnViewWidget::create(['url' => '/admin/option/view/' . $row['id']])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnEditWidget::create(['url' => '/admin/option/update/' . $row['id']])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnDeleteWidget::create(['url' => '/admin/option/delete/' . $row['id']])->run();
+});
+
$table->create();
$table->render();
\ No newline at end of file
diff --git a/kernel/modules/option/views/view.php b/kernel/modules/option/views/view.php
index b0e77b0..c9ee06e 100644
--- a/kernel/modules/option/views/view.php
+++ b/kernel/modules/option/views/view.php
@@ -8,15 +8,18 @@ use Itguild\EloquentTable\ViewJsonTableEloquentModel;
use kernel\IGTabel\btn\DangerBtn;
use kernel\IGTabel\btn\PrimaryBtn;
use kernel\IGTabel\btn\SuccessBtn;
+use kernel\widgets\IconBtn\IconBtnDeleteWidget;
+use kernel\widgets\IconBtn\IconBtnEditWidget;
+use kernel\widgets\IconBtn\IconBtnListWidget;
$table = new ViewEloquentTable(new ViewJsonTableEloquentModel($option, [
'params' => ["class" => "table table-bordered", "border" => "2"],
'baseUrl' => "/admin/user",
]));
$table->beforePrint(function () use ($option) {
- $btn = PrimaryBtn::create("Список", "/admin/option")->fetch();
- $btn .= SuccessBtn::create("Редактировать", "/admin/option/update/" . $option->id)->fetch();
- $btn .= DangerBtn::create("Удалить", "/admin/option/delete/" . $option->id)->fetch();
+ $btn = IconBtnListWidget::create(['url' => '/admin/option'])->run();
+ $btn .= IconBtnEditWidget::create(['url' => '/admin/option/update/' . $option->id])->run();
+ $btn .= IconBtnDeleteWidget::create(['url' => '/admin/option/delete/' . $option->id])->run();
return $btn;
});
diff --git a/kernel/modules/post/controllers/PostController.php b/kernel/modules/post/controllers/PostController.php
index ccd0d44..eef11f3 100644
--- a/kernel/modules/post/controllers/PostController.php
+++ b/kernel/modules/post/controllers/PostController.php
@@ -6,9 +6,12 @@ namespace kernel\modules\post\controllers;
use Exception;
use JetBrains\PhpStorm\NoReturn;
use kernel\AdminController;
+use kernel\EntityRelation;
+use kernel\helpers\Debug;
use kernel\modules\post\models\forms\CreatePostForm;
use kernel\modules\post\models\Post;
use kernel\modules\post\service\PostService;
+use kernel\Request;
class PostController extends AdminController
{
@@ -31,6 +34,10 @@ class PostController extends AdminController
$postForm->load($_REQUEST);
if ($postForm->validate()) {
$post = $this->postService->create($postForm);
+
+ $entityRelation = new EntityRelation();
+ $entityRelation->saveEntityRelation(entity: "post", model: $post, request: new Request());
+
if ($post) {
$this->redirect("/admin/post/view/" . $post->id);
}
@@ -86,6 +93,10 @@ class PostController extends AdminController
$postForm->load($_REQUEST);
if ($postForm->validate()) {
$post = $this->postService->update($postForm, $post);
+
+ $entityRelation = new EntityRelation();
+ $entityRelation->saveEntityRelation(entity: "post", model: $post, request: new Request());
+
if ($post) {
$this->redirect("/admin/post/view/" . $post->id);
}
@@ -102,6 +113,10 @@ class PostController extends AdminController
if (!$post){
throw new Exception(message: "The post not found");
}
+
+ $entityRelation = new EntityRelation();
+ $entityRelation->deleteEntityRelation(entity: "post", model: $post);
+
$post->delete();
$this->redirect("/admin/post/");
}
diff --git a/kernel/modules/post/manifest.json b/kernel/modules/post/manifest.json
index 7ff222b..35d04c9 100644
--- a/kernel/modules/post/manifest.json
+++ b/kernel/modules/post/manifest.json
@@ -3,6 +3,7 @@
"version": "0.2",
"author": "ITGuild",
"slug": "post",
+ "type": "entity",
"description": "Post module",
"module_class": "kernel\\modules\\post\\PostModule",
"module_class_file": "{KERNEL_MODULES}/post/PostModule.php",
diff --git a/kernel/modules/post/views/form.php b/kernel/modules/post/views/form.php
index ed898ea..39648da 100644
--- a/kernel/modules/post/views/form.php
+++ b/kernel/modules/post/views/form.php
@@ -6,7 +6,7 @@
use kernel\modules\post\models\Post;
$form = new \itguild\forms\ActiveForm();
-$form->beginForm(isset($model) ? "/admin/post/edit/" . $model->id : "/admin/post");
+$form->beginForm(isset($model) ? "/admin/post/edit/" . $model->id : "/admin/post", 'multipart/form-data');
$form->field(\itguild\forms\inputs\TextInput::class, 'title', [
'class' => "form-control",
@@ -33,6 +33,12 @@ $form->field(class: \itguild\forms\inputs\Select::class, name: "user_id", params
->setOptions(\kernel\modules\user\service\UserService::createUsernameArr())
->render();
+$entityRelations = new \kernel\EntityRelation();
+if (!isset($model)) {
+ $model = new Post();
+}
+$entityRelations->renderEntityAdditionalPropertyFormBySlug("post", $model);
+
?>
diff --git a/kernel/modules/post/views/index.php b/kernel/modules/post/views/index.php
index 26eb926..d82ecb5 100644
--- a/kernel/modules/post/views/index.php
+++ b/kernel/modules/post/views/index.php
@@ -13,6 +13,10 @@ use kernel\modules\user\models\User;
use Itguild\EloquentTable\EloquentDataProvider;
use Itguild\EloquentTable\ListEloquentTable;
use kernel\IGTabel\btn\PrimaryBtn;
+use kernel\widgets\IconBtn\IconBtnCreateWidget;
+use kernel\widgets\IconBtn\IconBtnDeleteWidget;
+use kernel\widgets\IconBtn\IconBtnEditWidget;
+use kernel\widgets\IconBtn\IconBtnViewWidget;
$table = new ListEloquentTable(new EloquentDataProvider(Post::class, [
'currentPage' => $page_number,
@@ -20,6 +24,16 @@ $table = new ListEloquentTable(new EloquentDataProvider(Post::class, [
'params' => ["class" => "table table-bordered", "border" => "2"],
'baseUrl' => "/admin/post"
]));
+
+$entityRelation = new \kernel\EntityRelation();
+$additionals = $entityRelation->getEntityRelationsBySlug("post");
+
+foreach ($additionals as $additional) {
+ $table->addColumn($additional, $additional, function ($id) use ($entityRelation, $additional) {
+ return $entityRelation->getAdditionalPropertyByEntityId("post", $id, $additional);
+ });
+}
+
$table->columns([
'created_at' => function ($data) {
if (!$data){
@@ -39,12 +53,18 @@ $table->columns([
return User::find($data)->username;
})
]);
+
$table->beforePrint(function () {
- return PrimaryBtn::create("Создать", "/admin/post/create")->fetch();
- //return (new PrimaryBtn("Создать", "/admin/user/create"))->fetch();
+ return IconBtnCreateWidget::create(['url' => '/admin/post/create'])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnViewWidget::create(['url' => '/admin/post/view/' . $row['id']])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnEditWidget::create(['url' => '/admin/post/update/' . $row['id']])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnDeleteWidget::create(['url' => '/admin/post/delete/' . $row['id']])->run();
});
-$table->addAction(ViewActionColumn::class);
-$table->addAction(EditActionColumn::class);
-$table->addAction(DeleteActionColumn::class);
$table->create();
$table->render();
\ No newline at end of file
diff --git a/kernel/modules/post/views/view.php b/kernel/modules/post/views/view.php
index 13837b1..e3693d1 100644
--- a/kernel/modules/post/views/view.php
+++ b/kernel/modules/post/views/view.php
@@ -10,26 +10,39 @@ use Itguild\EloquentTable\ViewJsonTableEloquentModel;
use kernel\IGTabel\btn\DangerBtn;
use kernel\IGTabel\btn\PrimaryBtn;
use kernel\IGTabel\btn\SuccessBtn;
+use kernel\widgets\IconBtn\IconBtnDeleteWidget;
+use kernel\widgets\IconBtn\IconBtnEditWidget;
+use kernel\widgets\IconBtn\IconBtnListWidget;
$table = new ViewEloquentTable(new ViewJsonTableEloquentModel($content, [
'params' => ["class" => "table table-bordered", "border" => "2"],
'baseUrl' => "/admin/post",
]));
$table->beforePrint(function () use ($content) {
- $btn = PrimaryBtn::create("Список", "/admin/post")->fetch();
- $btn .= SuccessBtn::create("Редактировать", "/admin/post/update/" . $content->id)->fetch();
- $btn .= DangerBtn::create("Удалить", "/admin/post/delete/" . $content->id)->fetch();
+ $btn = IconBtnListWidget::create(['url' => '/admin/post'])->run();
+ $btn .= IconBtnEditWidget::create(['url' => '/admin/post/update/' . $content->id])->run();
+ $btn .= IconBtnDeleteWidget::create(['url' => '/admin/post/delete/' . $content->id])->run();
return $btn;
});
+
+$entityRelation = new \kernel\EntityRelation();
+$additionals = $entityRelation->getEntityAdditionalProperty("post", $content);
+
+foreach ($additionals as $key => $additional) {
+ $table->addRow($key, function () use ($additional) {
+ return $additional;
+ }, ['after' => 'user_id']);
+}
+
$table->rows([
'created_at' => function ($data) {
- if (!$data){
+ if (!$data) {
return null;
}
return (new DateTimeImmutable($data))->format("d-m-Y");
},
'updated_at' => function ($data) {
- if (!$data){
+ if (!$data) {
return null;
}
return (new DateTimeImmutable($data))->format("d-m-Y");
diff --git a/kernel/modules/secure/controllers/SecureController.php b/kernel/modules/secure/controllers/SecureController.php
index 5eac006..8498c77 100644
--- a/kernel/modules/secure/controllers/SecureController.php
+++ b/kernel/modules/secure/controllers/SecureController.php
@@ -4,10 +4,19 @@ namespace kernel\modules\secure\controllers;
use JetBrains\PhpStorm\NoReturn;
use kernel\AdminController;
+use kernel\App;
use kernel\Flash;
use kernel\helpers\Debug;
+use kernel\Mailing;
+use kernel\modules\secure\models\forms\LoginEmailForm;
use kernel\modules\secure\models\forms\LoginForm;
+use kernel\modules\secure\models\forms\RegisterForm;
+use kernel\modules\secure\services\SecureService;
+use kernel\modules\user\models\User;
use kernel\modules\user\service\UserService;
+use kernel\Request;
+use PHPMailer\PHPMailer\Exception;
+use Random\RandomException;
class SecureController extends AdminController
{
@@ -16,7 +25,6 @@ class SecureController extends AdminController
protected function init(): void
{
parent::init();
-// $this->cgView->viewPath = KERNEL_DIR . "/views/secure/";
$this->cgView->viewPath = KERNEL_MODULES_DIR. "/secure/views/";
$this->cgView->layout = "/login.php";
$this->userService = new UserService();
@@ -24,7 +32,12 @@ class SecureController extends AdminController
public function actionLogin(): void
{
- $this->cgView->render('login.php');
+ $this->cgView->render(match (App::$secure['web_auth_type']) {
+ "login_password" => "login.php",
+ "email_code" => "email_login.php",
+ });
+
+// $this->cgView->render('login.php');
}
#[NoReturn] public function actionAuth(): void
@@ -44,8 +57,9 @@ class SecureController extends AdminController
Flash::setMessage("error", "User not found.");
$this->redirect("/admin/login", code: 302);
}
+
if (password_verify($loginForm->getItem("password"), $user->password_hash)) {
- setcookie('user_id', $user->id, time()+60*60*24, '/', $_SERVER['HTTP_HOST'], false);
+ setcookie('user_id', $user->id, time()+60*60*24, '/', $_SERVER['SERVER_NAME'], false);
$this->redirect("/admin", code: 302);
} else {
Flash::setMessage("error", "Username or password incorrect.");
@@ -53,11 +67,107 @@ class SecureController extends AdminController
}
}
+ /**
+ * @throws RandomException
+ * @throws Exception
+ */
+ public function actionEmailAuth(): void
+ {
+ $mailing = new Mailing();
+
+ $loginForm = new LoginEmailForm();
+ $loginForm->load($_REQUEST);
+
+ $email = $loginForm->getItem("email");
+ $user = $this->userService->getByField('email', $email);
+
+ if (!$user){
+ $password = bin2hex(random_bytes(8));
+
+ UserService::createUserByEmailAndPassword($email, $password);
+ $user = $this->userService->getByField('email', $email);
+
+ SecureService::createSecretCode($user);
+ $secretCode = SecureService::getByField("user_id", $user->id);
+
+
+ $mailing->send_html("register_by_code.php", ['code' => $secretCode->code, 'password' => $password], [
+ 'address' => $email,
+ 'subject' => "Код регистрации",
+ "from_name" => $_ENV['APP_NAME']
+ ]);
+ } else {
+ SecureService::updateSecretCode($user);
+ $secretCode = SecureService::getByField("user_id", $user->id);
+ $mailing->send_html("login_by_code.php", ['code' => $secretCode->code], [
+ 'address' => $email,
+ 'subject' => "Код авторизации",
+ "from_name" => $_ENV['APP_NAME']
+ ]);
+ }
+
+ setcookie('user_email', $email, time()+60*15, '/', $_SERVER['SERVER_NAME'], false);
+ $this->cgView->render("enter_code.php", ['email' => $email]);
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function actionCodeCheck(): void
+ {
+ $request = new Request();
+
+ if (isset($_COOKIE['user_email'])) {
+ $user = User::where('email', $_COOKIE["user_email"])->first();
+ if (!$user) {
+ throw new exception("User not found.");
+ }
+ $code = $request->post("code");
+ $secretCode = SecureService::getByField("user_id", $user->id);
+ if ($secretCode->code == $code && time() <= strtotime($secretCode->code_expires_at)) {
+ setcookie('user_id', $user->id, time() + 60 * 60 * 24, '/', $_SERVER['SERVER_NAME'], false);
+ $this->redirect("/admin", code: 302);
+ } else {
+ Flash::setMessage("error", "Wrong code.");
+ $this->cgView->render("enter_code.php", ['email' => $_COOKIE["user_email"]]);
+ }
+
+ }
+ }
+
#[NoReturn] public function actionLogout(): void
{
unset($_COOKIE['user_id']);
setcookie('user_id', "", -1, '/', ".".$_SERVER['SERVER_NAME'], false);
+ setcookie('user_email', "", -1, '/', ".".$_SERVER['SERVER_NAME'], false);
$this->redirect("/", code: 302);
}
+ public function actionRegister(): void
+ {
+ $this->cgView->render('register.php');
+ }
+
+ public function actionRegistration(): void
+ {
+ $regForm = new RegisterForm();
+ $regForm->load($_REQUEST);
+
+ if ($this->userService->getByField('username', $regForm->getItem("username"))) {
+ Flash::setMessage("error", "Username already exists.");
+ $this->redirect("/admin/register", code: 302);
+ }
+
+ if ($this->userService->getByField('email', $regForm->getItem("email"))) {
+ Flash::setMessage("error", "Email already exists.");
+ $this->redirect("/admin/register", code: 302);
+ }
+
+ $user = $this->userService->create($regForm);
+ if ($user){
+ setcookie('user_id', $user->id, time()+60*60*24, '/', $_SERVER['SERVER_NAME'], false);
+ $this->redirect("/admin", code: 302);
+ }
+ }
+
}
\ No newline at end of file
diff --git a/kernel/modules/secure/controllers/SecureRestController.php b/kernel/modules/secure/controllers/SecureRestController.php
index 42ede4a..7e82699 100644
--- a/kernel/modules/secure/controllers/SecureRestController.php
+++ b/kernel/modules/secure/controllers/SecureRestController.php
@@ -7,10 +7,15 @@ use Firebase\JWT\Key;
use JetBrains\PhpStorm\NoReturn;
use kernel\App;
use kernel\helpers\Debug;
+use kernel\Mailing;
+use kernel\modules\secure\models\SecretCode;
+use kernel\modules\secure\services\SecureService;
use kernel\modules\user\models\User;
+use kernel\modules\user\service\UserService;
use kernel\Request;
use kernel\RestController;
use kernel\services\TokenService;
+use PHPMailer\PHPMailer\Exception;
use Random\RandomException;
class SecureRestController extends RestController
@@ -51,4 +56,75 @@ class SecureRestController extends RestController
$this->renderApi($res);
}
-}
\ No newline at end of file
+ /**
+ * @throws Exception
+ * @throws RandomException
+ */
+ #[NoReturn] public function actionEmailAuth(): void
+ {
+ $mailing = new Mailing();
+ $request = new Request();
+ $data = $request->post();
+ $model = $this->model->where('email', $data['email'])->first();
+
+ if (!$model) {
+ $password = bin2hex(random_bytes(8));
+
+ UserService::createUserByEmailAndPassword($data['email'], $password);
+ $model = UserService::getByField('email', $data['email']);
+
+ SecureService::createSecretCode($model);
+ $secretCode = SecureService::getByField("user_id", $model->id);
+
+
+ $mailing->send_html("register_by_code.php", ['code' => $secretCode->code, 'password' => $password], [
+ 'address' => $data['email'],
+ 'subject' => "Код регистрации",
+ "from_name" => $_ENV['APP_NAME']
+ ]);
+ } else {
+ SecureService::updateSecretCode($model);
+ $secretCode = SecureService::getByField("user_id", $model->id);
+
+ $mailing->send_html("login_by_code.php", ['code' => $secretCode->code], [
+ 'address' => $data['email'],
+ 'subject' => "Код авторизации",
+ "from_name" => $_ENV['APP_NAME']
+ ]);
+ }
+
+ $res = [
+ "status" => "success",
+ "code_expires_at" => $secretCode->code_expires_at,
+ ];
+
+ setcookie('user_email', $data['email'], time()+60*15, '/', $_SERVER['SERVER_NAME'], false);
+ $this->renderApi($res);
+ }
+
+ /**
+ * @throws Exception
+ */
+ #[NoReturn] public function actionCodeCheck(): void
+ {
+ $request = new Request();
+ $code = $request->post("code");
+
+ $model = SecretCode::where("code", $code)->first();
+ if (time() <= strtotime($model->code_expires_at)) {
+ $user = $this->model->where("id", $model->user_id)->first();
+ if ($user){
+ $user->access_token_expires_at = date("Y-m-d H:i:s", strtotime(App::$secure['token_expired_time']));
+ $user->access_token = SecureService::generateAccessToken();
+ $user->save();
+ $this->renderApi([
+ "access_token" => $user->access_token,
+ "access_token_expires_at" => $user->access_token_expires_at,
+ ]);
+ }
+ }
+
+ $this->renderApi(['status' => 'error', 'message' => 'incorrect code']);
+ }
+
+}
diff --git a/kernel/modules/secure/migrations/2024_12_09_081420_create_secret_code_table.php b/kernel/modules/secure/migrations/2024_12_09_081420_create_secret_code_table.php
new file mode 100644
index 0000000..c5acce1
--- /dev/null
+++ b/kernel/modules/secure/migrations/2024_12_09_081420_create_secret_code_table.php
@@ -0,0 +1,31 @@
+schema->create('secret_code', function (Blueprint $table) {
+ $table->increments('id');
+ $table->integer('user_id');
+ $table->integer('code');
+ $table->dateTime('code_expires_at')->nullable(true);
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ \kernel\App::$db->schema->dropIfExists('secret_code');
+
+ }
+};
diff --git a/kernel/modules/secure/models/SecretCode.php b/kernel/modules/secure/models/SecretCode.php
new file mode 100644
index 0000000..0caaa60
--- /dev/null
+++ b/kernel/modules/secure/models/SecretCode.php
@@ -0,0 +1,25 @@
+ 'Пользователь',
+ 'code' => 'Код',
+ 'code_expires_at' => 'Срок жизни кода',
+ ];
+ }
+
+}
diff --git a/kernel/modules/secure/models/forms/LoginEmailForm.php b/kernel/modules/secure/models/forms/LoginEmailForm.php
new file mode 100644
index 0000000..201817a
--- /dev/null
+++ b/kernel/modules/secure/models/forms/LoginEmailForm.php
@@ -0,0 +1,17 @@
+ 'required|string|email|max255',
+ ];
+ }
+
+}
\ No newline at end of file
diff --git a/kernel/modules/secure/models/forms/RegisterForm.php b/kernel/modules/secure/models/forms/RegisterForm.php
new file mode 100644
index 0000000..9d4a18e
--- /dev/null
+++ b/kernel/modules/secure/models/forms/RegisterForm.php
@@ -0,0 +1,19 @@
+ 'required|min-str-len:5|max-str-len:50',
+ 'email' => 'required|email|max-str-len:50',
+ 'password' => 'required|min-str-len:6|max-str-len:50',
+ ];
+ }
+
+}
\ No newline at end of file
diff --git a/kernel/modules/secure/routs/secure.php b/kernel/modules/secure/routs/secure.php
index 84b37c3..be041d8 100644
--- a/kernel/modules/secure/routs/secure.php
+++ b/kernel/modules/secure/routs/secure.php
@@ -14,11 +14,17 @@ App::$collector->group(["prefix" => "admin"], function (RouteCollector $router){
App::$collector->get('/login', [\kernel\modules\secure\controllers\SecureController::class, 'actionLogin']);
App::$collector->get('/logout', [\kernel\modules\secure\controllers\SecureController::class, 'actionLogout']);
App::$collector->post('/auth', [\kernel\modules\secure\controllers\SecureController::class, 'actionAuth']);
+ App::$collector->post('/email_auth', [\kernel\modules\secure\controllers\SecureController::class, 'actionEmailAuth']);
+ App::$collector->get('/register', [\kernel\modules\secure\controllers\SecureController::class, 'actionRegister']);
+ App::$collector->post('/registration', [\kernel\modules\secure\controllers\SecureController::class, 'actionRegistration']);
+ App::$collector->post('/code_check', [\kernel\modules\secure\controllers\SecureController::class, 'actionCodeCheck']);
});
App::$collector->group(["prefix" => "api"], function (CgRouteCollector $router){
App::$collector->group(["prefix" => "secure"], function (CgRouteCollector $router) {
App::$collector->post('/auth', [\kernel\modules\secure\controllers\SecureRestController::class, 'actionAuth']);
+ App::$collector->post('/email_auth', [\kernel\modules\secure\controllers\SecureRestController::class, 'actionEmailAuth']);
+ App::$collector->post('/code_check', [\kernel\modules\secure\controllers\SecureRestController::class, 'actionCodeCheck']);
});
});
diff --git a/kernel/modules/secure/services/SecureService.php b/kernel/modules/secure/services/SecureService.php
new file mode 100644
index 0000000..b47f4d4
--- /dev/null
+++ b/kernel/modules/secure/services/SecureService.php
@@ -0,0 +1,54 @@
+user_id = $user->id;
+ $secretCode->code = mt_rand(100000, 999999);
+ $secretCode->code_expires_at = date("Y-m-d H:i:s", strtotime("+5 minutes"));;
+ $secretCode->save();
+ }
+
+ public static function updateSecretCode(User $user): void
+ {
+ $secretCode = SecretCode::where('user_id', $user->id)->first();
+ $secretCode->code = mt_rand(100000, 999999);
+ $secretCode->code_expires_at = date("Y-m-d H:i:s", strtotime("+5 minutes"));;
+ $secretCode->save();
+ }
+
+ public static function getCodeByUserId(int $user_id)
+ {
+ return SecretCode::where('user_id', $user_id)->one()->code;
+ }
+
+ public static function getByField(string $field, mixed $value)
+ {
+ return SecretCode::where($field, $value)->first();
+ }
+
+ public static function generateAccessToken(): string
+ {
+ return match (App::$secure['token_type']) {
+ "JWT" => TokenService::JWT($_ENV['SECRET_KEY'], 'HS256'),
+ "md5" => TokenService::md5(),
+ "crypt" => TokenService::crypt(),
+ "hash" => TokenService::hash('sha256'),
+ default => TokenService::random_bytes(20),
+ };
+ }
+
+}
\ No newline at end of file
diff --git a/kernel/modules/secure/views/email_login.php b/kernel/modules/secure/views/email_login.php
new file mode 100644
index 0000000..eadc71b
--- /dev/null
+++ b/kernel/modules/secure/views/email_login.php
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
Форма авторизации/регистрации
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kernel/modules/secure/views/enter_code.php b/kernel/modules/secure/views/enter_code.php
new file mode 100644
index 0000000..57aed3a
--- /dev/null
+++ b/kernel/modules/secure/views/enter_code.php
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Введите код, отправленный на почту ""
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kernel/modules/secure/views/login.php b/kernel/modules/secure/views/login.php
index c6cd7c3..9503fce 100644
--- a/kernel/modules/secure/views/login.php
+++ b/kernel/modules/secure/views/login.php
@@ -24,6 +24,9 @@
-
diff --git a/kernel/modules/secure/views/register.php b/kernel/modules/secure/views/register.php
new file mode 100644
index 0000000..ecc8752
--- /dev/null
+++ b/kernel/modules/secure/views/register.php
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Регистрация
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/kernel/modules/user/controllers/UserController.php b/kernel/modules/user/controllers/UserController.php
index 47d439f..fdd8534 100644
--- a/kernel/modules/user/controllers/UserController.php
+++ b/kernel/modules/user/controllers/UserController.php
@@ -5,9 +5,11 @@ namespace kernel\modules\user\controllers;
use Exception;
use JetBrains\PhpStorm\NoReturn;
use kernel\AdminController;
+use kernel\EntityRelation;
use kernel\modules\user\models\forms\CreateUserForm;
use kernel\modules\user\models\User;
use kernel\modules\user\service\UserService;
+use kernel\Request;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
@@ -35,6 +37,11 @@ class UserController extends AdminController
$userForm->load($_REQUEST);
if ($userForm->validate()){
$user = $this->userService->create($userForm);
+
+
+ $entityRelation = new EntityRelation();
+ $entityRelation->saveEntityRelation(entity: "user", model: $user, request: new Request());
+
if ($user){
$this->redirect("/admin/user/view/" . $user->id);
}
@@ -91,8 +98,12 @@ class UserController extends AdminController
$userForm = new CreateUserForm();
$userService = new UserService();
$userForm->load($_REQUEST);
- if ($userForm->validate()){
+ if ($userForm->validateForUpdate()){
$user = $userService->update($userForm, $user);
+
+ $entityRelation = new EntityRelation();
+ $entityRelation->saveEntityRelation(entity: "user", model: $user, request: new Request());
+
if ($user){
$this->redirect("/admin/user/view/" . $user->id);
}
@@ -100,9 +111,20 @@ class UserController extends AdminController
$this->redirect("/admin/user/update/" . $id);
}
+ /**
+ * @throws Exception
+ */
#[NoReturn] public function actionDelete($id): void
{
- User::find($id)->delete();
+ $user = User::find($id)->first();
+ if (!$user){
+ throw new Exception(message: "The user not found");
+ }
+
+ $entityRelation = new EntityRelation();
+ $entityRelation->deleteEntityRelation(entity: "user", model: $user);
+
+ $user->delete();
$this->redirect("/admin/user/");
}
diff --git a/kernel/modules/user/manifest.json b/kernel/modules/user/manifest.json
index 72e1b80..1892127 100644
--- a/kernel/modules/user/manifest.json
+++ b/kernel/modules/user/manifest.json
@@ -3,6 +3,7 @@
"version": "0.1",
"author": "ITGuild",
"slug": "user",
+ "type": "entity",
"description": "User module",
"module_class": "kernel\\modules\\user\\UserModule",
"module_class_file": "{KERNEL_MODULES}/user/UserModule.php",
diff --git a/kernel/modules/user/models/forms/CreateUserForm.php b/kernel/modules/user/models/forms/CreateUserForm.php
index 632cfd9..73c5f77 100644
--- a/kernel/modules/user/models/forms/CreateUserForm.php
+++ b/kernel/modules/user/models/forms/CreateUserForm.php
@@ -16,4 +16,13 @@ class CreateUserForm extends FormModel
];
}
+ public function rulesForUpdate(): array
+ {
+ return [
+ 'username' => 'required|min-str-len:5|max-str-len:30',
+ 'password' => '',
+ 'email' => 'required|email'
+ ];
+ }
+
}
\ No newline at end of file
diff --git a/kernel/modules/user/service/UserService.php b/kernel/modules/user/service/UserService.php
index 8619038..9e8dd5d 100644
--- a/kernel/modules/user/service/UserService.php
+++ b/kernel/modules/user/service/UserService.php
@@ -3,6 +3,7 @@
namespace kernel\modules\user\service;
use kernel\FormModel;
+use kernel\helpers\Debug;
use kernel\modules\user\models\User;
class UserService
@@ -25,7 +26,9 @@ class UserService
{
$user->username = $form_model->getItem('username');
$user->email = $form_model->getItem('email');
- $user->password_hash = password_hash($form_model->getItem('password'), PASSWORD_DEFAULT);
+ if ($form_model->getItem('password')) {
+ $user->password_hash = password_hash($form_model->getItem('password'), PASSWORD_DEFAULT);
+ }
if ($user->save()){
return $user;
}
@@ -38,7 +41,7 @@ class UserService
* @param string $value
* @return mixed
*/
- public function getByField(string $field, string $value)
+ public static function getByField(string $field, string $value): mixed
{
return User::where($field, $value)->first();
}
@@ -82,4 +85,13 @@ class UserService
return $this->getByField("access_token", $token);
}
+ public static function createUserByEmailAndPassword(string $email, string $password): void
+ {
+ $user = new User();
+ $user->email = $email;
+ $user->username = $email;
+ $user->password_hash = password_hash($password, PASSWORD_DEFAULT);
+ $user->save();
+ }
+
}
\ No newline at end of file
diff --git a/kernel/modules/user/views/form.php b/kernel/modules/user/views/form.php
index 8c49d1e..e32d35f 100644
--- a/kernel/modules/user/views/form.php
+++ b/kernel/modules/user/views/form.php
@@ -6,7 +6,7 @@
use kernel\modules\user\models\User;
$form = new \itguild\forms\ActiveForm();
-$form->beginForm(isset($model) ? "/admin/user/edit/" . $model->id : "/admin/user");
+$form->beginForm(isset($model) ? "/admin/user/edit/" . $model->id : "/admin/user", enctype: 'multipart/form-data');
$form->field(class: \itguild\forms\inputs\TextInput::class, name: "username", params: [
'class' => "form-control",
@@ -32,6 +32,11 @@ $form->field(class: \itguild\forms\inputs\TextInput::class, name: "email", param
->setLabel("Email")
->render();
+$entityRelations = new \kernel\EntityRelation();
+if (!isset($model)) {
+ $model = new User();
+}
+$entityRelations->renderEntityAdditionalPropertyFormBySlug("user", $model);
?>
diff --git a/kernel/modules/user/views/index.php b/kernel/modules/user/views/index.php
index 5876e6c..e492f5e 100644
--- a/kernel/modules/user/views/index.php
+++ b/kernel/modules/user/views/index.php
@@ -12,6 +12,10 @@ use kernel\IGTabel\action_column\EditActionColumn;
use kernel\IGTabel\action_column\ViewActionColumn;
use kernel\IGTabel\btn\PrimaryBtn;
use kernel\modules\user\models\User;
+use kernel\widgets\IconBtn\IconBtnCreateWidget;
+use kernel\widgets\IconBtn\IconBtnDeleteWidget;
+use kernel\widgets\IconBtn\IconBtnEditWidget;
+use kernel\widgets\IconBtn\IconBtnViewWidget;
$table = new ListEloquentTable(new EloquentDataProvider(User::class, [
'currentPage' => $page_number,
@@ -20,6 +24,16 @@ $table = new ListEloquentTable(new EloquentDataProvider(User::class, [
'baseUrl' => "/admin/user",
'filters' => ['email'],
]));
+
+$entityRelation = new \kernel\EntityRelation();
+$additionals = $entityRelation->getEntityRelationsBySlug("user");
+
+foreach ($additionals as $additional) {
+ $table->addColumn($additional, $additional, function ($id) use ($entityRelation, $additional) {
+ return $entityRelation->getAdditionalPropertyByEntityId("user", $id, $additional);
+ });
+}
+
$table->columns([
'username' => [
"filter" => [
@@ -42,11 +56,16 @@ $table->columns([
}
]);
$table->beforePrint(function () {
- return PrimaryBtn::create("Создать", "/admin/user/create")->fetch();
- //return (new PrimaryBtn("Создать", "/admin/user/create"))->fetch();
+ return IconBtnCreateWidget::create(['url' => '/admin/user/create'])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnViewWidget::create(['url' => '/admin/user/view/' . $row['id']])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnEditWidget::create(['url' => '/admin/user/update/' . $row['id']])->run();
+});
+$table->addAction(function($row) {
+ return IconBtnDeleteWidget::create(['url' => '/admin/user/delete/' . $row['id']])->run();
});
-$table->addAction(ViewActionColumn::class);
-$table->addAction(EditActionColumn::class);
-$table->addAction(DeleteActionColumn::class);
$table->create();
$table->render();
\ No newline at end of file
diff --git a/kernel/modules/user/views/view.php b/kernel/modules/user/views/view.php
index fc8293b..856186f 100644
--- a/kernel/modules/user/views/view.php
+++ b/kernel/modules/user/views/view.php
@@ -10,17 +10,30 @@ use Itguild\EloquentTable\ViewJsonTableEloquentModel;
use kernel\IGTabel\btn\DangerBtn;
use kernel\IGTabel\btn\PrimaryBtn;
use kernel\IGTabel\btn\SuccessBtn;
+use kernel\widgets\IconBtn\IconBtnDeleteWidget;
+use kernel\widgets\IconBtn\IconBtnEditWidget;
+use kernel\widgets\IconBtn\IconBtnListWidget;
$table = new ViewEloquentTable(new ViewJsonTableEloquentModel($user, [
'params' => ["class" => "table table-bordered", "border" => "2"],
'baseUrl' => "/admin/user",
]));
$table->beforePrint(function () use ($user) {
- $btn = PrimaryBtn::create("Список", "/admin/user")->fetch();
- $btn .= SuccessBtn::create("Редактировать", "/admin/user/update/" . $user->id)->fetch();
- $btn .= DangerBtn::create("Удалить", "/admin/user/delete/" . $user->id)->fetch();
+ $btn = IconBtnListWidget::create(['url' => '/admin/user'])->run();
+ $btn .= IconBtnEditWidget::create(['url' => '/admin/user/update/' . $user->id])->run();
+ $btn .= IconBtnDeleteWidget::create(['url' => '/admin/user/delete/' . $user->id])->run();
return $btn;
});
+
+$entityRelation = new \kernel\EntityRelation();
+$additionals = $entityRelation->getEntityAdditionalProperty("user", $user);
+
+foreach ($additionals as $key => $additional) {
+ $table->addRow($key, function () use ($additional) {
+ return $additional;
+ }, ['after' => 'email']);
+}
+
$table->rows([
'created_at' => function ($data) {
if (!$data){
diff --git a/kernel/services/MigrationService.php b/kernel/services/MigrationService.php
index 8205fa7..aabee7b 100644
--- a/kernel/services/MigrationService.php
+++ b/kernel/services/MigrationService.php
@@ -23,6 +23,7 @@ class MigrationService
public function runAtPath(string $path = ROOT_DIR . '/migrations'): array
{
$path = getConst($path);
+// Debug::dd($path);
try {
$dmr = new DatabaseMigrationRepository(App::$db->capsule->getDatabaseManager(), 'migration');
@@ -31,7 +32,7 @@ class MigrationService
return $m->run($path);
} catch (\Exception $e) {
- throw new \Exception('Не удалось поднять играции');
+ throw new \Exception('Не удалось поднять миграции');
}
}
diff --git a/kernel/services/ModuleService.php b/kernel/services/ModuleService.php
index 3840192..50a3603 100644
--- a/kernel/services/ModuleService.php
+++ b/kernel/services/ModuleService.php
@@ -3,18 +3,22 @@
namespace kernel\services;
use DirectoryIterator;
-use GuzzleHttp\Client;
+use kernel\EntityRelation;
+use kernel\Flash;
use kernel\helpers\Debug;
use kernel\helpers\Files;
use kernel\helpers\Manifest;
use kernel\helpers\RESTClient;
use kernel\models\Option;
+use MongoDB\Driver\Session;
use ZipArchive;
class ModuleService
{
protected array $errors = [];
+ protected null|bool $serverAvailable = null;
+
/**
* @param string $module
* @return false|array|string
@@ -67,9 +71,9 @@ class ModuleService
{
$active_modules = Option::where("key", "active_modules")->first();
if ($active_modules) {
- $path = json_decode($active_modules->value);
- foreach ($path->modules as $p) {
- if ($p === $slug) {
+ $modules = json_decode($active_modules->value);
+ foreach ($modules->modules as $mod) {
+ if ($mod === $slug) {
return true;
}
}
@@ -109,7 +113,7 @@ class ModuleService
if (isset($module_info['dependence'])) {
$dependence_array = explode(',', $module_info['dependence']);
foreach ($dependence_array as $depend) {
- if (!in_array($depend, $active_modules->modules)) {
+ if (!in_array(trim($depend), $active_modules->modules)) {
$this->addError("first activate the $depend module");
return false;
}
@@ -131,6 +135,10 @@ class ModuleService
public function deactivateModule(string $module): bool
{
$active_modules_info = Option::where("key", "active_modules")->first();
+
+ EntityRelation::removeEntityRelation($module);
+ EntityRelation::removePropertyRelation($module);
+
$active_modules = json_decode($active_modules_info->value);
if (!in_array($module, $active_modules->modules)) {
return true;
@@ -355,8 +363,6 @@ class ModuleService
mkdir(RESOURCES_DIR . '/tmp/modules', 0777, true);
}
$fileHelper->pack($tmpModuleDirFull, RESOURCES_DIR . '/tmp/modules/' . $moduleName . '.igm');
-
- //$fileHelper->recursiveRemoveDir($tmpModuleDirFull);
}
/**
@@ -438,17 +444,19 @@ class ModuleService
public function isLastVersion(string $slug): bool
{
- $modules_info = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
+ if ($this->isServerAvailable()){
+ $modules_info = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
- $modules_info = json_decode($modules_info->getBody()->getContents(), true);
- $mod_info = $this->getModuleInfoBySlug($slug);
- foreach ($modules_info as $mod) {
- if ($mod['slug'] === $mod_info['slug'] && $mod['version'] === $mod_info['version']) {
- return true;
+ $modules_info = json_decode($modules_info->getBody()->getContents(), true);
+ $mod_info = $this->getModuleInfoBySlug($slug);
+ foreach ($modules_info as $mod) {
+ if ($mod['slug'] === $mod_info['slug'] && $mod['version'] === $mod_info['version']) {
+ return true;
+ }
}
}
- return false;
+ return false;
}
public function isKernelModule(string $slug): bool
@@ -463,6 +471,27 @@ class ModuleService
return false;
}
+ public function isShopModule(string $slug): bool
+ {
+ if ($this->isServerAvailable()){
+ $modules_info = RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
+
+ if (!$this->issetModuleShopToken()){
+ return false;
+ }
+
+ $modules_info = json_decode($modules_info->getBody()->getContents(), true);
+ $mod_info = $this->getModuleInfoBySlug($slug);
+ foreach ($modules_info as $mod) {
+ if ($mod['slug'] === $mod_info['slug']) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
public function getKernelModules(): array
{
$modules_info = [];
@@ -474,4 +503,30 @@ class ModuleService
return $modules_info;
}
+ public function isServerAvailable(): bool
+ {
+ if (null !== $this->serverAvailable){
+ return $this->serverAvailable;
+ }
+
+ try {
+ RESTClient::request($_ENV['MODULE_SHOP_URL'] . '/api/module_shop/gb_slug');
+ $this->serverAvailable = true;
+
+ return true;
+ } catch (\Exception $e) {
+ $this->serverAvailable = false;
+ return false;
+ }
+ }
+
+ public function issetModuleShopToken(): bool
+ {
+ if (!empty($_ENV['MODULE_SHOP_TOKEN'])){
+ return true;
+ }
+
+ return false;
+ }
+
}
\ No newline at end of file
diff --git a/kernel/services/ModuleShopService.php b/kernel/services/ModuleShopService.php
new file mode 100644
index 0000000..72562ad
--- /dev/null
+++ b/kernel/services/ModuleShopService.php
@@ -0,0 +1,36 @@
+url = $_ENV['MODULE_SHOP_URL'];
+ $this->token = $_ENV['MODULE_SHOP_TOKEN'];
+ }
+
+ /**
+ * @throws GuzzleException
+ */
+ public function email_auth(string $email)
+ {
+ $request = RESTClient::post($this->url . "/api/secure/email_auth", ['email' => $email], false);
+
+ return json_decode($request->getBody()->getContents(), true);
+ }
+
+ public function code_check(string $code)
+ {
+ $request = RESTClient::post($this->url . "/api/secure/code_check", ['code' => $code], false);
+
+ return json_decode($request->getBody()->getContents(), true);
+ }
+
+}
\ No newline at end of file
diff --git a/kernel/views/mailing/login_by_code.php b/kernel/views/mailing/login_by_code.php
new file mode 100644
index 0000000..a172e1d
--- /dev/null
+++ b/kernel/views/mailing/login_by_code.php
@@ -0,0 +1,12 @@
+
+
+
+ Код подтверждения: = $code ?>
+
+
+ Если вы не запрашивали код, проигнорируйте данное письмо.
+
\ No newline at end of file
diff --git a/kernel/views/mailing/register_by_code.php b/kernel/views/mailing/register_by_code.php
new file mode 100644
index 0000000..4dc6a54
--- /dev/null
+++ b/kernel/views/mailing/register_by_code.php
@@ -0,0 +1,15 @@
+
+
+
+ Код подтверждения: = $code ?>
+ Ваш пароль: = $password ?>
+
+
+
+ Если вы не запрашивали код, проигнорируйте данное письмо.
+
\ No newline at end of file
diff --git a/kernel/views/module/index.php b/kernel/views/module/index.php
index aeee0ad..8cb34f8 100644
--- a/kernel/views/module/index.php
+++ b/kernel/views/module/index.php
@@ -7,6 +7,14 @@
* @var \kernel\services\ModuleService $moduleService
*/
+use kernel\Flash;
+use kernel\widgets\IconBtn\IconBtnActivateWidget;
+use kernel\widgets\IconBtn\IconBtnDeactivateWidget;
+use kernel\widgets\IconBtn\IconBtnDeleteWidget;
+use kernel\widgets\IconBtn\IconBtnUpdateWidget;
+use kernel\widgets\IconBtn\IconBtnViewWidget;
+use kernel\widgets\ModuleTabsWidget;
+
$meta = [];
$meta['columns'] = [
"name" => "Название",
@@ -25,35 +33,32 @@ $info_to_table['data'] = $modules_info;
$table = new \Itguild\Tables\ListJsonTable(json_encode($info_to_table, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
-
$table->addAction(function ($row, $url) use ($moduleService) {
$slug = $row['slug'];
if ($moduleService->isActive($slug)) {
- $label = "Деактивировать";
- $btn_type = "warning";
- $btn = "
$label ";
+ $url = "$url/deactivate/?slug=". $row['slug'];
+ return IconBtnDeactivateWidget::create(['url' => $url])->run();
} else {
- $label = "
";
- $btn_type = "success";
- $btn = "
$label ";
- }
+ $url = "$url/activate/?slug=". $row['slug'];
- return $btn;
+ return IconBtnActivateWidget::create(['url' => $url])->run();
+ }
});
+
$table->addAction(function ($row, $url) use ($moduleService) {
- $slug = $row['slug'];
- return "
Просмотр ";
+ $url = "$url/view/?slug=". $row['slug'];
+
+ return IconBtnViewWidget::create(['url' => $url])->run();
});
$table->addAction(function ($row, $url) use ($moduleService){
- $slug = $row['slug'];
- if (!$moduleService->isKernelModule($slug)){
- if (!$moduleService->isLastVersion($slug)) {
- $label = "Обновить";
- $btn_type = "info";
- return "
$label ";
+ if ($moduleService->isShopModule($row['slug'])){
+ if (!$moduleService->isLastVersion($row['slug'])) {
+ $url = "$url/update/?slug=". $row['slug'];
+
+ return IconBtnUpdateWidget::create(['url' => $url])->run();
}
}
@@ -62,16 +67,19 @@ $table->addAction(function ($row, $url) use ($moduleService){
$table->addAction(function ($row) use ($moduleService){
$slug = $row['slug'];
- if (!$moduleService->isKernelModule($slug)){
- $label = "Удалить";
- $btn_type = "danger";
- return "
$label ";
+ if (!$moduleService->isKernelModule($slug)) {
+ $url = "admin/module_shop_client/delete/?slug=" . $row['slug'];
+
+ return IconBtnDeleteWidget::create(['url' => $url])->run();
}
return false;
});
-$table->create();
if ($moduleService->isActive('module_shop_client')) {
- \kernel\widgets\ModuleTabsWidget::create()->run();
+ ModuleTabsWidget::create()->run();
}
+
+
+
+$table->create();
$table->render();
diff --git a/kernel/views/module/view.php b/kernel/views/module/view.php
index 168fcf9..ba9e5eb 100644
--- a/kernel/views/module/view.php
+++ b/kernel/views/module/view.php
@@ -3,9 +3,8 @@
* @var array $data
*/
-use kernel\IGTabel\btn\DangerBtn;
-use kernel\IGTabel\btn\PrimaryBtn;
-use kernel\IGTabel\btn\SuccessBtn;
+use Itguild\Tables\ViewJsonTable;
+use kernel\widgets\IconBtn\IconBtnListWidget;
$table_info = [
"meta" => [
@@ -20,11 +19,10 @@ $table_info = [
],
"data" => $data
];
-$table = new \Itguild\Tables\ViewJsonTable(json_encode($table_info, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
+$table = new ViewJsonTable(json_encode($table_info, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
$table->beforePrint(function () {
- $btn = PrimaryBtn::create("Список", "/admin")->fetch();
- return $btn;
+ return IconBtnListWidget::create(['url' => '/admin'])->run();
});
$table->create();
$table->render();
\ No newline at end of file
diff --git a/kernel/views/widgets/action_button.php b/kernel/views/widgets/action_button.php
new file mode 100644
index 0000000..b58234d
--- /dev/null
+++ b/kernel/views/widgets/action_button.php
@@ -0,0 +1,10 @@
+
+
+
= $label ?>
\ No newline at end of file
diff --git a/kernel/views/widgets/admin/action_button.php b/kernel/views/widgets/admin/action_button.php
deleted file mode 100644
index 32dee23..0000000
--- a/kernel/views/widgets/admin/action_button.php
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-"
$icon ";
\ No newline at end of file
diff --git a/kernel/views/widgets/admin/menu.php b/kernel/views/widgets/menu.php
similarity index 91%
rename from kernel/views/widgets/admin/menu.php
rename to kernel/views/widgets/menu.php
index 124c239..fe5773b 100644
--- a/kernel/views/widgets/admin/menu.php
+++ b/kernel/views/widgets/menu.php
@@ -18,7 +18,7 @@
-
">
+ ">
= $item->label ?>
diff --git a/kernel/views/widgets/admin/module_tabs.php b/kernel/views/widgets/tabs.php
similarity index 100%
rename from kernel/views/widgets/admin/module_tabs.php
rename to kernel/views/widgets/tabs.php
diff --git a/kernel/widgets/ActionButtonWidget.php b/kernel/widgets/ActionButtonWidget.php
index adea90f..13d57d1 100644
--- a/kernel/widgets/ActionButtonWidget.php
+++ b/kernel/widgets/ActionButtonWidget.php
@@ -2,15 +2,24 @@
namespace kernel\widgets;
+use kernel\helpers\Debug;
use kernel\Widget;
class ActionButtonWidget extends Widget
{
- public function run(): void
+
+ public static function create(array $data = []): ActionButtonWidget
{
- $icon = $this->data['icon'];
- $btn = $this->data['btn'];
+ return new static($data);
+ }
+
+ public function run(): string
+ {
+ $label = $this->data['label'];
+ $btn_type = $this->data['btn_type'];
$url = $this->data['url'];
- $this->cgView->render('/admin/action_button.php', ['icon' => $icon, 'btn' => $btn, 'url' => $url]);
+ $title = $this->data['title'] ?? '';
+
+ return $this->cgView->fetch('/action_button.php', ['label' => $label, 'btn_type' => $btn_type, 'url' => $url, 'title' => $title]);
}
}
\ No newline at end of file
diff --git a/kernel/widgets/IconBtn/IconBtnActivateWidget.php b/kernel/widgets/IconBtn/IconBtnActivateWidget.php
new file mode 100644
index 0000000..2665265
--- /dev/null
+++ b/kernel/widgets/IconBtn/IconBtnActivateWidget.php
@@ -0,0 +1,26 @@
+data['url'];
+
+ return ActionButtonWidget::create([
+ 'label' => "
",
+ 'url' => $url,
+ 'btn_type' => "success",
+ 'title' => "Активировать"
+ ])->run();
+ }
+}
\ No newline at end of file
diff --git a/kernel/widgets/IconBtn/IconBtnCreateWidget.php b/kernel/widgets/IconBtn/IconBtnCreateWidget.php
new file mode 100644
index 0000000..da3d462
--- /dev/null
+++ b/kernel/widgets/IconBtn/IconBtnCreateWidget.php
@@ -0,0 +1,26 @@
+data['url'];
+
+ return ActionButtonWidget::create([
+ 'label' => "
",
+ 'url' => $url,
+ 'btn_type' => "success",
+ 'title' => "Создать"
+ ])->run();
+ }
+}
\ No newline at end of file
diff --git a/kernel/widgets/IconBtn/IconBtnDeactivateWidget.php b/kernel/widgets/IconBtn/IconBtnDeactivateWidget.php
new file mode 100644
index 0000000..005bfbd
--- /dev/null
+++ b/kernel/widgets/IconBtn/IconBtnDeactivateWidget.php
@@ -0,0 +1,26 @@
+data['url'];
+
+ return ActionButtonWidget::create([
+ 'label' => "
",
+ 'url' => $url,
+ 'btn_type' => "warning",
+ 'title' => "Деактивировать"
+ ])->run();
+ }
+}
\ No newline at end of file
diff --git a/kernel/widgets/IconBtn/IconBtnDeleteWidget.php b/kernel/widgets/IconBtn/IconBtnDeleteWidget.php
new file mode 100644
index 0000000..e8ba1d0
--- /dev/null
+++ b/kernel/widgets/IconBtn/IconBtnDeleteWidget.php
@@ -0,0 +1,26 @@
+data['url'];
+
+ return ActionButtonWidget::create([
+ 'label' => "
",
+ 'url' => $url,
+ 'btn_type' => "danger",
+ 'title' => "Удалить"
+ ])->run();
+ }
+}
\ No newline at end of file
diff --git a/kernel/widgets/IconBtn/IconBtnEditWidget.php b/kernel/widgets/IconBtn/IconBtnEditWidget.php
new file mode 100644
index 0000000..cdf9406
--- /dev/null
+++ b/kernel/widgets/IconBtn/IconBtnEditWidget.php
@@ -0,0 +1,26 @@
+data['url'];
+
+ return ActionButtonWidget::create([
+ 'label' => "
",
+ 'url' => $url,
+ 'btn_type' => "success",
+ 'title' => "Редактировать"
+ ])->run();
+ }
+}
\ No newline at end of file
diff --git a/kernel/widgets/IconBtn/IconBtnInstallWidget.php b/kernel/widgets/IconBtn/IconBtnInstallWidget.php
new file mode 100644
index 0000000..7a09f39
--- /dev/null
+++ b/kernel/widgets/IconBtn/IconBtnInstallWidget.php
@@ -0,0 +1,26 @@
+data['url'];
+
+ return ActionButtonWidget::create([
+ 'label' => "
",
+ 'url' => $url,
+ 'btn_type' => "success",
+ 'title' => "Установить"
+ ])->run();
+ }
+}
\ No newline at end of file
diff --git a/kernel/widgets/IconBtn/IconBtnListWidget.php b/kernel/widgets/IconBtn/IconBtnListWidget.php
new file mode 100644
index 0000000..e0e0f06
--- /dev/null
+++ b/kernel/widgets/IconBtn/IconBtnListWidget.php
@@ -0,0 +1,26 @@
+data['url'];
+
+ return ActionButtonWidget::create([
+ 'label' => "
",
+ 'url' => $url,
+ 'btn_type' => "primary",
+ 'title' => "Список"
+ ])->run();
+ }
+}
\ No newline at end of file
diff --git a/kernel/widgets/IconBtn/IconBtnUpdateWidget.php b/kernel/widgets/IconBtn/IconBtnUpdateWidget.php
new file mode 100644
index 0000000..b421009
--- /dev/null
+++ b/kernel/widgets/IconBtn/IconBtnUpdateWidget.php
@@ -0,0 +1,26 @@
+data['url'];
+
+ return ActionButtonWidget::create([
+ 'label' => "
",
+ 'url' => $url,
+ 'btn_type' => "info",
+ 'title' => "Обновить"
+ ])->run();
+ }
+}
\ No newline at end of file
diff --git a/kernel/widgets/IconBtn/IconBtnViewWidget.php b/kernel/widgets/IconBtn/IconBtnViewWidget.php
new file mode 100644
index 0000000..73ee3d8
--- /dev/null
+++ b/kernel/widgets/IconBtn/IconBtnViewWidget.php
@@ -0,0 +1,27 @@
+data['url'];
+
+ return ActionButtonWidget::create([
+ 'btn_type' => "primary",
+ 'label' => "
",
+ 'url' => $url,
+ 'title' => "Просмотреть"
+ ])->run();
+ }
+
+}
\ No newline at end of file
diff --git a/kernel/widgets/MenuWidget.php b/kernel/widgets/MenuWidget.php
index 52dfe62..d45da7f 100644
--- a/kernel/widgets/MenuWidget.php
+++ b/kernel/widgets/MenuWidget.php
@@ -11,7 +11,7 @@ class MenuWidget extends Widget
public function run(): void
{
$menu = Menu::where("parent_id", 0)->get()->sortBy("priority");
- $this->cgView->render('/admin/menu.php', ['menu' => $menu]);
+ $this->cgView->render('/menu.php', ['menu' => $menu]);
}
}
\ No newline at end of file
diff --git a/kernel/widgets/ModuleTabsWidget.php b/kernel/widgets/ModuleTabsWidget.php
index 94686f2..d740dcf 100644
--- a/kernel/widgets/ModuleTabsWidget.php
+++ b/kernel/widgets/ModuleTabsWidget.php
@@ -13,6 +13,6 @@ class ModuleTabsWidget extends Widget
'/admin' => 'Локальные',
'/admin/module_shop_client' => 'Каталог'
];
- $this->cgView->render('/admin/module_tabs.php', ['tabs' => $tabs]);
+ $this->cgView->render('/tabs.php', ['tabs' => $tabs]);
}
}
\ No newline at end of file
diff --git a/kernel/widgets/TagTabsWidget.php b/kernel/widgets/TagTabsWidget.php
new file mode 100644
index 0000000..a569dda
--- /dev/null
+++ b/kernel/widgets/TagTabsWidget.php
@@ -0,0 +1,18 @@
+ 'tag',
+ '/admin/tag_entity' => 'tag entity'
+ ];
+ $this->cgView->render('/tabs.php', ['tabs' => $tabs]);
+ }
+}
\ No newline at end of file