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

Merge branch 'master' of https://github.com/unaio/una

RomanL 6 лет назад
Родитель
Сommit
70fe33779d

+ 4 - 4
inc/classes/BxDolModuleProxy.php

@@ -82,16 +82,16 @@ class BxDolModuleProxy
     /**
      * Dirty fix for pass by reference to BxNtfsTemplate::getNotificationEmail
      */
-    public function getNotificationEmail(&$aEvent)
+    public function getNotificationEmail($iRecipient, &$aEvent)
     {
-        return $this->_oProxifiedObject->getNotificationEmail($aEvent);
+        return $this->_oProxifiedObject->getNotificationEmail($iRecipient, $aEvent);
     }
     /**
      * Dirty fix for pass by reference to BxNtfsTemplate::getNotificationPush
      */
-    public function getNotificationPush(&$aEvent)
+    public function getNotificationPush($iRecipient, &$aEvent)
     {
-        return $this->_oProxifiedObject->getNotificationPush($aEvent);
+        return $this->_oProxifiedObject->getNotificationPush($iRecipient, $aEvent);
     }
 }
 

+ 1 - 1
inc/classes/BxDolPush.php

@@ -54,7 +54,7 @@ class BxDolPush extends BxDolFactory implements iBxDolSingleton
             $iProfileId = bx_get_logged_profile_id();
 
         $oProfile = BxDolProfile::getInstance($iProfileId);
-        $oAccount = $oProfile->getAccountObject();
+        $oAccount = $oProfile ? $oProfile->getAccountObject() : null;
         if (!$oProfile || !$oAccount)
             return false;
 

+ 40 - 13
modules/base/general/classes/BxBaseModGeneralModule.php

