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