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)); } 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')); } /** * 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); } /** * Returns email event object based on given kEvent object * * @param kEvent $event * @return kDBItem */ function &_getEmailEvent($event) { $false = false; $name = $event->getEventParam('EmailEventName'); $type = $event->getEventParam('EmailEventType'); $object =& $event->getObject( Array('skip_autoload' => true) ); /* @var $object kDBItem */ if (!$object->isLoaded() || ($object->GetDBField('Event') != $name || $object->GetDBField('Type') != $type)) { // get event parameters by name & type $load_keys = Array ('Event' => $name, 'Type' => $type); $object->Load($load_keys); if (!$object->isLoaded() || ($object->GetDBField('Enabled') == STATUS_DISABLED)) { // event record not found OR is disabled return $false; } if ($object->GetDBField('FrontEndOnly') && $this->Application->isAdmin) { return $false; } } return $object; } /** * Processes email sender * * @param kEvent $event * @param Array $direct_params */ function _processSender($event, $direct_params = Array ()) { $this->Application->removeObject('u.email-from'); $object =& $this->_getEmailEvent($event); /* @var $object kDBItem */ $email = $name = ''; // set defaults from event if ($object->GetDBField('CustomSender')) { $address = $object->GetDBField('SenderAddress'); $address_type = $object->GetDBField('SenderAddressType'); switch ($address_type) { case EmailEvent::ADDRESS_TYPE_EMAIL: $email = $address; break; case EmailEvent::ADDRESS_TYPE_USER: $sql = 'SELECT FirstName, LastName, Email, PortalUserId FROM ' . TABLE_PREFIX . 'Users WHERE Username = ' . $this->Conn->qstr($address); $user_info = $this->Conn->GetRow($sql); if ($user_info) { // user still exists $email = $user_info['Email']; $name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']); $user =& $this->Application->recallObject('u.email-from', null, Array('skip_autoload' => true)); /* @var $user UsersItem */ $user->Load($user_info['PortalUserId']); } break; } if ($object->GetDBField('SenderName')) { $name = $object->GetDBField('SenderName'); } } // update with custom data given during event execution if (array_key_exists('from_email', $direct_params)) { $email = $direct_params['from_email']; } if (array_key_exists('from_name', $direct_params)) { $name = $direct_params['from_name']; } // still nothing, set defaults if (!$email) { $email = $this->Application->ConfigValue('DefaultEmailSender'); } if (!$name) { $name = strip_tags( $this->Application->ConfigValue('Site_Name') ); } $esender =& $this->Application->recallObject('EmailSender'); /* @var $esender kEmailSendingHelper */ $esender->SetFrom($email, $name); return Array ($email, $name); } /** * Processes email recipients * * @param kEvent $event * @param Array $direct_params * @return Array */ function _processRecipients($event, &$direct_params = Array ()) { $this->Application->removeObject('u.email-to'); $object =& $this->_getEmailEvent($event); /* @var $object kDBItem */ $to_email = $to_name = ''; $all_recipients = Array (); $this->_addRecipientsFromXml($all_recipients, $object->GetDBField('Recipients')); if ( !array_key_exists(EmailEvent::RECIPIENT_TYPE_TO, $all_recipients) ) { $all_recipients[EmailEvent::RECIPIENT_TYPE_TO] = Array (); } // remove all "To" recipients, when not allowed $overwrite_to_email = array_key_exists('overwrite_to_email', $direct_params) ? $direct_params['overwrite_to_email'] : false; if ( !$object->GetDBField('CustomRecipient') || $overwrite_to_email ) { $all_recipients[EmailEvent::RECIPIENT_TYPE_TO] = Array (); } // update with custom data given during event execution (user_id) $to_user_id = $event->getEventParam('EmailEventToUserId'); if ( $to_user_id > 0 ) { $language_field = $event->getEventParam('EmailEventType') == EmailEvent::EVENT_TYPE_FRONTEND ? 'FrontLanguage' : 'AdminLanguage'; $sql = 'SELECT FirstName, LastName, Email, ' . $language_field . ' AS Language FROM ' . TABLE_PREFIX . 'Users WHERE PortalUserId = ' . $to_user_id; $user_info = $this->Conn->GetRow($sql); if ( $user_info ) { $add_recipient = Array ( 'RecipientAddressType' => EmailEvent::ADDRESS_TYPE_EMAIL, 'RecipientAddress' => $user_info['Email'], 'RecipientName' => trim($user_info['FirstName'] . ' ' . $user_info['LastName']), ); if ( $user_info['Language'] && !isset($direct_params['language_id']) ) { $direct_params['language_id'] = $user_info['Language']; } array_unshift($all_recipients[EmailEvent::RECIPIENT_TYPE_TO], $add_recipient); $user =& $this->Application->recallObject('u.email-to', null, Array('skip_autoload' => true)); /* @var $user UsersItem */ $user->Load($to_user_id); } } elseif ( is_numeric($to_user_id) ) { // recipient is system user with negative ID (root, guest, etc.) -> send to admin $this->_addDefaultRecipient($all_recipients); } // update with custom data given during event execution (email + name) $add_recipient = Array (); if ( array_key_exists('to_email', $direct_params) ) { $add_recipient['RecipientName'] = ''; $add_recipient['RecipientAddressType'] = EmailEvent::ADDRESS_TYPE_EMAIL; $add_recipient['RecipientAddress'] = $direct_params['to_email']; } if ( array_key_exists('to_name', $direct_params) ) { $add_recipient['RecipientName'] = $direct_params['to_name']; } if ( $add_recipient ) { array_unshift($all_recipients[EmailEvent::RECIPIENT_TYPE_TO], $add_recipient); } if ( ($object->GetDBField('Type') == EmailEvent::EVENT_TYPE_ADMIN) && !$all_recipients[EmailEvent::RECIPIENT_TYPE_TO] ) { // admin email event without direct recipient -> send to admin $this->_addDefaultRecipient($all_recipients); } $esender =& $this->Application->recallObject('EmailSender'); /* @var $esender kEmailSendingHelper */ $header_mapping = Array ( EmailEvent::RECIPIENT_TYPE_TO => 'To', EmailEvent::RECIPIENT_TYPE_CC => 'Cc', EmailEvent::RECIPIENT_TYPE_BCC => 'Bcc', ); $default_email = $this->Application->ConfigValue('DefaultEmailSender'); foreach ($all_recipients as $recipient_type => $recipients) { // add recipients to email $pairs = Array (); foreach ($recipients as $recipient) { $address = $recipient['RecipientAddress']; $address_type = $recipient['RecipientAddressType']; $recipient_name = $recipient['RecipientName']; switch ($address_type) { case EmailEvent::ADDRESS_TYPE_EMAIL: $pairs[] = Array ('email' => $address, 'name' => $recipient_name); break; case EmailEvent::ADDRESS_TYPE_USER: $sql = 'SELECT FirstName, LastName, Email FROM ' . TABLE_PREFIX . 'Users WHERE Username = ' . $this->Conn->qstr($address); $user_info = $this->Conn->GetRow($sql); if ($user_info) { // user still exists $name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']); $pairs[] = Array ( 'email' => $user_info['Email'], 'name' => $name ? $name : $recipient_name, ); } break; case EmailEvent::ADDRESS_TYPE_GROUP: $sql = 'SELECT u.FirstName, u.LastName, u.Email FROM ' . TABLE_PREFIX . 'UserGroups g JOIN ' . TABLE_PREFIX . 'UserGroupRelations ug ON ug.GroupId = g.GroupId JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = ug.PortalUserId WHERE g.Name = ' . $this->Conn->qstr($address); $users = $this->Conn->Query($sql); foreach ($users as $user_info) { $name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']); $pairs[] = Array ( 'email' => $user_info['Email'], 'name' => $name ? $name : $recipient_name, ); } break; } } if ( !$pairs ) { continue; } if ( $recipient_type == EmailEvent::RECIPIENT_TYPE_TO ) { $to_email = $pairs[0]['email'] ? $pairs[0]['email'] : $default_email; $to_name = $pairs[0]['name'] ? $pairs[0]['name'] : $to_email; } $header_name = $header_mapping[$recipient_type]; foreach ($pairs as $pair) { $email = $pair['email'] ? $pair['email'] : $default_email; $name = $pair['name'] ? $pair['name'] : $email; $esender->AddRecipient($header_name, $email, $name); } } return Array ($to_email, $to_name); } /** * This is default recipient, when we can't determine actual one * * @param Array $recipients * @return void */ function _addDefaultRecipient(&$recipients) { $xml = $this->Application->ConfigValue('DefaultEmailRecipients'); if ( !$this->_addRecipientsFromXml($recipients, $xml) ) { $recipient = Array ( 'RecipientName' => $this->Application->ConfigValue('DefaultEmailSender'), 'RecipientAddressType' => EmailEvent::ADDRESS_TYPE_EMAIL, 'RecipientAddress' => $this->Application->ConfigValue('DefaultEmailSender'), ); array_unshift($recipients[EmailEvent::RECIPIENT_TYPE_TO], $recipient); } } /** * Adds multiple recipients from an XML * * @param Array $recipients * @param string $xml * @return bool * @access protected */ protected function _addRecipientsFromXml(&$recipients, $xml) { if ( !$xml ) { return false; } $minput_helper =& $this->Application->recallObject('MInputHelper'); /* @var $minput_helper MInputHelper */ // group recipients by type $records = $minput_helper->parseMInputXML($xml); foreach ($records as $record) { $recipient_type = $record['RecipientType']; if ( !array_key_exists($recipient_type, $recipients) ) { $recipients[$recipient_type] = Array (); } $recipients[$recipient_type][] = $record; } return true; } /** * Returns email event message by ID (headers & body in one piece) * * @param kEvent $event * @param int $language_id * @return string */ function _getMessageBody($event, $language_id = null) { if (!isset($language_id)) { $language_id = $this->Application->GetVar('m_lang'); } $object =& $this->_getEmailEvent($event); // 1. get message body $message_body = $this->_formMessageBody($object, $language_id, $object->GetDBField('MessageType')); // 2. replace tags if needed $default_replacement_tags = Array ( ' ' ' 'GetDBField('ReplacementTags'); $replacement_tags = $replacement_tags ? unserialize($replacement_tags) : Array (); $replacement_tags = array_merge($default_replacement_tags, $replacement_tags); foreach ($replacement_tags as $replace_from => $replace_to) { $message_body = str_replace($replace_from, $replace_to, $message_body); } return $message_body; } /** * Prepare email message body * * @param kDBItem $object * @param int $language_id * @return string */ function _formMessageBody(&$object, $language_id) { $default_language_id = $this->Application->GetDefaultLanguageId(); $fields_hash = Array ( 'Headers' => $object->GetDBField('Headers'), ); // prepare subject $subject = $object->GetDBField('l' . $language_id . '_Subject'); if (!$subject) { $subject = $object->GetDBField('l' . $default_language_id . '_Subject'); } $fields_hash['Subject'] = $subject; // prepare body $body = $object->GetDBField('l' . $language_id . '_Body'); if (!$body) { $body = $object->GetDBField('l' . $default_language_id . '_Body'); } $fields_hash['Body'] = $body; $email_message_helper =& $this->Application->recallObject('EmailMessageHelper'); /* @var $email_message_helper EmailMessageHelper */ $ret = $email_message_helper->buildTemplate($fields_hash); // add footer $footer = $this->_getFooter($language_id, $object->GetDBField('MessageType')); if ($ret && $footer) { $ret .= "\r\n" . $footer; } return $ret; } /** * Returns email footer * * @param int $language_id * @param string $message_type * @return string */ function _getFooter($language_id, $message_type) { static $footer = null; if (!isset($footer)) { $default_language_id = $this->Application->GetDefaultLanguageId(); $sql = 'SELECT l' . $language_id . '_Body, l' . $default_language_id . '_Body FROM ' . $this->Application->getUnitOption('emailevents', 'TableName') . ' em WHERE Event = "COMMON.FOOTER"'; $footer_data = $this->Conn->GetRow($sql); $footer = $footer_data['l' . $language_id . '_Body']; if (!$footer) { $footer = $footer_data['l' . $default_language_id . '_Body']; } if ($message_type == 'text') { $esender =& $this->Application->recallObject('EmailSender'); /* @var $esender kEmailSendingHelper */ $footer = $esender->ConvertToText($footer); } } return $footer; } /** * Parse message template and return headers (as array) and message body part * * @param string $message * @param Array $direct_params * @return Array */ function ParseMessageBody($message, $direct_params = Array ()) { $message_language = $this->_getSendLanguage($direct_params); $this->_changeLanguage($message_language); $direct_params['message_text'] = isset($direct_params['message']) ? $direct_params['message'] : ''; // parameter alias // 1. parse template $this->Application->InitParser(); $parser_params = $this->Application->Parser->Params; // backup parser params $this->Application->Parser->SetParams( array_merge($parser_params, $direct_params) ); $message = implode('&|&', explode("\n\n", $message, 2)); // preserves double \n in case when tag is located in subject field $message = $this->Application->Parser->Parse($message, 'email_template', 0); $this->Application->Parser->SetParams($parser_params); // restore parser params // 2. replace line endings, that are send with data submitted via request $message = str_replace("\r\n", "\n", $message); // possible case $message = str_replace("\r", "\n", $message); // impossible case, but just in case replace this too // 3. separate headers from body $message_headers = Array (); list($headers, $message_body) = explode('&|&', $message, 2); $category_helper =& $this->Application->recallObject('CategoryHelper'); /* @var $category_helper CategoryHelper */ $message_body = $category_helper->replacePageIds($message_body); $headers = explode("\n", $headers); foreach ($headers as $header) { $header = explode(':', $header, 2); $message_headers[ trim($header[0]) ] = trim($header[1]); } $this->_changeLanguage(); return Array ($message_headers, $message_body); } /** * Raised when email message should be sent * * @param kEvent $event * @return void * @access protected */ protected function OnEmailEvent($event) { $email_event_name = $event->getEventParam('EmailEventName'); if ( strpos($email_event_name, '_') !== false ) { throw new Exception('Invalid email event name ' . $email_event_name . '. Use only UPPERCASE characters and dots as email event names'); } $object =& $this->_getEmailEvent($event); if ( !is_object($object) ) { // email event not found OR it's won't be send under given circumstances return ; } // additional parameters from kApplication->EmailEvent $send_params = $event->getEventParam('DirectSendParams'); // 1. get information about message sender and recipient list ($from_email, $from_name) = $this->_processSender($event, $send_params); list ($to_email, $to_name) = $this->_processRecipients($event, $send_params); // 2. prepare message to be sent $message_language = $this->_getSendLanguage($send_params); $message_template = $this->_getMessageBody($event, $message_language); if ( !trim($message_template) ) { trigger_error('Message template is empty', E_USER_WARNING); return ; } list ($message_headers, $message_body) = $this->ParseMessageBody($message_template, $send_params); if ( !trim($message_body) ) { trigger_error('Message template is empty after parsing', E_USER_WARNING); return ; } // 3. set headers & send message $esender =& $this->Application->recallObject('EmailSender'); /* @var $esender kEmailSendingHelper */ $message_subject = isset($message_headers['Subject']) ? $message_headers['Subject'] : 'Mail message'; $esender->SetSubject($message_subject); if ( $this->Application->isDebugMode() ) { // set special header with event name, so it will be easier to determine what's actually was received $message_headers['X-Event-Name'] = $email_event_name . ' - ' . ($object->GetDBField('Type') == EmailEvent::EVENT_TYPE_ADMIN ? 'ADMIN' : 'USER'); } foreach ($message_headers as $header_name => $header_value) { $esender->SetEncodedHeader($header_name, $header_value); } $esender->CreateTextHtmlPart($message_body, $object->GetDBField('MessageType') == 'html'); $log_fields_hash = Array ( 'fromuser' => $from_name . ' (' . $from_email . ')', 'addressto' => $to_name . ' (' . $to_email . ')', 'subject' => $message_subject, 'timestamp' => adodb_mktime(), 'event' => $email_event_name, 'EventParams' => serialize( $this->removeSendingParams($send_params) ), ); $esender->setLogData($log_fields_hash); $event->status = $esender->Deliver() ? kEvent::erSUCCESS : kEvent::erFAIL; } /** * Removes parameters, used during e-mail sending * * @param Array $params * @return Array * @access protected */ protected function removeSendingParams($params) { $send_keys = Array ('from_email', 'from_name', 'to_email', 'to_name', 'message'); foreach ($send_keys as $send_key) { unset($params[$send_key]); } return $params; } function _getSendLanguage($send_params) { if (array_key_exists('language_id', $send_params)) { return $send_params['language_id']; } return $this->Application->GetVar('m_lang'); } function _changeLanguage($language_id = null) { static $prev_language_id = null; if ( !isset($language_id) ) { // restore language $language_id = $prev_language_id; } $this->Application->SetVar('m_lang', $language_id); $language =& $this->Application->recallObject('lang.current'); /* @var $language LanguagesItem */ $language->Load($language_id); $this->Application->Phrases->LanguageId = $language_id; $this->Application->Phrases->Phrases = Array (); $prev_language_id = $language_id; // for restoring it later } /** * 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); } /** * Performs custom validation + keep read-only fields * * @param kEvent $event */ function _itemChanged($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'); 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); } } /** * 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', 'Body'); 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; } /** * Validates address using given field prefix * * @param kEvent $event * @param string $field_prefix */ 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; } } /** * 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 ''; } /** * Validates subject and body fields of Email template * @param kDBItem $object */ function _validateEmailTemplate(&$object) { $this->parseField($object, 'Subject'); $this->parseField($object, 'Body'); } /** * Parses contents of given object field and sets error, when invalid in-portal tags found * @param kDBItem $object * @param string $field * @return void */ function parseField(&$object, $field) { $this->Application->InitParser(); try { $this->Application->Parser->CompileRaw($object->GetField($field), 'email_template'); } catch (ParserException $e) { if ( $this->Application->isDebugMode() ) { $this->Application->Debugger->appendHTML('Error in Email Template: ' . $e->getMessage() . ' (line: ' . $e->getLine() . ')'); } $object->SetError($field, 'parsing_error'); } } /** * 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, ) ); } }