/**
  * Method used to send a diff-style notification email to the issue
  * subscribers about updates to its attributes.
  *
  * @param   integer $issue_id The issue ID
  * @param   array $old The old issue details
  * @param   array $new The new issue details
  * @param   array $updated_custom_fields An array of the custom fields that were changed.
  */
 public static function notifyIssueUpdated($issue_id, $old, $new, $updated_custom_fields)
 {
     $prj_id = Issue::getProjectID($issue_id);
     $diffs = array();
     if (@$new['keep_assignments'] == 'no') {
         if (empty($new['assignments'])) {
             $new['assignments'] = array();
         }
         $assign_diff = Misc::arrayDiff($old['assigned_users'], $new['assignments']);
         if (count($assign_diff) > 0) {
             $diffs[] = '-' . ev_gettext('Assignment List') . ': ' . $old['assignments'];
             @($diffs[] = '+' . ev_gettext('Assignment List') . ': ' . implode(', ', User::getFullName($new['assignments'])));
         }
     }
     if (isset($new['expected_resolution_date']) && @$old['iss_expected_resolution_date'] != $new['expected_resolution_date']) {
         $diffs[] = '-' . ev_gettext('Expected Resolution Date') . ': ' . $old['iss_expected_resolution_date'];
         $diffs[] = '+' . ev_gettext('Expected Resolution Date') . ': ' . $new['expected_resolution_date'];
     }
     if (isset($new['category']) && $old['iss_prc_id'] != $new['category']) {
         $diffs[] = '-' . ev_gettext('Category') . ': ' . Category::getTitle($old['iss_prc_id']);
         $diffs[] = '+' . ev_gettext('Category') . ': ' . Category::getTitle($new['category']);
     }
     if (isset($new['release']) && $old['iss_pre_id'] != $new['release']) {
         $diffs[] = '-' . ev_gettext('Release') . ': ' . Release::getTitle($old['iss_pre_id']);
         $diffs[] = '+' . ev_gettext('Release') . ': ' . Release::getTitle($new['release']);
     }
     if (isset($new['priority']) && $old['iss_pri_id'] != $new['priority']) {
         $diffs[] = '-' . ev_gettext('Priority') . ': ' . Priority::getTitle($old['iss_pri_id']);
         $diffs[] = '+' . ev_gettext('Priority') . ': ' . Priority::getTitle($new['priority']);
     }
     if (isset($new['severity']) && $old['iss_sev_id'] != $new['severity']) {
         $diffs[] = '-' . ev_gettext('Severity') . ': ' . Severity::getTitle($old['iss_sev_id']);
         $diffs[] = '+' . ev_gettext('Severity') . ': ' . Severity::getTitle($new['severity']);
     }
     if (isset($new['status']) && $old['iss_sta_id'] != $new['status']) {
         $diffs[] = '-' . ev_gettext('Status') . ': ' . Status::getStatusTitle($old['iss_sta_id']);
         $diffs[] = '+' . ev_gettext('Status') . ': ' . Status::getStatusTitle($new['status']);
     }
     if (isset($new['resolution']) && $old['iss_res_id'] != $new['resolution']) {
         $diffs[] = '-' . ev_gettext('Resolution') . ': ' . Resolution::getTitle($old['iss_res_id']);
         $diffs[] = '+' . ev_gettext('Resolution') . ': ' . Resolution::getTitle($new['resolution']);
     }
     if (isset($new['estimated_dev_time']) && $old['iss_dev_time'] != $new['estimated_dev_time']) {
         $diffs[] = '-' . ev_gettext('Estimated Dev. Time') . ': ' . Misc::getFormattedTime($old['iss_dev_time'] * 60);
         $diffs[] = '+' . ev_gettext('Estimated Dev. Time') . ': ' . Misc::getFormattedTime($new['estimated_dev_time'] * 60);
     }
     if (isset($new['summary']) && $old['iss_summary'] != $new['summary']) {
         $diffs[] = '-' . ev_gettext('Summary') . ': ' . $old['iss_summary'];
         $diffs[] = '+' . ev_gettext('Summary') . ': ' . $new['summary'];
     }
     if (isset($new['percent_complete']) && $old['iss_original_percent_complete'] != $new['percent_complete']) {
         $diffs[] = '-' . ev_gettext('Percent complete') . ': ' . $old['iss_original_percent_complete'];
         $diffs[] = '+' . ev_gettext('Percent complete') . ': ' . $new['percent_complete'];
     }
     if (isset($new['description']) && $old['iss_description'] != $new['description']) {
         $old['iss_description'] = explode("\n", $old['iss_original_description']);
         $new['description'] = explode("\n", $new['description']);
         $diff = new Text_Diff($old['iss_description'], $new['description']);
         $renderer = new Text_Diff_Renderer_unified();
         $desc_diff = explode("\n", trim($renderer->render($diff)));
         $diffs[] = 'Description:';
         foreach ($desc_diff as $diff) {
             $diffs[] = $diff;
         }
     }
     $data = Issue::getDetails($issue_id);
     $data['diffs'] = implode("\n", $diffs);
     $data['updated_by'] = User::getFullName(Auth::getUserID());
     $all_emails = array();
     $role_emails = array(User::ROLE_VIEWER => array(), User::ROLE_REPORTER => array(), User::ROLE_CUSTOMER => array(), User::ROLE_USER => array(), User::ROLE_DEVELOPER => array(), User::ROLE_MANAGER => array(), User::ROLE_ADMINISTRATOR => array());
     $users = self::getUsersByIssue($issue_id, 'updated');
     foreach ($users as $user) {
         if (empty($user['sub_usr_id'])) {
             $email = $user['sub_email'];
             // non users are treated as "Viewers" for permission checks
             $role = User::ROLE_VIEWER;
         } else {
             $prefs = Prefs::get($user['sub_usr_id']);
             if (Auth::getUserID() == $user['sub_usr_id'] && (empty($prefs['receive_copy_of_own_action'][$prj_id]) || $prefs['receive_copy_of_own_action'][$prj_id] == false)) {
                 continue;
             }
             $email = User::getFromHeader($user['sub_usr_id']);
             $role = $user['pru_role'];
         }
         // now add it to the list of emails
         if (!empty($email) && !in_array($email, $all_emails)) {
             $all_emails[] = $email;
             $role_emails[$role][] = $email;
         }
     }
     // get additional email addresses to notify
     $additional_emails = Workflow::getAdditionalEmailAddresses($prj_id, $issue_id, 'issue_updated', array('old' => $old, 'new' => $new));
     $data['custom_field_diffs'] = implode("\n", Custom_Field::formatUpdatesToDiffs($updated_custom_fields, User::ROLE_VIEWER));
     foreach ($additional_emails as $email) {
         if (!in_array($email, $all_emails)) {
             $role_emails[User::ROLE_VIEWER][] = $email;
         }
     }
     // send email to each role separately due to custom field restrictions
     foreach ($role_emails as $role => $emails) {
         if (count($emails) > 0) {
             $data['custom_field_diffs'] = implode("\n", Custom_Field::formatUpdatesToDiffs($updated_custom_fields, $role));
             if (!empty($data['custom_field_diffs']) || !empty($data['diffs'])) {
                 self::notifySubscribers($issue_id, $emails, 'updated', $data, ev_gettext('Updated'), false);
             }
         }
     }
 }
