Add screen to list service users
Change-Id: I268d75f1abd7f00d1b28df86319f7ad630d2fab3
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java
index 22a6077..74ac5ba 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java
@@ -19,6 +19,8 @@
import com.google.gerrit.extensions.webui.TopMenu;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.CapabilityControl;
+import com.google.gerrit.server.config.ConfigResource;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -29,17 +31,28 @@
private final String pluginName;
private final Provider<CurrentUser> userProvider;
private final List<MenuEntry> menuEntries;
+ private final Provider<ListServiceUsers> listServiceUsers;
@Inject
public ServiceUserMenu(@PluginName String pluginName,
- Provider<CurrentUser> userProvider) {
+ Provider<CurrentUser> userProvider,
+ Provider<ListServiceUsers> listServiceUsers) {
this.pluginName = pluginName;
this.userProvider = userProvider;
+ this.listServiceUsers = listServiceUsers;
menuEntries = Lists.newArrayList();
+
+ List<MenuItem> peopleItems = Lists.newArrayListWithExpectedSize(2);
if (canCreateServiceUser()) {
- menuEntries.add(new MenuEntry("People", Collections
- .singletonList(new MenuItem("Create Service User", "#/x/" + pluginName + "/create", ""))));
+ peopleItems.add(new MenuItem("Create Service User", "#/x/" + pluginName + "/create", ""));
}
+ if (canCreateServiceUser() || hasServiceUser()) {
+ peopleItems.add(new MenuItem("List Service Users", "#/x/" + pluginName + "/list", ""));
+ }
+ if (!peopleItems.isEmpty()) {
+ menuEntries.add(new MenuEntry("People", peopleItems));
+ }
+
if (userProvider.get().getCapabilities().canAdministrateServer()) {
menuEntries.add(new MenuEntry("Plugins", Collections
.singletonList(new MenuItem("Service User Admin", "#/x/" + pluginName + "/admin", ""))));
@@ -56,6 +69,14 @@
}
}
+ private boolean hasServiceUser() {
+ try {
+ return !listServiceUsers.get().apply(new ConfigResource()).isEmpty();
+ } catch (OrmException e) {
+ return false;
+ }
+ }
+
@Override
public List<MenuEntry> getEntries() {
return menuEntries;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/NativeMap.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/NativeMap.java
new file mode 100644
index 0000000..27bb222
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/NativeMap.java
@@ -0,0 +1,100 @@
+// Copyright (C) 2012 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.plugin.client.rpc.Natives;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import java.util.Set;
+
+/** A map of native JSON objects, keyed by a string. */
+public class NativeMap<T extends JavaScriptObject> extends JavaScriptObject {
+ public static <T extends JavaScriptObject> NativeMap<T> create() {
+ return createObject().cast();
+ }
+
+ /**
+ * Loop through the result map's entries and copy the key strings into the
+ * "name" property of the corresponding child object. This only runs on the
+ * top level map of the result, and requires the children to be JSON objects
+ * and not a JSON primitive (e.g. boolean or string).
+ */
+ public static <T extends JavaScriptObject,
+ M extends NativeMap<T>> AsyncCallback<M> copyKeysIntoChildren(
+ AsyncCallback<M> callback) {
+ return copyKeysIntoChildren("name", callback);
+ }
+
+ /** Loop through the result map and set asProperty on the children. */
+ public static <T extends JavaScriptObject,
+ M extends NativeMap<T>> AsyncCallback<M> copyKeysIntoChildren(
+ final String asProperty, AsyncCallback<M> callback) {
+ return new TransformCallback<M, M>(callback) {
+ @Override
+ protected M transform(M result) {
+ result.copyKeysIntoChildren(asProperty);
+ return result;
+ }
+ };
+ }
+
+ protected NativeMap() {
+ }
+
+ public final Set<String> keySet() {
+ return Natives.keys(this);
+ }
+
+ public final native JsArray<T> values()
+ /*-{
+ var s = this;
+ var v = [];
+ var i = 0;
+ for (var k in s) {
+ if (s.hasOwnProperty(k)) {
+ v[i++] = s[k];
+ }
+ }
+ return v;
+ }-*/;
+
+ public final int size() {
+ return keySet().size();
+ }
+
+ public final boolean isEmpty() {
+ return size() == 0;
+ }
+
+ public final boolean containsKey(String n) {
+ return get(n) != null;
+ }
+
+ public final native T get(String n) /*-{ return this[n]; }-*/;
+ public final native void put(String n, T v) /*-{ this[n] = v; }-*/;
+
+ public final native void copyKeysIntoChildren(String p)
+ /*-{
+ var s = this;
+ for (var k in s) {
+ if (s.hasOwnProperty(k)) {
+ var c = s[k];
+ c[p] = k;
+ }
+ }
+ }-*/;
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserInfo.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserInfo.java
new file mode 100644
index 0000000..68c0a7b
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserInfo.java
@@ -0,0 +1,28 @@
+// 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.gwt.core.client.JavaScriptObject;
+
+public class ServiceUserInfo extends JavaScriptObject {
+ public final native int _account_id() /*-{ return this._account_id || 0; }-*/;
+ public final native String name() /*-{ return this.name; }-*/;
+ public final native String email() /*-{ return this.email; }-*/;
+ public final native String created_by() /*-{ return this.created_by; }-*/;
+ public final native String created_at() /*-{ return this.created_at; }-*/;
+
+ protected ServiceUserInfo() {
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserListScreen.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserListScreen.java
new file mode 100644
index 0000000..945859e
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserListScreen.java
@@ -0,0 +1,88 @@
+// 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.plugin.client.Plugin;
+import com.google.gerrit.plugin.client.rpc.RestApi;
+import com.google.gerrit.plugin.client.screen.Screen;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+public class ServiceUserListScreen extends VerticalPanel {
+ static class Factory implements Screen.EntryPoint {
+ @Override
+ public void onLoad(Screen screen) {
+ screen.setPageTitle("Service Users");
+ screen.show(new ServiceUserListScreen());
+ }
+ }
+
+ ServiceUserListScreen() {
+ setStyleName("serviceuser-panel");
+
+ new RestApi("config").id("server").view(Plugin.get().getPluginName(), "serviceusers")
+ .get(NativeMap.copyKeysIntoChildren("username",
+ new AsyncCallback<NativeMap<ServiceUserInfo>>() {
+ @Override
+ public void onSuccess(NativeMap<ServiceUserInfo> info) {
+ display(info);
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ // never invoked
+ }
+ }));
+ }
+
+ private void display(NativeMap<ServiceUserInfo> info) {
+ int columns = 5;
+ FlexTable t = new FlexTable();
+ t.setStyleName("serviceuser-serviceUserTable");
+ FlexCellFormatter fmt = t.getFlexCellFormatter();
+ for (int c = 0; c < columns; c++) {
+ fmt.addStyleName(0, c, "dataHeader");
+ fmt.addStyleName(0, c, "topMostCell");
+ }
+ fmt.addStyleName(0, 0, "leftMostCell");
+
+ t.setText(0, 0, "Username");
+ t.setText(0, 1, "Full Name");
+ t.setText(0, 2, "Email");
+ t.setText(0, 3, "Created By");
+ t.setText(0, 4, "Created At");
+
+ int row = 1;
+ for (String username : info.keySet()) {
+ ServiceUserInfo a = info.get(username);
+
+ for (int c = 0; c < columns; c++) {
+ fmt.addStyleName(row, c, "dataCell");
+ fmt.addStyleName(row, 0, "leftMostCell");
+ }
+
+ t.setText(row, 0, username);
+ t.setText(row, 1, a.name());
+ t.setText(row, 2, a.email());
+ t.setText(row, 3, a.created_by());
+ t.setText(row, 4, a.created_at());
+ row++;
+ }
+
+ add(t);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserPlugin.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserPlugin.java
index 42c5a8f..4210adc 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserPlugin.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserPlugin.java
@@ -25,5 +25,6 @@
public void onPluginLoad() {
Plugin.get().screen("create", new CreateServiceUserScreen.Factory());
Plugin.get().screen("admin", new ServiceUserAdminScreen.Factory());
+ Plugin.get().screen("list", new ServiceUserListScreen.Factory());
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/TransformCallback.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/TransformCallback.java
new file mode 100644
index 0000000..b7d601c
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/TransformCallback.java
@@ -0,0 +1,38 @@
+// Copyright (C) 2012 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.gwt.user.client.rpc.AsyncCallback;
+
+/** Transforms a value and passes it on to another callback. */
+public abstract class TransformCallback<I, O> implements AsyncCallback<I>{
+ private final AsyncCallback<O> callback;
+
+ protected TransformCallback(AsyncCallback<O> callback) {
+ this.callback = callback;
+ }
+
+ @Override
+ public void onSuccess(I result) {
+ callback.onSuccess(transform(result));
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ callback.onFailure(caught);
+ }
+
+ protected abstract O transform(I result);
+}
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 6cf9292..a094130 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
@@ -6,3 +6,34 @@
margin-left: 10px !important;
}
+.serviceuser-serviceUserTable {
+ border-collapse: separate;
+ border-spacing: 0;
+}
+
+.serviceuser-serviceUserTable .leftMostCell {
+ border-left: 1px solid #EEE;
+}
+
+.serviceuser-serviceUserTable .topMostCell {
+ border-top: 1px solid #EEE;
+}
+
+.serviceuser-serviceUserTable .dataHeader {
+ border: 1px solid #FFF;
+ padding: 2px 6px 1px;
+ background-color: #EEE;
+ font-style: italic;
+ white-space: nowrap;
+ color: textColor;
+}
+
+.serviceuser-serviceUserTable .dataCell {
+ padding-left: 5px;
+ padding-right: 5px;
+ border-right: 1px solid #EEE;
+ border-bottom: 1px solid #EEE;
+ vertical-align: middle;
+ height: 20px;
+}
+