Просмотр исходного кода

Merge branch 'master' of https://github.com/unacms/UNA

AntonLV 5 месяцев назад
Родитель
Сommit
cd8f7d89c5

+ 42 - 1
inc/classes/BxDolAIQuery.php

@@ -893,7 +893,7 @@ class BxDolAIQuery extends BxDolDb
 
 
     public function getAgentsByAlertUnitAndAction($sUnit, $sAction, $bActiveOnly = true)
     public function getAgentsByAlertUnitAndAction($sUnit, $sAction, $bActiveOnly = true)
     {
     {
-        return $this->getAll("SELECT * FROM `sys_agents_agents` WHERE `trigger` = 'alert' AND `alert_unit` = :unit AND `alert_action` = :action AND `active` = :active", ['unit' => $sUnit, 'action' => $sAction, 'active' => $bActiveOnly ? 1 : 0]);
+        return $this->getAll("SELECT * FROM `sys_agents_agents` WHERE `trigger` = 'alert' AND `alert` = :alert AND `active` = :active", ['alert' => $sUnit . ':' . $sAction, 'active' => $bActiveOnly ? 1 : 0]);
     }
     }
 
 
     public function getAgentsByProfileId($iProfileId, $bActiveOnly = true)
     public function getAgentsByProfileId($iProfileId, $bActiveOnly = true)
@@ -942,6 +942,47 @@ class BxDolAIQuery extends BxDolDb
         return $this->query($sQuery, ['val' => $aAgent['trigger'] . ':' . $aAgent['id'] . ':%']);
         return $this->query($sQuery, ['val' => $aAgent['trigger'] . ':' . $aAgent['id'] . ':%']);
     }
     }
 
 
+    public function getAlert($s) {
+        if (!$s)
+            return false;
+        $a = explode(':', $s);
+        return $this->getRow("SELECT * FROM `sys_alerts_log` WHERE `unit` = :unit AND `action` = :action", [
+            'unit' => $a[0] ?? '',
+            'action' => $a[1] ?? '',
+        ]);
+    }
+
+    public function getAlerts()
+    {
+        $aValues = [];
+        $aAlerts = $this->getAll("SELECT `unit`, `action` FROM `sys_alerts_log` ORDER BY `unit`, `action`");
+        foreach ($aAlerts as $a) {
+            $sKey = $a['unit'] . ':' . $a['action'];
+            $aValues[$sKey] = [
+                'key' => $sKey,
+                'unit' => $a['unit'],
+                'action' => $a['action'],
+                'name' => $a['unit'] . ' - ' . $a['action'],
+                'desc' => $this->getAlertDesc($a['unit'] . ':' . $a['action']),
+            ];
+        }
+        return $aValues;
+    }
+
+    public function getAlertDesc($sAlert) 
+    {
+        [$sUnit, $sAction] = explode(':', $sAlert);
+        $sDesc = $this->getOne("SELECT `description` FROM `sys_alerts_desc` WHERE `unit` = :unit AND `action` = :action LIMIT 1", [
+            'unit' => $sUnit,
+            'action' => $sAction,
+        ]);
+        if (!$sDesc) {
+            $this->getOne("SELECT `description` FROM `sys_alerts_desc` WHERE `unit` LIKE '{%}' AND `action` = :action LIMIT 1", [
+                'action' => $sAction,
+            ]);
+        }
+        return $sDesc;
+    }
 }
 }
 
 
 /** @} */
 /** @} */

+ 6 - 0
inc/classes/BxDolAlerts.php

@@ -254,6 +254,12 @@ class BxDolAlerts extends BxDol
         $oDb = BxDolDb::getInstance();
         $oDb = BxDolDb::getInstance();
         $oDb->query("UPDATE sys_alerts_log SET counter_24h = 0");
         $oDb->query("UPDATE sys_alerts_log SET counter_24h = 0");
     }
     }
+
+    static public function deleteModuleAlerts($sUnit)
+    {
+        $oDb = BxDolDb::getInstance();
+        $oDb->query("DELETE FROM sys_alerts_log WHERE unit = :unit", ['unit' => $sUnit]);
+    }
 }
 }
 
 
 class BxDolAlertsResponse extends BxDol
 class BxDolAlertsResponse extends BxDol

+ 359 - 0
install/sql/sys-alerts-desc.sql

