From 8e102d3729e9aa8839ca133f55bac02e92989ada Mon Sep 17 00:00:00 2001 From: "AVE.cms" Date: Mon, 27 Jul 2026 15:54:12 +0300 Subject: [PATCH] AVE.cms 3.3 build 0.32 --- .gitignore | 45 ++++--- PACKAGE-MANIFEST.json | 90 ++++--------- README.md | 15 +-- adminx/modules/Blocks/Controller.php | 8 ++ adminx/modules/Catalog/Controller.php | 9 +- adminx/modules/Groups/Model.php | 2 - adminx/modules/Templates/TagRegistry.php | 8 +- changelog.txt | 0 help/database/README.md | 2 +- help/database/tables.md | 10 +- help/en/database/README.md | 2 +- help/en/database/tables.md | 10 +- system/App/Common/Cache.php | 5 + system/App/Common/ModuleManager.php | 2 +- system/App/Common/OutboundHttpClient.php | 15 +++ system/App/Common/Session.php | 2 +- .../Content/Blocks/ContentBlockRegistry.php | 5 + .../Content/Fields/DocumentRelationValue.php | 1 + .../Fields/Templates/date/field-req-177.php | 19 --- .../Fields/Templates/date/field-req-185.php | 17 --- .../Fields/Templates/date/field-req-187.php | 17 --- .../doc_from_rub_search/field-req-137.php | 18 --- .../doc_from_rub_search/field-req-180.php | 18 --- .../Templates/image_mega/field-doc-22-1.php | 20 --- .../Templates/image_mega/field-doc-22-2.php | 24 ---- .../Templates/image_mega/field-doc-22.php | 27 ---- .../Templates/image_mega/field-req-22.php | 21 --- .../Templates/image_multi/field-doc-123.php | 27 ---- .../Templates/image_multi/field-req-22.php | 18 --- .../Templates/image_single/field-doc-14.php | 27 ---- .../Templates/image_single/field-doc-18.php | 19 --- .../Templates/image_single/field-req-14.php | 19 --- .../Templates/image_single/field-req-142.php | 19 --- .../Templates/image_single/field-req-159.php | 22 ---- .../Templates/multi_links/field-doc-137.php | 20 --- .../Templates/multi_links/field-doc-181.php | 25 ---- .../single_line_numeric/field-doc-200.php | 16 --- .../single_line_numeric/field-req-157.php | 16 --- system/App/Content/PaymentPrograms.php | 10 +- .../Auth/OAuth/IdentityRepository.php | 1 + .../Frontend/Auth/Phone/PhoneAuthService.php | 1 + system/App/Frontend/Feeds/FeedPresets.php | 123 ++++++++++-------- system/release.php | 2 +- 43 files changed, 196 insertions(+), 581 deletions(-) delete mode 100644 changelog.txt delete mode 100644 system/App/Content/Fields/Templates/date/field-req-177.php delete mode 100644 system/App/Content/Fields/Templates/date/field-req-185.php delete mode 100644 system/App/Content/Fields/Templates/date/field-req-187.php delete mode 100644 system/App/Content/Fields/Templates/doc_from_rub_search/field-req-137.php delete mode 100644 system/App/Content/Fields/Templates/doc_from_rub_search/field-req-180.php delete mode 100644 system/App/Content/Fields/Templates/image_mega/field-doc-22-1.php delete mode 100644 system/App/Content/Fields/Templates/image_mega/field-doc-22-2.php delete mode 100644 system/App/Content/Fields/Templates/image_mega/field-doc-22.php delete mode 100644 system/App/Content/Fields/Templates/image_mega/field-req-22.php delete mode 100644 system/App/Content/Fields/Templates/image_multi/field-doc-123.php delete mode 100644 system/App/Content/Fields/Templates/image_multi/field-req-22.php delete mode 100644 system/App/Content/Fields/Templates/image_single/field-doc-14.php delete mode 100644 system/App/Content/Fields/Templates/image_single/field-doc-18.php delete mode 100644 system/App/Content/Fields/Templates/image_single/field-req-14.php delete mode 100644 system/App/Content/Fields/Templates/image_single/field-req-142.php delete mode 100644 system/App/Content/Fields/Templates/image_single/field-req-159.php delete mode 100644 system/App/Content/Fields/Templates/multi_links/field-doc-137.php delete mode 100644 system/App/Content/Fields/Templates/multi_links/field-doc-181.php delete mode 100644 system/App/Content/Fields/Templates/single_line_numeric/field-doc-200.php delete mode 100644 system/App/Content/Fields/Templates/single_line_numeric/field-req-157.php diff --git a/.gitignore b/.gitignore index 6cb2ae1..5be2119 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,35 @@ .DS_Store -# Runtime configuration +# IDE / local tooling +/.idea/ +/.vscode/ +/.claude/ +/.agents/ + +# Node dependencies +/node_modules/ + +# Composer dev dependencies (тесты). composer.json/composer.lock — в гите. +/vendor/ +/.phpunit.result.cache + +# Runtime configuration / secrets /configs/db.config.php -# Runtime state and secrets -/storage/* -!/storage/.htaccess +# Runtime data +/tmp/ +/uploads/ +/storage/backups/ +/storage/releases/ +/storage/runtime/ +/storage/secrets/ +/storage/updates/ +/storage/installed.lock +/sample/ +/demo/ +/landing-old/ +/banned/active/ +/banned/block/ -# Cache, logs and sessions -/tmp/* -!/tmp/.htaccess - -# Uploaded files -/uploads/* -!/uploads/.htaccess -!/uploads/index.php - -# Installed optional modules -/modules/* +# Generated caches / logs +*.log diff --git a/PACKAGE-MANIFEST.json b/PACKAGE-MANIFEST.json index 37c4f63..4906586 100644 --- a/PACKAGE-MANIFEST.json +++ b/PACKAGE-MANIFEST.json @@ -2,18 +2,19 @@ "format": "ave-core-package-v2", "product": "AVE.cms", "version": "3.3", - "build": "0.31", + "build": "0.32", "package": "core", - "built_at": "2026-07-27T09:53:48+00:00", + "built_at": "2026-07-27T12:48:15+00:00", "installed_modules": 0, "bundled_optional_modules": [], "optional_after_install": [ "setup/" ], - "core_fingerprint": "2a79bbbfa29729ad2c31f47f5496f632384f6abc0e62ec888b45e4a18b77b5cc", + "core_fingerprint": "7e65e16538e861c03bc15322b9642d07f75830abec0a852da54ce22431887dc5", "files": { + ".gitignore": "e2c156d23abc1be6e5a61c9478bb3f1c2b31eea9c7ff2f5e8bd768745638bd93", ".htaccess": "71c06b7bc41b09c347a562ca72768acaa0ee1ef8388c749fc67956c793d8a826", - "README.md": "f1d366f4f481b866bf67b8c35c766bbf74eb7534ab1a1caf055f47b6720b5fe3", + "README.md": "9660a68a4a9f99436a32e219d3cabd5b373caecd7b41404a637d95a4626cb464", "adminx/.htaccess": "d03ea2d2972af8b7545a2d57c6253f303d15adeb30b775e161d887ca5ff73378", "adminx/Support/AdminLocale.php": "a7fe84d86d65c9f021106172b1789c8bc6221c36b2fe39cf883ca9a505e3e8ad", "adminx/Support/CodeEditor.php": "51532980b1990e595b796d884c1a8bcc46f77f88344386e5153b4bef4cae973c", @@ -150,7 +151,7 @@ "adminx/modules/Auth/language/ru/runtime.xml": "94f025e2ddd2327ced6aa4740dba80025ae1d71b08f2ce6bd7de9a222277e058", "adminx/modules/Auth/module.php": "da1ef0924fdaee46a2c1333c43ed05d3afcb02ca16f1994b0eea840a657a4f12", "adminx/modules/Auth/view/login.twig": "9848bfbd9da64798c3ba4508dbf7bd413541c3e6870ea95fe3bdf07d12133b95", - "adminx/modules/Blocks/Controller.php": "891d958a63e9bc60eeb947b5535a61de3f338428aba9c3f9e38b8dd72c27c880", + "adminx/modules/Blocks/Controller.php": "5665327885171e07f87823b473f97e22f416ab896471a25ff7a2dff498a30d22", "adminx/modules/Blocks/Model.php": "1a6d971f4a777e3f91385271ae8e207bacb10cdc1e236921f43a9578f6f9bcb5", "adminx/modules/Blocks/Revisions.php": "b67cfbad6830a30dd7f99f5dc4108b33f2bc5d40fe979cab6fb03c3c8f749577", "adminx/modules/Blocks/Syntax.php": "9b2eb8d40171633cdbef6cf21545958f801f4983d62176e9256bec8e4763a624", @@ -174,7 +175,7 @@ "adminx/modules/Blocks/migrations/012_merge_visual_blocks.php": "5c9cd6efd66a027134621859da1059b2c403bacb732885d6b405699cbce8fc14", "adminx/modules/Blocks/module.php": "e196ec71bc17da48f9e1663f74db4a7de8fcd28d0f32a3f36beebd8247656322", "adminx/modules/Blocks/view/index.twig": "39f9225b6a95c65549d0c861afb7db7879ca338c251290653dded6ab7cb715cc", - "adminx/modules/Catalog/Controller.php": "ef5819e817071525e6c987194d2569455c0d6be5ad76b4dff6b30e76019159a7", + "adminx/modules/Catalog/Controller.php": "e9f7add9ea4724221259589d1a861d0233895a150c5a14942325a74a46ac6018", "adminx/modules/Catalog/Model.php": "e7c7cffd91754e04dac322c31a64b420739c671079a7f8e7effb550f5019ee13", "adminx/modules/Catalog/assets/catalog-drawer.css": "07ac184a0fbc18954117d5e4d559574400cf6cb7d9b511d852120c00cf17a059", "adminx/modules/Catalog/assets/catalog.css": "5587eed0a0c7d22fb8e841b238df2f9477857b0c75d90f232c5816897ee6bfce", @@ -304,7 +305,7 @@ "adminx/modules/Events/module.php": "d506c314dfc71abe7216ec80243f46549a833a6cc3371333d1e7a6435312c46b", "adminx/modules/Events/view/index.twig": "eade5c87c3cb76dd8ea4795ad72927848a40fb0f042e4938bf31d785f8c33b4b", "adminx/modules/Groups/Controller.php": "37959bbc4cf73ea2968616c195763fbd1bbe14cea90c01d4dae5fad2970803d6", - "adminx/modules/Groups/Model.php": "6ebd6edc714a580c6123b3298249c596c0e510d55af0e2faf2e83c4ddd084371", + "adminx/modules/Groups/Model.php": "889ba3e4c93ee59ddd6515f4fa4b5ce4c82335e91b3dc6eb315dd095ce6f8fa2", "adminx/modules/Groups/Setup.php": "b7140a87474e343455fa81809f8f8f2dfe7e1ee3640c5f024a1bb06ebd783865", "adminx/modules/Groups/assets/groups.css": "6d16a57db9ab5f42f8722b52dcecefb02a51d68360b9855187dfece83b36191d", "adminx/modules/Groups/assets/groups.js": "1e8e6c9b183cae19587e823f037e2dec5e69aedf10629c555edeffe68369a64b", @@ -481,7 +482,7 @@ "adminx/modules/Templates/Model.php": "4f7a9082f462170533c0c140ef085f6a33111d20061b464864eb86066d50289f", "adminx/modules/Templates/Revisions.php": "59ddb9b0e65ce12df10a6c1d370c5988ecfe14307852bc157731f7a13b16e0c8", "adminx/modules/Templates/Syntax.php": "a0172c03a4e091f5fcaafde39713189bc341c1cf7ac9ae1eed50c5cec657bd24", - "adminx/modules/Templates/TagRegistry.php": "3c6b4f15a60597d909f9f2d16b0c78791293a9d053a1c2ee8f9a9f8bdcce9d3d", + "adminx/modules/Templates/TagRegistry.php": "85344896cf21767c67b19092830e1ee9545b21067f1e43140efe2faf6eca2731", "adminx/modules/Templates/assets/templates.css": "083100ac836b6b1cdf3f8e2d3ed9dac08bc4504dd6f8299562df24dd133a50d3", "adminx/modules/Templates/assets/templates.js": "6684f9d2c1f3a956fb111035b5390dd62ca2afa79ca75cc0acde84a8715d1f81", "adminx/modules/Templates/language/en/client.xml": "d7280440a3c00674ae2db6a2c837a8114fbfd4fa27590b7e0ddd72395fb08887", @@ -540,7 +541,6 @@ "adminx/view/auth.twig": "e44eb6337248470418be7015886e6e5d7bf5b0021fc917f4cc0dcd98c6492d85", "adminx/view/error.twig": "1187e6d0c325e0bbf6a7bd9836a5ef6d96cb8f72a0599050d3da7120683a6202", "adminx/view/main.twig": "2ec8f2ffd5d6d3f2fd45027ab30cc9c8a611b0dd4e0c5baa081fce8021a3fb43", - "changelog.txt": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "configs/db.config.example.php": "e42bdb47aa7d1bc9cd85cb36e05acf940cafd951d6220664c485d1b971f18809", "configs/index.php": "48e6b249e3d83530187c095ede0198af498c59f384bd458db74f9e0c2306eba9", "configs/public.config.php": "7047f7acfb9f64e56c7320c3cdc306522a187f5f9e12cef6e95937446ee07441", @@ -574,14 +574,14 @@ "help/core/permissions.md": "3147cfd90fd1139961822505e611c444e54bea4ab66b86f1c0da121301fcc57a", "help/core/routing.md": "320dbb50b97f918fff0f24d8c7f6a7acd6e1d5c29f9dd4c73d56619c09b2204f", "help/core/sessions-csrf.md": "08ac0274e31ca93b90f0e58879027668bacc09878049647bf8b3d0cb1b04f0f9", - "help/database/README.md": "8177fe10ce6cc44ad4f33c2c4c05a7d6af8491346e025869cdf4d04f1593be15", + "help/database/README.md": "c98f5c272d60b9ca69fc4bc6fe391f04a243021dd37af7b95ed10fe2c30f72ae", "help/database/cache.md": "705197358a0d2cfc876a1d221d47bf1867a4e95957f446737fa3a54ecf3b1692", "help/database/crud.md": "c1358a4943e19f36aa558300700cd9fd701ae16c2d069561ed7ac214e7a8b344", "help/database/placeholders.md": "8e729e0fed961f221a936ea70c5b449206506ce3a7baf8e658f1b3714da34a4e", "help/database/queries.md": "ab557fcf9f31e8409501902c299e939747b5a222f19457515bf0d150084ca63e", "help/database/results.md": "c32999f9945a18917445947f8dcf3fb1c219d5546c0394cdfc53b17d89bae11e", "help/database/security.md": "581d5a89b5ea7cc01f7800878dd879b48e48a912f4a4c81c5f5dadd9b990e556", - "help/database/tables.md": "1bcc1bc26b4096d1a85aa1a8aa4f25297753edf9d74a344b2109dad51badabd7", + "help/database/tables.md": "a027eb9c5e3c65bce645e6a7afd8ad9e37adfcf2e514926836d8a14cb0258075", "help/database/transactions.md": "da679da1e7656be20048566f25b51c6018a0d7eff1f2e5d54228fb3d54071aff", "help/debug/README.md": "41b7954c443330efe28cd3a14519c7c8076165a9d96c0dc3d3781a111e757085", "help/debug/custom-data.md": "445ed27dbda5b0ca035504e2f0cda023746def5edd3aa1f62189e133946e293b", @@ -615,14 +615,14 @@ "help/en/core/permissions.md": "6e6f1d5d1c20c85f6e3d71aa3f4a7de8e822ca08358aae38981bc7f7082b13ec", "help/en/core/routing.md": "24c3ef29ca9882ea0b76cb3d449cc74dd544038b5310d43f7f1fefcab9ad1645", "help/en/core/sessions-csrf.md": "9658e34c59e3f2b76577efa3f889500eab141f08adad94e2d27e5751b7731c26", - "help/en/database/README.md": "11ace925ab12df0eb704c4be3145a40f34d724de0f1dd8be298ae28a056f9cae", + "help/en/database/README.md": "613b076e9db9452719342aa414f6d1569a83ebaf38550fff74793d35f917be69", "help/en/database/cache.md": "d2955c017f07d5a21117912d8d7b151debbabf1d120abf336ecbb40cfd8230c7", "help/en/database/crud.md": "6d98e6e2784e9c5733774164f58d4106c0fc0fed2c7dff9369e2fcbc8a982dbb", "help/en/database/placeholders.md": "7b9174018006fe78e1b334d522e1b0036f2f900c54b64e5bd4142beb64d0f7ff", "help/en/database/queries.md": "9e2f31009e9e012af8b8a06ae8fc4ca2872cfc45957ebe53d47135e4bc0a7aba", "help/en/database/results.md": "ec428e28364e7a3508716ed5df8cd0b1206516cdf98b43b54e69865663a87bf9", "help/en/database/security.md": "f2d0b218fe9ba8c8c5fcef2b6a832cebc58e0af26400a13f0c4a32d7d2ce1d93", - "help/en/database/tables.md": "a13431858a26ca867464a0d6a1c608f13d491e152e6ef345d4007acf323b0ca6", + "help/en/database/tables.md": "d117e9b6ecf04f8b8cbcc99e81874a09b84871dc8273a248ba676304f37e8c67", "help/en/database/transactions.md": "9cd1b15425647281d40d11d7d0453f8758a1c41859ce3bf1de5d091ccbf2246d", "help/en/debug/README.md": "4000fae72a034ec3be9d1059fd0e0a850efa8911dbd4b8498d8cb0b23ddfa4a0", "help/en/debug/custom-data.md": "0cd068b8d74bd98240bb86d9d4bc01d2630129eaeff8eec88b1630a094016f32", @@ -832,7 +832,7 @@ "system/App/Common/Auth/IdentityLinker.php": "c614215dc98de43a6dd31c7c4435cac3540acd886b0f450f6e0fdc1537276563", "system/App/Common/Auth/PublicUserNames.php": "0345d1f452e0a9accaa9b98eea71f27a428692a5b4f2ad225a10ad8bcf777684", "system/App/Common/Auth/PublicUserProvider.php": "b24beb04d30756d8f7ed30ace4d0e5f70882e5a28989080b6c377baffd8a77d3", - "system/App/Common/Cache.php": "9092c5409d874ea76d55630df10362946543f8051c6ab838572f4badfcf8c4d2", + "system/App/Common/Cache.php": "bb322246cbfa12cbcdd67c16a24c55715ad67b31d356b4f18091c0aa1d00eb9a", "system/App/Common/CacheKey.php": "47400cd90d1880d061995bfea585b56210e18a870607d9b1cf7f0eeaccf15032", "system/App/Common/CompiledModuleRegistry.php": "9ab055fa759f4041944bb94bfc2e28361986a09b742210981928bd6ee15f758e", "system/App/Common/Controller.php": "b80ca1f6f1f2cbff6effdcbdb9e9606b5aa9877922ab442cf7b1ae1798aa9f00", @@ -877,14 +877,14 @@ "system/App/Common/LoginThrottle.php": "de6550ad689f5743dee92e5071bbff1a12a68ffaadcbe08e2e5fffccc51f98d3", "system/App/Common/Logs.php": "d23e9a3ba1ef925b37b756d4dcbba47b42edaa0ad732804b4c99d1dd2c0d8ec5", "system/App/Common/ModuleLifecyclePreflight.php": "66749f25d63dde05a06cffeb75a0a22c5ead68e51ef6ac71578384fecd8520c9", - "system/App/Common/ModuleManager.php": "4ee256b23222b7501fb756e6e7b4422c53eca16540a9ffe0b2878c773d9a1479", + "system/App/Common/ModuleManager.php": "5f5ed1aa57e6d8884930ab4f5bf18077889eeacaa93ba66febbc7bbf9071defc", "system/App/Common/ModuleMigrator.php": "d9aea1aa006a1736d8314823053ecbb970cc7553f9af315b8b6fc092ffb07d83", "system/App/Common/ModuleSecretStore.php": "6ef62294077db7f09b85ce26f3167b39cd980547d1f21bee213b59a9c7e2e6da", "system/App/Common/ModuleSettings.php": "b3280ad547e59bfcefb4a338339a36905fab5db1548345b0f00e257d275a6294", "system/App/Common/ModuleTagRegistry.php": "9e68b64303825a25ef4f71f31a7adedee9d2752e4d1d06162605da1dc510a6a5", "system/App/Common/Navigation.php": "1a1b0a3552d941dc0fc59c334ab705e86a73ee96ee42871dc958012bec1d81f6", "system/App/Common/NotFoundLog.php": "3b1cdeefd05ae250e90d1a05dd9e1bc0ba2cb0c2cbb89d504fe009151f20452a", - "system/App/Common/OutboundHttpClient.php": "2b3f4beef15f399624e21abef4ea58b9a214b1f1e935ae3dad6531e34bb763e3", + "system/App/Common/OutboundHttpClient.php": "ef46209e2b093fc152000b050bad6d5d497489486e09abc78cceabc0176ed2d8", "system/App/Common/PackageModuleRuntime.php": "8afcbf0439fb3b69b6b9e098109eeb2fc1521d3435d5d2d654085d5bd2b2a470", "system/App/Common/Permission.php": "8e2241bca829de0104741dc2518860cd15489866dc310437e07aeab2bf0f0355", "system/App/Common/Proxy.php": "707564208ec8c24ac2ffb5bf41cba34f1b39059ce6bda31a69aaf4b116d864e2", @@ -905,7 +905,7 @@ "system/App/Common/RuntimeConstantSchema.php": "08daf898ed9bfa12940adf8ddcd3e0dac811d28de8b798770afc42cbd20f1125", "system/App/Common/RuntimeConstants.php": "decb1277dada75ee2b5c7d531f064db7ffecef5b3ad71d306111b2a45121d34f", "system/App/Common/RuntimeDirectoryGuard.php": "adc9ae97a5e5ae494e3b58073f195426daf2915bdae02c4e3e07312df272fa6b", - "system/App/Common/Session.php": "fc2c805cd57e622b5a030afa4bc9fd490055b82b7ff1993945ec664a536f7371", + "system/App/Common/Session.php": "4a870a109c75ca941bebfd798d64b1396dde7d56ec060d9491f7d71b70a13deb", "system/App/Common/Session/SessionDB.php": "6340cd88d5ce61ca39601347275547293a0b857cdd3978a4293eaa71076f83db", "system/App/Common/Session/SessionFiles.php": "9be6009241d0cf6f2f909ddc6881a3dc3cf1de0aefd5ef6103de8032c997dbf0", "system/App/Common/Session/SessionNative.php": "3ca6de1038e0b26e03e0797e9b1dc321ec383d85ad058503509d6b369d88168f", @@ -921,7 +921,7 @@ "system/App/Common/UploadPolicy.php": "a8ad388681a65a31981767c2d1c17f635f4c490a17803f35d3548a47758c596d", "system/App/Common/WebMaintenance.php": "a91f9ee8371da6c6a020d9ce39e1f9f7b517b2644ea51ada65f1f487ff337e6b", "system/App/Content/BasketTables.php": "1c4d1d9a5ff894c6ebb0edbcfd7bb6f791124e46dd8bed3b70fb0ef2c15069a0", - "system/App/Content/Blocks/ContentBlockRegistry.php": "54f8818bab252b8e1135f053cddb24e0c8cd91b9b395aad71e32a39db1ef5569", + "system/App/Content/Blocks/ContentBlockRegistry.php": "53bc204e7dd1f9d61781049627162341a4d7e656783915161fa5c4eae4cfa228", "system/App/Content/CatalogMenuRepository.php": "1ef7e4fac76f1b1571eb85611002cbb18bfd61829471fb189024c651efed8355", "system/App/Content/CatalogTables.php": "5abd93b17142ea5c57a0726c8c6e3dcaf896790cf4ba31ea69be19a828ac9517", "system/App/Content/ContactsTables.php": "d0042c761b854903b483e1b3a30d6014c596eef1a03c40cdbedae4fecb3c25d8", @@ -956,7 +956,7 @@ "system/App/Content/Fields/DocumentMediaFieldType.php": "f2a461a3780354159a915f4f107a479c7326f255357ee82eec25d3bfc658b4d1", "system/App/Content/Fields/DocumentRelationFieldTrait.php": "eb397fd4aabeea93cf4d280f7c680f10d92a17596bafaea8c3eddc4bedb17c78", "system/App/Content/Fields/DocumentRelationIndex.php": "40551bf019428d1f6f81f07f3b8f45d0ebdc349387303e4d9085c413d3453444", - "system/App/Content/Fields/DocumentRelationValue.php": "d5366bddfcceb62d0503da6e9e4e9bb612a57a96f85a2695c815b98d0100aaa0", + "system/App/Content/Fields/DocumentRelationValue.php": "44abfd5820a0e58f7d7bdfe3cc460bb0db3ff33433bb94aa50dc3d4ef9b9152c", "system/App/Content/Fields/FieldConditionEvaluator.php": "93ef44322ee4da475a2d7b7c0964d13578a67ededb3da8a5d7e5ebcd05aecf66", "system/App/Content/Fields/FieldContext.php": "97e4d4171bba1ce5c5185068c33eaeb91fdfab670b1ce3fc9f56e10f5cca1d0b", "system/App/Content/Fields/FieldInstallationAudit.php": "0e9817806c2a8b1f9ca64ce9c4f8bbc97942942d7e77fbb9fd62dbf6070a1216", @@ -974,26 +974,6 @@ "system/App/Content/Fields/PublicFieldTemplateContext.php": "785d6757710dee59d8d30756917235bb4f49eb5bd743c01d2365c05d74bf0a5a", "system/App/Content/Fields/PublicFieldTemplateResolver.php": "72c0750c50129cbabc0a97147fe2f2f4b2b3811cd77f4de197dc3753db46903a", "system/App/Content/Fields/SerialFieldType.php": "61685c9a19c0fe9aede73f16f7bdd730dc3562d6223e7b3d4eae5e3e303fce1f", - "system/App/Content/Fields/Templates/date/field-req-177.php": "4dddad6279ed747d2d4546108e22c6a3fef042d0d352be8c96de73d88639d4c2", - "system/App/Content/Fields/Templates/date/field-req-185.php": "23788ff41c2bf3331ed455e41ee0d51a27d7b195f6a7f376a4a3548cd0b6af81", - "system/App/Content/Fields/Templates/date/field-req-187.php": "fad69a87af9aaae52ab7a24cb88d49dac1d9f3ad604eb79cb24c6d9d8555909c", - "system/App/Content/Fields/Templates/doc_from_rub_search/field-req-137.php": "d6063dc9910e224a8e4c182e3e80d1eb5d91b1f150391a04c4cc58b2de64f375", - "system/App/Content/Fields/Templates/doc_from_rub_search/field-req-180.php": "1d9dd5820679cc4c65c93d2bba428e5d9028dbda0325f00639e777fe8aab550d", - "system/App/Content/Fields/Templates/image_mega/field-doc-22-1.php": "5b7c3e6a0bb9085f1622ba5114c8887f34007c011b3e931b555514fc43687c14", - "system/App/Content/Fields/Templates/image_mega/field-doc-22-2.php": "8b7b566dc64cd6fd9993fdf7542e52977629cf33ccfd02fe0eb98cdee07db7de", - "system/App/Content/Fields/Templates/image_mega/field-doc-22.php": "cab8ad33b2e780c305c4793126e66f393639176db917c102ecfb93e24b563488", - "system/App/Content/Fields/Templates/image_mega/field-req-22.php": "dab5bb2cafc214f195c53dd4032451c857e0e225056b0ba83599da7eb01cba36", - "system/App/Content/Fields/Templates/image_multi/field-doc-123.php": "d8b51ba166248b65eacacdce86d52dd69d7a3140f2ee23510df54200938ec25f", - "system/App/Content/Fields/Templates/image_multi/field-req-22.php": "da544da1c22a7d276da5921589b84ae52c5f6ff522143170de521e09ae209049", - "system/App/Content/Fields/Templates/image_single/field-doc-14.php": "67acf2ec1ee7600a1d2ef8a23567d457a858d5b43eff3bc687d77378d2d71c42", - "system/App/Content/Fields/Templates/image_single/field-doc-18.php": "ce9188feb56e64e61faad54674376d2822a15a544f1841163ca708442f84e5f0", - "system/App/Content/Fields/Templates/image_single/field-req-14.php": "8bf6ffd26a5a861ae844c35fc8539532fa71c0bde40eb297cceef9a00fa431e2", - "system/App/Content/Fields/Templates/image_single/field-req-142.php": "13f0db85d7c077e96ae8c8e32a854fc29f5d7259843b10ac62cedcad61d090f7", - "system/App/Content/Fields/Templates/image_single/field-req-159.php": "7692d5f09db63ca8bdd36871904b0ae1906488be5fd795347bde02d15881e9f7", - "system/App/Content/Fields/Templates/multi_links/field-doc-137.php": "c490f9d98503dc3b9f0e55ee6287ea508c358b6cb636f8984293e1c01a9d4864", - "system/App/Content/Fields/Templates/multi_links/field-doc-181.php": "e7cff37603f088d32c3dda333f5d47d6930e15e84baede7519539d714b0fab66", - "system/App/Content/Fields/Templates/single_line_numeric/field-doc-200.php": "c5ccd1afe8938f8459a14e9199b39190eee7ffc3e15a8bdcfddaa2e7875b0b27", - "system/App/Content/Fields/Templates/single_line_numeric/field-req-157.php": "50ceb1ac667ee0bf5f8bcc46d07343023fd89087f357ea701ca9d31f89e7194e", "system/App/Content/Fields/Types/AddressValue.php": "ae244e819453247a385f604b7ee4df3735bb6474346686bc29a0cc32c35133ec", "system/App/Content/Fields/Types/Analoque.php": "d4169e7474f700831a5b572163a75185e410447c2f6c56050226fdbcc5a61e19", "system/App/Content/Fields/Types/Catalog.php": "2126e5a6bcb097f96c5851a8b84a5fbbf04c0c83de200491b9a68d51caf5b597", @@ -1046,7 +1026,7 @@ "system/App/Content/Packages/ContentPackageWriter.php": "dea33706a29e11d2a04ca6904bad49f8ff6c062b2cc1eeef1bf9ba18f49adb00", "system/App/Content/Packages/PackageDependencyContext.php": "8a1f8ca6bbb7add9d8af11d28cdf7137c9a9eaf25b528b0259cf9bd0be00c8b7", "system/App/Content/Packages/PackageModuleProvisioner.php": "28a922ac5471d86ea0c467de11164c97fecd0ee432814e79927bb875995629cc", - "system/App/Content/PaymentPrograms.php": "3f6a6c1b5297001d0ee5027fa6fccb2323d5a603abd045421a83cba65e4e0ec8", + "system/App/Content/PaymentPrograms.php": "d233564780b9ab9655f8c41c490aad207c95731f36e6967fb52ac54b9c89e52e", "system/App/Content/ProductShipping.php": "4a33a877983a8509ce35fdd88ed95db43591d3b35d5e4f5d9a5b67c566434c9b", "system/App/Content/PublicShellTables.php": "f89cd224436da9d1122c988a3a0ac19e5bef85351c51649506fe16a05c514cd9", "system/App/Content/PublicUserTables.php": "56745969410ab9e8e4272103657f805e346336db34166461de7f2113a6a52ac2", @@ -1072,14 +1052,14 @@ "system/App/Frontend/Auth/Feature.php": "60ff394cbf95ea3ca3f35476a6eb2bc4016fe472be85cd11ebac117635a54440", "system/App/Frontend/Auth/FormTemplateRepository.php": "97882ee4b46e0c4e31493a44831564409b5a64c096363aaf812f181d13abae64", "system/App/Frontend/Auth/OAuth/HttpClient.php": "b09acf92b312bd05ca78500fccaac3b77d36a1046d64d3615a00d60af4e3594f", - "system/App/Frontend/Auth/OAuth/IdentityRepository.php": "41cca9011a1f0e56090cc40361594ba223316516997d52384a29fdebfba6a707", + "system/App/Frontend/Auth/OAuth/IdentityRepository.php": "35ab143e0d536185125c685f17f5f4bb0ba0cc72daba62552ef6f82370e38ec1", "system/App/Frontend/Auth/OAuth/OAuthFlow.php": "842e9c9bea61578bdf124dc8bd1921e5c505349822a95e5812bf09e2710f2278", "system/App/Frontend/Auth/OAuth/OAuthService.php": "c310a2a6756425a4b2875b12c048b0476dd5b424e89561ac1fa73aebfb3cf045", "system/App/Frontend/Auth/OAuth/ProviderInterface.php": "c99525fd51a1bebc24c189f52f1a08bcef087b98ffa960d1b378deb68022d9ba", "system/App/Frontend/Auth/OAuth/ProviderRegistry.php": "e0ff4bc12ef2349d4f914299c78715438d9fbd44ab98e00937534786baa07800", "system/App/Frontend/Auth/Phone/ChallengeRepository.php": "1e53d355aaf0adcc8e10a2b1b50e638916fd688c62a7ed6a4bd9c161c14a6390", "system/App/Frontend/Auth/Phone/Controller.php": "bb07bfb74a89742c2dbeeb7edf79f02ae43ef6a252d02a3bb7c3c78144cf280d", - "system/App/Frontend/Auth/Phone/PhoneAuthService.php": "90e96d1616df285713dd9f41f84af5a21aee2af3f1ddf8ef86dfba619f6ecd62", + "system/App/Frontend/Auth/Phone/PhoneAuthService.php": "816a29b7102b8dd58d3c46d4e563f83beda0397b037bc17377f1f8d4fc8545b0", "system/App/Frontend/Auth/Phone/ProviderInterface.php": "55107c8f6a89bea01b91314dfe523b684bccf5bf9f1a3c8f047fd3a509aa6d00", "system/App/Frontend/Auth/Phone/ProviderRegistry.php": "fbeb488c9b63843085b680500ecafd61389a29f55e0d76692550939e378d2f16", "system/App/Frontend/Auth/ProfileRepository.php": "9cd7be35b048faf407a925e6369a5895b8bfafe6cf756eb3c4321ea4979a9af6", @@ -1131,7 +1111,7 @@ "system/App/Frontend/ExternalContentDispatcher.php": "e9fca1fff73d2b819a46b8817f1e070f71d93563342ea2044631b21decf067f4", "system/App/Frontend/Feeds/Controller.php": "2d446f4bb973c781ce01bf4831721b3e5fac1f6e1642f1862d86da8e8f4c271d", "system/App/Frontend/Feeds/Feature.php": "1322bf61d4296c79ad8825671ed556cca79bc9b2eed46cbee8b4f70d19f6ca6b", - "system/App/Frontend/Feeds/FeedPresets.php": "96123dc9dd5c82a325db64092681b79e9f1b00997a697f6bf26e7d49c732cd26", + "system/App/Frontend/Feeds/FeedPresets.php": "bff8edea9f095a63fa2c127ee6afb35c5a3ce4434ca309e9a8a7dd047ba16428", "system/App/Frontend/Feeds/Generator.php": "4234369a293bad237fe0d36dd3c78da616d03ce37070ac72988893f796773da9", "system/App/Frontend/Feeds/PathController.php": "faf72ea5ba08256c8566a5ee9a73adfcabd59ef0f510c108a6003b659659635b", "system/App/Frontend/Feeds/Repository.php": "d45113f59327efbba03747f2acafee018e0253815838275f3a6879cdee939584", @@ -1228,7 +1208,7 @@ "system/language/ru/lang.xml": "7d46cc9822f064a1af4d6528ccfe2dd4a9cc318912e327fd807befd2ca3dfd11", "system/preload.php": "66bfb1aaf36ba85945b729b09a37e96ead0be1cc2749ebd9abd4b9da4f25ba0e", "system/public.php": "3f72b5bf44bc0ba5ba6fb6b3adc2e2f9d5e9902d9cdfa3d7b748f4aebd179b87", - "system/release.php": "17d3bd33447e6f6e7c8b20a68332fe696c9eb78be26af1573f2f82d445cb3647", + "system/release.php": "3f39c44d6c95e376a74272bcd4d91dc3669ab643279f67609de2de6ac93a309d", "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", @@ -1818,6 +1798,7 @@ "robots.txt": "d8119db904b34c2aab74cc2b6a09d13119f7c19add8b51ffbf4717eba65e8218" }, "file_owners": { + ".gitignore": "core", ".htaccess": "core", "README.md": "core", "adminx/.htaccess": "core", @@ -2346,7 +2327,6 @@ "adminx/view/auth.twig": "core", "adminx/view/error.twig": "core", "adminx/view/main.twig": "core", - "changelog.txt": "core", "configs/db.config.example.php": "core", "configs/index.php": "core", "configs/public.config.php": "core", @@ -2780,26 +2760,6 @@ "system/App/Content/Fields/PublicFieldTemplateContext.php": "core", "system/App/Content/Fields/PublicFieldTemplateResolver.php": "core", "system/App/Content/Fields/SerialFieldType.php": "core", - "system/App/Content/Fields/Templates/date/field-req-177.php": "core", - "system/App/Content/Fields/Templates/date/field-req-185.php": "core", - "system/App/Content/Fields/Templates/date/field-req-187.php": "core", - "system/App/Content/Fields/Templates/doc_from_rub_search/field-req-137.php": "core", - "system/App/Content/Fields/Templates/doc_from_rub_search/field-req-180.php": "core", - "system/App/Content/Fields/Templates/image_mega/field-doc-22-1.php": "core", - "system/App/Content/Fields/Templates/image_mega/field-doc-22-2.php": "core", - "system/App/Content/Fields/Templates/image_mega/field-doc-22.php": "core", - "system/App/Content/Fields/Templates/image_mega/field-req-22.php": "core", - "system/App/Content/Fields/Templates/image_multi/field-doc-123.php": "core", - "system/App/Content/Fields/Templates/image_multi/field-req-22.php": "core", - "system/App/Content/Fields/Templates/image_single/field-doc-14.php": "core", - "system/App/Content/Fields/Templates/image_single/field-doc-18.php": "core", - "system/App/Content/Fields/Templates/image_single/field-req-14.php": "core", - "system/App/Content/Fields/Templates/image_single/field-req-142.php": "core", - "system/App/Content/Fields/Templates/image_single/field-req-159.php": "core", - "system/App/Content/Fields/Templates/multi_links/field-doc-137.php": "core", - "system/App/Content/Fields/Templates/multi_links/field-doc-181.php": "core", - "system/App/Content/Fields/Templates/single_line_numeric/field-doc-200.php": "core", - "system/App/Content/Fields/Templates/single_line_numeric/field-req-157.php": "core", "system/App/Content/Fields/Types/AddressValue.php": "core", "system/App/Content/Fields/Types/Analoque.php": "core", "system/App/Content/Fields/Types/Catalog.php": "core", diff --git a/README.md b/README.md index 94c7eed..431015d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # AVE.cms -**AVE.cms 3.3 build 0.31** — модульная система управления сайтами на PHP. +**AVE.cms 3.3 build 0.32** — модульная система управления сайтами на PHP. Она подходит для проектов, в которых структуру содержимого нужно собирать из собственных рубрик, полей, документов, запросов, блоков и шаблонов, не привязываясь к заранее заданному типу сайта. @@ -133,19 +133,6 @@ index.php публичная точка входа - [работа с базой данных](help/database/README.md); - [English documentation](help/en/README.md). -## Безопасность - -- Не публикуйте `configs/db.config.php`, секреты модулей и содержимое - `storage/`. -- Оставляйте публичный Debug Toolbar доступным только доверенным - администраторам. -- Устанавливайте модули и обновления только из доверенного источника. -- Для Nginx вручную перенесите правила защиты `uploads/` и `modules/`, - приведённые в инструкции по установке. -- Перед обновлением рабочей системы создавайте проверенную резервную копию. - -Об уязвимостях сообщайте непублично на `support@ave-cms.ru`. - ## Лицензия AVE.cms распространяется по лицензии GNU General Public License версии 2 или diff --git a/adminx/modules/Blocks/Controller.php b/adminx/modules/Blocks/Controller.php index 98ce860..68f99ed 100644 --- a/adminx/modules/Blocks/Controller.php +++ b/adminx/modules/Blocks/Controller.php @@ -62,6 +62,7 @@ if (!$item) { return $this->error('Системный блок не найден', array(), 404); } + if (($err = $this->guardPhpItem($item)) !== null) { return $err; } return $this->success('', array('data' => $item)); @@ -134,6 +135,7 @@ if (!$before) { return $this->error('Системный блок не найден', array(), 404); } + if (($err = $this->guardPhpItem($before)) !== null) { return $err; } $input = Request::postAll(); @@ -166,6 +168,7 @@ } catch (\Throwable $e) { return $this->error($e->getMessage(), array(), 422); } + $this->audit('block.copied', $newId, array('source_id' => (int) $source['id'], 'editor' => (string) $source['sysblock_editor'])); return $this->success('Копия создана', array('redirect' => $this->base() . '/blocks')); @@ -178,6 +181,7 @@ if (!$item) { return $this->error('Системный блок не найден', array(), 404); } + if (($err = $this->guardPhpItem($item)) !== null) { return $err; } return $this->success('', array( @@ -198,6 +202,7 @@ if (!$revision) { return $this->error('Ревизия не найдена', array(), 404); } + if (($err = $this->guardPhpSnapshot(isset($revision['snapshot']) ? $revision['snapshot'] : array())) !== null) { return $err; } return $this->success('', array('data' => $revision)); @@ -218,6 +223,7 @@ } catch (\Throwable $e) { return $this->error($e->getMessage(), array(), 422); } + $this->audit('block.revision_restored', $blockId, array('revision_id' => $revisionId)); return $this->success('Блок восстановлен из ревизии', array( @@ -255,6 +261,7 @@ if (!$item) { return $this->error('Системный блок не найден', array(), 404); } + if (($err = $this->guardPhpItem($item)) !== null) { return $err; } $count = Revisions::deleteForBlock($id); @@ -303,6 +310,7 @@ if (!Model::delete($id, Auth::id())) { return $this->error('Системный блок не найден', array(), 404); } + $this->audit('block.deleted', $id, array('editor' => (string) $item['sysblock_editor'])); return $this->success('Системный блок удалён'); diff --git a/adminx/modules/Catalog/Controller.php b/adminx/modules/Catalog/Controller.php index 53ea3bc..7947128 100644 --- a/adminx/modules/Catalog/Controller.php +++ b/adminx/modules/Catalog/Controller.php @@ -24,6 +24,7 @@ use App\Common\ModuleManager; use App\Common\Loader\Load; use App\Common\Twig; + use App\Helpers\Hooks; use App\Helpers\Request; use App\Adminx\Rubrics\FieldAdminEditors; use App\Adminx\Documents\Model as DocumentsModel; @@ -887,7 +888,10 @@ try { $enabled = PaymentPrograms::setProduct($productId, isset($params['program']) ? $params['program'] : '', Request::postBool('enabled', false)); } catch (\Throwable $e) { return $this->error($e->getMessage(), array(), 422); } $this->audit('catalog.product_payment_program_changed', $productId, array('program' => (string) $params['program'], 'enabled' => $enabled)); - return $this->success($enabled ? 'Оплата через СФР доступна товару' : 'Оплата через СФР отключена для товара', array('data' => array('enabled' => $enabled))); + return $this->success( + $enabled ? 'Платёжная программа доступна товару' : 'Платёжная программа отключена для товара', + array('data' => array('enabled' => $enabled)) + ); } public function createCatalog(array $params = array()) @@ -1470,10 +1474,11 @@ $filters = array( 'q' => Request::getStr('q', ''), 'rubric_id' => Request::getInt('rubric_id', 0), 'category_id' => Request::getInt('category_id', 0), 'state' => Request::getStr('state', ''), - 'sfr' => Request::getStr('sfr', ''), 'sfr_code' => Request::getStr('sfr_code', ''), 'incomplete' => Request::getBool('incomplete', false), 'limit' => Request::getInt('limit', 25), 'page' => Request::getInt('page', 1), ); + $filters = Hooks::filter('catalog.quick_edit.filters', $filters); + if (!is_array($filters)) { $filters = array(); } return array('result' => QuickEditor::items($filters), 'filters' => $filters, 'rubrics' => QuickEditor::rubrics(), 'categories' => QuickEditor::categories(), 'can_manage' => Permission::check('manage_catalog')); diff --git a/adminx/modules/Groups/Model.php b/adminx/modules/Groups/Model.php index 28c706d..101568b 100644 --- a/adminx/modules/Groups/Model.php +++ b/adminx/modules/Groups/Model.php @@ -136,7 +136,6 @@ 'notfound' => 'Ошибки 404', 'other' => 'Прочее', 'products' => 'Товары', - 'psb' => 'ПСБ / СФР', 'ratings' => 'Рейтинги', 'related' => 'Похожие документы', 'requests' => 'Запросы', @@ -154,7 +153,6 @@ 'users' => 'Пользователи', 'vk_oauth' => 'Вход через VK ID', 'yandex_oauth' => 'Вход через Яндекс', - 'yookassa' => 'YooKassa', ); foreach (ModuleManager::all() as $module) { $code = isset($module['code']) ? trim((string) $module['code']) : ''; diff --git a/adminx/modules/Templates/TagRegistry.php b/adminx/modules/Templates/TagRegistry.php index e34b228..7041534 100644 --- a/adminx/modules/Templates/TagRegistry.php +++ b/adminx/modules/Templates/TagRegistry.php @@ -18,12 +18,13 @@ use DB; use App\Content\ContentTables; + use App\Helpers\Hooks; class TagRegistry { public static function groups() { - return array( + $groups = array( self::group('Основные', array( self::tag('[tag:theme:folder]', 'Папка темы', 'folder'), self::tag('[tag:sitename]', 'Название сайта'), @@ -65,8 +66,6 @@ self::group('Условия', array( self::tag("[tag:if_print]\n\n[/tag:if_print]", 'Для печати', '', '[tag:if_print]'), self::tag("[tag:if_notprint]\n\n[/tag:if_notprint]", 'Не печать', '', '[tag:if_notprint]'), - self::tag("[tag:if_payment_program:sfr]\n\n[tag:if:else]\n\n[tag:/if_payment_program]", 'Оплата через СФР', 'Условие доступности товара для программы СФР', '[tag:if_payment_program:sfr]'), - self::tag('[tag:payment_program_code:sfr]', 'Код СФР', 'Информационный код СФР текущего товара', '[tag:payment_program_code:sfr]'), )), self::group('HTML', array( self::tag("
    \n\n
