summaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
authorJames Moger <james.moger@gitblit.com>2014-05-05 10:46:02 -0600
committerJames Moger <james.moger@gitblit.com>2014-05-05 10:46:02 -0600
commit8f0f665b9ee4e2cd21e9e0d5d7cfc69b1d19b86f (patch)
treeb435b1c014e7e3b7e237d2c2decfbba7a621465f /src/main
parent3920e1f852b0417fd1217095d7ec12cbd6f41cb8 (diff)
parent7a401a3ff909bf82fb4068d6dba430497f74084a (diff)
downloadgitblit-8f0f665b9ee4e2cd21e9e0d5d7cfc69b1d19b86f.tar.gz
gitblit-8f0f665b9ee4e2cd21e9e0d5d7cfc69b1d19b86f.zip
Merged #23 "Enhance the plugin infrastructure to allow deeper plugin integration"
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/WEB-INF/web.xml11
-rw-r--r--src/main/java/com/gitblit/dagger/DaggerFilter.java4
-rw-r--r--src/main/java/com/gitblit/extensions/GitblitWicketPlugin.java49
-rw-r--r--src/main/java/com/gitblit/extensions/HttpRequestFilter.java49
-rw-r--r--src/main/java/com/gitblit/extensions/NavLinkExtension.java40
-rw-r--r--src/main/java/com/gitblit/extensions/RepositoryNavLinkExtension.java42
-rw-r--r--src/main/java/com/gitblit/extensions/UserMenuExtension.java40
-rw-r--r--src/main/java/com/gitblit/models/Menu.java302
-rw-r--r--src/main/java/com/gitblit/models/NavLink.java140
-rw-r--r--src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java5
-rw-r--r--src/main/java/com/gitblit/servlet/AuthenticationFilter.java3
-rw-r--r--src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java3
-rw-r--r--src/main/java/com/gitblit/servlet/FilterRuntimeConfig.java71
-rw-r--r--src/main/java/com/gitblit/servlet/GitFilter.java5
-rw-r--r--src/main/java/com/gitblit/servlet/ProxyFilter.java86
-rw-r--r--src/main/java/com/gitblit/servlet/RpcFilter.java5
-rw-r--r--src/main/java/com/gitblit/servlet/SyndicationFilter.java5
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.java108
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.properties4
-rw-r--r--src/main/java/com/gitblit/wicket/GitblitWicketApp.java72
-rw-r--r--src/main/java/com/gitblit/wicket/PageRegistration.java243
-rw-r--r--src/main/java/com/gitblit/wicket/PluginClassResolver.java122
-rw-r--r--src/main/java/com/gitblit/wicket/UrlExternalFormComparator.java39
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ActivityPage.java16
-rw-r--r--src/main/java/com/gitblit/wicket/pages/DashboardPage.java14
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ProjectPage.java30
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ProjectsPage.java14
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java14
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RepositoryPage.java61
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RootPage.html14
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RootPage.java1312
-rw-r--r--src/main/java/com/gitblit/wicket/pages/TeamsPage.html13
-rw-r--r--src/main/java/com/gitblit/wicket/pages/TeamsPage.java30
-rw-r--r--src/main/java/com/gitblit/wicket/pages/UserPage.java14
-rw-r--r--src/main/java/com/gitblit/wicket/pages/UsersPage.html2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/UsersPage.java3
-rw-r--r--src/main/java/com/gitblit/wicket/panels/DropDownMenu.java74
-rw-r--r--src/main/java/com/gitblit/wicket/panels/NavigationPanel.java58
38 files changed, 2131 insertions, 986 deletions
diff --git a/src/main/java/WEB-INF/web.xml b/src/main/java/WEB-INF/web.xml
index cb483af4..3a6c4490 100644
--- a/src/main/java/WEB-INF/web.xml
+++ b/src/main/java/WEB-INF/web.xml
@@ -214,6 +214,15 @@
<url-pattern>/robots.txt</url-pattern>
</servlet-mapping>
+ <filter>
+ <filter-name>ProxyFilter</filter-name>
+ <filter-class>com.gitblit.servlet.ProxyFilter</filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>ProxyFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
<!-- Git Access Restriction Filter
<url-pattern> MUST match:
* GitServlet
@@ -353,4 +362,4 @@
<url-pattern>/*</url-pattern>
</filter-mapping>
-</web-app>
+</web-app> \ No newline at end of file
diff --git a/src/main/java/com/gitblit/dagger/DaggerFilter.java b/src/main/java/com/gitblit/dagger/DaggerFilter.java
index 1c73d4b7..01c07a4a 100644
--- a/src/main/java/com/gitblit/dagger/DaggerFilter.java
+++ b/src/main/java/com/gitblit/dagger/DaggerFilter.java
@@ -36,10 +36,10 @@ public abstract class DaggerFilter implements Filter {
public final void init(FilterConfig filterConfig) throws ServletException {
ServletContext context = filterConfig.getServletContext();
ObjectGraph objectGraph = (ObjectGraph) context.getAttribute(DaggerContext.INJECTOR_NAME);
- inject(objectGraph);
+ inject(objectGraph, filterConfig);
}
- protected abstract void inject(ObjectGraph dagger);
+ protected abstract void inject(ObjectGraph dagger, FilterConfig filterConfig) throws ServletException;
@Override
public void destroy() {
diff --git a/src/main/java/com/gitblit/extensions/GitblitWicketPlugin.java b/src/main/java/com/gitblit/extensions/GitblitWicketPlugin.java
new file mode 100644
index 00000000..130f4993
--- /dev/null
+++ b/src/main/java/com/gitblit/extensions/GitblitWicketPlugin.java
@@ -0,0 +1,49 @@
+/*
+ * 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 org.apache.wicket.Application;
+import org.apache.wicket.IInitializer;
+
+import ro.fortsoft.pf4j.PluginWrapper;
+
+import com.gitblit.wicket.GitblitWicketApp;
+
+/**
+ * A Gitblit plugin that is allowed to extend the Wicket webapp.
+ *
+ * @author James Moger
+ * @since 1.6.0
+ */
+public abstract class GitblitWicketPlugin extends GitblitPlugin implements IInitializer {
+
+ public GitblitWicketPlugin(PluginWrapper wrapper) {
+ super(wrapper);
+ }
+
+ @Override
+ public final void init(Application application) {
+ init((GitblitWicketApp) application);
+ }
+
+ /**
+ * Allows plugins to extend the web application.
+ *
+ * @param app
+ * @since 1.6.0
+ */
+ protected abstract void init(GitblitWicketApp app);
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/extensions/HttpRequestFilter.java b/src/main/java/com/gitblit/extensions/HttpRequestFilter.java
new file mode 100644
index 00000000..e3e330cb
--- /dev/null
+++ b/src/main/java/com/gitblit/extensions/HttpRequestFilter.java
@@ -0,0 +1,49 @@
+/*
+ * 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.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import ro.fortsoft.pf4j.ExtensionPoint;
+
+/**
+ * Extension point to intercept HTTP requests passing through the server.
+ *
+ * @author David Ostrovsky
+ * @since 1.6.0
+ *
+ */
+public abstract class HttpRequestFilter implements Filter, ExtensionPoint {
+
+ @Override
+ public void init(FilterConfig config) throws ServletException {
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ @Override
+ public abstract void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException;
+}
diff --git a/src/main/java/com/gitblit/extensions/NavLinkExtension.java b/src/main/java/com/gitblit/extensions/NavLinkExtension.java
new file mode 100644
index 00000000..c8958603
--- /dev/null
+++ b/src/main/java/com/gitblit/extensions/NavLinkExtension.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.NavLink;
+import com.gitblit.models.UserModel;
+
+/**
+ * Extension point to contribute top-level navigation links.
+ *
+ * @author James Moger
+ * @since 1.6.0
+ *
+ */
+public abstract class NavLinkExtension implements ExtensionPoint {
+
+ /**
+ * @param user
+ * @since 1.6.0
+ * @return a list of nav links
+ */
+ public abstract List<NavLink> getNavLinks(UserModel user);
+}
diff --git a/src/main/java/com/gitblit/extensions/RepositoryNavLinkExtension.java b/src/main/java/com/gitblit/extensions/RepositoryNavLinkExtension.java
new file mode 100644
index 00000000..2b05c5a0
--- /dev/null
+++ b/src/main/java/com/gitblit/extensions/RepositoryNavLinkExtension.java
@@ -0,0 +1,42 @@
+/*
+ * 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.NavLink;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+
+/**
+ * Extension point to contribute repository page navigation links.
+ *
+ * @author James Moger
+ * @since 1.6.0
+ *
+ */
+public abstract class RepositoryNavLinkExtension implements ExtensionPoint {
+
+ /**
+ * @param user
+ * @param repository
+ * @since 1.6.0
+ * @return a list of nav links
+ */
+ public abstract List<NavLink> getNavLinks(UserModel user, RepositoryModel repository);
+}
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<MenuItem> getMenuItems(UserModel user);
+}
diff --git a/src/main/java/com/gitblit/models/Menu.java b/src/main/java/com/gitblit/models/Menu.java
new file mode 100644
index 00000000..7c949b3f
--- /dev/null
+++ b/src/main/java/com/gitblit/models/Menu.java
@@ -0,0 +1,302 @@
+package com.gitblit.models;
+
+import java.io.Serializable;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.WebPage;
+
+import com.gitblit.utils.StringUtils;
+
+public class Menu {
+
+ /**
+ * A MenuItem for a drop down menu.
+ *
+ * @author James Moger
+ * @since 1.6.0
+ */
+ public abstract static class MenuItem implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ final String displayText;
+
+ MenuItem(String displayText) {
+ this.displayText = displayText;
+ }
+
+ @Override
+ public int hashCode() {
+ return displayText.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof MenuItem) {
+ return hashCode() == o.hashCode();
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return displayText;
+ }
+ }
+
+ /**
+ * A divider for the menu.
+ *
+ * @since 1.6.0
+ */
+ public static class MenuDivider extends MenuItem {
+
+ private static final long serialVersionUID = 1L;
+
+ public MenuDivider() {
+ super("");
+ }
+ }
+
+
+ /**
+ * A MenuItem for setting a parameter of the current url.
+ *
+ * @author James Moger
+ *
+ */
+ public static class ParameterMenuItem extends MenuItem {
+
+ private static final long serialVersionUID = 1L;
+
+ final PageParameters parameters;
+ final String parameter;
+ final String value;
+ final boolean isSelected;
+
+ /**
+ * @param displayText
+ */
+ public ParameterMenuItem(String displayText) {
+ this(displayText, null, null, null);
+ }
+
+ /**
+ * @param displayText
+ * @param parameter
+ * @param value
+ */
+ public ParameterMenuItem(String displayText, String parameter, String value) {
+ this(displayText, parameter, value, null);
+ }
+
+ /**
+ * @param displayText
+ * @param parameter
+ * @param value
+ */
+ public ParameterMenuItem(String displayText, String parameter, String value,
+ PageParameters params) {
+ super(displayText);
+ this.parameter = parameter;
+ this.value = value;
+
+ if (params == null) {
+ // no parameters specified
+ parameters = new PageParameters();
+ setParameter(parameter, value);
+ isSelected = false;
+ } else {
+ parameters = new PageParameters(params);
+ if (parameters.containsKey(parameter)) {
+ isSelected = params.getString(parameter).equals(value);
+ // set the new selection value
+ setParameter(parameter, value);
+ } else {
+ // not currently selected
+ isSelected = false;
+ setParameter(parameter, value);
+ }
+ }
+ }
+
+ protected void setParameter(String parameter, String value) {
+ if (!StringUtils.isEmpty(parameter)) {
+ if (StringUtils.isEmpty(value)) {
+ this.parameters.remove(parameter);
+ } else {
+ this.parameters.put(parameter, value);
+ }
+ }
+ }
+
+ public String formatParameter() {
+ if (StringUtils.isEmpty(parameter) || StringUtils.isEmpty(value)) {
+ return "";
+ }
+ return parameter + "=" + value;
+ }
+
+ public PageParameters getPageParameters() {
+ return parameters;
+ }
+
+ public boolean isSelected() {
+ return isSelected;
+ }
+
+ @Override
+ public int hashCode() {
+ if (StringUtils.isEmpty(displayText)) {
+ return value.hashCode() + parameter.hashCode();
+ }
+ return displayText.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof MenuItem) {
+ return hashCode() == o.hashCode();
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ if (StringUtils.isEmpty(displayText)) {
+ return formatParameter();
+ }
+ return displayText;
+ }
+ }
+
+ /**
+ * Menu item for toggling a parameter.
+ *
+ */
+ public static class ToggleMenuItem extends ParameterMenuItem {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param displayText
+ * @param parameter
+ * @param value
+ */
+ public ToggleMenuItem(String displayText, String parameter, String value,
+ PageParameters params) {
+ super(displayText, parameter, value, params);
+ if (isSelected) {
+ // already selected, so remove this enables toggling
+ parameters.remove(parameter);
+ }
+ }
+ }
+
+ /**
+ * Menu item for linking to another Wicket page.
+ *
+ * @since 1.6.0
+ */
+ public static class PageLinkMenuItem extends MenuItem {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Class<? extends WebPage> pageClass;
+
+ private final PageParameters params;
+
+ /**
+ * Page Link Item links to another page.
+ *
+ * @param displayText
+ * @param pageClass
+ * @since 1.6.0
+ */
+ public PageLinkMenuItem(String displayText, Class<? extends WebPage> pageClass) {
+ this(displayText, pageClass, null);
+ }
+
+ /**
+ * Page Link Item links to another page.
+ *
+ * @param displayText
+ * @param pageClass
+ * @param params
+ * @since 1.6.0
+ */
+ public PageLinkMenuItem(String displayText, Class<? extends WebPage> pageClass, PageParameters params) {
+ super(displayText);
+ this.pageClass = pageClass;
+ this.params = params;
+ }
+
+ /**
+ * @return the page class
+ * @since 1.6.0
+ */
+ public Class<? extends WebPage> getPageClass() {
+ return pageClass;
+ }
+
+ /**
+ * @return the page parameters
+ * @since 1.6.0
+ */
+ public PageParameters getPageParameters() {
+ return params;
+ }
+ }
+
+ /**
+ * Menu item to link to an external page.
+ *
+ * @since 1.6.0
+ */
+ public static class ExternalLinkMenuItem extends MenuItem {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String href;
+
+ private final boolean newWindow;
+
+ /**
+ * External Link Item links to something else.
+ *
+ * @param displayText
+ * @param href
+ * @since 1.6.0
+ */
+ public ExternalLinkMenuItem(String displayText, String href) {
+ this(displayText, href, false);
+ }
+
+ /**
+ * External Link Item links to something else.
+ *
+ * @param displayText
+ * @param href
+ * @since 1.6.0
+ */
+ public ExternalLinkMenuItem(String displayText, String href, boolean newWindow) {
+ super(displayText);
+ this.href = href;
+ this.newWindow = newWindow;
+ }
+
+ /**
+ * @since 1.6.0
+ */
+ public String getHref() {
+ return href;
+ }
+
+ /**
+ * @since 1.6.0
+ */
+ public boolean openInNewWindow() {
+ return newWindow;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/models/NavLink.java b/src/main/java/com/gitblit/models/NavLink.java
new file mode 100644
index 00000000..993d6954
--- /dev/null
+++ b/src/main/java/com/gitblit/models/NavLink.java
@@ -0,0 +1,140 @@
+/*
+ * 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.models;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.WebPage;
+
+import com.gitblit.models.Menu.MenuItem;
+
+/**
+ * Represents a navigation link for the navigation panel.
+ *
+ * @author James Moger
+ *
+ */
+public abstract class NavLink implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public final String translationKey;
+ public final boolean hiddenPhone;
+
+ public NavLink(String translationKey, boolean hiddenPhone) {
+ this.translationKey = translationKey;
+ this.hiddenPhone = hiddenPhone;
+ }
+
+
+ /**
+ * Represents a Wicket page link.
+ *
+ * @author James Moger
+ *
+ */
+ public static class PageNavLink extends NavLink implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public final Class<? extends WebPage> pageClass;
+ public final PageParameters params;
+
+ public PageNavLink(String translationKey, Class<? extends WebPage> pageClass) {
+ this(translationKey, pageClass, null);
+ }
+
+ public PageNavLink(String translationKey, Class<? extends WebPage> pageClass,
+ PageParameters params) {
+ this(translationKey, pageClass, params, false);
+ }
+
+ public PageNavLink(String translationKey, Class<? extends WebPage> pageClass,
+ PageParameters params, boolean hiddenPhone) {
+ super(translationKey, hiddenPhone);
+ this.pageClass = pageClass;
+ this.params = params;
+ }
+ }
+
+ /**
+ * Represents an explicitly href link.
+ *
+ * @author James Moger
+ *
+ */
+ public static class ExternalNavLink extends NavLink implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public final String url;
+
+ public ExternalNavLink(String keyOrText, String url) {
+ super(keyOrText, false);
+ this.url = url;
+ }
+
+ public ExternalNavLink(String keyOrText, String url, boolean hiddenPhone) {
+ super(keyOrText, hiddenPhone);
+ this.url = url;
+ }
+ }
+
+ /**
+ * Represents a DropDownMenu for the current page.
+ *
+ * @author James Moger
+ *
+ */
+ public static class DropDownPageMenuNavLink extends PageNavLink implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public final List<MenuItem> menuItems;
+
+ public DropDownPageMenuNavLink(String keyOrText, Class<? extends WebPage> pageClass) {
+ this(keyOrText, pageClass, false);
+ }
+
+ public DropDownPageMenuNavLink(String keyOrText, Class<? extends WebPage> pageClass, boolean hiddenPhone) {
+ super(keyOrText, pageClass, null, hiddenPhone);
+ menuItems = new ArrayList<MenuItem>();
+ }
+ }
+
+ /**
+ * Represents a DropDownMenu.
+ *
+ * @author James Moger
+ *
+ */
+ public static class DropDownMenuNavLink extends NavLink implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public final List<MenuItem> menuItems;
+
+ public DropDownMenuNavLink(String keyOrText) {
+ this(keyOrText, false);
+ }
+
+ public DropDownMenuNavLink(String keyOrText, boolean hiddenPhone) {
+ super(keyOrText, hiddenPhone);
+ menuItems = new ArrayList<MenuItem>();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
index e6a0169c..0e6d323d 100644
--- a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
+++ b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
@@ -19,6 +19,7 @@ import java.io.IOException;
import java.text.MessageFormat;
import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -54,8 +55,8 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter {
protected IRepositoryManager repositoryManager;
@Override
- protected void inject(ObjectGraph dagger) {
- super.inject(dagger);
+ protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
+ super.inject(dagger, filterConfig);
this.runtimeManager = dagger.get(IRuntimeManager.class);
this.repositoryManager = dagger.get(IRepositoryManager.class);
}
diff --git a/src/main/java/com/gitblit/servlet/AuthenticationFilter.java b/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
index dd821ac7..5710a4af 100644
--- a/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
+++ b/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
@@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.Map;
import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -64,7 +65,7 @@ public abstract class AuthenticationFilter extends DaggerFilter {
protected IAuthenticationManager authenticationManager;
@Override
- protected void inject(ObjectGraph dagger) {
+ protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
this.authenticationManager = dagger.get(IAuthenticationManager.class);
}
diff --git a/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java b/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
index 5fdccb71..c015021d 100644
--- a/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
+++ b/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
@@ -19,6 +19,7 @@ import java.io.IOException;
import java.text.MessageFormat;
import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -53,7 +54,7 @@ public class EnforceAuthenticationFilter extends DaggerFilter {
private IAuthenticationManager authenticationManager;
@Override
- protected void inject(ObjectGraph dagger) {
+ protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
this.settings = dagger.get(IStoredSettings.class);
this.authenticationManager = dagger.get(IAuthenticationManager.class);
}
diff --git a/src/main/java/com/gitblit/servlet/FilterRuntimeConfig.java b/src/main/java/com/gitblit/servlet/FilterRuntimeConfig.java
new file mode 100644
index 00000000..9f0c0ac5
--- /dev/null
+++ b/src/main/java/com/gitblit/servlet/FilterRuntimeConfig.java
@@ -0,0 +1,71 @@
+/*
+ * 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.servlet;
+
+import java.util.Enumeration;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.manager.IRuntimeManager;
+
+/**
+ * Wraps a filter config and will prefer a setting retrieved from IStoredSettings
+ * if one is available.
+ *
+ * @author James Moger
+ * @since 1.6.0
+ */
+public class FilterRuntimeConfig implements FilterConfig {
+
+ final IRuntimeManager runtime;
+ final IStoredSettings settings;
+ final String namespace;
+ final FilterConfig config;
+
+ public FilterRuntimeConfig(IRuntimeManager runtime, String namespace, FilterConfig config) {
+ this.runtime = runtime;
+ this.settings = runtime.getSettings();
+ this.namespace = namespace;
+ this.config = config;
+ }
+
+ @Override
+ public String getFilterName() {
+ return config.getFilterName();
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return config.getServletContext();
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ String key = namespace + "." + name;
+ if (settings.hasSettings(key)) {
+ String value = settings.getString(key, null);
+ return value;
+ }
+ return config.getInitParameter(name);
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return config.getInitParameterNames();
+ }
+}
diff --git a/src/main/java/com/gitblit/servlet/GitFilter.java b/src/main/java/com/gitblit/servlet/GitFilter.java
index f9c062d2..bb3d3216 100644
--- a/src/main/java/com/gitblit/servlet/GitFilter.java
+++ b/src/main/java/com/gitblit/servlet/GitFilter.java
@@ -17,6 +17,7 @@ package com.gitblit.servlet;
import java.text.MessageFormat;
+import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import com.gitblit.Constants.AccessRestrictionType;
@@ -53,8 +54,8 @@ public class GitFilter extends AccessRestrictionFilter {
private IFederationManager federationManager;
@Override
- protected void inject(ObjectGraph dagger) {
- super.inject(dagger);
+ protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
+ super.inject(dagger, filterConfig);
this.settings = dagger.get(IStoredSettings.class);
this.federationManager = dagger.get(IFederationManager.class);
}
diff --git a/src/main/java/com/gitblit/servlet/ProxyFilter.java b/src/main/java/com/gitblit/servlet/ProxyFilter.java
new file mode 100644
index 00000000..46f59de9
--- /dev/null
+++ b/src/main/java/com/gitblit/servlet/ProxyFilter.java
@@ -0,0 +1,86 @@
+/*
+ * 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.servlet;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import ro.fortsoft.pf4j.PluginWrapper;
+
+import com.gitblit.dagger.DaggerFilter;
+import com.gitblit.extensions.HttpRequestFilter;
+import com.gitblit.manager.IPluginManager;
+import com.gitblit.manager.IRuntimeManager;
+
+import dagger.ObjectGraph;
+
+/**
+ * A request filter than allows registered extension request filters to access
+ * request data. The intended purpose is for server monitoring plugins.
+ *
+ * @author David Ostrovsky
+ * @since 1.6.0
+ */
+public class ProxyFilter extends DaggerFilter {
+ private List<HttpRequestFilter> filters;
+
+ @Override
+ protected void inject(ObjectGraph dagger, FilterConfig filterConfig) throws ServletException {
+ IRuntimeManager runtimeManager = dagger.get(IRuntimeManager.class);
+ IPluginManager pluginManager = dagger.get(IPluginManager.class);
+
+ filters = pluginManager.getExtensions(HttpRequestFilter.class);
+ for (HttpRequestFilter f : filters) {
+ // wrap the filter config for Gitblit settings retrieval
+ PluginWrapper pluginWrapper = pluginManager.whichPlugin(f.getClass());
+ FilterConfig runtimeConfig = new FilterRuntimeConfig(runtimeManager,
+ pluginWrapper.getPluginId(), filterConfig);
+
+ f.init(runtimeConfig);
+ }
+ }
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, final FilterChain last)
+ throws IOException, ServletException {
+ final Iterator<HttpRequestFilter> itr = filters.iterator();
+ new FilterChain() {
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res) throws IOException,
+ ServletException {
+ if (itr.hasNext()) {
+ itr.next().doFilter(req, res, this);
+ } else {
+ last.doFilter(req, res);
+ }
+ }
+ }.doFilter(req, res);
+ }
+
+ @Override
+ public void destroy() {
+ for (HttpRequestFilter f : filters) {
+ f.destroy();
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/servlet/RpcFilter.java b/src/main/java/com/gitblit/servlet/RpcFilter.java
index e0b1a233..23bf956e 100644
--- a/src/main/java/com/gitblit/servlet/RpcFilter.java
+++ b/src/main/java/com/gitblit/servlet/RpcFilter.java
@@ -19,6 +19,7 @@ import java.io.IOException;
import java.text.MessageFormat;
import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -53,8 +54,8 @@ public class RpcFilter extends AuthenticationFilter {
private IRuntimeManager runtimeManager;
@Override
- protected void inject(ObjectGraph dagger) {
- super.inject(dagger);
+ protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
+ super.inject(dagger, filterConfig);
this.settings = dagger.get(IStoredSettings.class);
this.runtimeManager = dagger.get(IRuntimeManager.class);
}
diff --git a/src/main/java/com/gitblit/servlet/SyndicationFilter.java b/src/main/java/com/gitblit/servlet/SyndicationFilter.java
index 67a845ea..78da47e9 100644
--- a/src/main/java/com/gitblit/servlet/SyndicationFilter.java
+++ b/src/main/java/com/gitblit/servlet/SyndicationFilter.java
@@ -19,6 +19,7 @@ import java.io.IOException;
import java.text.MessageFormat;
import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -50,8 +51,8 @@ public class SyndicationFilter extends AuthenticationFilter {
private IProjectManager projectManager;
@Override
- protected void inject(ObjectGraph dagger) {
- super.inject(dagger);
+ protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
+ super.inject(dagger, filterConfig);
this.runtimeManager = dagger.get(IRuntimeManager.class);
this.repositoryManager = dagger.get(IRepositoryManager.class);
this.projectManager = dagger.get(IProjectManager.class);
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index dc79af26..d3aa62fd 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -28,8 +28,12 @@ import org.apache.wicket.Session;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.protocol.http.WebApplication;
+import ro.fortsoft.pf4j.PluginState;
+import ro.fortsoft.pf4j.PluginWrapper;
+
import com.gitblit.IStoredSettings;
import com.gitblit.Keys;
+import com.gitblit.extensions.GitblitWicketPlugin;
import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.manager.IFederationManager;
import com.gitblit.manager.IGitblit;
@@ -77,12 +81,13 @@ 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;
import com.gitblit.wicket.pages.UsersPage;
-public class GitBlitWebApp extends WebApplication {
+public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
private final Class<? extends WebPage> homePageClass = MyDashboardPage.class;
@@ -181,6 +186,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
@@ -208,11 +214,29 @@ public class GitBlitWebApp extends WebApplication {
mount("/forks", ForksPage.class, "r");
mount("/fork", ForkPage.class, "r");
+ // allow started Wicket plugins to initialize
+ for (PluginWrapper pluginWrapper : pluginManager.getPlugins()) {
+ if (PluginState.STARTED != pluginWrapper.getPluginState()) {
+ continue;
+ }
+ if (pluginWrapper.getPlugin() instanceof GitblitWicketPlugin) {
+ GitblitWicketPlugin wicketPlugin = (GitblitWicketPlugin) pluginWrapper.getPlugin();
+ wicketPlugin.init(this);
+ }
+ }
+
+ // customize the Wicket class resolver to load from plugins
+ PluginClassResolver classResolver = new PluginClassResolver(pluginManager);
+ getApplicationSettings().setClassResolver(classResolver);
+
getMarkupSettings().setDefaultMarkupEncoding("UTF-8");
- super.init();
}
- private void mount(String location, Class<? extends WebPage> clazz, String... parameters) {
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#mount(java.lang.String, java.lang.Class, java.lang.String)
+ */
+ @Override
+ public void mount(String location, Class<? extends WebPage> clazz, String... parameters) {
if (parameters == null) {
parameters = new String[] {};
}
@@ -228,15 +252,26 @@ public class GitBlitWebApp extends WebApplication {
}
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#getHomePage()
+ */
@Override
public Class<? extends WebPage> getHomePage() {
return homePageClass;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#isCacheablePage(java.lang.String)
+ */
+ @Override
public boolean isCacheablePage(String mountPoint) {
return cacheablePages.containsKey(mountPoint);
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#getCacheControl(java.lang.String)
+ */
+ @Override
public CacheControl getCacheControl(String mountPoint) {
return cacheablePages.get(mountPoint);
}
@@ -252,15 +287,18 @@ public class GitBlitWebApp extends WebApplication {
return gitBlitWebSession;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#settings()
+ */
+ @Override
public IStoredSettings settings() {
return settings;
}
- /**
- * Is Gitblit running in debug mode?
- *
- * @return true if Gitblit is running in debug mode
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#isDebugMode()
*/
+ @Override
public boolean isDebugMode() {
return runtimeManager.isDebugMode();
}
@@ -269,58 +307,114 @@ public class GitBlitWebApp extends WebApplication {
* These methods look strange... and they are... but they are the first
* step towards modularization across multiple commits.
*/
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#getBootDate()
+ */
+ @Override
public Date getBootDate() {
return runtimeManager.getBootDate();
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#getLastActivityDate()
+ */
+ @Override
public Date getLastActivityDate() {
return repositoryManager.getLastActivityDate();
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#runtime()
+ */
+ @Override
public IRuntimeManager runtime() {
return runtimeManager;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#plugins()
+ */
+ @Override
public IPluginManager plugins() {
return pluginManager;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#notifier()
+ */
+ @Override
public INotificationManager notifier() {
return notificationManager;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#users()
+ */
+ @Override
public IUserManager users() {
return userManager;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#authentication()
+ */
+ @Override
public IAuthenticationManager authentication() {
return authenticationManager;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#keys()
+ */
+ @Override
public IPublicKeyManager keys() {
return publicKeyManager;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#repositories()
+ */
+ @Override
public IRepositoryManager repositories() {
return repositoryManager;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#projects()
+ */
+ @Override
public IProjectManager projects() {
return projectManager;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#federation()
+ */
+ @Override
public IFederationManager federation() {
return federationManager;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#gitblit()
+ */
+ @Override
public IGitblit gitblit() {
return gitblit;
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#tickets()
+ */
+ @Override
public ITicketService tickets() {
return gitblit.getTicketService();
}
+ /* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#getTimezone()
+ */
+ @Override
public TimeZone getTimezone() {
return runtimeManager.getTimezone();
}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
index 0ed2ed59..d0c2d48c 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -680,3 +680,7 @@ gb.notifyChangedOpenTickets = send notification for changed open tickets
gb.overdue = overdue
gb.openMilestones = open milestones
gb.closedMilestones = closed milestones
+gb.administration = administration
+gb.plugins = plugins
+gb.extensions = extensions
+
diff --git a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
new file mode 100644
index 00000000..a56e6996
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
@@ -0,0 +1,72 @@
+package com.gitblit.wicket;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.apache.wicket.markup.html.WebPage;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.manager.IAuthenticationManager;
+import com.gitblit.manager.IFederationManager;
+import com.gitblit.manager.IGitblit;
+import com.gitblit.manager.INotificationManager;
+import com.gitblit.manager.IPluginManager;
+import com.gitblit.manager.IProjectManager;
+import com.gitblit.manager.IRepositoryManager;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.manager.IUserManager;
+import com.gitblit.tickets.ITicketService;
+import com.gitblit.transport.ssh.IPublicKeyManager;
+
+public interface GitblitWicketApp {
+
+ public abstract void mount(String location, Class<? extends WebPage> clazz, String... parameters);
+
+ public abstract Class<? extends WebPage> getHomePage();
+
+ public abstract boolean isCacheablePage(String mountPoint);
+
+ public abstract CacheControl getCacheControl(String mountPoint);
+
+ public abstract IStoredSettings settings();
+
+ /**
+ * Is Gitblit running in debug mode?
+ *
+ * @return true if Gitblit is running in debug mode
+ */
+ public abstract boolean isDebugMode();
+
+ /*
+ * These methods look strange... and they are... but they are the first
+ * step towards modularization across multiple commits.
+ */
+ public abstract Date getBootDate();
+
+ public abstract Date getLastActivityDate();
+
+ public abstract IRuntimeManager runtime();
+
+ public abstract IPluginManager plugins();
+
+ public abstract INotificationManager notifier();
+
+ public abstract IUserManager users();
+
+ public abstract IAuthenticationManager authentication();
+
+ public abstract IPublicKeyManager keys();
+
+ public abstract IRepositoryManager repositories();
+
+ public abstract IProjectManager projects();
+
+ public abstract IFederationManager federation();
+
+ public abstract IGitblit gitblit();
+
+ public abstract ITicketService tickets();
+
+ public abstract TimeZone getTimezone();
+
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/PageRegistration.java b/src/main/java/com/gitblit/wicket/PageRegistration.java
deleted file mode 100644
index 1b98f2c7..00000000
--- a/src/main/java/com/gitblit/wicket/PageRegistration.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.wicket.PageParameters;
-import org.apache.wicket.markup.html.WebPage;
-
-import com.gitblit.utils.StringUtils;
-
-/**
- * Represents a page link registration for the topbar.
- *
- * @author James Moger
- *
- */
-public class PageRegistration implements Serializable {
- private static final long serialVersionUID = 1L;
-
- public final String translationKey;
- public final Class<? extends WebPage> pageClass;
- public final PageParameters params;
- public final boolean hiddenPhone;
-
- public PageRegistration(String translationKey, Class<? extends WebPage> pageClass) {
- this(translationKey, pageClass, null);
- }
-
- public PageRegistration(String translationKey, Class<? extends WebPage> pageClass,
- PageParameters params) {
- this(translationKey, pageClass, params, false);
- }
-
- public PageRegistration(String translationKey, Class<? extends WebPage> pageClass,
- PageParameters params, boolean hiddenPhone) {
- this.translationKey = translationKey;
- this.pageClass = pageClass;
- this.params = params;
- this.hiddenPhone = hiddenPhone;
- }
-
- /**
- * Represents a page link to a non-Wicket page. Might be external.
- *
- * @author James Moger
- *
- */
- public static class OtherPageLink extends PageRegistration {
-
- private static final long serialVersionUID = 1L;
-
- public final String url;
-
- public OtherPageLink(String translationKey, String url) {
- super(translationKey, null);
- this.url = url;
- }
-
- public OtherPageLink(String translationKey, String url, boolean hiddenPhone) {
- super(translationKey, null, null, hiddenPhone);
- this.url = url;
- }
- }
-
- /**
- * Represents a DropDownMenu for the topbar
- *
- * @author James Moger
- *
- */
- public static class DropDownMenuRegistration extends PageRegistration {
-
- private static final long serialVersionUID = 1L;
-
- public final List<DropDownMenuItem> menuItems;
-
- public DropDownMenuRegistration(String translationKey, Class<? extends WebPage> pageClass) {
- super(translationKey, pageClass);
- menuItems = new ArrayList<DropDownMenuItem>();
- }
- }
-
- /**
- * A MenuItem for the DropDownMenu.
- *
- * @author James Moger
- *
- */
- public static class DropDownMenuItem implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- final PageParameters parameters;
- final String displayText;
- final String parameter;
- final String value;
- final boolean isSelected;
-
- /**
- * Divider constructor.
- */
- public DropDownMenuItem() {
- this(null, null, null, null);
- }
-
- /**
- * Standard Menu Item constructor.
- *
- * @param displayText
- * @param parameter
- * @param value
- */
- public DropDownMenuItem(String displayText, String parameter, String value) {
- this(displayText, parameter, value, null);
- }
-
- /**
- * Standard Menu Item constructor that preserves aggregate parameters.
- *
- * @param displayText
- * @param parameter
- * @param value
- */
- public DropDownMenuItem(String displayText, String parameter, String value,
- PageParameters params) {
- this.displayText = displayText;
- this.parameter = parameter;
- this.value = value;
-
- if (params == null) {
- // no parameters specified
- parameters = new PageParameters();
- setParameter(parameter, value);
- isSelected = false;
- } else {
- parameters = new PageParameters(params);
- if (parameters.containsKey(parameter)) {
- isSelected = params.getString(parameter).equals(value);
- // set the new selection value
- setParameter(parameter, value);
- } else {
- // not currently selected
- isSelected = false;
- setParameter(parameter, value);
- }
- }
- }
-
- protected void setParameter(String parameter, String value) {
- if (!StringUtils.isEmpty(parameter)) {
- if (StringUtils.isEmpty(value)) {
- this.parameters.remove(parameter);
- } else {
- this.parameters.put(parameter, value);
- }
- }
- }
-
- public String formatParameter() {
- if (StringUtils.isEmpty(parameter) || StringUtils.isEmpty(value)) {
- return "";
- }
- return parameter + "=" + value;
- }
-
- public PageParameters getPageParameters() {
- return parameters;
- }
-
- public boolean isDivider() {
- return displayText == null && value == null && parameter == null;
- }
-
- public boolean isSelected() {
- return isSelected;
- }
-
- @Override
- public int hashCode() {
- if (isDivider()) {
- // divider menu item
- return super.hashCode();
- }
- if (StringUtils.isEmpty(displayText)) {
- return value.hashCode() + parameter.hashCode();
- }
- return displayText.hashCode();
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof DropDownMenuItem) {
- return hashCode() == o.hashCode();
- }
- return false;
- }
-
- @Override
- public String toString() {
- if (StringUtils.isEmpty(displayText)) {
- return formatParameter();
- }
- return displayText;
- }
- }
-
- public static class DropDownToggleItem extends DropDownMenuItem {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * Toggle Menu Item constructor that preserves aggregate parameters.
- *
- * @param displayText
- * @param parameter
- * @param value
- */
- public DropDownToggleItem(String displayText, String parameter, String value,
- PageParameters params) {
- super(displayText, parameter, value, params);
- if (isSelected) {
- // already selected, so remove this enables toggling
- parameters.remove(parameter);
- }
- }
- }
-} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/PluginClassResolver.java b/src/main/java/com/gitblit/wicket/PluginClassResolver.java
new file mode 100644
index 00000000..ba53b04b
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/PluginClassResolver.java
@@ -0,0 +1,122 @@
+/*
+ * 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.wicket;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.application.IClassResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ro.fortsoft.pf4j.PluginState;
+import ro.fortsoft.pf4j.PluginWrapper;
+
+import com.gitblit.manager.IPluginManager;
+
+/**
+ * Resolves plugin classes and resources.
+ */
+public class PluginClassResolver implements IClassResolver {
+ private static final Logger logger = LoggerFactory.getLogger(PluginClassResolver.class);
+
+ private final IPluginManager pluginManager;
+
+ public PluginClassResolver(IPluginManager pluginManager) {
+ this.pluginManager = pluginManager;
+ }
+
+ @Override
+ public Class<?> resolveClass(final String className) throws ClassNotFoundException {
+ boolean debugEnabled = logger.isDebugEnabled();
+
+ for (PluginWrapper plugin : pluginManager.getPlugins()) {
+ if (PluginState.STARTED != plugin.getPluginState()) {
+ // ignore this plugin
+ continue;
+ }
+
+ try {
+ return plugin.getPluginClassLoader().loadClass(className);
+ } catch (ClassNotFoundException cnfx) {
+ if (debugEnabled) {
+ logger.debug("ClassResolver '{}' cannot find class: '{}'", plugin.getPluginId(), className);
+ }
+ }
+ }
+
+ throw new ClassNotFoundException(className);
+ }
+
+ @Override
+ public Iterator<URL> getResources(final String name) {
+ Set<URL> urls = new TreeSet<URL>(new UrlExternalFormComparator());
+
+ for (PluginWrapper plugin : pluginManager.getPlugins()) {
+ if (PluginState.STARTED != plugin.getPluginState()) {
+ // ignore this plugin
+ continue;
+ }
+
+ Iterator<URL> it = getResources(name, plugin);
+ while (it.hasNext()) {
+ URL url = it.next();
+ urls.add(url);
+ }
+ }
+
+ return urls.iterator();
+ }
+
+ protected Iterator<URL> getResources(String name, PluginWrapper plugin) {
+ HashSet<URL> loadedFiles = new HashSet<URL>();
+ try {
+ // Try the classloader for the wicket jar/bundle
+ Enumeration<URL> resources = plugin.getPluginClassLoader().getResources(name);
+ loadResources(resources, loadedFiles);
+
+ // Try the classloader for the user's application jar/bundle
+ resources = Application.get().getClass().getClassLoader().getResources(name);
+ loadResources(resources, loadedFiles);
+
+ // Try the context class loader
+ resources = Thread.currentThread().getContextClassLoader().getResources(name);
+ loadResources(resources, loadedFiles);
+ } catch (IOException e) {
+ throw new WicketRuntimeException(e);
+ }
+
+ return loadedFiles.iterator();
+ }
+
+ private void loadResources(Enumeration<URL> resources, Set<URL> loadedFiles) {
+ if (resources != null) {
+ while (resources.hasMoreElements()) {
+ final URL url = resources.nextElement();
+ if (!loadedFiles.contains(url)) {
+ loadedFiles.add(url);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/UrlExternalFormComparator.java b/src/main/java/com/gitblit/wicket/UrlExternalFormComparator.java
new file mode 100644
index 00000000..90f4b320
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/UrlExternalFormComparator.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+import java.net.URL;
+import java.util.Comparator;
+
+/**
+ * A comparator of URL instances.
+ *
+ * Comparing URLs with their implementation of #equals() is
+ * bad because it may cause problems like DNS resolving, or other
+ * slow checks. This comparator uses the external form of an URL
+ * to make a simple comparison of two Strings.
+ *
+ * @since 1.5.6
+ */
+public class UrlExternalFormComparator implements Comparator<URL>
+{
+ @Override
+ public int compare(URL url1, URL url2)
+ {
+ return url1.toExternalForm().compareTo(url2.toExternalForm());
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/ActivityPage.java b/src/main/java/com/gitblit/wicket/pages/ActivityPage.java
index f0e390dc..c505a666 100644
--- a/src/main/java/com/gitblit/wicket/pages/ActivityPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/ActivityPage.java
@@ -31,15 +31,15 @@ import org.apache.wicket.markup.html.panel.Fragment;
import com.gitblit.Keys;
import com.gitblit.models.Activity;
+import com.gitblit.models.Menu.ParameterMenuItem;
+import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
import com.gitblit.models.Metric;
+import com.gitblit.models.NavLink;
import com.gitblit.models.RepositoryModel;
import com.gitblit.utils.ActivityUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.CacheControl;
import com.gitblit.wicket.CacheControl.LastModified;
-import com.gitblit.wicket.PageRegistration;
-import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
-import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.charting.Chart;
import com.gitblit.wicket.charting.Charts;
@@ -135,8 +135,8 @@ public class ActivityPage extends RootPage {
}
@Override
- protected void addDropDownMenus(List<PageRegistration> pages) {
- DropDownMenuRegistration filters = new DropDownMenuRegistration("gb.filters",
+ protected void addDropDownMenus(List<NavLink> navLinks) {
+ DropDownPageMenuNavLink filters = new DropDownPageMenuNavLink("gb.filters",
ActivityPage.class);
PageParameters currentParameters = getPageParameters();
@@ -153,9 +153,9 @@ public class ActivityPage extends RootPage {
if (filters.menuItems.size() > 0) {
// Reset Filter
- filters.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ filters.menuItems.add(new ParameterMenuItem(getString("gb.reset")));
}
- pages.add(filters);
+ navLinks.add(filters);
}
/**
@@ -209,7 +209,7 @@ public class ActivityPage extends RootPage {
}
charts.addChart(chart);
- // active repositories pie chart
+ // active repositories pie chart
chart = charts.createPieChart("chartRepositories", getString("gb.activeRepositories"),
getString("gb.repository"), getString("gb.commits"));
for (Metric metric : repositoryMetrics.values()) {
diff --git a/src/main/java/com/gitblit/wicket/pages/DashboardPage.java b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java
index 9853449e..9c10e01b 100644
--- a/src/main/java/com/gitblit/wicket/pages/DashboardPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java
@@ -36,7 +36,10 @@ import org.eclipse.jgit.lib.Repository;
import com.gitblit.Keys;
import com.gitblit.models.DailyLogEntry;
+import com.gitblit.models.Menu.ParameterMenuItem;
+import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
import com.gitblit.models.Metric;
+import com.gitblit.models.NavLink;
import com.gitblit.models.RefLogEntry;
import com.gitblit.models.RepositoryCommit;
import com.gitblit.models.RepositoryModel;
@@ -45,9 +48,6 @@ import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.RefLogUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebApp;
-import com.gitblit.wicket.PageRegistration;
-import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
-import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
import com.gitblit.wicket.charting.Chart;
import com.gitblit.wicket.charting.Charts;
import com.gitblit.wicket.charting.Flotr2Charts;
@@ -141,10 +141,10 @@ public abstract class DashboardPage extends RootPage {
}
@Override
- protected void addDropDownMenus(List<PageRegistration> pages) {
+ protected void addDropDownMenus(List<NavLink> navLinks) {
PageParameters params = getPageParameters();
- DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ DropDownPageMenuNavLink menu = new DropDownPageMenuNavLink("gb.filters",
GitBlitWebApp.get().getHomePage());
// preserve repository filter option on time choices
@@ -152,10 +152,10 @@ public abstract class DashboardPage extends RootPage {
if (menu.menuItems.size() > 0) {
// Reset Filter
- menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ menu.menuItems.add(new ParameterMenuItem(getString("gb.reset")));
}
- pages.add(menu);
+ navLinks.add(menu);
}
diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectPage.java b/src/main/java/com/gitblit/wicket/pages/ProjectPage.java
index b92282b4..d358b775 100644
--- a/src/main/java/com/gitblit/wicket/pages/ProjectPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/ProjectPage.java
@@ -26,6 +26,11 @@ import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.ExternalLink;
import com.gitblit.Keys;
+import com.gitblit.models.Menu.MenuDivider;
+import com.gitblit.models.Menu.MenuItem;
+import com.gitblit.models.Menu.ParameterMenuItem;
+import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
+import com.gitblit.models.NavLink;
import com.gitblit.models.ProjectModel;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
@@ -37,9 +42,6 @@ import com.gitblit.wicket.CacheControl.LastModified;
import com.gitblit.wicket.GitBlitWebApp;
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.GitblitRedirectException;
-import com.gitblit.wicket.PageRegistration;
-import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
-import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.FilterableRepositoryList;
@@ -159,10 +161,10 @@ public class ProjectPage extends DashboardPage {
}
@Override
- protected void addDropDownMenus(List<PageRegistration> pages) {
+ protected void addDropDownMenus(List<NavLink> navLinks) {
PageParameters params = getPageParameters();
- DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ DropDownPageMenuNavLink menu = new DropDownPageMenuNavLink("gb.filters",
ProjectPage.class);
// preserve time filter option on repository choices
menu.menuItems.addAll(getRepositoryFilterItems(params));
@@ -172,15 +174,15 @@ public class ProjectPage extends DashboardPage {
if (menu.menuItems.size() > 0) {
// Reset Filter
- menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), "p", WicketUtils.getProjectName(params)));
+ menu.menuItems.add(new ParameterMenuItem(getString("gb.reset"), "p", WicketUtils.getProjectName(params)));
}
- pages.add(menu);
+ navLinks.add(menu);
- DropDownMenuRegistration projects = new DropDownMenuRegistration("gb.projects",
+ DropDownPageMenuNavLink projects = new DropDownPageMenuNavLink("gb.projects",
ProjectPage.class);
projects.menuItems.addAll(getProjectsMenu());
- pages.add(projects);
+ navLinks.add(projects);
}
@Override
@@ -202,8 +204,8 @@ public class ProjectPage extends DashboardPage {
return null;
}
- protected List<DropDownMenuItem> getProjectsMenu() {
- List<DropDownMenuItem> menu = new ArrayList<DropDownMenuItem>();
+ protected List<MenuItem> getProjectsMenu() {
+ List<MenuItem> menu = new ArrayList<MenuItem>();
List<ProjectModel> projects = new ArrayList<ProjectModel>();
for (ProjectModel model : getProjectModels()) {
if (!model.isUserProject()) {
@@ -230,11 +232,11 @@ public class ProjectPage extends DashboardPage {
}
for (ProjectModel project : projects) {
- menu.add(new DropDownMenuItem(project.getDisplayName(), "p", project.name));
+ menu.add(new ParameterMenuItem(project.getDisplayName(), "p", project.name));
}
if (showAllProjects) {
- menu.add(new DropDownMenuItem());
- menu.add(new DropDownMenuItem("all projects", null, null));
+ menu.add(new MenuDivider());
+ menu.add(new ParameterMenuItem("all projects"));
}
return menu;
}
diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java
index 77d49846..f04fa78a 100644
--- a/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java
@@ -24,11 +24,11 @@ import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.ListDataProvider;
import com.gitblit.Keys;
+import com.gitblit.models.Menu.ParameterMenuItem;
+import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
+import com.gitblit.models.NavLink;
import com.gitblit.models.ProjectModel;
import com.gitblit.wicket.GitBlitWebSession;
-import com.gitblit.wicket.PageRegistration;
-import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
-import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.LinkPanel;
@@ -115,10 +115,10 @@ public class ProjectsPage extends RootPage {
}
@Override
- protected void addDropDownMenus(List<PageRegistration> pages) {
+ protected void addDropDownMenus(List<NavLink> navLinks) {
PageParameters params = getPageParameters();
- DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ DropDownPageMenuNavLink menu = new DropDownPageMenuNavLink("gb.filters",
ProjectsPage.class);
// preserve time filter option on repository choices
menu.menuItems.addAll(getRepositoryFilterItems(params));
@@ -128,9 +128,9 @@ public class ProjectsPage extends RootPage {
if (menu.menuItems.size() > 0) {
// Reset Filter
- menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ menu.menuItems.add(new ParameterMenuItem(getString("gb.reset")));
}
- pages.add(menu);
+ navLinks.add(menu);
}
}
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java
index f4ddf402..a0b15a83 100644
--- a/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java
@@ -29,15 +29,15 @@ import org.apache.wicket.markup.html.basic.Label;
import org.eclipse.jgit.lib.Constants;
import com.gitblit.Keys;
+import com.gitblit.models.Menu.ParameterMenuItem;
+import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
+import com.gitblit.models.NavLink;
import com.gitblit.models.RepositoryModel;
import com.gitblit.utils.MarkdownUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.CacheControl;
import com.gitblit.wicket.CacheControl.LastModified;
import com.gitblit.wicket.GitBlitWebSession;
-import com.gitblit.wicket.PageRegistration;
-import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
-import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.RepositoriesPanel;
@@ -92,10 +92,10 @@ public class RepositoriesPage extends RootPage {
}
@Override
- protected void addDropDownMenus(List<PageRegistration> pages) {
+ protected void addDropDownMenus(List<NavLink> navLinks) {
PageParameters params = getPageParameters();
- DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ DropDownPageMenuNavLink menu = new DropDownPageMenuNavLink("gb.filters",
RepositoriesPage.class);
// preserve time filter option on repository choices
menu.menuItems.addAll(getRepositoryFilterItems(params));
@@ -105,10 +105,10 @@ public class RepositoriesPage extends RootPage {
if (menu.menuItems.size() > 0) {
// Reset Filter
- menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ menu.menuItems.add(new ParameterMenuItem(getString("gb.reset")));
}
- pages.add(menu);
+ navLinks.add(menu);
}
private String readMarkdown(String messageSource, String resource) {
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
index 5ea99fd8..165feedf 100644
--- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
@@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -49,6 +48,10 @@ import org.slf4j.LoggerFactory;
import com.gitblit.Constants;
import com.gitblit.GitBlitException;
import com.gitblit.Keys;
+import com.gitblit.extensions.RepositoryNavLinkExtension;
+import com.gitblit.models.NavLink;
+import com.gitblit.models.NavLink.ExternalNavLink;
+import com.gitblit.models.NavLink.PageNavLink;
import com.gitblit.models.ProjectModel;
import com.gitblit.models.RefModel;
import com.gitblit.models.RepositoryModel;
@@ -66,8 +69,6 @@ import com.gitblit.utils.RefLogUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.CacheControl;
import com.gitblit.wicket.GitBlitWebSession;
-import com.gitblit.wicket.PageRegistration;
-import com.gitblit.wicket.PageRegistration.OtherPageLink;
import com.gitblit.wicket.SessionlessForm;
import com.gitblit.wicket.TicketsUI;
import com.gitblit.wicket.WicketUtils;
@@ -91,7 +92,6 @@ public abstract class RepositoryPage extends RootPage {
private Map<String, SubmoduleModel> submodules;
- private final Map<String, PageRegistration> registeredPages;
private boolean showAdmin;
private boolean isOwner;
@@ -150,12 +150,11 @@ public abstract class RepositoryPage extends RootPage {
}
}
- // register the available page links for this page and user
- registeredPages = registerPages();
+ // register the available navigation links for this page and user
+ List<NavLink> navLinks = registerNavLinks();
- // standard page links
- List<PageRegistration> pages = new ArrayList<PageRegistration>(registeredPages.values());
- NavigationPanel navigationPanel = new NavigationPanel("repositoryNavPanel", getRepoNavPageClass(), pages);
+ // standard navigation links
+ NavigationPanel navigationPanel = new NavigationPanel("repositoryNavPanel", getRepoNavPageClass(), navLinks);
add(navigationPanel);
add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()
@@ -183,45 +182,56 @@ public abstract class RepositoryPage extends RootPage {
return new BugtraqProcessor(app().settings());
}
- private Map<String, PageRegistration> registerPages() {
+ private List<NavLink> registerNavLinks() {
PageParameters params = null;
if (!StringUtils.isEmpty(repositoryName)) {
params = WicketUtils.newRepositoryParameter(repositoryName);
}
- Map<String, PageRegistration> pages = new LinkedHashMap<String, PageRegistration>();
+ List<NavLink> navLinks = new ArrayList<NavLink>();
Repository r = getRepository();
RepositoryModel model = getRepositoryModel();
// standard links
if (RefLogUtils.getRefLogBranch(r) == null) {
- pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
+ navLinks.add(new PageNavLink("gb.summary", SummaryPage.class, params));
} else {
- pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
+ navLinks.add(new PageNavLink("gb.summary", SummaryPage.class, params));
// pages.put("overview", new PageRegistration("gb.overview", OverviewPage.class, params));
- pages.put("reflog", new PageRegistration("gb.reflog", ReflogPage.class, params));
+ navLinks.add(new PageNavLink("gb.reflog", ReflogPage.class, params));
}
- pages.put("commits", new PageRegistration("gb.commits", LogPage.class, params));
- pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
+ navLinks.add(new PageNavLink("gb.commits", LogPage.class, params));
+ navLinks.add(new PageNavLink("gb.tree", TreePage.class, params));
if (app().tickets().isReady() && (app().tickets().isAcceptingNewTickets(getRepositoryModel()) || app().tickets().hasTickets(getRepositoryModel()))) {
PageParameters tParams = new PageParameters(params);
for (String state : TicketsUI.openStatii) {
tParams.add(Lucene.status.name(), state);
}
- pages.put("tickets", new PageRegistration("gb.tickets", TicketsPage.class, tParams));
+ navLinks.add(new PageNavLink("gb.tickets", TicketsPage.class, tParams));
}
- pages.put("docs", new PageRegistration("gb.docs", DocsPage.class, params, true));
+ navLinks.add(new PageNavLink("gb.docs", DocsPage.class, params, true));
if (app().settings().getBoolean(Keys.web.allowForking, true)) {
- pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params, true));
+ navLinks.add(new PageNavLink("gb.forks", ForksPage.class, params, true));
}
- pages.put("compare", new PageRegistration("gb.compare", ComparePage.class, params, true));
+ navLinks.add(new PageNavLink("gb.compare", ComparePage.class, params, true));
// conditional links
- // per-repository extra page links
+ // per-repository extra navlinks
if (JGitUtils.getPagesBranch(r) != null) {
- OtherPageLink pagesLink = new OtherPageLink("gb.pages", PagesServlet.asLink(
+ ExternalNavLink pagesLink = new ExternalNavLink("gb.pages", PagesServlet.asLink(
getRequest().getRelativePathPrefixToContextRoot(), repositoryName, null), true);
- pages.put("pages", pagesLink);
+ navLinks.add(pagesLink);
+ }
+
+ UserModel user = UserModel.ANONYMOUS;
+ if (GitBlitWebSession.get().isLoggedIn()) {
+ user = GitBlitWebSession.get().getUser();
+ }
+
+ // add repository nav link extensions
+ List<RepositoryNavLinkExtension> extensions = app().plugins().getExtensions(RepositoryNavLinkExtension.class);
+ for (RepositoryNavLinkExtension ext : extensions) {
+ navLinks.addAll(ext.getNavLinks(user, model));
}
// Conditionally add edit link
@@ -233,9 +243,8 @@ public abstract class RepositoryPage extends RootPage {
showAdmin = app().settings().getBoolean(Keys.web.allowAdministration, false);
}
isOwner = GitBlitWebSession.get().isLoggedIn()
- && (model.isOwner(GitBlitWebSession.get()
- .getUsername()));
- return pages;
+ && (model.isOwner(GitBlitWebSession.get().getUsername()));
+ return navLinks;
}
protected boolean allowForkControls() {
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 @@
<li class="dropdown">
<a data-toggle="dropdown" class="dropdown-toggle" style="text-decoration: none;" href="#"><span wicket:id="username"></span> <b class="caret"></b></a>
<ul class="dropdown-menu">
- <li style="color:#ccc;padding-left:15px;font-weight:bold;"><span wicket:id="displayName"></span></li>
- <li class="divider"></li>
- <li><a wicket:id="newRepository"><wicket:message key="gb.newRepository"></wicket:message></a></li>
- <li><a wicket:id="myProfile"><wicket:message key="gb.myProfile"></wicket:message></a></li>
- <li><a wicket:id="changePassword"><wicket:message key="gb.changePassword"></wicket:message></a></li>
- <li class="divider"></li>
+ <span wicket:id="standardMenu"></span>
+ <span wicket:id="adminMenu"></span>
+ <span wicket:id="extensionsMenu"></span>
<li><a wicket:id="logout"><wicket:message key="gb.logout"></wicket:message></a></li>
</ul>
</li>
</wicket:fragment>
+
+ <wicket:fragment wicket:id="submenuFragment">
+ <li style="color:#ccc;padding-left:15px;font-weight:bold;"><span wicket:id="submenuTitle"></span></li>
+ <li wicket:id="submenuItem"><span wicket:id="submenuLink"></span></li>
+ </wicket:fragment>
</wicket:extend>
</body>
diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java
index c59c1892..a2f3a497 100644
--- a/src/main/java/com/gitblit/wicket/pages/RootPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java
@@ -1,604 +1,708 @@
-/*
- * 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.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.DropDownMenuItem;
-import com.gitblit.wicket.PageRegistration.DropDownToggleItem;
-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<String> username = new Model<String>("");
- IModel<String> password = new Model<String>("");
- List<RepositoryModel> repositoryModels = new ArrayList<RepositoryModel>();
-
- 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("<style type=\"text/css\">\n");
- buffer.append(".navbar-inner {\n");
- final String headerBackground = app().settings().getString(Keys.web.headerBackgroundColor, null);
- if (!StringUtils.isEmpty(headerBackground)) {
- buffer.append(MessageFormat.format("background-color: {0};\n", headerBackground));
- }
- final String headerBorder = app().settings().getString(Keys.web.headerBorderColor, null);
- if (!StringUtils.isEmpty(headerBorder)) {
- buffer.append(MessageFormat.format("border-bottom: 1px solid {0} !important;\n", headerBorder));
- }
- buffer.append("}\n");
- final String headerBorderFocus = app().settings().getString(Keys.web.headerBorderFocusColor, null);
- if (!StringUtils.isEmpty(headerBorderFocus)) {
- buffer.append(".navbar ul li:focus, .navbar .active {\n");
- buffer.append(MessageFormat.format("border-bottom: 4px solid {0};\n", headerBorderFocus));
- buffer.append("}\n");
- }
- final String headerForeground = app().settings().getString(Keys.web.headerForegroundColor, null);
- if (!StringUtils.isEmpty(headerForeground)) {
- buffer.append(".navbar ul.nav li a {\n");
- buffer.append(MessageFormat.format("color: {0};\n", headerForeground));
- buffer.append("}\n");
- buffer.append(".navbar ul.nav .active a {\n");
- buffer.append(MessageFormat.format("color: {0};\n", headerForeground));
- buffer.append("}\n");
- }
- final String headerHover = app().settings().getString(Keys.web.headerHoverColor, null);
- if (!StringUtils.isEmpty(headerHover)) {
- buffer.append(".navbar ul.nav li a:hover {\n");
- buffer.append(MessageFormat.format("color: {0} !important;\n", headerHover));
- buffer.append("}\n");
- }
- buffer.append("</style>\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));
- }
-
- boolean showRegistrations = app().federation().canFederate()
- && app().settings().getBoolean(Keys.web.showFederationRegistrations, false);
-
- // navigation links
- List<PageRegistration> pages = new ArrayList<PageRegistration>();
- 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));
- }
- if (showAdmin) {
- pages.add(new PageRegistration("gb.users", UsersPage.class));
- }
- if (showAdmin || showRegistrations) {
- pages.add(new PageRegistration("gb.federation", FederationPage.class));
- }
-
- 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<? extends BasePage> 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<RepositoryModel> getRepositoryModels() {
- if (repositoryModels.isEmpty()) {
- final UserModel user = GitBlitWebSession.get().getUser();
- List<RepositoryModel> repositories = app().repositories().getRepositoryModels(user);
- repositoryModels.addAll(repositories);
- Collections.sort(repositoryModels);
- }
- return repositoryModels;
- }
-
- protected void addDropDownMenus(List<PageRegistration> pages) {
-
- }
-
- protected List<DropDownMenuItem> getRepositoryFilterItems(PageParameters params) {
- final UserModel user = GitBlitWebSession.get().getUser();
- Set<DropDownMenuItem> filters = new LinkedHashSet<DropDownMenuItem>();
- List<RepositoryModel> repositories = getRepositoryModels();
-
- // accessible repositories by federation set
- Map<String, AtomicInteger> setMap = new HashMap<String, AtomicInteger>();
- 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<String> sets = new ArrayList<String>(setMap.keySet());
- Collections.sort(sets);
- for (String set : sets) {
- filters.add(new DropDownToggleItem(MessageFormat.format("{0} ({1})", set,
- setMap.get(set).get()), "set", set, params));
- }
- // divider
- filters.add(new DropDownMenuItem());
- }
-
- // user's team memberships
- if (user != null && user.teams.size() > 0) {
- List<TeamModel> teams = new ArrayList<TeamModel>(user.teams);
- Collections.sort(teams);
- for (TeamModel team : teams) {
- filters.add(new DropDownToggleItem(MessageFormat.format("{0} ({1})", team.name,
- team.repositories.size()), "team", team.name, params));
- }
- // divider
- filters.add(new DropDownMenuItem());
- }
-
- // custom filters
- String customFilters = app().settings().getString(Keys.web.customFilters, null);
- if (!StringUtils.isEmpty(customFilters)) {
- boolean addedExpression = false;
- List<String> expressions = StringUtils.getStringsFromValue(customFilters, "!!!");
- for (String expression : expressions) {
- if (!StringUtils.isEmpty(expression)) {
- addedExpression = true;
- filters.add(new DropDownToggleItem(null, "x", expression, params));
- }
- }
- // if we added any custom expressions, add a divider
- if (addedExpression) {
- filters.add(new DropDownMenuItem());
- }
- }
- return new ArrayList<DropDownMenuItem>(filters);
- }
-
- protected List<DropDownMenuItem> 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<DropDownMenuItem> items = new ArrayList<DropDownMenuItem>();
- Set<Integer> choicesSet = new TreeSet<Integer>(app().settings().getIntegers(Keys.web.activityDurationChoices));
- if (choicesSet.isEmpty()) {
- choicesSet.addAll(Arrays.asList(1, 3, 7, 14, 21, 28));
- }
- List<Integer> choices = new ArrayList<Integer>(choicesSet);
- Collections.sort(choices);
- String lastDaysPattern = getString("gb.lastNDays");
- for (Integer db : choices) {
- if (db == 1) {
- items.add(new DropDownMenuItem(getString("gb.time.today"), "db", db.toString(), clonedParams));
- } else {
- String txt = MessageFormat.format(lastDaysPattern, db);
- items.add(new DropDownMenuItem(txt, "db", db.toString(), clonedParams));
- }
- }
- items.add(new DropDownMenuItem());
- return items;
- }
-
- protected List<RepositoryModel> 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<RepositoryModel> availableModels = getRepositoryModels();
- Set<RepositoryModel> models = new HashSet<RepositoryModel>();
-
- 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<String> 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<String> teams = StringUtils.getStringsFromValue(team, ",");
-
- // need TeamModels first
- List<TeamModel> teamModels = new ArrayList<TeamModel>();
- 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<RepositoryModel> timeFiltered = new HashSet<RepositoryModel>();
- for (RepositoryModel model : models) {
- if (model.lastChange.after(threshold)) {
- timeFiltered.add(model);
- }
- }
- models = timeFiltered;
- }
-
- List<RepositoryModel> list = new ArrayList<RepositoryModel>(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<Void> loginForm = new SessionlessForm<Void>("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<String> unameField = new TextField<String>("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<Void>("newRepository",
- EditRepositoryPage.class).setVisible(user.canAdmin() || user.canCreate()));
-
- add(new BookmarkablePageLink<Void>("myProfile",
- UserPage.class, WicketUtils.newUsernameParameter(user.username)));
-
- add(new BookmarkablePageLink<Void>("changePassword",
- ChangePasswordPage.class).setVisible(editCredentials));
-
- add(new BookmarkablePageLink<Void>("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.NavLinkExtension;
+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.NavLink;
+import com.gitblit.models.NavLink.PageNavLink;
+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.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<String> username = new Model<String>("");
+ IModel<String> password = new Model<String>("");
+ List<RepositoryModel> repositoryModels = new ArrayList<RepositoryModel>();
+
+ 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("<style type=\"text/css\">\n");
+ buffer.append(".navbar-inner {\n");
+ final String headerBackground = app().settings().getString(Keys.web.headerBackgroundColor, null);
+ if (!StringUtils.isEmpty(headerBackground)) {
+ buffer.append(MessageFormat.format("background-color: {0};\n", headerBackground));
+ }
+ final String headerBorder = app().settings().getString(Keys.web.headerBorderColor, null);
+ if (!StringUtils.isEmpty(headerBorder)) {
+ buffer.append(MessageFormat.format("border-bottom: 1px solid {0} !important;\n", headerBorder));
+ }
+ buffer.append("}\n");
+ final String headerBorderFocus = app().settings().getString(Keys.web.headerBorderFocusColor, null);
+ if (!StringUtils.isEmpty(headerBorderFocus)) {
+ buffer.append(".navbar ul li:focus, .navbar .active {\n");
+ buffer.append(MessageFormat.format("border-bottom: 4px solid {0};\n", headerBorderFocus));
+ buffer.append("}\n");
+ }
+ final String headerForeground = app().settings().getString(Keys.web.headerForegroundColor, null);
+ if (!StringUtils.isEmpty(headerForeground)) {
+ buffer.append(".navbar ul.nav li a {\n");
+ buffer.append(MessageFormat.format("color: {0};\n", headerForeground));
+ buffer.append("}\n");
+ buffer.append(".navbar ul.nav .active a {\n");
+ buffer.append(MessageFormat.format("color: {0};\n", headerForeground));
+ buffer.append("}\n");
+ }
+ final String headerHover = app().settings().getString(Keys.web.headerHoverColor, null);
+ if (!StringUtils.isEmpty(headerHover)) {
+ buffer.append(".navbar ul.nav li a:hover {\n");
+ buffer.append(MessageFormat.format("color: {0} !important;\n", headerHover));
+ buffer.append("}\n");
+ }
+ buffer.append("</style>\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<NavLink> navLinks = new ArrayList<NavLink>();
+ if (!authenticateView || (authenticateView && isLoggedIn)) {
+ navLinks.add(new PageNavLink(isLoggedIn ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class,
+ getRootPageParameters()));
+ if (isLoggedIn && app().tickets().isReady()) {
+ navLinks.add(new PageNavLink("gb.myTickets", MyTicketsPage.class));
+ }
+ navLinks.add(new PageNavLink("gb.repositories", RepositoriesPage.class,
+ getRootPageParameters()));
+ navLinks.add(new PageNavLink("gb.activity", ActivityPage.class, getRootPageParameters()));
+ if (allowLucene) {
+ navLinks.add(new PageNavLink("gb.search", LuceneSearchPage.class));
+ }
+
+ if (!authenticateView || (authenticateView && isLoggedIn)) {
+ addDropDownMenus(navLinks);
+ }
+
+ UserModel user = UserModel.ANONYMOUS;
+ if (isLoggedIn) {
+ user = GitBlitWebSession.get().getUser();
+ }
+
+ // add nav link extensions
+ List<NavLinkExtension> extensions = app().plugins().getExtensions(NavLinkExtension.class);
+ for (NavLinkExtension ext : extensions) {
+ navLinks.addAll(ext.getNavLinks(user));
+ }
+ }
+
+ NavigationPanel navPanel = new NavigationPanel("navPanel", getRootNavPageClass(), navLinks);
+ 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<? extends BasePage> 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<RepositoryModel> getRepositoryModels() {
+ if (repositoryModels.isEmpty()) {
+ final UserModel user = GitBlitWebSession.get().getUser();
+ List<RepositoryModel> repositories = app().repositories().getRepositoryModels(user);
+ repositoryModels.addAll(repositories);
+ Collections.sort(repositoryModels);
+ }
+ return repositoryModels;
+ }
+
+ protected void addDropDownMenus(List<NavLink> navLinks) {
+
+ }
+
+ protected List<com.gitblit.models.Menu.MenuItem> getRepositoryFilterItems(PageParameters params) {
+ final UserModel user = GitBlitWebSession.get().getUser();
+ Set<MenuItem> filters = new LinkedHashSet<MenuItem>();
+ List<RepositoryModel> repositories = getRepositoryModels();
+
+ // accessible repositories by federation set
+ Map<String, AtomicInteger> setMap = new HashMap<String, AtomicInteger>();
+ 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<String> sets = new ArrayList<String>(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<TeamModel> teams = new ArrayList<TeamModel>(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<String> 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<MenuItem>(filters);
+ }
+
+ protected List<MenuItem> 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<MenuItem> items = new ArrayList<MenuItem>();
+ Set<Integer> choicesSet = new TreeSet<Integer>(app().settings().getIntegers(Keys.web.activityDurationChoices));
+ if (choicesSet.isEmpty()) {
+ choicesSet.addAll(Arrays.asList(1, 3, 7, 14, 21, 28));
+ }
+ List<Integer> choices = new ArrayList<Integer>(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<RepositoryModel> 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<RepositoryModel> availableModels = getRepositoryModels();
+ Set<RepositoryModel> models = new HashSet<RepositoryModel>();
+
+ 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<String> 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<String> teams = StringUtils.getStringsFromValue(team, ",");
+
+ // need TeamModels first
+ List<TeamModel> teamModels = new ArrayList<TeamModel>();
+ 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<RepositoryModel> timeFiltered = new HashSet<RepositoryModel>();
+ for (RepositoryModel model : models) {
+ if (model.lastChange.after(threshold)) {
+ timeFiltered.add(model);
+ }
+ }
+ models = timeFiltered;
+ }
+
+ List<RepositoryModel> list = new ArrayList<RepositoryModel>(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<Void> loginForm = new SessionlessForm<Void>("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<String> unameField = new TextField<String>("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<MenuItem> standardItems = new ArrayList<MenuItem>();
+ 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<MenuItem> adminItems = new ArrayList<MenuItem>();
+ 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<MenuItem> extensionItems = new ArrayList<MenuItem>();
+ List<UserMenuExtension> extensions = app().plugins().getExtensions(UserMenuExtension.class);
+ for (UserMenuExtension ext : extensions) {
+ List<MenuItem> 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<Void>("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<MenuItem> menuItems) {
+ Fragment submenu = new Fragment(wicketId, "submenuFragment", this);
+ submenu.add(new Label("submenuTitle", submenuTitle).setRenderBodyOnly(true));
+ ListDataProvider<MenuItem> menuItemsDp = new ListDataProvider<MenuItem>(menuItems);
+ DataView<MenuItem> submenuItems = new DataView<MenuItem>("submenuItem", menuItemsDp) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void populateItem(final Item<MenuItem> 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 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+<body>
+<wicket:extend>
+<div class="container">
+ <div wicket:id="teamsPanel">[teams panel]</div>
+</div>
+</wicket:extend>
+</body>
+</html> \ 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/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java
index a5d38d16..6cb791eb 100644
--- a/src/main/java/com/gitblit/wicket/pages/UserPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java
@@ -29,6 +29,9 @@ import org.apache.wicket.markup.repeater.data.ListDataProvider;
import org.eclipse.jgit.lib.PersonIdent;
import com.gitblit.Keys;
+import com.gitblit.models.Menu.ParameterMenuItem;
+import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
+import com.gitblit.models.NavLink;
import com.gitblit.models.ProjectModel;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
@@ -36,9 +39,6 @@ import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebApp;
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.GitblitRedirectException;
-import com.gitblit.wicket.PageRegistration;
-import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
-import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.GravatarImage;
import com.gitblit.wicket.panels.LinkPanel;
@@ -127,10 +127,10 @@ public class UserPage extends RootPage {
}
@Override
- protected void addDropDownMenus(List<PageRegistration> pages) {
+ protected void addDropDownMenus(List<NavLink> navLinks) {
PageParameters params = getPageParameters();
- DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ DropDownPageMenuNavLink menu = new DropDownPageMenuNavLink("gb.filters",
UserPage.class);
// preserve time filter option on repository choices
menu.menuItems.addAll(getRepositoryFilterItems(params));
@@ -140,9 +140,9 @@ public class UserPage extends RootPage {
if (menu.menuItems.size() > 0) {
// Reset Filter
- menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ menu.menuItems.add(new ParameterMenuItem(getString("gb.reset")));
}
- pages.add(menu);
+ navLinks.add(menu);
}
}
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 @@
<body>
<wicket:extend>
<div class="container">
- <div wicket:id="teamsPanel">[teams panel]</div>
-
<div wicket:id="usersPanel">[users panel]</div>
</div>
</wicket:extend>
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/DropDownMenu.java b/src/main/java/com/gitblit/wicket/panels/DropDownMenu.java
index d1a632e2..4e7ae54c 100644
--- a/src/main/java/com/gitblit/wicket/panels/DropDownMenu.java
+++ b/src/main/java/com/gitblit/wicket/panels/DropDownMenu.java
@@ -21,38 +21,90 @@ import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.ListDataProvider;
-import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
-import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
+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.NavLink.DropDownMenuNavLink;
+import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
import com.gitblit.wicket.WicketUtils;
public class DropDownMenu extends Panel {
private static final long serialVersionUID = 1L;
- public DropDownMenu(String id, String label, final DropDownMenuRegistration menu) {
+ public DropDownMenu(String id, String label, final DropDownPageMenuNavLink menu) {
super(id);
add(new Label("label", label).setRenderBodyOnly(true));
- ListDataProvider<DropDownMenuItem> items = new ListDataProvider<DropDownMenuItem>(
- menu.menuItems);
- DataView<DropDownMenuItem> view = new DataView<DropDownMenuItem>("menuItems", items) {
+ ListDataProvider<MenuItem> items = new ListDataProvider<MenuItem>(menu.menuItems);
+ DataView<MenuItem> view = new DataView<MenuItem>("menuItems", items) {
private static final long serialVersionUID = 1L;
@Override
- public void populateItem(final Item<DropDownMenuItem> item) {
- DropDownMenuItem entry = item.getModelObject();
- if (entry.isDivider()) {
+ public void populateItem(final Item<MenuItem> item) {
+ MenuItem entry = item.getModelObject();
+ if (entry instanceof PageLinkMenuItem) {
+ // link to another Wicket page
+ PageLinkMenuItem pageLink = (PageLinkMenuItem) entry;
+ item.add(new LinkPanel("menuItem", null, null, pageLink.toString(), pageLink.getPageClass(),
+ pageLink.getPageParameters(), false).setRenderBodyOnly(true));
+ } else if (entry instanceof ExternalLinkMenuItem) {
+ // link to a specified href
+ ExternalLinkMenuItem extLink = (ExternalLinkMenuItem) entry;
+ item.add(new LinkPanel("menuItem", null, extLink.toString(), extLink.getHref(),
+ extLink.openInNewWindow()).setRenderBodyOnly(true));
+ } else if (entry instanceof MenuDivider) {
+ // divider
item.add(new Label("menuItem").setRenderBodyOnly(true));
WicketUtils.setCssClass(item, "divider");
} else {
+ ParameterMenuItem parameter = (ParameterMenuItem) entry;
+ // parameter link for the current page
String icon = null;
- if (entry.isSelected()) {
+ if (parameter.isSelected()) {
icon = "icon-ok";
} else {
icon = "icon-ok-white";
}
item.add(new LinkPanel("menuItem", icon, null, entry.toString(), menu.pageClass,
- entry.getPageParameters(), false).setRenderBodyOnly(true));
+ parameter.getPageParameters(), false).setRenderBodyOnly(true));
+ }
+ }
+ };
+ add(view);
+ setRenderBodyOnly(true);
+ }
+
+ public DropDownMenu(String id, String label, final DropDownMenuNavLink menu) {
+ super(id);
+
+ add(new Label("label", label).setRenderBodyOnly(true));
+ ListDataProvider<MenuItem> items = new ListDataProvider<MenuItem>(menu.menuItems);
+ DataView<MenuItem> view = new DataView<MenuItem>("menuItems", items) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void populateItem(final Item<MenuItem> item) {
+ MenuItem entry = item.getModelObject();
+ if (entry instanceof PageLinkMenuItem) {
+ // link to another Wicket page
+ PageLinkMenuItem pageLink = (PageLinkMenuItem) entry;
+ item.add(new LinkPanel("menuItem", null, null, pageLink.toString(), pageLink.getPageClass(),
+ pageLink.getPageParameters(), false).setRenderBodyOnly(true));
+ } else if (entry instanceof ExternalLinkMenuItem) {
+ // link to a specified href
+ ExternalLinkMenuItem extLink = (ExternalLinkMenuItem) entry;
+ item.add(new LinkPanel("menuItem", null, extLink.toString(), extLink.getHref(),
+ extLink.openInNewWindow()).setRenderBodyOnly(true));
+ } else if (entry instanceof MenuDivider) {
+ // divider
+ item.add(new Label("menuItem").setRenderBodyOnly(true));
+ WicketUtils.setCssClass(item, "divider");
+ } else {
+ throw new IllegalArgumentException(String.format("Unexpected menuitem type %s",
+ entry.getClass().getSimpleName()));
}
}
};
diff --git a/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java b/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java
index 393dd139..2bc92f4c 100644
--- a/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java
@@ -23,9 +23,11 @@ import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.ListDataProvider;
-import com.gitblit.wicket.PageRegistration;
-import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
-import com.gitblit.wicket.PageRegistration.OtherPageLink;
+import com.gitblit.models.NavLink;
+import com.gitblit.models.NavLink.DropDownMenuNavLink;
+import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
+import com.gitblit.models.NavLink.ExternalNavLink;
+import com.gitblit.models.NavLink.PageNavLink;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.pages.BasePage;
@@ -34,45 +36,59 @@ public class NavigationPanel extends Panel {
private static final long serialVersionUID = 1L;
public NavigationPanel(String id, final Class<? extends BasePage> pageClass,
- List<PageRegistration> registeredPages) {
+ List<NavLink> navLinks) {
super(id);
- ListDataProvider<PageRegistration> refsDp = new ListDataProvider<PageRegistration>(
- registeredPages);
- DataView<PageRegistration> refsView = new DataView<PageRegistration>("navLink", refsDp) {
+ ListDataProvider<NavLink> refsDp = new ListDataProvider<NavLink>(navLinks);
+ DataView<NavLink> linksView = new DataView<NavLink>("navLink", refsDp) {
private static final long serialVersionUID = 1L;
@Override
- public void populateItem(final Item<PageRegistration> item) {
- PageRegistration entry = item.getModelObject();
- if (entry.hiddenPhone) {
+ public void populateItem(final Item<NavLink> item) {
+ NavLink navLink = item.getModelObject();
+ String linkText = navLink.translationKey;
+ try {
+ // try to lookup translation key
+ linkText = getString(navLink.translationKey);
+ } catch (Exception e) {
+ }
+
+ if (navLink.hiddenPhone) {
WicketUtils.setCssClass(item, "hidden-phone");
}
- if (entry instanceof OtherPageLink) {
+ if (navLink instanceof ExternalNavLink) {
// other link
- OtherPageLink link = (OtherPageLink) entry;
- Component c = new LinkPanel("link", null, getString(entry.translationKey), link.url);
+ ExternalNavLink link = (ExternalNavLink) navLink;
+ Component c = new LinkPanel("link", null, linkText, link.url);
+ c.setRenderBodyOnly(true);
+ item.add(c);
+ } else if (navLink instanceof DropDownPageMenuNavLink) {
+ // drop down menu
+ DropDownPageMenuNavLink reg = (DropDownPageMenuNavLink) navLink;
+ Component c = new DropDownMenu("link", linkText, reg);
c.setRenderBodyOnly(true);
item.add(c);
- } else if (entry instanceof DropDownMenuRegistration) {
+ WicketUtils.setCssClass(item, "dropdown");
+ } else if (navLink instanceof DropDownMenuNavLink) {
// drop down menu
- DropDownMenuRegistration reg = (DropDownMenuRegistration) entry;
- Component c = new DropDownMenu("link", getString(entry.translationKey), reg);
+ DropDownMenuNavLink reg = (DropDownMenuNavLink) navLink;
+ Component c = new DropDownMenu("link", linkText, reg);
c.setRenderBodyOnly(true);
item.add(c);
WicketUtils.setCssClass(item, "dropdown");
- } else {
+ } else if (navLink instanceof PageNavLink) {
+ PageNavLink reg = (PageNavLink) navLink;
// standard page link
- Component c = new LinkPanel("link", null, getString(entry.translationKey),
- entry.pageClass, entry.params);
+ Component c = new LinkPanel("link", null, linkText,
+ reg.pageClass, reg.params);
c.setRenderBodyOnly(true);
- if (entry.pageClass.equals(pageClass)) {
+ if (reg.pageClass.equals(pageClass)) {
WicketUtils.setCssClass(item, "active");
}
item.add(c);
}
}
};
- add(refsView);
+ add(linksView);
}
} \ No newline at end of file