Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sun, Apr 20, 6:16 PM

in-portal

Index: branches/5.0.x/core/units/email_events/email_events_event_handler.php
===================================================================
--- branches/5.0.x/core/units/email_events/email_events_event_handler.php (revision 13012)
+++ branches/5.0.x/core/units/email_events/email_events_event_handler.php (revision 13013)
@@ -1,532 +1,537 @@
<?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 EmailEventsEventsHandler extends kDBEventHandler
{
/**
* Allows to override standart permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnFrontOnly' => Array('self' => 'edit'),
'OnSaveSelected' => Array('self' => 'view'),
'OnProcessEmailQueue' => Array('self' => 'add|edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Changes permission section to one from REQUEST, not from config
*
* @param kEvent $event
*/
function CheckPermission(&$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
* @access protected
* @see OnListBuild
*/
function SetCustomQuery(&$event)
{
if ($event->Special == 'module') {
$object =& $event->getObject();
$module = $this->Application->GetVar('module');
$object->addFilter('module_filter', '%1$s.Module = '.$this->Conn->qstr($module));
}
}
/**
* 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 = 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
*/
function OnSelectUser(&$event)
{
if ($event->Special != 'module') {
parent::OnSelectUser($event);
return ;
}
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = 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 sender & recipients ids plus event_id (as parameter by reference)
*
* @param kEvent $event
* @param int $event_id id of email event used
*
* @return mixed
*/
function GetMessageRecipients(&$event, &$event_id)
{
$email_event =& $event->getObject( Array('skip_autoload' => true) );
/* @var $email_event kDBItem */
// get event parameters by name & type
$load_keys = Array (
'Event' => $event->getEventParam('EmailEventName'),
'Type' => $event->getEventParam('EmailEventType'),
);
$email_event->Load($load_keys);
if (!$email_event->isLoaded()) {
// event record not found
return false;
}
if ($email_event->GetDBField('Enabled') == STATUS_DISABLED) {
return false;
}
if ($email_event->GetDBField('FrontEndOnly') && $this->Application->isAdmin) {
return false;
}
// initial values
$to_user_id = $event->getEventParam('EmailEventToUserId');
if ( !is_numeric($to_user_id) ) {
$to_user_id = -1; // when not specified, then send to "root"
}
$from_user_id = $email_event->GetDBField('FromUserId');
if ($email_event->GetDBField('Type') == EVENT_TYPE_ADMIN) {
// For type "Admin" recipient is a user from field FromUserId which means From/To user in Email events list
if ($to_user_id == -1) {
$to_user_id = $from_user_id;
}
$from_user_id = -1;
}
$event_id = $email_event->GetDBField('EventId');
return Array ($from_user_id, $to_user_id);
}
/**
* Returns user name, email by id, or ones, that specified in $direct_params
*
* @param int $user_id
* @param string $user_type type of user = {to,from}
* @param Array $direct_params
* @return Array
*/
function GetRecipientInfo($user_id, $user_type, $direct_params = null)
{
// load user, because it can be addressed from email template tags
$user =& $this->Application->recallObject('u.email-'.$user_type, null, Array('skip_autoload' => true));
/* @var $user UsersItem */
$email = $name = '';
$result = $user_id > 0 ? $user->Load( (int)$user_id ) : $user->Clear();
if ($user->IsLoaded()) {
$email = $user->GetDBField('Email');
$name = trim($user->GetDBField('FirstName').' '.$user->GetDBField('LastName'));
}
if (is_array($direct_params)) {
if (isset($direct_params[$user_type.'_email'])) {
$email = $direct_params[$user_type.'_email'];
}
if (isset($direct_params[$user_type.'_name'])) {
$name = $direct_params[$user_type.'_name'];
}
}
if (!$email) {
// if email is empty, then use admins email
$email = $this->Application->ConfigValue('Smtp_AdminMailFrom');
}
if (!$name) {
$name = $user_type == 'from' ? strip_tags($this->Application->ConfigValue('Site_Name')) : $email;
}
return Array ($email, $name);
}
/**
* Returns email event message by ID (headers & body in one piece)
*
* @param int $event_id
* @param string $message_type contains message type = {text,html}
* @param int $language_id
*/
function GetMessageBody($event_id, &$message_type, $language_id = null)
{
if (!isset($language_id)) {
$language_id = $this->Application->GetVar('m_lang');
}
$message =& $this->Application->recallObject('emailmessages', null, Array('skip_autoload' => true));
/* @var $message kDBItem */
$message->Load( Array('EventId' => $event_id, 'LanguageId' => $language_id) );
if (!$message->isLoaded()) {
// event translation on required language not found
return false;
}
$message_type = $message->GetDBField('MessageType');
// 1. get message body
$message_body = $message->GetDBField('Template');
// 2. add footer
$sql = 'SELECT em.Template
FROM '.$message->TableName.' em
LEFT JOIN '.TABLE_PREFIX.'Events e ON e.EventId = em.EventId
WHERE em.LanguageId = '.$language_id.' AND e.Event = "COMMON.FOOTER"';
list (, $footer) = explode("\n\n", $this->Conn->GetOne($sql));
if ($message_type == 'text') {
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$footer = $esender->ConvertToText($footer);
}
if ($footer) {
$message_body .= "\r\n".$footer;
}
// 3. replace tags if needed
$default_replacement_tags = Array (
'<inp:touser _Field="password"' => '<inp2:u_Field name="Password_plain"',
'<inp:touser _Field="UserName"' => '<inp2:u_Field name="Login"',
'<inp:touser _Field' => '<inp2:u_Field name',
);
$replacement_tags = $message->GetDBField('ReplacementTags');
$replacement_tags = $replacement_tags ? unserialize($replacement_tags) : Array ();
$replacement_tags = array_merge_recursive2($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;
}
/**
* 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 = null)
{
$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_recursive2($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 shoul be sent
*
* @param kEvent $event
*/
function OnEmailEvent(&$event)
{
$email_event_name = $event->getEventParam('EmailEventName');
if (strpos($email_event_name, '_') !== false) {
trigger_error('<span class="debug_error">Invalid email event name</span> <b>'.$email_event_name.'</b>. Use only <b>UPPERCASE characters</b> and <b>dots</b> as email event names', E_USER_ERROR);
}
// additional parameters from kApplication->EmailEvent
$send_params = $event->getEventParam('DirectSendParams');
// 1. get information about message sender and recipient
$recipients = $this->GetMessageRecipients($event, $event_id);
if ($recipients === false) {
// if not valid recipients found, then don't send event
return false;
}
list ($from_id, $to_id) = $recipients;
list ($from_email, $from_name) = $this->GetRecipientInfo($from_id, 'from', $send_params);
list ($to_email, $to_name) = $this->GetRecipientInfo($to_id, 'to', $send_params);
// 2. prepare message to be sent
$message_language = $this->_getSendLanguage($send_params);
$message_template = $this->GetMessageBody($event_id, $message_type, $message_language);
if (!trim($message_template)) {
trigger_error('Message template is empty', E_USER_WARNING);
return false;
}
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 false;
}
// 3. set headers & send message
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$esender->SetFrom($from_email, $from_name);
$esender->AddTo($to_email, $to_name);
$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 determite what's actually was received
$message_headers['X-Event-Name'] = $email_event_name . ' - ' . ($event->getEventParam('EmailEventType') == 1 ? 'ADMIN' : 'USER');
}
foreach ($message_headers as $header_name => $header_value) {
$esender->SetEncodedHeader($header_name, $header_value);
}
$esender->CreateTextHtmlPart($message_body, $message_type == 'html');
$event->status = $esender->Deliver() ? erSUCCESS : erFAIL;
if ($event->status == erSUCCESS){
// all keys, that are not used in email sending are written to log record
$send_keys = Array ('from_email', 'from_name', 'to_email', 'to_name', 'message');
foreach ($send_keys as $send_key) {
unset($send_params[$send_key]);
}
$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($send_params),
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'EmailLog');
}
$this->Application->removeObject('u.email-from');
$this->Application->removeObject('u.email-to');
}
function _getSendLanguage($send_params)
{
if ($send_params && 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 $lang_object kDBItem */
$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 = erSTOP;
echo ($emails_sent / $total_emails) * 100;
}
}
}
\ No newline at end of file

Event Timeline