@@ -1302,19 +1302,19 @@ class BxBaseModGeneralModule extends BxDolModule
         );
 
         if(!empty($this->_oConfig->CNF['FIELDS_DELAYED_PROCESSING'])) {
-            $aResult = array_merge($aResult, array(
-                'handlers' => array(
-                    array('group' => $sModule . '_object_publish_failed', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'publish_failed', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_publish_failed', 'module_class' => 'Module', 'module_event_privacy' => ''),
-                    array('group' => $sModule . '_object_publish_succeeded', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'publish_succeeded', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_publish_succeeded', 'module_class' => 'Module', 'module_event_privacy' => ''),
-                ),
-                'settings' => array(
-                    array('group' => 'content_publish_failed', 'unit' => $sModule, 'action' => 'publish_failed', 'types' => array('personal')),
-                    array('group' => 'content_publish_succeeded', 'unit' => $sModule, 'action' => 'publish_succeeded', 'types' => array('personal')),
-                ),
-                'alerts' => array(
-                    array('unit' => $sModule, 'action' => 'publish_failed'),
-                    array('unit' => $sModule, 'action' => 'publish_succeeded'),
-                )
+            $aResult['handlers'] = array_merge($aResult['handlers'], array(
+                array('group' => $sModule . '_object_publish_failed', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'publish_failed', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_publish_failed', 'module_class' => 'Module', 'module_event_privacy' => ''),
+                array('group' => $sModule . '_object_publish_succeeded', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'publish_succeeded', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_publish_succeeded', 'module_class' => 'Module', 'module_event_privacy' => ''),
+            ));
+
+            $aResult['settings'] = array_merge($aResult['settings'], array(
+                array('group' => 'content_publish_failed', 'unit' => $sModule, 'action' => 'publish_failed', 'types' => array('personal')),
+                array('group' => 'content_publish_succeeded', 'unit' => $sModule, 'action' => 'publish_succeeded', 'types' => array('personal')),
+            ));
+
+            $aResult['alerts'] = array_merge($aResult['alerts'], array(
+                array('unit' => $sModule, 'action' => 'publish_failed'),
+                array('unit' => $sModule, 'action' => 'publish_succeeded'),
             ));
         }
 
@@ -1731,6 +1731,25 @@ class BxBaseModGeneralModule extends BxDolModule
 
         return $this->$sMethod($aContentInfo, $isPerformAction);
     }
+
+    /**
+     * Check particular action permission with content for specified profile
+     * @param $sAction action to check, for example: View, Edit
+     * @param $iContentId content ID
+     * @param $iProfileId profile ID which the permissions to be cheked for
+     * @return message on error, or CHECK_ACTION_RESULT_ALLOWED when allowed
+     */ 
+    public function serviceCheckAllowedWithContentForProfile($sAction, $iContentId, $iProfileId, $isPerformAction = false)
+    {
+        if (!$iContentId || !($aContentInfo = $this->_oDb->getContentInfoById($iContentId)))
+            return _t('_sys_request_page_not_found_cpt');
+
+        $sMethod = 'checkAllowed' . bx_gen_method_name($sAction) . 'ForProfile';
+        if (!method_exists($this, $sMethod))
+            return _t('_sys_request_method_not_found_cpt');
+
+        return $this->$sMethod($aContentInfo, $iProfileId, $isPerformAction);
+    }
     
     public function serviceCheckAllowedCommentsView($iContentId, $sObjectComments) 
     {
@@ -1852,6 +1871,14 @@ class BxBaseModGeneralModule extends BxDolModule
         return $this->serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction);
     }
 
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedViewForProfile ($aDataEntry, $iProfileId, $isPerformAction = false)
+    {
+        return $this->serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction, $iProfileId);
+    }
+
     /**
      * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
      */

+ 14 - 0
modules/boonex/notifications/classes/BxNtfsConfig.php

@@ -30,6 +30,7 @@ class BxNtfsConfig extends BxBaseModNotificationsConfig
     protected $_aModulesContexts;
 
     protected $_iDeliveryTimeout;
+    protected $_iProcessedEvent;
 
     /**
      * Constructor
@@ -123,6 +124,7 @@ class BxNtfsConfig extends BxBaseModNotificationsConfig
     	}
 
         $this->_iDeliveryTimeout = (int)getParam($sOptionPrefix . 'delivery_timeout');
+        $this->_iProcessedEvent = (int)getParam($sOptionPrefix . 'processed_event');
     }
 
     public function getOwnerNameMaxLen()
@@ -163,6 +165,18 @@ class BxNtfsConfig extends BxBaseModNotificationsConfig
         return $this->_iDeliveryTimeout;
     }
 
+    public function getProcessedEvent()
+    {
+        return $this->_iProcessedEvent;
+    }
+    
+    public function setProcessedEvent($iEvent)
+    {
+        $this->_iProcessedEvent = $iEvent;
+
+        setParam($this->getPrefix('option') . 'processed_event', $iEvent);
+    }
+
     /**
      * Ancillary functions
      */

+ 15 - 0
modules/boonex/notifications/classes/BxNtfsDb.php

@@ -221,6 +221,21 @@ class BxNtfsDb extends BxBaseModNotificationsDb
         return array($sJoinClause, $sWhereClause);
     }
 
+    public function getEventsToProcess()
+    {
+        $aEvents = $this->getAll("SELECT * FROM `" . $this->_sTable . "` WHERE `id`>:id", array('id' => $this->_oConfig->getProcessedEvent()));
+
+        if(!empty($aEvents) && is_array($aEvents)) {
+            $aEventEnd = end($aEvents);
+
+            $this->_oConfig->setProcessedEvent($aEventEnd['id']);
+
+            reset($aEvents);
+        }
+
+        return $aEvents;
+    }
+
     public function queueGet($aParams)
     {
     	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));

+ 22 - 137
modules/boonex/notifications/classes/BxNtfsResponse.php

@@ -46,12 +46,10 @@ class BxNtfsResponse extends BxBaseModNotificationsResponse
                 $aDataItems = $this->$sMethod($oAlert, $aHandler);
                 foreach($aDataItems as $aDataItem) {
                     $iId = $this->_oModule->_oDb->insertEvent($aDataItem);
-                    if(!empty($iId)) {
-                        if($iSilentMode != BX_NTFS_SLTMODE_SITE)
-                            $this->sendNotifications($iId, $oAlert, $aHandler);
+                    if(empty($iId))
+                        continue;
 
-                        $this->_oModule->onPost($iId);
-                    }
+                    $this->_oModule->onPost($iId);
                 }
                 break;
 
@@ -100,7 +98,7 @@ class BxNtfsResponse extends BxBaseModNotificationsResponse
                 'object_owner_id' => $this->_getObjectOwnerId($oAlert->aExtras),
                 'object_privacy_view' => $iObjectPrivacyView,
                 'subobject_id' => $iSubobjectId,
-                'content' => '',
+                'content' => $this->_getContent($oAlert->aExtras),
                 'allow_view_event_to' => $this->_oModule->_oConfig->getPrivacyViewDefault('event'),
                 'processed' => 0
     	    );