", 'Список', '', 'OL'), @@ -87,6 +86,9 @@ self::tag("\t", 'Табуляция', '', 'TAB'), )), ); + + $groups = Hooks::filter('admin.templates.tag_groups', $groups); + return is_array($groups) ? $groups : array(); } protected static function sysblockTags() diff --git a/changelog.txt b/changelog.txt deleted file mode 100644 index e69de29..0000000 diff --git a/help/database/README.md b/help/database/README.md index 3e2b145..68134d4 100644 --- a/help/database/README.md +++ b/help/database/README.md @@ -43,7 +43,7 @@ DB::getDatabase(); // имя текущей БД ```php use App\Content\ContentTables; -$t = ContentTables::table('documents'); // → 'marketplace_documents' +$t = ContentTables::table('documents'); // например, 'ave_documents' // список (массив ассоц. строк; на пустой выборке — false) $items = DB::query('SELECT * FROM ' . $t . ' WHERE rubric_id = %i ORDER BY Id DESC', 5)->getAll() ?: array(); diff --git a/help/database/tables.md b/help/database/tables.md index af43c94..3abd795 100644 --- a/help/database/tables.md +++ b/help/database/tables.md @@ -12,10 +12,10 @@ | Класс | Домен | Пример результата | | --- | --- | --- | -| `App\Content\ContentTables::table($s)` | Контент: документы, рубрики, поля | `marketplace_documents` | -| `App\Common\SystemTables::table($s)` | Системные таблицы админки (по whitelist) | `marketplace_admin_notes` | -| `App\Content\ExtensionTables::table($s)` | Таблицы ядра контента | `marketplace_todos` | -| `App\Content\PublicShellTables::table($s)` | Публичная оболочка (сессии и т. п.) | `marketplace_public_sessions` | +| `App\Content\ContentTables::table($s)` | Контент: документы, рубрики, поля | `ave_documents` | +| `App\Common\SystemTables::table($s)` | Системные таблицы админки (по whitelist) | `ave_admin_notes` | +| `App\Content\ExtensionTables::table($s)` | Таблицы ядра контента | `ave_todos` | +| `App\Content\PublicShellTables::table($s)` | Публичная оболочка (сессии и т. п.) | `ave_public_sessions` | ```php use App\Content\ContentTables; @@ -44,7 +44,7 @@ ContentTables::table('users; DROP …'); // InvalidArgumentException ```php // ПЛОХО — префикс зашит, сломается в другом окружении/домене данных -$rows = DB::query('SELECT * FROM marketplace_documents')->getAll(); +$rows = DB::query('SELECT * FROM ' . ContentTables::table('documents'))->getAll(); // ХОРОШО — префикс подставит резолвер $t = ContentTables::table('documents'); diff --git a/help/en/database/README.md b/help/en/database/README.md index 52aa4d7..4ca43ad 100644 --- a/help/en/database/README.md +++ b/help/en/database/README.md @@ -43,7 +43,7 @@ DB::getDatabase(); // имя текущей БД ```php use App\Content\ContentTables; -$t = ContentTables::table('documents'); // → 'marketplace_documents' +$t = ContentTables::table('documents'); // for example, 'ave_documents' // список (массив ассоц. строк; на пустой выборке — false) $items = DB::query('SELECT * FROM ' . $t . ' WHERE rubric_id = %i ORDER BY Id DESC', 5)->getAll() ?: array(); diff --git a/help/en/database/tables.md b/help/en/database/tables.md index c61dd14..5519209 100644 --- a/help/en/database/tables.md +++ b/help/en/database/tables.md @@ -12,10 +12,10 @@ resolver**, rather than writing it as a line. This gives the correct prefix and | Class | Domain | Example result | | --- | --- | --- | -| `App\Content\ContentTables::table($s)` | Content: documents, headings, fields | `marketplace_documents` | -| `App\Common\SystemTables::table($s)` | Administrator system tables (by whitelist) | `marketplace_admin_notes` | -| `App\Content\ExtensionTables::table($s)` | Core Content Tables | `marketplace_todos` | -| `App\Content\PublicShellTables::table($s)` | Public shell (sessions, etc.) | `marketplace_public_sessions` | +| `App\Content\ContentTables::table($s)` | Content: documents, headings, fields | `ave_documents` | +| `App\Common\SystemTables::table($s)` | Administrator system tables (by whitelist) | `ave_admin_notes` | +| `App\Content\ExtensionTables::table($s)` | Core Content Tables | `ave_todos` | +| `App\Content\PublicShellTables::table($s)` | Public shell (sessions, etc.) | `ave_public_sessions` | ```php use App\Content\ContentTables; @@ -44,7 +44,7 @@ ContentTables::table('users; DROP …'); // InvalidArgumentException ```php // ПЛОХО — префикс зашит, сломается в другом окружении/домене данных -$rows = DB::query('SELECT * FROM marketplace_documents')->getAll(); +$rows = DB::query('SELECT * FROM ' . ContentTables::table('documents'))->getAll(); // ХОРОШО — префикс подставит резолвер $t = ContentTables::table('documents'); diff --git a/system/App/Common/Cache.php b/system/App/Common/Cache.php index 743567e..d4e0d8a 100644 --- a/system/App/Common/Cache.php +++ b/system/App/Common/Cache.php @@ -144,6 +144,7 @@ if (!File::putAtomic($file, $payload)) { return false; } + self::deleteLegacyPath($key); try { @@ -341,6 +342,7 @@ foreach (array_unique($files) as $file) { if (File::delete($file)) { $deleted++; } } + self::removeEmptyShards(self::dataDir()); self::removeEmptyShards(self::tagsDir()); @@ -386,6 +388,7 @@ if (strpos(basename($file), 'tag_') === 0) { continue; } + $files[] = $file; } @@ -572,6 +575,7 @@ $deleted = false; } } + self::removeEmptyShard(dirname(self::path($key)), self::dataDir()); return $deleted; @@ -588,6 +592,7 @@ foreach (array(self::tagPath($tag), self::legacyTagPath($tag)) as $file) { if (is_file($file)) { File::delete($file); } } + self::removeEmptyShard(dirname(self::tagPath($tag)), self::tagsDir()); } diff --git a/system/App/Common/ModuleManager.php b/system/App/Common/ModuleManager.php index 0f29e1a..af6deb5 100644 --- a/system/App/Common/ModuleManager.php +++ b/system/App/Common/ModuleManager.php @@ -611,7 +611,7 @@ if (self::$disabledCodes === null) { self::$disabledCodes = []; if (self::$mode === 'public') { - self::publicLifecycleState('__module_state_warmup__'); + self::lifecycleState('__module_state_warmup__', false); foreach (self::$publicLifecycleStates as $moduleCode => $row) { $status = isset($row['status']) ? (string) $row['status'] : ''; if (in_array($status, array('disabled', 'available'), true)) { diff --git a/system/App/Common/OutboundHttpClient.php b/system/App/Common/OutboundHttpClient.php index 3437fa7..f3f0238 100644 --- a/system/App/Common/OutboundHttpClient.php +++ b/system/App/Common/OutboundHttpClient.php @@ -84,6 +84,7 @@ if (self::origin($target) !== self::origin($nextTarget)) { $currentHeaders = self::withoutSensitiveHeaders($currentHeaders); } + $currentUrl = $nextTarget['url']; if ($response['status'] === 303 || (($response['status'] === 301 || $response['status'] === 302) && $currentMethod === 'POST')) { $currentMethod = 'GET'; @@ -134,6 +135,7 @@ $headerOverflow = true; return 0; } + $responseHeaders[$name] = $value; return $length; }, @@ -147,6 +149,7 @@ if (in_array('https', $options['allowed_schemes'], true)) { $protocols |= CURLPROTO_HTTPS; } $curlOptions[CURLOPT_PROTOCOLS] = $protocols; } + if ($method === 'POST') { $curlOptions[CURLOPT_POST] = true; $curlOptions[CURLOPT_POSTFIELDS] = (string) $body; @@ -161,9 +164,11 @@ if ($overflow || $headerOverflow) { throw new \RuntimeException('Удалённый ответ превышает допустимый размер'); } + if ($result === false) { throw new \RuntimeException('Не удалось получить удалённый ответ' . ($error !== '' ? ': ' . $error : '')); } + if (!self::sameIp($primaryIp, $target['ip'])) { throw new \RuntimeException('Удалённый сервер изменил проверенный сетевой адрес'); } @@ -198,6 +203,7 @@ if (!$ips) { throw new \RuntimeException('Удалённый хост не имеет доступного адреса'); } + foreach ($ips as $ip) { if (!self::isPublicIp($ip)) { throw new \RuntimeException('Удалённый хост указывает на private или reserved сеть'); @@ -222,6 +228,7 @@ if (filter_var($host, FILTER_VALIDATE_IP)) { return array($host); } + if (isset(self::$dnsCache[$host])) { return self::$dnsCache[$host]; } @@ -234,6 +241,7 @@ if (!empty($record['ipv6'])) { $addresses[] = (string) $record['ipv6']; } } } + if (!$addresses) { $ipv4 = @gethostbynamel($host); $addresses = is_array($ipv4) ? $ipv4 : array(); @@ -268,16 +276,20 @@ if ($host === '' || strlen($host) > 253) { throw new \InvalidArgumentException('Некорректный хост удалённого URL'); } + if (filter_var($host, FILTER_VALIDATE_IP)) { return $host; } + if (preg_match('/[^\x20-\x7e]/', $host)) { if (!function_exists('idn_to_ascii')) { throw new \InvalidArgumentException('IDN-хост не поддерживается сервером'); } + $variant = defined('INTL_IDNA_VARIANT_UTS46') ? INTL_IDNA_VARIANT_UTS46 : 0; $host = idn_to_ascii($host, 0, $variant); } + if (!is_string($host) || !preg_match('/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/', $host)) { throw new \InvalidArgumentException('Некорректный хост удалённого URL'); } @@ -291,6 +303,7 @@ if ($location === '' || preg_match('/[\x00-\x20\x7f]/', $location)) { throw new \RuntimeException('Удалённый сервер вернул некорректное перенаправление'); } + if (preg_match('#^https?://#i', $location)) { return $location; } @@ -299,11 +312,13 @@ if (strpos($location, '//') === 0) { return $parts['scheme'] . ':' . $location; } + $origin = $parts['scheme'] . '://' . (strpos($parts['host'], ':') !== false ? '[' . $parts['host'] . ']' : $parts['host']); if (isset($parts['port'])) { $origin .= ':' . (int) $parts['port']; } if ($location[0] === '/') { return $origin . $location; } + if ($location[0] === '?') { return $origin . (isset($parts['path']) ? $parts['path'] : '/') . $location; } diff --git a/system/App/Common/Session.php b/system/App/Common/Session.php index ca57d58..ea8c7a5 100644 --- a/system/App/Common/Session.php +++ b/system/App/Common/Session.php @@ -162,7 +162,7 @@ // COOKIE_DOMAIN или переданном аргументе. По умолчанию — host-only: // атрибут Domain не выставляется, cookie привязана строго к текущему // хосту. Это исключает коллизии сессии/auth между родительским доменом - // и поддоменами (напр. design.med-mos.ru ↔ .med-mos.ru). + // и поддоменами (например, preview.example.org и .example.org). if ($cookie_domain === '' && defined('COOKIE_DOMAIN') && COOKIE_DOMAIN !== '') { $cookie_domain = COOKIE_DOMAIN; } diff --git a/system/App/Content/Blocks/ContentBlockRegistry.php b/system/App/Content/Blocks/ContentBlockRegistry.php index e05d1cf..3eefe12 100644 --- a/system/App/Content/Blocks/ContentBlockRegistry.php +++ b/system/App/Content/Blocks/ContentBlockRegistry.php @@ -29,6 +29,7 @@ if (!preg_match('/^[a-z][a-z0-9_-]{1,63}$/', $code)) { throw new \InvalidArgumentException('Некорректный код блока контента: ' . $code); } + if (isset(self::$blocks[$code]) && (string) self::$blocks[$code]['source'] !== (string) $source) { throw new \RuntimeException('Код блока контента уже зарегистрирован: ' . $code); } @@ -48,6 +49,7 @@ $code = is_string($key) ? $key : (isset($definition['code']) ? $definition['code'] : ''); $registered[] = self::register($code, $definition, $source, $available); } + return $registered; } @@ -67,6 +69,7 @@ foreach (self::$blocks as $block) { if ($includeUnavailable || !empty($block['available'])) { $blocks[] = $block; } } + usort($blocks, function ($left, $right) { $priority = (int) $left['priority'] <=> (int) $right['priority']; return $priority !== 0 ? $priority : strcasecmp((string) $left['title'], (string) $right['title']); @@ -112,6 +115,7 @@ if (!preg_match('/^[a-z][a-z0-9_]{1,63}$/', $key) || $type === '' || isset($keys[$key])) { throw new \InvalidArgumentException('Некорректное поле блока ' . $code . ': ' . ($key !== '' ? $key : '(без ключа)')); } + $keys[$key] = true; $fields[] = array( 'key' => $key, @@ -121,6 +125,7 @@ 'settings' => isset($field['settings']) && is_array($field['settings']) ? $field['settings'] : array(), ); } + if (!$fields) { throw new \InvalidArgumentException('Блок контента не содержит полей: ' . $code); } return array( diff --git a/system/App/Content/Fields/DocumentRelationValue.php b/system/App/Content/Fields/DocumentRelationValue.php index 4da9fb0..f608605 100644 --- a/system/App/Content/Fields/DocumentRelationValue.php +++ b/system/App/Content/Fields/DocumentRelationValue.php @@ -80,6 +80,7 @@ self::collect($value['items'], $ids); return; } + foreach (array('document_id', 'id', 'Id') as $idKey) { if (isset($value[$idKey])) { self::collect($value[$idKey], $ids, $idKey); diff --git a/system/App/Content/Fields/Templates/date/field-req-177.php b/system/App/Content/Fields/Templates/date/field-req-177.php deleted file mode 100644 index fb02a28..0000000 --- a/system/App/Content/Fields/Templates/date/field-req-177.php +++ /dev/null @@ -1,19 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $timestamp = is_numeric($value) ? (int) $value : strtotime((string) $value); - if ($timestamp > 0): ?> -escape(date('d.m.Y', $timestamp)) ?> - diff --git a/system/App/Content/Fields/Templates/date/field-req-185.php b/system/App/Content/Fields/Templates/date/field-req-185.php deleted file mode 100644 index 354ec86..0000000 --- a/system/App/Content/Fields/Templates/date/field-req-185.php +++ /dev/null @@ -1,17 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $timestamp = is_numeric($value) ? (int) $value : strtotime((string) $value); ?> - 0 ? $template->escape(date('d.m.Y', $timestamp)) : '' ?> diff --git a/system/App/Content/Fields/Templates/date/field-req-187.php b/system/App/Content/Fields/Templates/date/field-req-187.php deleted file mode 100644 index 462602a..0000000 --- a/system/App/Content/Fields/Templates/date/field-req-187.php +++ /dev/null @@ -1,17 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $timestamp = is_numeric($value) ? (int) $value : strtotime((string) $value); ?> - 0 ? $template->escape(date('d.m.Y', $timestamp)) : '' ?> diff --git a/system/App/Content/Fields/Templates/doc_from_rub_search/field-req-137.php b/system/App/Content/Fields/Templates/doc_from_rub_search/field-req-137.php deleted file mode 100644 index 9b215cb..0000000 --- a/system/App/Content/Fields/Templates/doc_from_rub_search/field-req-137.php +++ /dev/null @@ -1,18 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); ?> - -[ () escape($item['document_title']) ?> ]    - diff --git a/system/App/Content/Fields/Templates/doc_from_rub_search/field-req-180.php b/system/App/Content/Fields/Templates/doc_from_rub_search/field-req-180.php deleted file mode 100644 index 1c0d3c2..0000000 --- a/system/App/Content/Fields/Templates/doc_from_rub_search/field-req-180.php +++ /dev/null @@ -1,18 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); ?> - -[ () escape($item['document_title']) ?> ]    - diff --git a/system/App/Content/Fields/Templates/image_mega/field-doc-22-1.php b/system/App/Content/Fields/Templates/image_mega/field-doc-22-1.php deleted file mode 100644 index 894575b..0000000 --- a/system/App/Content/Fields/Templates/image_mega/field-doc-22-1.php +++ /dev/null @@ -1,20 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $image = $template->first(); - $url = is_array($image) && !empty($image['url']) ? $image['url'] : '/uploads/default.png'; ?> - - [tag:doc:document_title] - diff --git a/system/App/Content/Fields/Templates/image_mega/field-doc-22-2.php b/system/App/Content/Fields/Templates/image_mega/field-doc-22-2.php deleted file mode 100644 index 5b842f5..0000000 --- a/system/App/Content/Fields/Templates/image_mega/field-doc-22-2.php +++ /dev/null @@ -1,24 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); ?> - -
- - - - - -
- diff --git a/system/App/Content/Fields/Templates/image_mega/field-doc-22.php b/system/App/Content/Fields/Templates/image_mega/field-doc-22.php deleted file mode 100644 index 1cf3553..0000000 --- a/system/App/Content/Fields/Templates/image_mega/field-doc-22.php +++ /dev/null @@ -1,27 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); ?> - - - diff --git a/system/App/Content/Fields/Templates/image_mega/field-req-22.php b/system/App/Content/Fields/Templates/image_mega/field-req-22.php deleted file mode 100644 index 75e075b..0000000 --- a/system/App/Content/Fields/Templates/image_mega/field-req-22.php +++ /dev/null @@ -1,21 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $image = $template->first(); ?> - - - -[tag:doc:document_title] - diff --git a/system/App/Content/Fields/Templates/image_multi/field-doc-123.php b/system/App/Content/Fields/Templates/image_multi/field-doc-123.php deleted file mode 100644 index d1b3f31..0000000 --- a/system/App/Content/Fields/Templates/image_multi/field-doc-123.php +++ /dev/null @@ -1,27 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); ?> - diff --git a/system/App/Content/Fields/Templates/image_multi/field-req-22.php b/system/App/Content/Fields/Templates/image_multi/field-req-22.php deleted file mode 100644 index 092fd89..0000000 --- a/system/App/Content/Fields/Templates/image_multi/field-req-22.php +++ /dev/null @@ -1,18 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $image = $template->first(); - $url = is_array($image) && !empty($image['url']) ? $image['url'] : '/uploads/default.png'; ?> -[tag:doc:document_title] diff --git a/system/App/Content/Fields/Templates/image_single/field-doc-14.php b/system/App/Content/Fields/Templates/image_single/field-doc-14.php deleted file mode 100644 index 7a9ab55..0000000 --- a/system/App/Content/Fields/Templates/image_single/field-doc-14.php +++ /dev/null @@ -1,27 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $image = $template->first(); ?> - -
-
-
- - <?= $template->escape($image['description']) ?> - -
-
-
- diff --git a/system/App/Content/Fields/Templates/image_single/field-doc-18.php b/system/App/Content/Fields/Templates/image_single/field-doc-18.php deleted file mode 100644 index 9d05df6..0000000 --- a/system/App/Content/Fields/Templates/image_single/field-doc-18.php +++ /dev/null @@ -1,19 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $image = $template->first(); ?> - -<?= $template->escape($image['description']) ?> - diff --git a/system/App/Content/Fields/Templates/image_single/field-req-14.php b/system/App/Content/Fields/Templates/image_single/field-req-14.php deleted file mode 100644 index f7da274..0000000 --- a/system/App/Content/Fields/Templates/image_single/field-req-14.php +++ /dev/null @@ -1,19 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $image = $template->first(); ?> - -<?= $template->escape($image['description']) ?> - diff --git a/system/App/Content/Fields/Templates/image_single/field-req-142.php b/system/App/Content/Fields/Templates/image_single/field-req-142.php deleted file mode 100644 index fdcfa3e..0000000 --- a/system/App/Content/Fields/Templates/image_single/field-req-142.php +++ /dev/null @@ -1,19 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $image = $template->first(); ?> - -<?= $template->escape($image['description']) ?> - diff --git a/system/App/Content/Fields/Templates/image_single/field-req-159.php b/system/App/Content/Fields/Templates/image_single/field-req-159.php deleted file mode 100644 index 9a1722e..0000000 --- a/system/App/Content/Fields/Templates/image_single/field-req-159.php +++ /dev/null @@ -1,22 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); - $image = $template->first(); ?> - - - - <?= $template->escape($image['description']) ?> - - diff --git a/system/App/Content/Fields/Templates/multi_links/field-doc-137.php b/system/App/Content/Fields/Templates/multi_links/field-doc-137.php deleted file mode 100644 index 9c6ffd7..0000000 --- a/system/App/Content/Fields/Templates/multi_links/field-doc-137.php +++ /dev/null @@ -1,20 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); ?> - diff --git a/system/App/Content/Fields/Templates/multi_links/field-doc-181.php b/system/App/Content/Fields/Templates/multi_links/field-doc-181.php deleted file mode 100644 index 22a9562..0000000 --- a/system/App/Content/Fields/Templates/multi_links/field-doc-181.php +++ /dev/null @@ -1,25 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); ?> - - - - - - - - - -
Документация
 escape($item['param']) ?>
