From b461a45f420471f931029898d97464ecc5039f49 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Sat, 22 Dec 2012 00:27:04 -0500
Subject: [PATCH] Do not pass null email address to PersonIdent

---
 src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java |  202 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 180 insertions(+), 22 deletions(-)

diff --git a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java
index b6ed890..4156cd1 100644
--- a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java
+++ b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java
@@ -15,12 +15,15 @@
  */
 package com.gitblit.wicket.panels;
 
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 import org.apache.wicket.ajax.markup.html.form.AjaxButton;
@@ -28,16 +31,21 @@
 import org.apache.wicket.markup.html.form.DropDownChoice;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.markup.html.panel.Fragment;
 import org.apache.wicket.markup.repeater.Item;
 import org.apache.wicket.markup.repeater.OddEvenItem;
 import org.apache.wicket.markup.repeater.RefreshingView;
 import org.apache.wicket.markup.repeater.util.ModelIteratorAdapter;
 import org.apache.wicket.model.CompoundPropertyModel;
 import org.apache.wicket.model.IModel;
+import org.eclipse.jgit.lib.PersonIdent;
 
 import com.gitblit.Constants.AccessPermission;
+import com.gitblit.Constants.PermissionType;
 import com.gitblit.Constants.RegistrantType;
+import com.gitblit.GitBlit;
 import com.gitblit.models.RegistrantAccessPermission;
+import com.gitblit.models.UserModel;
 import com.gitblit.utils.DeepCopier;
 import com.gitblit.utils.StringUtils;
 import com.gitblit.wicket.WicketUtils;