@@ -148,10 +146,6 @@ class BxNtfsResponse extends BxBaseModNotificationsResponse
         $iObjectPrivacyView = $this->_getObjectPrivacyView($oAlert->aExtras);
         $iPrivacyView = $this->_oModule->_oConfig->getPrivacyViewDefault('event');
 
-        $aContent = array(
-            'request' => empty($oAlert->aExtras['mutual']) ? 1 : 0
-        );
-
     	return array(
     	    array(
                 'owner_id' => $oAlert->aExtras['initiator'],
@@ -161,7 +155,9 @@ class BxNtfsResponse extends BxBaseModNotificationsResponse
                 'object_owner_id' => $oAlert->aExtras['content'],
                 'object_privacy_view' => $iObjectPrivacyView,
                 'subobject_id' => 0,
-                'content' => serialize($aContent),
+                'content' => $this->_getContent($oAlert->aExtras, array(
+                    'request' => empty($oAlert->aExtras['mutual']) ? 1 : 0
+                )),
                 'allow_view_event_to' => $iPrivacyView,
                 'processed' => 0
     	    )
@@ -203,7 +199,7 @@ class BxNtfsResponse extends BxBaseModNotificationsResponse
                 'object_owner_id' => $oAlert->aExtras['content'],
                 'object_privacy_view' => $this->_getObjectPrivacyView($oAlert->aExtras),
                 'subobject_id' => 0,
-                'content' => '',
+                'content' => $this->_getContent($oAlert->aExtras),
                 'allow_view_event_to' => $this->_oModule->_oConfig->getPrivacyViewDefault('event'),
                 'processed' => 0
     	    )
@@ -224,123 +220,6 @@ class BxNtfsResponse extends BxBaseModNotificationsResponse
         );
     }
 