@@ -0,0 +1,359 @@
+
+INSERT INTO `sys_alerts_desc` (`unit`, `action`, `description`) VALUES
+('system', 'check_send_mail', 'hook for disabling mail sending'),
+('system', 'before_send_mail', 'hook before mail sending'),
+('system', 'send_mail', 'hook when mail was sent'),
+('account', 'clear_xss', 'hook after string is checked for xss'),
+('system', 'permalink', 'hook to override permalink during link to permalink conversion'),
+('system', 'unpermalink', 'hook to override link during permalink to link conversion'),
+('system', 'set_cover', 'hook in set cover'),
+('system', 'set_cover_image', 'hook on cover image'),
+('feature', 'undo', 'hook on cancel feature'),
+('feature', 'do', 'hook on feature'),
+('{object_name}', 'connection_before_add', 'hook before connection was added. Connection params can be overridden'),
+('{object_name}', 'connection_added', 'hook after connection was added. Connection params can be overridden'),
+('{object_name}', 'connection_before_remove', 'hook before connection was removed. Connection params can be overridden'),
+('{object_name}', 'connection_removed', 'hook after a connection was removed.'),
+('{object_name}', 'connection_removed_all', 'hook after all connections with deleted \'initiator\' were removed.'),
+('system', 'transcode', 'hook before file is transcoded'),
+('system', 'transcoded', 'hook after file is transcoded'),
+('{object_name}', 'doVoteUp', 'hook after score vote'),
+('{object_name}', 'doVoteDown', 'hook after score vote'),
+('{object_name}', 'undoVoteUp', 'hook after undo score vote'),
+('{object_name}', 'undoVoteDown', 'hook after undo score vote'),
+('score', 'doUp', 'hook after score vote'),
+('score', 'doDown', 'hook after score vote'),
+('score', 'undoUp', 'hook after undo score vote'),
+('score', 'undoDown', 'hook after undo score vote'),
+('system', 'informer_permament_messages', 'hook on informer'),
+('{object_name}', 'keyword_added', 'hook after a keyword (hashtag) was recognized in provided text'),
+('meta_keyword', 'added', 'hook after a keyword (hashtag) was recognized in provided text'),
+('meta_keyword', 'url', 'hook to override meta keyword URL'),
+('meta_keyword', 'before_add_multiple', 'hook to override meta keywords before it will be processed'),
+('meta_keyword', 'before_added', 'hook to override meta keyword before it will be processed'),
+('meta_mention', 'before_added', 'hook to override meta keyword before it will be processed'),
+('grid', 'get_data', 'hook to override the data to be shown in the grid'),
+('grid', 'get_data_by_filter', 'hook to override the data to be shown in the grid'),
+('system', 'parse_email_template', 'hook on template with neccessary markers replaced'),
+('account', 'is_confirmed', 'hook in  $oAccount->isConfirmed check'),
+('account', 'is_confirmed_email', 'hook in  $oAccount->isConfirmedEmail check'),
+('account', 'is_confirmed_phone', 'hook in  $oAccount->isConfirmedPhone check'),
+('account', 'confirm', 'hook in email confirmation $oAccount->updateEmailConfirmed'),
+('account', 'edited', 'hook on account edited $oAccount->updatePassword'),
+('account', 'set_phone', 'hook after accout password changed'),
+('account', 'before_switch_context', 'hook before switch profile_id frof current logged user'),
+('account', 'switch_context', 'hook before switch profile_id frof current logged user'),
+('account', 'account_name', 'hook on get account display name'),
+('account', 'get_limit_profiles_number', 'hook on get account limit on the number of profiles'),
+('account', 'before_delete', 'hook on before delete account,'),
+('account', 'delete', 'hook on after delete account'),
+('account', 'is_need_to_change_password', 'hook on after delete account'),
+('profile', 'allow_create_another_profile', 'hook on check allow create profile'),
+('vote', 'undo', 'hook on cancel vote'),
+('vote', 'do', 'hook on new vote'),
+('search', 'get_mention', 'hook on get mention list'),
+('system', 'uri_generate', 'hook to override SEO URI generated for a page'),
+('profile', 'profile_name', 'hook on before profile deletion'),
+('profile', 'before_delete', 'hook on before profile deletion'),
+('profile', 'delete', 'hook on profile deleted'),
+('profile', 'add', 'hook on profile added'),
+('profile', 'approve', 'hook on switch profile'),
+('account', 'check_switch_context', 'hook on switch profile'),
+('meta_keyword', 'deleted', 'hook on delete meta keyword'),
+('system', 'get_color_palette', 'hook on get color palette'),
+('system', 'get_layout_images', 'hook on get layout images'),
+('system', 'add_files', 'hook on add file to page'),
+('system', 'design_before_output', 'hook on before page''s html generated'),
+('system', 'design_after_output', 'hook on after page''s html generated'),
+('system', 'form_check', 'hook to override form object after data checking was performed'),
+('system', 'form_submitted', 'hook to override form object after data was submitted and saved in database'),
+('system', 'check_spam', 'hook to override (perform) spam checking'),
+('module_template_method_call', '{method_name}', 'hook to override a method from template class in a module'),
+('favorite', 'favorite', 'hook on add new object to favorites lists or remove object from favorites lists'),
+('system', 'privacy_condition', 'hook on get necessary condition array to use privacy in search classes'),
+('system', 'check_privacy', 'check privacy for object'),
+('{object_name}', 'connection_confirmed', 'hook after relation was confirmed'),
+('{object_name}', 'get_relations', 'hook to override relation info'),
+('system', 'get_object', 'hook to override menu object'),
+('simple_search', 'before_get_data', 'hook on before after get data'),
+('simple_search', 'get_data', 'hook on after get data'),
+('simple_search', 'get_query', 'hook on get sql queries'),
+('membership', 'check_action', 'hook to override the result of checking whether an action is allowed or not'),
+('profile', 'unset_membership', 'hook after a default membership level was set'),
+('profile', 'set_membership', 'hook after a new membership level was set'),
+('profile', 'prolong_membership', 'hook after current membership level was prolonged'),
+('{object_name}', 'commentRemoved', 'hook after a comment was removed'),
+('comment', 'deleted', 'hook after a comment was removed'),
+('{object_name}', 'replyRemoved', 'hook after a reply was removed'),
+('reply', 'deleted', 'hook after a reply was removed'),
+('{object_name}', 'commentPost', 'hook after a comment was added'),
+('comment', 'added', 'hook after a comment was added'),
+('{object_name}', 'replyPost', 'hook after a reply was added'),
+('comment', 'replied', 'hook after a reply was added'),
+('{object_name}', 'commentUpdated', 'hook after a comment was updated (edited)'),
+('comment', 'edited', 'hook after a comment was updated (edited)'),
+('system', 'decode_comment_data_api', 'hook to override comment data prepared for sending in API response'),
+('{object_name}', 'decode_comment_data_api', 'hook to override comment data prepared for sending in API response'),
+('label', 'added', 'hook on new label added'),
+('label', 'edited', 'hook on new label edited'),
+('label', 'deleted', 'hook on new label deleted'),
+('comment', 'get_comments_count', 'hook to override number of comments for commented object'),
+('comment', 'get_comments', 'hook to override comments list. Is used during comments count retrieving.'),
+('system', 'push_tags', 'hook on get tags to send to PUSH server'),
+('account', 'login', 'hook after user performed login'),
+('account', 'logout', 'hook after user performed logout'),
+('account', 'logged', 'hook after user performed logged'),
+('account', 'encrypt_password_after', 'hook after user performed login'),
+('account', 'check_login', 'hook after user''s login/password check'),
+('bx_ads', 'doInterest', 'hook after ''interested'' action was performed'),
+('bx_ads', 'order_authorize', 'hook after the order was authorized with payment processing module'),
+('bx_ads', 'license_register', 'hook after the payment for an ad was processed with payment processing module'),
+('bx_ads', 'sold', 'hook after the payment was processed with payment processing module and there is no the ad (entry) for selling anymore'),
+('bx_ads', 'license_register_notif', 'hook before sending a notification about new license. Allows to override a notification message or cancel the notification'),
+('bx_ads', 'promotion_register', 'hook after the payment for promotion was processed with payment processing module'),
+('bx_ads', 'license_unregister', 'hook after the payment for ad was refunded with payment processing module'),
+('bx_ads', 'promotion_unregister', 'hook after the payment for promotion was refunded with payment processing module'),
+('bx_ads', 'is_entry_active', 'hook to override whether an ad (entry) active or not'),
+('bx_ads', 'offer_added', 'hook after an offer was added. Allows to override action results.'),
+('bx_ads', 'offer_accepted', 'hook after an offer was accepted.'),
+('bx_ads', 'offer_declined', 'hook after an offer was declined.'),
+('bx_ads', 'offer_canceled', 'hook after an offer was declined.'),
+('bx_ads', 'shipped', 'hook after the ad (entry) was marked as shipped'),
+('bx_ads', 'received', 'hook after the ad (entry) was marked as received'),
+('bx_convos', 'deleted', 'hook on delete conversation'),
+('profile', 'check_contact', 'hook on check some profile to allow contact him'),
+('bx_tasks', 'expired', 'hook on task unassigned to profile'),
+('bx_tasks', 'completed', 'hook on task unassigned to profile'),
+('bx_tasks', 'assigned', 'hook on task assigned to profile'),
+('bx_tasks', 'unassigned', 'hook on task unassigned to profile'),
+('bx_donations', 'donation_register', 'hook after the donation payment was processed with payment processing module'),
+('bx_donations', 'donation_unregister', 'hook after the donation payment was refunded with payment processing module'),
+('bx_donations', 'donate', 'hook to override the content of donate block'),
+('bx_payment', 'stripe_v3_create_tax', 'hook to override tax data redurned by payment provider'),
+('bx_payment', 'stripe_v3_retrieve_tax', 'hook to override tax data retrieved from payment provider'),
+('bx_payment', 'stripe_v3_get_code_session', 'hook to override session verification code'),
+('bx_payment', 'stripe_v3_verify_session', 'hook to override checking of session verification code'),
+('bx_payment', 'stripe_v3_retrieve_customer', 'hook to override customer data retrieved from payment provider'),
+('bx_payment', 'stripe_v3_create_session', 'hook to override session data redurned by payment provider'),
+('bx_payment', 'stripe_v3_retrieve_session', 'hook to override session data retrieved from payment provider'),
+('bx_payment', 'stripe_v3_retrieve_setup_intent', 'hook to override SetupIntent data retrieved from payment provider'),
+('bx_payment', 'stripe_v3_create_payment_intent', 'hook to override PaymentIntent data redurned by payment provider'),
+('bx_payment', 'stripe_v3_retrieve_payment_inten', 'hook to override PaymentIntent data retrieved from payment provider'),
+('bx_payment', 'stripe_v3_retrieve_subscription', 'hook to override subscription data retrieved from payment provider'),
+('bx_payment', 'stripe_v3_get_button', 'hook to override checkout/subscibe button'),
+('bx_payment', 'credits_cancel_subscription', 'hook after a subscription was canceled'),
+('bx_payment', 'chargebee_cancel_subscription', 'hook after a subscription was canceled'),
+('bx_payment', 'chargebee_v3_cancel_subscription', 'hook after a subscription was canceled'),
+('bx_payment', 'chargebee_v3_get_js_code', 'hook to override JavaScript code'),
+('bx_payment', 'chargebee_v3_get_button', 'hook to override checkout/subscibe button'),
+('bx_payment', 'stripe_retrieve_customer', 'hook to override customer data retrieved from payment provider'),
+('bx_payment', 'stripe_retrieve_charge', 'hook to override charge data retrieved from payment provider'),
+('bx_payment', 'stripe_v3_retrieve_charge', 'hook to override charge data retrieved from payment provider'),
+('bx_payment', 'stripe_cancel_subscription', 'hook after a subscription was canceled'),
+('bx_payment', 'stripe_v3_cancel_subscription', 'hook after a subscription was canceled'),
+('bx_payment', 'stripe_retrieve_product', 'hook to override product data retrieved from payment provider'),
+('bx_payment', 'stripe_v3_retrieve_product', 'hook to override product data retrieved from payment provider'),
+('bx_payment', 'stripe_get_code_charge', 'hook to override verification code for ''charge'' action'),
+('bx_payment', 'stripe_verify_charge', 'hook to override code verification for ''charge'' action'),
+('bx_payment', 'stripe_get_code_subscription', 'hook to override verification code for ''subscribe'' action'),
+('bx_payment', 'stripe_verify_subscription', 'hook to override code verification for ''subscribe'' action'),
+('bx_payment', 'stripe_create_customer', 'hook to override customer data redurned by payment provider'),
+('bx_payment', 'stripe_create_charge', 'hook to override charge data redurned by payment provider'),
+('bx_payment', 'stripe_create_subscription', 'hook to override subscription data redurned by payment provider'),
+('bx_payment', 'stripe_get_button', 'hook to override checkout/subscibe button'),
+('bx_reputation', 'before_register_alert', 'hook to override alert (hook) before processing'),
+('bx_stream', 'publish_succeeded', 'hook on stream published succeeded'),
+('bx_feedback', 'added_question', 'hook on new question added'),
+('bx_feedback', 'edited_question', 'hook on new question edited'),
+('bx_feedback', 'deleted_question', 'hook on question deleted'),
+('bx_feedback', 'added_answer', 'hook on new answer added'),
+('bx_feedback', 'added_answer_notif', 'hook on new answer added'),
+('bx_feedback', 'deleted_answer', 'hook on new answer deleted'),
+('bx_stories', 'media_added', 'hook on new media added in story'),
+('bx_messenger', 'send_jot', 'hook after a jot (message) was sent'),
+('bx_messenger', 'got_jot', 'hook after a lot (conversation) got a new jot (message)'),
+('profile', 'send_mail', 'hook in  $oAccount->isConfirmed check'),
+('bx_market', 'license_reset', 'hook on license reset'),
+('bx_market', 'license_expire', 'hook on found expired license'),
+('bx_events', 'check_in', 'hook in on somebody check-in some event'),
+('bx_events', 'calendar_data', 'hook in get data for calendar'),
+('bx_events', 'reminder', 'hook on enent''s reminder'),
+('bx_invites', 'add_friend', 'hook on add friend on new user registred by invitaion'),
+('bx_invites', 'request', 'hook on create new request on invite'),
+('bx_invites', 'request_notify', 'hook on notify all admins&moderators about new request'),
+('bx_invites', 'invite', 'hook on new invite'),
+('bx_timeline', 'cache_table_check_fields', 'hook to override cache table fields, which should be checked'),
+('bx_timeline', 'get_system_data', 'hook to override event''s data received from content modules before output'),
+('bx_timeline', 'get_events_before', 'hook to override params which are used to get events'),
+('bx_timeline', 'get_events', 'hook to override events list which will be received from database'),
+('bx_timeline', 'get_list_by_type', 'hook to override SQL query parts which are used to get events list'),
+('bx_timeline', 'add_live_update', 'hook to override params and/or code for live updates'),
+('bx_timeline', 'get_view', 'hook to override elements of view timeline block'),
+('bx_timeline', 'get_external_post', 'hook to override (add) external post(s) in timeline'),
+('bx_timeline', 'get_reposted_by', 'hook to override a list of users reposted a content'),
+('bx_timeline', 'get_post', 'hook to override a post (event) before output'),
+('bx_timeline', 'get_post_content', 'hook to override a post''s content before output'),
+('bx_timeline', 'promoted', 'hook after an event was promoted'),
+('bx_timeline', 'unpromoted', 'hook after an event was unpromoted'),
+('bx_timeline', 'muted', 'hook after an event author was muted'),
+('bx_timeline', 'on_get_post', 'hook to override just created direct post (update)'),
+('system', 'get_object_form', 'hook to override an object of create content form, @see BxDolForm'),
+('system', 'check_allowed_view', 'hook to override the result of checking whether \'view\' action is allowed or not to specified profile'),
+('{profile_module_name}', 'timeline_post', 'hook to override the result of checking whether \'post in profile\' action is allowed or not'),
+('{profile_module_name}', 'timeline_edit', 'hook to override the result of checking whether \'edit\' action is allowed or not'),
+('{profile_module_name}', 'timeline_delete', 'hook to override the result of checking whether \'delete\' action is allowed or not'),
+('{profile_module_name}', 'timeline_view_counter', 'hook to override the result of checking whether \'view counter\' action is allowed or not'),
+('{profile_module_name}', 'timeline_vote', 'hook to override the result of checking whether \'vote\' action is allowed or not'),
+('{profile_module_name}', 'timeline_vote_view', 'hook to override the result of checking whether \'vote\' action is allowed or not'),
+('{profile_module_name}', 'timeline_reaction', 'hook to override the result of checking whether \'give reaction vote\' action is allowed or not'),
+('{profile_module_name}', 'timeline_reaction_view', 'hook to override the result of checking whether \'view reactions\' action is allowed or not'),
+('{profile_module_name}', 'timeline_score', 'hook to override the result of checking whether \'give score vote\' action is allowed or not'),
+('{profile_module_name}', 'timeline_report', 'hook to override the result of checking whether \'give score vote\' action is allowed or not'),
+('bx_timeline', 'is_allowed_repost', 'hook to override the result of checking whether \'repost\' action is allowed or not'),
+('{profile_module_name}', 'timeline_send', 'hook to override the result of checking whether \'send\' action is allowed or not'),
+('bx_timeline', 'post_system', 'hook after system post was added and published'),
+('bx_timeline', 'post_common', 'hook after common post was added and published'),
+('bx_timeline', 'defer_system', 'hook after system post was added'),
+('bx_timeline', 'defer_common', 'hook after common post was added'),
+('bx_timeline', 'fail_system', 'hook after system post failed to publish'),
+('bx_timeline', 'fail_common', 'hook after common post failed to publish'),
+('bx_timeline', 'repost', 'hook after repost was added (published)'),
+('bx_timeline', 'hide_repost', 'hook after repost was hidden'),
+('bx_timeline', 'hide', 'hook after post (event) was hidden'),
+('bx_timeline', 'unhide_repost', 'hook after repost was unhidden'),
+('bx_timeline', 'unhide', 'hook after post (event) was unhidden'),
+('bx_timeline', 'delete_repost', 'hook after repost was deleted'),
+('bx_timeline', 'delete', 'hook after \'common\' post (event) was deleted'),
+('{profile_module_name}', 'timeline_view', 'hook to override view timeline block'),
+('{profile_module_name}', 'timeline_repost', 'hook to override the result of checking whether \'repost\' action is allowed or not'),
+('{profile_module_name}', 'timeline_pin', 'hook to override the result of checking whether \'pin\' action is allowed or not'),
+('{profile_module_name}', 'timeline_stick', 'hook to override the result of checking whether \'stick\' action is allowed or not'),
+('{profile_module_name}', 'timeline_promote', 'hook to override the result of checking whether \'promote\' action is allowed or not'),
+('bx_albums', 'media_added', 'hook on new media added in album'),
+('bx_credits', 'checkout', 'hook after checkout with creadits was performed'),
+('bx_credits', 'subscribe', 'hook after subscription was registered'),
+('bx_credits', 'update_balance', 'hook after profile''s credits balance was updated (credits were transferred from one profile to another)'),
+('bx_credits', 'granted', 'hook after some amount of credits was granted to a profile'),
+('bx_credits', 'sent', 'hook after some amount of credits was sent from one profile to another'),
+('bx_credits', 'withdraw_requested', 'hook after a profile requested to withdraw some amount of credits from his balance'),
+('bx_credits', 'withdraw_canceled', 'hook after a profile canceled his withdrawal request'),
+('bx_credits', 'withdraw_sent', 'hook after the amount of credits requested to withdraw was sent'),
+('bx_credits', 'order_register', 'hook after the payment for a bundle of credits was processed with payment processing module'),
+('bx_credits', 'order_prolong', 'hook isn''t currently used because \'single\' type payments for bundles are only supported'),
+('bx_credits', 'order_unregister', 'hook after the payment for a bundle of credits was refunded with payment processing module'),
+('bx_notifications', 'get_notification', 'hook to override notification or even cancel it'),
+('bx_notifications', 'get_content', 'hook to override notification content'),
+('bx_notifications', 'get_events_before', 'hook to override params which are used to get events'),
+('bx_notifications', 'get_events', 'hook to override events list which will be received from database'),
+('bx_notifications', 'get_list_by_type', 'hook to override SQL query parts which are used to get events list'),
+('bx_notifications', 'before_register_alert', 'hook to override alert (hook) before processing'),
+('bx_notifications', 'is_notification', 'hook to override checking if an event is available or not'),
+('bx_notifications', 'before_parse_email_template', 'hook to override email template'),
+('bx_notifications', 'before_send_notification_push', 'hook to override push message'),
+('bx_analytics', 'get_modules', 'hook on get modules list with avalaible analytics'),
+('bx_analytics', 'get_reports', 'hook on get avalaible reports for specified module'),
+('bx_analytics', 'get_chart_data_line', 'hook on get avalaible reports for specified module'),
+('bx_channels', 'hashtag_added', 'hook on found hashtag in content'),
+('system', 'prepare_alert_params', 'hook to override alert (hook) params'),
+('bx_channels', 'hashtag_added_notif', 'hook on after found hashtag in content'),
+('bx_channels', 'hashtag_deleted', 'hook on before delete content from channel'),
+('bx_channels', 'hashtag_deleted_notif', 'hook on before delete content from channel'),
+('{module_name}', 'get_cnf', 'hook to override module''s configuration array'),
+('{module_name}', 'redirect_after_add', 'hook to override redirect URL which is used after content creation'),
+('{module_name}', 'redirect_after_edit', 'hook to override redirect URL which is used after content changing'),
+('{module_name}', 'redirect_after_delete', 'hook to override redirect URL which is used after content deletion'),
+('{module_name}', 'deleted', 'hook after content was deleted'),
+('system', 'editor_query_params', 'hook to override http(s) request''s query params, which is used in HTML editor'),
+('{module_name}', 'publish_failed', 'hook to notify about failed content publishing'),
+('{module_name}', 'publish_succeeded', 'hook to notify about successfully published content'),
+('system', 'get_js_code', 'hook to override an instance of JavaScript class associate with the page'),
+('system', 'search_ids', 'hook to modify a list of found content ids'),
+('{module_name}', 'is_entry_active', 'hook to override whether an entry (content) active or not'),
+('{module_name}', 'is_entry_author', 'hook to check if a viewer is an author of viewed entry (content) or not'),
+('{module_name}', 'get_sortable_fields', 'hook to override a list of sortable fields'),
+('{module_name}', 'get_searchable_fields', 'hook to override a list of searchable fields'),
+('system', 'get_badges', 'hook to override bages assigned to an entry (content)'),
+('system', 'check_allowed_browse', 'hook to override the result of checking whether \'browse\' action is allowed or not to currently logged in profile'),
+('{module_name}', 'failed', 'hook after content creation when publishing was failed'),
+('{module_name}', 'approved', 'hook when module content has been approved'),
+('system', 'decode_data_api', 'hook to override content data prepared for sending in API response'),
+('{module_name}', 'decode_data_api', 'hook to override content data prepared for sending in API response'),
+('{module_name}', 'get_approve_form', 'hook to override approve content form'),
+('{module_name}', 'pending_approval', 'hook to notify admins/moderators about new pending approval content'),
+('system', '{payment_action}', 'hook after some payment related action happened'),
+('{payment_module_name}', '{payment_action}', 'hook after some payment related action happened'),
+('{module_name}', 'join_invitation', 'hook before adding (sending) new join to context invitation'),
+('{module_name}', 'join_invitation_notif', 'hook before adding new join to context invitation. Is needed for Notifications module.'),
+('{module_name}', 'join_request', 'hook before adding new join to context request'),
+('{module_name}', 'join_request_accepted', 'hook before accepting join to context request'),
+('{module_name}', 'fan_added', 'hook before adding (registering) new context member'),
+('system', 'check_allowed_fan_add', 'hook to override the result of checking whether \'fan add\' to context action is allowed or not to currently logged in user'),
+('system', 'check_allowed_action_by_role', 'hook to override the result of checking whether an action is allowed or not to context member by his role in the context'),
+('system', 'check_allowed_subscribe_add', 'hook to override the result of checking whether currently logged in user can subscribe (follow) the context or not'),
+('{module_name}', 'context_picture_changed', 'hook after context picture was changed'),
+('{module_name}', 'context_cover_changed', 'hook after context cover was changed'),
+('{module_name}', 'added', 'hook after context was added (published)'),
+('{module_name}', 'deferred', 'hook after context was added with pending approval status'),
+('{module_name}', 'set_role', 'hook after \'set role\' action was applied to context member'),
+('{module_name}', 'profile_picture_deleted', 'hook after profile picture was deleted'),
+('{module_name}', 'profile_cover_deleted', 'hook after profile cover was deleted'),
+('{module_name}', 'profile_badge_deleted', 'hook after profile badge was deleted'),
+('{module_name}', 'profile_name', 'hook to override profile display name'),
+('system', 'get_participating_profiles', 'hook to override context participants list'),
+('{module_name}', 'prepare_fields', 'hook to override prepared profile fields'),
+('system', 'check_allowed_post', 'hook to override the result of checking whether \'post\' action is allowed or not to specified profile'),
+('system', 'check_allowed_contact', 'hook to override the result of checking whether \'contact\' action is allowed or not to specified profile'),
+('{module_name}', 'profile_picture_changed', 'hook after profile picture was changed'),
+('{module_name}', 'profile_cover_changed', 'hook after profile cover was changed'),
+('{module_name}', 'edited', 'hook after profile was changed'),
+('profile', 'edit', 'hook after profile was changed'),
+('profile', 'unit', 'hook to override profile browsing unit'),
+('{module_name}', 'unit', 'hook to override profile browsing unit'),
+('system', 'image_editor', 'hook to override profile cover editor'),
+('profile', 'content_info_by_id', 'hook to modify profile info retrieved by content id'),
+('profile', 'content_info_by_profile_id', 'hook to modify profile info retrieved by profile id'),
+('profile', 'search_by_term', 'hook to modify a list of profiles found by term'),
+('{module_name}', 'comment_post_allowed', 'hook to override the result of checking whether comment posting action allowed or not'),
+('bx_base_text', 'media_deleted', 'hook on new media deleted from story'),
+('bx_base_text', 'medias_added', 'hook on new medias added in story (album)'),
+('{module_name}', 'profile_created', 'hook after a profile was created'),
+('{module_name}', 'fields_converted', 'hook before a profile is created, which allows to modify account and/or profile fields before creation'),
+('account', 'check_join', 'hook to check email address for spam'),
+('account', 'before_confirm_phone_send_sms', 'hook in confirm phone'),
+('account', 'after_email_confirmation', 'hook after email confirmed'),
+('account', 'before_forgot_password_send_sms', 'hook in  $oAccount->isConfirmed check'),
+('simple_search', 'show_data', 'hook in display block for search'),
+('system', 'view_comments', 'hook to override comments block'),
+('system', 'view_comment', 'hook on get comment'),
+('account', 'add_form_get', 'hook in get some account form'),
+('account', 'add_form_check', 'hook in  some account form after check'),
+('account', 'add_form', 'hook in  some account form after check'),
+('account', 'added', 'hook on new account created'),
+('comment', 'menu_custom_item', 'hook to override menu item'),
+('menu', 'get_code_before', 'hook before menu output'),
+('menu', 'get_code_after', 'hook after menu output'),
+('search', 'get_data', 'hook in get data for serach'),
+('system', 'get_page_api', 'hook to override page peremeters, is used in API calls'),
+('system', 'get_page_content_api', 'hook to override page content, is used in API calls'),
+('system', 'encrypt_password_after', 'hook to override password using another encrypt function'),
+('account', 'change_receive_news', 'hook after change receive_news parameter for account'),
+('system', 'page_output_block', 'hook with page block data to be output'),
+('system', 'page_output', 'hook with page data to be output'),
+('search', 'get_form', 'hook in create search form'),
+('{module_name}', 'menu_custom_item', 'hook to override menu item'),
+('menu', 'menu_custom_item', 'hook to override menu item'),
+('system', 'form_output', 'hook to override form object and/or code to be output'),
+('system', 'form_output_api', 'hook to override form object and/or code to be output. Is used in API calls.'),
+('system', 'check_spam_url', 'hook to override sClass for search'),
+('system', 'search_keyword', 'hook to override sClass for search'),
+('profile', 'show_login_form', 'hook before dhow login form'),
+('account', 'before_2fa_send_sms', 'hook after user performed login'),
+('account', 'login_after', 'hook on after login to rewrite url for redirect after login'),
+('system', 'display_cover', 'hook to override page cover code to be output'),
+('system', 'profiles_search_by_location', 'hook on serach profiles by location'),
+('system', 'account_profile_switcher', 'hook to get account profile switcher'),
+('system', 'page_output_block_acl_level', 'hook to override profile membership page block'),
+('report', 'undo', 'hook on cancel report'),
+('report', 'do', 'hook on create new report'),
+('{module_name}', 'reported_content', 'hook to notify admins/moderators about newly reported content');
+

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
install/sql/system.sql


