Merge "Allow to get/set notes related config parameter from REST and WebUI"
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
index 0980804..976ee07 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
@@ -14,17 +14,15 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
-import static com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.KEY_CREATOR_ID;
 import static com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.USER;
 
 import com.google.common.collect.Maps;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.config.ConfigResource;
@@ -42,20 +40,20 @@
 
 public class ListServiceUsers implements RestReadView<ConfigResource> {
   private final Provider<CurrentUser> userProvider;
-  private final IdentifiedUser.GenericFactory userFactory;
   private final ProjectLevelConfig storage;
   private final AccountCache accountCache;
+  private final Provider<ServiceUserCollection> serviceUsers;
   private final Provider<GetServiceUser> getServiceUser;
 
   @Inject
   ListServiceUsers(Provider<CurrentUser> userProvider,
-      IdentifiedUser.GenericFactory userFactory, @PluginName String pluginName,
-      ProjectCache projectCache, AccountCache accountCache,
+      @PluginName String pluginName, ProjectCache projectCache,
+      AccountCache accountCache, Provider<ServiceUserCollection> serviceUsers,
       Provider<GetServiceUser> getServiceUser) {
     this.userProvider = userProvider;
-    this.userFactory = userFactory;
     this.storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
     this.accountCache = accountCache;
+    this.serviceUsers = serviceUsers;
     this.getServiceUser = getServiceUser;
   }
 
@@ -69,22 +67,19 @@
 
     Map<String, ServiceUserInfo> accounts = Maps.newTreeMap();
     Config db = storage.get();
-    boolean isAdmin = user.getCapabilities().canAdministrateServer();
     for (String username : db.getSubsections(USER)) {
-      Account.Id createdBy =
-          new Account.Id(db.getInt(USER, username, KEY_CREATOR_ID, -1));
-      if (isAdmin || ((IdentifiedUser)user).getAccountId().equals(createdBy)) {
-        AccountState account = accountCache.getByUsername(username);
-        if (account != null) {
-          ServiceUserInfo info;
-          try {
-            info = getServiceUser.get().apply(
-                new ServiceUserResource(userFactory.create(account.getAccount().getId())));
-            info.username = null;
-            accounts.put(username, info);
-          } catch (ResourceNotFoundException e) {
-            // ignore this service user
-          }
+      AccountState account = accountCache.getByUsername(username);
+      if (account != null) {
+        ServiceUserInfo info;
+        try {
+          ServiceUserResource serviceUserResource =
+              serviceUsers.get().parse(new ConfigResource(),
+                  IdString.fromDecoded(username));
+          info = getServiceUser.get().apply(serviceUserResource);
+          info.username = null;
+          accounts.put(username, info);
+        } catch (ResourceNotFoundException e) {
+          // this service user is not visible to the caller -> ignore it
         }
       }
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java
index 0c9456a..5e1f2fe 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java
@@ -24,6 +24,7 @@
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.CreateEmail;
 import com.google.gerrit.server.account.DeleteEmail;
 import com.google.gerrit.server.account.PutPreferred;
@@ -45,18 +46,21 @@
   private final Provider<CreateEmail.Factory> createEmailFactory;
   private final Provider<DeleteEmail> deleteEmail;
   private final Provider<PutPreferred> putPreferred;
+  private final Provider<CurrentUser> self;
 
   @Inject
   PutEmail(Provider<GetConfig> getConfig,
       Provider<GetEmail> getEmail,
       Provider<CreateEmail.Factory> createEmailFactory,
       Provider<DeleteEmail> deleteEmail,
-      Provider<PutPreferred> putPreferred) {
+      Provider<PutPreferred> putPreferred,
+      Provider<CurrentUser> self) {
     this.getConfig = getConfig;
     this.getEmail = getEmail;
     this.createEmailFactory = createEmailFactory;
     this.deleteEmail = deleteEmail;
     this.putPreferred = putPreferred;
+    this.self = self;
   }
 
   @Override
@@ -65,7 +69,8 @@
       ResourceConflictException, MethodNotAllowedException, OrmException,
       BadRequestException, EmailException {
     Boolean emailAllowed = getConfig.get().apply(new ConfigResource()).allowEmail;
-    if (emailAllowed == null || !emailAllowed) {
+    if ((emailAllowed == null || !emailAllowed)
+        && !self.get().getCapabilities().canAdministrateServer()) {
       throw new ResourceConflictException("setting email not allowed");
     }
 
@@ -74,12 +79,14 @@
       if (Strings.emptyToNull(email) == null) {
         return Response.none();
       } else {
-        return deleteEmail.get().apply(rsrc.getUser(), input.email);
+        return deleteEmail.get().apply(rsrc.getUser(), email);
       }
-    } else if (email.equals(input.email)) {
+    } else if (email != null && email.equals(input.email)) {
       return Response.ok(email);
     } else {
-      deleteEmail.get().apply(rsrc.getUser(), email);
+      if (email != null) {
+        deleteEmail.get().apply(rsrc.getUser(), email);
+      }
       CreateEmail.Input in = new CreateEmail.Input();
       in.email = input.email;
       in.noConfirmation = true;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
index 698525a..30b125d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
@@ -71,7 +71,9 @@
   public ServiceUserResource parse(ConfigResource parent, IdString id)
       throws ResourceNotFoundException, AuthException, OrmException {
     IdentifiedUser serviceUser = accounts.get().parseId(id.get());
-    if (!storage.get().getSubsections(USER).contains(serviceUser.getUserName())) {
+    if (serviceUser == null
+        || !storage.get().getSubsections(USER)
+            .contains(serviceUser.getUserName())) {
       throw new ResourceNotFoundException(id);
     }
     CurrentUser user = userProvider.get();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/AccountCapabilities.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/AccountCapabilities.java
new file mode 100644
index 0000000..c705d53
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/AccountCapabilities.java
@@ -0,0 +1,34 @@
+// 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.rpc.RestApi;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+/** Capabilities the caller has from {@code /accounts/self/capabilities}.  */
+public class AccountCapabilities extends JavaScriptObject {
+  public static void all(AsyncCallback<AccountCapabilities> cb, String... filter) {
+    new RestApi("/accounts/self/capabilities")
+      .addParameter("q", filter)
+      .get(cb);
+  }
+
+  protected AccountCapabilities() {
+  }
+
+  public final native boolean canPerform(String name)
+  /*-{ return this[name] ? true : false; }-*/;
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserScreen.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserScreen.java
index d96c416..ea5c4fb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserScreen.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserScreen.java
@@ -48,8 +48,19 @@
                   .view(Plugin.get().getPluginName(), "config")
                   .get(new AsyncCallback<ConfigInfo>() {
                     @Override
-                    public void onSuccess(ConfigInfo configInfo) {
-                      display(serviceUserInfo, configInfo.getAllowEmail());
+                    public void onSuccess(final ConfigInfo configInfo) {
+                      AccountCapabilities.all(new AsyncCallback<AccountCapabilities>() {
+                        @Override
+                        public void onSuccess(AccountCapabilities ac) {
+                            display(serviceUserInfo, configInfo.getAllowEmail()
+                                || ac.canPerform("administrateServer"));
+                        }
+
+                        @Override
+                        public void onFailure(Throwable caught) {
+                          // never invoked
+                        }
+                      }, "administrateServer");
                     }
 
                     @Override