-    protected function sendNotifications($iId, &$oAlert, &$aHandler)
-    {
-        $aDeliveryTypes = array();
-
-        $iSilentMode = $this->_getSilentMode($oAlert->aExtras);
-        switch($iSilentMode) {
-            case BX_NTFS_SLTMODE_ABSOLUTE:
-            case BX_NTFS_SLTMODE_SITE:
-                return;
-
-            case BX_NTFS_SLTMODE_SITE_EMAIL:
-                $aDeliveryTypes[] = BX_BASE_MOD_NTFS_DTYPE_EMAIL;
-                break;
-
-            case BX_NTFS_SLTMODE_SITE_PUSH:
-                $aDeliveryTypes[] = BX_BASE_MOD_NTFS_DTYPE_PUSH;
-                break;
-
-            default:
-                $aDeliveryTypes = array(BX_BASE_MOD_NTFS_DTYPE_EMAIL, BX_BASE_MOD_NTFS_DTYPE_PUSH);
-        }
-
-        $aEvent = $this->_oModule->_oDb->getEvents(array('browse' => 'id', 'value' => $iId));
-        if(empty($aEvent) || !is_array($aEvent))
-            return;
-
-        $aSendUsing = array();
-        foreach($aDeliveryTypes as $sDeliveryType) {
-            $aHidden = $this->_oModule->_oConfig->getHandlersHidden($sDeliveryType);
-            if(in_array($aHandler['id'], $aHidden))
-                continue;
-
-            $sMethodPostfix = bx_gen_method_name($sDeliveryType);
-            $sMethodGet = 'getNotification' . $sMethodPostfix;
-            $sMethodSend = 'sendNotification' . $sMethodPostfix;
-            if(!$this->_oModule->_oTemplate->isMethodExists($sMethodGet) || !method_exists($this->_oModule, $sMethodSend))
-                continue;
-
-            $mixedNotification = $this->_oModule->_oTemplate->$sMethodGet($aEvent);
-            if($mixedNotification === false)
-                continue;
-
-            $aSendUsing[$sDeliveryType] = array(
-            	'method' => $sMethodSend,
-                'notification' => $mixedNotification
-            );
-        }
-
-        if(empty($aSendUsing) || !is_array($aSendUsing))
-            return;
-
-        $iOwner = (int)$aEvent['owner_id'];
-        $aRecipients = array();
-
-        //--- Get recipients: Subscribers.
-        $oConnection = BxDolConnection::getObjectInstance($this->_oModule->_oConfig->getObject('conn_subscriptions'));
-        $aSubscribers = $oConnection->getConnectedInitiators($iOwner);
-        if(!empty($aSubscribers) && is_array($aSubscribers)) {
-            $oOwner = BxDolProfile::getInstance($iOwner);
-            $sSettingType = bx_srv($oOwner->getModule(), 'act_as_profile') ? BX_NTFS_STYPE_FOLLOW_MEMBER : BX_NTFS_STYPE_FOLLOW_CONTEXT;
-
-            foreach($aSubscribers as $iSubscriber) 
-                $this->_addRecipient($iSubscriber, $sSettingType, $aRecipients);
-        }
-
-        //--- Get recipients: Content owner.
-        $iObjectOwner = (int)$aEvent['object_owner_id'];
-        if($iOwner != $iObjectOwner)
-            $this->_addRecipient($iObjectOwner, BX_NTFS_STYPE_PERSONAL, $aRecipients);
-
-        $bDeliveryTimeout = $this->_oModule->_oConfig->getDeliveryTimeout() > 0;
-
-        //--- Check recipients and send notifications.
-        $oPrivacyInt = BxDolPrivacy::getObjectInstance($this->_oModule->_oConfig->getObject('privacy_view'));
-        $oPrivacyExt = $this->_oModule->_oConfig->getPrivacyObject($aEvent['type'] . '_' . $aEvent['action']);
-        foreach($aRecipients as $iRecipient => $aSettingTypes) {
-            $oProfile = BxDolProfile::getInstance($iRecipient);
-            if(!$oProfile)
-                continue;
-
-            if(!bx_srv($oProfile->getModule(), 'act_as_profile'))
-                continue;
-
-            if($oPrivacyExt !== false && !$oPrivacyExt->check($aEvent['id'], $iRecipient)) 
-                continue;
-
-            if($oPrivacyInt !== false && !$oPrivacyInt->check($aEvent['id'], $iRecipient))
-                continue;
-
-            foreach($aSendUsing as $sDeliveryType => $aDeliveryType)
-                foreach($aSettingTypes as $sSettingType) {
-                    $aSetting = $this->_oModule->_oDb->getSetting(array('by' => 'tsu_allowed', 'handler_id' => $aHandler['id'], 'delivery' => $sDeliveryType, 'type' => $sSettingType, 'user_id' => $iRecipient));
-                    if(empty($aSetting) || !is_array($aSetting))
-                        continue;
-
-                    if((int)$aSetting['active_adm'] == 0 || (int)$aSetting['active_pnl'] == 0)
-                        continue;
-
-                    /**
-                     * 'break' is essential in the next two conditions to avoid 
-                     * duplicate sending to the same recipient.
-                     */
-                    if($bDeliveryTimeout && $this->_oModule->_oDb->queueAdd(array(
-                        'profile_id' => $iRecipient, 
-                        'event_id' => $aEvent['id'], 
-                        'delivery' => $sDeliveryType,
-                        'content' => serialize($aDeliveryType['notification']),
-                        'date' => time()
-                    )) !== false)
-                        break;
-
-                    if($this->_oModule->{$aDeliveryType['method']}($oProfile, $aDeliveryType['notification']) !== false)
-                        break;
-                }
-        }
-    }
-
     protected function _getObjectOwnerId($aExtras)
     {
         $iResult = parent::_getObjectOwnerId($aExtras);
@@ -353,20 +232,26 @@ class BxNtfsResponse extends BxBaseModNotificationsResponse
         return 0;
     }
 