+ 4 - 5
modules/boonex/english/data/langs/system/en.xml

@@ -2298,11 +2298,10 @@
     <string name="_sys_agents_automators_field_type_webhook"><![CDATA[Webhook]]></string>
     <string name="_sys_agents_automators_field_type_webhook"><![CDATA[Webhook]]></string>
     <string name="_sys_agents_field_trigger"><![CDATA[Trigger]]></string>
     <string name="_sys_agents_field_trigger"><![CDATA[Trigger]]></string>
     <string name="_sys_agents_field_trigger_info"><![CDATA[Trigger which will initiate agent to run. Alert — system event notification. Scheduler — time-based scheduled execution. Webhook — external HTTP trigger. Manual — user-initiated run. Agent — triggered by another agent. Message — triggered by chat message.]]></string>
     <string name="_sys_agents_field_trigger_info"><![CDATA[Trigger which will initiate agent to run. Alert — system event notification. Scheduler — time-based scheduled execution. Webhook — external HTTP trigger. Manual — user-initiated run. Agent — triggered by another agent. Message — triggered by chat message.]]></string>
-    <string name="_sys_agents_field_alert_sample"><![CDATA[Alert: sample data]]></string>
-    <string name="_sys_agents_waiting_for_sample_data"><![CDATA[Waiting for sample data...]]></string>
-    <string name="_sys_agents_field_alert_unit"><![CDATA[Alert: event type]]></string>
-    <string name="_sys_agents_field_alert_unit_info"><![CDATA[Type of event that triggers the agent, usually 'system' for system events, 'module_name' for modules events.]]></string>
-    <string name="_sys_agents_field_alert_action"><![CDATA[Alert: event action]]></string>
+    <string name="_sys_agents_field_alert_sample"><![CDATA[Alert: payload]]></string>
+    <string name="_sys_agents_waiting_for_sample_data"><![CDATA[Please select an alert to see its payload.]]></string>
+    <string name="_sys_agents_field_alert"><![CDATA[Alert: event name]]></string>
+    <string name="_sys_agents_field_alert_info"><![CDATA[Event that triggers the agent. Usually starts with system or module_name. Only events that have occurred at least once are shown.]]></string>
     <string name="_sys_agents_field_scheduler_cron"><![CDATA[Scheduler (CRON)]]></string>
     <string name="_sys_agents_field_scheduler_cron"><![CDATA[Scheduler (CRON)]]></string>
     <string name="_sys_agents_field_scheduler_cron_info"><![CDATA[CRON expression for scheduling the agent.]]></string>
     <string name="_sys_agents_field_scheduler_cron_info"><![CDATA[CRON expression for scheduling the agent.]]></string>
     <string name="_sys_agents_field_webhook_key"><![CDATA[Webhook: key]]></string>
     <string name="_sys_agents_field_webhook_key"><![CDATA[Webhook: key]]></string>

