James Moger
2013-11-13 c44dd099a432094a12131cf60dfc8a19f5aa8101
src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
@@ -19,6 +19,7 @@
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -28,6 +29,7 @@
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.TextField;
@@ -35,15 +37,17 @@
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.protocol.http.RequestUtils;
import org.apache.wicket.request.target.basic.RedirectRequestTarget;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.Constants;
import com.gitblit.GitBlit;
import com.gitblit.GitBlitException;
import com.gitblit.Keys;
import com.gitblit.PagesServlet;
import com.gitblit.SyndicationServlet;
@@ -52,10 +56,13 @@
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.SubmoduleModel;
import com.gitblit.models.UserModel;
import com.gitblit.models.UserRepositoryPreferences;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.DeepCopier;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.RefLogUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.utils.TicgitUtils;
import com.gitblit.wicket.CacheControl;
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.PageRegistration;
import com.gitblit.wicket.PageRegistration.OtherPageLink;
@@ -65,22 +72,26 @@
import com.gitblit.wicket.panels.NavigationPanel;
import com.gitblit.wicket.panels.RefsPanel;
public abstract class RepositoryPage extends BasePage {
public abstract class RepositoryPage extends RootPage {
   protected final Logger logger = LoggerFactory.getLogger(getClass());
   private final String PARAM_STAR = "star";
   protected final String projectName;
   protected final String repositoryName;
   protected final String objectId;
   private transient Repository r;
   private RepositoryModel m;
   private Map<String, SubmoduleModel> submodules;
   private final Map<String, PageRegistration> registeredPages;
   private boolean showAdmin;
   private boolean isOwner;
   public RepositoryPage(PageParameters params) {
      super(params);
      repositoryName = WicketUtils.getRepositoryName(params);
@@ -91,7 +102,7 @@
         projectName = root;
      }
      objectId = WicketUtils.getObject(params);
      if (StringUtils.isEmpty(repositoryName)) {
         error(MessageFormat.format(getString("gb.repositoryNotSpecifiedFor"), getPageName()), true);
      }
@@ -99,7 +110,7 @@
      if (!getRepositoryModel().hasCommits) {
         setResponsePage(EmptyRepositoryPage.class, params);
      }
      if (getRepositoryModel().isCollectingGarbage) {
         error(MessageFormat.format(getString("gb.busyCollectingGarbage"), getRepositoryModel().name), true);
      }
@@ -120,12 +131,28 @@
         }
      }
      if (params.containsKey(PARAM_STAR)) {
         // set starred state
         boolean star = params.getBoolean(PARAM_STAR);
         UserModel user = GitBlitWebSession.get().getUser();
         if (user != null && user.isAuthenticated) {
            UserRepositoryPreferences prefs = user.getPreferences().getRepositoryPreferences(getRepositoryModel().name);
            prefs.starred = star;
            try {
               GitBlit.self().updateUserModel(user.username, user, false);
            } catch (GitBlitException e) {
               logger.error("Failed to update user " + user.username, e);
               error(getString("gb.failedToUpdateUser"), false);
            }
         }
      }
      // register the available page links for this page and user
      registeredPages = registerPages();
      // standard page links
      List<PageRegistration> pages = new ArrayList<PageRegistration>(registeredPages.values());
      NavigationPanel navigationPanel = new NavigationPanel("navPanel", getClass(), pages);
      NavigationPanel navigationPanel = new NavigationPanel("repositoryNavPanel", getRepoNavPageClass(), pages);
      add(navigationPanel);
      add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()
