blob: 827741d3f3838a0b929d3ff3e69c893d7ce6800a [file] [log] [blame]
<?php
/*******************************************************************************
* Copyright (c) 2010 Eclipse Foundation and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
require_once($_SERVER['DOCUMENT_ROOT'] . "/projects/classes/common.php");
require_once($_SERVER['DOCUMENT_ROOT'] . "/projects/classes/debug.php");
require_once(dirname(__FILE__) . "/Forge.class.inc");
require_once(dirname(__FILE__) . "/database.inc");
define('REVIEW_TYPE_CREATION', 'creation');
define('REVIEW_TYPE_GRADUATION', 'graduation');
define('REVIEW_TYPE_RELEASE', 'release');
define('REVIEW_TYPE_RESTRUCTURE', 'restructure');
define('REVIEW_TYPE_TERMINATION', 'termination');
class Review {
var $info;
function __construct($info) {
$this->info = $info;
}
/**
* State should be one of 'complete' or 'upcoming'
*
* @param string $state
* @param int $cutoff Only return reviews that have occurred since this date
* @return Review[]
*/
public static function getReviews($state = 'upcoming', $cutoff = null) {
$reviews = array();
foreach(Forge::getForges() as $forge) {
$url = "{$forge->getUrl()}/json/reviews/$state";
if ($list = json_decode(getUrlContents($url), true)) {
foreach($list as $row) {
$review = new Review($row);
if ($cutoff && ($review->getDate() < $cutoff)) continue;
$review->statuses[] = new ReviewStatus($row);
$reviews[$review->getId()] = $review;
}
}
}
usort($reviews, 'sortReviewsByDate');
return $reviews;
}
/**
* Fetch completed reviews from all forges. The results are sorted by date.
* @return Review[]
*/
public static function getCompletedReviews() {
return self::getReviews('complete');
}
function getId() {
return $this->info['Id'];
}
function getProjectName() {
$name = @$this->info['ProjectName'];
if ($name) return $name;
/*
* If the name hasn't been specified, use the proposal name instead.
* That is, assume that we're looking at a Creation Review that's
* following a proposal.
*/
return @$this->info['ProposalName'];
}
function getProjectId() {
return $this->info['ProjectId'];
}
function getReviewName() {
$name = $this->info['ReviewName'];
if ($name) return $name;
/*
* If the review name has not been provided, but a proposal
* name has been provided, assume that this is a creation review.
*/
if ($this->info['ProposalName']) return 'Creation';
return "Unknown";
}
function getTitle() {
$projectName = $this->getProjectName();
$reviewName = $this->getReviewName();
return "$projectName $reviewName";
}
function getType() {
if ($this->isCreation()) return REVIEW_TYPE_CREATION;
if ($this->isGraduation()) return REVIEW_TYPE_GRADUATION;
if ($this->isRelease()) return REVIEW_TYPE_RELEASE;
if ($this->isRestructure()) return REVIEW_TYPE_RESTRUCTURE;
if ($this->isTermination()) return REVIEW_TYPE_TERMINATION;
return null;
}
function isCreation() {
return preg_match('/Creation/i', $this->getReviewName()) ? true : false;
}
/**
* If the name includes the word "release", or if the name is
* just a number, then it's a release.
*
* @return boolean
*/
function isRelease() {
if (preg_match('/release/i', $this->getReviewName())) return true;
if (preg_match('/^\d*(\.\d+){0,}$/', trim($this->getReviewName()))) return true;
return false;
}
function isGraduation() {
return preg_match('/Graduation/i', $this->getReviewName()) ? true : false;
}
function isRestructure() {
if (preg_match('/Restruct/i', $this->getReviewName())) return true;
if (preg_match('/Move/i', $this->getReviewName())) return true;
return false;
}
function isTermination() {
if (preg_match('/Termination/i', $this->getReviewName())) return true;
if (preg_match('/Archiv/i', $this->getReviewName())) return true;
return false;
}
function getVersion() {
if (preg_match('/(\d+)(\.\d+)?(\.\d+)?/', $this->getReviewName(), $matches)) {
$name = $matches[1];
$name .= isset($matches[2]) && $matches[2] ? $matches[2] : '.0';
$name .= isset($matches[3]) && $matches[3] ? $matches[3] : '.0';
return $name;
} else if (preg_match('/(\d+(\.\d+){1,2})/', $this->getReviewName())) {
return $match[1];
} else {
return null;
}
}
function getReviewDate() {
$date = $this->info['ReviewDate'];
if (!$date) return null;
return strtotime($date);
}
function getDate() {
return $this->getReviewDate();
}
function getProjectUrl() {
return $this->info['ProjectURL'];
}
function getBugNumber() {
return $this->info['BugNumber'];
}
function getIplogUrl() {
return $this->info['IPLogURL'];
}
function getLink() {
return $this->getSlidesUrl();
}
function getSlidesUrl() {
return $this->info['SlidesURL'];
}
function isWithdrawn() {
return $this->getReviewWithdrawn() != null;
}
function isSuccessful() {
return $this->getReviewSuccessful() != null;
}
function isUnsuccessful() {
return $this->getReviewUnsuccessful() != null;
}
function getReviewSuccessful() {
return $this->getStatus('Review Successful');
}
function getReviewWithdrawn() {
return $this->getStatus('Review Withdrawn');
}
function getReviewUnsuccessful() {
return $this->getStatus('Review Unsuccessful');
}
function getWaitingProvisioning() {
return $this->getStatus('Waiting Provisioning');
}
/**
* This function provides a line of HTML that describes the receiver; it
* provides links to the various bits of interesting information about
* the review. Yes, this probably doesn't belong here (it's more of
* UI thing).
*
* @return string
*/
function asHtml($ignore = null) {
global $App;
$projectName = $this->getProjectName();
$reviewName = $this->getReviewName();
$projectUrl = $this->getProjectUrl();
$reviewUrl = $this->getSlidesUrl();
$iplogUrl = $this->getIplogUrl();
$reviewDate = $this->getReviewDate();
$projectName = htmlentities($projectName);
$reviewName = htmlentities($reviewName);
$suffix = 'Review';
if ($projectUrl) $projectName = "<a href=\"$projectUrl\">$projectName</a>";
if ($reviewDate) {
$reviewDate = $App->getFormattedDate($reviewDate, 'short');
$reviewDate = str_replace(' ', '&nbsp;', $reviewDate);
} else {
$reviewDate= 'unscheduled';
}
if ($reviewUrl)
$suffix = "<a href=\"$reviewUrl\">$suffix</a>";
$icons = '';
if ($iplogUrl) {
$icons .= "<a href=\"$iplogUrl\"><img style=\"vertical-align:top\" title=\"IP Log\" src=\"http://dev.eclipse.org/small_icons/status/dialog-information.png\"/></a>";
}
if ($this->isSuccessful()) {
$icons .= "<img style=\"vertical-align:top\" title=\"Review Successful\" src=\"/projects/images/ok.gif\">";
}
if ($this->isUnsuccessful()) {
$icons .= "<img style=\"vertical-align:top\" title=\"Review Unsuccessful\" src=\"http://dev.eclipse.org/small_icons/actions/process-stop.png\">";
}
if ($this->isWithdrawn()) {
$reviewDate = "<strike>$reviewDate</strike>";
$projectName = "<strike>$projectName</strike>";
$reviewName = "<strike>$reviewName</strike>";
$icons .= "<img style=\"vertical-align:top\" title=\"Review Withdrawn\" src=\"http://dev.eclipse.org/small_icons/actions/process-stop.png\">";
}
return "${projectName} $reviewName <nobr>${suffix}${icons}</nobr>";
}
/**
* THIS IS NOT API
*/
/* private */ function getStatus($text) {
foreach($this->statuses as $status) {
if ($status->getText() == $text) return $status;
}
return null;
}
}
class ReviewStatus {
var $info;
function __construct($info) {
$this->info = $info;
}
function getText() {
return $this->info['Status'];
}
function getDate() {
return strtotime($this->info['Date']);
}
}
/**
* This function provides the list of all reviews. Note that the
* results are cached.
*
* @deprecated use Review::getCompletedReviews()
* @return Review[]
*/
function get_reviews() {
return Review::getCompletedReviews();
}
/**
* @deprecated
* @param string $projectId
*/
function getReviewsForProject($projectId) {
$reviews = array();
foreach(Review::getCompletedReviews() as $review) {
if ($review->getProjectId() == $projectId)
$reviews[] = $review;
}
return $reviews;
}
/**
* State should be one of 'complete' or 'upcoming'
*
* @deprecated use Review::getReviews()
* @param string $state
* @param int $cutoff Only return reviews that have occurred since this date
*/
function getReviews($state = 'upcoming', $cutoff = null) {
return Review::getReviews($state, $cutoff);
}
function sortReviewsByDate($a, $b) {
$dateA = $a->getReviewDate();
$dateB = $b->getReviewDate();
if ($dateA == $dateB) return 0;
return $dateA > $dateB ? -1 : 1;
}
/**
* Compare two Reviews for sorting. The most recently completed
* reviews are sorted first, followed by everything else. Within
* the groups, everything is sorted by date and then by project id.
*
* @internal
* @param Review $a
* @param Review $b
* @return -1, 0, 1 if <,==,>
*/
function sortReviewsByUpcoming($a, $b) {
$now = strtotime('now');
$lastWeek = strtotime('-1 week');
$aDate = $a->getDate();
$bDate = $b->getDate();
$aRecent = ($aDate < $now) && ($aDate > $lastWeek);
$bRecent = ($bDate < $now) && ($bDate > $lastWeek);
if ($aRecent == $bRecent) {
if ($aDate < $bDate) return -1;
if ($aDate > $bDate) return 1;
return strcasecmp($a->getProjectId(),$b->getProjectId());
}
if ($aRecent == 1) return -1;
return 1;
}
?>