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.

преди 13 години
преди 12 години
преди 12 години
преди 12 години
преди 11 години
преди 12 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 13 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  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.text.MessageFormat;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Calendar;
  21. import java.util.Collections;
  22. import java.util.Date;
  23. import java.util.HashMap;
  24. import java.util.HashSet;
  25. import java.util.LinkedHashSet;
  26. import java.util.List;
  27. import java.util.Map;
  28. import java.util.Set;
  29. import java.util.TreeSet;
  30. import java.util.concurrent.atomic.AtomicInteger;
  31. import java.util.regex.Pattern;
  32. import org.apache.wicket.MarkupContainer;
  33. import org.apache.wicket.PageParameters;
  34. import org.apache.wicket.behavior.HeaderContributor;
  35. import org.apache.wicket.markup.html.IHeaderContributor;
  36. import org.apache.wicket.markup.html.IHeaderResponse;
  37. import org.apache.wicket.markup.html.basic.Label;
  38. import org.apache.wicket.markup.html.form.PasswordTextField;
  39. import org.apache.wicket.markup.html.form.TextField;
  40. import org.apache.wicket.markup.html.link.BookmarkablePageLink;
  41. import org.apache.wicket.markup.html.panel.Fragment;
  42. import org.apache.wicket.model.IModel;
  43. import org.apache.wicket.model.Model;
  44. import org.apache.wicket.protocol.http.WebResponse;
  45. import com.gitblit.Constants;
  46. import com.gitblit.Keys;
  47. import com.gitblit.models.RepositoryModel;
  48. import com.gitblit.models.TeamModel;
  49. import com.gitblit.models.UserModel;
  50. import com.gitblit.utils.ModelUtils;
  51. import com.gitblit.utils.StringUtils;
  52. import com.gitblit.wicket.GitBlitWebSession;
  53. import com.gitblit.wicket.PageRegistration;
  54. import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
  55. import com.gitblit.wicket.PageRegistration.DropDownToggleItem;
  56. import com.gitblit.wicket.SessionlessForm;
  57. import com.gitblit.wicket.WicketUtils;
  58. import com.gitblit.wicket.panels.GravatarImage;
  59. import com.gitblit.wicket.panels.NavigationPanel;
  60. /**
  61. * Root page is a topbar, navigable page like Repositories, Users, or
  62. * Federation.
  63. *
  64. * @author James Moger
  65. *
  66. */
  67. public abstract class RootPage extends BasePage {
  68. boolean showAdmin;
  69. IModel<String> username = new Model<String>("");
  70. IModel<String> password = new Model<String>("");
  71. List<RepositoryModel> repositoryModels = new ArrayList<RepositoryModel>();
  72. public RootPage() {
  73. super();
  74. }
  75. public RootPage(PageParameters params) {
  76. super(params);
  77. }
  78. @Override
  79. protected void setupPage(String repositoryName, String pageName) {
  80. // CSS header overrides
  81. add(new HeaderContributor(new IHeaderContributor() {
  82. private static final long serialVersionUID = 1L;
  83. @Override
  84. public void renderHead(IHeaderResponse response) {
  85. StringBuilder buffer = new StringBuilder();
  86. buffer.append("<style type=\"text/css\">\n");
  87. buffer.append(".navbar-inner {\n");
  88. final String headerBackground = app().settings().getString(Keys.web.headerBackgroundColor, null);
  89. if (!StringUtils.isEmpty(headerBackground)) {
  90. buffer.append(MessageFormat.format("background-color: {0};\n", headerBackground));
  91. }
  92. final String headerBorder = app().settings().getString(Keys.web.headerBorderColor, null);
  93. if (!StringUtils.isEmpty(headerBorder)) {
  94. buffer.append(MessageFormat.format("border-bottom: 1px solid {0} !important;\n", headerBorder));
  95. }
  96. buffer.append("}\n");
  97. final String headerBorderFocus = app().settings().getString(Keys.web.headerBorderFocusColor, null);
  98. if (!StringUtils.isEmpty(headerBorderFocus)) {
  99. buffer.append(".navbar ul li:focus, .navbar .active {\n");
  100. buffer.append(MessageFormat.format("border-bottom: 4px solid {0};\n", headerBorderFocus));
  101. buffer.append("}\n");
  102. }
  103. final String headerForeground = app().settings().getString(Keys.web.headerForegroundColor, null);
  104. if (!StringUtils.isEmpty(headerForeground)) {
  105. buffer.append(".navbar ul.nav li a {\n");
  106. buffer.append(MessageFormat.format("color: {0};\n", headerForeground));
  107. buffer.append("}\n");
  108. buffer.append(".navbar ul.nav .active a {\n");
  109. buffer.append(MessageFormat.format("color: {0};\n", headerForeground));
  110. buffer.append("}\n");
  111. }
  112. final String headerHover = app().settings().getString(Keys.web.headerHoverColor, null);
  113. if (!StringUtils.isEmpty(headerHover)) {
  114. buffer.append(".navbar ul.nav li a:hover {\n");
  115. buffer.append(MessageFormat.format("color: {0} !important;\n", headerHover));
  116. buffer.append("}\n");
  117. }
  118. buffer.append("</style>\n");
  119. response.renderString(buffer.toString());
  120. }
  121. }));
  122. boolean authenticateView = app().settings().getBoolean(Keys.web.authenticateViewPages, false);
  123. boolean authenticateAdmin = app().settings().getBoolean(Keys.web.authenticateAdminPages, true);
  124. boolean allowAdmin = app().settings().getBoolean(Keys.web.allowAdministration, true);
  125. if (authenticateAdmin) {
  126. showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin();
  127. // authentication requires state and session
  128. setStatelessHint(false);
  129. } else {
  130. showAdmin = allowAdmin;
  131. if (authenticateView) {
  132. // authentication requires state and session
  133. setStatelessHint(false);
  134. } else {
  135. // no authentication required, no state and no session required
  136. setStatelessHint(true);
  137. }
  138. }
  139. if (authenticateView || authenticateAdmin) {
  140. if (GitBlitWebSession.get().isLoggedIn()) {
  141. UserMenu userFragment = new UserMenu("userPanel", "userMenuFragment", RootPage.this);
  142. add(userFragment);
  143. } else {
  144. LoginForm loginForm = new LoginForm("userPanel", "loginFormFragment", RootPage.this);
  145. add(loginForm);
  146. }
  147. } else {
  148. add(new Label("userPanel").setVisible(false));
  149. }
  150. boolean showRegistrations = app().federation().canFederate()
  151. && app().settings().getBoolean(Keys.web.showFederationRegistrations, false);
  152. // navigation links
  153. List<PageRegistration> pages = new ArrayList<PageRegistration>();
  154. if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) {
  155. pages.add(new PageRegistration(GitBlitWebSession.get().isLoggedIn() ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class,
  156. getRootPageParameters()));
  157. pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class,
  158. getRootPageParameters()));
  159. pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters()));
  160. if (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) {
  161. pages.add(new PageRegistration("gb.search", LuceneSearchPage.class));
  162. }
  163. if (showAdmin) {
  164. pages.add(new PageRegistration("gb.users", UsersPage.class));
  165. }
  166. if (showAdmin || showRegistrations) {
  167. pages.add(new PageRegistration("gb.federation", FederationPage.class));
  168. }
  169. if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) {
  170. addDropDownMenus(pages);
  171. }
  172. }
  173. NavigationPanel navPanel = new NavigationPanel("navPanel", getRootNavPageClass(), pages);
  174. add(navPanel);
  175. // display an error message cached from a redirect
  176. String cachedMessage = GitBlitWebSession.get().clearErrorMessage();
  177. if (!StringUtils.isEmpty(cachedMessage)) {
  178. error(cachedMessage);
  179. } else if (showAdmin) {
  180. int pendingProposals = app().federation().getPendingFederationProposals().size();
  181. if (pendingProposals == 1) {
  182. info(getString("gb.OneProposalToReview"));
  183. } else if (pendingProposals > 1) {
  184. info(MessageFormat.format(getString("gb.nFederationProposalsToReview"),
  185. pendingProposals));
  186. }
  187. }
  188. super.setupPage(repositoryName, pageName);
  189. }
  190. protected Class<? extends BasePage> getRootNavPageClass() {
  191. return getClass();
  192. }
  193. private PageParameters getRootPageParameters() {
  194. if (reusePageParameters()) {
  195. PageParameters pp = getPageParameters();
  196. if (pp != null) {
  197. PageParameters params = new PageParameters(pp);
  198. // remove named project parameter
  199. params.remove("p");
  200. // remove named repository parameter
  201. params.remove("r");
  202. // remove named user parameter
  203. params.remove("user");
  204. // remove days back parameter if it is the default value
  205. if (params.containsKey("db")
  206. && params.getInt("db") == app().settings().getInteger(Keys.web.activityDuration, 7)) {
  207. params.remove("db");
  208. }
  209. return params;
  210. }
  211. }
  212. return null;
  213. }
  214. protected boolean reusePageParameters() {
  215. return false;
  216. }
  217. private void loginUser(UserModel user) {
  218. if (user != null) {
  219. // Set the user into the session
  220. GitBlitWebSession session = GitBlitWebSession.get();
  221. // issue 62: fix session fixation vulnerability
  222. session.replaceSession();
  223. session.setUser(user);
  224. // Set Cookie
  225. if (app().settings().getBoolean(Keys.web.allowCookieAuthentication, false)) {
  226. WebResponse response = (WebResponse) getRequestCycle().getResponse();
  227. app().authentication().setCookie(response.getHttpServletResponse(), user);
  228. }
  229. if (!session.continueRequest()) {
  230. PageParameters params = getPageParameters();
  231. if (params == null) {
  232. // redirect to this page
  233. setResponsePage(getClass());
  234. } else {
  235. // Strip username and password and redirect to this page
  236. params.remove("username");
  237. params.remove("password");
  238. setResponsePage(getClass(), params);
  239. }
  240. }
  241. }
  242. }
  243. protected List<RepositoryModel> getRepositoryModels() {
  244. if (repositoryModels.isEmpty()) {
  245. final UserModel user = GitBlitWebSession.get().getUser();
  246. List<RepositoryModel> repositories = app().repositories().getRepositoryModels(user);
  247. repositoryModels.addAll(repositories);
  248. Collections.sort(repositoryModels);
  249. }
  250. return repositoryModels;
  251. }
  252. protected void addDropDownMenus(List<PageRegistration> pages) {
  253. }
  254. protected List<DropDownMenuItem> getRepositoryFilterItems(PageParameters params) {
  255. final UserModel user = GitBlitWebSession.get().getUser();
  256. Set<DropDownMenuItem> filters = new LinkedHashSet<DropDownMenuItem>();
  257. List<RepositoryModel> repositories = getRepositoryModels();
  258. // accessible repositories by federation set
  259. Map<String, AtomicInteger> setMap = new HashMap<String, AtomicInteger>();
  260. for (RepositoryModel repository : repositories) {
  261. for (String set : repository.federationSets) {
  262. String key = set.toLowerCase();
  263. if (setMap.containsKey(key)) {
  264. setMap.get(key).incrementAndGet();
  265. } else {
  266. setMap.put(key, new AtomicInteger(1));
  267. }
  268. }
  269. }
  270. if (setMap.size() > 0) {
  271. List<String> sets = new ArrayList<String>(setMap.keySet());
  272. Collections.sort(sets);
  273. for (String set : sets) {
  274. filters.add(new DropDownToggleItem(MessageFormat.format("{0} ({1})", set,
  275. setMap.get(set).get()), "set", set, params));
  276. }
  277. // divider
  278. filters.add(new DropDownMenuItem());
  279. }
  280. // user's team memberships
  281. if (user != null && user.teams.size() > 0) {
  282. List<TeamModel> teams = new ArrayList<TeamModel>(user.teams);
  283. Collections.sort(teams);
  284. for (TeamModel team : teams) {
  285. filters.add(new DropDownToggleItem(MessageFormat.format("{0} ({1})", team.name,
  286. team.repositories.size()), "team", team.name, params));
  287. }
  288. // divider
  289. filters.add(new DropDownMenuItem());
  290. }
  291. // custom filters
  292. String customFilters = app().settings().getString(Keys.web.customFilters, null);
  293. if (!StringUtils.isEmpty(customFilters)) {
  294. boolean addedExpression = false;
  295. List<String> expressions = StringUtils.getStringsFromValue(customFilters, "!!!");
  296. for (String expression : expressions) {
  297. if (!StringUtils.isEmpty(expression)) {
  298. addedExpression = true;
  299. filters.add(new DropDownToggleItem(null, "x", expression, params));
  300. }
  301. }
  302. // if we added any custom expressions, add a divider
  303. if (addedExpression) {
  304. filters.add(new DropDownMenuItem());
  305. }
  306. }
  307. return new ArrayList<DropDownMenuItem>(filters);
  308. }
  309. protected List<DropDownMenuItem> getTimeFilterItems(PageParameters params) {
  310. // days back choices - additive parameters
  311. int daysBack = app().settings().getInteger(Keys.web.activityDuration, 7);
  312. int maxDaysBack = app().settings().getInteger(Keys.web.activityDurationMaximum, 30);
  313. if (daysBack < 1) {
  314. daysBack = 7;
  315. }
  316. if (daysBack > maxDaysBack) {
  317. daysBack = maxDaysBack;
  318. }
  319. PageParameters clonedParams;
  320. if (params == null) {
  321. clonedParams = new PageParameters();
  322. } else {
  323. clonedParams = new PageParameters(params);
  324. }
  325. if (!clonedParams.containsKey("db")) {
  326. clonedParams.put("db", daysBack);
  327. }
  328. List<DropDownMenuItem> items = new ArrayList<DropDownMenuItem>();
  329. Set<Integer> choicesSet = new TreeSet<Integer>(app().settings().getIntegers(Keys.web.activityDurationChoices));
  330. if (choicesSet.isEmpty()) {
  331. choicesSet.addAll(Arrays.asList(1, 3, 7, 14, 21, 28));
  332. }
  333. List<Integer> choices = new ArrayList<Integer>(choicesSet);
  334. Collections.sort(choices);
  335. String lastDaysPattern = getString("gb.lastNDays");
  336. for (Integer db : choices) {
  337. if (db == 1) {
  338. items.add(new DropDownMenuItem(getString("gb.time.today"), "db", db.toString(), clonedParams));
  339. } else {
  340. String txt = MessageFormat.format(lastDaysPattern, db);
  341. items.add(new DropDownMenuItem(txt, "db", db.toString(), clonedParams));
  342. }
  343. }
  344. items.add(new DropDownMenuItem());
  345. return items;
  346. }
  347. protected List<RepositoryModel> getRepositories(PageParameters params) {
  348. if (params == null) {
  349. return getRepositoryModels();
  350. }
  351. boolean hasParameter = false;
  352. String projectName = WicketUtils.getProjectName(params);
  353. String userName = WicketUtils.getUsername(params);
  354. if (StringUtils.isEmpty(projectName)) {
  355. if (!StringUtils.isEmpty(userName)) {
  356. projectName = ModelUtils.getPersonalPath(userName);
  357. }
  358. }
  359. String repositoryName = WicketUtils.getRepositoryName(params);
  360. String set = WicketUtils.getSet(params);
  361. String regex = WicketUtils.getRegEx(params);
  362. String team = WicketUtils.getTeam(params);
  363. int daysBack = params.getInt("db", 0);
  364. int maxDaysBack = app().settings().getInteger(Keys.web.activityDurationMaximum, 30);
  365. List<RepositoryModel> availableModels = getRepositoryModels();
  366. Set<RepositoryModel> models = new HashSet<RepositoryModel>();
  367. if (!StringUtils.isEmpty(repositoryName)) {
  368. // try named repository
  369. hasParameter = true;
  370. for (RepositoryModel model : availableModels) {
  371. if (model.name.equalsIgnoreCase(repositoryName)) {
  372. models.add(model);
  373. break;
  374. }
  375. }
  376. }
  377. if (!StringUtils.isEmpty(projectName)) {
  378. // try named project
  379. hasParameter = true;
  380. if (projectName.equalsIgnoreCase(app().settings().getString(Keys.web.repositoryRootGroupName, "main"))) {
  381. // root project/group
  382. for (RepositoryModel model : availableModels) {
  383. if (model.name.indexOf('/') == -1) {
  384. models.add(model);
  385. }
  386. }
  387. } else {
  388. // named project/group
  389. String group = projectName.toLowerCase() + "/";
  390. for (RepositoryModel model : availableModels) {
  391. if (model.name.toLowerCase().startsWith(group)) {
  392. models.add(model);
  393. }
  394. }
  395. }
  396. }
  397. if (!StringUtils.isEmpty(regex)) {
  398. // filter the repositories by the regex
  399. hasParameter = true;
  400. Pattern pattern = Pattern.compile(regex);
  401. for (RepositoryModel model : availableModels) {
  402. if (pattern.matcher(model.name).find()) {
  403. models.add(model);
  404. }
  405. }
  406. }
  407. if (!StringUtils.isEmpty(set)) {
  408. // filter the repositories by the specified sets
  409. hasParameter = true;
  410. List<String> sets = StringUtils.getStringsFromValue(set, ",");
  411. for (RepositoryModel model : availableModels) {
  412. for (String curr : sets) {
  413. if (model.federationSets.contains(curr)) {
  414. models.add(model);
  415. }
  416. }
  417. }
  418. }
  419. if (!StringUtils.isEmpty(team)) {
  420. // filter the repositories by the specified teams
  421. hasParameter = true;
  422. List<String> teams = StringUtils.getStringsFromValue(team, ",");
  423. // need TeamModels first
  424. List<TeamModel> teamModels = new ArrayList<TeamModel>();
  425. for (String name : teams) {
  426. TeamModel teamModel = app().users().getTeamModel(name);
  427. if (teamModel != null) {
  428. teamModels.add(teamModel);
  429. }
  430. }
  431. // brute-force our way through finding the matching models
  432. for (RepositoryModel repositoryModel : availableModels) {
  433. for (TeamModel teamModel : teamModels) {
  434. if (teamModel.hasRepositoryPermission(repositoryModel.name)) {
  435. models.add(repositoryModel);
  436. }
  437. }
  438. }
  439. }
  440. if (!hasParameter) {
  441. models.addAll(availableModels);
  442. }
  443. // time-filter the list
  444. if (daysBack > 0) {
  445. if (maxDaysBack > 0 && daysBack > maxDaysBack) {
  446. daysBack = maxDaysBack;
  447. }
  448. Calendar cal = Calendar.getInstance();
  449. cal.set(Calendar.HOUR_OF_DAY, 0);
  450. cal.set(Calendar.MINUTE, 0);
  451. cal.set(Calendar.SECOND, 0);
  452. cal.set(Calendar.MILLISECOND, 0);
  453. cal.add(Calendar.DATE, -1 * daysBack);
  454. Date threshold = cal.getTime();
  455. Set<RepositoryModel> timeFiltered = new HashSet<RepositoryModel>();
  456. for (RepositoryModel model : models) {
  457. if (model.lastChange.after(threshold)) {
  458. timeFiltered.add(model);
  459. }
  460. }
  461. models = timeFiltered;
  462. }
  463. List<RepositoryModel> list = new ArrayList<RepositoryModel>(models);
  464. Collections.sort(list);
  465. return list;
  466. }
  467. /**
  468. * Inline login form.
  469. */
  470. private class LoginForm extends Fragment {
  471. private static final long serialVersionUID = 1L;
  472. public LoginForm(String id, String markupId, MarkupContainer markupProvider) {
  473. super(id, markupId, markupProvider);
  474. setRenderBodyOnly(true);
  475. SessionlessForm<Void> loginForm = new SessionlessForm<Void>("loginForm", RootPage.this.getClass(), getPageParameters()) {
  476. private static final long serialVersionUID = 1L;
  477. @Override
  478. public void onSubmit() {
  479. String username = RootPage.this.username.getObject();
  480. char[] password = RootPage.this.password.getObject().toCharArray();
  481. UserModel user = app().authentication().authenticate(username, password);
  482. if (user == null) {
  483. error(getString("gb.invalidUsernameOrPassword"));
  484. } else if (user.username.equals(Constants.FEDERATION_USER)) {
  485. // disallow the federation user from logging in via the
  486. // web ui
  487. error(getString("gb.invalidUsernameOrPassword"));
  488. user = null;
  489. } else {
  490. loginUser(user);
  491. }
  492. }
  493. };
  494. TextField<String> unameField = new TextField<String>("username", username);
  495. WicketUtils.setInputPlaceholder(unameField, markupProvider.getString("gb.username"));
  496. loginForm.add(unameField);
  497. PasswordTextField pwField = new PasswordTextField("password", password);
  498. WicketUtils.setInputPlaceholder(pwField, markupProvider.getString("gb.password"));
  499. loginForm.add(pwField);
  500. add(loginForm);
  501. }
  502. }
  503. /**
  504. * Menu for the authenticated user.
  505. */
  506. class UserMenu extends Fragment {
  507. private static final long serialVersionUID = 1L;
  508. public UserMenu(String id, String markupId, MarkupContainer markupProvider) {
  509. super(id, markupId, markupProvider);
  510. setRenderBodyOnly(true);
  511. GitBlitWebSession session = GitBlitWebSession.get();
  512. UserModel user = session.getUser();
  513. boolean editCredentials = app().authentication().supportsCredentialChanges(user);
  514. boolean standardLogin = session.authenticationType.isStandard();
  515. if (app().settings().getBoolean(Keys.web.allowGravatar, true)) {
  516. add(new GravatarImage("username", user, "navbarGravatar", 20, false));
  517. } else {
  518. add(new Label("username", user.getDisplayName()));
  519. }
  520. add(new Label("displayName", user.getDisplayName()));
  521. add(new BookmarkablePageLink<Void>("newRepository",
  522. EditRepositoryPage.class).setVisible(user.canAdmin() || user.canCreate()));
  523. add(new BookmarkablePageLink<Void>("myProfile",
  524. UserPage.class, WicketUtils.newUsernameParameter(user.username)));
  525. add(new BookmarkablePageLink<Void>("changePassword",
  526. ChangePasswordPage.class).setVisible(editCredentials));
  527. add(new BookmarkablePageLink<Void>("logout",
  528. LogoutPage.class).setVisible(standardLogin));
  529. }
  530. }
  531. }