@@ -140,6 +167,15 @@
      setStatelessHint(true);
   }
   @Override
   protected Class<? extends BasePage> getRootNavPageClass() {
      return RepositoriesPage.class;
   }
   protected Class<? extends BasePage> getRepoNavPageClass() {
      return getClass();
   }
   private Map<String, PageRegistration> registerPages() {
      PageParameters params = null;
      if (!StringUtils.isEmpty(repositoryName)) {
@@ -147,31 +183,32 @@
      }
      Map<String, PageRegistration> pages = new LinkedHashMap<String, PageRegistration>();
      // standard links
      pages.put("repositories", new PageRegistration("gb.repositories", RepositoriesPage.class));
      pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
      pages.put("log", new PageRegistration("gb.log", LogPage.class, params));
      pages.put("branches", new PageRegistration("gb.branches", BranchesPage.class, params));
      pages.put("tags", new PageRegistration("gb.tags", TagsPage.class, params));
      pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
      if (GitBlit.getBoolean(Keys.web.allowForking, true)) {
         pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));
      }
      // conditional links
      Repository r = getRepository();
      RepositoryModel model = getRepositoryModel();
      // per-repository extra page links
      if (model.useTickets && TicgitUtils.getTicketsBranch(r) != null) {
         pages.put("tickets", new PageRegistration("gb.tickets", TicketsPage.class, params));
      // standard links
      if (RefLogUtils.getRefLogBranch(r) == null) {
         pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
      } else {
         pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
//         pages.put("overview", new PageRegistration("gb.overview", OverviewPage.class, params));
         pages.put("reflog", new PageRegistration("gb.reflog", ReflogPage.class, params));
      }
      pages.put("commits", new PageRegistration("gb.commits", LogPage.class, params));
      pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
      pages.put("compare", new PageRegistration("gb.compare", ComparePage.class, params, true));
      if (GitBlit.getBoolean(Keys.web.allowForking, true)) {
         pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params, true));
      }
      // conditional links
      // per-repository extra page links
      if (model.useDocs) {
         pages.put("docs", new PageRegistration("gb.docs", DocsPage.class, params));
         pages.put("docs", new PageRegistration("gb.docs", DocsPage.class, params, true));
      }
      if (JGitUtils.getPagesBranch(r) != null) {
         OtherPageLink pagesLink = new OtherPageLink("gb.pages", PagesServlet.asLink(
               getRequest().getRelativePathPrefixToContextRoot(), repositoryName, null));
               getRequest().getRelativePathPrefixToContextRoot(), repositoryName, null), true);
         pages.put("pages", pagesLink);
      }
@@ -186,12 +223,9 @@
      isOwner = GitBlitWebSession.get().isLoggedIn()
            && (model.isOwner(GitBlitWebSession.get()
                  .getUsername()));
      if (showAdmin || isOwner) {
         pages.put("edit", new PageRegistration("gb.edit", EditRepositoryPage.class, params));
      }
      return pages;
   }
   protected boolean allowForkControls() {
      return GitBlit.getBoolean(Keys.web.allowForking, true);
   }