-    protected function _getSilentMode($aExtras)
+    protected function _getContent($aExtras, $aAdd = array())
     {
-        if(isset($aExtras['silent_mode']))
-            return (int)$aExtras['silent_mode'];
+        $aResult = array();
 
-        return BX_NTFS_SLTMODE_DISABLED;
+        $iSilentMode = $this->_getSilentMode($aExtras);
+        if($iSilentMode != BX_NTFS_SLTMODE_DISABLED)
+            $aResult['silent_mode'] = $iSilentMode;
+
+        if(!empty($aAdd) && is_array($aAdd))
+            $aResult = array_merge($aResult, $aAdd);
+
+        return !empty($aResult) && is_array($aResult) ? serialize($aResult) : '';
     }
 
-    protected function _addRecipient($iUser, $sSettingType, &$aRecipients)
+    protected function _getSilentMode($aExtras)
     {
-        if(!isset($aRecipients[$iUser]))
-            $aRecipients[$iUser] = array();
+        if(isset($aExtras['silent_mode']))
+            return (int)$aExtras['silent_mode'];
 
-        $aRecipients[$iUser][] = $sSettingType;
+        return BX_NTFS_SLTMODE_DISABLED;
     }
 }
 

+ 23 - 11
modules/boonex/notifications/classes/BxNtfsTemplate.php

@@ -129,18 +129,21 @@ class BxNtfsTemplate extends BxBaseModNotificationsTemplate
         if((int)$aEvent['processed'] == 0 || empty($aEvent['content']))
             return '';
 
-        $sParam = 'perform_privacy_check';
-        if(!isset($aBrowseParams[$sParam]) || $aBrowseParams[$sParam] === true) {
+        $sParamCheck = 'perform_privacy_check';
+        if(!isset($aBrowseParams[$sParamCheck]) || $aBrowseParams[$sParamCheck] === true) {
+            $sParamCheckFor = 'perform_privacy_check_for';
+            $iViewerId = !empty($aBrowseParams[$sParamCheckFor]) ? (int)$aBrowseParams[$sParamCheckFor] : 0;
+
             $oPrivacyInt = BxDolPrivacy::getObjectInstance($this->_oConfig->getObject('privacy_view'));
-            if(!$oPrivacyInt->check($aEvent['id']))
+            if(!$oPrivacyInt->check($aEvent['id'], $iViewerId))
                 return '';
 
             $oPrivacyExt = $oModule->_oConfig->getPrivacyObject($aEvent['type'] . '_' . $aEvent['action']);
-            if($oPrivacyExt !== false && !$oPrivacyExt->check($aEvent['id']))
+            if($oPrivacyExt !== false && !$oPrivacyExt->check($aEvent['id'], $iViewerId))
                 return '';
 
-            $sService = 'check_allowed_with_content';
-            if(BxDolRequest::serviceExists($aEvent['type'], $sService) && BxDolService::call($aEvent['type'], $sService, array('view', $this->_getContentObjectId($aEvent))) !== CHECK_ACTION_RESULT_ALLOWED)
+            $sService = 'check_allowed_with_content_for_profile';
+            if(BxDolRequest::serviceExists($aEvent['type'], $sService) && BxDolService::call($aEvent['type'], $sService, array('view', $this->_getContentObjectId($aEvent), $iViewerId)) !== CHECK_ACTION_RESULT_ALLOWED)
                 return '';
         }
 
@@ -232,9 +235,9 @@ class BxNtfsTemplate extends BxBaseModNotificationsTemplate
         ));
     }
 
-    public function getNotificationEmail(&$aEvent)
+    public function getNotificationEmail($iRecipient, &$aEvent)
     {
-        $sEvent = $this->getPost($aEvent, array('perform_privacy_check' => false, 'show_real_profile' => false));
+        $sEvent = $this->getPost($aEvent, array('perform_privacy_check_for' => $iRecipient, 'show_real_profile' => false));
         if(empty($sEvent) || empty($aEvent['content_parsed']))
             return false;
 
@@ -250,9 +253,9 @@ class BxNtfsTemplate extends BxBaseModNotificationsTemplate
         );
     }
 
