James Moger
2013-09-06 5dd8057b49803a7c1b84112418dcfca7b256fce0
commit | author | age
f13c4c 1 /*
JM 2  * Copyright 2011 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
1f9dae 16 package com.gitblit.wicket.pages;
5fe7df 17
85c2e6 18 import java.io.Serializable;
bc9d4a 19 import java.text.MessageFormat;
3e087a 20 import java.util.ArrayList;
JM 21 import java.util.Arrays;
a7db57 22 import java.util.Date;
eb870f 23 import java.util.HashMap;
9e5bee 24 import java.util.LinkedHashMap;
eb870f 25 import java.util.LinkedHashSet;
5fe7df 26 import java.util.List;
JM 27 import java.util.Map;
eb870f 28 import java.util.Set;
5fe7df 29
98ce17 30 import org.apache.wicket.Component;
5fe7df 31 import org.apache.wicket.PageParameters;
79d324 32 import org.apache.wicket.behavior.SimpleAttributeModifier;
5fe7df 33 import org.apache.wicket.markup.html.basic.Label;
3e087a 34 import org.apache.wicket.markup.html.form.DropDownChoice;
JM 35 import org.apache.wicket.markup.html.form.TextField;
c22722 36 import org.apache.wicket.markup.html.link.ExternalLink;
98ce17 37 import org.apache.wicket.markup.html.panel.Fragment;
3e087a 38 import org.apache.wicket.model.IModel;
JM 39 import org.apache.wicket.model.Model;
77e1d2 40 import org.apache.wicket.protocol.http.RequestUtils;
JM 41 import org.apache.wicket.request.target.basic.RedirectRequestTarget;
9bc17d 42 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
98ce17 43 import org.eclipse.jgit.lib.PersonIdent;
5fe7df 44 import org.eclipse.jgit.lib.Repository;
JM 45 import org.eclipse.jgit.revwalk.RevCommit;
79d324 46 import org.slf4j.Logger;
JM 47 import org.slf4j.LoggerFactory;
5fe7df 48
33d8d8 49 import com.gitblit.Constants;
fc948c 50 import com.gitblit.GitBlit;
79d324 51 import com.gitblit.GitBlitException;
87cc1e 52 import com.gitblit.Keys;
11924d 53 import com.gitblit.PagesServlet;
c22722 54 import com.gitblit.SyndicationServlet;
1e1b85 55 import com.gitblit.models.ProjectModel;
85f639 56 import com.gitblit.models.RefModel;
1f9dae 57 import com.gitblit.models.RepositoryModel;
eb870f 58 import com.gitblit.models.SubmoduleModel;
1e1b85 59 import com.gitblit.models.UserModel;
79d324 60 import com.gitblit.models.UserRepositoryPreferences;
4e1930 61 import com.gitblit.utils.ArrayUtils;
79d324 62 import com.gitblit.utils.DeepCopier;
5fe7df 63 import com.gitblit.utils.JGitUtils;
ff7d3c 64 import com.gitblit.utils.RefLogUtils;
f5d0ad 65 import com.gitblit.utils.StringUtils;
a7db57 66 import com.gitblit.wicket.CacheControl;
1f9dae 67 import com.gitblit.wicket.GitBlitWebSession;
9e5bee 68 import com.gitblit.wicket.PageRegistration;
11924d 69 import com.gitblit.wicket.PageRegistration.OtherPageLink;
ed295f 70 import com.gitblit.wicket.SessionlessForm;
1f9dae 71 import com.gitblit.wicket.WicketUtils;
JM 72 import com.gitblit.wicket.panels.LinkPanel;
9e5bee 73 import com.gitblit.wicket.panels.NavigationPanel;
5fe7df 74 import com.gitblit.wicket.panels.RefsPanel;
JM 75
6ef8d7 76 public abstract class RepositoryPage extends RootPage {
5dd805 77
79d324 78     private final Logger logger = LoggerFactory.getLogger(getClass());
5fe7df 79
79d324 80     private final String PARAM_STAR = "star";
5dd805 81
13a3f5 82     protected final String projectName;
5fe7df 83     protected final String repositoryName;
bc9d4a 84     protected final String objectId;
5dd805 85
2a7306 86     private transient Repository r;
bc9d4a 87
2a7306 88     private RepositoryModel m;
5fe7df 89
eb870f 90     private Map<String, SubmoduleModel> submodules;
5dd805 91
9e5bee 92     private final Map<String, PageRegistration> registeredPages;
eb9979 93     private boolean showAdmin;
33622b 94     private boolean isOwner;
5dd805 95
cebf45 96     public RepositoryPage(PageParameters params) {
5fe7df 97         super(params);
7d35e2 98         repositoryName = WicketUtils.getRepositoryName(params);
1e1b85 99         String root =StringUtils.getFirstPathElement(repositoryName);
JM 100         if (StringUtils.isEmpty(root)) {
13a3f5 101             projectName = GitBlit.getString(Keys.web.repositoryRootGroupName, "main");
1e1b85 102         } else {
JM 103             projectName = root;
13a3f5 104         }
7d35e2 105         objectId = WicketUtils.getObject(params);
5dd805 106
e92c6d 107         if (StringUtils.isEmpty(repositoryName)) {
JM 108             error(MessageFormat.format(getString("gb.repositoryNotSpecifiedFor"), getPageName()), true);
109         }
110
111         if (!getRepositoryModel().hasCommits) {
112             setResponsePage(EmptyRepositoryPage.class, params);
113         }
5dd805 114
e92c6d 115         if (getRepositoryModel().isCollectingGarbage) {
JM 116             error(MessageFormat.format(getString("gb.busyCollectingGarbage"), getRepositoryModel().name), true);
117         }
5dd805 118
85f639 119         if (objectId != null) {
LM 120             RefModel branch = null;
121             if ((branch = JGitUtils.getBranch(getRepository(), objectId)) != null) {
6d23ca 122                 UserModel user = GitBlitWebSession.get().getUser();
JM 123                 if (user == null) {
124                     // workaround until get().getUser() is reviewed throughout the app
125                     user = UserModel.ANONYMOUS;
126                 }
92d477 127                 boolean canAccess = user.canView(getRepositoryModel(),
85f639 128                                 branch.reference.getName());
LM 129                 if (!canAccess) {
13f880 130                     error(getString("gb.accessDenied"), true);
79d324 131                 }
JM 132             }
133         }
5dd805 134
79d324 135         if (params.containsKey(PARAM_STAR)) {
JM 136             // set starred state
137             boolean star = params.getBoolean(PARAM_STAR);
138             UserModel user = GitBlitWebSession.get().getUser();
139             if (user != null && user.isAuthenticated) {
140                 UserRepositoryPreferences prefs = user.getPreferences().getRepositoryPreferences(getRepositoryModel().name);
141                 prefs.starred = star;
142                 try {
143                     GitBlit.self().updateUserModel(user.username, user, false);
144                 } catch (GitBlitException e) {
145                     logger.error("Failed to update user " + user.username, e);
146                     error(getString("gb.failedToUpdateUser"), false);
85f639 147                 }
LM 148             }
82df52 149         }
JM 150
9e5bee 151         // register the available page links for this page and user
JM 152         registeredPages = registerPages();
2a7306 153
3e087a 154         // standard page links
9e5bee 155         List<PageRegistration> pages = new ArrayList<PageRegistration>(registeredPages.values());
6ef8d7 156         NavigationPanel navigationPanel = new NavigationPanel("repositoryNavPanel", getRepoNavPageClass(), pages);
9e5bee 157         add(navigationPanel);
8c9a20 158
c22722 159         add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()
JM 160                 .getRelativePathPrefixToContextRoot(), repositoryName, null, 0)));
3e087a 161
JM 162         // add floating search form
163         SearchForm searchForm = new SearchForm("searchForm", repositoryName);
164         add(searchForm);
165         searchForm.setTranslatedAttributes();
bc9d4a 166
3e087a 167         // set stateless page preference
5fe7df 168         setStatelessHint(true);
3e087a 169     }
5dd805 170
6ef8d7 171     @Override
JM 172     protected Class<? extends BasePage> getRootNavPageClass() {
173         return RepositoriesPage.class;
174     }
9e5bee 175
6ef8d7 176     protected Class<? extends BasePage> getRepoNavPageClass() {
JM 177         return getClass();
178     }
5dd805 179
9e5bee 180     private Map<String, PageRegistration> registerPages() {
JM 181         PageParameters params = null;
182         if (!StringUtils.isEmpty(repositoryName)) {
183             params = WicketUtils.newRepositoryParameter(repositoryName);
184         }
185         Map<String, PageRegistration> pages = new LinkedHashMap<String, PageRegistration>();
186
6ef8d7 187         Repository r = getRepository();
JM 188         RepositoryModel model = getRepositoryModel();
189
9e5bee 190         // standard links
ff7d3c 191         if (RefLogUtils.getRefLogBranch(r) == null) {
6ef8d7 192             pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
JM 193         } else {
194             pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
195 //            pages.put("overview", new PageRegistration("gb.overview", OverviewPage.class, params));
ff7d3c 196             pages.put("reflog", new PageRegistration("gb.reflog", ReflogPage.class, params));
5dd805 197         }
6ef8d7 198         pages.put("commits", new PageRegistration("gb.commits", LogPage.class, params));
9e5bee 199         pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
889d48 200         pages.put("compare", new PageRegistration("gb.compare", ComparePage.class, params, true));
428b22 201         if (GitBlit.getBoolean(Keys.web.allowForking, true)) {
889d48 202             pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params, true));
428b22 203         }
9e5bee 204
JM 205         // conditional links
206         // per-repository extra page links
6ef8d7 207         if (model.showReadme || model.useDocs) {
889d48 208             pages.put("docs", new PageRegistration("gb.docs", DocsPage.class, params, true));
9e5bee 209         }
11924d 210         if (JGitUtils.getPagesBranch(r) != null) {
JM 211             OtherPageLink pagesLink = new OtherPageLink("gb.pages", PagesServlet.asLink(
889d48 212                     getRequest().getRelativePathPrefixToContextRoot(), repositoryName, null), true);
11924d 213             pages.put("pages", pagesLink);
JM 214         }
215
9e5bee 216         // Conditionally add edit link
33622b 217         showAdmin = false;
9e5bee 218         if (GitBlit.getBoolean(Keys.web.authenticateAdminPages, true)) {
JM 219             boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false);
220             showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin();
221         } else {
222             showAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false);
223         }
33622b 224         isOwner = GitBlitWebSession.get().isLoggedIn()
661db6 225                 && (model.isOwner(GitBlitWebSession.get()
33622b 226                         .getUsername()));
9e5bee 227         return pages;
JM 228     }
5dd805 229
1f52c8 230     protected boolean allowForkControls() {
428b22 231         return GitBlit.getBoolean(Keys.web.allowForking, true);
1f52c8 232     }
9e5bee 233
1f5915 234     @Override
11924d 235     protected void setupPage(String repositoryName, String pageName) {
1e1b85 236         String projectName = StringUtils.getFirstPathElement(repositoryName);
JM 237         ProjectModel project = GitBlit.self().getProjectModel(projectName);
238         if (project.isUserProject()) {
239             // user-as-project
240             add(new LinkPanel("projectTitle", null, project.getDisplayName(),
241                     UserPage.class, WicketUtils.newUsernameParameter(project.name.substring(1))));
ccab3a 242         } else {
1e1b85 243             // project
JM 244             add(new LinkPanel("projectTitle", null, project.name,
245                     ProjectPage.class, WicketUtils.newProjectParameter(project.name)));
246         }
5dd805 247
1e1b85 248         String name = StringUtils.stripDotGit(repositoryName);
JM 249         if (!StringUtils.isEmpty(projectName) && name.startsWith(projectName)) {
250             name = name.substring(projectName.length() + 1);
251         }
252         add(new LinkPanel("repositoryName", null, name, SummaryPage.class,
253                 WicketUtils.newRepositoryParameter(repositoryName)));
254         add(new Label("pageName", pageName).setRenderBodyOnly(true));
5dd805 255
eb1405 256         UserModel user = GitBlitWebSession.get().getUser();
616590 257         if (user == null) {
JM 258             user = UserModel.ANONYMOUS;
259         }
eb1405 260
1e1b85 261         // indicate origin repository
JM 262         RepositoryModel model = getRepositoryModel();
263         if (StringUtils.isEmpty(model.originRepository)) {
264             add(new Label("originRepository").setVisible(false));
265         } else {
eb1405 266             RepositoryModel origin = GitBlit.self().getRepositoryModel(model.originRepository);
JM 267             if (origin == null) {
268                 // no origin repository
269                 add(new Label("originRepository").setVisible(false));
20714a 270             } else if (!user.canView(origin)) {
eb1405 271                 // show origin repository without link
JM 272                 Fragment forkFrag = new Fragment("originRepository", "originFragment", this);
273                 forkFrag.add(new Label("originRepository", StringUtils.stripDotGit(model.originRepository)));
274                 add(forkFrag);
275             } else {
276                 // link to origin repository
277                 Fragment forkFrag = new Fragment("originRepository", "originFragment", this);
5dd805 278                 forkFrag.add(new LinkPanel("originRepository", null, StringUtils.stripDotGit(model.originRepository),
eb1405 279                         SummaryPage.class, WicketUtils.newRepositoryParameter(model.originRepository)));
JM 280                 add(forkFrag);
281             }
1e1b85 282         }
5dd805 283
9b26b7 284         // (un)star link allows a user to star a repository
JM 285         if (user.isAuthenticated) {
79d324 286             PageParameters starParams = DeepCopier.copy(getPageParameters());
JM 287             starParams.put(PARAM_STAR, !user.getPreferences().isStarredRepository(model.name));
288             String toggleStarUrl = getRequestCycle().urlFor(getClass(), starParams).toString();
289             if (user.getPreferences().isStarredRepository(model.name)) {
290                 // show unstar button
291                 add(new Label("starLink").setVisible(false));
292                 addToolbarButton("unstarLink", "icon-star-empty", getString("gb.unstar"), toggleStarUrl);
293             } else {
294                 // show star button
295                 addToolbarButton("starLink", "icon-star", getString("gb.star"), toggleStarUrl);
296                 add(new Label("unstarLink").setVisible(false));
297             }
298         } else {
9b26b7 299             // anonymous user
79d324 300             add(new Label("starLink").setVisible(false));
JM 301             add(new Label("unstarLink").setVisible(false));
302         }
303
eb1405 304         // fork controls
616590 305         if (!allowForkControls() || user == null || !user.isAuthenticated) {
eb1405 306             // must be logged-in to fork, hide all fork controls
JM 307             add(new ExternalLink("forkLink", "").setVisible(false));
308             add(new ExternalLink("myForkLink", "").setVisible(false));
1e1b85 309         } else {
eb1405 310             String fork = GitBlit.self().getFork(user.username, model.name);
JM 311             boolean hasFork = fork != null;
20714a 312             boolean canFork = user.canFork(model);
eb1405 313
JM 314             if (hasFork || !canFork) {
315                 // user not allowed to fork or fork already exists or repo forbids forking
316                 add(new ExternalLink("forkLink", "").setVisible(false));
5dd805 317
eb1405 318                 if (hasFork && !fork.equals(model.name)) {
JM 319                     // user has fork, view my fork link
320                     String url = getRequestCycle().urlFor(SummaryPage.class, WicketUtils.newRepositoryParameter(fork)).toString();
321                     add(new ExternalLink("myForkLink", url));
322                 } else {
323                     // no fork, hide view my fork link
324                     add(new ExternalLink("myForkLink", "").setVisible(false));
325                 }
326             } else if (canFork) {
327                 // can fork and we do not have one
328                 add(new ExternalLink("myForkLink", "").setVisible(false));
1f52c8 329                 String url = getRequestCycle().urlFor(ForkPage.class, WicketUtils.newRepositoryParameter(model.name)).toString();
JM 330                 add(new ExternalLink("forkLink", url));
1e1b85 331             }
JM 332         }
5dd805 333
067a2f 334         if (showAdmin || isOwner) {
JM 335             String url = getRequestCycle().urlFor(EditRepositoryPage.class, WicketUtils.newRepositoryParameter(model.name)).toString();
5dd805 336             add(new ExternalLink("editLink", url));
067a2f 337         } else {
JM 338             add(new Label("editLink").setVisible(false));
339         }
5dd805 340
1f5915 341         super.setupPage(repositoryName, pageName);
8c9a20 342     }
5dd805 343
79d324 344     protected void addToolbarButton(String wicketId, String iconClass, String label, String url) {
JM 345         Fragment button = new Fragment(wicketId, "toolbarLinkFragment", this);
346         Label icon = new Label("icon");
347         WicketUtils.setCssClass(icon, iconClass);
348         button.add(icon);
349         button.add(new Label("label", label));
350         button.add(new SimpleAttributeModifier("href", url));
351         add(button);
352     }
8c9a20 353
JM 354     protected void addSyndicationDiscoveryLink() {
355         add(WicketUtils.syndicationDiscoveryLink(SyndicationServlet.getTitle(repositoryName,
356                 objectId), SyndicationServlet.asLink(getRequest()
357                 .getRelativePathPrefixToContextRoot(), repositoryName, objectId, 0)));
5fe7df 358     }
JM 359
360     protected Repository getRepository() {
361         if (r == null) {
f5d0ad 362             Repository r = GitBlit.self().getRepository(repositoryName);
7ba0ec 363             if (r == null) {
6caa93 364                 error(getString("gb.canNotLoadRepository") + " " + repositoryName, true);
7ba0ec 365                 return null;
JM 366             }
367             this.r = r;
5fe7df 368         }
JM 369         return r;
370     }
bc9d4a 371
f97bf0 372     protected RepositoryModel getRepositoryModel() {
JM 373         if (m == null) {
2a7306 374             RepositoryModel model = GitBlit.self().getRepositoryModel(
JM 375                     GitBlitWebSession.get().getUser(), repositoryName);
dfb889 376             if (model == null) {
7b0f30 377                 if (GitBlit.self().hasRepository(repositoryName, true)) {
d97e52 378                     // has repository, but unauthorized
JM 379                     authenticationError(getString("gb.unauthorizedAccessForRepository") + " " + repositoryName);
380                 } else {
381                     // does not have repository
382                     error(getString("gb.canNotLoadRepository") + " " + repositoryName, true);
383                 }
00afd7 384                 return null;
dfb889 385             }
JM 386             m = model;
f97bf0 387         }
JM 388         return m;
bc9d4a 389     }
dfb889 390
bc9d4a 391     protected RevCommit getCommit() {
JM 392         RevCommit commit = JGitUtils.getCommit(r, objectId);
393         if (commit == null) {
6caa93 394             error(MessageFormat.format(getString("gb.failedToFindCommit"),
1078f8 395                     objectId, repositoryName, getPageName()), null, LogPage.class,
JM 396                     WicketUtils.newRepositoryParameter(repositoryName));
bc9d4a 397         }
eb870f 398         getSubmodules(commit);
bc9d4a 399         return commit;
f97bf0 400     }
5dd805 401
JM 402     protected Map<String, SubmoduleModel> getSubmodules(RevCommit commit) {
eb870f 403         if (submodules == null) {
JM 404             submodules = new HashMap<String, SubmoduleModel>();
405             for (SubmoduleModel model : JGitUtils.getSubmodules(r, commit.getTree())) {
406                 submodules.put(model.path, model);
407             }
408         }
409         return submodules;
410     }
5dd805 411
eb870f 412     protected SubmoduleModel getSubmodule(String path) {
80d636 413         SubmoduleModel model = null;
JM 414         if (submodules != null) {
415             model = submodules.get(path);
416         }
eb870f 417         if (model == null) {
JM 418             // undefined submodule?!
419             model = new SubmoduleModel(path.substring(path.lastIndexOf('/') + 1), path, path);
420             model.hasSubmodule = false;
421             model.gitblitPath = model.name;
422             return model;
423         } else {
424             // extract the repository name from the clone url
425             List<String> patterns = GitBlit.getStrings(Keys.git.submoduleUrlPatterns);
426             String submoduleName = StringUtils.extractRepositoryPath(model.url, patterns.toArray(new String[0]));
5dd805 427
eb870f 428             // determine the current path for constructing paths relative
JM 429             // to the current repository
430             String currentPath = "";
431             if (repositoryName.indexOf('/') > -1) {
432                 currentPath = repositoryName.substring(0, repositoryName.lastIndexOf('/') + 1);
433             }
434
435             // try to locate the submodule repository
436             // prefer bare to non-bare names
437             List<String> candidates = new ArrayList<String>();
438
439             // relative
440             candidates.add(currentPath + StringUtils.stripDotGit(submoduleName));
441             candidates.add(candidates.get(candidates.size() - 1) + ".git");
442
443             // relative, no subfolder
444             if (submoduleName.lastIndexOf('/') > -1) {
445                 String name = submoduleName.substring(submoduleName.lastIndexOf('/') + 1);
446                 candidates.add(currentPath + StringUtils.stripDotGit(name));
5e3771 447                 candidates.add(candidates.get(candidates.size() - 1) + ".git");
eb870f 448             }
JM 449
450             // absolute
451             candidates.add(StringUtils.stripDotGit(submoduleName));
452             candidates.add(candidates.get(candidates.size() - 1) + ".git");
453
454             // absolute, no subfolder
455             if (submoduleName.lastIndexOf('/') > -1) {
456                 String name = submoduleName.substring(submoduleName.lastIndexOf('/') + 1);
457                 candidates.add(StringUtils.stripDotGit(name));
458                 candidates.add(candidates.get(candidates.size() - 1) + ".git");
459             }
460
461             // create a unique, ordered set of candidate paths
462             Set<String> paths = new LinkedHashSet<String>(candidates);
463             for (String candidate : paths) {
464                 if (GitBlit.self().hasRepository(candidate)) {
465                     model.hasSubmodule = true;
466                     model.gitblitPath = candidate;
467                     return model;
468                 }
469             }
5dd805 470
eb870f 471             // we do not have a copy of the submodule, but we need a path
JM 472             model.gitblitPath = candidates.get(0);
473             return model;
5dd805 474         }
eb870f 475     }
5fe7df 476
008322 477     protected String getShortObjectId(String objectId) {
e627cf 478         return objectId.substring(0, GitBlit.getInteger(Keys.web.shortCommitIdLength, 6));
008322 479     }
JM 480
5fe7df 481     protected void addRefs(Repository r, RevCommit c) {
1e1b85 482         add(new RefsPanel("refsPanel", repositoryName, c, JGitUtils.getAllRefs(r, getRepositoryModel().showRemoteBranches)));
5fe7df 483     }
JM 484
485     protected void addFullText(String wicketId, String text, boolean substituteRegex) {
bca8c5 486         String html = StringUtils.escapeForHtml(text, false);
5fe7df 487         if (substituteRegex) {
bca8c5 488             html = GitBlit.self().processCommitMessage(repositoryName, html);
f339f5 489         } else {
227736 490             html = StringUtils.breakLinesForHtml(html);
f339f5 491         }
JM 492         add(new Label(wicketId, html).setEscapeModelStrings(false));
5fe7df 493     }
1e47ab 494
cebf45 495     protected abstract String getPageName();
5fe7df 496
2a7306 497     protected Component createPersonPanel(String wicketId, PersonIdent identity,
33d8d8 498             Constants.SearchType searchType) {
e11f48 499         String name = identity == null ? "" : identity.getName();
JM 500         String address = identity == null ? "" : identity.getEmailAddress();
ac7e9a 501         name = StringUtils.removeNewlines(name);
JM 502         address = StringUtils.removeNewlines(address);
2a7306 503         boolean showEmail = GitBlit.getBoolean(Keys.web.showEmailAddresses, false);
e11f48 504         if (!showEmail || StringUtils.isEmpty(name) || StringUtils.isEmpty(address)) {
JM 505             String value = name;
98ce17 506             if (StringUtils.isEmpty(value)) {
f5d0ad 507                 if (showEmail) {
e11f48 508                     value = address;
f5d0ad 509                 } else {
JM 510                     value = getString("gb.missingUsername");
511                 }
98ce17 512             }
JM 513             Fragment partial = new Fragment(wicketId, "partialPersonIdent", this);
4e1930 514             LinkPanel link = new LinkPanel("personName", "list", value, GitSearchPage.class,
2a7306 515                     WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType));
98ce17 516             setPersonSearchTooltip(link, value, searchType);
JM 517             partial.add(link);
518             return partial;
519         } else {
520             Fragment fullPerson = new Fragment(wicketId, "fullPersonIdent", this);
4e1930 521             LinkPanel nameLink = new LinkPanel("personName", "list", name, GitSearchPage.class,
e11f48 522                     WicketUtils.newSearchParameter(repositoryName, objectId, name, searchType));
JM 523             setPersonSearchTooltip(nameLink, name, searchType);
98ce17 524             fullPerson.add(nameLink);
3e087a 525
227736 526             LinkPanel addressLink = new LinkPanel("personAddress", "hidden-phone list", "<" + address + ">",
4e1930 527                     GitSearchPage.class, WicketUtils.newSearchParameter(repositoryName, objectId,
e11f48 528                             address, searchType));
JM 529             setPersonSearchTooltip(addressLink, address, searchType);
98ce17 530             fullPerson.add(addressLink);
JM 531             return fullPerson;
532         }
533     }
3e087a 534
11924d 535     protected void setPersonSearchTooltip(Component component, String value,
JM 536             Constants.SearchType searchType) {
33d8d8 537         if (searchType.equals(Constants.SearchType.AUTHOR)) {
1e8390 538             WicketUtils.setHtmlTooltip(component, getString("gb.searchForAuthor") + " " + value);
33d8d8 539         } else if (searchType.equals(Constants.SearchType.COMMITTER)) {
1e8390 540             WicketUtils.setHtmlTooltip(component, getString("gb.searchForCommitter") + " " + value);
98ce17 541         }
JM 542     }
3e087a 543
9bc17d 544     protected void setChangeTypeTooltip(Component container, ChangeType type) {
JM 545         switch (type) {
546         case ADD:
1e8390 547             WicketUtils.setHtmlTooltip(container, getString("gb.addition"));
9bc17d 548             break;
JM 549         case COPY:
550         case RENAME:
1e8390 551             WicketUtils.setHtmlTooltip(container, getString("gb.rename"));
9bc17d 552             break;
JM 553         case DELETE:
1e8390 554             WicketUtils.setHtmlTooltip(container, getString("gb.deletion"));
9bc17d 555             break;
JM 556         case MODIFY:
1e8390 557             WicketUtils.setHtmlTooltip(container, getString("gb.modification"));
9bc17d 558             break;
JM 559         }
560     }
3e087a 561
1e47ab 562     @Override
JM 563     protected void onBeforeRender() {
564         // dispose of repository object
565         if (r != null) {
566             r.close();
567             r = null;
568         }
569         // setup page header and footer
cebf45 570         setupPage(repositoryName, "/ " + getPageName());
1e47ab 571         super.onBeforeRender();
5fe7df 572     }
5dd805 573
a7db57 574     @Override
JM 575     protected void setLastModified() {
576         if (getClass().isAnnotationPresent(CacheControl.class)) {
577             CacheControl cacheControl = getClass().getAnnotation(CacheControl.class);
578             switch (cacheControl.value()) {
579             case REPOSITORY:
580                 RepositoryModel repository = getRepositoryModel();
581                 if (repository != null) {
582                     setLastModified(repository.lastChange);
583                 }
584                 break;
585             case COMMIT:
586                 RevCommit commit = getCommit();
587                 if (commit != null) {
588                     Date commitDate = JGitUtils.getCommitDate(commit);
589                     setLastModified(commitDate);
590                 }
591                 break;
592             default:
593                 super.setLastModified();
594             }
595         }
596     }
5fe7df 597
JM 598     protected PageParameters newRepositoryParameter() {
698678 599         return WicketUtils.newRepositoryParameter(repositoryName);
5fe7df 600     }
7ba0ec 601
5fe7df 602     protected PageParameters newCommitParameter() {
ef5c58 603         return WicketUtils.newObjectParameter(repositoryName, objectId);
5fe7df 604     }
7ba0ec 605
5fe7df 606     protected PageParameters newCommitParameter(String commitId) {
ef5c58 607         return WicketUtils.newObjectParameter(repositoryName, commitId);
5fe7df 608     }
JM 609
33622b 610     public boolean isShowAdmin() {
JM 611         return showAdmin;
612     }
5dd805 613
33622b 614     public boolean isOwner() {
JM 615         return isOwner;
eb9979 616     }
5dd805 617
ed295f 618     private class SearchForm extends SessionlessForm<Void> implements Serializable {
3e087a 619         private static final long serialVersionUID = 1L;
JM 620
621         private final String repositoryName;
622
623         private final IModel<String> searchBoxModel = new Model<String>("");
624
11924d 625         private final IModel<Constants.SearchType> searchTypeModel = new Model<Constants.SearchType>(
JM 626                 Constants.SearchType.COMMIT);
3e087a 627
JM 628         public SearchForm(String id, String repositoryName) {
ed295f 629             super(id, RepositoryPage.this.getClass(), RepositoryPage.this.getPageParameters());
3e087a 630             this.repositoryName = repositoryName;
11924d 631             DropDownChoice<Constants.SearchType> searchType = new DropDownChoice<Constants.SearchType>(
JM 632                     "searchType", Arrays.asList(Constants.SearchType.values()));
3e087a 633             searchType.setModel(searchTypeModel);
2a7306 634             add(searchType.setVisible(GitBlit.getBoolean(Keys.web.showSearchTypeSelection, false)));
3e087a 635             TextField<String> searchBox = new TextField<String>("searchBox", searchBoxModel);
JM 636             add(searchBox);
637         }
bc9d4a 638
JM 639         void setTranslatedAttributes() {
3e087a 640             WicketUtils.setHtmlTooltip(get("searchType"), getString("gb.searchTypeTooltip"));
9e5bee 641             WicketUtils.setHtmlTooltip(get("searchBox"),
JM 642                     MessageFormat.format(getString("gb.searchTooltip"), repositoryName));
bc9d4a 643             WicketUtils.setInputPlaceholder(get("searchBox"), getString("gb.search"));
3e087a 644         }
JM 645
646         @Override
647         public void onSubmit() {
33d8d8 648             Constants.SearchType searchType = searchTypeModel.getObject();
3e087a 649             String searchString = searchBoxModel.getObject();
6ef8d7 650             if (StringUtils.isEmpty(searchString)) {
5dd805 651                 // redirect to self to avoid wicket page update bug
6ef8d7 652                 PageParameters params = RepositoryPage.this.getPageParameters();
JM 653                 String relativeUrl = urlFor(RepositoryPage.this.getClass(), params).toString();
654                 String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
655                 getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
8c5d72 656                 return;
JM 657             }
33d8d8 658             for (Constants.SearchType type : Constants.SearchType.values()) {
3e087a 659                 if (searchString.toLowerCase().startsWith(type.name().toLowerCase() + ":")) {
JM 660                     searchType = type;
2a7306 661                     searchString = searchString.substring(type.name().toLowerCase().length() + 1)
JM 662                             .trim();
3e087a 663                     break;
JM 664                 }
665             }
4e1930 666             Class<? extends BasePage> searchPageClass = GitSearchPage.class;
JM 667             RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName);
7db092 668             if (GitBlit.getBoolean(Keys.web.allowLuceneIndexing, true)
JM 669                     && !ArrayUtils.isEmpty(model.indexedBranches)) {
4e1930 670                 // this repository is Lucene-indexed
JM 671                 searchPageClass = LuceneSearchPage.class;
672             }
77e1d2 673             // use an absolute url to workaround Wicket-Tomcat problems with
JM 674             // mounted url parameters (issue-111)
675             PageParameters params = WicketUtils.newSearchParameter(repositoryName, null, searchString, searchType);
676             String relativeUrl = urlFor(searchPageClass, params).toString();
677             String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
678             getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
3e087a 679         }
JM 680     }
428b22 681 }