+ 3 - 3
modules/boonex/russian/data/langs/system/ru.xml

@@ -2275,9 +2275,9 @@
         <string name="_sys_agents_field_trigger"><![CDATA[Триггер]]></string>
         <string name="_sys_agents_field_trigger"><![CDATA[Триггер]]></string>
         <string name="_sys_agents_field_trigger_info"><![CDATA[Триггер, который запускает агента. Alert — системное событие. Scheduler — запуск по расписанию. Webhook — HTTP внешний вызов. Manual — ручной запуск. Agent — запуск другим агентом. Message — сообщение пользователя.]]></string>
         <string name="_sys_agents_field_trigger_info"><![CDATA[Триггер, который запускает агента. Alert — системное событие. Scheduler — запуск по расписанию. Webhook — HTTP внешний вызов. Manual — ручной запуск. Agent — запуск другим агентом. Message — сообщение пользователя.]]></string>
         <string name="_sys_agents_field_alert_sample"><![CDATA[Alert - пример данных]]></string>
         <string name="_sys_agents_field_alert_sample"><![CDATA[Alert - пример данных]]></string>
-        <string name="_sys_agents_waiting_for_sample_data"><![CDATA[Ожидание примера данных...]]></string>
-        <string name="_sys_agents_field_alert_unit"><![CDATA[Alert - тип события]]></string>
-        <string name="_sys_agents_field_alert_unit_info"><![CDATA[Тип события, которое вызывает агента, обычно 'system' - для системных событий, 'имя_модуля' - для модульных событий]]></string>
+        <string name="_sys_agents_waiting_for_sample_data"><![CDATA[Пожалуйста, выберите алерт, чтобы увидеть его данные.]]></string>
+        <string name="_sys_agents_field_alert"><![CDATA[Alert - событие]]></string>
+        <string name="_sys_agents_field_alert_info"><![CDATA[Событие, запускающее агента. Обычно начинается с system или module_name. Показаны только уже произошедшие события.]]></string>
         <string name="_sys_agents_field_alert_action"><![CDATA[Alert - действие события]]></string>
         <string name="_sys_agents_field_alert_action"><![CDATA[Alert - действие события]]></string>
         <string name="_sys_agents_field_scheduler_cron"><![CDATA[Scheduler - Планировщик (CRON)]]></string>
         <string name="_sys_agents_field_scheduler_cron"><![CDATA[Scheduler - Планировщик (CRON)]]></string>
         <string name="_sys_agents_field_scheduler_cron_info"><![CDATA[Scheduler - CRON строка для планирования агента.]]></string>
         <string name="_sys_agents_field_scheduler_cron_info"><![CDATA[Scheduler - CRON строка для планирования агента.]]></string>

