function scm_ping($module, $username, $scm_name, $issues, $commit_msg) { // module is per file (svn hook) if (is_array($module)) { $module = null; } // process checkins for each issue foreach ($issues as $issue_id) { // check early if issue exists to report proper message back // workflow needs to know project_id to find out which workflow class to use. $prj_id = Issue::getProjectID($issue_id); if (empty($prj_id)) { echo "issue #{$issue_id} not found\n"; continue; } $files = array(); $nfiles = count($_GET['files']); for ($y = 0; $y < $nfiles; $y++) { $file = array('file' => $_GET['files'][$y], 'old_version' => isset($_GET['old_versions'][$y]) ? $_GET['old_versions'][$y] : null, 'new_version' => isset($_GET['new_versions'][$y]) ? $_GET['new_versions'][$y] : null, 'module' => isset($module) ? $module : $_GET['module'][$y]); $files[] = $file; } $commit_time = Date_Helper::getCurrentDateGMT(); SCM::addCheckins($issue_id, $commit_time, $scm_name, $username, $commit_msg, $files); // print report to stdout of commits so hook could report status back to commiter $details = Issue::getDetails($issue_id); echo "#{$issue_id} - {$details['iss_summary']} ({$details['sta_title']})\n"; } }
/** * Adds an email to the outgoing mail queue. * * @param string $recipient The recipient of this email * @param array $headers The list of headers that should be sent with this email * @param string $body The body of the message * @param integer $save_email_copy Whether to send a copy of this email to a configurable address or not (eventum_sent@) * @param integer $issue_id The ID of the issue. If false, email will not be associated with issue. * @param string $type The type of message this is. * @param integer $sender_usr_id The id of the user sending this email. * @param integer $type_id The ID of the event that triggered this notification (issue_id, sup_id, not_id, etc) * @return true, or a PEAR_Error object */ public static function add($recipient, $headers, $body, $save_email_copy = 0, $issue_id = false, $type = '', $sender_usr_id = false, $type_id = false) { Workflow::modifyMailQueue(Auth::getCurrentProject(false), $recipient, $headers, $body, $issue_id, $type, $sender_usr_id, $type_id); // avoid sending emails out to users with inactive status $recipient_email = Mail_Helper::getEmailAddress($recipient); $usr_id = User::getUserIDByEmail($recipient_email); if (!empty($usr_id)) { $user_status = User::getStatusByEmail($recipient_email); // if user is not set to an active status, then silently ignore if (!User::isActiveStatus($user_status) && !User::isPendingStatus($user_status)) { return false; } } $to_usr_id = User::getUserIDByEmail($recipient_email); $recipient = Mail_Helper::fixAddressQuoting($recipient); $reminder_addresses = Reminder::_getReminderAlertAddresses(); // add specialized headers if (!empty($issue_id) && (!empty($to_usr_id) && User::getRoleByUser($to_usr_id, Issue::getProjectID($issue_id)) != User::getRoleID('Customer')) || @in_array(Mail_Helper::getEmailAddress($recipient), $reminder_addresses)) { $headers += Mail_Helper::getSpecializedHeaders($issue_id, $type, $headers, $sender_usr_id); } // try to prevent triggering absence auto responders $headers['precedence'] = 'bulk'; // the 'classic' way, works with e.g. the unix 'vacation' tool $headers['Auto-submitted'] = 'auto-generated'; // the RFC 3834 way if (empty($issue_id)) { $issue_id = 'null'; } // if the Date: header is missing, add it. if (empty($headers['Date'])) { $headers['Date'] = Mime_Helper::encode(date('D, j M Y H:i:s O')); } if (!empty($headers['To'])) { $headers['To'] = Mail_Helper::fixAddressQuoting($headers['To']); } // encode headers and add special mime headers $headers = Mime_Helper::encodeHeaders($headers); $res = Mail_Helper::prepareHeaders($headers); if (Misc::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return $res; } // convert array of headers into text headers list(, $text_headers) = $res; $params = array('maq_save_copy' => $save_email_copy, 'maq_queued_date' => Date_Helper::getCurrentDateGMT(), 'maq_sender_ip_address' => !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '', 'maq_recipient' => $recipient, 'maq_headers' => $text_headers, 'maq_body' => $body, 'maq_iss_id' => $issue_id, 'maq_subject' => $headers['Subject'], 'maq_type' => $type); if ($sender_usr_id) { $params['maq_usr_id'] = $sender_usr_id; } if ($type_id) { $params['maq_type_id'] = $type_id; } $stmt = 'INSERT INTO {{%mail_queue}} SET ' . DB_Helper::buildSet($params); try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { return $res; } return true; }
function getIncidentTypes($p) { $email = XML_RPC_decode($p->getParam(0)); $password = XML_RPC_decode($p->getParam(1)); $auth = authenticate($email, $password); if (is_object($auth)) { return $auth; } $issue_id = XML_RPC_decode($p->getParam(2)); $redeemed_only = XML_RPC_decode($p->getParam(3)); $prj_id = Issue::getProjectID($issue_id); createFakeCookie($email, $prj_id); $customer_id = Issue::getCustomerID($issue_id); if (!Customer::hasCustomerIntegration($prj_id)) { // no customer integration return new XML_RPC_Response(0, $XML_RPC_erruser + 1, "No customer integration for issue #{$issue_id}"); } elseif (!Customer::hasPerIncidentContract($prj_id, $customer_id)) { // check if is per incident contract return new XML_RPC_Response(0, $XML_RPC_erruser + 1, "Customer for issue #{$issue_id} does not have a per-incident contract"); } $details = Customer::getDetails($prj_id, $customer_id); foreach ($details['incident_details'] as $type_id => $type_details) { $is_redeemed = Customer::isRedeemedIncident($prj_id, $issue_id, $type_id); if ($redeemed_only && !$is_redeemed || !$redeemed_only && $is_redeemed) { unset($details['incident_details'][$type_id]); } } return new XML_RPC_Response(XML_RPC_Encode($details['incident_details'])); }
/** * Method used to send an alert to a set of email addresses when * a reminder action was triggered, but no action was really * taken because no recipients could be found. * * @param integer $issue_id The issue ID * @param string $type Which reminder are we trying to send, email or sms * @param array $reminder The reminder details * @param array $action The action details * @return void */ private function _recordNoRecipientError($issue_id, $type, $reminder, $action, $data, $conditions) { $to = Reminder::_getReminderAlertAddresses(); if (count($to) > 0) { $tpl = new Template_Helper(); $tpl->setTemplate('reminders/alert_no_recipients.tpl.text'); $tpl->assign(array('type' => $type, 'data' => $data, 'reminder' => $reminder, 'action' => $action, 'conditions' => $conditions, 'has_customer_integration' => CRM::hasCustomerIntegration(Issue::getProjectID($issue_id)))); $text_message = $tpl->getTemplateContents(); foreach ($to as $address) { // send email (use PEAR's classes) $mail = new Mail_Helper(); $mail->setTextBody($text_message); $setup = $mail->getSMTPSettings(); // TRANSLATORS: %1 = issue_id, %2 - rma_title $subject = ev_gettext('[#%1$s] Reminder Not Triggered: [#%2$s]', $issue_id, $action['rma_title']); $mail->send($setup['from'], $address, $subject, 0, $issue_id); } } }
/** * Method used to get the full listing of time entries in the system for a * specific issue * * @param integer $issue_id The issue ID * @return array The full list of time entries */ public static function getTimeEntryListing($issue_id) { $stmt = 'SELECT ttr_id, ttr_created_date, ttr_summary, ttr_time_spent, ttc_title, ttr_usr_id, usr_full_name FROM {{%time_tracking}}, {{%time_tracking_category}}, {{%user}} WHERE ttr_ttc_id=ttc_id AND ttr_usr_id=usr_id AND ttr_iss_id=? ORDER BY ttr_created_date ASC'; try { $res = DB_Helper::getInstance()->getAll($stmt, array($issue_id)); } catch (DbException $e) { return 0; } $total_time_spent = 0; $total_time_by_user = array(); foreach ($res as &$row) { $row['ttr_summary'] = Link_Filter::processText(Issue::getProjectID($issue_id), nl2br(htmlspecialchars($row['ttr_summary']))); $row['formatted_time'] = Misc::getFormattedTime($row['ttr_time_spent']); $row['ttr_created_date'] = Date_Helper::getFormattedDate($row['ttr_created_date']); if (isset($total_time_by_user[$row['ttr_usr_id']])) { $total_time_by_user[$row['ttr_usr_id']]['time_spent'] += $row['ttr_time_spent']; } else { $total_time_by_user[$row['ttr_usr_id']] = array('usr_full_name' => $row['usr_full_name'], 'time_spent' => $row['ttr_time_spent']); } $total_time_spent += $row['ttr_time_spent']; } usort($total_time_by_user, function ($a, $b) { return $a['time_spent'] < $b['time_spent']; }); foreach ($total_time_by_user as &$item) { $item['time_spent'] = Misc::getFormattedTime($item['time_spent']); } return array('total_time_spent' => Misc::getFormattedTime($total_time_spent), 'total_time_by_user' => $total_time_by_user, 'list' => $res); }
/** * This method inserts a blank value for all custom fields that do not already have a record. * It currently is not called by the main code, but is included to be called from workflow classes. * * @param integer $issue_id The Issue ID */ public function populateAllFields($issue_id) { $prj_id = Issue::getProjectID($issue_id); $fields = self::getListByIssue($prj_id, $issue_id, APP_SYSTEM_USER_ID); foreach ($fields as $field) { if (empty($field['value'])) { self::removeIssueAssociation($field['fld_id'], $issue_id); self::associateIssue($issue_id, $field['fld_id'], ''); } } }
/** * Adds a real user to the authorized repliers list. * * @param integer $issue_id The id of the issue. * @param integer $usr_id The id of the user. * @param boolean $add_history If this should be logged. */ public static function addUser($issue_id, $usr_id, $add_history = true) { // don't add customers to this list. They should already be able to send if (User::getRoleByUser($usr_id, Issue::getProjectID($issue_id)) == User::getRoleID('Customer')) { return -2; } $stmt = 'INSERT INTO {{%issue_user_replier}} ( iur_iss_id, iur_usr_id ) VALUES ( ?, ? )'; try { DB_Helper::getInstance()->query($stmt, array($issue_id, $usr_id)); } catch (DbException $e) { return -1; } if ($add_history) { // add the change to the history of the issue $current_usr_id = Auth::getUserID(); History::add($issue_id, $current_usr_id, 'replier_added', '{other_user} added to the authorized repliers list by {user}', array('other_user' => User::getFullName($usr_id), 'user' => User::getFullName($current_usr_id))); } return 1; }
/** * Adds a real user to the authorized repliers list. * * @access public * @param integer $issue_id The id of the issue. * @param integer $usr_id The id of the user. * @param boolean $add_history If this should be logged. */ function addUser($issue_id, $usr_id, $add_history = true) { // don't add customers to this list. They should already be able to send if (User::getRoleByUser($usr_id, Issue::getProjectID($issue_id)) == User::getRoleID("Customer")) { return -2; } $stmt = "INSERT INTO\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user_replier\n (\n iur_iss_id,\n iur_usr_id\n ) VALUES (\n " . Misc::escapeInteger($issue_id) . ",\n " . Misc::escapeInteger($usr_id) . "\n )"; $res = $GLOBALS["db_api"]->dbh->query($stmt); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return -1; } else { if ($add_history) { // add the change to the history of the issue $summary = User::getFullName($usr_id) . ' added to the authorized repliers list by ' . User::getFullName(Auth::getUserID()); History::add($issue_id, Auth::getUserID(), History::getTypeID('replier_added'), $summary); } } return 1; }
// XXX: this new note, but that's how it was already $res = Note::insert(Auth::getUserID(), $HTTP_POST_VARS['issue']); // remove the associated email if ($res) { list($HTTP_POST_VARS["from"]) = Support::getSender(array($HTTP_POST_VARS['item'][$i])); Workflow::handleBlockedEmail(Issue::getProjectID($HTTP_POST_VARS['issue']), $HTTP_POST_VARS['issue'], $HTTP_POST_VARS, 'associated'); Support::removeEmail($HTTP_POST_VARS['item'][$i]); } } $tpl->assign("associate_result", $res); } @$tpl->assign('total_emails', count($HTTP_POST_VARS['item'])); } else { @$tpl->assign('emails', $HTTP_GET_VARS['item']); @$tpl->assign('total_emails', count($HTTP_GET_VARS['item'])); $prj_id = Issue::getProjectID($HTTP_GET_VARS['issue']); if (Customer::hasCustomerIntegration($prj_id)) { // check if the selected emails all have sender email addresses that are associated with the issue' customer $senders = Support::getSender($HTTP_GET_VARS['item']); $sender_emails = array(); for ($i = 0; $i < count($senders); $i++) { $email = Mail_API::getEmailAddress($senders[$i]); $sender_emails[$email] = $senders[$i]; } $customer_id = Issue::getCustomerID($HTTP_GET_VARS['issue']); if (!empty($customer_id)) { $contact_emails = array_keys(Customer::getContactEmailAssocList($prj_id, $customer_id)); $unknown_contacts = array(); foreach ($sender_emails as $email => $address) { if (!@in_array($email, $contact_emails)) { $usr_id = User::getUserIDByEmail($email);
/** * Method used to get the full list of requirements and impact analysis for * a specific issue. * * @param integer $issue_id The issue ID * @return array The full list of requirements */ public static function getListing($issue_id) { $stmt = 'SELECT isr_id, isr_requirement, isr_dev_time, isr_impact_analysis, A.usr_full_name AS submitter_name, B.usr_full_name AS handler_name FROM ( {{%issue_requirement}}, {{%user}} A ) LEFT JOIN {{%user}} B ON isr_updated_usr_id=B.usr_id WHERE isr_iss_id=? AND isr_usr_id=A.usr_id'; try { $res = DB_Helper::getInstance()->getAll($stmt, array($issue_id)); } catch (DbException $e) { return ''; } if (count($res) == 0) { return ''; } $prj_id = Issue::getProjectID($issue_id); foreach ($res as &$row) { $row['isr_requirement'] = Link_Filter::processText($prj_id, nl2br(htmlspecialchars($row['isr_requirement']))); $row['isr_impact_analysis'] = Link_Filter::processText($prj_id, nl2br(htmlspecialchars($row['isr_impact_analysis']))); $row['formatted_dev_time'] = Misc::getFormattedTime($row['isr_dev_time']); } return $res; }
// +----------------------------------------------------------------------+ // | Authors: Raul Raat <*****@*****.**> | // | Authors: Elan Ruusamäe <*****@*****.**> | // +----------------------------------------------------------------------+ require_once dirname(__FILE__) . '/../../init.php'; // check login Auth::checkAuthentication(APP_COOKIE); $field_name = !empty($_POST['field_name']) ? $_POST['field_name'] : null; $issue_id = !empty($_POST['issue_id']) ? (int) $_POST['issue_id'] : null; // check if correct issue id was sent if (!$issue_id || !Issue::exists($issue_id)) { die('Invalid issue_id'); } $usr_id = Auth::getUserID(); // check if user role is above "Standard User" if (User::getRoleByUser($usr_id, Issue::getProjectID($issue_id)) < User::getRoleID('Standard User')) { die('Forbidden'); } // check if user can acess the issue if (!Issue::canAccess($issue_id, $usr_id)) { die('Forbidden'); } switch ($field_name) { case 'expected_resolution_date': $day = Misc::escapeInteger($_POST['day']); $month = Misc::escapeInteger($_POST['month']); $year = Misc::escapeInteger($_POST['year']); if ($day == 0 && $month == 1 && $year == 0) { // clear button $date = null; } else {
// one project, and redirect the user to the main page of the // application on that case $assigned_projects = Project::getAssocList(Auth::getUserID()); if (count($assigned_projects) == 1) { list($prj_id) = each($assigned_projects); Auth::setCurrentProject($prj_id, 0); checkCustomerAuthentication($prj_id); if (!empty($_GET['url'])) { Auth::redirect($_GET['url']); } else { Auth::redirect('list.php'); } } elseif (!empty($_GET['url']) && (preg_match("/.*view\\.php\\?id=(\\d*)/", $_GET['url'], $matches) > 0 || preg_match("/switch_prj_id=(\\d*)/", $_GET['url'], $matches) > 0)) { // check if url is directly linking to an issue, and if it is, don't prompt for project if (stristr($_GET['url'], 'view.php')) { $prj_id = Issue::getProjectID($matches[1]); } else { $prj_id = $matches[1]; } if (!empty($assigned_projects[$prj_id])) { Auth::setCurrentProject($prj_id, 0); checkCustomerAuthentication($prj_id); Auth::redirect($_GET['url']); } } $tpl->assign('active_projects', $assigned_projects); } if (@$_GET['err'] != '') { Auth::removeCookie(APP_PROJECT_COOKIE); $tpl->assign('err', $_GET['err']); }
/** * Method used to add a note using the user interface form * available in the application. * * @param integer $usr_id The user ID * @param integer $issue_id The issue ID * @param string $unknown_user The email address of a user that sent the blocked email that was turned into this note. Default is false. * @param boolean $log If adding this note should be logged. Default true. * @param boolean $closing If The issue is being closed. Default false * @param boolean $send_notification Whether to send a notification about this note or not * @access public * @return integer the new note id if the insert worked, -1 or -2 otherwise */ function insert($usr_id, $issue_id, $unknown_user = FALSE, $log = true, $closing = false, $send_notification = true) { global $HTTP_POST_VARS; $issue_id = Misc::escapeInteger($issue_id); if (@$HTTP_POST_VARS['add_extra_recipients'] != 'yes') { $note_cc = array(); } else { $note_cc = $HTTP_POST_VARS['note_cc']; } // add the poster to the list of people to be subscribed to the notification list // only if there is no 'unknown user'. $note_cc[] = $usr_id; if ($unknown_user == false) { for ($i = 0; $i < count($note_cc); $i++) { Notification::subscribeUser($usr_id, $issue_id, $note_cc[$i], Notification::getDefaultActions()); } } if (Validation::isWhitespace($HTTP_POST_VARS["note"])) { return -2; } if (empty($HTTP_POST_VARS['message_id'])) { $HTTP_POST_VARS['message_id'] = Mail_API::generateMessageID(); } $stmt = "INSERT INTO\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "note\n (\n not_iss_id,\n not_usr_id,\n not_created_date,\n not_note,\n not_title"; if (!@empty($HTTP_POST_VARS['blocked_msg'])) { $stmt .= ", not_blocked_message"; } $stmt .= ", not_message_id"; if (!@empty($HTTP_POST_VARS['parent_id'])) { $stmt .= ", not_parent_id"; } if ($unknown_user != false) { $stmt .= ", not_unknown_user"; } $stmt .= "\n ) VALUES (\n {$issue_id},\n {$usr_id},\n '" . Date_API::getCurrentDateGMT() . "',\n '" . Misc::escapeString($HTTP_POST_VARS["note"]) . "',\n '" . Misc::escapeString($HTTP_POST_VARS["title"]) . "'"; if (!@empty($HTTP_POST_VARS['blocked_msg'])) { $stmt .= ", '" . Misc::escapeString($HTTP_POST_VARS['blocked_msg']) . "'"; } $stmt .= ", '" . Misc::escapeString($HTTP_POST_VARS['message_id']) . "'"; if (!@empty($HTTP_POST_VARS['parent_id'])) { $stmt .= ", " . Misc::escapeInteger($HTTP_POST_VARS['parent_id']) . ""; } if ($unknown_user != false) { $stmt .= ", '" . Misc::escapeString($unknown_user) . "'"; } $stmt .= "\n )"; $res = $GLOBALS["db_api"]->dbh->query($stmt); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return -1; } else { $new_note_id = $GLOBALS["db_api"]->get_last_insert_id(); Issue::markAsUpdated($issue_id, 'note'); if ($log) { // need to save a history entry for this History::add($issue_id, $usr_id, History::getTypeID('note_added'), 'Note added by ' . User::getFullName($usr_id)); } // send notifications for the issue being updated if ($send_notification) { $internal_only = true; if (@$HTTP_POST_VARS['add_extra_recipients'] != 'yes' && @count($HTTP_POST_VARS['note_cc']) > 0) { Notification::notify($issue_id, 'notes', $new_note_id, $internal_only, $HTTP_POST_VARS['note_cc']); } else { Notification::notify($issue_id, 'notes', $new_note_id, $internal_only); } Workflow::handleNewNote(Issue::getProjectID($issue_id), $issue_id, $usr_id, $closing); } // need to return the new note id here so it can // be re-used to associate internal-only attachments return $new_note_id; } }
/** * Returns the options associated with a specific field * * @param string $field_name The name of the field * @param integer $issue_id The ID of the issue * @return array An array of options for the specified field */ private static function getOptions($field_name, $issue_id) { $prj_id = Issue::getProjectID($issue_id); switch ($field_name) { case 'assignee': $users = Project::getUserAssocList($prj_id, 'active', User::ROLE_CUSTOMER); $current_assignees = Issue::getAssignedUserIDs($issue_id); foreach ($current_assignees as $usr_id) { if (!isset($users[$usr_id])) { $users[$usr_id] = User::getFullName($usr_id); } asort($users); } return $users; case 'priority': return Priority::getAssocList($prj_id); case 'severity': return Severity::getAssocList($prj_id); } return array(); }
/** * Method used to associate checkins to an existing issue * * @param integer $issue_id The ID of the issue. * @param string $commit_time Time when commit occurred (in UTC) * @param string $scm_name SCM definition name in Eventum * @param string $username SCM user doing the checkin. * @param string $commit_msg Message associated with the SCM commit. * @param array $files Files info with their version numbers changes made on. * @return integer 1 if the update worked, -1 otherwise */ public static function addCheckins($issue_id, $commit_time, $scm_name, $username, $commit_msg, $files) { // validate that $scm_name is valid // this will throw if invalid self::getScmCheckinByName($scm_name); // TODO: add workflow pre method first, so it may setup username, etc $usr_id = APP_SYSTEM_USER_ID; // workflow needs to know project_id to find out which workflow class to use. $prj_id = Issue::getProjectID($issue_id); foreach ($files as $file) { self::insertCheckin($issue_id, $commit_time, $scm_name, $file, $username, $commit_msg); } // need to mark this issue as updated Issue::markAsUpdated($issue_id, 'scm checkin'); // need to save a history entry for this // TRANSLATORS: %1: scm username History::add($issue_id, $usr_id, 'scm_checkin_associated', "SCM Checkins associated by SCM user '{user}'", array('user' => $username)); Workflow::handleSCMCheckins($prj_id, $issue_id, $files, $username, $commit_msg); return 1; }
/** * Method used to get the full listing of time entries in the system for a * specific issue * * @access public * @param integer $issue_id The issue ID * @return array The full list of time entries */ function getListing($issue_id) { $stmt = "SELECT\n ttr_id,\n ttr_created_date,\n ttr_summary,\n ttr_time_spent,\n ttc_title,\n ttr_usr_id,\n usr_full_name\n FROM\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "time_tracking,\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "time_tracking_category,\n " . ETEL_USER_TABLE . "\n WHERE\n ttr_ttc_id=ttc_id AND\n ttr_usr_id=usr_id AND\n ttr_iss_id=" . Misc::escapeInteger($issue_id) . "\n ORDER BY\n ttr_created_date ASC"; $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return 0; } else { $total_time_spent = 0; for ($i = 0; $i < count($res); $i++) { $res[$i]["ttr_summary"] = Link_Filter::processText(Issue::getProjectID($issue_id), nl2br(htmlspecialchars($res[$i]["ttr_summary"]))); $res[$i]["formatted_time"] = Misc::getFormattedTime($res[$i]["ttr_time_spent"]); $res[$i]["ttr_created_date"] = Date_API::getFormattedDate($res[$i]["ttr_created_date"]); $total_time_spent += $res[$i]["ttr_time_spent"]; } return array("total_time_spent" => Misc::getFormattedTime($total_time_spent), "list" => $res); } }
public static function getPartnerCodesByIssue($iss_id) { $prj_id = Issue::getProjectID($iss_id); $sql = 'SELECT ipa_par_code FROM {{%issue_partner}}, {{%partner_project}} WHERE ipa_par_code = pap_par_code AND pap_prj_id = ? AND ipa_iss_id = ?'; try { $partners = DB_Helper::getInstance()->getColumn($sql, array($prj_id, $iss_id)); } catch (DbException $e) { return array(); } return $partners; }
/** * Check if this email needs to be blocked and if so, block it. * * */ public static function blockEmailIfNeeded($email) { if (empty($email['issue_id'])) { return false; } $issue_id = $email['issue_id']; $prj_id = Issue::getProjectID($issue_id); $sender_email = strtolower(Mail_Helper::getEmailAddress($email['from'])); list($text_headers, $body) = Mime_Helper::splitHeaderBody($email['full_email']); if (Mail_Helper::isVacationAutoResponder($email['headers']) || Notification::isBounceMessage($sender_email) || !self::isAllowedToEmail($issue_id, $sender_email)) { // add the message body as a note $_POST = array('full_message' => $email['full_email'], 'title' => @$email['headers']['subject'], 'note' => Mail_Helper::getCannedBlockedMsgExplanation($issue_id) . $email['body'], 'message_id' => Mail_Helper::getMessageID($text_headers, $body)); // avoid having this type of message re-open the issue if (Mail_Helper::isVacationAutoResponder($email['headers'])) { $closing = true; $notify = false; } else { $closing = false; $notify = true; } $res = Note::insertFromPost(Auth::getUserID(), $issue_id, $email['headers']['from'], false, $closing, $notify, true); // associate the email attachments as internal-only files on this issue if ($res != -1) { self::extractAttachments($issue_id, $email['full_email'], true, $res); } $_POST['issue_id'] = $issue_id; $_POST['from'] = $sender_email; // avoid having this type of message re-open the issue if (Mail_Helper::isVacationAutoResponder($email['headers'])) { $email_type = 'vacation-autoresponder'; } else { $email_type = 'routed'; } Workflow::handleBlockedEmail($prj_id, $issue_id, $_POST, $email_type); // try to get usr_id of sender, if not, use system account $usr_id = User::getUserIDByEmail(Mail_Helper::getEmailAddress($email['from']), true); if (!$usr_id) { $usr_id = APP_SYSTEM_USER_ID; } History::add($issue_id, $usr_id, 'email_blocked', "Email from '{from}' blocked", array('from' => $email['from'])); return true; } return false; }
/** * Method used to send an alert to a set of email addresses when * a reminder action was triggered, but no action was really * taken because no recipients could be found. * * @access private * @param integer $issue_id The issue ID * @param string $type Which reminder are we trying to send, email or sms * @param array $reminder The reminder details * @param array $action The action details * @return void */ function _recordNoRecipientError($issue_id, $type, $reminder, $action) { $to = Reminder::_getReminderAlertAddresses(); if (count($to) > 0) { $tpl = new Template_API(); $tpl->setTemplate('reminders/alert_no_recipients.tpl.text'); $tpl->bulkAssign(array("type" => $type, "data" => $data, "reminder" => $reminder, "action" => $action, "conditions" => $conditions, "has_customer_integration" => Customer::hasCustomerIntegration(Issue::getProjectID($issue_id)))); $text_message = $tpl->getTemplateContents(); foreach ($to as $address) { // send email (use PEAR's classes) $mail = new Mail_API(); $mail->setTextBody($text_message); $setup = $mail->getSMTPSettings(); $mail->send($setup["from"], $address, "[#{$issue_id}] Reminder Not Triggered: " . $action['rma_title'], 0, $issue_id); } } }
/** * Generates the specialized headers for an email. * * @access public * @param integer $issue_id The issue ID * @param string $type The type of message this is * @param string $headers The existing headers of this message. * @param integer $sender_usr_id The id of the user sending this email. * @return array An array of specialized headers */ function getSpecializedHeaders($issue_id, $type, $headers, $sender_usr_id) { $new_headers = array(); if (!empty($issue_id)) { $prj_id = Issue::getProjectID($issue_id); if (count(Group::getAssocList($prj_id)) > 0) { // group issue is currently assigned too $new_headers['X-Eventum-Group-Issue'] = Group::getName(Issue::getGroupID($issue_id)); // group of whoever is sending this message. if (empty($sender_usr_id)) { $new_headers['X-Eventum-Group-Replier'] = $new_headers['X-Eventum-Group-Issue']; } else { $new_headers['X-Eventum-Group-Replier'] = Group::getName(User::getGroupID($sender_usr_id)); } // group of current assignee $assignees = Issue::getAssignedUserIDs($issue_id); if (empty($assignees[0])) { $new_headers['X-Eventum-Group-Assignee'] = ''; } else { $new_headers['X-Eventum-Group-Assignee'] = @Group::getName(User::getGroupID($assignees[0])); } } if (Customer::hasCustomerIntegration($prj_id)) { if (empty($support_levels)) { $support_levels = Customer::getSupportLevelAssocList($prj_id); } $customer_id = Issue::getCustomerID($issue_id); if (!empty($customer_id)) { $customer_details = Customer::getDetails($prj_id, $customer_id); $new_headers['X-Eventum-Customer'] = $customer_details['customer_name']; } if (count($support_levels) > 0) { $new_headers['X-Eventum-Level'] = $support_levels[Customer::getSupportLevelID($prj_id, $customer_id)]; } } $new_headers['X-Eventum-Category'] = Category::getTitle(Issue::getCategory($issue_id)); $new_headers['X-Eventum-Project'] = Project::getName($prj_id); } $new_headers['X-Eventum-Type'] = $type; return $new_headers; }
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | // | GNU General Public License for more details. | // | | // | You should have received a copy of the GNU General Public License | // | along with this program; if not, write to: | // | | // | Free Software Foundation, Inc. | // | 51 Franklin Street, Suite 330 | // | Boston, MA 02110-1301, USA. | // +----------------------------------------------------------------------+ // | Authors: João Prado Maia <*****@*****.**> | // +----------------------------------------------------------------------+ require_once dirname(__FILE__) . '/../init.php'; $tpl = new Template_Helper(); $tpl->setTemplate('add_phone_entry.tpl.html'); Auth::checkAuthentication(APP_COOKIE, 'index.php?err=5', true); $issue_id = @$_POST['issue_id'] ? $_POST['issue_id'] : $_GET['iss_id']; if (!Issue::canAccess($issue_id, Auth::getUserID()) || Auth::getCurrentRole() <= User::getRoleID('Customer')) { $tpl = new Template_Helper(); $tpl->setTemplate('permission_denied.tpl.html'); $tpl->displayTemplate(); exit; } if (@$_POST['cat'] == 'add_phone') { $res = Phone_Support::insert(); $tpl->assign('add_phone_result', $res); } $prj_id = Issue::getProjectID($issue_id); $usr_id = Auth::getUserID(); $tpl->assign(array('issue_id' => $issue_id, 'phone_categories' => Phone_Support::getCategoryAssocList($prj_id), 'current_user_prefs' => Prefs::get($usr_id))); $tpl->displayTemplate();
include_once APP_INC_PATH . "class.note.php"; include_once APP_INC_PATH . "class.user.php"; include_once APP_INC_PATH . "db_access.php"; $tpl = new Template_API(); $tpl->setTemplate("view_note.tpl.html"); Auth::checkAuthentication(APP_COOKIE, 'index.php?err=5', true); $usr_id = Auth::getUserID(); $note = Note::getDetails($HTTP_GET_VARS["id"]); if ($note == '') { $tpl->assign("note", ''); $tpl->displayTemplate(); exit; } else { $note["message"] = $note["not_note"]; $issue_id = Note::getIssueID($HTTP_GET_VARS["id"]); $usr_id = Auth::getUserID(); } if (User::getRoleByUser($usr_id, Issue::getProjectID($issue_id)) < User::getRoleID('Standard User') || !Issue::canAccess($issue_id, Auth::getUserID())) { $tpl->setTemplate("permission_denied.tpl.html"); $tpl->displayTemplate(); exit; } $note = Note::getDetails($HTTP_GET_VARS["id"]); $note["message"] = $note["not_note"]; $issue_id = Note::getIssueID($HTTP_GET_VARS["id"]); $tpl->bulkAssign(array("note" => $note, "issue_id" => $issue_id, 'extra_title' => "Note #" . $HTTP_GET_VARS['num'] . ": " . $note['not_title'])); if (!empty($issue_id)) { $sides = Note::getSideLinks($issue_id, $HTTP_GET_VARS["id"]); $tpl->assign(array('previous' => $sides['previous'], 'next' => $sides['next'])); } $tpl->displayTemplate();
/** * @param int $issue_id * @param bool $redeemed_only * @return array * @access protected */ public function getIncidentTypes($issue_id, $redeemed_only) { $prj_id = Issue::getProjectID($issue_id); AuthCookie::setProjectCookie($prj_id); // FIXME: $customer_id unused $customer_id = Issue::getCustomerID($issue_id); if (!CRM::hasCustomerIntegration($prj_id)) { // no customer integration throw new RemoteApiException("No customer integration for issue #{$issue_id}"); } $crm = CRM::getInstance($prj_id); // FIXME: $all_types unused $all_types = $crm->getIncidentTypes(); $contract = $crm->getContract(Issue::getContractID($issue_id)); if (!$contract->hasPerIncident()) { // check if is per incident contract throw new RemoteApiException("Customer for issue #{$issue_id} does not have a per-incident contract"); } $incidents = $contract->getIncidents(); foreach ($incidents as $type_id => $type_details) { $is_redeemed = $contract->isRedeemedIncident($issue_id, $type_id); if ($redeemed_only && !$is_redeemed || !$redeemed_only && $is_redeemed) { unset($incidents[$type_id]); } } return $incidents; }
/** * Check if this email needs to be blocked and if so, block it. * * */ function blockEmailIfNeeded($email) { global $HTTP_POST_VARS; if (empty($email['issue_id'])) { return false; } $issue_id = $email['issue_id']; $prj_id = Issue::getProjectID($issue_id); $sender_email = strtolower(Mail_API::getEmailAddress($email['headers']['from'])); if (Mail_API::isVacationAutoResponder($email['headers']) || Notification::isBounceMessage($sender_email) || !Support::isAllowedToEmail($issue_id, $sender_email)) { // add the message body as a note $HTTP_POST_VARS = array('blocked_msg' => $email['full_email'], 'title' => @$email['headers']['subject'], 'note' => Mail_API::getCannedBlockedMsgExplanation($issue_id) . $email['body']); // avoid having this type of message re-open the issue if (Mail_API::isVacationAutoResponder($email['headers'])) { $closing = true; } else { $closing = false; } $res = Note::insert(Auth::getUserID(), $issue_id, $email['headers']['from'], false, $closing); // associate the email attachments as internal-only files on this issue if ($res != -1) { Support::extractAttachments($issue_id, $email['full_email'], true, $res); } $HTTP_POST_VARS['issue_id'] = $issue_id; $HTTP_POST_VARS['from'] = $sender_email; // avoid having this type of message re-open the issue if (Mail_API::isVacationAutoResponder($email['headers'])) { $email_type = 'vacation-autoresponder'; } else { $email_type = 'routed'; } Workflow::handleBlockedEmail($prj_id, $issue_id, $HTTP_POST_VARS, $email_type); // try to get usr_id of sender, if not, use system account $usr_id = User::getUserIDByEmail(Mail_API::getEmailAddress($email['from'])); if (!$usr_id) { $usr_id = APP_SYSTEM_USER_ID; } // log blocked email History::add($issue_id, $usr_id, History::getTypeID('email_blocked'), "Email from '" . $email['from'] . "' blocked."); return true; } return false; }
// +----------------------------------------------------------------------+ require_once dirname(__FILE__) . '/../init.php'; $tpl = new Template_Helper(); $tpl->setTemplate('view_note.tpl.html'); Auth::checkAuthentication(APP_COOKIE, 'index.php?err=5', true); $usr_id = Auth::getUserID(); $note_id = $_GET['id']; $note = Note::getDetails($note_id); if ($note == '') { $tpl->assign('note', ''); $tpl->displayTemplate(); exit; } else { $note['message'] = $note['not_note']; $issue_id = Note::getIssueID($note_id); $usr_id = Auth::getUserID(); } if (User::getRoleByUser($usr_id, Issue::getProjectID($issue_id)) < User::getRoleID('Standard User') || !Access::canViewInternalNotes($issue_id, Auth::getUserID())) { $tpl->setTemplate('permission_denied.tpl.html'); $tpl->displayTemplate(); exit; } $note = Note::getDetails($_GET['id']); $note['message'] = $note['not_note']; $issue_id = Note::getIssueID($_GET['id']); $tpl->assign(array('note' => $note, 'issue_id' => $issue_id, 'extra_title' => 'Note #' . Note::getNoteSequenceNumber($issue_id, $note_id) . ': ' . $note['not_title'], 'recipients' => Mail_Queue::getMessageRecipients('notes', $note_id))); if (!empty($issue_id)) { $sides = Note::getSideLinks($issue_id, $_GET['id']); $tpl->assign(array('previous' => $sides['previous'], 'next' => $sides['next'])); } $tpl->displayTemplate();
/** * Attach uploaded files to an issue * It also notifies any subscribers of this new attachment. * * @param int $issue_id The issue ID * @param int $usr_id The user ID * @param int[] $iaf_ids attachment file id-s to attach * @param boolean $internal_only Whether this attachment is supposed to be internal only or not * @param string $file_description File description text * @param string $unknown_user The email of the user who originally sent this email, who doesn't have an account. * @param integer $associated_note_id The note ID that these attachments should be associated with */ public static function attachFiles($issue_id, $usr_id, $iaf_ids, $internal_only, $file_description, $unknown_user = null, $associated_note_id = null) { if (!$iaf_ids) { throw new LogicException('No attachment ids'); } $attachment_id = self::add($issue_id, $usr_id, $file_description, $internal_only, $unknown_user, $associated_note_id); self::associateFiles($attachment_id, $iaf_ids); Issue::markAsUpdated($issue_id, 'file uploaded'); History::add($issue_id, $usr_id, 'attachment_added', 'Attachment uploaded by {user}', array('user' => User::getFullName($usr_id))); // if there is customer integration, mark last customer action $prj_id = Issue::getProjectID($issue_id); $has_crm = CRM::hasCustomerIntegration($prj_id); $is_customer = User::getRoleByUser($usr_id, $prj_id) == User::ROLE_CUSTOMER; if ($has_crm && $is_customer) { Issue::recordLastCustomerAction($issue_id); } Workflow::handleAttachment($prj_id, $issue_id, $usr_id); Notification::notify($issue_id, 'files', $attachment_id, $internal_only); }
public static function canUpdateIssue($issue_id, $usr_id) { if (!self::canAccessIssue($issue_id, $usr_id)) { return false; } $prj_id = Issue::getProjectID($issue_id); $workflow = Workflow::canUpdateIssue($prj_id, $issue_id, $usr_id); if ($workflow !== null) { return $workflow; } if (User::isPartner($usr_id)) { $partner = Partner::canUpdateIssue($issue_id, $usr_id); if (is_bool($partner)) { return $partner; } } if (User::getRoleByUser($usr_id, $prj_id) >= User::getRoleID('Customer')) { return true; } return false; }
// XXX: this new note, but that's how it was already $res = Note::insertFromPost(Auth::getUserID(), $_POST['issue_id'], false, true, false, true, true); // remove the associated email if ($res) { list($_POST['from']) = Support::getSender(array($item)); Workflow::handleBlockedEmail(Issue::getProjectID($_POST['issue_id']), $_POST['issue_id'], $_POST, 'associated'); Support::removeEmail($item); } } $tpl->assign('associate_result', $res); } @$tpl->assign('total_emails', count($_POST['item'])); } else { @$tpl->assign('emails', $_GET['item']); @$tpl->assign('total_emails', count($_GET['item'])); $prj_id = Issue::getProjectID($_GET['issue_id']); if (CRM::hasCustomerIntegration($prj_id)) { // check if the selected emails all have sender email addresses that are associated with the issue' customer $crm = CRM::getInstance($prj_id); $senders = Support::getSender($_GET['item']); $sender_emails = array(); foreach ($senders as $sender) { $email = Mail_Helper::getEmailAddress($sender); $sender_emails[$email] = $sender; } $contract_id = Issue::getContractID($_GET['issue_id']); if (!empty($contract_id)) { try { $contract = $crm->getContract($contract_id); // TODOCRM: Active contacts only $contact_emails = array_keys($contract->getContactEmailAssocList());
/** * Insert note to system, send out notification and log. * * @param int $usr_id The user ID * @param int $issue_id The issue ID * @param string $title Title of the note * @param string $note Note contents * @param array $options extra optional options: * - (array) cc: extra recipients to notify (usr_id list) * - (bool) add_extra_recipients: whether to add recipients in 'cc' to notification list * - (bool) closing: If The issue is being closed. Default false * - (bool) is_blocked: FIXME * - (bool) log: If adding this note should be logged. Default true * - (bool) send_notification: Whether to send a notification about this note or not. Default true * - (int) parent_id: FIXME * - (string) full_message: FIXME * - (string) message_id: FIXME * - (string) unknown_user: The email address of a user that sent the blocked email that was turned into this note * @return int the new note id if the insert worked, -1 or -2 otherwise */ public static function insertNote($usr_id, $issue_id, $title, $note, $options = array()) { if (Validation::isWhitespace($note)) { return -2; } $options = array_merge(array('unknown_user' => null, 'log' => true, 'closing' => false, 'send_notification' => true, 'is_blocked' => false, 'message_id' => null, 'cc' => null, 'full_message' => null, 'parent_id' => null), $options); $prj_id = Issue::getProjectID($issue_id); // NOTE: workflow may modify the parameters as $data is passed as reference $data = array('title' => &$title, 'note' => &$note, 'options' => $options); $workflow = Workflow::preNoteInsert($prj_id, $issue_id, $data); if ($workflow !== null) { // cancel insert of note return $workflow; } // add the poster to the list of people to be subscribed to the notification list // only if there is no 'unknown user' and the note is not blocked if (!$options['unknown_user'] && !$options['is_blocked']) { $note_cc = $options['add_extra_recipients'] ? $options['cc'] : array(); // always add the current user to the note_cc list $note_cc[] = $usr_id; $actions = Notification::getDefaultActions($issue_id, User::getEmail($usr_id), 'note'); foreach ($note_cc as $subscriber_usr_id) { Notification::subscribeUser($usr_id, $issue_id, $subscriber_usr_id, $actions); } } $params = array('not_iss_id' => $issue_id, 'not_usr_id' => $usr_id, 'not_created_date' => Date_Helper::getCurrentDateGMT(), 'not_note' => $note, 'not_title' => $title, 'not_message_id' => $options['message_id'] ?: Mail_Helper::generateMessageID()); if ($options['full_message']) { $params['not_full_message'] = $options['full_message']; } if ($options['is_blocked']) { $params['not_is_blocked'] = '1'; } if ($options['parent_id']) { $params['not_parent_id'] = $options['parent_id']; } if ($options['unknown_user']) { $params['not_unknown_user'] = $options['unknown_user']; } $stmt = 'INSERT INTO {{%note}} SET ' . DB_Helper::buildSet($params); try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { return -1; } $note_id = DB_Helper::get_last_insert_id(); Issue::markAsUpdated($issue_id, 'note'); if ($options['log']) { // need to save a history entry for this History::add($issue_id, $usr_id, 'note_added', 'Note added by {subject}', array('subject' => User::getFullName($usr_id))); } // send notifications for the issue being updated if ($options['send_notification']) { $internal_only = true; Notification::notify($issue_id, 'notes', $note_id, $internal_only, $options['cc']); Workflow::handleNewNote($prj_id, $issue_id, $usr_id, $options['closing'], $note_id); } // need to return the new note id here so it can // be re-used to associate internal-only attachments return $note_id; }
/** * Adds an email to the outgoing mail queue. * * @access public * @param string $recipient The recipient of this email * @param array $headers The list of headers that should be sent with this email * @param string $body The body of the message * @param integer $save_email_copy Whether to send a copy of this email to a configurable address or not (eventum_sent@) * @param integer $issue_id The ID of the issue. If false, email will not be associated with issue. * @param string $type The type of message this is. * @param integer $sender_usr_id The id of the user sending this email. * @param integer $type_id The ID of the event that triggered this notification (issue_id, sup_id, not_id, etc) * @return true, or a PEAR_Error object */ function add($recipient, $headers, $body, $save_email_copy = 0, $issue_id = false, $type = '', $sender_usr_id = false, $type_id = false) { // avoid sending emails out to users with inactive status $recipient_email = Mail_API::getEmailAddress($recipient); $usr_id = User::getUserIDByEmail($recipient_email); if (!empty($usr_id)) { $user_status = User::getStatusByEmail($recipient_email); // if user is not set to an active status, then silently ignore if (!User::isActiveStatus($user_status) && !User::isPendingStatus($user_status)) { return false; } } $to_usr_id = User::getUserIDByEmail($recipient_email); $recipient = Mail_API::fixAddressQuoting($recipient); $reminder_addresses = Reminder::_getReminderAlertAddresses(); // add specialized headers if (!empty($issue_id) && (!empty($to_usr_id) && User::getRoleByUser($to_usr_id, Issue::getProjectID($issue_id)) > User::getRoleID("Customer")) || @in_array(Mail_API::getEmailAddress($to), $reminder_addresses)) { $headers += Mail_API::getSpecializedHeaders($issue_id, $type, $headers, $sender_usr_id); } if (empty($issue_id)) { $issue_id = 'null'; } // if the Date: header is missing, add it. if (!in_array('Date', array_keys($headers))) { $headers['Date'] = MIME_Helper::encode(date('D, j M Y H:i:s O')); } if (!empty($headers['To'])) { $headers['To'] = Mail_API::fixAddressQuoting($headers['To']); } list(, $text_headers) = Mail_API::prepareHeaders($headers); $stmt = "INSERT INTO\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "mail_queue\n (\n maq_save_copy,\n maq_queued_date,\n maq_sender_ip_address,\n maq_recipient,\n maq_headers,\n maq_body,\n maq_iss_id,\n maq_subject,\n maq_type"; if ($sender_usr_id != false) { $stmt .= ",\nmaq_usr_id"; } if ($type_id != false) { $stmt .= ",\nmaq_type_id"; } $stmt .= ") VALUES (\n {$save_email_copy},\n '" . Date_API::getCurrentDateGMT() . "',\n '" . getenv("REMOTE_ADDR") . "',\n '" . Misc::escapeString($recipient) . "',\n '" . Misc::escapeString($text_headers) . "',\n '" . Misc::escapeString($body) . "',\n " . Misc::escapeInteger($issue_id) . ",\n '" . Misc::escapeString($headers["Subject"]) . "',\n '{$type}'"; if ($sender_usr_id != false) { $stmt .= ",\n" . $sender_usr_id; } if ($type_id != false) { $stmt .= ",\n" . $type_id; } $stmt .= ")"; $res = $GLOBALS["db_api"]->dbh->query($stmt); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return $res; } else { return true; } }