/** * Returns the columns that should be displayed for the specified page. * This method will remove columns that should not be displayed, due to * lack of customer integration or insufficient role. * * @access public * @param integer $prj_id The ID of the project. * @param string $page The page to return columns for. * @return array An array of columns that should be displayed. */ function getColumnsToDisplay($prj_id, $page) { static $returns; // poor man's caching system if (!empty($returns[$prj_id][$page])) { return $returns[$prj_id][$page]; } $current_role = Auth::getCurrentRole(); $data = Display_Column::getSelectedColumns($prj_id, $page); $has_customer_integration = Customer::hasCustomerIntegration($prj_id); $only_with_customers = array('iss_customer_id'); // remove groups if there are no groups in the system. if (count(Group::getAssocList($prj_id)) < 1) { unset($data['iss_grp_id']); } // remove category column if there are no categories in the system if (count(Category::getAssocList($prj_id)) < 1) { unset($data['prc_title']); } // remove custom fields column if there are no custom fields if (count(Custom_Field::getFieldsToBeListed($prj_id)) < 1) { unset($data['custom_fields']); } // remove customer field if user has a role of customer if ($current_role == User::getRoleID("Customer")) { unset($data['iss_customer_id']); } foreach ($data as $field => $info) { // remove fields based on role if ($info['min_role'] > $current_role) { unset($data[$field]); continue; } // remove fields based on customer integration if (!$has_customer_integration && in_array($field, $only_with_customers)) { unset($data[$field]); continue; } // get title $data[$field] = Display_Column::getColumnInfo($page, $field); } $returns[$prj_id][$page] = $data; return $data; }
// issue, so let's remove that as an option $priorities = array_flip(Priority::getAssocList($info['rem_prj_id'])); unset($priorities['Not Prioritized']); $tpl->assign("priorities", array_flip($priorities)); } elseif (@$HTTP_GET_VARS["cat"] == "change_rank") { Reminder::changeRank($HTTP_GET_VARS['id'], $HTTP_GET_VARS['rank']); } elseif (!empty($HTTP_GET_VARS['prj_id'])) { $tpl->assign("info", array('rem_prj_id' => $HTTP_GET_VARS['prj_id'])); $tpl->assign('issues', Reminder::getIssueAssocListByProject($HTTP_GET_VARS['prj_id'])); // wouldn't make much sense to create a reminder for a 'Not Prioritized' // issue, so let's remove that as an option $priorities = array_flip(Priority::getAssocList($HTTP_GET_VARS['prj_id'])); unset($priorities['Not Prioritized']); $tpl->assign("priorities", array_flip($priorities)); // only show customers and support levels if the selected project really needs it $project_has_customer_integration = Customer::hasCustomerIntegration($HTTP_GET_VARS['prj_id']); $tpl->assign("project_has_customer_integration", $project_has_customer_integration); if ($project_has_customer_integration) { $tpl->assign("customers", Customer::getAssocList($HTTP_GET_VARS['prj_id'])); $backend_uses_support_levels = Customer::doesBackendUseSupportLevels($HTTP_GET_VARS['prj_id']); if ($backend_uses_support_levels) { $tpl->assign("support_levels", Customer::getSupportLevelAssocList($HTTP_GET_VARS['prj_id'])); } $tpl->assign("backend_uses_support_levels", $backend_uses_support_levels); } } $tpl->assign("project_list", Project::getAll()); $tpl->assign("list", Reminder::getAdminList()); } else { $tpl->assign("show_not_allowed_msg", true); }
function processResult($res, $date_field, $issue_field) { global $prj_id; global $usr_id; $data = array(); for ($i = 0; $i < count($res); $i++) { if (!Issue::canAccess($res[$i][$issue_field], $usr_id)) { continue; } if (Customer::hasCustomerIntegration($prj_id)) { $details = Customer::getDetails($prj_id, Issue::getCustomerID($res[$i][$issue_field])); $res[$i]["customer"] = @$details['customer_name']; } $res[$i]["date"] = Date_API::getFormattedDate($res[$i][$date_field], Date_API::getPreferredTimezone($usr_id)); // need to decode From:, To: mail headers if (isset($res[$i]["sup_from"])) { $res[$i]["sup_from"] = Mime_Helper::fixEncoding($res[$i]["sup_from"]); } if (isset($res[$i]["sup_to"])) { $res[$i]["sup_to"] = Mime_Helper::fixEncoding($res[$i]["sup_to"]); } $data[] = $res[$i]; } return $data; }
/** * Returns data for the custom fields report, based on the field and options passed in. * * @access public * @param integer $fld_id The id of the custom field. * @param array $cfo_ids An array of option ids. * @param string $group_by How the data should be grouped. * @param boolean $list If the values should be listed out instead of just counted. * @return array An array of data. */ function getCustomFieldReport($fld_id, $cfo_ids, $group_by = "issue", $list = false) { $prj_id = Auth::getCurrentProject(); $fld_id = Misc::escapeInteger($fld_id); $cfo_ids = array_map(array('Misc', 'escapeString'), $cfo_ids); $backend = Custom_Field::getBackend($fld_id); if (is_object($backend)) { $options = array(); foreach ($cfo_ids as $cfo_id) { $options[$cfo_id] = Custom_Field::getOptionValue($fld_id, $cfo_id); } $in_field = 'icf_value'; } else { // get field values $stmt = "SELECT\n cfo_id,\n cfo_value\n FROM\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "custom_field_option\n WHERE\n cfo_fld_id = {$fld_id} AND\n cfo_id IN('" . join("','", $cfo_ids) . "')\n ORDER BY\n cfo_id"; $options = $GLOBALS["db_api"]->dbh->getAssoc($stmt); if (PEAR::isError($options)) { Error_Handler::logError(array($options->getMessage(), $options->getDebugInfo()), __FILE__, __LINE__); return array(); } $in_field = 'cfo_id'; } if ($group_by == "customer") { $group_by_field = "iss_customer_id"; } else { $group_by_field = "iss_id"; } if ($list == true) { $sql = "SELECT\n DISTINCT({$group_by_field}),\n iss_id,\n iss_summary,\n iss_customer_id,\n count(DISTINCT(iss_id)) as row_count\n FROM\n"; if (!is_object($backend)) { $sql .= APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "custom_field_option,\n"; } $sql .= APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_custom_field,\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue\n WHERE\n"; if (!is_object($backend)) { $sql .= "cfo_id = icf_value AND"; } $sql .= "\nicf_iss_id = iss_id AND\n icf_fld_id = {$fld_id} AND\n {$in_field} IN('" . join("','", array_keys($options)) . "')\n GROUP BY\n {$group_by_field}\n ORDER BY\n row_count DESC"; $res = $GLOBALS["db_api"]->dbh->getAll($sql, DB_FETCHMODE_ASSOC); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return array(); } if (Customer::hasCustomerIntegration($prj_id)) { Customer::getCustomerTitlesByIssues($prj_id, $res); if ($group_by == "issue") { usort($res, create_function('$a,$b', 'if ($a["customer_title"] < $b["customer_title"]) { return -1; } elseif ($a["customer_title"] > $b["customer_title"]) { return 1; } else { return 0; }')); } } return $res; } $data = array(); foreach ($options as $cfo_id => $value) { $stmt = "SELECT\n COUNT(DISTINCT {$group_by_field})\n FROM\n"; if (!is_object($backend)) { $stmt .= APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "custom_field_option,\n"; } $stmt .= APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_custom_field,\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue\n WHERE\n"; if (!is_object($backend)) { $stmt .= "cfo_id = icf_value AND"; } $stmt .= "\nicf_iss_id = iss_id AND\n icf_fld_id = {$fld_id} AND\n {$in_field} = '" . Misc::escapeString($cfo_id) . "'"; $count = $GLOBALS["db_api"]->dbh->getOne($stmt); if (PEAR::isError($count)) { Error_Handler::logError(array($count->getMessage(), $count->getDebugInfo()), __FILE__, __LINE__); return array(); } $data[$value] = $count; } // include count of all other values (used in pie chart) $stmt = "SELECT\n COUNT(DISTINCT {$group_by_field})\n FROM\n"; if (!is_object($backend)) { $stmt .= APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "custom_field_option,\n"; } $stmt .= APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_custom_field,\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue\n WHERE\n"; if (!is_object($backend)) { $stmt .= "cfo_id = icf_value AND"; } $stmt .= "\nicf_iss_id = iss_id AND\n icf_fld_id = {$fld_id} AND\n {$in_field} NOT IN('" . join("','", $cfo_ids) . "')"; $res = $GLOBALS["db_api"]->dbh->getOne($stmt); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return array(); } $data["All Others"] = $res; return $data; }
/** * 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); } } }
function handleExpiredCustomer($prj_id) { global $tpl; if (Customer::hasCustomerIntegration($prj_id)) { // check if customer is expired $usr_id = Auth::getUserID(); $contact_id = User::getCustomerContactID($usr_id); if (!empty($contact_id) && $contact_id != -1) { $status = Customer::getContractStatus($prj_id, User::getCustomerID($usr_id)); $email = User::getEmailByContactID($contact_id); if ($status == 'expired') { Customer::sendExpirationNotice($prj_id, $contact_id, true); Auth::saveLoginAttempt($email, 'failure', 'expired contract'); Auth::removeCookie(APP_PROJECT_COOKIE); $contact_id = User::getCustomerContactID($usr_id); $tpl->setTemplate("customer/" . Customer::getBackendImplementationName($prj_id) . "/customer_expired.tpl.html"); $tpl->assign('customer', Customer::getContractDetails($prj_id, $contact_id, false)); $tpl->displayTemplate(); exit; } elseif ($status == 'in_grace_period') { Customer::sendExpirationNotice($prj_id, $contact_id); $tpl->setTemplate("customer/" . Customer::getBackendImplementationName($prj_id) . "/grace_period.tpl.html"); $tpl->assign('customer', Customer::getContractDetails($prj_id, $contact_id, false)); $tpl->assign('expiration_offset', Customer::getExpirationOffset($prj_id)); $tpl->displayTemplate(); exit; } // check with cnt_support to see if this contact is allowed in this support contract if (!Customer::isAllowedSupportContact($prj_id, $contact_id)) { Auth::saveLoginAttempt($email, 'failure', 'not allowed as technical contact'); Auth::redirect(APP_RELATIVE_URL . "index.php?err=4&email=" . $email); } } } }
include_once APP_INC_PATH . "class.misc.php"; include_once APP_INC_PATH . "class.project.php"; include_once APP_INC_PATH . "class.setup.php"; include_once APP_INC_PATH . "db_access.php"; $tpl = new Template_API(); $tpl->setTemplate("manage/index.tpl.html"); Auth::checkAuthentication(APP_COOKIE); $tpl->assign("type", "issue_auto_creation"); @($ema_id = $HTTP_POST_VARS["ema_id"] ? $HTTP_POST_VARS["ema_id"] : $HTTP_GET_VARS["ema_id"]); $role_id = Auth::getCurrentRole(); if ($role_id == User::getRoleID('administrator') || $role_id == User::getRoleID('manager')) { if ($role_id == User::getRoleID('administrator')) { $tpl->assign("show_setup_links", true); } $prj_id = Email_Account::getProjectID($ema_id); if (@$HTTP_POST_VARS["cat"] == "update") { @Email_Account::updateIssueAutoCreation($ema_id, $HTTP_POST_VARS['issue_auto_creation'], $HTTP_POST_VARS['options']); } // load the form fields $tpl->assign("info", Email_Account::getDetails($ema_id)); $tpl->assign("cats", Category::getAssocList($prj_id)); $tpl->assign("priorities", Priority::getList($prj_id)); $tpl->assign("users", Project::getUserAssocList($prj_id, 'active')); $tpl->assign("options", Email_Account::getIssueAutoCreationOptions($ema_id)); $tpl->assign("ema_id", $ema_id); $tpl->assign("prj_title", Project::getName($prj_id)); $tpl->assign("uses_customer_integration", Customer::hasCustomerIntegration($prj_id)); } else { $tpl->assign("show_not_allowed_msg", true); } $tpl->displayTemplate();
$tpl->setTemplate("manage/index.tpl.html"); Auth::checkAuthentication(APP_COOKIE); $tpl->assign("type", "customize_listing"); $role_id = Auth::getCurrentRole(); if ($role_id == User::getRoleID('administrator')) { $tpl->assign("show_setup_links", true); if (@$HTTP_POST_VARS["cat"] == "new") { $tpl->assign("result", Status::insertCustomization($HTTP_POST_VARS['project'], $HTTP_POST_VARS['status'], $HTTP_POST_VARS['date_field'], $HTTP_POST_VARS['label'])); } elseif (@$HTTP_POST_VARS["cat"] == "update") { $tpl->assign("result", Status::updateCustomization($HTTP_POST_VARS['id'], $HTTP_POST_VARS['project'], $HTTP_POST_VARS['status'], $HTTP_POST_VARS['date_field'], $HTTP_POST_VARS['label'])); } elseif (@$HTTP_POST_VARS["cat"] == "delete") { Status::removeCustomization($HTTP_POST_VARS['items']); } if (@$HTTP_GET_VARS["cat"] == "edit") { $details = Status::getCustomizationDetails($HTTP_GET_VARS["id"]); $tpl->assign(array("info" => $details, 'project_id' => $details['psd_prj_id'], 'status_list' => Status::getAssocStatusList($details['psd_prj_id'], TRUE))); } $display_customer_fields = false; @($prj_id = $HTTP_POST_VARS["prj_id"] ? $HTTP_POST_VARS["prj_id"] : $HTTP_GET_VARS["prj_id"]); if (!empty($prj_id)) { $tpl->assign("status_list", Status::getAssocStatusList($prj_id, TRUE)); $tpl->assign('project_id', $prj_id); $display_customer_fields = Customer::hasCustomerIntegration($prj_id); } $tpl->assign("date_fields", Issue::getDateFieldsAssocList($display_customer_fields)); $tpl->assign("project_list", Project::getAll()); $tpl->assign("list", Status::getCustomizationList()); } else { $tpl->assign("show_not_allowed_msg", true); } $tpl->displayTemplate();
function getBackendImplementationName($prj_id) { if (!Customer::hasCustomerIntegration($prj_id)) { return ''; } $backend =& Customer::_getBackend($prj_id); if ($backend) { return $backend->getName(); } }
Auth::checkAuthentication(APP_COOKIE); $tpl->assign("type", "custom_fields"); $role_id = Auth::getCurrentRole(); if ($role_id == User::getRoleID('administrator')) { $tpl->assign("show_setup_links", true); if (@$HTTP_POST_VARS["cat"] == "new") { $tpl->assign("result", Custom_Field::insert()); } elseif (@$HTTP_POST_VARS["cat"] == "update") { $tpl->assign("result", Custom_Field::update()); } elseif (@$HTTP_POST_VARS["cat"] == "delete") { Custom_Field::remove(); } elseif (@$_REQUEST["cat"] == "change_rank") { Custom_Field::changeRank(); } if (@$HTTP_GET_VARS["cat"] == "edit") { $tpl->assign("info", Custom_Field::getDetails($HTTP_GET_VARS["id"])); } $excluded_roles = array(); if (!Customer::hasCustomerIntegration(Auth::getCurrentProject())) { $excluded_roles[] = "customer"; } $user_roles = User::getRoles($excluded_roles); $user_roles[9] = "Never Display"; $tpl->assign("list", Custom_Field::getList()); $tpl->assign("project_list", Project::getAll()); $tpl->assign("user_roles", $user_roles); $tpl->assign("backend_list", Custom_Field::getBackendList()); } else { $tpl->assign("show_not_allowed_msg", true); } $tpl->displayTemplate();
/** * 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; }
include_once APP_INC_PATH . "class.notification.php"; include_once APP_INC_PATH . "db_access.php"; $tpl = new Template_API(); $tpl->setTemplate("close.tpl.html"); Auth::checkAuthentication(APP_COOKIE); $prj_id = Auth::getCurrentProject(); $issue_id = @$HTTP_POST_VARS["issue_id"] ? $HTTP_POST_VARS["issue_id"] : $HTTP_GET_VARS["id"]; $tpl->assign("extra_title", "Close Issue #{$issue_id}"); $notification_list = Notification::getSubscribers($issue_id, 'closed'); $tpl->assign("notification_list_all", $notification_list['all']); $notification_list_internal = Notification::getSubscribers($issue_id, 'closed', User::getRoleID("standard User")); $tpl->assign("notification_list_internal", $notification_list_internal['all']); if (@$HTTP_POST_VARS["cat"] == "close") { $res = Issue::close(Auth::getUserID(), $HTTP_POST_VARS["issue_id"], $HTTP_POST_VARS["send_notification"], $HTTP_POST_VARS["resolution"], $HTTP_POST_VARS["status"], $HTTP_POST_VARS["reason"], @$_REQUEST['notification_list']); if (!empty($HTTP_POST_VARS['time_spent'])) { $HTTP_POST_VARS['summary'] = 'Time entry inserted when closing issue.'; Time_Tracking::insertEntry(); } if (Customer::hasCustomerIntegration($prj_id) && Customer::hasPerIncidentContract($prj_id, Issue::getCustomerID($issue_id))) { Customer::updateRedeemedIncidents($prj_id, $issue_id, @$_REQUEST['redeem']); } $tpl->assign("close_result", $res); } $tpl->assign("statuses", Status::getClosedAssocList($prj_id)); $tpl->assign("resolutions", Resolution::getAssocList()); $tpl->assign("time_categories", Time_Tracking::getAssocCategories()); if (Customer::hasCustomerIntegration($prj_id) && Customer::hasPerIncidentContract($prj_id, Issue::getCustomerID($issue_id))) { $details = Issue::getDetails($issue_id); $tpl->assign(array('redeemed' => Customer::getRedeemedIncidentDetails($prj_id, $issue_id), 'incident_details' => $details['customer_info']['incident_details'])); } $tpl->displayTemplate();
/** * Method to determine if user can access a particular issue * * @access public * @param integer $issue_id The ID of the issue. * @param integer $usr_id The ID of the user * @return boolean If the user can access the issue */ function canAccess($issue_id, $usr_id) { static $access; if (empty($issue_id)) { return true; } if (isset($access[$issue_id . "-" . $usr_id])) { return $access[$issue_id . "-" . $usr_id]; } $details = Issue::getDetails($issue_id); if (empty($details)) { return true; } $usr_details = User::getDetails($usr_id); $usr_role = User::getRoleByUser($usr_id, $details['iss_prj_id']); $prj_id = Issue::getProjectID($issue_id); // check customer permissions if (Customer::hasCustomerIntegration($details['iss_prj_id']) && $usr_role == User::getRoleID("Customer") && $details['iss_customer_id'] != $usr_details['usr_customer_id']) { $return = false; } elseif ($details['iss_private'] == 1) { // check if the issue is even private // check role, reporter, assigment and group if (User::getRoleByUser($usr_id, $details['iss_prj_id']) > User::getRoleID("Developer")) { $return = true; } elseif ($details['iss_usr_id'] == $usr_id) { $return = true; } elseif (Issue::isAssignedToUser($issue_id, $usr_id)) { $return = true; } elseif (!empty($details['iss_grp_id']) && !empty($usr_details['usr_grp_id']) && $details['iss_grp_id'] == $usr_details['usr_grp_id']) { $return = true; } elseif (Authorized_Replier::isUserAuthorizedReplier($issue_id, $usr_id)) { $return = true; } else { $return = false; } } elseif (Auth::getCurrentRole() <= User::getRoleID("Standard User") && Project::getSegregateReporters($prj_id) && $details['iss_usr_id'] != $usr_id && !Issue::isAssignedToUser($issue_id, $usr_id) && !Authorized_Replier::isUserAuthorizedReplier($issue_id, $usr_id)) { return false; } else { $return = true; } $access[$issue_id . "-" . $usr_id] = $return; return $return; }
/** * Method used to send an email notification to the sender of a * set of email messages that were manually converted into an * issue. * * @access public * @param integer $prj_id The project ID * @param integer $issue_id The issue ID * @param array $sup_ids The email IDs * @param integer $customer_id The customer ID * @return array The list of recipient emails */ function notifyEmailConvertedIntoIssue($prj_id, $issue_id, $sup_ids, $customer_id = FALSE) { if (Customer::hasCustomerIntegration($prj_id)) { return Customer::notifyEmailConvertedIntoIssue($prj_id, $issue_id, $sup_ids, $customer_id); } else { // build the list of recipients $recipients = array(); $recipient_emails = array(); for ($i = 0; $i < count($sup_ids); $i++) { $senders = Support::getSender(array($sup_ids[$i])); if (count($senders) > 0) { $sender_email = Mail_API::getEmailAddress($senders[0]); $recipients[$sup_ids[$i]] = $senders[0]; $recipient_emails[] = $sender_email; } } if (count($recipients) == 0) { return false; } $data = Issue::getDetails($issue_id); foreach ($recipients as $sup_id => $recipient) { // open text template $tpl = new Template_API(); $tpl->setTemplate('notifications/new_auto_created_issue.tpl.text'); $tpl->bulkAssign(array("data" => $data, "sender_name" => Mail_API::getName($recipient))); $email_details = Support::getEmailDetails(Email_Account::getAccountByEmail($sup_id), $sup_id); $tpl->assign(array('email' => array('date' => $email_details['sup_date'], 'from' => $email_details['sup_from'], 'subject' => $email_details['sup_subject']))); $text_message = $tpl->getTemplateContents(); // send email (use PEAR's classes) $mail = new Mail_API(); $mail->setTextBody($text_message); $setup = $mail->getSMTPSettings(); $from = Notification::getFixedFromHeader($issue_id, $setup["from"], 'issue'); $mail->setHeaders(Mail_API::getBaseThreadingHeaders($issue_id)); $mail->send($from, $recipient, 'New Issue Created', 1, $issue_id, 'email_converted_to_issue'); } return $recipient_emails; } }
/** * Checks whether the given email address is allowed to send emails in the * issue ID. * * @access public * @param integer $issue_id The issue ID * @param string $sender_email The email address * @return boolean */ function isAllowedToEmail($issue_id, $sender_email) { $prj_id = Issue::getProjectID($issue_id); // check the workflow $workflow_can_email = Workflow::canEmailIssue($prj_id, $issue_id, $sender_email); if ($workflow_can_email != null) { return $workflow_can_email; } $is_allowed = true; $sender_usr_id = User::getUserIDByEmail($sender_email); if (empty($sender_usr_id)) { if (Customer::hasCustomerIntegration($prj_id)) { // check for a customer contact with several email addresses $customer_id = Issue::getCustomerID($issue_id); $contact_emails = array_keys(Customer::getContactEmailAssocList($prj_id, $customer_id, Issue::getContractID($issue_id))); $contact_emails = array_map('strtolower', $contact_emails); if (!in_array(strtolower($sender_email), $contact_emails) && !Authorized_Replier::isAuthorizedReplier($issue_id, $sender_email)) { $is_allowed = false; } } else { if (!Authorized_Replier::isAuthorizedReplier($issue_id, $sender_email)) { $is_allowed = false; } } } else { // check if this user is not a customer and // also not in the assignment list for the current issue and // also not in the authorized repliers list // also not the reporter $details = Issue::getDetails($issue_id); if (!Issue::canAccess($issue_id, $sender_usr_id)) { $is_allowed = false; } if ($sender_usr_id != $details['iss_usr_id'] && !Authorized_Replier::isUserAuthorizedReplier($issue_id, $sender_usr_id) && !Issue::isAssignedToUser($issue_id, $sender_usr_id) && User::getRoleByUser($sender_usr_id, Issue::getProjectID($issue_id)) != User::getRoleID('Customer')) { $is_allowed = false; } elseif (User::getRoleByUser($sender_usr_id, Issue::getProjectID($issue_id)) == User::getRoleID('Customer') && User::getCustomerID($sender_usr_id) != Issue::getCustomerID($issue_id)) { $is_allowed = false; } } return $is_allowed; }
/** * Converts a note to a draft or an email * * @access public * @param $note_id The id of the note * @param $target What the not should be converted too * @param $authorize_sender If the sender should be added to authorized senders list. */ function convertNote($note_id, $target, $authorize_sender = false) { $note_id = Misc::escapeInteger($note_id); $issue_id = Note::getIssueID($note_id); $email_account_id = Email_Account::getEmailAccount(); $blocked_message = Note::getBlockedMessage($note_id); $unknown_user = Note::getUnknownUser($note_id); $structure = Mime_Helper::decode($blocked_message, true, true); $body = Mime_Helper::getMessageBody($structure); $sender_email = strtolower(Mail_API::getEmailAddress($structure->headers['from'])); if ($target == 'email') { if (Mime_Helper::hasAttachments($blocked_message)) { $has_attachments = 1; } else { $has_attachments = 0; } list($blocked_message, $headers) = Mail_API::rewriteThreadingHeaders($issue_id, $blocked_message, @$structure->headers); $t = array('issue_id' => $issue_id, 'ema_id' => $email_account_id, 'message_id' => @$structure->headers['message-id'], 'date' => Date_API::getCurrentDateGMT(), 'from' => @$structure->headers['from'], 'to' => @$structure->headers['to'], 'cc' => @$structure->headers['cc'], 'subject' => @$structure->headers['subject'], 'body' => @$body, 'full_email' => @$blocked_message, 'has_attachment' => $has_attachments, 'headers' => $headers); // need to check for a possible customer association if (!empty($structure->headers['from'])) { $details = Email_Account::getDetails($email_account_id); // check from the associated project if we need to lookup any customers by this email address if (Customer::hasCustomerIntegration($details['ema_prj_id'])) { // check for any customer contact association list($customer_id, ) = Customer::getCustomerIDByEmails($details['ema_prj_id'], array($sender_email)); if (!empty($customer_id)) { $t['customer_id'] = $customer_id; } } } if (empty($t['customer_id'])) { $update_type = 'staff response'; $t['customer_id'] = "NULL"; } else { $update_type = 'customer action'; } $res = Support::insertEmail($t, $structure, $sup_id); if ($res != -1) { Support::extractAttachments($issue_id, $blocked_message); // notifications about new emails are always external $internal_only = false; // special case when emails are bounced back, so we don't want to notify the customer about those if (Notification::isBounceMessage($sender_email)) { $internal_only = true; } Notification::notifyNewEmail(Auth::getUserID(), $issue_id, $t, $internal_only, false, '', $sup_id); Issue::markAsUpdated($issue_id, $update_type); Note::remove($note_id, false); History::add($issue_id, Auth::getUserID(), History::getTypeID('note_converted_email'), "Note converted to e-mail (from: " . @$structure->headers['from'] . ") by " . User::getFullName(Auth::getUserID())); // now add sender as an authorized replier if ($authorize_sender) { Authorized_Replier::manualInsert($issue_id, @$structure->headers['from']); } } return $res; } else { // save message as a draft $res = Draft::saveEmail($issue_id, $structure->headers['to'], $structure->headers['cc'], $structure->headers['subject'], $body, false, $unknown_user); // remove the note, if the draft was created successfully if ($res) { Note::remove($note_id, false); History::add($issue_id, Auth::getUserID(), History::getTypeID('note_converted_draft'), "Note converted to draft (from: " . @$structure->headers['from'] . ") by " . User::getFullName(Auth::getUserID())); } return $res; } }
/** * Processes the template and assigns common variables automatically. * * @access private */ function processTemplate() { global $HTTP_SERVER_VARS; // determine the correct CSS file to use if (ereg('MSIE ([0-9].[0-9]{1,2})', @$HTTP_SERVER_VARS["HTTP_USER_AGENT"], $log_version)) { $user_agent = 'ie'; } else { $user_agent = 'other'; } $this->assign("user_agent", $user_agent); // create the list of projects $usr_id = Auth::getUserID(); if ($usr_id != '') { $prj_id = Auth::getCurrentProject(); if (!empty($prj_id)) { $role_id = User::getRoleByUser($usr_id, $prj_id); $this->assign("current_project", $prj_id); $this->assign("current_project_name", Auth::getCurrentProjectName()); $has_customer_integration = Customer::hasCustomerIntegration($prj_id); $this->assign("has_customer_integration", $has_customer_integration); if ($has_customer_integration) { $this->assign("customer_backend_name", Customer::getBackendImplementationName($prj_id)); } if ($role_id == User::getRoleID('administrator') || $role_id == User::getRoleID('manager')) { $this->assign("show_admin_link", true); } if ($role_id > 0) { $this->assign("current_role", (int) $role_id); $this->assign("current_role_name", User::getRole($role_id)); } } $info = User::getNameEmail($usr_id); $this->assign("active_projects", Project::getAssocList($usr_id)); $this->assign("current_full_name", $info["usr_full_name"]); $this->assign("current_email", $info["usr_email"]); $this->assign("current_user_id", $usr_id); $this->assign("is_current_user_clocked_in", User::isClockedIn($usr_id)); $this->assign("roles", User::getAssocRoleIDs()); } $this->assign("app_setup", Setup::load()); $this->assign("app_setup_path", APP_SETUP_PATH); $this->assign("app_setup_file", APP_SETUP_FILE); $this->assign("application_version", APP_VERSION); $this->assign("application_title", APP_NAME); $this->assign("app_base_url", APP_BASE_URL); $this->assign("rel_url", APP_RELATIVE_URL); $this->assign("lang", APP_CURRENT_LANG); $this->assign("SID", SID); // now for the browser detection stuff Net_UserAgent_Detect::detect(); $this->assign("browser", Net_UserAgent_Detect::_getStaticProperty('browser')); $this->assign("os", Net_UserAgent_Detect::_getStaticProperty('os')); // this is only used by the textarea resize script $js_script_name = str_replace('/', '_', str_replace('.php', '', $HTTP_SERVER_VARS['PHP_SELF'])); $this->assign("js_script_name", $js_script_name); $this->assign("total_queries", $GLOBALS['TOTAL_QUERIES']); $this->assign(array("cell_color" => APP_CELL_COLOR, "light_color" => APP_LIGHT_COLOR, "middle_color" => APP_MIDDLE_COLOR, "dark_color" => APP_DARK_COLOR, "cycle" => APP_CYCLE_COLORS, "internal_color" => APP_INTERNAL_COLOR)); }
/** * Returns a list of issues touched by the specified user in the specified time frame. * * @access public * @param integer $usr_id The id of the user. * @param date $start The start date * @param date $end The end date * @param date $separate_closed If closed issues should be included in a separate array * @return array An array of issues touched by the user. */ function getTouchedIssuesByUser($usr_id, $start, $end, $separate_closed = false) { $stmt = "SELECT\n iss_id,\n iss_prj_id,\n iss_summary,\n iss_customer_id,\n sta_is_closed\n FROM\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history,\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue\n LEFT JOIN\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "status\n ON\n iss_sta_id = sta_id\n WHERE\n his_iss_id = iss_id AND\n his_usr_id = " . Misc::escapeInteger($usr_id) . " AND\n his_created_date BETWEEN '" . Misc::escapeString($start) . "' AND '" . Misc::escapeString($end) . "' AND\n his_htt_id NOT IN(" . join(',', History::getTypeID(array('notification_removed', 'notification_added', 'notification_updated', 'remote_replier_added', 'replier_added', 'replier_removed', 'replier_other_added'))) . ")\n GROUP BY\n iss_id"; $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 ""; } else { $data = array("closed" => array(), "other" => array()); if (count($res) > 0) { foreach ($res as $index => $row) { if (!empty($row["iss_customer_id"]) && Customer::hasCustomerIntegration($row['iss_prj_id'])) { $details = Customer::getDetails($row["iss_prj_id"], $row["iss_customer_id"]); $row["customer_name"] = $details["customer_name"]; } if ($separate_closed && $row['sta_is_closed'] == 1) { $data['closed'][] = $row; } else { $data['other'][] = $row; } } $sort_function = create_function('$a,$b', 'return strcasecmp(@$a["customer_name"], @$b["customer_name"]);'); @usort($data['closed'], $sort_function); @usort($data['other'], $sort_function); } } return $data; }
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 generate a where clause from the given list of conditions. * * @access public * @param array $reminder An array of reminder info. * @param array $conditions The list of conditions * @return string The where clause */ function getWhereClause($reminder, $conditions) { $stmt = ' WHERE iss_prj_id=' . $reminder['rem_prj_id'] . "\n"; $requirement = Reminder::getRequirements($reminder['rem_id']); if ($requirement['type'] == 'issue') { $stmt .= ' AND iss_id IN (' . implode(', ', $requirement['values']) . ")\n"; } else { if (Customer::hasCustomerIntegration($reminder['rem_prj_id'])) { if ($requirement['type'] == 'customer') { $stmt .= ' AND iss_customer_id IN (' . implode(', ', $requirement['values']) . ")\n"; } elseif ($requirement['type'] == 'support_level') { if (Customer::doesBackendUseSupportLevels($reminder['rem_prj_id'])) { $customer_ids = Customer::getListBySupportLevel($reminder['rem_prj_id'], $requirement['values'], CUSTOMER_EXCLUDE_EXPIRED); // break the query on purpose if no customers could be found if (count($customer_ids) == 0) { $customer_ids = array(-1); } $stmt .= ' AND iss_customer_id IN (' . implode(', ', $customer_ids) . ")\n"; } } } } $priorities = Reminder::getAssociatedPriorities($reminder['rem_id']); if (count($priorities) > 0) { $stmt .= ' AND iss_pri_id IN (' . implode(', ', $priorities) . ")\n"; } // now for the interesting stuff for ($i = 0; $i < count($conditions); $i++) { // check for fields that compare to other fields if (!empty($conditions[$i]['rlc_comparison_rmf_id'])) { $sql_field = Reminder_Condition::getSQLField($conditions[$i]['rlc_comparison_rmf_id']); $stmt .= sprintf(" AND %s %s %s\n", $conditions[$i]['rmf_sql_field'], $conditions[$i]['rmo_sql_representation'], $sql_field); } else { // date field values are always saved as number of hours, so let's calculate them now as seconds if (stristr($conditions[$i]['rmf_title'], 'date')) { // support NULL as values for a date field if (strtoupper($conditions[$i]['rlc_value']) == 'NULL') { $conditions[$i]['rmf_sql_representation'] = $conditions[$i]['rmf_sql_field']; } else { $conditions[$i]['rlc_value'] = $conditions[$i]['rlc_value'] * 60 * 60; if (@$reminder["rem_skip_weekend"] == 1) { $sql_field = Reminder_Condition::getSQLField($conditions[$i]['rlc_rmf_id']); $conditions[$i]['rmf_sql_representation'] = DB_API::getNoWeekendDateDiffSQL($sql_field); } } } $stmt .= sprintf(" AND %s %s %s\n", $conditions[$i]['rmf_sql_representation'], $conditions[$i]['rmo_sql_representation'], $conditions[$i]['rlc_value']); } } return $stmt; }
if (@$HTTP_POST_VARS["cat"] == "save") { $tpl->assign("result", Display_Column::save()); } $page = 'list_issues'; $available = Display_Column::getAllColumns($page); $selected = Display_Column::getSelectedColumns($prj_id, $page); // re-order available array to match rank $available_ordered = array(); foreach ($selected as $field_name => $field_info) { $available_ordered[$field_name] = $available[$field_name]; unset($available[$field_name]); } if (count($available) > 0) { $available_ordered += $available; } $excluded_roles = array(); if (!Customer::hasCustomerIntegration($prj_id)) { $excluded_roles[] = "customer"; } $user_roles = User::getRoles($excluded_roles); $user_roles[9] = "Never Display"; // generate ranks $ranks = array(); for ($i = 1; $i <= count($available_ordered); $i++) { $ranks[$i] = $i; } $tpl->assign(array("available" => $available_ordered, "selected" => $selected, "user_roles" => $user_roles, "page" => $page, "ranks" => $ranks, "prj_id" => $prj_id, "project_name" => Project::getName($prj_id))); } else { $tpl->assign("show_not_allowed_msg", true); } $tpl->displayTemplate();
/** * Routes an email to the correct issue. * * @param string $full_message The full email message, including headers * @param integer $email_account_id The ID of the email account this email should be routed too. If empty this method will try to figure it out */ function route_emails($full_message, $email_account_id = 0) { global $HTTP_POST_VARS; // save the full message for logging purposes Support::saveRoutedEmail($full_message); if (preg_match("/^(boundary=).*/m", $full_message)) { $pattern = "/(Content-Type: multipart\\/)(.+); ?\r?\n(boundary=)(.*)\$/im"; $replacement = '$1$2; $3$4'; $full_message = preg_replace($pattern, $replacement, $full_message); } // associate routed emails to the internal system account $sys_account = User::getNameEmail(APP_SYSTEM_USER_ID); $associated_user = $sys_account['usr_email']; // need some validation here if (empty($full_message)) { return array(66, "Error: The email message was empty.\n"); } if (empty($associated_user)) { return array(78, "Error: The associated user for the email routing interface needs to be set.\n"); } // // DON'T EDIT ANYTHING BELOW THIS LINE // // remove the reply-to: header if (preg_match("/^(reply-to:).*/im", $full_message)) { $full_message = preg_replace("/^(reply-to:).*\n/im", '', $full_message, 1); } // check for magic cookie if (Mail_API::hasMagicCookie($full_message)) { // strip the magic cookie $full_message = Mail_API::stripMagicCookie($full_message); $has_magic_cookie = true; } else { $has_magic_cookie = false; } Auth::createFakeCookie(APP_SYSTEM_USER_ID); // check if the email routing interface is even supposed to be enabled $setup = Setup::load(); if ($setup['email_routing']['status'] != 'enabled') { return array(78, "Error: The email routing interface is disabled.\n"); } $prefix = $setup['email_routing']['address_prefix']; // escape plus signs so '*****@*****.**' becomes a valid routing address $prefix = str_replace('+', '\\+', $prefix); $mail_domain = quotemeta($setup['email_routing']['address_host']); $mail_domain_alias = quotemeta(@$setup['email_routing']['host_alias']); if (!empty($mail_domain_alias)) { $mail_domain = "(?:" . $mail_domain . "|" . $mail_domain_alias . ")"; } if (empty($prefix)) { return array(78, "Error: Please configure the email address prefix.\n"); } if (empty($mail_domain)) { return array(78, "Error: Please configure the email address domain.\n"); } $structure = Mime_Helper::decode($full_message, true, true); // find which issue ID this email refers to @preg_match("/{$prefix}(\\d*)@{$mail_domain}/i", $structure->headers['to'], $matches); @($issue_id = $matches[1]); // validation is always a good idea if (empty($issue_id)) { // we need to try the Cc header as well @preg_match("/{$prefix}(\\d*)@{$mail_domain}/i", $structure->headers['cc'], $matches); if (!empty($matches[1])) { $issue_id = $matches[1]; } else { return array(65, "Error: The routed email had no associated Eventum issue ID or had an invalid recipient address.\n"); } } if (empty($email_account_id)) { $issue_prj_id = Issue::getProjectID($issue_id); if (empty($issue_prj_id)) { return array(65, "Error: The routed email had no associated Eventum issue ID or had an invalid recipient address.\n"); } $email_account_id = Email_Account::getEmailAccount($issue_prj_id); } if (empty($email_account_id)) { return array(78, "Error: Please provide the email account ID.\n"); } $body = Mime_Helper::getMessageBody($structure); // hack for clients that set more then one from header if (is_array($structure->headers['from'])) { $structure->headers['from'] = $structure->headers['from'][0]; } // associate the email to the issue $parts = array(); Mime_Helper::parse_output($structure, $parts); // get the sender's email address $sender_email = strtolower(Mail_API::getEmailAddress($structure->headers['from'])); // strip out the warning message sent to staff users if ($setup['email_routing']['status'] == 'enabled' && $setup['email_routing']['warning']['status'] == 'enabled') { $full_message = Mail_API::stripWarningMessage($full_message); $body = Mail_API::stripWarningMessage($body); } $prj_id = Issue::getProjectID($issue_id); Auth::createFakeCookie(APP_SYSTEM_USER_ID, $prj_id); $staff_emails = Project::getUserEmailAssocList($prj_id, 'active', User::getRoleID('Customer')); $staff_emails = array_map('strtolower', $staff_emails); // only allow staff users to use the magic cookie if (!in_array($sender_email, array_values($staff_emails))) { $has_magic_cookie = false; } if (Mime_Helper::hasAttachments($full_message)) { $has_attachments = 1; } else { $has_attachments = 0; } // remove certain CC addresses if (!empty($structure->headers['cc']) && @$setup['smtp']['save_outgoing_email'] == 'yes') { $ccs = explode(",", @$structure->headers['cc']); for ($i = 0; $i < count($ccs); $i++) { if (Mail_API::getEmailAddress($ccs[$i]) == $setup['smtp']['save_address']) { unset($ccs[$i]); } } @($structure->headers['cc'] = join(', ', $ccs)); } // Remove excess Re's @($structure->headers['subject'] = Mail_API::removeExcessRe(@$structure->headers['subject'], true)); $t = array('issue_id' => $issue_id, 'ema_id' => $email_account_id, 'message_id' => @$structure->headers['message-id'], 'date' => Date_API::getCurrentDateGMT(), 'from' => @$structure->headers['from'], 'to' => @$structure->headers['to'], 'cc' => @$structure->headers['cc'], 'subject' => @$structure->headers['subject'], 'body' => @$body, 'full_email' => @$full_message, 'has_attachment' => $has_attachments, 'headers' => @$structure->headers); // automatically associate this incoming email with a customer if (Customer::hasCustomerIntegration($prj_id)) { if (!empty($structure->headers['from'])) { list($customer_id, ) = Customer::getCustomerIDByEmails($prj_id, array($sender_email)); if (!empty($customer_id)) { $t['customer_id'] = $customer_id; } } } if (empty($t['customer_id'])) { $t['customer_id'] = "NULL"; } if (!$has_magic_cookie && Support::blockEmailIfNeeded($t)) { return true; } // re-write Threading headers if needed list($t['full_email'], $t['headers']) = Mail_API::rewriteThreadingHeaders($t['issue_id'], $t['full_email'], $t['headers'], "email"); $res = Support::insertEmail($t, $structure, $sup_id); if ($res != -1) { Support::extractAttachments($issue_id, $full_message); // notifications about new emails are always external $internal_only = false; $assignee_only = false; // special case when emails are bounced back, so we don't want a notification to customers about those if (Notification::isBounceMessage($sender_email)) { // broadcast this email only to the assignees for this issue $internal_only = true; $assignee_only = true; } Notification::notifyNewEmail(Auth::getUserID(), $issue_id, $t, $internal_only, $assignee_only, '', $sup_id); // try to get usr_id of sender, if not, use system account $usr_id = User::getUserIDByEmail(Mail_API::getEmailAddress($structure->headers['from'])); if (!$usr_id) { $usr_id = APP_SYSTEM_USER_ID; } // mark this issue as updated if (!empty($t['customer_id']) && $t['customer_id'] != 'NULL') { Issue::markAsUpdated($issue_id, 'customer action'); } else { if (!empty($usr_id) && User::getRoleByUser($usr_id, $prj_id) > User::getRoleID('Customer')) { Issue::markAsUpdated($issue_id, 'staff response'); } else { Issue::markAsUpdated($issue_id, 'user response'); } } // log routed email History::add($issue_id, $usr_id, History::getTypeID('email_routed'), "Email routed from " . $structure->headers['from']); } return true; }