* 'master' of https://git.pmease.com/p/robin/commons:
  Simplify model by removing individual permissions and role concept.
  Be able to configure context path running QuickBuild web UI.
  Fix the issue that wizard has not default button.

Conflicts:
	gitop.web/src/main/java/com/pmease/gitop/web/GitopWebApp.java
This commit is contained in:
steve 2013-09-29 18:56:06 +08:00
commit ebbd50386d
59 changed files with 480 additions and 838 deletions

View File

@ -271,6 +271,10 @@ public class Bootstrap {
public static File getConfDir() {
return new File(installDir, "conf");
}
public static File getSiteDir() {
return new File(installDir, "site");
}
private static class CachedUrl {
private final URL url;

View File

@ -72,7 +72,6 @@ public class JettyPlugin extends AbstractPlugin {
context.setClassLoader(JettyPlugin.class.getClassLoader());
context.setContextPath("/");
context.setErrorHandler(new ErrorPageErrorHandler());
context.addFilter(DisableTraceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));

View File

@ -7,8 +7,8 @@
<div class="buttons">
<a wicket:id="previous" class="btn btn-default previous">Previous</a>
<a wicket:id="skip" class="btn btn-default skip">Skip</a>
<a wicket:id="next" class="btn btn-primary next">Next</a>
<a wicket:id="finish" class="btn btn-primary finish">Finish</a>
<input type="submit" value="Next" wicket:id="next" class="btn btn-primary next"></input>
<input type="submit" value="Finish" wicket:id="finish" class="btn btn-primary finish"></input>
</div>
</form>
</div>

View File

@ -16,8 +16,8 @@ import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.HeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.AbstractReadOnlyModel;
@ -99,7 +99,7 @@ public abstract class Wizard extends Panel {
}
});
form.add(new SubmitLink("next") {
form.add(new Button("next") {
@Override
public void onSubmit() {
@ -116,7 +116,7 @@ public abstract class Wizard extends Panel {
}
});
form.add(new SubmitLink("finish") {
form.add(new Button("finish") {
@Override
public void onSubmit() {

View File

@ -16,8 +16,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.pmease.commons.git.Git;
import com.pmease.gitop.core.manager.RepositoryManager;
import com.pmease.gitop.core.model.Repository;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.model.Project;
@Singleton
@SuppressWarnings("serial")
@ -27,39 +27,39 @@ public class GitServlet extends HttpServlet {
private static final String INFO_REFS = "info/refs";
private final RepositoryManager repositoryManager;
private final ProjectManager projectManager;
@Inject
public GitServlet(RepositoryManager repositoryManager) {
this.repositoryManager = repositoryManager;
public GitServlet(ProjectManager projectManager) {
this.projectManager = projectManager;
}
private Repository getRepository(HttpServletRequest request, HttpServletResponse response, String repoInfo)
private Project getProject(HttpServletRequest request, HttpServletResponse response, String repoInfo)
throws IOException {
repoInfo = StringUtils.stripStart(StringUtils.stripEnd(repoInfo, "/"), "/");
String ownerName = StringUtils.substringBefore(repoInfo, "/");
String repositoryName = StringUtils.substringAfter(repoInfo, "/");
String projectName = StringUtils.substringAfter(repoInfo, "/");
if (StringUtils.isBlank(ownerName) || StringUtils.isBlank(repositoryName)) {
if (StringUtils.isBlank(ownerName) || StringUtils.isBlank(projectName)) {
String url = request.getRequestURL().toString();
String urlRoot = url.substring(0, url.length()-request.getPathInfo().length());
String message = "Expecting url of format " + urlRoot + "/<owner name>/<repository name>";
String message = "Expecting url of format " + urlRoot + "/<owner name>/<project name>";
logger.error("Error serving git request: " + message);
response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
return null;
}
Repository repository = repositoryManager.find(ownerName, repositoryName);
if (repository == null) {
String message = "Unable to find repository '" + repositoryName + "' owned by '" + ownerName + "'.";
Project project = projectManager.find(ownerName, projectName);
if (project == null) {
String message = "Unable to find project '" + projectName + "' owned by '" + ownerName + "'.";
logger.error("Error serving git request: " + message);
response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
return null;
}
return repository;
return project;
}
private void doNotCache(HttpServletResponse response) {
@ -74,13 +74,13 @@ public class GitServlet extends HttpServlet {
String service = StringUtils.substringAfterLast(pathInfo, "/");
String repoInfo = StringUtils.substringBeforeLast(pathInfo, "/");
Repository repository = getRepository(req, resp, repoInfo);
Project project = getProject(req, resp, repoInfo);
if (repository != null) {
if (project != null) {
doNotCache(resp);
resp.setHeader("Content-Type", "application/x-" + service + "-result");
Git git = new Git(repositoryManager.locateStorage(repository));
Git git = new Git(projectManager.locateStorage(project).ofCode());
try {
if (service.contains("upload")) {
@ -111,8 +111,8 @@ public class GitServlet extends HttpServlet {
}
String repoInfo = pathInfo.substring(0, pathInfo.length() - INFO_REFS.length());
Repository repository = getRepository(req, resp, repoInfo);
if (repository != null) {
Project project = getProject(req, resp, repoInfo);
if (project != null) {
doNotCache(resp);
String service = req.getParameter("service");
resp.setHeader("Content-Type", "application/x-" + service + "-advertisement");
@ -122,7 +122,7 @@ public class GitServlet extends HttpServlet {
pack.writeString("# service=" + service + "\n");
pack.end();
Git git = new Git(repositoryManager.locateStorage(repository));
Git git = new Git(projectManager.locateStorage(project).ofCode());
try {
if (service.contains("upload")) {

View File

@ -8,6 +8,7 @@ import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -67,10 +68,34 @@ public class Gitop extends AbstractPlugin {
throw new RuntimeException(e);
}
String serverUrl;
if (serverConfig.getHttpPort() != 0)
return "http://" + hostName + ":" + serverConfig.getHttpPort();
serverUrl = "http://" + hostName + ":" + serverConfig.getHttpPort();
else
return "https://" + hostName + ":" + serverConfig.getSslConfig().getPort();
serverUrl = "https://" + hostName + ":" + serverConfig.getSslConfig().getPort();
return serverUrl + serverConfig.getContextPath();
}
/**
* Get context aware servlet request path given path inside context. For instance if
* pathInContext is &quot;/images/ok.png&quot;, this method will return
* &quot;/gitop/images/ok.png&quot; if Gitop web UI is configured to run under
* context path &quot;/gitop&quot;
*
* @param pathInContext
* servlet request path inside servlet context. It does not matter whether or
* not this path starts with slash
* @return
* absolute path prepending servlet context path
*/
public String getContextAwarePath(String pathInContext) {
String contextAwarePath = serverConfig.getContextPath();
contextAwarePath = StringUtils.stripEnd(contextAwarePath, "/");
if (pathInContext.startsWith("/"))
return contextAwarePath + pathInContext;
else
return contextAwarePath + "/" + pathInContext;
}
public String getAppName() {

View File

@ -5,7 +5,7 @@ import java.util.Collection;
import com.pmease.commons.editable.annotation.Editable;
import com.pmease.gitop.core.model.MergeRequest;
import com.pmease.gitop.core.model.User;
import com.pmease.gitop.core.permission.operation.RepositoryOperation;
import com.pmease.gitop.core.permission.operation.GeneralOperation;
@SuppressWarnings("serial")
@Editable
@ -13,7 +13,7 @@ public class ApprovedByAuthorizedUsers extends AbstractGateKeeper {
@Override
public CheckResult check(MergeRequest request) {
Collection<User> authorizedUsers = request.getDestination().getRepository().findAuthorizedUsers(RepositoryOperation.WRITE);
Collection<User> authorizedUsers = request.getDestination().getProject().findAuthorizedUsers(GeneralOperation.WRITE);
OrGateKeeper or = new OrGateKeeper();
for (User user: authorizedUsers) {
ApprovedBySpecifiedUser entry = new ApprovedBySpecifiedUser();

View File

@ -0,0 +1,29 @@
package com.pmease.gitop.core.gatekeeper;
import com.google.common.collect.Sets;
import com.pmease.commons.editable.annotation.Editable;
import com.pmease.gitop.core.model.MergeRequest;
import com.pmease.gitop.core.model.User;
import com.pmease.gitop.core.model.Vote;
@SuppressWarnings("serial")
@Editable
public class ApprovedByProjectOwner extends AbstractGateKeeper {
@Override
public CheckResult check(MergeRequest request) {
User projectOwner = request.getDestination().getProject().getOwner();
Vote.Result result = projectOwner.checkVoteSince(request.getBaseUpdate());
if (result == null) {
request.inviteToVote(Sets.newHashSet(projectOwner), 1);
return pending("To be approved by user '" + projectOwner.getName() + "'.");
} else if (result.isAccept()) {
return accept("Approved by user '" + projectOwner.getName() + "'.");
} else {
return reject("Rejected by user '" + projectOwner.getName() + "'.");
}
}
}

View File

@ -1,29 +0,0 @@
package com.pmease.gitop.core.gatekeeper;
import com.google.common.collect.Sets;
import com.pmease.commons.editable.annotation.Editable;
import com.pmease.gitop.core.model.MergeRequest;
import com.pmease.gitop.core.model.User;
import com.pmease.gitop.core.model.Vote;
@SuppressWarnings("serial")
@Editable
public class ApprovedByRepositoryOwner extends AbstractGateKeeper {
@Override
public CheckResult check(MergeRequest request) {
User repositoryOwner = request.getDestination().getRepository().getOwner();
Vote.Result result = repositoryOwner.checkVoteSince(request.getBaseUpdate());
if (result == null) {
request.inviteToVote(Sets.newHashSet(repositoryOwner), 1);
return pending("To be approved by user '" + repositoryOwner.getName() + "'.");
} else if (result.isAccept()) {
return accept("Approved by user '" + repositoryOwner.getName() + "'.");
} else {
return reject("Rejected by user '" + repositoryOwner.getName() + "'.");
}
}
}

View File

@ -7,7 +7,7 @@ import javax.validation.constraints.Min;
import com.pmease.commons.editable.annotation.Editable;
import com.pmease.gitop.core.model.MergeRequest;
import com.pmease.gitop.core.model.TeamMembership;
import com.pmease.gitop.core.model.Membership;
import com.pmease.gitop.core.model.User;
import com.pmease.gitop.core.model.Vote;
@ -30,7 +30,7 @@ public class ApprovedBySpecifiedTeam extends TeamAwareGateKeeper {
@Override
public CheckResult check(MergeRequest request) {
Collection<User> members = new HashSet<User>();
for (TeamMembership membership: getTeam().getMemberships())
for (Membership membership: getTeam().getMemberships())
members.add(membership.getUser());
int approvals = 0;

View File

@ -7,7 +7,7 @@ import javax.validation.constraints.Min;
import com.pmease.commons.editable.annotation.Editable;
import com.pmease.gitop.core.model.MergeRequest;
import com.pmease.gitop.core.model.TeamMembership;
import com.pmease.gitop.core.model.Membership;
import com.pmease.gitop.core.model.User;
import com.pmease.gitop.core.model.Vote;
@ -40,7 +40,7 @@ public class GetMinScoreFromSpecifiedTeam extends TeamAwareGateKeeper {
@Override
public CheckResult check(MergeRequest request) {
Collection<User> members = new HashSet<User>();
for (TeamMembership membership: getTeam().getMemberships())
for (Membership membership: getTeam().getMemberships())
members.add(membership.getUser());
int score = 0;

View File

@ -2,7 +2,7 @@ package com.pmease.gitop.core.gatekeeper;
import com.pmease.commons.editable.annotation.Editable;
import com.pmease.gitop.core.model.MergeRequest;
import com.pmease.gitop.core.model.TeamMembership;
import com.pmease.gitop.core.model.Membership;
import com.pmease.gitop.core.model.Vote;
@SuppressWarnings("serial")
@ -12,7 +12,7 @@ public class NoRejectionBySpecifiedTeam extends TeamAwareGateKeeper {
@Override
public CheckResult check(MergeRequest request) {
for (TeamMembership membership: getTeam().getMemberships()) {
for (Membership membership: getTeam().getMemberships()) {
Vote.Result result = membership.getUser().checkVoteSince(request.getBaseUpdate());
if (result.isReject()) {
return reject("Rejected by user '" + membership.getUser().getName() + "'.");

View File

@ -12,7 +12,7 @@ import com.pmease.commons.util.pattern.PatternSetMatcher;
import com.pmease.commons.util.pattern.WildcardPathMatcher;
import com.pmease.gitop.core.manager.BranchManager;
import com.pmease.gitop.core.model.MergeRequest;
import com.pmease.gitop.core.model.Repository;
import com.pmease.gitop.core.model.Project;
@SuppressWarnings("serial")
@Editable
@ -32,9 +32,9 @@ public class SubmittedToSpecifiedBranch extends AbstractGateKeeper {
@Override
public CheckResult check(MergeRequest request) {
Repository repository = request.getDestination().getRepository();
Project project = request.getDestination().getProject();
BranchManager branchManager = AppLoader.getInstance(BranchManager.class);
EntityLoader entityLoader = branchManager.asEntityLoader(repository);
EntityLoader entityLoader = branchManager.asEntityLoader(project);
EntityMatcher entityMatcher = new EntityMatcher(entityLoader, new WildcardPathMatcher());
PatternSetMatcher patternSetMatcher = new PatternSetMatcher(entityMatcher);
@ -48,13 +48,13 @@ public class SubmittedToSpecifiedBranch extends AbstractGateKeeper {
@Override
public Object trim(Object context) {
Preconditions.checkArgument(context instanceof Repository);
Preconditions.checkArgument(context instanceof Project);
Repository repository = (Repository) context;
Project project = (Project) context;
BranchManager branchManager = AppLoader.getInstance(BranchManager.class);
EntityLoader entityLoader = branchManager.asEntityLoader(repository);
EntityLoader entityLoader = branchManager.asEntityLoader(project);
EntityPatternSet patternSet = EntityPatternSet.fromStored(getBranchPatterns(), entityLoader);
patternSet.trim(repository);
patternSet.trim(project);
if (patternSet.getStored().isEmpty()) {
return null;

View File

@ -10,7 +10,7 @@ import com.pmease.commons.git.FindChangedFilesCommand;
import com.pmease.commons.git.Git;
import com.pmease.commons.loader.AppLoader;
import com.pmease.commons.util.pattern.WildcardUtils;
import com.pmease.gitop.core.manager.RepositoryManager;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.model.MergeRequest;
import com.pmease.gitop.core.model.MergeRequestUpdate;
@ -32,8 +32,8 @@ public class TouchSpecifiedFiles extends AbstractGateKeeper {
@Override
public CheckResult check(MergeRequest request) {
RepositoryManager repositoryManager = AppLoader.getInstance(RepositoryManager.class);
File repoDir = repositoryManager.locateStorage(request.getDestination().getRepository());
ProjectManager projectManager = AppLoader.getInstance(ProjectManager.class);
File repoDir = projectManager.locateStorage(request.getDestination().getProject()).ofCode();
FindChangedFilesCommand command = new Git(repoDir).findChangedFiles();

View File

@ -0,0 +1,11 @@
package com.pmease.gitop.core.manager;
import com.google.inject.ImplementedBy;
import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.gitop.core.manager.impl.DefaultAuthorizationManager;
import com.pmease.gitop.core.model.Authorization;
@ImplementedBy(DefaultAuthorizationManager.class)
public interface AuthorizationManager extends GenericDao<Authorization> {
}

View File

@ -5,13 +5,13 @@ import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.commons.util.namedentity.EntityLoader;
import com.pmease.gitop.core.manager.impl.DefaultBranchManager;
import com.pmease.gitop.core.model.Branch;
import com.pmease.gitop.core.model.Repository;
import com.pmease.gitop.core.model.Project;
@ImplementedBy(DefaultBranchManager.class)
public interface BranchManager extends GenericDao<Branch> {
public Branch find(Repository repository, String branchName);
public Branch find(Project project, String branchName);
public EntityLoader asEntityLoader(Repository repository);
public EntityLoader asEntityLoader(Project project);
}

View File

@ -0,0 +1,19 @@
package com.pmease.gitop.core.manager;
import java.util.Collection;
import com.google.inject.ImplementedBy;
import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.gitop.core.manager.impl.DefaultProjectManager;
import com.pmease.gitop.core.model.Project;
import com.pmease.gitop.core.storage.ProjectStorage;
@ImplementedBy(DefaultProjectManager.class)
public interface ProjectManager extends GenericDao<Project> {
ProjectStorage locateStorage(Project project);
Project find(String ownerName, String projectName);
Collection<Project> findPublic();
}

View File

@ -1,11 +0,0 @@
package com.pmease.gitop.core.manager;
import com.google.inject.ImplementedBy;
import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.gitop.core.manager.impl.DefaultRepositoryAuthorizationByTeamManager;
import com.pmease.gitop.core.model.RepositoryAuthorizationByIndividual;
@ImplementedBy(DefaultRepositoryAuthorizationByTeamManager.class)
public interface RepositoryAuthorizationByIndividualManager extends GenericDao<RepositoryAuthorizationByIndividual> {
}

View File

@ -1,11 +0,0 @@
package com.pmease.gitop.core.manager;
import com.google.inject.ImplementedBy;
import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.gitop.core.manager.impl.DefaultRepositoryAuthorizationByTeamManager;
import com.pmease.gitop.core.model.RepositoryAuthorizationByTeam;
@ImplementedBy(DefaultRepositoryAuthorizationByTeamManager.class)
public interface RepositoryAuthorizationByTeamManager extends GenericDao<RepositoryAuthorizationByTeam> {
}

View File

@ -1,19 +0,0 @@
package com.pmease.gitop.core.manager;
import java.io.File;
import java.util.Collection;
import com.google.inject.ImplementedBy;
import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.gitop.core.manager.impl.DefaultRepositoryManager;
import com.pmease.gitop.core.model.Repository;
@ImplementedBy(DefaultRepositoryManager.class)
public interface RepositoryManager extends GenericDao<Repository> {
File locateStorage(Repository repository);
Repository find(String ownerName, String repositoryName);
Collection<Repository> findPublic();
}

View File

@ -1,11 +0,0 @@
package com.pmease.gitop.core.manager;
import com.google.inject.ImplementedBy;
import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.gitop.core.manager.impl.DefaultRoleManager;
import com.pmease.gitop.core.model.Role;
@ImplementedBy(DefaultRoleManager.class)
public interface RoleManager extends GenericDao<Role> {
}

View File

@ -1,11 +0,0 @@
package com.pmease.gitop.core.manager;
import com.google.inject.ImplementedBy;
import com.pmease.commons.hibernate.dao.GenericDao;
import com.pmease.gitop.core.manager.impl.DefaultRepositoryAuthorizationByTeamManager;
import com.pmease.gitop.core.model.UserAuthorizationByIndividual;
@ImplementedBy(DefaultRepositoryAuthorizationByTeamManager.class)
public interface UserAuthorizationByIndividualManager extends GenericDao<UserAuthorizationByIndividual> {
}

View File

@ -0,0 +1,20 @@
package com.pmease.gitop.core.manager.impl;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.pmease.commons.hibernate.dao.AbstractGenericDao;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.gitop.core.manager.AuthorizationManager;
import com.pmease.gitop.core.model.Authorization;
@Singleton
public class DefaultAuthorizationManager extends AbstractGenericDao<Authorization>
implements AuthorizationManager {
@Inject
public DefaultAuthorizationManager(GeneralDao generalDao) {
super(generalDao);
}
}

View File

@ -13,7 +13,7 @@ import com.pmease.commons.util.namedentity.EntityLoader;
import com.pmease.commons.util.namedentity.NamedEntity;
import com.pmease.gitop.core.manager.BranchManager;
import com.pmease.gitop.core.model.Branch;
import com.pmease.gitop.core.model.Repository;
import com.pmease.gitop.core.model.Project;
@Singleton
public class DefaultBranchManager extends AbstractGenericDao<Branch> implements BranchManager {
@ -26,12 +26,12 @@ public class DefaultBranchManager extends AbstractGenericDao<Branch> implements
@Sessional
@Override
public Branch find(Repository repository, String name) {
return find(new Criterion[]{Restrictions.eq("repository", repository), Restrictions.eq("name", name)});
public Branch find(Project project, String name) {
return find(new Criterion[]{Restrictions.eq("project", project), Restrictions.eq("name", name)});
}
@Override
public EntityLoader asEntityLoader(final Repository repository) {
public EntityLoader asEntityLoader(final Project project) {
return new EntityLoader() {
@Override
@ -58,7 +58,7 @@ public class DefaultBranchManager extends AbstractGenericDao<Branch> implements
@Override
public NamedEntity get(String name) {
final Branch branch = find(repository, name);
final Branch branch = find(project, name);
if (branch != null) {
return new NamedEntity() {

View File

@ -14,18 +14,18 @@ import com.pmease.commons.git.Git;
import com.pmease.commons.hibernate.Transactional;
import com.pmease.commons.hibernate.dao.AbstractGenericDao;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.commons.util.FileUtils;
import com.pmease.gitop.core.manager.ConfigManager;
import com.pmease.gitop.core.manager.RepositoryManager;
import com.pmease.gitop.core.model.Repository;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.model.Project;
import com.pmease.gitop.core.storage.ProjectStorage;
@Singleton
public class DefaultRepositoryManager extends AbstractGenericDao<Repository> implements RepositoryManager {
public class DefaultProjectManager extends AbstractGenericDao<Project> implements ProjectManager {
private ConfigManager configManager;
@Inject
public DefaultRepositoryManager(GeneralDao generalDao, ConfigManager configManager) {
public DefaultProjectManager(GeneralDao generalDao, ConfigManager configManager) {
super(generalDao);
this.configManager = configManager;
@ -33,14 +33,14 @@ public class DefaultRepositoryManager extends AbstractGenericDao<Repository> imp
@Transactional
@Override
public void save(Repository entity) {
public void save(Project entity) {
if (entity.isNew()) {
super.save(entity);
File gitDir = locateStorage(entity);
FileUtils.cleanDir(gitDir);
ProjectStorage storage = locateStorage(entity);
storage.clean();
new Git(gitDir).init().bare(true).call();
new Git(storage.ofCode()).init().bare(true).call();
} else {
super.save(entity);
}
@ -48,31 +48,31 @@ public class DefaultRepositoryManager extends AbstractGenericDao<Repository> imp
@Transactional
@Override
public void delete(Repository entity) {
public void delete(Project entity) {
super.delete(entity);
FileUtils.deleteDir(locateStorage(entity));
locateStorage(entity).delete();
}
@Override
public File locateStorage(Repository repository) {
return new File(configManager.getStorageSetting().getRepoStorageDir(), repository.getId().toString());
public ProjectStorage locateStorage(Project project) {
return new ProjectStorage(new File(configManager.getStorageSetting().getStorageDir(), project.getId().toString()));
}
@Override
public Collection<Repository> findPublic() {
public Collection<Project> findPublic() {
return query(new Criterion[]{Restrictions.eq("publiclyAccessible", true)});
}
@Override
public Repository find(String ownerName, String repositoryName) {
public Project find(String ownerName, String projectName) {
Criteria criteria = createCriteria();
criteria.add(Restrictions.eq("name", repositoryName));
criteria.add(Restrictions.eq("name", projectName));
criteria.createAlias("owner", "owner");
criteria.add(Restrictions.eq("owner.name", ownerName));
criteria.setMaxResults(1);
return (Repository) criteria.uniqueResult();
return (Project) criteria.uniqueResult();
}
}

View File

@ -1,21 +0,0 @@
package com.pmease.gitop.core.manager.impl;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.pmease.commons.hibernate.dao.AbstractGenericDao;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.gitop.core.manager.RepositoryAuthorizationByIndividualManager;
import com.pmease.gitop.core.model.RepositoryAuthorizationByIndividual;
@Singleton
public class DefaultRepositoryAuthorizationByIndividualManager
extends AbstractGenericDao<RepositoryAuthorizationByIndividual>
implements RepositoryAuthorizationByIndividualManager {
@Inject
public DefaultRepositoryAuthorizationByIndividualManager(GeneralDao generalDao) {
super(generalDao);
}
}

View File

@ -1,20 +0,0 @@
package com.pmease.gitop.core.manager.impl;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.pmease.commons.hibernate.dao.AbstractGenericDao;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.gitop.core.manager.RepositoryAuthorizationByTeamManager;
import com.pmease.gitop.core.model.RepositoryAuthorizationByTeam;
@Singleton
public class DefaultRepositoryAuthorizationByTeamManager extends AbstractGenericDao<RepositoryAuthorizationByTeam>
implements RepositoryAuthorizationByTeamManager {
@Inject
public DefaultRepositoryAuthorizationByTeamManager(GeneralDao generalDao) {
super(generalDao);
}
}

View File

@ -1,22 +0,0 @@
package com.pmease.gitop.core.manager.impl;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.hibernate.Session;
import com.pmease.commons.hibernate.dao.AbstractGenericDao;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.gitop.core.manager.RoleManager;
import com.pmease.gitop.core.model.Role;
@Singleton
public class DefaultRoleManager extends AbstractGenericDao<Role> implements RoleManager {
@Inject
public DefaultRoleManager(GeneralDao generalDao, Provider<Session> sessionProvider) {
super(generalDao);
}
}

View File

@ -1,21 +0,0 @@
package com.pmease.gitop.core.manager.impl;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.pmease.commons.hibernate.dao.AbstractGenericDao;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.gitop.core.manager.UserAuthorizationByIndividualManager;
import com.pmease.gitop.core.model.UserAuthorizationByIndividual;
@Singleton
public class DefaultUserAuthorizationByIndividualManager
extends AbstractGenericDao<UserAuthorizationByIndividual>
implements UserAuthorizationByIndividualManager {
@Inject
public DefaultUserAuthorizationByIndividualManager(GeneralDao generalDao) {
super(generalDao);
}
}

View File

@ -7,14 +7,14 @@ import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.gitop.core.permission.operation.RepositoryOperation;
import com.pmease.gitop.core.permission.operation.GeneralOperation;
@SuppressWarnings("serial")
@Entity
@Table(uniqueConstraints={
@UniqueConstraint(columnNames={"team", "repository"})
@UniqueConstraint(columnNames={"team", "project"})
})
public class RepositoryAuthorizationByTeam extends AbstractEntity {
public class Authorization extends AbstractEntity {
@ManyToOne
@JoinColumn(nullable=false)
@ -22,15 +22,15 @@ public class RepositoryAuthorizationByTeam extends AbstractEntity {
@ManyToOne
@JoinColumn(nullable=false)
private Repository repository;
private Project project;
private RepositoryOperation authorizedOperation = RepositoryOperation.READ;
private GeneralOperation authorizedOperation = GeneralOperation.READ;
public RepositoryOperation getAuthorizedOperation() {
public GeneralOperation getAuthorizedOperation() {
return authorizedOperation;
}
public void setAuthorizedOperation(RepositoryOperation authorizedOperation) {
public void setAuthorizedOperation(GeneralOperation authorizedOperation) {
this.authorizedOperation = authorizedOperation;
}
@ -42,12 +42,12 @@ public class RepositoryAuthorizationByTeam extends AbstractEntity {
this.team = team;
}
public Repository getRepository() {
return repository;
public Project getProject() {
return project;
}
public void setRepository(Repository repository) {
this.repository = repository;
public void setProject(Project project) {
this.project = project;
}
}

View File

@ -12,23 +12,23 @@ import com.pmease.commons.hibernate.AbstractEntity;
@SuppressWarnings("serial")
@Entity
@Table(uniqueConstraints={
@UniqueConstraint(columnNames={"repository", "name"})
@UniqueConstraint(columnNames={"project", "name"})
})
public class Branch extends AbstractEntity {
@ManyToOne
@JoinColumn(nullable=false)
private Repository repository;
private Project project;
@Column(nullable=false)
private String name;
public Repository getRepository() {
return repository;
public Project getProject() {
return project;
}
public void setRepository(Repository repository) {
this.repository = repository;
public void setProject(Project project) {
this.project = project;
}
public String getName() {

View File

@ -13,7 +13,7 @@ import com.pmease.commons.hibernate.AbstractEntity;
@Table(uniqueConstraints={
@UniqueConstraint(columnNames={"user", "team"})
})
public class TeamMembership extends AbstractEntity {
public class Membership extends AbstractEntity {
@ManyToOne
@JoinColumn(nullable=false)

View File

@ -26,7 +26,7 @@ import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.gatekeeper.CheckResult;
import com.pmease.gitop.core.gatekeeper.GateKeeper;
import com.pmease.gitop.core.manager.RepositoryManager;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.manager.VoteInvitationManager;
@SuppressWarnings("serial")
@ -172,7 +172,7 @@ public class MergeRequest extends AbstractEntity {
if (effectiveUpdates == null) {
effectiveUpdates = new ArrayList<MergeRequestUpdate>();
File repoDir = Gitop.getInstance(RepositoryManager.class).locateStorage(getDestination().getRepository());
File repoDir = Gitop.getInstance(ProjectManager.class).locateStorage(getDestination().getProject()).ofCode();
Git git = new Git(repoDir);
CheckAncestorCommand command = git.checkAncestor();
command.ancestor(getMergeBase());
@ -195,7 +195,7 @@ public class MergeRequest extends AbstractEntity {
}
public boolean isFastForward() {
File repoDir = Gitop.getInstance(RepositoryManager.class).locateStorage(getDestination().getRepository());
File repoDir = Gitop.getInstance(ProjectManager.class).locateStorage(getDestination().getProject()).ofCode();
CheckAncestorCommand command = new Git(repoDir).checkAncestor();
command.ancestor(getDestination().getName());
command.descendant(getLatestUpdate().getRefName());
@ -203,8 +203,8 @@ public class MergeRequest extends AbstractEntity {
}
public Collection<String> findTouchedFiles() {
RepositoryManager repositoryManager = Gitop.getInstance(RepositoryManager.class);
File repoDir = repositoryManager.locateStorage(getDestination().getRepository());
ProjectManager projectManager = Gitop.getInstance(ProjectManager.class);
File repoDir = projectManager.locateStorage(getDestination().getProject()).ofCode();
MergeRequestUpdate update = getLatestUpdate();
if (update != null) {
FindChangedFilesCommand command = new Git(repoDir).findChangedFiles();
@ -218,8 +218,8 @@ public class MergeRequest extends AbstractEntity {
public boolean isMerged() {
if (merged == null) {
RepositoryManager repositoryManager = Gitop.getInstance(RepositoryManager.class);
File repoDir = repositoryManager.locateStorage(getDestination().getRepository());
ProjectManager projectManager = Gitop.getInstance(ProjectManager.class);
File repoDir = projectManager.locateStorage(getDestination().getProject()).ofCode();
CheckAncestorCommand command = new Git(repoDir).checkAncestor();
command.ancestor(getLatestUpdate().getRefName());
command.descendant(getDestination().getName());
@ -230,8 +230,8 @@ public class MergeRequest extends AbstractEntity {
public String getMergeBase() {
if (mergeBase == null) {
RepositoryManager repositoryManager = Gitop.getInstance(RepositoryManager.class);
File repoDir = repositoryManager.locateStorage(getDestination().getRepository());
ProjectManager projectManager = Gitop.getInstance(ProjectManager.class);
File repoDir = projectManager.locateStorage(getDestination().getProject()).ofCode();
CalcMergeBaseCommand command = new Git(repoDir).calcMergeBase();
command.rev1(getLatestUpdate().getRefName());
command.rev2(getDestination().getName());
@ -315,7 +315,7 @@ public class MergeRequest extends AbstractEntity {
}
/**
* Check this request with gate keeper of target repository.
* Check this request with gate keeper of target project.
* <p>
* @param force
* whether or not to force the check. Since the check might be time-consuming, Gitop
@ -326,7 +326,7 @@ public class MergeRequest extends AbstractEntity {
*/
public Optional<CheckResult> check(boolean force) {
if (checkResult == null || force) {
GateKeeper gateKeeper = getDestination().getRepository().getGateKeeper();
GateKeeper gateKeeper = getDestination().getProject().getGateKeeper();
if (gateKeeper != null) {
checkResult = Optional.of(gateKeeper.check(this));

View File

@ -23,7 +23,7 @@ import com.pmease.gitop.core.manager.UserManager;
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.RepositoryOperation;
import com.pmease.gitop.core.permission.operation.GeneralOperation;
@Entity
@Table(uniqueConstraints={
@ -31,7 +31,7 @@ import com.pmease.gitop.core.permission.operation.RepositoryOperation;
})
@SuppressWarnings("serial")
@Editable
public class Repository extends AbstractEntity implements UserBelonging {
public class Project extends AbstractEntity implements UserBelonging {
@ManyToOne
@JoinColumn(nullable=false)
@ -44,17 +44,13 @@ public class Repository extends AbstractEntity implements UserBelonging {
private boolean publiclyAccessible;
private RepositoryOperation defaultAuthorizedOperation;
@Column(nullable=false)
private GeneralOperation defaultAuthorizedOperation = GeneralOperation.NO_ACCESS;
private GateKeeper gateKeeper;
@OneToMany(mappedBy="repository")
private Collection<RepositoryAuthorizationByTeam> authorizationsByTeam =
new ArrayList<RepositoryAuthorizationByTeam>();
@OneToMany(mappedBy="repository")
private Collection<RepositoryAuthorizationByIndividual> authorizationsByIndividual =
new ArrayList<RepositoryAuthorizationByIndividual>();
@OneToMany(mappedBy="project")
private Collection<Authorization> authorizations = new ArrayList<Authorization>();
public User getOwner() {
return owner;
@ -65,7 +61,7 @@ public class Repository extends AbstractEntity implements UserBelonging {
}
@Editable(description=
"Specify name of the repository. It will be used to identify the repository when accessing via Git.")
"Specify name of the project. It will be used to identify the project when accessing via Git.")
@NotEmpty
public String getName() {
return name;
@ -75,7 +71,7 @@ public class Repository extends AbstractEntity implements UserBelonging {
this.name = name;
}
@Editable(description="Specify description of the repository.")
@Editable(description="Specify description of the project.")
public String getDescription() {
return description;
}
@ -85,7 +81,7 @@ public class Repository extends AbstractEntity implements UserBelonging {
}
@Editable(name="Public", description=
"If a repository is made public, it will be able to be browsed/pulled by anonymous users.")
"If a project is made public, it will be able to be browsed/pulled by anonymous users.")
public boolean isPubliclyAccessible() {
return publiclyAccessible;
}
@ -94,12 +90,12 @@ public class Repository extends AbstractEntity implements UserBelonging {
this.publiclyAccessible = publiclyAccessible;
}
public RepositoryOperation getDefaultAuthorizedOperation() {
public GeneralOperation getDefaultAuthorizedOperation() {
return defaultAuthorizedOperation;
}
public void setDefaultAuthorizedOperation(
RepositoryOperation defaultAuthorizedOperation) {
GeneralOperation defaultAuthorizedOperation) {
this.defaultAuthorizedOperation = defaultAuthorizedOperation;
}
@ -119,35 +115,25 @@ public class Repository extends AbstractEntity implements UserBelonging {
return getOwner();
}
public Collection<RepositoryAuthorizationByTeam> getAuthorizationsByTeam() {
return authorizationsByTeam;
public Collection<Authorization> getAuthorizations() {
return authorizations;
}
public void setAuthorizationsByTeam(
Collection<RepositoryAuthorizationByTeam> authorizationsByTeam) {
this.authorizationsByTeam = authorizationsByTeam;
}
public Collection<RepositoryAuthorizationByIndividual> getAuthorizationsByIndividual() {
return authorizationsByIndividual;
}
public void setAuthorizationsByIndividual(
Collection<RepositoryAuthorizationByIndividual> authorizationsByIndividual) {
this.authorizationsByIndividual = authorizationsByIndividual;
public void setAuthorizations(Collection<Authorization> authorizations) {
this.authorizations = authorizations;
}
@Override
public boolean has(ProtectedObject object) {
if (object instanceof Repository) {
Repository repository = (Repository) object;
return repository.getId().equals(getId());
if (object instanceof Project) {
Project project = (Project) object;
return project.getId().equals(getId());
} else {
return false;
}
}
public Collection<User> findAuthorizedUsers(RepositoryOperation operation) {
public Collection<User> findAuthorizedUsers(GeneralOperation operation) {
Set<User> authorizedUsers = new HashSet<User>();
for (User user: Gitop.getInstance(UserManager.class).query(null)) {
if (user.asSubject().isPermitted(new ObjectPermission(this, operation)))

View File

@ -1,53 +0,0 @@
package com.pmease.gitop.core.model;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.gitop.core.permission.operation.RepositoryOperation;
@SuppressWarnings("serial")
@Entity
@Table(uniqueConstraints={
@UniqueConstraint(columnNames={"individual", "repository"})
})
public class RepositoryAuthorizationByIndividual extends AbstractEntity {
@ManyToOne
@JoinColumn(nullable=false)
private User individual;
@ManyToOne
@JoinColumn(nullable=false)
private Repository repository;
private RepositoryOperation authorizedOperation = RepositoryOperation.READ;
public RepositoryOperation getAuthorizedOperation() {
return authorizedOperation;
}
public void setAuthorizedOperation(RepositoryOperation authorizedOperation) {
this.authorizedOperation = authorizedOperation;
}
public User getIndividual() {
return individual;
}
public void setIndividual(User individual) {
this.individual = individual;
}
public Repository getRepository() {
return repository;
}
public void setRepository(Repository repository) {
this.repository = repository;
}
}

View File

@ -1,75 +0,0 @@
package com.pmease.gitop.core.model;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import org.apache.shiro.authz.Permission;
import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.gitop.core.permission.ObjectPermission;
import com.pmease.gitop.core.permission.operation.PrivilegedOperation;
@Entity
@SuppressWarnings("serial")
public class Role extends AbstractEntity implements Permission {
@Column(nullable=false, unique=true)
private String name;
private String description;
@Column(nullable=false)
private ArrayList<PrivilegedOperation> operations = new ArrayList<PrivilegedOperation>();
@OneToMany(mappedBy="role")
private Collection<RoleMembership> memberships = new ArrayList<RoleMembership>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Collection<RoleMembership> getMemberships() {
return memberships;
}
public void setMemberships(Collection<RoleMembership> memberships) {
this.memberships = memberships;
}
public ArrayList<PrivilegedOperation> getOperations() {
return operations;
}
public void setOperations(ArrayList<PrivilegedOperation> operations) {
this.operations = operations;
}
@Override
public boolean implies(Permission permission) {
if (permission instanceof ObjectPermission) {
ObjectPermission objectPermission = (ObjectPermission) permission;
for (PrivilegedOperation each: getOperations()) {
if (each.can(objectPermission.getOperation()))
return true;
}
}
return false;
}
}

View File

@ -1,42 +0,0 @@
package com.pmease.gitop.core.model;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import com.pmease.commons.hibernate.AbstractEntity;
@SuppressWarnings("serial")
@Entity
@Table(uniqueConstraints={
@UniqueConstraint(columnNames={"user", "role"})
})
public class RoleMembership extends AbstractEntity {
@ManyToOne
@JoinColumn(nullable=false)
private User user;
@ManyToOne
@JoinColumn(nullable=false)
private Role role;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}

View File

@ -15,7 +15,7 @@ import org.apache.shiro.authz.Permission;
import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.gitop.core.permission.ObjectPermission;
import com.pmease.gitop.core.permission.operation.UserOperation;
import com.pmease.gitop.core.permission.operation.GeneralOperation;
@Entity
@Table(uniqueConstraints={
@ -33,18 +33,14 @@ public class Team extends AbstractEntity implements Permission {
private String description;
private boolean anonymous;
private boolean register;
@Column(nullable=false)
private UserOperation authorizedOperation = UserOperation.READ;
private GeneralOperation authorizedOperation = GeneralOperation.READ;
@OneToMany(mappedBy="team")
private Collection<TeamMembership> memberships = new ArrayList<TeamMembership>();
private Collection<Membership> memberships = new ArrayList<Membership>();
@OneToMany(mappedBy="team")
private Collection<RepositoryAuthorizationByTeam> repositoryAuthorizations = new ArrayList<RepositoryAuthorizationByTeam>();
private Collection<Authorization> authorizations = new ArrayList<Authorization>();
public User getOwner() {
return owner;
@ -70,44 +66,28 @@ public class Team extends AbstractEntity implements Permission {
this.description = description;
}
public boolean isAnonymous() {
return anonymous;
}
public void setAnonymous(boolean anonymous) {
this.anonymous = anonymous;
}
public boolean isRegister() {
return register;
}
public void setRegister(boolean register) {
this.register = register;
}
public UserOperation getAuthorizedOperation() {
public GeneralOperation getAuthorizedOperation() {
return authorizedOperation;
}
public void setAuthorizedOperation(UserOperation authorizedOeration) {
public void setAuthorizedOperation(GeneralOperation authorizedOeration) {
this.authorizedOperation = authorizedOeration;
}
public Collection<TeamMembership> getMemberships() {
public Collection<Membership> getMemberships() {
return memberships;
}
public void setMemberships(Collection<TeamMembership> memberships) {
public void setMemberships(Collection<Membership> memberships) {
this.memberships = memberships;
}
public Collection<RepositoryAuthorizationByTeam> getRepositoryAuthorizations() {
return repositoryAuthorizations;
public Collection<Authorization> getAuthorizations() {
return authorizations;
}
public void setRepositoryAuthorizations(Collection<RepositoryAuthorizationByTeam> repositoryAuthorizations) {
this.repositoryAuthorizations = repositoryAuthorizations;
public void setAuthorizations(Collection<Authorization> authorizations) {
this.authorizations = authorizations;
}
@Override
@ -118,10 +98,10 @@ public class Team extends AbstractEntity implements Permission {
if (userPermission.implies(objectPermission))
return true;
for (RepositoryAuthorizationByTeam authorization: getRepositoryAuthorizations()) {
Permission repositoryPermission = new ObjectPermission(
authorization.getRepository(), authorization.getAuthorizedOperation());
if (repositoryPermission.implies(objectPermission))
for (Authorization authorization: getAuthorizations()) {
Permission projectPermission = new ObjectPermission(
authorization.getProject(), authorization.getAuthorizedOperation());
if (projectPermission.implies(objectPermission))
return true;
}
}

View File

@ -17,19 +17,19 @@ import com.pmease.commons.editable.annotation.Password;
import com.pmease.commons.loader.AppLoader;
import com.pmease.commons.shiro.AbstractUser;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.manager.RepositoryManager;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.manager.UserManager;
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.RepositoryOperation;
import com.pmease.gitop.core.permission.operation.GeneralOperation;
/**
* This class represents either a project or an user in the system.
* <p>
* In Gitop, users and projects are the same thing.
* If necessary, you can always treat an user account as a project account.
* {@link Repository} and {@link Team} are always created under a specific account.
* {@link Project} and {@link Team} are always created under a specific account.
*
* @author robin
*
@ -39,7 +39,12 @@ import com.pmease.gitop.core.permission.operation.RepositoryOperation;
@Editable
public class User extends AbstractUser implements ProtectedObject {
public static final User ANONYMOUS = new User(0L, "Anonymous");
public static final User ANONYMOUS = new User();
static {
ANONYMOUS.setId(0L);
ANONYMOUS.setName("Guest");
}
@Column(nullable=false)
private String email;
@ -50,17 +55,16 @@ public class User extends AbstractUser implements ProtectedObject {
@Column
private String avatarUrl;
@OneToMany(mappedBy="user")
private Collection<TeamMembership> teamMemberships = new ArrayList<TeamMembership>();
private boolean admin;
@OneToMany(mappedBy="user")
private Collection<RoleMembership> roleMemberships = new ArrayList<RoleMembership>();
private Collection<Membership> memberships = new ArrayList<Membership>();
@OneToMany(mappedBy="submitter")
private Collection<MergeRequest> mergeRequests = new ArrayList<MergeRequest>();
@OneToMany(mappedBy="owner")
private Collection<Repository> repositories = new ArrayList<Repository>();
private Collection<Project> repositories = new ArrayList<Project>();
@OneToMany(mappedBy="owner")
private Collection<Team> teams = new ArrayList<Team>();
@ -71,34 +75,23 @@ public class User extends AbstractUser implements ProtectedObject {
@OneToMany(mappedBy="voter")
private Collection<VoteInvitation> voteVitations = new ArrayList<VoteInvitation>();
@OneToMany(mappedBy="individual")
private Collection<RepositoryAuthorizationByIndividual> repositoryAuthorizations =
new ArrayList<RepositoryAuthorizationByIndividual>();
@OneToMany(mappedBy="individual")
private Collection<UserAuthorizationByIndividual> userAuthorizations =
new ArrayList<UserAuthorizationByIndividual>();
@OneToMany(mappedBy="user")
private Collection<UserAuthorizationByIndividual> authorizationsByIndividual =
new ArrayList<UserAuthorizationByIndividual>();
public User() {
}
private User(Long id, String name) {
setId(id);
setName(name);
}
@Editable
@Editable(order=100)
@NotEmpty
@Override
public String getName() {
return super.getName();
}
@Editable
@Editable(order=200)
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
@Editable(order=300)
@NotEmpty
@Email
public String getEmail() {
@ -109,7 +102,7 @@ public class User extends AbstractUser implements ProtectedObject {
this.email = email;
}
@Editable(name="Password")
@Editable(name="Password", order=400)
@Password(confirmative=true)
@NotEmpty
@Override
@ -117,13 +110,12 @@ public class User extends AbstractUser implements ProtectedObject {
return super.getPasswordHash();
}
@Editable
public String getDisplayName() {
return displayName;
public boolean isAdmin() {
return admin;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
public void setAdmin(boolean admin) {
this.admin = admin;
}
public String getAvatarUrl() {
@ -134,27 +126,19 @@ public class User extends AbstractUser implements ProtectedObject {
this.avatarUrl = avatarUrl;
}
public Collection<TeamMembership> getTeamMemberships() {
return teamMemberships;
public Collection<Membership> getMemberships() {
return memberships;
}
public void setTeamMemberships(Collection<TeamMembership> teamMemberships) {
this.teamMemberships = teamMemberships;
public void setMemberships(Collection<Membership> memberships) {
this.memberships = memberships;
}
public Collection<RoleMembership> getRoleMemberships() {
return roleMemberships;
}
public void setRoleMemberships(Collection<RoleMembership> roleMemberships) {
this.roleMemberships = roleMemberships;
}
public Collection<Repository> getRepositories() {
public Collection<Project> getRepositories() {
return repositories;
}
public void setRepositories(Collection<Repository> repositories) {
public void setRepositories(Collection<Project> repositories) {
this.repositories = repositories;
}
@ -198,33 +182,6 @@ public class User extends AbstractUser implements ProtectedObject {
this.voteVitations = voteVitations;
}
public Collection<RepositoryAuthorizationByIndividual> getRepositoryAuthorizations() {
return repositoryAuthorizations;
}
public void setRepositoryAuthorizations(
Collection<RepositoryAuthorizationByIndividual> repositoryAuthorizations) {
this.repositoryAuthorizations = repositoryAuthorizations;
}
public Collection<UserAuthorizationByIndividual> getUserAuthorizations() {
return userAuthorizations;
}
public void setUserAuthorizations(
Collection<UserAuthorizationByIndividual> userAuthorizations) {
this.userAuthorizations = userAuthorizations;
}
public Collection<UserAuthorizationByIndividual> getAuthorizationsByIndividual() {
return authorizationsByIndividual;
}
public void setAuthorizationsByIndividual(
Collection<UserAuthorizationByIndividual> authorizationsByIndividual) {
this.authorizationsByIndividual = authorizationsByIndividual;
}
@Override
public boolean has(ProtectedObject object) {
if (object instanceof User) {
@ -259,11 +216,18 @@ public class User extends AbstractUser implements ProtectedObject {
return User.ANONYMOUS;
}
}
public static User anonymous() {
User user = new User();
user.setId(0L);
user.setName("Guest");
return user;
}
@Override
public boolean implies(Permission permission) {
// Root user can do anything
if (isRoot())
// Administrator can do anything
if (isRoot() || isAdmin())
return true;
if (permission instanceof ObjectPermission) {
@ -273,40 +237,22 @@ public class User extends AbstractUser implements ProtectedObject {
if (has(objectPermission.getObject()))
return true;
for (RepositoryAuthorizationByIndividual authorization: getRepositoryAuthorizations()) {
ObjectPermission repositoryPermission = new ObjectPermission(
authorization.getRepository(), authorization.getAuthorizedOperation());
if (repositoryPermission.implies(objectPermission))
return true;
}
for (UserAuthorizationByIndividual each: getUserAuthorizations()) {
ObjectPermission userPermission = new ObjectPermission(each.getUser(), each.getAuthorizedOperation());
if (userPermission.implies(objectPermission))
return true;
}
for (Team team: getTeams()) {
if (team.implies(objectPermission))
return true;
}
for (RoleMembership each: getRoleMemberships()) {
if (each.getRole().implies(objectPermission))
return true;
}
for (Repository each: Gitop.getInstance(RepositoryManager.class).query(null)) {
ObjectPermission repositoryPermission = new ObjectPermission(each, each.getDefaultAuthorizedOperation());
if (repositoryPermission.implies(objectPermission))
for (Project each: Gitop.getInstance(ProjectManager.class).query(null)) {
ObjectPermission projectPermission = new ObjectPermission(each, each.getDefaultAuthorizedOperation());
if (projectPermission.implies(objectPermission))
return true;
}
}
// check if is public access
for (Repository each: Gitop.getInstance(RepositoryManager.class).findPublic()) {
ObjectPermission repositoryPermission = new ObjectPermission(each, RepositoryOperation.READ);
if (repositoryPermission.implies(objectPermission))
for (Project each: Gitop.getInstance(ProjectManager.class).findPublic()) {
ObjectPermission projectPermission = new ObjectPermission(each, GeneralOperation.READ);
if (projectPermission.implies(objectPermission))
return true;
}
}

View File

@ -1,53 +0,0 @@
package com.pmease.gitop.core.model;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import com.pmease.commons.hibernate.AbstractEntity;
import com.pmease.gitop.core.permission.operation.UserOperation;
@SuppressWarnings("serial")
@Entity
@Table(uniqueConstraints={
@UniqueConstraint(columnNames={"individual", "user"})
})
public class UserAuthorizationByIndividual extends AbstractEntity {
@ManyToOne
@JoinColumn(nullable=false)
private User individual;
@ManyToOne
@JoinColumn(nullable=false)
private User user;
private UserOperation authorizedOperation = UserOperation.READ;
public UserOperation getAuthorizedOperation() {
return authorizedOperation;
}
public void setAuthorizedOperation(UserOperation authorizedOperation) {
this.authorizedOperation = authorizedOperation;
}
public User getIndividual() {
return individual;
}
public void setIndividual(User individual) {
this.individual = individual;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

View File

@ -1,24 +0,0 @@
package com.pmease.gitop.core.permission;
import com.pmease.gitop.core.permission.operation.PrivilegedOperation;
public class BranchPermission {
private final String branchNames;
private final PrivilegedOperation branchOperation;
public BranchPermission(String branchNames, PrivilegedOperation branchOperation) {
this.branchNames = branchNames;
this.branchOperation = branchOperation;
}
public String getBranchNames() {
return branchNames;
}
public PrivilegedOperation getBranchOperation() {
return branchOperation;
}
}

View File

@ -2,14 +2,11 @@ package com.pmease.gitop.core.permission;
import org.apache.shiro.authz.Permission;
import com.pmease.gitop.core.model.Repository;
import com.pmease.gitop.core.model.Project;
import com.pmease.gitop.core.model.User;
import com.pmease.gitop.core.permission.object.ProtectedObject;
import com.pmease.gitop.core.permission.object.SystemObject;
import com.pmease.gitop.core.permission.operation.GeneralOperation;
import com.pmease.gitop.core.permission.operation.PrivilegedOperation;
import com.pmease.gitop.core.permission.operation.RepositoryOperation;
import com.pmease.gitop.core.permission.operation.SystemOperation;
import com.pmease.gitop.core.permission.operation.UserOperation;
/**
* This class represents permissions to operate an account and its belongings.
@ -56,31 +53,27 @@ public class ObjectPermission implements Permission {
}
public static ObjectPermission ofUserAdmin(User user) {
return new ObjectPermission(user, UserOperation.ADMINISTRATION);
return new ObjectPermission(user, GeneralOperation.ADMINISTRATION);
}
public static ObjectPermission ofUserRead(User user) {
return new ObjectPermission(user, UserOperation.READ);
return new ObjectPermission(user, GeneralOperation.READ);
}
public static ObjectPermission ofUserWrite(User user) {
return new ObjectPermission(user, UserOperation.WRITE);
return new ObjectPermission(user, GeneralOperation.WRITE);
}
public static ObjectPermission ofRepositoryAdmin(Repository repository) {
return new ObjectPermission(repository, RepositoryOperation.ADMINISTRATION);
public static ObjectPermission ofProjectAdmin(Project project) {
return new ObjectPermission(project, GeneralOperation.ADMINISTRATION);
}
public static ObjectPermission ofRepositoryRead(Repository repository) {
return new ObjectPermission(repository, RepositoryOperation.READ);
public static ObjectPermission ofProjectRead(Project project) {
return new ObjectPermission(project, GeneralOperation.READ);
}
public static ObjectPermission ofRepositoryWrite(Repository repository) {
return new ObjectPermission(repository, RepositoryOperation.WRITE);
public static ObjectPermission ofProjectWrite(Project project) {
return new ObjectPermission(project, GeneralOperation.WRITE);
}
public static ObjectPermission ofSystem(SystemOperation operation) {
return new ObjectPermission(new SystemObject(), operation);
}
}

View File

@ -8,7 +8,6 @@ import org.apache.shiro.authc.credential.CredentialsMatcher;
import com.pmease.commons.hibernate.dao.GeneralDao;
import com.pmease.commons.shiro.AbstractRealm;
import com.pmease.commons.shiro.AbstractUser;
import com.pmease.gitop.core.manager.RoleManager;
import com.pmease.gitop.core.manager.TeamManager;
import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.core.model.User;
@ -20,7 +19,7 @@ public class UserRealm extends AbstractRealm {
@Inject
public UserRealm(GeneralDao generalDao, CredentialsMatcher credentialsMatcher,
UserManager userManager, RoleManager roleManager, TeamManager teamManager) {
UserManager userManager, TeamManager teamManager) {
super(credentialsMatcher);
this.userManager = userManager;
@ -31,9 +30,7 @@ public class UserRealm extends AbstractRealm {
if (userId != 0L) {
return userManager.load(userId);
} else {
User user = new User();
user.setId(0L);
return user;
return User.anonymous();
}
}

View File

@ -1,10 +0,0 @@
package com.pmease.gitop.core.permission.object;
public class SystemObject implements ProtectedObject {
@Override
public boolean has(ProtectedObject object) {
return true;
}
}

View File

@ -0,0 +1,49 @@
package com.pmease.gitop.core.permission.operation;
public enum GeneralOperation implements PrivilegedOperation {
NO_ACCESS("No Access") {
@Override
public boolean can(PrivilegedOperation operation) {
return false;
}
},
READ("Read") {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == READ;
}
},
WRITE("Write") {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == WRITE || READ.can(operation);
}
},
ADMINISTRATION("Administration") {
@Override
public boolean can(PrivilegedOperation operation) {
return true;
}
};
private final String displayName;
GeneralOperation(String displayName) {
this.displayName = displayName;
}
@Override
public String toString() {
return displayName;
}
}

View File

@ -1,28 +0,0 @@
package com.pmease.gitop.core.permission.operation;
public enum RepositoryOperation implements PrivilegedOperation {
READ {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == READ;
}
},
WRITE {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == WRITE || READ.can(operation);
}
},
ADMINISTRATION {
@Override
public boolean can(PrivilegedOperation operation) {
return true;
}
}
}

View File

@ -8,14 +8,6 @@ public enum SystemOperation implements PrivilegedOperation {
return true;
}
},
VOTE {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == VOTE;
}
},
ADD_COMMENT {
@ -24,6 +16,14 @@ public enum SystemOperation implements PrivilegedOperation {
return operation == ADD_COMMENT;
}
},
CREATE_PROJECT {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == CREATE_PROJECT;
}
},
CREATE_MERGE_REQUEST {
@ -32,31 +32,5 @@ public enum SystemOperation implements PrivilegedOperation {
return operation == CREATE_MERGE_REQUEST;
}
},
CREATE_REPOSITORY {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == CREATE_REPOSITORY;
}
},
READ_ALL_REPOSITORIES {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == READ_ALL_REPOSITORIES || RepositoryOperation.READ.can(operation);
}
},
WRITE_ALL_REPOSITORIES {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == WRITE_ALL_REPOSITORIES
|| READ_ALL_REPOSITORIES.can(operation)
|| RepositoryOperation.WRITE.can(operation);
}
}
}

View File

@ -1,28 +0,0 @@
package com.pmease.gitop.core.permission.operation;
public enum UserOperation implements PrivilegedOperation {
READ {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == READ || RepositoryOperation.READ.can(operation);
}
},
WRITE {
@Override
public boolean can(PrivilegedOperation operation) {
return operation == WRITE || READ.can(operation) || RepositoryOperation.WRITE.can(operation);
}
},
ADMINISTRATION {
@Override
public boolean can(PrivilegedOperation operation) {
return true;
}
}
}

View File

@ -12,6 +12,14 @@ public interface ServerConfig {
*/
int getHttpPort();
/**
* Get servlet context path for QuickBuild UI.
*
* @return
* context path to serve QuickBuild UI
*/
String getContextPath();
/**
* Get ssl config of the server.
* <p>

View File

@ -10,16 +10,16 @@ import com.pmease.commons.editable.annotation.Editable;
@Editable
public class StorageSetting implements Serializable {
private String repoStorageDir;
private String storageDir;
@Editable
@NotEmpty
public String getRepoStorageDir() {
return repoStorageDir;
public String getStorageDir() {
return storageDir;
}
public void setRepoStorageDir(String repoStorageDir) {
this.repoStorageDir = repoStorageDir;
public void setStorageDir(String storageDir) {
this.storageDir = storageDir;
}
}

View File

@ -0,0 +1,30 @@
package com.pmease.gitop.core.storage;
import java.io.File;
import com.pmease.commons.util.FileUtils;
public class ProjectStorage {
private final File storageDir;
public ProjectStorage(File storageDir) {
this.storageDir = storageDir;
}
public File ofCode() {
return new File(storageDir, "code");
}
public File ofWiki() {
return new File(storageDir, "wiki");
}
public void delete() {
FileUtils.deleteDir(storageDir);
}
public void clean() {
FileUtils.cleanDir(storageDir);
}
}

View File

@ -18,6 +18,8 @@ public class DefaultServerConfig implements ServerConfig {
private int httpPort;
private int sessionTimeout;
private String contextPath;
private SslConfig sslConfig;
@ -25,24 +27,32 @@ public class DefaultServerConfig implements ServerConfig {
public DefaultServerConfig(@Named("server") Properties props) {
String httpPortStr = props.getProperty("httpPort");
if (StringUtils.isNotBlank(httpPortStr)) {
httpPort = Integer.parseInt(httpPortStr);
httpPort = Integer.parseInt(httpPortStr.trim());
}
String httpsPortStr = props.getProperty("httpsPort");
if (StringUtils.isNotBlank(httpsPortStr)) {
SslConfigBean sslConfigBean = new SslConfigBean();
sslConfigBean.setPort(Integer.parseInt(httpsPortStr));
sslConfigBean.setPort(Integer.parseInt(httpsPortStr.trim()));
String keystorePath = props.getProperty("sslKeystorePath");
if (StringUtils.isBlank(keystorePath))
keystorePath = "sample.keystore";
else
keystorePath = keystorePath.trim();
String keystorePassword = props.getProperty("sslKeystorePassword");
if (StringUtils.isBlank(keystorePassword))
keystorePassword = "123456";
else
keystorePassword = keystorePassword.trim();
String keystoreKeyPassword = props.getProperty("sslKeystoreKeyPassword");
if (StringUtils.isBlank(keystoreKeyPassword))
keystoreKeyPassword = "123456";
else
keystoreKeyPassword = keystoreKeyPassword.trim();
File keystoreFile = new File(keystorePath);
if (!keystoreFile.isAbsolute())
@ -58,11 +68,21 @@ public class DefaultServerConfig implements ServerConfig {
if (httpPort == 0 && sslConfig == null)
throw new RuntimeException("Either httpPort or httpsPort or both should be enabled.");
String sessionTimeout = props.getProperty("sessionTimeout");
if (StringUtils.isNotBlank(sessionTimeout))
this.sessionTimeout = Integer.parseInt(sessionTimeout);
String sessionTimeoutStr = props.getProperty("sessionTimeout");
if (StringUtils.isNotBlank(sessionTimeoutStr))
this.sessionTimeout = Integer.parseInt(sessionTimeoutStr.trim());
else
throw new RuntimeException("sessionTimeout is not specified.");
contextPath = props.getProperty("contextPath");
if (StringUtils.isNotBlank(contextPath)) {
contextPath = StringUtils.stripStart(contextPath.trim(), "/ ");
contextPath = StringUtils.stripEnd(contextPath, "/ ");
contextPath = "/" + contextPath;
} else {
contextPath = "/";
}
}
@Override
@ -79,4 +99,9 @@ public class DefaultServerConfig implements ServerConfig {
public int getSessionTimeout() {
return sessionTimeout;
}
@Override
public String getContextPath() {
return contextPath;
}
}

View File

@ -23,6 +23,8 @@ public class GitopServletContextConfigurator implements ServletContextConfigurat
@Override
public void configure(ServletContextHandler context) {
context.setContextPath(serverConfig.getContextPath());
context.getSessionHandler().getSessionManager().setMaxInactiveInterval(serverConfig.getSessionTimeout());
/*

View File

@ -14,6 +14,11 @@ httpPort = 8810
#
httpsPort = 9910
# Optionally specify context path to access QuickBuild web UI. If specified, web UI
# will be accessed in form of http(s)://<server>:<port>/<contextPath>/; otherwise,
# it will be accessed in form of http(s)://<server>:<port>/
#contextPath =
# Uncomment various keystore properties below to use custom keystore path and corresponding
# passwords. Keystore can be generated by running command like below:
# /path/to/jdk/bin/keytool -keystore /path/to/keystore -alias MyProduct -genkey -keyalg RSA

View File

@ -31,7 +31,7 @@ public class SitePaths {
public File dataDir() {
// TODO: this is not correct, should change repo storage dir to data dir
return new File(configManager.getStorageSetting().getRepoStorageDir());
return new File(configManager.getStorageSetting().getStorageDir());
}
public File avatarsDir() {

View File

@ -5,9 +5,9 @@ import org.apache.wicket.markup.html.form.Form;
import com.pmease.commons.editable.EditContext;
import com.pmease.commons.wicket.editable.EditHelper;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.manager.RepositoryManager;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.core.model.Repository;
import com.pmease.gitop.core.model.Project;
import com.pmease.gitop.web.page.BasePage;
@SuppressWarnings("serial")
@ -17,7 +17,7 @@ public class TestPage extends BasePage {
protected void onInitialize() {
super.onInitialize();
final EditContext editContext = EditHelper.getContext(new Repository());
final EditContext editContext = EditHelper.getContext(new Project());
Form<?> form = new Form<Void>("form") {
@ -26,9 +26,9 @@ public class TestPage extends BasePage {
super.onSubmit();
editContext.validate();
if (!editContext.hasValidationError(true)) {
Repository repository = (Repository) editContext.getBean();
repository.setOwner(Gitop.getInstance(UserManager.class).getRootUser());
Gitop.getInstance(RepositoryManager.class).save(repository);
Project project = (Project) editContext.getBean();
project.setOwner(Gitop.getInstance(UserManager.class).getRootUser());
Gitop.getInstance(ProjectManager.class).save(project);
}
}

View File

@ -0,0 +1,29 @@
package com.pmease.gitop.web;
import javax.inject.Singleton;
import org.apache.wicket.Page;
import com.pmease.commons.wicket.AbstractWicketConfig;
import com.pmease.gitop.web.page.home.HomePage;
import com.pmease.gitop.web.page.init.ServerInitPage;
@Singleton
public class WicketConfig extends AbstractWicketConfig {
@Override
protected void init() {
super.init();
mountPage("/", HomePage.class);
mountPage("/init", ServerInitPage.class);
mountPage("/test/dudu", TestPage.class);
}
@Override
public Class<? extends Page> getHomePage() {
return HomePage.class;
}
}

View File

@ -6,9 +6,9 @@ import org.apache.wicket.RuntimeConfigurationType;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.head.CssReferenceHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
import com.pmease.commons.wicket.asset.JQueryHeaderItem;
import com.pmease.commons.wicket.asset.bootstrap.BootstrapHeaderItem;
public class BaseResourceBehavior extends Behavior {
@ -29,7 +29,7 @@ public class BaseResourceBehavior extends Behavior {
response.render(JavaScriptReferenceHeaderItem.forReference(AssetLocator.MODERNIZR_JS));
// render jquery
response.render(JavaScriptHeaderItem.forReference(Application.get().getJavaScriptLibrarySettings().getJQueryReference()));
response.render(JQueryHeaderItem.get());
// render bootstrap
response.render(BootstrapHeaderItem.get());

View File

@ -11,7 +11,7 @@ import org.apache.wicket.model.Model;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import com.google.common.base.Strings;
import com.pmease.gitop.core.model.Repository;
import com.pmease.gitop.core.model.Project;
import com.pmease.gitop.core.model.User;
@StatelessComponent
@ -55,7 +55,7 @@ public class AvatarImage extends Panel {
return (new StatelessAvatarImage("avatar", params));
}
} else {
Repository project = (Repository) getDefaultModelObject();
Project project = (Project) getDefaultModelObject();
PageParameters params = new PageParameters();
params.set("type", AvatarImageType.REPOSITORY.name().toLowerCase());
params.set("id", project.getId());