From 79dfe69726b6255464599ab852018e4d2ff96fdc Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Fri, 19 Oct 2012 22:47:35 -0400
Subject: [PATCH] Split edit repository page into tabs
---
src/com/gitblit/GitBlit.java | 270 ++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 221 insertions(+), 49 deletions(-)
diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java
index 5a41356..ce556b6 100644
--- a/src/com/gitblit/GitBlit.java
+++ b/src/com/gitblit/GitBlit.java
@@ -55,8 +55,11 @@
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
import org.apache.wicket.protocol.http.WebResponse;
+import org.apache.wicket.resource.ContextRelativeResource;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.lib.RepositoryCache.FileKey;
@@ -69,17 +72,20 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.gitblit.Constants.AccessPermission;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.Constants.AuthorizationControl;
import com.gitblit.Constants.FederationRequest;
import com.gitblit.Constants.FederationStrategy;
import com.gitblit.Constants.FederationToken;
+import com.gitblit.Constants.RegistrantType;
import com.gitblit.models.FederationModel;
import com.gitblit.models.FederationProposal;
import com.gitblit.models.FederationSet;
import com.gitblit.models.ForkModel;
import com.gitblit.models.Metric;
import com.gitblit.models.ProjectModel;
+import com.gitblit.models.RegistrantAccessPermission;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.SearchResult;
import com.gitblit.models.ServerSettings;
@@ -97,6 +103,7 @@
import com.gitblit.utils.MetricUtils;
import com.gitblit.utils.ObjectCache;
import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
/**
* GitBlit is the servlet context listener singleton that acts as the core for
@@ -162,6 +169,11 @@
// set the static singleton reference
gitblit = this;
}
+ }
+
+ public GitBlit(final IUserService userService) {
+ this.userService = userService;
+ gitblit = this;
}
/**
@@ -509,6 +521,28 @@
}
/**
+ * Authenticate a user based on HTTP request paramters.
+ * This method is inteded to be used as fallback when other
+ * means of authentication are failing (username / password or cookies).
+ * @param httpRequest
+ * @return a user object or null
+ */
+ public UserModel authenticate(HttpServletRequest httpRequest) {
+ return null;
+ }
+
+ /**
+ * Open a file resource using the Servlet container.
+ * @param file to open
+ * @return InputStream of the opened file
+ * @throws ResourceStreamNotFoundException
+ */
+ public InputStream getResourceAsStream(String file) throws ResourceStreamNotFoundException {
+ ContextRelativeResource res = WicketUtils.getResource(file);
+ return res.getResourceStream().getInputStream();
+ }
+
+ /**
* Sets a cookie for the specified user.
*
* @param response
@@ -598,12 +632,44 @@
}
/**
- * Returns the list of all users who are allowed to bypass the access
- * restriction placed on the specified repository.
+ * Returns the list of users and their access permissions for the specified repository.
+ *
+ * @param repository
+ * @return a list of User-AccessPermission tuples
+ */
+ public List<RegistrantAccessPermission> getUserAccessPermissions(RepositoryModel repository) {
+ List<RegistrantAccessPermission> permissions = new ArrayList<RegistrantAccessPermission>();
+ for (String user : userService.getUsernamesForRepositoryRole(repository.name)) {
+ AccessPermission ap = userService.getUserModel(user).getRepositoryPermission(repository);
+ permissions.add(new RegistrantAccessPermission(user, ap, RegistrantType.USER));
+ }
+ return permissions;
+ }
+
+ /**
+ * Sets the access permissions to the specified repository for the specified users.
+ *
+ * @param repository
+ * @param permissions
+ * @return true if the user models have been updated
+ */
+ public boolean setUserAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) {
+ List<UserModel> users = new ArrayList<UserModel>();
+ for (RegistrantAccessPermission up : permissions) {
+ UserModel user = userService.getUserModel(up.registrant);
+ user.setRepositoryPermission(repository.name, up.permission);
+ users.add(user);
+ }
+ return userService.updateUserModels(users);
+ }
+
+ /**
+ * Returns the list of all users who have an explicit access permission
+ * for the specified repository.
*
* @see IUserService.getUsernamesForRepositoryRole(String)
* @param repository
- * @return list of all usernames that can bypass the access restriction
+ * @return list of all usernames that have an access permission for the repository
*/
public List<String> getRepositoryUsers(RepositoryModel repository) {
return userService.getUsernamesForRepositoryRole(repository.name);
@@ -618,8 +684,11 @@
* @param usernames
* @return true if successful
*/
+ @Deprecated
public boolean setRepositoryUsers(RepositoryModel repository, List<String> repositoryUsers) {
- return userService.setUsernamesForRepositoryRole(repository.name, repositoryUsers);
+ // rejects all changes since 1.2.0 because this would elevate
+ // all discrete access permissions to RW+
+ return false;
}
/**
@@ -639,6 +708,22 @@
throw new GitBlitException(MessageFormat.format(
"Failed to rename ''{0}'' because ''{1}'' already exists.", username,
user.username));
+ }
+
+ // rename repositories and owner fields for all repositories
+ for (RepositoryModel model : getRepositoryModels(user)) {
+ if (model.isUsersPersonalRepository(username)) {
+ // personal repository
+ model.owner = user.username;
+ String oldRepositoryName = model.name;
+ model.name = "~" + user.username + model.name.substring(model.projectPath.length());
+ model.projectPath = "~" + user.username;
+ updateRepositoryModel(oldRepositoryName, model, false);
+ } else if (model.isOwner(username)) {
+ // common/shared repo
+ model.owner = user.username;
+ updateRepositoryModel(model.name, model, false);
+ }
}
}
if (!userService.updateUserModel(username, user)) {
@@ -677,14 +762,46 @@
public TeamModel getTeamModel(String teamname) {
return userService.getTeamModel(teamname);
}
-
+
/**
- * Returns the list of all teams who are allowed to bypass the access
- * restriction placed on the specified repository.
+ * Returns the list of teams and their access permissions for the specified repository.
+ *
+ * @param repository
+ * @return a list of Team-AccessPermission tuples
+ */
+ public List<RegistrantAccessPermission> getTeamAccessPermissions(RepositoryModel repository) {
+ List<RegistrantAccessPermission> permissions = new ArrayList<RegistrantAccessPermission>();
+ for (String team : userService.getTeamnamesForRepositoryRole(repository.name)) {
+ AccessPermission ap = userService.getTeamModel(team).getRepositoryPermission(repository);
+ permissions.add(new RegistrantAccessPermission(team, ap, RegistrantType.TEAM));
+ }
+ return permissions;
+ }
+
+ /**
+ * Sets the access permissions to the specified repository for the specified teams.
+ *
+ * @param repository
+ * @param permissions
+ * @return true if the team models have been updated
+ */
+ public boolean setTeamAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) {
+ List<TeamModel> teams = new ArrayList<TeamModel>();
+ for (RegistrantAccessPermission tp : permissions) {
+ TeamModel team = userService.getTeamModel(tp.registrant);
+ team.setRepositoryPermission(repository.name, tp.permission);
+ teams.add(team);
+ }
+ return userService.updateTeamModels(teams);
+ }
+
+ /**
+ * Returns the list of all teams who have an explicit access permission for
+ * the specified repository.
*
* @see IUserService.getTeamnamesForRepositoryRole(String)
* @param repository
- * @return list of all teamnames that can bypass the access restriction
+ * @return list of all teamnames with explicit access permissions to the repository
*/
public List<String> getRepositoryTeams(RepositoryModel repository) {
return userService.getTeamnamesForRepositoryRole(repository.name);
@@ -699,8 +816,11 @@
* @param teamnames
* @return true if successful
*/
+ @Deprecated
public boolean setRepositoryTeams(RepositoryModel repository, List<String> repositoryTeams) {
- return userService.setTeamnamesForRepositoryRole(repository.name, repositoryTeams);
+ // rejects all changes since 1.2.0 because this would elevate
+ // all discrete access permissions to RW+
+ return false;
}
/**
@@ -957,14 +1077,13 @@
if (model == null) {
return null;
}
- if (model.accessRestriction.atLeast(AccessRestrictionType.VIEW)) {
- if (user != null && user.canAccessRepository(model)) {
- return model;
- }
- return null;
- } else {
+ if (user == null) {
+ user = UserModel.ANONYMOUS;
+ }
+ if (user.canView(model)) {
return model;
}
+ return null;
}
/**
@@ -1224,11 +1343,7 @@
}
model.hasCommits = JGitUtils.hasCommits(r);
model.lastChange = JGitUtils.getLastChange(r);
- if (repositoryName.indexOf('/') == -1) {
- model.projectPath = "";
- } else {
- model.projectPath = repositoryName.substring(0, repositoryName.indexOf('/'));
- }
+ model.projectPath = StringUtils.getFirstPathElement(repositoryName);
StoredConfig config = r.getConfig();
boolean hasOrigin = !StringUtils.isEmpty(config.getString("remote", "origin", "url"));
@@ -1243,6 +1358,7 @@
"accessRestriction", settings.getString(Keys.git.defaultAccessRestriction, null)));
model.authorizationControl = AuthorizationControl.fromName(getConfig(config,
"authorizationControl", settings.getString(Keys.git.defaultAuthorizationControl, null)));
+ model.verifyCommitter = getConfig(config, "verifyCommitter", false);
model.showRemoteBranches = getConfig(config, "showRemoteBranches", hasOrigin);
model.isFrozen = getConfig(config, "isFrozen", false);
model.showReadme = getConfig(config, "showReadme", false);
@@ -1449,6 +1565,9 @@
*/
private void closeRepository(String repositoryName) {
Repository repository = getRepository(repositoryName);
+ if (repository == null) {
+ return;
+ }
RepositoryCache.close(repository);
// assume 2 uses in case reflection fails
@@ -1547,6 +1666,13 @@
public void updateRepositoryModel(String repositoryName, RepositoryModel repository,
boolean isCreate) throws GitBlitException {
Repository r = null;
+ String projectPath = StringUtils.getFirstPathElement(repository.name);
+ if (!StringUtils.isEmpty(projectPath)) {
+ if (projectPath.equalsIgnoreCase(getString(Keys.web.repositoryRootGroupName, "main"))) {
+ // strip leading group name
+ repository.name = repository.name.substring(projectPath.length() + 1);
+ }
+ }
if (isCreate) {
// ensure created repository name ends with .git
if (!repository.name.toLowerCase().endsWith(org.eclipse.jgit.lib.Constants.DOT_GIT_EXT)) {
@@ -1614,6 +1740,14 @@
rf.close();
}
}
+
+ // remove this repository from any origin model's fork list
+ if (!StringUtils.isEmpty(repository.originRepository)) {
+ RepositoryModel origin = repositoryListCache.get(repository.originRepository);
+ if (origin != null && !ArrayUtils.isEmpty(origin.forks)) {
+ origin.forks.remove(repositoryName);
+ }
+ }
// clear the cache
clearRepositoryMetadataCache(repositoryName);
@@ -1666,6 +1800,7 @@
config.setBoolean(Constants.CONFIG_GITBLIT, null, "allowForks", repository.allowForks);
config.setString(Constants.CONFIG_GITBLIT, null, "accessRestriction", repository.accessRestriction.name());
config.setString(Constants.CONFIG_GITBLIT, null, "authorizationControl", repository.authorizationControl.name());
+ config.setBoolean(Constants.CONFIG_GITBLIT, null, "verifyCommitter", repository.verifyCommitter);
config.setBoolean(Constants.CONFIG_GITBLIT, null, "showRemoteBranches", repository.showRemoteBranches);
config.setBoolean(Constants.CONFIG_GITBLIT, null, "isFrozen", repository.isFrozen);
config.setBoolean(Constants.CONFIG_GITBLIT, null, "showReadme", repository.showReadme);
@@ -1741,7 +1876,7 @@
clearRepositoryMetadataCache(repositoryName);
RepositoryModel model = removeFromCachedRepositoryList(repositoryName);
- if (!ArrayUtils.isEmpty(model.forks)) {
+ if (model != null && !ArrayUtils.isEmpty(model.forks)) {
resetRepositoryListCache();
}
@@ -2393,10 +2528,11 @@
* Parse the properties file and aggregate all the comments by the setting
* key. A setting model tracks the current value, the default value, the
* description of the setting and and directives about the setting.
+ * @param referencePropertiesInputStream
*
* @return Map<String, SettingModel>
*/
- private ServerSettings loadSettingModels() {
+ private ServerSettings loadSettingModels(InputStream referencePropertiesInputStream) {
ServerSettings settingsModel = new ServerSettings();
settingsModel.supportsCredentialChanges = userService.supportsCredentialChanges();
settingsModel.supportsDisplayNameChanges = userService.supportsDisplayNameChanges();
@@ -2406,7 +2542,7 @@
// Read bundled Gitblit properties to extract setting descriptions.
// This copy is pristine and only used for populating the setting
// models map.
- InputStream is = servletContext.getResourceAsStream("/WEB-INF/reference.properties");
+ InputStream is = referencePropertiesInputStream;
BufferedReader propertiesReader = new BufferedReader(new InputStreamReader(is));
StringBuilder description = new StringBuilder();
SettingModel setting = new SettingModel();
@@ -2484,21 +2620,23 @@
logTimezone(Constants.NAME, getTimezone());
serverStatus = new ServerStatus(isGO());
- String realm = settings.getString(Keys.realm.userService, "users.properties");
- IUserService loginService = null;
- try {
- // check to see if this "file" is a login service class
- Class<?> realmClass = Class.forName(realm);
- loginService = (IUserService) realmClass.newInstance();
- } catch (Throwable t) {
- loginService = new GitblitUserService();
+
+ if (this.userService == null) {
+ String realm = settings.getString(Keys.realm.userService, "users.properties");
+ IUserService loginService = null;
+ try {
+ // check to see if this "file" is a login service class
+ Class<?> realmClass = Class.forName(realm);
+ loginService = (IUserService) realmClass.newInstance();
+ } catch (Throwable t) {
+ loginService = new GitblitUserService();
+ }
+ setUserService(loginService);
}
- setUserService(loginService);
// load and cache the project metadata
projectConfigs = new FileBasedConfig(getFileOrFolder(Keys.web.projectsFile, "projects.conf"), FS.detect());
getProjectConfigs();
-
mailExecutor = new MailExecutor(settings);
if (mailExecutor.isReady()) {
logger.info("Mail executor is scheduled to process the message queue every 2 minutes.");
@@ -2553,6 +2691,10 @@
*/
@Override
public void contextInitialized(ServletContextEvent contextEvent) {
+ contextInitialized(contextEvent, contextEvent.getServletContext().getResourceAsStream("/WEB-INF/reference.properties"));
+ }
+
+ public void contextInitialized(ServletContextEvent contextEvent, InputStream referencePropertiesInputStream) {
servletContext = contextEvent.getServletContext();
if (settings == null) {
// Gitblit WAR is running in a servlet container
@@ -2593,7 +2735,7 @@
}
}
- settingsModel = loadSettingModels();
+ settingsModel = loadSettingModels(referencePropertiesInputStream);
serverStatus.servletContainer = servletContext.getServerInfo();
}
@@ -2631,29 +2773,59 @@
// create a Gitblit repository model for the clone
RepositoryModel cloneModel = repository.cloneAs(cloneName);
+ // owner has REWIND/RW+ permissions
cloneModel.owner = user.username;
updateRepositoryModel(cloneName, cloneModel, false);
- if (AuthorizationControl.NAMED.equals(cloneModel.authorizationControl)) {
- // add the owner of the source repository to the clone's access list
- if (!StringUtils.isEmpty(repository.owner)) {
- UserModel owner = getUserModel(repository.owner);
- if (owner != null) {
- owner.repositories.add(cloneName);
- updateUserModel(owner.username, owner, false);
- }
+ // add the owner of the source repository to the clone's access list
+ if (!StringUtils.isEmpty(repository.owner)) {
+ UserModel originOwner = getUserModel(repository.owner);
+ if (originOwner != null) {
+ originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE);
+ updateUserModel(originOwner.username, originOwner, false);
}
-
- // inherit origin's access lists
- List<String> users = getRepositoryUsers(repository);
- setRepositoryUsers(cloneModel, users);
-
- List<String> teams = getRepositoryTeams(repository);
- setRepositoryTeams(cloneModel, teams);
}
+
+ // grant origin's user list clone permission to fork
+ List<String> users = getRepositoryUsers(repository);
+ List<UserModel> cloneUsers = new ArrayList<UserModel>();
+ for (String name : users) {
+ if (!name.equalsIgnoreCase(user.username)) {
+ UserModel cloneUser = getUserModel(name);
+ if (cloneUser.canClone(repository)) {
+ // origin user can clone origin, grant clone access to fork
+ cloneUser.setRepositoryPermission(cloneName, AccessPermission.CLONE);
+ }
+ cloneUsers.add(cloneUser);
+ }
+ }
+ userService.updateUserModels(cloneUsers);
+
+ // grant origin's team list clone permission to fork
+ List<String> teams = getRepositoryTeams(repository);
+ List<TeamModel> cloneTeams = new ArrayList<TeamModel>();
+ for (String name : teams) {
+ TeamModel cloneTeam = getTeamModel(name);
+ if (cloneTeam.canClone(repository)) {
+ // origin team can clone origin, grant clone access to fork
+ cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE);
+ }
+ cloneTeams.add(cloneTeam);
+ }
+ userService.updateTeamModels(cloneTeams);
// add this clone to the cached model
addToCachedRepositoryList(cloneModel);
return cloneModel;
}
+
+ /**
+ * Allow to understand if GitBlit supports and is configured to allow
+ * cookie-based authentication.
+ *
+ * @return status of Cookie authentication enablement.
+ */
+ public boolean allowCookieAuthentication() {
+ return GitBlit.getBoolean(Keys.web.allowCookieAuthentication, true) && userService.supportsCookies();
+ }
}
--
Gitblit v1.9.1