();
- for (User user: Gitop.getInstance(UserManager.class).query(null)) {
+ for (User user: Gitop.getInstance(UserManager.class).query()) {
if (user.asSubject().isPermitted(new ObjectPermission(this, operation)))
authorizedUsers.add(user);
}
diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java b/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java
index a60441c00a..bac4a427b6 100644
--- a/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java
+++ b/gitop.core/src/main/java/com/pmease/gitop/core/model/User.java
@@ -23,17 +23,8 @@ import com.pmease.gitop.core.permission.ObjectPermission;
import com.pmease.gitop.core.permission.object.ProtectedObject;
import com.pmease.gitop.core.permission.object.UserBelonging;
import com.pmease.gitop.core.permission.operation.GeneralOperation;
+import com.pmease.gitop.core.validation.UserName;
-/**
- * This class represents either a project or an user in the system.
- *
- * In Gitop, users and projects are the same thing.
- * If necessary, you can always treat an user account as a project account.
- * {@link Project} and {@link Team} are always created under a specific account.
- *
- * @author robin
- *
- */
@SuppressWarnings("serial")
@Entity
@Editable
@@ -49,10 +40,8 @@ public class User extends AbstractUser implements ProtectedObject {
@Column(nullable=false)
private String email;
- @Column
private String displayName;
- @Column
private String avatarUrl;
private boolean admin;
@@ -76,7 +65,7 @@ public class User extends AbstractUser implements ProtectedObject {
private Collection voteVitations = new ArrayList();
@Editable(order=100)
- @NotEmpty
+ @UserName
@Override
public String getName() {
return super.getName();
@@ -217,13 +206,6 @@ public class User extends AbstractUser implements ProtectedObject {
}
}
- public static User anonymous() {
- User user = new User();
- user.setId(0L);
- user.setName("Guest");
- return user;
- }
-
@Override
public boolean implies(Permission permission) {
// Administrator can do anything
@@ -242,7 +224,7 @@ public class User extends AbstractUser implements ProtectedObject {
return true;
}
- for (Project each: Gitop.getInstance(ProjectManager.class).query(null)) {
+ for (Project each: Gitop.getInstance(ProjectManager.class).query()) {
ObjectPermission projectPermission = new ObjectPermission(each, each.getDefaultAuthorizedOperation());
if (projectPermission.implies(objectPermission))
return true;
diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/permission/UserRealm.java b/gitop.core/src/main/java/com/pmease/gitop/core/permission/UserRealm.java
index 0b6b49c654..3ff2ac071f 100644
--- a/gitop.core/src/main/java/com/pmease/gitop/core/permission/UserRealm.java
+++ b/gitop.core/src/main/java/com/pmease/gitop/core/permission/UserRealm.java
@@ -30,7 +30,7 @@ public class UserRealm extends AbstractRealm {
if (userId != 0L) {
return userManager.load(userId);
} else {
- return User.anonymous();
+ return User.ANONYMOUS;
}
}
diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectName.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectName.java
new file mode 100644
index 0000000000..9d3add2db0
--- /dev/null
+++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectName.java
@@ -0,0 +1,24 @@
+package com.pmease.gitop.core.validation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+import com.pmease.commons.editable.annotation.Name;
+
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Name
+@Constraint(validatedBy=ProjectNameValidator.class)
+public @interface ProjectName {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+}
diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameReservation.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameReservation.java
new file mode 100644
index 0000000000..c117beb799
--- /dev/null
+++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameReservation.java
@@ -0,0 +1,10 @@
+package com.pmease.gitop.core.validation;
+
+import java.util.Set;
+
+import com.pmease.commons.loader.ExtensionPoint;
+
+@ExtensionPoint
+public interface ProjectNameReservation {
+ Set getReserved();
+}
diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameValidator.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameValidator.java
new file mode 100644
index 0000000000..8840e5c3a5
--- /dev/null
+++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/ProjectNameValidator.java
@@ -0,0 +1,22 @@
+package com.pmease.gitop.core.validation;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import com.pmease.gitop.core.Gitop;
+import com.pmease.gitop.core.manager.ProjectManager;
+
+public class ProjectNameValidator implements ConstraintValidator {
+
+ public void initialize(ProjectName constaintAnnotation) {
+ }
+
+ public boolean isValid(String value, ConstraintValidatorContext constraintContext) {
+ if (value == null)
+ return true;
+
+ constraintContext.disableDefaultConstraintViolation();
+ constraintContext.buildConstraintViolationWithTemplate(value + " is a reserved word.").addConstraintViolation();
+ return !Gitop.getInstance(ProjectManager.class).getReservedNames().contains(value);
+ }
+}
diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserName.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserName.java
new file mode 100644
index 0000000000..afc15eec8c
--- /dev/null
+++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserName.java
@@ -0,0 +1,24 @@
+package com.pmease.gitop.core.validation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+import com.pmease.commons.editable.annotation.Name;
+
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Name
+@Constraint(validatedBy=UserNameValidator.class)
+public @interface UserName {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+}
diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameReservation.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameReservation.java
new file mode 100644
index 0000000000..4c951a17cb
--- /dev/null
+++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameReservation.java
@@ -0,0 +1,10 @@
+package com.pmease.gitop.core.validation;
+
+import java.util.Set;
+
+import com.pmease.commons.loader.ExtensionPoint;
+
+@ExtensionPoint
+public interface UserNameReservation {
+ Set getReserved();
+}
diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameValidator.java b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameValidator.java
new file mode 100644
index 0000000000..c821a5d65f
--- /dev/null
+++ b/gitop.core/src/main/java/com/pmease/gitop/core/validation/UserNameValidator.java
@@ -0,0 +1,22 @@
+package com.pmease.gitop.core.validation;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import com.pmease.gitop.core.Gitop;
+import com.pmease.gitop.core.manager.UserManager;
+
+public class UserNameValidator implements ConstraintValidator {
+
+ public void initialize(UserName constaintAnnotation) {
+ }
+
+ public boolean isValid(String value, ConstraintValidatorContext constraintContext) {
+ if (value == null)
+ return true;
+
+ constraintContext.disableDefaultConstraintViolation();
+ constraintContext.buildConstraintViolationWithTemplate(value + " is a reserved word.").addConstraintViolation();
+ return !Gitop.getInstance(UserManager.class).getReservedNames().contains(value);
+ }
+}
diff --git a/gitop.product/pom.xml b/gitop.product/pom.xml
index 8bb7145ba6..7a1a0d48ce 100644
--- a/gitop.product/pom.xml
+++ b/gitop.product/pom.xml
@@ -113,6 +113,11 @@
commons.jersey
1.0.30
+
+ com.pmease
+ gitop.rest
+ 1.0.0
+
diff --git a/gitop.product/src/main/java/com/pmease/gitop/product/GitopServerConfigurator.java b/gitop.product/src/main/java/com/pmease/gitop/product/ProductConfigurator.java
similarity index 89%
rename from gitop.product/src/main/java/com/pmease/gitop/product/GitopServerConfigurator.java
rename to gitop.product/src/main/java/com/pmease/gitop/product/ProductConfigurator.java
index a281ffe830..4e37ff9de0 100644
--- a/gitop.product/src/main/java/com/pmease/gitop/product/GitopServerConfigurator.java
+++ b/gitop.product/src/main/java/com/pmease/gitop/product/ProductConfigurator.java
@@ -10,12 +10,12 @@ import com.pmease.commons.jetty.ServerConfigurator;
import com.pmease.gitop.core.setting.ServerConfig;
import com.pmease.gitop.core.setting.SslConfig;
-public class GitopServerConfigurator implements ServerConfigurator {
+public class ProductConfigurator implements ServerConfigurator {
private ServerConfig serverConfig;
@Inject
- public GitopServerConfigurator(ServerConfig serverConfig) {
+ public ProductConfigurator(ServerConfig serverConfig) {
this.serverConfig = serverConfig;
}
diff --git a/gitop.product/src/main/java/com/pmease/gitop/product/ProductModule.java b/gitop.product/src/main/java/com/pmease/gitop/product/ProductModule.java
index 245bb6d68a..54e1ef93fe 100644
--- a/gitop.product/src/main/java/com/pmease/gitop/product/ProductModule.java
+++ b/gitop.product/src/main/java/com/pmease/gitop/product/ProductModule.java
@@ -6,7 +6,7 @@ import java.util.Properties;
import com.google.inject.name.Names;
import com.pmease.commons.bootstrap.Bootstrap;
import com.pmease.commons.jetty.ServerConfigurator;
-import com.pmease.commons.jetty.ServletContextConfigurator;
+import com.pmease.commons.jetty.ServletConfigurator;
import com.pmease.commons.loader.AbstractPluginModule;
import com.pmease.commons.loader.AppName;
import com.pmease.commons.util.FileUtils;
@@ -30,8 +30,9 @@ public class ProductModule extends AbstractPluginModule {
bind(ServerConfig.class).to(DefaultServerConfig.class);
- contribute(ServerConfigurator.class, GitopServerConfigurator.class);
- contribute(ServletContextConfigurator.class, GitopServletContextConfigurator.class);
+ contribute(ServerConfigurator.class, ProductConfigurator.class);
+ contribute(ServletConfigurator.class, ProductServletConfigurator.class);
+
}
}
diff --git a/gitop.product/src/main/java/com/pmease/gitop/product/GitopServletContextConfigurator.java b/gitop.product/src/main/java/com/pmease/gitop/product/ProductServletConfigurator.java
similarity index 75%
rename from gitop.product/src/main/java/com/pmease/gitop/product/GitopServletContextConfigurator.java
rename to gitop.product/src/main/java/com/pmease/gitop/product/ProductServletConfigurator.java
index a06b3b3f25..9b7c75371d 100644
--- a/gitop.product/src/main/java/com/pmease/gitop/product/GitopServletContextConfigurator.java
+++ b/gitop.product/src/main/java/com/pmease/gitop/product/ProductServletConfigurator.java
@@ -1,7 +1,5 @@
package com.pmease.gitop.product;
-import java.io.File;
-
import javax.inject.Inject;
import org.eclipse.jetty.servlet.ServletContextHandler;
@@ -9,15 +7,15 @@ import org.eclipse.jetty.servlet.ServletHolder;
import com.pmease.commons.bootstrap.Bootstrap;
import com.pmease.commons.jetty.FileAssetServlet;
-import com.pmease.commons.jetty.ServletContextConfigurator;
+import com.pmease.commons.jetty.ServletConfigurator;
import com.pmease.gitop.core.setting.ServerConfig;
-public class GitopServletContextConfigurator implements ServletContextConfigurator {
+public class ProductServletConfigurator implements ServletConfigurator {
private final ServerConfig serverConfig;
@Inject
- public GitopServletContextConfigurator(ServerConfig serverConfig) {
+ public ProductServletConfigurator(ServerConfig serverConfig) {
this.serverConfig = serverConfig;
}
@@ -31,8 +29,7 @@ public class GitopServletContextConfigurator implements ServletContextConfigurat
* Configure a servlet to serve contents under site folder. Site folder can be used
* to hold site specific web assets.
*/
- File siteDir = new File(Bootstrap.installDir, "site");
- ServletHolder servletHolder = new ServletHolder(new FileAssetServlet(siteDir));
+ ServletHolder servletHolder = new ServletHolder(new FileAssetServlet(Bootstrap.getSiteDir()));
context.addServlet(servletHolder, "/site/*");
context.addServlet(servletHolder, "/robots.txt");
}
diff --git a/gitop.rest/pom.xml b/gitop.rest/pom.xml
new file mode 100644
index 0000000000..d2a246444e
--- /dev/null
+++ b/gitop.rest/pom.xml
@@ -0,0 +1,57 @@
+
+ 4.0.0
+ gitop.rest
+ 1.0.0
+
+ com.pmease
+ parent.general
+ 1.0.28
+
+
+
+
+
+ com.pmease
+ plugin.maven
+
+
+ maven-source-plugin
+
+
+ maven-javadoc-plugin
+
+
+
+
+
+
+ com.pmease
+ gitop.core
+ 1.0.30
+
+
+
+
+
+ pmeaseRepo
+ PMEase Repository
+
+ true
+ never
+ fail
+
+
+ true
+ always
+ fail
+
+ http://artifact.pmease.com/
+
+
+
+
+ com.pmease.gitop.rest.RestModule
+
+
+
diff --git a/gitop.rest/src/main/java/com/pmease/gitop/rest/RestModule.java b/gitop.rest/src/main/java/com/pmease/gitop/rest/RestModule.java
new file mode 100644
index 0000000000..ed0fd2221e
--- /dev/null
+++ b/gitop.rest/src/main/java/com/pmease/gitop/rest/RestModule.java
@@ -0,0 +1,29 @@
+package com.pmease.gitop.rest;
+
+import org.apache.shiro.web.filter.mgt.FilterChainManager;
+
+import com.pmease.commons.loader.AbstractPluginModule;
+import com.pmease.commons.shiro.FilterChainConfigurator;
+
+/**
+ * NOTE: Do not forget to rename moduleClass property defined in the pom if you've renamed this class.
+ *
+ */
+public class RestModule extends AbstractPluginModule {
+
+ @Override
+ protected void configure() {
+ super.configure();
+
+ // put your guice bindings here
+ contribute(FilterChainConfigurator.class, new FilterChainConfigurator() {
+
+ @Override
+ public void configure(FilterChainManager filterChainManager) {
+ filterChainManager.createChain("/rest/**", "noSessionCreation, authcBasic");
+ }
+
+ });
+ }
+
+}
diff --git a/gitop.web/pom.xml b/gitop.web/pom.xml
index 6aef42079a..47aca66ed6 100644
--- a/gitop.web/pom.xml
+++ b/gitop.web/pom.xml
@@ -35,11 +35,6 @@
commons.wicket
1.0.29
-
- com.pmease
- commons.jersey
- 1.0.30
-
@@ -83,6 +78,11 @@
dropwizard-jackson
0.7.0-SNAPSHOT
+
+ com.pmease
+ commons.jetty
+ 1.0.29
+
@@ -113,24 +113,6 @@
true
-
-
- nexus-owsi-core
- Nexus OWSI Core
- https://projects.openwide.fr/services/nexus/content/repositories/owsi-core
-
- false
-
-
-
-
- nexus-owsi-core-snapshots
- Nexus OWSI Core Snapshots
- https://projects.openwide.fr/services/nexus/content/repositories/owsi-core-snapshots
-
- false
-
-
diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java b/gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java
index 335405766d..df16e6220e 100644
--- a/gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java
+++ b/gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java
@@ -2,17 +2,23 @@ package com.pmease.gitop.web;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import javax.inject.Singleton;
import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.Application;
import org.apache.wicket.Page;
import org.apache.wicket.Session;
import org.apache.wicket.bean.validation.BeanValidationConfiguration;
+import org.apache.wicket.core.request.mapper.MountedMapper;
+import org.apache.wicket.request.IRequestMapper;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
+import org.apache.wicket.request.Url;
import org.apache.wicket.request.resource.caching.FilenameWithVersionResourceCachingStrategy;
import org.apache.wicket.request.resource.caching.version.LastModifiedResourceVersion;
import org.apache.wicket.util.time.Duration;
@@ -21,6 +27,9 @@ import org.apache.wicket.util.time.Time;
import com.google.common.base.Throwables;
import com.google.common.io.ByteStreams;
import com.pmease.commons.wicket.AbstractWicketConfig;
+import com.pmease.gitop.core.Gitop;
+import com.pmease.gitop.core.manager.ProjectManager;
+import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.web.assets.AssetLocator;
import com.pmease.gitop.web.common.component.avatar.AvatarImageResource;
import com.pmease.gitop.web.common.component.avatar.AvatarImageResourceReference;
@@ -32,6 +41,7 @@ import com.pmease.gitop.web.page.account.setting.profile.AccountProfilePage;
import com.pmease.gitop.web.page.account.setting.repos.AccountReposPage;
import com.pmease.gitop.web.page.home.HomePage;
import com.pmease.gitop.web.page.init.ServerInitPage;
+import com.pmease.gitop.web.page.project.ProjectHomePage;
import com.pmease.gitop.web.shiro.LoginPage;
import com.pmease.gitop.web.shiro.LogoutPage;
import com.pmease.gitop.web.shiro.ShiroWicketPlugin;
@@ -119,19 +129,60 @@ public class GitopWebApp extends AbstractWicketConfig {
// account related pages
// --------------------------------------------------------
+ // project dashboard
+ mount(new MountedMapper("/${user}/${project}", ProjectHomePage.class) {
+
+ @Override
+ protected boolean urlStartsWith(Url url, String... segments) {
+ List normalizedSegments = normalizeUrlSegments(url.getSegments());
+ if (normalizedSegments.size() < 2)
+ return false;
+ String userName = normalizedSegments.get(0);
+ if (Gitop.getInstance(UserManager.class).getReservedNames().contains(userName))
+ return false;
+
+ String projectName = normalizedSegments.get(1);
+ return !Gitop.getInstance(ProjectManager.class).getReservedNames().contains(projectName);
+ }
+
+ });
+
// account dashboard
- mountPage("account/${user}", AccountHomePage.class);
+ mount(new MountedMapper("/${user}", AccountHomePage.class) {
+
+ @Override
+ protected boolean urlStartsWith(Url url, String... segments) {
+ List normalizedSegments = normalizeUrlSegments(url.getSegments());
+ if (normalizedSegments.size() < 1)
+ return false;
+ String userName = normalizedSegments.get(0);
+ return !Gitop.getInstance(UserManager.class).getReservedNames().contains(userName);
+ }
+
+ });
// account settings
mountPage("settings/profile", AccountProfilePage.class);
mountPage("settings/password", AccountPasswordPage.class);
mountPage("settings/permission", AccountPermissionPage.class);
mountPage("settings/repos", AccountReposPage.class);
+
+ mountPage("/test", TestPage.class);
// repository pages
// --------------------------------------------------------
}
+
+ private List normalizeUrlSegments(List segments) {
+ List normalized = new ArrayList();
+ for (String each: segments) {
+ each = StringUtils.remove(each, '/');
+ if (each.length() != 0)
+ normalized.add(each);
+ }
+ return normalized;
+ }
private void mountResources() {
getSharedResources().add(AvatarImageResourceReference.AVATAR_RESOURCE, new AvatarImageResource());
@@ -148,4 +199,8 @@ public class GitopWebApp extends AbstractWicketConfig {
public boolean isPublicSignupEnabled() {
return true;
}
+
+ public Iterable getRequestMappers() {
+ return getRootRequestMapperAsCompound();
+ }
}
diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java b/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java
new file mode 100644
index 0000000000..1266a6643c
--- /dev/null
+++ b/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java
@@ -0,0 +1,48 @@
+package com.pmease.gitop.web;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.form.Form;
+
+import com.pmease.commons.editable.EditContext;
+import com.pmease.commons.editable.EditableUtils;
+import com.pmease.gitop.core.Gitop;
+import com.pmease.gitop.core.manager.ProjectManager;
+import com.pmease.gitop.core.manager.UserManager;
+import com.pmease.gitop.core.model.Project;
+import com.pmease.gitop.web.page.BasePage;
+
+@SuppressWarnings("serial")
+public class TestPage extends BasePage {
+
+ @Override
+ protected void onInitialize() {
+ super.onInitialize();
+
+ final EditContext editContext = EditableUtils.getContext(new Project());
+
+ Form> form = new Form("form") {
+
+ @Override
+ protected void onSubmit() {
+ super.onSubmit();
+ editContext.validate();
+ if (!editContext.hasValidationError(true)) {
+ Project project = (Project) editContext.getBean();
+ project.setOwner(Gitop.getInstance(UserManager.class).getRootUser());
+ Gitop.getInstance(ProjectManager.class).save(project);
+ }
+ }
+
+ };
+
+ form.add((Component)editContext.renderForEdit("editor"));
+
+ add(form);
+ }
+
+ @Override
+ protected String getPageTitle() {
+ return "Test page used by Robin";
+ }
+
+}
diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java b/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java
index 9c4cc244c6..74508d4159 100644
--- a/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java
+++ b/gitop.web/src/main/java/com/pmease/gitop/web/WebModule.java
@@ -1,20 +1,14 @@
package com.pmease.gitop.web;
import javax.inject.Singleton;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
import com.codahale.dropwizard.jackson.Jackson;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Provides;
-import com.pmease.commons.jetty.ClasspathAssetServlet;
-import com.pmease.commons.jetty.ServletContextConfigurator;
+import com.pmease.commons.jetty.ServletConfigurator;
import com.pmease.commons.loader.AbstractPluginModule;
import com.pmease.commons.wicket.AbstractWicketConfig;
-import com.pmease.gitop.web.assets.AssetLocator;
+import com.pmease.gitop.core.validation.UserNameReservation;
import com.pmease.gitop.web.resource.RestResourceModule;
/**
@@ -31,19 +25,8 @@ public class WebModule extends AbstractPluginModule {
bind(AbstractWicketConfig.class).to(GitopWebApp.class);
bind(SitePaths.class).in(Singleton.class);
- contribute(ServletContextConfigurator.class, new ServletContextConfigurator() {
-
- @Override
- public void configure(ServletContextHandler context) {
- ServletHolder servletHolder = new ServletHolder(new ClasspathAssetServlet(AssetLocator.class));
- context.addServlet(servletHolder, "/assets/*");
- context.addServlet(servletHolder, "/favicon.ico");
-
- ErrorPageErrorHandler errorHandler = (ErrorPageErrorHandler) context.getErrorHandler();
- errorHandler.addErrorPage(HttpServletResponse.SC_NOT_FOUND, "/assets/404.html");
- }
-
- });
+ contribute(ServletConfigurator.class, WebServletConfigurator.class);
+ contribute(UserNameReservation.class, WebUserNameReservation.class);
install(new RestResourceModule());
}
diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/WebServletConfigurator.java b/gitop.web/src/main/java/com/pmease/gitop/web/WebServletConfigurator.java
new file mode 100644
index 0000000000..bcbe4a617b
--- /dev/null
+++ b/gitop.web/src/main/java/com/pmease/gitop/web/WebServletConfigurator.java
@@ -0,0 +1,44 @@
+package com.pmease.gitop.web;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.wicket.protocol.http.WicketServlet;
+import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+
+import com.pmease.commons.jetty.ClasspathAssetServlet;
+import com.pmease.commons.jetty.ServletConfigurator;
+import com.pmease.gitop.web.assets.AssetLocator;
+
+@Singleton
+public class WebServletConfigurator implements ServletConfigurator {
+
+ private final WicketServlet wicketServlet;
+
+ @Inject
+ public WebServletConfigurator(WicketServlet wicketServlet) {
+ this.wicketServlet = wicketServlet;
+ }
+
+ @Override
+ public void configure(ServletContextHandler context) {
+ ServletHolder servletHolder = new ServletHolder(wicketServlet);
+
+ /*
+ * Add wicket servlet as the default servlet which will serve all requests failed to
+ * match a path pattern
+ */
+ context.addServlet(servletHolder, "/");
+
+ servletHolder = new ServletHolder(new ClasspathAssetServlet(AssetLocator.class));
+ context.addServlet(servletHolder, "/assets/*");
+ context.addServlet(servletHolder, "/favicon.ico");
+
+ ErrorPageErrorHandler errorHandler = (ErrorPageErrorHandler) context.getErrorHandler();
+ errorHandler.addErrorPage(HttpServletResponse.SC_NOT_FOUND, "/assets/404.html");
+ }
+
+}
diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java b/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java
new file mode 100644
index 0000000000..df8e520b32
--- /dev/null
+++ b/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java
@@ -0,0 +1,64 @@
+package com.pmease.gitop.web;
+
+import java.lang.reflect.Field;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.wicket.core.request.mapper.MountedMapper;
+import org.apache.wicket.core.request.mapper.ResourceMapper;
+import org.apache.wicket.request.IRequestMapper;
+import org.eclipse.jetty.servlet.ServletMapping;
+
+import com.google.common.base.Preconditions;
+import com.pmease.commons.jetty.JettyPlugin;
+import com.pmease.commons.util.ReflectionUtils;
+import com.pmease.gitop.core.validation.UserNameReservation;
+
+public class WebUserNameReservation implements UserNameReservation {
+
+ private final JettyPlugin jettyPlugin;
+
+ private final GitopWebApp webApp;
+
+ @Inject
+ public WebUserNameReservation(JettyPlugin jettyPlugin, GitopWebApp webApp) {
+ this.jettyPlugin = jettyPlugin;
+ this.webApp = webApp;
+ }
+
+ @Override
+ public Set getReserved() {
+ Set reserved = new HashSet();
+ for (ServletMapping mapping: jettyPlugin.getContextHandler().getServletHandler().getServletMappings()) {
+ for (String pathSpec: mapping.getPathSpecs()) {
+ pathSpec = StringUtils.stripStart(pathSpec, "/");
+ pathSpec = StringUtils.substringBefore(pathSpec, "/");
+ if (pathSpec.trim().length() != 0)
+ reserved.add(pathSpec.trim());
+ }
+ }
+
+ reserved.add("wicket");
+
+ for (IRequestMapper mapper: webApp.getRequestMappers()) {
+ if (mapper instanceof MountedMapper || mapper instanceof ResourceMapper) {
+ try {
+ Field field = ReflectionUtils.findField(mapper.getClass(), "mountSegments");
+ Preconditions.checkNotNull(field);
+ field.setAccessible(true);
+ String[] mountSegments = (String[]) field.get(mapper);
+ if (mountSegments != null && mountSegments.length != 0 && mountSegments[0] != null)
+ reserved.add(mountSegments[0]);
+ } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ return reserved;
+ }
+
+}
diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.html b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.html
index 98b2a00836..3a84612183 100644
--- a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.html
+++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.html
@@ -1,5 +1,7 @@
Welcome, Account home
+
+ link
\ No newline at end of file
diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java
index 4fa3fe15d9..b3d5b5bcd0 100644
--- a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java
+++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java
@@ -1,16 +1,79 @@
package com.pmease.gitop.web.page.account;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import com.pmease.commons.util.GeneralException;
+import com.pmease.gitop.core.Gitop;
+import com.pmease.gitop.core.manager.UserManager;
+import com.pmease.gitop.core.model.User;
import com.pmease.gitop.web.page.AbstractLayoutPage;
@SuppressWarnings("serial")
@RequiresAuthentication
public class AccountHomePage extends AbstractLayoutPage {
+ private final IModel accountModel;
+
+ public AccountHomePage(PageParameters params) {
+ String accountName = params.get("user").toString();
+
+ User account = Gitop.getInstance(UserManager.class).find(accountName);
+ if (account == null)
+ throw new GeneralException("Account %s does not exist!", accountName);
+
+ final Long accountId = account.getId();
+
+ accountModel = new LoadableDetachableModel() {
+
+ @Override
+ protected User load() {
+ return Gitop.getInstance(UserManager.class).load(accountId);
+ }
+
+ };
+ }
+
+ @Override
+ protected void onInitialize() {
+ super.onInitialize();
+
+ add(new Label("accountName", getAccount().getName()));
+
+ add(new Link("link") {
+
+ @Override
+ public void onClick() {
+
+ }
+
+ });
+ }
+
@Override
protected String getPageTitle() {
return "Gitop";
}
+ public User getAccount() {
+ return accountModel.getObject();
+ }
+
+ @Override
+ public void detachModels() {
+ accountModel.detach();
+
+ super.detachModels();
+ }
+
+ public static PageParameters paramsOf(User account) {
+ PageParameters params = new PageParameters();
+ params.set("user", account.getName());
+ return params;
+ }
+
}
diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html
index 9c2fbc7831..c72c3cf9e2 100644
--- a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html
+++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html
@@ -31,5 +31,7 @@
Confirmation
+ account
+ project
-