Beispiel #2
0
 /**
  * Method to update the details of a specific issue.
  *
  * @param   integer $issue_id The issue ID
  * @return  integer 1 if the update worked, -1 or -2 otherwise
  */
 public static function update($issue_id)
 {
     $issue_id = (int) $issue_id;
     $usr_id = Auth::getUserID();
     $prj_id = self::getProjectID($issue_id);
     $workflow = Workflow::preIssueUpdated($prj_id, $issue_id, $usr_id, $_POST);
     if ($workflow !== true) {
         return $workflow;
     }
     // get all of the 'current' information of this issue
     $current = self::getDetails($issue_id);
     $associated_issues = isset($_POST['associated_issues']) ? explode(',', $_POST['associated_issues']) : array();
     self::updateAssociatedIssuesRelations($issue_id, $associated_issues);
     $assignments_changed = false;
     if (@$_POST['keep_assignments'] == 'no') {
         // only change the issue-user associations if there really were any changes
         $old_assignees = array_merge($current['assigned_users'], $current['assigned_inactive_users']);
         if (!empty($_POST['assignments'])) {
             $new_assignees = @$_POST['assignments'];
         } else {
             $new_assignees = array();
         }
         $assignment_notifications = array();
         // remove people from the assignment list, if appropriate
         foreach ($old_assignees as $assignee) {
             if (!in_array($assignee, $new_assignees)) {
                 self::deleteUserAssociation($issue_id, $assignee);
                 $assignments_changed = true;
             }
         }
         // add people to the assignment list, if appropriate
         foreach ($new_assignees as $assignee) {
             if (!in_array($assignee, $old_assignees)) {
                 self::addUserAssociation($usr_id, $issue_id, $assignee);
                 Notification::subscribeUser($usr_id, $issue_id, $assignee, Notification::getDefaultActions($issue_id, User::getEmail($assignee), 'issue_update'), true);
                 $assignment_notifications[] = $assignee;
                 $assignments_changed = true;
             }
         }
         if (count($assignment_notifications) > 0) {
             Notification::notifyNewAssignment($assignment_notifications, $issue_id);
         }
     }
     if (empty($_POST['estimated_dev_time'])) {
         $_POST['estimated_dev_time'] = 0;
     }
     $params = array('iss_updated_date' => Date_Helper::getCurrentDateGMT(), 'iss_last_public_action_date' => Date_Helper::getCurrentDateGMT(), 'iss_last_public_action_type' => 'updated', 'iss_sta_id' => $_POST['status'], 'iss_summary' => $_POST['summary'], 'iss_description' => $_POST['description']);
     if (isset($_POST['release'])) {
         $params['iss_pre_id'] = $_POST['release'];
     }
     if (isset($_POST['percentage_complete'])) {
         $params['iss_percent_complete'] = $_POST['percentage_complete'];
     }
     if (isset($_POST['group'])) {
         $params['iss_grp_id'] = $_POST['group'];
     }
     if (isset($_POST['estimated_dev_time'])) {
         $params['iss_dev_time'] = $_POST['estimated_dev_time'];
     }
     if (isset($_POST['trigger_reminders'])) {
         $params['iss_trigger_reminders'] = $_POST['trigger_reminders'];
     }
     if (isset($_POST['resolution'])) {
         $params['iss_res_id'] = $_POST['resolution'];
     }
     if (!empty($_POST['category'])) {
         $params['iss_prc_id'] = $_POST['category'];
     }
     if (@$_POST['keep'] == 'no') {
         $params['iss_pre_id'] = $_POST['release'];
     }
     if (!empty($_POST['expected_resolution_date'])) {
         $params['iss_expected_resolution_date'] = $_POST['expected_resolution_date'];
     } else {
         $params['iss_expected_resolution_date'] = null;
     }
     if (isset($_POST['private'])) {
         $params['iss_private'] = $_POST['private'];
     }
     if (isset($_POST['priority'])) {
         $params['iss_pri_id'] = $_POST['priority'];
     }
     if (isset($_POST['severity'])) {
         $params['iss_sev_id'] = $_POST['severity'];
     }
     if (isset($_POST['scheduled_release'])) {
         $params['iss_pre_id'] = $_POST['scheduled_release'];
     }
     $stmt = 'UPDATE {{%issue}} SET ' . DB_Helper::buildSet($params) . ' WHERE iss_id=?';
     $params[] = $issue_id;
     try {
         DB_Helper::getInstance()->query($stmt, $params);
     } catch (DbException $e) {
         return -1;
     }
     // change product
     if (isset($_POST['product'])) {
         $product_changes = Product::updateProductsByIssue($issue_id, $_POST['product'], $_POST['product_version']);
     }
     // add change to the history (only for changes on specific fields?)
     $updated_fields = array();
     if ($current['iss_expected_resolution_date'] != $_POST['expected_resolution_date']) {
         $updated_fields['Expected Resolution Date'] = History::formatChanges($current['iss_expected_resolution_date'], $_POST['expected_resolution_date']);
     }
     if (isset($_POST['category']) && $current['iss_prc_id'] != $_POST['category']) {
         $updated_fields['Category'] = History::formatChanges(Category::getTitle($current['iss_prc_id']), Category::getTitle($_POST['category']));
     }
     if (isset($_POST['release']) && $current['iss_pre_id'] != $_POST['release']) {
         $updated_fields['Release'] = History::formatChanges(Release::getTitle($current['iss_pre_id']), Release::getTitle($_POST['release']));
     }
     if (isset($_POST['priority']) && $current['iss_pri_id'] != $_POST['priority']) {
         $updated_fields['Priority'] = History::formatChanges(Priority::getTitle($current['iss_pri_id']), Priority::getTitle($_POST['priority']));
         Workflow::handlePriorityChange($prj_id, $issue_id, $usr_id, $current, $_POST);
     }
     if (isset($_POST['severity']) && $current['iss_sev_id'] != $_POST['severity']) {
         $updated_fields['Severity'] = History::formatChanges(Severity::getTitle($current['iss_sev_id']), Severity::getTitle($_POST['severity']));
         Workflow::handleSeverityChange($prj_id, $issue_id, $usr_id, $current, $_POST);
     }
     if (isset($_POST['scheduled_release']) && $current['iss_pre_id'] != $_POST['scheduled_release']) {
         $updated_fields['Scheduled Release'] = History::formatChanges(Release::getTitle($current['iss_pre_id']), Release::getTitle($_POST['scheduled_release']));
     }
     if (isset($_POST['status']) && $current['iss_sta_id'] != $_POST['status']) {
         // clear out the last-triggered-reminder flag when changing the status of an issue
         Reminder_Action::clearLastTriggered($issue_id);
         // if old status was closed and new status is not, clear closed data from issue.
         $old_status_details = Status::getDetails($current['iss_sta_id']);
         if ($old_status_details['sta_is_closed'] == 1) {
             $new_status_details = Status::getDetails($_POST['status']);
             if ($new_status_details['sta_is_closed'] != 1) {
                 self::clearClosed($issue_id);
             }
         }
         $updated_fields['Status'] = History::formatChanges(Status::getStatusTitle($current['iss_sta_id']), Status::getStatusTitle($_POST['status']));
     }
     if (isset($_POST['resolution']) && $current['iss_res_id'] != $_POST['resolution']) {
         $updated_fields['Resolution'] = History::formatChanges(Resolution::getTitle($current['iss_res_id']), Resolution::getTitle($_POST['resolution']));
     }
     if (isset($_POST['estimated_dev_time']) && $current['iss_dev_time'] != $_POST['estimated_dev_time']) {
         $updated_fields['Estimated Dev. Time'] = History::formatChanges(Misc::getFormattedTime($current['iss_dev_time'] * 60), Misc::getFormattedTime($_POST['estimated_dev_time'] * 60));
     }
     if ($current['iss_summary'] != $_POST['summary']) {
         $updated_fields['Summary'] = '';
     }
     if (isset($_POST['percentage_complete']) && $current['iss_original_percent_complete'] != $_POST['percentage_complete']) {
         $updated_fields['Percentage complete'] = History::formatChanges($current['iss_original_percent_complete'], $_POST['percentage_complete']);
     }
     if ($current['iss_original_description'] != $_POST['description']) {
         $updated_fields['Description'] = '';
     }
     if (isset($_POST['private']) && $_POST['private'] != $current['iss_private']) {
         $updated_fields['Private'] = History::formatChanges(Misc::getBooleanDisplayValue($current['iss_private']), Misc::getBooleanDisplayValue($_POST['private']));
     }
     if (isset($_POST['product']) && count($product_changes) > 0) {
         $updated_fields['Product'] = implode('; ', $product_changes);
     }
     if (isset($_POST['custom_fields']) && count($_POST['custom_fields']) > 0) {
         $updated_custom_fields = Custom_Field::updateValues($issue_id, $_POST['custom_fields']);
     } else {
         $updated_custom_fields = array();
     }
     if (count($updated_fields) > 0) {
         // log the changes
         $changes = '';
         $i = 0;
         foreach ($updated_fields as $key => $value) {
             if ($i > 0) {
                 $changes .= '; ';
             }
             if ($key != 'Summary' && $key != 'Description') {
                 $changes .= "{$key}: {$value}";
             } else {
                 $changes .= "{$key}";
             }
             $i++;
         }
         History::add($issue_id, $usr_id, 'issue_updated', 'Issue updated ({changes}) by {user}', array('changes' => $changes, 'user' => User::getFullName($usr_id)));
     }
     if (count($updated_fields) > 0 || count($updated_custom_fields) > 0) {
         // send notifications for the issue being updated
         Notification::notifyIssueUpdated($issue_id, $current, $_POST, $updated_custom_fields);
     }
     // record group change as a separate change
     if (isset($_POST['group']) && $current['iss_grp_id'] != (int) $_POST['group']) {
         History::add($issue_id, $usr_id, 'group_changed', 'Group changed ({changes}) by {user}', array('changes' => History::formatChanges(Group::getName($current['iss_grp_id']), Group::getName($_POST['group'])), 'user' => User::getFullName($usr_id)));
     }
     // now update any duplicates, if any
     $update_dupe = array('Category', 'Release', 'Priority', 'Release', 'Resolution');
     $intersect = array_intersect($update_dupe, array_keys($updated_fields));
     if ($current['duplicates'] != '' && count($intersect) > 0) {
         self::updateDuplicates($issue_id);
     }
     // if there is customer integration, mark last customer action
     if (CRM::hasCustomerIntegration($prj_id) && User::getRoleByUser($usr_id, $prj_id) == User::ROLE_CUSTOMER) {
         self::recordLastCustomerAction($issue_id);
     }
     if ($assignments_changed) {
         // XXX: we may want to also send the email notification for those "new" assignees
         Workflow::handleAssignmentChange(self::getProjectID($issue_id), $issue_id, $usr_id, self::getDetails($issue_id), @$_POST['assignments'], false);
     }
     Workflow::handleIssueUpdated($prj_id, $issue_id, $usr_id, $current, $_POST);
     // Move issue to another project
     if (isset($_POST['move_issue']) and User::getRoleByUser($usr_id, $prj_id) >= User::ROLE_DEVELOPER) {
         $new_prj_id = (int) @$_POST['new_prj'];
         if ($prj_id != $new_prj_id && array_key_exists($new_prj_id, Project::getAssocList($usr_id))) {
             if (User::getRoleByUser($usr_id, $new_prj_id) >= User::ROLE_REPORTER) {
                 $res = self::moveIssue($issue_id, $new_prj_id);
                 if ($res == -1) {
                     return $res;
                 }
             } else {
                 return -1;
             }
         }
     }
     return 1;
 }
 /**
  * Method used to send a diff-style notification email to the issue
  * subscribers about updates to its attributes.
  *
  * @param   integer $issue_id The issue ID
  * @param   array $old The old issue details
  * @param   array $new The new issue details
  */
 public static function notifyIssueUpdated($issue_id, $old, $new)
 {
     $prj_id = Issue::getProjectID($issue_id);
     $diffs = array();
     if (@$new['keep_assignments'] == 'no') {
         if (empty($new['assignments'])) {
             $new['assignments'] = array();
         }
         $assign_diff = Misc::arrayDiff($old['assigned_users'], $new['assignments']);
         if (count($assign_diff) > 0) {
             $diffs[] = '-' . ev_gettext('Assignment List') . ': ' . $old['assignments'];
             @($diffs[] = '+' . ev_gettext('Assignment List') . ': ' . implode(', ', User::getFullName($new['assignments'])));
         }
     }
     if (isset($new['expected_resolution_date']) && @$old['iss_expected_resolution_date'] != $new['expected_resolution_date']) {
         $diffs[] = '-' . ev_gettext('Expected Resolution Date') . ': ' . $old['iss_expected_resolution_date'];
         $diffs[] = '+' . ev_gettext('Expected Resolution Date') . ': ' . $new['expected_resolution_date'];
     }
     if (isset($new['category']) && $old['iss_prc_id'] != $new['category']) {
         $diffs[] = '-' . ev_gettext('Category') . ': ' . Category::getTitle($old['iss_prc_id']);
         $diffs[] = '+' . ev_gettext('Category') . ': ' . Category::getTitle($new['category']);
     }
     if (isset($new['release']) && $old['iss_pre_id'] != $new['release']) {
         $diffs[] = '-' . ev_gettext('Release') . ': ' . Release::getTitle($old['iss_pre_id']);
         $diffs[] = '+' . ev_gettext('Release') . ': ' . Release::getTitle($new['release']);
     }
     if (isset($new['priority']) && $old['iss_pri_id'] != $new['priority']) {
         $diffs[] = '-' . ev_gettext('Priority') . ': ' . Priority::getTitle($old['iss_pri_id']);
         $diffs[] = '+' . ev_gettext('Priority') . ': ' . Priority::getTitle($new['priority']);
     }
     if (isset($new['severity']) && $old['iss_sev_id'] != $new['severity']) {
         $diffs[] = '-' . ev_gettext('Severity') . ': ' . Severity::getTitle($old['iss_sev_id']);
         $diffs[] = '+' . ev_gettext('Severity') . ': ' . Severity::getTitle($new['severity']);
     }
     if (isset($new['status']) && $old['iss_sta_id'] != $new['status']) {
         $diffs[] = '-' . ev_gettext('Status') . ': ' . Status::getStatusTitle($old['iss_sta_id']);
         $diffs[] = '+' . ev_gettext('Status') . ': ' . Status::getStatusTitle($new['status']);
     }
     if (isset($new['resolution']) && $old['iss_res_id'] != $new['resolution']) {
         $diffs[] = '-' . ev_gettext('Resolution') . ': ' . Resolution::getTitle($old['iss_res_id']);
         $diffs[] = '+' . ev_gettext('Resolution') . ': ' . Resolution::getTitle($new['resolution']);
     }
     if (isset($new['estimated_dev_time']) && $old['iss_dev_time'] != $new['estimated_dev_time']) {
         $diffs[] = '-' . ev_gettext('Estimated Dev. Time') . ': ' . Misc::getFormattedTime($old['iss_dev_time'] * 60);
         $diffs[] = '+' . ev_gettext('Estimated Dev. Time') . ': ' . Misc::getFormattedTime($new['estimated_dev_time'] * 60);
     }
     if (isset($new['summary']) && $old['iss_summary'] != $new['summary']) {
         $diffs[] = '-' . ev_gettext('Summary') . ': ' . $old['iss_summary'];
         $diffs[] = '+' . ev_gettext('Summary') . ': ' . $new['summary'];
     }
     if (isset($new['percent_complete']) && $old['iss_original_percent_complete'] != $new['percent_complete']) {
         $diffs[] = '-' . ev_gettext('Percent complete') . ': ' . $old['iss_original_percent_complete'];
         $diffs[] = '+' . ev_gettext('Percent complete') . ': ' . $new['percent_complete'];
     }
     if (isset($new['description']) && $old['iss_description'] != $new['description']) {
         $old['iss_description'] = explode("\n", $old['iss_original_description']);
         $new['description'] = explode("\n", $new['description']);
         $diff = new Text_Diff($old['iss_description'], $new['description']);
         $renderer = new Text_Diff_Renderer_unified();
         $desc_diff = explode("\n", trim($renderer->render($diff)));
         $diffs[] = 'Description:';
         foreach ($desc_diff as $diff) {
             $diffs[] = $diff;
         }
     }
     $emails = array();
     $users = self::getUsersByIssue($issue_id, 'updated');
     $user_emails = Project::getUserEmailAssocList(Issue::getProjectID($issue_id), 'active', User::getRoleID('Customer'));
     // FIXME: $user_emails unused
     $user_emails = array_map(function ($s) {
         return strtolower($s);
     }, $user_emails);
     foreach ($users as $user) {
         if (empty($user['sub_usr_id'])) {
             $email = $user['sub_email'];
         } else {
             $prefs = Prefs::get($user['sub_usr_id']);
             if (Auth::getUserID() == $user['sub_usr_id'] && (empty($prefs['receive_copy_of_own_action'][$prj_id]) || $prefs['receive_copy_of_own_action'][$prj_id] == false)) {
                 continue;
             }
             $email = User::getFromHeader($user['sub_usr_id']);
         }
         // now add it to the list of emails
         if (!empty($email) && !in_array($email, $emails)) {
             $emails[] = $email;
         }
     }
     // get additional email addresses to notify
     $emails = array_merge($emails, Workflow::getAdditionalEmailAddresses($prj_id, $issue_id, 'issue_updated', array('old' => $old, 'new' => $new)));
     $data = Issue::getDetails($issue_id);
     $data['diffs'] = implode("\n", $diffs);
     $data['updated_by'] = User::getFullName(Auth::getUserID());
     self::notifySubscribers($issue_id, $emails, 'updated', $data, ev_gettext('Updated'), false);
 }