You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RepositoryPage.java 26KB

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