@@ -209,7 +243,7 @@
         add(new LinkPanel("projectTitle", null, project.name,
               ProjectPage.class, WicketUtils.newProjectParameter(project.name)));
      }
      String name = StringUtils.stripDotGit(repositoryName);
      if (!StringUtils.isEmpty(projectName) && name.startsWith(projectName)) {
         name = name.substring(projectName.length() + 1);
@@ -217,7 +251,7 @@
      add(new LinkPanel("repositoryName", null, name, SummaryPage.class,
            WicketUtils.newRepositoryParameter(repositoryName)));
      add(new Label("pageName", pageName).setRenderBodyOnly(true));
      UserModel user = GitBlitWebSession.get().getUser();
      if (user == null) {
         user = UserModel.ANONYMOUS;
@@ -226,7 +260,14 @@
      // indicate origin repository
      RepositoryModel model = getRepositoryModel();
      if (StringUtils.isEmpty(model.originRepository)) {
         add(new Label("originRepository").setVisible(false));
         if (model.isMirror) {
            Fragment mirrorFrag = new Fragment("originRepository", "mirrorFragment", this);
            Label lbl = new Label("originRepository", MessageFormat.format(getString("gb.mirrorOf"), "<b>" + model.origin + "</b>"));
            mirrorFrag.add(lbl.setEscapeModelStrings(false));
            add(mirrorFrag);
         } else {
            add(new Label("originRepository").setVisible(false));
         }
      } else {
         RepositoryModel origin = GitBlit.self().getRepositoryModel(model.originRepository);
         if (origin == null) {
@@ -240,20 +281,30 @@
         } else {
            // link to origin repository
            Fragment forkFrag = new Fragment("originRepository", "originFragment", this);
            forkFrag.add(new LinkPanel("originRepository", null, StringUtils.stripDotGit(model.originRepository),
            forkFrag.add(new LinkPanel("originRepository", null, StringUtils.stripDotGit(model.originRepository),
                  SummaryPage.class, WicketUtils.newRepositoryParameter(model.originRepository)));
            add(forkFrag);
         }
      }
      if (getRepositoryModel().isBare) {
         add(new Label("workingCopyIndicator").setVisible(false));
      // (un)star link allows a user to star a repository
      if (user.isAuthenticated) {
         PageParameters starParams = DeepCopier.copy(getPageParameters());
         starParams.put(PARAM_STAR, !user.getPreferences().isStarredRepository(model.name));
         String toggleStarUrl = getRequestCycle().urlFor(getClass(), starParams).toString();
         if (user.getPreferences().isStarredRepository(model.name)) {
            // show unstar button
            add(new Label("starLink").setVisible(false));
            addToolbarButton("unstarLink", "icon-star-empty", getString("gb.unstar"), toggleStarUrl);
         } else {
            // show star button
            addToolbarButton("starLink", "icon-star", getString("gb.star"), toggleStarUrl);
            add(new Label("unstarLink").setVisible(false));
         }
      } else {
         Fragment wc = new Fragment("workingCopyIndicator", "workingCopyFragment", this);
         Label lbl = new Label("workingCopy", getString("gb.workingCopy"));
         WicketUtils.setHtmlTooltip(lbl,  getString("gb.workingCopyWarning"));
         wc.add(lbl);
         add(wc);
         // anonymous user
         add(new Label("starLink").setVisible(false));
         add(new Label("unstarLink").setVisible(false));
      }
      // fork controls
@@ -261,7 +312,6 @@
         // must be logged-in to fork, hide all fork controls
         add(new ExternalLink("forkLink", "").setVisible(false));
         add(new ExternalLink("myForkLink", "").setVisible(false));
         add(new Label("forksProhibitedIndicator").setVisible(false));
      } else {
         String fork = GitBlit.self().getFork(user.username, model.name);
         boolean hasFork = fork != null;
@@ -270,19 +320,7 @@
         if (hasFork || !canFork) {
            // user not allowed to fork or fork already exists or repo forbids forking
            add(new ExternalLink("forkLink", "").setVisible(false));
            if (user.canFork() && !model.allowForks) {
               // show forks prohibited indicator
               Fragment wc = new Fragment("forksProhibitedIndicator", "forksProhibitedFragment", this);
               Label lbl = new Label("forksProhibited", getString("gb.forksProhibited"));
               WicketUtils.setHtmlTooltip(lbl,  getString("gb.forksProhibitedWarning"));
               wc.add(lbl);
               add(wc);
            } else {
               // can not fork, no need for forks prohibited indicator
               add(new Label("forksProhibitedIndicator").setVisible(false));
            }
            if (hasFork && !fork.equals(model.name)) {
               // user has fork, view my fork link
               String url = getRequestCycle().urlFor(SummaryPage.class, WicketUtils.newRepositoryParameter(fork)).toString();
@@ -293,14 +331,30 @@
            }
         } else if (canFork) {
            // can fork and we do not have one
            add(new Label("forksProhibitedIndicator").setVisible(false));
            add(new ExternalLink("myForkLink", "").setVisible(false));
            String url = getRequestCycle().urlFor(ForkPage.class, WicketUtils.newRepositoryParameter(model.name)).toString();
            add(new ExternalLink("forkLink", url));
         }
      }
      if (showAdmin || isOwner) {
         String url = getRequestCycle().urlFor(EditRepositoryPage.class, WicketUtils.newRepositoryParameter(model.name)).toString();
         add(new ExternalLink("editLink", url));
      } else {
         add(new Label("editLink").setVisible(false));
      }
      super.setupPage(repositoryName, pageName);
   }
   protected void addToolbarButton(String wicketId, String iconClass, String label, String url) {
      Fragment button = new Fragment(wicketId, "toolbarLinkFragment", this);
      Label icon = new Label("icon");
      WicketUtils.setCssClass(icon, iconClass);
      button.add(icon);
      button.add(new Label("label", label));
      button.add(new SimpleAttributeModifier("href", url));
      add(button);
   }
   protected void addSyndicationDiscoveryLink() {
@@ -344,13 +398,38 @@
      RevCommit commit = JGitUtils.getCommit(r, objectId);
      if (commit == null) {
         error(MessageFormat.format(getString("gb.failedToFindCommit"),
               objectId, repositoryName, getPageName()), true);
               objectId, repositoryName, getPageName()), null, LogPage.class,
               WicketUtils.newRepositoryParameter(repositoryName));
      }
      getSubmodules(commit);
      return commit;
   }
   private Map<String, SubmoduleModel> getSubmodules(RevCommit commit) {
   protected String getBestCommitId(RevCommit commit) {
      String head = null;
      try {
         head = r.resolve(getRepositoryModel().HEAD).getName();
      } catch (Exception e) {
      }
      String id = commit.getName();
      if (!StringUtils.isEmpty(head) && head.equals(id)) {
         // match default branch
         return Repository.shortenRefName(getRepositoryModel().HEAD);
      }
      // find first branch match
      for (RefModel ref : JGitUtils.getLocalBranches(r, false, -1)) {
         if (ref.getObjectId().getName().equals(id)) {
            return ref.getName();
         }
      }
      // return sha
      return id;
   }
   protected Map<String, SubmoduleModel> getSubmodules(RevCommit commit) {
      if (submodules == null) {
         submodules = new HashMap<String, SubmoduleModel>();
         for (SubmoduleModel model : JGitUtils.getSubmodules(r, commit.getTree())) {
@@ -359,9 +438,12 @@
      }
      return submodules;
   }
   protected SubmoduleModel getSubmodule(String path) {
      SubmoduleModel model = submodules.get(path);
      SubmoduleModel model = null;
      if (submodules != null) {
         model = submodules.get(path);
      }
      if (model == null) {
         // undefined submodule?!
         model = new SubmoduleModel(path.substring(path.lastIndexOf('/') + 1), path, path);
@@ -372,7 +454,7 @@
         // extract the repository name from the clone url
         List<String> patterns = GitBlit.getStrings(Keys.git.submoduleUrlPatterns);
         String submoduleName = StringUtils.extractRepositoryPath(model.url, patterns.toArray(new String[0]));
         // determine the current path for constructing paths relative
         // to the current repository
         String currentPath = "";
@@ -392,7 +474,7 @@
         if (submoduleName.lastIndexOf('/') > -1) {
            String name = submoduleName.substring(submoduleName.lastIndexOf('/') + 1);
            candidates.add(currentPath + StringUtils.stripDotGit(name));
            candidates.add(currentPath + candidates.get(candidates.size() - 1) + ".git");
            candidates.add(candidates.get(candidates.size() - 1) + ".git");
         }
         // absolute
@@ -415,11 +497,11 @@
               return model;
            }
         }
         // we do not have a copy of the submodule, but we need a path
         model.gitblitPath = candidates.get(0);
         return model;
      }
      }
   }
   protected String getShortObjectId(String objectId) {
@@ -430,12 +512,17 @@
      add(new RefsPanel("refsPanel", repositoryName, c, JGitUtils.getAllRefs(r, getRepositoryModel().showRemoteBranches)));
   }
   protected void addFullText(String wicketId, String text, boolean substituteRegex) {
      String html = StringUtils.escapeForHtml(text, true);
      if (substituteRegex) {
         html = GitBlit.self().processCommitMessage(repositoryName, text);
      } else {
         html = StringUtils.breakLinesForHtml(html);
   protected void addFullText(String wicketId, String text) {
      RepositoryModel model = getRepositoryModel();
      String content = GitBlit.self().processCommitMessage(model, text);
      String html;
      switch (model.commitMessageRenderer) {
      case MARKDOWN:
         html = MessageFormat.format("<div class='commit_message'>{0}</div>", content);
         break;
      default:
         html = MessageFormat.format("<pre class='commit_message'>{0}</pre>", content);
         break;
      }
      add(new Label(wicketId, html).setEscapeModelStrings(false));
   }
@@ -519,6 +606,30 @@
      super.onBeforeRender();
   }
   @Override
   protected void setLastModified() {
      if (getClass().isAnnotationPresent(CacheControl.class)) {
         CacheControl cacheControl = getClass().getAnnotation(CacheControl.class);
         switch (cacheControl.value()) {
         case REPOSITORY:
            RepositoryModel repository = getRepositoryModel();
            if (repository != null) {
               setLastModified(repository.lastChange);
            }
            break;
         case COMMIT:
            RevCommit commit = getCommit();
            if (commit != null) {
               Date commitDate = JGitUtils.getCommitDate(commit);
               setLastModified(commitDate);
            }
            break;
         default:
            super.setLastModified();
         }
      }
   }
   protected PageParameters newRepositoryParameter() {
      return WicketUtils.newRepositoryParameter(repositoryName);
   }
@@ -534,11 +645,11 @@
   public boolean isShowAdmin() {
      return showAdmin;
   }
   public boolean isOwner() {
      return isOwner;
   }
   private class SearchForm extends SessionlessForm<Void> implements Serializable {
      private static final long serialVersionUID = 1L;
@@ -571,7 +682,10 @@
      public void onSubmit() {
         Constants.SearchType searchType = searchTypeModel.getObject();
         String searchString = searchBoxModel.getObject();
         if (searchString == null) {
         if (StringUtils.isEmpty(searchString)) {
            // redirect to self to avoid wicket page update bug
            String absoluteUrl = getCanonicalUrl();
            getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
            return;
         }
         for (Constants.SearchType type : Constants.SearchType.values()) {
@@ -592,8 +706,7 @@
         // use an absolute url to workaround Wicket-Tomcat problems with
         // mounted url parameters (issue-111)
         PageParameters params = WicketUtils.newSearchParameter(repositoryName, null, searchString, searchType);
         String relativeUrl = urlFor(searchPageClass, params).toString();
         String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
         String absoluteUrl = getCanonicalUrl(searchPageClass, params);
         getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
      }
   }