| <?php |
| /******************************************************************************* |
| * Copyright (c) 2010, 2015 Eclipse Foundation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Wayne Beaton (Eclipse Foundation) - initial API and implementation |
| * Wayne Beaton (Eclipse Foundation) - Added getProjectId() function |
| *******************************************************************************/ |
| |
| /* |
| * This script assumes that it is being included by another script. We |
| * assume that the $App variable has already been defined. |
| */ |
| |
| require_once(dirname(__FILE__) . "/common.php"); |
| require_once(dirname(__FILE__) . "/debug.php"); |
| trace_file_info(__FILE__); |
| |
| class Proposal { |
| var $info; |
| var $date; |
| var $statuses = array(); |
| |
| function __construct($info) { |
| $this->info = $info; |
| } |
| |
| function getName() { |
| return $this->info['ProposalName']; |
| } |
| |
| /** |
| * Once the project is created, the ProjectId field should be filled in. |
| */ |
| function getProjectId() { |
| return $this->info['ProjectId']; |
| } |
| |
| function getProjectUrl() { |
| return normalizeHttpUrl($this->info['ProjectURL']); |
| } |
| |
| function asHtml() { |
| $name = $this->getName(); |
| $proposalUrl = $this->getProposalUrl(); |
| $projectUrl = $this->getProjectUrl(); |
| |
| $text = htmlentities($name); |
| if ($projectUrl) $text = "<a href=\"$projectUrl\">$text</a>"; |
| |
| if ($proposalUrl) |
| $text .= " <a href=\"$proposalUrl\"><img style=\"vertical-align:top\" title=\"Proposal\" src=\"http://dev.eclipse.org/small_icons/mimetypes/text-x-generic.png\"/></a>"; |
| |
| if ($this->isSuccessful()) { |
| $text .= "<img style=\"vertical-align:top\" title=\"This project has been created.\" src=\"/projects/images/ok.gif\">"; |
| } |
| |
| if ($this->isWithdrawn()) $text = "<strike>$text</strike><img style=\"vertical-align:top\" title=\"Review Withdrawn\" src=\"http://dev.eclipse.org/small_icons/actions/process-stop.png\">"; |
| |
| return $text; |
| } |
| |
| /** |
| * This function gets the scope for the receiver from the |
| * proposal document. This is a relatively expensive operation, and |
| * no caching is provided. We use some very crude parsing to extract |
| * the contents from the <h2>Scope</h2> section of the document. |
| */ |
| function getScope() { |
| $id = $this->getProjectId(); |
| $trace = trace("Finding scope for $id"); |
| $url = $this->getProposalUrl(); |
| if (!$url) { |
| $trace->trace("Proposal URL is not specified."); |
| return null; |
| } |
| $trace->trace("URL is specified as $url"); |
| |
| $path = $this->getProposalDocumentFilePath($url); |
| |
| $trace->trace("Proposal URL $path"); |
| |
| $contents = @file_get_contents($path); |
| return $this->extractScope($trace, $contents); |
| } |
| |
| /** |
| * Find the real path of the proposal document. |
| * @internal |
| * @return NULL|string |
| */ |
| function getProposalDocumentFilePath($url) { |
| $path = realpath(normalizeFilePathUrl($url)); |
| if (is_file($path)) return $path; |
| |
| $file = "$path/proposal.html"; |
| if (is_file($file)) return $file; |
| |
| $file = "$path/index.php"; |
| if (is_file($file)) return $file; |
| |
| trace("Cannot find Proposal document at $url."); |
| return null; |
| } |
| |
| /** |
| * @internal |
| * @param unknown_type $url |
| * @param unknown_type $contents |
| * @return NULL|string |
| */ |
| function extractScope($trace, $contents) { |
| if (!$contents) { |
| $trace->trace("Proposal document is empty."); |
| return null; |
| } |
| |
| if (preg_match('/<h2[^>]*>.*?Scope.*?<\/h2>(.*?)<h\d[^>]*>/is', $contents, $matches)) { |
| $scope = $matches[1]; |
| } else { |
| $trace->trace("Cannot find scope tag."); |
| return null; |
| } |
| |
| $scope = preg_replace('/<!--.*?-->/s','', $scope); |
| $scope = preg_replace('/\s+/', ' ', $scope); |
| $scope = trim($scope); |
| |
| $trace->trace("Scope: $scope"); |
| |
| return $scope; |
| } |
| |
| function isWithdrawn() { |
| return $this->getProposalWithdrawn() != null; |
| } |
| |
| function isSuccessful() { |
| return $this->getReviewSuccessful() != null; |
| } |
| |
| function isActive() { |
| if ($this->isSuccessful()) return false; |
| if ($this->isWithdrawn()) return false; |
| return $this->getActiveDate() > strtotime('-3 month'); |
| } |
| |
| function getReviewSuccessful() { |
| return $this->getStatus('Review Successful'); |
| } |
| |
| function getProposalWithdrawn() { |
| return $this->getStatus('Proposal Withdrawn'); |
| } |
| |
| function getProposalPosted() { |
| return $this->getStatus('Proposal Posted'); |
| } |
| |
| function getProposalUrl() { |
| return normalizeHttpUrl($this->info['ProposalURL']); |
| } |
| /** |
| * This function returns the date of the proposal. We consider this to |
| * be the date of the earliest status. |
| */ |
| function getDate() { |
| if (!$this->date) $this->date = $this->compute_date(); |
| return $this->date; |
| } |
| |
| function getActiveDate() { |
| $date = 0; |
| foreach($this->statuses as $status) { |
| $status_date = $status->getDate(); |
| if ($status_date > $date) $date = $status_date; |
| } |
| return $date; |
| } |
| |
| /** |
| * It would be easier to just determine |
| * this value from the 'Proposal Posted' date, but we have found some |
| * entries that do not have this status... |
| * |
| * THIS IS NOT API |
| */ |
| /* private */ function compute_date() { |
| $date = strtotime('now'); |
| foreach($this->statuses as $status) { |
| $status_date = $status->getDate(); |
| if ($status_date < $date) $date = $status_date; |
| } |
| return $date; |
| } |
| |
| /** |
| * THIS IS NOT API |
| */ |
| /* private */ function getStatus($text) { |
| foreach($this->statuses as $status) { |
| if ($status->getText() == $text) return $status; |
| } |
| return null; |
| } |
| } |
| |
| class ProposalStatus { |
| var $info; |
| |
| function __construct($info) { |
| $this->info = $info; |
| } |
| |
| function getText() { |
| return $this->info['Status']; |
| } |
| |
| function getDate() { |
| return strtotime($this->info['Date']); |
| } |
| } |
| |
| function get_proposals($App) { |
| $sql = " |
| SELECT |
| r.id as Id, |
| r.ProjectName, r.ProjectId, |
| ProjectURL, ProposalURL, SlidesURL, IPLogURL, BugNumber, ReviewDate, |
| ReviewName, ProposalName, |
| s.status as Status, s.value as Date |
| FROM |
| ProjectReviews as r |
| join ProjectReviewStatus as s on (r.id = s.id and s.value != 0) |
| WHERE |
| length(trim(ProposalName)) > 0 |
| ORDER BY Date desc"; |
| |
| $result = $App->foundation_sql($sql); |
| |
| $proposals = array(); |
| while($row = mysql_fetch_assoc($result)) { |
| $id = $row['Id']; |
| if (isset($proposals[$id])) { |
| $proposal = $proposals[$id]; |
| } else { |
| $proposal = new Proposal($row); |
| $proposals[$id] = $proposal; |
| } |
| $proposal->statuses[] = new ProposalStatus($row); |
| } |
| |
| // FIXME Refactor redundant code |
| if ($forge = json_decode(@file_get_contents('http://projects.eclipse.org/json/proposals/all'), true)) { |
| foreach($forge as $row) { |
| $id = $row['Id']; |
| if (isset($proposals[$id])) { |
| $proposal = $proposals[$id]; |
| } else { |
| $proposal = new Proposal($row); |
| $proposals[$id] = $proposal; |
| } |
| $proposal->statuses[] = new ProposalStatus($row); |
| } |
| } |
| |
| if ($forge = json_decode(@file_get_contents('http://www.locationtech.org/json/proposals/all'), true)) { |
| foreach($forge as $row) { |
| $id = $row['Id']; |
| if (isset($proposals[$id])) { |
| $proposal = $proposals[$id]; |
| } else { |
| $proposal = new Proposal($row); |
| $proposals[$id] = $proposal; |
| } |
| $proposal->statuses[] = new ProposalStatus($row); |
| } |
| } |
| |
| if ($forge = json_decode(@file_get_contents('http://www.polarsys.org/json/proposals/all'), true)) { |
| foreach($forge as $row) { |
| $id = $row['Id']; |
| $proposal = new Proposal($row); |
| $proposal->statuses[] = new ProposalStatus($row); |
| $proposals[$id] = $proposal; |
| } |
| } |
| |
| return $proposals; |
| } |
| |
| |
| /** |
| * This function returns the proposal corresponding to the project |
| * with the provided id. |
| * |
| * Requires that the $App variable be defined. |
| * |
| * @param string $id A project id. |
| */ |
| function getProposalForProject($id) { |
| if (!isValidProjectId($id)) return; |
| |
| global $App; |
| |
| $sql = " |
| SELECT |
| r.id as Id, |
| r.ProjectName, r.ProjectId, |
| ProjectURL, ProposalURL, SlidesURL, IPLogURL, BugNumber, ReviewDate, |
| ReviewName, ProposalName, |
| s.status as Status, s.value as Date |
| FROM |
| ProjectReviews as r |
| join ProjectReviewStatus as s on (r.id = s.id and s.value != 0) |
| WHERE |
| trim(r.ProposalURL) != '' |
| AND r.ProjectId = '$id' |
| ORDER BY Date desc"; |
| |
| $result = $App->foundation_sql($sql); |
| $proposal = null; |
| while($row = mysql_fetch_assoc($result)) { |
| if (!$proposal) $proposal = new Proposal($row); |
| $proposal->statuses[] = new ProposalStatus($row); |
| } |
| |
| return $proposal; |
| } |
| |
| |
| function getProposals() { |
| $proposals = array(); |
| |
| foreach(getForges() as $forge) { |
| $url = "$forge/json/proposals"; |
| $json = getUrlContents($url); |
| if ($list = json_decode($json, true)) { |
| foreach($list as $row) { |
| $proposals[] = new Proposal($row); |
| } |
| } |
| } |
| |
| usort($proposals, 'proposals_sortByDate'); |
| |
| return $proposals; |
| } |
| |
| |
| function proposals_sortByDate($a, $b) { |
| $aDate = $a->getDate(); |
| $bDate = $b->getDate(); |
| |
| if ($aDate < $bDate) return 1; |
| if ($aDate > $bDate) return -1; |
| return 0; |
| } |
| |
| ?> |