lemval
2012-01-31 1c30dad2115fc513791d8a5b292ad0f7d7b85749
commit | author | age
a7571b 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  */
16 package com.gitblit.wicket.pages;
17
18 import java.text.MessageFormat;
9e5bee 19 import java.util.ArrayList;
bc57cd 20 import java.util.Arrays;
JM 21 import java.util.Calendar;
a22eb4 22 import java.util.Collections;
bc57cd 23 import java.util.Date;
a22eb4 24 import java.util.HashMap;
bc57cd 25 import java.util.HashSet;
31bcbe 26 import java.util.LinkedHashSet;
9e5bee 27 import java.util.List;
a22eb4 28 import java.util.Map;
31bcbe 29 import java.util.Set;
a22eb4 30 import java.util.concurrent.atomic.AtomicInteger;
cb57ec 31 import java.util.regex.Pattern;
a7571b 32
d376ab 33 import org.apache.wicket.PageParameters;
a7571b 34 import org.apache.wicket.markup.html.form.PasswordTextField;
JM 35 import org.apache.wicket.markup.html.form.StatelessForm;
36 import org.apache.wicket.markup.html.form.TextField;
37 import org.apache.wicket.model.IModel;
38 import org.apache.wicket.model.Model;
39 import org.apache.wicket.protocol.http.WebResponse;
40
41 import com.gitblit.Constants;
42 import com.gitblit.GitBlit;
43 import com.gitblit.Keys;
cb57ec 44 import com.gitblit.models.RepositoryModel;
JM 45 import com.gitblit.models.TeamModel;
a7571b 46 import com.gitblit.models.UserModel;
JM 47 import com.gitblit.utils.StringUtils;
48 import com.gitblit.wicket.GitBlitWebSession;
9e5bee 49 import com.gitblit.wicket.PageRegistration;
31bcbe 50 import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
8c5d72 51 import com.gitblit.wicket.WicketUtils;
9e5bee 52 import com.gitblit.wicket.panels.NavigationPanel;
a7571b 53
d376ab 54 /**
JM 55  * Root page is a topbar, navigable page like Repositories, Users, or
56  * Federation.
57  * 
58  * @author James Moger
59  * 
60  */
a7571b 61 public abstract class RootPage extends BasePage {
JM 62
d376ab 63     boolean showAdmin;
a7571b 64
JM 65     IModel<String> username = new Model<String>("");
66     IModel<String> password = new Model<String>("");
67
68     public RootPage() {
69         super();
d376ab 70     }
a7571b 71
d376ab 72     public RootPage(PageParameters params) {
JM 73         super(params);
74     }
a7571b 75
d376ab 76     @Override
JM 77     protected void setupPage(String repositoryName, String pageName) {
31bcbe 78         boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, false);
JM 79         boolean authenticateAdmin = GitBlit.getBoolean(Keys.web.authenticateAdminPages, true);
80         boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, true);
a22eb4 81
JM 82         if (authenticateAdmin) {
a7571b 83             showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin();
JM 84             // authentication requires state and session
85             setStatelessHint(false);
86         } else {
31bcbe 87             showAdmin = allowAdmin;
JM 88             if (authenticateView) {
a7571b 89                 // authentication requires state and session
JM 90                 setStatelessHint(false);
91             } else {
92                 // no authentication required, no state and no session required
93                 setStatelessHint(true);
94             }
95         }
96         boolean showRegistrations = GitBlit.canFederate()
97                 && GitBlit.getBoolean(Keys.web.showFederationRegistrations, false);
98
99         // navigation links
9e5bee 100         List<PageRegistration> pages = new ArrayList<PageRegistration>();
bc57cd 101         pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class,
JM 102                 getRootPageParameters()));
7f14da 103         pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters()));
9e5bee 104         if (showAdmin) {
JM 105             pages.add(new PageRegistration("gb.users", UsersPage.class));
106         }
107         if (showAdmin || showRegistrations) {
108             pages.add(new PageRegistration("gb.federation", FederationPage.class));
cb57ec 109         }
31bcbe 110
JM 111         if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) {
112             addDropDownMenus(pages);
113         }
114
9e5bee 115         NavigationPanel navPanel = new NavigationPanel("navPanel", getClass(), pages);
JM 116         add(navPanel);
a7571b 117
JM 118         // login form
119         StatelessForm<Void> loginForm = new StatelessForm<Void>("loginForm") {
120
121             private static final long serialVersionUID = 1L;
122
123             @Override
124             public void onSubmit() {
125                 String username = RootPage.this.username.getObject();
126                 char[] password = RootPage.this.password.getObject().toCharArray();
127
128                 UserModel user = GitBlit.self().authenticate(username, password);
129                 if (user == null) {
130                     error("Invalid username or password!");
131                 } else if (user.username.equals(Constants.FEDERATION_USER)) {
132                     // disallow the federation user from logging in via the
133                     // web ui
134                     error("Invalid username or password!");
135                     user = null;
136                 } else {
137                     loginUser(user);
138                 }
139             }
140         };
8c5d72 141         TextField<String> unameField = new TextField<String>("username", username);
JM 142         WicketUtils.setInputPlaceholder(unameField, getString("gb.username"));
143         loginForm.add(unameField);
144         PasswordTextField pwField = new PasswordTextField("password", password);
145         WicketUtils.setInputPlaceholder(pwField, getString("gb.password"));
146         loginForm.add(pwField);
a7571b 147         add(loginForm);
a22eb4 148
31bcbe 149         if (authenticateView || authenticateAdmin) {
a7571b 150             loginForm.setVisible(!GitBlitWebSession.get().isLoggedIn());
JM 151         } else {
152             loginForm.setVisible(false);
153         }
154
155         // display an error message cached from a redirect
156         String cachedMessage = GitBlitWebSession.get().clearErrorMessage();
157         if (!StringUtils.isEmpty(cachedMessage)) {
158             error(cachedMessage);
159         } else if (showAdmin) {
160             int pendingProposals = GitBlit.self().getPendingFederationProposals().size();
161             if (pendingProposals == 1) {
162                 info("There is 1 federation proposal awaiting review.");
163             } else if (pendingProposals > 1) {
164                 info(MessageFormat.format("There are {0} federation proposals awaiting review.",
165                         pendingProposals));
166             }
167         }
168
d376ab 169         super.setupPage(repositoryName, pageName);
a7571b 170     }
bc57cd 171
7f14da 172     private PageParameters getRootPageParameters() {
bc57cd 173         if (reusePageParameters()) {
8f86e2 174             PageParameters pp = getPageParameters();
JM 175             if (pp != null) {
176                 PageParameters params = new PageParameters(pp);
bc57cd 177                 // remove named repository parameter
JM 178                 params.remove("r");
8f86e2 179
JM 180                 // remove days back parameter if it is the default value
181                 if (params.containsKey("db")
182                         && params.getInt("db") == GitBlit.getInteger(Keys.web.activityDuration, 14)) {
183                     params.remove("db");
184                 }
185                 return params;
186             }            
7f14da 187         }
bc57cd 188         return null;
JM 189     }
190
191     protected boolean reusePageParameters() {
192         return false;
7f14da 193     }
a7571b 194
JM 195     private void loginUser(UserModel user) {
196         if (user != null) {
197             // Set the user into the session
198             GitBlitWebSession.get().setUser(user);
199
200             // Set Cookie
201             if (GitBlit.getBoolean(Keys.web.allowCookieAuthentication, false)) {
202                 WebResponse response = (WebResponse) getRequestCycle().getResponse();
203                 GitBlit.self().setCookie(response, user);
204             }
205
206             if (!continueToOriginalDestination()) {
207                 // Redirect to home page
208                 setResponsePage(getApplication().getHomePage());
209             }
210         }
31bcbe 211     }
JM 212
213     protected void addDropDownMenus(List<PageRegistration> pages) {
214
215     }
216
bc57cd 217     protected List<DropDownMenuItem> getRepositoryFilterItems(PageParameters params) {
31bcbe 218         final UserModel user = GitBlitWebSession.get().getUser();
JM 219         Set<DropDownMenuItem> filters = new LinkedHashSet<DropDownMenuItem>();
a22eb4 220         List<RepositoryModel> repositories = GitBlit.self().getRepositoryModels(user);
31bcbe 221
JM 222         // accessible repositories by federation set
a22eb4 223         Map<String, AtomicInteger> setMap = new HashMap<String, AtomicInteger>();
JM 224         for (RepositoryModel repository : repositories) {
31bcbe 225             for (String set : repository.federationSets) {
a22eb4 226                 String key = set.toLowerCase();
JM 227                 if (setMap.containsKey(key)) {
228                     setMap.get(key).incrementAndGet();
229                 } else {
230                     setMap.put(key, new AtomicInteger(1));
231                 }
31bcbe 232             }
JM 233         }
a22eb4 234         if (setMap.size() > 0) {
JM 235             List<String> sets = new ArrayList<String>(setMap.keySet());
236             Collections.sort(sets);
237             for (String set : sets) {
238                 filters.add(new DropDownMenuItem(MessageFormat.format("{0} ({1})", set,
bc57cd 239                         setMap.get(set).get()), "set", set, params));
a22eb4 240             }
31bcbe 241             // divider
JM 242             filters.add(new DropDownMenuItem());
243         }
244
245         // user's team memberships
246         if (user != null && user.teams.size() > 0) {
a22eb4 247             List<TeamModel> teams = new ArrayList<TeamModel>(user.teams);
JM 248             Collections.sort(teams);
249             for (TeamModel team : teams) {
250                 filters.add(new DropDownMenuItem(MessageFormat.format("{0} ({1})", team.name,
bc57cd 251                         team.repositories.size()), "team", team.name, params));
31bcbe 252             }
JM 253             // divider
254             filters.add(new DropDownMenuItem());
255         }
256
257         // custom filters
258         String customFilters = GitBlit.getString(Keys.web.customFilters, null);
259         if (!StringUtils.isEmpty(customFilters)) {
e76fee 260             boolean addedExpression = false;
31bcbe 261             List<String> expressions = StringUtils.getStringsFromValue(customFilters, "!!!");
JM 262             for (String expression : expressions) {
e76fee 263                 if (!StringUtils.isEmpty(expression)) {
JM 264                     addedExpression = true;
bc57cd 265                     filters.add(new DropDownMenuItem(null, "x", expression, params));
e76fee 266                 }
JM 267             }
268             // if we added any custom expressions, add a divider
269             if (addedExpression) {
270                 filters.add(new DropDownMenuItem());
31bcbe 271             }
8f86e2 272         }
31bcbe 273         return new ArrayList<DropDownMenuItem>(filters);
bc57cd 274     }
JM 275
276     protected List<DropDownMenuItem> getTimeFilterItems(PageParameters params) {
277         // days back choices - additive parameters
278         int daysBack = GitBlit.getInteger(Keys.web.activityDuration, 14);
279         if (daysBack < 1) {
280             daysBack = 14;
281         }
282         List<DropDownMenuItem> items = new ArrayList<DropDownMenuItem>();
283         Set<Integer> choicesSet = new HashSet<Integer>(Arrays.asList(daysBack, 14, 28, 60, 90, 180));
284         List<Integer> choices = new ArrayList<Integer>(choicesSet);
285         Collections.sort(choices);
286         for (Integer db : choices) {
287             String txt = "last " + db + (db.intValue() > 1 ? " days" : "day");
288             items.add(new DropDownMenuItem(txt, "db", db.toString(), params));
289         }
290         items.add(new DropDownMenuItem());
291         return items;
a7571b 292     }
cb57ec 293
JM 294     protected List<RepositoryModel> getRepositories(PageParameters params) {
295         final UserModel user = GitBlitWebSession.get().getUser();
296         if (params == null) {
297             return GitBlit.self().getRepositoryModels(user);
298         }
299
bc57cd 300         boolean hasParameter = false;
cb57ec 301         String repositoryName = WicketUtils.getRepositoryName(params);
JM 302         String set = WicketUtils.getSet(params);
303         String regex = WicketUtils.getRegEx(params);
304         String team = WicketUtils.getTeam(params);
bc57cd 305         int daysBack = params.getInt("db", 0);
cb57ec 306
bc57cd 307         List<RepositoryModel> availableModels = GitBlit.self().getRepositoryModels(user);
JM 308         Set<RepositoryModel> models = new HashSet<RepositoryModel>();
cb57ec 309
JM 310         if (!StringUtils.isEmpty(repositoryName)) {
311             // try named repository
bc57cd 312             hasParameter = true;
JM 313             for (RepositoryModel model : availableModels) {
314                 if (model.name.equalsIgnoreCase(repositoryName)) {
315                     models.add(model);
316                     break;
317                 }
cb57ec 318             }
JM 319         }
320
321         if (!StringUtils.isEmpty(regex)) {
322             // filter the repositories by the regex
bc57cd 323             hasParameter = true;
cb57ec 324             Pattern pattern = Pattern.compile(regex);
bc57cd 325             for (RepositoryModel model : availableModels) {
JM 326                 if (pattern.matcher(model.name).find()) {
327                     models.add(model);
cb57ec 328                 }
JM 329             }
bc57cd 330         }
JM 331
332         if (!StringUtils.isEmpty(set)) {
cb57ec 333             // filter the repositories by the specified sets
bc57cd 334             hasParameter = true;
cb57ec 335             List<String> sets = StringUtils.getStringsFromValue(set, ",");
bc57cd 336             for (RepositoryModel model : availableModels) {
cb57ec 337                 for (String curr : sets) {
JM 338                     if (model.federationSets.contains(curr)) {
bc57cd 339                         models.add(model);
cb57ec 340                     }
JM 341                 }
342             }
bc57cd 343         }
JM 344
345         if (!StringUtils.isEmpty(team)) {
cb57ec 346             // filter the repositories by the specified teams
bc57cd 347             hasParameter = true;
cb57ec 348             List<String> teams = StringUtils.getStringsFromValue(team, ",");
31bcbe 349
cb57ec 350             // need TeamModels first
JM 351             List<TeamModel> teamModels = new ArrayList<TeamModel>();
352             for (String name : teams) {
bc57cd 353                 TeamModel teamModel = GitBlit.self().getTeamModel(name);
JM 354                 if (teamModel != null) {
355                     teamModels.add(teamModel);
cb57ec 356                 }
JM 357             }
31bcbe 358
cb57ec 359             // brute-force our way through finding the matching models
bc57cd 360             for (RepositoryModel repositoryModel : availableModels) {
cb57ec 361                 for (TeamModel teamModel : teamModels) {
JM 362                     if (teamModel.hasRepository(repositoryModel.name)) {
bc57cd 363                         models.add(repositoryModel);
cb57ec 364                     }
JM 365                 }
366             }
367         }
bc57cd 368
JM 369         if (!hasParameter) {
370             models.addAll(availableModels);
371         }
8f86e2 372
bc57cd 373         // time-filter the list
JM 374         if (daysBack > 0) {
375             Calendar cal = Calendar.getInstance();
376             cal.set(Calendar.HOUR_OF_DAY, 0);
377             cal.set(Calendar.MINUTE, 0);
378             cal.set(Calendar.SECOND, 0);
379             cal.set(Calendar.MILLISECOND, 0);
380             cal.add(Calendar.DATE, -1 * daysBack);
381             Date threshold = cal.getTime();
382             Set<RepositoryModel> timeFiltered = new HashSet<RepositoryModel>();
383             for (RepositoryModel model : models) {
384                 if (model.lastChange.after(threshold)) {
385                     timeFiltered.add(model);
386                 }
387             }
388             models = timeFiltered;
389         }
390         return new ArrayList<RepositoryModel>(models);
cb57ec 391     }
a7571b 392 }