+ 118 - 0
scripts/scrape_alerts_desc.php

@@ -0,0 +1,118 @@
+<?php
+
+require_once (__DIR__ . '/../inc/header.inc.php');
+require_once(BX_DIRECTORY_PATH_INC . 'design.inc.php');
+
+$baseDir = __DIR__ . DIRECTORY_SEPARATOR . '..';
+
+$foldersRecursive = [
+    'inc',
+    'modules',
+    'periodic',
+    'studio',
+    'template'
+];
+
+// skip any path containing /modules/*/*/updates
+function shouldSkip($path) {
+    // normalize for safety
+    $path = str_replace('\\', '/', $path);
+
+    // matches: modules/anything/anything/updates
+    if (preg_match('#/modules/[^/]+/[^/]+/updates(/|$)#', $path)) {
+        return true;
+    }
+
+    return false;
+}
+
+$pattern = '/@hookdef\s+hook-[^\s]+\s+\'([^\']+)\'\s*,\s*\'([^\']+)\'\s*-\s*(.+)/';
+
+$result = [];
+
+function processFile($baseDir, $filePath, $pattern, &$result) {
+    $handle = fopen($filePath, 'r');
+    if (!$handle) return;
+
+    $lineNumber = 0;
+
+    while (($line = fgets($handle)) !== false) {
+        $lineNumber++;
+
+        if (strpos($line, '@hookdef') === false) continue;
+
+        if (preg_match($pattern, $line, $m)) {
+            $result[] = [
+                'file'   => str_replace($baseDir . DIRECTORY_SEPARATOR, '', $filePath),
+                'line'   => $lineNumber,
+                'unit'   => $m[1],
+                'action' => $m[2],
+                'desc'   => trim($m[3]),
+            ];
+        }
+    }
+
+    fclose($handle);
+}
+
+/**
+ * Base dir (non-recursive)
+ */
+foreach (scandir($baseDir) as $file) {
+    $path = $baseDir . DIRECTORY_SEPARATOR . $file;
+
+    if (is_file($path) && pathinfo($path, PATHINFO_EXTENSION) === 'php') {
+        processFile($baseDir, $path, $pattern, $result);
+    }
+}
+
+/**
+ * Recursive folders with skip logic
+ */
+foreach ($foldersRecursive as $folder) {
+    $dir = $baseDir . DIRECTORY_SEPARATOR . $folder;
+
+    if (!is_dir($dir)) continue;
+
+    $directory = new RecursiveDirectoryIterator(
+        $dir,
+        FilesystemIterator::SKIP_DOTS
+    );
+
+    $filter = new RecursiveCallbackFilterIterator(
+        $directory,
+        function ($current, $key, $iterator) {
+
+            $path = $current->getPathname();
+
+            // skip unwanted subtree
+            if (shouldSkip($path)) {
+                return false;
+            }
+
+            return true;
+        }
+    );
+
+    $iterator = new RecursiveIteratorIterator($filter);
+
+    foreach ($iterator as $file) {
+        if ($file->getExtension() !== 'php') continue;
+
+        processFile($baseDir, $file->getPathname(), $pattern, $result);
+    }
+}
+
+/**
+ * Output
+ */
+BxDolDb::getInstance()->query("TRUNCATE TABLE sys_alerts_desc");
+foreach ($result as $row) {
+    echo "{$row['unit']} | {$row['action']} | {$row['desc']}\n";
+    echo "  -> {$row['file']}:{$row['line']}\n\n";
+    BxDolDb::getInstance()->query("INSERT IGNORE INTO sys_alerts_desc SET `unit` = :unit, `action` = :action, `description` = :desc", [
+        'unit' => $row['unit'],
+        'action' => $row['action'],
+        'desc' => $row['desc']
+    ]);
+}

