Beispiel #1
0
 protected function _getIssueFromRequest(TBGRequest $request)
 {
     if ($issue_no = TBGContext::getRequest()->getParameter('issue_no')) {
         $issue = TBGIssue::getIssueFromLink($issue_no);
         if ($issue instanceof TBGIssue) {
             if (!$this->selected_project instanceof TBGProject || $issue->getProjectID() != $this->selected_project->getID()) {
                 $issue = null;
             }
         } else {
             TBGLogging::log("Issue no [{$issue_no}] not a valid issue no", 'main', TBGLogging::LEVEL_WARNING_RISK);
         }
     }
     TBGLogging::log('done (Loading issue)');
     //$this->getResponse()->setPage('viewissue');
     if ($issue instanceof TBGIssue && (!$issue->hasAccess() || $issue->isDeleted())) {
         $issue = null;
     }
     return $issue;
 }
Beispiel #2
0
 public function extractIssues($matches)
 {
     $issue = TBGIssue::getIssueFromLink($matches["issues"]);
     if ($issue instanceof TBGIssue) {
         if (!TBGContext::isProjectContext() || TBGContext::isProjectContext() && $issue->getProjectID() == TBGContext::getCurrentProject()->getID()) {
             $this->foundissues[$issue->getID()] = $issue;
             $this->resultcount++;
         }
     }
 }
