Store for each service user who created it and when it was created

The plugin now stores some properties for the created service users in
the 'refs/meta/config' branch of the 'All-Projects' project in the
file 'serviceuser.db', which is a Git config file. Having this file in
the 'All-Projects' git repository means that it can easily be
replicated and there is a version history for the data.

This information may be useful for the Gerrit administrators, e.g. if
a user creates a huge amount of service users the permission to create
service users could be revoked.

In future there may be also other features that require this
information. E.g. a user could list the service users that he created
or he may be allowed to upload additional SSH keys for those users.

Change-Id: I8361897ce04533556624a926df3f493ce2bec91e
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
index 542c5ee..25b253e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
@@ -24,21 +24,41 @@
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.account.CreateAccount;
 import com.google.gerrit.server.config.ConfigResource;
 import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectLevelConfig;
+import com.google.gerrit.server.project.ProjectCache;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
 
 import com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.Input;
 
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.PersonIdent;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
 import java.util.List;
+import java.util.Locale;
 
 @RequiresCapability(CreateServiceUserCapability.ID)
 public class CreateServiceUser implements RestModifyView<ConfigResource, Input> {
+  private static final String USER = "user";
+  private static final String KEY_CREATED_BY = "createdBy";
+  private static final String KEY_CREATED_AT = "createdAt";
+
   static class Input {
     String username;
     String sshKey;
@@ -52,10 +72,21 @@
   private final CreateAccount.Factory createAccountFactory;
   private final String username;
   private final List<String> blockedNames;
+  private final Provider<CurrentUser> userProvider;
+  private final MetaDataUpdate.User metaDataUpdateFactory;
+  private final Project.NameKey allProjects;
+  private final ProjectLevelConfig storage;
+  private final DateFormat rfc2822DateFormatter;
 
   @Inject
-  CreateServiceUser(PluginConfigFactory cfgFactory, @PluginName String pluginName,
-      CreateAccount.Factory createAccountFactory, @Assisted String username) {
+  CreateServiceUser(PluginConfigFactory cfgFactory,
+      @PluginName String pluginName,
+      CreateAccount.Factory createAccountFactory,
+      Provider<CurrentUser> userProvider,
+      @GerritPersonIdent PersonIdent gerritIdent,
+      MetaDataUpdate.User metaDataUpdateFactory,
+      ProjectCache projectCache,
+      @Assisted String username) {
     this.cfg = cfgFactory.getFromGerritConfig(pluginName);
     this.createAccountFactory = createAccountFactory;
     this.username = username;
@@ -67,12 +98,20 @@
                 return blockedName.toLowerCase();
               }
             });
+    this.userProvider = userProvider;
+    this.metaDataUpdateFactory = metaDataUpdateFactory;
+    this.storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
+    this.allProjects = projectCache.getAllProjects().getProject().getNameKey();
+    this.rfc2822DateFormatter =
+        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
+    this.rfc2822DateFormatter.setCalendar(Calendar.getInstance(
+        gerritIdent.getTimeZone(), Locale.US));
   }
 
   @Override
   public Object apply(ConfigResource resource, Input input)
       throws BadRequestException, ResourceConflictException,
-      UnprocessableEntityException, OrmException {
+      UnprocessableEntityException, OrmException, IOException {
     if (input == null) {
       input = new Input();
     }
@@ -90,6 +129,19 @@
 
     CreateAccount.Input in =
         new ServiceUserInput(username, input.sshKey, cfg);
-    return createAccountFactory.create(username).apply(TopLevelResource.INSTANCE, in);
+    Object response = createAccountFactory.create(username)
+            .apply(TopLevelResource.INSTANCE, in);
+
+    Config db = storage.get();
+    db.setString(USER, username, KEY_CREATED_BY,
+        userProvider.get().getUserName());
+    db.setString(USER, username, KEY_CREATED_AT,
+        rfc2822DateFormatter.format(new Date()));
+
+    MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+    md.setMessage("Create Service User '" + username + "'\n");
+    storage.commit(md);
+
+    return response;
   }
 }
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index d428721..bb91d0e 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -17,8 +17,36 @@
 groups](config.html#group). This allows to automatically assign or
 block certain access rights for the service users.
 
+For each created service user the plugin stores some
+[properties](#properties).
+
 <a id="webui"></a>
 Create Service User in WebUI
 ----------------------------
 In the `People` top menu there is a menu item `Create Service User`
 that opens a dialog for creating a service user.
+
+<a id="properties"></a>
+Service User Properties
+-----------------------
+The service user properties are stored in the `refs/meta/config` branch
+of the `All-Projects` project in the file `@PLUGIN@.db`, which is a
+Git config file:
+
+```
+  [user "build-bot"]
+    createdBy = jdoe
+    createdAt = Wed, 13 Nov 2013 14:31:11 +0100
+  [user "voter"]
+    createdBy = jroe
+    createdAt = Wed, 13 Nov 2013 14:45:00 +0100
+```
+
+<a id="createdBy">
+`user.<service-user-name>.createdBy`
+: The username of the user who created the service user.
+
+<a id="createdAt">
+`user.<service-user-name>.createdAt`
+: The date when the service user was created.
+