/* * Copyright 2012 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gitblit.wicket.pages; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.wicket.Component; import org.apache.wicket.PageParameters; import org.apache.wicket.behavior.HeaderContributor; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.link.ExternalLink; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.SyndicationServlet; import com.gitblit.models.Activity; import com.gitblit.models.Metric; import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; import com.gitblit.utils.ActivityUtils; import com.gitblit.utils.MarkdownUtils; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.GitblitRedirectException; import com.gitblit.wicket.PageRegistration; import com.gitblit.wicket.PageRegistration.DropDownMenuItem; import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.charting.GoogleChart; import com.gitblit.wicket.charting.GoogleCharts; import com.gitblit.wicket.charting.GoogleLineChart; import com.gitblit.wicket.charting.GooglePieChart; import com.gitblit.wicket.panels.ActivityPanel; import com.gitblit.wicket.panels.ProjectRepositoryPanel; public class ProjectPage extends RootPage { List projectModels = new ArrayList(); public ProjectPage() { super(); throw new GitblitRedirectException(GitBlitWebApp.get().getHomePage()); } public ProjectPage(PageParameters params) { super(params); setup(params); } @Override protected boolean reusePageParameters() { return true; } private void setup(PageParameters params) { setupPage("", ""); // check to see if we should display a login message boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true); if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) { authenticationError("Please login"); return; } String projectName = WicketUtils.getProjectName(params); if (StringUtils.isEmpty(projectName)) { throw new GitblitRedirectException(GitBlitWebApp.get().getHomePage()); } ProjectModel project = getProjectModel(projectName); if (project == null) { throw new GitblitRedirectException(GitBlitWebApp.get().getHomePage()); } add(new Label("projectTitle", project.getDisplayName())); add(new Label("projectDescription", project.description)); String feedLink = SyndicationServlet.asLink(getRequest().getRelativePathPrefixToContextRoot(), projectName, null, 0); add(new ExternalLink("syndication", feedLink)); add(WicketUtils.syndicationDiscoveryLink(SyndicationServlet.getTitle(project.getDisplayName(), null), feedLink)); // project markdown message String pmessage = transformMarkdown(project.projectMarkdown); Component projectMessage = new Label("projectMessage", pmessage) .setEscapeModelStrings(false).setVisible(pmessage.length() > 0); add(projectMessage); // markdown message above repositories list String rmessage = transformMarkdown(project.repositoriesMarkdown); Component repositoriesMessage = new Label("repositoriesMessage", rmessage) .setEscapeModelStrings(false).setVisible(rmessage.length() > 0); add(repositoriesMessage); List repositories = getRepositories(params); Collections.sort(repositories, new Comparator() { @Override public int compare(RepositoryModel o1, RepositoryModel o2) { // reverse-chronological sort return o2.lastChange.compareTo(o1.lastChange); } }); final ListDataProvider dp = new ListDataProvider(repositories); DataView dataView = new DataView("repositoryList", dp) { private static final long serialVersionUID = 1L; public void populateItem(final Item item) { final RepositoryModel entry = item.getModelObject(); ProjectRepositoryPanel row = new ProjectRepositoryPanel("repository", getLocalizer(), this, showAdmin, entry, getAccessRestrictions()); item.add(row); } }; add(dataView); // project activity // parameters int daysBack = WicketUtils.getDaysBack(params); if (daysBack < 1) { daysBack = 14; } String objectId = WicketUtils.getObject(params); List recentActivity = ActivityUtils.getRecentActivity(repositories, daysBack, objectId, getTimeZone()); if (recentActivity.size() == 0) { // no activity, skip graphs and activity panel add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityNone"), daysBack))); add(new Label("activityPanel")); } else { // calculate total commits and total authors int totalCommits = 0; Set uniqueAuthors = new HashSet(); for (Activity activity : recentActivity) { totalCommits += activity.getCommitCount(); uniqueAuthors.addAll(activity.getAuthorMetrics().keySet()); } int totalAuthors = uniqueAuthors.size(); // add the subheader with stat numbers add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityStats"), daysBack, totalCommits, totalAuthors))); // create the activity charts GoogleCharts charts = createCharts(recentActivity); add(new HeaderContributor(charts)); // add activity panel add(new ActivityPanel("activityPanel", recentActivity)); } } /** * Creates the daily activity line chart, the active repositories pie chart, * and the active authors pie chart * * @param recentActivity * @return */ private GoogleCharts createCharts(List recentActivity) { // activity metrics Map repositoryMetrics = new HashMap(); Map authorMetrics = new HashMap(); // aggregate repository and author metrics for (Activity activity : recentActivity) { // aggregate author metrics for (Map.Entry entry : activity.getAuthorMetrics().entrySet()) { String author = entry.getKey(); if (!authorMetrics.containsKey(author)) { authorMetrics.put(author, new Metric(author)); } authorMetrics.get(author).count += entry.getValue().count; } // aggregate repository metrics for (Map.Entry entry : activity.getRepositoryMetrics().entrySet()) { String repository = StringUtils.stripDotGit(entry.getKey()); if (!repositoryMetrics.containsKey(repository)) { repositoryMetrics.put(repository, new Metric(repository)); } repositoryMetrics.get(repository).count += entry.getValue().count; } } // build google charts int w = 310; int h = 150; GoogleCharts charts = new GoogleCharts(); // sort in reverse-chronological order and then reverse that Collections.sort(recentActivity); Collections.reverse(recentActivity); // daily line chart GoogleChart chart = new GoogleLineChart("chartDaily", getString("gb.dailyActivity"), "day", getString("gb.commits")); SimpleDateFormat df = new SimpleDateFormat("MMM dd"); df.setTimeZone(getTimeZone()); for (Activity metric : recentActivity) { chart.addValue(df.format(metric.startDate), metric.getCommitCount()); } chart.setWidth(w); chart.setHeight(h); charts.addChart(chart); // active repositories pie chart chart = new GooglePieChart("chartRepositories", getString("gb.activeRepositories"), getString("gb.repository"), getString("gb.commits")); for (Metric metric : repositoryMetrics.values()) { chart.addValue(metric.name, metric.count); } chart.setWidth(w); chart.setHeight(h); charts.addChart(chart); // active authors pie chart chart = new GooglePieChart("chartAuthors", getString("gb.activeAuthors"), getString("gb.author"), getString("gb.commits")); for (Metric metric : authorMetrics.values()) { chart.addValue(metric.name, metric.count); } chart.setWidth(w); chart.setHeight(h); charts.addChart(chart); return charts; } @Override protected void addDropDownMenus(List pages) { PageParameters params = getPageParameters(); DropDownMenuRegistration projects = new DropDownMenuRegistration("gb.projects", ProjectPage.class); projects.menuItems.addAll(getProjectsMenu()); pages.add(0, projects); DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters", ProjectPage.class); // preserve time filter option on repository choices menu.menuItems.addAll(getRepositoryFilterItems(params)); // preserve repository filter option on time choices menu.menuItems.addAll(getTimeFilterItems(params)); if (menu.menuItems.size() > 0) { // Reset Filter menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null)); } pages.add(menu); } @Override protected List getProjectModels() { if (projectModels.isEmpty()) { List repositories = getRepositoryModels(); List projects = GitBlit.self().getProjectModels(repositories, false); projectModels.addAll(projects); } return projectModels; } private ProjectModel getProjectModel(String name) { for (ProjectModel project : getProjectModels()) { if (name.equalsIgnoreCase(project.name)) { return project; } } return null; } protected List getProjectsMenu() { List menu = new ArrayList(); List projects = new ArrayList(); for (ProjectModel model : getProjectModels()) { if (!model.isUserProject()) { projects.add(model); } } int maxProjects = 15; boolean showAllProjects = projects.size() > maxProjects; if (showAllProjects) { // sort by last changed Collections.sort(projects, new Comparator() { @Override public int compare(ProjectModel o1, ProjectModel o2) { return o2.lastChange.compareTo(o1.lastChange); } }); // take most recent subset projects = projects.subList(0, maxProjects); // sort those by name Collections.sort(projects); } for (ProjectModel project : projects) { menu.add(new DropDownMenuItem(project.getDisplayName(), "p", project.name)); } if (showAllProjects) { menu.add(new DropDownMenuItem()); menu.add(new DropDownMenuItem("all projects", null, null)); } return menu; } private String transformMarkdown(String markdown) { String message = ""; if (!StringUtils.isEmpty(markdown)) { // Read user-supplied message try { message = MarkdownUtils.transformMarkdown(markdown); } catch (Throwable t) { message = getString("gb.failedToRead") + " " + markdown; warn(message, t); } } return message; } }