public function __construct() { $this->usr_id = Auth::getUserID(); if (!Access::canAccessReports($this->usr_id)) { throw new LogicException('Invalid role'); } $this->prj_id = Auth::getCurrentProject(); $this->activity_types = !empty($_REQUEST['activity_types']) ? (array) $_REQUEST['activity_types'] : array(); $this->report_type = isset($_REQUEST['report_type']) ? (string) $_REQUEST['report_type'] : null; $this->unit = $this->getParam('unit', array('hour', 'day')); $this->amount = isset($_REQUEST['amount']) ? $_REQUEST['amount'] : null; $this->developer = isset($_REQUEST['developer']) ? $_REQUEST['developer'] : null; $this->start_date = $this->parseDate(isset($_POST['start']) ? $_POST['start'] : null); $this->end_date = $this->parseDate(isset($_POST['end']) ? $_POST['end'] : null); $this->sort_order = $this->getParam('sort_order', array('ASC', 'DESC')); if (CRM::hasCustomerIntegration($this->prj_id)) { $this->crm = CRM::getInstance($this->prj_id); } }
/** * Method used to get the list of associated support levels for a given * FAQ entry. * * @param integer $prj_id The project ID * @param integer $faq_id The FAQ ID * @return array The list of projects */ public function getAssociatedSupportLevels($prj_id, $faq_id) { if (CRM::hasCustomerIntegration($prj_id)) { $crm = CRM::getInstance($prj_id); $stmt = 'SELECT fsl_support_level_id FROM {{%faq_support_level}} WHERE fsl_faq_id=?'; $ids = DB_Helper::getInstance()->getColumn($stmt, array($faq_id)); $t = array(); $levels = $crm->getSupportLevelAssocList(); foreach ($levels as $support_level_id => $support_level) { if (in_array($support_level_id, $ids)) { $t[$support_level_id] = $support_level; } } return $t; } else { return array(); } }
/** * TODO: merge use of $options and $email arrays to just $email * * @param int $issue_id * @param string $type type of email * @param string $from * @param string $to * @param string $cc * @param string $subject * @param string $body * @param array $options optional parameters * - (int) parent_sup_id * - (array) iaf_ids attachment file ids * - (bool) add_unknown * - (int) ema_id * @return int 1 if it worked, -1 otherwise */ public static function sendEmail($issue_id, $type, $from, $to, $cc, $subject, $body, $options = array()) { $parent_sup_id = $options['parent_sup_id']; $iaf_ids = $options['iaf_ids']; $add_unknown = $options['add_unknown']; $ema_id = $options['ema_id']; $current_usr_id = Auth::getUserID(); $prj_id = Issue::getProjectID($issue_id); // if we are replying to an existing email, set the In-Reply-To: header accordingly $in_reply_to = $parent_sup_id ? self::getMessageIDByID($parent_sup_id) : false; // get ID of whoever is sending this. $sender_usr_id = User::getUserIDByEmail(Mail_Helper::getEmailAddress($from)) ?: false; // remove extra 'Re: ' from subject $subject = Mail_Helper::removeExcessRe($subject, true); $internal_only = false; $message_id = Mail_Helper::generateMessageID(); // process any files being uploaded // from ajax upload, attachment file ids if ($iaf_ids) { // FIXME: is it correct to use sender from post data? $attach_usr_id = $sender_usr_id ?: $current_usr_id; Attachment::attachFiles($issue_id, $attach_usr_id, $iaf_ids, false, 'Attachment originated from outgoing email'); } // hack needed to get the full headers of this web-based email $full_email = self::buildFullHeaders($issue_id, $message_id, $from, $to, $cc, $subject, $body, $in_reply_to, $iaf_ids); // email blocking should only be done if this is an email about an associated issue if ($issue_id) { $user_info = User::getNameEmail($current_usr_id); // check whether the current user is allowed to send this email to customers or not if (!self::isAllowedToEmail($issue_id, $user_info['usr_email'])) { // add the message body as a note $note = Mail_Helper::getCannedBlockedMsgExplanation() . $body; $note_options = array('full_message' => $full_email, 'is_blocked' => true); Note::insertNote($current_usr_id, $issue_id, $subject, $note, $note_options); $email_details = array('from' => $from, 'to' => $to, 'cc' => $cc, 'subject' => $subject, 'body' => &$body, 'message' => &$body, 'title' => $subject); Workflow::handleBlockedEmail($prj_id, $issue_id, $email_details, 'web'); return 1; } } // only send a direct email if the user doesn't want to add the Cc'ed people to the notification list if (($add_unknown || Workflow::shouldAutoAddToNotificationList($prj_id)) && $issue_id) { // add the recipients to the notification list of the associated issue $recipients = array($to); $recipients = array_merge($recipients, self::getRecipientsCC($cc)); foreach ($recipients as $address) { if ($address && !Notification::isIssueRoutingSender($issue_id, $address)) { $actions = Notification::getDefaultActions($issue_id, $address, 'add_unknown_user'); Notification::subscribeEmail($current_usr_id, $issue_id, Mail_Helper::getEmailAddress($address), $actions); } } } else { // Usually when sending out emails associated to an issue, we would // simply insert the email in the table and call the Notification::notifyNewEmail() method, // but on this case we need to actually send the email to the recipients that are not // already in the notification list for the associated issue, if any. // In the case of replying to an email that is not yet associated with an issue, then // we are always directly sending the email, without using any notification list // functionality. if ($issue_id) { // send direct emails only to the unknown addresses, and leave the rest to be // catched by the notification list $from = Notification::getFixedFromHeader($issue_id, $from, 'issue'); // build the list of unknown recipients if ($to) { $recipients = array($to); $recipients = array_merge($recipients, self::getRecipientsCC($cc)); } else { $recipients = self::getRecipientsCC($cc); } $unknowns = array(); foreach ($recipients as $address) { if (!Notification::isSubscribedToEmails($issue_id, $address)) { $unknowns[] = $address; } } if ($unknowns) { $to2 = array_shift($unknowns); $cc2 = implode('; ', $unknowns); // send direct emails self::sendDirectEmail($issue_id, $from, $to2, $cc2, $subject, $body, $_FILES['attachment'], $message_id, $sender_usr_id); } } else { // send direct emails to all recipients, since we don't have an associated issue $project_info = Project::getOutgoingSenderAddress(Auth::getCurrentProject()); // use the project-related outgoing email address, if there is one if (!empty($project_info['email'])) { $from = Mail_Helper::getFormattedName(User::getFullName($current_usr_id), $project_info['email']); } else { // otherwise, use the real email address for the current user $from = User::getFromHeader($current_usr_id); } // send direct emails self::sendDirectEmail($issue_id, $from, $to, $cc, $subject, $body, $_FILES['attachment'], $message_id); } } $email = array('customer_id' => 'NULL', 'issue_id' => $issue_id, 'ema_id' => $ema_id, 'message_id' => $message_id, 'date' => Date_Helper::getCurrentDateGMT(), 'from' => $from, 'to' => $to, 'cc' => $cc, 'subject' => $subject, 'body' => $body, 'full_email' => $full_email); // associate this new email with a customer, if appropriate if (Auth::getCurrentRole() == User::getRoleID('Customer')) { if ($issue_id) { $crm = CRM::getInstance($prj_id); try { $contact = $crm->getContact(User::getCustomerContactID($current_usr_id)); $issue_contract = $crm->getContract(Issue::getContractID($issue_id)); if ($contact->canAccessContract($issue_contract)) { $email['customer_id'] = $issue_contract->getCustomerID(); } } catch (CRMException $e) { } } else { $customer_id = User::getCustomerID($current_usr_id); if ($customer_id && $customer_id != -1) { $email['customer_id'] = $customer_id; } } } $email['has_attachment'] = $iaf_ids ? 1 : 0; $structure = Mime_Helper::decode($full_email, true, false); $email['headers'] = $structure->headers; self::insertEmail($email, $structure, $sup_id); if ($issue_id) { // need to send a notification Notification::notifyNewEmail($current_usr_id, $issue_id, $email, $internal_only, false, $type, $sup_id); // mark this issue as updated $has_customer = $email['customer_id'] && $email['customer_id'] != 'NULL'; if ($has_customer && (!$current_usr_id || User::getRoleByUser($current_usr_id, $prj_id) == User::getRoleID('Customer'))) { Issue::markAsUpdated($issue_id, 'customer action'); } else { if ($sender_usr_id && User::getRoleByUser($sender_usr_id, $prj_id) > User::getRoleID('Customer')) { Issue::markAsUpdated($issue_id, 'staff response'); } else { Issue::markAsUpdated($issue_id, 'user response'); } } History::add($issue_id, $current_usr_id, 'email_sent', 'Outgoing email sent by {user}', array('user' => User::getFullName($current_usr_id))); } return 1; }
/** * Method used to get the list of issues to be displayed in the grid layout. * * @param array $options The search parameters * @return string The where clause */ public static function buildWhereClause($options) { $usr_id = Auth::getUserID(); $prj_id = Auth::getCurrentProject(); $role_id = User::getRoleByUser($usr_id, $prj_id); $usr_details = User::getDetails($usr_id); $stmt = ' AND iss_usr_id = usr_id'; if ($role_id == User::getRoleID('Customer')) { $crm = CRM::getInstance($prj_id); $contact = $crm->getContact($usr_details['usr_customer_contact_id']); $stmt .= " AND iss_customer_contract_id IN('" . implode("','", $contact->getContractIDS()) . "')"; $stmt .= " AND iss_customer_id ='" . Auth::getCurrentCustomerID() . "'"; } elseif ($role_id == User::getRoleID('Reporter') && Project::getSegregateReporters($prj_id)) { $stmt .= " AND (\n iss_usr_id = {$usr_id} OR\n iur_usr_id = {$usr_id}\n )"; } if (!empty($usr_details['usr_par_code'])) { // restrict partners $stmt .= " AND ipa_par_code = '" . Misc::escapeString($usr_details['usr_par_code']) . "'"; } if (!empty($options['users'])) { $stmt .= " AND (\n"; if (stristr($options['users'], 'grp') !== false) { $chunks = explode(':', $options['users']); $stmt .= 'iss_grp_id = ' . Misc::escapeInteger($chunks[1]); } else { if ($options['users'] == '-1') { $stmt .= 'isu_usr_id IS NULL'; } elseif ($options['users'] == '-2') { $stmt .= 'isu_usr_id IS NULL OR isu_usr_id=' . $usr_id; } elseif ($options['users'] == '-3') { $stmt .= 'isu_usr_id = ' . $usr_id . ' OR iss_grp_id = ' . User::getGroupID($usr_id); } elseif ($options['users'] == '-4') { $stmt .= 'isu_usr_id IS NULL OR isu_usr_id = ' . $usr_id . ' OR iss_grp_id = ' . User::getGroupID($usr_id); } else { $stmt .= 'isu_usr_id =' . Misc::escapeInteger($options['users']); } } $stmt .= ')'; } if (!empty($options['reporter'])) { $stmt .= ' AND iss_usr_id = ' . Misc::escapeInteger($options['reporter']); } if (!empty($options['show_authorized_issues'])) { $stmt .= " AND (iur_usr_id={$usr_id})"; } if (!empty($options['show_notification_list_issues'])) { $stmt .= " AND (sub_usr_id={$usr_id})"; } if (!empty($options['keywords'])) { $stmt .= " AND (\n"; if ($options['search_type'] == 'all_text' && APP_ENABLE_FULLTEXT) { $stmt .= 'iss_id IN(' . implode(', ', self::getFullTextIssues($options)) . ')'; } elseif ($options['search_type'] == 'customer' && CRM::hasCustomerIntegration($prj_id)) { // check if the user is trying to search by customer name / email $crm = CRM::getInstance($prj_id); $customer_ids = $crm->getCustomerIDsByString($options['keywords'], true); if (count($customer_ids) > 0) { $stmt .= ' iss_customer_id IN (' . implode(', ', $customer_ids) . ')'; } else { // no results, kill query $stmt .= ' iss_customer_id = -1'; } } else { $stmt .= '(' . Misc::prepareBooleanSearch('iss_summary', $options['keywords']); $stmt .= ' OR ' . Misc::prepareBooleanSearch('iss_description', $options['keywords']) . ')'; } $stmt .= "\n) "; } if (!empty($options['customer_id'])) { $stmt .= " AND iss_customer_id='" . Misc::escapeString($options['customer_id']) . "'"; } if (!empty($options['priority'])) { $stmt .= ' AND iss_pri_id=' . Misc::escapeInteger($options['priority']); } if (!empty($options['status'])) { $stmt .= ' AND iss_sta_id=' . Misc::escapeInteger($options['status']); } if (!empty($options['category'])) { if (!is_array($options['category'])) { $options['category'] = array($options['category']); } $stmt .= ' AND iss_prc_id IN(' . implode(', ', Misc::escapeInteger($options['category'])) . ')'; } if (!empty($options['hide_closed'])) { $stmt .= ' AND sta_is_closed=0'; } if (!empty($options['release'])) { $stmt .= ' AND iss_pre_id = ' . Misc::escapeInteger($options['release']); } if (!empty($options['product'])) { $stmt .= ' AND ipv_pro_id = ' . Misc::escapeInteger($options['product']); } // now for the date fields $date_fields = array('created_date', 'updated_date', 'last_response_date', 'first_response_date', 'closed_date'); foreach ($date_fields as $field_name) { if (!empty($options[$field_name])) { switch ($options[$field_name]['filter_type']) { case 'greater': $stmt .= " AND iss_{$field_name} >= '" . Misc::escapeString($options[$field_name]['start']) . "'"; break; case 'less': $stmt .= " AND iss_{$field_name} <= '" . Misc::escapeString($options[$field_name]['start']) . "'"; break; case 'between': $stmt .= " AND iss_{$field_name} BETWEEN '" . Misc::escapeString($options[$field_name]['start']) . "' AND '" . Misc::escapeString($options[$field_name]['end']) . "'"; break; case 'null': $stmt .= " AND iss_{$field_name} IS NULL"; break; case 'in_past': if (strlen($options[$field_name]['time_period']) == 0) { $options[$field_name]['time_period'] = 0; } $stmt .= " AND (UNIX_TIMESTAMP('" . Date_Helper::getCurrentDateGMT() . "') - UNIX_TIMESTAMP(iss_{$field_name})) <= (" . Misc::escapeInteger($options[$field_name]['time_period']) . '*3600)'; break; } } } // custom fields if (is_array($options['custom_field']) && count($options['custom_field']) > 0) { foreach ($options['custom_field'] as $fld_id => $search_value) { if (empty($search_value)) { continue; } $field = Custom_Field::getDetails($fld_id); $fld_db_name = Custom_Field::getDBValueFieldNameByType($field['fld_type']); if ($field['fld_type'] == 'date' && (empty($search_value['Year']) || empty($search_value['Month']) || empty($search_value['Day']))) { continue; } if ($field['fld_type'] == 'integer' && empty($search_value['value'])) { continue; } if ($field['fld_type'] == 'multiple') { $search_value = Misc::escapeString($search_value); foreach ($search_value as $cfo_id) { $cfo_id = Misc::escapeString($cfo_id); $stmt .= " AND\n cf" . $fld_id . '_' . $cfo_id . '.icf_iss_id = iss_id'; $stmt .= " AND\n cf" . $fld_id . '_' . $cfo_id . ".icf_fld_id = {$fld_id}"; $stmt .= " AND\n cf" . $fld_id . '_' . $cfo_id . '.' . $fld_db_name . " = '{$cfo_id}'"; } } elseif ($field['fld_type'] == 'date') { if (empty($search_value['Year']) || empty($search_value['Month']) || empty($search_value['Day'])) { continue; } $search_value = $search_value['Year'] . '-' . $search_value['Month'] . '-' . $search_value['Day']; $stmt .= " AND\n (iss_id = cf" . $fld_id . '.icf_iss_id AND cf' . $fld_id . '.' . $fld_db_name . " = '" . Misc::escapeString($search_value) . "')"; } elseif ($field['fld_type'] == 'integer') { $value = $search_value['value']; switch ($search_value['filter_type']) { case 'ge': $cmp = '>='; break; case 'le': $cmp = '<='; break; case 'gt': $cmp = '>'; break; case 'lt': $cmp = '<'; break; default: $cmp = '='; break; } $stmt .= " AND\n (iss_id = cf" . $fld_id . '.icf_iss_id'; $stmt .= " AND\n cf" . $fld_id . ".icf_fld_id = {$fld_id}"; $stmt .= ' AND cf' . $fld_id . '.' . $fld_db_name . $cmp . Misc::escapeString($value) . ')'; } else { $stmt .= " AND\n (iss_id = cf" . $fld_id . '.icf_iss_id'; $stmt .= " AND\n cf" . $fld_id . ".icf_fld_id = {$fld_id}"; if ($field['fld_type'] == 'combo') { $stmt .= ' AND cf' . $fld_id . '.' . $fld_db_name . " IN('" . implode("', '", Misc::escapeString($search_value)) . "')"; } else { $stmt .= ' AND cf' . $fld_id . '.' . $fld_db_name . " LIKE '%" . Misc::escapeString($search_value) . "%'"; } $stmt .= ')'; } } } // clear cached full-text values if we are not searching fulltext anymore if (APP_ENABLE_FULLTEXT && @$options['search_type'] != 'all_text') { Session::set('fulltext_string', ''); Session::set('fulltext_issues', ''); } return $stmt; }
// 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($info['rem_prj_id'])); unset($priorities['Not Prioritized']); $tpl->assign('priorities', array_flip($priorities)); $tpl->assign('severities', Severity::getAssocList($info['rem_prj_id'])); $tpl->assign('products', Product::getAssocList()); } elseif (@$_GET['cat'] == 'change_rank') { Reminder::changeRank($_GET['id'], $_GET['rank']); } elseif (!empty($_GET['prj_id'])) { $tpl->assign('info', array('rem_prj_id' => $_GET['prj_id'])); $tpl->assign('issues', Reminder::getIssueAssocListByProject($_GET['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($_GET['prj_id'])); unset($priorities['Not Prioritized']); $tpl->assign('priorities', array_flip($priorities)); $tpl->assign('severities', Severity::getAssocList($_GET['prj_id'])); $tpl->assign('products', Product::getAssocList()); // only show customers and support levels if the selected project really needs it $project_has_customer_integration = CRM::hasCustomerIntegration($_GET['prj_id']); $tpl->assign('project_has_customer_integration', $project_has_customer_integration); if ($project_has_customer_integration) { $crm = CRM::getInstance($_GET['prj_id']); $tpl->assign('customers', $crm->getCustomerAssocList()); $tpl->assign('support_levels', $crm->getSupportLevelAssocList()); } } $tpl->assign('project_list', Project::getAll()); $tpl->assign('list', Reminder::getAdminList()); $tpl->displayTemplate();
/** * Converts a note to a draft or an email * * @param int $note_id The id of the note * @param string $target What the note should be converted too (email, etc) * @param bool $authorize_sender If $authorize_sender If the sender should be added to authorized senders list. * @return int */ public static function convertNote($note_id, $target, $authorize_sender = false) { $issue_id = self::getIssueID($note_id); $email_account_id = Email_Account::getEmailAccount(); $blocked_message = self::getBlockedMessage($note_id); $unknown_user = self::getUnknownUser($note_id); $structure = Mime_Helper::decode($blocked_message, true, true); $body = $structure->body; $sender_email = strtolower(Mail_Helper::getEmailAddress($structure->headers['from'])); $current_usr_id = Auth::getUserID(); if ($target == 'email') { if (Mime_Helper::hasAttachments($structure)) { $has_attachments = 1; } else { $has_attachments = 0; } list($blocked_message, $headers) = Mail_Helper::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_Helper::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 (CRM::hasCustomerIntegration($details['ema_prj_id'])) { $crm = CRM::getInstance($details['ema_prj_id']); // check for any customer contact association try { $contact = $crm->getContactByEmail($sender_email); $issue_contract = $crm->getContract(Issue::getContractID($issue_id)); if ($contact->canAccessContract($issue_contract)) { $t['customer_id'] = $issue_contract->getCustomerID(); } } catch (CRMException $e) { } } } 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, $structure); // 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($current_usr_id, $issue_id, $t, $internal_only, false, '', $sup_id); Issue::markAsUpdated($issue_id, $update_type); self::remove($note_id, false); History::add($issue_id, $current_usr_id, 'note_converted_email', 'Note converted to e-mail (from: {from}) by {user}', array('from' => @$structure->headers['from'], 'user' => User::getFullName($current_usr_id))); // now add sender as an authorized replier if ($authorize_sender) { Authorized_Replier::manualInsert($issue_id, @$structure->headers['from']); } } return $res; } // 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) { self::remove($note_id, false); $usr_id = $current_usr_id; History::add($issue_id, $usr_id, 'note_converted_draft', 'Note converted to draft (from: {from}) by {user}', array('from' => @$structure->headers['from'], 'user' => User::getFullName($current_usr_id))); } return $res; }
function checkCustomerAuthentication($prj_id) { if (CRM::hasCustomerIntegration($prj_id)) { $crm = CRM::getInstance($prj_id); // check if customer is expired $usr_id = Auth::getUserID(); $contact_id = User::getCustomerContactID($usr_id); if (User::getRoleByUser($usr_id, $prj_id) == User::ROLE_CUSTOMER) { $crm->authenticateCustomer(); } } }
/** * Method used to get the details for a specific issue. * * @param integer $issue_id The issue ID * @param boolean $force_refresh If the cache should not be used. * @return array The details for the specified issue */ public static function getDetails($issue_id, $force_refresh = false) { static $returns; if (empty($issue_id)) { return ''; } if (!empty($returns[$issue_id]) && $force_refresh != true) { return $returns[$issue_id]; } $stmt = 'SELECT {{%issue}}.*, prj_title, prc_title, pre_title, pri_title, sev_title, sta_title, sta_abbreviation, sta_color status_color, sta_is_closed FROM ( {{%issue}}, {{%project}} ) LEFT JOIN {{%project_priority}} ON iss_pri_id=pri_id LEFT JOIN {{%project_severity}} ON iss_sev_id=sev_id LEFT JOIN {{%status}} ON iss_sta_id=sta_id LEFT JOIN {{%project_category}} ON iss_prc_id=prc_id LEFT JOIN {{%project_release}} ON iss_pre_id=pre_id WHERE iss_id=? AND iss_prj_id=prj_id'; try { $res = DB_Helper::getInstance()->getRow($stmt, array($issue_id)); } catch (DbException $e) { return ''; } if (empty($res)) { return ''; } $created_date_ts = Date_Helper::getUnixTimestamp($res['iss_created_date'], Date_Helper::getDefaultTimezone()); // get customer information, if any if (!empty($res['iss_customer_id']) && CRM::hasCustomerIntegration($res['iss_prj_id'])) { $crm = CRM::getInstance($res['iss_prj_id']); try { $customer = $crm->getCustomer($res['iss_customer_id']); $contract = $crm->getContract($res['iss_customer_contract_id']); $res['contact_local_time'] = Date_Helper::getFormattedDate(Date_Helper::getCurrentDateGMT(), $res['iss_contact_timezone']); $res['customer'] = $customer; $res['contract'] = $contract; $res['contact'] = $crm->getContact($res['iss_customer_contact_id']); // TODOCRM: Deal with incidents // $res['redeemed_incidents'] = Customer::getRedeemedIncidentDetails($res['iss_prj_id'], $res['iss_id']); $max_first_response_time = $contract->getMaximumFirstResponseTime($issue_id); $res['max_first_response_time'] = Misc::getFormattedTime($max_first_response_time / 60); if (empty($res['iss_first_response_date'])) { $first_response_deadline = $created_date_ts + $max_first_response_time; if (time() <= $first_response_deadline) { $res['max_first_response_time_left'] = Date_Helper::getFormattedDateDiff($first_response_deadline, time()); } else { $res['overdue_first_response_time'] = Date_Helper::getFormattedDateDiff(time(), $first_response_deadline); } } } catch (CRMException $e) { // TODOCRM: Log exception? } } $res['iss_original_description'] = $res['iss_description']; $res['iss_original_percent_complete'] = $res['iss_percent_complete']; $res['iss_description'] = nl2br(htmlspecialchars($res['iss_description'])); $res['iss_resolution'] = Resolution::getTitle($res['iss_res_id']); $res['iss_impact_analysis'] = nl2br(htmlspecialchars($res['iss_impact_analysis'])); $res['iss_created_date_ts'] = $created_date_ts; $res['assignments'] = @implode(', ', array_values(self::getAssignedUsers($res['iss_id']))); list($res['authorized_names'], $res['authorized_repliers']) = Authorized_Replier::getAuthorizedRepliers($res['iss_id']); $temp = self::getAssignedUsersStatus($res['iss_id']); $res['has_inactive_users'] = 0; $res['assigned_users'] = array(); $res['assigned_inactive_users'] = array(); foreach ($temp as $usr_id => $usr_status) { if (!User::isActiveStatus($usr_status)) { $res['assigned_inactive_users'][] = $usr_id; $res['has_inactive_users'] = 1; } else { $res['assigned_users'][] = $usr_id; } } if (@in_array(Auth::getUserID(), $res['assigned_users'])) { $res['is_current_user_assigned'] = 1; } else { $res['is_current_user_assigned'] = 0; } $res['associated_issues_details'] = self::getAssociatedIssuesDetails($res['iss_id']); $res['associated_issues'] = self::getAssociatedIssues($res['iss_id']); $res['reporter'] = User::getFullName($res['iss_usr_id']); if (empty($res['iss_updated_date'])) { $res['iss_updated_date'] = $res['iss_created_date']; } $res['estimated_formatted_time'] = Misc::getFormattedTime($res['iss_dev_time']); if (Release::isAssignable($res['iss_pre_id'])) { $release = Release::getDetails($res['iss_pre_id']); $res['pre_title'] = $release['pre_title']; $res['pre_status'] = $release['pre_status']; } // need to return the list of issues that are duplicates of this one $res['duplicates'] = self::getDuplicateList($res['iss_id']); $res['duplicates_details'] = self::getDuplicateDetailsList($res['iss_id']); // also get the issue title of the duplicated issue if (!empty($res['iss_duplicated_iss_id'])) { $res['duplicated_issue'] = self::getDuplicatedDetails($res['iss_duplicated_iss_id']); } // get group information if (!empty($res['iss_grp_id'])) { $res['group'] = Group::getDetails($res['iss_grp_id']); } // get quarantine issue $res['quarantine'] = self::getQuarantineInfo($res['iss_id']); $res['products'] = Product::getProductsByIssue($res['iss_id']); $returns[$issue_id] = $res; return $res; }
/** * Returns an array of notes for all customers. * * @return array An array of notes. */ public static function getNoteList() { $stmt = 'SELECT cno_id, cno_prj_id, cno_customer_id, cno_note FROM {{%customer_note}} ORDER BY cno_customer_id ASC'; try { $res = DB_Helper::getInstance()->getAll($stmt); } catch (DbException $e) { return array(); } foreach ($res as &$row) { try { $crm = CRM::getInstance($row['cno_prj_id']); $row['customer_title'] = $crm->getCustomer($row['cno_customer_id'])->getName(); } catch (Exception $e) { } } return $res; }
if (@$_POST['cat'] == 'new') { $res = FAQ::insert(); Misc::mapMessages($res, array(1 => array(ev_gettext('Thank you, the FAQ entry was added successfully.'), Misc::MSG_INFO), -1 => array(ev_gettext('An error occurred while trying to add the FAQ entry.'), Misc::MSG_ERROR), -2 => array(ev_gettext('Please enter the title for this FAQ entry.'), Misc::MSG_ERROR), -3 => array(ev_gettext('Please enter the message for this FAQ entry.'), Misc::MSG_ERROR))); } elseif (@$_POST['cat'] == 'update') { $res = FAQ::update(); Misc::mapMessages($res, array(1 => array(ev_gettext('Thank you, the FAQ entry was updated successfully.'), Misc::MSG_INFO), -1 => array(ev_gettext('An error occurred while trying to update the FAQ entry information.'), Misc::MSG_ERROR), -2 => array(ev_gettext('Please enter the title for this FAQ entry.'), Misc::MSG_ERROR), -3 => array(ev_gettext('Please enter the message for this FAQ entry.'), Misc::MSG_ERROR))); } elseif (@$_POST['cat'] == 'delete') { FAQ::remove(); } elseif (!empty($_GET['prj_id'])) { $tpl->assign('info', array('faq_prj_id' => $_GET['prj_id'])); if (CRM::hasCustomerIntegration($_GET['prj_id'])) { $crm = CRM::getInstance($_GET['prj_id']); $tpl->assign('support_levels', $crm->getSupportLevelAssocList()); } } if (@$_GET['cat'] == 'edit') { $info = FAQ::getDetails($_GET['id']); if (!empty($_GET['prj_id'])) { $info['faq_prj_id'] = $_GET['prj_id']; } if (CRM::hasCustomerIntegration($info['faq_prj_id'])) { $crm = CRM::getInstance($info['faq_prj_id']); $tpl->assign('support_levels', $crm->getSupportLevelAssocList()); } $tpl->assign('info', $info); } elseif (@$_GET['cat'] == 'change_rank') { FAQ::changeRank($_GET['id'], $_GET['rank']); } $tpl->assign('list', FAQ::getList()); $tpl->assign('project_list', Project::getAll()); $tpl->displayTemplate();
/** * Method used to generate a where clause from the given list of conditions. * * @param array $reminder An array of reminder info. * @param array $conditions The list of conditions * @return string The where clause */ public function getWhereClause($reminder, $conditions) { $stmt = ' WHERE iss_prj_id=' . $reminder['rem_prj_id'] . "\n"; $requirement = self::getRequirements($reminder['rem_id']); if ($requirement['type'] == 'issue') { $stmt .= ' AND iss_id IN (' . implode(', ', $requirement['values']) . ")\n"; } else { if (CRM::hasCustomerIntegration($reminder['rem_prj_id'])) { $crm = CRM::getInstance($reminder['rem_prj_id']); if ($requirement['type'] == 'customer') { $stmt .= ' AND iss_customer_id IN (' . implode(', ', $requirement['values']) . ")\n"; } elseif ($requirement['type'] == 'support_level') { $customer_ids = $crm->getCustomerIDsBySupportLevel($requirement['values'], array(CRM_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 = self::getAssociatedPriorities($reminder['rem_id']); if (count($priorities) > 0) { $stmt .= ' AND iss_pri_id IN (' . implode(', ', $priorities) . ")\n"; } $products = self::getAssociatedProducts($reminder['rem_id']); if (count($products) > 0) { $stmt .= ' AND ipv_iss_id = iss_id AND ipv_pro_id IN (' . implode(', ', $products) . ")\n"; } $severities = self::getAssociatedSeverities($reminder['rem_id']); if (count($severities) > 0) { $stmt .= ' AND iss_sev_id IN (' . implode(', ', $severities) . ")\n"; } // now for the interesting stuff foreach ($conditions as &$cond) { if (empty($cond['rmf_sql_representation'])) { continue; } // check for fields that compare to other fields if (!empty($cond['rlc_comparison_rmf_id'])) { $sql_field = Reminder_Condition::getSQLField($cond['rlc_comparison_rmf_id']); $stmt .= sprintf(" AND %s %s %s\n", $cond['rmf_sql_field'], $cond['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($cond['rmf_title'], 'date')) { // support NULL as values for a date field if (strtoupper($cond['rlc_value']) == 'NULL') { $cond['rmf_sql_representation'] = $cond['rmf_sql_field']; } elseif (strtoupper($cond['rlc_value']) == 'NOW') { $cond['rmf_sql_representation'] = 'UNIX_TIMESTAMP(' . $cond['rmf_sql_field'] . ')'; $cond['rlc_value'] = 'UNIX_TIMESTAMP()'; } else { $cond['rlc_value'] = $cond['rlc_value'] * 60 * 60; if (@$reminder['rem_skip_weekend'] == 1) { $sql_field = Reminder_Condition::getSQLField($cond['rlc_rmf_id']); $cond['rmf_sql_representation'] = DB_Helper::getNoWeekendDateDiffSQL($sql_field); } } } $stmt .= sprintf(" AND %s %s %s\n", $cond['rmf_sql_representation'], $cond['rmo_sql_representation'], $cond['rlc_value']); } } return $stmt; }
/** * Generates the specialized headers for an email. * * @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 */ public static 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 (CRM::hasCustomerIntegration($prj_id)) { $crm = CRM::getInstance($prj_id); try { $customer = $crm->getCustomer(Issue::getCustomerID($issue_id)); $new_headers['X-Eventum-Customer'] = $customer->getName(); } catch (CustomerNotFoundException $e) { } try { $contract = $crm->getContract(Issue::getContractID($issue_id)); $support_level = $contract->getSupportLevel(); if (is_object($support_level)) { $new_headers['X-Eventum-Level'] = $support_level->getName(); } } catch (ContractNotFoundException $e) { } } // add assignee header $new_headers['X-Eventum-Assignee'] = implode(',', User::getEmail(Issue::getAssignedUserIDs($issue_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-Priority'] = Priority::getTitle(Issue::getPriority($issue_id)); // handle custom fields $cf_values = Custom_Field::getValuesByIssue($prj_id, $issue_id); $cf_titles = Custom_Field::getFieldsToBeListed($prj_id); foreach ($cf_values as $fld_id => $values) { // skip empty titles // TODO: why they are empty? if (!isset($cf_titles[$fld_id])) { continue; } // skip empty values if (empty($values)) { continue; } $cf_value = implode(', ', (array) $values); // value could be empty after multivalued field join if (empty($cf_value)) { continue; } // convert spaces for header fields $cf_title = str_replace(' ', '_', $cf_titles[$fld_id]); $new_headers['X-Eventum-CustomField-' . $cf_title] = $cf_value; } } $new_headers['X-Eventum-Type'] = $type; return $new_headers; }
/** * Method used to send an email notification to the sender of a * set of email messages that were manually converted into an * issue. * * @param integer $prj_id The project ID * @param integer $issue_id The issue ID * @param array $sup_ids The email IDs * @param bool|int $customer_id The customer ID * @return array The list of recipient emails */ public static function notifyEmailConvertedIntoIssue($prj_id, $issue_id, $sup_ids, $customer_id = false) { if (CRM::hasCustomerIntegration($prj_id)) { $crm = CRM::getInstance($prj_id); return $crm->notifyEmailConvertedIntoIssue($issue_id, $sup_ids, $customer_id); } else { // build the list of recipients $recipients = array(); $recipient_emails = array(); foreach ($sup_ids as $sup_id) { $senders = Support::getSender(array($sup_id)); if (count($senders) > 0) { $sender_email = Mail_Helper::getEmailAddress($senders[0]); $recipients[$sup_id] = $senders[0]; $recipient_emails[] = $sender_email; } } if (!$recipients) { return false; } $data = Issue::getDetails($issue_id); foreach ($recipients as $sup_id => $recipient) { $recipient_usr_id = User::getUserIDByEmail(Mail_Helper::getEmailAddress($recipient)); // open text template $tpl = new Template_Helper(); $tpl->setTemplate('notifications/new_auto_created_issue.tpl.text'); $tpl->assign(array('data' => $data, 'sender_name' => Mail_Helper::getName($recipient), 'app_title' => Misc::getToolCaption(), 'recipient_name' => Mail_Helper::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']))); // change the current locale if (!empty($recipient_usr_id)) { Language::set(User::getLang($recipient_usr_id)); } else { Language::set(APP_DEFAULT_LOCALE); } $text_message = $tpl->getTemplateContents(); // send email (use PEAR's classes) $mail = new Mail_Helper(); $mail->setTextBody($text_message); $setup = $mail->getSMTPSettings(); $from = self::getFixedFromHeader($issue_id, $setup['from'], 'issue'); $mail->setHeaders(Mail_Helper::getBaseThreadingHeaders($issue_id)); // TRANSLATORS: %1 - issue_id, %2 - iss_summary $subject = ev_gettext('[#%1$s] Issue Created: %2$s', $issue_id, $data['iss_summary']); $mail->send($from, $recipient, $subject, 1, $issue_id, 'email_converted_to_issue'); } Language::restore(); return $recipient_emails; } }
/** * @static * @return Contact */ public static function getCurrentContact() { $crm = CRM::getInstance(self::getCurrentProject()); return $crm->getContact(User::getCustomerContactID(self::getUserID())); }
/** * Processes the template and assign common variables automatically. * @return $this */ private function processTemplate() { $core = array('rel_url' => APP_RELATIVE_URL, 'base_url' => APP_BASE_URL, 'app_title' => APP_NAME, 'app_version' => APP_VERSION, 'app_setup' => Setup::load(), 'messages' => Misc::getMessages(), 'roles' => User::getAssocRoleIDs(), 'auth_backend' => APP_AUTH_BACKEND, 'current_url' => $_SERVER['PHP_SELF']); // If VCS version is present "Eventum 2.3.3-148-g78b3368", link ref to github $vcsVersion = self::getVcsVersion(); if ($vcsVersion) { $link = "https://github.com/eventum/eventum/commit/{$vcsVersion}"; $core['application_version_link'] = $link; // append VCS version if not yet there if (!preg_match('/-g[0-9a-f]+$/', APP_VERSION)) { $core['app_version'] = "v{$core['app_version']}-g{$vcsVersion}"; } } $usr_id = Auth::getUserID(); if ($usr_id) { $core['user'] = User::getDetails($usr_id); $prj_id = Auth::getCurrentProject(); $setup = Setup::load(); if (!empty($prj_id)) { $role_id = User::getRoleByUser($usr_id, $prj_id); $has_crm = CRM::hasCustomerIntegration($prj_id); $core = $core + array('project_id' => $prj_id, 'project_name' => Auth::getCurrentProjectName(), 'has_crm' => $has_crm, 'current_role' => $role_id, 'current_role_name' => User::getRole($role_id), 'feature_access' => Access::getFeatureAccessArray($usr_id)); if ($has_crm) { $crm = CRM::getInstance($prj_id); $core['crm_template_path'] = $crm->getTemplatePath(); if ($role_id == User::getRoleID('Customer')) { try { $contact = $crm->getContact($core['user']['usr_customer_contact_id']); $core['allowed_customers'] = $contact->getCustomers(); $core['current_customer'] = $crm->getCustomer(Auth::getCurrentCustomerID(false)); } catch (CRMException $e) { } } } } $info = User::getDetails($usr_id); $raw_projects = Project::getAssocList(Auth::getUserID(), false, true); $active_projects = array(); foreach ($raw_projects as $prj_id => $prj_info) { if ($prj_info['status'] == 'archived') { $prj_info['prj_title'] .= ' ' . ev_gettext('(archived)'); } $active_projects[$prj_id] = $prj_info['prj_title']; } $core = $core + array('active_projects' => $active_projects, 'current_full_name' => $info['usr_full_name'], 'current_email' => $info['usr_email'], 'current_user_id' => $usr_id, 'current_user_datetime' => Date_Helper::getISO8601date('now', '', true), 'is_current_user_clocked_in' => User::isCLockedIn($usr_id), 'is_anon_user' => Auth::isAnonUser(), 'is_current_user_partner' => !empty($info['usr_par_code']), 'roles' => User::getAssocRoleIDs(), 'current_user_prefs' => Prefs::get(Auth::getUserID())); $this->assign('current_full_name', $core['user']['usr_full_name']); $this->assign('current_email', $core['user']['usr_email']); $this->assign('current_user_id', $usr_id); $this->assign('handle_clock_in', $setup['handle_clock_in'] == 'enabled'); $this->assign('is_current_user_clocked_in', User::isClockedIn($usr_id)); $this->assign('roles', User::getAssocRoleIDs()); } $this->assign('core', $core); return $this; }
/** * @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; }
$tpl->displayTemplate(); exit; } if (@$_POST['cat'] == 'new') { $res = CRM::insertAccountManager(); Misc::mapMessages($res, array(1 => array(ev_gettext('Thank you, the account manager was added successfully.'), Misc::MSG_INFO), -1 => array(ev_gettext('An error occurred while trying to add the the account manager.'), Misc::MSG_ERROR))); } elseif (@$_POST['cat'] == 'update') { $res = CRM::updateAccountManager(); Misc::mapMessages($res, array(1 => array(ev_gettext('Thank you, the account manager was updated successfully.'), Misc::MSG_INFO), -1 => array(ev_gettext('An error occurred while trying to update the the account manager.'), Misc::MSG_ERROR))); } elseif (@$_POST['cat'] == 'delete') { CRM::removeAccountManager(); } elseif (!empty($_GET['prj_id'])) { $tpl->assign('info', array('cam_prj_id' => $_GET['prj_id'])); $crm = CRM::getInstance($_GET['prj_id']); $tpl->assign('customers', $crm->getCustomerAssocList()); } if (@$_GET['cat'] == 'edit') { $info = CRM::getAccountManagerDetails($_GET['id']); if (!empty($_GET['prj_id'])) { $info['cam_prj_id'] = $_GET['prj_id']; } $tpl->assign('customers', CRM::getInstance($info['cam_prj_id'])->getCustomerAssocList()); $tpl->assign('user_options', User::getActiveAssocList($info['cam_prj_id'], User::ROLE_CUSTOMER)); $tpl->assign('info', $info); } $tpl->assign('list', CRM::getAccountManagerList()); if (!empty($_REQUEST['prj_id'])) { $tpl->assign('user_options', User::getActiveAssocList($_REQUEST['prj_id'], User::ROLE_CUSTOMER)); } $tpl->assign('project_list', Project::getAll(false)); $tpl->displayTemplate();
if (CRM::hasCustomerIntegration($prj_id)) { $sender_email = Mail_Helper::getEmailAddress($email_details['sup_from']); try { $contact = $crm->getContactByEmail($sender_email); $tpl->assign('contact_details', $contact->getDetails()); } catch (CRMException $e) { } } } } } $tpl->assign(array('cats' => Category::getAssocList($prj_id), 'priorities' => Priority::getAssocList($prj_id), 'severities' => Severity::getList($prj_id), 'users' => Project::getUserAssocList($prj_id, 'active', User::getRoleID('Customer')), 'releases' => Release::getAssocList($prj_id), 'custom_fields' => Custom_Field::getListByProject($prj_id, 'report_form'), 'max_attachment_size' => Attachment::getMaxAttachmentSize(), 'max_attachment_bytes' => Attachment::getMaxAttachmentSize(true), 'field_display_settings' => Project::getFieldDisplaySettings($prj_id), 'groups' => Group::getAssocList($prj_id), 'products' => Product::getList(false))); $prefs = Prefs::get($usr_id); $tpl->assign('user_prefs', $prefs); $tpl->assign('zones', Date_Helper::getTimezoneList()); if (Auth::getCurrentRole() == User::getRoleID('Customer')) { $crm = CRM::getInstance(Auth::getCurrentProject()); $customer_contact_id = User::getCustomerContactID($usr_id); $contact = $crm->getContact($customer_contact_id); $customer_id = Auth::getCurrentCustomerID(); $customer = $crm->getCustomer($customer_id); // TODOCRM: Pull contacts via ajax when user selects contract $tpl->assign(array('customer_id' => $customer_id, 'contact_id' => $customer_contact_id, 'customer' => $customer, 'contact' => $contact)); } $clone_iss_id = isset($_GET['clone_iss_id']) ? (int) $_GET['clone_iss_id'] : null; if ($clone_iss_id && Access::canCloneIssue($clone_iss_id, $usr_id)) { $tpl->assign(Issue::getCloneIssueTemplateVariables($clone_iss_id)); } else { $tpl->assign('defaults', $_REQUEST); } $tpl->displayTemplate();
/** * Returns an array of active filters * * @param array $options The options array * @return array */ public static function getActiveFilters($options) { $prj_id = Auth::getCurrentProject(); $filter_info = self::getFiltersInfo(); $return = array(); foreach ($filter_info as $filter_key => $filter) { $display = false; if (isset($filter['param']) && isset($options[$filter['param']])) { $filter_details = $options[$filter['param']]; } if (isset($filter['is_custom'])) { // custom fields $fld_id = $filter['fld_id']; if (!isset($options['custom_field'][$fld_id]) || empty($options['custom_field'][$fld_id])) { continue; } elseif ($filter['fld_type'] == 'date' && empty($options['custom_field'][$fld_id]['Year'])) { continue; } elseif ($filter['fld_type'] == 'integer') { if (!isset($options['custom_field'][$fld_id]['value']) || empty($options['custom_field'][$fld_id]['value'])) { continue; } else { $filter_details = $options['custom_field'][$fld_id]; switch ($filter_details['filter_type']) { case 'ge': $display = ev_gettext('%1$s or greater', $filter_details['value']); break; case 'le': $display = ev_gettext('%1$s or less', $filter_details['value']); break; case 'gt': $display = ev_gettext('Greater than %1$s', $filter_details['value']); break; case 'lt': $display = ev_gettext('Less than %1$s', $filter_details['value']); break; default: $display = $filter_details['value']; } } } elseif (in_array($filter['fld_type'], array('multiple', 'combo'))) { $display = implode(', ', Custom_Field::getOptions($fld_id, $options['custom_field'][$fld_id])); } else { $display = $options['custom_field'][$fld_id]; } } elseif (!isset($options[$filter['param']]) || empty($options[$filter['param']]) || in_array($filter_key, array('sort_order', 'sort_by', 'rows', 'search_type'))) { continue; } elseif (isset($filter['is_date']) && $filter['is_date'] == true) { if (!empty($filter_details['Year']) || isset($filter_details['time_period'])) { switch ($filter_details['filter_type']) { case 'in_past': $display = ev_gettext('In Past %1$s hours', $filter_details['time_period']); break; case 'null': $display = ev_gettext('Is NULL'); break; case 'between': $end = $options[$filter['param'] . '_end']; $display = ev_gettext('Is between %1$s-%2$s-%3$s AND %4$s-%5$s-%6$s', $filter_details['Year'], $filter_details['Month'], $filter_details['Day'], $end['Year'], $end['Month'], $end['Day']); break; case 'greater': $display = ev_gettext('Is greater than %1$s-%2$s-%3$s', $filter_details['Year'], $filter_details['Month'], $filter_details['Day']); break; case 'less': $display = ev_gettext('Is less than %1$s-%2$s-%3$s', $filter_details['Year'], $filter_details['Month'], $filter_details['Day']); } } } elseif ($filter['param'] == 'status') { $statuses = Status::getAssocStatusList($prj_id); $display = $statuses[$filter_details]; } elseif ($filter['param'] == 'category') { $categories = Category::getAssocList($prj_id); if (is_array($filter_details)) { $active_categories = array(); foreach ($filter_details as $category) { $active_categories[] = $categories[$category]; } $display = implode(', ', $active_categories); } else { $display = $categories[$filter_details]; } } elseif ($filter['param'] == 'priority') { $priorities = Priority::getAssocList($prj_id); $display = $priorities[$filter_details]; } elseif ($filter['param'] == 'severity') { $severities = Severity::getAssocList($prj_id); $display = $severities[$filter_details]; } elseif ($filter['param'] == 'users') { if ($filter_details == -1) { $display = ev_gettext('un-assigned'); } elseif ($filter_details == -2) { $display = ev_gettext('myself and un-assigned'); } elseif ($filter_details == -3) { $display = ev_gettext('myself and my group'); } elseif ($filter_details == -4) { $display = ev_gettext('myself, un-assigned and my group'); } elseif (substr($filter_details, 0, 3) == 'grp') { $display = ev_gettext('%1$s Group', Group::getName(substr($filter_details, 4))); } else { $display = User::getFullName($filter_details); } } elseif ($filter['param'] == 'hide_closed') { if ($filter_details == true) { $display = ev_gettext('Yes'); } } elseif ($filter['param'] == 'reporter') { $display = User::getFullName($filter_details); } elseif ($filter['param'] == 'release') { $display = Release::getTitle($filter_details); } elseif ($filter['param'] == 'customer_id') { try { $crm = CRM::getInstance($prj_id); $customer = $crm->getCustomer($filter_details); $display = $customer->getName(); } catch (CRMException $e) { $display = $filter_details; } } elseif ($filter['param'] == 'product') { $display = Product::getTitle($filter_details); } else { $display = $filter_details; } if ($display != false) { $return[$filter['title']] = array('value' => $display, 'remove_link' => 'list.php?view=clearandfilter&' . self::buildUrl($filter_info, $options, $filter_key, true)); } } return $return; }
/** * Method to determine if user can access a particular issue * * @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 */ public static function canAccessIssue($issue_id, $usr_id) { static $access; if (empty($issue_id)) { return false; } 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 = $details['iss_prj_id']; $can_access_contract = false; if (CRM::hasCustomerIntegration($prj_id)) { $crm = CRM::getInstance($prj_id); try { if (!empty($usr_details['usr_customer_contact_id']) && !empty($details['iss_customer_contract_id'])) { $contact = $crm->getContact($usr_details['usr_customer_contact_id']); $can_access_contract = $contact->canAccessContract($crm->getContract($details['iss_customer_contract_id'])); } } catch (CRMException $e) { // TODOCRM: Log exception? } } if (empty($usr_role)) { // check if they are even allowed to access the project $return = false; } elseif (CRM::hasCustomerIntegration($details['iss_prj_id']) && $usr_role == User::getRoleID('Customer') && $can_access_contract === false) { // check customer permissions $return = false; } elseif (!empty($usr_details['usr_par_code']) && !Partner::isPartnerEnabledForIssue($usr_details['usr_par_code'], $issue_id)) { // check if the user is a partner $return = false; } elseif ($details['iss_private'] == 1) { // check if the issue is even private // check role, reporter, assignment and group if ($usr_role > 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('Reporter') && Project::getSegregateReporters($prj_id) && $details['iss_usr_id'] != $usr_id && !Authorized_Replier::isUserAuthorizedReplier($issue_id, $usr_id)) { return false; } else { $return = true; } $access[$issue_id . '-' . $usr_id] = $return; return $return; }
$tpl->setTemplate('select_customer.tpl.html'); session_start(); // check if cookies are enabled, first of all if (!Auth::hasCookieSupport(APP_COOKIE)) { Auth::redirect('index.php?err=11'); } if (!Auth::hasValidCookie(APP_COOKIE)) { Auth::redirect('index.php?err=5'); } $prj_id = Auth::getCurrentProject(); $usr_id = Auth::getUserID(); $contact_id = User::getCustomerContactID($usr_id); if (!CRM::hasCustomerIntegration($prj_id) || empty($contact_id)) { Auth::redirect('main.php'); } $crm = CRM::getInstance($prj_id); $contact = $crm->getContact($contact_id); $customers = $contact->getCustomers(); if (isset($_REQUEST['customer_id'])) { $customer_id = $_REQUEST['customer_id']; if (in_array($customer_id, array_keys($customers))) { Auth::setCurrentCustomerID($customer_id); if (!empty($_POST['url'])) { Auth::redirect($_REQUEST['url']); } else { Auth::redirect('main.php'); } } } $tpl->assign('customers', $customers); $tpl->displayTemplate();
/** * Returns data for the custom fields report, based on the field and options passed in. * * @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 string $start_date * @param string $end_date * @param boolean $list If the values should be listed out instead of just counted. * @param string $interval The interval values should be grouped over time, empty (none) by default. * @param integer $assignee The assignee the issue should belong to. * @return array An array of data. */ public static function getCustomFieldReport($fld_id, $cfo_ids, $group_by = 'issue', $start_date = null, $end_date = null, $list = false, $interval = null, $assignee = null) { $prj_id = Auth::getCurrentProject(); $fld_id = (int) $fld_id; // get field values $options = Custom_Field::getOptions($fld_id, $cfo_ids); if ($group_by == 'customer') { $group_by_field = 'iss_customer_id'; } else { $group_by_field = 'iss_id'; } if ($assignee == -1) { $assignee = null; } $label_field = ''; $interval_group_by_field = ''; switch ($interval) { case 'day': $label_field = "CONCAT(YEAR(iss_created_date), '-', MONTH(iss_created_date), '-', DAY(iss_created_date))"; $interval_group_by_field = 'CONCAT(YEAR(iss_created_date), MONTH(iss_created_date), DAY(iss_created_date))'; break; case 'week': $label_field = "CONCAT(YEAR(iss_created_date), '/', WEEK(iss_created_date))"; $interval_group_by_field = 'WEEK(iss_created_date)'; break; case 'month': $label_field = "CONCAT(YEAR(iss_created_date), '/', MONTH(iss_created_date))"; $interval_group_by_field = 'MONTH(iss_created_date)'; break; case 'year': $label_field = 'YEAR(iss_created_date)'; $interval_group_by_field = 'YEAR(iss_created_date)'; break; } if ($list == true) { $params = array(); $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 iss_private,\n fld_id"; if ($label_field) { $sql .= ",\n {$label_field} as interval_label"; } $sql .= ' FROM {{%custom_field}},'; if (count($options) > 0) { $sql .= ' {{%custom_field_option}},'; } $sql .= ' {{%issue_custom_field}}, {{%issue}}, {{%issue_user}} WHERE fld_id = icf_fld_id AND'; if (count($options) > 0) { $sql .= ' cfo_id = icf_value AND'; } $sql .= ' icf_iss_id = iss_id AND isu_iss_id = iss_id AND icf_fld_id = ?'; $params[] = $fld_id; if (count($options) > 0) { $ids = array_keys($options); $list = DB_Helper::buildList($ids); $sql .= " AND cfo_id IN({$list})"; $params = array_merge($params, $ids); } if ($start_date && $end_date) { $sql .= " AND\niss_created_date BETWEEN ? AND ?"; $params[] = $start_date; $params[] = $end_date; } if ($assignee) { $sql .= " AND\nisu_usr_id = ?"; $params[] = $assignee; } $sql .= "\n GROUP BY\n {$group_by_field}\n ORDER BY"; if ($label_field) { $sql .= "\n {$label_field} DESC,"; } $sql .= ' row_count DESC'; try { $res = DB_Helper::getInstance()->getAll($sql, $params); } catch (DbException $e) { return array(); } if (CRM::hasCustomerIntegration($prj_id)) { $crm = CRM::getInstance($prj_id); $crm->processListIssuesResult($res); if ($group_by == 'issue') { usort($res, function ($a, $b) { if ($a['customer_title'] < $b['customer_title']) { return -1; } elseif ($a['customer_title'] > $b['customer_title']) { return 1; } else { return 0; } }); } } foreach ($res as &$row) { $row['field_value'] = Custom_Field::getDisplayValue($row['iss_id'], $row['fld_id']); } return $res; } $data = array(); foreach ($options as $cfo_id => $value) { $params = array(); $stmt = 'SELECT'; if ($label_field != '') { $stmt .= "\n {$label_field} as label,"; } $stmt .= "\n COUNT(DISTINCT {$group_by_field})\n FROM\n {{%issue_custom_field}},\n {{%issue}},\n {{%issue_user}}\n WHERE\n icf_iss_id = iss_id AND\n isu_iss_id = iss_id AND\n icf_fld_id = ? AND\n icf_value = ?"; $params = array($fld_id, $cfo_id); if ($start_date && $end_date) { $stmt .= " AND\niss_created_date BETWEEN ? AND ?"; $params[] = $start_date; $params[] = $end_date; } if ($assignee) { $stmt .= " AND\nisu_usr_id = ?"; $params[] = $assignee; } if ($interval_group_by_field != '') { $stmt .= "\n GROUP BY\n {$interval_group_by_field}\n ORDER BY\n {$label_field} ASC"; try { $res = DB_Helper::getInstance()->fetchAssoc($stmt, $params); } catch (DbException $e) { return array(); } } else { try { $res = DB_Helper::getInstance()->getOne($stmt, $params); } catch (DbException $e) { return array(); } } $data[$value] = $res; } // include count of all other values (used in pie chart) $list = DB_Helper::buildList($cfo_ids); $stmt = "SELECT\n COUNT(DISTINCT {$group_by_field})\n FROM\n {{%custom_field_option}},\n {{%issue_custom_field}},\n {{%issue}}\n WHERE\n cfo_id = icf_value AND\n icf_iss_id = iss_id AND\n cfo_id NOT IN({$list}) AND\n icf_fld_id = ?\n "; $params = $cfo_ids; $params[] = $fld_id; try { $res = DB_Helper::getInstance()->getOne($stmt, $params); } catch (DbException $e) { return array(); } $data['All Others'] = $res; return $data; }
/** * Routes an email to the correct issue. * * @param string $full_message The full email message, including headers * @return mixed true or array(ERROR_CODE, ERROR_STRING) in case of failure */ public static function route_emails($full_message) { // need some validation here if (empty($full_message)) { return array(self::EX_NOINPUT, ev_gettext('Error: The email message was empty') . ".\n"); } // save the full message for logging purposes Support::saveRoutedEmail($full_message); // check if the email routing interface is even supposed to be enabled $setup = Setup::get(); if ($setup['email_routing']['status'] != 'enabled') { return array(self::EX_CONFIG, ev_gettext('Error: The email routing interface is disabled.') . "\n"); } if (empty($setup['email_routing']['address_prefix'])) { return array(self::EX_CONFIG, ev_gettext('Error: Please configure the email address prefix.') . "\n"); } if (empty($setup['email_routing']['address_host'])) { return array(self::EX_CONFIG, ev_gettext('Error: Please configure the email address domain.') . "\n"); } // associate routed emails to the internal system account $sys_account = User::getNameEmail(APP_SYSTEM_USER_ID); if (empty($sys_account['usr_email'])) { return array(self::EX_CONFIG, ev_gettext('Error: The associated user for the email routing interface needs to be set.') . "\n"); } unset($sys_account); // join the Content-Type line (for easier parsing?) if (preg_match('/^boundary=/m', $full_message)) { $pattern = "#(Content-Type: multipart/.+); ?\r?\n(boundary=.*)\$#im"; $replacement = '$1; $2'; $full_message = preg_replace($pattern, $replacement, $full_message); } // remove the reply-to: header if (preg_match('/^reply-to:.*/im', $full_message)) { $full_message = preg_replace("/^(reply-to:).*\n/im", '', $full_message, 1); } AuthCookie::setAuthCookie(APP_SYSTEM_USER_ID); $structure = Mime_Helper::decode($full_message, true, true); // find which issue ID this email refers to if (isset($structure->headers['to'])) { $issue_id = self::getMatchingIssueIDs($structure->headers['to'], 'email'); } // we need to try the Cc header as well if (empty($issue_id) and isset($structure->headers['cc'])) { $issue_id = self::getMatchingIssueIDs($structure->headers['cc'], 'email'); } if (empty($issue_id)) { return array(self::EX_DATAERR, ev_gettext('Error: The routed email had no associated Eventum issue ID or had an invalid recipient address.') . "\n"); } $issue_prj_id = Issue::getProjectID($issue_id); if (empty($issue_prj_id)) { return array(self::EX_DATAERR, ev_gettext('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(self::EX_CONFIG, ev_gettext('Error: Please provide the email account ID.') . "\n"); } $body = $structure->body; // 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_Helper::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_Helper::stripWarningMessage($full_message); $body = Mail_Helper::stripWarningMessage($body); } $prj_id = Issue::getProjectID($issue_id); AuthCookie::setAuthCookie(APP_SYSTEM_USER_ID); AuthCookie::setProjectCookie($prj_id); if (Mime_Helper::hasAttachments($structure)) { $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']); foreach ($ccs as $i => $address) { if (Mail_Helper::getEmailAddress($address) == $setup['smtp']['save_address']) { unset($ccs[$i]); } } $structure->headers['cc'] = implode(', ', $ccs); } // Remove excess Re's $structure->headers['subject'] = Mail_Helper::removeExcessRe(@$structure->headers['subject'], true); $t = array('issue_id' => $issue_id, 'ema_id' => $email_account_id, 'message_id' => @$structure->headers['message-id'], 'date' => Date_Helper::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 (CRM::hasCustomerIntegration($prj_id)) { $crm = CRM::getInstance($prj_id); if (!empty($structure->headers['from'])) { try { $contact = $crm->getContactByEmail($sender_email); $issue_contract = $crm->getContract(Issue::getContractID($issue_id)); if ($contact->canAccessContract($issue_contract)) { $t['customer_id'] = $issue_contract->getCustomerID(); } } catch (CRMException $e) { } } } if (empty($t['customer_id'])) { $t['customer_id'] = null; } if (Support::blockEmailIfNeeded($t)) { return true; } // re-write Threading headers if needed list($t['full_email'], $t['headers']) = Mail_Helper::rewriteThreadingHeaders($t['issue_id'], $t['full_email'], $t['headers'], 'email'); $res = Support::insertEmail($t, $structure, $sup_id); if ($res != -1) { Support::extractAttachments($issue_id, $structure); // 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_Helper::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) && $usr_id != APP_SYSTEM_USER_ID && User::getRoleByUser($usr_id, $prj_id) > User::ROLE_CUSTOMER) { Issue::markAsUpdated($issue_id, 'staff response'); } else { Issue::markAsUpdated($issue_id, 'user response'); } } // log routed email History::add($issue_id, $usr_id, 'email_routed', 'Email routed from {from}', array('from' => $structure->headers['from'])); } return true; }