From: James Moger Date: Tue, 22 Apr 2014 20:08:52 +0000 (-0400) Subject: Integrate admin menu into user menu and add user menu extension X-Git-Tag: v1.6.0~90^2~1 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=859deba551b5e6850fb6331084493a402cecce45;p=gitblit.git Integrate admin menu into user menu and add user menu extension --- diff --git a/src/main/java/com/gitblit/extensions/UserMenuExtension.java b/src/main/java/com/gitblit/extensions/UserMenuExtension.java new file mode 100644 index 00000000..078dbfd4 --- /dev/null +++ b/src/main/java/com/gitblit/extensions/UserMenuExtension.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.extensions; + +import java.util.List; + +import ro.fortsoft.pf4j.ExtensionPoint; + +import com.gitblit.models.Menu.MenuItem; +import com.gitblit.models.UserModel; + +/** + * Extension point to contribute user menu items. + * + * @author James Moger + * @since 1.6.0 + * + */ +public abstract class UserMenuExtension implements ExtensionPoint { + + /** + * @param user + * @since 1.6.0 + * @return a list of menu items + */ + public abstract List getMenuItems(UserModel user); +} diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java index dc79af26..3ca7d48f 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -77,6 +77,7 @@ import com.gitblit.wicket.pages.ReviewProposalPage; import com.gitblit.wicket.pages.SummaryPage; import com.gitblit.wicket.pages.TagPage; import com.gitblit.wicket.pages.TagsPage; +import com.gitblit.wicket.pages.TeamsPage; import com.gitblit.wicket.pages.TicketsPage; import com.gitblit.wicket.pages.TreePage; import com.gitblit.wicket.pages.UserPage; @@ -181,6 +182,7 @@ public class GitBlitWebApp extends WebApplication { mount("/metrics", MetricsPage.class, "r"); mount("/blame", BlamePage.class, "r", "h", "f"); mount("/users", UsersPage.class); + mount("/teams", TeamsPage.class); mount("/logout", LogoutPage.class); // setup ticket urls diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 2c83dd6c..d0c2d48c 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -680,4 +680,7 @@ gb.notifyChangedOpenTickets = send notification for changed open tickets gb.overdue = overdue gb.openMilestones = open milestones gb.closedMilestones = closed milestones -gb.adminMenuItem = admin +gb.administration = administration +gb.plugins = plugins +gb.extensions = extensions + diff --git a/src/main/java/com/gitblit/wicket/PageRegistration.java b/src/main/java/com/gitblit/wicket/PageRegistration.java index ff4a55b4..9fd8f870 100644 --- a/src/main/java/com/gitblit/wicket/PageRegistration.java +++ b/src/main/java/com/gitblit/wicket/PageRegistration.java @@ -67,13 +67,13 @@ public class PageRegistration implements Serializable { public final String url; - public OtherPageLink(String translationKey, String url) { - super(translationKey, null); + public OtherPageLink(String keyOrText, String url) { + super(keyOrText, null); this.url = url; } - public OtherPageLink(String translationKey, String url, boolean hiddenPhone) { - super(translationKey, null, null, hiddenPhone); + public OtherPageLink(String keyOrText, String url, boolean hiddenPhone) { + super(keyOrText, null, null, hiddenPhone); this.url = url; } } @@ -90,8 +90,8 @@ public class PageRegistration implements Serializable { public final List menuItems; - public DropDownMenuRegistration(String translationKey, Class pageClass) { - super(translationKey, pageClass); + public DropDownMenuRegistration(String keyOrText, Class pageClass) { + super(keyOrText, pageClass); menuItems = new ArrayList(); } } diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.html b/src/main/java/com/gitblit/wicket/pages/RootPage.html index 11f7f38d..2ff305f2 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.html +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.html @@ -51,16 +51,18 @@ + + +
  • +
  • +
    diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index b9055c13..3003c70e 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -1,624 +1,719 @@ -/* - * Copyright 2011 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.wicket.pages; - -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.regex.Pattern; - -import org.apache.wicket.MarkupContainer; -import org.apache.wicket.PageParameters; -import org.apache.wicket.behavior.HeaderContributor; -import org.apache.wicket.markup.html.IHeaderContributor; -import org.apache.wicket.markup.html.IHeaderResponse; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.form.PasswordTextField; -import org.apache.wicket.markup.html.form.TextField; -import org.apache.wicket.markup.html.link.BookmarkablePageLink; -import org.apache.wicket.markup.html.panel.Fragment; -import org.apache.wicket.model.IModel; -import org.apache.wicket.model.Model; -import org.apache.wicket.protocol.http.WebResponse; - -import com.gitblit.Constants; -import com.gitblit.Keys; -import com.gitblit.extensions.AdminMenuExtension; -import com.gitblit.models.Menu.MenuDivider; -import com.gitblit.models.Menu.MenuItem; -import com.gitblit.models.Menu.PageLinkMenuItem; -import com.gitblit.models.Menu.ParameterMenuItem; -import com.gitblit.models.Menu.ToggleMenuItem; -import com.gitblit.models.RepositoryModel; -import com.gitblit.models.TeamModel; -import com.gitblit.models.UserModel; -import com.gitblit.utils.ModelUtils; -import com.gitblit.utils.StringUtils; -import com.gitblit.wicket.GitBlitWebSession; -import com.gitblit.wicket.PageRegistration; -import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration; -import com.gitblit.wicket.SessionlessForm; -import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.panels.GravatarImage; -import com.gitblit.wicket.panels.NavigationPanel; - -/** - * Root page is a topbar, navigable page like Repositories, Users, or - * Federation. - * - * @author James Moger - * - */ -public abstract class RootPage extends BasePage { - - boolean showAdmin; - - IModel username = new Model(""); - IModel password = new Model(""); - List repositoryModels = new ArrayList(); - - public RootPage() { - super(); - } - - public RootPage(PageParameters params) { - super(params); - } - - @Override - protected void setupPage(String repositoryName, String pageName) { - - // CSS header overrides - add(new HeaderContributor(new IHeaderContributor() { - private static final long serialVersionUID = 1L; - - @Override - public void renderHead(IHeaderResponse response) { - StringBuilder buffer = new StringBuilder(); - buffer.append("\n"); - response.renderString(buffer.toString()); - } - })); - - boolean authenticateView = app().settings().getBoolean(Keys.web.authenticateViewPages, false); - boolean authenticateAdmin = app().settings().getBoolean(Keys.web.authenticateAdminPages, true); - boolean allowAdmin = app().settings().getBoolean(Keys.web.allowAdministration, true); - boolean allowLucene = app().settings().getBoolean(Keys.web.allowLuceneIndexing, true); - boolean isLoggedIn = GitBlitWebSession.get().isLoggedIn(); - - if (authenticateAdmin) { - showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin(); - // authentication requires state and session - setStatelessHint(false); - } else { - showAdmin = allowAdmin; - if (authenticateView) { - // authentication requires state and session - setStatelessHint(false); - } else { - // no authentication required, no state and no session required - setStatelessHint(true); - } - } - - if (authenticateView || authenticateAdmin) { - if (isLoggedIn) { - UserMenu userFragment = new UserMenu("userPanel", "userMenuFragment", RootPage.this); - add(userFragment); - } else { - LoginForm loginForm = new LoginForm("userPanel", "loginFormFragment", RootPage.this); - add(loginForm); - } - } else { - add(new Label("userPanel").setVisible(false)); - } - - // navigation links - List pages = new ArrayList(); - if (!authenticateView || (authenticateView && isLoggedIn)) { - pages.add(new PageRegistration(isLoggedIn ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class, - getRootPageParameters())); - if (isLoggedIn && app().tickets().isReady()) { - pages.add(new PageRegistration("gb.myTickets", MyTicketsPage.class)); - } - pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, - getRootPageParameters())); - pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); - if (allowLucene) { - pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); - } - - UserModel user = GitBlitWebSession.get().getUser(); - - if (showAdmin) { - // admin dropdown menu - DropDownMenuRegistration adminMenu = new DropDownMenuRegistration("gb.adminMenuItem", MyDashboardPage.class); - - adminMenu.menuItems.add(new PageLinkMenuItem(getString("gb.users"), UsersPage.class)); - - boolean showRegistrations = app().federation().canFederate() - && app().settings().getBoolean(Keys.web.showFederationRegistrations, false); - if (showRegistrations) { - adminMenu.menuItems.add(new PageLinkMenuItem(getString("gb.federation"), FederationPage.class)); - } - - // allow plugins to contribute admin menu items - List extensions = app().plugins().getExtensions(AdminMenuExtension.class); - for (AdminMenuExtension ext : extensions) { - adminMenu.menuItems.add(new MenuDivider()); - adminMenu.menuItems.addAll(ext.getMenuItems(user)); - } - - pages.add(adminMenu); - } - - if (!authenticateView || (authenticateView && isLoggedIn)) { - addDropDownMenus(pages); - } - } - - NavigationPanel navPanel = new NavigationPanel("navPanel", getRootNavPageClass(), pages); - add(navPanel); - - // display an error message cached from a redirect - String cachedMessage = GitBlitWebSession.get().clearErrorMessage(); - if (!StringUtils.isEmpty(cachedMessage)) { - error(cachedMessage); - } else if (showAdmin) { - int pendingProposals = app().federation().getPendingFederationProposals().size(); - if (pendingProposals == 1) { - info(getString("gb.OneProposalToReview")); - } else if (pendingProposals > 1) { - info(MessageFormat.format(getString("gb.nFederationProposalsToReview"), - pendingProposals)); - } - } - - super.setupPage(repositoryName, pageName); - } - - protected Class getRootNavPageClass() { - return getClass(); - } - - private PageParameters getRootPageParameters() { - if (reusePageParameters()) { - PageParameters pp = getPageParameters(); - if (pp != null) { - PageParameters params = new PageParameters(pp); - // remove named project parameter - params.remove("p"); - - // remove named repository parameter - params.remove("r"); - - // remove named user parameter - params.remove("user"); - - // remove days back parameter if it is the default value - if (params.containsKey("db") - && params.getInt("db") == app().settings().getInteger(Keys.web.activityDuration, 7)) { - params.remove("db"); - } - return params; - } - } - return null; - } - - protected boolean reusePageParameters() { - return false; - } - - private void loginUser(UserModel user) { - if (user != null) { - // Set the user into the session - GitBlitWebSession session = GitBlitWebSession.get(); - // issue 62: fix session fixation vulnerability - session.replaceSession(); - session.setUser(user); - - // Set Cookie - if (app().settings().getBoolean(Keys.web.allowCookieAuthentication, false)) { - WebResponse response = (WebResponse) getRequestCycle().getResponse(); - app().authentication().setCookie(response.getHttpServletResponse(), user); - } - - if (!session.continueRequest()) { - PageParameters params = getPageParameters(); - if (params == null) { - // redirect to this page - setResponsePage(getClass()); - } else { - // Strip username and password and redirect to this page - params.remove("username"); - params.remove("password"); - setResponsePage(getClass(), params); - } - } - } - } - - protected List getRepositoryModels() { - if (repositoryModels.isEmpty()) { - final UserModel user = GitBlitWebSession.get().getUser(); - List repositories = app().repositories().getRepositoryModels(user); - repositoryModels.addAll(repositories); - Collections.sort(repositoryModels); - } - return repositoryModels; - } - - protected void addDropDownMenus(List pages) { - - } - - protected List getRepositoryFilterItems(PageParameters params) { - final UserModel user = GitBlitWebSession.get().getUser(); - Set filters = new LinkedHashSet(); - List repositories = getRepositoryModels(); - - // accessible repositories by federation set - Map setMap = new HashMap(); - for (RepositoryModel repository : repositories) { - for (String set : repository.federationSets) { - String key = set.toLowerCase(); - if (setMap.containsKey(key)) { - setMap.get(key).incrementAndGet(); - } else { - setMap.put(key, new AtomicInteger(1)); - } - } - } - if (setMap.size() > 0) { - List sets = new ArrayList(setMap.keySet()); - Collections.sort(sets); - for (String set : sets) { - filters.add(new ToggleMenuItem(MessageFormat.format("{0} ({1})", set, - setMap.get(set).get()), "set", set, params)); - } - // divider - filters.add(new MenuDivider()); - } - - // user's team memberships - if (user != null && user.teams.size() > 0) { - List teams = new ArrayList(user.teams); - Collections.sort(teams); - for (TeamModel team : teams) { - filters.add(new ToggleMenuItem(MessageFormat.format("{0} ({1})", team.name, - team.repositories.size()), "team", team.name, params)); - } - // divider - filters.add(new MenuDivider()); - } - - // custom filters - String customFilters = app().settings().getString(Keys.web.customFilters, null); - if (!StringUtils.isEmpty(customFilters)) { - boolean addedExpression = false; - List expressions = StringUtils.getStringsFromValue(customFilters, "!!!"); - for (String expression : expressions) { - if (!StringUtils.isEmpty(expression)) { - addedExpression = true; - filters.add(new ToggleMenuItem(null, "x", expression, params)); - } - } - // if we added any custom expressions, add a divider - if (addedExpression) { - filters.add(new MenuDivider()); - } - } - return new ArrayList(filters); - } - - protected List getTimeFilterItems(PageParameters params) { - // days back choices - additive parameters - int daysBack = app().settings().getInteger(Keys.web.activityDuration, 7); - int maxDaysBack = app().settings().getInteger(Keys.web.activityDurationMaximum, 30); - if (daysBack < 1) { - daysBack = 7; - } - if (daysBack > maxDaysBack) { - daysBack = maxDaysBack; - } - PageParameters clonedParams; - if (params == null) { - clonedParams = new PageParameters(); - } else { - clonedParams = new PageParameters(params); - } - - if (!clonedParams.containsKey("db")) { - clonedParams.put("db", daysBack); - } - - List items = new ArrayList(); - Set choicesSet = new TreeSet(app().settings().getIntegers(Keys.web.activityDurationChoices)); - if (choicesSet.isEmpty()) { - choicesSet.addAll(Arrays.asList(1, 3, 7, 14, 21, 28)); - } - List choices = new ArrayList(choicesSet); - Collections.sort(choices); - String lastDaysPattern = getString("gb.lastNDays"); - for (Integer db : choices) { - if (db == 1) { - items.add(new ParameterMenuItem(getString("gb.time.today"), "db", db.toString(), clonedParams)); - } else { - String txt = MessageFormat.format(lastDaysPattern, db); - items.add(new ParameterMenuItem(txt, "db", db.toString(), clonedParams)); - } - } - items.add(new MenuDivider()); - return items; - } - - protected List getRepositories(PageParameters params) { - if (params == null) { - return getRepositoryModels(); - } - - boolean hasParameter = false; - String projectName = WicketUtils.getProjectName(params); - String userName = WicketUtils.getUsername(params); - if (StringUtils.isEmpty(projectName)) { - if (!StringUtils.isEmpty(userName)) { - projectName = ModelUtils.getPersonalPath(userName); - } - } - String repositoryName = WicketUtils.getRepositoryName(params); - String set = WicketUtils.getSet(params); - String regex = WicketUtils.getRegEx(params); - String team = WicketUtils.getTeam(params); - int daysBack = params.getInt("db", 0); - int maxDaysBack = app().settings().getInteger(Keys.web.activityDurationMaximum, 30); - - List availableModels = getRepositoryModels(); - Set models = new HashSet(); - - if (!StringUtils.isEmpty(repositoryName)) { - // try named repository - hasParameter = true; - for (RepositoryModel model : availableModels) { - if (model.name.equalsIgnoreCase(repositoryName)) { - models.add(model); - break; - } - } - } - - if (!StringUtils.isEmpty(projectName)) { - // try named project - hasParameter = true; - if (projectName.equalsIgnoreCase(app().settings().getString(Keys.web.repositoryRootGroupName, "main"))) { - // root project/group - for (RepositoryModel model : availableModels) { - if (model.name.indexOf('/') == -1) { - models.add(model); - } - } - } else { - // named project/group - String group = projectName.toLowerCase() + "/"; - for (RepositoryModel model : availableModels) { - if (model.name.toLowerCase().startsWith(group)) { - models.add(model); - } - } - } - } - - if (!StringUtils.isEmpty(regex)) { - // filter the repositories by the regex - hasParameter = true; - Pattern pattern = Pattern.compile(regex); - for (RepositoryModel model : availableModels) { - if (pattern.matcher(model.name).find()) { - models.add(model); - } - } - } - - if (!StringUtils.isEmpty(set)) { - // filter the repositories by the specified sets - hasParameter = true; - List sets = StringUtils.getStringsFromValue(set, ","); - for (RepositoryModel model : availableModels) { - for (String curr : sets) { - if (model.federationSets.contains(curr)) { - models.add(model); - } - } - } - } - - if (!StringUtils.isEmpty(team)) { - // filter the repositories by the specified teams - hasParameter = true; - List teams = StringUtils.getStringsFromValue(team, ","); - - // need TeamModels first - List teamModels = new ArrayList(); - for (String name : teams) { - TeamModel teamModel = app().users().getTeamModel(name); - if (teamModel != null) { - teamModels.add(teamModel); - } - } - - // brute-force our way through finding the matching models - for (RepositoryModel repositoryModel : availableModels) { - for (TeamModel teamModel : teamModels) { - if (teamModel.hasRepositoryPermission(repositoryModel.name)) { - models.add(repositoryModel); - } - } - } - } - - if (!hasParameter) { - models.addAll(availableModels); - } - - // time-filter the list - if (daysBack > 0) { - if (maxDaysBack > 0 && daysBack > maxDaysBack) { - daysBack = maxDaysBack; - } - Calendar cal = Calendar.getInstance(); - cal.set(Calendar.HOUR_OF_DAY, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MILLISECOND, 0); - cal.add(Calendar.DATE, -1 * daysBack); - Date threshold = cal.getTime(); - Set timeFiltered = new HashSet(); - for (RepositoryModel model : models) { - if (model.lastChange.after(threshold)) { - timeFiltered.add(model); - } - } - models = timeFiltered; - } - - List list = new ArrayList(models); - Collections.sort(list); - return list; - } - - /** - * Inline login form. - */ - private class LoginForm extends Fragment { - private static final long serialVersionUID = 1L; - - public LoginForm(String id, String markupId, MarkupContainer markupProvider) { - super(id, markupId, markupProvider); - setRenderBodyOnly(true); - - SessionlessForm loginForm = new SessionlessForm("loginForm", RootPage.this.getClass(), getPageParameters()) { - - private static final long serialVersionUID = 1L; - - @Override - public void onSubmit() { - String username = RootPage.this.username.getObject(); - char[] password = RootPage.this.password.getObject().toCharArray(); - - UserModel user = app().authentication().authenticate(username, password); - if (user == null) { - error(getString("gb.invalidUsernameOrPassword")); - } else if (user.username.equals(Constants.FEDERATION_USER)) { - // disallow the federation user from logging in via the - // web ui - error(getString("gb.invalidUsernameOrPassword")); - user = null; - } else { - loginUser(user); - } - } - }; - TextField unameField = new TextField("username", username); - WicketUtils.setInputPlaceholder(unameField, markupProvider.getString("gb.username")); - loginForm.add(unameField); - PasswordTextField pwField = new PasswordTextField("password", password); - WicketUtils.setInputPlaceholder(pwField, markupProvider.getString("gb.password")); - loginForm.add(pwField); - add(loginForm); - } - } - - /** - * Menu for the authenticated user. - */ - class UserMenu extends Fragment { - - private static final long serialVersionUID = 1L; - - public UserMenu(String id, String markupId, MarkupContainer markupProvider) { - super(id, markupId, markupProvider); - setRenderBodyOnly(true); - - GitBlitWebSession session = GitBlitWebSession.get(); - UserModel user = session.getUser(); - boolean editCredentials = app().authentication().supportsCredentialChanges(user); - boolean standardLogin = session.authenticationType.isStandard(); - - if (app().settings().getBoolean(Keys.web.allowGravatar, true)) { - add(new GravatarImage("username", user, "navbarGravatar", 20, false)); - } else { - add(new Label("username", user.getDisplayName())); - } - - add(new Label("displayName", user.getDisplayName())); - - add(new BookmarkablePageLink("newRepository", - EditRepositoryPage.class).setVisible(user.canAdmin() || user.canCreate())); - - add(new BookmarkablePageLink("myProfile", - UserPage.class, WicketUtils.newUsernameParameter(user.username))); - - add(new BookmarkablePageLink("changePassword", - ChangePasswordPage.class).setVisible(editCredentials)); - - add(new BookmarkablePageLink("logout", - LogoutPage.class).setVisible(standardLogin)); - } - } -} +/* + * Copyright 2011 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; + +import org.apache.wicket.MarkupContainer; +import org.apache.wicket.PageParameters; +import org.apache.wicket.behavior.HeaderContributor; +import org.apache.wicket.markup.html.IHeaderContributor; +import org.apache.wicket.markup.html.IHeaderResponse; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.PasswordTextField; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; +import org.apache.wicket.markup.html.panel.Fragment; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.protocol.http.WebResponse; + +import com.gitblit.Constants; +import com.gitblit.Keys; +import com.gitblit.extensions.UserMenuExtension; +import com.gitblit.models.Menu.ExternalLinkMenuItem; +import com.gitblit.models.Menu.MenuDivider; +import com.gitblit.models.Menu.MenuItem; +import com.gitblit.models.Menu.PageLinkMenuItem; +import com.gitblit.models.Menu.ParameterMenuItem; +import com.gitblit.models.Menu.ToggleMenuItem; +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.TeamModel; +import com.gitblit.models.UserModel; +import com.gitblit.utils.ModelUtils; +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.PageRegistration; +import com.gitblit.wicket.SessionlessForm; +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.GravatarImage; +import com.gitblit.wicket.panels.LinkPanel; +import com.gitblit.wicket.panels.NavigationPanel; + +/** + * Root page is a topbar, navigable page like Repositories, Users, or + * Federation. + * + * @author James Moger + * + */ +public abstract class RootPage extends BasePage { + + boolean showAdmin; + + IModel username = new Model(""); + IModel password = new Model(""); + List repositoryModels = new ArrayList(); + + public RootPage() { + super(); + } + + public RootPage(PageParameters params) { + super(params); + } + + @Override + protected void setupPage(String repositoryName, String pageName) { + + // CSS header overrides + add(new HeaderContributor(new IHeaderContributor() { + private static final long serialVersionUID = 1L; + + @Override + public void renderHead(IHeaderResponse response) { + StringBuilder buffer = new StringBuilder(); + buffer.append("\n"); + response.renderString(buffer.toString()); + } + })); + + boolean authenticateView = app().settings().getBoolean(Keys.web.authenticateViewPages, false); + boolean authenticateAdmin = app().settings().getBoolean(Keys.web.authenticateAdminPages, true); + boolean allowAdmin = app().settings().getBoolean(Keys.web.allowAdministration, true); + boolean allowLucene = app().settings().getBoolean(Keys.web.allowLuceneIndexing, true); + boolean isLoggedIn = GitBlitWebSession.get().isLoggedIn(); + + if (authenticateAdmin) { + showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin(); + // authentication requires state and session + setStatelessHint(false); + } else { + showAdmin = allowAdmin; + if (authenticateView) { + // authentication requires state and session + setStatelessHint(false); + } else { + // no authentication required, no state and no session required + setStatelessHint(true); + } + } + + if (authenticateView || authenticateAdmin) { + if (isLoggedIn) { + UserMenu userFragment = new UserMenu("userPanel", "userMenuFragment", RootPage.this); + add(userFragment); + } else { + LoginForm loginForm = new LoginForm("userPanel", "loginFormFragment", RootPage.this); + add(loginForm); + } + } else { + add(new Label("userPanel").setVisible(false)); + } + + // navigation links + List pages = new ArrayList(); + if (!authenticateView || (authenticateView && isLoggedIn)) { + pages.add(new PageRegistration(isLoggedIn ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class, + getRootPageParameters())); + if (isLoggedIn && app().tickets().isReady()) { + pages.add(new PageRegistration("gb.myTickets", MyTicketsPage.class)); + } + pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, + getRootPageParameters())); + pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); + if (allowLucene) { + pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); + } + + UserModel user = GitBlitWebSession.get().getUser(); + + if (showAdmin) { + // admin dropdown menu + DropDownMenuRegistration adminMenu = new DropDownMenuRegistration("gb.adminMenuItem", MyDashboardPage.class); + + adminMenu.menuItems.add(new PageLinkMenuItem(getString("gb.users"), UsersPage.class)); + + boolean showRegistrations = app().federation().canFederate() + && app().settings().getBoolean(Keys.web.showFederationRegistrations, false); + if (showRegistrations) { + adminMenu.menuItems.add(new PageLinkMenuItem(getString("gb.federation"), FederationPage.class)); + } + + // allow plugins to contribute admin menu items + List extensions = app().plugins().getExtensions(AdminMenuExtension.class); + for (AdminMenuExtension ext : extensions) { + adminMenu.menuItems.add(new MenuDivider()); + adminMenu.menuItems.addAll(ext.getMenuItems(user)); + } + + pages.add(adminMenu); + } + + if (!authenticateView || (authenticateView && isLoggedIn)) { + addDropDownMenus(pages); + } + } + + NavigationPanel navPanel = new NavigationPanel("navPanel", getRootNavPageClass(), pages); + add(navPanel); + + // display an error message cached from a redirect + String cachedMessage = GitBlitWebSession.get().clearErrorMessage(); + if (!StringUtils.isEmpty(cachedMessage)) { + error(cachedMessage); + } else if (showAdmin) { + int pendingProposals = app().federation().getPendingFederationProposals().size(); + if (pendingProposals == 1) { + info(getString("gb.OneProposalToReview")); + } else if (pendingProposals > 1) { + info(MessageFormat.format(getString("gb.nFederationProposalsToReview"), + pendingProposals)); + } + } + + super.setupPage(repositoryName, pageName); + } + + protected Class getRootNavPageClass() { + return getClass(); + } + + private PageParameters getRootPageParameters() { + if (reusePageParameters()) { + PageParameters pp = getPageParameters(); + if (pp != null) { + PageParameters params = new PageParameters(pp); + // remove named project parameter + params.remove("p"); + + // remove named repository parameter + params.remove("r"); + + // remove named user parameter + params.remove("user"); + + // remove days back parameter if it is the default value + if (params.containsKey("db") + && params.getInt("db") == app().settings().getInteger(Keys.web.activityDuration, 7)) { + params.remove("db"); + } + return params; + } + } + return null; + } + + protected boolean reusePageParameters() { + return false; + } + + private void loginUser(UserModel user) { + if (user != null) { + // Set the user into the session + GitBlitWebSession session = GitBlitWebSession.get(); + // issue 62: fix session fixation vulnerability + session.replaceSession(); + session.setUser(user); + + // Set Cookie + if (app().settings().getBoolean(Keys.web.allowCookieAuthentication, false)) { + WebResponse response = (WebResponse) getRequestCycle().getResponse(); + app().authentication().setCookie(response.getHttpServletResponse(), user); + } + + if (!session.continueRequest()) { + PageParameters params = getPageParameters(); + if (params == null) { + // redirect to this page + setResponsePage(getClass()); + } else { + // Strip username and password and redirect to this page + params.remove("username"); + params.remove("password"); + setResponsePage(getClass(), params); + } + } + } + } + + protected List getRepositoryModels() { + if (repositoryModels.isEmpty()) { + final UserModel user = GitBlitWebSession.get().getUser(); + List repositories = app().repositories().getRepositoryModels(user); + repositoryModels.addAll(repositories); + Collections.sort(repositoryModels); + } + return repositoryModels; + } + + protected void addDropDownMenus(List pages) { + + } + + protected List getRepositoryFilterItems(PageParameters params) { + final UserModel user = GitBlitWebSession.get().getUser(); + Set filters = new LinkedHashSet(); + List repositories = getRepositoryModels(); + + // accessible repositories by federation set + Map setMap = new HashMap(); + for (RepositoryModel repository : repositories) { + for (String set : repository.federationSets) { + String key = set.toLowerCase(); + if (setMap.containsKey(key)) { + setMap.get(key).incrementAndGet(); + } else { + setMap.put(key, new AtomicInteger(1)); + } + } + } + if (setMap.size() > 0) { + List sets = new ArrayList(setMap.keySet()); + Collections.sort(sets); + for (String set : sets) { + filters.add(new ToggleMenuItem(MessageFormat.format("{0} ({1})", set, + setMap.get(set).get()), "set", set, params)); + } + // divider + filters.add(new MenuDivider()); + } + + // user's team memberships + if (user != null && user.teams.size() > 0) { + List teams = new ArrayList(user.teams); + Collections.sort(teams); + for (TeamModel team : teams) { + filters.add(new ToggleMenuItem(MessageFormat.format("{0} ({1})", team.name, + team.repositories.size()), "team", team.name, params)); + } + // divider + filters.add(new MenuDivider()); + } + + // custom filters + String customFilters = app().settings().getString(Keys.web.customFilters, null); + if (!StringUtils.isEmpty(customFilters)) { + boolean addedExpression = false; + List expressions = StringUtils.getStringsFromValue(customFilters, "!!!"); + for (String expression : expressions) { + if (!StringUtils.isEmpty(expression)) { + addedExpression = true; + filters.add(new ToggleMenuItem(null, "x", expression, params)); + } + } + // if we added any custom expressions, add a divider + if (addedExpression) { + filters.add(new MenuDivider()); + } + } + return new ArrayList(filters); + } + + protected List getTimeFilterItems(PageParameters params) { + // days back choices - additive parameters + int daysBack = app().settings().getInteger(Keys.web.activityDuration, 7); + int maxDaysBack = app().settings().getInteger(Keys.web.activityDurationMaximum, 30); + if (daysBack < 1) { + daysBack = 7; + } + if (daysBack > maxDaysBack) { + daysBack = maxDaysBack; + } + PageParameters clonedParams; + if (params == null) { + clonedParams = new PageParameters(); + } else { + clonedParams = new PageParameters(params); + } + + if (!clonedParams.containsKey("db")) { + clonedParams.put("db", daysBack); + } + + List items = new ArrayList(); + Set choicesSet = new TreeSet(app().settings().getIntegers(Keys.web.activityDurationChoices)); + if (choicesSet.isEmpty()) { + choicesSet.addAll(Arrays.asList(1, 3, 7, 14, 21, 28)); + } + List choices = new ArrayList(choicesSet); + Collections.sort(choices); + String lastDaysPattern = getString("gb.lastNDays"); + for (Integer db : choices) { + if (db == 1) { + items.add(new ParameterMenuItem(getString("gb.time.today"), "db", db.toString(), clonedParams)); + } else { + String txt = MessageFormat.format(lastDaysPattern, db); + items.add(new ParameterMenuItem(txt, "db", db.toString(), clonedParams)); + } + } + items.add(new MenuDivider()); + return items; + } + + protected List getRepositories(PageParameters params) { + if (params == null) { + return getRepositoryModels(); + } + + boolean hasParameter = false; + String projectName = WicketUtils.getProjectName(params); + String userName = WicketUtils.getUsername(params); + if (StringUtils.isEmpty(projectName)) { + if (!StringUtils.isEmpty(userName)) { + projectName = ModelUtils.getPersonalPath(userName); + } + } + String repositoryName = WicketUtils.getRepositoryName(params); + String set = WicketUtils.getSet(params); + String regex = WicketUtils.getRegEx(params); + String team = WicketUtils.getTeam(params); + int daysBack = params.getInt("db", 0); + int maxDaysBack = app().settings().getInteger(Keys.web.activityDurationMaximum, 30); + + List availableModels = getRepositoryModels(); + Set models = new HashSet(); + + if (!StringUtils.isEmpty(repositoryName)) { + // try named repository + hasParameter = true; + for (RepositoryModel model : availableModels) { + if (model.name.equalsIgnoreCase(repositoryName)) { + models.add(model); + break; + } + } + } + + if (!StringUtils.isEmpty(projectName)) { + // try named project + hasParameter = true; + if (projectName.equalsIgnoreCase(app().settings().getString(Keys.web.repositoryRootGroupName, "main"))) { + // root project/group + for (RepositoryModel model : availableModels) { + if (model.name.indexOf('/') == -1) { + models.add(model); + } + } + } else { + // named project/group + String group = projectName.toLowerCase() + "/"; + for (RepositoryModel model : availableModels) { + if (model.name.toLowerCase().startsWith(group)) { + models.add(model); + } + } + } + } + + if (!StringUtils.isEmpty(regex)) { + // filter the repositories by the regex + hasParameter = true; + Pattern pattern = Pattern.compile(regex); + for (RepositoryModel model : availableModels) { + if (pattern.matcher(model.name).find()) { + models.add(model); + } + } + } + + if (!StringUtils.isEmpty(set)) { + // filter the repositories by the specified sets + hasParameter = true; + List sets = StringUtils.getStringsFromValue(set, ","); + for (RepositoryModel model : availableModels) { + for (String curr : sets) { + if (model.federationSets.contains(curr)) { + models.add(model); + } + } + } + } + + if (!StringUtils.isEmpty(team)) { + // filter the repositories by the specified teams + hasParameter = true; + List teams = StringUtils.getStringsFromValue(team, ","); + + // need TeamModels first + List teamModels = new ArrayList(); + for (String name : teams) { + TeamModel teamModel = app().users().getTeamModel(name); + if (teamModel != null) { + teamModels.add(teamModel); + } + } + + // brute-force our way through finding the matching models + for (RepositoryModel repositoryModel : availableModels) { + for (TeamModel teamModel : teamModels) { + if (teamModel.hasRepositoryPermission(repositoryModel.name)) { + models.add(repositoryModel); + } + } + } + } + + if (!hasParameter) { + models.addAll(availableModels); + } + + // time-filter the list + if (daysBack > 0) { + if (maxDaysBack > 0 && daysBack > maxDaysBack) { + daysBack = maxDaysBack; + } + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + cal.add(Calendar.DATE, -1 * daysBack); + Date threshold = cal.getTime(); + Set timeFiltered = new HashSet(); + for (RepositoryModel model : models) { + if (model.lastChange.after(threshold)) { + timeFiltered.add(model); + } + } + models = timeFiltered; + } + + List list = new ArrayList(models); + Collections.sort(list); + return list; + } + + /** + * Inline login form. + */ + private class LoginForm extends Fragment { + private static final long serialVersionUID = 1L; + + public LoginForm(String id, String markupId, MarkupContainer markupProvider) { + super(id, markupId, markupProvider); + setRenderBodyOnly(true); + + SessionlessForm loginForm = new SessionlessForm("loginForm", RootPage.this.getClass(), getPageParameters()) { + + private static final long serialVersionUID = 1L; + + @Override + public void onSubmit() { + String username = RootPage.this.username.getObject(); + char[] password = RootPage.this.password.getObject().toCharArray(); + + UserModel user = app().authentication().authenticate(username, password); + if (user == null) { + error(getString("gb.invalidUsernameOrPassword")); + } else if (user.username.equals(Constants.FEDERATION_USER)) { + // disallow the federation user from logging in via the + // web ui + error(getString("gb.invalidUsernameOrPassword")); + user = null; + } else { + loginUser(user); + } + } + }; + TextField unameField = new TextField("username", username); + WicketUtils.setInputPlaceholder(unameField, markupProvider.getString("gb.username")); + loginForm.add(unameField); + PasswordTextField pwField = new PasswordTextField("password", password); + WicketUtils.setInputPlaceholder(pwField, markupProvider.getString("gb.password")); + loginForm.add(pwField); + add(loginForm); + } + } + + /** + * Menu for the authenticated user. + */ + class UserMenu extends Fragment { + + private static final long serialVersionUID = 1L; + + public UserMenu(String id, String markupId, MarkupContainer markupProvider) { + super(id, markupId, markupProvider); + setRenderBodyOnly(true); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + GitBlitWebSession session = GitBlitWebSession.get(); + UserModel user = session.getUser(); + boolean editCredentials = app().authentication().supportsCredentialChanges(user); + boolean standardLogin = session.authenticationType.isStandard(); + + if (app().settings().getBoolean(Keys.web.allowGravatar, true)) { + add(new GravatarImage("username", user, "navbarGravatar", 20, false)); + } else { + add(new Label("username", user.getDisplayName())); + } + + List standardItems = new ArrayList(); + standardItems.add(new MenuDivider()); + if (user.canAdmin() || user.canCreate()) { + standardItems.add(new PageLinkMenuItem("gb.newRepository", EditRepositoryPage.class)); + } + standardItems.add(new PageLinkMenuItem("gb.myProfile", UserPage.class, + WicketUtils.newUsernameParameter(user.username))); + if (editCredentials) { + standardItems.add(new PageLinkMenuItem("gb.changePassword", ChangePasswordPage.class)); + } + standardItems.add(new MenuDivider()); + add(newSubmenu("standardMenu", user.getDisplayName(), standardItems)); + + if (showAdmin) { + // admin menu + List adminItems = new ArrayList(); + adminItems.add(new MenuDivider()); + adminItems.add(new PageLinkMenuItem("gb.users", UsersPage.class)); + adminItems.add(new PageLinkMenuItem("gb.teams", TeamsPage.class)); + + boolean showRegistrations = app().federation().canFederate() + && app().settings().getBoolean(Keys.web.showFederationRegistrations, false); + if (showRegistrations) { + adminItems.add(new PageLinkMenuItem("gb.federation", FederationPage.class)); + } + adminItems.add(new MenuDivider()); + + add(newSubmenu("adminMenu", getString("gb.administration"), adminItems)); + } else { + add(new Label("adminMenu").setVisible(false)); + } + + // plugin extension items + List extensionItems = new ArrayList(); + List extensions = app().plugins().getExtensions(UserMenuExtension.class); + for (UserMenuExtension ext : extensions) { + List items = ext.getMenuItems(user); + extensionItems.addAll(items); + } + + if (extensionItems.isEmpty()) { + // no extension items + add(new Label("extensionsMenu").setVisible(false)); + } else { + // found extension items + extensionItems.add(0, new MenuDivider()); + add(newSubmenu("extensionsMenu", getString("gb.extensions"), extensionItems)); + extensionItems.add(new MenuDivider()); + } + + add(new BookmarkablePageLink("logout", + LogoutPage.class).setVisible(standardLogin)); + } + + /** + * Creates a submenu. This is not actually submenu because we're using + * an older Twitter Bootstrap which is pre-submenu. + * + * @param wicketId + * @param submenuTitle + * @param menuItems + * @return a submenu fragment + */ + private Fragment newSubmenu(String wicketId, String submenuTitle, List menuItems) { + Fragment submenu = new Fragment(wicketId, "submenuFragment", this); + submenu.add(new Label("submenuTitle", submenuTitle).setRenderBodyOnly(true)); + ListDataProvider menuItemsDp = new ListDataProvider(menuItems); + DataView submenuItems = new DataView("submenuItem", menuItemsDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item menuItem) { + final MenuItem item = menuItem.getModelObject(); + String name = item.toString(); + try { + // try to lookup translation + name = getString(name); + } catch (Exception e) { + } + if (item instanceof PageLinkMenuItem) { + // link to another Wicket page + PageLinkMenuItem pageLink = (PageLinkMenuItem) item; + menuItem.add(new LinkPanel("submenuLink", null, null, name, pageLink.getPageClass(), + pageLink.getPageParameters(), false).setRenderBodyOnly(true)); + } else if (item instanceof ExternalLinkMenuItem) { + // link to a specified href + ExternalLinkMenuItem extLink = (ExternalLinkMenuItem) item; + menuItem.add(new LinkPanel("submenuLink", null, name, extLink.getHref(), + extLink.openInNewWindow()).setRenderBodyOnly(true)); + } else if (item instanceof MenuDivider) { + // divider + menuItem.add(new Label("submenuLink").setRenderBodyOnly(true)); + WicketUtils.setCssClass(menuItem, "divider"); + } + } + }; + submenu.add(submenuItems); + submenu.setRenderBodyOnly(true); + return submenu; + } + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/TeamsPage.html b/src/main/java/com/gitblit/wicket/pages/TeamsPage.html new file mode 100644 index 00000000..981fe5b1 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TeamsPage.html @@ -0,0 +1,13 @@ + + + + +
    +
    [teams panel]
    +
    +
    + + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/TeamsPage.java b/src/main/java/com/gitblit/wicket/pages/TeamsPage.java new file mode 100644 index 00000000..e0e7bf47 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TeamsPage.java @@ -0,0 +1,30 @@ +/* + * Copyright 2011 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import com.gitblit.wicket.RequiresAdminRole; +import com.gitblit.wicket.panels.TeamsPanel; + +@RequiresAdminRole +public class TeamsPage extends RootPage { + + public TeamsPage() { + super(); + setupPage("", ""); + + add(new TeamsPanel("teamsPanel", showAdmin).setVisible(showAdmin)); + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/UsersPage.html b/src/main/java/com/gitblit/wicket/pages/UsersPage.html index 6eec358d..a9a39397 100644 --- a/src/main/java/com/gitblit/wicket/pages/UsersPage.html +++ b/src/main/java/com/gitblit/wicket/pages/UsersPage.html @@ -6,8 +6,6 @@
    -
    [teams panel]
    -
    [users panel]
    diff --git a/src/main/java/com/gitblit/wicket/pages/UsersPage.java b/src/main/java/com/gitblit/wicket/pages/UsersPage.java index 652bdba6..eab0b18d 100644 --- a/src/main/java/com/gitblit/wicket/pages/UsersPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UsersPage.java @@ -16,7 +16,6 @@ package com.gitblit.wicket.pages; import com.gitblit.wicket.RequiresAdminRole; -import com.gitblit.wicket.panels.TeamsPanel; import com.gitblit.wicket.panels.UsersPanel; @RequiresAdminRole @@ -26,8 +25,6 @@ public class UsersPage extends RootPage { super(); setupPage("", ""); - add(new TeamsPanel("teamsPanel", showAdmin).setVisible(showAdmin)); - add(new UsersPanel("usersPanel", showAdmin).setVisible(showAdmin)); } } diff --git a/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java b/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java index 393dd139..7db29fa2 100644 --- a/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java @@ -45,25 +45,32 @@ public class NavigationPanel extends Panel { @Override public void populateItem(final Item item) { PageRegistration entry = item.getModelObject(); + String linkText = entry.translationKey; + try { + // try to lookup translation key + linkText = getString(entry.translationKey); + } catch (Exception e) { + } + if (entry.hiddenPhone) { WicketUtils.setCssClass(item, "hidden-phone"); } if (entry instanceof OtherPageLink) { // other link OtherPageLink link = (OtherPageLink) entry; - Component c = new LinkPanel("link", null, getString(entry.translationKey), link.url); + Component c = new LinkPanel("link", null, linkText, link.url); c.setRenderBodyOnly(true); item.add(c); } else if (entry instanceof DropDownMenuRegistration) { // drop down menu DropDownMenuRegistration reg = (DropDownMenuRegistration) entry; - Component c = new DropDownMenu("link", getString(entry.translationKey), reg); + Component c = new DropDownMenu("link", linkText, reg); c.setRenderBodyOnly(true); item.add(c); WicketUtils.setCssClass(item, "dropdown"); } else { // standard page link - Component c = new LinkPanel("link", null, getString(entry.translationKey), + Component c = new LinkPanel("link", null, linkText, entry.pageClass, entry.params); c.setRenderBodyOnly(true); if (entry.pageClass.equals(pageClass)) { diff --git a/src/site/plugins_extensions.mkd b/src/site/plugins_extensions.mkd index 684373e0..18a7e325 100644 --- a/src/site/plugins_extensions.mkd +++ b/src/site/plugins_extensions.mkd @@ -205,23 +205,23 @@ public class MyRequestFilter extends HttpRequestFilter { } ``` -### Admin Menu Items +### User Menu Items *SINCE 1.6.0* -You can provide your own admin menu items by subclassing the *AdminMenuExtension* class. +You can provide your own user menu items by subclassing the *UserMenuExtension* class. ```java import java.util.Arrays; import java.util.List; import ro.fortsoft.pf4j.Extension; -import com.gitblit.extensions.AdminMenuExtension; +import com.gitblit.extensions.UserMenuExtension; import com.gitblit.models.Menu.ExternalLinkMenuItem; import com.gitblit.models.Menu.MenuItem; import com.gitblit.models.UserModel; @Extension -public class MyAdminMenuContributor extends AdminMenuExtension { +public class MyUserMenuContributor extends UserMenuExtension { @Override public List getMenuItems(UserModel user) { @@ -229,5 +229,3 @@ public class MyAdminMenuContributor extends AdminMenuExtension { } } ``` - -