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