lemval
2012-01-31 1c30dad2115fc513791d8a5b292ad0f7d7b85749
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;
9e5bee 22 import java.util.LinkedHashMap;
5fe7df 23 import java.util.List;
JM 24 import java.util.Map;
25
98ce17 26 import org.apache.wicket.Component;
5fe7df 27 import org.apache.wicket.PageParameters;
JM 28 import org.apache.wicket.markup.html.basic.Label;
3e087a 29 import org.apache.wicket.markup.html.form.DropDownChoice;
JM 30 import org.apache.wicket.markup.html.form.StatelessForm;
31 import org.apache.wicket.markup.html.form.TextField;
c22722 32 import org.apache.wicket.markup.html.link.ExternalLink;
98ce17 33 import org.apache.wicket.markup.html.panel.Fragment;
3e087a 34 import org.apache.wicket.model.IModel;
JM 35 import org.apache.wicket.model.Model;
9bc17d 36 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
98ce17 37 import org.eclipse.jgit.lib.PersonIdent;
5fe7df 38 import org.eclipse.jgit.lib.Repository;
JM 39 import org.eclipse.jgit.revwalk.RevCommit;
40
33d8d8 41 import com.gitblit.Constants;
fc948c 42 import com.gitblit.GitBlit;
87cc1e 43 import com.gitblit.Keys;
11924d 44 import com.gitblit.PagesServlet;
c22722 45 import com.gitblit.SyndicationServlet;
1f9dae 46 import com.gitblit.models.RepositoryModel;
5fe7df 47 import com.gitblit.utils.JGitUtils;
f5d0ad 48 import com.gitblit.utils.StringUtils;
793f76 49 import com.gitblit.utils.TicgitUtils;
1f9dae 50 import com.gitblit.wicket.GitBlitWebSession;
9e5bee 51 import com.gitblit.wicket.PageRegistration;
11924d 52 import com.gitblit.wicket.PageRegistration.OtherPageLink;
1f9dae 53 import com.gitblit.wicket.WicketUtils;
JM 54 import com.gitblit.wicket.panels.LinkPanel;
9e5bee 55 import com.gitblit.wicket.panels.NavigationPanel;
5fe7df 56 import com.gitblit.wicket.panels.RefsPanel;
JM 57
58 public abstract class RepositoryPage extends BasePage {
59
60     protected final String repositoryName;
bc9d4a 61     protected final String objectId;
7ba0ec 62
2a7306 63     private transient Repository r;
bc9d4a 64
2a7306 65     private RepositoryModel m;
5fe7df 66
9e5bee 67     private final Map<String, PageRegistration> registeredPages;
3e087a 68
cebf45 69     public RepositoryPage(PageParameters params) {
5fe7df 70         super(params);
7d35e2 71         repositoryName = WicketUtils.getRepositoryName(params);
JM 72         objectId = WicketUtils.getObject(params);
5fe7df 73
bc9d4a 74         if (StringUtils.isEmpty(repositoryName)) {
JM 75             error(MessageFormat.format("Repository not specified for {0}!", getPageName()), true);
76         }
77
82df52 78         if (!getRepositoryModel().hasCommits) {
JM 79             setResponsePage(EmptyRepositoryPage.class, params);
80         }
81
9e5bee 82         // register the available page links for this page and user
JM 83         registeredPages = registerPages();
2a7306 84
3e087a 85         // standard page links
9e5bee 86         List<PageRegistration> pages = new ArrayList<PageRegistration>(registeredPages.values());
JM 87         NavigationPanel navigationPanel = new NavigationPanel("navPanel", getClass(), pages);
88         add(navigationPanel);
8c9a20 89
c22722 90         add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()
JM 91                 .getRelativePathPrefixToContextRoot(), repositoryName, null, 0)));
3e087a 92
JM 93         // add floating search form
94         SearchForm searchForm = new SearchForm("searchForm", repositoryName);
95         add(searchForm);
96         searchForm.setTranslatedAttributes();
bc9d4a 97
3e087a 98         // set stateless page preference
5fe7df 99         setStatelessHint(true);
3e087a 100     }
9e5bee 101
JM 102     private Map<String, PageRegistration> registerPages() {
103         PageParameters params = null;
104         if (!StringUtils.isEmpty(repositoryName)) {
105             params = WicketUtils.newRepositoryParameter(repositoryName);
106         }
107         Map<String, PageRegistration> pages = new LinkedHashMap<String, PageRegistration>();
108
109         // standard links
110         pages.put("repositories", new PageRegistration("gb.repositories", RepositoriesPage.class));
111         pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
112         pages.put("log", new PageRegistration("gb.log", LogPage.class, params));
113         pages.put("branches", new PageRegistration("gb.branches", BranchesPage.class, params));
114         pages.put("tags", new PageRegistration("gb.tags", TagsPage.class, params));
115         pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
116
117         // conditional links
118         Repository r = getRepository();
119         RepositoryModel model = getRepositoryModel();
120
121         // per-repository extra page links
122         if (model.useTickets && TicgitUtils.getTicketsBranch(r) != null) {
123             pages.put("tickets", new PageRegistration("gb.tickets", TicketsPage.class, params));
124         }
125         if (model.useDocs) {
126             pages.put("docs", new PageRegistration("gb.docs", DocsPage.class, params));
127         }
11924d 128         if (JGitUtils.getPagesBranch(r) != null) {
JM 129             OtherPageLink pagesLink = new OtherPageLink("gb.pages", PagesServlet.asLink(
130                     getRequest().getRelativePathPrefixToContextRoot(), repositoryName, null));
131             pages.put("pages", pagesLink);
132         }
133
9e5bee 134         // Conditionally add edit link
JM 135         final boolean showAdmin;
136         if (GitBlit.getBoolean(Keys.web.authenticateAdminPages, true)) {
137             boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false);
138             showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin();
139         } else {
140             showAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false);
141         }
142         if (showAdmin
143                 || GitBlitWebSession.get().isLoggedIn()
144                 && (model.owner != null && model.owner.equalsIgnoreCase(GitBlitWebSession.get()
145                         .getUser().username))) {
146             pages.put("edit", new PageRegistration("gb.edit", EditRepositoryPage.class, params));
147         }
148         return pages;
149     }
150
1f5915 151     @Override
11924d 152     protected void setupPage(String repositoryName, String pageName) {
JM 153         add(new LinkPanel("repositoryName", null, StringUtils.stripDotGit(repositoryName),
154                 SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryName)));
1f5915 155         add(new Label("pageName", pageName));
JM 156
157         super.setupPage(repositoryName, pageName);
8c9a20 158     }
JM 159
160     protected void addSyndicationDiscoveryLink() {
161         add(WicketUtils.syndicationDiscoveryLink(SyndicationServlet.getTitle(repositoryName,
162                 objectId), SyndicationServlet.asLink(getRequest()
163                 .getRelativePathPrefixToContextRoot(), repositoryName, objectId, 0)));
5fe7df 164     }
JM 165
166     protected Repository getRepository() {
167         if (r == null) {
f5d0ad 168             Repository r = GitBlit.self().getRepository(repositoryName);
7ba0ec 169             if (r == null) {
00afd7 170                 error("Can not load repository " + repositoryName, true);
7ba0ec 171                 return null;
JM 172             }
173             this.r = r;
5fe7df 174         }
JM 175         return r;
176     }
bc9d4a 177
f97bf0 178     protected RepositoryModel getRepositoryModel() {
JM 179         if (m == null) {
2a7306 180             RepositoryModel model = GitBlit.self().getRepositoryModel(
JM 181                     GitBlitWebSession.get().getUser(), repositoryName);
dfb889 182             if (model == null) {
85c2e6 183                 authenticationError("Unauthorized access for repository " + repositoryName);
00afd7 184                 return null;
dfb889 185             }
JM 186             m = model;
f97bf0 187         }
JM 188         return m;
bc9d4a 189     }
dfb889 190
bc9d4a 191     protected RevCommit getCommit() {
JM 192         RevCommit commit = JGitUtils.getCommit(r, objectId);
193         if (commit == null) {
2a7306 194             error(MessageFormat.format("Failed to find commit \"{0}\" in {1} for {2} page!",
JM 195                     objectId, repositoryName, getPageName()), true);
bc9d4a 196         }
JM 197         return commit;
f97bf0 198     }
5fe7df 199
008322 200     protected String getShortObjectId(String objectId) {
JM 201         return objectId.substring(0, 8);
202     }
203
5fe7df 204     protected void addRefs(Repository r, RevCommit c) {
155bf7 205         add(new RefsPanel("refsPanel", repositoryName, c, JGitUtils.getAllRefs(r)));
5fe7df 206     }
JM 207
208     protected void addFullText(String wicketId, String text, boolean substituteRegex) {
f339f5 209         String html;
5fe7df 210         if (substituteRegex) {
8c9a20 211             html = GitBlit.self().processCommitMessage(repositoryName, text);
f339f5 212         } else {
JM 213             html = StringUtils.breakLinesForHtml(text);
214         }
215         add(new Label(wicketId, html).setEscapeModelStrings(false));
5fe7df 216     }
1e47ab 217
cebf45 218     protected abstract String getPageName();
5fe7df 219
2a7306 220     protected Component createPersonPanel(String wicketId, PersonIdent identity,
33d8d8 221             Constants.SearchType searchType) {
e11f48 222         String name = identity == null ? "" : identity.getName();
JM 223         String address = identity == null ? "" : identity.getEmailAddress();
2a7306 224         boolean showEmail = GitBlit.getBoolean(Keys.web.showEmailAddresses, false);
e11f48 225         if (!showEmail || StringUtils.isEmpty(name) || StringUtils.isEmpty(address)) {
JM 226             String value = name;
98ce17 227             if (StringUtils.isEmpty(value)) {
f5d0ad 228                 if (showEmail) {
e11f48 229                     value = address;
f5d0ad 230                 } else {
JM 231                     value = getString("gb.missingUsername");
232                 }
98ce17 233             }
JM 234             Fragment partial = new Fragment(wicketId, "partialPersonIdent", this);
2a7306 235             LinkPanel link = new LinkPanel("personName", "list", value, SearchPage.class,
JM 236                     WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType));
98ce17 237             setPersonSearchTooltip(link, value, searchType);
JM 238             partial.add(link);
239             return partial;
240         } else {
241             Fragment fullPerson = new Fragment(wicketId, "fullPersonIdent", this);
e11f48 242             LinkPanel nameLink = new LinkPanel("personName", "list", name, SearchPage.class,
JM 243                     WicketUtils.newSearchParameter(repositoryName, objectId, name, searchType));
244             setPersonSearchTooltip(nameLink, name, searchType);
98ce17 245             fullPerson.add(nameLink);
3e087a 246
e11f48 247             LinkPanel addressLink = new LinkPanel("personAddress", "list", "<" + address + ">",
JM 248                     SearchPage.class, WicketUtils.newSearchParameter(repositoryName, objectId,
249                             address, searchType));
250             setPersonSearchTooltip(addressLink, address, searchType);
98ce17 251             fullPerson.add(addressLink);
JM 252             return fullPerson;
253         }
254     }
3e087a 255
11924d 256     protected void setPersonSearchTooltip(Component component, String value,
JM 257             Constants.SearchType searchType) {
33d8d8 258         if (searchType.equals(Constants.SearchType.AUTHOR)) {
1e8390 259             WicketUtils.setHtmlTooltip(component, getString("gb.searchForAuthor") + " " + value);
33d8d8 260         } else if (searchType.equals(Constants.SearchType.COMMITTER)) {
1e8390 261             WicketUtils.setHtmlTooltip(component, getString("gb.searchForCommitter") + " " + value);
98ce17 262         }
JM 263     }
3e087a 264
9bc17d 265     protected void setChangeTypeTooltip(Component container, ChangeType type) {
JM 266         switch (type) {
267         case ADD:
1e8390 268             WicketUtils.setHtmlTooltip(container, getString("gb.addition"));
9bc17d 269             break;
JM 270         case COPY:
271         case RENAME:
1e8390 272             WicketUtils.setHtmlTooltip(container, getString("gb.rename"));
9bc17d 273             break;
JM 274         case DELETE:
1e8390 275             WicketUtils.setHtmlTooltip(container, getString("gb.deletion"));
9bc17d 276             break;
JM 277         case MODIFY:
1e8390 278             WicketUtils.setHtmlTooltip(container, getString("gb.modification"));
9bc17d 279             break;
JM 280         }
281     }
3e087a 282
1e47ab 283     @Override
JM 284     protected void onBeforeRender() {
285         // dispose of repository object
286         if (r != null) {
287             r.close();
288             r = null;
289         }
290         // setup page header and footer
cebf45 291         setupPage(repositoryName, "/ " + getPageName());
1e47ab 292         super.onBeforeRender();
5fe7df 293     }
JM 294
295     protected PageParameters newRepositoryParameter() {
698678 296         return WicketUtils.newRepositoryParameter(repositoryName);
5fe7df 297     }
7ba0ec 298
5fe7df 299     protected PageParameters newCommitParameter() {
ef5c58 300         return WicketUtils.newObjectParameter(repositoryName, objectId);
5fe7df 301     }
7ba0ec 302
5fe7df 303     protected PageParameters newCommitParameter(String commitId) {
ef5c58 304         return WicketUtils.newObjectParameter(repositoryName, commitId);
5fe7df 305     }
JM 306
85c2e6 307     private static class SearchForm extends StatelessForm<Void> implements Serializable {
3e087a 308         private static final long serialVersionUID = 1L;
JM 309
310         private final String repositoryName;
311
312         private final IModel<String> searchBoxModel = new Model<String>("");
313
11924d 314         private final IModel<Constants.SearchType> searchTypeModel = new Model<Constants.SearchType>(
JM 315                 Constants.SearchType.COMMIT);
3e087a 316
JM 317         public SearchForm(String id, String repositoryName) {
318             super(id);
319             this.repositoryName = repositoryName;
11924d 320             DropDownChoice<Constants.SearchType> searchType = new DropDownChoice<Constants.SearchType>(
JM 321                     "searchType", Arrays.asList(Constants.SearchType.values()));
3e087a 322             searchType.setModel(searchTypeModel);
2a7306 323             add(searchType.setVisible(GitBlit.getBoolean(Keys.web.showSearchTypeSelection, false)));
3e087a 324             TextField<String> searchBox = new TextField<String>("searchBox", searchBoxModel);
JM 325             add(searchBox);
326         }
bc9d4a 327
JM 328         void setTranslatedAttributes() {
3e087a 329             WicketUtils.setHtmlTooltip(get("searchType"), getString("gb.searchTypeTooltip"));
9e5bee 330             WicketUtils.setHtmlTooltip(get("searchBox"),
JM 331                     MessageFormat.format(getString("gb.searchTooltip"), repositoryName));
bc9d4a 332             WicketUtils.setInputPlaceholder(get("searchBox"), getString("gb.search"));
3e087a 333         }
JM 334
335         @Override
336         public void onSubmit() {
33d8d8 337             Constants.SearchType searchType = searchTypeModel.getObject();
3e087a 338             String searchString = searchBoxModel.getObject();
8c5d72 339             if (searchString == null) {
JM 340                 // FIXME IE intermittently has no searchString. Wicket bug?
341                 return;
342             }
33d8d8 343             for (Constants.SearchType type : Constants.SearchType.values()) {
3e087a 344                 if (searchString.toLowerCase().startsWith(type.name().toLowerCase() + ":")) {
JM 345                     searchType = type;
2a7306 346                     searchString = searchString.substring(type.name().toLowerCase().length() + 1)
JM 347                             .trim();
3e087a 348                     break;
JM 349                 }
350             }
2a7306 351             setResponsePage(SearchPage.class,
JM 352                     WicketUtils.newSearchParameter(repositoryName, null, searchString, searchType));
3e087a 353         }
JM 354     }
5fe7df 355 }