James Moger
2012-10-23 2d48e28bf1068b20129b2e3d5b96ecaff48f9f2f
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
b0e164 18 import java.text.MessageFormat;
13a3f5 19 import java.util.ArrayList;
JM 20 import java.util.Calendar;
21 import java.util.Collections;
22 import java.util.Date;
23 import java.util.HashSet;
f98825 24 import java.util.LinkedHashMap;
13a3f5 25 import java.util.List;
f98825 26 import java.util.Map;
9adf62 27 import java.util.ResourceBundle;
13a3f5 28 import java.util.Set;
bc10f9 29 import java.util.TimeZone;
13a3f5 30 import java.util.regex.Pattern;
bc10f9 31
85c2e6 32 import javax.servlet.http.Cookie;
cebf45 33 import javax.servlet.http.HttpServletRequest;
JM 34
3cc6e2 35 import org.apache.wicket.Application;
20165d 36 import org.apache.wicket.MarkupContainer;
5fe7df 37 import org.apache.wicket.PageParameters;
d97e52 38 import org.apache.wicket.RedirectToUrlException;
1e1b85 39 import org.apache.wicket.RequestCycle;
85c2e6 40 import org.apache.wicket.RestartResponseException;
62cec2 41 import org.apache.wicket.markup.html.CSSPackageResource;
5fe7df 42 import org.apache.wicket.markup.html.WebPage;
JM 43 import org.apache.wicket.markup.html.basic.Label;
20165d 44 import org.apache.wicket.markup.html.link.BookmarkablePageLink;
94750e 45 import org.apache.wicket.markup.html.link.ExternalLink;
c1c3c6 46 import org.apache.wicket.markup.html.panel.FeedbackPanel;
20165d 47 import org.apache.wicket.markup.html.panel.Fragment;
d97e52 48 import org.apache.wicket.protocol.http.RequestUtils;
85c2e6 49 import org.apache.wicket.protocol.http.WebRequest;
JM 50 import org.apache.wicket.protocol.http.WebResponse;
cebf45 51 import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
5fe7df 52 import org.slf4j.Logger;
JM 53 import org.slf4j.LoggerFactory;
54
cebf45 55 import com.gitblit.Constants;
b0e164 56 import com.gitblit.Constants.AccessPermission;
f98825 57 import com.gitblit.Constants.AccessRestrictionType;
831469 58 import com.gitblit.Constants.FederationStrategy;
87cc1e 59 import com.gitblit.GitBlit;
155bf7 60 import com.gitblit.Keys;
13a3f5 61 import com.gitblit.models.ProjectModel;
e21181 62 import com.gitblit.models.RepositoryModel;
13a3f5 63 import com.gitblit.models.TeamModel;
85c2e6 64 import com.gitblit.models.UserModel;
13a3f5 65 import com.gitblit.utils.StringUtils;
9adf62 66 import com.gitblit.utils.TimeUtils;
1f9dae 67 import com.gitblit.wicket.GitBlitWebSession;
94750e 68 import com.gitblit.wicket.WicketUtils;
1f9dae 69 import com.gitblit.wicket.panels.LinkPanel;
5fe7df 70
JM 71 public abstract class BasePage extends WebPage {
72
87cc1e 73     private final Logger logger;
9adf62 74     
JM 75     private transient TimeUtils timeUtils;
5fe7df 76
JM 77     public BasePage() {
78         super();
87cc1e 79         logger = LoggerFactory.getLogger(getClass());
62cec2 80         customizeHeader();
85f639 81         login();
5fe7df 82     }
JM 83
84     public BasePage(PageParameters params) {
85         super(params);
87cc1e 86         logger = LoggerFactory.getLogger(getClass());
62cec2 87         customizeHeader();
85f639 88         login();
85c2e6 89     }
3cc6e2 90     
62cec2 91     private void customizeHeader() {
JM 92         if (GitBlit.getBoolean(Keys.web.useResponsiveLayout, true)) {
93             add(CSSPackageResource.getHeaderContribution("bootstrap/css/bootstrap-responsive.css"));
94         }
95     }
96     
9adf62 97     protected String getLanguageCode() {
JM 98         return GitBlitWebSession.get().getLocale().getLanguage();
99     }
100     
101     protected TimeUtils getTimeUtils() {
102         if (timeUtils == null) {
103             ResourceBundle bundle;        
104             try {
105                 bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp", GitBlitWebSession.get().getLocale());
106             } catch (Throwable t) {
107                 bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp");
108             }
109             timeUtils = new TimeUtils(bundle);
110         }
111         return timeUtils;
112     }
113     
3cc6e2 114     @Override
JM 115     protected void onBeforeRender() {
116         if (GitBlit.isDebugMode()) {
117             // strip Wicket tags in debug mode for jQuery DOM traversal
118             Application.get().getMarkupSettings().setStripWicketTags(true);
119         }
120         super.onBeforeRender();
121     }
122
123     @Override
124     protected void onAfterRender() {
125         if (GitBlit.isDebugMode()) {
126             // restore Wicket debug tags
127             Application.get().getMarkupSettings().setStripWicketTags(false);
128         }
129         super.onAfterRender();
130     }    
85c2e6 131
85f639 132     private void login() {
85c2e6 133         Cookie[] cookies = ((WebRequest) getRequestCycle().getRequest()).getCookies();
85f639 134         UserModel user = null;
LM 135         if (GitBlit.self().allowCookieAuthentication() && cookies != null && cookies.length > 0) {
136             // Grab cookie from Browser Session
85c2e6 137             user = GitBlit.self().authenticate(cookies);
85f639 138         } else {
LM 139             user = GitBlit.self().authenticate(((WebRequest) getRequestCycle().getRequest()).getHttpServletRequest());
85c2e6 140         }
JM 141
142         // Login the user
143         if (user != null) {
144             // Set the user into the session
e78838 145             GitBlitWebSession session = GitBlitWebSession.get();
JM 146             // issue 62: fix session fixation vulnerability
147             session.replaceSession();
148             session.setUser(user);
85c2e6 149
JM 150             // Set Cookie
151             WebResponse response = (WebResponse) getRequestCycle().getResponse();
152             GitBlit.self().setCookie(response, user);
d97e52 153             
JM 154             session.continueRequest();
85c2e6 155         }
5fe7df 156     }
155bf7 157
cebf45 158     protected void setupPage(String repositoryName, String pageName) {
JM 159         if (repositoryName != null && repositoryName.trim().length() > 0) {
160             add(new Label("title", getServerName() + " - " + repositoryName));
161         } else {
162             add(new Label("title", getServerName()));
163         }
155bf7 164
94750e 165         ExternalLink rootLink = new ExternalLink("rootLink", urlFor(RepositoriesPage.class, null).toString());
JM 166         WicketUtils.setHtmlTooltip(rootLink, GitBlit.getString(Keys.web.siteName, Constants.NAME));
167         add(rootLink);
168
c1c3c6 169         // Feedback panel for info, warning, and non-fatal error messages
JM 170         add(new FeedbackPanel("feedback"));
171
cebf45 172         // footer
2a7306 173         if (GitBlit.getBoolean(Keys.web.authenticateViewPages, true)
JM 174                 || GitBlit.getBoolean(Keys.web.authenticateAdminPages, true)) {
20165d 175             UserFragment userFragment = new UserFragment("userPanel", "userFragment", BasePage.this);
JM 176             add(userFragment);
94b96b 177         } else {
87cc1e 178             add(new Label("userPanel", ""));
94b96b 179         }
20165d 180
cebf45 181         add(new Label("gbVersion", "v" + Constants.VERSION));
2a7306 182         if (GitBlit.getBoolean(Keys.web.aggressiveHeapManagement, false)) {
cebf45 183             System.gc();
JM 184         }
185     }
155bf7 186
f98825 187     protected Map<AccessRestrictionType, String> getAccessRestrictions() {
JM 188         Map<AccessRestrictionType, String> map = new LinkedHashMap<AccessRestrictionType, String>();
189         for (AccessRestrictionType type : AccessRestrictionType.values()) {
190             switch (type) {
191             case NONE:
192                 map.put(type, getString("gb.notRestricted"));
193                 break;
194             case PUSH:
195                 map.put(type, getString("gb.pushRestricted"));
196                 break;
197             case CLONE:
198                 map.put(type, getString("gb.cloneRestricted"));
199                 break;
200             case VIEW:
201                 map.put(type, getString("gb.viewRestricted"));
202                 break;
203             }
204         }
205         return map;
206     }
831469 207     
b0e164 208     protected Map<AccessPermission, String> getAccessPermissions() {
JM 209         Map<AccessPermission, String> map = new LinkedHashMap<AccessPermission, String>();
210         for (AccessPermission type : AccessPermission.values()) {
211             switch (type) {
212             case NONE:
213                 map.put(type, MessageFormat.format(getString("gb.noPermission"), type.code));
214                 break;
2d48e2 215             case EXCLUDE:
JM 216                 map.put(type, MessageFormat.format(getString("gb.excludePermission"), type.code));
217                 break;
b0e164 218             case VIEW:
JM 219                 map.put(type, MessageFormat.format(getString("gb.viewPermission"), type.code));
220                 break;
221             case CLONE:
222                 map.put(type, MessageFormat.format(getString("gb.clonePermission"), type.code));
223                 break;
224             case PUSH:
225                 map.put(type, MessageFormat.format(getString("gb.pushPermission"), type.code));
226                 break;
227             case CREATE:
228                 map.put(type, MessageFormat.format(getString("gb.createPermission"), type.code));
229                 break;
230             case DELETE:
231                 map.put(type, MessageFormat.format(getString("gb.deletePermission"), type.code));
232                 break;
233             case REWIND:
234                 map.put(type, MessageFormat.format(getString("gb.rewindPermission"), type.code));
235                 break;
236             }
237         }
238         return map;
239     }
240     
831469 241     protected Map<FederationStrategy, String> getFederationTypes() {
JM 242         Map<FederationStrategy, String> map = new LinkedHashMap<FederationStrategy, String>();
243         for (FederationStrategy type : FederationStrategy.values()) {
244             switch (type) {
245             case EXCLUDE:
246                 map.put(type, getString("gb.excludeFromFederation"));
247                 break;
248             case FEDERATE_THIS:
249                 map.put(type, getString("gb.federateThis"));
250                 break;
251             case FEDERATE_ORIGIN:
252                 map.put(type, getString("gb.federateOrigin"));
253                 break;
254             }
255         }
256         return map;
257     }
f98825 258
bc10f9 259     protected TimeZone getTimeZone() {
2a7306 260         return GitBlit.getBoolean(Keys.web.useClientTimezone, false) ? GitBlitWebSession.get()
6c6e7d 261                 .getTimezone() : GitBlit.getTimezone();
bc10f9 262     }
155bf7 263
cebf45 264     protected String getServerName() {
JM 265         ServletWebRequest servletWebRequest = (ServletWebRequest) getRequest();
266         HttpServletRequest req = servletWebRequest.getHttpServletRequest();
267         return req.getServerName();
268     }
e21181 269     
1e1b85 270     public static String getRepositoryUrl(RepositoryModel repository) {
e21181 271         StringBuilder sb = new StringBuilder();
1e1b85 272         sb.append(WicketUtils.getGitblitURL(RequestCycle.get().getRequest()));
e21181 273         sb.append(Constants.GIT_PATH);
JM 274         sb.append(repository.name);
275         
276         // inject username into repository url if authentication is required
277         if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE)
278                 && GitBlitWebSession.get().isLoggedIn()) {
d97e52 279             String username = GitBlitWebSession.get().getUsername();
e21181 280             sb.insert(sb.indexOf("://") + 3, username + "@");
JM 281         }
282         return sb.toString();
283     }
13a3f5 284     
JM 285     protected List<ProjectModel> getProjectModels() {
286         final UserModel user = GitBlitWebSession.get().getUser();
1e1b85 287         List<ProjectModel> projects = GitBlit.self().getProjectModels(user, true);
13a3f5 288         return projects;
JM 289     }
290     
291     protected List<ProjectModel> getProjects(PageParameters params) {
292         if (params == null) {
293             return getProjectModels();
294         }
295
296         boolean hasParameter = false;
297         String regex = WicketUtils.getRegEx(params);
298         String team = WicketUtils.getTeam(params);
299         int daysBack = params.getInt("db", 0);
300
301         List<ProjectModel> availableModels = getProjectModels();
302         Set<ProjectModel> models = new HashSet<ProjectModel>();
303
304         if (!StringUtils.isEmpty(regex)) {
305             // filter the projects by the regex
306             hasParameter = true;
307             Pattern pattern = Pattern.compile(regex);
308             for (ProjectModel model : availableModels) {
309                 if (pattern.matcher(model.name).find()) {
310                     models.add(model);
311                 }
312             }
313         }
314
315         if (!StringUtils.isEmpty(team)) {
316             // filter the projects by the specified teams
317             hasParameter = true;
318             List<String> teams = StringUtils.getStringsFromValue(team, ",");
319
320             // need TeamModels first
321             List<TeamModel> teamModels = new ArrayList<TeamModel>();
322             for (String name : teams) {
323                 TeamModel teamModel = GitBlit.self().getTeamModel(name);
324                 if (teamModel != null) {
325                     teamModels.add(teamModel);
326                 }
327             }
328
329             // brute-force our way through finding the matching models
330             for (ProjectModel projectModel : availableModels) {
331                 for (String repositoryName : projectModel.repositories) {
332                     for (TeamModel teamModel : teamModels) {
20714a 333                         if (teamModel.hasRepositoryPermission(repositoryName)) {
13a3f5 334                             models.add(projectModel);
JM 335                         }
336                     }
337                 }
338             }
339         }
340
341         if (!hasParameter) {
342             models.addAll(availableModels);
343         }
344
345         // time-filter the list
346         if (daysBack > 0) {
347             Calendar cal = Calendar.getInstance();
348             cal.set(Calendar.HOUR_OF_DAY, 0);
349             cal.set(Calendar.MINUTE, 0);
350             cal.set(Calendar.SECOND, 0);
351             cal.set(Calendar.MILLISECOND, 0);
352             cal.add(Calendar.DATE, -1 * daysBack);
353             Date threshold = cal.getTime();
354             Set<ProjectModel> timeFiltered = new HashSet<ProjectModel>();
355             for (ProjectModel model : models) {
356                 if (model.lastChange.after(threshold)) {
357                     timeFiltered.add(model);
358                 }
359             }
360             models = timeFiltered;
361         }
362
363         List<ProjectModel> list = new ArrayList<ProjectModel>(models);
364         Collections.sort(list);
365         return list;
366     }
85c2e6 367
5450d0 368     public void warn(String message, Throwable t) {
JM 369         logger.warn(message, t);
370     }
13a3f5 371     
bc9d4a 372     public void error(String message, boolean redirect) {
d97e52 373         logger.error(message  + " for " + GitBlitWebSession.get().getUsername());
bc9d4a 374         if (redirect) {
JM 375             GitBlitWebSession.get().cacheErrorMessage(message);
d97e52 376             String relativeUrl = urlFor(RepositoriesPage.class, null).toString();
JM 377             String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
378             throw new RedirectToUrlException(absoluteUrl);
bc9d4a 379         } else {
JM 380             super.error(message);
381         }
382     }
383
384     public void error(String message, Throwable t, boolean redirect) {
5fe7df 385         logger.error(message, t);
bc9d4a 386         if (redirect) {
JM 387             GitBlitWebSession.get().cacheErrorMessage(message);
85c2e6 388             throw new RestartResponseException(getApplication().getHomePage());
bc9d4a 389         } else {
JM 390             super.error(message);
391         }
5fe7df 392     }
85c2e6 393
JM 394     public void authenticationError(String message) {
d97e52 395         logger.error(getRequest().getURL() + " for " + GitBlitWebSession.get().getUsername());
JM 396         if (!GitBlitWebSession.get().isLoggedIn()) {
397             // cache the request if we have not authenticated.
398             // the request will continue after authentication.
399             GitBlitWebSession.get().cacheRequest(getClass());
85c2e6 400         }
d97e52 401         error(message, true);
85c2e6 402     }
20165d 403
JM 404     /**
405      * Panel fragment for displaying login or logout/change_password links.
406      * 
407      */
88598b 408     static class UserFragment extends Fragment {
20165d 409
JM 410         private static final long serialVersionUID = 1L;
411
412         public UserFragment(String id, String markupId, MarkupContainer markupProvider) {
413             super(id, markupId, markupProvider);
414
415             if (GitBlitWebSession.get().isLoggedIn()) {
416                 // username, logout, and change password
4682d1 417                 add(new Label("username", GitBlitWebSession.get().getUser().getDisplayName() + ":"));
20165d 418                 add(new LinkPanel("loginLink", null, markupProvider.getString("gb.logout"),
JM 419                         LogoutPage.class));
6cca86 420                 boolean editCredentials = GitBlit.self().supportsCredentialChanges();
88598b 421                 // quick and dirty hack for showing a separator
6cca86 422                 add(new Label("separator", "|").setVisible(editCredentials));
JM 423                 add(new BookmarkablePageLink<Void>("changePasswordLink", 
424                         ChangePasswordPage.class).setVisible(editCredentials));
20165d 425             } else {
JM 426                 // login
427                 add(new Label("username").setVisible(false));
a7571b 428                 add(new Label("loginLink").setVisible(false));
20165d 429                 add(new Label("separator").setVisible(false));
JM 430                 add(new Label("changePasswordLink").setVisible(false));
431             }
432         }
433     }
5fe7df 434 }