-    public function getNotificationPush(&$aEvent)
+    public function getNotificationPush($iRecipient, &$aEvent)
     {
-        $sEvent = $this->getPost($aEvent, array('perform_privacy_check' => false, 'show_real_profile' => false));
+        $sEvent = $this->getPost($aEvent, array('perform_privacy_check_for' => $iRecipient, 'show_real_profile' => false));
         if(empty($sEvent) || empty($aEvent['content_parsed']))
             return false;
 
@@ -302,7 +305,16 @@ class BxNtfsTemplate extends BxBaseModNotificationsTemplate
             unset($aContent['entry_privacy']);
         }
 
-        $aEvent['content'] = $aContent;
+        if(!empty($aEvent['content'])) {
+            if(is_string($aEvent['content']))
+                $aEvent['content'] = unserialize($aEvent['content']);
+
+            if(is_array($aEvent['content']))
+                $aEvent['content'] = array_merge($aEvent['content'], $aContent);
+        }
+        else
+            $aEvent['content'] = $aContent;
+
         $aEvent['processed'] = 1;
 
         $aSet = array_merge($aSet, array(

+ 1 - 0
modules/boonex/notifications/install/langs/en.xml

@@ -42,6 +42,7 @@
     <string name="_bx_ntfs_option_events_hide_push"><![CDATA[Push notifications]]></string>
     <string name="_bx_ntfs_option_enable_group_settings"><![CDATA[Group Settings]]></string>
     <string name="_bx_ntfs_option_delivery_timeout"><![CDATA[Delay before sending Email and/or Push notifications (in seconds)]]></string>
+    <string name="_bx_ntfs_option_processed_event"><![CDATA[The last processed event upon notifications sending]]></string>
 
     <string name="_bx_ntfs_privacy_view"><![CDATA[View event]]></string>
 

+ 4 - 2
modules/boonex/notifications/install/sql/enable.sql

@@ -77,7 +77,8 @@ SET @iCategId = LAST_INSERT_ID();
 INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
 ('bx_notifications_events_hide_site', '', @iCategId, '_bx_ntfs_option_events_hide_site', 'rlist', '', '', '', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:21:"get_actions_checklist";}', 1),
 ('bx_notifications_events_hide_email', '', @iCategId, '_bx_ntfs_option_events_hide_email', 'rlist', '', '', '', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:21:"get_actions_checklist";}', 2),
-('bx_notifications_events_hide_push', '', @iCategId, '_bx_ntfs_option_events_hide_push', 'rlist', '', '', '', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:21:"get_actions_checklist";}', 3);
+('bx_notifications_events_hide_push', '', @iCategId, '_bx_ntfs_option_events_hide_push', 'rlist', '', '', '', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:21:"get_actions_checklist";}', 3),
+('bx_notifications_processed_event', '', @iCategId, '_bx_ntfs_option_processed_event', 'digit', '', '', '', '', 10);
 
 INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `hidden`, `order`) VALUES (@iTypeId, @sName, '_bx_ntfs', 0, 1);
 SET @iCategId = LAST_INSERT_ID();
@@ -152,4 +153,5 @@ INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `conf
 
 -- CRON
 INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
-('bx_notifications_queue', '* * * * *', 'BxNtfsCronQueue', 'modules/boonex/notifications/classes/BxNtfsCronQueue.php', '');
+('bx_notifications_queue', '* * * * *', 'BxNtfsCronQueue', 'modules/boonex/notifications/classes/BxNtfsCronQueue.php', ''),
+('bx_notifications_notify', '* * * * *', 'BxNtfsCronNotify', 'modules/boonex/notifications/classes/BxNtfsCronNotify.php', '');

+ 1 - 0
modules/boonex/russian/data/langs/bx_notifications/ru.xml

@@ -42,6 +42,7 @@
     <string name="_bx_ntfs_option_events_hide_push"><![CDATA[Push-уведомления]]></string>
     <string name="_bx_ntfs_option_enable_group_settings"><![CDATA[Сгруппировать настройки]]></string>
     <string name="_bx_ntfs_option_delivery_timeout"><![CDATA[Задержка перед отправкой Email и/или Push уведомлений (в секундах)]]></string>
+    <string name="_bx_ntfs_option_processed_event"><![CDATA[Последнее событие, обработанное в процессе отправки оповещений]]></string>
 
     <string name="_bx_ntfs_privacy_view"><![CDATA[Просматривать события]]></string>