Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sat, Feb 22, 12:00 AM

in-portal

Index: branches/5.3.x/core/kernel/utility/email.php
===================================================================
--- branches/5.3.x/core/kernel/utility/email.php (revision 15917)
+++ branches/5.3.x/core/kernel/utility/email.php (revision 15918)
@@ -1,862 +1,877 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2012 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kEmail extends kBase {
/**
* Reference to class, that could send out e-mail
*
* @var kEmailSendingHelper
* @access protected
*/
protected $sender = null;
/**
* Parameters of e-mail
*
* @var Array
* @access protected
* @see kEmail::_getCustomParams() List of possible system parameters supported
*/
protected $params = Array ();
/**
* Reference to e-mail template object, that would be used as data source
*
* @var kDBItem
*/
protected $emailTemplate = null;
/**
* Sender name
*
* @var string
* @access protected
*/
protected $fromName = '';
/**
* Sender e-mail
*
* @var string
* @access protected
*/
protected $fromEmail = '';
/**
* Recipient name
*
* @var string
* @access protected
*/
protected $toName = '';
/**
* Recipient e-mail
*
* @var string
* @access protected
*/
protected $toEmail = '';
/**
* ID of recipient user
*
* @var int
*/
protected $recipientUserId = null;
/**
* List of e-mail recipients
*
* @var Array
* @access protected
*/
protected $recipients = Array (
EmailTemplate::RECIPIENT_TYPE_TO => Array (),
EmailTemplate::RECIPIENT_TYPE_CC => Array (),
EmailTemplate::RECIPIENT_TYPE_BCC => Array (),
);
/**
* Creates e-mail instance
*/
public function __construct()
{
parent::__construct();
$this->sender = $this->Application->recallObject('EmailSender');
}
/**
* Resets state of e-mail
*
* @return void
* @access protected
*/
protected function _resetState()
{
$this->fromEmail = $this->fromName = '';
$this->Application->removeObject('u.email-from');
$this->recipients = Array (
EmailTemplate::RECIPIENT_TYPE_TO => Array (),
EmailTemplate::RECIPIENT_TYPE_CC => Array (),
EmailTemplate::RECIPIENT_TYPE_BCC => Array (),
);
$this->toEmail = $this->toEmail = '';
$this->Application->removeObject('u.email-to');
}
/**
* Finds e-mail template matching user data
*
* @param string $name
* @param int $type
* @return bool
* @throws InvalidArgumentException
* @access public
*/
public function findTemplate($name, $type)
{
if ( !$name || !preg_match('/^[A-Z\.]+$/', $name) ) {
throw new InvalidArgumentException('Invalid e-mail template name "<strong>' . $name . '</strong>". Only <strong>UPPERCASE characters</strong> and <strong>dots</strong> are allowed.');
}
if ( $type != EmailTemplate::TEMPLATE_TYPE_ADMIN && $type != EmailTemplate::TEMPLATE_TYPE_FRONTEND ) {
throw new InvalidArgumentException('Invalid e-mail template type');
}
// use "-item" special prevent error, when e-mail sent out from e-mail templates list
$this->emailTemplate = $this->Application->recallObject('email-template.-item', null, Array ('skip_autoload' => true));
if ( !$this->emailTemplate->isLoaded() || !$this->_sameTemplate($name, $type) ) {
// get template parameters by name & type
$this->emailTemplate->Load(Array ('TemplateName' => $name, 'Type' => $type));
}
return $this->_templateUsable();
}
/**
* Detects, that given e-mail template data matches currently used e-mail template
*
* @param string $name
* @param int $type
* @return bool
* @access protected
*/
protected function _sameTemplate($name, $type)
{
return $this->emailTemplate->GetDBField('TemplateName') == $name && $this->emailTemplate->GetDBField('Type') == $type;
}
/**
* Determines if we can use e-mail template we've found based on user data
*
* @return bool
* @access protected
*/
protected function _templateUsable()
{
if ( !$this->emailTemplate->isLoaded() || $this->emailTemplate->GetDBField('Enabled') == STATUS_DISABLED ) {
return false;
}
if ( $this->emailTemplate->GetDBField('FrontEndOnly') && $this->Application->isAdmin ) {
return false;
}
return true;
}
/**
* Sets e-mail template params
*
* @param Array $params
* @access public
*/
public function setParams($params)
{
$this->params = $params;
}
/**
* Returns any custom parameters, that are passed when invoked e-mail template sending
*
* @return Array
* @access protected
*/
protected function _getCustomParams()
{
$ret = $this->params;
$send_keys = Array ('from_email', 'from_name', 'to_email', 'to_name', 'overwrite_to_email', 'language_id', 'use_custom_design', 'delivery');
foreach ($send_keys as $send_key) {
unset($ret[$send_key]);
}
return $ret;
}
/**
* Sends e-mail now or puts it in queue
*
* @param int $recipient_user_id
* @return bool
* @access public
*/
public function send($recipient_user_id = null)
{
$this->recipientUserId = $recipient_user_id;
$this->_resetState();
$this->_processSender();
$this->_processRecipients();
$this->_changeLanguage(false);
// 1. set headers
- $message_headers = $this->_getHeaders();
+ try {
+ $message_headers = $this->_getHeaders();
+ }
+ catch ( Exception $e ) {
+ trigger_error('Error parsing e-mail message headers', E_USER_WARNING);
+
+ return false;
+ }
+
$message_subject = isset($message_headers['Subject']) ? $message_headers['Subject'] : 'Mail message';
$this->sender->SetSubject($message_subject);
foreach ($message_headers as $header_name => $header_value) {
$this->sender->SetEncodedHeader($header_name, $header_value);
}
if ( $this->_storeEmailLog() ) {
// 2. prepare log
$log_fields_hash = Array (
'From' => $this->fromName . ' (' . $this->fromEmail . ')',
'To' => $this->toName . ' (' . $this->toEmail . ')',
'OtherRecipients' => serialize($this->recipients),
'Subject' => $message_subject,
'SentOn' => TIMENOW,
'TemplateName' => $this->emailTemplate->GetDBField('TemplateName'),
'EventType' => $this->emailTemplate->GetDBField('Type'),
'EventParams' => serialize($this->_getCustomParams()),
);
$this->params['email_access_key'] = $this->_generateAccessKey($log_fields_hash);
}
// 3. set body
- $html_message_body = $this->_getMessageBody(true);
- $plain_message_body = $this->_getMessageBody(false);
+ try {
+ $html_message_body = $this->_getMessageBody(true);
+ $plain_message_body = $this->_getMessageBody(false);
+ }
+ catch ( Exception $e ) {
+ trigger_error('Error parsing e-mail message body', E_USER_WARNING);
+
+ return false;
+ }
if ( $html_message_body === false && $plain_message_body === false ) {
trigger_error('Message template is empty (maybe after parsing).', E_USER_WARNING);
return false;
}
if ( $html_message_body !== false ) {
$this->sender->CreateTextHtmlPart($html_message_body, true);
}
if ( $plain_message_body !== false ) {
$this->sender->CreateTextHtmlPart($plain_message_body, false);
}
$this->_changeLanguage(true);
if ( $this->_storeEmailLog() ) {
// 4. set log
$log_fields_hash['HtmlBody'] = $html_message_body;
$log_fields_hash['TextBody'] = $plain_message_body;
$log_fields_hash['AccessKey'] = $this->params['email_access_key'];
$this->sender->setLogData($log_fields_hash);
}
$delivery = isset($this->params['delivery']) ? $this->params['delivery'] : $this->Application->ConfigValue('EmailDelivery');
return $this->sender->Deliver(null, $delivery == EmailDelivery::IMMEDIATE);
}
/**
* Determines whatever we should keep e-mail log or not
*
* @return bool
* @access protected
*/
protected function _storeEmailLog()
{
return $this->Application->ConfigValue('EnableEmailLog');
}
/**
* Generates access key for accessing e-mail later
*
* @param Array $log_fields_hash
* @return string
* @access protected
*/
protected function _generateAccessKey($log_fields_hash)
{
$ret = '';
$use_fields = Array ('From', 'To', 'Subject');
foreach ($use_fields as $use_field) {
$ret .= $log_fields_hash[$use_field] . ':';
}
return md5($ret . microtime(true));
}
/**
* Processes email sender
*
* @return void
* @access protected
*/
protected function _processSender()
{
if ( $this->emailTemplate->GetDBField('CustomSender') ) {
$this->_processCustomSender();
}
// update with custom data given during event execution
if ( isset($this->params['from_email']) ) {
$this->fromEmail = $this->params['from_email'];
}
if ( isset($this->params['from_name']) ) {
$this->fromName = $this->params['from_name'];
}
// still nothing, set defaults
$this->_ensureDefaultSender();
$this->sender->SetFrom($this->fromEmail, $this->fromName);
}
/**
* Processes custom e-mail sender
*
* @return void
* @access protected
*/
protected function _processCustomSender()
{
$address = $this->emailTemplate->GetDBField('SenderAddress');
$address_type = $this->emailTemplate->GetDBField('SenderAddressType');
switch ($address_type) {
case EmailTemplate::ADDRESS_TYPE_EMAIL:
$this->fromEmail = $address;
break;
case EmailTemplate::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
$this->fromEmail = $user_info['Email'];
$this->fromName = 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 ( $this->emailTemplate->GetDBField('SenderName') ) {
$this->fromName = $this->emailTemplate->GetDBField('SenderName');
}
}
/**
* Ensures, that sender name & e-mail are not empty
*
* @return void
* @access protected
*/
protected function _ensureDefaultSender()
{
if ( !$this->fromEmail ) {
$this->fromEmail = $this->Application->ConfigValue('DefaultEmailSender');
}
if ( !$this->fromName ) {
$this->fromName = strip_tags($this->Application->ConfigValue('Site_Name'));
}
}
/**
* Processes email recipients
*
* @return void
* @access protected
*/
protected function _processRecipients()
{
$this->_collectRecipients();
$header_mapping = Array (
EmailTemplate::RECIPIENT_TYPE_TO => 'To',
EmailTemplate::RECIPIENT_TYPE_CC => 'Cc',
EmailTemplate::RECIPIENT_TYPE_BCC => 'Bcc',
);
$default_email = $this->Application->ConfigValue('DefaultEmailSender');
$this->recipients = array_map(Array ($this, '_transformRecipientsIntoPairs'), $this->recipients);
foreach ($this->recipients as $recipient_type => $recipients) {
// add recipients to email
if ( !$recipients ) {
continue;
}
if ( $recipient_type == EmailTemplate::RECIPIENT_TYPE_TO ) {
$this->toEmail = $recipients[0]['email'] ? $recipients[0]['email'] : $default_email;
$this->toName = $recipients[0]['name'] ? $recipients[0]['name'] : $this->toEmail;
}
$header_name = $header_mapping[$recipient_type];
foreach ($recipients as $recipient) {
$email = $recipient['email'] ? $recipient['email'] : $default_email;
$name = $recipient['name'] ? $recipient['name'] : $email;
$this->sender->AddRecipient($header_name, $email, $name);
}
}
}
/**
* Collects e-mail recipients from various sources
*
* @return void
* @access protected
*/
protected function _collectRecipients()
{
$this->_addRecipientsFromXml($this->emailTemplate->GetDBField('Recipients'));
$this->_overwriteToRecipient();
$this->_addRecipientByUserId();
$this->_addRecipientFromParams();
if ( ($this->emailTemplate->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_ADMIN) && !$this->recipients[EmailTemplate::RECIPIENT_TYPE_TO] ) {
// admin email template without direct recipient -> send to admin
$this->_addDefaultRecipient();
}
}
/**
* Adds multiple recipients from an XML
*
* @param string $xml
* @return bool
* @access protected
*/
protected function _addRecipientsFromXml($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) {
$this->recipients[$record['RecipientType']][] = $record;
}
return true;
}
/**
* Remove all "To" recipients, when not allowed
*
* @return void
* @access protected
*/
protected function _overwriteToRecipient()
{
$overwrite_to_email = isset($this->params['overwrite_to_email']) ? $this->params['overwrite_to_email'] : false;
if ( !$this->emailTemplate->GetDBField('CustomRecipient') || $overwrite_to_email ) {
$this->recipients[EmailTemplate::RECIPIENT_TYPE_TO] = Array ();
}
}
/**
* Update with custom data given during event execution (user_id)
*
* @return void
* @access protected
*/
protected function _addRecipientByUserId()
{
if ( !is_numeric($this->recipientUserId) ) {
return;
}
if ( $this->recipientUserId <= 0 ) {
// recipient is system user with negative ID (root, guest, etc.) -> send to admin
$this->_addDefaultRecipient();
return;
}
$language_field = $this->emailTemplate->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_FRONTEND ? 'FrontLanguage' : 'AdminLanguage';
$sql = 'SELECT FirstName, LastName, Email, ' . $language_field . ' AS Language
FROM ' . TABLE_PREFIX . 'Users
WHERE PortalUserId = ' . $this->recipientUserId;
$user_info = $this->Conn->GetRow($sql);
if ( !$user_info ) {
return;
}
$add_recipient = Array (
'RecipientAddressType' => EmailTemplate::ADDRESS_TYPE_EMAIL,
'RecipientAddress' => $user_info['Email'],
'RecipientName' => trim($user_info['FirstName'] . ' ' . $user_info['LastName']),
);
if ( $user_info['Language'] && !isset($this->params['language_id']) ) {
$this->params['language_id'] = $user_info['Language'];
}
array_unshift($this->recipients[EmailTemplate::RECIPIENT_TYPE_TO], $add_recipient);
$user = $this->Application->recallObject('u.email-to', null, Array('skip_autoload' => true));
/* @var $user UsersItem */
$user->Load($this->recipientUserId);
}
/**
* Update with custom data given during event execution (email + name)
*
* @return void
* @access protected
*/
protected function _addRecipientFromParams()
{
$add_recipient = Array ();
if ( isset($this->params['to_email']) && $this->params['to_email'] ) {
$add_recipient['RecipientName'] = '';
$add_recipient['RecipientAddressType'] = EmailTemplate::ADDRESS_TYPE_EMAIL;
$add_recipient['RecipientAddress'] = $this->params['to_email'];
}
if ( isset($this->params['to_name']) && $this->params['to_name'] ) {
$add_recipient['RecipientName'] = $this->params['to_name'];
}
if ( $add_recipient ) {
array_unshift($this->recipients[EmailTemplate::RECIPIENT_TYPE_TO], $add_recipient);
}
}
/**
* This is default recipient, when we can't determine actual one
*
* @return void
* @access protected
*/
protected function _addDefaultRecipient()
{
$xml = $this->Application->ConfigValue('DefaultEmailRecipients');
if ( !$this->_addRecipientsFromXml($xml) ) {
$recipient = Array (
'RecipientName' => $this->Application->ConfigValue('DefaultEmailSender'),
'RecipientAddressType' => EmailTemplate::ADDRESS_TYPE_EMAIL,
'RecipientAddress' => $this->Application->ConfigValue('DefaultEmailSender'),
);
array_unshift($this->recipients[EmailTemplate::RECIPIENT_TYPE_TO], $recipient);
}
}
/**
* Transforms recipients into name/e-mail pairs
*
* @param Array $recipients
* @return Array
* @access protected
*/
protected function _transformRecipientsIntoPairs($recipients)
{
if ( !$recipients ) {
return Array ();
}
$pairs = Array ();
foreach ($recipients as $recipient) {
$address = $recipient['RecipientAddress'];
$address_type = $recipient['RecipientAddressType'];
$recipient_name = $recipient['RecipientName'];
switch ($address_type) {
case EmailTemplate::ADDRESS_TYPE_EMAIL:
$pairs[] = Array ('email' => $address, 'name' => $recipient_name);
break;
case EmailTemplate::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 EmailTemplate::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;
}
}
return $pairs;
}
/**
* Change system language temporarily to send e-mail on user language
*
* @param bool $restore
* @return void
* @access protected
*/
protected function _changeLanguage($restore = false)
{
static $prev_language_id = null;
if ( !isset($prev_language_id) ) {
$prev_language_id = $this->Application->GetVar('m_lang');
}
// ensure that language is set
if ( !isset($this->params['language_id']) ) {
$this->params['language_id'] = $this->Application->GetVar('m_lang');
}
$language_id = $restore ? $prev_language_id : $this->params['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 ();
}
/**
* Parses message headers into array
*
* @return Array
* @access protected
*/
protected function _getHeaders()
{
$headers = $this->emailTemplate->GetDBField('Headers');
$headers = 'Subject: ' . $this->emailTemplate->GetField('Subject') . ($headers ? "\n" . $headers : '');
$headers = explode("\n", $this->_parseText($headers));
$ret = Array ();
foreach ($headers as $header) {
$header = explode(':', $header, 2);
$ret[ trim($header[0]) ] = trim($header[1]);
}
if ( $this->Application->isDebugMode() ) {
// set special header with template name, so it will be easier to determine what's actually was received
$template_type = $this->emailTemplate->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_ADMIN ? 'ADMIN' : 'USER';
$ret['X-Template-Name'] = $this->emailTemplate->GetDBField('TemplateName') . ' - ' . $template_type;
}
return $ret;
}
/**
* Applies design to given e-mail text
*
* @param string $text
* @param bool $is_html
* @return string
* @access protected
*/
protected function _applyMessageDesign($text, $is_html = true)
{
static $design_templates = Array();
$design_key = 'L' . $this->params['language_id'] . ':' . ($is_html ? 'html' : 'text');
if ( !isset($design_templates[$design_key]) ) {
$language = $this->Application->recallObject('lang.current');
/* @var $language LanguagesItem */
$design_template = $language->GetDBField($is_html ? 'HtmlEmailTemplate' : 'TextEmailTemplate');
if ( !$is_html && !$design_template ) {
$design_template = $this->sender->ConvertToText($language->GetDBField('HtmlEmailTemplate'), true);
}
$design_templates[$design_key] = $design_template;
}
return $this->_parseText(str_replace('$body', $text, $design_templates[$design_key]), $is_html);
}
/**
* Returns message body
*
* @param bool $is_html
* @return bool|string
* @access protected
*/
protected function _getMessageBody($is_html = false)
{
$message_body = $this->emailTemplate->GetField($is_html ? 'HtmlBody' : 'PlainTextBody');
if ( !trim($message_body) && !$is_html ) {
// no plain text part available -> make it from html part then
$message_body = $this->sender->ConvertToText($this->emailTemplate->GetField('HtmlBody'), true);
}
if ( !trim($message_body) ) {
return false;
}
if ( isset($this->params['use_custom_design']) && $this->params['use_custom_design'] ) {
$message_body = $this->_parseText($message_body, $is_html);
}
else {
$message_body = $this->_applyMessageDesign($message_body, $is_html);
}
return trim($message_body) ? $message_body : false;
}
/**
* Parse message template and return headers (as array) and message body part
*
* @param string $text
* @param bool $is_html
* @return string
* @access protected
*/
protected function _parseText($text, $is_html = true)
{
$text = $this->_substituteReplacementTags($text);
if ( !$text ) {
return '';
}
// init for cases, when e-mail is sent from event before page template rendering
$this->Application->InitParser();
$parser_params = $this->Application->Parser->Params; // backup parser params
$this->Application->Parser->SetParams($this->params);
$text = $this->Application->Parser->Parse($this->_normalizeLineEndings($text), 'email_template');
$this->Application->Parser->SetParams($parser_params); // restore parser params
$category_helper = $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
return $category_helper->replacePageIds($is_html ? $this->_removeTrailingLineEndings($text) : $text);
}
/**
* Substitutes replacement tags in given text
*
* @param string $text
* @return string
* @access protected
*/
protected function _substituteReplacementTags($text)
{
$default_replacement_tags = Array (
'<inp:touser _Field="password"' => '<inp2:u_Field name="Password_plain"',
'<inp:touser _Field="UserName"' => '<inp2:u_Field name="Username"',
'<inp:touser _Field' => '<inp2:u_Field name',
);
$replacement_tags = $this->emailTemplate->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) {
$text = str_replace($replace_from, $replace_to, $text);
}
return $text;
}
/**
* Convert Unix/Windows/Mac line ending into Unix line endings
*
* @param string $text
* @return string
* @access protected
*/
protected function _normalizeLineEndings($text)
{
return str_replace(Array ("\r\n", "\r"), "\n", $text);
}
/**
* Remove trailing line endings
*
* @param $text
* @return string
* @access protected
*/
protected function _removeTrailingLineEndings($text)
{
return preg_replace('/(\n|\r)+/', "\\1", $text);
}
-}
\ No newline at end of file
+}
Index: branches/5.3.x/core/units/email_templates/email_template_eh.php
===================================================================
--- branches/5.3.x/core/units/email_templates/email_template_eh.php (revision 15917)
+++ branches/5.3.x/core/units/email_templates/email_template_eh.php (revision 15918)
@@ -1,689 +1,689 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class EmailTemplateEventHandler extends kDBEventHandler
{
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnFrontOnly' => Array ('self' => 'edit'),
'OnSaveSelected' => Array ('self' => 'view'),
'OnExportEmailTemplates' => 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'),
'OnSend' => 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
+ // checking permission when listing 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->getUnitConfig($main_prefix)->getPermSectionByName('email');
$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;
}
$config = $event->getUnitConfig();
$sql = 'UPDATE ' . $config->getTableName() . '
SET FrontEndOnly = 1
WHERE ' . $config->getIDField() . ' IN (' . implode(',', $this->StoreSelectedIDs($event)) . ')';
$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 ) {
list ($user_id, ) = each($items_info);
$config = $event->getUnitConfig();
$ids = $this->Application->RecallVar($event->getPrefixSpecial() . '_selected_ids');
$sql = 'UPDATE ' . $config->getTableName() . '
SET ' . $this->Application->RecallVar('dst_field') . ' = ' . $user_id . '
WHERE ' . $config->getIDField() . ' IN (' . $ids . ')';
$this->Conn->Query($sql);
}
$this->finalizePopup($event);
}
/**
* Saves selected ids to session
*
* @param kEvent $event
*/
function OnSaveSelected($event)
{
$this->StoreSelectedIDs($event);
}
/**
* 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;
}
$config = $event->getUnitConfig();
$fields = $config->getFields();
$fields['Module']['options'] = $options;
$config->setFields($fields);
if ( $this->Application->GetVar('regional') ) {
$config->setPopulateMlFields(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', EmailTemplate::RECIPIENT_TYPE_TO);
}
else {
$object->SetDBField('RecipientType', EmailTemplate::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 EmailTemplate::ADDRESS_TYPE_EMAIL:
$field = 'Email';
$table_name = TABLE_PREFIX . 'Users';
break;
case EmailTemplate::ADDRESS_TYPE_USER:
$field = 'Username';
$table_name = TABLE_PREFIX . 'Users';
break;
case EmailTemplate::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 '<suggestions>';
foreach ($data as $item) {
echo '<item>' . kUtil::escape($item, kUtil::ESCAPE_HTML) . '</item>';
}
echo '</suggestions>';
}
/**
* 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_template_helper = $this->Application->recallObject('kEmailTemplateHelper');
/* @var $email_template_helper kEmailTemplateHelper */
$email_template_helper->parseField($object, 'Subject');
$email_template_helper->parseField($object, 'HtmlBody');
$email_template_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 EmailTemplate::ADDRESS_TYPE_EMAIL:
if ( !preg_match('/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', $address) ) {
$object->SetError($field_prefix . 'Address', 'invalid_email');
}
break;
case EmailTemplate::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 EmailTemplate::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 OnExportEmailTemplates(kEvent $event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
$this->Application->getUnitConfig('phrases')->setAutoLoad(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 EmailTemplateId = ' . $object->GetID();
$ids = $this->Conn->GetCol($sql);
if ( !$ids ) {
return;
}
$temp_handler = $this->Application->recallObject('system-event-subscription_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event->MasterEvent));
/* @var $temp_handler kTempTablesHandler */
$temp_handler->DeleteItems('system-event-subscription', '', $ids);
}
/**
* Sends selected e-mail event
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSend(kEvent $event)
{
$object = $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$ids = $this->StoreSelectedIDs($event);
foreach ($ids as $id) {
$object->Load($id);
if ( $object->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_ADMIN ) {
$this->Application->emailAdmin($object->GetDBField('TemplateName'));
}
else {
$this->Application->emailUser($object->GetDBField('TemplateName'));
}
}
$this->clearSelectedIDs($event);
}
}
\ No newline at end of file

Event Timeline