Нет файлов для скачивания
diff --git a/system/App/Content/Fields/Templates/single_line_numeric/field-doc-200.php b/system/App/Content/Fields/Templates/single_line_numeric/field-doc-200.php deleted file mode 100644 index 6848ce4..0000000 --- a/system/App/Content/Fields/Templates/single_line_numeric/field-doc-200.php +++ /dev/null @@ -1,16 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); ?> -escape($value) ?> месяцев diff --git a/system/App/Content/Fields/Templates/single_line_numeric/field-req-157.php b/system/App/Content/Fields/Templates/single_line_numeric/field-req-157.php deleted file mode 100644 index 826ade7..0000000 --- a/system/App/Content/Fields/Templates/single_line_numeric/field-req-157.php +++ /dev/null @@ -1,16 +0,0 @@ - - | @copyright 2007-2026 (c) AVE.cms - | @link https://ave-cms.ru - | @version 3.3 - */ - - defined('BASEPATH') || die('Direct access to this location is not allowed.'); ?> -escape($value) ?> diff --git a/system/App/Content/PaymentPrograms.php b/system/App/Content/PaymentPrograms.php index 605632f..bf36bdc 100644 --- a/system/App/Content/PaymentPrograms.php +++ b/system/App/Content/PaymentPrograms.php @@ -19,6 +19,7 @@ use DB; use App\Content\BasketTables; use App\Common\FileCacheInvalidator; + use App\Helpers\Hooks; /** Product eligibility and runtime availability for alternative payment programs. */ class PaymentPrograms @@ -144,7 +145,14 @@ protected static function documentProgramField($productId, $code) { - $fieldAlias = $code === 'sfr' ? 'sertificattcr' : $code; + $context = Hooks::filter('content.payment_program.field_alias', array( + 'code' => (string) $code, + 'alias' => (string) $code, + )); + $fieldAlias = is_array($context) && isset($context['alias']) + ? trim((string) $context['alias']) + : (string) $code; + if ($fieldAlias === '') { return false; } return DB::query('SELECT rf.Id FROM ' . ContentTables::table('rubric_fields') . ' rf' . ' INNER JOIN ' . ContentTables::table('documents') . ' d ON d.rubric_id=rf.rubric_id' . ' WHERE d.Id=%i AND rf.rubric_field_alias=%s LIMIT 1', (int) $productId, (string) $fieldAlias)->getAssoc() ?: false; diff --git a/system/App/Frontend/Auth/OAuth/IdentityRepository.php b/system/App/Frontend/Auth/OAuth/IdentityRepository.php index 4eba5c8..a9a783e 100644 --- a/system/App/Frontend/Auth/OAuth/IdentityRepository.php +++ b/system/App/Frontend/Auth/OAuth/IdentityRepository.php @@ -58,6 +58,7 @@ if ($linkedProvider && (string) $linkedProvider['provider_user_id'] !== $providerUserId) { throw new \RuntimeException('К аккаунту уже привязана другая учётная запись этого сервиса.'); } + $current = $this->find($provider, $providerUserId); $now = time(); $data = array( diff --git a/system/App/Frontend/Auth/Phone/PhoneAuthService.php b/system/App/Frontend/Auth/Phone/PhoneAuthService.php index b2b4483..0825e6f 100644 --- a/system/App/Frontend/Auth/Phone/PhoneAuthService.php +++ b/system/App/Frontend/Auth/Phone/PhoneAuthService.php @@ -95,6 +95,7 @@ 'phone_mask' => Phone::mask($phone), ), null, array(), 'phone_auth'); } + return array( 'challenge' => $publicId, 'phone_mask' => Phone::mask($phone), diff --git a/system/App/Frontend/Feeds/FeedPresets.php b/system/App/Frontend/Feeds/FeedPresets.php index f4bdf26..1067f58 100644 --- a/system/App/Frontend/Feeds/FeedPresets.php +++ b/system/App/Frontend/Feeds/FeedPresets.php @@ -17,8 +17,10 @@ defined('BASEPATH') || die('Direct access to this location is not allowed.'); use App\Content\CatalogTables; + use App\Helpers\Hooks; use DB; + /** Extensible feed presets. Site-specific paths and mappings belong to modules. */ class FeedPresets { protected static $seeded = false; @@ -27,15 +29,21 @@ { if (self::$seeded) { return; } self::$seeded = true; - foreach (self::definitions() as $definition) { self::create($definition[0], $definition[1], $definition[2], isset($definition[3]) ? $definition[3] : 'yml_catalog'); } + foreach (self::definitions() as $definition) { + if (is_array($definition)) { self::create($definition); } + } } public static function ensureCategory($categoryId) { $categoryId = (int) $categoryId; if ($categoryId < 1 || !self::categoryExists($categoryId)) { return null; } - $alias = 'legacy-category-' . $categoryId; - self::create($alias, 'Legacy: категория ' . $categoryId, array($categoryId)); + $alias = 'catalog-category-' . $categoryId; + self::create(array( + 'alias' => $alias, + 'name' => 'Категория каталога ' . $categoryId, + 'categories' => array($categoryId), + )); return $alias; } @@ -47,67 +55,72 @@ public static function paths() { - return array( - 'export.xml'=>'legacy-catalog-all','offers.xml'=>'legacy-offers-all','yandex_2025.xml'=>'legacy-yandex-2025', - 'sbermega_2025.xml'=>'legacy-sbermega-2025','sbermegaall_2025.xml'=>'legacy-sbermegaall-2025', - 'yml/yml_homebeds.xml'=>'legacy-offers-all','yml/yml_wcbeds_2025.xml'=>'legacy-wcbeds-65', - 'yml/yml_homebeds_2025.xml'=>'legacy-homebeds-66','yml/yml_kidsbeds_2025.xml'=>'legacy-kidsbeds-67', - 'yml/yml_medbeds_2025.xml'=>'legacy-medbeds-64','yml/yml_reanimation_2025.xml'=>'legacy-reanimation-69', - 'yml/yml_birth_2025.xml'=>'legacy-birth-68','yml/yml_beds.xml'=>'legacy-beds-97', - 'yml/massazhnye-stoly-skladnye.yml'=>'legacy-category-12','yml/massazhnye-stoly-stacionarnye.yml'=>'legacy-category-93', - 'yml/massazhnye-stoly-s-elektroprivodom.yml'=>'legacy-category-92','yml/massazhnoe-oborudovanie.yml'=>'legacy-massage', - 'yml/kosmetologicheskie-kresla.yml'=>'legacy-cosmetology','yml/kosmetologicheskie.yml'=>'legacy-category-87', - 'yml/pedikyurnye.yml'=>'legacy-category-88','yml/krovati-obcshebolnichnye.yml'=>'legacy-medbeds-64', - 'yml/krovati-s-tualetnym-ustrojstvom.yml'=>'legacy-wcbeds-65','yml/krovati-dlya-domashnego-ispolzovaniya.yml'=>'legacy-homebeds-66', - 'yml/detskie-medicinskie-krovati.yml'=>'legacy-kidsbeds-67','yml/reanimacionnye-krovati.yml'=>'legacy-reanimation-69', - 'yml/medicinskie-krovati-mehanicheskie.yml'=>'legacy-category-95','yml/medicinskie-krovati-s-elektroprivodom.yml'=>'legacy-category-96', - 'yml/medicinskie-krovati.yml'=>'legacy-medical-beds','yml/krovati-medicinskie.yml'=>'legacy-medical-beds', - 'yml/stoliki-reanimacionnye-anesteziologicheskie.yml'=>'legacy-category-47' - ); + $paths = Hooks::filter('feeds.preset_paths', array()); + if (!is_array($paths)) { return array(); } + + $normalized = array(); + foreach ($paths as $path => $alias) { + $path = ltrim(trim((string) $path), '/'); + $alias = trim((string) $alias); + if ($path === '' || $alias === '' || strpos($path, '..') !== false) { continue; } + $normalized[$path] = $alias; + } + + return $normalized; } - protected static function definitions() + public static function definitions() { - return array( - array('legacy-catalog-all','Legacy: весь каталог',array()), - array('legacy-offers-all','Legacy: цены и предложения',array(),'yml_offers'), - array('legacy-yandex-2025','Legacy: Яндекс 2025',array()), - array('legacy-sbermega-2025','Legacy: СберМега 2025',array()), - array('legacy-sbermegaall-2025','Legacy: СберМега, весь каталог 2025',array()), - array('legacy-beds-97','Legacy: медицинские кровати',array(97)), - array('legacy-medbeds-64','Legacy: медицинские кровати, категория 64',array(64)), - array('legacy-wcbeds-65','Legacy: кровати с туалетом',array(65)), - array('legacy-homebeds-66','Legacy: домашние кровати',array(66)), - array('legacy-kidsbeds-67','Legacy: детские кровати',array(67)), - array('legacy-birth-68','Legacy: родовые кровати',array(68)), - array('legacy-reanimation-69','Legacy: реанимационные кровати',array(69)), - array('legacy-medical-beds','Legacy: все медицинские кровати',array(1,67,68,69,95,96)), - array('legacy-cosmetology','Legacy: косметология',array(87,88)), - array('legacy-massage','Legacy: массаж',array(99,12,92)), - array('legacy-category-47','Legacy: категория 47',array(47)), - array('legacy-category-12','Legacy: категория 12',array(12)), - array('legacy-category-65','Legacy: категория 65',array(65)), - array('legacy-category-87','Legacy: категория 87',array(87)), - array('legacy-category-88','Legacy: категория 88',array(88)), - array('legacy-category-92','Legacy: категория 92',array(92)), - array('legacy-category-93','Legacy: категория 93',array(93)), - array('legacy-category-95','Legacy: категория 95',array(95)), - array('legacy-category-96','Legacy: категория 96',array(96)) - ); + $definitions = Hooks::filter('feeds.preset_definitions', array()); + return is_array($definitions) ? array_values($definitions) : array(); } - protected static function create($alias, $name, array $categories, $profile = 'yml_catalog') + protected static function create(array $definition) { + $alias = isset($definition['alias']) ? trim((string) $definition['alias']) : ''; + $name = isset($definition['name']) ? trim((string) $definition['name']) : ''; + if ($alias === '' || $name === '') { return; } if (DB::query('SELECT id FROM ' . Schema::table('definitions') . ' WHERE alias=%s LIMIT 1', $alias)->getValue()) { return; } - $host = defined('HOST') && HOST ? rtrim(HOST, '/') : 'https://med-mos.ru'; - $mapping = array('name'=>'index:title','url'=>'document:url','price'=>'index:price','oldprice'=>'index:old_price','vendorCode'=>'index:article','vendor'=>'static:Мед-Мос','description'=>'field:17','pictures'=>'index:images'); - $catalogFieldId=(int)DB::query("SELECT field_id FROM ".CatalogTables::table('module_catalog_settings')." WHERE rubric_id=6 AND purpose='commerce' ORDER BY id LIMIT 1")->getValue(); + $rubricId = isset($definition['rubric_id']) ? (int) $definition['rubric_id'] : 0; + $catalogFieldId = isset($definition['catalog_field_id']) ? (int) $definition['catalog_field_id'] : 0; + if ($catalogFieldId < 1 && $rubricId > 0) { + $catalogFieldId = (int) DB::query( + 'SELECT field_id FROM ' . CatalogTables::table('module_catalog_settings') + . " WHERE rubric_id=%i AND purpose='commerce' ORDER BY id LIMIT 1", + $rubricId + )->getValue(); + } + + $mapping = isset($definition['mappings']) && is_array($definition['mappings']) + ? $definition['mappings'] + : array(); + $categories = isset($definition['categories']) && is_array($definition['categories']) + ? $definition['categories'] + : array(); + $host = isset($definition['base_url']) ? trim((string) $definition['base_url']) : ''; + if ($host === '' && defined('HOST') && HOST) { $host = rtrim(HOST, '/'); } $now = time(); DB::Insert(Schema::table('definitions'), array( - 'name'=>$name,'alias'=>$alias,'status'=>1,'profile'=>$profile,'rubric_id'=>6,'catalog_field_id'=>$catalogFieldId,'site_name'=>'Мед-Мос', - 'company_name'=>'Мед-Мос','base_url'=>$host,'currency'=>'RUB','category_mode'=>'tree','include_descendants'=>0, - 'min_price'=>0,'cache_ttl'=>3600,'access_token'=>'','mappings_json'=>json_encode($mapping, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), - 'params_json'=>'[]','conditions_json'=>'[]','created_at'=>$now,'updated_at'=>$now + 'name' => $name, + 'alias' => $alias, + 'status' => !isset($definition['status']) || !empty($definition['status']) ? 1 : 0, + 'profile' => isset($definition['profile']) ? (string) $definition['profile'] : 'yml_catalog', + 'rubric_id' => $rubricId, + 'catalog_field_id' => $catalogFieldId, + 'site_name' => isset($definition['site_name']) ? (string) $definition['site_name'] : '', + 'company_name' => isset($definition['company_name']) ? (string) $definition['company_name'] : '', + 'base_url' => $host, + 'currency' => isset($definition['currency']) ? (string) $definition['currency'] : 'RUB', + 'category_mode' => isset($definition['category_mode']) ? (string) $definition['category_mode'] : 'tree', + 'include_descendants' => !empty($definition['include_descendants']) ? 1 : 0, + 'min_price' => isset($definition['min_price']) ? (float) $definition['min_price'] : 0, + 'cache_ttl' => isset($definition['cache_ttl']) ? max(0, (int) $definition['cache_ttl']) : 3600, + 'access_token' => isset($definition['access_token']) ? (string) $definition['access_token'] : '', + 'mappings_json' => json_encode($mapping, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + 'params_json' => json_encode(isset($definition['params']) ? $definition['params'] : array(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + 'conditions_json' => json_encode(isset($definition['conditions']) ? $definition['conditions'] : array(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + 'created_at' => $now, + 'updated_at' => $now, )); $feedId = (int) DB::insertId(); foreach (array_unique(array_map('intval', $categories)) as $categoryId) { diff --git a/system/release.php b/system/release.php index 0347c9b..885213c 100644 --- a/system/release.php +++ b/system/release.php @@ -17,5 +17,5 @@ return array( 'product' => 'AVE.cms', 'version' => '3.3', - 'build' => '0.31', + 'build' => '0.32', );