blob: ccf69031eb0a1f912292c78dc1a39aa870f95c62 [file] [log] [blame]
<?php
/*******************************************************************************
* Copyright (c) 2010 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
*******************************************************************************/
require_once(dirname(__FILE__) . "/Project.class.php");
require_once(dirname(__FILE__) . "/images.inc");
require_once(dirname(__FILE__) . "/debug.php");
trace_file_info(__FILE__);
class ProjectSummary {
/**
* @var Project
*/
var $project;
function __construct($project) {
$this->project = $project;
}
/**
* Answer some HTML describing the repositories.
*
* @return string
*/
function getSourceRepositoriesHtml($max = 25) {
$repositories = $this->project->getSourceRepositories();
if (!$repositories) return null;
$html = "<p>Eclipse projects store all of their source code in public revision control systems.</p>";
$html .= "<ul>";
foreach($repositories as $repository) {
if ($max-- <= 0) {
$html .= "<li>...</li>";
break;
}
$name = $repository->getName();
$link = $repository->getLink();
$type = $repository->getType();
$item = "<a href=\"$link\">$name</a> ($type)";
if ($type == 'git') {
$git = $repository->getGitUrl();
$item .= "<ul>
<li>Clone: $git</li>
<li><a href=\"https://github.com/eclipse/$name\">Clone on GitHub</a></li>
</ul>";
} else {
}
$html .= "<li>$item</li>";
}
$html .= "</ul>";
return $html;
}
function getUpdateSiteHtml() {
$site = $this->project->getUpdateSiteUrl();
if (!$site) return null;
$html = "<p>This project maintains a p2 repository of binary artifacts.
Copy and paste this link into the &quot;Install New Software&quot; dialog
to install this project's software.</p><p style=\"text-align:center\"><code>$site</code></p>
<p>Note that the repository link will not necessarily display anything meaningful
in your browser.</p>";
return $html;
}
/**
* Answer some HTML describing the releases.
*
* @param int $count (Optional) the maximum number of releases to show (5 by default).
*/
function getReleasesHtml($count = 10) {
if (!$this->project->hasReleases()) return;
/* @var App */
global $App;
$releases = array_reverse($this->project->getReleases());
$html = "<table>";
foreach($releases as $release) {
/* @var $release Release */
if($count-- <= 0) break;
$name = $release->getName();
$status = $release->getStatus();
$download = $release->getDownload();
$plan = $release->getPlan();
$noteworthy = $release->getNoteworthyUrl();
$date = $App->getFormattedDate($release->getDate(), 'short');
$title = $name;
if ($release->getDownload()) $title = "<a href=\"$download\">$title</a>";
if ($plan) {
// if the URL ends with .xml, assume a standard format plan and provide a
// URL that redirects to the standard plan formatter. Otherwise, just use
// the provided URL.
$planurl = preg_match('/\\.xml$/', $plan) ? "/projects/project-plan.php?planurl=$plan" : $plan;
$plan = "<a href=\"$planurl\"><img title=\"Plan for $name\" src=\"http://dev.eclipse.org/small_icons/mimetypes/x-office-presentation.png\"/></a>";
}
$noteworthy = $noteworthy ? "<a href=\"$noteworthy\"><img title=\"New and Noteworthy for $name\" src=\"http://dev.eclipse.org/small_icons/mimetypes/x-office-document.png\"/></a>" : "";
$html .= "<tr><td>$date</td><td>$title $status $plan $noteworthy</td></tr>";
}
$html .= "</table>";
return $html;
}
function getForumsHtml() {
if (!$this->project->getNewsgroups()) return null;
$newsgroups = $this->project->getNewsgroups();
usort($newsgroups, array('ProjectSummary','_sortProjectForums'));
$html = "<p>This project uses the following <a href=\"/forums\">forums</a>:</p>";
$html .= "<ul>";
foreach ($newsgroups as $newsgroup) {
/* @var $newsgroup Newsgroup */
$name = $newsgroup->getName();
if (!$name) continue;
$forumUrl = "http://www.eclipse.org/forums/$name";
$info = "<a href=\"$forumUrl\">$name</a> ";
if ($newsgroup->getType() == 'main') $info .= ' (main)';
$description = $newsgroup->getDescription();
if ($description) $info .= "<br/>$description";
$html .= "<li>$info</li>";
}
$html .= "</ul>";
return $html;
}
/**
* This function is used to sort both newsgroups and mailing lists.
* Any entry designated as 'main' are at the top. The rest are listed
* below. Entries in the respective groups are sorted by name.
*
* @internal
* @param Newsgroup $a
* @param newsgroup $b
* @return number
*/
function _sortProjectForums($a, $b) {
$typeA = $a->getType();
$typeB = $b->getType();
if (($typeA == 'main') && ($typeB != 'main')) return -1;
if (($typeA != 'main') && ($typeB == 'main')) return 1;
return strcasecmp($a->getName(), $b->getName());
}
function getCommittersHtml() {
require_once 'Committer.class.php';
$committers = getCommittersForProject($this->project->getId());
$html = "<h6>Project Leads</h6><ul>";
foreach ($committers as $committer) {
if (!$committer->isProjectLead($this->project->getId())) continue;
$name = htmlentities("$committer->$firstName $committer->lastName");
$html .= "<li>$name</li>";
}
$html .= "</ul>";
$html .= "</ul>";
$html .= "<h6>Committers</h6><ul>";
foreach ($committers as $committer) {
$name = htmlentities("$committer->$firstName $committer->lastName");
$html .= "<li>$name</li>";
}
$html .= "</ul>";
return $html;
}
function getMailingListsHtml() {
$mailinglists = $this->project->getMailingLists();
if (!$mailinglists) return;
usort($mailinglists, array('ProjectSummary','_sortProjectForums'));
$html = "<p>This project uses the following <a href=\"/mail\">mailing lists</a>:</p>";
$html .= "<ul>";
$hasDevList = false;
foreach ($mailinglists as $list) {
$name = $list->getName();
$listUrl = "http://dev.eclipse.org/mailman/listinfo/$name";
$info = "<a href=\"$listUrl\">$name</a> ";
if ($list->getType() == 'main') $info .= ' (main)';
$description = $list->getDescription();
if ($description) $info .= "<br/>$description";
if (preg_match('/\-(dev|pmc)$/', $name)) $hasDevList = true;
$html .= "<li>$info</li>";
}
$html .= "</ul>";
if ($hasDevList)
$html .= "<p>Note that -dev and -pmc lists are intended for project-related
communications among project developers.</p>";
return $html;
}
function getCommitsActivityHtml($width=800, $height=100) {
if (!$this->project->getCommitActivity()) return null;
$this->requiresGoogleChartsSupport();
global $App;
$divName = 'CommitActivityDiv';
$chartJS = $this->getCommitActivityJS($divName, $width, $height);
$App->AddExtraHtmlHeader("<script type=\"text/javascript\">$chartJS</script>");
return "<div id=\"$divName\"></div>";
}
/**
* Private - Generate the JavaScript code required to render the
* commit activity pie chart using Google Chart APIs.
*
* THIS METHOD IS NOT PUBLIC API.
*
* @internal
* @param string $divName Name of the div that contains the chart.
* @param int $width Width of the chart (defaults to 800px)
* @param int $height Height of the chart (defaults to 100px).
*
* @return string
*/
function getCommitActivityJS($divName, $width=800, $height=100) {
$js = "google.load(\"visualization\", \"1\", {packages:[\"corechart\"]});";
$js .= "google.setOnLoadCallback(drawChart_$divName);";
$js .= "function drawChart_$divName() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Period');
data.addColumn('number', 'Commits');";
$activity = $this->project->getCommitActivity();
$range = $this->getPeriodRange(array_keys($activity));
$total = count($range);
$js .= "data.addRows($total);";
$index = 0;
foreach ($range as $period => $label) {
$count = isset($activity[$period]) ? $activity[$period] : 0;
$js .= "data.setValue($index, 0, '$label');";
$js .= "data.setValue($index, 1, $count);";
$index++;
}
$js .= "var chart = new google.visualization.ColumnChart(document.getElementById('$divName'));";
$js .= "chart.draw(data,{titlePosition:\"none\",width:$width, height:$height,hAxis: {title: \"Period\"},legend: \"none\"});";
$js .= "}";
return $js;
}
function getPeriodRange($periods) {
sort($periods);
$min = reset($periods);
$max = end($periods);
// TODO deal with malformed data.
preg_match('/^(\d\d\d\d)(\d\d)$/', $min, $matches);
$year = $matches[1];
$month = $matches[2];
$range = array();
while (true) {
$period = (int)sprintf('%04d%02d', $year, $month);
$date = date("F Y", strtotime("$year-$month-01"));
$range[$period] = $date;
if ($period == $max) break;
if (++$month > 12) {
$year++;
$month = 1;
}
}
return $range;
}
function requiresGoogleChartsSupport() {
require_once dirname(__FILE__) . '/util/google-charts.php';
}
/**
* Return HTML that provides a "company commit activity" pie chart
* using the Google Chart APIs. Note that calling this method will
* automatically add the necessary JavaScript libraries to the page.
*
* Only the last three months of activity is reported.
*
* @see Project#getCompanyCommitActivity();
*
* @return string|null
*/
function getCompanyCommitActivityHtml($width=450, $height=300) {
if (!$this->project->getCompanyCommitActivity()) return null;
$this->requiresGoogleChartsSupport();
global $App;
$divName = 'CompanyCommitDiv';
$chartJS = $this->getCompanyCommitActivityJS($divName, $width, $height);
$App->AddExtraHtmlHeader("<script type=\"text/javascript\">$chartJS</script>");
return "<div id=\"$divName\"></div>";
}
function getCommitterCommitActivityHtml($width=450, $height=300) {
if (!$this->project->getCommitterCommitActivity()) return null;
$this->requiresGoogleChartsSupport();
global $App;
$divName = 'CommitterCommitDiv';
$chartJS = $this->getCommitterCommitActivityJS($divName, $width, $height);
$App->AddExtraHtmlHeader("<script type=\"text/javascript\">$chartJS</script>");
return "<div id=\"$divName\"></div>";
}
/**
* Private - Generate the JavaScript code required to render the
* commit activity pie chart using Google Chart APIs.
*
* THIS METHOD IS NOT PUBLIC API.
*
* @internal
* @param string $divName Name of the div that contains the chart.
* @param int $width Width of the chart (defaults to 450px)
* @param int $height Height of the chart (defaults to 300px).
*
* @return string
*/
function getCompanyCommitActivityJS($divName, $width=450, $height=300) {
$js = "google.load(\"visualization\", \"1\", {packages:[\"corechart\"]});";
$js .= "google.setOnLoadCallback(drawChart_$divName);";
$js .= "function drawChart_$divName() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Company');
data.addColumn('number', 'Commits');";
$activity = $this->project->getCompanyCommitActivity();
$total = count($activity);
$js .= "data.addRows($total);";
$index = 0;
foreach ($activity as $company => $count) {
$js .= "data.setValue($index, 0, '$company');";
$js .= "data.setValue($index, 1, $count);";
$index++;
}
$js .= "var chart = new google.visualization.PieChart(document.getElementById('$divName'));";
$js .= "chart.draw(data, {titlePosition:\"none\",width:$width,height:$height});";
$js .= "}";
return $js;
}
/**
* Private - Generate the JavaScript code required to render the
* commit activity pie chart using Google Chart APIs.
*
* THIS METHOD IS NOT PUBLIC API.
*
* @internal
* @param string $divName Name of the div that contains the chart.
* @param int $width Width of the chart (defaults to 450px)
* @param int $height Height of the chart (defaults to 300px).
*
* @return string
*/
function getCommitterCommitActivityJS($divName, $width=450, $height=300) {
// TODO Refactoring opportunity
require_once(dirname(__FILE__) . "/Committer.class.php");
$js = "google.load(\"visualization\", \"1\", {packages:[\"corechart\"]});";
$js .= "google.setOnLoadCallback(drawChart_$divName);";
$js .= "function drawChart_$divName() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Committers');
data.addColumn('number', 'Commits');";
$activity = $this->project->getCommitterCommitActivity();
$names = getCommitterNames(array_keys($activity));
$total = count($activity);
$js .= "data.addRows($total);";
$index = 0;
foreach ($activity as $committer => $count) {
$name = isset($names[$committer]) ? utf8_encode($names[$committer]) : $committer;
$js .= "data.setValue($index, 0, '$name');";
$js .= "data.setValue($index, 1, $count);";
$index++;
}
$js .= "var chart = new google.visualization.PieChart(document.getElementById('$divName'));";
$js .= "chart.draw(data, {titlePosition:\"none\",width:$width,height:$height});";
$js .= "}";
return $js;
}
function renderReleases() {
if (!$this->project->getReleases()) return;
// TODO What do we do if the preview and full are the same length?
$preview = $this->getReleasesHtml(5);
$full = $this->getReleasesHtml(1000);
// TODO Need to better understand function scope in JavaScript.
// i.e. what happens if I include this twice on the same page?
$html = "
<script language=\"JavaScript\">
function ShowFullReleases() {
document.getElementById('previewReleases').style.display = 'none';
document.getElementById('fullReleases').style.display = '';
}
function ShowPreviewReleases() {
document.getElementById('fullReleases').style.display = 'none';
document.getElementById('previewReleases').style.display = '';
}
</script>
<div id=\"previewReleases\">
$preview
<p><a href=\"javascript:ShowFullReleases();\">more</a></p>
</div>
<div id=\"fullReleases\"style=\"display:none\">
$full
<p><a href=\"javascript:ShowPreviewReleases();\">less</a></p>
</div>";
$this->renderBox('Releases', "http://dev.eclipse.org/large_icons/mimetypes/package-x-generic.png", $html);
}
function getReviewsHtml($max = 10) {
global $App;
$reviews = $this->project->getReviews();
if (!$reviews) return;
$html = "<p><table>\n";
$count = 0;
foreach($reviews as $review) {
/* @var $release Release */
if($count++ >= $max) break;
$projectName = $review->getProjectName();
$reviewName = $review->getReviewName();
$documentUrl = $review->getSlidesUrl();
$date = $App->getFormattedDate($review->getReviewDate(), 'short');
$date = str_replace(' ', '&nbsp;', $date);
$iplogUrl = $review->getIplogUrl();
$title = "$projectName $reviewName Review";
if ($documentUrl) $title = "<a href=\"$documentUrl\">$title</a>";
if ($review->isWithdrawn()) $title = "<span style=\"color:grey\">$title (withdrawn)</span>";
$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 ($review->isSuccessful())
$icons .= "<img style=\"vertical-align:top\" title=\"Review Successful\" src=\"/projects/images/ok.gif\">";
if ($review->isUnsuccessful())
$icons .= "<img style=\"vertical-align:top\" title=\"Review Unsuccessful\" src=\"http://dev.eclipse.org/small_icons/actions/process-stop.png\">";
$html .= "<tr><td>$date</td><td>$title $icons</td></tr>\n";
}
$html .= "</table></p>\n";
return $html;
}
function getCommitsActivityHomeItem() {
$activity = $this->getCommitsActivityHtml(450, 200);
if (!$activity) return null;
return "<div class=\"homeitem\">
<h3>Overall Commit Activity</h3>
<p>Commits on this project (lifetime).</p>
$activity
</div>";
}
function getCommitterCommitsActivityHomeItem() {
$activity = $this->getCommitterCommitActivityHtml(450, 300);
if (!$activity) return null;
return "<div class=\"homeitem\">
<h3>Committer Activity</h3>
<p>Commits on this project by committers over the last three months.</p>
$activity
</div>";
}
function getCompanyCommitsActivityHomeItem() {
$activity = $this->getCompanyCommitActivityHtml(450, 300);
if (!$activity) return null;
return "<div class=\"homeitem\">
<h3>Organization Commit Activity</h3>
<p>Commits on this project by supporting organization over the last three months.</p>
$activity
</div>";
}
function getSourceRepositoriesHomeItem() {
$html = $this->getSourceRepositoriesHtml();
if (!$html) return null;
return "<div class=\"homeitem\">
<h3>Source Repositories</h3>
$html
</div>";
}
function getUpdateSiteHomeItem() {
$html = $this->getUpdateSiteHtml();
if (!$html) return null;
return "<div class=\"homeitem\">
<h3>Software Repository</h3>
$html
</div>";
}
function getReleasesHomeItem($max = 5) {
$html = $this->getReleasesHtml($max);
if (!$html) return null;
return "<div class=\"homeitem\">
<h3>Releases</h3>
$html
</div>";
}
function getReviewsHomeItem($max = 10) {
$html = $this->getReviewsHtml($max);
if (!$html) return null;
return "<div class=\"homeitem\">
<h3>Reviews</h3>
$html
</div>";
}
function getCommunicationHomeItem() {
$html = $this->getForumsHtml() . $this->getMailingListsHtml();
if (!$html) return null;
return "<div class=\"homeitem\">
<h3>Communication</h3>
$html
</div>";
}
function getIncubationSideItem() {
if (!$this->project->isInIncubationPhase()) return '';
global $images;
$headerImg = $this->project->isInIncubationConformingPhase() ?
$images->incubation_conforming_small :
$images->incubation_nonconforming_small;
return "<div class=\"sideitem\">
<h6><img src=\"$headerImg\" align=\"right\"/>Incubation</h6>
<div style=\"text-align:center\"><a href=\"/projects/what-is-incubation.php\"><img
align=\"center\" src=\"$images->incubation_large\"
border=\"0\" alt=\"Incubation\" /></a></div>
</div>";
}
function getCommittersSideItem() {
global $images;
require_once 'Committer.class.php';
/*
* "Require once" the script that adds the necessary JavaScript
* (including JQuery) to the header. By using require_once, we
* don't have to worry about whether or not we've already done
* this.
*/
require_once dirname(__FILE__) . '/util/summary.php';
$id = $this->project->getId();
$people = $this->project->getPeople();
$pmcLeads = array();
$pmcMembers = array();
$leads = array();
$committers = array();
$emeritus = array();
$mentors = array();
$organizations = array();
foreach($people as $person) {
if ($person->isCommitter($id)) $committers[] = $person;
if ($person->isEmeritus($id)) $emeritus[] = $person;
if ($person->isProjectLead($id)) $leads[] = $person;
if ($person->isPmcLead($id)) $pmcLeads[] = $person;
else if ($person->isPmcMember($id)) $pmcMembers[] = $person;
if ($person->isMentor($id)) $mentors[] = $person;
if ($person->isActive($id)) {
$organization = $person->getOrganization();
if ($organization && $organization->isMember()) {
$organizations[$organization->getId()] = $organization;
}
}
}
$html = "<div class=\"sideitem\">";
$this->dumpCommittersSideItem($html, "PMC Leads", null, $images->pl_large, $pmcLeads);
$this->dumpCommittersSideItem($html, "PMC Members", null, $images->pl_large, $pmcMembers);
$this->dumpCommittersSideItem($html, "Project Leads", null, $images->pl_large, $leads);
$this->dumpCommittersSideItem($html, "Committers", "Current project committers", $images->committers_large, $committers);
$this->dumpCommittersSideItem($html, "Committers Emeritus", "Inactive committers who have made significant contributions to the project", $images->emeritus_large, $emeritus);
if ($this->project->isInIncubationPhase()) $this->dumpCommittersSideItem($html, "Mentors", "Mentors from the Architecture Council provide guidance for this project.", $images->mentor_large, $mentors);
$this->dumpCompaniesSideItem($html, $organizations);
$html .= "</div>";
return $html;
}
/* private */ function dumpCommittersSideItem(&$html, $title, $description, $image, $committers) {
if (!$committers) return;
global $images;
$projectId = $this->project->getId();
$html .= "<img src=\"$image\" align=\"right\"/><h6>$title</h6>";
// TODO Sort out CSS issues
//if ($description) $html .= "<p>$description</p>";
$html .= "<ul>";
foreach ($committers as $committer) {
$committerId = $committer->id;
$name = "$committer->firstName $committer->lastName";
$name = htmlentities($name);
$commitsUrl = "http://dash.eclipse.org/dash/commits/web-app/summary.cgi?type=y&month=x&project=$projectId&login=$committerId";
if ($committer->isActive($projectId)) $name = "<b>$name</b>";
$actions = '';
if ($committer->hasCommits($projectId))
$actions .= "<a href=\"$commitsUrl\"><img src=\"$images->commits_small\" title=\"Commits\" alt=\"[commits]\ target=\"_dash\"/></a>";
$html .= "<li class=\"actions_holder\">$name <span class=\"actions\">$actions</span></li>";
}
$html .= "</ul>";
}
/* private */ function dumpCompaniesSideItem(&$html, $companies) {
if (!$companies) return;
global $images;
$html .= "<img src=\"$images->company_large\" align=\"right\"/><h6>Supporting Organizations</h6>";
foreach ($companies as $id => $organization) {
$name = $organization->getName();
$src = "http://www.eclipse.org/membership/scripts/get_image.php?id=$id&size=small";
$link = "http://www.eclipse.org/membership/showMember.php?member_id=$id";
$html .= "<div style=\"text-align:center;margin-bottom:20px\">";
$html .= "<a href=\"$link\"><img src=\"$src\" align=\"center\" alt=\"$name\" title=\"$name\" /></a>";
$html .= "</div>";
}
}
}
?>