+ 3 - 0
studio/classes/BxDolStudioInstaller.php

@@ -981,6 +981,9 @@ class BxDolStudioInstaller extends BxDolInstallerUtils
         // delete SEO links
         // delete SEO links
         BxDolPage::deleteSeoLinkByModule($this->_aConfig['name']);
         BxDolPage::deleteSeoLinkByModule($this->_aConfig['name']);
 
 
+        // delete alerts
+        BxDolAlerts::deleteModuleAlerts($this->_aConfig['name']);
+
         // queue for deletion storage files
         // queue for deletion storage files
         if(!empty($this->_aConfig['storages']) && is_array($this->_aConfig['storages']))        
         if(!empty($this->_aConfig['storages']) && is_array($this->_aConfig['storages']))        
             foreach($this->_aConfig['storages'] as $s)
             foreach($this->_aConfig['storages'] as $s)

+ 12 - 0
studio/template/agents_agents_alerts_payload.html

@@ -0,0 +1,12 @@
+<div id="bx-agents-agents-alert-payload">
+    
+    <div class="payload-off" style="display:__text-visibility__">
+        __text__
+    </div>
+
+    <div class="payload-on" style="display:__payload-visibility__">
+        <i>__desc__</i>
+        <pre class="bx-def-border">__payload__</pre>
+    </div>
+
+</div>

