Array ('self' => 'edit'), 'OnSaveSelected' => Array ('self' => 'view'), 'OnProcessEmailQueue' => Array ('self' => 'add|edit'), 'OnExportEmailEvents' => Array ('self' => 'view'), 'OnSuggestAddress' => Array ('self' => 'add|edit'), // events only for developers 'OnPreCreate' => Array ('self' => 'debug'), 'OnDelete' => Array ('self' => 'debug'), 'OnDeleteAll' => Array ('self' => 'debug'), 'OnMassDelete' => Array ('self' => 'debug'), 'OnMassApprove' => Array ('self' => 'debug'), 'OnMassDecline' => Array ('self' => 'debug'), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Changes permission section to one from REQUEST, not from config * * @param kEvent $event * @return bool * @access public */ public function CheckPermission(kEvent $event) { $module = $this->Application->GetVar('module'); if ( strlen($module) > 0 ) { // checking permission when lising module email events in separate section $module = explode(':', $module, 2); if ( count($module) == 1 ) { $main_prefix = $this->Application->findModule('Name', $module[0], 'Var'); } else { $exceptions = Array ('Category' => 'c', 'Users' => 'u'); $main_prefix = $exceptions[$module[1]]; } $section = $this->Application->getUnitOption($main_prefix . '.email', 'PermSection'); $event->setEventParam('PermSection', $section); } // checking permission when listing all email events when editing language return parent::CheckPermission($event); } /** * Apply any custom changes to list's sql query * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetCustomQuery(kEvent $event) { parent::SetCustomQuery($event); $object = $event->getObject(); /* @var $object kDBList */ if ( $event->Special == 'module' ) { $module = $this->Application->GetVar('module'); $object->addFilter('module_filter', '%1$s.Module = ' . $this->Conn->qstr($module)); } else { $object->addFilter('module_filter', '%1$s.Module IN (SELECT Name FROM ' . TABLE_PREFIX . 'Modules WHERE Loaded = 1)'); } if ( !$event->Special && !$this->Application->isDebugMode() ) { // no special $object->addFilter('enabled_filter', '%1$s.Enabled <> ' . STATUS_DISABLED); } } /** * Prepares new kDBItem object * * @param kEvent $event * @return void * @access protected */ protected function OnNew(kEvent $event) { parent::OnNew($event); $mapping = Array ('conf' => 'VariableValue', 'site-domain' => 'DefaultEmailRecipients'); if ( isset($mapping[$event->Special]) ) { $object = $event->getObject(); /* @var $object kDBItem */ $target_object = $this->Application->recallObject($event->Special); /* @var $target_object kDBList */ $object->SetDBField('Recipients', $target_object->GetDBField($mapping[$event->Special])); } } /** * Set default headers * * @param kEvent $event * @return void * @access protected */ protected function OnPreCreate(kEvent $event) { parent::OnPreCreate($event); $object = $event->getObject(); /* @var $object kDBItem */ $object->SetDBField('Headers', $this->Application->ConfigValue('Smtp_DefaultHeaders')); $this->setRequired($event); } /** * Sets status Front-End Only to selected email events * * @param kEvent $event */ function OnFrontOnly($event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $ids = implode(',', $this->StoreSelectedIDs($event)); $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName'); $sql = 'UPDATE ' . $table_name . ' SET FrontEndOnly = 1 WHERE EventId IN (' . $ids . ')'; $this->Conn->Query($sql); $this->clearSelectedIDs($event); } /** * Sets selected user to email events selected * * @param kEvent $event * @return void * @access protected */ protected function OnSelectUser(kEvent $event) { if ( $event->Special != 'module' ) { parent::OnSelectUser($event); return; } if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $items_info = $this->Application->GetVar('u'); if ( $items_info ) { $user_id = array_shift(array_keys($items_info)); $selected_ids = $this->getSelectedIDs($event, true); $ids = $this->Application->RecallVar($event->getPrefixSpecial() . '_selected_ids'); $id_field = $this->Application->getUnitOption($event->Prefix, 'IDField'); $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName'); $sql = 'UPDATE ' . $table_name . ' SET ' . $this->Application->RecallVar('dst_field') . ' = ' . $user_id . ' WHERE ' . $id_field . ' IN (' . $ids . ')'; $this->Conn->Query($sql); } $this->finalizePopup($event); } /** * Saves selected ids to session * * @param kEvent $event */ function OnSaveSelected($event) { $this->StoreSelectedIDs($event); } /** * Process emails from queue * * @param kEvent $event * @todo Move to MailingList */ function OnProcessEmailQueue($event) { $deliver_count = $event->getEventParam('deliver_count'); if ( $deliver_count === false ) { $deliver_count = $this->Application->ConfigValue('MailingListSendPerStep'); if ( $deliver_count === false ) { $deliver_count = 10; // 10 emails per script run (if not specified directly) } } $processing_type = $this->Application->GetVar('type'); if ( $processing_type = 'return_progress' ) { $email_queue_progress = $this->Application->RecallVar('email_queue_progress'); if ( $email_queue_progress === false ) { $emails_sent = 0; $sql = 'SELECT COUNT(*) FROM ' . TABLE_PREFIX . 'EmailQueue WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ')'; $total_emails = $this->Conn->GetOne($sql); $this->Application->StoreVar('email_queue_progress', $emails_sent . ':' . $total_emails); } else { list ($emails_sent, $total_emails) = explode(':', $email_queue_progress); } } $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'EmailQueue WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ') LIMIT 0,' . $deliver_count; $messages = $this->Conn->Query($sql); $message_count = count($messages); if ( !$message_count ) { // no messages left to send in queue if ( $processing_type = 'return_progress' ) { $this->Application->RemoveVar('email_queue_progress'); $this->Application->Redirect($this->Application->GetVar('finish_template')); } return; } $mailing_list_helper = $this->Application->recallObject('MailingListHelper'); /* @var $mailing_list_helper MailingListHelper */ $mailing_list_helper->processQueue($messages); if ( $processing_type = 'return_progress' ) { $emails_sent += $message_count; if ( $emails_sent >= $total_emails ) { $this->Application->RemoveVar('email_queue_progress'); $this->Application->Redirect($this->Application->GetVar('finish_template')); } $this->Application->StoreVar('email_queue_progress', $emails_sent . ':' . $total_emails); $event->status = kEvent::erSTOP; echo ($emails_sent / $total_emails) * 100; } } /** * Prefills module dropdown * * @param kEvent $event * @return void * @access protected */ protected function OnAfterConfigRead(kEvent $event) { parent::OnAfterConfigRead($event); $options = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { if ( $module_name == 'In-Portal' ) { continue; } $options[$module_name] = $module_name; } $fields = $this->Application->getUnitOption($event->Prefix, 'Fields'); $fields['Module']['options'] = $options; $this->Application->setUnitOption($event->Prefix, 'Fields', $fields); if ( $this->Application->GetVar('regional') ) { $this->Application->setUnitOption($event->Prefix, 'PopulateMlFields', true); } } /** * Prepare temp tables and populate it * with items selected in the grid * * @param kEvent $event * @return void * @access protected */ protected function OnEdit(kEvent $event) { parent::OnEdit($event); // use language from grid, instead of primary language used by default $event->SetRedirectParam('m_lang', $this->Application->GetVar('m_lang')); } /** * Fixes default recipient type * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemLoad(kEvent $event) { parent::OnAfterItemLoad($event); $object = $event->getObject(); /* @var $object kDBItem */ if ( !$this->Application->isDebugMode(false) ) { if ( $object->GetDBField('AllowChangingRecipient') ) { $object->SetDBField('RecipientType', EmailEvent::RECIPIENT_TYPE_TO); } else { $object->SetDBField('RecipientType', EmailEvent::RECIPIENT_TYPE_CC); } } // process replacement tags $records = Array (); $replacement_tags = $object->GetDBField('ReplacementTags'); $replacement_tags = $replacement_tags ? unserialize($replacement_tags) : Array (); foreach ($replacement_tags as $tag => $replacement) { $records[] = Array ('Tag' => $tag, 'Replacement' => $replacement); } $minput_helper = $this->Application->recallObject('MInputHelper'); /* @var $minput_helper MInputHelper */ $xml = $minput_helper->prepareMInputXML($records, Array ('Tag', 'Replacement')); $object->SetDBField('ReplacementTagsXML', $xml); $this->setRequired($event); } /** * Performs custom validation + keep read-only fields * * @param kEvent $event */ function _itemChanged($event) { $object = $event->getObject(); /* @var $object kDBItem */ if ( !$this->Application->isDebugMode(false) ) { // only allow to enable/disable event while in debug mode $to_restore = Array ('Enabled', 'AllowChangingSender', 'AllowChangingRecipient'); if ( !$object->GetOriginalField('AllowChangingSender') ) { $to_restore = array_merge($to_restore, Array ('CustomSender', 'SenderName', 'SenderAddressType', 'SenderAddress')); } if ( !$object->GetOriginalField('AllowChangingRecipient') ) { $to_restore = array_merge($to_restore, Array ('CustomRecipient' /*, 'Recipients'*/)); } // prevent specific fields from editing foreach ($to_restore as $restore_field) { $original_value = $object->GetOriginalField($restore_field); if ( $object->GetDBField($restore_field) != $original_value ) { $object->SetDBField($restore_field, $original_value); } } } // process replacement tags if ( $object->GetDBField('ReplacementTagsXML') ) { $minput_helper = $this->Application->recallObject('MInputHelper'); /* @var $minput_helper MInputHelper */ $replacement_tags = Array (); $records = $minput_helper->parseMInputXML($object->GetDBField('ReplacementTagsXML')); foreach ($records as $record) { $replacement_tags[trim($record['Tag'])] = trim($record['Replacement']); } $object->SetDBField('ReplacementTags', $replacement_tags ? serialize($replacement_tags) : NULL); } if ( $this->translationChanged($object) ) { $object->SetDBField('LastChanged_date', TIMENOW); $object->SetDBField('LastChanged_time', TIMENOW); } $this->setRequired($event); } /** * Dynamically changes required fields * * @param kEvent $event * @return void * @access protected */ protected function setRequired(kEvent $event) { $object = $event->getObject(); /* @var $object kDBItem */ $language_prefix = 'l' . $this->Application->GetVar('m_lang') . '_'; $object->setRequired($language_prefix . 'HtmlBody', !$object->GetField('PlainTextBody')); $object->setRequired($language_prefix . 'PlainTextBody', !$object->GetField('HtmlBody')); } /** * Checks, that at least one of phrase's translations was changed * * @param kDBItem $object * @return bool */ function translationChanged($object) { $changed_fields = array_keys($object->GetChangedFields()); $translation_fields = Array ('Subject', 'HtmlBody', 'PlainTextBody'); foreach ($changed_fields as $changed_field) { $changed_field = preg_replace('/^l[\d]+_/', '', $changed_field); if ( in_array($changed_field, $translation_fields) ) { return true; } } return false; } /** * Don't allow to enable/disable events in non-debug mode * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemCreate(kEvent $event) { parent::OnBeforeItemCreate($event); $this->_itemChanged($event); } /** * Don't allow to enable/disable events in non-debug mode * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemUpdate(kEvent $event) { parent::OnBeforeItemUpdate($event); $this->_itemChanged($event); } /** * Suggest address based on typed address and selected address type * * @param kEvent $event */ function OnSuggestAddress($event) { $event->status = kEvent::erSTOP; $address_type = $this->Application->GetVar('type'); $address = $this->Application->GetVar('value'); $limit = $this->Application->GetVar('limit'); if ( !$limit ) { $limit = 20; } switch ($address_type) { case EmailEvent::ADDRESS_TYPE_EMAIL: $field = 'Email'; $table_name = TABLE_PREFIX . 'Users'; break; case EmailEvent::ADDRESS_TYPE_USER: $field = 'Username'; $table_name = TABLE_PREFIX . 'Users'; break; case EmailEvent::ADDRESS_TYPE_GROUP: $field = 'Name'; $table_name = TABLE_PREFIX . 'UserGroups'; break; default: $field = $table_name = ''; break; } if ( $field ) { $sql = 'SELECT DISTINCT ' . $field . ' FROM ' . $table_name . ' WHERE ' . $field . ' LIKE ' . $this->Conn->qstr($address . '%') . ' ORDER BY ' . $field . ' ASC LIMIT 0,' . $limit; $data = $this->Conn->GetCol($sql); } else { $data = Array (); } $this->Application->XMLHeader(); echo ''; foreach ($data as $item) { echo '' . htmlspecialchars($item) . ''; } echo ''; } /** * Does custom validation * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemValidate(kEvent $event) { parent::OnBeforeItemValidate($event); $object = $event->getObject(); /* @var $object kDBItem */ // validate email subject and body for parsing errors $this->_validateEmailTemplate($object); // validate sender and recipient addresses if ( $object->GetDBField('CustomSender') ) { $this->_validateAddress($event, 'Sender'); } $this->_validateAddress($event, 'Recipient'); $this->_validateBindEvent($object); } /** * Validates subject and body fields of Email template * * @param kDBItem $object * @return void * @access protected */ protected function _validateEmailTemplate($object) { $email_message_helper = $this->Application->recallObject('kEmailMessageHelper'); /* @var $email_message_helper kEmailMessageHelper */ $email_message_helper->parseField($object, 'Subject'); $email_message_helper->parseField($object, 'HtmlBody'); $email_message_helper->parseField($object, 'PlainTextBody'); } /** * Validates address using given field prefix * * @param kEvent $event * @param string $field_prefix * @return void * @access protected */ protected function _validateAddress($event, $field_prefix) { $object = $event->getObject(); /* @var $object kDBItem */ $address_type = $object->GetDBField($field_prefix . 'AddressType'); $object->setRequired($field_prefix . 'Address', $address_type > 0); $address = $object->GetDBField($field_prefix . 'Address'); if ( !$address ) { // don't validate against empty address return; } switch ($address_type) { case EmailEvent::ADDRESS_TYPE_EMAIL: if ( !preg_match('/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', $address) ) { $object->SetError($field_prefix . 'Address', 'invalid_email'); } break; case EmailEvent::ADDRESS_TYPE_USER: $sql = 'SELECT PortalUserId FROM ' . TABLE_PREFIX . 'Users WHERE Username = ' . $this->Conn->qstr($address); if ( !$this->Conn->GetOne($sql) ) { $object->SetError($field_prefix . 'Address', 'invalid_user'); } break; case EmailEvent::ADDRESS_TYPE_GROUP: $sql = 'SELECT GroupId FROM ' . TABLE_PREFIX . 'UserGroups WHERE Name = ' . $this->Conn->qstr($address); if ( !$this->Conn->GetOne($sql) ) { $object->SetError($field_prefix . 'Address', 'invalid_group'); } break; } } /** * Checks that bind event is specified in correct format and exists * * @param kDBItem $object */ protected function _validateBindEvent($object) { $event_string = $object->GetDBField('BindToSystemEvent'); if ( !$event_string ) { return; } try { $this->Application->eventImplemented(new kEvent($event_string)); } catch (Exception $e) { $object->SetError('BindToSystemEvent', 'invalid_event', '+' . $e->getMessage()); } } /** * Stores ids of selected phrases and redirects to export language step 1 * * @param kEvent $event * @return void * @access protected */ protected function OnExportEmailEvents(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $this->Application->setUnitOption('phrases', 'AutoLoad', false); $this->StoreSelectedIDs($event); $this->Application->StoreVar('export_language_ids', $this->Application->GetVar('m_lang')); $event->setRedirectParams( Array ( 'phrases.export_event' => 'OnNew', 'pass' => 'all,phrases.export', 'export_mode' => $event->Prefix, ) ); } /** * Deletes all subscribers to e-mail event after it was deleted * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemDelete(kEvent $event) { parent::OnAfterItemDelete($event); $object = $event->getObject(); /* @var $object kDBItem */ $sql = 'SELECT SubscriptionId FROM ' . TABLE_PREFIX . 'SystemEventSubscriptions WHERE EmailEventId = ' . $object->GetID(); $ids = $this->Conn->GetCol($sql); if ( !$ids ) { return; } $temp_handler = $this->Application->recallObject('system-event-subscription_TempHandler', 'kTempTablesHandler'); /* @var $temp_handler kTempTablesHandler */ $temp_handler->DeleteItems('system-event-subscription', '', $ids); } }