diff --git a/CHANGELOG.md b/CHANGELOG.md index a6ea72b..25aa575 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,29 @@ ## Не выпущено -Новые изменения будут добавлены после build 0.39. +Новые изменения будут добавлены после build 0.40. + +## 3.3 build 0.40 — 25 августа 2026 + +### Публичный сайт и вход + +- Неизвестный адрес снова показывает назначенную страницу 404, а не содержимое + главной страницы. HTTP-статус 404 и метаданные сохранены. +- Публичная регистрация и вход могут работать только по телефону: email больше + не требуется, номер форматируется по маске, а доступные способы входа + определяются настройками системы. +- Настройки телефонного входа и подсказки в кабинете приведены к одному набору + разрешённых способов авторизации. + +### Пользователи сайта + +- В разделе пользователей сайта форма учитывает регистрацию без email и + корректно показывает телефон как основной идентификатор. + +### Выпуск + +- Для build 0.40 подготовлены чистая core-сборка, компактный установщик и + накопительное обновление с build 0.20. ## 3.3 build 0.39 — 25 августа 2026 diff --git a/PACKAGE-MANIFEST.json b/PACKAGE-MANIFEST.json index a703c34..4808a43 100644 --- a/PACKAGE-MANIFEST.json +++ b/PACKAGE-MANIFEST.json @@ -2,19 +2,19 @@ "format": "ave-core-package-v2", "product": "AVE.cms", "version": "3.3", - "build": "0.39", + "build": "0.40", "package": "core", - "built_at": "2026-08-25T09:00:39+00:00", + "built_at": "2026-08-25T11:42:07+00:00", "installed_modules": 0, "bundled_optional_modules": [], "optional_after_install": [ "setup/" ], - "core_fingerprint": "cd348589924dbf95a20d6e41994c39f036bd55372250ad6caa8c3484158bd6a5", + "core_fingerprint": "045c60e55daab45dcf75d86b72e01dd6aed8ca7103efa4293dd1676f0be349ab", "files": { ".gitignore": "20d4fb177d47da6944a7a1c2dbf5918fd62766881aa52b00901f9054b1db4b49", ".htaccess": "71c06b7bc41b09c347a562ca72768acaa0ee1ef8388c749fc67956c793d8a826", - "CHANGELOG.md": "58ab5f834aad74ac1f8101983102fce3f0708d720999efadcdff9efdefa2ed64", + "CHANGELOG.md": "4adedd967bb28883655dfb981ebcc7fdc1e32367a79efb4e4417e3fd70d4f04e", "README.md": "19b820f1b092780039aae011e133dc6a1e5f1cf213b435e0ff1962b592b9095b", "adminx/.htaccess": "d03ea2d2972af8b7545a2d57c6253f303d15adeb30b775e161d887ca5ff73378", "adminx/Support/AdminLocale.php": "a7fe84d86d65c9f021106172b1789c8bc6221c36b2fe39cf883ca9a505e3e8ad", @@ -185,7 +185,7 @@ "adminx/modules/Blocks/migrations/012_merge_visual_blocks.php": "5c9cd6efd66a027134621859da1059b2c403bacb732885d6b405699cbce8fc14", "adminx/modules/Blocks/module.php": "53eb434566d820814f5b25382200b75ed02b0067c066c8f8cb62bee13529b964", "adminx/modules/Blocks/view/index.twig": "39f9225b6a95c65549d0c861afb7db7879ca338c251290653dded6ab7cb715cc", - "adminx/modules/Catalog/Controller.php": "22a19db35e22824abf3bea9053050c2cdd74c937022de905684c5b627d52de57", + "adminx/modules/Catalog/Controller.php": "dea3f7ac5cdb8bd1757e18f95bcbeb2dd433123536d6f0766bc584bb1c09fcbf", "adminx/modules/Catalog/Model.php": "d524730981ad388928cfc29208a821ed1d474bd01d6db1749fd37fdfb4e4958e", "adminx/modules/Catalog/assets/catalog-drawer.css": "b3e4f798d7bdf329aa91987ae5be435910ddccfeb8a32211059846ab9dc6b7c4", "adminx/modules/Catalog/assets/catalog.css": "49e7a33fc444f8330806e1cc5cbb0d523b673c64faafd25dbf0fe33067643efd", @@ -219,7 +219,7 @@ "adminx/modules/Customers/GlobalSearchProvider.php": "6be85ba385ade05cef1167a6acf146a7e078d176b72db773e0d26d2ab8ea65de", "adminx/modules/Customers/Model.php": "fb84df79d1ef9b403f16e44100325d26db5c144b6cbc6a69e3425a9a3f29a043", "adminx/modules/Customers/assets/customers.css": "2542f8ba075ce20f4fa48a966eda5de82b5e574a17f5bebc88727b608eb47bb8", - "adminx/modules/Customers/assets/customers.js": "3a0bc1875dea633b78840b75feb11e903d2b2404080e0f505821156f98a8ffa7", + "adminx/modules/Customers/assets/customers.js": "7ef3b863eff78c83bce7d78a7cdd67fc715d26fe8d9d9239af8d43f27bbb45c9", "adminx/modules/Customers/language/en/center.xml": "0ebf643e8a2e00fdf07a290adfd108d0d7e53781d15c37f44d55564c7476b738", "adminx/modules/Customers/language/en/client.xml": "6f22d85d37d66aba749b7b4794635fd644a12e9e71e2a5eff66ee3b1c9813e40", "adminx/modules/Customers/language/en/interface.xml": "573a7ca126beeaff77a8865d6114dac0429b588d8061f939c5ed7af316d4070b", @@ -235,10 +235,10 @@ "adminx/modules/Customers/migrations/005_checkout_registration.sql": "4e5ac6d4d5868f9e1c91b896fc03ad0982d5716287101e721a3820d21abe1744", "adminx/modules/Customers/migrations/006_phone_identity.php": "97e8aa457fd8f8ade781a03a98bdc7ee03cac5734782f9e72fb0b76bdbd2cdbb", "adminx/modules/Customers/migrations/007_customer_center.php": "7adde1ce2b92f24b7f1d1d483aca4304bad918d06ae2f213226eca96dcff344e", - "adminx/modules/Customers/module.php": "a8a567e986129c8960621235c5bb75c03fd19bcae5a0ae4a1065d8d1eb063d21", + "adminx/modules/Customers/module.php": "ef1055dbaf8d23748b492f0fcd8a7ce184b534d72714744d684875735f4b7f73", "adminx/modules/Customers/view/customer-center-detail.twig": "2239602955041c4eebe704c70e835fd45272f721abd28bf254904901bd77a4eb", "adminx/modules/Customers/view/customer-center.twig": "223e657861275fbfe482ce624a6216a91e8df893cd1c5fe58a2999606468addf", - "adminx/modules/Customers/view/index.twig": "5b011dab9ca33d66fbd138297875861054477af56f093282d08aaa4c576a7f12", + "adminx/modules/Customers/view/index.twig": "61b25d07799e50b3a06c5ab91b4895dd685b54a29085f896f9c51aebbfdb3d7b", "adminx/modules/Dashboard/Controller.php": "7e6ad0610df7581bb010cee574d8d093c4737af439bd2b0763142f50ddee1c54", "adminx/modules/Dashboard/Widgets.php": "56fc7ba7c1f9e30d7eae8c61524b6441b1c706a2cd56b1db883bb8bff7186eed", "adminx/modules/Dashboard/assets/dashboard.css": "8e28b56cac2e55d9b57304ea6e265fd94a52400674c082fbdd78f1eed1872424", @@ -1010,7 +1010,7 @@ "system/App/Common/Permission.php": "8e2241bca829de0104741dc2518860cd15489866dc310437e07aeab2bf0f0355", "system/App/Common/Proxy.php": "707564208ec8c24ac2ffb5bf41cba34f1b39059ce6bda31a69aaf4b116d864e2", "system/App/Common/PublicAsset.php": "06f9ae414f7336206073e07597669991098114c396e80748c654c82b370a39c4", - "system/App/Common/PublicAuthSettings.php": "a3dd7d0bef9ab608c1e99b161d30962cceeacb4babf37bc24c26511d2d433b3d", + "system/App/Common/PublicAuthSettings.php": "56b57c58d51f821797edf5d65b445dc4881be761781e4b13e039a2e15c11ec44", "system/App/Common/PublicBootstrap.php": "b22aa593a13d32ea6382b8ec342a5cfd79a9986b627730eb77e6fec4aaca85cd", "system/App/Common/PublicConfiguration.php": "1daf6c26de04277f8618be4e25453aa479de9f7dfc09ba770d405eb7f9454760", "system/App/Common/PublicModuleRuntime.php": "5aafede8a2c0cf35023419a024566ca453676ea2dd9274a4d5ca99faa9273d15", @@ -1192,8 +1192,8 @@ "system/App/Content/Rubrics/RubricMutationService.php": "e3190ef1ddd94bdaf077148ce84c5758b2a32683369730a2b847dbbd0d72a74c", "system/App/Content/Templates/TemplateMutationService.php": "8c7e52202454e35eb0c8176325cc23ba760ac40ff0430cbba5e1446c83cf7a87", "system/App/Frontend/Auth/AuthService.php": "1cef24cffd7773f3783ec96479b8e7daa1808b03a34dfc8da37b84e6e09144b8", - "system/App/Frontend/Auth/Controller.php": "14a425c24653fdfda4225550635130bcdf67a6d63a1eb3817ad86a41d292efe9", - "system/App/Frontend/Auth/Feature.php": "dbaeac564886c7949e0e47c85fc5496c25221d880c4f03cee40cc5e15d042a1c", + "system/App/Frontend/Auth/Controller.php": "8002201011ff8e1c477dc879ec57d2138bf325621978ccbc9a56921c4eff7f9d", + "system/App/Frontend/Auth/Feature.php": "7910b5f938854a4a32feed637b757182b12f4a7178cad97a1498509173571776", "system/App/Frontend/Auth/FormTemplateRepository.php": "bcd8797e63cb67803aef2267a2c62e3ad368b5fd947057a768adbb1288ee9281", "system/App/Frontend/Auth/OAuth/HttpClient.php": "b09acf92b312bd05ca78500fccaac3b77d36a1046d64d3615a00d60af4e3594f", "system/App/Frontend/Auth/OAuth/IdentityRepository.php": "35ab143e0d536185125c685f17f5f4bb0ba0cc72daba62552ef6f82370e38ec1", @@ -1211,20 +1211,20 @@ "system/App/Frontend/Auth/Registration/EmailRegistrationGate.php": "ce6dcad98a944aade0fd9a80444c183b4f29bc50e1f119aa3d1d72bdfc3fa732", "system/App/Frontend/Auth/Registration/RegistrationGateInterface.php": "99e73d0d6db972bb5b2c2a7a21dd50823a9bcef7d05937c525d0e7096775aedd", "system/App/Frontend/Auth/Registration/RegistrationGateRegistry.php": "bc7c8546780daacd23243d16778062384f043661674956d1a5a47a8b6440eb44", - "system/App/Frontend/Auth/Renderer.php": "94ed24082c9170c6f7ad09d1b59565c8b4251947979b6502f426d8adfff13efc", + "system/App/Frontend/Auth/Renderer.php": "502cfc65cc32e653bae3be85a0a93299365fcec56143cc6e1c7f2bb4d53023ab", "system/App/Frontend/Auth/Tags.php": "92fc1c466e720be36a0adce5a735e47c94bf88d9a3e70ba9d62196ef63e639f5", "system/App/Frontend/Auth/TokenRepository.php": "5e09b154d4747bfb3d2795a9b449ae4aefffe47508edef92d1a7b392c0371207", "system/App/Frontend/Auth/UserRepository.php": "07a35cb3a82201465360b7f75e4be1534c88d53789ad2a5b1ef617be97a060e3", "system/App/Frontend/Auth/assets/auth.css": "a16949511a17462d9157945f2ceccb445254b34243e9e368796dd3137aac49c8", - "system/App/Frontend/Auth/assets/auth.js": "840c7322fc21f9a8dd61af8cd16e0ceed36d6beaeac45d948bedbcb87b6012c4", - "system/App/Frontend/Auth/view/login.twig": "1f33ca2d7b99d9ad60a82deb5e3904b7b1be1ef6a2c6c021ee565523ee0fe074", + "system/App/Frontend/Auth/assets/auth.js": "a619f46dfbdf5dbe783a316ac5964a6ed40b89f872b3bd7a5dd88d5825c1acfe", + "system/App/Frontend/Auth/view/login.twig": "87ca03cc43b778ded40a8a6c8481d0463977219c1b48424896a18fd6f0ec84cd", "system/App/Frontend/Auth/view/message.twig": "4e9a660af7d0deae9424a07550816c401902e75279414b11657e0eddf573deea", "system/App/Frontend/Auth/view/oauth.twig": "7ccb2c7ae36a378586334887c32fda96909cb6fa235601f1f697d4c8049af648", "system/App/Frontend/Auth/view/oauth_connections.twig": "e2d845ce9d906ca12d3f642e92ede1aa415203f7dc2ac472006f40e80eb8bf27", "system/App/Frontend/Auth/view/overview.twig": "97ad0cd5f72f63b6c92139f7cba54041840131975fdca417352dacf7f64ddb68", - "system/App/Frontend/Auth/view/panel.twig": "3e7237263702462969b937254b6e2d4268599352f801ed4681db7b1aab07f508", + "system/App/Frontend/Auth/view/panel.twig": "de638d18587b6c6671d1ba9db4f9eb3c8cc7765be560aee55ceda4625cd9eb50", "system/App/Frontend/Auth/view/password.twig": "099d7c1e48649faba57eb50df9bd9a091c79dad12e9c1fee9b38c3f2e025ed80", - "system/App/Frontend/Auth/view/phone.twig": "8119ebc00ef866b80eadb559ce71b4d1c6511fc88523e41e7d3ac693db10dbdf", + "system/App/Frontend/Auth/view/phone.twig": "f84dc89e54a9d2197cb6a9f8b3c4b838f008805e109061add189a43232dc427e", "system/App/Frontend/Auth/view/profile.twig": "71032aeeebc80036301181932c90ee004d9440bbc64b1b3f79ba03c0e3037a87", "system/App/Frontend/Auth/view/register.twig": "92f78ab66ba8c16e0b7c3727ac80ae239e01f696399b72049f19a1087d3f3cc9", "system/App/Frontend/Auth/view/remember.twig": "fb170509256e4ecf13ebe5f64cae8cbd6ad8ef143abe645f4bc1f269e0d8a0fe", @@ -1246,7 +1246,7 @@ "system/App/Frontend/DocumentFieldRepository.php": "fc8e80455feca50e4bb5bff3566eb6814fcca1994f1167bd8dd7972f1c87ac69", "system/App/Frontend/DocumentPaginationRenderer.php": "560c9441fb758bc760b14f37bd88c39c36207c1717a18f43b5c57599a61231ed", "system/App/Frontend/DocumentRenderCache.php": "9dd0e9e666021e00eda8c4d09cf8f197f17468b8ad545b4d357654bf646bfc15", - "system/App/Frontend/DocumentRepository.php": "8aa13746bc4cbb6ff1d1e0550a0cc94a6e5d9f3c0431a3f982668758d2ff1454", + "system/App/Frontend/DocumentRepository.php": "f5388b21eee81b3536ef32f239a521dd3187410c9874adbdbdc416949409c27a", "system/App/Frontend/DocumentRevisionPreview.php": "372b751f673411722c2de5f04ee1fac57b745e327a2259916313781a3f175e89", "system/App/Frontend/DocumentRevisionRepository.php": "bbfb1c5a77c979b9998cc647a0e410150ca33727f6caf46f7c49f6ed01774f45", "system/App/Frontend/DocumentRouteRepository.php": "68b7a9c4972613c7fae886c74273cced26d5749d9242f0cf7463176c1ac0d854", @@ -1354,7 +1354,7 @@ "system/language/ru/lang.xml": "7d46cc9822f064a1af4d6528ccfe2dd4a9cc318912e327fd807befd2ca3dfd11", "system/preload.php": "66bfb1aaf36ba85945b729b09a37e96ead0be1cc2749ebd9abd4b9da4f25ba0e", "system/public.php": "3f72b5bf44bc0ba5ba6fb6b3adc2e2f9d5e9902d9cdfa3d7b748f4aebd179b87", - "system/release.php": "73af5bab9ab6ad78aa6c4fc4509dd4419cf68e66142381c1500c01a72b655c8e", + "system/release.php": "313f3e82832ba2ed320647a9a3eee63b54cda5b390b8b1916fb9ceb7d2344764", "system/vendor/Captcha/fonts/palatino_linotype_bold.png": "38b6a1d4a4bd1d0c056205119c5e24176913ac0d898371f53a0339952a319365", "system/vendor/Captcha/fonts/perpetua_bold.png": "55dbbe97dae128dea47b5e8d640414b3d813119c854c688037a20a581ec8fdc4", "system/vendor/Captcha/fonts/times_bold.png": "d3d32ce1f418e3c3c3b1afe3b6acabadb36207bc12368f5e86420cf1a529ff8f", diff --git a/adminx/modules/Catalog/Controller.php b/adminx/modules/Catalog/Controller.php index 5872e77..9eaa334 100644 --- a/adminx/modules/Catalog/Controller.php +++ b/adminx/modules/Catalog/Controller.php @@ -50,6 +50,7 @@ use App\Adminx\Packages\Products\ProductCollections; use App\Adminx\Packages\Products\ProductDemands; use App\Adminx\Packages\Products\ProductDuplicator; + use App\Adminx\Packages\Products\QualitySnapshot; use App\Adminx\Packages\Products\ProductReadiness; use App\Adminx\Packages\Products\PublicViewTemplates; use App\Adminx\Packages\Products\ShippingPackageTemplates; @@ -144,6 +145,28 @@ )); } + public function refreshProductQualitySnapshot(array $params = array()) + { + if (($error = $this->csrfGuard()) !== null) { return $error; } + if (!Permission::check('view_products')) { return $this->error('Недостаточно прав', array(), 403); } + + try { + $snapshot = QualitySnapshot::refresh(); + } catch (\Throwable $e) { + error_log('[products.quality] ' . $e->getMessage()); + return $this->error('Не удалось рассчитать качество товаров', array(), 500); + } + + return $this->success('Сводка качества обновлена', array( + 'data' => array( + 'generated_label' => (string) $snapshot['generated_label'], + 'quality_total' => (int) $snapshot['stats']['quality_total'], + 'required' => (int) $snapshot['required'], + 'score' => (int) $snapshot['stats']['score'], + ), + )); + } + public function productComparison(array $params = array()) { if (!Permission::check('view_products')) { return $this->renderStatus('@adminx/404.twig', array('title' => 'Недостаточно прав'), 403); } diff --git a/adminx/modules/Customers/assets/customers.js b/adminx/modules/Customers/assets/customers.js index cab1b13..85ba00e 100644 --- a/adminx/modules/Customers/assets/customers.js +++ b/adminx/modules/Customers/assets/customers.js @@ -398,6 +398,7 @@ syncRegistrationGate: function () { var gate = document.querySelector('[data-registration-gate]'); var hasEmail = gate && gate.value !== 'phone'; + var phoneOnly = gate && gate.value === 'phone'; var emailAndPhone = gate && gate.value === 'email_phone'; var description = document.querySelector('[data-auth-email-field-description]'); var visibility = document.querySelector('[data-auth-email-visibility]'); @@ -406,12 +407,16 @@ document.querySelectorAll('[data-auth-email-registration], [data-auth-email-form-fields], [data-auth-email-settings]').forEach(function (section) { section.hidden = !hasEmail; }); - if (description) { description.textContent = emailAndPhone ? 'Запрашивается только при выборе регистрации по email' : 'Логин и канал подтверждения регистрации по email'; } - if (visibility) { visibility.textContent = emailAndPhone ? 'В email-форме' : 'Показывается'; } + if (description) { description.textContent = phoneOnly ? 'Не используется для входа; можно добавить в профиле как контакт' : (emailAndPhone ? 'Запрашивается только при выборе регистрации по email' : 'Логин и канал подтверждения регистрации по email'); } + if (visibility) { + visibility.textContent = phoneOnly ? 'Только в профиле' : (emailAndPhone ? 'В email-форме' : 'Показывается'); + visibility.classList.toggle('badge-blue', !phoneOnly); + visibility.classList.toggle('badge-gray', phoneOnly); + } if (required) { - required.textContent = emailAndPhone ? 'По выбору способа' : 'Обязательно'; - required.classList.toggle('badge-blue', !emailAndPhone); - required.classList.toggle('badge-gray', emailAndPhone); + required.textContent = phoneOnly ? 'Необязательно' : (emailAndPhone ? 'По выбору способа' : 'Обязательно'); + required.classList.toggle('badge-blue', !phoneOnly && !emailAndPhone); + required.classList.toggle('badge-gray', phoneOnly || emailAndPhone); } }, diff --git a/adminx/modules/Customers/module.php b/adminx/modules/Customers/module.php index 41e9651..dc602f7 100644 --- a/adminx/modules/Customers/module.php +++ b/adminx/modules/Customers/module.php @@ -17,7 +17,7 @@ use App\Adminx\Customers\GlobalSearchProvider; return array( - 'code' => 'customers', 'name' => 'Пользователи сайта', 'version' => '0.10.2', + 'code' => 'customers', 'name' => 'Пользователи сайта', 'version' => '0.10.3', 'permissions' => array('key' => 'customers', 'items' => array( array( 'code' => 'view_customers', diff --git a/adminx/modules/Customers/view/index.twig b/adminx/modules/Customers/view/index.twig index 12b0d43..27263c1 100644 --- a/adminx/modules/Customers/view/index.twig +++ b/adminx/modules/Customers/view/index.twig @@ -73,7 +73,7 @@

