Allow to get/set blocked usernames from REST and WebUI
Change-Id: I4e1f5226e23e876002e3342ac2dd4e6ba8eb1313
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
index 43afe00..8ec538b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
@@ -22,6 +22,9 @@
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.inject.Inject;
+import java.util.Arrays;
+import java.util.List;
+
public class GetConfig implements RestReadView<ConfigResource> {
private final PluginConfig cfg;
@@ -40,6 +43,9 @@
info.allowEmail = toBoolean(cfg.getBoolean("allowEmail", false));
info.createNotes = toBoolean(cfg.getBoolean("createNotes", true));
info.createNotesAsync = toBoolean(cfg.getBoolean("createNotesAsync", false));
+ String[] blocked = cfg.getStringList("block");
+ Arrays.sort(blocked);
+ info.blockedNames = Arrays.asList(blocked);
return info;
}
@@ -48,10 +54,11 @@
}
public class ConfigInfo {
- String info;
- String onSuccess;
- Boolean allowEmail;
- Boolean createNotes;
- Boolean createNotesAsync;
+ public String info;
+ public String onSuccess;
+ public Boolean allowEmail;
+ public Boolean createNotes;
+ public Boolean createNotesAsync;
+ public List<String> blockedNames;
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutConfig.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutConfig.java
index 524afb8..92694c5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutConfig.java
@@ -33,6 +33,7 @@
import org.eclipse.jgit.util.FS;
import java.io.IOException;
+import java.util.List;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
public class PutConfig implements RestModifyView<ConfigResource, Input>{
@@ -42,6 +43,7 @@
public Boolean allowEmail;
public Boolean createNotes;
public Boolean createNotesAsync;
+ public List<String> blockedNames;
}
private final PluginConfigFactory cfgFactory;
@@ -79,6 +81,9 @@
if (input.createNotesAsync != null) {
setBoolean(cfg, "createNotesAsync", input.createNotesAsync);
}
+ if (input.blockedNames != null) {
+ cfg.setStringList("plugin", pluginName, "block", input.blockedNames);
+ }
cfg.save();
cfgFactory.getFromGerritConfig(pluginName, true);
return Response.<String> ok("OK");
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ConfigInfo.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ConfigInfo.java
index ae81ca4..197cdae 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ConfigInfo.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ConfigInfo.java
@@ -15,6 +15,9 @@
package com.googlesource.gerrit.plugins.serviceuser.client;
import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
+
+import java.util.List;
public class ConfigInfo extends JavaScriptObject {
final native String getInfoMessage() /*-{ return this.info }-*/;
@@ -22,6 +25,7 @@
final native boolean getAllowEmail() /*-{ return this.allow_email ? true : false; }-*/;
final native boolean getCreateNotes() /*-{ return this.create_notes ? true : false; }-*/;
final native boolean getCreateNotesAsync() /*-{ return this.create_notes_async ? true : false; }-*/;
+ final native JsArrayString getBlockedNames() /*-{ return this.blocked_names; }-*/;
final native void setInfoMessage(String s) /*-{ this.info = s; }-*/;
final native void setOnSuccessMessage(String s) /*-{ this.on_success = s; }-*/;
@@ -29,6 +33,17 @@
final native void setCreateNotes(boolean s) /*-{ this.create_notes = s; }-*/;
final native void setCreateNotesAsync(boolean s) /*-{ this.create_notes_async = s; }-*/;
+ final void setBlockedNames(List<String> blockedNames) {
+ initBlockedNames();
+ for (String n : blockedNames) {
+ addBlockedName(n);
+ }
+
+ }
+
+ final native void initBlockedNames() /*-{ this.blocked_names = []; }-*/;
+ final native void addBlockedName(String n) /*-{ this.blocked_names.push(n); }-*/;
+
static ConfigInfo create() {
ConfigInfo g = (ConfigInfo) createObject();
return g;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserSettingsScreen.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserSettingsScreen.java
index d142154..7d2fc98 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserSettingsScreen.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserSettingsScreen.java
@@ -48,6 +48,7 @@
private CheckBox allowEmailCheckBox;
private CheckBox createNotesCheckBox;
private CheckBox createNotesAsyncCheckBox;
+ private StringListPanel blockedUsernamesPanel;
private Button saveButton;
ServiceUserSettingsScreen() {
@@ -157,9 +158,6 @@
}
});
- HorizontalPanel buttons = new HorizontalPanel();
- add(buttons);
-
saveButton = new Button("Save");
saveButton.addStyleName("serviceuser-saveButton");
saveButton.addClickHandler(new ClickHandler() {
@@ -168,6 +166,15 @@
doSave();
}
});
+
+ blockedUsernamesPanel =
+ new StringListPanel("Blocked Usernames", "Username",
+ info.getBlockedNames(), saveButton);
+ add(blockedUsernamesPanel);
+
+ HorizontalPanel buttons = new HorizontalPanel();
+ add(buttons);
+
buttons.add(saveButton);
saveButton.setEnabled(false);
OnEditEnabler onEditEnabler = new OnEditEnabler(saveButton, infoMsgTxt);
@@ -189,6 +196,7 @@
if (createNotesAsyncCheckBox.isEnabled()) {
in.setCreateNotesAsync(createNotesAsyncCheckBox.getValue());
}
+ in.setBlockedNames(blockedUsernamesPanel.getValues());
new RestApi("config").id("server").view(Plugin.get().getPluginName(), "config")
.put(in, new AsyncCallback<JavaScriptObject>() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/StringListPanel.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/StringListPanel.java
new file mode 100644
index 0000000..27ca410
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/StringListPanel.java
@@ -0,0 +1,182 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.serviceuser.client;
+
+import com.google.gerrit.client.rpc.Natives;
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.dom.client.KeyPressHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FocusWidget;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwtexpui.globalkey.client.NpTextBox;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StringListPanel extends FlowPanel {
+ private final NpTextBox input;
+ private final StringListTable t;
+ private final Button deleteButton;
+
+ StringListPanel(String title, String fieldName, JsArrayString values,
+ final FocusWidget w) {
+ Label titleLabel = new Label(title);
+ titleLabel.setStyleName("serviceuser-smallHeading");
+ add(titleLabel);
+ input = new NpTextBox();
+ input.addKeyPressHandler(new KeyPressHandler() {
+ @Override
+ public void onKeyPress(KeyPressEvent event) {
+ if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
+ w.setEnabled(true);
+ add();
+ }
+ }
+ });
+ HorizontalPanel p = new HorizontalPanel();
+ p.add(input);
+ Button addButton = new Button("Add");
+ addButton.setEnabled(false);
+ new OnEditEnabler(addButton, input);
+ addButton.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ w.setEnabled(true);
+ add();
+ }
+ });
+ p.add(addButton);
+ add(p);
+
+ t = new StringListTable(fieldName);
+ add(t);
+
+ deleteButton = new Button("Delete");
+ deleteButton.setEnabled(false);
+ add(deleteButton);
+ deleteButton.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ w.setEnabled(true);
+ t.deleteChecked();
+ }
+ });
+
+ t.display(values);
+ }
+
+ List<String> getValues() {
+ return t.getValues();
+ }
+
+ private void add() {
+ String v = input.getValue().trim();
+ if (!v.isEmpty()) {
+ input.setValue("");
+ t.insert(v);
+ }
+ }
+
+ private class StringListTable extends FlexTable {
+ StringListTable(String name) {
+ setStyleName("serviceuser-stringListTable");
+ FlexCellFormatter fmt = getFlexCellFormatter();
+ fmt.addStyleName(0, 0, "iconHeader");
+ fmt.addStyleName(0, 0, "topMostCell");
+ fmt.addStyleName(0, 0, "leftMostCell");
+ fmt.addStyleName(0, 1, "dataHeader");
+ fmt.addStyleName(0, 1, "topMostCell");
+
+ setText(0, 1, name);
+ }
+
+ void display(JsArrayString values) {
+ int row = 1;
+ for (String v : Natives.asList(values)) {
+ populate(row, v);
+ row++;
+ }
+ }
+
+ List<String> getValues() {
+ List<String> values = new ArrayList<String>();
+ for (int row = 1; row < getRowCount(); row++) {
+ values.add(getText(row, 1));
+ }
+ return values;
+ }
+
+ private void populate(int row, String value) {
+ FlexCellFormatter fmt = getFlexCellFormatter();
+ fmt.addStyleName(row, 0, "leftMostCell");
+ fmt.addStyleName(row, 0, "iconCell");
+ fmt.addStyleName(row, 1, "dataCell");
+
+ CheckBox checkBox = new CheckBox();
+ checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
+ @Override
+ public void onValueChange(ValueChangeEvent<Boolean> event) {
+ enableDelete();
+ }
+ });
+ setWidget(row, 0, checkBox);
+ setText(row, 1, value);
+ }
+
+ void insert(String v) {
+ int insertPos = getRowCount();
+ for (int row = 1; row < getRowCount(); row++) {
+ int compareResult = v.compareTo(getText(row, 1));
+ if (compareResult < 0) {
+ insertPos = row;
+ break;
+ } else if (compareResult == 0) {
+ return;
+ }
+ }
+ insertRow(insertPos);
+ populate(insertPos, v);
+ }
+
+ void enableDelete() {
+ for (int row = 1; row < getRowCount(); row++) {
+ if (((CheckBox) getWidget(row, 0)).getValue()) {
+ deleteButton.setEnabled(true);
+ return;
+ }
+ }
+ deleteButton.setEnabled(false);
+ }
+
+ void deleteChecked() {
+ deleteButton.setEnabled(false);
+ for (int row = 1; row < getRowCount(); row++) {
+ if (((CheckBox) getWidget(row, 0)).getValue()) {
+ removeRow(row--);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/public/serviceuser.css b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/public/serviceuser.css
index 7f70168..807b1be 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/public/serviceuser.css
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/public/serviceuser.css
@@ -7,23 +7,27 @@
}
.serviceuser-serviceUserTable,
-.serviceuser-sshKeyTable {
+.serviceuser-sshKeyTable,
+.serviceuser-stringListTable {
border-collapse: separate;
border-spacing: 0;
}
.serviceuser-serviceUserTable .leftMostCell,
-.serviceuser-sshKeyTable .leftMostCell {
+.serviceuser-sshKeyTable .leftMostCell,
+.serviceuser-stringListTable .leftMostCell {
border-left: 1px solid #EEE;
}
.serviceuser-serviceUserTable .topMostCell,
-.serviceuser-sshKeyTable .topMostCell {
+.serviceuser-sshKeyTable .topMostCell,
+.serviceuser-stringListTable .topMostCell {
border-top: 1px solid #EEE;
}
.serviceuser-serviceUserTable .dataHeader,
-.serviceuser-sshKeyTable .dataHeader {
+.serviceuser-sshKeyTable .dataHeader,
+.serviceuser-stringListTable .dataHeader {
border: 1px solid #FFF;
padding: 2px 6px 1px;
background-color: #EEE;
@@ -32,14 +36,16 @@
color: textColor;
}
-.serviceuser-sshKeyTable .iconHeader {
+.serviceuser-sshKeyTable .iconHeader,
+.serviceuser-stringListTable .iconHeader {
border-top: 1px solid #FFF;
border-bottom: 1px solid #FFF;
background-color: #EEE;
}
.serviceuser-serviceUserTable .dataCell,
-.serviceuser-sshKeyTable .dataCell {
+.serviceuser-sshKeyTable .dataCell,
+.serviceuser-stringListTable .dataCell {
padding-left: 5px;
padding-right: 5px;
border-right: 1px solid #EEE;
@@ -48,7 +54,8 @@
height: 20px;
}
-.serviceuser-sshKeyTable .iconCell {
+.serviceuser-sshKeyTable .iconCell,
+.serviceuser-stringListTable .iconCell {
width: 1px;
padding: 0px;
vertical-align: middle;
@@ -124,3 +131,8 @@
background: #BFC;
border-style: inset;
}
+
+.serviceuser-smallHeading {
+ margin-top: 5px;
+ font-weight: bold;
+}
diff --git a/src/main/resources/Documentation/rest-api-config.md b/src/main/resources/Documentation/rest-api-config.md
index f06090a..453299b 100644
--- a/src/main/resources/Documentation/rest-api-config.md
+++ b/src/main/resources/Documentation/rest-api-config.md
@@ -657,6 +657,8 @@
* _create\_notes\_async_: Whether the Git notes on commits that are
pushed by a service user should be created asynchronously (not set if
`false`).
+* _blocked\_names_: List of usernames which are forbidden to be used as
+ name for a service user. The blocked usernames are case insensitive.
### <a id="email-input"></a>EmailInput