+ 42 - 0
studio/template/agents_agents_alerts_select.html

@@ -0,0 +1,42 @@
+<div id="bx-agents-agents-alert-cont" style="overflow:visible;">
+<select id="bx-agents-agents-alert" name="alert" class="bx-def-font-inputs bx-form-input-select">
+    <bx_repeat:alerts>
+        <option value="__value__" <bx_if:sel>__sel__</bx_if:sel> data-desc="__desc__">__name__</option>
+    </bx_repeat:alerts>
+</select>
+</div>
+<script>
+    function formatItem(state) {
+        if (!state.id) 
+            return state.text;
+        const desc = $(state.element).data('desc');
+        return $(`
+            <div>
+                <div class="bx-alert-text">${state.text}</div>
+                <div class="bx-alert-desc">${desc || ''}</div>
+            </div>
+        `);
+    }
+    $('#bx-agents-agents-alert').select2({
+        templateResult: formatItem,
+        templateSelection: d => d.text,
+    });
+
+    $('#bx-agents-agents-alert').on('change', function () {
+        const value = $(this).val();
+        const sUrl = sUrlRoot + "grid.php?o=__grid_object__&a=get_alert&csrf_token=" + window.glGrids.__grid_object__._sCsrfToken;
+        $.post(sUrl, {alert: value}, function(oResult) {
+            if (typeof(oResult.code) !== 'undefined' && oResult.code == 200) {
+                $('#bx-agents-agents-alert-payload .payload-on i').html(oResult.desc);
+                $('#bx-agents-agents-alert-payload .payload-on pre').html(JSON.stringify(oResult.payload, null, 4));
+                $('#bx-agents-agents-alert-payload .payload-on').show();
+                $('#bx-agents-agents-alert-payload .payload-off').hide();
+            } else {
+                $('#bx-agents-agents-alert-payload .payload-on').hide();
+                $('#bx-agents-agents-alert-payload .payload-off').show();
+            }
+        }, 'json');
+    });
+
+
+</script>

+ 20 - 0
studio/template/css/agents.css

@@ -116,3 +116,23 @@
     display: inline-block;
     display: inline-block;
     float: none;
     float: none;
 }
 }
+
+#bx-agents-agents-alert-payload pre {
+    max-height:250px; 
+    overflow:scroll;
+}
+
+.select2-container {
+    z-index: 999999 !important;
+}
+.select2-container .select2-selection--single {
+    height: 30px;
+}
+
+.select2-results__option .bx-alert-text {
+    font-weight:600;
+}
+.select2-results__option .bx-alert-desc {
+    font-size:12px;
+    color:#888;
+}

+ 81 - 18
studio/template/scripts/BxBaseStudioAgentsAgents.php

@@ -27,6 +27,16 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
         return 'oBxDolStudioPageAgents';
         return 'oBxDolStudioPageAgents';
     }
     }
 
 