Создание аккаунта

Кто может зарегистрироваться и когда станет доступен вход.

- +
@@ -83,7 +83,7 @@

Поля регистрации по email

Для регистрации по телефону достаточно номера и SMS-кода. Остальные данные пользователь заполнит в профиле.

ПолеПоказыватьОбязательное
-
Email{{ auth_settings.registration_gate == 'email_phone' ? 'Запрашивается только при выборе регистрации по email' : 'Логин и канал подтверждения регистрации по email' }}{{ auth_settings.registration_gate == 'email_phone' ? 'В email-форме' : 'Показывается' }}{{ auth_settings.registration_gate == 'email_phone' ? 'По выбору способа' : 'Обязательно' }}
+
Email{{ auth_settings.registration_gate == 'phone' ? 'Не используется для входа; можно добавить в профиле как контакт' : (auth_settings.registration_gate == 'email_phone' ? 'Запрашивается только при выборе регистрации по email' : 'Логин и канал подтверждения регистрации по email') }}{{ auth_settings.registration_gate == 'phone' ? 'Только в профиле' : (auth_settings.registration_gate == 'email_phone' ? 'В email-форме' : 'Показывается') }}{{ auth_settings.registration_gate == 'phone' ? 'Необязательно' : (auth_settings.registration_gate == 'email_phone' ? 'По выбору способа' : 'Обязательно') }}
ИмяОсновное имя пользователяВсегда
ФамилияДополняет отображаемое имя
ТелефонКонтакт для заказов и доставки
diff --git a/system/App/Common/PublicAuthSettings.php b/system/App/Common/PublicAuthSettings.php index bf11ad3..fbd4fd6 100644 --- a/system/App/Common/PublicAuthSettings.php +++ b/system/App/Common/PublicAuthSettings.php @@ -78,6 +78,18 @@ return $gate === $method || $gate === 'email_phone'; } + /** Password login is disabled when public access is configured as phone-only. */ + public static function allowsPasswordLogin(array $settings = null) + { + $settings = $settings === null ? self::all() : $settings; + $gate = isset($settings['registration_gate']) + ? strtolower(trim((string) $settings['registration_gate'])) + : 'email'; + if ($gate === 'both') { $gate = 'email_phone'; } + + return $gate !== 'phone'; + } + protected static function defaults(array $fallback) { return array( diff --git a/system/App/Frontend/Auth/Controller.php b/system/App/Frontend/Auth/Controller.php index 6e0f86a..695d08d 100644 --- a/system/App/Frontend/Auth/Controller.php +++ b/system/App/Frontend/Auth/Controller.php @@ -47,6 +47,10 @@ return $this->redirect(Feature::url('overview')); } + if (!Feature::passwordLoginEnabled()) { + return $this->loginError('Вход по паролю отключён. Используйте код из SMS.', 403); + } + if (!$this->verifyCsrf()) { return $this->loginError('Сессия устарела. Обновите страницу.', 403); } diff --git a/system/App/Frontend/Auth/Feature.php b/system/App/Frontend/Auth/Feature.php index e28cae9..8c68966 100644 --- a/system/App/Frontend/Auth/Feature.php +++ b/system/App/Frontend/Auth/Feature.php @@ -100,6 +100,11 @@ })); } + public static function passwordLoginEnabled() + { + return PublicAuthSettings::allowsPasswordLogin(self::$config); + } + public static function page($key) { return isset(self::$config['pages'][$key]) ? self::$config['pages'][$key] : array(); diff --git a/system/App/Frontend/Auth/Renderer.php b/system/App/Frontend/Auth/Renderer.php index 08d54bc..4c972b7 100644 --- a/system/App/Frontend/Auth/Renderer.php +++ b/system/App/Frontend/Auth/Renderer.php @@ -36,7 +36,7 @@ $displayUser = $user ?: $systemUser; $accountLinks = Hooks::filter('auth.account.links', array()); if (!is_array($accountLinks)) { $accountLinks = array(); } - $html = (new FormTemplateRepository())->render('panel', array( + $context = array( 'base' => $base, 'csrf' => Session::csrfToken(), 'return_url' => self::returnUrl(), @@ -49,20 +49,26 @@ 'admin_url' => AdminLocation::url('/'), 'registration_enabled' => Feature::registrationFormEnabled(), 'password_reset_enabled' => !empty(Feature::config()['password_reset_enabled']), + 'password_login_enabled' => Feature::passwordLoginEnabled(), 'auth_urls' => Feature::urls(), 'login_page' => Feature::page('login'), 'oauth_providers' => ProviderRegistry::publicItems(), 'phone_providers' => PhoneProviderRegistry::publicItems(), 'account_extension_links' => $accountLinks, 'error' => (string) $error, - )); + ); + $html = (new FormTemplateRepository())->render('panel', $context); + if (empty($context['password_login_enabled']) + && preg_match('/name\s*=\s*["\']user_login["\']/i', $html)) { + $html = Twig::twig()->render('@system_auth/panel.twig', $context); + } if (!$includeAssets) { return $html; } - return '' - . '' + return '' + . '' . $html; } @@ -80,11 +86,17 @@ 'preview' => false, 'oauth_providers' => ProviderRegistry::publicItems(), 'phone_providers' => PhoneProviderRegistry::publicItems(), + 'password_login_enabled' => Feature::passwordLoginEnabled(), 'email_registration_enabled' => Feature::emailRegistrationEnabled(), 'phone_registration_enabled' => Feature::phoneRegistrationEnabled(), 'registration_phone_providers' => Feature::phoneRegistrationProviders(), ), $data); $html = (new FormTemplateRepository())->render($template, $context); + if ($template === 'login' && empty($context['password_login_enabled']) + && preg_match('/name\s*=\s*["\']user_login["\']/i', $html)) { + $html = Twig::twig()->render('@system_auth/login.twig', $context); + } + if ($template === 'register' && empty($context['email_registration_enabled']) && preg_match('/name\s*=\s*["\']email["\']/i', $html)) { $html = Twig::twig()->render('@system_auth/register.twig', $context); @@ -120,8 +132,8 @@ $html = '
Предпросмотр формыОтправка данных отключена.
' . $html; } - $html = '' - . '' + $html = '' + . '' . $html; PublicModuleRuntime::deferPage($html, array( 'title' => isset($context['title']) ? (string) $context['title'] : (isset($page['title']) ? (string) $page['title'] : ''), @@ -132,6 +144,13 @@ return ''; } + protected static function assetVersion($name) + { + $file = __DIR__ . '/assets/' . basename((string) $name); + $modified = is_file($file) ? @filemtime($file) : false; + return $modified === false ? '1' : (string) $modified; + } + protected static function returnUrl() { $query = Request::queryString(); diff --git a/system/App/Frontend/Auth/assets/auth.js b/system/App/Frontend/Auth/assets/auth.js index 2dcf8c5..5ed37f0 100644 --- a/system/App/Frontend/Auth/assets/auth.js +++ b/system/App/Frontend/Auth/assets/auth.js @@ -59,6 +59,41 @@ message.classList.toggle('is-error', !!error); } + function phoneDigits(value) { + var digits = String(value || '').replace(/\D/g, ''); + if (digits.charAt(0) === '8') { digits = '7' + digits.slice(1); } + if (digits.charAt(0) !== '7') { digits = '7' + digits; } + return digits.slice(0, 11); + } + + function formatPhone(value) { + var digits = phoneDigits(value); + var local = digits.slice(1); + var result = '+7'; + if (local.length > 0) { result += ' ' + local.slice(0, 3); } + if (local.length > 3) { result += ' ' + local.slice(3, 6); } + if (local.length > 6) { result += '-' + local.slice(6, 8); } + if (local.length > 8) { result += '-' + local.slice(8, 10); } + return result; + } + + function applyPhoneMask(input) { + if (!input) { return; } + input.value = formatPhone(input.value); + } + + document.addEventListener('focusin', function (event) { + var input = event.target.closest('[data-phone-mask]'); + if (!input) { return; } + applyPhoneMask(input); + }); + + document.addEventListener('input', function (event) { + var input = event.target.closest('[data-phone-mask]'); + if (!input) { return; } + applyPhoneMask(input); + }); + function phoneCountdown(root, seconds) { var button = root.querySelector('[data-phone-auth-resend]'); var remaining = Math.max(0, Number(seconds) || 0); diff --git a/system/App/Frontend/Auth/view/login.twig b/system/App/Frontend/Auth/view/login.twig index 8d46b07..898fead 100644 --- a/system/App/Frontend/Auth/view/login.twig +++ b/system/App/Frontend/Auth/view/login.twig @@ -3,6 +3,7 @@
{% if page.description %}

{{ page.description }}

{% endif %} {% if error %}{% endif %} + {% if password_login_enabled %}
@@ -12,6 +13,7 @@
{% if config.password_reset_enabled %}Забыли пароль?{% endif %}
{% if registration_enabled %}

Нет аккаунта? Зарегистрироваться

{% endif %}
+ {% endif %} {% include '@system_auth/phone.twig' %} {% include '@system_auth/oauth.twig' %}
diff --git a/system/App/Frontend/Auth/view/panel.twig b/system/App/Frontend/Auth/view/panel.twig index 6576941..6cb5ebc 100644 --- a/system/App/Frontend/Auth/view/panel.twig +++ b/system/App/Frontend/Auth/view/panel.twig @@ -32,6 +32,7 @@
  • + {% if password_login_enabled %}
    @@ -48,6 +49,9 @@
    + {% else %} + Войти по телефону + {% endif %}
    {% if registration_enabled %} diff --git a/system/App/Frontend/Auth/view/phone.twig b/system/App/Frontend/Auth/view/phone.twig index 67b8097..996244e 100644 --- a/system/App/Frontend/Auth/view/phone.twig +++ b/system/App/Frontend/Auth/view/phone.twig @@ -1,14 +1,14 @@ {% if phone_providers %} {% set phone_provider = phone_providers|first %}
    -
    {{ phone_auth_registration|default(false) ? (email_registration_enabled ? 'или зарегистрируйтесь по телефону' : 'Регистрация по телефону') : 'или войдите по телефону' }}
    +
    {{ phone_auth_registration|default(false) ? (email_registration_enabled ? 'или зарегистрируйтесь по телефону' : 'Регистрация по телефону') : ((password_login_enabled is defined and not password_login_enabled) ? 'Вход по номеру телефона' : 'или войдите по телефону') }}
    - +
    {% if phone_provider.allow_registration and phone_registration_enabled %} diff --git a/system/App/Frontend/DocumentRepository.php b/system/App/Frontend/DocumentRepository.php index 4a00502..6b44075 100644 --- a/system/App/Frontend/DocumentRepository.php +++ b/system/App/Frontend/DocumentRepository.php @@ -131,7 +131,7 @@ public function findNotFoundPage($documentId, $userGroupId) { - return $this->findWithPageContext($documentId, $userGroupId, false); + return $this->findForPage($documentId, $userGroupId); } protected function findWithPageContext($documentId, $userGroupId, $includeAlternateTemplate) diff --git a/system/release.php b/system/release.php index 77b0849..e726c4b 100644 --- a/system/release.php +++ b/system/release.php @@ -17,5 +17,5 @@ return array( 'product' => 'AVE.cms', 'version' => '3.3', - 'build' => '0.39', + 'build' => '0.40', );