/** * Return associative array of changes that is easy to display * * @param void * @return array */ function getVerboseChanges() { $result = array(); if (is_foreachable($this->getChanges())) { foreach ($this->getChanges() as $field => $change_data) { list($old_value, $new_value) = $change_data; $log_fields = array('project_id', 'milestone_id', 'parent_id', 'name', 'body', 'priority', 'due_on'); switch ($field) { case 'project_id': $old_project = Projects::findById($old_value); $new_project = Projects::findById($new_value); $old_project_name = instance_of($old_project, 'Project') ? $old_project->getName() : lang('unknown project'); $new_project_name = instance_of($new_project, 'Project') ? $new_project->getName() : lang('unknown project'); $result[] = lang('Moved from <span>:from</span> to <span>:to</span>', array('from' => $old_project_name, 'to' => $new_project_name)); break; case 'milestone_id': $old_milestone = Milestones::findById($old_value); $new_milestone = Milestones::findById($new_value); $old_milestone_name = instance_of($old_milestone, 'Milestone') ? $old_milestone->getName() : lang('-- none --'); $new_milestone_name = instance_of($new_milestone, 'Milestone') ? $new_milestone->getName() : lang('-- none --'); $result[] = lang('Moved from <span>:from</span> to <span>:to</span> milestone', array('from' => $old_milestone_name, 'to' => $new_milestone_name)); break; case 'parent_id': $old_parent = ProjectObjects::findById($old_value); $new_parent = ProjectObjects::findById($new_value); $old_parent_name = instance_of($old_parent, 'Category') ? $old_parent->getName() : lang('-- none --'); $new_parent_name = instance_of($new_parent, 'Category') ? $new_parent->getName() : lang('-- none --'); $result[] = lang('Moved from <span>:from</span> to <span>:to</span> category', array('from' => $old_parent_name, 'to' => $new_parent_name)); break; case 'name': $result[] = lang('Summary is changed from <span>:from</span> to <span>:to</span>', array('from' => $old_value, 'to' => $new_value)); break; case 'body': $result[] = lang('Long description is changed'); break; case 'priority': switch ($old_value) { case PRIORITY_HIGHEST: $old_priority = lang('Highest'); break; case PRIORITY_HIGH: $old_priority = lang('High'); break; case PRIORITY_NORMAL: $old_priority = lang('Normal'); break; case PRIORITY_LOW: $old_priority = lang('Low'); break; case PRIORITY_LOWEST: $old_priority = lang('Lowest'); break; case PRIORITY_ONGOING: $old_priority = lang('Ongoing'); break; case PRIORITY_HOLD: $old_priority = lang('Hold'); break; } // switch switch ($new_value) { case PRIORITY_HIGHEST: $new_priority = lang('Highest'); break; case PRIORITY_HIGH: $new_priority = lang('High'); break; case PRIORITY_NORMAL: $new_priority = lang('Normal'); break; case PRIORITY_LOW: $new_priority = lang('Low'); break; case PRIORITY_LOWEST: $new_priority = lang('Lowest'); break; case PRIORITY_ONGOING: $new_priority = lang('Ongoing'); break; case PRIORITY_HOLD: $new_priority = lang('Hold'); break; } // switch $result[] = lang('Priority is changed from <span>:from</span> to <span>:to</span>', array('from' => $old_priority, 'to' => $new_priority)); break; case 'due_on': require_once SMARTY_PATH . '/plugins/modifier.date.php'; $old_due_on = instance_of($old_value, 'DateValue') ? smarty_modifier_date($old_value, 0) : lang('-- none --'); $new_due_on = instance_of($new_value, 'DateValue') ? smarty_modifier_date($new_value, 0) : lang('-- none --'); $result[] = lang('Due date is changed from <span>:from</span> to <span>:to</span>', array('from' => $old_due_on, 'to' => $new_due_on)); break; case 'completed_on': if (instance_of($old_value, 'DateValue') && $new_value === null) { $result[] = lang('Status changed to: Open'); } elseif ($old_value === null && instance_of($new_value, 'DateValue')) { $result[] = lang('Status changed to: Completed'); } // if break; case 'owner': if ($new_value) { $new_owner = Users::findById($new_value); if (instance_of($new_owner, 'User')) { $result[] = lang(':user is responsible', array('user' => $new_owner->getDisplayName())); } else { $result[] = lang('Owner changed (unknown user or deleted in the meantime)'); } // if } else { $result[] = lang('Anyone can pick up and work on this ticket'); } // if break; case 'assignees': $old_assignees = array(); if (is_foreachable($old_value)) { $old_assignees_users = Users::findByIds($old_value); if (is_foreachable($old_assignees_users)) { foreach ($old_assignees_users as $user) { $old_assignees[$user->getId()] = $user->getDisplayName(); } // foreach } // if } // if $new_assignees = array(); if (is_foreachable($new_value)) { $new_assignees_users = Users::findByIds($new_value); if (is_foreachable($new_assignees_users)) { foreach ($new_assignees_users as $user) { $new_assignees[$user->getId()] = $user->getDisplayName(); } // foreach } // if } // if foreach ($new_assignees as $new_assignee_id => $new_assignee) { if (!array_key_exists($new_assignee_id, $old_assignees)) { $result[] = lang(':user has been assigned to this ticket', array('user' => $new_assignee)); } // if } // foreach foreach ($old_assignees as $old_assignee_id => $old_assignee) { if (!array_key_exists($old_assignee_id, $new_assignees)) { $result[] = lang(':user has been removed from this ticket', array('user' => $old_assignee)); } // if } // foreach break; } // switch } // foreach } // if return $result; }
/** * Find project objects in commit message, make them links and * save the relations to database * * @param string $commit_message * @param string $commit_author * @param integer $revision * @param Repository $repository * @param Project $project * @return string */ function analyze_message($commit_message, $commit_author, $revision, $repository, $project) { if (define('PURIFY_HTML') && PURIFY_HTML) { $commit_message = purify_html($commit_message); // Clean! } // if $pattern = '/((complete[d]*)[\\s]+)?(ticket|milestone|discussion|task)[s]*[\\s]+[#]*\\d+/i'; if (preg_match_all($pattern, $commit_message, $matches)) { $i = 0; $search = array(); $replace = array(); $matches_unique = array_unique($matches['0']); foreach ($matches_unique as $key => $match) { $match_data = preg_split('/[\\s,]+/', $match, null, PREG_SPLIT_NO_EMPTY); // check if the object got completed by this commit $object_completed = false; if (strpos(strtolower($match_data['0']), 'complete') !== false) { $object_completed = true; unset($match_data['0']); $match_data = array_values($match_data); } // if $object_class_name = $match_data['0']; $module_name = Inflector::pluralize($object_class_name); $object_id = trim($match_data['1'], '#'); $search[$i] = $match; if (class_exists($module_name) && class_exists($object_class_name)) { $object = null; switch (strtolower($module_name)) { case 'tickets': $object = Tickets::findByTicketId($project, $object_id); break; case 'discussions': $object = Discussions::findById($object_id); break; case 'milestones': $object = Milestones::findById($object_id); break; case 'tasks': $object = Tasks::findById($object_id); break; } // switch if (instance_of($object, $object_class_name)) { $link_already_created = CommitProjectObjects::count("object_id = '" . $object->getId() . "' AND revision = '{$revision}'") > 0; if (!$link_already_created) { $comit_project_object = new CommitProjectObject(); $comit_project_object->setProjectId($object->getProjectId()); $comit_project_object->setObjectId($object->getId()); $comit_project_object->setObjectType(ucfirst($object_class_name)); $comit_project_object->setRepositoryId($repository->getId()); $comit_project_object->setRevision($revision); db_begin_work(); $save = $comit_project_object->save(); if ($save && !is_error($save)) { db_commit(); } else { db_rollback(); } // if save } // if $replace[$i] = ($object_completed ? 'Completed ' : '') . '<a href="' . $object->getViewUrl() . '">' . $match_data['0'] . ' ' . $match_data['1'] . '</a>'; // set the object as completed if ($object_completed && !instance_of($object, 'Discussion')) { $completed_by = $repository->getMappedUser($commit_author); $object->complete($completed_by); } // if } else { $replace[$i] = ($object_completed ? 'Completed ' : '') . '<a href="#" class="project_object_missing" title="' . lang('Project object does not exist in this project') . '">' . $match_data['0'] . ' ' . $match_data['1'] . '</a>'; } // if instance_of $i++; } // if module loaded } // foreach return str_ireplace($search, $replace, htmlspecialchars($commit_message)); // linkify } // if preg_match return $commit_message; }
/** * Return parent milestone * * @param void * @return Milestone */ function &getMilestone() { if ($this->milestone === false) { $this->milestone = $this->getMilestoneId() ? Milestones::findById($this->getMilestoneId()) : null; } // if return $this->milestone; }
/** * Add AC object links to commit messages * * @param string * @return string **/ private function analyzeCommitMessage($commit_message) { $pattern = '/(ticket|milestone|discussion|task)[s]*[\\s]+[#]*(\\d+)/i'; if (preg_match_all($pattern, $commit_message, $matches)) { $i = 0; $search = array(); $replace = array(); $matches_unique = array_unique($matches['0']); foreach ($matches_unique as $key => $match) { $match_data = preg_split('/[\\s,]+/', $match, null, PREG_SPLIT_NO_EMPTY); $object_class_name = $match_data['0']; $module_name = Inflector::pluralize($object_class_name); $object_id = trim($match_data['1'], '#'); $search[$i] = $match; if (class_exists($module_name) && class_exists($object_class_name)) { $object = null; switch (strtolower($module_name)) { case 'tickets': $object = Tickets::findByTicketId($this->active_project, $object_id); break; case 'discussions': $object = Discussions::findById($object_id); break; case 'milestones': $object = Milestones::findById($object_id); break; case 'tasks': $object = Tasks::findById($object_id); break; } // switch if (instance_of($object, $object_class_name)) { $replace[$i] = '<a href="' . $object->getViewUrl() . '">' . $match_data['0'] . ' ' . $match_data['1'] . '</a>'; } else { $replace[$i] = '<a href="#" class="project_object_missing" title="' . lang('Project object does not exist in this project') . '">' . $match_data['0'] . ' ' . $match_data['1'] . '</a>'; } // if instance_of $i++; } // if module loaded } // foreach return str_ireplace($search, $replace, htmlspecialchars($commit_message)); // linkify } // if preg_match return $commit_message; }
/** * Show and process reorder task form * * @param void * @return null */ function reorder_tickets() { $this->wireframe->print_button = false; $milestone = Milestones::findById($this->request->get('milestone_id')); if (instance_of($milestone, 'Milestone')) { $milestone_id = $milestone->getId(); } else { $milestone_id = null; } // if if (!$this->request->isSubmitted()) { $this->httpError(HTTP_ERR_BAD_REQUEST, null, true, true); } // if if (!Ticket::canManage($this->logged_user, $this->active_project)) { $this->httpError(HTTP_ERR_FORBIDDEN, null, true, true); } // if $order_data = $this->request->post('reorder_ticket'); $ids = array_keys($order_data); if (is_foreachable($order_data)) { $x = 1; foreach ($order_data as $key => $value) { $order_data[$key] = $x; $x++; } // foreach } // if $tickets = Tickets::findByIds($ids, STATE_VISIBLE, $this->logged_user->getVisibility()); if (is_foreachable($tickets)) { foreach ($tickets as $ticket) { $ticket->setMilestoneId($milestone_id); $ticket->setPosition(array_var($order_data, $ticket->getId())); $ticket->save(); } // foreach } // if $this->httpOk(); }