Beispiel #3
0
 public function runUpdateIssueDetails(TBGRequest $request)
 {
     $this->forward403if(TBGContext::getCurrentProject()->isArchived());
     $this->error = false;
     try {
         $i18n = TBGContext::getI18n();
         $issue = TBGIssue::getIssueFromLink($request['issue_no']);
         if ($issue->getProject()->getID() != $this->selected_project->getID()) {
             throw new Exception($i18n->__('This issue is not valid for this project'));
         }
         if (!$issue instanceof TBGIssue) {
             die;
         }
         $workflow_transition = null;
         if ($passed_transition = $request['workflow_transition']) {
             //echo "looking for transition ";
             $key = str_replace(' ', '', mb_strtolower($passed_transition));
             //echo $key . "\n";
             foreach ($issue->getAvailableWorkflowTransitions() as $transition) {
                 //echo str_replace(' ', '', mb_strtolower($transition->getName())) . "?";
                 if (mb_strpos(str_replace(' ', '', mb_strtolower($transition->getName())), $key) !== false) {
                     $workflow_transition = $transition;
                     //echo "found transition " . $transition->getID();
                     break;
                 }
                 //echo "no";
             }
             if (!$workflow_transition instanceof TBGWorkflowTransition) {
                 throw new Exception("This transition ({$key}) is not valid");
             }
         }
         $fields = $request->getRawParameter('fields', array());
         $return_values = array();
         if ($workflow_transition instanceof TBGWorkflowTransition) {
             foreach ($fields as $field_key => $field_value) {
                 $classname = "TBG" . ucfirst($field_key);
                 $method = "set" . ucfirst($field_key);
                 $choices = $classname::getAll();
                 $found = false;
                 foreach ($choices as $choice_key => $choice) {
                     if (mb_strpos(str_replace(' ', '', mb_strtolower($choice->getName())), str_replace(' ', '', mb_strtolower($field_value))) !== false) {
                         $request->setParameter($field_key . '_id', $choice->getId());
                         break;
                     }
                 }
             }
             $request->setParameter('comment_body', $request['message']);
             $return_values['applied_transition'] = $workflow_transition->getName();
             if ($workflow_transition->validateFromRequest($request)) {
                 $retval = $workflow_transition->transitionIssueToOutgoingStepFromRequest($issue, $request);
                 $return_values['transition_ok'] = $retval === false ? false : true;
             } else {
                 $return_values['transition_ok'] = false;
                 $return_values['message'] = "Please pass all information required for this transition";
             }
         } elseif ($issue->isUpdateable()) {
             foreach ($fields as $field_key => $field_value) {
                 try {
                     if (in_array($field_key, array_merge(array('title', 'state'), TBGDatatype::getAvailableFields(true)))) {
                         switch ($field_key) {
                             case 'state':
                                 $issue->setState($field_value == 'open' ? TBGIssue::STATE_OPEN : TBGIssue::STATE_CLOSED);
                                 break;
                             case 'title':
                                 if ($field_value != '') {
                                     $issue->setTitle($field_value);
                                 } else {
                                     throw new Exception($i18n->__('Invalid title'));
                                 }
                                 break;
                             case 'description':
                             case 'reproduction_steps':
                                 $method = "set" . ucfirst($field_key);
                                 $issue->{$method}($field_value);
                                 break;
                             case 'status':
                             case 'resolution':
                             case 'reproducability':
                             case 'priority':
                             case 'severity':
                             case 'category':
                                 $classname = "TBG" . ucfirst($field_key);
                                 $method = "set" . ucfirst($field_key);
                                 $choices = $classname::getAll();
                                 $found = false;
                                 foreach ($choices as $choice_key => $choice) {
                                     if (str_replace(' ', '', mb_strtolower($choice->getName())) == str_replace(' ', '', mb_strtolower($field_value))) {
                                         $issue->{$method}($choice);
                                         $found = true;
                                     }
                                 }
                                 if (!$found) {
                                     throw new Exception('Could not find this value');
                                 }
                                 break;
                             case 'percent_complete':
                                 $issue->setPercentCompleted($field_value);
                                 break;
                             case 'owner':
                             case 'assignee':
                                 $set_method = "set" . ucfirst($field_key);
                                 $unset_method = "un{$set_method}";
                                 switch (mb_strtolower($field_value)) {
                                     case 'me':
                                         $issue->{$set_method}(TBGContext::getUser());
                                         break;
                                     case 'none':
                                         $issue->{$unset_method}();
                                         break;
                                     default:
                                         try {
                                             $user = TBGUser::findUser(mb_strtolower($field_value));
                                             if ($user instanceof TBGUser) {
                                                 $issue->{$set_method}($user);
                                             }
                                         } catch (Exception $e) {
                                             throw new Exception('No such user found');
                                         }
                                         break;
                                 }
                                 break;
                             case 'estimated_time':
                             case 'spent_time':
                                 $set_method = "set" . ucfirst(str_replace('_', '', $field_key));
                                 $issue->{$set_method}($field_value);
                                 break;
                             case 'milestone':
                                 $found = false;
                                 foreach ($this->selected_project->getMilestones() as $milestone) {
                                     if (str_replace(' ', '', mb_strtolower($milestone->getName())) == str_replace(' ', '', mb_strtolower($field_value))) {
                                         $issue->setMilestone($milestone->getID());
                                         $found = true;
                                     }
                                 }
                                 if (!$found) {
                                     throw new Exception('Could not find this milestone');
                                 }
                                 break;
                             default:
                                 throw new Exception($i18n->__('Invalid field'));
                         }
                     }
                     $return_values[$field_key] = array('success' => true);
                 } catch (Exception $e) {
                     $return_values[$field_key] = array('success' => false, 'error' => $e->getMessage());
                 }
             }
         }
         if (!$workflow_transition instanceof TBGWorkflowTransition) {
             $issue->getWorkflow()->moveIssueToMatchingWorkflowStep($issue);
         }
         if (!array_key_exists('transition_ok', $return_values) || $return_values['transition_ok']) {
             $comment = new TBGComment();
             $comment->setTitle('');
             $comment->setContent($request->getParameter('message', null, false));
             $comment->setPostedBy(TBGContext::getUser()->getID());
             $comment->setTargetID($issue->getID());
             $comment->setTargetType(TBGComment::TYPE_ISSUE);
             $comment->setModuleName('core');
             $comment->setIsPublic(true);
             $comment->setSystemComment(false);
             $comment->save();
             $issue->setSaveComment($comment);
             $issue->save();
         }
         $this->return_values = $return_values;
     } catch (Exception $e) {
         //$this->getResponse()->setHttpStatus(400);
         return $this->renderJSON(array('failed' => true, 'error' => $e->getMessage()));
     }
 }
 protected function _parse_issuelink($matches)
 {
     $theIssue = TBGIssue::getIssueFromLink($matches[0]);
     $output = '';
     $classname = '';
     if ($theIssue instanceof TBGIssue && ($theIssue->isClosed() || $theIssue->isDeleted())) {
         $classname = 'closed';
     }
     if ($theIssue instanceof TBGIssue) {
         $output = ' ' . link_tag(make_url('viewissue', array('issue_no' => $theIssue->getFormattedIssueNo(false), 'project_key' => $theIssue->getProject()->getKey())), $theIssue->getFormattedTitle(), array('class' => $classname));
     } else {
         $output = $matches[1];
     }
     return $output;
 }
 public function addNewCommit($project, $commit_msg, $old_rev, $new_rev, $date = null, $changed, $author)
 {
     /* Find issues to update */
     $fixes_grep = "#((bug|issue|ticket|fix|fixes|fixed|fixing|applies to|closes|references|ref|addresses|re|see|according to|also see)\\s\\#?(([A-Z0-9]+\\-)?\\d+))#ie";
     $output = '';
     $f_issues = array();
     try {
         TBGContext::getI18n();
     } catch (Exception $e) {
         TBGContext::reinitializei18n();
     }
     try {
         $project = new TBGProject($project);
     } catch (Exception $e) {
         return TBGContext::getI18n()->__('Error: Invalid project ID');
     }
     if (preg_match_all($fixes_grep, $commit_msg, $f_issues)) {
         // Github
         if (is_array($changed)) {
             $entries = $changed;
             $changed = '';
             // Now handle changed files
             foreach ($entries[0] as $file) {
                 $changed .= 'M' . $file . "\n";
             }
             // Now handle new files
             foreach ($entries[1] as $file) {
                 $changed .= 'A' . $file . "\n";
             }
             // Now handle deleted files
             foreach ($entries[2] as $file) {
                 $changed .= 'D' . $file . "\n";
             }
         }
         $f_issues = array_unique($f_issues[3]);
         $file_lines = preg_split('/[\\n\\r]+/', $changed);
         $files = array();
         foreach ($file_lines as $aline) {
             $action = substr($aline, 0, 1);
             if ($action == "A" || $action == "U" || $action == "D" || $action == "M") {
                 $theline = trim(substr($aline, 1));
                 $files[] = array($action, $theline);
             }
         }
         foreach ($f_issues as $issue_no) {
             TBGContext::setCurrentProject($project);
             $theIssue = TBGIssue::getIssueFromLink($issue_no, true);
             if ($theIssue instanceof TBGIssue) {
                 $uid = 0;
                 /*
                  * Some VCSes use a different format of storing the committer's name. Systems like bzr, git and hg use the format
                  * Joe Bloggs <*****@*****.**>, instead of a classic username. Therefore a user will be found via 4 queries:
                  * a) First we extract the email if there is one, and find a user with that email
                  * b) If one is not found - or if no email was specified, then instead test against the real name (using the name part if there was an email)
                  * c) the username or full name is checked against the friendly name field
                  * d) and if we still havent found one, then we check against the username
                  * e) and if we STILL havent found one, we just say the user is id 0 (unknown user).
                  */
                 if (preg_match("/(?<=<)(.*)(?=>)/", $author, $matches)) {
                     $email = $matches[0];
                     // a)
                     $crit = new B2DBCriteria();
                     $crit->setFromTable(TBGUsersTable::getTable());
                     $crit->addSelectionColumn(TBGUsersTable::ID);
                     $crit->addWhere(TBGUsersTable::EMAIL, $email);
                     $row = TBGUsersTable::getTable()->doSelectOne($crit);
                     if ($row != null) {
                         $uid = $row->get(TBGUsersTable::ID);
                     } else {
                         // Not found by email
                         preg_match("/(?<=^)(.*)(?= <)/", $author, $matches);
                         $author = $matches[0];
                     }
                 }
                 // b)
                 if ($uid == 0) {
                     $crit = new B2DBCriteria();
                     $crit->setFromTable(TBGUsersTable::getTable());
                     $crit->addSelectionColumn(TBGUsersTable::ID);
                     $crit->addWhere(TBGUsersTable::REALNAME, $author);
                     $row = TBGUsersTable::getTable()->doSelectOne($crit);
                     if ($row != null) {
                         $uid = $row->get(TBGUsersTable::ID);
                     }
                 }
                 // c)
                 if ($uid == 0) {
                     $crit = new B2DBCriteria();
                     $crit->setFromTable(TBGUsersTable::getTable());
                     $crit->addSelectionColumn(TBGUsersTable::ID);
                     $crit->addWhere(TBGUsersTable::BUDDYNAME, $author);
                     $row = TBGUsersTable::getTable()->doSelectOne($crit);
                     if ($row != null) {
                         $uid = $row->get(TBGUsersTable::ID);
                     }
                 }
                 // d)
                 if ($uid == 0) {
                     $crit = new B2DBCriteria();
                     $crit->setFromTable(TBGUsersTable::getTable());
                     $crit->addSelectionColumn(TBGUsersTable::ID);
                     $crit->addWhere(TBGUsersTable::UNAME, $author);
                     $row = TBGUsersTable::getTable()->doSelectOne($crit);
                     if ($row != null) {
                         $uid = $row->get(TBGUsersTable::ID);
                     }
                 }
                 $theIssue->addSystemComment(TBGContext::getI18n()->__('Issue updated from code repository'), TBGContext::getI18n()->__('This issue has been updated with the latest changes from the code repository.<source>%commit_msg%</source>', array('%commit_msg%' => $commit_msg)), $uid);
                 foreach ($files as $afile) {
                     if ($date == null) {
                         $date = time();
                     }
                     TBGVCSIntegrationTable::addEntry($theIssue->getID(), $afile[0], $commit_msg, $afile[1], $new_rev, $old_rev, $uid, $date);
                 }
                 $output .= 'Updated ' . $theIssue->getFormattedIssueNo() . "\n";
             } else {
                 $output .= 'Can\'t find ' . $issue_no . ' so not updating that one.' . "\n";
             }
         }
     }
     return $output;
 }
