From 570ecad55170d81b3b0db09406d6c39b7645dc55 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 1 Aug 2023 17:27:33 +0500 Subject: [PATCH] from server --- .../api/BlogPostsApiController.php | 191 ++++- .../api/CategoriesAPIController.php | 15 +- .../controllers/api/ProductsApiController.php | 181 +++-- .../controllers/api/VendorApiController.php | 72 ++ plugins/ahmadfatoni/apigenerator/routes.php | 33 +- plugins/rainlab/notify/LICENSE.md | 21 + plugins/rainlab/notify/Plugin.php | 74 ++ plugins/rainlab/notify/README.md | 400 ++++++++++ plugins/rainlab/notify/classes/ActionBase.php | 168 ++++ .../notify/classes/CompoundCondition.php | 178 +++++ .../rainlab/notify/classes/ConditionBase.php | 211 +++++ plugins/rainlab/notify/classes/EventBase.php | 237 ++++++ .../rainlab/notify/classes/EventParams.php | 59 ++ .../classes/ModelAttributesConditionBase.php | 743 ++++++++++++++++++ plugins/rainlab/notify/classes/Notifier.php | 134 ++++ .../notify/classes/ScheduledAction.php | 63 ++ .../classes/compoundcondition/fields.yaml | 14 + .../_column_select_record.htm | 10 + .../_field_value.htm | 107 +++ .../modelattributesconditionbase/fields.yaml | 22 + plugins/rainlab/notify/composer.json | 25 + .../notify/controllers/Notifications.php | 130 +++ .../notifications/_add_rule_event_form.htm | 39 + .../notifications/_add_rule_group_form.htm | 47 ++ .../notifications/_form_toolbar.htm | 39 + .../notifications/_list_toolbar.htm | 9 + .../notifications/config_form.yaml | 16 + .../notifications/config_list.yaml | 20 + .../controllers/notifications/create.htm | 31 + .../controllers/notifications/index.htm | 2 + .../controllers/notifications/update.htm | 30 + .../notify/formwidgets/ActionBuilder.php | 388 +++++++++ .../notify/formwidgets/ConditionBuilder.php | 455 +++++++++++ .../actionbuilder/assets/css/actions.css | 227 ++++++ .../actionbuilder/assets/js/actions.js | 156 ++++ .../actionbuilder/assets/less/actions.less | 273 +++++++ .../actionbuilder/partials/_action.htm | 29 + .../partials/_action_settings_form.htm | 77 ++ .../actionbuilder/partials/_actions.htm | 31 + .../partials/_actions_container.htm | 14 + .../partials/_available_tags.htm | 23 + .../partials/_create_action_form.htm | 46 ++ .../actionbuilder/partials/_schedule.htm | 22 + .../assets/css/conditions.css | 227 ++++++ .../conditionbuilder/assets/js/conditions.js | 184 +++++ .../assets/js/conditions.multivalue.js | 139 ++++ .../assets/less/conditions.less | 286 +++++++ .../conditionbuilder/partials/_condition.htm | 99 +++ .../partials/_condition_settings_form.htm | 68 ++ .../conditionbuilder/partials/_conditions.htm | 10 + .../partials/_conditions_container.htm | 15 + .../partials/_create_child_form.htm | 67 ++ plugins/rainlab/notify/interfaces/Action.php | 31 + .../notify/interfaces/CompoundCondition.php | 19 + .../rainlab/notify/interfaces/Condition.php | 32 + plugins/rainlab/notify/interfaces/Event.php | 21 + plugins/rainlab/notify/lang/ar.json | 61 ++ plugins/rainlab/notify/lang/be.json | 61 ++ plugins/rainlab/notify/lang/bg.json | 61 ++ plugins/rainlab/notify/lang/cs.json | 61 ++ plugins/rainlab/notify/lang/da.json | 61 ++ plugins/rainlab/notify/lang/de.json | 61 ++ plugins/rainlab/notify/lang/es.json | 61 ++ plugins/rainlab/notify/lang/et.json | 61 ++ plugins/rainlab/notify/lang/fa.json | 61 ++ plugins/rainlab/notify/lang/fr.json | 61 ++ plugins/rainlab/notify/lang/hu.json | 61 ++ plugins/rainlab/notify/lang/it.json | 61 ++ plugins/rainlab/notify/lang/nl.json | 61 ++ plugins/rainlab/notify/lang/ru.json | 61 ++ plugins/rainlab/notify/lang/sk.json | 61 ++ plugins/rainlab/notify/lang/sl.json | 61 ++ plugins/rainlab/notify/lang/xx.json | 61 ++ plugins/rainlab/notify/lang/zh-cn.json | 80 ++ .../rainlab/notify/models/Notification.php | 114 +++ .../notify/models/NotificationRule.php | 289 +++++++ plugins/rainlab/notify/models/RuleAction.php | 201 +++++ .../rainlab/notify/models/RuleCondition.php | 172 ++++ .../models/notificationrule/columns.yaml | 13 + .../models/notificationrule/fields.yaml | 47 ++ .../notify/models/ruleaction/columns.yaml | 8 + .../notify/models/ruleaction/fields.yaml | 8 + .../models/ruleaction/fields_schedule.yaml | 30 + .../notifyrules/ExecutionContextCondition.php | 136 ++++ .../notify/notifyrules/SaveDatabaseAction.php | 119 +++ .../notifyrules/SendMailTemplateAction.php | 225 ++++++ .../executioncontextcondition/fields.yaml | 21 + .../savedatabaseaction/fields.yaml | 8 + .../sendmailtemplateaction/fields.yaml | 42 + .../create_notification_rules_table.php | 29 + .../updates/create_notifications_table.php | 28 + .../updates/create_rule_actions_table.php | 25 + .../updates/create_rule_conditions_table.php | 29 + plugins/rainlab/notify/updates/version.yaml | 13 + plugins/rainlab/user/models/User.php | 2 + plugins/rainlab/userplus/LICENCE.md | 19 + plugins/rainlab/userplus/Plugin.php | 124 +++ plugins/rainlab/userplus/README.md | 13 + .../userplus/assets/css/notifications.css | 74 ++ .../userplus/assets/js/notifications.js | 13 + .../userplus/assets/less/notifications.less | 84 ++ .../userplus/components/Notifications.php | 129 +++ .../components/notifications/default.htm | 1 + .../components/notifications/desktop.htm | 14 + .../components/notifications/mobile.htm | 14 + .../notifications/notifications-list.htm | 20 + plugins/rainlab/userplus/composer.json | 8 + .../userplus/config/notify_presets.yaml | 11 + .../userplus/config/profile_fields.yaml | 47 ++ plugins/rainlab/userplus/lang/cs/lang.php | 19 + plugins/rainlab/userplus/lang/en/lang.php | 19 + plugins/rainlab/userplus/lang/fa/lang.php | 16 + plugins/rainlab/userplus/lang/fr/lang.php | 15 + plugins/rainlab/userplus/lang/hu/lang.php | 19 + plugins/rainlab/userplus/lang/pt-br/lang.php | 19 + plugins/rainlab/userplus/lang/tr/lang.php | 19 + .../UserLocationAttributeCondition.php | 37 + .../attributes.yaml | 23 + .../updates/user_add_location_fields.php | 29 + .../updates/user_add_mobile_field.php | 28 + .../updates/user_add_profile_fields.php | 32 + plugins/rainlab/userplus/updates/version.yaml | 10 + plugins/rainlab/userplus/vendor/autoload.php | 7 + .../userplus/vendor/composer/ClassLoader.php | 413 ++++++++++ .../rainlab/userplus/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 9 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 10 + .../vendor/composer/autoload_real.php | 45 ++ .../userplus/vendor/composer/installed.json | 210 +++++ .../vendor/composer/installers/CHANGELOG.md | 60 ++ .../composer/installers/CONTRIBUTING.md | 24 + .../vendor/composer/installers/LICENSE | 19 + .../vendor/composer/installers/README.md | 214 +++++ .../vendor/composer/installers/composer.json | 99 +++ .../composer/installers/phpunit.xml.dist | 25 + .../src/Composer/Installers/AglInstaller.php | 21 + .../Composer/Installers/AimeosInstaller.php | 9 + .../Installers/AnnotateCmsInstaller.php | 11 + .../Composer/Installers/AsgardInstaller.php | 49 ++ .../Composer/Installers/AttogramInstaller.php | 9 + .../src/Composer/Installers/BaseInstaller.php | 136 ++++ .../Composer/Installers/BitrixInstaller.php | 126 +++ .../Composer/Installers/BonefishInstaller.php | 9 + .../Composer/Installers/CakePHPInstaller.php | 83 ++ .../src/Composer/Installers/ChefInstaller.php | 11 + .../Installers/ClanCatsFrameworkInstaller.php | 10 + .../Composer/Installers/CockpitInstaller.php | 34 + .../Installers/CodeIgniterInstaller.php | 11 + .../Installers/Concrete5Installer.php | 13 + .../Composer/Installers/CraftInstaller.php | 35 + .../Composer/Installers/CroogoInstaller.php | 21 + .../Composer/Installers/DecibelInstaller.php | 10 + .../Composer/Installers/DokuWikiInstaller.php | 50 ++ .../Composer/Installers/DolibarrInstaller.php | 16 + .../Composer/Installers/DrupalInstaller.php | 16 + .../src/Composer/Installers/ElggInstaller.php | 9 + .../Composer/Installers/EliasisInstaller.php | 9 + .../Installers/ExpressionEngineInstaller.php | 29 + .../src/Composer/Installers/FuelInstaller.php | 11 + .../Composer/Installers/FuelphpInstaller.php | 9 + .../src/Composer/Installers/GravInstaller.php | 30 + .../Composer/Installers/HuradInstaller.php | 25 + .../Composer/Installers/ImageCMSInstaller.php | 11 + .../src/Composer/Installers/Installer.php | 197 +++++ .../src/Composer/Installers/ItopInstaller.php | 9 + .../Composer/Installers/JoomlaInstaller.php | 15 + .../Composer/Installers/KanboardInstaller.php | 18 + .../Composer/Installers/KirbyInstaller.php | 11 + .../Composer/Installers/KodiCMSInstaller.php | 10 + .../Composer/Installers/KohanaInstaller.php | 9 + .../Composer/Installers/LaravelInstaller.php | 9 + .../Composer/Installers/LavaLiteInstaller.php | 10 + .../Composer/Installers/LithiumInstaller.php | 10 + .../Installers/MODULEWorkInstaller.php | 9 + .../Composer/Installers/MODXEvoInstaller.php | 16 + .../Composer/Installers/MagentoInstaller.php | 11 + .../src/Composer/Installers/MakoInstaller.php | 9 + .../Composer/Installers/MauticInstaller.php | 25 + .../src/Composer/Installers/MayaInstaller.php | 33 + .../Installers/MediaWikiInstaller.php | 50 ++ .../Installers/MicroweberInstaller.php | 111 +++ .../Composer/Installers/MoodleInstaller.php | 57 ++ .../Composer/Installers/OctoberInstaller.php | 46 ++ .../Composer/Installers/OntoWikiInstaller.php | 24 + .../src/Composer/Installers/OxidInstaller.php | 59 ++ .../src/Composer/Installers/PPIInstaller.php | 9 + .../Composer/Installers/PhiftyInstaller.php | 11 + .../Composer/Installers/PhpBBInstaller.php | 11 + .../Composer/Installers/PimcoreInstaller.php | 21 + .../Composer/Installers/PiwikInstaller.php | 32 + .../Installers/PlentymarketsInstaller.php | 29 + .../src/Composer/Installers/Plugin.php | 17 + .../Composer/Installers/PortoInstaller.php | 9 + .../Installers/PrestashopInstaller.php | 10 + .../Composer/Installers/PuppetInstaller.php | 11 + .../Composer/Installers/RadPHPInstaller.php | 24 + .../Composer/Installers/ReIndexInstaller.php | 10 + .../Composer/Installers/RedaxoInstaller.php | 10 + .../Installers/RoundcubeInstaller.php | 22 + .../src/Composer/Installers/SMFInstaller.php | 10 + .../Composer/Installers/ShopwareInstaller.php | 60 ++ .../Installers/SilverStripeInstaller.php | 36 + .../Composer/Installers/SyDESInstaller.php | 49 ++ .../Composer/Installers/Symfony1Installer.php | 26 + .../Composer/Installers/TYPO3CmsInstaller.php | 16 + .../Installers/TYPO3FlowInstaller.php | 38 + .../Composer/Installers/TheliaInstaller.php | 12 + .../src/Composer/Installers/TuskInstaller.php | 14 + .../Composer/Installers/VanillaInstaller.php | 10 + .../Composer/Installers/VgmcpInstaller.php | 49 ++ .../Composer/Installers/WHMCSInstaller.php | 10 + .../Composer/Installers/WolfCMSInstaller.php | 9 + .../Installers/WordPressInstaller.php | 11 + .../Composer/Installers/YawikInstaller.php | 32 + .../src/Composer/Installers/ZendInstaller.php | 11 + .../Composer/Installers/ZikulaInstaller.php | 10 + .../composer/installers/src/bootstrap.php | 13 + .../Installers/Test/AsgardInstallerTest.php | 79 ++ .../Installers/Test/BitrixInstallerTest.php | 76 ++ .../Installers/Test/CakePHPInstallerTest.php | 115 +++ .../Installers/Test/CraftInstallerTest.php | 83 ++ .../Installers/Test/DokuWikiInstallerTest.php | 89 +++ .../Installers/Test/GravInstallerTest.php | 63 ++ .../Installers/Test/InstallerTest.php | 512 ++++++++++++ .../Installers/Test/MayaInstallerTest.php | 61 ++ .../Test/MediaWikiInstallerTest.php | 66 ++ .../Installers/Test/OctoberInstallerTest.php | 66 ++ .../Installers/Test/OntoWikiInstallerTest.php | 85 ++ .../Installers/Test/PimcoreInstallerTest.php | 44 ++ .../Installers/Test/PiwikInstallerTest.php | 63 ++ .../Installers/Test/SyDESInstallerTest.php | 81 ++ .../Composer/Installers/Test/TestCase.php | 64 ++ .../Installers/Test/VgmcpInstallerTest.php | 79 ++ .../Installers/Test/YawikInstallerTest.php | 64 ++ .../composer/installers/tests/bootstrap.php | 4 + .../tps/birzha/classes/ProductResource.php | 9 +- plugins/tps/birzha/controllers/City.php | 18 + plugins/tps/birzha/controllers/Comment.php | 18 + plugins/tps/birzha/controllers/Favourites.php | 18 + .../birzha/controllers/city/_list_toolbar.htm | 18 + .../birzha/controllers/city/config_form.yaml | 10 + .../birzha/controllers/city/config_list.yaml | 12 + .../tps/birzha/controllers/city/create.htm | 46 ++ plugins/tps/birzha/controllers/city/index.htm | 1 + .../tps/birzha/controllers/city/preview.htm | 22 + .../tps/birzha/controllers/city/update.htm | 54 ++ .../controllers/comment/_list_toolbar.htm | 18 + .../controllers/comment/config_form.yaml | 10 + .../controllers/comment/config_list.yaml | 12 + .../tps/birzha/controllers/comment/create.htm | 46 ++ .../tps/birzha/controllers/comment/index.htm | 1 + .../birzha/controllers/comment/preview.htm | 22 + .../tps/birzha/controllers/comment/update.htm | 54 ++ .../controllers/favourites/_list_toolbar.htm | 18 + .../controllers/favourites/config_form.yaml | 10 + .../controllers/favourites/config_list.yaml | 12 + .../birzha/controllers/favourites/create.htm | 46 ++ .../birzha/controllers/favourites/index.htm | 1 + .../birzha/controllers/favourites/preview.htm | 22 + .../birzha/controllers/favourites/update.htm | 54 ++ plugins/tps/birzha/models/City.php | 35 + plugins/tps/birzha/models/Comment.php | 32 + plugins/tps/birzha/models/Favourites.php | 34 + plugins/tps/birzha/models/Product.php | 17 +- plugins/tps/birzha/models/ProductComments.php | 27 + .../tps/birzha/models/category/columns.yaml | 3 + .../tps/birzha/models/category/fields.yaml | 4 + plugins/tps/birzha/models/city/columns.yaml | 13 + plugins/tps/birzha/models/city/fields.yaml | 13 + .../tps/birzha/models/comment/columns.yaml | 19 + plugins/tps/birzha/models/comment/fields.yaml | 25 + .../tps/birzha/models/favourites/columns.yaml | 19 + .../tps/birzha/models/favourites/fields.yaml | 9 + .../tps/birzha/models/product/columns.yaml | 8 + plugins/tps/birzha/models/product/fields.yaml | 23 +- .../tps/birzha/models/sliderapp/fields.yaml | 2 + plugins/tps/birzha/plugin.yaml | 12 + ...builder_table_create_tps_birzha_cities.php | 26 + ...ilder_table_create_tps_birzha_comments.php | 27 + ...der_table_create_tps_birzha_favourites.php | 26 + ...r_table_update_tps_birzha_categories_3.php | 23 + ...builder_table_update_tps_birzha_cities.php | 23 + ...ilder_table_update_tps_birzha_comments.php | 23 + ...der_table_update_tps_birzha_comments_2.php | 23 + ...der_table_update_tps_birzha_comments_3.php | 23 + ...er_table_update_tps_birzha_products_30.php | 23 + ...er_table_update_tps_birzha_products_31.php | 23 + ...er_table_update_tps_birzha_products_32.php | 23 + ...er_table_update_tps_birzha_products_33.php | 23 + ...er_table_update_tps_birzha_products_34.php | 23 + plugins/tps/birzha/updates/version.yaml | 39 + plugins/vdomah/jwtauth/routes.php | 9 + 293 files changed, 15970 insertions(+), 88 deletions(-) create mode 100644 plugins/ahmadfatoni/apigenerator/controllers/api/VendorApiController.php create mode 100644 plugins/rainlab/notify/LICENSE.md create mode 100644 plugins/rainlab/notify/Plugin.php create mode 100644 plugins/rainlab/notify/README.md create mode 100644 plugins/rainlab/notify/classes/ActionBase.php create mode 100644 plugins/rainlab/notify/classes/CompoundCondition.php create mode 100644 plugins/rainlab/notify/classes/ConditionBase.php create mode 100644 plugins/rainlab/notify/classes/EventBase.php create mode 100644 plugins/rainlab/notify/classes/EventParams.php create mode 100644 plugins/rainlab/notify/classes/ModelAttributesConditionBase.php create mode 100644 plugins/rainlab/notify/classes/Notifier.php create mode 100644 plugins/rainlab/notify/classes/ScheduledAction.php create mode 100644 plugins/rainlab/notify/classes/compoundcondition/fields.yaml create mode 100644 plugins/rainlab/notify/classes/modelattributesconditionbase/_column_select_record.htm create mode 100644 plugins/rainlab/notify/classes/modelattributesconditionbase/_field_value.htm create mode 100644 plugins/rainlab/notify/classes/modelattributesconditionbase/fields.yaml create mode 100644 plugins/rainlab/notify/composer.json create mode 100644 plugins/rainlab/notify/controllers/Notifications.php create mode 100644 plugins/rainlab/notify/controllers/notifications/_add_rule_event_form.htm create mode 100644 plugins/rainlab/notify/controllers/notifications/_add_rule_group_form.htm create mode 100644 plugins/rainlab/notify/controllers/notifications/_form_toolbar.htm create mode 100644 plugins/rainlab/notify/controllers/notifications/_list_toolbar.htm create mode 100644 plugins/rainlab/notify/controllers/notifications/config_form.yaml create mode 100644 plugins/rainlab/notify/controllers/notifications/config_list.yaml create mode 100644 plugins/rainlab/notify/controllers/notifications/create.htm create mode 100644 plugins/rainlab/notify/controllers/notifications/index.htm create mode 100644 plugins/rainlab/notify/controllers/notifications/update.htm create mode 100644 plugins/rainlab/notify/formwidgets/ActionBuilder.php create mode 100644 plugins/rainlab/notify/formwidgets/ConditionBuilder.php create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/assets/css/actions.css create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/assets/js/actions.js create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/assets/less/actions.less create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/partials/_action.htm create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/partials/_action_settings_form.htm create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/partials/_actions.htm create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/partials/_actions_container.htm create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/partials/_available_tags.htm create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/partials/_create_action_form.htm create mode 100644 plugins/rainlab/notify/formwidgets/actionbuilder/partials/_schedule.htm create mode 100644 plugins/rainlab/notify/formwidgets/conditionbuilder/assets/css/conditions.css create mode 100644 plugins/rainlab/notify/formwidgets/conditionbuilder/assets/js/conditions.js create mode 100644 plugins/rainlab/notify/formwidgets/conditionbuilder/assets/js/conditions.multivalue.js create mode 100644 plugins/rainlab/notify/formwidgets/conditionbuilder/assets/less/conditions.less create mode 100644 plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_condition.htm create mode 100644 plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_condition_settings_form.htm create mode 100644 plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_conditions.htm create mode 100644 plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_conditions_container.htm create mode 100644 plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_create_child_form.htm create mode 100644 plugins/rainlab/notify/interfaces/Action.php create mode 100644 plugins/rainlab/notify/interfaces/CompoundCondition.php create mode 100644 plugins/rainlab/notify/interfaces/Condition.php create mode 100644 plugins/rainlab/notify/interfaces/Event.php create mode 100644 plugins/rainlab/notify/lang/ar.json create mode 100644 plugins/rainlab/notify/lang/be.json create mode 100644 plugins/rainlab/notify/lang/bg.json create mode 100644 plugins/rainlab/notify/lang/cs.json create mode 100644 plugins/rainlab/notify/lang/da.json create mode 100644 plugins/rainlab/notify/lang/de.json create mode 100644 plugins/rainlab/notify/lang/es.json create mode 100644 plugins/rainlab/notify/lang/et.json create mode 100644 plugins/rainlab/notify/lang/fa.json create mode 100644 plugins/rainlab/notify/lang/fr.json create mode 100644 plugins/rainlab/notify/lang/hu.json create mode 100644 plugins/rainlab/notify/lang/it.json create mode 100644 plugins/rainlab/notify/lang/nl.json create mode 100644 plugins/rainlab/notify/lang/ru.json create mode 100644 plugins/rainlab/notify/lang/sk.json create mode 100644 plugins/rainlab/notify/lang/sl.json create mode 100644 plugins/rainlab/notify/lang/xx.json create mode 100644 plugins/rainlab/notify/lang/zh-cn.json create mode 100644 plugins/rainlab/notify/models/Notification.php create mode 100644 plugins/rainlab/notify/models/NotificationRule.php create mode 100644 plugins/rainlab/notify/models/RuleAction.php create mode 100644 plugins/rainlab/notify/models/RuleCondition.php create mode 100644 plugins/rainlab/notify/models/notificationrule/columns.yaml create mode 100644 plugins/rainlab/notify/models/notificationrule/fields.yaml create mode 100644 plugins/rainlab/notify/models/ruleaction/columns.yaml create mode 100644 plugins/rainlab/notify/models/ruleaction/fields.yaml create mode 100644 plugins/rainlab/notify/models/ruleaction/fields_schedule.yaml create mode 100644 plugins/rainlab/notify/notifyrules/ExecutionContextCondition.php create mode 100644 plugins/rainlab/notify/notifyrules/SaveDatabaseAction.php create mode 100644 plugins/rainlab/notify/notifyrules/SendMailTemplateAction.php create mode 100644 plugins/rainlab/notify/notifyrules/executioncontextcondition/fields.yaml create mode 100644 plugins/rainlab/notify/notifyrules/savedatabaseaction/fields.yaml create mode 100644 plugins/rainlab/notify/notifyrules/sendmailtemplateaction/fields.yaml create mode 100644 plugins/rainlab/notify/updates/create_notification_rules_table.php create mode 100644 plugins/rainlab/notify/updates/create_notifications_table.php create mode 100644 plugins/rainlab/notify/updates/create_rule_actions_table.php create mode 100644 plugins/rainlab/notify/updates/create_rule_conditions_table.php create mode 100644 plugins/rainlab/notify/updates/version.yaml create mode 100644 plugins/rainlab/userplus/LICENCE.md create mode 100644 plugins/rainlab/userplus/Plugin.php create mode 100644 plugins/rainlab/userplus/README.md create mode 100644 plugins/rainlab/userplus/assets/css/notifications.css create mode 100644 plugins/rainlab/userplus/assets/js/notifications.js create mode 100644 plugins/rainlab/userplus/assets/less/notifications.less create mode 100644 plugins/rainlab/userplus/components/Notifications.php create mode 100644 plugins/rainlab/userplus/components/notifications/default.htm create mode 100644 plugins/rainlab/userplus/components/notifications/desktop.htm create mode 100644 plugins/rainlab/userplus/components/notifications/mobile.htm create mode 100644 plugins/rainlab/userplus/components/notifications/notifications-list.htm create mode 100644 plugins/rainlab/userplus/composer.json create mode 100644 plugins/rainlab/userplus/config/notify_presets.yaml create mode 100644 plugins/rainlab/userplus/config/profile_fields.yaml create mode 100644 plugins/rainlab/userplus/lang/cs/lang.php create mode 100644 plugins/rainlab/userplus/lang/en/lang.php create mode 100644 plugins/rainlab/userplus/lang/fa/lang.php create mode 100644 plugins/rainlab/userplus/lang/fr/lang.php create mode 100644 plugins/rainlab/userplus/lang/hu/lang.php create mode 100644 plugins/rainlab/userplus/lang/pt-br/lang.php create mode 100644 plugins/rainlab/userplus/lang/tr/lang.php create mode 100644 plugins/rainlab/userplus/notifyrules/UserLocationAttributeCondition.php create mode 100644 plugins/rainlab/userplus/notifyrules/userlocationattributecondition/attributes.yaml create mode 100644 plugins/rainlab/userplus/updates/user_add_location_fields.php create mode 100644 plugins/rainlab/userplus/updates/user_add_mobile_field.php create mode 100644 plugins/rainlab/userplus/updates/user_add_profile_fields.php create mode 100644 plugins/rainlab/userplus/updates/version.yaml create mode 100644 plugins/rainlab/userplus/vendor/autoload.php create mode 100644 plugins/rainlab/userplus/vendor/composer/ClassLoader.php create mode 100644 plugins/rainlab/userplus/vendor/composer/LICENSE create mode 100644 plugins/rainlab/userplus/vendor/composer/autoload_classmap.php create mode 100644 plugins/rainlab/userplus/vendor/composer/autoload_namespaces.php create mode 100644 plugins/rainlab/userplus/vendor/composer/autoload_psr4.php create mode 100644 plugins/rainlab/userplus/vendor/composer/autoload_real.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installed.json create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/CHANGELOG.md create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/CONTRIBUTING.md create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/LICENSE create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/README.md create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/composer.json create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/phpunit.xml.dist create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AglInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AimeosInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AsgardInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AttogramInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BonefishInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ChefInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CockpitInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DecibelInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DokuWikiInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/EliasisInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/FuelphpInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/GravInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ImageCMSInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Installer.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ItopInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KanboardInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KodiCMSInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LavaLiteInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MauticInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MayaInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OntoWikiInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PhiftyInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Plugin.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PortoInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PrestashopInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PuppetInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RadPHPInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ReIndexInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RedaxoInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SMFInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SyDESInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TheliaInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/VanillaInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/VgmcpInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WHMCSInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/YawikInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/src/bootstrap.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/AsgardInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/BitrixInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/CakePHPInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/CraftInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/DokuWikiInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/GravInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/InstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/MayaInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/MediaWikiInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/OctoberInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/OntoWikiInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/PimcoreInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/PiwikInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/SyDESInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/TestCase.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/VgmcpInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/YawikInstallerTest.php create mode 100644 plugins/rainlab/userplus/vendor/composer/installers/tests/bootstrap.php create mode 100644 plugins/tps/birzha/controllers/City.php create mode 100644 plugins/tps/birzha/controllers/Comment.php create mode 100644 plugins/tps/birzha/controllers/Favourites.php create mode 100644 plugins/tps/birzha/controllers/city/_list_toolbar.htm create mode 100644 plugins/tps/birzha/controllers/city/config_form.yaml create mode 100644 plugins/tps/birzha/controllers/city/config_list.yaml create mode 100644 plugins/tps/birzha/controllers/city/create.htm create mode 100644 plugins/tps/birzha/controllers/city/index.htm create mode 100644 plugins/tps/birzha/controllers/city/preview.htm create mode 100644 plugins/tps/birzha/controllers/city/update.htm create mode 100644 plugins/tps/birzha/controllers/comment/_list_toolbar.htm create mode 100644 plugins/tps/birzha/controllers/comment/config_form.yaml create mode 100644 plugins/tps/birzha/controllers/comment/config_list.yaml create mode 100644 plugins/tps/birzha/controllers/comment/create.htm create mode 100644 plugins/tps/birzha/controllers/comment/index.htm create mode 100644 plugins/tps/birzha/controllers/comment/preview.htm create mode 100644 plugins/tps/birzha/controllers/comment/update.htm create mode 100644 plugins/tps/birzha/controllers/favourites/_list_toolbar.htm create mode 100644 plugins/tps/birzha/controllers/favourites/config_form.yaml create mode 100644 plugins/tps/birzha/controllers/favourites/config_list.yaml create mode 100644 plugins/tps/birzha/controllers/favourites/create.htm create mode 100644 plugins/tps/birzha/controllers/favourites/index.htm create mode 100644 plugins/tps/birzha/controllers/favourites/preview.htm create mode 100644 plugins/tps/birzha/controllers/favourites/update.htm create mode 100644 plugins/tps/birzha/models/City.php create mode 100644 plugins/tps/birzha/models/Comment.php create mode 100644 plugins/tps/birzha/models/Favourites.php create mode 100644 plugins/tps/birzha/models/ProductComments.php create mode 100644 plugins/tps/birzha/models/city/columns.yaml create mode 100644 plugins/tps/birzha/models/city/fields.yaml create mode 100644 plugins/tps/birzha/models/comment/columns.yaml create mode 100644 plugins/tps/birzha/models/comment/fields.yaml create mode 100644 plugins/tps/birzha/models/favourites/columns.yaml create mode 100644 plugins/tps/birzha/models/favourites/fields.yaml create mode 100644 plugins/tps/birzha/updates/builder_table_create_tps_birzha_cities.php create mode 100644 plugins/tps/birzha/updates/builder_table_create_tps_birzha_comments.php create mode 100644 plugins/tps/birzha/updates/builder_table_create_tps_birzha_favourites.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_categories_3.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_cities.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments_2.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments_3.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_30.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_31.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_32.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_33.php create mode 100644 plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_34.php diff --git a/plugins/ahmadfatoni/apigenerator/controllers/api/BlogPostsApiController.php b/plugins/ahmadfatoni/apigenerator/controllers/api/BlogPostsApiController.php index 6ee00d0..9d0a782 100644 --- a/plugins/ahmadfatoni/apigenerator/controllers/api/BlogPostsApiController.php +++ b/plugins/ahmadfatoni/apigenerator/controllers/api/BlogPostsApiController.php @@ -11,6 +11,11 @@ use Illuminate\Support\Facades\Validator; use RainLab\Blog\Models\Post; use TPS\Birzha\Classes\BlogPostResource; use TPS\Birzha\Models\SliderApp; +use TPS\Birzha\Models\UserSliders; +use TPS\Birzha\Models\Product; +use TPS\Birzha\Models\City; +use TPS\Birzha\Models\Favourites; +use TPS\Birzha\Models\Comment; use RainLab\User\Models\User; class BlogPostsApiController extends Controller @@ -19,10 +24,12 @@ class BlogPostsApiController extends Controller protected $helpers; - public function __construct(Post $Post, Helpers $helpers) + public function __construct(Post $Post, Favourites $Favourites, Comment $Comment, Helpers $helpers) { parent::__construct(); $this->Post = $Post; + $this->Favourites = $Favourites; + $this->Comment = $Comment; $this->helpers = $helpers; } @@ -45,6 +52,184 @@ class BlogPostsApiController extends Controller ->paginate($data['per_page'] ?? 7))->response()->getData(), 200); } + public function getAccountSliders($id) + { + $data = UserSliders::where('user_id', $id)->paginate(9); + + if($data) { + $data->each(function ($item, $key) { + $item->img = 'http://78.111.88.8:9086' . \Config::get('cms.storage.media.path') . $item->img; + }); + } + + return response()->json($data, 200); + } + + + public function createComment(Request $request) + { + $currentUser = \JWTAuth::parseToken()->authenticate(); + + $data = $request->all(); + $validator = Validator::make($data, [ + 'product_id' => 'required', + 'comment' => 'required', + 'rating' => 'required|numeric' + ]); + + if($validator->fails()) { + return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() ); + } + + + $comment = new $this->Comment; + //dd($favourite); + $comment->user_id = $currentUser->id; + $comment->product_id = (int)$data['product_id']; + $comment->comment = $data['comment']; + $comment->rating = $data['rating']; + + $comment->save(); + + return $this->helpers->apiArrayResponseBuilder(201, 'ok', ['comment' => $comment]); + + } + + + public function getComment(Request $request) + { + //$data = $request->all(); + // $validator = Validator::make($data, [ + // 'product_id' => 'required', + // ]); + + // if($validator->fails()) { + // return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() ); + // } + + $currentUser = \JWTAuth::parseToken()->authenticate(); + $comment = $this->Comment::where('user_id', $currentUser->id)->paginate(9); + //dd($favourite); + + return response()->json($comment, 200); + + } + + public function getProductComment(Request $request) + { + $data = $request->all(); + $validator = Validator::make($data, [ + 'product_id' => 'required', + ]); + + if($validator->fails()) { + return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() ); + } + + $comment = $this->Comment::where('product_id', $data["product_id"])->where('is_approve', 1)->paginate(15); + //dd($favourite); + + return response()->json($comment, 200); + + } + + + public function createFav(Request $request) + { + $currentUser = \JWTAuth::parseToken()->authenticate(); + + $data = $request->all(); + $validator = Validator::make($data, [ + 'product_id' => 'required' + ]); + + if($validator->fails()) { + return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() ); + } + + + $favourite = new $this->Favourites; + //dd($favourite); + $favourite->user_id = $currentUser->id; + $favourite->product_id = (int)$data['product_id']; + + $favourite->save(); + + return $this->helpers->apiArrayResponseBuilder(201, 'ok', ['favourite' => $favourite]); + + + + } + + + public function getFav(Request $request) + { + $currentUser = \JWTAuth::parseToken()->authenticate(); + + + $favourite = $this->Favourites::where('user_id', $currentUser->id) + ->with(['product' => function($q){ + $q->approved()->with(['images', 'place', 'files', 'translations:locale,model_id,attribute_data']); + }])->paginate(9); + //dd($favourite); + + return response()->json($favourite, 200); + + } + + public function deleteFav($id){ + + $favourite = $this->Favourites->find($id); + $favourite->delete(); + + return $this->helpers->apiArrayResponseBuilder(200, 'success', ['message' => 'Data has been deleted successfully']); + } + + + public function getAccountProducts($id) + { + $data = Product::where('vendor_id', $id) + ->with('categories:id,name') + ->with([ + 'translations:locale,model_id,attribute_data', + 'images:attachment_id,attachment_type,disk_name,file_name', + ]) + ->approved() + ->paginate(9); + + return response()->json($data, 200); + } + + public function getPlaces() + { + $data = City::with([ + 'translations:locale,model_id,attribute_data', + ]) + ->paginate(100); + + return response()->json($data, 200); + } + + + public function getAccountDatas($id) + { + //$data = User::find($id)->first; + + + $data = User::where('id', $id)->select('id', 'name', 'email', 'username', 'type', 'logo', 'shop_title', 'slogan', 'work_time', 'description', 'map', 'banner', 'is_instagram') + ->with(['categories' => function($q){ + $q->with('translations:locale,model_id,attribute_data'); + }]) + ->with('sliders') + ->first(); + + $data->pathUrl = 'http://78.111.88.8:9086' . \Config::get('cms.storage.media.path'); + + return response()->json($data, 200); + } + + + public function getAccounts(Request $request) { @@ -52,7 +237,7 @@ class BlogPostsApiController extends Controller $dataAccounts = User::select('id', 'name', 'email', 'username', 'type', 'logo', 'shop_title', 'slogan', 'work_time', 'description', 'map', 'banner', 'is_instagram') ->with('categories:id,name,slug,icon') - ->get(); + ->paginate(9); if($data && $data["type"] == "home"){ @@ -94,7 +279,7 @@ class BlogPostsApiController extends Controller if($validator->fails()) { return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() ); } - $dataSlider = SliderApp::where('type', $data['type'])->orderBy('order', 'desc')->select('id', 'img', 'type', 'order')->get(); + $dataSlider = SliderApp::where('type', $data['type'])->orderBy('order', 'desc')->select('id', 'img', 'type', 'order')->paginate(9); //$dataSlider["img"] = $path.$dataSlider["img"]; diff --git a/plugins/ahmadfatoni/apigenerator/controllers/api/CategoriesAPIController.php b/plugins/ahmadfatoni/apigenerator/controllers/api/CategoriesAPIController.php index 26e6efd..7e3a799 100644 --- a/plugins/ahmadfatoni/apigenerator/controllers/api/CategoriesAPIController.php +++ b/plugins/ahmadfatoni/apigenerator/controllers/api/CategoriesAPIController.php @@ -33,31 +33,30 @@ class CategoriesAPIController extends Controller if($data["featured"] == 3){ $dataCat = $this->Category - ->select('id', 'name', 'icon', 'status', 'slug', 'sort_order', 'is_featured') + ->select('id', 'name', 'icon', 'status', 'slug', 'sort_order', 'is_featured', 'is_file_category') ->with('translations:locale,model_id,attribute_data') ->orderBy('sort_order', 'asc') ->active() - ->get(); + ->paginate(9); }else{ $dataCat = $this->Category - ->select('id', 'name', 'icon', 'status', 'slug', 'sort_order', 'is_featured') + ->select('id', 'name', 'icon', 'status', 'slug', 'sort_order', 'is_featured', 'is_file_category') ->with('translations:locale,model_id,attribute_data') ->where('is_featured', $data["featured"]) ->orderBy('sort_order', 'asc') ->active() - ->get(); + ->paginate(9); } - - if($dataCat) { $dataCat->each(function ($item, $key) { - $item->icon = $this->pageUrl('index') . \Config::get('cms.storage.media.path') . $item->icon; + $item->icon = 'http://78.111.88.8:9086' . \Config::get('cms.storage.media.path') . $item->icon; }); } + - return $this->helpers->apiArrayResponseBuilder(200, 'success', $dataCat); + return response()->json($dataCat, 200); } public function show($id){ diff --git a/plugins/ahmadfatoni/apigenerator/controllers/api/ProductsApiController.php b/plugins/ahmadfatoni/apigenerator/controllers/api/ProductsApiController.php index af99c6c..0454655 100644 --- a/plugins/ahmadfatoni/apigenerator/controllers/api/ProductsApiController.php +++ b/plugins/ahmadfatoni/apigenerator/controllers/api/ProductsApiController.php @@ -6,6 +6,7 @@ use AhmadFatoni\ApiGenerator\Helpers\Helpers; use Illuminate\Support\Facades\Validator; use TPS\Birzha\Models\Product; use TPS\Birzha\Models\Category; +use TPS\Birzha\Models\City; use TPS\Birzha\Models\Term; use TPS\Birzha\Models\Measure; use TPS\Birzha\Models\Settings; @@ -28,6 +29,7 @@ class ProductsAPIController extends Controller } public function index(){ + //dd("sdf"); $sortOrderParam = strtolower(input('sort_order')); // protect from sql injection @@ -40,13 +42,16 @@ class ProductsAPIController extends Controller $categoryId = intval(input('category_id')); // intval protects from injection $perPage = intval(input('custom_per_page')); // intval protects from injection $productId = intval(input('product_id')); // intval protects from injection + $is_home = intval(input('is_home')); $queryString = input('q'); $locale = input('locale'); // $query = $this->Product::with('categories:id,name') - $query = $this->Product::with([ + $query = Product::with([ 'translations:locale,model_id,attribute_data', 'images:attachment_id,attachment_type,disk_name,file_name', + 'vendor:id,name,email,type,logo,banner,shop_title,slogan,is_instagram', + 'place', ]) ->approved() ->orderBy('ends_at', $sortOrder); @@ -66,6 +71,19 @@ class ProductsAPIController extends Controller $query = null; } } + + if($is_home) { // fetch offers by the category of the product + + $query = $this->Product::with([ + 'translations:locale,model_id,attribute_data', + 'images:attachment_id,attachment_type,disk_name,file_name', + 'place', + 'vendor:id,name,email,type,logo,banner,shop_title,slogan,is_instagram' + ]) + ->where('is_home', 1) + ->approved() + ->orderBy('ends_at', $sortOrder); + } if($productId) { // fetch offers with products in the same category @@ -97,7 +115,8 @@ class ProductsAPIController extends Controller ]) ->orderBy('ends_at', $sortOrder); } - + + $data = $query ? $query->paginate($perPage) : null; @@ -109,8 +128,11 @@ class ProductsAPIController extends Controller $data = $this->Product::with([ 'translations:locale,model_id,attribute_data', 'images:attachment_id,attachment_type,disk_name,file_name', - 'vendor:id,name,surname,email,username' + 'vendor:id,name,surname,email,username,logo,banner', + 'files', 'place' ])->find($id); + + $data->main_path = 'http://78.111.88.8:9086' . \Config::get('cms.storage.media.path'); if ($data && $data->status == 'approved' /*&& $data->ends_at >= \Carbon\Carbon::now()*/){ return response()->json($data, 200); @@ -123,23 +145,20 @@ class ProductsAPIController extends Controller // step1 public function store(Request $request){ $data = $request->all(); - + // dd($data); $rules = [ 'name_ru' => 'required', - // 'name_en' => 'required', 'name_tm' => 'required', - 'price' => 'required|numeric', - 'place' => 'required', + 'place_id' => 'required', 'description_tm' => 'required', - 'description_ru' => 'required', - - 'old_img' => 'array', 'new_img' => 'array', - + 'is_file' => 'required',m // allowed only jpg & png files with size <= 1024 'new_img.*' => 'mimes:jpg,png|max:1024', + + //'new_file.*' => 'max:9024', 'category_id' => [ 'required', @@ -152,6 +171,9 @@ class ProductsAPIController extends Controller } } ], + + + //'place_id' => 'required', ]; @@ -159,44 +181,105 @@ class ProductsAPIController extends Controller if($validator->fails()) { return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() ); } - - $category = Category::find($data['category_id']); - - if(isset($data['productForEditing'])) { // if product is being edited - not added - - if(!$product = $this->checkUserHasProduct($data['productForEditing'])) { - return $this->helpers->apiArrayResponseBuilder(404, 'not found', ['error' => "Resource id = {$data['productForEditing']} could not be found"]); - } - - //approved edilen produkty prodlenie uchin drafta tayinlamak, bagly transacsiasyny goparmak, - if($product && $product->status == 'approved' && $product->transaction) - { - $product->transaction()->update(['description'=>"Lot #{$product->id} {$product->name} harydyn onki publikasia tolegidir.(bu haryt prodlenia uchin taze transaksia doredilyar)"]); - $product->transaction = null; - } - } else { - $product = new $this->Product; + + // validate if no old images and no new images + if(!$request->has('new_img')) { + return response()->json(ErrorResponseApi::translateErrorMessage('atleast_1_image'), 400); } + // if new_img field is passed but empty + if($request->has('new_img')) { + $rules = [ + 'new_img' => 'required' + ]; + $validator = $this->validateForm($data, $rules); + if($validator->fails()) { + return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() ); + } + } + + + + $category = Category::find($data['category_id']); + + + $product = new $this->Product; + + + + + $product->translateContext('tm'); + + $product->name = $data['name_tm']; + $product->setAttributeTranslated('name', $data['name_ru'], 'ru'); + $product->translateContext('tm'); - $product->name = $data['name_tm']; - // Sets a single translated attribute for a language - $product->setAttributeTranslated('name', $data['name_ru'], 'ru'); - // $product->setAttributeTranslated('name', $data['name_en'], 'en'); + $product->description = $data['description_tm']; // Sets a single translated attribute for a language + $product->setAttributeTranslated('description', $data['description_ru'], 'ru'); + $product->setAttributeTranslated('slug', \Str::slug($data['name_ru'],'-'), 'ru'); - // $product->setAttributeTranslated('slug', \Str::slug($data['name_en'],'-'), 'en'); $product->slug = \Str::slug($data['name_tm'],'-'); - $product->status = 'draft'; - + $product->status = 'new'; + + $product->place_id = $data['place_id']; + $product->price = $data['price']; + + $product->is_file_product = $data['is_file']; + + if($data['is_file'] == 1){ + // validate if no old images and no new images + if(!$request->has('new_file')) { + return response()->json(ErrorResponseApi::translateErrorMessage('atleast_1_file'), 400); + } + + // if new_img field is passed but empty + if($request->has('new_file')) { + $rules = [ + 'new_file' => 'required' + ]; + $validator = $this->validateForm($data, $rules); + if($validator->fails()) { + return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() ); + } + } + + + try { + + foreach($data['new_file'] ?? [] as $key => $fileq) { + $product->files = $fileq; + $product->save(); + } + + } catch(\Throwable $e) { + + return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'something went wrong file']); + } + + } $product->vendor_id = \JWTAuth::parseToken()->authenticate()->id; $product->ends_at = null; // if approved but date was expired - - + + + try { + + foreach($data['new_img'] ?? [] as $key => $img) { + $product->images = $img; + $product->save(); + } + + } catch(\Throwable $e) { + + return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'qqqsomething went wrong']); + } + + // product found, validation passed -> can fill product &save + if(!isset($data['productForEditing'])) { // $product->created_at = Carbon::now('Asia/Ashgabat'); $category->products()->save($product); @@ -206,6 +289,10 @@ class ProductsAPIController extends Controller // attach to a new category $category->products()->save($product); } + + + //$produt->save(); + return $this->helpers->apiArrayResponseBuilder(200, 'ok', ['product' => $product]); } @@ -413,16 +500,11 @@ class ProductsAPIController extends Controller $attachedProduct->description = $data['description_tm']; // Sets a single translated attribute for a language $attachedProduct->setAttributeTranslated('description', $data['description_ru'], 'ru'); - $attachedProduct->setAttributeTranslated('description', $data['description_en'], 'en'); + - $attachedProduct->quantity = $data['quantity']; + $attachedProduct->price = $data['price']; - $attachedProduct->measure_id = $data['measure_id']; - $attachedProduct->payment_term_id = $data['payment_term_id']; - $attachedProduct->delivery_term_id = $data['delivery_term_id']; - $attachedProduct->packaging = $data['packaging']; $attachedProduct->place = $data['place']; - $attachedProduct->currency_id = $data['currency_id']; $attachedProduct->save(); return $attachedProduct; @@ -430,21 +512,18 @@ class ProductsAPIController extends Controller public function myProducts() { + dd("sdf"); $perPage = intval(input('custom_per_page')); // intval protects from injection try { $products = \JWTAuth::parseToken()->authenticate() ->products() - ->with('translations:locale,model_id,attribute_data', - 'images:attachment_id,attachment_type,disk_name,file_name') + ->with(['translations:locale,model_id,attribute_data', + 'images:attachment_id,attachment_type,disk_name,file_name', 'place', 'files']) ->orderBy('updated_at', 'desc') ->paginate($perPage); - if($products) { - foreach ($products as $product) { - $product->unit = new MeasureResource($product->measure); - } - } + } catch (\Throwable $th) { return $this->helpers->apiArrayResponseBuilder(500, 'server error', ['message' => 'Something went wrong']); } diff --git a/plugins/ahmadfatoni/apigenerator/controllers/api/VendorApiController.php b/plugins/ahmadfatoni/apigenerator/controllers/api/VendorApiController.php new file mode 100644 index 0000000..8d442ce --- /dev/null +++ b/plugins/ahmadfatoni/apigenerator/controllers/api/VendorApiController.php @@ -0,0 +1,72 @@ +Vendor = $Vendor; + $this->helpers = $helpers; + } + + public function updateVendor(Request $request){ + + $data = $request->all(); + + $validator = Validator::make($data, [ + 'shop_title' => 'required', + 'slogan' => 'required', + 'work_time' => 'required', + 'description' => 'required', + ]); + + + + // $validator = $this->validateForm($data, $rules); + if($validator->fails()) { + return $this->helpers->apiArrayResponseBuilder(400, 'fail', $validator->errors() ); + } + //dd($data); + $currentUser = \JWTAuth::parseToken()->authenticate(); + $vendor = Vendor::find($currentUser->id)->first(); + + //dd($vendor->type); + + if ($vendor->type != "simple"){ + + $vendor->shop_title = $data["shop_title"]; + $vendor->slogan = $data["slogan"]; + $vendor->work_time = $data["work_time"]; + $vendor->description = $data["description"]; + $vendor->save(); + + return $this->helpers->apiArrayResponseBuilder(200, 'ok', [$vendor]); + + }else{ + + return $this->helpers->apiArrayResponseBuilder(400, 'fail'); + + } + + } + + public static function getAfterFilters() {return [];} + public static function getBeforeFilters() {return [];} + public static function getMiddleware() {return [];} + public function callAction($method, $parameters=false) { + return call_user_func_array(array($this, $method), $parameters); + } + +} diff --git a/plugins/ahmadfatoni/apigenerator/routes.php b/plugins/ahmadfatoni/apigenerator/routes.php index ec3aa90..9a933bd 100644 --- a/plugins/ahmadfatoni/apigenerator/routes.php +++ b/plugins/ahmadfatoni/apigenerator/routes.php @@ -9,17 +9,12 @@ Route::group(['prefix' =>'api/v1','namespace' =>'AhmadFatoni\ApiGenerator\Contro // Route::get('categories/{id}/delete', ['as' => 'categories.delete', 'uses' => 'CategoriesAPIController@destroy']); Route::get('products', ['as' => 'products.index', 'uses' => 'ProductsApiController@index']); + // Route::get('products', 'ProductsApiController@index'); Route::get('products/{id}', ['as' => 'products.show', 'uses' => 'ProductsApiController@show']); Route::get('test',['as' => 'test', 'uses' => 'SmsController@index']); // Route::get('products/{id}/delete', ['as' => 'products.delete', 'uses' => 'ProductsApiController@destroy']); - // Route::resource('countries', 'CountriesapiController', ['except' => ['destroy', 'create', 'edit']]); - // Route::resource('currencies', 'CurrenciesapiController', ['except' => ['destroy', 'create', 'edit']]); - // Route::resource('measures', 'MeasuresapiController', ['except' => ['destroy', 'create', 'edit']]); - - - // Route::get('measures/{id}/delete', ['as' => 'measures.delete', 'uses' => 'MeasuresapiController@destroy']); Route::resource('terms', 'TermsapiController', ['except' => ['destroy', 'create', 'edit']]); // Route::get('terms/{id}/delete', ['as' => 'terms.delete', 'uses' => 'TermsapiController@destroy']); @@ -30,19 +25,37 @@ Route::group(['prefix' =>'api/v1','namespace' =>'AhmadFatoni\ApiGenerator\Contro Route::get('news/{id}', 'BlogPostsApiController@show')->where(['id' => '[0-9]+']); Route::get('sliders', 'BlogPostsApiController@getSliders'); + + Route::get('places', 'BlogPostsApiController@getPlaces'); + Route::get('accounts', 'BlogPostsApiController@getAccounts'); + + Route::get('get/product/comments', 'BlogPostsApiController@getProductComment'); + +// Route::get('account/{id}/sliders', 'BlogPostsApiController@getAccountSliders')->where(['id' => '[0-9]+']); + Route::get('account/{id}/products', 'BlogPostsApiController@getAccountProducts')->where(['id' => '[0-9]+']); + Route::get('account/{id}/datas', 'BlogPostsApiController@getAccountDatas'); Route::middleware(['\Tymon\JWTAuth\Middleware\GetUserFromToken'])->group(function () { + Route::post('update/vendor/data', 'VendorApiController@updateVendor'); + + Route::post('create/fav', 'BlogPostsApiController@createFav'); + Route::get('get/fav', 'BlogPostsApiController@getFav'); + Route::delete('fav/{id}', 'BlogPostsApiController@deleteFav'); + + Route::post('create/comment', 'BlogPostsApiController@createComment'); + Route::get('get/customer/comments', 'BlogPostsApiController@getComment'); Route::post('products', 'ProductsApiController@store'); - Route::post('products/{id}', 'ProductsApiController@update') - - ->where('id', '[0-9]+'); + Route::post('products/{id}', 'ProductsApiController@update')->where('id', '[0-9]+'); + Route::delete('products/{id}/image-delete/{image_id}', 'ProductsApiController@imageDelete') ->where(['id' => '[0-9]+', 'image_id' => '[0-9]+']); Route::post('products/{id}/publish', 'ProductsApiController@publish') ->where('id', '[0-9]+'); - Route::get('my-products/','ProductsApiController@myProducts'); + + + Route::get('my-products','ProductsApiController@customerProducts'); Route::get('my-products/{id}','ProductsApiController@showMyProductById'); Route::delete('my-products/{id}', 'ProductsApiController@delete') ->where('id', '[0-9]+'); diff --git a/plugins/rainlab/notify/LICENSE.md b/plugins/rainlab/notify/LICENSE.md new file mode 100644 index 0000000..e49b459 --- /dev/null +++ b/plugins/rainlab/notify/LICENSE.md @@ -0,0 +1,21 @@ +# MIT license + +Copyright (c) 2014-2022 Responsiv Pty Ltd, October CMS + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/rainlab/notify/Plugin.php b/plugins/rainlab/notify/Plugin.php new file mode 100644 index 0000000..783e32d --- /dev/null +++ b/plugins/rainlab/notify/Plugin.php @@ -0,0 +1,74 @@ + 'Notify', + 'description' => 'Notification Services', + 'author' => 'Alexey Bobkov, Samuel Georges', + 'icon' => 'icon-bullhorn' + ]; + } + + /** + * registerSettings + */ + public function registerSettings() + { + return [ + 'notifications' => [ + 'label' => 'Notification Rules', + 'description' => 'Manage the events and actions that trigger notifications.', + 'category' => SettingsManager::CATEGORY_NOTIFICATIONS, + 'icon' => 'icon-bullhorn', + 'url' => Backend::url('rainlab/notify/notifications'), + 'permissions' => ['rainlab.notify.manage_notifications'], + 'order' => 600, + 'keywords' => 'notify' + ], + ]; + } + + /** + * registerNotificationRules + */ + public function registerNotificationRules() + { + return [ + 'groups' => [], + 'events' => [], + 'actions' => [ + \RainLab\Notify\NotifyRules\SaveDatabaseAction::class, + \RainLab\Notify\NotifyRules\SendMailTemplateAction::class, + ], + 'conditions' => [ + \RainLab\Notify\NotifyRules\ExecutionContextCondition::class, + ], + ]; + } + + /** + * registerPermissions + */ + public function registerPermissions() + { + return [ + 'rainlab.notify.manage_notifications' => [ + 'tab' => SettingsManager::CATEGORY_NOTIFICATIONS, + 'label' => 'Notifications management' + ], + ]; + } +} diff --git a/plugins/rainlab/notify/README.md b/plugins/rainlab/notify/README.md new file mode 100644 index 0000000..d1edf67 --- /dev/null +++ b/plugins/rainlab/notify/README.md @@ -0,0 +1,400 @@ +# Notification engine + +**Plugin is currently in Beta status. Proceed with caution.** + +Adds support for sending notifications across a variety of different channels, including mail, SMS and Slack. + +Notifications are managed in the back-end area by navigating to *Settings > Notification rules*. + +## Notification workflow + +When a notification fires, it uses the following workflow: + +1. Plugin registers associated actions, conditions and events using `registerNotificationRules` +1. A notification class is bound to a system event using `Notifier::bindEvent` +1. A system event is fired `Event::fire` +1. The parameters of the event are captured, along with any global context parameters +1. A command is pushed on the queue to process the notification `Queue::push` +1. The command finds all notification rules using the notification class and triggers them +1. The notification conditions are checked and only proceed if met +1. The notification actions are triggered + +Here is an example of a plugin registering notification rules. The `groups` definition will create containers that are used to better organise events. The `presets` definition specifies notification rules defined by the system. + +```php +public function registerNotificationRules() +{ + return [ + 'events' => [ + \RainLab\User\NotifyRules\UserActivatedEvent::class, + ], + 'actions' => [ + \RainLab\User\NotifyRules\SaveToDatabaseAction::class, + ], + 'conditions' => [ + \RainLab\User\NotifyRules\UserAttributeCondition::class + ], + 'groups' => [ + 'user' => [ + 'label' => 'User', + 'icon' => 'icon-user' + ], + ], + 'presets' => '$/rainlab/user/config/notify_presets.yaml', + ]; +} +``` + +Here is an example of triggering a notification. The system event `rainlab.user.activate` is bound to the `UserActivatedEvent` class. + +```php +// Bind to a system event +\RainLab\Notify\Classes\Notifier::bindEvents([ + 'rainlab.user.activate' => \RainLab\User\NotifyRules\UserActivatedEvent::class +]); + +// Fire the system event +Event::fire('rainlab.user.activate', [$this]); +``` + +Here is an example of registering context parameters, which are available globally to all notifications. + +```php +\RainLab\Notify\Classes\Notifier::instance()->registerCallback(function($manager) { + $manager->registerGlobalParams([ + 'user' => Auth::getUser() + ]); +}); +``` + +Here is an example of an event preset: + +```yaml +# =================================== +# Event Presets +# =================================== + +welcome_email: + name: Send welcome email to user + event: RainLab\User\NotifyRules\UserRegisteredEvent + items: + - action: RainLab\Notify\NotifyRules\SendMailTemplateAction + mail_template: rainlab.user::mail.welcome + send_to_mode: user + conditions: + - condition: RainLab\Notify\NotifyRules\ExecutionContextCondition + subcondition: environment + operator: is + value: dev + condition_text: Application environment is dev +``` + +## Creating Event classes + +An event class is responsible for preparing the parameters passed to the conditions and actions. The static method `makeParamsFromEvent` will take the arguments provided by the system event and convert them in to parameters. + +```php +class UserActivatedEvent extends \RainLab\Notify\Classes\EventBase +{ + /** + * @var array Local conditions supported by this event. + */ + public $conditions = [ + \RainLab\User\NotifyRules\UserAttributeCondition::class + ]; + + /** + * Returns information about this event, including name and description. + */ + public function eventDetails() + { + return [ + 'name' => 'Activated', + 'description' => 'A user is activated', + 'group' => 'user' + ]; + } + + /** + * Defines the usable parameters provided by this class. + */ + public function defineParams() + { + return [ + 'name' => [ + 'title' => 'Name', + 'label' => 'Name of the user', + ], + // ... + ]; + } + + public static function makeParamsFromEvent(array $args, $eventName = null) + { + return [ + 'user' => array_get($args, 0) + ]; + } +} +``` + +## Creating Action classes + +Action classes define the final step in a notification and subsequently perform the notification itself. Some examples might be sending and email or writing to the database. + +```php +class SendMailTemplateAction extends \RainLab\Notify\Classes\ActionBase +{ + /** + * Returns information about this event, including name and description. + */ + public function actionDetails() + { + return [ + 'name' => 'Compose a mail message', + 'description' => 'Send a message to a recipient', + 'icon' => 'icon-envelope' + ]; + } + + /** + * Field configuration for the action. + */ + public function defineFormFields() + { + return 'fields.yaml'; + } + + public function getText() + { + $template = $this->host->template_name; + + return 'Send a message using '.$template; + } + + /** + * Triggers this action. + * @param array $params + * @return void + */ + public function triggerAction($params) + { + $email = 'test@email.tld'; + $template = $this->host->template_name; + + Mail::sendTo($email, $template, $params); + } +} +``` + +A form fields definition file is used to provide form fields when the action is established. These values are accessed from condition using the host model via the `$this->host` property. + +```yaml +# =================================== +# Field Definitions +# =================================== + +fields: + + template_name: + label: Template name + type: text +``` + +An action may choose to provide no form fields by simply returning false from the `defineFormFields` method. + +```php +public function defineFormFields() +{ + return false; +} +``` + +## Creating Condition classes + +A condition class should specify how it should appear in the user interface, providing a name, title and summary text. It also must declare an `isTrue` method for evaluating whether the condition is true or not. + +```php +class MyCondition extends \RainLab\Notify\Classes\ConditionBase +{ + /** + * Return either ConditionBase::TYPE_ANY or ConditionBase::TYPE_LOCAL + */ + public function getConditionType() + { + // If the condition should appear for all events + return ConditionBase::TYPE_ANY; + + // If the condition should appear only for some events + return ConditionBase::TYPE_LOCAL; + } + + /** + * Field configuration for the condition. + */ + public function defineFormFields() + { + return 'fields.yaml'; + } + + public function getName() + { + return 'My condition is checked'; + } + + public function getTitle() + { + return 'My condition'; + } + + public function getText() + { + $value = $this->host->mycondition; + + return 'My condition is '.$value; + } + + /** + * Checks whether the condition is TRUE for specified parameters + * @param array $params + * @return bool + */ + public function isTrue(&$params) + { + return true; + } +} +``` + +A form fields definition file is used to provide form fields when the condition is established. These values are accessed from condition using the host model via the `$this->host` property. + +```yaml +# =================================== +# Field Definitions +# =================================== + +fields: + + mycondition: + label: My condition + type: dropdown + options: + true: True + false: False +``` + +## Model attribute condition classes + +Model attribute conditions are designed specially for applying conditions to sets of model attributes. + +```php +class UserAttributeCondition extends \RainLab\Notify\Classes\ModelAttributesConditionBase +{ + protected $modelClass = \RainLab\User\Models\User::class; + + public function getGroupingTitle() + { + return 'User attribute'; + } + + public function getTitle() + { + return 'User attribute'; + } + + /** + * Checks whether the condition is TRUE for specified parameters + * @param array $params Specifies a list of parameters as an associative array. + * @return bool + */ + public function isTrue(&$params) + { + $hostObj = $this->host; + + $attribute = $hostObj->subcondition; + + if (!$user = array_get($params, 'user')) { + throw new ApplicationException('Error evaluating the user attribute condition: the user object is not found in the condition parameters.'); + } + + return parent::evalIsTrue($user); + } +} +``` + +An attributes definition file is used to specify which attributes should be included in the condition. + +```yaml +# =================================== +# Condition Attribute Definitions +# =================================== + +attributes: + + name: + label: Name + + email: + label: Email address + + country: + label: Country + type: relation + relation: + model: RainLab\Location\Models\Country + label: Name + nameFrom: name + keyFrom: id +``` + +## Save to database action + +There is a dedicated table in the database for storing events and their parameters. This table is accessed using the `RainLab\Notify\Models\Notification` model and can be referenced as a relation from your own models. In this example the `MyProject` model contains its own notification channel called `notifications`. + +```php +class MyProject extends Model +{ + // ... + + public $morphMany = [ + 'my_notifications' => [ + \RainLab\Notify\Models\Notification::class, + 'name' => 'notifiable' + ] + ]; +} +``` + +This channel should be registered with the `RainLab\Notify\NotifyRules\SaveDatabaseAction` so it appears as a related object when selecting the action. + +```php +SaveDatabaseAction::extend(function ($action) { + $action->addTableDefinition([ + 'label' => 'Project activity', + 'class' => MyProject::class, + 'relation' => 'my_notifications', + 'param' => 'project' + ]); +}); +``` + +The **label** is shown as the related object, the **class** references the model class, the **relation** refers to the relation name. The **param** defines the parameter name, passed to the triggering event. + +So essentially if you pass a `project` to the event parameters, or if `project` is a global parameter, a notification model is created with the parameters stored in the `data` attribute. Equivalent to the following code: + +```php +$myproject->my_notifications()->create([ + // ... + 'data' => $params +]); +``` + +## Dynamically adding conditions to events + +Events can be extended to include new local conditions. Simply add the condition class to the event `$conditions` array property. + +```php +UserActivatedEvent::extend(function($event) { + $event->conditions[] = \RainLab\UserPlus\NotifyRules\UserLocationAttributeCondition::class; +}); +``` diff --git a/plugins/rainlab/notify/classes/ActionBase.php b/plugins/rainlab/notify/classes/ActionBase.php new file mode 100644 index 0000000..c64b09e --- /dev/null +++ b/plugins/rainlab/notify/classes/ActionBase.php @@ -0,0 +1,168 @@ + 'Action', + 'description' => 'Action Description', + 'icon' => 'icon-dot-circle-o' + ]; + } + + public function __construct($host = null) + { + /* + * Paths + */ + $this->viewPath = $this->configPath = $this->guessConfigPathFrom($this); + + /* + * Parse the config, if available + */ + if ($formFields = $this->defineFormFields()) { + $this->fieldConfig = $this->makeConfig($formFields); + } + + if (!$this->host = $host) { + return; + } + + $this->boot($host); + } + + /** + * Boot method called when the condition class is first loaded + * with an existing model. + * @return array + */ + public function boot($host) + { + // Set default data + if (!$host->exists) { + $this->initConfigData($host); + } + + // Apply validation rules + $host->rules = array_merge($host->rules, $this->defineValidationRules()); + } + + public function triggerAction($params) + { + } + + public function getTitle() + { + return $this->getActionName(); + } + + public function getText() + { + return $this->getActionDescription(); + } + + public function getActionName() + { + return array_get($this->actionDetails(), 'name'); + } + + public function getActionDescription() + { + return array_get($this->actionDetails(), 'description'); + } + + public function getActionIcon() + { + return array_get($this->actionDetails(), 'icon', 'icon-dot-circle-o'); + } + + /** + * Extra field configuration for the condition. + */ + public function defineFormFields() + { + return 'fields.yaml'; + } + + /** + * Determines if this action uses form fields. + * @return bool + */ + public function hasFieldConfig() + { + return !!$this->fieldConfig; + } + + /** + * Returns the field configuration used by this model. + */ + public function getFieldConfig() + { + return $this->fieldConfig; + } + + /** + * Initializes configuration data when the condition is first created. + * @param Model $host + */ + public function initConfigData($host) {} + + /** + * Defines validation rules for the custom fields. + * @return array + */ + public function defineValidationRules() + { + return []; + } + + /** + * Spins over types registered in plugin base class with `registerNotificationRules`. + * @return array + */ + public static function findActions() + { + $results = []; + $bundles = PluginManager::instance()->getRegistrationMethodValues('registerNotificationRules'); + + foreach ($bundles as $plugin => $bundle) { + foreach ((array) array_get($bundle, 'actions', []) as $conditionClass) { + if (!class_exists($conditionClass)) { + continue; + } + + $obj = new $conditionClass; + $results[$conditionClass] = $obj; + } + } + + return $results; + } +} diff --git a/plugins/rainlab/notify/classes/CompoundCondition.php b/plugins/rainlab/notify/classes/CompoundCondition.php new file mode 100644 index 0000000..56c7a8b --- /dev/null +++ b/plugins/rainlab/notify/classes/CompoundCondition.php @@ -0,0 +1,178 @@ +host->condition_type == 0 + ? __('ALL of subconditions should be') . ' ' + : __('ANY of subconditions should be') . ' '; + + $result .= $this->host->condition == 'false' ? 'FALSE' : 'TRUE'; + + return $result; + } + + /** + * getJoinText returns the text to use when joining two rules within. + * @return string + */ + public function getJoinText() + { + return $this->host->condition_type == 0 ? 'AND' : 'OR'; + } + + /** + * Returns a list of condition types (`ConditionBase::TYPE_*` constants) + * that can be added to this compound condition + */ + public function getAllowedSubtypes() + { + return []; + } + + /** + * defineFormFields + */ + public function defineFormFields() + { + return 'fields.yaml'; + } + + public function initConfigData($host) + { + $host->condition_type = 0; + $host->condition = 'true'; + } + + public function getConditionOptions() + { + $options = [ + 'true' => 'TRUE', + 'false' => 'FALSE' + ]; + + return $options; + } + + public function getConditionTypeOptions() + { + $options = [ + '0' => 'ALL subconditions should meet the requirement', + '1' => 'ANY subconditions should meet the requirement' + ]; + + return $options; + } + + /** + * getChildOptions + */ + public function getChildOptions(array $options) + { + extract(array_merge([ + 'extraRules' => [], + ], $options)); + + $result = [ + 'Compound condition' => CompoundCondition::class + ]; + + $classes = $extraRules + self::findConditionsByType(ConditionBase::TYPE_ANY); + + $result = $this->addClassesSubconditions($classes, $result); + + return $result; + } + + protected function addClassesSubconditions($classes, $list) + { + foreach ($classes as $conditionClass => $obj) { + + $subConditions = $obj->listSubconditions(); + + if ($subConditions) { + $groupName = $obj->getGroupingTitle(); + + foreach ($subConditions as $name => $subcondition) { + if (!$groupName) { + $list[$name] = $conditionClass.':'.$subcondition; + } + else { + if (!array_key_exists($groupName, $list)) { + $list[$groupName] = []; + } + + $list[$groupName][$name] = $conditionClass.':'.$subcondition; + } + } + } + else { + $list[$obj->getName()] = $conditionClass; + } + } + + return $list; + } + + /** + * Checks whether the condition is TRUE for specified parameters. + * + * @param array $params + * @return bool + */ + public function isTrue(&$params) + { + $hostObj = $this->host; + + $requiredConditionValue = $hostObj->condition == 'true' ? true : false; + + foreach ($hostObj->children as $subcondition) { + $subconditionResult = $subcondition->getConditionObject()->isTrue($params) ? true : false; + + /* + * All + */ + if ($hostObj->condition_type == 0) { + if ($subconditionResult !== $requiredConditionValue) { + return false; + } + + } + /* + * Any + */ + else { + if ($subconditionResult === $requiredConditionValue) { + return true; + } + } + } + + /* + * All + */ + if ($hostObj->condition_type == 0) { + return true; + } + + return false; + } +} diff --git a/plugins/rainlab/notify/classes/ConditionBase.php b/plugins/rainlab/notify/classes/ConditionBase.php new file mode 100644 index 0000000..81cfaaf --- /dev/null +++ b/plugins/rainlab/notify/classes/ConditionBase.php @@ -0,0 +1,211 @@ +viewPath = $this->configPath = $this->guessConfigPathFrom($this); + + /* + * Parse the config + */ + $this->fieldConfig = $this->makeConfig($this->defineFormFields()); + + if (!$this->host = $host) { + return; + } + + $this->boot($host); + } + + /** + * Boot method called when the condition class is first loaded + * with an existing model. + * @return array + */ + public function boot($host) + { + // Set default data + if (!$host->exists) { + $this->initConfigData($host); + } + + // Apply validation rules + $host->rules = array_merge($host->rules, $this->defineValidationRules()); + + // Inject view paths to the controller through the Form widget + $host->bindEvent('model.form.filterFields', function($form) { + $form->getController()->addViewPath($this->getViewPaths()); + }); + } + + /** + * Extra field configuration for the condition. + */ + public function defineFormFields() + { + return 'fields.yaml'; + } + + /** + * Initializes configuration data when the condition is first created. + * @param Model $host + */ + public function initConfigData($host) {} + + /** + * Defines validation rules for the custom fields. + * @return array + */ + public function defineValidationRules() + { + return []; + } + + public function getText() + { + return 'Condition Text'; + } + + /** + * Returns a condition name for displaying in the condition selection drop-down menu + */ + public function getName() + { + return 'Condition'; + } + + /** + * Returns a condition title for displaying in the condition settings form + */ + public function getTitle() + { + return 'Condition'; + } + + /** + * This function should return one of the `ConditionBase::TYPE_*` constants + * depending on a place where the condition is valid + */ + public function getConditionType() + { + return ConditionBase::TYPE_ANY; + } + + public function listSubconditions() + { + return []; + } + + /** + * Returns a title to use for grouping subconditions + * in the Create Condition drop-down menu + */ + public function getGroupingTitle() + { + return null; + } + + /** + * Returns the field configuration used by this model. + */ + public function getFieldConfig() + { + return $this->fieldConfig; + } + + /** + * Spins over types registered in plugin base class with `registerNotificationRules`, + * checks if the condition type matches and adds it to an array that is returned. + * + * @param string $type Use `self::TYPE_*` constants + * @return array + */ + public static function findConditionsByType($type) + { + $results = []; + $bundles = PluginManager::instance()->getRegistrationMethodValues(static::$registrationMethod); + + foreach ($bundles as $plugin => $bundle) { + foreach ((array) array_get($bundle, 'conditions', []) as $conditionClass) { + if (!class_exists($conditionClass)) { + continue; + } + + $obj = new $conditionClass; + if ($obj->getConditionType() != $type) { + continue; + } + + $results[$conditionClass] = $obj; + } + } + + return $results; + } + + public function setFormFields($fields) + { + + } + + public function setCustomData() + { + } + + public function onPreRender($controller, $widget) + { + } + + /** + * Checks whether the condition is TRUE for specified parameters + * @param array $params + * @return bool + */ + public function isTrue(&$params) + { + return false; + } + + public function getChildOptions(array $options) + { + return []; + } +} diff --git a/plugins/rainlab/notify/classes/EventBase.php b/plugins/rainlab/notify/classes/EventBase.php new file mode 100644 index 0000000..db6241e --- /dev/null +++ b/plugins/rainlab/notify/classes/EventBase.php @@ -0,0 +1,237 @@ + 'Event', + 'description' => 'Event description', + 'group' => 'groupcode' + ]; + } + + public function __construct($host = null) + { + $this->host = $host; + } + + /** + * Defines the parameters used by this class. + * This method should be used as an override in the extended class. + */ + public function defineParams() + { + return []; + } + + /** + * Local conditions supported by this event. + */ + public function defineConditions() + { + return $this->conditions; + } + + /** + * Sets multiple params. + * @param array $params + * @return void + */ + public function setParams($params) + { + $this->params = $params; + } + + /** + * Returns all params. + * @return array + */ + public function getParams() + { + return $this->params; + } + + /** + * Generates event parameters based on arguments from the triggering system event. + * @param array $args + * @param string $eventName + * @return void + */ + public static function makeParamsFromEvent(array $args, $eventName = null) + { + } + + public function getEventName() + { + return Lang::get(array_get($this->eventDetails(), 'name')); + } + + public function getEventDescription() + { + return Lang::get(array_get($this->eventDetails(), 'description')); + } + + public function getEventGroup() + { + return array_get($this->eventDetails(), 'group'); + } + + /** + * Resolves an event or action identifier from a class name or object. + * @param mixed Class name or object + * @return string Identifier in format of vendor-plugin-class + */ + public function getEventIdentifier() + { + $namespace = Str::normalizeClassName(get_called_class()); + if (strpos($namespace, '\\') === null) { + return $namespace; + } + + $parts = explode('\\', $namespace); + $class = array_pop($parts); + $slice = array_slice($parts, 1, 2); + $code = strtolower(implode('-', $slice) . '-' . $class); + + return $code; + } + + /** + * Spins over types registered in plugin base class with `registerNotificationRules`. + * @return array + */ + public static function findEvents() + { + $results = []; + $bundles = PluginManager::instance()->getRegistrationMethodValues('registerNotificationRules'); + + foreach ($bundles as $plugin => $bundle) { + foreach ((array) array_get($bundle, 'events', []) as $conditionClass) { + if (!class_exists($conditionClass)) { + continue; + } + + $obj = new $conditionClass; + $results[$conditionClass] = $obj; + } + } + + return $results; + } + + public static function findEventGroups() + { + $results = []; + $bundles = PluginManager::instance()->getRegistrationMethodValues('registerNotificationRules'); + + foreach ($bundles as $plugin => $bundle) { + if ($groups = array_get($bundle, 'groups')) { + $results += $groups; + } + } + + return $results; + } + + public static function findEventsByGroup($group) + { + $results = []; + + foreach (self::findEvents() as $conditionClass => $obj) { + if ($obj->getEventGroup() != $group) { + continue; + } + + $results[$conditionClass] = $obj; + } + + return $results; + } + + public static function findEventByIdentifier($identifier) + { + foreach (self::findEvents() as $class => $obj) { + if ($obj->getEventIdentifier() == $identifier) { + return $obj; + } + } + } + + /** + * Spins over preset registered in plugin base class with `registerNotificationRules`. + * @return array + */ + public static function findEventPresets() + { + $results = []; + $bundles = PluginManager::instance()->getRegistrationMethodValues('registerNotificationRules'); + + foreach ($bundles as $plugin => $bundle) { + if (!$presets = array_get($bundle, 'presets')) { + continue; + } + + if (!is_array($presets)) { + $presets = Yaml::parse(File::get(File::symbolizePath($presets))); + } + + if ($presets && is_array($presets)) { + $results += $presets; + } + } + + return $results; + } + + public static function findEventPresetsByClass($className) + { + $results = []; + + foreach (self::findEventPresets() as $code => $definition) { + if (!$eventClass = array_get($definition, 'event')) { + continue; + } + + if ($eventClass != $className) { + continue; + } + + $results[$code] = $definition; + } + + return $results; + } +} diff --git a/plugins/rainlab/notify/classes/EventParams.php b/plugins/rainlab/notify/classes/EventParams.php new file mode 100644 index 0000000..cf17577 --- /dev/null +++ b/plugins/rainlab/notify/classes/EventParams.php @@ -0,0 +1,59 @@ +eventClass = $eventClass; + + $this->params = $this->serializeParams($params); + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $this->delete(); + + Notifier::instance()->fireEvent($this->eventClass, $this->unserializeParams()); + } + + protected function serializeParams($params) + { + $result = []; + + foreach ($params as $param => $value) { + $result[$param] = $this->getSerializedPropertyValue($value); + } + + return $result; + } + + protected function unserializeParams() + { + $result = []; + + foreach ($this->params as $param => $value) { + $result[$param] = $this->getRestoredPropertyValue($value); + } + + return $result; + } +} diff --git a/plugins/rainlab/notify/classes/ModelAttributesConditionBase.php b/plugins/rainlab/notify/classes/ModelAttributesConditionBase.php new file mode 100644 index 0000000..b6183a6 --- /dev/null +++ b/plugins/rainlab/notify/classes/ModelAttributesConditionBase.php @@ -0,0 +1,743 @@ + 'is', + 'is_not' => 'is not', + 'equals_or_greater' => 'equals or greater than', + 'equals_or_less' => 'equals or less than', + 'contains' => 'contains', + 'does_not_contain' => 'does not contain', + 'greater' => 'greater than', + 'less' => 'less than', + 'one_of' => 'is one of', + 'not_one_of' => 'is not one of' + ]; + + protected $modelObj = null; + protected $referenceInfo = null; + protected $modelAttributes = null; + + protected static $modelObjCache = []; + protected static $attributeControlTypeCache = []; + + public function __construct($host = null) + { + parent::__construct($host); + + /* + * This is used as a base class, so register view path from here too + */ + $this->addViewPath($this->guessViewPathFrom(__CLASS__)); + } + + public function initConfigData($host) + { + $host->operator = 'is'; + } + + public function setCustomData() + { + $this->host->condition_control_type = $this->evalControlType(); + } + + // + // Definitions + // + + /** + * This function should return one of the `ConditionBase::TYPE_*` constants + * depending on a place where the condition is valid + */ + public function getConditionType() + { + return ConditionBase::TYPE_LOCAL; + } + + public function defineModelAttributes($type = null) + { + return 'attributes.yaml'; + } + + public function defineValidationRules() + { + return [ + 'value' => 'required' + ]; + } + + public function defineFormFields() + { + return plugins_path('rainlab/notify/classes/modelattributesconditionbase/fields.yaml'); + } + + // + // Text helpers + // + + public function getText() + { + $host = $this->host; + $attributes = $this->listModelAttributes(); + + if (isset($attributes[$host->subcondition])) { + $result = $this->getConditionTextPrefix($host, $attributes); + } + else { + $result = __('Unknown Attribute'); + } + + $result .= ' '.array_get($this->operators, $host->operator, $host->operator).' '; + + $controlType = $this->getValueControlType(); + + if ($controlType == 'text') { + $result .= $host->value; + } + else { + $textValue = $this->getCustomTextValue(); + if ($textValue !== false) { + return $result.' '.$textValue; + } + + $referenceInfo = $this->prepareReferenceListInfo(); + $modelObj = $referenceInfo->referenceModel; + + if (!count($referenceInfo->columns)) { + return $result; + } + + if (!strlen($host->value)) { + return $result .= '?'; + } + + $visibleField = $referenceInfo->primaryColumn; + + if ($controlType == 'dropdown') { + $obj = $modelObj->where('id', $host->value)->first(); + if ($obj) { + $result .= e($obj->{$visibleField}); + } + } + else { + $ids = explode(',', $host->value); + foreach ($ids as &$id) { + $id = trim(e($id)); + } + + $records = $modelObj + ->whereIn('id', $ids) + ->orderBy($visibleField) + ->get(); + + $recordNames = []; + foreach ($records as $record) { + $recordNames[] = $record->{$visibleField}; + } + + $result .= '('.implode(', ', $recordNames).')'; + } + } + + return $result; + } + + protected function getConditionTextPrefix($parametersHost, $attributes) + { + return $attributes[$parametersHost->subcondition]; + } + + public function getCustomTextValue() + { + return false; + } + + // + // Options + // + + /** + * getSubconditionOptions + */ + public function getSubconditionOptions() + { + return $this->listModelAttributes(); + } + + /** + * getOperatorOptions + */ + public function getOperatorOptions() + { + $hostObj = $this->host; + $options = []; + $attribute = $hostObj->subcondition; + + $currentOperatorValue = $hostObj->operator; + + $model = $this->getModelObj(); + $definitions = $this->listModelAttributeInfo(); + + if (!isset($definitions[$attribute])) { + $options = ['none' => 'Unknown attribute selected']; + } + else { + $columnType = array_get($definitions[$attribute], 'type'); + + if ($columnType != ConditionBase::CAST_RELATION) { + if ($columnType == ConditionBase::CAST_STRING) { + $options = [ + 'is' => 'is', + 'is_not' => 'is not', + 'contains' => 'contains', + 'does_not_contain' => 'does not contain' + ]; + } + else { + $options = [ + 'is' => 'is', + 'is_not' => 'is not', + 'equals_or_greater' => 'equals or greater than', + 'equals_or_less' => 'equals or less than', + 'greater' => 'greater than', + 'less' => 'less than' + ]; + } + } + else { + $options = [ + 'is' => 'is', + 'is_not' => 'is not', + 'one_of' => 'is one of', + 'not_one_of' => 'is not one of' + ]; + } + } + + if (!array_key_exists($currentOperatorValue, $options)) { + $keys = array_keys($options); + if (count($keys)) { + $hostObj->operator = $options[$keys[0]]; + } + else { + $hostObj->operator = null; + } + } + + return $options; + } + + public function getValueDropdownOptions() + { + $hostObj = $this->host; + $attribute = $hostObj->subcondition; + $definitions = $this->listModelAttributeInfo(); + + if (!isset($definitions[$attribute])) { + return []; + } + + $columnType = array_get($definitions[$attribute], 'type'); + + if ($columnType != ConditionBase::CAST_RELATION) { + return []; + } + + $referenceInfo = $this->prepareReferenceListInfo(); + $referenceModel = $referenceInfo->referenceModel; + $nameFrom = $referenceInfo->primaryColumn; + $keyFrom = $referenceInfo->primaryKey; + + // Determine if the model uses a tree trait + $treeTraits = [ + \October\Rain\Database\Traits\NestedTree::class, + \October\Rain\Database\Traits\SimpleTree::class + ]; + $usesTree = count(array_intersect($treeTraits, class_uses($referenceModel))) > 0; + + $results = $referenceModel->get(); + + return $usesTree + ? $results->listsNested($nameFrom, $keyFrom) + : $results->lists($nameFrom, $keyFrom); + } + + // + // Control type + // + + protected function evalControlType() + { + $hostObj = $this->host; + $attribute = $hostObj->subcondition; + $operator = $hostObj->operator; + + $definitions = $this->listModelAttributeInfo(); + + if (!isset($definitions[$attribute])) { + return 'text'; + } + + $columnType = array_get($definitions[$attribute], 'type'); + + if ($columnType != ConditionBase::CAST_RELATION) { + return 'text'; + } + else { + if ($operator == 'is' || $operator == 'is_not') { + return 'dropdown'; + } + + return 'multi_value'; + } + } + + public function getValueControlType() + { + if (App::runningInBackend()) { + return $this->evalControlType(); + } + + $hostObj = $this->host; + + if ($controlType = $hostObj->condition_control_type) { + return $controlType; + } + + $controlType = $this->evalControlType(); + + $this->getModelObj() + ->where('id', $hostObj->id) + ->update(['condition_control_type' => $controlType]); + + return $hostObj->condition_control_type = $controlType; + } + + // + // Attributes + // + + public function listSubconditions() + { + $attributes = $this->listModelAttributes(); + + $result = []; + + foreach ($attributes as $name => $code) { + $result[$code] = $name; + } + + return $result; + } + + /** + * Returns the supported attributes by a condition as an array. + * The key is the attribute and the value is the label. + * + * @return array + */ + protected function listModelAttributes() + { + $attributeInfo = $this->listModelAttributeInfo(); + + foreach ($attributeInfo as $attribute => $info) { + $attributes[$attribute] = array_get($info, 'label'); + } + + asort($attributes); + + return $attributes; + } + + protected function listModelAttributeInfo() + { + if ($this->modelAttributes) { + return $this->modelAttributes; + } + + $config = $this->makeConfig($this->defineModelAttributes($this->getConditionType())); + + $attributes = $config->attributes ?? []; + + /* + * Set defaults + */ + foreach ($attributes as $attribute => $info) { + if (!isset($info['type'])) { + $attributes[$attribute]['type'] = 'string'; + } + } + + return $this->modelAttributes = $attributes; + } + + // + // Relation based attributes + // + + public function getReferencePrimaryColumn($record) + { + $referenceInfo = $this->prepareReferenceListInfo(); + + return $record->{$referenceInfo->primaryColumn}; + } + + public function listSelectedReferenceRecords() + { + $referenceInfo = $this->prepareReferenceListInfo(); + $model = $referenceInfo->referenceModel; + + $value = $this->host->value; + $keys = strlen($value) ? explode(',', $value) : []; + + if (count($keys)) { + $model = $model->whereIn('id', $keys); + } + else { + $model = $model->whereRaw('id <> id'); + } + + $orderField = $referenceInfo->primaryColumn; + + return $model->orderBy($orderField)->get(); + } + + public function prepareReferenceListInfo() + { + if (!is_null($this->referenceInfo)) { + return $this->referenceInfo; + } + + $model = $this->getModelObj(); + $attribute = $this->host->subcondition; + $definitions = $this->listModelAttributeInfo(); + $definition = array_get($definitions, $attribute); + + $columns = array_get($definition, 'columns'); + $primaryColumn = array_get($definition, 'relation.nameFrom', 'name'); + + if ($model->hasRelation($attribute)) { + $relationType = $model->getRelationType($attribute); + $relationModel = $model->makeRelation($attribute); + $relationObject = $model->{$attribute}(); + + // Some simpler relations can specify a custom local or foreign "other" key, + // which can be detected and implemented here automagically. + $primaryKey = in_array($relationType, ['hasMany', 'belongsTo', 'hasOne']) + ? $relationObject->getOtherKey() + : $relationModel->getKeyName(); + } + elseif ($relationClass = array_get($definition, 'relation.model')) { + $relationModel = new $relationClass; + $primaryKey = array_get($definition, 'relation.keyFrom', 'id'); + } + else { + throw new SystemException(sprintf('Model %s does not contain a relation "%s"', get_class($model), $attribute)); + } + + if (!$columns) { + $columns = [ + $primaryColumn => [ + 'label' => array_get($definition, 'relation.label', '?'), + 'searchable' => true + ] + ]; + } + + $this->referenceInfo = []; + $this->referenceInfo['referenceModel'] = $relationModel; + $this->referenceInfo['primaryKey'] = $primaryKey; + $this->referenceInfo['primaryColumn'] = $primaryColumn; + $this->referenceInfo['columns'] = $columns; + + return $this->referenceInfo = (object) $this->referenceInfo; + } + + public function onPreRender($controller, $widget) + { + $controlType = $this->getValueControlType(); + + if ($controlType != 'multi_value') { + return; + } + + $selectionColumn = [ + '_select_record' => [ + 'label' => '', + 'sortable' => false, + 'type' => 'partial', + 'width' => '10px', + 'path' => plugins_path('rainlab/notify/classes/modelattributesconditionbase/_column_select_record.htm') + ] + ]; + + $referenceInfo = $this->prepareReferenceListInfo(); + $filterModel = $referenceInfo->referenceModel; + $filterColumns = $selectionColumn + $referenceInfo->columns; + + /* + * List widget + */ + $config = $this->makeConfig(); + $config->columns = $filterColumns; + $config->model = $filterModel; + $config->alias = $widget->alias . 'List'; + $config->showSetup = false; + $config->showCheckboxes = false; + $config->recordsPerPage = 6; + $listWidget = $controller->makeWidget('Backend\Widgets\Lists', $config); + + /* + * Search widget + */ + $config = $this->makeConfig(); + $config->alias = $widget->alias . 'Search'; + $config->growable = false; + $config->prompt = 'backend::lang.list.search_prompt'; + $searchWidget = $controller->makeWidget('Backend\Widgets\Search', $config); + $searchWidget->cssClasses[] = 'condition-filter-search'; + + $listWidget->bindToController(); + $searchWidget->bindToController(); + + /* + * Extend list query + */ + $listWidget->bindEvent('list.extendQueryBefore', function ($query) use ($filterModel) { + $this->prepareFilterQuery($query, $filterModel); + }); + + /* + * Link the Search Widget to the List Widget + */ + $listWidget->setSearchTerm($searchWidget->getActiveTerm()); + + $searchWidget->bindEvent('search.submit', function () use (&$searchWidget, $listWidget) { + $listWidget->setSearchTerm($searchWidget->getActiveTerm()); + return $listWidget->onRefresh(); + }); + + $controller->vars['listWidget'] = $listWidget; + $controller->vars['searchWidget'] = $searchWidget; + $controller->vars['filterHostModel'] = $this->host; + } + + public function prepareFilterQuery($query, $model) + { + } + + // + // Condition check + // + + /** + * Checks whether the condition is TRUE for a specified model + * @return bool + */ + public function evalIsTrue($model, $customValue = '__no_eval_value__') + { + $hostObj = $this->host; + + $operator = $hostObj->operator; + $attribute = $hostObj->subcondition; + + $conditionValue = $hostObj->value; + $conditionValue = trim(mb_strtolower($conditionValue)); + + $controlType = $this->getValueControlType(); + + if ($controlType == 'text') { + if ($customValue === self::NO_EVAL_VALUE) { + $modelValue = trim(mb_strtolower($model->{$attribute})); + } + else { + $modelValue = trim(mb_strtolower($customValue)); + } + + if ($operator == 'is') { + return $modelValue == $conditionValue; + } + + if ($operator == 'is_not') { + return $modelValue != $conditionValue; + } + + if ($operator == 'contains') { + return mb_strpos($modelValue, $conditionValue) !== false; + } + + if ($operator == 'does_not_contain') { + return mb_strpos($modelValue, $conditionValue) === false; + } + + if ($operator == 'equals_or_greater') { + return $modelValue >= $conditionValue; + } + + if ($operator == 'equals_or_less') { + return $modelValue <= $conditionValue; + } + + if ($operator == 'greater') { + return $modelValue > $conditionValue; + } + + if ($operator == 'less') { + return $modelValue < $conditionValue; + } + } + + if ($controlType == 'dropdown') { + if ($customValue === self::NO_EVAL_VALUE) { + $modelValue = $model->{$attribute}; + } + else { + $modelValue = $customValue; + } + + if ($operator == 'is') { + if ($modelValue == null) { + return false; + } + + if ($modelValue instanceof EloquentModel) { + return $modelValue->getKey() == $conditionValue; + } + + if ( + is_array($modelValue) && + count($modelValue) == 1 && + array_key_exists(0, $modelValue) + ) { + return $modelValue[0] == $conditionValue; + } + + if ($modelValue instanceof EloquentCollection) { + if ($modelValue->count() != 1) { + return false; + } + + return $modelValue[0]->getKey() == $conditionValue; + } + } + + if ($operator == 'is_not') { + if ($modelValue == null) { + return true; + } + + if ($modelValue instanceof EloquentModel) { + return $modelValue->getKey() != $conditionValue; + } + + if (is_array($modelValue)) { + if (count($modelValue) != 1) { + return true; + } + + if (!array_key_exists(0, $modelValue)) { + return true; + } + + return $modelValue[0] != $conditionValue; + } + + if ($modelValue instanceof EloquentCollection) { + if (!$modelValue->count() || $modelValue->count() > 1) { + return true; + } + + return $modelValue->first()->getKey() != $conditionValue; + } + } + } + + if ($controlType == 'multi_value') { + if ($customValue === self::NO_EVAL_VALUE) { + $modelValue = $model->{$attribute}; + } + else { + $modelValue = $customValue; + } + + if ( + (!$modelValue instanceof EloquentCollection) && + (!$modelValue instanceof EloquentModel) && + !is_array($modelValue) + ) { + return false; + } + + if (strlen($conditionValue)) { + $conditionValues = explode(',', $conditionValue); + foreach ($conditionValues as &$value) { + $value = trim($value); + } + } else { + $conditionValues = []; + } + + if ($modelValue instanceof EloquentCollection) { + $modelKeys = array_keys($modelValue->lists('id', 'id')); + } + elseif ($modelValue instanceof EloquentModel) { + $modelKeys = [$modelValue->getKey()]; + } + else { + $modelKeys = $modelValue; + } + + if ($operator == 'is') { + $operator = 'one_of'; + } + elseif ($operator == 'is_not') { + $operator = 'not_one_of'; + } + + if ($operator == 'one_of') { + return count(array_intersect($conditionValues, $modelKeys)) ? true : false; + } + + if ($operator == 'not_one_of') { + return count(array_intersect($conditionValues, $modelKeys)) ? false : true; + } + } + + return false; + } + + // + // Helpers + // + + public function getModelObj() + { + if ($this->modelObj === null) { + if (array_key_exists($this->modelClass, self::$modelObjCache)) { + $this->modelObj = self::$modelObjCache[$this->modelClass]; + } + else { + $this->modelObj = self::$modelObjCache[$this->modelClass] = new $this->modelClass; + } + } + + return $this->modelObj; + } +} diff --git a/plugins/rainlab/notify/classes/Notifier.php b/plugins/rainlab/notify/classes/Notifier.php new file mode 100644 index 0000000..de0f520 --- /dev/null +++ b/plugins/rainlab/notify/classes/Notifier.php @@ -0,0 +1,134 @@ +registerGlobalParams([...]); + * }); + * + * @param callable $callback A callable function. + */ + public function registerCallback(callable $callback) + { + $this->callbacks[] = $callback; + } + + /** + * Helper to process callbacks once and once only. + * @return void + */ + protected function processCallbacks() + { + if ($this->registered) { + return; + } + + foreach ($this->callbacks as $callback) { + $callback($this); + } + + $this->registered = true; + } + + // + // Event binding + // + + public static function bindEvents(array $events) + { + foreach ($events as $event => $class) { + self::bindEvent($event, $class); + } + } + + public static function bindEvent($systemEventName, $notifyEventClass) + { + Event::listen($systemEventName, function() use ($notifyEventClass, $systemEventName) { + $params = $notifyEventClass::makeParamsFromEvent(func_get_args(), $systemEventName); + + self::instance()->queueEvent($notifyEventClass, $params); + }); + } + + public function queueEvent($eventClass, array $params) + { + $params += $this->getContextVars(); + + // Use queue + if (true) { + Queue::push(new EventParams($eventClass, $params)); + } + else { + $this->fireEvent($eventClass, $params); + } + } + + public function fireEvent($eventClass, array $params) + { + $models = NotificationRuleModel::listRulesForEvent($eventClass); + + foreach ($models as $model) { + $model->setParams($params); + $model->triggerRule(); + } + } + + public function registerGlobalParams(array $params) + { + if (!$this->registeredGlobalParams) { + $this->registeredGlobalParams = []; + } + + $this->registeredGlobalParams = $params + $this->registeredGlobalParams; + } + + public function getContextVars() + { + $this->processCallbacks(); + + $globals = $this->registeredGlobalParams ?: []; + + return [ + 'isBackend' => App::runningInBackend() ? 1 : 0, + 'isConsole' => App::runningInConsole() ? 1 : 0, + 'appLocale' => App::getLocale(), + 'sender' => null // unsafe:BackendAuth::getUser() + ] + $globals; + } +} diff --git a/plugins/rainlab/notify/classes/ScheduledAction.php b/plugins/rainlab/notify/classes/ScheduledAction.php new file mode 100644 index 0000000..bfde132 --- /dev/null +++ b/plugins/rainlab/notify/classes/ScheduledAction.php @@ -0,0 +1,63 @@ +action = $action->id; + $this->params = $this->serializeParams($params); + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $this->delete(); + + if (! $actionClass = RuleAction::find($this->action)) { + return traceLog('Error: Could not restore action #' . $this->action); + } + + $params = $this->unserializeParams(); + $actionClass->triggerAction($params, false); + } + + protected function serializeParams($params) + { + $result = []; + + foreach ($params as $param => $value) { + $result[$param] = $this->getSerializedPropertyValue($value); + } + + return $result; + } + + protected function unserializeParams() + { + $result = []; + + foreach ($this->params as $param => $value) { + $result[$param] = $this->getRestoredPropertyValue($value); + } + + return $result; + } +} diff --git a/plugins/rainlab/notify/classes/compoundcondition/fields.yaml b/plugins/rainlab/notify/classes/compoundcondition/fields.yaml new file mode 100644 index 0000000..551ae81 --- /dev/null +++ b/plugins/rainlab/notify/classes/compoundcondition/fields.yaml @@ -0,0 +1,14 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + condition_type: + label: Condition Type + span: auto + type: dropdown + + condition: + label: Required Value + span: auto + type: dropdown diff --git a/plugins/rainlab/notify/classes/modelattributesconditionbase/_column_select_record.htm b/plugins/rainlab/notify/classes/modelattributesconditionbase/_column_select_record.htm new file mode 100644 index 0000000..a218745 --- /dev/null +++ b/plugins/rainlab/notify/classes/modelattributesconditionbase/_column_select_record.htm @@ -0,0 +1,10 @@ + + + + + diff --git a/plugins/rainlab/notify/classes/modelattributesconditionbase/_field_value.htm b/plugins/rainlab/notify/classes/modelattributesconditionbase/_field_value.htm new file mode 100644 index 0000000..1ac013d --- /dev/null +++ b/plugins/rainlab/notify/classes/modelattributesconditionbase/_field_value.htm @@ -0,0 +1,107 @@ +subcondition; + $controlType = $formModel->getValueControlType(); +?> + + + + + + getValueDropdownOptions(); + ?> + + + + listSelectedReferenceRecords(); + $hasData = $selectedRecords->count(); + ?> +
+ +
+ render() ?> + render() ?> +
+ + +
+
+ + + + + + + + + + + +
+ + + + + + + getReferencePrimaryColumn($record)) ?> +
+
+
+ + + + + + + +
+ + diff --git a/plugins/rainlab/notify/classes/modelattributesconditionbase/fields.yaml b/plugins/rainlab/notify/classes/modelattributesconditionbase/fields.yaml new file mode 100644 index 0000000..d0c4981 --- /dev/null +++ b/plugins/rainlab/notify/classes/modelattributesconditionbase/fields.yaml @@ -0,0 +1,22 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + + subcondition: + label: Attribute + span: auto + type: dropdown + + operator: + label: Operator + span: auto + type: dropdown + dependsOn: subcondition + + value: + label: Value + dependsOn: [subcondition, operator] + type: partial + path: field_value diff --git a/plugins/rainlab/notify/composer.json b/plugins/rainlab/notify/composer.json new file mode 100644 index 0000000..f55725b --- /dev/null +++ b/plugins/rainlab/notify/composer.json @@ -0,0 +1,25 @@ +{ + "name": "rainlab/notify-plugin", + "type": "october-plugin", + "description": "Notify plugin for October CMS", + "homepage": "https://octobercms.com/plugin/rainlab-pages", + "keywords": ["october", "octobercms", "pages"], + "license": "MIT", + "authors": [ + { + "name": "Alexey Bobkov", + "email": "aleksey.bobkov@gmail.com", + "role": "Co-founder" + }, + { + "name": "Samuel Georges", + "email": "daftspunky@gmail.com", + "role": "Co-founder" + } + ], + "require": { + "php": ">=5.5.9", + "composer/installers": "~1.0" + }, + "minimum-stability": "dev" +} diff --git a/plugins/rainlab/notify/controllers/Notifications.php b/plugins/rainlab/notify/controllers/Notifications.php new file mode 100644 index 0000000..20e65f6 --- /dev/null +++ b/plugins/rainlab/notify/controllers/Notifications.php @@ -0,0 +1,130 @@ +asExtension('ListController')->index(); + } + + public function create($eventAlias = null) + { + try { + if (!$eventAlias) { + throw new ApplicationException('Missing a rule code'); + } + + $this->eventAlias = $eventAlias; + $this->bodyClass = 'compact-container breadcrumb-fancy'; + $this->asExtension('FormController')->create(); + } + catch (Exception $ex) { + $this->handleError($ex); + } + } + + public function update($recordId = null, $context = null) + { + $this->bodyClass = 'compact-container breadcrumb-fancy'; + $this->asExtension('FormController')->update($recordId, $context); + } + + public function formExtendModel($model) + { + if (!$model->exists) { + $model->applyEventClass($this->getEventClass()); + $model->name = $model->getEventDescription(); + } + + return $model; + } + + // public function formBeforeSave($model) + // { + // $model->is_custom = 1; + // } + + public function index_onLoadRuleGroupForm() + { + try { + $groups = EventBase::findEventGroups(); + $this->vars['eventGroups'] = $groups; + } + catch (Exception $ex) { + $this->handleError($ex); + } + + return $this->makePartial('add_rule_group_form'); + } + + /** + * This handler requires the group code passed from `onLoadRuleGroupForm` + */ + public function index_onLoadRuleEventForm() + { + try { + if (!$code = post('code')) { + throw new ApplicationException('Missing event group code'); + } + + $events = EventBase::findEventsByGroup($code); + $this->vars['events'] = $events; + } + catch (Exception $ex) { + $this->handleError($ex); + } + + return $this->makePartial('add_rule_event_form'); + } + + protected function getEventClass() + { + $alias = post('event_alias', $this->eventAlias); + + if ($this->eventClass !== null) { + return $this->eventClass; + } + + if (!$event = EventBase::findEventByIdentifier($alias)) { + throw new ApplicationException('Unable to find event with alias: '. $alias); + } + + return $this->eventClass = get_class($event); + } +} diff --git a/plugins/rainlab/notify/controllers/notifications/_add_rule_event_form.htm b/plugins/rainlab/notify/controllers/notifications/_add_rule_event_form.htm new file mode 100644 index 0000000..8e939e2 --- /dev/null +++ b/plugins/rainlab/notify/controllers/notifications/_add_rule_event_form.htm @@ -0,0 +1,39 @@ + 'addRuleEventForm']) ?> + + + + + diff --git a/plugins/rainlab/notify/controllers/notifications/_add_rule_group_form.htm b/plugins/rainlab/notify/controllers/notifications/_add_rule_group_form.htm new file mode 100644 index 0000000..23507f4 --- /dev/null +++ b/plugins/rainlab/notify/controllers/notifications/_add_rule_group_form.htm @@ -0,0 +1,47 @@ + 'addRuleGroupForm']) ?> + + + + + diff --git a/plugins/rainlab/notify/controllers/notifications/_form_toolbar.htm b/plugins/rainlab/notify/controllers/notifications/_form_toolbar.htm new file mode 100644 index 0000000..f2277a3 --- /dev/null +++ b/plugins/rainlab/notify/controllers/notifications/_form_toolbar.htm @@ -0,0 +1,39 @@ +formGetContext() == 'create'; + $pageUrl = isset($pageUrl) ? $pageUrl : null; +?> +
+ + data-request-data="redirect:0" + data-hotkey="ctrl+s, cmd+s"> + + + + + + + + + + + + + + +
diff --git a/plugins/rainlab/notify/controllers/notifications/_list_toolbar.htm b/plugins/rainlab/notify/controllers/notifications/_list_toolbar.htm new file mode 100644 index 0000000..52030b6 --- /dev/null +++ b/plugins/rainlab/notify/controllers/notifications/_list_toolbar.htm @@ -0,0 +1,9 @@ +
+ + + +
diff --git a/plugins/rainlab/notify/controllers/notifications/config_form.yaml b/plugins/rainlab/notify/controllers/notifications/config_form.yaml new file mode 100644 index 0000000..2e2bda0 --- /dev/null +++ b/plugins/rainlab/notify/controllers/notifications/config_form.yaml @@ -0,0 +1,16 @@ +# =================================== +# Form Behavior Config +# =================================== + +name: Notification Rule +form: $/rainlab/notify/models/notificationrule/fields.yaml +modelClass: RainLab\Notify\Models\NotificationRule +defaultRedirect: rainlab/notify/notifications + +create: + redirect: rainlab/notify/notifications/update/:id + redirectClose: rainlab/notify/notifications + +update: + redirect: rainlab/notify/notifications + redirectClose: rainlab/notify/notifications diff --git a/plugins/rainlab/notify/controllers/notifications/config_list.yaml b/plugins/rainlab/notify/controllers/notifications/config_list.yaml new file mode 100644 index 0000000..1d923a2 --- /dev/null +++ b/plugins/rainlab/notify/controllers/notifications/config_list.yaml @@ -0,0 +1,20 @@ +# =================================== +# List Behavior Config +# =================================== + +title: Notification Rules +list: $/rainlab/notify/models/notificationrule/columns.yaml +modelClass: RainLab\Notify\Models\NotificationRule +recordUrl: rainlab/notify/notifications/update/:id +noRecordsMessage: backend::lang.list.no_records +recordsPerPage: 30 +showSetup: true +showCheckboxes: true +defaultSort: + column: count + direction: desc + +toolbar: + buttons: list_toolbar + search: + prompt: backend::lang.list.search_prompt diff --git a/plugins/rainlab/notify/controllers/notifications/create.htm b/plugins/rainlab/notify/controllers/notifications/create.htm new file mode 100644 index 0000000..c1d8cf2 --- /dev/null +++ b/plugins/rainlab/notify/controllers/notifications/create.htm @@ -0,0 +1,31 @@ + + + + +fatalError): ?> + +
+ 'layout', + 'data-change-monitor' => 'true', + 'data-window-close-confirm' => e(__('Are you sure?')), + 'id' => 'post-form' + ]) ?> + + + formRender() ?> + + +
+ + + +
+

fatalError)) ?>

+

+
+ + diff --git a/plugins/rainlab/notify/controllers/notifications/index.htm b/plugins/rainlab/notify/controllers/notifications/index.htm new file mode 100644 index 0000000..766877d --- /dev/null +++ b/plugins/rainlab/notify/controllers/notifications/index.htm @@ -0,0 +1,2 @@ + +listRender() ?> diff --git a/plugins/rainlab/notify/controllers/notifications/update.htm b/plugins/rainlab/notify/controllers/notifications/update.htm new file mode 100644 index 0000000..ab37689 --- /dev/null +++ b/plugins/rainlab/notify/controllers/notifications/update.htm @@ -0,0 +1,30 @@ + + + + +fatalError): ?> + +
+ 'layout', + 'data-change-monitor' => 'true', + 'data-window-close-confirm' => e(__('Are you sure?')), + 'id' => 'post-form' + ]) ?> + + formRender() ?> + + +
+ + + +
+

fatalError)) ?>

+

+
+ + diff --git a/plugins/rainlab/notify/formwidgets/ActionBuilder.php b/plugins/rainlab/notify/formwidgets/ActionBuilder.php new file mode 100644 index 0000000..02d3933 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/ActionBuilder.php @@ -0,0 +1,388 @@ +fillFromConfig([ + // ]); + + if ($widget = $this->makeActionFormWidget()) { + $widget->bindToController(); + } + + if ($widget = $this->makeActionScheduleFormWidget()) { + $widget->bindToController(); + } + } + + /** + * {@inheritDoc} + */ + protected function loadAssets() + { + $this->addJs('js/actions.js', 'RainLab.Notify'); + $this->addCss('css/actions.css', 'RainLab.Notify'); + } + + /** + * {@inheritDoc} + */ + public function render() + { + $this->prepareVars(); + + return $this->makePartial('actions_container'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $this->vars['name'] = $this->getFieldName(); + $this->vars['formModel'] = $this->model; + $this->vars['actions'] = $this->getActions(); + $this->vars['actionFormWidget'] = $this->actionFormWidget; + $connection = config('queue.default'); + $this->vars['queueDriver'] = config("queue.connections.{$connection}.driver"); + $this->vars['actionScheduleFormWidget'] = $this->actionScheduleFormWidget; + $this->vars['availableTags'] = $this->getAvailableTags(); + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + $this->model->bindEvent('model.afterSave', function() { + $this->processSave(); + }); + + return FormField::NO_SAVE_DATA; + } + + protected function processSave() + { + $cache = $this->getCacheActionDataPayload(); + + foreach ($cache as $id => $data) { + $action = $this->findActionObj($id); + + if ($attributes = $this->getCacheActionAttributes($action)) { + $action->fill($attributes); + } + + $action->save(null, $this->sessionKey); + } + } + + // + // AJAX + // + + public function onLoadCreateActionForm() + { + try { + $actions = ActionBase::findActions(); + $this->vars['actions'] = $actions; + } + catch (Exception $ex) { + $this->handleError($ex); + } + + return $this->makePartial('create_action_form'); + } + + public function onSaveAction() + { + $this->restoreCacheActionDataPayload(); + + $action = $this->findActionObj(); + + $data = post('Action', []); + $schedule = post('ActionSchedule', []); + $action->fill($data); + $action->fill($schedule); + $action->validate(); + $action->action_text = $action->getActionObject()->getText(); + + $action->applyCustomData(); + + $this->setCacheActionData($action); + + return $this->renderActions($action); + } + + public function onLoadActionSetup() + { + try { + $action = $this->findActionObj(); + + $data = $this->getCacheActionAttributes($action); + + if (!is_null($this->actionFormWidget)) { + $this->actionFormWidget->setFormValues($data); + } + $this->actionScheduleFormWidget->setFormValues($data); + + $this->prepareVars(); + $this->vars['action'] = $action; + } + catch (Exception $ex) { + $this->handleError($ex); + } + + return $this->makePartial('action_settings_form'); + } + + public function onCreateAction() + { + if (!$className = post('action_class')) { + throw new ApplicationException('Please specify an action'); + } + + $this->restoreCacheActionDataPayload(); + + $newAction = $this->getRelationModel(); + $newAction->class_name = $className; + $newAction->save(); + + $this->model->rule_actions()->add($newAction, post('_session_key')); + + $this->vars['newActionId'] = $newAction->id; + + return $this->renderActions(); + } + + public function onDeleteAction() + { + $action = $this->findActionObj(); + + $this->model->rule_actions()->remove($action, post('_session_key')); + + return $this->renderActions(); + } + + public function onCancelActionSettings() + { + $action = $this->findActionObj(post('new_action_id')); + + $action->delete(); + + return $this->renderActions(); + } + + // + // Postback deferring + // + + public function getCacheActionAttributes($action) + { + return array_get($this->getCacheActionData($action), 'attributes'); + } + + public function getCacheActionTitle($action) + { + return array_get($this->getCacheActionData($action), 'title'); + } + + public function getCacheActionText($action) + { + return array_get($this->getCacheActionData($action), 'text'); + } + + public function getCacheActionData($action, $default = null) + { + $cache = post('action_data', []); + + if (is_array($cache) && array_key_exists($action->id, $cache)) { + return json_decode($cache[$action->id], true); + } + + if ($default === false) { + return null; + } + + return $this->makeCacheActionData($action); + } + + public function makeCacheActionData($action) + { + $data = [ + 'attributes' => $action->config_data, + 'title' => $action->getTitle(), + 'text' => $action->getText(), + ]; + + return $data; + } + + public function setCacheActionData($action) + { + $cache = post('action_data', []); + + $cache[$action->id] = json_encode($this->makeCacheActionData($action)); + + Request::merge([ + 'action_data' => $cache + ]); + } + + public function restoreCacheActionDataPayload() + { + Request::merge([ + 'action_data' => json_decode(post('current_action_data'), true) + ]); + } + + public function getCacheActionDataPayload() + { + return post('action_data', []); + } + + // + // Helpers + // + + protected function getAvailableTags() + { + $tags = []; + + if ($this->model->methodExists('defineParams')) { + $params = $this->model->defineParams(); + + foreach ($params as $param => $definition) { + $tags[$param] = array_get($definition, 'label'); + } + } + + return $tags; + } + + /** + * Updates the primary rule actions container + * @return array + */ + protected function renderActions() + { + $this->prepareVars(); + + return [ + '#'.$this->getId() => $this->makePartial('actions') + ]; + } + + protected function makeActionFormWidget() + { + if ($this->actionFormWidget !== null) { + return $this->actionFormWidget; + } + + if (!$model = $this->findActionObj(null, false)) { + return null; + } + + if (!$model->hasFieldConfig()) { + return null; + } + + $config = $model->getFieldConfig(); + $config->model = $model; + $config->alias = $this->alias . 'Form'; + $config->arrayName = 'Action'; + + $widget = $this->makeWidget('Backend\Widgets\Form', $config); + + return $this->actionFormWidget = $widget; + } + + protected function makeActionScheduleFormWidget() + { + if ($this->actionScheduleFormWidget !== null) { + return $this->actionScheduleFormWidget; + } + + if (!$model = $this->findActionObj(null, false)) { + return null; + } + + $config = $this->makeConfig('$/rainlab/notify/models/ruleaction/fields_schedule.yaml'); + $config->model = $model; + $config->alias = $this->alias . 'ScheduleForm'; + $config->arrayName = 'ActionSchedule'; + + $widget = $this->makeWidget('Backend\Widgets\Form', $config); + + return $this->actionScheduleFormWidget = $widget; + } + + protected function getActions() + { + if ($this->actionsCache !== false) { + return $this->actionsCache; + } + + $relationObject = $this->getRelationObject(); + $actions = $relationObject->withDeferred($this->sessionKey)->get(); + + return $this->actionsCache = $actions ?: null; + } + + protected function findActionObj($actionId = null, $throw = true) + { + $actionId = $actionId ? $actionId : post('current_action_id'); + + $action = null; + + if (strlen($actionId)) { + $action = $this->getRelationModel()->find($actionId); + } + + if ($throw && !$action) { + throw new ApplicationException('Action not found'); + } + + return $action; + } +} diff --git a/plugins/rainlab/notify/formwidgets/ConditionBuilder.php b/plugins/rainlab/notify/formwidgets/ConditionBuilder.php new file mode 100644 index 0000000..083716d --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/ConditionBuilder.php @@ -0,0 +1,455 @@ +fillFromConfig([ + 'conditionsRuleType', + ]); + + if ($widget = $this->makeConditionFormWidget()) { + $widget->bindToController(); + } + + $this->initRootCondition(); + } + + /** + * {@inheritDoc} + */ + protected function loadAssets() + { + $this->addJs('js/conditions.js', 'RainLab.Notify'); + $this->addJs('js/conditions.multivalue.js', 'RainLab.Notify'); + $this->addCss('css/conditions.css', 'RainLab.Notify'); + } + + /** + * {@inheritDoc} + */ + public function render() + { + $this->prepareVars(); + + return $this->makePartial('conditions_container'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $this->vars['name'] = $this->getFieldName(); + $this->vars['rootCondition'] = $this->getConditionsRoot(); + $this->vars['conditionFormWidget'] = $this->conditionFormWidget; + } + + public function initRootCondition() + { + if ($this->getConditionsRoot()) { + return; + } + + $relationObject = $this->getRelationObject(); + + $rootRule = $this->getRelationModel(); + $rootRule->rule_host_type = $this->conditionsRuleType; + $rootRule->class_name = $rootRule->getRootConditionClass(); + $rootRule->save(); + + $relationObject->add($rootRule, $this->sessionKey); + + $this->conditionsRoot = $rootRule; + } + + public function isRootCondition($condition) + { + if ($root = $this->getConditionsRoot()) { + return $condition->id === $root->id; + } + + return false; + } + + public function getConditionsRoot() + { + if ($this->conditionsRoot !== false) { + return $this->conditionsRoot; + } + + $relationObject = $this->getRelationObject(); + $rootCondition = $relationObject->withDeferred($this->sessionKey)->first(); + + return $this->conditionsRoot = $rootCondition ?: null; + } + + /** + * @inheritDoc + */ + public function getSaveValue($value) + { + $this->model->bindEvent('model.afterSave', function() { + $this->processSave(); + }); + + return FormField::NO_SAVE_DATA; + } + + protected function processSave() + { + $cache = $this->getCacheConditionDataPayload(); + + foreach ($cache as $id => $data) { + $condition = $this->findConditionObj($id); + $attributes = $this->getCacheConditionAttributes($condition); + $condition->fill($attributes); + $condition->save(null, $this->sessionKey.'_'.$condition->id); + } + } + + // + // AJAX + // + + public function onLoadConditionSetup() + { + try { + $condition = $this->findConditionObj(); + + $this->prepareVars(); + + $this->vars['condition'] = $condition; + } + catch (Exception $ex) { + $this->handleError($ex); + } + + return $this->makePartial('condition_settings_form'); + } + + public function onLoadCreateChildCondition() + { + try { + $condition = $this->findConditionObj(); + + /* + * Look up parents + */ + $parents = [$condition->id]; + $parentsArray = post('condition_parent_id', []); + $currentId = $condition->id; + + while (array_key_exists($currentId, $parentsArray) && $parentsArray[$currentId]) { + $parents[] = $currentId = $parentsArray[$currentId]; + } + + /* + * Custom rules provided by model + */ + $extraRules = []; + if ($this->model->methodExists('getExtraConditionRules')) { + $extraRules = $this->model->getExtraConditionRules(); + } + + /* + * Look up conditions + */ + $options = $condition->getChildOptions([ + 'ruleType' => $this->conditionsRuleType, + 'parentIds' => $parents, + 'extraRules' => $extraRules + ]); + + $this->prepareVars(); + $this->vars['condition'] = $condition; + $this->vars['options'] = $options; + } + catch (Exception $ex) { + $this->handleError($ex); + } + + return $this->makePartial('create_child_form'); + } + + public function onSaveCondition() + { + $this->restoreCacheConditionDataPayload(); + + $condition = $this->findConditionObj(); + + $data = post('Condition', []); + $condition->fill($data); + $condition->validate(); + $condition->condition_text = $condition->getConditionObject()->getText(); + + $condition->applyCustomData(); + + $this->setCacheConditionData($condition); + + return $this->renderConditions($condition); + } + + public function onCreateCondition() + { + if (!$className = post('condition_class')) { + throw new ValidationException(['condition_class' => 'Please specify a condition']); + } + + $this->restoreCacheConditionDataPayload(); + + $subcondition = null; + + $parts = explode(':', $className); + if (count($parts) > 1) { + $subcondition = $parts[1]; + $className = $parts[0]; + } + + $parentCondition = $this->findConditionObj(); + + $newCondition = $this->getRelationModel(); + $newCondition->class_name = $className; + $newCondition->rule_host_type = $parentCondition->rule_host_type; + + if ($subcondition) { + $newCondition->subcondition = $subcondition; + } + + $newCondition->save(); + + $parentCondition->children()->add($newCondition, post('_session_key').'_'.$parentCondition->id); + + $this->vars['newConditionId'] = $newCondition->id; + + return $this->renderConditions($parentCondition); + } + + public function onDeleteCondition() + { + $parentCondition = null; + + $condition = $this->findConditionObj(); + + if ($parentId = $this->getParentIdFromCondition($condition)) { + $parentCondition = $this->findConditionObj($parentId); + + if ($parentCondition) { + $parentCondition->children()->remove($condition, post('_session_key').'_'.$parentCondition->id); + } + } + + return $this->renderConditions($parentCondition); + } + + public function onCancelConditionSettings() + { + $condition = $this->findConditionObj(post('new_condition_id')); + + $condition->delete(); + + return $this->renderConditions(); + } + + // + // Postback deferring + // + + public function getCacheConditionAttributes($condition) + { + return array_get($this->getCacheConditionData($condition), 'attributes'); + } + + public function getCacheConditionText($condition) + { + return array_get($this->getCacheConditionData($condition), 'text'); + } + + public function getCacheConditionJoinText($condition) + { + return array_get($this->getCacheConditionData($condition), 'joinText'); + } + + public function getCacheConditionData($condition, $default = null) + { + $cache = post('condition_data', []); + + if (is_array($cache) && array_key_exists($condition->id, $cache)) { + return json_decode($cache[$condition->id], true); + } + + if ($default === false) { + return null; + } + + return $this->makeCacheConditionData($condition); + } + + public function makeCacheConditionData($condition) + { + $data = [ + 'attributes' => $condition->config_data, + 'text' => $condition->getText() + ]; + + if ($condition->isCompound()) { + $data['joinText'] = $condition->getJoinText(); + } + + return $data; + } + + public function setCacheConditionData($condition) + { + $cache = post('condition_data', []); + + $cache[$condition->id] = json_encode($this->makeCacheConditionData($condition)); + + Request::merge([ + 'condition_data' => $cache + ]); + } + + public function restoreCacheConditionDataPayload() + { + Request::merge([ + 'condition_data' => json_decode(post('current_condition_data', []), true) + ]); + } + + public function getCacheConditionDataPayload() + { + return post('condition_data'); + } + + // + // Helpers + // + + public function getParentIdFromCondition($condition) + { + if ($parentId = post('current_parent_id')) { + return $parentId; + } + + $parentIds = post('condition_parent_id', []); + + if (isset($parentIds[$condition->id])) { + return $parentIds[$condition->id]; + } + } + + /** + * Updates the primary rule conditions container + * @return array + */ + protected function renderConditions($currentCondition = null) + { + if ($currentCondition && $this->isRootCondition($currentCondition)) { + $condition = $currentCondition; + } + else { + $condition = $this->getConditionsRoot(); + } + + return [ + '#'.$this->getId() => $this->makePartial('conditions', ['condition' => $condition]) + ]; + } + + protected function makeConditionFormWidget() + { + if ($this->conditionFormWidget !== null) { + return $this->conditionFormWidget; + } + + if (!$model = $this->findConditionObj(null, false)) { + return null; + } + + $config = $model->getFieldConfig(); + $config->model = $model; + $config->alias = $this->alias . 'Form'; + $config->arrayName = 'Condition'; + + $widget = $this->makeWidget('Backend\Widgets\Form', $config); + + /* + * Set form values based on postback or cached attributes + */ + if (!$data = post('Condition')) { + $data = $this->getCacheConditionAttributes($model); + } + + $widget->setFormValues($data); + + /* + * Allow conditions to register their own widgets + */ + $model->onPreRender($this->controller, $this); + + return $this->conditionFormWidget = $widget; + } + + protected function findConditionObj($conditionId = null, $throw = true) + { + $conditionId = $conditionId ? $conditionId : post('current_condition_id'); + + $condition = null; + + if (strlen($conditionId)) { + $condition = $this->getRelationModel()->find($conditionId); + } + + if ($throw && !$condition) { + throw new ApplicationException('Condition not found'); + } + + return $condition; + } +} diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/assets/css/actions.css b/plugins/rainlab/notify/formwidgets/actionbuilder/assets/css/actions.css new file mode 100644 index 0000000..817a940 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/assets/css/actions.css @@ -0,0 +1,227 @@ +.action-set { + margin-top: 10px; +} +.action-set ol { + margin: 0; + padding: 0; + list-style: none; +} +.action-set ol > li { + -webkit-transition: width 1s; + transition: width 1s; +} +.action-set ol > li > div { + font-size: 14px; + font-weight: normal; + position: relative; +} +.action-set ol > li > div > a, +.action-set ol > li > div div.content { + color: #2b3e50; + padding: 10px 45px 10px 91px; + display: block; + line-height: 150%; + text-decoration: none; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.action-set ol > li > div span.icon { + display: block; + position: absolute; + width: 22px; + height: 22px; + left: 20px; + top: 15px; + text-align: center; + font-weight: 500; + line-height: 22px; + color: #999; +} +.action-set ol > li > div span.icon > i { + line-height: 22px; + font-weight: normal; + font-size: 22px; + color: #999; +} +.action-set ol > li > div:not(.no-hover):hover, +.action-set ol > li > div.popover-highlight { + background-color: #4ea5e0 !important; +} +.action-set ol > li > div:not(.no-hover):hover span.icon > i, +.action-set ol > li > div.popover-highlight span.icon > i { + color: #fff !important; +} +.action-set ol > li > div:not(.no-hover):hover > a, +.action-set ol > li > div.popover-highlight > a { + color: #ffffff !important; +} +.action-set ol > li > div:not(.no-hover):hover:before, +.action-set ol > li > div.popover-highlight:before { + background-position: 0px -80px; +} +.action-set ol > li > div:not(.no-hover):hover:after, +.action-set ol > li > div.popover-highlight:after { + top: 0 !important; + bottom: 0 !important; +} +.action-set ol > li > div:not(.no-hover):hover span, +.action-set ol > li > div.popover-highlight span { + color: #ffffff !important; +} +.action-set ol > li > div:not(.no-hover):hover span.drag-handle, +.action-set ol > li > div.popover-highlight span.drag-handle { + cursor: move; + opacity: 1; + filter: alpha(opacity=100); +} +.action-set ol > li > div:not(.no-hover):active { + background-color: #3498db !important; +} +.action-set ol > li > div:not(.no-hover):active > a { + color: #ffffff !important; +} +.action-set ol > li > div span.icon:first-child { + font-size: 11px; + color: #ccc; +} +.action-set ol > li > div span.icon:first-child > i { + color: #ccc; + font-size: 15px; +} +.action-set ol > li > div span.icon:last-child { + left: 52px; +} +.action-set ol > li > div span.comment { + display: block; + font-weight: 400; + color: #95a5a6; + font-size: 13px; + margin-top: 2px; + overflow: hidden; + text-overflow: ellipsis; +} +.action-set ol > li > div > .subpanel { + right: 0; + top: 0; + height: 100%; + position: absolute; + z-index: 200; + padding: 0 20px; +} +.action-set ol > li > div > ul.submenu { + position: absolute; + right: 0; + top: 0; + padding: 0; + list-style: none; + z-index: 200; + height: 100%; + display: none; + margin: 0; + font-size: 0; +} +.action-set ol > li > div > ul.submenu li { + font-size: 12px; + height: 100%; + display: inline-block; + background: #2581b8; + border-right: 1px solid #328ec8; +} +.action-set ol > li > div > ul.submenu li p { + display: table; + height: 100%; + padding: 0; + margin: 0; +} +.action-set ol > li > div > ul.submenu li p a { + display: table-cell; + vertical-align: middle; + height: 100%; + padding: 0 20px; + font-size: 13px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + color: #ffffff; + text-decoration: none; +} +.action-set ol > li > div > ul.submenu li p a i.control-icon { + font-size: 22px; +} +.action-set ol > li > div:hover > ul.submenu { + display: block; +} +.action-set ol > li > div .checkbox { + position: absolute; + top: -2px; + right: 0; +} +.action-set ol > li > div .checkbox label { + margin-right: 0; +} +.action-set ol > li > div .checkbox label:before { + border-color: #cccccc; +} +.action-set ol > li > div.popover-highlight { + background-color: #4ea5e0 !important; +} +.action-set ol > li > div.popover-highlight:before { + background-position: 0px -80px; +} +.action-set ol > li > div.popover-highlight > a { + color: #ffffff !important; + cursor: default; +} +.action-set ol > li > div.popover-highlight span { + color: #ffffff !important; +} +.action-set ol > li > div.popover-highlight > ul.submenu, +.action-set ol > li > div.popover-highlight > span.drag-handle { + display: none !important; +} +.action-set ol > li.active > div { + background: #dddddd; +} +.action-set ol > li.active > div:after { + position: absolute; + width: 4px; + left: 0; + top: -1px; + bottom: -1px; + background: #e67e22; + display: block; + content: ' '; +} +.action-set ol > li.active > div > span.comment, +.action-set ol > li.active > div > span.expand { + color: #8f8f8f; +} +.action-set a.menu-control { + display: block; + margin: 20px; + padding: 13px 15px; + border: dotted 2px #ebebeb; + color: #bdc3c7; + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + border-radius: 5px; + vertical-align: middle; +} +.action-set a.menu-control:hover, +.action-set a.menu-control:focus { + text-decoration: none; + background-color: #4ea5e0; + color: #ffffff; + border: none; + padding: 15px 17px; +} +.action-set a.menu-control:active { + background: #3498db; + color: #ffffff; +} +.action-set a.menu-control i { + margin-right: 10px; + font-size: 14px; +} diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/assets/js/actions.js b/plugins/rainlab/notify/formwidgets/actionbuilder/assets/js/actions.js new file mode 100644 index 0000000..ea7a12d --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/assets/js/actions.js @@ -0,0 +1,156 @@ +/* + * Global helpers + */ +function showActionSettings(id) { + var $control = $('[data-action-id='+id+']').closest('[data-control="ruleactions"]') + + $control.ruleActions('onShowNewActionSettings', id) +} + +/* + * Plugin definition + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var RuleActions = function (element, options) { + this.$el = $(element) + this.options = options || {} + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + RuleActions.prototype = Object.create(BaseProto) + RuleActions.prototype.constructor = RuleActions + + RuleActions.prototype.init = function() { + this.$el.on('click', '[data-actions-settings]', this.proxy(this.onShowSettings)) + this.$el.on('click', '[data-actions-delete]', this.proxy(this.onDeleteAction)) + this.$el.one('dispose-control', this.proxy(this.dispose)) + } + + RuleActions.prototype.dispose = function() { + this.$el.off('click', '[data-actions-settings]', this.proxy(this.onShowSettings)) + this.$el.off('click', '[data-actions-delete]', this.proxy(this.onDeleteAction)) + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.ruleActions') + + this.$el = null + + // In some cases options could contain callbacks, + // so it's better to clean them up too. + this.options = null + + BaseProto.dispose.call(this) + } + + RuleActions.prototype.onDeleteAction = function(event) { + var $el = $(event.target), + actionId = getActionIdFromElement($el) + + $el.request(this.options.deleteHandler, { + data: { current_action_id: actionId }, + confirm: 'Do you really want to delete this action?' + }) + } + + RuleActions.prototype.onShowNewActionSettings = function(actionId) { + var $el = $('[data-action-id='+actionId+']') + + var popup_size = 'giant'; + // Action does not use settings + if ($el.hasClass('no-form')) { + // Popup will contain scheduling option only + popup_size = 'medium' + } + + $el.popup({ + handler: this.options.settingsHandler, + extraData: { current_action_id: actionId }, + size: popup_size + }) + + // This will not fire on successful save because the target element + // is replaced by the time the popup loader has finished to call it + $el.one('hide.oc.popup', this.proxy(this.onCancelAction)) + } + + RuleActions.prototype.onCancelAction = function(event) { + var $el = $(event.target), + actionId = getActionIdFromElement($el) + + $el.request(this.options.cancelHandler, { + data: { new_action_id: actionId } + }) + + return false + } + + RuleActions.prototype.onShowSettings = function(event) { + var $el = $(event.target), + actionId = getActionIdFromElement($el) + + var popup_size = 'giant'; + // Action does not use settings + if ($el.closest('li.action-item').hasClass('no-form')) { + popup_size = 'medium' + } + + $el.popup({ + handler: this.options.settingsHandler, + extraData: { current_action_id: actionId }, + size: popup_size + }) + + return false + } + + function getActionIdFromElement($el) { + var $item = $el.closest('li.action-item') + + return $item.data('action-id') + } + + RuleActions.DEFAULTS = { + settingsHandler: null, + deleteHandler: null, + cancelHandler: null, + createHandler: null + } + + // PLUGIN DEFINITION + // ============================ + + var old = $.fn.ruleActions + + $.fn.ruleActions = function (option) { + var args = Array.prototype.slice.call(arguments, 1), items, result + + items = this.each(function () { + var $this = $(this) + var data = $this.data('oc.ruleActions') + var options = $.extend({}, RuleActions.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.ruleActions', (data = new RuleActions(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : items + } + + $.fn.ruleActions.Constructor = RuleActions + + $.fn.ruleActions.noConflict = function () { + $.fn.ruleActions = old + return this + } + + // Add this only if required + $(document).render(function (){ + $('[data-control="ruleactions"]').ruleActions() + }) + +}(window.jQuery); diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/assets/less/actions.less b/plugins/rainlab/notify/formwidgets/actionbuilder/assets/less/actions.less new file mode 100644 index 0000000..16440bb --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/assets/less/actions.less @@ -0,0 +1,273 @@ +@import "../../../../../../../modules/backend/assets/less/core/boot.less"; + +// +// Actions +// -------------------------------------------------- + +@color-actions-item-bg: #ffffff; +@color-actions-item-title: #2b3e50; +@color-actions-item-comment: #95a5a6; +@color-actions-control: #bdc3c7; +@color-actions-hover-bg: @highlight-hover-bg; +@color-actions-hover-text: @highlight-hover-text; +@color-actions-active-bg: @highlight-active-bg; +@color-actions-active-text: @highlight-active-text; +@color-actions-item-active-comment: #8f8f8f; +@color-actions-submenu-text: #ffffff; +@color-actions-light-submenu-bg: #2581b8; +@color-actions-light-submenu-border: #328ec8; + +.action-set { + margin-top: 10px; + + ol { + margin: 0; + padding: 0; + list-style: none; + + > li { + .transition(width 1s); + + > div { + font-size: @font-size-base; + font-weight: normal; + position: relative; + + > a, div.content { + color: @color-actions-item-title; + padding: 10px 45px 10px 91px; + display: block; + line-height: 150%; + text-decoration: none; + .box-sizing(border-box); + } + + span.icon { + display: block; + position: absolute; + width: 22px; + height: 22px; + left: 20px; + top: 15px; + text-align: center; + font-weight: 500; + line-height: 22px; + color: #999; + + > i { + line-height: 22px; + font-weight: normal; + font-size: 22px; + color: #999; + } + } + + &:not(.no-hover):hover, &.popover-highlight { + background-color: @color-actions-hover-bg !important; + + span.icon > i { + color: #fff !important; + } + + > a { + color: @color-actions-hover-text !important; + } + + &:before { + background-position: 0px -80px; + } + + &:after { + top: 0 !important; + bottom: 0 !important; + } + + span { + color: @color-actions-hover-text !important; + + &.drag-handle { + cursor: move; + .opacity(1); + } + } + } + + &:not(.no-hover):active { + background-color: @color-actions-active-bg !important; + + > a { + color: @color-actions-active-text !important; + } + } + + span.icon:first-child { + font-size: 11px; + color: #ccc; + + > i { + color: #ccc; + font-size: 15px; + } + } + span.icon:last-child { + left: 52px; + } + + span.comment { + display: block; + font-weight: 400; + color: @color-actions-item-comment; + font-size: @font-size-base - 1; + margin-top: 2px; + overflow: hidden; + text-overflow: ellipsis; + } + + > .subpanel { + right: 0; + top: 0; + height: 100%; + position: absolute; + z-index: 200; + padding: 0 20px; + } + + > ul.submenu { + position: absolute; + right: 0; + top: 0; + padding: 0; + list-style: none; + z-index: 200; + height: 100%; + display: none; + margin: 0; + font-size: 0; + + li { + font-size: @font-size-base - 2; + height: 100%; + display: inline-block; + background: @color-actions-light-submenu-bg; + border-right: 1px solid @color-actions-light-submenu-border; + + p { + display: table; + height: 100%; + padding: 0; + margin: 0; + + a { + display: table-cell; + vertical-align: middle; + height: 100%; + padding: 0 20px; + font-size: @font-size-base - 1; + .box-sizing(border-box); + color: @color-actions-submenu-text; + text-decoration: none; + + i.control-icon { + font-size: 22px; + } + } + } + } + } + + &:hover { + > ul.submenu { + display: block; + } + } + + .checkbox { + position: absolute; + top: -2px; + right: 0; + + label { + margin-right: 0; + + &:before { + border-color: @color-filelist-cb-border; + } + } + } + + &.popover-highlight { + background-color: @color-actions-hover-bg !important; + + &:before { + background-position: 0px -80px; + } + + > a { + color: @color-actions-hover-text !important; + cursor: default; + } + + span { + color: @color-actions-hover-text !important; + } + + > ul.submenu, > span.drag-handle { + display: none !important; + } + } + } + + &.active { + > div { + background: @color-list-active; + + &:after { + position: absolute; + width: 4px; + left: 0; + top: -1px; + bottom: -1px; + background: @color-list-active-border; + display: block; + content: ' '; + } + + > span.comment, > span.expand { + color: @color-actions-item-active-comment; + } + } + } + } + } + + a.menu-control { + display: block; + margin: 20px; + padding: 13px 15px; + border: dotted 2px #ebebeb; + color: #bdc3c7; + font-size: @font-size-base - 2; + font-weight: 600; + text-transform: uppercase; + border-radius: 5px; + vertical-align: middle; + + &:hover, &:focus { + text-decoration: none; + background-color: @color-actions-hover-bg; + color: @color-actions-hover-text; + border: none; + padding: 15px 17px; + } + + &:active { + background: @color-actions-active-bg; + color: @color-actions-active-text; + } + + i { + margin-right: 10px; + font-size: 14px; + } + } +} \ No newline at end of file diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_action.htm b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_action.htm new file mode 100644 index 0000000..ecda30b --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_action.htm @@ -0,0 +1,29 @@ +
  • +
    +
    + + +
    + + getCacheActionTitle($action))) ?> + getCacheActionText($action))) ?> + + +
    + + +
  • diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_action_settings_form.htm b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_action_settings_form.htm new file mode 100644 index 0000000..5ca84f8 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_action_settings_form.htm @@ -0,0 +1,77 @@ + 'propertyForm']) ?> + + + + fatalError): ?> + + + + + + + + + + + + + + + diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_actions.htm b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_actions.htm new file mode 100644 index 0000000..afabf2d --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_actions.htm @@ -0,0 +1,31 @@ +
    +
      +
    1. +
      +
      + + +
      +
      + getEventName()) ?> + getEventDescription()) ?> +
      +
      +
    2. + + makePartial('action', ['action' => $action]) ?> + +
    + + + + +
    + + + + diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_actions_container.htm b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_actions_container.htm new file mode 100644 index 0000000..3e50fe9 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_actions_container.htm @@ -0,0 +1,14 @@ +
    +
    + makePartial('actions', ['actions' => $actions]) ?> +
    + + +
    diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_available_tags.htm b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_available_tags.htm new file mode 100644 index 0000000..324de43 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_available_tags.htm @@ -0,0 +1,23 @@ + +
    +

    +
    +
      + $description): ?> +
    • + {{ }} +
    • + +
    +
    +
    +
    + +
    +
    +
    + diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_create_action_form.htm b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_create_action_form.htm new file mode 100644 index 0000000..01b04d9 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_create_action_form.htm @@ -0,0 +1,46 @@ + 'addRuleActionForm']) ?> + + + + + + + + diff --git a/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_schedule.htm b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_schedule.htm new file mode 100644 index 0000000..d011fde --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/actionbuilder/partials/_schedule.htm @@ -0,0 +1,22 @@ +
    +

    + + +

    +

    + render() ?> +

    +
    + + + + + + + + + + + +
    +
    diff --git a/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/css/conditions.css b/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/css/conditions.css new file mode 100644 index 0000000..84cba64 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/css/conditions.css @@ -0,0 +1,227 @@ +ul.condition-set { + padding: 5px 0 0; + margin: 0; + list-style: none; +} +ul.condition-set ul { + padding: 0; + margin: 0; + list-style: none; +} +ul.condition-set li { + margin: 0; + padding: 0; +} +ul.condition-set .condition-item { + border-radius: 4px; +} +ul.condition-set .condition-item.is-root { + border-radius: 0; +} +ul.condition-set .condition-item.collapsed .compound-content { + border-left-color: transparent !important; +} +ul.condition-set .condition-item.collapsed .condition-set { + display: none; +} +ul.condition-set .condition-item.collapsed.is-inner .compound-add-item { + display: none; +} +ul.condition-set .condition-item .condition-delete { + position: absolute; + display: block; + width: 10px; + height: 10px; + right: 7px; + top: 7px; +} +ul.condition-set a.condition-collapse { + text-decoration: none; + display: block; + position: absolute; + right: 8px; + top: 2px; +} +ul.condition-set a.condition-collapse > i { + -webkit-transition: transform 0.3s; + transition: transform 0.3s; + width: 15px; + height: 15px; + color: #bdc3c7; + font-size: 12px; + display: block; +} +ul.condition-set a.condition-collapse:hover > i { + color: #999; +} +ul.condition-set li.collapsed a.condition-collapse > i { + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +ul.condition-set .compound-join { + text-align: center; + padding: 3px 0 2px 0; +} +ul.condition-set .compound-join a { + color: #333333; + text-decoration: none; +} +ul.condition-set .compound-join a:hover { + text-decoration: underline; +} +ul.condition-set .condition-item.is-single { + padding: 8px 20px 9px 24px; + background: #fff; + border: 1px solid #eee; + position: relative; +} +ul.condition-set .condition-item.is-single:before { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f126"; + line-height: 100%; + font-size: 16px; + color: #bdc3c7; + position: absolute; + width: 15px; + height: 15px; + left: 12px; + top: 11px; +} +ul.condition-set .condition-item.is-single .condition-text { + padding-left: 10px; +} +ul.condition-set .condition-item.is-single .condition-text a { + color: #333333; + text-decoration: none; +} +ul.condition-set .condition-item.is-single .condition-text a:hover { + text-decoration: underline; +} +ul.condition-set .condition-item.is-single .condition-text a span.operator { + font-weight: 500; +} +ul.condition-set .condition-item.is-single a.condition-delete { + right: 12px; + top: 9px; +} +ul.condition-set .condition-item.is-compound .compound-content { + position: relative; + border-left: 1px solid #dbdee0; + margin-left: 5px; +} +ul.condition-set .condition-item.is-compound .compound-content:before { + color: #bdc3c7; + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f111"; + font-size: 8px; + position: absolute; + left: -4px; + top: -2px; +} +ul.condition-set .condition-item.is-compound .compound-content h4 { + padding: 0 30px 5px 5px; + margin: 0; + position: relative; + top: -5px; + font-size: 13px; + line-height: 130%; + font-weight: 400; + color: #666; +} +ul.condition-set .condition-item.is-compound .compound-content h4 a.condition-text { + color: #333333; + padding-left: 10px; +} +ul.condition-set .condition-item.is-compound .compound-content h4 a.condition-text:hover { + text-decoration: underline; +} +ul.condition-set .condition-item.is-compound .compound-content .condition-set { + padding-left: 15px; +} +ul.condition-set .condition-item.is-compound .compound-add-item { + position: relative; + margin-top: 10px; + margin-left: 20px; + border: 2px dotted #e0e0e0; + border-radius: 5px; +} +ul.condition-set .condition-item.is-compound .compound-add-item:before { + color: #bdc3c7; + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f067"; + font-size: 16px; + position: absolute; + left: -23px; + top: -11px; +} +ul.condition-set .condition-item.is-compound .compound-add-item > a { + color: #bdc3c7; + text-align: center; + display: block; + text-decoration: none; + padding: 13px 15px; + text-transform: uppercase; + font-weight: 600; + font-size: 12px; +} +ul.condition-set .condition-item.is-compound .compound-add-item:hover, +ul.condition-set .condition-item.is-compound .compound-add-item:focus { + background-color: #4ea5e0; + border-color: #4ea5e0; +} +ul.condition-set .condition-item.is-compound .compound-add-item:hover:before, +ul.condition-set .condition-item.is-compound .compound-add-item:focus:before { + color: #999; +} +ul.condition-set .condition-item.is-compound .compound-add-item:hover > a, +ul.condition-set .condition-item.is-compound .compound-add-item:focus > a { + color: #ffffff; +} +ul.condition-set .condition-item.is-compound .compound-add-item:active { + background: #3498db; + border-color: #3498db; +} +ul.condition-set .condition-item.is-compound .compound-add-item:active > a { + color: #ffffff; +} +ul.condition-set .condition-item.is-compound.is-inner { + padding-right: 20px; +} +ul.condition-set .condition-item.is-compound.is-inner a.condition-delete-compound { + right: -7px; + top: 0; +} +.condition-multi-value .condition-filter-search { + background-position: right -81px !important; + border-top: none !important; + border-left: none !important; + border-right: none !important; + border-radius: 0; + padding-left: 20px; +} +.condition-multi-value .filter-list { + margin: 0 -20px; +} +.condition-multi-value .filter-list .list-footer { + padding-top: 0; + padding-bottom: 0; +} +.condition-multi-value .added-filter-list { + margin: 0 -20px; +} diff --git a/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/js/conditions.js b/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/js/conditions.js new file mode 100644 index 0000000..e4a7379 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/js/conditions.js @@ -0,0 +1,184 @@ +/* + * Global helpers + */ +function showConditionSettings(id) { + var $control = $('[data-condition-id='+id+']').closest('[data-control="ruleconditions"]') + + $control.ruleConditions('onShowNewConditionSettings', id) +} + +/* + * Plugin definition + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var RuleConditions = function (element, options) { + this.$el = $(element) + this.options = options || {} + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + RuleConditions.prototype = Object.create(BaseProto) + RuleConditions.prototype.constructor = RuleConditions + + RuleConditions.prototype.init = function() { + this.$el.on('click', '[data-conditions-collapse]', this.proxy(this.onConditionsToggle)) + this.$el.on('click', '[data-conditions-settings]', this.proxy(this.onShowSettings)) + this.$el.on('click', '[data-conditions-create]', this.proxy(this.onCreateChildCondition)) + this.$el.on('click', '[data-conditions-delete]', this.proxy(this.onDeleteCondition)) + this.$el.one('dispose-control', this.proxy(this.dispose)) + } + + RuleConditions.prototype.dispose = function() { + this.$el.off('click', '[data-conditions-collapse]', this.proxy(this.onConditionsToggle)) + this.$el.off('click', '[data-conditions-settings]', this.proxy(this.onShowSettings)) + this.$el.off('click', '[data-conditions-create]', this.proxy(this.onCreateChildCondition)) + this.$el.off('click', '[data-conditions-delete]', this.proxy(this.onDeleteCondition)) + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.ruleConditions') + + this.$el = null + + // In some cases options could contain callbacks, + // so it's better to clean them up too. + this.options = null + + BaseProto.dispose.call(this) + } + + RuleConditions.prototype.onDeleteCondition = function(event) { + var $el = $(event.target), + conditionId = getConditionIdFromElement($el) + + $el.request(this.options.deleteHandler, { + data: { current_condition_id: conditionId }, + confirm: 'Do you really want to delete this condition?' + }) + } + + RuleConditions.prototype.onCreateChildCondition = function(event) { + var $el = $(event.target), + conditionId = getConditionIdFromElement($el) + + $el.popup({ + handler: this.options.createHandler, + extraData: { current_condition_id: conditionId }, + size: 'large' + }) + + return false + } + + RuleConditions.prototype.onConditionsToggle = function(event) { + var $el = $(event.target), + $item = $el.closest('li'), + newStatusValue = $item.hasClass('collapsed') ? 0 : 1, + conditionId = getConditionIdFromElement($el) + + $el.request(this.options.collapseHandler, { + data: { + status: newStatusValue, + group: conditionId + } + }) + + if (newStatusValue) { + $el.parents('li:first').addClass('collapsed'); + } + else { + $el.parents('li:first').removeClass('collapsed'); + } + + return false + } + + RuleConditions.prototype.onShowNewConditionSettings = function(conditionId) { + var $el = $('[data-condition-id='+conditionId+']') + + $el.popup({ + handler: this.options.settingsHandler, + extraData: { current_condition_id: conditionId }, + size: 'large' + }) + + // This will not fire on successful save because the target element + // is replaced by the time the popup loader has finished to call it + $el.one('hide.oc.popup', this.proxy(this.onCancelCondition)) + } + + RuleConditions.prototype.onCancelCondition = function(event) { + var $el = $(event.target), + conditionId = getConditionIdFromElement($el) + + $el.request(this.options.cancelHandler, { + data: { new_condition_id: conditionId } + }) + + return false + } + + RuleConditions.prototype.onShowSettings = function(event) { + var $el = $(event.target), + conditionId = getConditionIdFromElement($el) + + $el.popup({ + handler: this.options.settingsHandler, + extraData: { current_condition_id: conditionId }, + size: 'large' + }) + + return false + } + + function getConditionIdFromElement($el) { + var $item = $el.closest('li.condition-item') + + return $item.data('condition-id') + } + + RuleConditions.DEFAULTS = { + collapseHandler: null, + settingsHandler: null, + deleteHandler: null, + cancelHandler: null, + createHandler: null + } + + // PLUGIN DEFINITION + // ============================ + + var old = $.fn.ruleConditions + + $.fn.ruleConditions = function (option) { + var args = Array.prototype.slice.call(arguments, 1), items, result + + items = this.each(function () { + var $this = $(this) + var data = $this.data('oc.ruleConditions') + var options = $.extend({}, RuleConditions.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.ruleConditions', (data = new RuleConditions(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : items + } + + $.fn.ruleConditions.Constructor = RuleConditions + + $.fn.ruleConditions.noConflict = function () { + $.fn.ruleConditions = old + return this + } + + // Add this only if required + $(document).render(function (){ + $('[data-control="ruleconditions"]').ruleConditions() + }) + +}(window.jQuery); diff --git a/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/js/conditions.multivalue.js b/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/js/conditions.multivalue.js new file mode 100644 index 0000000..f87e2f8 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/js/conditions.multivalue.js @@ -0,0 +1,139 @@ +/* + * Plugin definition + */ ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var ConditionMultiValue = function (element, options) { + this.$el = $(element) + this.options = options || {} + this.$template = $('[data-record-template]', this.$el) + this.$emptyTemplate = $('[data-empty-record-template]', this.$el) + this.$addedRecords = $('[data-added-records]', this.$el) + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + + this.init() + this.recompileData() + } + + ConditionMultiValue.prototype = Object.create(BaseProto) + ConditionMultiValue.prototype.constructor = ConditionMultiValue + + ConditionMultiValue.prototype.init = function() { + this.$el.on('click', '[data-multivalue-add-record]', this.proxy(this.onAddRecord)) + this.$el.on('click', '[data-multivalue-remove-record]', this.proxy(this.onRemoveRecord)) + this.$el.one('dispose-control', this.proxy(this.dispose)) + } + + ConditionMultiValue.prototype.dispose = function() { + this.$el.off('click', '[data-multivalue-add-record]', this.proxy(this.onAddRecord)) + this.$el.off('click', '[data-multivalue-remove-record]', this.proxy(this.onRemoveRecord)) + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.conditionMultiValue') + + this.$el = null + + // In some cases options could contain callbacks, + // so it's better to clean them up too. + this.options = null + + BaseProto.dispose.call(this) + } + + ConditionMultiValue.prototype.onAddRecord = function(event) { + var $el = $(event.target), + recordId = $el.closest('[data-record-key]').data('record-key'), + recordValue = $el.closest('a').data('record-value') + + if (!!$('[data-record-key='+recordId+']', this.$addedRecords).length) { + return + } + + this.$addedRecords.append(this.renderTemplate({ + key: recordId, + value: recordValue + })) + + this.recompileData() + } + + ConditionMultiValue.prototype.onRemoveRecord = function(event) { + var $el = $(event.target), + recordId = $el.closest('[data-record-key]').data('record-key') + + $('[data-record-key='+recordId+']', this.$addedRecords).remove() + + this.recompileData() + } + + ConditionMultiValue.prototype.recompileData = function(params) { + var $recordElements = $('[data-record-key]', this.$addedRecords), + hasData = !!$recordElements.length + + if (hasData) { + $('[data-no-record-data]', this.$addedRecords).remove() + } + else { + this.$addedRecords.append(this.renderEmptyTemplate()) + } + + if (this.options.dataLocker) { + var $locker = $(this.options.dataLocker), + selectedIds = [] + + $recordElements.each(function(key, record) { + selectedIds.push($(record).data('record-key')) + }) + + $locker.val(selectedIds.join(',')) + } + } + + ConditionMultiValue.prototype.renderTemplate = function(params) { + return Mustache.render(this.$template.html(), params) + } + + ConditionMultiValue.prototype.renderEmptyTemplate = function() { + return this.$emptyTemplate.html() + } + + ConditionMultiValue.DEFAULTS = { + dataLocker: null + } + + // PLUGIN DEFINITION + // ============================ + + var old = $.fn.conditionMultiValue + + $.fn.conditionMultiValue = function (option) { + var args = Array.prototype.slice.call(arguments, 1), items, result + + items = this.each(function () { + var $this = $(this) + var data = $this.data('oc.conditionMultiValue') + var options = $.extend({}, ConditionMultiValue.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('oc.conditionMultiValue', (data = new ConditionMultiValue(this, options))) + if (typeof option == 'string') result = data[option].apply(data, args) + if (typeof result != 'undefined') return false + }) + + return result ? result : items + } + + $.fn.conditionMultiValue.Constructor = ConditionMultiValue + + $.fn.conditionMultiValue.noConflict = function () { + $.fn.conditionMultiValue = old + return this + } + + // Add this only if required + $(document).render(function (){ + $('[data-control="condition-multivalue"]').conditionMultiValue() + }) + +}(window.jQuery); diff --git a/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/less/conditions.less b/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/less/conditions.less new file mode 100644 index 0000000..e406b20 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/conditionbuilder/assets/less/conditions.less @@ -0,0 +1,286 @@ +@import "../../../../../../../modules/backend/assets/less/core/boot.less"; + +// +// Conditions +// -------------------------------------------------- + +ul.condition-set { + padding: 5px 0 0; + margin: 0; + list-style: none; + + ul { + padding: 0; + margin: 0; + list-style: none; + } + + li { + margin: 0; + padding: 0; + } + + .condition-item { + border-radius: 4px; + + &.is-root { + border-radius: 0; + } + + &.is-inner {} + + &.collapsed { + .compound-content { + border-left-color: transparent !important; + } + + .condition-set { + display: none; + } + + &.is-inner .compound-add-item { + display: none; + } + } + + .condition-delete { + position: absolute; + display: block; + width: 10px; + height: 10px; + right: 7px; + top: 7px; + } + } + + // + // Collapse + // + + a.condition-collapse { + text-decoration: none; + display: block; + position: absolute; + right: 8px; + top: 2px; + + > i { + .transition(~'transform 0.3s'); + width: 15px; + height: 15px; + color: #bdc3c7; + font-size: 12px; + display: block; + } + + &:hover { + > i { + color: #999; + } + } + } + + li.collapsed a.condition-collapse { + > i { + .transform(scale(1,-1)); + } + } + + // + // Joins + // + + .compound-join { + text-align: center; + padding: 3px 0 2px 0; + a { + color: #333333; + text-decoration: none; + &:hover { + text-decoration: underline; + } + } + } + + // + // Single + // + + .condition-item.is-single { + padding: 8px 20px 9px 24px; + background: #fff; + border: 1px solid #eee; + position: relative; + + &:before { + .icon(@code-fork); + line-height: 100%; + font-size: 16px; + color: #bdc3c7; + + position: absolute; + width: 15px; + height: 15px; + left: 12px; + top: 11px; + } + + .condition-text { + padding-left: 10px; + + a { + color: #333333; + text-decoration: none; + &:hover { + text-decoration: underline; + } + + span.operator { + font-weight: 500; + } + } + } + + a.condition-delete { + right: 12px; + top: 9px; + } + } + + // + // Compound + // + + .condition-item.is-compound { + .compound-content { + position: relative; + border-left: 1px solid #dbdee0; + margin-left: 5px; + + &:before { + color: #bdc3c7; + .icon(@circle); + font-size: 8px; + position: absolute; + left: -4px; + top: -2px; + } + + h4 { + padding: 0 30px 5px 5px; + margin: 0; + position: relative; + top: -5px; + font-size: 13px; + line-height: 130%; + font-weight: 400; + color: #666; + a.condition-text { + color: #333333; + padding-left: 10px; + &:hover { + text-decoration: underline; + } + } + } + + .condition-set { + padding-left: 15px; + } + } + + .condition-item.is-compound { + + } + + .compound-add-item { + position: relative; + margin-top: 10px; + margin-left: 20px; + border: 2px dotted #e0e0e0; + border-radius: 5px; + + &:before { + color: #bdc3c7; + .icon(@plus); + font-size: 16px; + position: absolute; + left: -23px; + top: -11px; + } + + > a { + color: #bdc3c7; + text-align: center; + display: block; + text-decoration: none; + padding: 13px 15px; + text-transform: uppercase; + font-weight: 600; + font-size: @font-size-base - 2; + } + + &:hover, &:focus { + background-color: @highlight-hover-bg; + border-color: @highlight-hover-bg; + + &:before { + color: #999; + } + + > a { + color: @highlight-hover-text; + } + } + + &:active { + background: @highlight-active-bg; + border-color: @highlight-active-bg; + > a { + color: @highlight-active-text; + } + } + } + } + + // + // Compound (Inner) + // + + .condition-item.is-compound.is-inner { + padding-right: 20px; + + a.condition-delete-compound { + right: -7px; + top: 0; + } + } +} + +// +// Multi value +// + +.condition-multi-value { + .condition-filter-search { + background-position: right -81px !important; + border-top: none !important; + border-left: none !important; + border-right: none !important; + border-radius: 0; + padding-left: 20px; + } + + .filter-list { + margin: 0 -20px; + + .list-footer { + padding-top: 0; + padding-bottom: 0; + } + } + + .added-filter-list { + margin: 0 -20px; + } +} diff --git a/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_condition.htm b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_condition.htm new file mode 100644 index 0000000..95bb61d --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_condition.htm @@ -0,0 +1,99 @@ +isCompound(); + $isRoot = $treeLevel == 0; + $collapsed = $this->getCollapseStatus($condition->id, false); +?> +
  • + + + +
    +

    + + + + + + getCacheConditionText($condition)) ?> + + + + + + +

    +
      + children()->withDeferred($this->sessionKey.'_'.$condition->id)->get(); + $lastIndex = $children->count() - 1; + ?> + $childCondition): ?> + makePartial('condition', [ + 'condition' => $childCondition, + 'treeLevel' => $treeLevel + 1, + 'parentCondition' => $condition + ]) ?> + +
    • + + getCacheConditionJoinText($condition)) ?> + +
    • + + +
    +
    + +
    + + + +
    + + + + + + + + + + + + + + + + +
  • diff --git a/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_condition_settings_form.htm b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_condition_settings_form.htm new file mode 100644 index 0000000..77e0d84 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_condition_settings_form.htm @@ -0,0 +1,68 @@ + 'propertyForm']) ?> + + + + fatalError): ?> + + + + + + + + + + + + + + + + diff --git a/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_conditions.htm b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_conditions.htm new file mode 100644 index 0000000..8cc8c4b --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_conditions.htm @@ -0,0 +1,10 @@ + + + + + diff --git a/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_conditions_container.htm b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_conditions_container.htm new file mode 100644 index 0000000..737b072 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_conditions_container.htm @@ -0,0 +1,15 @@ +
    +
    + makePartial('conditions', ['condition' => $rootCondition]) ?> +
    + + +
    diff --git a/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_create_child_form.htm b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_create_child_form.htm new file mode 100644 index 0000000..3e9e863 --- /dev/null +++ b/plugins/rainlab/notify/formwidgets/conditionbuilder/partials/_create_child_form.htm @@ -0,0 +1,67 @@ + 'propertyForm']) ?> + + + + fatalError): ?> + + + + + + + + + + + + + + + diff --git a/plugins/rainlab/notify/interfaces/Action.php b/plugins/rainlab/notify/interfaces/Action.php new file mode 100644 index 0000000..011cc13 --- /dev/null +++ b/plugins/rainlab/notify/interfaces/Action.php @@ -0,0 +1,31 @@ + [], + ]; + + /** + * Mark the notification as read. + * + * @return void + */ + public function markAsRead() + { + if (is_null($this->read_at)) { + $this->forceFill(['read_at' => $this->freshTimestamp()])->save(); + } + } + + /** + * Determine if a notification has been read. + * + * @return bool + */ + public function read() + { + return $this->read_at !== null; + } + + /** + * Determine if a notification has not been read. + * + * @return bool + */ + public function unread() + { + return $this->read_at === null; + } + + /** + * Get the entity's unread notifications. + */ + public function scopeApplyUnread($query) + { + return $query->whereNull('read_at'); + } + + /** + * Get the entity's read notifications. + */ + public function scopeApplyRead($query) + { + return $query->whereNotNull('read_at'); + } + + /** + * Get the parsed body of the announcement. + * + * @return string + */ + public function getParsedBodyAttribute() + { + return Markdown::parse($this->body); + } +} diff --git a/plugins/rainlab/notify/models/NotificationRule.php b/plugins/rainlab/notify/models/NotificationRule.php new file mode 100644 index 0000000..8db57a4 --- /dev/null +++ b/plugins/rainlab/notify/models/NotificationRule.php @@ -0,0 +1,289 @@ + 'required' + ]; + + /** + * @var array Relations + */ + public $hasMany = [ + 'rule_conditions' => [ + RuleCondition::class, + 'key' => 'rule_host_id', + 'conditions' => 'rule_parent_id is null', + 'delete' => true + ], + 'rule_actions' => [ + RuleAction::class, + 'key' => 'rule_host_id', + 'delete' => true + ], + ]; + + /** + * Kicks off this notification rule, fires the event to obtain its parameters, + * checks the rule conditions evaluate as true, then spins over each action. + */ + public function triggerRule() + { + $params = $this->getEventObject()->getParams(); + $rootCondition = $this->rule_conditions->first(); + + if ($rootCondition && !$rootCondition->getConditionObject()->isTrue($params)) { + return false; + } + + foreach ($this->rule_actions as $action) { + $action->setRelation('notification_rule', $this); + $action->triggerAction($params); + } + } + + /** + * Returns extra conditions provided by the event. + * @return array + */ + public function getExtraConditionRules() + { + $rules = []; + + $classes = $this->getEventObject()->defineConditions(); + + foreach ($classes as $class) { + $rules[$class] = new $class; + } + + return $rules; + } + + /** + * Extends this class with the event class + * @param string $class Class name + * @return boolean + */ + public function applyEventClass($class = null) + { + if (!$class) { + $class = $this->class_name; + } + + if (!$class) { + return false; + } + + if (!$this->isClassExtendedWith($class)) { + $this->extendClassWith($class); + } + + $this->class_name = $class; + $this->event_name = Lang::get(array_get($this->eventDetails(), 'name', 'Unknown')); + return true; + } + + /** + * Returns the event class extension object. + * @return \RainLab\Notify\Classes\NotificationEvent + */ + public function getEventObject() + { + $this->applyEventClass(); + + return $this->asExtension($this->getEventClass()); + } + + public function getEventClass() + { + return $this->class_name; + } + + // + // Events + // + + public function afterFetch() + { + $this->applyEventClass(); + } + + public function beforeValidate() + { + if (!$this->applyEventClass()) { + return; + } + } + + // + // Scopes + // + + public function scopeApplyEnabled($query) + { + return $query->where('is_enabled', true); + } + + public function scopeApplyClass($query, $class) + { + if (!is_string($class)) { + $class = get_class($class); + } + + return $query->where('class_name', $class); + } + + // + // Presets + // + + /** + * Returns an array of rule codes and descriptions. + * @return array + */ + public static function listRulesForEvent($eventClass) + { + $results = []; + + $dbRules = self::applyClass($eventClass)->get(); + $presets = (array) EventBase::findEventPresetsByClass($eventClass); + + foreach ($dbRules as $dbRule) { + if ($dbRule->code) { + unset($presets[$dbRule->code]); + } + + if ($dbRule->is_enabled) { + $results[] = $dbRule; + } + } + + foreach ($presets as $code => $preset) { + if ($newPreset = self::createFromPreset($code, $preset)) { + $results[] = $newPreset; + } + } + + return $results; + } + + /** + * Syncronise all file-based presets to the database. + * @return void + */ + public static function syncAll() + { + $presets = (array) EventBase::findEventPresets(); + $dbRules = self::where('code', '!=', '')->whereNotNull('code')->lists('is_custom', 'code'); + $newRules = array_diff_key($presets, $dbRules); + + /* + * Clean up non-customized templates + */ + foreach ($dbRules as $code => $isCustom) { + if ($isCustom) { + continue; + } + + if (!array_key_exists($code, $presets) && ($record = self::whereCode($code)->first())) { + $record->delete(); + } + } + + /* + * Create new rules + */ + foreach ($newRules as $code => $preset) { + self::createFromPreset($code, $preset); + } + } + + public static function createFromPreset($code, $preset) + { + $actions = array_get($preset, 'items'); + if (!$actions || !is_array($actions)) { + return; + } + + $newRule = new self; + $newRule->code = $code; + $newRule->is_enabled = 1; + $newRule->is_custom = 0; + $newRule->name = array_get($preset, 'name'); + $newRule->class_name = array_get($preset, 'event'); + $newRule->forceSave(); + + // Add the actions + foreach ($actions as $action) { + $params = array_except($action, 'action'); + + $newAction = new RuleAction; + $newAction->class_name = array_get($action, 'action'); + $newAction->notification_rule = $newRule; + $newAction->fill($params); + $newAction->forceSave(); + } + + // Add the conditions + $conditions = array_get($preset, 'conditions'); + if (!$conditions || !is_array($conditions)) { + return $newRule; + } + + // Create the root condition + $rootCondition = new RuleCondition(); + $rootCondition->rule_host_type = ConditionBase::TYPE_ANY; + $rootCondition->class_name = $rootCondition->getRootConditionClass(); + $rootCondition->notification_rule = $newRule; + $rootCondition->save(); + + // Add the sub conditions + foreach ($conditions as $condition) { + $params = array_except($condition, 'condition'); + $newCondition = new RuleCondition(); + $newCondition->class_name = array_get($condition, 'condition'); + $newCondition->parent = $rootCondition; + $newCondition->fill($params); + $newCondition->forceSave(); + } + + return $newRule; + } +} diff --git a/plugins/rainlab/notify/models/RuleAction.php b/plugins/rainlab/notify/models/RuleAction.php new file mode 100644 index 0000000..7d4b42c --- /dev/null +++ b/plugins/rainlab/notify/models/RuleAction.php @@ -0,0 +1,201 @@ + [NotificationRule::class, 'key' => 'rule_host_id'], + ]; + + public function triggerAction($params, $scheduled = true) + { + try { + $actionObject = $this->getActionObject(); + + // Check if action is muted in which case we don't proceed sending a notification + if (method_exists($actionObject, 'isMuted') && $actionObject->isMuted()) { + return; + } + + // Apply action schedule + if ($scheduled && $schedule = $this->getSchedule()) { + // We delay the execution using Queues. When dequeued + // ScheduledAction will call this triggerAction + // function with $scheduled=false + Queue::later($schedule, new ScheduledAction($this, $params)); + } + else { + // We trigger the action + $actionObject->triggerAction($params); + } + } + catch (Exception $ex) { + // We could log the error here, for now we should suppress + // any exceptions to let other actions proceed as normal + traceLog('Error with ' . $this->getActionClass()); + traceLog($ex); + } + } + + /** + * Extends this model with the action class + * @param string $class Class name + * @return boolean + */ + public function applyActionClass($class = null) + { + if (!$class) { + $class = $this->class_name; + } + + if (!$class) { + return false; + } + + if (!$this->isClassExtendedWith($class)) { + $this->extendClassWith($class); + } + + $this->class_name = $class; + return true; + } + + public function beforeSave() + { + $this->setCustomData(); + } + + public function afterSave() + { + // Make sure that this record is removed from the DB after being removed from a rule + $removedFromRule = $this->rule_host_id === null && $this->getOriginal('rule_host_id'); + if ($removedFromRule && !$this->notification_rule()->withDeferred(post('_session_key'))->exists()) { + $this->delete(); + } + } + + public function applyCustomData() + { + $this->setCustomData(); + $this->loadCustomData(); + } + + protected function loadCustomData() + { + $this->setRawAttributes((array) $this->getAttributes() + (array) $this->config_data, true); + } + + protected function setCustomData() + { + if (!$actionObj = $this->getActionObject()) { + throw new SystemException(sprintf('Unable to find action object [%s]', $this->getActionClass())); + } + + /* + * Spin over each field and add it to config_data + */ + + $metaAttributes = [ + 'action_text', + 'schedule_type', + 'schedule_delay', + 'schedule_delay_factor', + ]; + + $formAttributes = []; + $config = $actionObj->getFieldConfig(); + if (isset($config->fields)) { + $formAttributes = array_keys($config->fields); + } + + $fieldAttributes = array_merge($formAttributes, $metaAttributes); + + $dynamicAttributes = array_only($this->getAttributes(), $fieldAttributes); + $this->config_data = $dynamicAttributes; + + $this->setRawAttributes(array_except($this->getAttributes(), $fieldAttributes)); + } + + public function afterFetch() + { + $this->applyActionClass(); + $this->loadCustomData(); + } + + public function getText() + { + if (strlen($this->action_text)) { + return $this->action_text; + } + + if ($actionObj = $this->getActionObject()) { + return $actionObj->getText(); + } + } + + public function getSchedule() + { + if ($this->schedule_type !== 'delayed') { + return false; + } + + if (!is_numeric($this->schedule_delay) || !is_numeric($this->schedule_delay_factor)) { + return false; + } + + $delay = (int) $this->schedule_delay; + $delay_factor = (int) $this->schedule_delay_factor; + + return abs($delay * $delay_factor); + } + + public function getActionObject() + { + $this->applyActionClass(); + + return $this->asExtension($this->getActionClass()); + } + + public function getActionClass() + { + return $this->class_name; + } +} diff --git a/plugins/rainlab/notify/models/RuleCondition.php b/plugins/rainlab/notify/models/RuleCondition.php new file mode 100644 index 0000000..0282748 --- /dev/null +++ b/plugins/rainlab/notify/models/RuleCondition.php @@ -0,0 +1,172 @@ + [self::class, 'key' => 'rule_parent_id', 'delete' => true], + ]; + + public $belongsTo = [ + 'parent' => [self::class, 'key' => 'rule_parent_id'], + 'notification_rule' => [NotificationRule::class, 'key'=>'rule_host_id'] + ]; + + public function filterFields($fields, $context) + { + /* + * Let the condition contribute + */ + $this->getConditionObject()->setFormFields($fields); + } + + /** + * Extends this model with the condition class + * @param string $class Class name + * @return boolean + */ + public function applyConditionClass($class = null) + { + if (!$class) { + $class = $this->class_name; + } + + if (!$class) { + return false; + } + + if (!$this->isClassExtendedWith($class)) { + $this->extendClassWith($class); + } + + $this->class_name = $class; + return true; + } + + public function beforeSave() + { + $this->setCustomData(); + } + + public function applyCustomData() + { + $this->setCustomData(); + $this->loadCustomData(); + } + + protected function loadCustomData() + { + $this->setRawAttributes((array) $this->getAttributes() + (array) $this->config_data, true); + } + + protected function setCustomData() + { + /* + * Let the condition contribute + */ + $this->getConditionObject()->setCustomData($this); + + /* + * Spin over each field and add it to config_data + */ + $config = $this->getFieldConfig(); + + if (!isset($config->fields)) { + throw new SystemException('Condition class has no fields.'); + } + + $staticAttributes = ['condition_text']; + + $fieldAttributes = array_merge($staticAttributes, array_keys($config->fields)); + + $dynamicAttributes = array_only($this->getAttributes(), $fieldAttributes); + + $this->config_data = $dynamicAttributes; + + $this->setRawAttributes(array_except($this->getAttributes(), $fieldAttributes)); + } + + public function afterFetch() + { + $this->applyConditionClass(); + $this->loadCustomData(); + } + + public function afterSave() + { + // Make sure that this record is removed from the DB after being removed from a rule + $removedFromRule = $this->rule_parent_id === null && $this->getOriginal('rule_parent_id'); + if ($removedFromRule && !$this->notification_rule()->withDeferred(post('_session_key'))->exists()) { + $this->delete(); + } + } + + public function getText() + { + if (strlen($this->condition_text)) { + return $this->condition_text; + } + + if ($conditionObj = $this->getConditionObject()) { + return $conditionObj->getText(); + } + } + + public function isCompound() + { + return $this->getConditionObject() instanceof CompoundConditionInterface; + } + + public function getConditionObject() + { + $this->applyConditionClass(); + + return $this->asExtension($this->getConditionClass()); + } + + public function getConditionClass() + { + return $this->class_name; + } + + public function getRootConditionClass() + { + return CompoundCondition::class; + } +} diff --git a/plugins/rainlab/notify/models/notificationrule/columns.yaml b/plugins/rainlab/notify/models/notificationrule/columns.yaml new file mode 100644 index 0000000..2e298a3 --- /dev/null +++ b/plugins/rainlab/notify/models/notificationrule/columns.yaml @@ -0,0 +1,13 @@ +# =================================== +# Column Definitions +# =================================== + +columns: + + name: + label: Name + searchable: true + + code: + label: Code + searchable: true diff --git a/plugins/rainlab/notify/models/notificationrule/fields.yaml b/plugins/rainlab/notify/models/notificationrule/fields.yaml new file mode 100644 index 0000000..b0eec2a --- /dev/null +++ b/plugins/rainlab/notify/models/notificationrule/fields.yaml @@ -0,0 +1,47 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + name: + label: Name + placeholder: New notification rule name + attributes: + autofocus: 1 + + toolbar: + type: partial + path: form_toolbar + cssClass: collapse-visible + +tabs: + stretch: true + cssClass: master-area + paneCssClass: + 'Actions': 'pane-compact' + + fields: + rule_actions: + type: RainLab\Notify\FormWidgets\ActionBuilder + tab: Actions + + rule_conditions: + type: RainLab\Notify\FormWidgets\ConditionBuilder + tab: Conditions + + is_enabled: + label: Active + type: checkbox + tab: Settings + default: true + + description: + label: Description + type: textarea + size: tiny + tab: Settings + + code: + label: API Code + span: auto + tab: Settings diff --git a/plugins/rainlab/notify/models/ruleaction/columns.yaml b/plugins/rainlab/notify/models/ruleaction/columns.yaml new file mode 100644 index 0000000..b11160b --- /dev/null +++ b/plugins/rainlab/notify/models/ruleaction/columns.yaml @@ -0,0 +1,8 @@ +# =================================== +# List Column Definitions +# =================================== + +columns: + id: + label: ID + searchable: true diff --git a/plugins/rainlab/notify/models/ruleaction/fields.yaml b/plugins/rainlab/notify/models/ruleaction/fields.yaml new file mode 100644 index 0000000..c611f31 --- /dev/null +++ b/plugins/rainlab/notify/models/ruleaction/fields.yaml @@ -0,0 +1,8 @@ +# =================================== +# Form Field Definitions +# =================================== + +fields: + id: + label: ID + disabled: true diff --git a/plugins/rainlab/notify/models/ruleaction/fields_schedule.yaml b/plugins/rainlab/notify/models/ruleaction/fields_schedule.yaml new file mode 100644 index 0000000..bd3d80c --- /dev/null +++ b/plugins/rainlab/notify/models/ruleaction/fields_schedule.yaml @@ -0,0 +1,30 @@ +# =================================== +# Form Field Definitions +# =================================== + +fields: + schedule_type: + type: dropdown + options: + disabled: None + delayed: Delay execution + schedule_delay: + type: number + span: left + trigger: + action: show + field: schedule_type + condition: value[delayed] + schedule_delay_factor: + type: dropdown + span: right + options: + 1: Seconds + 60: Minutes + 3600: Hours + 86400: Days + 2592000: Months + trigger: + action: show + field: schedule_type + condition: value[delayed] diff --git a/plugins/rainlab/notify/notifyrules/ExecutionContextCondition.php b/plugins/rainlab/notify/notifyrules/ExecutionContextCondition.php new file mode 100644 index 0000000..32369ca --- /dev/null +++ b/plugins/rainlab/notify/notifyrules/ExecutionContextCondition.php @@ -0,0 +1,136 @@ + 'is', + 'is_not' => 'is not', + ]; + + public function getName() + { + return 'Event is triggered from environment'; + } + + public function getTitle() + { + return 'Execution context'; + } + + public function getText() + { + $host = $this->host; + $value = $host->value; + $attribute = $host->subcondition; + $subconditions = $this->getSubconditionOptions(); + + $result = array_get($subconditions, $attribute, 'Execution context'); + $result .= ' '.array_get($this->operators, $host->operator, $host->operator).' '; + + if ($attribute == 'locale' || $attribute == 'environment') { + $result .= strtolower($value) ?: '?'; + } + elseif ($value) { + $options = $this->getValueOptions(); + $result .= strtolower(array_get($options, $value)); + } + else { + $result .= '?'; + } + + return $result; + } + + /** + * Returns a title to use for grouping subconditions + * in the Create Condition drop-down menu + */ + public function getGroupingTitle() + { + return 'Execution context'; + } + + public function listSubconditions() + { + return array_flip($this->getSubconditionOptions()); + } + + public function initConfigData($host) + { + $host->operator = 'is'; + } + + public function setFormFields($fields) + { + $attribute = $fields->subcondition->value; + + if ($attribute == 'locale' || $attribute == 'environment') { + $fields->value->type = 'text'; + } + else { + $fields->value->type = 'dropdown'; + } + } + + public function getValueOptions() + { + $attribute = $this->host->subcondition; + $result = []; + + if ($attribute == 'context') { + $result = [ + 'backend' => 'Back-end area', + 'front' => 'Front-end website', + 'console' => 'Command line interface', + ]; + } + + if ($attribute == 'theme') { + foreach (Theme::all() as $theme) { + $result[$theme->getDirName()] = $theme->getDirName(); + } + } + + return $result; + } + + public function getSubconditionOptions() + { + return [ + 'environment' => 'Application environment', + 'context' => 'Request context', + 'theme' => 'Active theme', + 'locale' => 'Visitor locale', + ]; + } + + public function getOperatorOptions() + { + return $this->operators; + } + + /** + * Checks whether the condition is TRUE for specified parameters + * @param array $params + * @return bool + */ + public function isTrue(&$params) + { + $hostObj = $this->host; + $attribute = $hostObj->subcondition; + + $conditionValue = $hostObj->value; + $conditionValue = trim(mb_strtolower($conditionValue)); + + if ($attribute == 'locale') { + return array_get($params, 'appLocale') == $conditionValue; + } else if ($attribute === 'environment') { + return $conditionValue === \App::environment(); + } + + return false; + } +} diff --git a/plugins/rainlab/notify/notifyrules/SaveDatabaseAction.php b/plugins/rainlab/notify/notifyrules/SaveDatabaseAction.php new file mode 100644 index 0000000..6192126 --- /dev/null +++ b/plugins/rainlab/notify/notifyrules/SaveDatabaseAction.php @@ -0,0 +1,119 @@ + 'Store in database', + 'description' => 'Log event data in the notifications activity log', + 'icon' => 'icon-database' + ]; + } + + public function defineFormFields() + { + return 'fields.yaml'; + } + + public function getText() + { + if ($this->host->related_object) { + $label = array_get($this->getRelatedObjectOptions(), $this->host->related_object); + + return 'Log event in the '.$label.' log'; + } + + return parent::getText(); + } + + /** + * Triggers this action. + * @param array $params + * @return void + */ + public function triggerAction($params) + { + if ( + (!$definition = array_get($this->tableDefinitions, $this->host->related_object)) || + (!$param = array_get($definition, 'param')) || + (!$value = array_get($params, $param)) + ) { + throw new ApplicationException('Error evaluating the save database action: the related object is not found in the action parameters.'); + } + + if (!$value instanceof EloquentModel) { + // @todo Perhaps value is an ID or a model array, + // look up model $definition[class] from ID ... + } + + $rule = $this->host->notification_rule; + $relation = array_get($definition, 'relation'); + + $value->$relation()->create([ + 'id' => Uuid::uuid4()->toString(), + 'event_type' => $rule->getEventClass(), + 'icon' => $this->host->icon, + 'type' => $this->host->type, + 'body' => $this->host->body, + 'data' => $this->getData($params), + 'read_at' => null, + ]); + } + + /** + * Get the data for the notification. + * + * @param array $notifiable + * @return array + */ + protected function getData($params) + { + // This should check for params that cannot be jsonable. + return $params; + } + + public function getRelatedObjectOptions() + { + $result = []; + + foreach ($this->tableDefinitions as $key => $definition) { + $result[$key] = array_get($definition, 'label'); + } + + return $result; + } + + public function getTableDefinitions() + { + return $this->tableDefinitions; + } + + public function addTableDefinition($options) + { + if (!$className = array_get($options, 'class')) { + throw new ApplicationException('Missing class name from table definition.'); + } + + $options = array_merge([ + 'label' => 'Undefined table', + 'class' => null, + 'param' => null, + 'relation' => 'notifications', + ], $options); + + $keyName = $className . '@' . array_get($options, 'relation'); + + $this->tableDefinitions[$keyName] = $options; + } +} diff --git a/plugins/rainlab/notify/notifyrules/SendMailTemplateAction.php b/plugins/rainlab/notify/notifyrules/SendMailTemplateAction.php new file mode 100644 index 0000000..e7abf4b --- /dev/null +++ b/plugins/rainlab/notify/notifyrules/SendMailTemplateAction.php @@ -0,0 +1,225 @@ + 'System default', + 'user' => 'User email address (if applicable)', + 'sender' => 'Sender user email address (if applicable)', + 'admin' => 'Back-end administrators', + 'custom' => 'Specific email address', + ]; + + /** + * Returns information about this event, including name and description. + */ + public function actionDetails() + { + return [ + 'name' => 'Compose a mail message', + 'description' => 'Send a message to a recipient', + 'icon' => 'icon-envelope' + ]; + } + + /** + * Triggers this action. + * @param array $params + * @return void + */ + public function triggerAction($params) + { + $template = $this->host->mail_template; + + $recipient = $this->getRecipientAddress($params); + + $replyTo = $this->getReplyToAddress($params); + + if (!$recipient || !$template) { + throw new ApplicationException('Missing valid recipient or mail template'); + } + + Mail::sendTo($recipient, $template, $params, function($message) use ($replyTo) { + if ($replyTo) { + $message->replyTo($replyTo); + } + }); + } + + /** + * Field configuration for the action. + */ + public function defineFormFields() + { + return 'fields.yaml'; + } + + /** + * Defines validation rules for the custom fields. + * @return array + */ + public function defineValidationRules() + { + return [ + 'mail_template' => 'required', + 'send_to_mode' => 'required', + ]; + } + + public function getTitle() + { + if ($this->isAdminMode()) { + return 'Compose mail to administrators'; + } + + return parent::getTitle(); + } + + public function getActionIcon() + { + if ($this->isAdminMode()) { + return 'icon-envelope-square'; + } + + return parent::getActionIcon(); + } + + public function getText() + { + $hostObj = $this->host; + + $recipient = array_get($this->recipientModes, $hostObj->send_to_mode); + + if ($this->isAdminMode()) { + if ($groupId = $this->host->send_to_admin) { + if ($group = AdminGroupModel::find($groupId)) { + $adminText = $group->name; + } + else { + $adminText = '?'; + } + + $adminText .= ' admin group'; + } + else { + $adminText = 'all admins'; + } + return sprintf( + 'Send a message to %s using template %s', + $adminText, + $hostObj->mail_template + ); + } + + if ($hostObj->mail_template) { + return sprintf( + 'Send a message to %s using template %s', + mb_strtolower($recipient), + $hostObj->mail_template + ); + } + + return parent::getText(); + } + + public function getSendToAdminOptions() + { + $options = ['' => '- All administrators -']; + + $groups = AdminGroupModel::lists('name', 'id'); + + return $options + $groups; + } + + public function getSendToModeOptions() + { + $modes = $this->recipientModes; + + unset($modes['system']); + + return $modes; + } + + public function getReplyToModeOptions() + { + $modes = $this->recipientModes; + + unset($modes['admin']); + + return $modes; + } + + public function getMailTemplateOptions() + { + $codes = array_keys(MailTemplate::listAllTemplates()); + + $result = array_combine($codes, $codes); + + // Wrap to prevent collisions with language keys + array_walk($result, function(&$value, $key) { + $value = "[$value]"; + }); + + return $result; + } + + protected function getReplyToAddress($params) + { + $mode = $this->host->reply_to_mode; + + if ($mode == 'custom') { + return $this->host->reply_to_custom; + } + + if ($mode == 'user' || $mode == 'sender') { + $obj = array_get($params, $mode); + return $obj->email; + } + } + + protected function getRecipientAddress($params) + { + $mode = $this->host->send_to_mode; + + if ($mode == 'custom') { + return $this->host->send_to_custom; + } + + if ($mode == 'system') { + $name = Config::get('mail.from.name', 'Your Site'); + $address = Config::get('mail.from.address', 'admin@domain.tld'); + return [$address => $name]; + } + + if ($mode == 'admin') { + if ($groupId = $this->host->send_to_admin) { + if (!$group = AdminGroupModel::find($groupId)) { + throw new ApplicationException('Unable to find admin group with ID: '.$groupId); + } + + return $group->users->lists('full_name', 'email'); + } + else { + return AdminUserModel::all()->lists('full_name', 'email'); + } + } + + if ($mode == 'user' || $mode == 'sender') { + return array_get($params, $mode); + } + } + + protected function isAdminMode() + { + return $this->host->send_to_mode == 'admin'; + } +} diff --git a/plugins/rainlab/notify/notifyrules/executioncontextcondition/fields.yaml b/plugins/rainlab/notify/notifyrules/executioncontextcondition/fields.yaml new file mode 100644 index 0000000..9981f87 --- /dev/null +++ b/plugins/rainlab/notify/notifyrules/executioncontextcondition/fields.yaml @@ -0,0 +1,21 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + + subcondition: + label: Attribute + span: auto + type: dropdown + + operator: + label: Operator + span: auto + type: dropdown + dependsOn: subcondition + + value: + label: Value + dependsOn: [subcondition, operator] + type: dropdown diff --git a/plugins/rainlab/notify/notifyrules/savedatabaseaction/fields.yaml b/plugins/rainlab/notify/notifyrules/savedatabaseaction/fields.yaml new file mode 100644 index 0000000..77c144f --- /dev/null +++ b/plugins/rainlab/notify/notifyrules/savedatabaseaction/fields.yaml @@ -0,0 +1,8 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + related_object: + label: Related object + type: dropdown diff --git a/plugins/rainlab/notify/notifyrules/sendmailtemplateaction/fields.yaml b/plugins/rainlab/notify/notifyrules/sendmailtemplateaction/fields.yaml new file mode 100644 index 0000000..13aa548 --- /dev/null +++ b/plugins/rainlab/notify/notifyrules/sendmailtemplateaction/fields.yaml @@ -0,0 +1,42 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + mail_template: + label: Mail template + type: dropdown + placeholder: Select template + + send_to_mode: + label: Send to + type: radio + span: left + + send_to_custom: + cssClass: radio-align + trigger: + action: show + field: send_to_mode + condition: value[custom] + + send_to_admin: + label: Send to admin group + span: right + type: dropdown + trigger: + action: show + field: send_to_mode + condition: value[admin] + + reply_to_mode: + label: Reply-to address + type: radio + span: left + + reply_to_custom: + cssClass: radio-align + trigger: + action: show + field: reply_to_mode + condition: value[custom] diff --git a/plugins/rainlab/notify/updates/create_notification_rules_table.php b/plugins/rainlab/notify/updates/create_notification_rules_table.php new file mode 100644 index 0000000..2bcc6b0 --- /dev/null +++ b/plugins/rainlab/notify/updates/create_notification_rules_table.php @@ -0,0 +1,29 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->string('name')->nullable(); + $table->string('code')->index()->nullable(); + $table->string('class_name')->nullable(); + $table->text('description')->nullable(); + $table->mediumText('config_data')->nullable(); + $table->mediumText('condition_data')->nullable(); + $table->boolean('is_enabled')->default(0); + $table->boolean('is_custom')->default(1); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('rainlab_notify_notification_rules'); + } +} diff --git a/plugins/rainlab/notify/updates/create_notifications_table.php b/plugins/rainlab/notify/updates/create_notifications_table.php new file mode 100644 index 0000000..4c73bb4 --- /dev/null +++ b/plugins/rainlab/notify/updates/create_notifications_table.php @@ -0,0 +1,28 @@ +uuid('id')->primary(); + $table->string('event_type'); + $table->morphs('notifiable'); + $table->string('icon')->nullable(); + $table->string('type')->nullable(); + $table->text('body')->nullable(); + $table->mediumText('data'); + $table->timestamp('read_at')->nullable(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('rainlab_notify_notifications'); + } +} diff --git a/plugins/rainlab/notify/updates/create_rule_actions_table.php b/plugins/rainlab/notify/updates/create_rule_actions_table.php new file mode 100644 index 0000000..af89e41 --- /dev/null +++ b/plugins/rainlab/notify/updates/create_rule_actions_table.php @@ -0,0 +1,25 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->string('class_name')->nullable(); + $table->mediumText('config_data')->nullable(); + $table->integer('rule_host_id')->unsigned()->nullable()->index(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('rainlab_notify_rule_actions'); + } +} diff --git a/plugins/rainlab/notify/updates/create_rule_conditions_table.php b/plugins/rainlab/notify/updates/create_rule_conditions_table.php new file mode 100644 index 0000000..4a0211e --- /dev/null +++ b/plugins/rainlab/notify/updates/create_rule_conditions_table.php @@ -0,0 +1,29 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->string('class_name')->nullable(); + $table->mediumText('config_data')->nullable(); + $table->string('condition_control_type', 100)->nullable(); + $table->string('rule_host_type', 100)->nullable(); + $table->integer('rule_host_id')->unsigned()->nullable()->index(); + $table->integer('rule_parent_id')->unsigned()->nullable()->index(); + $table->index(['rule_host_id', 'rule_host_type'], 'host_rule_id_type'); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('rainlab_notify_rule_conditions'); + } +} diff --git a/plugins/rainlab/notify/updates/version.yaml b/plugins/rainlab/notify/updates/version.yaml new file mode 100644 index 0000000..af1dae0 --- /dev/null +++ b/plugins/rainlab/notify/updates/version.yaml @@ -0,0 +1,13 @@ +v1.0.1: + - First version of Notify + - create_notifications_table.php + - create_notification_rules_table.php + - create_rule_conditions_table.php + - create_rule_actions_table.php +v1.0.2: Fixes crashing bug. +v1.0.3: Added Turkish & Russian translations, various bug fixes. +v1.1.0: Fixes support for October CMS 2.0 +v1.1.1: Fixes missing template bug when saving notification rule +v1.1.2: Fixes collisions with language keys in compose mail action +v1.2.0: Adds delayed execution to actions +v1.2.1: Improve support with October v3 diff --git a/plugins/rainlab/user/models/User.php b/plugins/rainlab/user/models/User.php index 102fded..338cfbe 100644 --- a/plugins/rainlab/user/models/User.php +++ b/plugins/rainlab/user/models/User.php @@ -61,6 +61,8 @@ class User extends UserBase 'transactions' => ['TPS\Birzha\Models\Transaction', 'softDelete' => true], 'exchangerequests' => ['TPS\Birzha\Models\Exchangerequest', 'softDelete' => true], 'sliders' => ['TPS\Birzha\Models\UserSliders', 'softDelete' => true], + 'favourites' => ['TPS\Birzha\Models\Favourites', 'softDelete' => true, 'table' => 'tps_birzha_favourites'], + 'comments' => ['TPS\Birzha\Models\Comment','table' => 'tps_birzha_comments'], ]; diff --git a/plugins/rainlab/userplus/LICENCE.md b/plugins/rainlab/userplus/LICENCE.md new file mode 100644 index 0000000..d68943e --- /dev/null +++ b/plugins/rainlab/userplus/LICENCE.md @@ -0,0 +1,19 @@ +# MIT license + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/plugins/rainlab/userplus/Plugin.php b/plugins/rainlab/userplus/Plugin.php new file mode 100644 index 0000000..0c80059 --- /dev/null +++ b/plugins/rainlab/userplus/Plugin.php @@ -0,0 +1,124 @@ + 'rainlab.userplus::lang.plugin.name', + 'description' => 'rainlab.userplus::lang.plugin.description', + 'author' => 'Alexey Bobkov, Samuel Georges', + 'icon' => 'icon-user-plus', + 'homepage' => 'https://github.com/rainlab/userplus-plugin' + ]; + } + + public function boot() + { + $this->extendUserModel(); + $this->extendUsersController(); + $this->extendSaveDatabaseAction(); + $this->extendUserEventBase(); + } + + public function registerComponents() + { + return [ + \RainLab\UserPlus\Components\Notifications::class => 'notifications', + ]; + } + + protected function extendUserModel() + { + UserModel::extend(function($model) { + $model->addFillable([ + 'phone', + 'mobile', + 'company', + 'street_addr', + 'city', + 'zip' + ]); + + $model->implement[] = 'RainLab.Location.Behaviors.LocationModel'; + + $model->morphMany['notifications'] = [ + NotificationModel::class, + 'name' => 'notifiable', + 'order' => 'created_at desc' + ]; + }); + } + + protected function extendUsersController() + { + UsersController::extendFormFields(function($widget) { + // Prevent extending of related form instead of the intended User form + if (!$widget->model instanceof UserModel) { + return; + } + + $configFile = plugins_path('rainlab/userplus/config/profile_fields.yaml'); + $config = Yaml::parse(File::get($configFile)); + $widget->addTabFields($config); + }); + } + + public function registerNotificationRules() + { + return [ + 'events' => [], + 'actions' => [], + 'conditions' => [ + \RainLab\UserPlus\NotifyRules\UserLocationAttributeCondition::class + ], + 'presets' => '$/rainlab/userplus/config/notify_presets.yaml', + ]; + } + + protected function extendUserEventBase() + { + if (!class_exists(UserEventBase::class)) { + return; + } + + UserEventBase::extend(function($event) { + $event->conditions[] = \RainLab\UserPlus\NotifyRules\UserLocationAttributeCondition::class; + }); + } + + protected function extendSaveDatabaseAction() + { + if (!class_exists(SaveDatabaseAction::class)) { + return; + } + + SaveDatabaseAction::extend(function ($action) { + $action->addTableDefinition([ + 'label' => 'User activity', + 'class' => UserModel::class, + 'param' => 'user' + ]); + }); + } +} diff --git a/plugins/rainlab/userplus/README.md b/plugins/rainlab/userplus/README.md new file mode 100644 index 0000000..8a98daf --- /dev/null +++ b/plugins/rainlab/userplus/README.md @@ -0,0 +1,13 @@ +# User Plus+ plugin + +This plugin extends the [User plugin](http://octobercms.com/plugin/rainlab-user) with extra profile fields and features. + +* Adds the following extra fields to a user: `phone`, `mobile`, `company`, `street_addr`, `city`, `zip`. +* A user can belong to a Country and/or State, sourced from the [Location plugin](http://octobercms.com/plugin/rainlab-location). + +### Potential features + +* A user can befriend other users via a friendship system. +* A user can earn "Experience Points" by performing predefined activities. + +> Note these features may or may not be implemented in the future, but act only as an indicator of the plugin's potential. diff --git a/plugins/rainlab/userplus/assets/css/notifications.css b/plugins/rainlab/userplus/assets/css/notifications.css new file mode 100644 index 0000000..234271f --- /dev/null +++ b/plugins/rainlab/userplus/assets/css/notifications.css @@ -0,0 +1,74 @@ +.rainlab-userplus { + position: relative; +} +.rainlab-userplus .notifications-popover { + background: #fff; + border: 1px solid #f0f0f0; + position: absolute; + width: 480px; + z-index: 2; + right: 0; + display: none; +} +.rainlab-userplus.active .notifications-popover { + display: block; +} +.rainlab-userplus .notifications-header { + border-bottom: 1px solid #f0f0f0; + padding: 15px; +} +.rainlab-userplus .notifications-header h4 { + padding: 0; + margin: 0; + display: inline-block; +} +.rainlab-userplus .notifications-header .close, +.rainlab-userplus .notifications-header .mark-all-read { + float: right; + margin: 0 5px; +} +.rainlab-userplus .notifications-content .notifications-loading, +.notification_area .notifications-loading, +.accord_notification .notifications-loading { + padding: 20px; + font-size: 24px; + text-align: center; +} +.rainlab-userplus .notifications-content .no-notifications, +.notification_area .no-notifications, +.accord_notification .no-notifications { + text-align: center; + padding: 25px; + margin: 0; +} +.rainlab-userplus .notifications-content > ul { + padding: 0; + margin: 0; + list-style: none; + overflow: auto; + max-height: 400px; +} +.rainlab-userplus .notifications-content > ul > li { + position: relative; + padding: 10px 25px 10px 60px; + border-bottom: 1px solid #f9f9f9; +} +.rainlab-userplus .notifications-content > ul > li > i { + position: absolute; + left: 25px; + top: 12px; + font-size: 18px; + opacity: .5; +} +.rainlab-userplus .notifications-content > ul > li .parsed-body > *:last-child { + margin-bottom: 0; +} +.rainlab-userplus .notifications-content > ul > li .date { + white-space: nowrap; + opacity: .75; +} +.rainlab-userplus .notifications-footer { + border-top: 1px solid #f0f0f0; + padding: 15px; + text-align: center; +} diff --git a/plugins/rainlab/userplus/assets/js/notifications.js b/plugins/rainlab/userplus/assets/js/notifications.js new file mode 100644 index 0000000..1faba42 --- /dev/null +++ b/plugins/rainlab/userplus/assets/js/notifications.js @@ -0,0 +1,13 @@ +function toggleNotificationsPopover(el) { + + if($(el).next().hasClass('notification_area')) { + $(el).request('onLoadNotifications', { + update: { '@notifications-list': '#notification_area' } + }) + } else if($(el).next().hasClass('accord_notification')) { + $(el).request('onLoadNotifications', { + update: { '@notifications-list': '#accord_notification' } + }) + } + +} diff --git a/plugins/rainlab/userplus/assets/less/notifications.less b/plugins/rainlab/userplus/assets/less/notifications.less new file mode 100644 index 0000000..92fad58 --- /dev/null +++ b/plugins/rainlab/userplus/assets/less/notifications.less @@ -0,0 +1,84 @@ +.rainlab-userplus { + position: relative; + + .notifications-popover { + background: #fff; + border: 1px solid #f0f0f0; + position: absolute; + width: 480px; + z-index: 2; + right: 0; + display: none; + } + + &.active .notifications-popover { + display: block; + } + + .notifications-header { + border-bottom: 1px solid #f0f0f0; + padding: 15px; + + h4 { + padding: 0; + margin: 0; + display: inline-block; + } + + .close, .mark-all-read { + float: right; + margin: 0 5px; + } + } + + .notifications-content { + .notifications-loading { + padding: 20px; + font-size: 24px; + text-align: center; + } + + .no-notifications { + text-align: center; + padding: 25px; + margin: 0; + } + + > ul { + padding: 0; + margin: 0; + list-style: none; + overflow: auto; + max-height: 400px; + } + + > ul > li { + position: relative; + padding: 10px 25px 10px 60px; + border-bottom: 1px solid #f9f9f9; + + > i { + position: absolute; + left: 25px; + top: 12px; + font-size: 18px; + opacity: .5; + } + + .parsed-body > *:last-child { + margin-bottom: 0; + } + + .date { + white-space: nowrap; + opacity: .75; + } + } + } + + .notifications-footer { + border-top: 1px solid #f0f0f0; + padding: 15px; + text-align: center; + } +} diff --git a/plugins/rainlab/userplus/components/Notifications.php b/plugins/rainlab/userplus/components/Notifications.php new file mode 100644 index 0000000..f8decf0 --- /dev/null +++ b/plugins/rainlab/userplus/components/Notifications.php @@ -0,0 +1,129 @@ + 'Notifications Component', + 'description' => 'Display user and site-wide notifications' + ]; + } + + public function defineProperties() + { + return [ + 'recordsPerPage' => [ + 'title' => 'Records per page', + 'comment' => 'Number of notifications to display per page', + 'default' => 7 + ], + 'includeAssets' => [ + 'title' => 'Include assets', + 'comment' => 'Inject the JavaScript and Stylesheet used by the default component markup', + 'type' => 'checkbox', + 'default' => true + ], + 'frontend' => [ + 'title' => 'Frontend block', + 'description' => 'Choose where in the page to display', + 'type' => 'dropdown', + 'options' => ['desktop','mobile'], + 'default' => 'desktop' + ] + ]; + } + + public function onRun() + { + if (!Auth::getUser()) { + return; + } + + if ($this->property('includeAssets')) { + $this->addCss('assets/css/notifications.css'); + $this->addJs('assets/js/notifications.js'); + } + + $this->prepareVars(); + } + + protected function prepareVars() + { + $this->page['recordsToDisplay'] = $this->getRecordCountToDisplay(); + $this->page['hasNotifications'] = $this->hasNotifications(); + } + + public function hasNotifications() + { + return $this->getUnreadQuery()->count() > 0; + } + + public function unreadNotifications($recordsToDisplay = null) + { + if (!$recordsToDisplay) { + $recordsToDisplay = $this->getRecordCountToDisplay(); + } + + return $this->getUnreadQuery()->paginate($recordsToDisplay); + } + + // + // AJAX + // + + public function onLoadNotifications() + { + $this->prepareVars(); + $this->page['notifications'] = $this->unreadNotifications(); + } + + public function onLoadOlderNotifications() + { + $recordsToDisplay = $this->getRecordCountToDisplay() + $this->property('recordsPerPage'); + + $this->page['recordsToDisplay'] = $recordsToDisplay; + $this->page['notifications'] = $this->unreadNotifications($recordsToDisplay); + } + + public function onMarkAllNotificationsAsRead() + { + $this->getUnreadQuery()->update(['read_at' => Carbon::now()]); + + $this->prepareVars(); + $this->page['notifications'] = $this->unreadNotifications(); + } + + public function onMarkNotificationAsRead() + { + $this->getUnreadQuery() + ->where('id', \Input::get('notification_id')) + ->update(['read_at' => Carbon::now()]); + + return Redirect::to(\Input::get('redirect_link')); + } + + // + // Helpers + // + + protected function getRecordCountToDisplay() + { + return ((int) post('records_per_page')) ?: $this->property('recordsPerPage'); + } + + protected function getUnreadQuery() + { + if (!$user = Auth::getUser()) { + throw new ApplicationException('You must be logged in'); + } + + return $user->notifications()->applyUnread(); + } +} diff --git a/plugins/rainlab/userplus/components/notifications/default.htm b/plugins/rainlab/userplus/components/notifications/default.htm new file mode 100644 index 0000000..e4a2115 --- /dev/null +++ b/plugins/rainlab/userplus/components/notifications/default.htm @@ -0,0 +1 @@ +{% partial __SELF__~"::"~__SELF__.property('frontend') %} diff --git a/plugins/rainlab/userplus/components/notifications/desktop.htm b/plugins/rainlab/userplus/components/notifications/desktop.htm new file mode 100644 index 0000000..504793d --- /dev/null +++ b/plugins/rainlab/userplus/components/notifications/desktop.htm @@ -0,0 +1,14 @@ +
    +
    +
    + bell +
    +

    {{ 'auth.notifications'|_ }}

    +
    + +
    +
    + +
    +
    +
    \ No newline at end of file diff --git a/plugins/rainlab/userplus/components/notifications/mobile.htm b/plugins/rainlab/userplus/components/notifications/mobile.htm new file mode 100644 index 0000000..b019790 --- /dev/null +++ b/plugins/rainlab/userplus/components/notifications/mobile.htm @@ -0,0 +1,14 @@ +
    +
    + bell +
    +

    + {{ 'auth.notifications'|_ }} +

    +
    + +
    +
    + +
    +
    \ No newline at end of file diff --git a/plugins/rainlab/userplus/components/notifications/notifications-list.htm b/plugins/rainlab/userplus/components/notifications/notifications-list.htm new file mode 100644 index 0000000..69f69dc --- /dev/null +++ b/plugins/rainlab/userplus/components/notifications/notifications-list.htm @@ -0,0 +1,20 @@ +{% if notifications.total %} + {% for notification in notifications %} + +

    + {{ notification.description }} +

    +

    + {{ notification.created_at|date('H:i - d.m.Y') }} +

    +
    + {% endfor %} + +{% else %} +

    {{ 'auth.no_notifications'|_ }}

    +{% endif %} diff --git a/plugins/rainlab/userplus/composer.json b/plugins/rainlab/userplus/composer.json new file mode 100644 index 0000000..3cba8bc --- /dev/null +++ b/plugins/rainlab/userplus/composer.json @@ -0,0 +1,8 @@ +{ + "name": "rainlab/userplus-plugin", + "type": "october-plugin", + "description": "None", + "require": { + "composer/installers": "~1.0" + } +} \ No newline at end of file diff --git a/plugins/rainlab/userplus/config/notify_presets.yaml b/plugins/rainlab/userplus/config/notify_presets.yaml new file mode 100644 index 0000000..e05e4d8 --- /dev/null +++ b/plugins/rainlab/userplus/config/notify_presets.yaml @@ -0,0 +1,11 @@ +# =================================== +# Event Presets +# =================================== + +welcome_email: + name: Send welcome email to user + event: RainLab\User\NotifyRules\UserRegisteredEvent + items: + - action: RainLab\Notify\NotifyRules\SendMailTemplateAction + mail_template: rainlab.user::welcome + send_to_mode: user diff --git a/plugins/rainlab/userplus/config/profile_fields.yaml b/plugins/rainlab/userplus/config/profile_fields.yaml new file mode 100644 index 0000000..eabbe9c --- /dev/null +++ b/plugins/rainlab/userplus/config/profile_fields.yaml @@ -0,0 +1,47 @@ +# =================================== +# Extended Profile Field Definitions +# =================================== + +phone: + label: rainlab.userplus::lang.user.phone + tab: rainlab.userplus::lang.tab.profile + span: left + +mobile: + label: rainlab.userplus::lang.user.mobile + tab: rainlab.userplus::lang.tab.profile + span: right + +company: + label: rainlab.userplus::lang.user.company + tab: rainlab.userplus::lang.tab.profile + span: left + +street_addr: + label: rainlab.userplus::lang.user.street_addr + tab: rainlab.userplus::lang.tab.profile + +city: + label: rainlab.userplus::lang.user.city + tab: rainlab.userplus::lang.tab.profile + span: left + +zip: + label: rainlab.userplus::lang.user.zip + tab: rainlab.userplus::lang.tab.profile + span: right + +country: + label: rainlab.location::lang.country.label + placeholder: rainlab.location::lang.country.select + type: dropdown + tab: rainlab.userplus::lang.tab.profile + span: left + +state: + label: rainlab.location::lang.state.label + placeholder: rainlab.location::lang.state.select + type: dropdown + tab: rainlab.userplus::lang.tab.profile + span: right + dependsOn: country \ No newline at end of file diff --git a/plugins/rainlab/userplus/lang/cs/lang.php b/plugins/rainlab/userplus/lang/cs/lang.php new file mode 100644 index 0000000..ec7a1f9 --- /dev/null +++ b/plugins/rainlab/userplus/lang/cs/lang.php @@ -0,0 +1,19 @@ + [ + 'name' => 'User Plus+', + 'description' => 'Přidává uživatelům profilová políčka.', + ], + 'tab' => [ + 'profile' => 'Profil', + ], + 'user' => [ + 'phone' => 'Telefon', + 'mobile' => 'Mobil', + 'company' => 'Firma', + 'city' => 'Město', + 'zip' => 'PSČ', + 'street_addr' => 'Ulice', + ], +]; diff --git a/plugins/rainlab/userplus/lang/en/lang.php b/plugins/rainlab/userplus/lang/en/lang.php new file mode 100644 index 0000000..cd0dae2 --- /dev/null +++ b/plugins/rainlab/userplus/lang/en/lang.php @@ -0,0 +1,19 @@ + [ + 'name' => 'User Plus+', + 'description' => 'Adds profile fields to users.', + ], + 'tab' => [ + 'profile' => 'Profile', + ], + 'user' => [ + 'phone' => 'Phone', + 'mobile' => 'Mobile', + 'company' => 'Company', + 'city' => 'City', + 'zip' => 'Legalization number', + 'street_addr' => 'Street Address', + ], +]; diff --git a/plugins/rainlab/userplus/lang/fa/lang.php b/plugins/rainlab/userplus/lang/fa/lang.php new file mode 100644 index 0000000..c78c2f1 --- /dev/null +++ b/plugins/rainlab/userplus/lang/fa/lang.php @@ -0,0 +1,16 @@ + [ + 'name' => 'گسترش کاربر', + 'description' => 'افزودن فیلد به پروفایل کاربران', + ], + 'user' => [ + 'phone' => 'تلفن', + 'mobile' => 'تلفن همراه', + 'company' => 'شرکت', + 'city' => 'شهر', + 'zip' => 'کد پستی', + 'street_addr' => 'آدرس', + ], +]; diff --git a/plugins/rainlab/userplus/lang/fr/lang.php b/plugins/rainlab/userplus/lang/fr/lang.php new file mode 100644 index 0000000..4d21d24 --- /dev/null +++ b/plugins/rainlab/userplus/lang/fr/lang.php @@ -0,0 +1,15 @@ + [ + 'name' => 'User Plus+', + 'description' => 'Ajoute des champs de profil aux utilisateurs.', + ], + 'user' => [ + 'phone' => 'Téléhone', + 'mobile' => 'Mobile', + 'company' => 'Société', + 'city' => 'Ville', + 'zip' => 'Code postal', + 'street_addr' => 'Addresse', + ], +]; diff --git a/plugins/rainlab/userplus/lang/hu/lang.php b/plugins/rainlab/userplus/lang/hu/lang.php new file mode 100644 index 0000000..1f86db8 --- /dev/null +++ b/plugins/rainlab/userplus/lang/hu/lang.php @@ -0,0 +1,19 @@ + [ + 'name' => 'Felhasználók Plusz+', + 'description' => 'Új személyes mezők a felhasználók adatlapjához.', + ], + 'tab' => [ + 'profile' => 'Személyes', + ], + 'user' => [ + 'phone' => 'Telefon', + 'mobile' => 'Mobil', + 'company' => 'Cég', + 'city' => 'Város', + 'zip' => 'Irszám.', + 'street_addr' => 'Postacím', + ], +]; diff --git a/plugins/rainlab/userplus/lang/pt-br/lang.php b/plugins/rainlab/userplus/lang/pt-br/lang.php new file mode 100644 index 0000000..524afda --- /dev/null +++ b/plugins/rainlab/userplus/lang/pt-br/lang.php @@ -0,0 +1,19 @@ + [ + 'name' => 'Usuário Plus+', + 'description' => 'Adiciona campos de perfil aos usuários.', + ], + 'tab' => [ + 'profile' => 'Perfil', + ], + 'user' => [ + 'phone' => 'Telefone', + 'mobile' => 'Celular', + 'company' => 'Empresa', + 'city' => 'Cidade', + 'zip' => 'Cep', + 'street_addr' => 'Endereço', + ], +]; diff --git a/plugins/rainlab/userplus/lang/tr/lang.php b/plugins/rainlab/userplus/lang/tr/lang.php new file mode 100644 index 0000000..6a80d3d --- /dev/null +++ b/plugins/rainlab/userplus/lang/tr/lang.php @@ -0,0 +1,19 @@ + [ + 'name' => 'Üye Plus+', + 'description' => 'Üyeler için ek profil bilgileri sağlar.', + ], + 'tab' => [ + 'profile' => 'Profil', + ], + 'user' => [ + 'phone' => 'Telefon', + 'mobile' => 'Cep telefon', + 'company' => 'Firma', + 'city' => 'Şehir', + 'zip' => 'Legalizasyon kodu', + 'street_addr' => 'Adresi', + ], +]; diff --git a/plugins/rainlab/userplus/notifyrules/UserLocationAttributeCondition.php b/plugins/rainlab/userplus/notifyrules/UserLocationAttributeCondition.php new file mode 100644 index 0000000..db6701b --- /dev/null +++ b/plugins/rainlab/userplus/notifyrules/UserLocationAttributeCondition.php @@ -0,0 +1,37 @@ +host; + + $attribute = $hostObj->subcondition; + + if (!$user = array_get($params, 'user')) { + throw new ApplicationException('Error evaluating the user attribute condition: the user object is not found in the condition parameters.'); + } + + return parent::evalIsTrue($user); + } +} diff --git a/plugins/rainlab/userplus/notifyrules/userlocationattributecondition/attributes.yaml b/plugins/rainlab/userplus/notifyrules/userlocationattributecondition/attributes.yaml new file mode 100644 index 0000000..56c0f98 --- /dev/null +++ b/plugins/rainlab/userplus/notifyrules/userlocationattributecondition/attributes.yaml @@ -0,0 +1,23 @@ +# =================================== +# Condition Attribute Definitions +# =================================== + +attributes: + + country: + label: Country + type: relation + relation: + model: RainLab\Location\Models\Country + label: Name + nameFrom: name + keyFrom: id + + state: + label: State + type: relation + relation: + model: RainLab\Location\Models\State + label: Name + nameFrom: name + keyFrom: id diff --git a/plugins/rainlab/userplus/updates/user_add_location_fields.php b/plugins/rainlab/userplus/updates/user_add_location_fields.php new file mode 100644 index 0000000..3ffc997 --- /dev/null +++ b/plugins/rainlab/userplus/updates/user_add_location_fields.php @@ -0,0 +1,29 @@ +integer('state_id')->unsigned()->nullable()->index(); + $table->integer('country_id')->unsigned()->nullable()->index(); + }); + } + + public function down() + { + if (Schema::hasTable('users')) { + Schema::table('users', function ($table) { + $table->dropColumn(['state_id', 'country_id']); + }); + } + } +} diff --git a/plugins/rainlab/userplus/updates/user_add_mobile_field.php b/plugins/rainlab/userplus/updates/user_add_mobile_field.php new file mode 100644 index 0000000..254bddf --- /dev/null +++ b/plugins/rainlab/userplus/updates/user_add_mobile_field.php @@ -0,0 +1,28 @@ +string('mobile', 100)->nullable(); + }); + } + + public function down() + { + if (Schema::hasTable('users')) { + Schema::table('users', function ($table) { + $table->dropColumn(['mobile']); + }); + } + } +} diff --git a/plugins/rainlab/userplus/updates/user_add_profile_fields.php b/plugins/rainlab/userplus/updates/user_add_profile_fields.php new file mode 100644 index 0000000..1a56fc7 --- /dev/null +++ b/plugins/rainlab/userplus/updates/user_add_profile_fields.php @@ -0,0 +1,32 @@ +string('phone', 100)->nullable(); + $table->string('company', 100)->nullable(); + $table->string('street_addr')->nullable(); + $table->string('city', 100)->nullable(); + $table->string('zip', 20)->nullable(); + }); + } + + public function down() + { + if (Schema::hasTable('users')) { + Schema::table('users', function ($table) { + $table->dropColumn(['phone', 'company', 'street_addr', 'city', 'zip']); + }); + } + } +} diff --git a/plugins/rainlab/userplus/updates/version.yaml b/plugins/rainlab/userplus/updates/version.yaml new file mode 100644 index 0000000..b13960a --- /dev/null +++ b/plugins/rainlab/userplus/updates/version.yaml @@ -0,0 +1,10 @@ +1.0.1: First version of User Profile +1.0.2: + - Reintroduce profile fields that were removed from User plugin + - user_add_profile_fields.php + - user_add_location_fields.php +1.0.3: + - Add mobile phone user profile field. + - user_add_mobile_field.php +1.0.4: Add various languages and minor bug fixes. +1.1.0: Compatibility with Notify plugin. diff --git a/plugins/rainlab/userplus/vendor/autoload.php b/plugins/rainlab/userplus/vendor/autoload.php new file mode 100644 index 0000000..87b20f4 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + + private $classMapAuthoritative = false; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative) { + return false; + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if ($file === null && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if ($file === null) { + // Remember that this class does not exist. + return $this->classMap[$class] = false; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { + if (0 === strpos($class, $prefix)) { + foreach ($this->prefixDirsPsr4[$prefix] as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/plugins/rainlab/userplus/vendor/composer/LICENSE b/plugins/rainlab/userplus/vendor/composer/LICENSE new file mode 100644 index 0000000..1a28124 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) 2016 Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/plugins/rainlab/userplus/vendor/composer/autoload_classmap.php b/plugins/rainlab/userplus/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..7a91153 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + array($vendorDir . '/composer/installers/src/Composer/Installers'), +); diff --git a/plugins/rainlab/userplus/vendor/composer/autoload_real.php b/plugins/rainlab/userplus/vendor/composer/autoload_real.php new file mode 100644 index 0000000..7b9afb9 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/autoload_real.php @@ -0,0 +1,45 @@ + $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + + $loader->register(true); + + return $loader; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installed.json b/plugins/rainlab/userplus/vendor/composer/installed.json new file mode 100644 index 0000000..3635188 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installed.json @@ -0,0 +1,210 @@ +[ + { + "name": "composer/installers", + "version": "v1.3.0", + "version_normalized": "1.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/installers.git", + "reference": "79ad876c7498c0bbfe7eed065b8651c93bfd6045" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/installers/zipball/79ad876c7498c0bbfe7eed065b8651c93bfd6045", + "reference": "79ad876c7498c0bbfe7eed065b8651c93bfd6045", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0" + }, + "replace": { + "roundcube/plugin-installer": "*", + "shama/baton": "*" + }, + "require-dev": { + "composer/composer": "1.0.*@dev", + "phpunit/phpunit": "4.1.*" + }, + "time": "2017-04-24 06:37:16", + "type": "composer-plugin", + "extra": { + "class": "Composer\\Installers\\Plugin", + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Composer\\Installers\\": "src/Composer/Installers" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kyle Robinson Young", + "email": "kyle@dontkry.com", + "homepage": "https://github.com/shama" + } + ], + "description": "A multi-framework Composer library installer", + "homepage": "https://composer.github.io/installers/", + "keywords": [ + "Craft", + "Dolibarr", + "Eliasis", + "Hurad", + "ImageCMS", + "Kanboard", + "MODX Evo", + "Mautic", + "Maya", + "OXID", + "Plentymarkets", + "Porto", + "RadPHP", + "SMF", + "Thelia", + "WolfCMS", + "agl", + "aimeos", + "annotatecms", + "attogram", + "bitrix", + "cakephp", + "chef", + "cockpit", + "codeigniter", + "concrete5", + "croogo", + "dokuwiki", + "drupal", + "elgg", + "expressionengine", + "fuelphp", + "grav", + "installer", + "itop", + "joomla", + "kohana", + "laravel", + "lavalite", + "lithium", + "magento", + "mako", + "mediawiki", + "modulework", + "moodle", + "phpbb", + "piwik", + "ppi", + "puppet", + "reindex", + "roundcube", + "shopware", + "silverstripe", + "sydes", + "symfony", + "typo3", + "wordpress", + "yawik", + "zend", + "zikula" + ] + }, + { + "name": "rainlab/user-plugin", + "version": "dev-master", + "version_normalized": "9999999-dev", + "source": { + "type": "git", + "url": "https://github.com/rainlab/user-plugin.git", + "reference": "d270514438c736633790aa575150ac4edfc82912" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rainlab/user-plugin/zipball/d270514438c736633790aa575150ac4edfc82912", + "reference": "d270514438c736633790aa575150ac4edfc82912", + "shasum": "" + }, + "require": { + "composer/installers": "~1.0", + "php": ">=5.5.9" + }, + "time": "2017-07-29 00:22:36", + "type": "october-plugin", + "installation-source": "source", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alexey Bobkov", + "email": "aleksey.bobkov@gmail.com", + "role": "Co-founder" + }, + { + "name": "Samuel Georges", + "email": "daftspunky@gmail.com", + "role": "Co-founder" + } + ], + "description": "User plugin for October CMS", + "homepage": "https://octobercms.com/plugin/rainlab-user", + "keywords": [ + "october", + "octobercms", + "user" + ] + }, + { + "name": "rainlab/location-plugin", + "version": "dev-master", + "version_normalized": "9999999-dev", + "source": { + "type": "git", + "url": "https://github.com/rainlab/location-plugin.git", + "reference": "39aecc73acd9b6935abdf724251ead4f3b6293cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rainlab/location-plugin/zipball/39aecc73acd9b6935abdf724251ead4f3b6293cf", + "reference": "39aecc73acd9b6935abdf724251ead4f3b6293cf", + "shasum": "" + }, + "require": { + "composer/installers": "~1.0", + "php": ">=5.5.9" + }, + "time": "2017-06-21 19:57:10", + "type": "october-plugin", + "installation-source": "source", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alexey Bobkov", + "email": "aleksey.bobkov@gmail.com", + "role": "Co-founder" + }, + { + "name": "Samuel Georges", + "email": "daftspunky@gmail.com", + "role": "Co-founder" + } + ], + "description": "Location plugin for October CMS", + "homepage": "https://octobercms.com/plugin/rainlab-location", + "keywords": [ + "location", + "october", + "octobercms" + ] + } +] diff --git a/plugins/rainlab/userplus/vendor/composer/installers/CHANGELOG.md b/plugins/rainlab/userplus/vendor/composer/installers/CHANGELOG.md new file mode 100644 index 0000000..d5d2619 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/CHANGELOG.md @@ -0,0 +1,60 @@ +# Change Log + +## v1.3.0 - 2017-04-24 +### Added +* Kanboard plugins installer. +* Porto-SAP installer. +* Add `core` to concrete5 installer. +* Support Moodle "search" plugin type. +* SyDES installer. +* iTop installer. +* Lavalite installer. +* Module type for Eliasis. +* Vgmcp installer. +* OntoWiki installer. +* The requirements for contributing (CONTRIBUTING.md). + +### Changed +* Concrete5: block & theme install location updates. + +## v1.2.0 - 2016-08-13 +### Added +* Installer for Attogram. +* Installer for Cockpit. +* Installer for Plentymarkets. +* Installer for ReIndex. +* Installer for Vanilla. +* Installer for YAWIK. +* Added missing environments for new Shopware (5.2) Plugin System. + +## v1.1.0 - 2016-07-05 +### Added +* Installer for ReIndex. +* Installer for RadPHP. +* Installer for Decibel. +* Installer for Phifty. +* Installer for ExpressionEngine. + +### Changed +* New paths for new Bitrix CMS. Old paths is deprecated. + +### Deprecated +* Old paths in Bitrix CMS Installer is deprecated. + +## v1.0.25 - 2016-04-13 +### Removed +* Revert TYPO3 installer deletion. + +## v1.0.24 - 2016-04-05 +### Added +* Installer for ImageCMS. +* Installer for Mautic. +* New types in the Kirby installer: `kirby-plugin` and `kirby-field`. +* New types in the Drupal installer: `custom-theme` and `custom-module`. + +### Changed +* Switch to PSR-4. +* Update Bitrix Installer: configuration for setting custom path to directory with kernel. + +### Removed +* Remove TYPO3 Extension installers. diff --git a/plugins/rainlab/userplus/vendor/composer/installers/CONTRIBUTING.md b/plugins/rainlab/userplus/vendor/composer/installers/CONTRIBUTING.md new file mode 100644 index 0000000..1b1998e --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contributing + +If you would like to help, please take a look at the list of +[issues](https://github.com/composer/installers/issues). + +## Pull requests + +* [Fork and clone](https://help.github.com/articles/fork-a-repo). +* Run the command `php composer.phar install` to install the dependencies. + This will also install the dev dependencies. See [Composer](https://getcomposer.org/doc/03-cli.md#install). +* Use the command `phpunit` to run the tests. See [PHPUnit](http://phpunit.de). +* Create a branch, commit, push and send us a + [pull request](https://help.github.com/articles/using-pull-requests). + +To ensure a consistent code base, you should make sure the code follows the +coding standards [PSR-1](http://www.php-fig.org/psr/psr-1/) and +[PSR-2](http://www.php-fig.org/psr/psr-2/). + +### Create a new Installer + +* Create class extends `Composer\Installers\BaseInstaller` with your Installer. +* Create unit tests as a separate class or as part of a `Composer\Installers\Test\InstallerTest`. +* Add information about your Installer in `README.md` in section "Current Supported Package Types". +* Run the tests. diff --git a/plugins/rainlab/userplus/vendor/composer/installers/LICENSE b/plugins/rainlab/userplus/vendor/composer/installers/LICENSE new file mode 100644 index 0000000..85f97fc --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Kyle Robinson Young + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/plugins/rainlab/userplus/vendor/composer/installers/README.md b/plugins/rainlab/userplus/vendor/composer/installers/README.md new file mode 100644 index 0000000..332142c --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/README.md @@ -0,0 +1,214 @@ +# A Multi-Framework [Composer](http://getcomposer.org) Library Installer + +[![Build Status](http://img.shields.io/travis/composer/installers.svg)](http://travis-ci.org/composer/installers) + +This is for PHP package authors to require in their `composer.json`. It will +install their package to the correct location based on the specified package +type. + +The goal of Installers is to be a simple package type to install path map. +Users can also customize the install path per package and package authors can +modify the package name upon installing. + +Installers isn't intended on replacing all custom installers. If your +package requires special installation handling then by all means, create a +custom installer to handle it. + +**Natively Supported Frameworks**: + +The following frameworks natively work with Composer and will be +installed to the default `vendor` directory. `composer/installers` +is not needed to install packages with these frameworks: + +* Aura +* Symfony2 +* Yii +* Yii2 + +## Current Supported Package Types + +> Stable types are marked as **bold**, this means that installation paths +> for those type will not be changed. Any adjustment for those types would +> require creation of brand new type that will cover required changes. + +| Framework | Types +| --------- | ----- +| Aimeos | `aimeos-extension` +| Asgard | `asgard-module`
    `asgard-theme` +| Attogram | `attogram-module` +| AGL | `agl-module` +| Bonefish | `bonefish-package` +| AnnotateCms | `annotatecms-module`
    `annotatecms-component`
    `annotatecms-service` +| Bitrix | `bitrix-module` (deprecated)
    `bitrix-component` (deprecated)
    `bitrix-theme` (deprecated)

    `bitrix-d7-module`
    `bitrix-d7-component`
    `bitrix-d7-template` +| CakePHP 2+ | **`cakephp-plugin`** +| Chef | `chef-cookbook`
    `chef-role` +| CCFramework | `ccframework-ship`
    `ccframework-theme` +| Cockpit | `cockpit-module` +| CodeIgniter | `codeigniter-library`
    `codeigniter-third-party`
    `codeigniter-module` +| concrete5 | `concrete5-core`
    `concrete5-package`
    `concrete5-theme`
    `concrete5-block`
    `concrete5-update` +| Craft | `craft-plugin` +| Croogo | `croogo-plugin`
    `croogo-theme` +| Decibel | `decibel-app` +| DokuWiki | `dokuwiki-plugin`
    `dokuwiki-template` +| Dolibarr | `dolibarr-module` +| Drupal | `drupal-core`
    `drupal-module`
    `drupal-theme`

    `drupal-library`
    `drupal-profile`
    `drupal-drush` +| Elgg | `elgg-plugin` +| Eliasis | `eliasis-module` +| ExpressionEngine 3 | `ee3-addon`
    `ee3-theme` +| FuelPHP v1.x | `fuel-module`
    `fuel-package`
    `fuel-theme` +| FuelPHP v2.x | `fuelphp-component` +| Grav | `grav-plugin`
    `grav-theme` +| Hurad | `hurad-plugin`
    `hurad-theme` +| ImageCMS | `imagecms-template`
    `imagecms-module`
    `imagecms-library` +| iTop | `itop-extension` +| Joomla | `joomla-component`
    `joomla-module`
    `joomla-template`
    `joomla-plugin`
    `joomla-library` +| Kanboard | `kanboard-plugin` +| Kirby | **`kirby-plugin`**
    `kirby-field`
    `kirby-tag` +| KodiCMS | `kodicms-plugin`
    `kodicms-media` +| Kohana | **`kohana-module`** +| Laravel | `laravel-library` +| Lavalite | `lavalite-theme`
    `lavalite-package` +| Lithium | **`lithium-library`
    `lithium-source`** +| Magento | `magento-library`
    `magento-skin`
    `magento-theme` +| Mako | `mako-package` +| Mautic | `mautic-plugin`
    `mautic-theme` +| Maya | `maya-module` +| MODX Evo | `modxevo-snippet`
    `modxevo-plugin`
    `modxevo-module`
    `modxevo-template`
    `modxevo-lib` +| MediaWiki | `mediawiki-extension` +| October | **`october-module`
    `october-plugin`
    `october-theme`** +| OntoWiki | `ontowiki-extension`
    `ontowiki-theme`
    `ontowiki-translation` +| OXID | `oxid-module`
    `oxid-theme`
    `oxid-out` +| MODULEWork | `modulework-module` +| Moodle | `moodle-*` (Please [check source](https://raw.githubusercontent.com/composer/installers/master/src/Composer/Installers/MoodleInstaller.php) for all supported types) +| Piwik | `piwik-plugin` +| phpBB | `phpbb-extension`
    `phpbb-style`
    `phpbb-language` +| Pimcore | `pimcore-plugin` +| Plentymarkets | `plentymarkets-plugin` +| PPI | **`ppi-module`** +| Puppet | `puppet-module` +| Porto | `porto-container` +| RadPHP | `radphp-bundle` +| REDAXO | `redaxo-addon` +| ReIndex | **`reindex-plugin`**
    **`reindex-theme`** +| Roundcube | `roundcube-plugin` +| shopware | `shopware-backend-plugin`
    `shopware-core-plugin`
    `shopware-frontend-plugin`
    `shopware-theme`
    `shopware-plugin`
    `shopware-frontend-theme` +| SilverStripe | `silverstripe-module`
    `silverstripe-theme` +| SMF | `smf-module`
    `smf-theme` +| SyDES | `sydes-module`
    `sydes-theme` +| symfony1 | **`symfony1-plugin`** +| Tusk | `tusk-task`
    `tusk-command`
    `tusk-asset` +| TYPO3 Flow | `typo3-flow-package`
    `typo3-flow-framework`
    `typo3-flow-plugin`
    `typo3-flow-site`
    `typo3-flow-boilerplate`
    `typo3-flow-build` +| TYPO3 CMS | `typo3-cms-extension` (Deprecated in this package, use the [TYPO3 CMS Installers](https://packagist.org/packages/typo3/cms-composer-installers) instead) +| Vanilla | `vanilla-plugin`
    `vanilla-theme` +| Vgmcp | `vgmcp-bundle`
    `vgmcp-theme` +| Wolf CMS | `wolfcms-plugin` +| WordPress | `wordpress-plugin`
    `wordpress-theme`

    `wordpress-muplugin` +| YAWIK | `yawik-module` +| Zend | `zend-library`
    `zend-extra`
    `zend-module` +| Zikula | `zikula-module`
    `zikula-theme` +| Prestashop | `prestashop-module`
    `prestashop-theme` +| Phifty | `phifty-bundle`
    `phifty-framework`
    `phifty-library` + +## Example `composer.json` File + +This is an example for a CakePHP plugin. The only important parts to set in your +composer.json file are `"type": "cakephp-plugin"` which describes what your +package is and `"require": { "composer/installers": "~1.0" }` which tells composer +to load the custom installers. + +```json +{ + "name": "you/ftp", + "type": "cakephp-plugin", + "require": { + "composer/installers": "~1.0" + } +} +``` + +This would install your package to the `Plugin/Ftp/` folder of a CakePHP app +when a user runs `php composer.phar install`. + +So submit your packages to [packagist.org](http://packagist.org)! + +## Custom Install Paths + +If you are consuming a package that uses the `composer/installers` you can +override the install path with the following extra in your `composer.json`: + +```json +{ + "extra": { + "installer-paths": { + "your/custom/path/{$name}/": ["shama/ftp", "vendor/package"] + } + } +} +``` + +A package type can have a custom installation path with a `type:` prefix. + +``` json +{ + "extra": { + "installer-paths": { + "your/custom/path/{$name}/": ["type:wordpress-plugin"] + } + } +} +``` + +You can also have the same vendor packages with a custom installation path by +using the `vendor:` prefix. + +``` json +{ + "extra": { + "installer-paths": { + "your/custom/path/{$name}/": ["vendor:my_organization"] + } + } +} +``` + +These would use your custom path for each of the listed packages. The available +variables to use in your paths are: `{$name}`, `{$vendor}`, `{$type}`. + +## Custom Install Names + +If you're a package author and need your package to be named differently when +installed consider using the `installer-name` extra. + +For example you have a package named `shama/cakephp-ftp` with the type +`cakephp-plugin`. Installing with `composer/installers` would install to the +path `Plugin/CakephpFtp`. Due to the strict naming conventions, you as a +package author actually need the package to be named and installed to +`Plugin/Ftp`. Using the following config within your **package** `composer.json` +will allow this: + +```json +{ + "name": "shama/cakephp-ftp", + "type": "cakephp-plugin", + "extra": { + "installer-name": "Ftp" + } +} +``` + +Please note the name entered into `installer-name` will be the final and will +not be inflected. + +## Should we allow dynamic package types or paths? No. + +What are they? The ability for a package author to determine where a package +will be installed either through setting the path directly in their +`composer.json` or through a dynamic package type: `"type": +"framework-install-here"`. + +It has been proposed many times. Even implemented once early on and then +removed. Installers won't do this because it would allow a single package +author to wipe out entire folders without the user's consent. That user would +then come here to yell at us. + +Anyone still wanting this capability should consider requiring https://github.com/oomphinc/composer-installers-extender. diff --git a/plugins/rainlab/userplus/vendor/composer/installers/composer.json b/plugins/rainlab/userplus/vendor/composer/installers/composer.json new file mode 100644 index 0000000..4dd0b90 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/composer.json @@ -0,0 +1,99 @@ +{ + "name": "composer/installers", + "type": "composer-plugin", + "license": "MIT", + "description": "A multi-framework Composer library installer", + "keywords": [ + "installer", + "Aimeos", + "AGL", + "AnnotateCms", + "Attogram", + "Bitrix", + "CakePHP", + "Chef", + "Cockpit", + "CodeIgniter", + "concrete5", + "Craft", + "Croogo", + "DokuWiki", + "Dolibarr", + "Drupal", + "Elgg", + "Eliasis", + "ExpressionEngine", + "FuelPHP", + "Grav", + "Hurad", + "ImageCMS", + "iTop", + "Joomla", + "Kanboard", + "Kohana", + "Laravel", + "Lavalite", + "Lithium", + "Magento", + "Mako", + "Mautic", + "Maya", + "MODX Evo", + "MediaWiki", + "OXID", + "MODULEWork", + "Moodle", + "Piwik", + "phpBB", + "Plentymarkets", + "PPI", + "Puppet", + "Porto", + "RadPHP", + "ReIndex", + "Roundcube", + "shopware", + "SilverStripe", + "SMF", + "SyDES", + "symfony", + "Thelia", + "TYPO3", + "WolfCMS", + "WordPress", + "YAWIK", + "Zend", + "Zikula" + ], + "homepage": "https://composer.github.io/installers/", + "authors": [ + { + "name": "Kyle Robinson Young", + "email": "kyle@dontkry.com", + "homepage": "https://github.com/shama" + } + ], + "autoload": { + "psr-4": { "Composer\\Installers\\": "src/Composer/Installers" } + }, + "extra": { + "class": "Composer\\Installers\\Plugin", + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "replace": { + "shama/baton": "*", + "roundcube/plugin-installer": "*" + }, + "require": { + "composer-plugin-api": "^1.0" + }, + "require-dev": { + "composer/composer": "1.0.*@dev", + "phpunit/phpunit": "4.1.*" + }, + "scripts": { + "test": "phpunit" + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/phpunit.xml.dist b/plugins/rainlab/userplus/vendor/composer/installers/phpunit.xml.dist new file mode 100644 index 0000000..cc5cc99 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/phpunit.xml.dist @@ -0,0 +1,25 @@ + + + + + + tests/Composer/Installers + + + + + + src/Composer/Installers + + + \ No newline at end of file diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AglInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AglInstaller.php new file mode 100644 index 0000000..01b8a41 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AglInstaller.php @@ -0,0 +1,21 @@ + 'More/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = preg_replace_callback('/(?:^|_|-)(.?)/', function ($matches) { + return strtoupper($matches[1]); + }, $vars['name']); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AimeosInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AimeosInstaller.php new file mode 100644 index 0000000..79a0e95 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AimeosInstaller.php @@ -0,0 +1,9 @@ + 'ext/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php new file mode 100644 index 0000000..89d7ad9 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php @@ -0,0 +1,11 @@ + 'addons/modules/{$name}/', + 'component' => 'addons/components/{$name}/', + 'service' => 'addons/services/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AsgardInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AsgardInstaller.php new file mode 100644 index 0000000..22dad1b --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AsgardInstaller.php @@ -0,0 +1,49 @@ + 'Modules/{$name}/', + 'theme' => 'Themes/{$name}/' + ); + + /** + * Format package name. + * + * For package type asgard-module, cut off a trailing '-plugin' if present. + * + * For package type asgard-theme, cut off a trailing '-theme' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'asgard-module') { + return $this->inflectPluginVars($vars); + } + + if ($vars['type'] === 'asgard-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + protected function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/-module$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } + + protected function inflectThemeVars($vars) + { + $vars['name'] = preg_replace('/-theme$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AttogramInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AttogramInstaller.php new file mode 100644 index 0000000..d62fd8f --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/AttogramInstaller.php @@ -0,0 +1,9 @@ + 'modules/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php new file mode 100644 index 0000000..7082bf2 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php @@ -0,0 +1,136 @@ +composer = $composer; + $this->package = $package; + $this->io = $io; + } + + /** + * Return the install path based on package type. + * + * @param PackageInterface $package + * @param string $frameworkType + * @return string + */ + public function getInstallPath(PackageInterface $package, $frameworkType = '') + { + $type = $this->package->getType(); + + $prettyName = $this->package->getPrettyName(); + if (strpos($prettyName, '/') !== false) { + list($vendor, $name) = explode('/', $prettyName); + } else { + $vendor = ''; + $name = $prettyName; + } + + $availableVars = $this->inflectPackageVars(compact('name', 'vendor', 'type')); + + $extra = $package->getExtra(); + if (!empty($extra['installer-name'])) { + $availableVars['name'] = $extra['installer-name']; + } + + if ($this->composer->getPackage()) { + $extra = $this->composer->getPackage()->getExtra(); + if (!empty($extra['installer-paths'])) { + $customPath = $this->mapCustomInstallPaths($extra['installer-paths'], $prettyName, $type, $vendor); + if ($customPath !== false) { + return $this->templatePath($customPath, $availableVars); + } + } + } + + $packageType = substr($type, strlen($frameworkType) + 1); + $locations = $this->getLocations(); + if (!isset($locations[$packageType])) { + throw new \InvalidArgumentException(sprintf('Package type "%s" is not supported', $type)); + } + + return $this->templatePath($locations[$packageType], $availableVars); + } + + /** + * For an installer to override to modify the vars per installer. + * + * @param array $vars + * @return array + */ + public function inflectPackageVars($vars) + { + return $vars; + } + + /** + * Gets the installer's locations + * + * @return array + */ + public function getLocations() + { + return $this->locations; + } + + /** + * Replace vars in a path + * + * @param string $path + * @param array $vars + * @return string + */ + protected function templatePath($path, array $vars = array()) + { + if (strpos($path, '{') !== false) { + extract($vars); + preg_match_all('@\{\$([A-Za-z0-9_]*)\}@i', $path, $matches); + if (!empty($matches[1])) { + foreach ($matches[1] as $var) { + $path = str_replace('{$' . $var . '}', $$var, $path); + } + } + } + + return $path; + } + + /** + * Search through a passed paths array for a custom install path. + * + * @param array $paths + * @param string $name + * @param string $type + * @param string $vendor = NULL + * @return string + */ + protected function mapCustomInstallPaths(array $paths, $name, $type, $vendor = NULL) + { + foreach ($paths as $path => $names) { + if (in_array($name, $names) || in_array('type:' . $type, $names) || in_array('vendor:' . $vendor, $names)) { + return $path; + } + } + + return false; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php new file mode 100644 index 0000000..e80cd1e --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php @@ -0,0 +1,126 @@ +.`. + * - `bitrix-d7-component` — copy the component to directory `bitrix/components//`. + * - `bitrix-d7-template` — copy the template to directory `bitrix/templates/_`. + * + * You can set custom path to directory with Bitrix kernel in `composer.json`: + * + * ```json + * { + * "extra": { + * "bitrix-dir": "s1/bitrix" + * } + * } + * ``` + * + * @author Nik Samokhvalov + * @author Denis Kulichkin + */ +class BitrixInstaller extends BaseInstaller +{ + protected $locations = array( + 'module' => '{$bitrix_dir}/modules/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken) + 'component' => '{$bitrix_dir}/components/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken) + 'theme' => '{$bitrix_dir}/templates/{$name}/', // deprecated, remove on the major release (Backward compatibility will be broken) + 'd7-module' => '{$bitrix_dir}/modules/{$vendor}.{$name}/', + 'd7-component' => '{$bitrix_dir}/components/{$vendor}/{$name}/', + 'd7-template' => '{$bitrix_dir}/templates/{$vendor}_{$name}/', + ); + + /** + * @var array Storage for informations about duplicates at all the time of installation packages. + */ + private static $checkedDuplicates = array(); + + /** + * {@inheritdoc} + */ + public function inflectPackageVars($vars) + { + if ($this->composer->getPackage()) { + $extra = $this->composer->getPackage()->getExtra(); + + if (isset($extra['bitrix-dir'])) { + $vars['bitrix_dir'] = $extra['bitrix-dir']; + } + } + + if (!isset($vars['bitrix_dir'])) { + $vars['bitrix_dir'] = 'bitrix'; + } + + return parent::inflectPackageVars($vars); + } + + /** + * {@inheritdoc} + */ + protected function templatePath($path, array $vars = array()) + { + $templatePath = parent::templatePath($path, $vars); + $this->checkDuplicates($templatePath, $vars); + + return $templatePath; + } + + /** + * Duplicates search packages. + * + * @param string $path + * @param array $vars + */ + protected function checkDuplicates($path, array $vars = array()) + { + $packageType = substr($vars['type'], strlen('bitrix') + 1); + $localDir = explode('/', $vars['bitrix_dir']); + array_pop($localDir); + $localDir[] = 'local'; + $localDir = implode('/', $localDir); + + $oldPath = str_replace( + array('{$bitrix_dir}', '{$name}'), + array($localDir, $vars['name']), + $this->locations[$packageType] + ); + + if (in_array($oldPath, static::$checkedDuplicates)) { + return; + } + + if ($oldPath !== $path && file_exists($oldPath) && $this->io && $this->io->isInteractive()) { + + $this->io->writeError(' Duplication of packages:'); + $this->io->writeError(' Package ' . $oldPath . ' will be called instead package ' . $path . ''); + + while (true) { + switch ($this->io->ask(' Delete ' . $oldPath . ' [y,n,?]? ', '?')) { + case 'y': + $fs = new Filesystem(); + $fs->removeDirectory($oldPath); + break 2; + + case 'n': + break 2; + + case '?': + default: + $this->io->writeError(array( + ' y - delete package ' . $oldPath . ' and to continue with the installation', + ' n - don\'t delete and to continue with the installation', + )); + $this->io->writeError(' ? - print help'); + break; + } + } + } + + static::$checkedDuplicates[] = $oldPath; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BonefishInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BonefishInstaller.php new file mode 100644 index 0000000..da3aad2 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/BonefishInstaller.php @@ -0,0 +1,9 @@ + 'Packages/{$vendor}/{$name}/' + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php new file mode 100644 index 0000000..96e987a --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php @@ -0,0 +1,83 @@ + 'Plugin/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + if ($this->matchesCakeVersion('>=', '3.0.0')) { + return $vars; + } + + $nameParts = explode('/', $vars['name']); + foreach ($nameParts as &$value) { + $value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value)); + $value = str_replace(array('-', '_'), ' ', $value); + $value = str_replace(' ', '', ucwords($value)); + } + $vars['name'] = implode('/', $nameParts); + + return $vars; + } + + /** + * Change the default plugin location when cakephp >= 3.0 + */ + public function getLocations() + { + if ($this->matchesCakeVersion('>=', '3.0.0')) { + $this->locations['plugin'] = $this->composer->getConfig()->get('vendor-dir') . '/{$vendor}/{$name}/'; + } + return $this->locations; + } + + /** + * Check if CakePHP version matches against a version + * + * @param string $matcher + * @param string $version + * @return bool + */ + protected function matchesCakeVersion($matcher, $version) + { + if (class_exists('Composer\Semver\Constraint\MultiConstraint')) { + $multiClass = 'Composer\Semver\Constraint\MultiConstraint'; + $constraintClass = 'Composer\Semver\Constraint\Constraint'; + } else { + $multiClass = 'Composer\Package\LinkConstraint\MultiConstraint'; + $constraintClass = 'Composer\Package\LinkConstraint\VersionConstraint'; + } + + $repositoryManager = $this->composer->getRepositoryManager(); + if ($repositoryManager) { + $repos = $repositoryManager->getLocalRepository(); + if (!$repos) { + return false; + } + $cake3 = new $multiClass(array( + new $constraintClass($matcher, $version), + new $constraintClass('!=', '9999999-dev'), + )); + $pool = new Pool('dev'); + $pool->addRepository($repos); + $packages = $pool->whatProvides('cakephp/cakephp'); + foreach ($packages as $package) { + $installed = new $constraintClass('=', $package->getVersion()); + if ($cake3->matches($installed)) { + return true; + } + } + } + return false; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ChefInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ChefInstaller.php new file mode 100644 index 0000000..ab2f9aa --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ChefInstaller.php @@ -0,0 +1,11 @@ + 'Chef/{$vendor}/{$name}/', + 'role' => 'Chef/roles/{$name}/', + ); +} + diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php new file mode 100644 index 0000000..c887815 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php @@ -0,0 +1,10 @@ + 'CCF/orbit/{$name}/', + 'theme' => 'CCF/app/themes/{$name}/', + ); +} \ No newline at end of file diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CockpitInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CockpitInstaller.php new file mode 100644 index 0000000..c7816df --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CockpitInstaller.php @@ -0,0 +1,34 @@ + 'cockpit/modules/addons/{$name}/', + ); + + /** + * Format module name. + * + * Strip `module-` prefix from package name. + * + * @param array @vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] == 'cockpit-module') { + return $this->inflectModuleVars($vars); + } + + return $vars; + } + + public function inflectModuleVars($vars) + { + $vars['name'] = ucfirst(preg_replace('/cockpit-/i', '', $vars['name'])); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php new file mode 100644 index 0000000..3b4a4ec --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php @@ -0,0 +1,11 @@ + 'application/libraries/{$name}/', + 'third-party' => 'application/third_party/{$name}/', + 'module' => 'application/modules/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php new file mode 100644 index 0000000..5c01baf --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php @@ -0,0 +1,13 @@ + 'concrete/', + 'block' => 'application/blocks/{$name}/', + 'package' => 'packages/{$name}/', + 'theme' => 'application/themes/{$name}/', + 'update' => 'updates/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php new file mode 100644 index 0000000..d37a77a --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php @@ -0,0 +1,35 @@ + 'craft/plugins/{$name}/', + ); + + /** + * Strip `craft-` prefix and/or `-plugin` suffix from package names + * + * @param array $vars + * + * @return array + */ + final public function inflectPackageVars($vars) + { + return $this->inflectPluginVars($vars); + } + + private function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/-' . self::NAME_SUFFIX . '$/i', '', $vars['name']); + $vars['name'] = preg_replace('/^' . self::NAME_PREFIX . '-/i', '', $vars['name']); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php new file mode 100644 index 0000000..d94219d --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php @@ -0,0 +1,21 @@ + 'Plugin/{$name}/', + 'theme' => 'View/Themed/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(str_replace(array('-', '_'), ' ', $vars['name'])); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DecibelInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DecibelInstaller.php new file mode 100644 index 0000000..f4837a6 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DecibelInstaller.php @@ -0,0 +1,10 @@ + 'app/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DokuWikiInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DokuWikiInstaller.php new file mode 100644 index 0000000..cfd638d --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DokuWikiInstaller.php @@ -0,0 +1,50 @@ + 'lib/plugins/{$name}/', + 'template' => 'lib/tpl/{$name}/', + ); + + /** + * Format package name. + * + * For package type dokuwiki-plugin, cut off a trailing '-plugin', + * or leading dokuwiki_ if present. + * + * For package type dokuwiki-template, cut off a trailing '-template' if present. + * + */ + public function inflectPackageVars($vars) + { + + if ($vars['type'] === 'dokuwiki-plugin') { + return $this->inflectPluginVars($vars); + } + + if ($vars['type'] === 'dokuwiki-template') { + return $this->inflectTemplateVars($vars); + } + + return $vars; + } + + protected function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/-plugin$/', '', $vars['name']); + $vars['name'] = preg_replace('/^dokuwiki_?-?/', '', $vars['name']); + + return $vars; + } + + protected function inflectTemplateVars($vars) + { + $vars['name'] = preg_replace('/-template$/', '', $vars['name']); + $vars['name'] = preg_replace('/^dokuwiki_?-?/', '', $vars['name']); + + return $vars; + } + +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php new file mode 100644 index 0000000..21f7e8e --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php @@ -0,0 +1,16 @@ + + */ +class DolibarrInstaller extends BaseInstaller +{ + //TODO: Add support for scripts and themes + protected $locations = array( + 'module' => 'htdocs/custom/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php new file mode 100644 index 0000000..a41ee2e --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php @@ -0,0 +1,16 @@ + 'core/', + 'module' => 'modules/{$name}/', + 'theme' => 'themes/{$name}/', + 'library' => 'libraries/{$name}/', + 'profile' => 'profiles/{$name}/', + 'drush' => 'drush/{$name}/', + 'custom-theme' => 'themes/custom/{$name}/', + 'custom-module' => 'modules/custom/{$name}', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php new file mode 100644 index 0000000..c0bb609 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php @@ -0,0 +1,9 @@ + 'mod/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/EliasisInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/EliasisInstaller.php new file mode 100644 index 0000000..2be4e3c --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/EliasisInstaller.php @@ -0,0 +1,9 @@ + 'modules/{$name}/' + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php new file mode 100644 index 0000000..d5321a8 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php @@ -0,0 +1,29 @@ + 'system/expressionengine/third_party/{$name}/', + 'theme' => 'themes/third_party/{$name}/', + ); + + private $ee3Locations = array( + 'addon' => 'system/user/addons/{$name}/', + 'theme' => 'themes/user/{$name}/', + ); + + public function getInstallPath(PackageInterface $package, $frameworkType = '') + { + + $version = "{$frameworkType}Locations"; + $this->locations = $this->$version; + + return parent::getInstallPath($package, $frameworkType); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php new file mode 100644 index 0000000..6eba2e3 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php @@ -0,0 +1,11 @@ + 'fuel/app/modules/{$name}/', + 'package' => 'fuel/packages/{$name}/', + 'theme' => 'fuel/app/themes/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/FuelphpInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/FuelphpInstaller.php new file mode 100644 index 0000000..29d980b --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/FuelphpInstaller.php @@ -0,0 +1,9 @@ + 'components/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/GravInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/GravInstaller.php new file mode 100644 index 0000000..dbe63e0 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/GravInstaller.php @@ -0,0 +1,30 @@ + 'user/plugins/{$name}/', + 'theme' => 'user/themes/{$name}/', + ); + + /** + * Format package name + * + * @param array $vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + $restrictedWords = implode('|', array_keys($this->locations)); + + $vars['name'] = strtolower($vars['name']); + $vars['name'] = preg_replace('/^(?:grav-)?(?:(?:'.$restrictedWords.')-)?(.*?)(?:-(?:'.$restrictedWords.'))?$/ui', + '$1', + $vars['name'] + ); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php new file mode 100644 index 0000000..8fe017f --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php @@ -0,0 +1,25 @@ + 'plugins/{$name}/', + 'theme' => 'plugins/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $nameParts = explode('/', $vars['name']); + foreach ($nameParts as &$value) { + $value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value)); + $value = str_replace(array('-', '_'), ' ', $value); + $value = str_replace(' ', '', ucwords($value)); + } + $vars['name'] = implode('/', $nameParts); + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ImageCMSInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ImageCMSInstaller.php new file mode 100644 index 0000000..5e2142e --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ImageCMSInstaller.php @@ -0,0 +1,11 @@ + 'templates/{$name}/', + 'module' => 'application/modules/{$name}/', + 'library' => 'application/libraries/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Installer.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Installer.php new file mode 100644 index 0000000..10f28bb --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Installer.php @@ -0,0 +1,197 @@ + 'AimeosInstaller', + 'asgard' => 'AsgardInstaller', + 'attogram' => 'AttogramInstaller', + 'agl' => 'AglInstaller', + 'annotatecms' => 'AnnotateCmsInstaller', + 'bitrix' => 'BitrixInstaller', + 'bonefish' => 'BonefishInstaller', + 'cakephp' => 'CakePHPInstaller', + 'chef' => 'ChefInstaller', + 'ccframework' => 'ClanCatsFrameworkInstaller', + 'cockpit' => 'CockpitInstaller', + 'codeigniter' => 'CodeIgniterInstaller', + 'concrete5' => 'Concrete5Installer', + 'craft' => 'CraftInstaller', + 'croogo' => 'CroogoInstaller', + 'dokuwiki' => 'DokuWikiInstaller', + 'dolibarr' => 'DolibarrInstaller', + 'decibel' => 'DecibelInstaller', + 'drupal' => 'DrupalInstaller', + 'elgg' => 'ElggInstaller', + 'eliasis' => 'EliasisInstaller', + 'ee3' => 'ExpressionEngineInstaller', + 'ee2' => 'ExpressionEngineInstaller', + 'fuel' => 'FuelInstaller', + 'fuelphp' => 'FuelphpInstaller', + 'grav' => 'GravInstaller', + 'hurad' => 'HuradInstaller', + 'imagecms' => 'ImageCMSInstaller', + 'itop' => 'ItopInstaller', + 'joomla' => 'JoomlaInstaller', + 'kanboard' => 'KanboardInstaller', + 'kirby' => 'KirbyInstaller', + 'kodicms' => 'KodiCMSInstaller', + 'kohana' => 'KohanaInstaller', + 'laravel' => 'LaravelInstaller', + 'lavalite' => 'LavaLiteInstaller', + 'lithium' => 'LithiumInstaller', + 'magento' => 'MagentoInstaller', + 'mako' => 'MakoInstaller', + 'maya' => 'MayaInstaller', + 'mautic' => 'MauticInstaller', + 'mediawiki' => 'MediaWikiInstaller', + 'microweber' => 'MicroweberInstaller', + 'modulework' => 'MODULEWorkInstaller', + 'modxevo' => 'MODXEvoInstaller', + 'moodle' => 'MoodleInstaller', + 'october' => 'OctoberInstaller', + 'ontowiki' => 'OntoWikiInstaller', + 'oxid' => 'OxidInstaller', + 'phpbb' => 'PhpBBInstaller', + 'pimcore' => 'PimcoreInstaller', + 'piwik' => 'PiwikInstaller', + 'plentymarkets'=> 'PlentymarketsInstaller', + 'ppi' => 'PPIInstaller', + 'puppet' => 'PuppetInstaller', + 'radphp' => 'RadPHPInstaller', + 'phifty' => 'PhiftyInstaller', + 'porto' => 'PortoInstaller', + 'redaxo' => 'RedaxoInstaller', + 'reindex' => 'ReIndexInstaller', + 'roundcube' => 'RoundcubeInstaller', + 'shopware' => 'ShopwareInstaller', + 'silverstripe' => 'SilverStripeInstaller', + 'smf' => 'SMFInstaller', + 'sydes' => 'SyDESInstaller', + 'symfony1' => 'Symfony1Installer', + 'thelia' => 'TheliaInstaller', + 'tusk' => 'TuskInstaller', + 'typo3-cms' => 'TYPO3CmsInstaller', + 'typo3-flow' => 'TYPO3FlowInstaller', + 'vanilla' => 'VanillaInstaller', + 'whmcs' => 'WHMCSInstaller', + 'wolfcms' => 'WolfCMSInstaller', + 'wordpress' => 'WordPressInstaller', + 'yawik' => 'YawikInstaller', + 'zend' => 'ZendInstaller', + 'zikula' => 'ZikulaInstaller', + 'prestashop' => 'PrestashopInstaller' + ); + + /** + * {@inheritDoc} + */ + public function getInstallPath(PackageInterface $package) + { + $type = $package->getType(); + $frameworkType = $this->findFrameworkType($type); + + if ($frameworkType === false) { + throw new \InvalidArgumentException( + 'Sorry the package type of this package is not yet supported.' + ); + } + + $class = 'Composer\\Installers\\' . $this->supportedTypes[$frameworkType]; + $installer = new $class($package, $this->composer, $this->getIO()); + + return $installer->getInstallPath($package, $frameworkType); + } + + public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) + { + if (!$repo->hasPackage($package)) { + throw new \InvalidArgumentException('Package is not installed: '.$package); + } + + $repo->removePackage($package); + + $installPath = $this->getInstallPath($package); + $this->io->write(sprintf('Deleting %s - %s', $installPath, $this->filesystem->removeDirectory($installPath) ? 'deleted' : 'not deleted')); + } + + /** + * {@inheritDoc} + */ + public function supports($packageType) + { + $frameworkType = $this->findFrameworkType($packageType); + + if ($frameworkType === false) { + return false; + } + + $locationPattern = $this->getLocationPattern($frameworkType); + + return preg_match('#' . $frameworkType . '-' . $locationPattern . '#', $packageType, $matches) === 1; + } + + /** + * Finds a supported framework type if it exists and returns it + * + * @param string $type + * @return string + */ + protected function findFrameworkType($type) + { + $frameworkType = false; + + krsort($this->supportedTypes); + + foreach ($this->supportedTypes as $key => $val) { + if ($key === substr($type, 0, strlen($key))) { + $frameworkType = substr($type, 0, strlen($key)); + break; + } + } + + return $frameworkType; + } + + /** + * Get the second part of the regular expression to check for support of a + * package type + * + * @param string $frameworkType + * @return string + */ + protected function getLocationPattern($frameworkType) + { + $pattern = false; + if (!empty($this->supportedTypes[$frameworkType])) { + $frameworkClass = 'Composer\\Installers\\' . $this->supportedTypes[$frameworkType]; + /** @var BaseInstaller $framework */ + $framework = new $frameworkClass(null, $this->composer, $this->getIO()); + $locations = array_keys($framework->getLocations()); + $pattern = $locations ? '(' . implode('|', $locations) . ')' : false; + } + + return $pattern ? : '(\w+)'; + } + + /** + * Get I/O object + * + * @return IOInterface + */ + private function getIO() + { + return $this->io; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ItopInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ItopInstaller.php new file mode 100644 index 0000000..c6c1b33 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ItopInstaller.php @@ -0,0 +1,9 @@ + 'extensions/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php new file mode 100644 index 0000000..9ee7759 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php @@ -0,0 +1,15 @@ + 'components/{$name}/', + 'module' => 'modules/{$name}/', + 'template' => 'templates/{$name}/', + 'plugin' => 'plugins/{$name}/', + 'library' => 'libraries/{$name}/', + ); + + // TODO: Add inflector for mod_ and com_ names +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KanboardInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KanboardInstaller.php new file mode 100644 index 0000000..9cb7b8c --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KanboardInstaller.php @@ -0,0 +1,18 @@ + 'plugins/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php new file mode 100644 index 0000000..36b2f84 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php @@ -0,0 +1,11 @@ + 'site/plugins/{$name}/', + 'field' => 'site/fields/{$name}/', + 'tag' => 'site/tags/{$name}/' + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KodiCMSInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KodiCMSInstaller.php new file mode 100644 index 0000000..7143e23 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KodiCMSInstaller.php @@ -0,0 +1,10 @@ + 'cms/plugins/{$name}/', + 'media' => 'cms/media/vendor/{$name}/' + ); +} \ No newline at end of file diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php new file mode 100644 index 0000000..dcd6d26 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php @@ -0,0 +1,9 @@ + 'modules/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php new file mode 100644 index 0000000..be4d53a --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php @@ -0,0 +1,9 @@ + 'libraries/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LavaLiteInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LavaLiteInstaller.php new file mode 100644 index 0000000..8130b88 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LavaLiteInstaller.php @@ -0,0 +1,10 @@ + 'packages/{$name}/', + 'theme' => 'public/themes/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php new file mode 100644 index 0000000..47bbd4c --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php @@ -0,0 +1,10 @@ + 'libraries/{$name}/', + 'source' => 'libraries/_source/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php new file mode 100644 index 0000000..9c2e9fb --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php @@ -0,0 +1,9 @@ + 'modules/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php new file mode 100644 index 0000000..5a66460 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php @@ -0,0 +1,16 @@ + 'assets/snippets/{$name}/', + 'plugin' => 'assets/plugins/{$name}/', + 'module' => 'assets/modules/{$name}/', + 'template' => 'assets/templates/{$name}/', + 'lib' => 'assets/lib/{$name}/' + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php new file mode 100644 index 0000000..cf18e94 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php @@ -0,0 +1,11 @@ + 'app/design/frontend/{$name}/', + 'skin' => 'skin/frontend/default/{$name}/', + 'library' => 'lib/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php new file mode 100644 index 0000000..ca3cfac --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php @@ -0,0 +1,9 @@ + 'app/packages/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MauticInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MauticInstaller.php new file mode 100644 index 0000000..3e1ce2b --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MauticInstaller.php @@ -0,0 +1,25 @@ + 'plugins/{$name}/', + 'theme' => 'themes/{$name}/', + ); + + /** + * Format package name of mautic-plugins to CamelCase + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] == 'mautic-plugin') { + $vars['name'] = preg_replace_callback('/(-[a-z])/', function ($matches) { + return strtoupper($matches[0][1]); + }, ucfirst($vars['name'])); + } + + return $vars; + } + +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MayaInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MayaInstaller.php new file mode 100644 index 0000000..30a9167 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MayaInstaller.php @@ -0,0 +1,33 @@ + 'modules/{$name}/', + ); + + /** + * Format package name. + * + * For package type maya-module, cut off a trailing '-module' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'maya-module') { + return $this->inflectModuleVars($vars); + } + + return $vars; + } + + protected function inflectModuleVars($vars) + { + $vars['name'] = preg_replace('/-module$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php new file mode 100644 index 0000000..01008c6 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php @@ -0,0 +1,50 @@ + 'extensions/{$name}/', + 'skin' => 'skins/{$name}/', + ); + + /** + * Format package name. + * + * For package type mediawiki-extension, cut off a trailing '-extension' if present and transform + * to CamelCase keeping existing uppercase chars. + * + * For package type mediawiki-skin, cut off a trailing '-skin' if present. + * + */ + public function inflectPackageVars($vars) + { + + if ($vars['type'] === 'mediawiki-extension') { + return $this->inflectExtensionVars($vars); + } + + if ($vars['type'] === 'mediawiki-skin') { + return $this->inflectSkinVars($vars); + } + + return $vars; + } + + protected function inflectExtensionVars($vars) + { + $vars['name'] = preg_replace('/-extension$/', '', $vars['name']); + $vars['name'] = str_replace('-', ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } + + protected function inflectSkinVars($vars) + { + $vars['name'] = preg_replace('/-skin$/', '', $vars['name']); + + return $vars; + } + +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php new file mode 100644 index 0000000..4bbbec8 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php @@ -0,0 +1,111 @@ + 'userfiles/modules/{$name}/', + 'module-skin' => 'userfiles/modules/{$name}/templates/', + 'template' => 'userfiles/templates/{$name}/', + 'element' => 'userfiles/elements/{$name}/', + 'vendor' => 'vendor/{$name}/', + 'components' => 'components/{$name}/' + ); + + /** + * Format package name. + * + * For package type microweber-module, cut off a trailing '-module' if present + * + * For package type microweber-template, cut off a trailing '-template' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'microweber-template') { + return $this->inflectTemplateVars($vars); + } + if ($vars['type'] === 'microweber-templates') { + return $this->inflectTemplatesVars($vars); + } + if ($vars['type'] === 'microweber-core') { + return $this->inflectCoreVars($vars); + } + if ($vars['type'] === 'microweber-adapter') { + return $this->inflectCoreVars($vars); + } + if ($vars['type'] === 'microweber-module') { + return $this->inflectModuleVars($vars); + } + if ($vars['type'] === 'microweber-modules') { + return $this->inflectModulesVars($vars); + } + if ($vars['type'] === 'microweber-skin') { + return $this->inflectSkinVars($vars); + } + if ($vars['type'] === 'microweber-element' or $vars['type'] === 'microweber-elements') { + return $this->inflectElementVars($vars); + } + + return $vars; + } + + protected function inflectTemplateVars($vars) + { + $vars['name'] = preg_replace('/-template$/', '', $vars['name']); + $vars['name'] = preg_replace('/template-$/', '', $vars['name']); + + return $vars; + } + + protected function inflectTemplatesVars($vars) + { + $vars['name'] = preg_replace('/-templates$/', '', $vars['name']); + $vars['name'] = preg_replace('/templates-$/', '', $vars['name']); + + return $vars; + } + + protected function inflectCoreVars($vars) + { + $vars['name'] = preg_replace('/-providers$/', '', $vars['name']); + $vars['name'] = preg_replace('/-provider$/', '', $vars['name']); + $vars['name'] = preg_replace('/-adapter$/', '', $vars['name']); + + return $vars; + } + + protected function inflectModuleVars($vars) + { + $vars['name'] = preg_replace('/-module$/', '', $vars['name']); + $vars['name'] = preg_replace('/module-$/', '', $vars['name']); + + return $vars; + } + + protected function inflectModulesVars($vars) + { + $vars['name'] = preg_replace('/-modules$/', '', $vars['name']); + $vars['name'] = preg_replace('/modules-$/', '', $vars['name']); + + return $vars; + } + + protected function inflectSkinVars($vars) + { + $vars['name'] = preg_replace('/-skin$/', '', $vars['name']); + $vars['name'] = preg_replace('/skin-$/', '', $vars['name']); + + return $vars; + } + + protected function inflectElementVars($vars) + { + $vars['name'] = preg_replace('/-elements$/', '', $vars['name']); + $vars['name'] = preg_replace('/elements-$/', '', $vars['name']); + $vars['name'] = preg_replace('/-element$/', '', $vars['name']); + $vars['name'] = preg_replace('/element-$/', '', $vars['name']); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php new file mode 100644 index 0000000..a89c82f --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php @@ -0,0 +1,57 @@ + 'mod/{$name}/', + 'admin_report' => 'admin/report/{$name}/', + 'atto' => 'lib/editor/atto/plugins/{$name}/', + 'tool' => 'admin/tool/{$name}/', + 'assignment' => 'mod/assignment/type/{$name}/', + 'assignsubmission' => 'mod/assign/submission/{$name}/', + 'assignfeedback' => 'mod/assign/feedback/{$name}/', + 'auth' => 'auth/{$name}/', + 'availability' => 'availability/condition/{$name}/', + 'block' => 'blocks/{$name}/', + 'booktool' => 'mod/book/tool/{$name}/', + 'cachestore' => 'cache/stores/{$name}/', + 'cachelock' => 'cache/locks/{$name}/', + 'calendartype' => 'calendar/type/{$name}/', + 'format' => 'course/format/{$name}/', + 'coursereport' => 'course/report/{$name}/', + 'datafield' => 'mod/data/field/{$name}/', + 'datapreset' => 'mod/data/preset/{$name}/', + 'editor' => 'lib/editor/{$name}/', + 'enrol' => 'enrol/{$name}/', + 'filter' => 'filter/{$name}/', + 'gradeexport' => 'grade/export/{$name}/', + 'gradeimport' => 'grade/import/{$name}/', + 'gradereport' => 'grade/report/{$name}/', + 'gradingform' => 'grade/grading/form/{$name}/', + 'local' => 'local/{$name}/', + 'logstore' => 'admin/tool/log/store/{$name}/', + 'ltisource' => 'mod/lti/source/{$name}/', + 'ltiservice' => 'mod/lti/service/{$name}/', + 'message' => 'message/output/{$name}/', + 'mnetservice' => 'mnet/service/{$name}/', + 'plagiarism' => 'plagiarism/{$name}/', + 'portfolio' => 'portfolio/{$name}/', + 'qbehaviour' => 'question/behaviour/{$name}/', + 'qformat' => 'question/format/{$name}/', + 'qtype' => 'question/type/{$name}/', + 'quizaccess' => 'mod/quiz/accessrule/{$name}/', + 'quiz' => 'mod/quiz/report/{$name}/', + 'report' => 'report/{$name}/', + 'repository' => 'repository/{$name}/', + 'scormreport' => 'mod/scorm/report/{$name}/', + 'search' => 'search/engine/{$name}/', + 'theme' => 'theme/{$name}/', + 'tinymce' => 'lib/editor/tinymce/plugins/{$name}/', + 'profilefield' => 'user/profile/field/{$name}/', + 'webservice' => 'webservice/{$name}/', + 'workshopallocation' => 'mod/workshop/allocation/{$name}/', + 'workshopeval' => 'mod/workshop/eval/{$name}/', + 'workshopform' => 'mod/workshop/form/{$name}/' + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php new file mode 100644 index 0000000..6bf53fd --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php @@ -0,0 +1,46 @@ + 'modules/{$name}/', + 'plugin' => 'plugins/{$vendor}/{$name}/', + 'theme' => 'themes/{$name}/' + ); + + /** + * Format package name. + * + * For package type october-plugin, cut off a trailing '-plugin' if present. + * + * For package type october-theme, cut off a trailing '-theme' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'october-plugin') { + return $this->inflectPluginVars($vars); + } + + if ($vars['type'] === 'october-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + protected function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/-plugin$/', '', $vars['name']); + + return $vars; + } + + protected function inflectThemeVars($vars) + { + $vars['name'] = preg_replace('/-theme$/', '', $vars['name']); + + return $vars; + } +} \ No newline at end of file diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OntoWikiInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OntoWikiInstaller.php new file mode 100644 index 0000000..5dd3438 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OntoWikiInstaller.php @@ -0,0 +1,24 @@ + 'extensions/{$name}/', + 'theme' => 'extensions/themes/{$name}/', + 'translation' => 'extensions/translations/{$name}/', + ); + + /** + * Format package name to lower case and remove ".ontowiki" suffix + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower($vars['name']); + $vars['name'] = preg_replace('/.ontowiki$/', '', $vars['name']); + $vars['name'] = preg_replace('/-theme$/', '', $vars['name']); + $vars['name'] = preg_replace('/-translation$/', '', $vars['name']); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php new file mode 100644 index 0000000..49940ff --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php @@ -0,0 +1,59 @@ +.+)\/.+/'; + + protected $locations = array( + 'module' => 'modules/{$name}/', + 'theme' => 'application/views/{$name}/', + 'out' => 'out/{$name}/', + ); + + /** + * getInstallPath + * + * @param PackageInterface $package + * @param string $frameworkType + * @return void + */ + public function getInstallPath(PackageInterface $package, $frameworkType = '') + { + $installPath = parent::getInstallPath($package, $frameworkType); + $type = $this->package->getType(); + if ($type === 'oxid-module') { + $this->prepareVendorDirectory($installPath); + } + return $installPath; + } + + /** + * prepareVendorDirectory + * + * Makes sure there is a vendormetadata.php file inside + * the vendor folder if there is a vendor folder. + * + * @param string $installPath + * @return void + */ + protected function prepareVendorDirectory($installPath) + { + $matches = ''; + $hasVendorDirectory = preg_match(self::VENDOR_PATTERN, $installPath, $matches); + if (!$hasVendorDirectory) { + return; + } + + $vendorDirectory = $matches['vendor']; + $vendorPath = getcwd() . '/modules/' . $vendorDirectory; + if (!file_exists($vendorPath)) { + mkdir($vendorPath, 0755, true); + } + + $vendorMetaDataPath = $vendorPath . '/vendormetadata.php'; + touch($vendorMetaDataPath); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php new file mode 100644 index 0000000..170136f --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php @@ -0,0 +1,9 @@ + 'modules/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PhiftyInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PhiftyInstaller.php new file mode 100644 index 0000000..4e59a8a --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PhiftyInstaller.php @@ -0,0 +1,11 @@ + 'bundles/{$name}/', + 'library' => 'libraries/{$name}/', + 'framework' => 'frameworks/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php new file mode 100644 index 0000000..deb2b77 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php @@ -0,0 +1,11 @@ + 'ext/{$vendor}/{$name}/', + 'language' => 'language/{$name}/', + 'style' => 'styles/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php new file mode 100644 index 0000000..4781fa6 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php @@ -0,0 +1,21 @@ + 'plugins/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name'])); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php new file mode 100644 index 0000000..c17f457 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php @@ -0,0 +1,32 @@ + 'plugins/{$name}/', + ); + + /** + * Format package name to CamelCase + * @param array $vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name'])); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php new file mode 100644 index 0000000..903e55f --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php @@ -0,0 +1,29 @@ + '{$name}/' + ); + + /** + * Remove hyphen, "plugin" and format to camelcase + * @param array $vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + $vars['name'] = explode("-", $vars['name']); + foreach ($vars['name'] as $key => $name) { + $vars['name'][$key] = ucfirst($vars['name'][$key]); + if (strcasecmp($name, "Plugin") == 0) { + unset($vars['name'][$key]); + } + } + $vars['name'] = implode("",$vars['name']); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Plugin.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Plugin.php new file mode 100644 index 0000000..5eb04af --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Plugin.php @@ -0,0 +1,17 @@ +getInstallationManager()->addInstaller($installer); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PortoInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PortoInstaller.php new file mode 100644 index 0000000..dbf85e6 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PortoInstaller.php @@ -0,0 +1,9 @@ + 'app/Containers/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PrestashopInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PrestashopInstaller.php new file mode 100644 index 0000000..4c8421e --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PrestashopInstaller.php @@ -0,0 +1,10 @@ + 'modules/{$name}/', + 'theme' => 'themes/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PuppetInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PuppetInstaller.php new file mode 100644 index 0000000..77cc3dd --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/PuppetInstaller.php @@ -0,0 +1,11 @@ + 'modules/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RadPHPInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RadPHPInstaller.php new file mode 100644 index 0000000..0f78b5c --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RadPHPInstaller.php @@ -0,0 +1,24 @@ + 'src/{$name}/' + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $nameParts = explode('/', $vars['name']); + foreach ($nameParts as &$value) { + $value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value)); + $value = str_replace(array('-', '_'), ' ', $value); + $value = str_replace(' ', '', ucwords($value)); + } + $vars['name'] = implode('/', $nameParts); + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ReIndexInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ReIndexInstaller.php new file mode 100644 index 0000000..252c733 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ReIndexInstaller.php @@ -0,0 +1,10 @@ + 'themes/{$name}/', + 'plugin' => 'plugins/{$name}/' + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RedaxoInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RedaxoInstaller.php new file mode 100644 index 0000000..0954457 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RedaxoInstaller.php @@ -0,0 +1,10 @@ + 'redaxo/include/addons/{$name}/', + 'bestyle-plugin' => 'redaxo/include/addons/be_style/plugins/{$name}/' + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php new file mode 100644 index 0000000..d8d795b --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php @@ -0,0 +1,22 @@ + 'plugins/{$name}/', + ); + + /** + * Lowercase name and changes the name to a underscores + * + * @param array $vars + * @return array + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(str_replace('-', '_', $vars['name'])); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SMFInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SMFInstaller.php new file mode 100644 index 0000000..1acd3b1 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SMFInstaller.php @@ -0,0 +1,10 @@ + 'Sources/{$name}/', + 'theme' => 'Themes/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php new file mode 100644 index 0000000..d0193cb --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php @@ -0,0 +1,60 @@ + 'engine/Shopware/Plugins/Local/Backend/{$name}/', + 'core-plugin' => 'engine/Shopware/Plugins/Local/Core/{$name}/', + 'frontend-plugin' => 'engine/Shopware/Plugins/Local/Frontend/{$name}/', + 'theme' => 'templates/{$name}/', + 'plugin' => 'custom/plugins/{$name}/', + 'frontend-theme' => 'themes/Frontend/{$name}/', + ); + + /** + * Transforms the names + * @param array $vars + * @return array + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'shopware-theme') { + return $this->correctThemeName($vars); + } else { + return $this->correctPluginName($vars); + } + } + + /** + * Changes the name to a camelcased combination of vendor and name + * @param array $vars + * @return array + */ + private function correctPluginName($vars) + { + $camelCasedName = preg_replace_callback('/(-[a-z])/', function ($matches) { + return strtoupper($matches[0][1]); + }, $vars['name']); + + $vars['name'] = ucfirst($vars['vendor']) . ucfirst($camelCasedName); + + return $vars; + } + + /** + * Changes the name to a underscore separated name + * @param array $vars + * @return array + */ + private function correctThemeName($vars) + { + $vars['name'] = str_replace('-', '_', $vars['name']); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php new file mode 100644 index 0000000..17ca543 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php @@ -0,0 +1,36 @@ + '{$name}/', + 'theme' => 'themes/{$name}/', + ); + + /** + * Return the install path based on package type. + * + * Relies on built-in BaseInstaller behaviour with one exception: silverstripe/framework + * must be installed to 'sapphire' and not 'framework' if the version is <3.0.0 + * + * @param PackageInterface $package + * @param string $frameworkType + * @return string + */ + public function getInstallPath(PackageInterface $package, $frameworkType = '') + { + if ( + $package->getName() == 'silverstripe/framework' + && preg_match('/^\d+\.\d+\.\d+/', $package->getVersion()) + && version_compare($package->getVersion(), '2.999.999') < 0 + ) { + return $this->templatePath($this->locations['module'], array('name' => 'sapphire')); + } else { + return parent::getInstallPath($package, $frameworkType); + } + + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SyDESInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SyDESInstaller.php new file mode 100644 index 0000000..83ef9d0 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/SyDESInstaller.php @@ -0,0 +1,49 @@ + 'app/modules/{$name}/', + 'theme' => 'themes/{$name}/', + ); + + /** + * Format module name. + * + * Strip `sydes-` prefix and a trailing '-theme' or '-module' from package name if present. + * + * @param array @vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] == 'sydes-module') { + return $this->inflectModuleVars($vars); + } + + if ($vars['type'] === 'sydes-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + public function inflectModuleVars($vars) + { + $vars['name'] = preg_replace('/(^sydes-|-module$)/i', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } + + protected function inflectThemeVars($vars) + { + $vars['name'] = preg_replace('/(^sydes-|-theme$)/', '', $vars['name']); + $vars['name'] = strtolower($vars['name']); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php new file mode 100644 index 0000000..1675c4f --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php @@ -0,0 +1,26 @@ + + */ +class Symfony1Installer extends BaseInstaller +{ + protected $locations = array( + 'plugin' => 'plugins/{$name}/', + ); + + /** + * Format package name to CamelCase + */ + public function inflectPackageVars($vars) + { + $vars['name'] = preg_replace_callback('/(-[a-z])/', function ($matches) { + return strtoupper($matches[0][1]); + }, $vars['name']); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php new file mode 100644 index 0000000..b1663e8 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php @@ -0,0 +1,16 @@ + + */ +class TYPO3CmsInstaller extends BaseInstaller +{ + protected $locations = array( + 'extension' => 'typo3conf/ext/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php new file mode 100644 index 0000000..42572f4 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php @@ -0,0 +1,38 @@ + 'Packages/Application/{$name}/', + 'framework' => 'Packages/Framework/{$name}/', + 'plugin' => 'Packages/Plugins/{$name}/', + 'site' => 'Packages/Sites/{$name}/', + 'boilerplate' => 'Packages/Boilerplates/{$name}/', + 'build' => 'Build/{$name}/', + ); + + /** + * Modify the package name to be a TYPO3 Flow style key. + * + * @param array $vars + * @return array + */ + public function inflectPackageVars($vars) + { + $autoload = $this->package->getAutoload(); + if (isset($autoload['psr-0']) && is_array($autoload['psr-0'])) { + $namespace = key($autoload['psr-0']); + $vars['name'] = str_replace('\\', '.', $namespace); + } + if (isset($autoload['psr-4']) && is_array($autoload['psr-4'])) { + $namespace = key($autoload['psr-4']); + $vars['name'] = rtrim(str_replace('\\', '.', $namespace), '.'); + } + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TheliaInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TheliaInstaller.php new file mode 100644 index 0000000..158af52 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TheliaInstaller.php @@ -0,0 +1,12 @@ + 'local/modules/{$name}/', + 'frontoffice-template' => 'templates/frontOffice/{$name}/', + 'backoffice-template' => 'templates/backOffice/{$name}/', + 'email-template' => 'templates/email/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php new file mode 100644 index 0000000..7c0113b --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php @@ -0,0 +1,14 @@ + + */ + class TuskInstaller extends BaseInstaller + { + protected $locations = array( + 'task' => '.tusk/tasks/{$name}/', + 'command' => '.tusk/commands/{$name}/', + 'asset' => 'assets/tusk/{$name}/', + ); + } diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/VanillaInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/VanillaInstaller.php new file mode 100644 index 0000000..24ca645 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/VanillaInstaller.php @@ -0,0 +1,10 @@ + 'plugins/{$name}/', + 'theme' => 'themes/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/VgmcpInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/VgmcpInstaller.php new file mode 100644 index 0000000..7d90c5e --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/VgmcpInstaller.php @@ -0,0 +1,49 @@ + 'src/{$vendor}/{$name}/', + 'theme' => 'themes/{$name}/' + ); + + /** + * Format package name. + * + * For package type vgmcp-bundle, cut off a trailing '-bundle' if present. + * + * For package type vgmcp-theme, cut off a trailing '-theme' if present. + * + */ + public function inflectPackageVars($vars) + { + if ($vars['type'] === 'vgmcp-bundle') { + return $this->inflectPluginVars($vars); + } + + if ($vars['type'] === 'vgmcp-theme') { + return $this->inflectThemeVars($vars); + } + + return $vars; + } + + protected function inflectPluginVars($vars) + { + $vars['name'] = preg_replace('/-bundle$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } + + protected function inflectThemeVars($vars) + { + $vars['name'] = preg_replace('/-theme$/', '', $vars['name']); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WHMCSInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WHMCSInstaller.php new file mode 100644 index 0000000..2cbb4a4 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WHMCSInstaller.php @@ -0,0 +1,10 @@ + 'modules/gateways/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php new file mode 100644 index 0000000..cb38788 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php @@ -0,0 +1,9 @@ + 'wolf/plugins/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php new file mode 100644 index 0000000..b03219c --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php @@ -0,0 +1,11 @@ + 'wp-content/plugins/{$name}/', + 'theme' => 'wp-content/themes/{$name}/', + 'muplugin' => 'wp-content/mu-plugins/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/YawikInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/YawikInstaller.php new file mode 100644 index 0000000..27f429f --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/YawikInstaller.php @@ -0,0 +1,32 @@ + 'module/{$name}/', + ); + + /** + * Format package name to CamelCase + * @param array $vars + * + * @return array + */ + public function inflectPackageVars($vars) + { + $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name'])); + $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']); + $vars['name'] = str_replace(' ', '', ucwords($vars['name'])); + + return $vars; + } +} \ No newline at end of file diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php new file mode 100644 index 0000000..bde9bc8 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php @@ -0,0 +1,11 @@ + 'library/{$name}/', + 'extra' => 'extras/library/{$name}/', + 'module' => 'module/{$name}/', + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php new file mode 100644 index 0000000..56cdf5d --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php @@ -0,0 +1,10 @@ + 'modules/{$vendor}-{$name}/', + 'theme' => 'themes/{$vendor}-{$name}/' + ); +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/src/bootstrap.php b/plugins/rainlab/userplus/vendor/composer/installers/src/bootstrap.php new file mode 100644 index 0000000..0de276e --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/src/bootstrap.php @@ -0,0 +1,13 @@ +installer = new AsgardInstaller( + new Package('NyanCat', '4.2', '4.2'), + new Composer() + ); + } + + /** + * @dataProvider packageNameInflectionProvider + */ + public function testInflectPackageVars($type, $name, $expected) + { + $this->assertEquals( + array('name' => $expected, 'type' => $type), + $this->installer->inflectPackageVars(array('name' => $name, 'type' => $type)) + ); + } + + public function packageNameInflectionProvider() + { + return array( + // Should keep module name StudlyCase + array( + 'asgard-module', + 'user-profile', + 'UserProfile' + ), + array( + 'asgard-module', + 'asgard-module', + 'Asgard' + ), + array( + 'asgard-module', + 'blog', + 'Blog' + ), + // tests that exactly one '-module' is cut off + array( + 'asgard-module', + 'some-module-module', + 'SomeModule', + ), + // tests that exactly one '-theme' is cut off + array( + 'asgard-theme', + 'some-theme-theme', + 'SomeTheme', + ), + // tests that names without '-theme' suffix stay valid + array( + 'asgard-theme', + 'someothertheme', + 'Someothertheme', + ), + // Should keep theme name StudlyCase + array( + 'asgard-theme', + 'adminlte-advanced', + 'AdminlteAdvanced' + ), + ); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/BitrixInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/BitrixInstallerTest.php new file mode 100644 index 0000000..e909bb4 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/BitrixInstallerTest.php @@ -0,0 +1,76 @@ +composer = new Composer(); + } + + /** + * @param string $vars + * @param string $expectedVars + * + * @covers ::inflectPackageVars + * + * @dataProvider provideExpectedInflectionResults + */ + final public function testInflectPackageVars($vars, $expectedVars) + { + + $this->installer = new BitrixInstaller( + new Package($vars['name'], '4.2', '4.2'), + $this->composer + ); + $actual = $this->installer->inflectPackageVars($vars); + $this->assertEquals($actual, $expectedVars); + } + + /** + * Provides various parameters for packages and the expected result after inflection + * + * @return array + */ + final public function provideExpectedInflectionResults() + { + return array( + //check bitrix-dir is correct + array( + array('name' => 'Nyan/Cat'), + array('name' => 'Nyan/Cat', 'bitrix_dir' => 'bitrix') + ), + array( + array('name' => 'Nyan/Cat', 'bitrix_dir' => 'bitrix'), + array('name' => 'Nyan/Cat', 'bitrix_dir' => 'bitrix') + ), + array( + array('name' => 'Nyan/Cat', 'bitrix_dir' => 'local'), + array('name' => 'Nyan/Cat', 'bitrix_dir' => 'local') + ), + ); + } +} \ No newline at end of file diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/CakePHPInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/CakePHPInstallerTest.php new file mode 100644 index 0000000..523e847 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/CakePHPInstallerTest.php @@ -0,0 +1,115 @@ +package = new Package('CamelCased', '1.0', '1.0'); + $this->io = $this->getMock('Composer\IO\PackageInterface'); + $this->composer = new Composer(); + $this->composer->setConfig(new Config(false)); + } + + /** + * testInflectPackageVars + * + * @return void + */ + public function testInflectPackageVars() + { + $installer = new CakePHPInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'CamelCased')); + $this->assertEquals($result, array('name' => 'CamelCased')); + + $installer = new CakePHPInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'with-dash')); + $this->assertEquals($result, array('name' => 'WithDash')); + + $installer = new CakePHPInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'with_underscore')); + $this->assertEquals($result, array('name' => 'WithUnderscore')); + + $installer = new CakePHPInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'cake/acl')); + $this->assertEquals($result, array('name' => 'Cake/Acl')); + + $installer = new CakePHPInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'cake/debug-kit')); + $this->assertEquals($result, array('name' => 'Cake/DebugKit')); + } + + /** + * Test getLocations returning appropriate values based on CakePHP version + * + */ + public function testGetLocations() { + $package = new RootPackage('CamelCased', '1.0', '1.0'); + $composer = $this->composer; + $rm = new RepositoryManager( + $this->getMock('Composer\IO\IOInterface'), + $this->getMock('Composer\Config') + ); + $composer->setRepositoryManager($rm); + $installer = new CakePHPInstaller($package, $composer); + + // 2.0 < cakephp < 3.0 + $this->setCakephpVersion($rm, '2.0.0'); + $result = $installer->getLocations(); + $this->assertContains('Plugin/', $result['plugin']); + + $this->setCakephpVersion($rm, '2.5.9'); + $result = $installer->getLocations(); + $this->assertContains('Plugin/', $result['plugin']); + + $this->setCakephpVersion($rm, '~2.5'); + $result = $installer->getLocations(); + $this->assertContains('Plugin/', $result['plugin']); + + // special handling for 2.x versions when 3.x is still in development + $this->setCakephpVersion($rm, 'dev-master'); + $result = $installer->getLocations(); + $this->assertContains('Plugin/', $result['plugin']); + + $this->setCakephpVersion($rm, '>=2.5'); + $result = $installer->getLocations(); + $this->assertContains('Plugin/', $result['plugin']); + + // cakephp >= 3.0 + $this->setCakephpVersion($rm, '3.0.*-dev'); + $result = $installer->getLocations(); + $this->assertContains('vendor/{$vendor}/{$name}/', $result['plugin']); + + $this->setCakephpVersion($rm, '~8.8'); + $result = $installer->getLocations(); + $this->assertContains('vendor/{$vendor}/{$name}/', $result['plugin']); + } + + protected function setCakephpVersion($rm, $version) { + $parser = new VersionParser(); + list(, $version) = explode(' ', $parser->parseConstraints($version)); + $installed = new InstalledArrayRepository(); + $package = new Package('cakephp/cakephp', $version, $version); + $installed->addPackage($package); + $rm->setLocalRepository($installed); + } + +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/CraftInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/CraftInstallerTest.php new file mode 100644 index 0000000..31ccecd --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/CraftInstallerTest.php @@ -0,0 +1,83 @@ +installer = new CraftInstaller(); + } + + /** + * @param string $packageName + * @param string $expectedName + * + * @covers ::inflectPackageVars + * + * @dataProvider provideExpectedInflectionResults + */ + final public function testInflectPackageVars($packageName, $expectedName) + { + $installer = $this->installer; + + $vars = array('name' => $packageName); + $expected = array('name' => $expectedName); + + $actual = $installer->inflectPackageVars($vars); + + $this->assertEquals($actual, $expected); + } + + /** + * Provides various names for packages and the expected result after inflection + * + * @return array + */ + final public function provideExpectedInflectionResults() + { + return array( + // lowercase + array('foo', 'foo'), + array('craftfoo', 'craftfoo'), + array('fooplugin', 'fooplugin'), + array('craftfooplugin', 'craftfooplugin'), + // lowercase - dash + array('craft-foo', 'foo'), + array('foo-plugin', 'foo'), + array('craft-foo-plugin', 'foo'), + // lowercase - underscore + array('craft_foo', 'craft_foo'), + array('foo_plugin', 'foo_plugin'), + array('craft_foo_plugin', 'craft_foo_plugin'), + // CamelCase + array('Foo', 'Foo'), + array('CraftFoo', 'CraftFoo'), + array('FooPlugin', 'FooPlugin'), + array('CraftFooPlugin', 'CraftFooPlugin'), + // CamelCase - Dash + array('Craft-Foo', 'Foo'), + array('Foo-Plugin', 'Foo'), + array('Craft-Foo-Plugin', 'Foo'), + // CamelCase - underscore + array('Craft_Foo', 'Craft_Foo'), + array('Foo_Plugin', 'Foo_Plugin'), + array('Craft_Foo_Plugin', 'Craft_Foo_Plugin'), + ); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/DokuWikiInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/DokuWikiInstallerTest.php new file mode 100644 index 0000000..9e385e6 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/DokuWikiInstallerTest.php @@ -0,0 +1,89 @@ +installer = new DokuWikiInstaller( + new Package('NyanCat', '4.2', '4.2'), + new Composer() + ); + } + + /** + * @dataProvider packageNameInflectionProvider + */ + public function testInflectPackageVars($type, $name, $expected) + { + $this->assertEquals( + $this->installer->inflectPackageVars(array('name' => $name, 'type'=>$type)), + array('name' => $expected, 'type'=>$type) + ); + } + + public function packageNameInflectionProvider() + { + return array( + array( + 'dokuwiki-plugin', + 'dokuwiki-test-plugin', + 'test', + ), + array( + 'dokuwiki-plugin', + 'test-plugin', + 'test', + ), + array( + 'dokuwiki-plugin', + 'dokuwiki_test', + 'test', + ), + array( + 'dokuwiki-plugin', + 'test', + 'test', + ), + array( + 'dokuwiki-plugin', + 'test-template', + 'test-template', + ), + array( + 'dokuwiki-template', + 'dokuwiki-test-template', + 'test', + ), + array( + 'dokuwiki-template', + 'test-template', + 'test', + ), + array( + 'dokuwiki-template', + 'dokuwiki_test', + 'test', + ), + array( + 'dokuwiki-template', + 'test', + 'test', + ), + array( + 'dokuwiki-template', + 'test-plugin', + 'test-plugin', + ), + ); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/GravInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/GravInstallerTest.php new file mode 100644 index 0000000..b757799 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/GravInstallerTest.php @@ -0,0 +1,63 @@ +composer = new Composer(); + } + + public function testInflectPackageVars() + { + $package = $this->getPackage('vendor/name', '0.0.0'); + $installer = new GravInstaller($package, $this->composer); + $packageVars = $this->getPackageVars($package); + + $result = $installer->inflectPackageVars(array_merge($packageVars, array('name' => 'test'))); + $this->assertEquals('test', $result['name']); + + foreach ($installer->getLocations() as $name => $location) { + $result = $installer->inflectPackageVars(array_merge($packageVars, array('name' => "$name-test"))); + $this->assertEquals('test', $result['name']); + $result = $installer->inflectPackageVars(array_merge($packageVars, array('name' => "test-$name"))); + $this->assertEquals('test', $result['name']); + $result = $installer->inflectPackageVars(array_merge($packageVars, array('name' => "$name-test-test"))); + $this->assertEquals('test-test', $result['name']); + $result = $installer->inflectPackageVars(array_merge($packageVars, array('name' => "test-test-$name"))); + $this->assertEquals('test-test', $result['name']); + $result = $installer->inflectPackageVars(array_merge($packageVars, array('name' => "grav-$name-test"))); + $this->assertEquals('test', $result['name']); + $result = $installer->inflectPackageVars(array_merge($packageVars, array('name' => "grav-test-$name"))); + $this->assertEquals('test', $result['name']); + $result = $installer->inflectPackageVars(array_merge($packageVars, array('name' => "grav-$name-test-test"))); + $this->assertEquals('test-test', $result['name']); + $result = $installer->inflectPackageVars(array_merge($packageVars, array('name' => "grav-test-test-$name"))); + $this->assertEquals('test-test', $result['name']); + } + } + + /** + * @param $package \Composer\Package\PackageInterface + */ + public function getPackageVars($package) + { + $type = $package->getType(); + + $prettyName = $package->getPrettyName(); + if (strpos($prettyName, '/') !== false) { + list($vendor, $name) = explode('/', $prettyName); + } else { + $vendor = ''; + $name = $prettyName; + } + + return compact('name', 'vendor', 'type'); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/InstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/InstallerTest.php new file mode 100644 index 0000000..91a303a --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/InstallerTest.php @@ -0,0 +1,512 @@ +fs = new Filesystem; + + $this->composer = new Composer(); + $this->config = new Config(); + $this->composer->setConfig($this->config); + + $this->vendorDir = realpath(sys_get_temp_dir()) . DIRECTORY_SEPARATOR . 'baton-test-vendor'; + $this->ensureDirectoryExistsAndClear($this->vendorDir); + + $this->binDir = realpath(sys_get_temp_dir()) . DIRECTORY_SEPARATOR . 'baton-test-bin'; + $this->ensureDirectoryExistsAndClear($this->binDir); + + $this->config->merge(array( + 'config' => array( + 'vendor-dir' => $this->vendorDir, + 'bin-dir' => $this->binDir, + ), + )); + + $this->dm = $this->getMockBuilder('Composer\Downloader\DownloadManager') + ->disableOriginalConstructor() + ->getMock(); + $this->composer->setDownloadManager($this->dm); + + $this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface'); + $this->io = $this->getMock('Composer\IO\IOInterface'); + } + + /** + * tearDown + * + * @return void + */ + public function tearDown() + { + $this->fs->removeDirectory($this->vendorDir); + $this->fs->removeDirectory($this->binDir); + } + + /** + * testSupports + * + * @return void + * + * @dataProvider dataForTestSupport + */ + public function testSupports($type, $expected) + { + $installer = new Installer($this->io, $this->composer); + $this->assertSame($expected, $installer->supports($type), sprintf('Failed to show support for %s', $type)); + } + + /** + * dataForTestSupport + */ + public function dataForTestSupport() + { + return array( + array('agl-module', true), + array('aimeos-extension', true), + array('annotatecms-module', true), + array('annotatecms-component', true), + array('annotatecms-service', true), + array('attogram-module', true), + array('bitrix-module', true), + array('bitrix-component', true), + array('bitrix-theme', true), + array('bonefish-package', true), + array('cakephp', false), + array('cakephp-', false), + array('cakephp-app', false), + array('cakephp-plugin', true), + array('chef-cookbook', true), + array('chef-role', true), + array('cockpit-module', true), + array('codeigniter-app', false), + array('codeigniter-library', true), + array('codeigniter-third-party', true), + array('codeigniter-module', true), + array('concrete5-block', true), + array('concrete5-package', true), + array('concrete5-theme', true), + array('concrete5-core', true), + array('concrete5-update', true), + array('craft-plugin', true), + array('croogo-plugin', true), + array('croogo-theme', true), + array('decibel-app', true), + array('dokuwiki-plugin', true), + array('dokuwiki-template', true), + array('drupal-module', true), + array('dolibarr-module', true), + array('ee3-theme', true), + array('ee3-addon', true), + array('ee2-theme', true), + array('ee2-addon', true), + array('elgg-plugin', true), + array('eliasis-module', true), + array('fuel-module', true), + array('fuel-package', true), + array('fuel-theme', true), + array('fuelphp-component', true), + array('hurad-plugin', true), + array('hurad-theme', true), + array('imagecms-template', true), + array('imagecms-module', true), + array('imagecms-library', true), + array('itop-extension', true), + array('joomla-library', true), + array('kanboard-plugin', true), + array('kirby-plugin', true), + array('kohana-module', true), + array('laravel-library', true), + array('lavalite-theme', true), + array('lavalite-package', true), + array('lithium-library', true), + array('magento-library', true), + array('mako-package', true), + array('modxevo-snippet', true), + array('modxevo-plugin', true), + array('modxevo-module', true), + array('modxevo-template', true), + array('modxevo-lib', true), + array('mediawiki-extension', true), + array('mediawiki-skin', true), + array('microweber-module', true), + array('modulework-module', true), + array('moodle-mod', true), + array('october-module', true), + array('october-plugin', true), + array('piwik-plugin', true), + array('phpbb-extension', true), + array('pimcore-plugin', true), + array('plentymarkets-plugin', true), + array('ppi-module', true), + array('prestashop-module', true), + array('prestashop-theme', true), + array('puppet-module', true), + array('porto-container', true), + array('radphp-bundle', true), + array('redaxo-addon', true), + array('redaxo-bestyle-plugin', true), + array('reindex-theme', true), + array('reindex-plugin', true), + array('roundcube-plugin', true), + array('shopware-backend-plugin', true), + array('shopware-core-plugin', true), + array('shopware-frontend-plugin', true), + array('shopware-theme', true), + array('shopware-plugin', true), + array('shopware-frontend-theme', true), + array('silverstripe-module', true), + array('silverstripe-theme', true), + array('smf-module', true), + array('smf-theme', true), + array('sydes-module', true), + array('sydes-theme', true), + array('symfony1-plugin', true), + array('thelia-module', true), + array('thelia-frontoffice-template', true), + array('thelia-backoffice-template', true), + array('thelia-email-template', true), + array('tusk-task', true), + array('tusk-asset', true), + array('typo3-flow-plugin', true), + array('typo3-cms-extension', true), + array('vanilla-plugin', true), + array('vanilla-theme', true), + array('whmcs-gateway', true), + array('wolfcms-plugin', true), + array('wordpress-plugin', true), + array('wordpress-core', false), + array('yawik-module', true), + array('zend-library', true), + array('zikula-module', true), + array('zikula-theme', true), + array('kodicms-plugin', true), + array('kodicms-media', true), + array('phifty-bundle', true), + array('phifty-library', true), + array('phifty-framework', true), + ); + } + + /** + * testInstallPath + * + * @dataProvider dataForTestInstallPath + */ + public function testInstallPath($type, $path, $name, $version = '1.0.0') + { + $installer = new Installer($this->io, $this->composer); + $package = new Package($name, $version, $version); + + $package->setType($type); + $result = $installer->getInstallPath($package); + $this->assertEquals($path, $result); + } + + /** + * dataFormTestInstallPath + */ + public function dataForTestInstallPath() + { + return array( + array('agl-module', 'More/MyTestPackage/', 'agl/my_test-package'), + array('aimeos-extension', 'ext/ai-test/', 'author/ai-test'), + array('annotatecms-module', 'addons/modules/my_module/', 'vysinsky/my_module'), + array('annotatecms-component', 'addons/components/my_component/', 'vysinsky/my_component'), + array('annotatecms-service', 'addons/services/my_service/', 'vysinsky/my_service'), + array('attogram-module', 'modules/my_module/', 'author/my_module'), + array('bitrix-module', 'bitrix/modules/my_module/', 'author/my_module'), + array('bitrix-component', 'bitrix/components/my_component/', 'author/my_component'), + array('bitrix-theme', 'bitrix/templates/my_theme/', 'author/my_theme'), + array('bitrix-d7-module', 'bitrix/modules/author.my_module/', 'author/my_module'), + array('bitrix-d7-component', 'bitrix/components/author/my_component/', 'author/my_component'), + array('bitrix-d7-template', 'bitrix/templates/author_my_template/', 'author/my_template'), + array('bonefish-package', 'Packages/bonefish/package/', 'bonefish/package'), + array('cakephp-plugin', 'Plugin/Ftp/', 'shama/ftp'), + array('chef-cookbook', 'Chef/mre/my_cookbook/', 'mre/my_cookbook'), + array('chef-role', 'Chef/roles/my_role/', 'mre/my_role'), + array('cockpit-module', 'cockpit/modules/addons/My_module/', 'piotr-cz/cockpit-my_module'), + array('codeigniter-library', 'application/libraries/my_package/', 'shama/my_package'), + array('codeigniter-module', 'application/modules/my_package/', 'shama/my_package'), + array('concrete5-block', 'application/blocks/concrete5_block/', 'remo/concrete5_block'), + array('concrete5-package', 'packages/concrete5_package/', 'remo/concrete5_package'), + array('concrete5-theme', 'application/themes/concrete5_theme/', 'remo/concrete5_theme'), + array('concrete5-core', 'concrete/', 'concrete5/core'), + array('concrete5-update', 'updates/concrete5/', 'concrete5/concrete5'), + array('craft-plugin', 'craft/plugins/my_plugin/', 'mdcpepper/my_plugin'), + array('croogo-plugin', 'Plugin/Sitemaps/', 'fahad19/sitemaps'), + array('croogo-theme', 'View/Themed/Readable/', 'rchavik/readable'), + array('decibel-app', 'app/someapp/', 'author/someapp'), + array('dokuwiki-plugin', 'lib/plugins/someplugin/', 'author/someplugin'), + array('dokuwiki-template', 'lib/tpl/sometemplate/', 'author/sometemplate'), + array('dolibarr-module', 'htdocs/custom/my_module/', 'shama/my_module'), + array('drupal-module', 'modules/my_module/', 'shama/my_module'), + array('drupal-theme', 'themes/my_module/', 'shama/my_module'), + array('drupal-profile', 'profiles/my_module/', 'shama/my_module'), + array('drupal-drush', 'drush/my_module/', 'shama/my_module'), + array('elgg-plugin', 'mod/sample_plugin/', 'test/sample_plugin'), + array('eliasis-module', 'modules/my_module/', 'shama/my_module'), + array('ee3-addon', 'system/user/addons/ee_theme/', 'author/ee_theme'), + array('ee3-theme', 'themes/user/ee_package/', 'author/ee_package'), + array('ee2-addon', 'system/expressionengine/third_party/ee_theme/', 'author/ee_theme'), + array('ee2-theme', 'themes/third_party/ee_package/', 'author/ee_package'), + array('fuel-module', 'fuel/app/modules/module/', 'fuel/module'), + array('fuel-package', 'fuel/packages/orm/', 'fuel/orm'), + array('fuel-theme', 'fuel/app/themes/theme/', 'fuel/theme'), + array('fuelphp-component', 'components/demo/', 'fuelphp/demo'), + array('hurad-plugin', 'plugins/Akismet/', 'atkrad/akismet'), + array('hurad-theme', 'plugins/Hurad2013/', 'atkrad/Hurad2013'), + array('imagecms-template', 'templates/my_template/', 'shama/my_template'), + array('imagecms-module', 'application/modules/my_module/', 'shama/my_module'), + array('imagecms-library', 'application/libraries/my_library/', 'shama/my_library'), + array('itop-extension', 'extensions/my_extension/', 'shama/my_extension'), + array('joomla-plugin', 'plugins/my_plugin/', 'shama/my_plugin'), + array('kanboard-plugin', 'plugins/my_plugin/', 'shama/my_plugin'), + array('kirby-plugin', 'site/plugins/my_plugin/', 'shama/my_plugin'), + array('kohana-module', 'modules/my_package/', 'shama/my_package'), + array('laravel-library', 'libraries/my_package/', 'shama/my_package'), + array('lavalite-theme', 'public/themes/my_theme/', 'shama/my_theme'), + array('lavalite-package', 'packages/my_package/', 'shama/my_package'), + array('lithium-library', 'libraries/li3_test/', 'user/li3_test'), + array('magento-library', 'lib/foo/', 'test/foo'), + array('modxevo-snippet', 'assets/snippets/my_snippet/', 'shama/my_snippet'), + array('modxevo-plugin', 'assets/plugins/my_plugin/', 'shama/my_plugin'), + array('modxevo-module', 'assets/modules/my_module/', 'shama/my_module'), + array('modxevo-template', 'assets/templates/my_template/', 'shama/my_template'), + array('modxevo-lib', 'assets/lib/my_lib/', 'shama/my_lib'), + array('mako-package', 'app/packages/my_package/', 'shama/my_package'), + array('mediawiki-extension', 'extensions/APC/', 'author/APC'), + array('mediawiki-extension', 'extensions/APC/', 'author/APC-extension'), + array('mediawiki-extension', 'extensions/UploadWizard/', 'author/upload-wizard'), + array('mediawiki-extension', 'extensions/SyntaxHighlight_GeSHi/', 'author/syntax-highlight_GeSHi'), + array('mediawiki-skin', 'skins/someskin/', 'author/someskin-skin'), + array('mediawiki-skin', 'skins/someskin/', 'author/someskin'), + array('microweber-module', 'userfiles/modules/my-thing/', 'author/my-thing-module'), + array('modulework-module', 'modules/my_package/', 'shama/my_package'), + array('moodle-mod', 'mod/my_package/', 'shama/my_package'), + array('october-module', 'modules/my_plugin/', 'shama/my_plugin'), + array('october-plugin', 'plugins/shama/my_plugin/', 'shama/my_plugin'), + array('october-theme', 'themes/my_theme/', 'shama/my_theme'), + array('piwik-plugin', 'plugins/VisitSummary/', 'shama/visit-summary'), + array('prestashop-module', 'modules/a-module/', 'vendor/a-module'), + array('prestashop-theme', 'themes/a-theme/', 'vendor/a-theme'), + array('phpbb-extension', 'ext/test/foo/', 'test/foo'), + array('phpbb-style', 'styles/foo/', 'test/foo'), + array('phpbb-language', 'language/foo/', 'test/foo'), + array('pimcore-plugin', 'plugins/MyPlugin/', 'ubikz/my_plugin'), + array('plentymarkets-plugin', 'HelloWorld/', 'plugin-hello-world'), + array('ppi-module', 'modules/foo/', 'test/foo'), + array('puppet-module', 'modules/puppet-name/', 'puppet/puppet-name'), + array('porto-container', 'app/Containers/container-name/', 'test/container-name'), + array('radphp-bundle', 'src/Migration/', 'atkrad/migration'), + array('redaxo-addon', 'redaxo/include/addons/my_plugin/', 'shama/my_plugin'), + array('redaxo-bestyle-plugin', 'redaxo/include/addons/be_style/plugins/my_plugin/', 'shama/my_plugin'), + array('reindex-theme', 'themes/my_module/', 'author/my_module'), + array('reindex-plugin', 'plugins/my_module/', 'author/my_module'), + array('roundcube-plugin', 'plugins/base/', 'test/base'), + array('roundcube-plugin', 'plugins/replace_dash/', 'test/replace-dash'), + array('shopware-backend-plugin', 'engine/Shopware/Plugins/Local/Backend/ShamaMyBackendPlugin/', 'shama/my-backend-plugin'), + array('shopware-core-plugin', 'engine/Shopware/Plugins/Local/Core/ShamaMyCorePlugin/', 'shama/my-core-plugin'), + array('shopware-frontend-plugin', 'engine/Shopware/Plugins/Local/Frontend/ShamaMyFrontendPlugin/', 'shama/my-frontend-plugin'), + array('shopware-theme', 'templates/my_theme/', 'shama/my-theme'), + array('shopware-frontend-theme', 'themes/Frontend/ShamaMyFrontendTheme/', 'shama/my-frontend-theme'), + array('shopware-plugin', 'custom/plugins/ShamaMyPlugin/', 'shama/my-plugin'), + array('silverstripe-module', 'my_module/', 'shama/my_module'), + array('silverstripe-module', 'sapphire/', 'silverstripe/framework', '2.4.0'), + array('silverstripe-module', 'framework/', 'silverstripe/framework', '3.0.0'), + array('silverstripe-module', 'framework/', 'silverstripe/framework', '3.0.0-rc1'), + array('silverstripe-module', 'framework/', 'silverstripe/framework', 'my/branch'), + array('silverstripe-theme', 'themes/my_theme/', 'shama/my_theme'), + array('smf-module', 'Sources/my_module/', 'shama/my_module'), + array('smf-theme', 'Themes/my_theme/', 'shama/my_theme'), + array('symfony1-plugin', 'plugins/sfShamaPlugin/', 'shama/sfShamaPlugin'), + array('symfony1-plugin', 'plugins/sfShamaPlugin/', 'shama/sf-shama-plugin'), + array('thelia-module', 'local/modules/my_module/', 'shama/my_module'), + array('thelia-frontoffice-template', 'templates/frontOffice/my_template_fo/', 'shama/my_template_fo'), + array('thelia-backoffice-template', 'templates/backOffice/my_template_bo/', 'shama/my_template_bo'), + array('thelia-email-template', 'templates/email/my_template_email/', 'shama/my_template_email'), + array('tusk-task', '.tusk/tasks/my_task/', 'shama/my_task'), + array('typo3-flow-package', 'Packages/Application/my_package/', 'shama/my_package'), + array('typo3-flow-build', 'Build/my_package/', 'shama/my_package'), + array('typo3-cms-extension', 'typo3conf/ext/my_extension/', 'shama/my_extension'), + array('vanilla-plugin', 'plugins/my_plugin/', 'shama/my_plugin'), + array('vanilla-theme', 'themes/my_theme/', 'shama/my_theme'), + array('whmcs-gateway', 'modules/gateways/gateway_name/', 'vendor/gateway_name'), + array('wolfcms-plugin', 'wolf/plugins/my_plugin/', 'shama/my_plugin'), + array('wordpress-plugin', 'wp-content/plugins/my_plugin/', 'shama/my_plugin'), + array('wordpress-muplugin', 'wp-content/mu-plugins/my_plugin/', 'shama/my_plugin'), + array('zend-extra', 'extras/library/zend_test/', 'shama/zend_test'), + array('zikula-module', 'modules/my-test_module/', 'my/test_module'), + array('zikula-theme', 'themes/my-test_theme/', 'my/test_theme'), + array('kodicms-media', 'cms/media/vendor/my_media/', 'shama/my_media'), + array('kodicms-plugin', 'cms/plugins/my_plugin/', 'shama/my_plugin'), + array('phifty-bundle', 'bundles/core/', 'shama/core'), + array('phifty-library', 'libraries/my-lib/', 'shama/my-lib'), + array('phifty-framework', 'frameworks/my-framework/', 'shama/my-framework'), + array('yawik-module', 'module/MyModule/', 'shama/my_module'), + ); + } + + /** + * testGetCakePHPInstallPathException + * + * @return void + * + * @expectedException \InvalidArgumentException + */ + public function testGetCakePHPInstallPathException() + { + $installer = new Installer($this->io, $this->composer); + $package = new Package('shama/ftp', '1.0.0', '1.0.0'); + + $package->setType('cakephp-whoops'); + $result = $installer->getInstallPath($package); + } + + /** + * testCustomInstallPath + */ + public function testCustomInstallPath() + { + $installer = new Installer($this->io, $this->composer); + $package = new Package('shama/ftp', '1.0.0', '1.0.0'); + $package->setType('cakephp-plugin'); + $consumerPackage = new RootPackage('foo/bar', '1.0.0', '1.0.0'); + $this->composer->setPackage($consumerPackage); + $consumerPackage->setExtra(array( + 'installer-paths' => array( + 'my/custom/path/{$name}/' => array( + 'shama/ftp', + 'foo/bar', + ), + ), + )); + $result = $installer->getInstallPath($package); + $this->assertEquals('my/custom/path/Ftp/', $result); + } + + /** + * testCustomInstallerName + */ + public function testCustomInstallerName() + { + $installer = new Installer($this->io, $this->composer); + $package = new Package('shama/cakephp-ftp-plugin', '1.0.0', '1.0.0'); + $package->setType('cakephp-plugin'); + $package->setExtra(array( + 'installer-name' => 'FTP', + )); + $result = $installer->getInstallPath($package); + $this->assertEquals('Plugin/FTP/', $result); + } + + /** + * testCustomTypePath + */ + public function testCustomTypePath() + { + $installer = new Installer($this->io, $this->composer); + $package = new Package('slbmeh/my_plugin', '1.0.0', '1.0.0'); + $package->setType('wordpress-plugin'); + $consumerPackage = new RootPackage('foo/bar', '1.0.0', '1.0.0'); + $this->composer->setPackage($consumerPackage); + $consumerPackage->setExtra(array( + 'installer-paths' => array( + 'my/custom/path/{$name}/' => array( + 'type:wordpress-plugin' + ), + ), + )); + $result = $installer->getInstallPath($package); + $this->assertEquals('my/custom/path/my_plugin/', $result); + } + + /** + * testVendorPath + */ + public function testVendorPath() + { + $installer = new Installer($this->io, $this->composer); + $package = new Package('penyaskito/my_module', '1.0.0', '1.0.0'); + $package->setType('drupal-module'); + $consumerPackage = new RootPackage('drupal/drupal', '1.0.0', '1.0.0'); + $this->composer->setPackage($consumerPackage); + $consumerPackage->setExtra(array( + 'installer-paths' => array( + 'modules/custom/{$name}/' => array( + 'vendor:penyaskito' + ), + ), + )); + $result = $installer->getInstallPath($package); + $this->assertEquals('modules/custom/my_module/', $result); + } + + /** + * testNoVendorName + */ + public function testNoVendorName() + { + $installer = new Installer($this->io, $this->composer); + $package = new Package('sfPhpunitPlugin', '1.0.0', '1.0.0'); + + $package->setType('symfony1-plugin'); + $result = $installer->getInstallPath($package); + $this->assertEquals('plugins/sfPhpunitPlugin/', $result); + } + + /** + * testTypo3Inflection + */ + public function testTypo3Inflection() + { + $installer = new Installer($this->io, $this->composer); + $package = new Package('typo3/fluid', '1.0.0', '1.0.0'); + + $package->setAutoload(array( + 'psr-0' => array( + 'TYPO3\\Fluid' => 'Classes', + ), + )); + + $package->setType('typo3-flow-package'); + $result = $installer->getInstallPath($package); + $this->assertEquals('Packages/Application/TYPO3.Fluid/', $result); + } + + public function testUninstallAndDeletePackageFromLocalRepo() + { + $package = new Package('foo', '1.0.0', '1.0.0'); + + $installer = $this->getMock('Composer\Installers\Installer', array('getInstallPath'), array($this->io, $this->composer)); + $installer->expects($this->once())->method('getInstallPath')->with($package)->will($this->returnValue(sys_get_temp_dir().'/foo')); + + $repo = $this->getMock('Composer\Repository\InstalledRepositoryInterface'); + $repo->expects($this->once())->method('hasPackage')->with($package)->will($this->returnValue(true)); + $repo->expects($this->once())->method('removePackage')->with($package); + + $installer->uninstall($repo, $package); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/MayaInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/MayaInstallerTest.php new file mode 100644 index 0000000..f800c61 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/MayaInstallerTest.php @@ -0,0 +1,61 @@ +installer = new MayaInstaller( + new Package('NyanCat', '4.2', '4.2'), + new Composer() + ); + } + + /** + * @dataProvider packageNameInflectionProvider + */ + public function testInflectPackageVars($type, $name, $expected) + { + $this->assertEquals( + array('name' => $expected, 'type' => $type), + $this->installer->inflectPackageVars(array('name' => $name, 'type' => $type)) + ); + } + + public function packageNameInflectionProvider() + { + return array( + // Should keep module name StudlyCase + array( + 'maya-module', + 'user-profile', + 'UserProfile' + ), + array( + 'maya-module', + 'maya-module', + 'Maya' + ), + array( + 'maya-module', + 'blog', + 'Blog' + ), + // tests that exactly one '-module' is cut off + array( + 'maya-module', + 'some-module-module', + 'SomeModule', + ), + ); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/MediaWikiInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/MediaWikiInstallerTest.php new file mode 100644 index 0000000..3675e18 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/MediaWikiInstallerTest.php @@ -0,0 +1,66 @@ +installer = new MediaWikiInstaller( + new Package('NyanCat', '4.2', '4.2'), + new Composer() + ); + } + + /** + * @dataProvider packageNameInflectionProvider + */ + public function testInflectPackageVars($type, $name, $expected) + { + $this->assertEquals( + $this->installer->inflectPackageVars(array('name' => $name, 'type'=>$type)), + array('name' => $expected, 'type'=>$type) + ); + } + + public function packageNameInflectionProvider() + { + return array( + array( + 'mediawiki-extension', + 'sub-page-list', + 'SubPageList', + ), + array( + 'mediawiki-extension', + 'sub-page-list-extension', + 'SubPageList', + ), + array( + 'mediawiki-extension', + 'semantic-mediawiki', + 'SemanticMediawiki', + ), + // tests that exactly one '-skin' is cut off, and that skins do not get ucwords treatment like extensions + array( + 'mediawiki-skin', + 'some-skin-skin', + 'some-skin', + ), + // tests that names without '-skin' suffix stay valid + array( + 'mediawiki-skin', + 'someotherskin', + 'someotherskin', + ), + ); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/OctoberInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/OctoberInstallerTest.php new file mode 100644 index 0000000..fd427cd --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/OctoberInstallerTest.php @@ -0,0 +1,66 @@ +installer = new OctoberInstaller( + new Package('NyanCat', '4.2', '4.2'), + new Composer() + ); + } + + /** + * @dataProvider packageNameInflectionProvider + */ + public function testInflectPackageVars($type, $name, $expected) + { + $this->assertEquals( + $this->installer->inflectPackageVars(array('name' => $name, 'type' => $type)), + array('name' => $expected, 'type' => $type) + ); + } + + public function packageNameInflectionProvider() + { + return array( + array( + 'october-plugin', + 'subpagelist', + 'subpagelist', + ), + array( + 'october-plugin', + 'subpagelist-plugin', + 'subpagelist', + ), + array( + 'october-plugin', + 'semanticoctober', + 'semanticoctober', + ), + // tests that exactly one '-theme' is cut off + array( + 'october-theme', + 'some-theme-theme', + 'some-theme', + ), + // tests that names without '-theme' suffix stay valid + array( + 'october-theme', + 'someothertheme', + 'someothertheme', + ), + ); + } +} \ No newline at end of file diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/OntoWikiInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/OntoWikiInstallerTest.php new file mode 100644 index 0000000..24c498c --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/OntoWikiInstallerTest.php @@ -0,0 +1,85 @@ +installer = new OntoWikiInstaller(); + } + + /** + * @dataProvider packageNameInflectionProvider + */ + public function testInflectPackageVars($type, $name, $expected) + { + $this->assertEquals( + $this->installer->inflectPackageVars(array('name' => $name, 'type'=>$type)), + array('name' => $expected, 'type'=>$type) + ); + } + + public function packageNameInflectionProvider() + { + return array( + array( + 'ontowiki-extension', + 'CSVImport.ontowiki', + 'csvimport', + ), + array( + 'ontowiki-extension', + 'csvimport', + 'csvimport', + ), + array( + 'ontowiki-extension', + 'some_ontowiki_extension', + 'some_ontowiki_extension', + ), + array( + 'ontowiki-extension', + 'some_ontowiki_extension.ontowiki', + 'some_ontowiki_extension', + ), + array( + 'ontowiki-translation', + 'de-translation.ontowiki', + 'de', + ), + array( + 'ontowiki-translation', + 'en-US-translation.ontowiki', + 'en-us', + ), + array( + 'ontowiki-translation', + 'en-US-translation', + 'en-us', + ), + array( + 'ontowiki-theme', + 'blue-theme.ontowiki', + 'blue', + ), + array( + 'ontowiki-theme', + 'blue-theme', + 'blue', + ), + ); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/PimcoreInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/PimcoreInstallerTest.php new file mode 100644 index 0000000..ea79374 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/PimcoreInstallerTest.php @@ -0,0 +1,44 @@ +package = new Package('CamelCased', '1.0', '1.0'); + $this->io = $this->getMock('Composer\IO\PackageInterface'); + $this->composer = new Composer(); + } + + /** + * testInflectPackageVars + * + * @return void + */ + public function testInflectPackageVars() + { + $installer = new PimcoreInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'CamelCased')); + $this->assertEquals($result, array('name' => 'CamelCased')); + + $installer = new PimcoreInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'with-dash')); + $this->assertEquals($result, array('name' => 'WithDash')); + + $installer = new PimcoreInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'with_underscore')); + $this->assertEquals($result, array('name' => 'WithUnderscore')); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/PiwikInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/PiwikInstallerTest.php new file mode 100644 index 0000000..8d9ff3f --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/PiwikInstallerTest.php @@ -0,0 +1,63 @@ +package = new Package('VisitSummary', '1.0', '1.0'); + $this->io = $this->getMock('Composer\IO\PackageInterface'); + $this->composer = new Composer(); + } + + /** + * testInflectPackageVars + * + * @return void + */ + public function testInflectPackageVars() + { + $installer = new PiwikInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'VisitSummary')); + $this->assertEquals($result, array('name' => 'VisitSummary')); + + $installer = new PiwikInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'visit-summary')); + $this->assertEquals($result, array('name' => 'VisitSummary')); + + $installer = new PiwikInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => 'visit_summary')); + $this->assertEquals($result, array('name' => 'VisitSummary')); + } + +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/SyDESInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/SyDESInstallerTest.php new file mode 100644 index 0000000..1521fbf --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/SyDESInstallerTest.php @@ -0,0 +1,81 @@ +installer = new SyDESInstaller( + new Package('NyanCat', '4.2', '4.2'), + new Composer() + ); + } + + /** + * @dataProvider packageNameInflectionProvider + */ + public function testInflectPackageVars($type, $name, $expected) + { + $this->assertEquals( + array('name' => $expected, 'type' => $type), + $this->installer->inflectPackageVars(array('name' => $name, 'type' => $type)) + ); + } + + public function packageNameInflectionProvider() + { + return array( + // modules + array( + 'sydes-module', + 'name', + 'Name' + ), + array( + 'sydes-module', + 'sample-name', + 'SampleName' + ), + array( + 'sydes-module', + 'sydes-name', + 'Name' + ), + array( + 'sydes-module', + 'sample-name-module', + 'SampleName', + ), + array( + 'sydes-module', + 'sydes-sample-name-module', + 'SampleName' + ), + // themes + array( + 'sydes-theme', + 'some-theme-theme', + 'some-theme', + ), + array( + 'sydes-theme', + 'sydes-sometheme', + 'sometheme', + ), + array( + 'sydes-theme', + 'Sample-Name', + 'sample-name' + ), + ); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/TestCase.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/TestCase.php new file mode 100644 index 0000000..6418a03 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/TestCase.php @@ -0,0 +1,64 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Installers\Test; + +use Composer\Package\Version\VersionParser; +use Composer\Package\Package; +use Composer\Package\AliasPackage; +use Composer\Package\LinkConstraint\VersionConstraint; +use Composer\Util\Filesystem; + +abstract class TestCase extends \PHPUnit_Framework_TestCase +{ + private static $parser; + + protected static function getVersionParser() + { + if (!self::$parser) { + self::$parser = new VersionParser(); + } + + return self::$parser; + } + + protected function getVersionConstraint($operator, $version) + { + return new VersionConstraint( + $operator, + self::getVersionParser()->normalize($version) + ); + } + + protected function getPackage($name, $version) + { + $normVersion = self::getVersionParser()->normalize($version); + + return new Package($name, $normVersion, $version); + } + + protected function getAliasPackage($package, $version) + { + $normVersion = self::getVersionParser()->normalize($version); + + return new AliasPackage($package, $normVersion, $version); + } + + protected function ensureDirectoryExistsAndClear($directory) + { + $fs = new Filesystem(); + if (is_dir($directory)) { + $fs->removeDirectory($directory); + } + mkdir($directory, 0777, true); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/VgmcpInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/VgmcpInstallerTest.php new file mode 100644 index 0000000..8b33ab8 --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/VgmcpInstallerTest.php @@ -0,0 +1,79 @@ +installer = new VgmcpInstaller( + new Package('NyanCat', '4.2', '4.2'), + new Composer() + ); + } + + /** + * @dataProvider packageNameInflectionProvider + */ + public function testInflectPackageVars($type, $name, $expected) + { + $this->assertEquals( + array('name' => $expected, 'type' => $type), + $this->installer->inflectPackageVars(array('name' => $name, 'type' => $type)) + ); + } + + public function packageNameInflectionProvider() + { + return array( + // Should keep bundle name StudlyCase + array( + 'vgmcp-bundle', + 'user-profile', + 'UserProfile' + ), + array( + 'vgmcp-bundle', + 'vgmcp-bundle', + 'Vgmcp' + ), + array( + 'vgmcp-bundle', + 'blog', + 'Blog' + ), + // tests that exactly one '-bundle' is cut off + array( + 'vgmcp-bundle', + 'some-bundle-bundle', + 'SomeBundle', + ), + // tests that exactly one '-theme' is cut off + array( + 'vgmcp-theme', + 'some-theme-theme', + 'SomeTheme', + ), + // tests that names without '-theme' suffix stay valid + array( + 'vgmcp-theme', + 'someothertheme', + 'Someothertheme', + ), + // Should keep theme name StudlyCase + array( + 'vgmcp-theme', + 'adminlte-advanced', + 'AdminlteAdvanced' + ), + ); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/YawikInstallerTest.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/YawikInstallerTest.php new file mode 100644 index 0000000..d8d35ff --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/Composer/Installers/Test/YawikInstallerTest.php @@ -0,0 +1,64 @@ +package = new Package('YawikCompanyRegistration', '1.0', '1.0'); + $this->io = $this->getMock('Composer\IO\PackageInterface'); + $this->composer = new Composer(); + } + + /** + * testInflectPackageVars + * + * @dataProvider packageNameProvider + * @return void + */ + public function testInflectPackageVars($input) + { + $installer = new YawikInstaller($this->package, $this->composer); + $result = $installer->inflectPackageVars(array('name' => $input)); + $this->assertEquals($result, array('name' => 'YawikCompanyRegistration')); + } + + public function packageNameProvider() + { + return array( + array('yawik-company-registration'), + array('yawik_company_registration'), + array('YawikCompanyRegistration') + ); + } +} diff --git a/plugins/rainlab/userplus/vendor/composer/installers/tests/bootstrap.php b/plugins/rainlab/userplus/vendor/composer/installers/tests/bootstrap.php new file mode 100644 index 0000000..30c8fdc --- /dev/null +++ b/plugins/rainlab/userplus/vendor/composer/installers/tests/bootstrap.php @@ -0,0 +1,4 @@ +add('Composer\Installers\Test', __DIR__); diff --git a/plugins/tps/birzha/classes/ProductResource.php b/plugins/tps/birzha/classes/ProductResource.php index 6b4768f..7d6a45b 100644 --- a/plugins/tps/birzha/classes/ProductResource.php +++ b/plugins/tps/birzha/classes/ProductResource.php @@ -18,21 +18,14 @@ class ProductResource extends JsonResource 'id' => $this->id, 'name_ru' => $this->getAttributeTranslated('name', 'ru'), 'name_en' => $this->getAttributeTranslated('name', 'en'), - 'name_tm' => $this->getAttributeTranslated('name', 'tm'), 'category_id' => $this->categories()->first()->id, 'productForEditing' => $this->id, 'quantity' => $this->quantity, 'price' => $this->price, 'place' => $this->place, 'description_tm' => $this->getAttributeTranslated('description', 'tm'), - 'description_en' => $this->getAttributeTranslated('description', 'en'), 'description_ru' => $this->getAttributeTranslated('description', 'ru'), - 'payment_term_id' => $this->payment_term ? $this->payment_term->id : null, - 'packaging' => $this->packaging, - 'delivery_term_id' => $this->delivery_term ? $this->delivery_term->id : null, - 'currency_id' => $this->currency ? $this->currency->id : null, - 'measure_id' => $this->measure ? $this->measure->id : null, - 'old_img' => ImageResource::collection($this->images) + ]; } } \ No newline at end of file diff --git a/plugins/tps/birzha/controllers/City.php b/plugins/tps/birzha/controllers/City.php new file mode 100644 index 0000000..fc1bd47 --- /dev/null +++ b/plugins/tps/birzha/controllers/City.php @@ -0,0 +1,18 @@ + + + + diff --git a/plugins/tps/birzha/controllers/city/config_form.yaml b/plugins/tps/birzha/controllers/city/config_form.yaml new file mode 100644 index 0000000..15a7ca2 --- /dev/null +++ b/plugins/tps/birzha/controllers/city/config_form.yaml @@ -0,0 +1,10 @@ +name: City +form: $/tps/birzha/models/city/fields.yaml +modelClass: TPS\Birzha\Models\City +defaultRedirect: tps/birzha/city +create: + redirect: 'tps/birzha/city/update/:id' + redirectClose: tps/birzha/city +update: + redirect: tps/birzha/city + redirectClose: tps/birzha/city diff --git a/plugins/tps/birzha/controllers/city/config_list.yaml b/plugins/tps/birzha/controllers/city/config_list.yaml new file mode 100644 index 0000000..7cd2d6b --- /dev/null +++ b/plugins/tps/birzha/controllers/city/config_list.yaml @@ -0,0 +1,12 @@ +list: $/tps/birzha/models/city/columns.yaml +modelClass: TPS\Birzha\Models\City +title: City +noRecordsMessage: 'backend::lang.list.no_records' +showSetup: true +showCheckboxes: true +recordsPerPage: 20 +toolbar: + buttons: list_toolbar + search: + prompt: 'backend::lang.list.search_prompt' +recordUrl: 'tps/birzha/city/update/:id' diff --git a/plugins/tps/birzha/controllers/city/create.htm b/plugins/tps/birzha/controllers/city/create.htm new file mode 100644 index 0000000..45b11d5 --- /dev/null +++ b/plugins/tps/birzha/controllers/city/create.htm @@ -0,0 +1,46 @@ + +
      +
    • City
    • +
    • pageTitle) ?>
    • +
    + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + +
    +
    + + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/tps/birzha/controllers/city/index.htm b/plugins/tps/birzha/controllers/city/index.htm new file mode 100644 index 0000000..ea43a36 --- /dev/null +++ b/plugins/tps/birzha/controllers/city/index.htm @@ -0,0 +1 @@ +listRender() ?> diff --git a/plugins/tps/birzha/controllers/city/preview.htm b/plugins/tps/birzha/controllers/city/preview.htm new file mode 100644 index 0000000..905b12f --- /dev/null +++ b/plugins/tps/birzha/controllers/city/preview.htm @@ -0,0 +1,22 @@ + +
      +
    • City
    • +
    • pageTitle) ?>
    • +
    + + +fatalError): ?> + +
    + formRenderPreview() ?> +
    + + +

    fatalError) ?>

    + + +

    + + + +

    \ No newline at end of file diff --git a/plugins/tps/birzha/controllers/city/update.htm b/plugins/tps/birzha/controllers/city/update.htm new file mode 100644 index 0000000..d30bfba --- /dev/null +++ b/plugins/tps/birzha/controllers/city/update.htm @@ -0,0 +1,54 @@ + +
      +
    • City
    • +
    • pageTitle) ?>
    • +
    + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + + + +
    +
    + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/tps/birzha/controllers/comment/_list_toolbar.htm b/plugins/tps/birzha/controllers/comment/_list_toolbar.htm new file mode 100644 index 0000000..f7d8c5b --- /dev/null +++ b/plugins/tps/birzha/controllers/comment/_list_toolbar.htm @@ -0,0 +1,18 @@ +
    + + +
    diff --git a/plugins/tps/birzha/controllers/comment/config_form.yaml b/plugins/tps/birzha/controllers/comment/config_form.yaml new file mode 100644 index 0000000..5fc9716 --- /dev/null +++ b/plugins/tps/birzha/controllers/comment/config_form.yaml @@ -0,0 +1,10 @@ +name: Comment +form: $/tps/birzha/models/comment/fields.yaml +modelClass: TPS\Birzha\Models\Comment +defaultRedirect: tps/birzha/comment +create: + redirect: 'tps/birzha/comment/update/:id' + redirectClose: tps/birzha/comment +update: + redirect: tps/birzha/comment + redirectClose: tps/birzha/comment diff --git a/plugins/tps/birzha/controllers/comment/config_list.yaml b/plugins/tps/birzha/controllers/comment/config_list.yaml new file mode 100644 index 0000000..8af8954 --- /dev/null +++ b/plugins/tps/birzha/controllers/comment/config_list.yaml @@ -0,0 +1,12 @@ +list: $/tps/birzha/models/comment/columns.yaml +modelClass: TPS\Birzha\Models\Comment +title: Comment +noRecordsMessage: 'backend::lang.list.no_records' +showSetup: true +showCheckboxes: true +recordsPerPage: 20 +toolbar: + buttons: list_toolbar + search: + prompt: 'backend::lang.list.search_prompt' +recordUrl: 'tps/birzha/comment/update/:id' diff --git a/plugins/tps/birzha/controllers/comment/create.htm b/plugins/tps/birzha/controllers/comment/create.htm new file mode 100644 index 0000000..c54b7b8 --- /dev/null +++ b/plugins/tps/birzha/controllers/comment/create.htm @@ -0,0 +1,46 @@ + + + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + +
    +
    + + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/tps/birzha/controllers/comment/index.htm b/plugins/tps/birzha/controllers/comment/index.htm new file mode 100644 index 0000000..ea43a36 --- /dev/null +++ b/plugins/tps/birzha/controllers/comment/index.htm @@ -0,0 +1 @@ +listRender() ?> diff --git a/plugins/tps/birzha/controllers/comment/preview.htm b/plugins/tps/birzha/controllers/comment/preview.htm new file mode 100644 index 0000000..50a84bb --- /dev/null +++ b/plugins/tps/birzha/controllers/comment/preview.htm @@ -0,0 +1,22 @@ + + + + +fatalError): ?> + +
    + formRenderPreview() ?> +
    + + +

    fatalError) ?>

    + + +

    + + + +

    \ No newline at end of file diff --git a/plugins/tps/birzha/controllers/comment/update.htm b/plugins/tps/birzha/controllers/comment/update.htm new file mode 100644 index 0000000..edc865b --- /dev/null +++ b/plugins/tps/birzha/controllers/comment/update.htm @@ -0,0 +1,54 @@ + + + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + + + +
    +
    + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/tps/birzha/controllers/favourites/_list_toolbar.htm b/plugins/tps/birzha/controllers/favourites/_list_toolbar.htm new file mode 100644 index 0000000..643f97a --- /dev/null +++ b/plugins/tps/birzha/controllers/favourites/_list_toolbar.htm @@ -0,0 +1,18 @@ +
    + + +
    diff --git a/plugins/tps/birzha/controllers/favourites/config_form.yaml b/plugins/tps/birzha/controllers/favourites/config_form.yaml new file mode 100644 index 0000000..ca5403d --- /dev/null +++ b/plugins/tps/birzha/controllers/favourites/config_form.yaml @@ -0,0 +1,10 @@ +name: Favourites +form: $/tps/birzha/models/favourites/fields.yaml +modelClass: TPS\Birzha\Models\Favourites +defaultRedirect: tps/birzha/favourites +create: + redirect: 'tps/birzha/favourites/update/:id' + redirectClose: tps/birzha/favourites +update: + redirect: tps/birzha/favourites + redirectClose: tps/birzha/favourites diff --git a/plugins/tps/birzha/controllers/favourites/config_list.yaml b/plugins/tps/birzha/controllers/favourites/config_list.yaml new file mode 100644 index 0000000..2c099a1 --- /dev/null +++ b/plugins/tps/birzha/controllers/favourites/config_list.yaml @@ -0,0 +1,12 @@ +list: $/tps/birzha/models/favourites/columns.yaml +modelClass: TPS\Birzha\Models\Favourites +title: Favourites +noRecordsMessage: 'backend::lang.list.no_records' +showSetup: true +showCheckboxes: true +recordsPerPage: 20 +toolbar: + buttons: list_toolbar + search: + prompt: 'backend::lang.list.search_prompt' +recordUrl: 'tps/birzha/favourites/update/:id' diff --git a/plugins/tps/birzha/controllers/favourites/create.htm b/plugins/tps/birzha/controllers/favourites/create.htm new file mode 100644 index 0000000..7695062 --- /dev/null +++ b/plugins/tps/birzha/controllers/favourites/create.htm @@ -0,0 +1,46 @@ + + + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + +
    +
    + + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/tps/birzha/controllers/favourites/index.htm b/plugins/tps/birzha/controllers/favourites/index.htm new file mode 100644 index 0000000..ea43a36 --- /dev/null +++ b/plugins/tps/birzha/controllers/favourites/index.htm @@ -0,0 +1 @@ +listRender() ?> diff --git a/plugins/tps/birzha/controllers/favourites/preview.htm b/plugins/tps/birzha/controllers/favourites/preview.htm new file mode 100644 index 0000000..47b0d65 --- /dev/null +++ b/plugins/tps/birzha/controllers/favourites/preview.htm @@ -0,0 +1,22 @@ + + + + +fatalError): ?> + +
    + formRenderPreview() ?> +
    + + +

    fatalError) ?>

    + + +

    + + + +

    \ No newline at end of file diff --git a/plugins/tps/birzha/controllers/favourites/update.htm b/plugins/tps/birzha/controllers/favourites/update.htm new file mode 100644 index 0000000..136cec3 --- /dev/null +++ b/plugins/tps/birzha/controllers/favourites/update.htm @@ -0,0 +1,54 @@ + + + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + + + +
    +
    + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/tps/birzha/models/City.php b/plugins/tps/birzha/models/City.php new file mode 100644 index 0000000..1e44e6d --- /dev/null +++ b/plugins/tps/birzha/models/City.php @@ -0,0 +1,35 @@ + [ + 'TPS\Birzha\Models\Product', + ] + ]; + /** + * @var string The database table used by the model. + */ + public $table = 'tps_birzha_cities'; + + /** + * @var array Validation rules + */ + public $rules = [ + ]; +} diff --git a/plugins/tps/birzha/models/Comment.php b/plugins/tps/birzha/models/Comment.php new file mode 100644 index 0000000..42c584e --- /dev/null +++ b/plugins/tps/birzha/models/Comment.php @@ -0,0 +1,32 @@ + ['RainLab\User\Models\User', 'table' => 'users'], + 'product' => ['TPS\Birzha\Models\Product', 'table' => 'tps_birzha_products'], + ]; + + /** + * @var array Validation rules + */ + public $rules = [ + ]; +} diff --git a/plugins/tps/birzha/models/Favourites.php b/plugins/tps/birzha/models/Favourites.php new file mode 100644 index 0000000..b3dee79 --- /dev/null +++ b/plugins/tps/birzha/models/Favourites.php @@ -0,0 +1,34 @@ + ['RainLab\User\Models\User', 'table' => 'users'], + 'product' => ['TPS\Birzha\Models\Product', 'table' => 'tps_birzha_products'], + ]; + + + /** + * @var array Validation rules + */ + public $rules = [ + ]; +} diff --git a/plugins/tps/birzha/models/Product.php b/plugins/tps/birzha/models/Product.php index e1aaf0d..0755090 100644 --- a/plugins/tps/birzha/models/Product.php +++ b/plugins/tps/birzha/models/Product.php @@ -5,6 +5,7 @@ use October\Rain\Support\Facades\Event; use RainLab\User\Models\User; use Carbon\Carbon; use TPS\Birzha\Models\Settings; +use TPS\Birzha\Models\City; /** * Model @@ -45,17 +46,24 @@ class Product extends Model ]; public $belongsToMany = [ - 'categories' => ['TPS\Birzha\Models\Category','table' => 'tps_birzha_product_categories'] + 'categories' => ['TPS\Birzha\Models\Category','table' => 'tps_birzha_product_categories'], + //'favourites' => ['TPS\Birzha\Models\Favourites','table' => 'tps_birzha_favourites'], + ]; public $belongsTo = [ - // 'country' => ['TPS\Birzha\Models\Country'], + 'place' => City::class, //'measure' => ['TPS\Birzha\Models\Measure','key' => 'measure_id'], //'currency' => ['TPS\Birzha\Models\Currency'], //'payment_term' => ['TPS\Birzha\Models\Term','key' => 'payment_term_id'], //'delivery_term' => ['TPS\Birzha\Models\Term','key' => 'delivery_term_id'], 'vendor' => User::class, - 'payment' => ['TPS\Birzha\Models\Payment'], + //'payment' => ['TPS\Birzha\Models\Payment'], + ]; + + public $hasMany = [ + 'favourites' => ['TPS\Birzha\Models\Favourites', 'table' => 'tps_birzha_favourites'], + 'comments' => ['TPS\Birzha\Models\Comment','table' => 'tps_birzha_comments'], ]; public $morphOne = [ @@ -63,7 +71,8 @@ class Product extends Model ]; public $attachMany = [ - 'images' => 'System\Models\File' + 'images' => 'System\Models\File', + 'files' => 'System\Models\File' ]; public $translatable = [ diff --git a/plugins/tps/birzha/models/ProductComments.php b/plugins/tps/birzha/models/ProductComments.php new file mode 100644 index 0000000..3beef51 --- /dev/null +++ b/plugins/tps/birzha/models/ProductComments.php @@ -0,0 +1,27 @@ +engine = 'InnoDB'; + $table->increments('id')->unsigned(); + $table->timestamp('created_at')->nullable(); + $table->timestamp('updated_at')->nullable(); + $table->timestamp('deleted_at')->nullable(); + $table->string('name')->nullable(); + $table->text('note')->nullable(); + }); + } + + public function down() + { + Schema::dropIfExists('tps_birzha_cities'); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_create_tps_birzha_comments.php b/plugins/tps/birzha/updates/builder_table_create_tps_birzha_comments.php new file mode 100644 index 0000000..4d5510d --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_create_tps_birzha_comments.php @@ -0,0 +1,27 @@ +engine = 'InnoDB'; + $table->increments('id')->unsigned(); + $table->timestamp('created_at')->nullable(); + $table->timestamp('updated_at')->nullable(); + $table->timestamp('deleted_at')->nullable(); + $table->integer('product_id'); + $table->integer('user_id'); + $table->text('comment'); + }); + } + + public function down() + { + Schema::dropIfExists('tps_birzha_comments'); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_create_tps_birzha_favourites.php b/plugins/tps/birzha/updates/builder_table_create_tps_birzha_favourites.php new file mode 100644 index 0000000..ea9c4c2 --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_create_tps_birzha_favourites.php @@ -0,0 +1,26 @@ +engine = 'InnoDB'; + $table->increments('id')->unsigned(); + $table->timestamp('created_at')->nullable(); + $table->timestamp('updated_at')->nullable(); + $table->timestamp('deleted_at')->nullable(); + $table->integer('user_id'); + $table->integer('product_id'); + }); + } + + public function down() + { + Schema::dropIfExists('tps_birzha_favourites'); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_categories_3.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_categories_3.php new file mode 100644 index 0000000..d431974 --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_categories_3.php @@ -0,0 +1,23 @@ +boolean('is_file_category')->nullable()->default(0); + }); + } + + public function down() + { + Schema::table('tps_birzha_categories', function($table) + { + $table->dropColumn('is_file_category'); + }); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_cities.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_cities.php new file mode 100644 index 0000000..b23bfb7 --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_cities.php @@ -0,0 +1,23 @@ +integer('order')->nullable(); + }); + } + + public function down() + { + Schema::table('tps_birzha_cities', function($table) + { + $table->dropColumn('order'); + }); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments.php new file mode 100644 index 0000000..cb88ba9 --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments.php @@ -0,0 +1,23 @@ +text('comment')->nullable()->change(); + }); + } + + public function down() + { + Schema::table('tps_birzha_comments', function($table) + { + $table->text('comment')->nullable(false)->change(); + }); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments_2.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments_2.php new file mode 100644 index 0000000..6dc816f --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments_2.php @@ -0,0 +1,23 @@ +integer('rating')->nullable()->default(0); + }); + } + + public function down() + { + Schema::table('tps_birzha_comments', function($table) + { + $table->dropColumn('rating'); + }); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments_3.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments_3.php new file mode 100644 index 0000000..69878c2 --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_comments_3.php @@ -0,0 +1,23 @@ +boolean('is_approve')->nullable()->default(0); + }); + } + + public function down() + { + Schema::table('tps_birzha_comments', function($table) + { + $table->dropColumn('is_approve'); + }); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_30.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_30.php new file mode 100644 index 0000000..7967963 --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_30.php @@ -0,0 +1,23 @@ +dropColumn('place'); + }); + } + + public function down() + { + Schema::table('tps_birzha_products', function($table) + { + $table->string('place', 191)->nullable(); + }); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_31.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_31.php new file mode 100644 index 0000000..85620f8 --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_31.php @@ -0,0 +1,23 @@ +integer('place')->nullable(); + }); + } + + public function down() + { + Schema::table('tps_birzha_products', function($table) + { + $table->dropColumn('place'); + }); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_32.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_32.php new file mode 100644 index 0000000..42fc1a3 --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_32.php @@ -0,0 +1,23 @@ +renameColumn('place', 'place_id'); + }); + } + + public function down() + { + Schema::table('tps_birzha_products', function($table) + { + $table->renameColumn('place_id', 'place'); + }); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_33.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_33.php new file mode 100644 index 0000000..3e2b8c4 --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_33.php @@ -0,0 +1,23 @@ +boolean('is_file')->nullable()->default(false); + }); + } + + public function down() + { + Schema::table('tps_birzha_products', function($table) + { + $table->dropColumn('is_file'); + }); + } +} diff --git a/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_34.php b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_34.php new file mode 100644 index 0000000..afd766c --- /dev/null +++ b/plugins/tps/birzha/updates/builder_table_update_tps_birzha_products_34.php @@ -0,0 +1,23 @@ +renameColumn('is_file', 'is_file_product'); + }); + } + + public function down() + { + Schema::table('tps_birzha_products', function($table) + { + $table->renameColumn('is_file_product', 'is_file'); + }); + } +} diff --git a/plugins/tps/birzha/updates/version.yaml b/plugins/tps/birzha/updates/version.yaml index 007fe47..9d74043 100644 --- a/plugins/tps/birzha/updates/version.yaml +++ b/plugins/tps/birzha/updates/version.yaml @@ -347,3 +347,42 @@ 1.0.122: - 'Updated table tps_birzha_terms' - builder_table_update_tps_birzha_terms.php +1.0.123: + - 'Created table tps_birzha_cities' + - builder_table_create_tps_birzha_cities.php +1.0.124: + - 'Updated table tps_birzha_cities' + - builder_table_update_tps_birzha_cities.php +1.0.125: + - 'Updated table tps_birzha_products' + - builder_table_update_tps_birzha_products_30.php +1.0.126: + - 'Updated table tps_birzha_products' + - builder_table_update_tps_birzha_products_31.php +1.0.127: + - 'Updated table tps_birzha_products' + - builder_table_update_tps_birzha_products_32.php +1.0.128: + - 'Updated table tps_birzha_products' + - builder_table_update_tps_birzha_products_33.php +1.0.129: + - 'Updated table tps_birzha_products' + - builder_table_update_tps_birzha_products_34.php +1.0.130: + - 'Updated table tps_birzha_categories' + - builder_table_update_tps_birzha_categories_3.php +1.0.131: + - 'Created table tps_birzha_favourites' + - builder_table_create_tps_birzha_favourites.php +1.0.132: + - 'Created table tps_birzha_comments' + - builder_table_create_tps_birzha_comments.php +1.0.133: + - 'Updated table tps_birzha_comments' + - builder_table_update_tps_birzha_comments.php +1.0.134: + - 'Updated table tps_birzha_comments' + - builder_table_update_tps_birzha_comments_2.php +1.0.135: + - 'Updated table tps_birzha_comments' + - builder_table_update_tps_birzha_comments_3.php diff --git a/plugins/vdomah/jwtauth/routes.php b/plugins/vdomah/jwtauth/routes.php index 2cac5bb..c1e09c4 100644 --- a/plugins/vdomah/jwtauth/routes.php +++ b/plugins/vdomah/jwtauth/routes.php @@ -4,6 +4,15 @@ use RainLab\User\Models\User as UserModel; use Vdomah\JWTAuth\Models\Settings; Route::group(['prefix' => 'api'], function() { + + Route::get('me', function() { + + $me = \JWTAuth::parseToken()->authenticate() + ->only(['name','surname','email','username','type', 'logo', 'banner', 'shop_title', 'slogan', 'is_instagram']); + + return Response::json(compact('me')); + + })->middleware('\Tymon\JWTAuth\Middleware\GetUserFromToken'); Route::post('login', function (Request $request) { if (Settings::get('is_login_disabled'))