@@ -51,11 +59,42 @@
 public class RegistrantPermissionsPanel extends BasePanel {
 
 	private static final long serialVersionUID = 1L;
-
-	public RegistrantPermissionsPanel(String wicketId, List<String> allRegistrants, final List<RegistrantAccessPermission> permissions, final Map<AccessPermission, String> translations) {
-		super(wicketId);
+	
+	public enum Show {
+		specified, mutable, effective;
 		
-		// update existing permissions repeater
+		public boolean show(RegistrantAccessPermission ap) {
+			switch (this) {
+			case specified:
+				return ap.mutable || ap.isOwner();
+			case mutable:
+				return ap.mutable;
+			case effective:
+				return true;
+			default:
+				return true;
+			}
+		}
+	}
+	
+	private Show activeState = Show.mutable;
+	
+	public RegistrantPermissionsPanel(String wicketId, RegistrantType registrantType, List<String> allRegistrants, final List<RegistrantAccessPermission> permissions, final Map<AccessPermission, String> translations) {
+		super(wicketId);
+		setOutputMarkupId(true);
+
+		/*
+		 * Permission view toggle buttons
+		 */
+		Form<Void> permissionToggleForm = new Form<Void>("permissionToggleForm");
+		permissionToggleForm.add(new ShowStateButton("showSpecified", Show.specified));
+		permissionToggleForm.add(new ShowStateButton("showMutable", Show.mutable));
+		permissionToggleForm.add(new ShowStateButton("showEffective", Show.effective));
+		add(permissionToggleForm);
+
+		/*
+		 * Permission repeating display
+		 */
 		RefreshingView<RegistrantAccessPermission> dataView = new RefreshingView<RegistrantAccessPermission>("permissionRow") {
 			private static final long serialVersionUID = 1L;
 		
@@ -80,23 +119,83 @@
             
 			public void populateItem(final Item<RegistrantAccessPermission> item) {
 				final RegistrantAccessPermission entry = item.getModelObject();
-				if (RegistrantType.REPOSITORY.equals(entry.type)) {
-					// repository, strip .git and show swatch
+				if (RegistrantType.REPOSITORY.equals(entry.registrantType)) {
 					String repoName = StringUtils.stripDotGit(entry.registrant);
-					Label registrant = new Label("registrant", repoName);
-					WicketUtils.setCssClass(registrant, "repositorySwatch");
-					WicketUtils.setCssBackground(registrant, repoName);
-					item.add(registrant);
+					if (!entry.isMissing() && StringUtils.findInvalidCharacter(repoName) == null) {
+						// repository, strip .git and show swatch
+						Fragment repositoryFragment = new Fragment("registrant", "repositoryRegistrant", RegistrantPermissionsPanel.this);
+						Component swatch = new Label("repositorySwatch", "&nbsp;").setEscapeModelStrings(false);
+						WicketUtils.setCssBackground(swatch, entry.toString());
+						repositoryFragment.add(swatch);
+						Label registrant = new Label("repositoryName", repoName);
+						repositoryFragment.add(registrant);
+						item.add(repositoryFragment);
+					} else {
+						// regex or missing
+						Label label = new Label("registrant", entry.registrant);
+						WicketUtils.setCssStyle(label, "font-weight: bold;");
+						item.add(label);
+					}					
+				} else if (RegistrantType.USER.equals(entry.registrantType)) {
+					// user
+					PersonIdent ident = new PersonIdent(entry.registrant, "");
+					UserModel user = GitBlit.self().getUserModel(entry.registrant);
+					if (user != null) {
+						ident = new PersonIdent(user.getDisplayName(), user.emailAddress == null ? user.getDisplayName() : user.emailAddress);
+					}
+
+					Fragment userFragment = new Fragment("registrant", "userRegistrant", RegistrantPermissionsPanel.this);
+					userFragment.add(new GravatarImage("userAvatar", ident, 20, false));
+					userFragment.add(new Label("userName", entry.registrant));					
+					item.add(userFragment);					
 				} else {
-					item.add(new Label("registrant", entry.registrant));
+					// team
+					Fragment teamFragment = new Fragment("registrant", "teamRegistrant", RegistrantPermissionsPanel.this);
+					teamFragment.add(new Label("teamName", entry.registrant));
+					item.add(teamFragment);
 				}
-				if (entry.isExplicit) {
-					item.add(new Label("regex", "").setVisible(false));
-				} else {
-					Label regex = new Label("regex", "regex");
-					WicketUtils.setHtmlTooltip(regex, getString("gb.regexPermission"));
+				switch (entry.permissionType) {
+				case ADMINISTRATOR:
+					Label administrator = new Label("pType", entry.source == null ? getString("gb.administrator") : entry.source);
+					WicketUtils.setHtmlTooltip(administrator, getString("gb.administratorPermission"));
+					WicketUtils.setCssClass(administrator, "label label-inverse");
+					item.add(administrator);
+					break;
+				case OWNER:
+					Label owner = new Label("pType", getString("gb.owner"));
+					WicketUtils.setHtmlTooltip(owner, getString("gb.ownerPermission"));
+					WicketUtils.setCssClass(owner, "label label-info");
+					item.add(owner);
+					break;
+				case TEAM:
+					Label team = new Label("pType", entry.source == null ? getString("gb.team") : entry.source);
+					WicketUtils.setHtmlTooltip(team, MessageFormat.format(getString("gb.teamPermission"), entry.source));
+					WicketUtils.setCssClass(team, "label label-success");
+					item.add(team);
+					break;
+				case REGEX:
+					Label regex = new Label("pType", "regex");
+					if (!StringUtils.isEmpty(entry.source)) {
+						WicketUtils.setHtmlTooltip(regex, MessageFormat.format(getString("gb.regexPermission"), entry.source));
+					}
+					WicketUtils.setCssClass(regex, "label");
 					item.add(regex);
+					break;
+				default:
+					if (entry.isMissing()) {
+						// repository is missing, this permission will be removed on save
+						Label missing = new Label("pType", getString("gb.missing"));
+						WicketUtils.setCssClass(missing, "label label-important");
+						WicketUtils.setHtmlTooltip(missing, getString("gb.missingPermission"));
+						item.add(missing);
+					} else {
+						// standard permission
+						item.add(new Label("pType", "").setVisible(false));
+					}
+					break;
 				}
+
+				item.setVisible(activeState.show(entry));
 
 				// use ajax to get immediate update of permission level change
 				// otherwise we can lose it if they change levels and then add
@@ -106,8 +205,9 @@
 				// 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.setEnabled(entry.mutable);
+				permissionChoice.setOutputMarkupId(true);
+				if (entry.mutable) {
 					permissionChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") {
 		           
 						private static final long serialVersionUID = 1L;
@@ -127,11 +227,23 @@
 		// filter out registrants we already have permissions for
 		final List<String> registrants = new ArrayList<String>(allRegistrants);
 		for (RegistrantAccessPermission rp : permissions) {
-			registrants.remove(rp.registrant);
+			if (rp.mutable) {
+				// remove editable duplicates
+				// this allows for specifying an explicit permission
+				registrants.remove(rp.registrant);
+			} else if (rp.isAdmin()) {
+				// administrators can not have their permission changed
+				registrants.remove(rp.registrant);
+			} else if (rp.isOwner()) {
+				// owners can not have their permission changed
+				registrants.remove(rp.registrant);
+			}
 		}
 
-		// add new permission form
-		IModel<RegistrantAccessPermission> addPermissionModel = new CompoundPropertyModel<RegistrantAccessPermission>(new RegistrantAccessPermission());
+		/*
+		 * Add permission form
+		 */
+		IModel<RegistrantAccessPermission> addPermissionModel = new CompoundPropertyModel<RegistrantAccessPermission>(new RegistrantAccessPermission(registrantType));
 		Form<RegistrantAccessPermission> addPermissionForm = new Form<RegistrantAccessPermission>("addPermissionForm", addPermissionModel);
 		addPermissionForm.add(new DropDownChoice<String>("registrant", registrants));
 		addPermissionForm.add(new DropDownChoice<AccessPermission>("permission", Arrays
@@ -144,7 +256,18 @@
 			protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
 				// add permission to our list
 				RegistrantAccessPermission rp = (RegistrantAccessPermission) form.getModel().getObject();
-				permissions.add(DeepCopier.copy(rp));
+				if (rp.permission == null) {
+					return;
+				}
+				RegistrantAccessPermission copy = DeepCopier.copy(rp);
+				if (StringUtils.findInvalidCharacter(copy.registrant) != null) {
+					copy.permissionType = PermissionType.REGEX;
+					copy.source = copy.registrant;
+				}
+				permissions.add(copy);
+				
+				// resort permissions after insert to convey idea of eval order
+				Collections.sort(permissions);
 				
 				// remove registrant from available choices
 				registrants.remove(rp.registrant);
@@ -158,6 +281,12 @@
 		// only show add permission form if we have a registrant choice
 		add(addPermissionForm.setVisible(registrants.size() > 0));
 	}
+	
+	protected boolean getStatelessHint()
+	{
+		return false;
+	}
+
 	
 	private class AccessPermissionRenderer implements IChoiceRenderer<AccessPermission> {
 
@@ -179,4 +308,33 @@
 			return Integer.toString(index);
 		}
 	}
+	
+	private class ShowStateButton extends AjaxButton {
+		private static final long serialVersionUID = 1L;
+
+		Show buttonState;
+		
+		public ShowStateButton(String wicketId, Show state) {
+			super(wicketId);
+			this.buttonState = state;
+			setOutputMarkupId(true);
+		}
+		
+		@Override
+		protected void onBeforeRender()
+		{
+			String cssClass = "btn";
+			if (buttonState.equals(RegistrantPermissionsPanel.this.activeState)) {
+				cssClass = "btn btn-info active";
+			}
+			WicketUtils.setCssClass(this, cssClass);
+			super.onBeforeRender();
+		}
+		
+		@Override
+		protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
+			RegistrantPermissionsPanel.this.activeState = buttonState;
+			target.addComponent(RegistrantPermissionsPanel.this);
+		}
+	};
 }

--
Gitblit v1.9.1