Beispiel #6
0
 /** 
  * Runs one or more regular expressions against a supplied text, extracts
  * issue numbers from it, and then obtains corresponding issues. The
  * function will also obtain information about transitions (if this was
  * specified in the text). This data can be used for transitioning the
  * issues through a workflow.
  *
  * Once the function finishes processing, it will return an array of format:
  *
  * array('issues' => tbg_issues, 'transitions' => transitions).
  *
  * tbgissues is an array consisting of TBGIssue instances.
  *
  * transitions is an array containing transition arrays. The transition
  * arrays are accessed with issue numbers as keys (e.g. 'PREFIX-1',
  * 'PREFIX-5' or '2', '3' etc). Each transition array has the following
  * format:
  *
  * array(0 => command, 1 => parameters)
  *
  * command is a string representing the transision command (for example
  * 'Resolve issue') from the workflow definition. parameters is an array
  * that contains parameters and their values that should be passed to the
  * transition step:
  *
  * array( 'PARAM1' => 'VALUE1', 'PARAM2' => 'VALUE2', ...)
  * 
  *
  * @param text Text that should be parsed for issue numbers and transitions.
  *
  * @param preg An array of regular expressions that should be used for
  * matching issue numbers. If an empty array is provided (default), regular
  * expressions are obtained through TBGTextParser::getIssueRegex() call. The
  * regular expressions should contain two named parameters - 'issues' and
  * 'transitions'. These two will be used for extracting the issue number and
  * transition information.
  * 
  * @return An array with two elements, one denoting the matched issues, one
  * denoting the transitions for issues. These elements can be accessed using
  * keys 'issues', and 'transitions'. The key 'issues' can be used for
  * accessing an array made-up of TBGIssue instances. The key 'transitions'
  * can be used for accessing an array containing transition information
  * about each issue. The 'transitions' array uses issue numbers as keys,
  * and contains ordered transition information (see above for detailed
  * description of format).
  */
 public static function getIssuesFromTextByRegex($text, $preg = array())
 {
     // Fetch the default regular expressions if required.
     if (!$preg) {
         $issue_match_regexes = TBGTextParser::getIssueRegex();
     }
     $issue_numbers = array();
     // Issue numbers
     $issues = array();
     // Issue objects
     $transitions = array();
     // Transition information
     // Iterate over all regular expressions that should be used for
     // issue/transition matching in commit message.
     foreach ($issue_match_regexes as $issue_match_regex) {
         $matched_issue_data = array();
         // All data from regexp
         // If any match is found using the current regular expression, extract
         // the information.
         if (preg_match_all($issue_match_regex, $text, $matched_issue_data)) {
             // Identified issues are kept inside of named regex group.
             foreach ($matched_issue_data["issues"] as $key => $issue_number) {
                 // Get the matched transitions for the issue.
                 $matched_issue_transitions = $matched_issue_data["transitions"][$key];
                 // Create an empty array to store transitions for an issue. Don't
                 // overwrite it. Use issue number as key for transitions.
                 if (!array_key_exists($issue_number, $transitions)) {
                     $transitions[$issue_number] = array();
                 }
                 // Add the transition information (if any) for an issue.
                 if ($matched_issue_transitions) {
                     // Parse the transition information. Each transition string is in
                     // format:
                     // 'TRANSITION1: PARAM1_1=VALUE1_1 PARAM1_2=VALUE1_2; TRANSITION2: PARAM2_1=VALUE2_1 PARAM2_2=VALUE2_2'
                     foreach (explode("; ", $matched_issue_transitions) as $transition) {
                         // Split command from its parameters.
                         $transition_data = explode(": ", $transition);
                         $transition_command = $transition_data[0];
                         // Set-up array that will contain parameters
                         $transition_parameters = array();
                         // Process parameters if they were present.
                         if (count($transition_data) == 2) {
                             // Split into induvidual parameters.
                             foreach (explode(" ", $transition_data[1]) as $parameter) {
                                 // Only process proper parameters (of format 'PARAM=VALUE')
                                 if (mb_strpos($parameter, '=')) {
                                     list($param_key, $param_value) = explode('=', $parameter);
                                     $transition_parameters[$param_key] = $param_value;
                                 }
                             }
                         }
                         // Append the transition information for the current issue number.
                         $transitions[$issue_number][] = array($transition_command, $transition_parameters);
                     }
                 }
                 // Add the issue number to the list.
                 $issue_numbers[] = $issue_number;
             }
         }
     }
     // Make sure that each issue gets procssed only once for a single commit
     // (avoid duplication of commits).
     $issue_numbers = array_unique($issue_numbers);
     // Fetch all issues affected by the commit.
     foreach ($issue_numbers as $issue_no) {
         $issue = TBGIssue::getIssueFromLink($issue_no);
         if ($issue instanceof TBGIssue) {
             $issues[] = $issue;
         }
     }
     // Return array consisting out of two arrays - one with TBGIssue
     // instances, and the second one with transition information for those
     // issues.
     return array("issues" => $issues, "transitions" => $transitions);
 }
 /**
  * View an issue
  * 
  * @param TBGRequest $request
  */
 public function runViewIssue(TBGRequest $request)
 {
     //TBGEvent::listen('core', 'viewissue', array($this, 'listenViewIssuePostError'));
     TBGLogging::log('Loading issue');
     if ($issue_no = TBGContext::getRequest()->getParameter('issue_no')) {
         $issue = TBGIssue::getIssueFromLink($issue_no);
         if ($issue instanceof TBGIssue) {
             if (!$this->selected_project instanceof TBGProject || $issue->getProjectID() != $this->selected_project->getID()) {
                 $issue = null;
             }
         } else {
             TBGLogging::log("Issue no [{$issue_no}] not a valid issue no", 'main', TBGLogging::LEVEL_WARNING_RISK);
         }
     }
     TBGLogging::log('done (Loading issue)');
     //$this->getResponse()->setPage('viewissue');
     if ($issue instanceof TBGIssue && (!$issue->hasAccess() || $issue->isDeleted())) {
         $issue = null;
     }
     if ($issue instanceof TBGIssue) {
         if (!array_key_exists('viewissue_list', $_SESSION)) {
             $_SESSION['viewissue_list'] = array();
         }
         $k = array_search($issue->getID(), $_SESSION['viewissue_list']);
         if ($k !== false) {
             unset($_SESSION['viewissue_list'][$k]);
         }
         array_push($_SESSION['viewissue_list'], $issue->getID());
         if (count($_SESSION['viewissue_list']) > 10) {
             array_shift($_SESSION['viewissue_list']);
         }
         TBGEvent::createNew('core', 'viewissue', $issue)->trigger();
     }
     $message = TBGContext::getMessageAndClear('issue_saved');
     $uploaded = TBGContext::getMessageAndClear('issue_file_uploaded');
     if ($request->isMethod(TBGRequest::POST) && $issue instanceof TBGIssue && $request->hasParameter('issue_action')) {
         switch ($request->getParameter('issue_action')) {
             case 'save':
                 if ($issue->hasUnsavedChanges()) {
                     if (!$issue->hasMergeErrors()) {
                         try {
                             $issue->getWorkflowStep()->getWorkflow()->moveIssueToMatchingWorkflowStep($issue);
                             $issue->save();
                             TBGContext::setMessage('issue_saved', true);
                             $this->forward(TBGContext::getRouting()->generate('viewissue', array('project_key' => $issue->getProject()->getKey(), 'issue_no' => $issue->getFormattedIssueNo())));
                         } catch (TBGWorkflowException $e) {
                             $this->error = $e->getMessage();
                             $this->workflow_error = true;
                         } catch (Exception $e) {
                             $this->error = $e->getMessage();
                         }
                     } else {
                         $this->issue_unsaved = true;
                     }
                 } else {
                     $this->forward(TBGContext::getRouting()->generate('viewissue', array('project_key' => $issue->getProject()->getKey(), 'issue_no' => $issue->getFormattedIssueNo())));
                 }
                 break;
         }
     } elseif ($message == true) {
         $this->issue_saved = true;
     } elseif ($uploaded == true) {
         $this->issue_file_uploaded = true;
     } elseif (TBGContext::hasMessage('issue_error')) {
         $this->error = TBGContext::getMessageAndClear('issue_error');
     } elseif (TBGContext::hasMessage('issue_message')) {
         $this->issue_message = TBGContext::getMessageAndClear('issue_message');
     }
     $issuelist = array();
     $issues = TBGContext::getUser()->getStarredIssues();
     if (count($issues)) {
         foreach ($issues as $starred_issue) {
             if (!$starred_issue instanceof TBGIssue || !$starred_issue->getProject() instanceof TBGProject || !$this->selected_project instanceof TBGProject) {
                 continue;
             }
             if ($starred_issue->isOpen() && $starred_issue->getProject()->getID() == $this->selected_project->getID()) {
                 $issuelist[$starred_issue->getID()] = array('url' => TBGContext::getRouting()->generate('viewissue', array('project_key' => $this->selected_project->getKey(), 'issue_no' => $starred_issue->getFormattedIssueNo())), 'title' => $starred_issue->getFormattedTitle(true, true));
             }
         }
     }
     if (array_key_exists('viewissue_list', $_SESSION) && is_array($_SESSION['viewissue_list'])) {
         foreach ($_SESSION['viewissue_list'] as $k => $i_id) {
             try {
                 $an_issue = new TBGIssue($i_id);
                 array_unshift($issuelist, array('url' => TBGContext::getRouting()->generate('viewissue', array('project_key' => $an_issue->getProject()->getKey(), 'issue_no' => $an_issue->getFormattedIssueNo())), 'title' => $an_issue->getFormattedTitle(true, true)));
             } catch (Exception $e) {
                 unset($_SESSION['viewissue_list'][$k]);
             }
         }
     }
     if (count($issuelist) == 1) {
         $issuelist = null;
     }
     $this->issuelist = $issuelist;
     $this->issue = $issue;
     $event = TBGEvent::createNew('core', 'viewissue', $issue)->trigger();
     $this->listenViewIssuePostError($event);
 }