From 87f6c3e6510986a6676872aa64aed66fe7f24b01 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Mon, 22 Oct 2012 16:15:40 -0400
Subject: [PATCH] Differentiate between an explicit permission and a regex permission

---
 src/com/gitblit/models/RegistrantAccessPermission.java        |    5 +
 src/com/gitblit/GitBlit.java                                  |   30 ++++++---
 src/com/gitblit/wicket/GitBlitWebApp.properties               |    1 
 src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java |   26 ++++++--
 src/com/gitblit/client/GitblitClient.java                     |   11 ++-
 src/com/gitblit/client/RegistrantPermissionsPanel.java        |   30 +++++++++
 tests/com/gitblit/tests/RpcTests.java                         |    4 
 src/com/gitblit/models/TeamModel.java                         |   14 ++++
 src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html |    4 
 src/com/gitblit/client/RegistrantPermissionsTableModel.java   |   18 +++++
 src/com/gitblit/models/UserModel.java                         |   14 ++++
 11 files changed, 128 insertions(+), 29 deletions(-)

diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java
index ce556b6..e83da93 100644
--- a/src/com/gitblit/GitBlit.java
+++ b/src/com/gitblit/GitBlit.java
@@ -640,8 +640,10 @@
 	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));
+			UserModel model = userService.getUserModel(user);
+			AccessPermission ap = model.getRepositoryPermission(repository);
+			boolean isExplicit = model.hasExplicitRepositoryPermission(repository.name);
+			permissions.add(new RegistrantAccessPermission(user, ap, isExplicit, RegistrantType.USER));
 		}
 		return permissions;
 	}
@@ -656,9 +658,12 @@
 	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);
+			if (up.isExplicit) {
+				// only set explicitly defined permissions
+				UserModel user = userService.getUserModel(up.registrant);
+				user.setRepositoryPermission(repository.name, up.permission);
+				users.add(user);
+			}
 		}
 		return userService.updateUserModels(users);
 	}
@@ -772,8 +777,10 @@
 	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));
+			TeamModel model = userService.getTeamModel(team);
+			AccessPermission ap = model.getRepositoryPermission(repository);
+			boolean isExplicit = model.hasExplicitRepositoryPermission(repository.name);
+			permissions.add(new RegistrantAccessPermission(team, ap, isExplicit, RegistrantType.TEAM));
 		}
 		return permissions;
 	}
@@ -788,9 +795,12 @@
 	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);
+			if (tp.isExplicit) {
+				// only set explicitly defined access permissions
+				TeamModel team = userService.getTeamModel(tp.registrant);
+				team.setRepositoryPermission(repository.name, tp.permission);
+				teams.add(team);
+			}
 		}
 		return userService.updateTeamModels(teams);
 	}
diff --git a/src/com/gitblit/client/GitblitClient.java b/src/com/gitblit/client/GitblitClient.java
index 9e31c79..4620fef 100644
--- a/src/com/gitblit/client/GitblitClient.java
+++ b/src/com/gitblit/client/GitblitClient.java
@@ -28,6 +28,7 @@
 import java.util.TreeSet;
 
 import com.gitblit.Constants;
+import com.gitblit.Constants.AccessPermission;
 import com.gitblit.Constants.AccessRestrictionType;
 import com.gitblit.Constants.AuthorizationControl;
 import com.gitblit.Constants.RegistrantType;
@@ -36,10 +37,10 @@
 import com.gitblit.GitBlitException.UnauthorizedException;
 import com.gitblit.GitBlitException.UnknownRequestException;
 import com.gitblit.Keys;
-import com.gitblit.models.RegistrantAccessPermission;
 import com.gitblit.models.FederationModel;
 import com.gitblit.models.FeedEntryModel;
 import com.gitblit.models.FeedModel;
+import com.gitblit.models.RegistrantAccessPermission;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.ServerSettings;
 import com.gitblit.models.ServerStatus;
@@ -498,7 +499,9 @@
 		List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>();
 		for (UserModel user : allUsers) {
 			if (user.hasRepositoryPermission(repository.name)) {
-				list.add(new RegistrantAccessPermission(user.username, user.permissions.get(repository.name), RegistrantType.USER));
+				AccessPermission ap = user.getRepositoryPermission(repository);
+				boolean isExplicit = user.hasExplicitRepositoryPermission(repository.name);
+				list.add(new RegistrantAccessPermission(user.username, ap, isExplicit, RegistrantType.USER));
 			}
 		}
 		return list;
@@ -535,7 +538,9 @@
 		List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>();
 		for (TeamModel team : allTeams) {
 			if (team.hasRepositoryPermission(repository.name)) {
-				list.add(new RegistrantAccessPermission(team.name, team.permissions.get(repository.name), RegistrantType.TEAM));
+				AccessPermission ap = team.getRepositoryPermission(repository);
+				boolean isExplicit = team.hasExplicitRepositoryPermission(repository.name);
+				list.add(new RegistrantAccessPermission(team.name, ap, isExplicit, RegistrantType.TEAM));
 			}
 		}
 		return list;
diff --git a/src/com/gitblit/client/RegistrantPermissionsPanel.java b/src/com/gitblit/client/RegistrantPermissionsPanel.java
index fa7ff5a..4ea173f 100644
--- a/src/com/gitblit/client/RegistrantPermissionsPanel.java
+++ b/src/com/gitblit/client/RegistrantPermissionsPanel.java
@@ -29,6 +29,8 @@
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTable;
+import javax.swing.SwingConstants;
+import javax.swing.table.DefaultTableCellRenderer;
 
 import com.gitblit.Constants.AccessPermission;
 import com.gitblit.models.RegistrantAccessPermission;
@@ -59,8 +61,10 @@
 		JScrollPane jsp = new JScrollPane(permissionsTable);
 		add(jsp, BorderLayout.CENTER);
 		
+		permissionsTable.getColumnModel().getColumn(RegistrantPermissionsTableModel.Columns.Type.ordinal())
+				.setCellRenderer(new RegexRenderer());
 		permissionsTable.getColumnModel().getColumn(RegistrantPermissionsTableModel.Columns.Permission.ordinal())
-				.setCellEditor(new AccessPermissionEditor());
+		.setCellEditor(new AccessPermissionEditor());
 		
 		registrantModel = new DefaultComboBoxModel();
 		registrantSelector = new JComboBox(registrantModel);
@@ -137,4 +141,28 @@
 	        super(new JComboBox(AccessPermission.values()));
 	    }
 	}
+	
+	private class RegexRenderer extends DefaultTableCellRenderer {
+
+		private static final long serialVersionUID = 1L;
+
+		public RegexRenderer() {
+			super();
+			setHorizontalAlignment(SwingConstants.CENTER);
+		}
+
+		@Override
+		protected void setValue(Object value) {
+			boolean isExplicit = (Boolean) value;
+			if (isExplicit) {
+				// explicit permission
+				setText("");
+				setToolTipText(null);
+			} else {
+				// regex matched permission
+				setText("regex");
+				setToolTipText(Translation.get("gb.regexPermission"));
+			}
+		}
+	}
 }
diff --git a/src/com/gitblit/client/RegistrantPermissionsTableModel.java b/src/com/gitblit/client/RegistrantPermissionsTableModel.java
index 91acec8..fcd9c8b 100644
--- a/src/com/gitblit/client/RegistrantPermissionsTableModel.java
+++ b/src/com/gitblit/client/RegistrantPermissionsTableModel.java
@@ -36,7 +36,7 @@
 	List<RegistrantAccessPermission> permissions;
 
 	enum Columns {
-		Registrant, Permission;
+		Registrant, Type, Permission;
 
 		@Override
 		public String toString() {
@@ -72,6 +72,8 @@
 		switch (col) {
 		case Registrant:
 			return Translation.get("gb.name");
+		case Type:
+			return Translation.get("gb.type");
 		case Permission:
 			return Translation.get("gb.permission");
 		}
@@ -88,13 +90,23 @@
 	public Class<?> getColumnClass(int columnIndex) {
 		if (columnIndex == Columns.Permission.ordinal()) {
 			return AccessPermission.class;
+		} else if (columnIndex == Columns.Type.ordinal()) {
+			return Boolean.class;
 		}
 		return String.class;
 	}
 	
 	@Override
 	public boolean isCellEditable(int rowIndex, int columnIndex) {
-		return columnIndex == Columns.Permission.ordinal();
+		if (columnIndex == Columns.Permission.ordinal()) {
+			// in order for the permission to be editable it must be
+			// explicitly defined on the object.  regex permissions are inherited
+			// and therefore can not be directly manipulated unless the current
+			// object is the source of the regex (i.e. a user or team with explicit
+			// regex definition)
+			return permissions.get(rowIndex).isExplicit;
+		}
+		return false;
 	}
 
 	@Override
@@ -104,6 +116,8 @@
 		switch (col) {
 		case Registrant:
 			return rp.registrant;
+		case Type:
+			return rp.isExplicit;
 		case Permission:
 			return rp.permission;
 		}
diff --git a/src/com/gitblit/models/RegistrantAccessPermission.java b/src/com/gitblit/models/RegistrantAccessPermission.java
index 9302745..4a560d4 100644
--- a/src/com/gitblit/models/RegistrantAccessPermission.java
+++ b/src/com/gitblit/models/RegistrantAccessPermission.java
@@ -33,13 +33,16 @@
 	public String registrant;
 	public AccessPermission permission;
 	public RegistrantType type;
+	public boolean isExplicit;
 
 	public RegistrantAccessPermission() {
+		isExplicit = true;
 	}
 	
-	public RegistrantAccessPermission(String registrant, AccessPermission permission, RegistrantType type) {
+	public RegistrantAccessPermission(String registrant, AccessPermission permission, boolean isExplicit, RegistrantType type) {
 		this.registrant = registrant;
 		this.permission = permission;
+		this.isExplicit = isExplicit;
 		this.type = type;
 	}
 	
diff --git a/src/com/gitblit/models/TeamModel.java b/src/com/gitblit/models/TeamModel.java
index 4c3a842..9ba2f66 100644
--- a/src/com/gitblit/models/TeamModel.java
+++ b/src/com/gitblit/models/TeamModel.java
@@ -97,7 +97,7 @@
 	public List<RegistrantAccessPermission> getRepositoryPermissions() {
 		List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>();
 		for (Map.Entry<String, AccessPermission> entry : permissions.entrySet()) {
-			list.add(new RegistrantAccessPermission(entry.getKey(), entry.getValue(), RegistrantType.REPOSITORY));
+			list.add(new RegistrantAccessPermission(entry.getKey(), entry.getValue(), true, RegistrantType.REPOSITORY));
 		}
 		Collections.sort(list);
 		return list;
@@ -130,6 +130,18 @@
 	}
 	
 	/**
+	 * Returns true if the team has an explicitly specified access permission for
+	 * this repository.
+	 * 
+	 * @param name
+	 * @return if the team has an explicitly specified access permission
+	 */
+	public boolean hasExplicitRepositoryPermission(String name) {
+		String repository = AccessPermission.repositoryFromRole(name).toLowerCase();
+		return permissions.containsKey(repository);
+	}
+	
+	/**
 	 * Adds a repository permission to the team.
 	 * <p>
 	 * Role may be formatted as:
diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java
index 7733704..97430bf 100644
--- a/src/com/gitblit/models/UserModel.java
+++ b/src/com/gitblit/models/UserModel.java
@@ -137,7 +137,7 @@
 	public List<RegistrantAccessPermission> getRepositoryPermissions() {
 		List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>();
 		for (Map.Entry<String, AccessPermission> entry : permissions.entrySet()) {
-			list.add(new RegistrantAccessPermission(entry.getKey(), entry.getValue(), RegistrantType.REPOSITORY));
+			list.add(new RegistrantAccessPermission(entry.getKey(), entry.getValue(), true, RegistrantType.REPOSITORY));
 		}
 		Collections.sort(list);
 		return list;
@@ -170,6 +170,18 @@
 	}
 	
 	/**
+	 * Returns true if the user has an explicitly specified access permission for
+	 * this repository.
+	 * 
+	 * @param name
+	 * @return if the user has an explicitly specified access permission
+	 */
+	public boolean hasExplicitRepositoryPermission(String name) {
+		String repository = AccessPermission.repositoryFromRole(name).toLowerCase();
+		return permissions.containsKey(repository);
+	}
+	
+	/**
 	 * Adds a repository permission to the team.
 	 * <p>
 	 * Role may be formatted as:
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties
index bdeb4a9..41cbdd4 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -356,3 +356,4 @@
 gb.deletePermission = {0} (push, ref creation+deletion)
 gb.rewindPermission = {0} (push, ref creation+deletion+rewind)
 gb.permission = permission
+gb.regexPermission = this permission is set from a regular expression
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html
index dd76d9f..f5da1c6 100644
--- a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html
+++ b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html
@@ -8,8 +8,8 @@
 <wicket:panel>
 
 	<div wicket:id="permissionRow">
-		<div style="padding-top:10px" class="row-fluid">
-			<span class="span8" wicket:id="registrant"></span> <select class="input-medium" wicket:id="permission"></select>
+		<div style="padding-top:10px;border-left:1px solid #ccc;border-right:1px solid #ccc;" class="row-fluid">
+			<div style="padding-top:5px;padding-left:5px;" class="span6" wicket:id="registrant"></div><div style="padding-top:5px;" class="span2"><span class="label label-info" wicket:id="regex">[regex]</span></div> <select class="input-medium" wicket:id="permission"></select>
 		</div>
 	</div>
 
diff --git a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java
index 936659d..9dee2f2 100644
--- a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java
+++ b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java
@@ -38,6 +38,7 @@
 import com.gitblit.Constants.AccessPermission;
 import com.gitblit.models.RegistrantAccessPermission;
 import com.gitblit.utils.DeepCopier;
+import com.gitblit.wicket.WicketUtils;
 
 /**
  * Allows user to manipulate registrant access permissions.
@@ -78,20 +79,33 @@
 			public void populateItem(final Item<RegistrantAccessPermission> item) {
 				final RegistrantAccessPermission entry = item.getModelObject();
 				item.add(new Label("registrant", entry.registrant));
+				if (entry.isExplicit) {
+					item.add(new Label("regex", "").setVisible(false));
+				} else {
+					Label regex = new Label("regex", "regex");
+					WicketUtils.setHtmlTooltip(regex, getString("gb.regexPermission"));
+					item.add(regex);
+				}
 
 				// use ajax to get immediate update of permission level change
 				// otherwise we can lose it if they change levels and then add
 				// a new repository permission
 				final DropDownChoice<AccessPermission> permissionChoice = new DropDownChoice<AccessPermission>(
 						"permission", Arrays.asList(AccessPermission.values()), new AccessPermissionRenderer(translations));
-				permissionChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") {
+				// only allow changing an explicitly defined permission
+				// this is designed to prevent changing a regex permission in
+				// a repository
+				permissionChoice.setEnabled(entry.isExplicit);
+				if (entry.isExplicit) {
+					permissionChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") {
 		           
-					private static final long serialVersionUID = 1L;
+						private static final long serialVersionUID = 1L;
 
-					protected void onUpdate(AjaxRequestTarget target) {
-		                target.addComponent(permissionChoice);
-		            }
-		        });
+						protected void onUpdate(AjaxRequestTarget target) {
+							target.addComponent(permissionChoice);
+						}
+					});
+				}
 
 				item.add(permissionChoice);
 			}
diff --git a/tests/com/gitblit/tests/RpcTests.java b/tests/com/gitblit/tests/RpcTests.java
index c739eba..0be2e02 100644
--- a/tests/com/gitblit/tests/RpcTests.java
+++ b/tests/com/gitblit/tests/RpcTests.java
@@ -199,7 +199,7 @@
 		List<RegistrantAccessPermission> permissions = RpcUtils.getRepositoryMemberPermissions(retrievedRepository, url, account,
 				password.toCharArray());
 		assertEquals("Membership permissions is not empty!", 0, permissions.size());
-		permissions.add(new RegistrantAccessPermission(testMember.username, AccessPermission.PUSH, RegistrantType.USER));
+		permissions.add(new RegistrantAccessPermission(testMember.username, AccessPermission.PUSH, true, RegistrantType.USER));
 		assertTrue(
 				"Failed to set member permissions!",
 				RpcUtils.setRepositoryMemberPermissions(retrievedRepository, permissions, url, account,
@@ -288,7 +288,7 @@
 		// set no teams
 		List<RegistrantAccessPermission> permissions = new ArrayList<RegistrantAccessPermission>();
 		for (String team : helloworldTeams) {
-			permissions.add(new RegistrantAccessPermission(team, AccessPermission.NONE, RegistrantType.TEAM));
+			permissions.add(new RegistrantAccessPermission(team, AccessPermission.NONE, true, RegistrantType.TEAM));
 		}
 		assertTrue(RpcUtils.setRepositoryTeamPermissions(helloworld, permissions, url, account,
 				password.toCharArray()));

--
Gitblit v1.9.1