+    public function performActionGetAlert()
+    {
+        $aAlert = $this->_getAlertPayload(bx_get('alert'));
+        echoJson([
+            'code' => $aAlert ? 200 : 404,
+            'desc' => $aAlert ? $this->_oDb->getAlertDesc(bx_get('alert')) : '',
+            'payload' => $aAlert,
+        ]);
+    }
+
     public function performActionManual()
     public function performActionManual()
     {
     {
         $iId = $this->_getId();        
         $iId = $this->_getId();        
@@ -360,34 +370,33 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
                     'type' => 'custom',
                     'type' => 'custom',
                     'name' => 'alert_sample',
                     'name' => 'alert_sample',
                     'caption' => _t('_sys_agents_field_alert_sample'),
                     'caption' => _t('_sys_agents_field_alert_sample'),
-                    'content' => isset($aAgent['alert_sample']) ? $aAgent['alert_sample'] : _t('_sys_agents_waiting_for_sample_data'),
-                ],
-                'alert_unit' => [
-                    'type' => 'text',
-                    'name' => 'alert_unit',
-                    'caption' => _t('_sys_agents_field_alert_unit'),
-                    'info' => _t('_sys_agents_field_alert_unit_info'),
-                    'value' => isset($aAgent['alert_unit']) ? $aAgent['alert_unit'] : '',
-                    'db' => [
-                        'pass' => 'Xss',
-                    ],
+                    'content' => $this->_oTemplate->parseHtmlByName('agents_agents_alerts_payload.html', [
+                        'text-visibility' => empty($aAgent['alert']) ? 'block' : 'none',
+                        'text' => _t('_sys_agents_waiting_for_sample_data'),
+
+                        'payload-visibility' => !empty($aAgent['alert']) ? 'block' : 'none',
+                        'desc' => $this->_oDb->getAlertDesc($aAgent['alert']),
+                        'payload' => !empty($aAgent['alert']) ? json_encode($this->_getAlertPayload($aAgent['alert']), JSON_PRETTY_PRINT) : '',
+                    ]),
                 ],
                 ],
-                'alert_action' => [
-                    'type' => 'text',
-                    'name' => 'alert_action',
-                    'caption' => _t('_sys_agents_field_alert_action'),
-                    'value' => isset($aAgent['alert_action']) ? $aAgent['alert_action'] : '',
+
+                'alert' => [
+                    'type' => 'custom',
+                    'name' => 'alert',
+                    'caption' => _t('_sys_agents_field_alert'),
+                    'info' => _t('_sys_agents_field_alert_info'),
+                    'content' => $this->_oTemplate->parseHtmlByName('agents_agents_alerts_select.html', $this->_getAlertValues(isset($aAgent['alert']) ? $aAgent['alert'] : '')),
                     'db' => [
                     'db' => [
                         'pass' => 'Xss',
                         'pass' => 'Xss',
                     ],
                     ],
                 ],
                 ],
 
 
-                'scheduler_section' => array(
+                'scheduler_section' => [
                     'type' => 'block_header',
                     'type' => 'block_header',
                     'caption' => 'Trigger - scheduler',
                     'caption' => 'Trigger - scheduler',
                     'collapsable' => true,
                     'collapsable' => true,
                     'collapsed' => true,
                     'collapsed' => true,
-                ),
+                ],
 
 
                 'scheduler_cron' => [
                 'scheduler_cron' => [
                     'type' => 'text',
                     'type' => 'text',
@@ -541,6 +550,52 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
         return $aForm;
         return $aForm;
     }
     }
 
 
+    protected function _getAlertPayload($s)
+    {
+        $aAlert = $this->_oDb->getAlert($s);
+        if (!$aAlert)
+            return '';
+        return [
+            'object_id' => $aAlert['object'],
+            'sender_profile_id' => $aAlert['sender'],            
+            'extra' => json_decode($aAlert['extra'], true),
+            'extra_modifiable_keys' => json_decode($aAlert['extra_refs'], true),
+        ];
+    }
+
+    protected function _getAlertValues($sValue)
+    {
+        $aAlerts = $this->_oDb->getAlerts();
+        $a = [
+            'grid_object' => $this->_sObject,
+            'bx_repeat:alerts' => [
+                [
+                    'name' => _t('_sys_please_select'), 
+                    'value' => '', 
+                    'desc' => '', 
+                    'bx_if:sel' => [
+                        'condition' => false,
+                        'content' => ['sel' => '']
+                    ]
+                ]
+            ]
+        ];
+        foreach ($aAlerts as $k => $r) {
+            $a['bx_repeat:alerts'][] = [
+                'name' => $r['name'],
+                'value' => $r['key'],
+                'desc' => bx_html_attribute($r['desc']),
+                'bx_if:sel' => [
+                    'condition' => $sValue == $r['key'],
+                    'content' => [
+                        'sel' => $sValue == $r['key'] ? 'selected' : '',
+                    ]
+                ]
+            ];
+        }
+        return $a;
+    }
+
     protected function _getUniqName($sName)
     protected function _getUniqName($sName)
     {
     {
         return uriGenerate($sName, 'sys_agents_automators', 'name', ['lowercase' => false]);
         return uriGenerate($sName, 'sys_agents_automators', 'name', ['lowercase' => false]);
@@ -635,6 +690,14 @@ class BxBaseStudioAgentsAgents extends BxDolStudioAgentsAgents
 
 
         return null;
         return null;
     }
     }
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+
+        $this->_oTemplate->addJs(['select2/js/select2.min.js']);
+        $this->_oTemplate->addCss([BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'select2/css/|select2.min.css']);
+    }
 }
 }
 
 
 /** @} */
 /** @} */

+ 63 - 1
template/css/tailwind.css

@@ -1587,4 +1587,66 @@
     .filepond--drop-label label{
     .filepond--drop-label label{
         @apply leading-6 text-base font-medium text-gray-700 dark:text-gray-300;
         @apply leading-6 text-base font-medium text-gray-700 dark:text-gray-300;
     }
     }
-}
+}
+
+/* Select2 dark/light styles */
+
+/* Base container */
+.select2-container .select2-selection--single {
+    @apply h-10 flex items-center border rounded-md px-3;
+}
+
+/* Light mode */
+.select2-container--default .select2-selection--single {
+    @apply bg-white border-gray-300 text-gray-900;
+}
+
+/* Dark mode */
+.dark .select2-container--default .select2-selection--single .select2-selection__rendered,
+.dark .select2-container--default .select2-selection--single {
+    @apply bg-gray-800 border-gray-600 text-gray-100;
+}
+
+/* Dropdown */
+.select2-dropdown {
+    @apply rounded-md border shadow-lg;
+}
+
+/* Light dropdown */
+.select2-container--default .select2-dropdown {
+    @apply bg-white border-gray-300;
+}
+
+/* Dark dropdown */
+.dark .select2-container--default .select2-dropdown {
+    @apply bg-gray-800 border-gray-600;
+}
+
+/* Options */
+.select2-results__option {
+    @apply px-3 py-2 cursor-pointer;
+}
+
+/* Hover / active */
+.select2-results__option--highlighted {
+    @apply bg-blue-500 text-white;
+}
+
+/* Selected item */
+.select2-results__option[aria-selected=true] {
+    @apply bg-blue-100;
+}
+
+.dark .select2-container--default .select2-results__option--highlighted.select2-results__option--selectable,
+.dark .select2-results__option[aria-selected=true] {
+    @apply bg-blue-700 text-white;
+}
+
+/* Search input */
+.select2-search__field {
+    @apply w-full px-2 py-1 border rounded-md;
+}
+
+.dark .select2-search__field {
+    @apply bg-gray-700 border-gray-600 text-white;
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов