/** * Returns the data used by the weekly report. * * @param string $usr_id The ID of the user this report is for. * @param int $prj_id The project id * @param string|DateTime $start The start date of this report. * @param string|DateTime $end The end date of this report. * @param array $options extra options for report: * - $separate_closed If closed issues should be separated from other issues. * - $ignore_statuses If issue status changes should be ignored in report. * - $separate_not_assigned_to_user Separate Issues Not Assigned to User * - $show_per_issue Add time spent on issue to issues * - $separate_no_time Separate No time spent issues * @return array An array of data containing all the elements of the weekly report. */ public static function getWeeklyReport($usr_id, $prj_id, $start, $end, $options = array()) { // figure out timezone $user_prefs = Prefs::get($usr_id); $tz = $user_prefs['timezone']; // if start or end is string, convert assume min and max date are specified if (!$start instanceof DateTime) { $start = Date_Helper::getDateTime($start, $tz)->setTime(0, 0, 0); } if (!$end instanceof DateTime) { $end = Date_Helper::getDateTime($end, $tz)->setTime(23, 59, 59); } $start_ts = Date_Helper::getSqlDateTime($start); $end_ts = Date_Helper::getSqlDateTime($end); $time_tracking = Time_Tracking::getSummaryByUser($usr_id, $prj_id, $start_ts, $end_ts); // replace spaces in index with _ and calculate total time $total_time = 0; foreach ($time_tracking as $category => $data) { unset($time_tracking[$category]); $time_tracking[str_replace(' ', '_', $category)] = $data; $total_time += $data['total_time']; } // get count of issues assigned in week of report. $stmt = 'SELECT COUNT(*) FROM {{%issue}}, {{%issue_user}}, {{%status}} WHERE iss_id = isu_iss_id AND iss_sta_id = sta_id AND isu_usr_id = ? AND iss_prj_id = ? AND isu_assigned_date BETWEEN ? AND ?'; $params = array($usr_id, Auth::getCurrentProject(), $start_ts, $end_ts); try { $newly_assigned = DB_Helper::getInstance()->getOne($stmt, $params); } catch (DbException $e) { $newly_assigned = null; } $email_count = array('associated' => Support::getSentEmailCountByUser($usr_id, $start_ts, $end_ts, true), 'other' => Support::getSentEmailCountByUser($usr_id, $start_ts, $end_ts, false)); $htt_exclude = array(); if (!empty($options['ignore_statuses'])) { $htt_exclude[] = 'status_changed'; $htt_exclude[] = 'status_auto_changed'; $htt_exclude[] = 'remote_status_change'; } $issue_list = History::getTouchedIssuesByUser($usr_id, $prj_id, $start_ts, $end_ts, $htt_exclude); $issues = array('no_time' => array(), 'not_mine' => array(), 'closed' => array(), 'other' => array()); // organize issues into categories if ($issue_list) { if (!empty($options['show_per_issue']) || !empty($options['separate_no_time'])) { Time_Tracking::fillTimeSpentByIssueAndTime($issue_list, $usr_id, $start_ts, $end_ts); } foreach ($issue_list as $row) { if (!empty($row['iss_customer_id']) && CRM::hasCustomerIntegration($row['iss_prj_id'])) { $row['customer_name'] = CRM::getCustomerName($row['iss_prj_id'], $row['iss_customer_id']); } else { $row['customer_name'] = null; } if (!empty($options['separate_closed']) && $row['sta_is_closed'] == 1) { $issues['closed'][] = $row; } elseif (!empty($options['separate_not_assigned_to_user']) && !Issue::isAssignedToUser($row['iss_id'], $usr_id)) { $issues['not_mine'][] = $row; } elseif (!empty($options['separate_no_time']) && empty($row['it_spent'])) { $issues['no_time'][] = $row; } else { $issues['other'][] = $row; } } $sort_function = function ($a, $b) { return strcasecmp($a['customer_name'], $b['customer_name']); }; usort($issues['closed'], $sort_function); usort($issues['other'], $sort_function); } return array('start' => $start_ts, 'end' => $end_ts, 'user' => User::getDetails($usr_id), 'group_name' => Group::getName(User::getGroupID($usr_id)), 'issues' => $issues, 'status_counts' => History::getTouchedIssueCountByStatus($usr_id, $prj_id, $start_ts, $end_ts), 'new_assigned_count' => $newly_assigned, 'time_tracking' => $time_tracking, 'email_count' => $email_count, 'phone_count' => Phone_Support::getCountByUser($usr_id, $start_ts, $end_ts), 'note_count' => Note::getCountByUser($usr_id, $start_ts, $end_ts), 'total_time' => Misc::getFormattedTime($total_time, false)); }
/** * Checks whether the given email address is allowed to send emails in the * issue ID. * * @param integer $issue_id The issue ID * @param string $sender_email The email address * @return boolean */ public static 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, true); if (empty($sender_usr_id)) { if (CRM::hasCustomerIntegration($prj_id)) { // check for a customer contact with several email addresses $crm = CRM::getInstance($prj_id); try { $contract = $crm->getContract(Issue::getContractID($issue_id)); $contact_emails = array_keys($contract->getContactEmailAssocList()); $contact_emails = array_map(function ($s) { return strtolower($s); }, $contact_emails); } catch (CRMException $e) { $contact_emails = array(); } 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 ($sender_usr_id == $details['iss_usr_id']) { $is_allowed = true; } elseif (User::isPartner($sender_usr_id) && in_array(User::getPartnerID($sender_usr_id), Partner::getPartnerCodesByIssue($issue_id))) { $is_allowed = true; } elseif (!Issue::canAccess($issue_id, $sender_usr_id) && !Authorized_Replier::isAuthorizedReplier($issue_id, $sender_email)) { $is_allowed = false; } elseif (!Authorized_Replier::isAuthorizedReplier($issue_id, $sender_email) && !Issue::isAssignedToUser($issue_id, $sender_usr_id) && User::getRoleByUser($sender_usr_id, Issue::getProjectID($issue_id)) != User::getRoleID('Customer')) { $is_allowed = false; } } return $is_allowed; }
/** * 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; }
/** * 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; }
$show_category = 0; } $cookie = Auth::getCookieInfo(APP_PROJECT_COOKIE); if (!empty($auto_switched_from)) { $tpl->assign(array("project_auto_switched" => 1, "old_project" => Project::getName($auto_switched_from))); } $setup = Setup::load(); $tpl->assign("allow_unassigned_issues", @$setup["allow_unassigned_issues"]); $tpl->assign(array('next_issue' => @$sides['next'], 'previous_issue' => @$sides['previous'], 'subscribers' => Notification::getSubscribers($issue_id), 'custom_fields' => Custom_Field::getListByIssue($prj_id, $issue_id), 'files' => Attachment::getList($issue_id), 'emails' => Support::getEmailsByIssue($issue_id), 'zones' => Date_API::getTimezoneList(), 'users' => Project::getUserAssocList($prj_id, 'active', User::getRoleID('Customer')), 'ema_id' => Email_Account::getEmailAccount(), 'max_attachment_size' => Attachment::getMaxAttachmentSize(), 'show_releases' => $show_releases, 'show_category' => $show_category, 'categories' => Category::getAssocList($prj_id), 'quarantine' => Issue::getQuarantineInfo($issue_id))); if ($role_id != User::getRoleID('customer')) { if (@$_REQUEST['show_all_drafts'] == 1) { $show_all_drafts = true; } else { $show_all_drafts = false; } if (Workflow::hasWorkflowIntegration($prj_id)) { $statuses = Workflow::getAllowedStatuses($prj_id, $issue_id); // if currently selected release is not on list, go ahead and add it. } else { $statuses = Status::getAssocStatusList($prj_id); } if (!empty($details['iss_sta_id']) && empty($statuses[$details['iss_sta_id']])) { $statuses[$details['iss_sta_id']] = Status::getStatusTitle($details['iss_sta_id']); } $time_entries = Time_Tracking::getListing($issue_id); $tpl->assign(array('notes' => Note::getListing($issue_id), 'is_user_assigned' => Issue::isAssignedToUser($issue_id, $usr_id), 'is_user_authorized' => Authorized_Replier::isUserAuthorizedReplier($issue_id, $usr_id), 'phone_entries' => Phone_Support::getListing($issue_id), 'phone_categories' => Phone_Support::getCategoryAssocList($prj_id), 'checkins' => SCM::getCheckinList($issue_id), 'time_categories' => Time_Tracking::getAssocCategories(), 'time_entries' => $time_entries['list'], 'total_time_spent' => $time_entries['total_time_spent'], 'impacts' => Impact_Analysis::getListing($issue_id), 'statuses' => $statuses, 'drafts' => Draft::getList($issue_id, $show_all_drafts), 'groups' => Group::getAssocList($prj_id))); } } } } $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 format and send the email notifications. * * @param integer $issue_id The issue ID * @param array $emails The list of emails * @param string $type The notification type * @param array $data The issue details * @param string $subject The subject of the email * @param integer $type_id The ID of the event that triggered this notification (issue_id, sup_id, not_id, etc) * @param array $headers Any extra headers that need to be added to this email (Default false) * @return void */ public function notifySubscribers($issue_id, $emails, $type, $data, $subject, $internal_only, $type_id = false, $headers = false) { global $_EVENTUM_LAST_NOTIFIED_LIST; $issue_id = (int) $issue_id; // open text template $tpl = new Template_Helper(); $tpl->setTemplate('notifications/' . $type . '.tpl.text'); $tpl->assign(array('app_title' => Misc::getToolCaption(), 'data' => $data, 'current_user' => User::getFullName(Auth::getUserID()))); // type of notification is sent out: email, note, blocked_email $notify_type = $type; $sender_usr_id = false; $threading_headers = Mail_Helper::getBaseThreadingHeaders($issue_id); $emails = array_unique($emails); foreach ($emails as $email) { $can_access = true; $email_address = Mail_Helper::getEmailAddress($email); $recipient_usr_id = User::getUserIDByEmail($email_address); if (!empty($recipient_usr_id)) { if (!Issue::canAccess($issue_id, $recipient_usr_id)) { $can_access = false; } $tpl->assign('recipient_role', User::getRoleByUser($recipient_usr_id, Issue::getProjectID($issue_id))); if (isset($data['custom_fields'])) { $data['custom_fields'] = Custom_Field::getListByIssue($data['iss_prj_id'], $issue_id, $recipient_usr_id); } $is_assigned = Issue::isAssignedToUser($issue_id, $recipient_usr_id); } else { $tpl->assign('recipient_role', 0); unset($data['custom_fields']); $is_assigned = false; } $tpl->assign('data', $data); $tpl->assign('is_assigned', $is_assigned); if ($can_access != true) { continue; } if (!Workflow::shouldEmailAddress(Issue::getProjectID($issue_id), $email_address, $issue_id, $type)) { continue; } // change the current locale if (!empty($recipient_usr_id)) { Language::set(User::getLang($recipient_usr_id)); } else { Language::set(APP_DEFAULT_LOCALE); } // send email (use PEAR's classes) $mail = new Mail_Helper(); $mail->setTextBody($tpl->getTemplateContents()); if ($headers != false) { $mail->setHeaders($headers); } if ($headers == false || $headers != false && (empty($headers['Message-ID']) && empty($headers['In-Reply-To']) && empty($headers['References']))) { $mail->setHeaders($threading_headers); } if ($type == 'notes') { // special handling of blocked messages if ($data['note']['not_is_blocked'] == 1) { $subject = ev_gettext('BLOCKED'); $notify_type = 'blocked_email'; } if (!empty($data['note']['not_unknown_user'])) { $sender = $data['note']['not_unknown_user']; } else { $sender = User::getFromHeader($data['note']['not_usr_id']); } $sender_usr_id = User::getUserIDByEmail(Mail_Helper::getEmailAddress($sender)); if (empty($sender_usr_id)) { $sender_usr_id = false; } // show the title of the note, not the issue summary $extra_subject = $data['note']['not_title']; // don't add the "[#3333] Note: " prefix to messages that already have that in the subject line if (strstr($extra_subject, "[#{$issue_id}] {$subject}: ")) { $pos = strpos($extra_subject, "[#{$issue_id}] {$subject}: "); $full_subject = substr($extra_subject, $pos); } else { $full_subject = "[#{$issue_id}] {$subject}: {$extra_subject}"; } } elseif ($type == 'new_issue' && $is_assigned) { $full_subject = "[#{$issue_id}] New Issue Assigned: " . $data['iss_summary']; } else { $extra_subject = $data['iss_summary']; $full_subject = "[#{$issue_id}] {$subject}: {$extra_subject}"; } if ($notify_type == 'notes' && $sender) { $from = self::getFixedFromHeader($issue_id, $sender, 'note'); } else { $from = self::getFixedFromHeader($issue_id, '', 'issue'); } $mail->send($from, $email, $full_subject, true, $issue_id, $notify_type, $sender_usr_id, $type_id); $_EVENTUM_LAST_NOTIFIED_LIST[$issue_id][] = $email; } // restore correct language Language::restore(); }
/** * Method used to format and send the email notifications. * * @access public * @param integer $issue_id The issue ID * @param array $emails The list of emails * @param string $type The notification type * @param array $data The issue details * @param string $subject The subject of the email * @param integer $type_id The ID of the event that triggered this notification (issue_id, sup_id, not_id, etc) * @param array $headers Any extra headers that need to be added to this email (Default false) * @return void */ function notifySubscribers($issue_id, $emails, $type, $data, $subject, $internal_only, $type_id = false, $headers = false) { // open text template $tpl = new Template_API(); $tpl->setTemplate('notifications/' . $type . '.tpl.text'); $tpl->bulkAssign(array("app_title" => Misc::getToolCaption(), "data" => $data)); $setup = Setup::load(); $final_type = $type; $sender_usr_id = false; $threading_headers = Mail_API::getBaseThreadingHeaders($issue_id); for ($i = 0; $i < count($emails); $i++) { $can_access = true; $recipient_usr_id = User::getUserIDByEmail(Mail_API::getEmailAddress($emails[$i])); if (!empty($recipient_usr_id)) { if (!Issue::canAccess($issue_id, $recipient_usr_id)) { $can_access = false; } $tpl->assign("recipient_role", User::getRoleByUser($recipient_usr_id, Issue::getProjectID($issue_id))); if (isset($data['custom_fields'])) { $data['custom_fields'] = Custom_Field::getListByIssue($data['iss_prj_id'], $issue_id, $recipient_usr_id); } $is_assigned = Issue::isAssignedToUser($issue_id, $recipient_usr_id); } else { $tpl->assign("recipient_role", 0); unset($data['custom_fields']); $is_assigned = false; } $tpl->assign("data", $data); $tpl->assign("is_assigned", $is_assigned); if ($can_access != true) { continue; } // send email (use PEAR's classes) $mail = new Mail_API(); $mail->setTextBody($tpl->getTemplateContents()); if ($headers != false) { $mail->setHeaders($headers); } if ($headers == false || $headers != false && (empty($headers['Message-ID']) && empty($headers['In-Reply-To']) && empty($headers['References']))) { $mail->setHeaders($threading_headers); } if ($type == 'notes') { // special handling of blocked messages if (!empty($data['note']['not_blocked_message'])) { $subject = 'BLOCKED'; $final_type = 'blocked_email'; } if (!empty($data["note"]["not_unknown_user"])) { $sender = $data["note"]["not_unknown_user"]; } else { $sender = User::getFromHeader($data["note"]["not_usr_id"]); } $sender_usr_id = User::getUserIDByEmail(Mail_API::getEmailAddress($sender)); if (empty($sender_usr_id)) { $sender_usr_id = false; } $from = Notification::getFixedFromHeader($issue_id, $sender, 'note'); } else { $from = Notification::getFixedFromHeader($issue_id, '', 'issue'); } // show the title of the note, not the issue summary if ($type == 'notes') { $extra_subject = $data['note']['not_title']; // don't add the "[#3333] Note: " prefix to messages that already have that in the subject line if (strstr($extra_subject, "[#{$issue_id}] {$subject}: ")) { $pos = strpos($extra_subject, "[#{$issue_id}] {$subject}: "); $full_subject = substr($extra_subject, 4); } else { $full_subject = "[#{$issue_id}] {$subject}: {$extra_subject}"; } } elseif ($type == 'new_issue' && $is_assigned) { $full_subject = "[#{$issue_id}] New Issue Assigned: " . $data['iss_summary']; } else { $extra_subject = $data['iss_summary']; $full_subject = "[#{$issue_id}] {$subject}: {$extra_subject}"; } $mail->send($from, $emails[$i], $full_subject, TRUE, $issue_id, $final_type, $sender_usr_id, $type_id); } }