Merge branch 'stable-2.16' into stable-3.0
* stable-2.16:
Upgrade bazlets to latest stable-2.16 to build with 2.16.22 API
Change-Id: I495bdaa761c16f6bc3f43533547f3e8742748d5d
diff --git a/.bazelversion b/.bazelversion
index fd2a018..47b322c 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-3.1.0
+3.4.1
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..3a9c4b9
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,79 @@
+{
+ "extends": ["eslint:recommended", "google"],
+ "parserOptions": {
+ "ecmaVersion": 8
+ },
+ "env": {
+ "browser": true,
+ "es6": true
+ },
+ "globals": {
+ "__dirname": false,
+ "app": false,
+ "page": false,
+ "Polymer": false,
+ "process": false,
+ "require": false,
+ "Gerrit": false,
+ "Promise": false,
+ "assert": false,
+ "test": false,
+ "flushAsynchronousOperations": false
+ },
+ "rules": {
+ "arrow-parens": ["error", "as-needed"],
+ "block-spacing": ["error", "always"],
+ "brace-style": ["error", "1tbs", { "allowSingleLine": true }],
+ "camelcase": "off",
+ "comma-dangle": ["error", "always-multiline"],
+ "eol-last": "off",
+ "indent": "off",
+ "indent-legacy": ["error", 2, {
+ "MemberExpression": 2,
+ "FunctionDeclaration": {"body": 1, "parameters": 2},
+ "FunctionExpression": {"body": 1, "parameters": 2},
+ "CallExpression": {"arguments": 2},
+ "ArrayExpression": 1,
+ "ObjectExpression": 1,
+ "SwitchCase": 1
+ }],
+ "keyword-spacing": ["error", { "after": true, "before": true }],
+ "max-len": [
+ "error",
+ 80,
+ 2,
+ {"ignoreComments": true}
+ ],
+ "new-cap": ["error", { "capIsNewExceptions": ["Polymer"] }],
+ "no-console": "off",
+ "no-restricted-syntax": [
+ "error",
+ {
+ "selector": "ExpressionStatement > CallExpression > MemberExpression[object.name='test'][property.name='only']",
+ "message": "Remove test.only."
+ },
+ {
+ "selector": "ExpressionStatement > CallExpression > MemberExpression[object.name='suite'][property.name='only']",
+ "message": "Remove suite.only."
+ }
+ ],
+ "no-undef": "off",
+ "no-useless-escape": "off",
+ "no-var": "error",
+ "object-shorthand": ["error", "always"],
+ "prefer-arrow-callback": "error",
+ "prefer-const": "error",
+ "prefer-spread": "error",
+ "quote-props": ["error", "consistent-as-needed"],
+ "require-jsdoc": "off",
+ "semi": [2, "always"],
+ "template-curly-spacing": "error",
+ "valid-jsdoc": "off"
+ },
+ "plugins": [
+ "html"
+ ],
+ "settings": {
+ "html/report-bad-indent": "error"
+ }
+ }
diff --git a/BUILD b/BUILD
index f4c8d63..fcad0e5 100644
--- a/BUILD
+++ b/BUILD
@@ -1,14 +1,26 @@
-load("//tools/bzl:plugin.bzl", "gerrit_plugin")
+load("//tools/bzl:junit.bzl", "junit_tests")
+load("//tools/bzl:plugin.bzl", "PLUGIN_DEPS", "PLUGIN_TEST_DEPS", "gerrit_plugin")
gerrit_plugin(
name = "serviceuser",
srcs = glob(["src/main/java/**/*.java"]),
- gwt_module = "com.googlesource.gerrit.plugins.serviceuser.CreateServiceUserForm",
manifest_entries = [
"Gerrit-PluginName: serviceuser",
"Gerrit-Module: com.googlesource.gerrit.plugins.serviceuser.Module",
"Gerrit-HttpModule: com.googlesource.gerrit.plugins.serviceuser.HttpModule",
"Gerrit-SshModule: com.googlesource.gerrit.plugins.serviceuser.SshModule",
],
- resources = glob(["src/main/**/*"]),
+ resources = glob(["src/main/resources/**/*"]),
+)
+
+junit_tests(
+ name = "serviceuser_tests",
+ testonly = 1,
+ srcs = glob([
+ "src/test/java/**/*Test.java",
+ ]),
+ tags = ["serviceuser"],
+ deps = PLUGIN_TEST_DEPS + PLUGIN_DEPS + [
+ ":serviceuser__plugin",
+ ],
)
diff --git a/WORKSPACE b/WORKSPACE
index 10610aa..a685113 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,31 +3,13 @@
load("//:bazlets.bzl", "load_bazlets")
load_bazlets(
- commit = "8ad33887665f4f6adf7cb465a03f6bd81b95e01d",
+ commit = "7a9ae377b519934c87184cc05845663ed708b69c",
#local_path = "/home/<user>/projects/bazlets",
)
-# Snapshot Plugin API
-#load(
-# "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
-# "gerrit_api_maven_local",
-#)
-
-# Load snapshot Plugin API
-#gerrit_api_maven_local()
-
-# Release Plugin API
load(
"@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
"gerrit_api",
)
-# Load release Plugin API
gerrit_api()
-
-load(
- "@com_googlesource_gerrit_bazlets//:gerrit_gwt.bzl",
- "gerrit_gwt",
-)
-
-gerrit_gwt()
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/AddSshKey.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/AddSshKey.java
index 64a024d..c5ccadd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/AddSshKey.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/AddSshKey.java
@@ -20,7 +20,6 @@
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -38,7 +37,7 @@
@Override
public Response<SshKeyInfo> apply(ServiceUserResource rsrc, SshKeyInput input)
- throws AuthException, BadRequestException, OrmException, IOException, ConfigInvalidException {
+ throws AuthException, BadRequestException, IOException, ConfigInvalidException {
return addSshKey.get().apply(rsrc.getUser(), input);
}
}
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 5b3ae51..80ddf1b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
@@ -42,7 +42,6 @@
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectLevelConfig;
import com.google.gerrit.server.restapi.account.CreateAccount;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -123,8 +122,7 @@
@Override
public Response<ServiceUserInfo> apply(
ConfigResource parentResource, IdString id, CreateServiceUser.Input input)
- throws RestApiException, OrmException, IOException, ConfigInvalidException,
- PermissionBackendException {
+ throws RestApiException, IOException, ConfigInvalidException, PermissionBackendException {
CurrentUser user = userProvider.get();
if (user == null || !user.isIdentifiedUser()) {
throw new AuthException("authentication required");
@@ -137,10 +135,15 @@
if (input.username != null && !username.equals(input.username)) {
throw new BadRequestException("username must match URL");
}
+
if (Strings.isNullOrEmpty(input.sshKey)) {
throw new BadRequestException("sshKey not set");
}
+ if (!SshKeyValidator.validateFormat(input.sshKey)) {
+ throw new BadRequestException("sshKey invalid.");
+ }
+
if (blockedNames.contains(username.toLowerCase())) {
throw new BadRequestException(
"The username '" + username + "' is not allowed as name for service users.");
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java
index bebd520..3f27975 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java
@@ -23,7 +23,6 @@
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import java.io.BufferedReader;
import java.io.IOException;
@@ -50,8 +49,7 @@
@Override
protected void run()
- throws OrmException, IOException, UnloggedFailure, ConfigInvalidException,
- PermissionBackendException {
+ throws IOException, UnloggedFailure, ConfigInvalidException, PermissionBackendException {
CreateServiceUser.Input input = new CreateServiceUser.Input();
input.sshKey = readSshKey();
input.username = username;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserForm.gwt.xml b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserForm.gwt.xml
deleted file mode 100644
index 9d921cb..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserForm.gwt.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2013 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.
--->
-<module rename-to="serviceuser">
- <!-- Inherit the core Web Toolkit stuff. -->
- <inherits name="com.google.gwt.user.User"/>
- <!-- Other module inherits -->
- <inherits name="com.google.gerrit.Plugin"/>
- <inherits name="com.google.gwt.http.HTTP"/>
- <inherits name="com.google.gwt.json.JSON"/>
- <inherits name='com.google.gwtexpui.clippy.Clippy'/>
- <inherits name='com.google.gwtexpui.globalkey.GlobalKey'/>
- <!-- Using GWT built-in themes adds a number of static -->
- <!-- resources to the plugin. No theme inherits lines were -->
- <!-- added in order to make this plugin as simple as possible -->
- <!-- Specify the app entry point class. -->
- <entry-point class="com.googlesource.gerrit.plugins.serviceuser.client.ServiceUserPlugin"/>
- <stylesheet src="serviceuser.css"/>
-</module>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserNotes.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserNotes.java
index c0e4c20..63cb875 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserNotes.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserNotes.java
@@ -27,7 +27,6 @@
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.git.NotesBranchUtil;
import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.googlesource.gerrit.plugins.serviceuser.GetServiceUser.ServiceUserInfo;
@@ -83,8 +82,7 @@
}
void createNotes(String branch, ObjectId oldObjectId, ObjectId newObjectId)
- throws IOException, OrmException, ConfigInvalidException, PermissionBackendException,
- RestApiException {
+ throws IOException, ConfigInvalidException, PermissionBackendException, RestApiException {
if (ObjectId.zeroId().equals(newObjectId)) {
return;
}
@@ -156,13 +154,13 @@
}
private ObjectId createNoteContent(String branch, ServiceUserInfo serviceUser)
- throws IOException, OrmException, MethodNotAllowedException, PermissionBackendException {
+ throws IOException, MethodNotAllowedException, PermissionBackendException {
return getInserter()
.insert(Constants.OBJ_BLOB, createServiceUserNote(branch, serviceUser).getBytes(UTF_8));
}
private String createServiceUserNote(String branch, ServiceUserInfo serviceUser)
- throws OrmException, MethodNotAllowedException, PermissionBackendException {
+ throws MethodNotAllowedException, PermissionBackendException {
HeaderFormatter fmt = new HeaderFormatter(gerritServerIdent.getTimeZone(), anonymousCowardName);
fmt.appendDate();
fmt.append("Project", project.get());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteActive.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteActive.java
index 5393e03..ec5d063 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteActive.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteActive.java
@@ -18,7 +18,6 @@
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -36,7 +35,7 @@
@Override
public Response<?> apply(ServiceUserResource rsrc, Input input)
- throws RestApiException, OrmException, IOException, ConfigInvalidException {
+ throws RestApiException, IOException, ConfigInvalidException {
return deleteActive.get().apply(rsrc, input);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteSshKey.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteSshKey.java
index 9092e74..9ce83d3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteSshKey.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteSshKey.java
@@ -20,7 +20,6 @@
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -39,8 +38,8 @@
@Override
public Response<?> apply(ServiceUserResource.SshKey rsrc, Input input)
- throws OrmException, AuthException, RepositoryNotFoundException, IOException,
- ConfigInvalidException, PermissionBackendException {
+ throws AuthException, RepositoryNotFoundException, IOException, ConfigInvalidException,
+ PermissionBackendException {
return deleteSshKey
.get()
.apply(new AccountResource.SshKey(rsrc.getUser(), rsrc.getSshKey()), input);
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 28d7be3..85da7b0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
@@ -27,7 +27,6 @@
import com.google.gerrit.server.group.InternalGroupDescription;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.restapi.group.GroupJson;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.Arrays;
@@ -60,7 +59,7 @@
}
@Override
- public ConfigInfo apply(ConfigResource rsrc) throws OrmException, PermissionBackendException {
+ public ConfigInfo apply(ConfigResource rsrc) throws PermissionBackendException {
PluginConfig cfg = cfgFactory.getFromGerritConfig(pluginName);
ConfigInfo info = new ConfigInfo();
info.info = Strings.emptyToNull(cfg.getString("infoMessage"));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java
index 47783f5..31c2eb6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java
@@ -30,7 +30,6 @@
import com.google.gerrit.server.project.ProjectLevelConfig;
import com.google.gerrit.server.restapi.group.GroupJson;
import com.google.gerrit.server.restapi.group.GroupsCollection;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -55,7 +54,7 @@
@Override
public Response<GroupInfo> apply(ServiceUserResource rsrc)
- throws RestApiException, OrmException, PermissionBackendException {
+ throws RestApiException, PermissionBackendException {
ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
String owner = storage.get().getString(USER, rsrc.getUser().getUserName().get(), KEY_OWNER);
if (owner != null) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java
index a4ad837..3a2460f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java
@@ -32,7 +32,6 @@
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectLevelConfig;
import com.google.gerrit.server.restapi.account.GetAccount;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -62,7 +61,7 @@
@Override
public ServiceUserInfo apply(ServiceUserResource rsrc)
- throws RestApiException, OrmException, PermissionBackendException {
+ throws RestApiException, PermissionBackendException {
ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
String username = rsrc.getUser().getUserName().get();
Config db = storage.get();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKeys.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKeys.java
index 92a9430..60dfc15 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKeys.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKeys.java
@@ -17,7 +17,6 @@
import com.google.gerrit.extensions.common.SshKeyInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -37,8 +36,7 @@
@Override
public List<SshKeyInfo> apply(ServiceUserResource rsrc)
- throws AuthException, OrmException, RepositoryNotFoundException, IOException,
- ConfigInvalidException {
+ throws AuthException, RepositoryNotFoundException, IOException, ConfigInvalidException {
return getSshKeys.get().apply(rsrc.getUser());
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/HttpModule.java
index 80d86e2..a99987b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/HttpModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/HttpModule.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2019 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.
@@ -15,14 +15,14 @@
package com.googlesource.gerrit.plugins.serviceuser;
import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.extensions.webui.GwtPlugin;
+import com.google.gerrit.extensions.webui.JavaScriptPlugin;
import com.google.gerrit.extensions.webui.WebUiPlugin;
-import com.google.inject.servlet.ServletModule;
+import com.google.inject.AbstractModule;
-class HttpModule extends ServletModule {
-
+public class HttpModule extends AbstractModule {
@Override
- protected void configureServlets() {
- DynamicSet.bind(binder(), WebUiPlugin.class).toInstance(new GwtPlugin("serviceuser"));
+ protected void configure() {
+ DynamicSet.bind(binder(), WebUiPlugin.class)
+ .toInstance(new JavaScriptPlugin("gr-serviceuser.html"));
}
}
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 cf6ea40..0b93721 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
@@ -30,7 +30,6 @@
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectLevelConfig;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -68,8 +67,7 @@
@Override
public Map<String, ServiceUserInfo> apply(ConfigResource rscr)
- throws OrmException, IOException, RestApiException, PermissionBackendException,
- ConfigInvalidException {
+ throws IOException, RestApiException, PermissionBackendException, ConfigInvalidException {
ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
CurrentUser user = userProvider.get();
if (user == null || !user.isIdentifiedUser()) {
@@ -84,7 +82,12 @@
ServiceUserInfo info;
try {
ServiceUserResource serviceUserResource =
- serviceUsers.get().parse(new ConfigResource(), IdString.fromDecoded(username));
+ serviceUsers
+ .get()
+ .parse(
+ new ConfigResource(),
+ IdString.fromDecoded(
+ String.valueOf(account.get().getAccount().getId().get())));
info = getServiceUser.get().apply(serviceUserResource);
info.username = null;
accounts.put(username, info);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java
index 9ceba80..56d14e1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java
@@ -24,7 +24,6 @@
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.RestApiModule;
-import com.google.gerrit.extensions.webui.TopMenu;
import com.google.gerrit.server.git.validators.CommitValidationListener;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
@@ -36,7 +35,6 @@
bind(CapabilityDefinition.class)
.annotatedWith(Exports.named(CreateServiceUserCapability.ID))
.to(CreateServiceUserCapability.class);
- DynamicSet.bind(binder(), TopMenu.class).to(ServiceUserMenu.class);
DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(RefUpdateListener.class);
DynamicSet.bind(binder(), CommitValidationListener.class).to(ValidateServiceUserCommits.class);
install(new FactoryModuleBuilder().build(CreateServiceUserNotes.Factory.class));
@@ -72,5 +70,6 @@
delete(SERVICE_USER_KIND, "owner").to(PutOwner.class);
}
});
+ install(new HttpModule());
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutActive.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutActive.java
index 1282935..f4b0365 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutActive.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutActive.java
@@ -18,7 +18,6 @@
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -36,7 +35,7 @@
@Override
public Response<String> apply(ServiceUserResource rsrc, Input input)
- throws OrmException, IOException, ConfigInvalidException, RestApiException {
+ throws IOException, ConfigInvalidException, RestApiException {
return putActive.get().apply(rsrc, input);
}
}
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 4a5c6f6..986b2bb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java
@@ -17,7 +17,7 @@
import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER;
import com.google.common.base.Strings;
-import com.google.gerrit.common.errors.EmailException;
+import com.google.gerrit.exceptions.EmailException;
import com.google.gerrit.extensions.api.accounts.EmailInput;
import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.IdString;
@@ -31,7 +31,6 @@
import com.google.gerrit.server.restapi.account.CreateEmail;
import com.google.gerrit.server.restapi.account.DeleteEmail;
import com.google.gerrit.server.restapi.account.PutPreferred;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -73,8 +72,8 @@
@Override
public Response<?> apply(ServiceUserResource rsrc, Input input)
- throws OrmException, ConfigInvalidException, EmailException, IOException,
- PermissionBackendException, RestApiException {
+ throws ConfigInvalidException, EmailException, IOException, PermissionBackendException,
+ RestApiException {
Boolean emailAllowed = getConfig.get().apply(new ConfigResource()).allowEmail;
if ((emailAllowed == null || !emailAllowed)) {
permissionBackend.user(self.get()).check(ADMINISTRATE_SERVER);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutHttpPassword.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutHttpPassword.java
index 61b5841..8d0110a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutHttpPassword.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutHttpPassword.java
@@ -26,7 +26,6 @@
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -61,7 +60,7 @@
@Override
public Response<String> apply(ServiceUserResource rsrc, Input input)
throws AuthException, ResourceConflictException, ConfigInvalidException,
- ResourceNotFoundException, OrmException, IOException, PermissionBackendException {
+ ResourceNotFoundException, IOException, PermissionBackendException {
if (input == null) {
input = new Input();
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutName.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutName.java
index 4bcdd6a..8b10d59 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutName.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutName.java
@@ -19,7 +19,6 @@
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -37,7 +36,7 @@
@Override
public Response<String> apply(ServiceUserResource rsrc, NameInput input)
- throws MethodNotAllowedException, ResourceNotFoundException, OrmException, IOException,
+ throws MethodNotAllowedException, ResourceNotFoundException, IOException,
ConfigInvalidException {
return putName.get().apply(rsrc.getUser(), input);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java
index 37bbf17..f444380 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java
@@ -40,7 +40,6 @@
import com.google.gerrit.server.project.ProjectLevelConfig;
import com.google.gerrit.server.restapi.group.GroupJson;
import com.google.gerrit.server.restapi.group.GroupsCollection;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -87,7 +86,7 @@
@Override
public Response<GroupInfo> apply(ServiceUserResource rsrc, Input input)
- throws RestApiException, IOException, OrmException, PermissionBackendException {
+ throws RestApiException, IOException, PermissionBackendException {
ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
Boolean ownerAllowed = getConfig.get().apply(new ConfigResource()).allowOwner;
if ((ownerAllowed == null || !ownerAllowed)) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RefUpdateListener.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RefUpdateListener.java
index 69512c5..c4090ac 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RefUpdateListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RefUpdateListener.java
@@ -24,7 +24,6 @@
import com.google.gerrit.server.git.ProjectRunnable;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -109,7 +108,6 @@
ObjectId.fromString(e.getNewObjectId()));
crn.commitNotes();
} catch (IOException
- | OrmException
| ConfigInvalidException
| PermissionBackendException
| RestApiException x) {
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 729282c..066898f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
@@ -38,7 +38,6 @@
import com.google.gerrit.server.project.ProjectLevelConfig;
import com.google.gerrit.server.restapi.account.AccountsCollection;
import com.google.gerrit.server.restapi.group.GroupsCollection;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -79,8 +78,8 @@
@Override
public ServiceUserResource parse(ConfigResource parent, IdString id)
- throws ResourceNotFoundException, AuthException, IOException, OrmException,
- PermissionBackendException, ConfigInvalidException {
+ throws ResourceNotFoundException, AuthException, IOException, PermissionBackendException,
+ ConfigInvalidException {
ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
IdentifiedUser serviceUser = accounts.get().parse(TopLevelResource.INSTANCE, id).getUser();
if (serviceUser == null
@@ -92,7 +91,8 @@
throw new AuthException("Authentication required");
}
if (!permissionBackend.user(user).testOrFalse(ADMINISTRATE_SERVER)) {
- String owner = storage.get().getString(USER, id.get(), KEY_OWNER);
+ String username = serviceUser.getUserName().get();
+ String owner = storage.get().getString(USER, username, KEY_OWNER);
if (owner != null) {
GroupDescription.Basic group =
groups.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(owner)).getGroup();
@@ -101,7 +101,7 @@
}
} else if (!((IdentifiedUser) user)
.getAccountId()
- .equals(new Account.Id(storage.get().getInt(USER, id.get(), KEY_CREATOR_ID, -1)))) {
+ .equals(new Account.Id(storage.get().getInt(USER, username, KEY_CREATOR_ID, -1)))) {
throw new ResourceNotFoundException(id);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java
deleted file mode 100644
index df2cf8c..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (C) 2013 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;
-
-import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER;
-
-import com.google.common.collect.Lists;
-import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.extensions.api.access.PluginPermission;
-import com.google.gerrit.extensions.client.MenuItem;
-import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.webui.TopMenu;
-import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.config.ConfigResource;
-import com.google.gerrit.server.permissions.PermissionBackend;
-import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import java.io.IOException;
-import java.util.List;
-import org.eclipse.jgit.errors.ConfigInvalidException;
-
-class ServiceUserMenu implements TopMenu {
- private final String pluginName;
- private final Provider<CurrentUser> userProvider;
- private final List<MenuEntry> menuEntries;
- private final Provider<ListServiceUsers> listServiceUsers;
- private final PermissionBackend permissionBackend;
-
- @Inject
- ServiceUserMenu(
- @PluginName String pluginName,
- Provider<CurrentUser> userProvider,
- Provider<ListServiceUsers> listServiceUsers,
- PermissionBackend permissionBackend)
- throws IOException, PermissionBackendException, ConfigInvalidException, RestApiException {
- this.pluginName = pluginName;
- this.userProvider = userProvider;
- this.listServiceUsers = listServiceUsers;
- menuEntries = Lists.newArrayList();
- this.permissionBackend = permissionBackend;
-
- List<MenuItem> peopleItems = Lists.newArrayListWithExpectedSize(2);
- if (canCreateServiceUser()) {
- 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));
- }
- }
-
- private boolean canCreateServiceUser() {
- if (userProvider.get().isIdentifiedUser()) {
- IdentifiedUser user = userProvider.get().asIdentifiedUser();
- return permissionBackend
- .user(user)
- .testOrFalse(new PluginPermission(pluginName, CreateServiceUserCapability.ID))
- || permissionBackend.user(user).testOrFalse(ADMINISTRATE_SERVER);
- }
- return false;
- }
-
- private boolean hasServiceUser()
- throws PermissionBackendException, IOException, ConfigInvalidException, RestApiException {
- try {
- return !listServiceUsers.get().apply(new ConfigResource()).isEmpty();
- } catch (AuthException | OrmException e) {
- return false;
- }
- }
-
- @Override
- public List<MenuEntry> getEntries() {
- return menuEntries;
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResolver.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResolver.java
index 686b6ba..e2f16a6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResolver.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResolver.java
@@ -21,11 +21,11 @@
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.server.ReviewDb;
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.AccountResolver;
+import com.google.gerrit.server.account.AccountResolver.UnresolvableAccountException;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.account.GroupMembership;
@@ -35,8 +35,6 @@
import com.google.gerrit.server.restapi.group.ListMembers;
import com.google.gerrit.server.util.RequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
-import com.google.gwtorm.server.OrmException;
-import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -56,7 +54,6 @@
private final IdentifiedUser.GenericFactory genericUserFactory;
private final Provider<GetServiceUser> getServiceUser;
private final Provider<ListMembers> listMembers;
- private final SchemaFactory<ReviewDb> schema;
private final ThreadLocalRequestContext tl;
private final AccountCache accountCache;
private final GroupControl.Factory groupControlFactory;
@@ -68,7 +65,6 @@
IdentifiedUser.GenericFactory genericUserFactory,
Provider<GetServiceUser> getServiceUser,
Provider<ListMembers> listMembers,
- SchemaFactory<ReviewDb> schema,
ThreadLocalRequestContext tl,
AccountCache accountCache,
GroupControl.Factory groupControlFactory,
@@ -77,7 +73,6 @@
this.genericUserFactory = genericUserFactory;
this.getServiceUser = getServiceUser;
this.listMembers = listMembers;
- this.schema = schema;
this.tl = tl;
this.accountCache = accountCache;
this.groupControlFactory = groupControlFactory;
@@ -85,103 +80,86 @@
}
ServiceUserInfo getAsServiceUser(PersonIdent committerIdent)
- throws ConfigInvalidException, IOException, OrmException, PermissionBackendException,
- RestApiException {
+ throws ConfigInvalidException, IOException, PermissionBackendException, RestApiException {
StringBuilder committer = new StringBuilder();
committer.append(committerIdent.getName());
committer.append(" <");
committer.append(committerIdent.getEmailAddress());
committer.append("> ");
- Account account = resolver.find(committer.toString());
- if (account == null) {
- return null;
- }
try {
+ Account account = resolver.resolve(committer.toString()).asUnique().getAccount();
return getServiceUser
.get()
.apply(new ServiceUserResource(genericUserFactory.create(account.getId())));
- } catch (ResourceNotFoundException e) {
+ } catch (ResourceNotFoundException | UnresolvableAccountException e) {
return null;
}
}
List<AccountInfo> listOwners(ServiceUserInfo serviceUser)
- throws OrmException, MethodNotAllowedException, PermissionBackendException {
+ throws MethodNotAllowedException, PermissionBackendException {
if (serviceUser.owner == null) {
return Collections.emptyList();
}
- try (ReviewDb db = schema.open()) {
- RequestContext context =
- new RequestContext() {
- @Override
- public CurrentUser getUser() {
- return new CurrentUser() {
+ RequestContext context =
+ new RequestContext() {
+ @Override
+ public CurrentUser getUser() {
+ return new CurrentUser() {
- @Override
- public GroupMembership getEffectiveGroups() {
- return new GroupMembership() {
- @Override
- public Set<AccountGroup.UUID> intersection(
- Iterable<AccountGroup.UUID> groupIds) {
- return null;
- }
+ @Override
+ public GroupMembership getEffectiveGroups() {
+ return new GroupMembership() {
+ @Override
+ public Set<AccountGroup.UUID> intersection(Iterable<AccountGroup.UUID> groupIds) {
+ return null;
+ }
- @Override
- public Set<AccountGroup.UUID> getKnownGroups() {
- return null;
- }
+ @Override
+ public Set<AccountGroup.UUID> getKnownGroups() {
+ return null;
+ }
- @Override
- public boolean containsAnyOf(Iterable<AccountGroup.UUID> groupIds) {
- return true;
- }
+ @Override
+ public boolean containsAnyOf(Iterable<AccountGroup.UUID> groupIds) {
+ return true;
+ }
- @Override
- public boolean contains(AccountGroup.UUID groupId) {
- return true;
- }
- };
- }
+ @Override
+ public boolean contains(AccountGroup.UUID groupId) {
+ return true;
+ }
+ };
+ }
- @Override
- public Object getCacheKey() {
- return null;
- }
- };
- }
-
- @Override
- public Provider<ReviewDb> getReviewDbProvider() {
- return new Provider<ReviewDb>() {
- @Override
- public ReviewDb get() {
- return db;
- }
- };
- }
- };
- RequestContext old = tl.setContext(context);
- try {
- GroupDescription.Basic group = groupResolver.parseId(serviceUser.owner.id);
- GroupControl ctl = groupControlFactory.controlFor(group);
- ListMembers lm = listMembers.get();
- GroupResource rsrc = new GroupResource(ctl);
- lm.setRecursive(true);
- List<AccountInfo> owners = new ArrayList<>();
- for (AccountInfo a : lm.apply(rsrc)) {
- owners.add(a);
- }
- return owners;
- } finally {
- tl.setContext(old);
+ @Override
+ public Object getCacheKey() {
+ return null;
+ }
+ };
+ }
+ };
+ RequestContext old = tl.setContext(context);
+ try {
+ GroupDescription.Basic group = groupResolver.parseId(serviceUser.owner.id);
+ GroupControl ctl = groupControlFactory.controlFor(group);
+ ListMembers lm = listMembers.get();
+ GroupResource rsrc = new GroupResource(ctl);
+ lm.setRecursive(true);
+ List<AccountInfo> owners = new ArrayList<>();
+ for (AccountInfo a : lm.apply(rsrc)) {
+ owners.add(a);
}
+ return owners;
+ } finally {
+ tl.setContext(old);
}
}
List<AccountInfo> listActiveOwners(ServiceUserInfo serviceUser)
- throws OrmException, MethodNotAllowedException, PermissionBackendException {
+ throws MethodNotAllowedException, PermissionBackendException {
List<AccountInfo> activeOwners = new ArrayList<>();
for (AccountInfo owner : listOwners(serviceUser)) {
Optional<AccountState> accountState = accountCache.get(new Account.Id(owner._accountId));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidator.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidator.java
new file mode 100644
index 0000000..9a95db1
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidator.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2019 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;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class SshKeyValidator {
+
+ private static final String OPENSSH_KEY_PREFIXES[] = {
+ "ssh-ed25519", "ssh-rsa", "ssh-dss", "ecdsa-sha2-"
+ };
+ private static final Pattern RFC_KEY_FORMAT_PATTERN =
+ Pattern.compile(
+ "(?s)^-{4,5}\\s?BEGIN.* PUBLIC KEY\\s?-{4,5}.+-{4,5}\\s?END.* PUBLIC KEY\\s?-{4,5}$");
+
+ static boolean validateFormat(String sshKey) {
+ if (validateRfcFormat(sshKey)) {
+ return true;
+ }
+
+ return validateOpenSshFormat(sshKey);
+ }
+
+ private static boolean validateOpenSshFormat(String sshKey) {
+ for (String prefix : OPENSSH_KEY_PREFIXES) {
+ if (sshKey.startsWith(prefix)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean validateRfcFormat(String sshKey) {
+ Matcher matcher = RFC_KEY_FORMAT_PATTERN.matcher(sshKey);
+ return matcher.find();
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeys.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeys.java
index 7858b12..70833ef 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeys.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeys.java
@@ -19,7 +19,6 @@
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestView;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -49,7 +48,7 @@
@Override
public ServiceUserResource.SshKey parse(ServiceUserResource parent, IdString id)
- throws ResourceNotFoundException, OrmException, IOException, ConfigInvalidException {
+ throws ResourceNotFoundException, IOException, ConfigInvalidException {
return new ServiceUserResource.SshKey(sshKeys.get().parse(parent.getUser(), id));
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ValidateServiceUserCommits.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ValidateServiceUserCommits.java
index ebf072b..d8c2176 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ValidateServiceUserCommits.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ValidateServiceUserCommits.java
@@ -23,7 +23,6 @@
import com.google.gerrit.server.git.validators.CommitValidationListener;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.serviceuser.GetServiceUser.ServiceUserInfo;
@@ -75,7 +74,6 @@
}
}
} catch (IOException
- | OrmException
| ConfigInvalidException
| PermissionBackendException
| RestApiException e) {
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
deleted file mode 100644
index a6f7f84..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/AccountCapabilities.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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/AccountInfo.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/AccountInfo.java
deleted file mode 100644
index ffc1953..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/AccountInfo.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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 AccountInfo 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 username() /*-{ return this.username; }-*/;
-
- public final native String email() /*-{ return this.email; }-*/;
-
- protected AccountInfo() {}
-}
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
deleted file mode 100644
index 6291319..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ConfigInfo.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.NativeMap;
-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 }-*/;
-
- final native String getOnSuccessMessage() /*-{ return this.on_success }-*/;
-
- final native boolean getAllowEmail() /*-{ return this.allow_email ? true : false; }-*/;
-
- final native boolean
- getAllowHttpPassword() /*-{ return this.allow_http_password ? true : false; }-*/;
-
- final native boolean getAllowOwner() /*-{ return this.allow_owner ? 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 NativeMap<GroupInfo> getGroups() /*-{ return this.groups; }-*/;
-
- final native void setInfoMessage(String s) /*-{ this.info = s; }-*/;
-
- final native void setOnSuccessMessage(String s) /*-{ this.on_success = s; }-*/;
-
- final native void setAllowEmail(boolean s) /*-{ this.allow_email = s; }-*/;
-
- final native void setAllowHttpPassword(boolean s) /*-{ this.allow_http_password = s; }-*/;
-
- final native void setAllowOwner(boolean s) /*-{ this.allow_owner = s; }-*/;
-
- 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); }-*/;
-
- final void setGroups(List<String> groups) {
- initGroups();
- for (String g : groups) {
- addGroup(g);
- }
- }
-
- final native void initGroups() /*-{ this.groups = []; }-*/;
-
- final native void addGroup(String g) /*-{ this.groups.push(g); }-*/;
-
- static ConfigInfo create() {
- ConfigInfo g = (ConfigInfo) createObject();
- return g;
- }
-
- protected ConfigInfo() {}
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/CreateServiceUserScreen.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/CreateServiceUserScreen.java
deleted file mode 100644
index c57eb5f..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/CreateServiceUserScreen.java
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright (C) 2013 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.core.client.JavaScriptObject;
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.dom.client.KeyPressHandler;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.DialogBox;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.Panel;
-import com.google.gwt.user.client.ui.TextArea;
-import com.google.gwt.user.client.ui.TextBox;
-import com.google.gwt.user.client.ui.VerticalPanel;
-
-public class CreateServiceUserScreen extends VerticalPanel {
- static class Factory implements Screen.EntryPoint {
- @Override
- public void onLoad(Screen screen) {
- screen.setPageTitle("Create Service User");
- screen.show(new CreateServiceUserScreen());
- }
- }
-
- private TextBox usernameTxt;
- private TextBox emailTxt;
- private TextArea sshKeyTxt;
- private String onSuccessMessage;
-
- CreateServiceUserScreen() {
- setStyleName("serviceuser-panel");
-
- Panel usernamePanel = new VerticalPanel();
- usernamePanel.add(new Label("Username:"));
- usernameTxt =
- new TextBox() {
- @Override
- public void onBrowserEvent(Event event) {
- super.onBrowserEvent(event);
- if (event.getTypeInt() == Event.ONPASTE) {
- Scheduler.get()
- .scheduleDeferred(
- new ScheduledCommand() {
- @Override
- public void execute() {
- if (getValue().trim().length() != 0) {
- setEnabled(true);
- }
- }
- });
- }
- }
- };
- usernameTxt.addKeyPressHandler(
- new KeyPressHandler() {
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- event.stopPropagation();
- }
- });
- usernameTxt.sinkEvents(Event.ONPASTE);
- usernameTxt.setVisibleLength(40);
- usernamePanel.add(usernameTxt);
- add(usernamePanel);
-
- Panel sshKeyPanel = new VerticalPanel();
- sshKeyPanel.add(new Label("Public SSH Key:"));
- sshKeyPanel.add(new SshKeyHelpPanel());
- sshKeyTxt = new TextArea();
- sshKeyTxt.addKeyPressHandler(
- new KeyPressHandler() {
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- event.stopPropagation();
- }
- });
- sshKeyTxt.setVisibleLines(12);
- sshKeyTxt.setCharacterWidth(80);
- sshKeyTxt.getElement().setPropertyBoolean("spellcheck", false);
- sshKeyPanel.add(sshKeyTxt);
- add(sshKeyPanel);
-
- HorizontalPanel buttons = new HorizontalPanel();
- add(buttons);
-
- final Button createButton = new Button("Create");
- createButton.addStyleName("serviceuser-createButton");
- createButton.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- doCreate();
- }
- });
- buttons.add(createButton);
- createButton.setEnabled(false);
- new OnEditEnabler(createButton, usernameTxt);
-
- usernameTxt.setFocus(true);
- createButton.setEnabled(false);
-
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "config")
- .get(
- new AsyncCallback<ConfigInfo>() {
- @Override
- public void onSuccess(ConfigInfo info) {
- onSuccessMessage = info.getOnSuccessMessage();
-
- String infoMessage = info.getInfoMessage();
- if (infoMessage != null && !"".equals(infoMessage)) {
- insert(new HTML(infoMessage), 0);
- }
-
- if (info.getAllowEmail()) {
- Panel emailPanel = new VerticalPanel();
- emailPanel.add(new Label("Email:"));
- emailTxt =
- new TextBox() {
- @Override
- public void onBrowserEvent(Event event) {
- super.onBrowserEvent(event);
- if (event.getTypeInt() == Event.ONPASTE) {
- Scheduler.get()
- .scheduleDeferred(
- new ScheduledCommand() {
- @Override
- public void execute() {
- if (getValue().trim().length() != 0) {
- setEnabled(true);
- }
- }
- });
- }
- }
- };
- emailTxt.addKeyPressHandler(
- new KeyPressHandler() {
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- event.stopPropagation();
- }
- });
- emailTxt.sinkEvents(Event.ONPASTE);
- emailTxt.setVisibleLength(40);
- emailPanel.add(emailTxt);
- insert(emailPanel, 2);
- }
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-
- private void doCreate() {
- final String username = usernameTxt.getValue().trim();
- String sshKey = sshKeyTxt.getText();
- if (sshKey != null) {
- sshKey = sshKey.trim();
- }
-
- ServiceUserInput in = ServiceUserInput.create();
- in.ssh_key(sshKey);
- if (emailTxt != null) {
- in.email(emailTxt.getValue().trim());
- }
- new RestApi("config")
- .id("server")
- .view("serviceuser", "serviceusers")
- .id(username)
- .post(
- in,
- new AsyncCallback<JavaScriptObject>() {
-
- @Override
- public void onSuccess(JavaScriptObject result) {
- clearForm();
- Plugin.get().go("/x/" + Plugin.get().getName() + "/user/" + username);
-
- final DialogBox successDialog = new DialogBox();
- successDialog.setText("Service User Created");
- successDialog.setAnimationEnabled(true);
-
- Panel p = new VerticalPanel();
- p.setStyleName("serviceuser-panel");
- p.add(new Label("The service user '" + username + "' was created."));
- Button okButton = new Button("OK");
- okButton.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- successDialog.hide();
- }
- });
-
- if (onSuccessMessage != null && !"".equals(onSuccessMessage)) {
- p.add(new HTML(onSuccessMessage));
- }
-
- p.add(okButton);
- successDialog.add(p);
-
- successDialog.center();
- successDialog.show();
- }
-
- @Override
- public void onFailure(Throwable caught) {}
- });
- }
-
- private void clearForm() {
- usernameTxt.setValue("");
- if (emailTxt != null) {
- emailTxt.setValue("");
- }
- sshKeyTxt.setValue("");
- }
-
- private static class ServiceUserInput extends JavaScriptObject {
- final native void ssh_key(String s) /*-{ this.ssh_key = s; }-*/;
-
- final native void email(String e) /*-{ this.email = e; }-*/;
-
- static ServiceUserInput create() {
- ServiceUserInput g = (ServiceUserInput) createObject();
- return g;
- }
-
- protected ServiceUserInput() {}
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/EditableValue.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/EditableValue.java
deleted file mode 100644
index 0ab741f..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/EditableValue.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// 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.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.user.client.ui.Anchor;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.InlineLabel;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtexpui.globalkey.client.NpTextBox;
-
-public abstract class EditableValue extends FlowPanel {
- private final Widget labelWidget;
- private final Image edit;
- private final NpTextBox input;
- private final Button save;
- private final Button cancel;
- private Image warning;
-
- EditableValue(String serviceUser, String value) {
- this(serviceUser, value, null);
- }
-
- EditableValue(final String serviceUser, String value, String href) {
- if (href != null) {
- labelWidget = new Anchor(value, href);
- } else {
- labelWidget = new InlineLabel(value);
- }
- edit = new Image(ServiceUserPlugin.RESOURCES.edit());
- edit.addStyleName("serviceuser-editButton");
- edit.setTitle("Edit");
-
- input = new NpTextBox();
- input.setVisibleLength(25);
- input.setValue(value);
- input.setVisible(false);
- save = new Button();
- save.setText("Save");
- save.setVisible(false);
- save.setEnabled(false);
- cancel = new Button();
- cancel.setText("Cancel");
- cancel.setVisible(false);
-
- OnEditEnabler e = new OnEditEnabler(save);
- e.listenTo(input);
-
- edit.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- labelWidget.setVisible(false);
- edit.setVisible(false);
- input.setVisible(true);
- input.setFocus(true);
- save.setVisible(true);
- if (warning != null) {
- warning.setVisible(true);
- }
- cancel.setVisible(true);
- }
- });
- save.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- save.setEnabled(false);
- save(serviceUser, input.getValue().trim());
- }
- });
- input.addKeyPressHandler(
- new KeyPressHandler() {
- @Override
- public void onKeyPress(KeyPressEvent event) {
- if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
- save.setEnabled(false);
- save(serviceUser, input.getValue().trim());
- } else if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) {
- cancel();
- }
- }
- });
- cancel.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- cancel();
- }
- });
-
- add(labelWidget);
- add(edit);
- add(input);
- add(save);
- add(cancel);
- }
-
- private void cancel() {
- labelWidget.setVisible(true);
- edit.setVisible(true);
- input.setVisible(false);
- if (labelWidget instanceof Label) {
- input.setValue(((Label) labelWidget).getText());
- } else {
- input.setValue(((Anchor) labelWidget).getText());
- }
- save.setVisible(false);
- save.setEnabled(false);
- if (warning != null) {
- warning.setVisible(false);
- }
- cancel.setVisible(false);
- }
-
- public void setWarning(String msg) {
- if (warning == null) {
- warning = new Image(ServiceUserPlugin.RESOURCES.warning());
- insert(warning, getWidgetIndex(save));
- warning.setVisible(save.isVisible());
- }
- warning.setTitle(msg);
- }
-
- protected void updateValue(String newValue) {
- if (labelWidget instanceof Label) {
- ((Label) labelWidget).setText(newValue);
- } else {
- ((Anchor) labelWidget).setText(newValue);
- }
- labelWidget.setVisible(true);
- edit.setVisible(true);
- input.setVisible(false);
- input.setValue(newValue);
- save.setVisible(false);
- if (warning != null) {
- warning.setVisible(false);
- }
- save.setEnabled(false);
- cancel.setVisible(false);
- }
-
- protected void updateHref(String newHref) {
- if (labelWidget instanceof Anchor) {
- ((Anchor) labelWidget).setHref(newHref);
- }
- }
-
- protected abstract void save(String serviceUser, final String newValue);
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/GroupInfo.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/GroupInfo.java
deleted file mode 100644
index b398092..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/GroupInfo.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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 GroupInfo extends JavaScriptObject {
- public final native String name() /*-{ return this.name; }-*/;
-
- public final native String url() /*-{ return this.url; }-*/;
-
- protected GroupInfo() {}
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/HttpPasswordInput.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/HttpPasswordInput.java
deleted file mode 100644
index 5549597..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/HttpPasswordInput.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (C) 2015 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 HttpPasswordInput extends JavaScriptObject {
- final native void generate(boolean g) /*-{ if (g) this.generate = g; }-*/;
-
- public static HttpPasswordInput create() {
- return createObject().cast();
- }
-
- protected HttpPasswordInput() {}
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/OnEditEnabler.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/OnEditEnabler.java
deleted file mode 100644
index 815962c..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/OnEditEnabler.java
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (C) 2010 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.Scheduler;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.event.dom.client.ChangeEvent;
-import com.google.gwt.event.dom.client.ChangeHandler;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.event.dom.client.KeyDownEvent;
-import com.google.gwt.event.dom.client.KeyDownHandler;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.dom.client.KeyPressHandler;
-import com.google.gwt.event.dom.client.MouseUpEvent;
-import com.google.gwt.event.dom.client.MouseUpHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.FocusWidget;
-import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwt.user.client.ui.TextBoxBase;
-import com.google.gwt.user.client.ui.ValueBoxBase;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Enables a FocusWidget (e.g. a Button) if an edit is detected from any registered input widget.
- */
-public class OnEditEnabler
- implements KeyPressHandler,
- KeyDownHandler,
- MouseUpHandler,
- ChangeHandler,
- ValueChangeHandler<Object> {
-
- private final FocusWidget widget;
- private Map<TextBoxBase, String> strings = new HashMap<>();
- private String originalValue;
-
- // The first parameter to the constructors must be the FocusWidget to enable,
- // subsequent parameters are widgets to listenTo.
-
- public OnEditEnabler(final FocusWidget w, final TextBoxBase tb) {
- this(w);
- originalValue = tb.getValue().trim();
- listenTo(tb);
- }
-
- public OnEditEnabler(final FocusWidget w, final ListBox lb) {
- this(w);
- listenTo(lb);
- }
-
- public OnEditEnabler(final FocusWidget w, final CheckBox cb) {
- this(w);
- listenTo(cb);
- }
-
- public OnEditEnabler(final FocusWidget w) {
- widget = w;
- }
-
- // Register input widgets to be listened to
-
- public void listenTo(final TextBoxBase tb) {
- strings.put(tb, tb.getText().trim());
- tb.addKeyPressHandler(this);
-
- // Is there another way to capture middle button X11 pastes in browsers
- // which do not yet support ONPASTE events (Firefox)?
- tb.addMouseUpHandler(this);
-
- // Resetting the "original text" on focus ensures that we are
- // up to date with non-user updates of the text (calls to
- // setText()...) and also up to date with user changes which
- // occured after enabling "widget".
- tb.addFocusHandler(
- new FocusHandler() {
- @Override
- public void onFocus(FocusEvent event) {
- strings.put(tb, tb.getText().trim());
- }
- });
-
- // CTRL-V Pastes in Chrome seem only detectable via BrowserEvents or
- // KeyDownEvents, the latter is better.
- tb.addKeyDownHandler(this);
- }
-
- public void listenTo(final ListBox lb) {
- lb.addChangeHandler(this);
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- public void listenTo(final CheckBox cb) {
- cb.addValueChangeHandler((ValueChangeHandler) this);
- }
-
- // Handlers
-
- @Override
- public void onKeyPress(final KeyPressEvent e) {
- on(e);
- }
-
- @Override
- public void onKeyDown(final KeyDownEvent e) {
- on(e);
- }
-
- @Override
- public void onMouseUp(final MouseUpEvent e) {
- on(e);
- }
-
- @Override
- public void onChange(final ChangeEvent e) {
- on(e);
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- public void onValueChange(final ValueChangeEvent e) {
- on(e);
- }
-
- private void on(final GwtEvent<?> e) {
- if (widget.isEnabled()
- || !(e.getSource() instanceof FocusWidget)
- || !((FocusWidget) e.getSource()).isEnabled()) {
- if (e.getSource() instanceof ValueBoxBase) {
- final TextBoxBase box = ((TextBoxBase) e.getSource());
- Scheduler.get()
- .scheduleDeferred(
- new ScheduledCommand() {
- @Override
- public void execute() {
- if (box.getValue().trim().equals(originalValue)) {
- widget.setEnabled(false);
- }
- }
- });
- }
- return;
- }
-
- if (e.getSource() instanceof TextBoxBase) {
- onTextBoxBase((TextBoxBase) e.getSource());
- } else {
- // For many widgets, we can assume that a change is an edit. If
- // a widget does not work that way, it should be special cased
- // above.
- widget.setEnabled(true);
- }
- }
-
- private void onTextBoxBase(final TextBoxBase tb) {
- // The text appears to not get updated until the handlers complete.
- Scheduler.get()
- .scheduleDeferred(
- new ScheduledCommand() {
- @Override
- public void execute() {
- String orig = strings.get(tb);
- if (orig == null) {
- orig = "";
- }
- if (!orig.equals(tb.getText().trim())) {
- widget.setEnabled(true);
- }
- }
- });
- }
-}
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
index 96c543d..47723f1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserInfo.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserInfo.java
@@ -14,34 +14,28 @@
package com.googlesource.gerrit.plugins.serviceuser.client;
-import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.GroupInfo;
-public class ServiceUserInfo extends JavaScriptObject {
+public class ServiceUserInfo {
public final String getDisplayName() {
- if (created_by().username() != null) {
- return created_by().username();
+ if (created_by.username != null) {
+ return created_by.username;
}
- if (created_by()._account_id() != -1) {
- return Integer.toString(created_by()._account_id());
+ if (created_by._accountId != -1) {
+ return Integer.toString(created_by._accountId);
}
return "N/A";
}
- public final native int _account_id() /*-{ return this._account_id || 0; }-*/;
-
- public final native String name() /*-{ return this.name; }-*/;
-
- public final native String username() /*-{ return this.username; }-*/;
-
- public final native String email() /*-{ return this.email; }-*/;
-
- public final native AccountInfo created_by() /*-{ return this.created_by; }-*/;
-
- public final native String created_at() /*-{ return this.created_at; }-*/;
-
- public final native boolean active() /*-{ return this.inactive ? false : true; }-*/;
-
- public final native GroupInfo owner() /*-{ return this.owner; }-*/;
+ public int _account_id;
+ public String name;
+ public String username;
+ public String email;
+ public AccountInfo created_by;
+ public String created_at;
+ public boolean active;
+ public GroupInfo owner;
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
deleted file mode 100644
index 5c30bea..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserListScreen.java
+++ /dev/null
@@ -1,110 +0,0 @@
-// 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.NativeMap;
-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.Anchor;
-import com.google.gwt.user.client.ui.FlexTable;
-import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
-import com.google.gwt.user.client.ui.InlineHyperlink;
-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 = 7;
- 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, "Owner");
- t.setText(0, 4, "Created By");
- t.setText(0, 5, "Created At");
- t.setText(0, 6, "Account State");
-
- 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.setWidget(
- row,
- 0,
- new InlineHyperlink(username, "/x/" + Plugin.get().getName() + "/user/" + username));
- t.setText(row, 1, a.name());
- t.setText(row, 2, a.email());
-
- if (a.owner() != null) {
- if (a.owner().url() != null) {
- t.setWidget(row, 3, new Anchor(a.owner().name(), a.owner().url()));
- } else {
- t.setText(row, 3, a.owner().name());
- }
- }
-
- t.setText(row, 4, a.getDisplayName());
- t.setText(row, 5, a.created_at());
- t.setText(row, 6, !a.active() ? "Inactive" : "");
- 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
deleted file mode 100644
index 393963d..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserPlugin.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.Resources;
-import com.google.gerrit.plugin.client.Plugin;
-import com.google.gerrit.plugin.client.PluginEntryPoint;
-import com.google.gwt.core.client.GWT;
-
-public class ServiceUserPlugin extends PluginEntryPoint {
- public static final Resources RESOURCES = GWT.create(Resources.class);
-
- @Override
- public void onPluginLoad() {
- Plugin.get().screen("create", new CreateServiceUserScreen.Factory());
- Plugin.get().screen("settings", new ServiceUserSettingsScreen.Factory());
- Plugin.get().screen("list", new ServiceUserListScreen.Factory());
- Plugin.get().screenRegex("user/(.*)", new ServiceUserScreen.Factory());
- }
-}
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
deleted file mode 100644
index 78cb65e..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserScreen.java
+++ /dev/null
@@ -1,371 +0,0 @@
-// 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.NativeString;
-import com.google.gerrit.plugin.client.Plugin;
-import com.google.gerrit.plugin.client.rpc.NoContent;
-import com.google.gerrit.plugin.client.rpc.RestApi;
-import com.google.gerrit.plugin.client.screen.Screen;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.Anchor;
-import com.google.gwt.user.client.ui.FlexTable;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.ToggleButton;
-import com.google.gwt.user.client.ui.VerticalPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtexpui.clippy.client.CopyableLabel;
-
-public class ServiceUserScreen extends VerticalPanel {
- static class Factory implements Screen.EntryPoint {
- @Override
- public void onLoad(Screen screen) {
- screen.setPageTitle("Service User " + screen.getToken(1));
- screen.show(new ServiceUserScreen(screen.getToken(1)));
- }
- }
-
- ServiceUserScreen(final String serviceUser) {
- setStyleName("serviceuser-panel");
-
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(serviceUser)
- .get(
- new AsyncCallback<ServiceUserInfo>() {
- @Override
- public void onSuccess(final ServiceUserInfo serviceUserInfo) {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "config")
- .get(
- new AsyncCallback<ConfigInfo>() {
- @Override
- public void onSuccess(final ConfigInfo configInfo) {
- AccountCapabilities.all(
- new AsyncCallback<AccountCapabilities>() {
- @Override
- public void onSuccess(AccountCapabilities ac) {
- boolean isAdmin = ac.canPerform("administrateServer");
- display(
- serviceUserInfo,
- configInfo.getAllowEmail() || isAdmin,
- configInfo.getAllowOwner() || isAdmin,
- configInfo.getAllowHttpPassword() || isAdmin);
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- },
- "administrateServer");
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-
- private void display(
- ServiceUserInfo info, boolean allowEmail, boolean allowOwner, boolean allowHttpPassword) {
- MyTable t = new MyTable();
- t.setStyleName("serviceuser-serviceUserInfoTable");
- t.addRow("Account State", createActiveToggle(info));
- t.addRow("Username", info.username());
- t.addRow(
- "Full Name",
- new EditableValue(info.username(), info.name()) {
- @Override
- protected void save(String serviceUser, final String newValue) {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(serviceUser)
- .view("name")
- .put(
- newValue,
- new AsyncCallback<NativeString>() {
- @Override
- public void onSuccess(NativeString result) {
- updateValue(newValue);
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
- });
- if (allowEmail) {
- t.addRow(
- "Email Address",
- new EditableValue(info.username(), info.email()) {
- @Override
- protected void save(String serviceUser, final String newValue) {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(serviceUser)
- .view("email")
- .put(
- newValue,
- new AsyncCallback<NativeString>() {
- @Override
- public void onSuccess(NativeString result) {
- updateValue(newValue);
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
- });
- } else {
- t.addRow("Email Address", info.email());
- }
- t.addRow("HTTP Password", createHttpPasswordWidget(info.username(), allowHttpPassword));
- t.addRow("Owner Group", createOwnerWidget(info, allowOwner));
- t.addRow("Created By", info.getDisplayName());
- t.addRow("Created At", info.created_at());
- add(t);
-
- add(new SshPanel(info.username()));
- }
-
- private ToggleButton createActiveToggle(final ServiceUserInfo info) {
- final ToggleButton activeToggle = new ToggleButton();
- activeToggle.setStyleName("serviceuser-toggleButton");
- activeToggle.setVisible(false);
- activeToggle.setValue(true);
- activeToggle.setText("Active");
- activeToggle.setValue(false);
- activeToggle.setText("Inactive");
- activeToggle.setValue(info.active());
- activeToggle.setVisible(true);
-
- activeToggle.addValueChangeHandler(
- new ValueChangeHandler<Boolean>() {
- @Override
- public void onValueChange(ValueChangeEvent<Boolean> event) {
- if (event.getValue()) {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(info.username())
- .view("active")
- .put(
- new AsyncCallback<NoContent>() {
- @Override
- public void onSuccess(NoContent result) {}
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- } else {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(info.username())
- .view("active")
- .delete(
- new AsyncCallback<NoContent>() {
- @Override
- public void onSuccess(NoContent result) {}
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
- }
- });
-
- return activeToggle;
- }
-
- private Widget createHttpPasswordWidget(final String serviceUser, boolean allowHttpPassword) {
- if (allowHttpPassword) {
- HorizontalPanel p = new HorizontalPanel();
- final CopyableLabel label = new CopyableLabel("");
- label.setVisible(false);
- p.add(label);
-
- // The redNot icon is only used as temporary measure until gerrit core
- // provides a better icon that symbolizes "clear".
- final Image delete = new Image(ServiceUserPlugin.RESOURCES.redNot());
- delete.addStyleName("serviceuser-deleteButton");
- delete.setTitle("Clear HTTP password");
- delete.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(serviceUser)
- .view("password.http")
- .delete(
- new AsyncCallback<NoContent>() {
- @Override
- public void onSuccess(NoContent noContent) {
- label.setText("");
- label.setVisible(false);
- delete.setVisible(false);
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
- });
- delete.setVisible(true);
- p.add(delete);
-
- Image generate = new Image(ServiceUserPlugin.RESOURCES.gear());
- generate.addStyleName("serviceuser-generateButton");
- generate.setTitle("Generate new HTTP password");
- generate.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- HttpPasswordInput in = HttpPasswordInput.create();
- in.generate(true);
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(serviceUser)
- .view("password.http")
- .put(
- in,
- new AsyncCallback<NativeString>() {
- @Override
- public void onSuccess(NativeString newPassword) {
- label.setText(newPassword.asString());
- label.setVisible(true);
- delete.setVisible(true);
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
- });
- p.add(generate);
- return p;
- }
- return new CopyableLabel("");
- }
-
- private Widget createOwnerWidget(ServiceUserInfo info, boolean allowOwner) {
- if (allowOwner) {
- EditableValue ownerWidget =
- new EditableValue(
- info.username(),
- info.owner() != null ? info.owner().name() : "",
- info.owner() != null ? info.owner().url() : null) {
- @Override
- protected void save(String serviceUser, final String newValue) {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(serviceUser)
- .view("owner")
- .put(
- newValue,
- new AsyncCallback<GroupInfo>() {
- @Override
- public void onSuccess(GroupInfo result) {
- updateValue(result != null ? result.name() : "");
- updateHref(result != null ? result.url() : "");
- Plugin.get().refresh();
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
- };
- StringBuilder ownerWarning = new StringBuilder();
- ownerWarning.append("If ");
- ownerWarning.append(
- info.owner() != null ? "the owner group is changed" : "an owner group is set");
- ownerWarning.append(" only members of the ");
- ownerWarning.append(info.owner() != null ? "new " : "");
- ownerWarning.append("owner group can see and administrate" + " the service user.");
- if (info.owner() != null) {
- ownerWarning.append(
- " If the owner group is removed only the"
- + " creator of the service user can see and administrate"
- + " the service user.");
- } else {
- ownerWarning.append(
- " The creator of the service user can no"
- + " longer see and administrate the service user if she/he"
- + " is not member of the owner group.");
- }
- ownerWidget.setWarning(ownerWarning.toString());
- return ownerWidget;
- }
- if (info.owner() != null && info.owner().url() != null) {
- return new Anchor(info.owner().name(), info.owner().url());
- }
- return new Label(info.owner() != null ? info.owner().name() : "");
- }
-
- private static class MyTable extends FlexTable {
- private static int row = 0;
-
- private void addRow(String label, String value) {
- setWidget(row, 0, new Label(label + ":"));
- setWidget(row, 1, new Label(value));
- row++;
- }
-
- private void addRow(String label, Widget w) {
- setWidget(row, 0, new Label(label + ":"));
- setWidget(row, 1, w);
- row++;
- }
- }
-}
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
deleted file mode 100644
index 1755cda..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/ServiceUserSettingsScreen.java
+++ /dev/null
@@ -1,268 +0,0 @@
-// 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.core.client.JavaScriptObject;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-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.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.Panel;
-import com.google.gwt.user.client.ui.TextArea;
-import com.google.gwt.user.client.ui.VerticalPanel;
-
-public class ServiceUserSettingsScreen extends VerticalPanel {
- static class Factory implements Screen.EntryPoint {
- @Override
- public void onLoad(Screen screen) {
- screen.setPageTitle("Service User Administration");
- screen.show(new ServiceUserSettingsScreen());
- }
- }
-
- private TextArea infoMsgTxt;
- private TextArea onSuccessMsgTxt;
- private CheckBox allowEmailCheckBox;
- private CheckBox allowHttpPasswordCheckBox;
- private CheckBox allowOwnerCheckBox;
- private CheckBox createNotesCheckBox;
- private CheckBox createNotesAsyncCheckBox;
- private StringListPanel blockedUsernamesPanel;
- private StringListPanel groupsPanel;
- private Button saveButton;
-
- ServiceUserSettingsScreen() {
- setStyleName("serviceuser-panel");
-
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "config")
- .get(
- new AsyncCallback<ConfigInfo>() {
- @Override
- public void onSuccess(ConfigInfo info) {
- display(info);
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-
- private void display(ConfigInfo info) {
- Panel infoMsgPanel = new VerticalPanel();
- Panel infoMsgTitelPanel = new HorizontalPanel();
- infoMsgTitelPanel.add(new Label("Info Message"));
- Image infoMsgInfo = new Image(ServiceUserPlugin.RESOURCES.info());
- infoMsgInfo.setTitle(
- "HTML formatted message that should be"
- + " displayed on the service user creation screen.");
- infoMsgTitelPanel.add(infoMsgInfo);
- infoMsgTitelPanel.add(new Label(":"));
- infoMsgPanel.add(infoMsgTitelPanel);
- infoMsgTxt = new TextArea();
- infoMsgTxt.setValue(info.getInfoMessage());
- infoMsgTxt.addKeyPressHandler(
- new KeyPressHandler() {
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- event.stopPropagation();
- }
- });
- infoMsgTxt.setVisibleLines(12);
- infoMsgTxt.setCharacterWidth(80);
- infoMsgTxt.getElement().setPropertyBoolean("spellcheck", false);
- infoMsgPanel.add(infoMsgTxt);
- add(infoMsgPanel);
-
- Panel onSuccessMsgPanel = new VerticalPanel();
- Panel onSuccessMsgTitelPanel = new HorizontalPanel();
- onSuccessMsgTitelPanel.add(new Label("On Success Message"));
- Image onSuccessMsgInfo = new Image(ServiceUserPlugin.RESOURCES.info());
- onSuccessMsgInfo.setTitle(
- "HTML formatted message that should be"
- + " displayed after a service user was successfully created.");
- onSuccessMsgTitelPanel.add(onSuccessMsgInfo);
- onSuccessMsgTitelPanel.add(new Label(":"));
- onSuccessMsgPanel.add(onSuccessMsgTitelPanel);
- onSuccessMsgTxt = new TextArea();
- onSuccessMsgTxt.setValue(info.getOnSuccessMessage());
- onSuccessMsgTxt.addKeyPressHandler(
- new KeyPressHandler() {
- @Override
- public void onKeyPress(final KeyPressEvent event) {
- event.stopPropagation();
- }
- });
- onSuccessMsgTxt.setVisibleLines(12);
- onSuccessMsgTxt.setCharacterWidth(80);
- onSuccessMsgTxt.getElement().setPropertyBoolean("spellcheck", false);
- onSuccessMsgPanel.add(onSuccessMsgTxt);
- add(onSuccessMsgPanel);
-
- Panel allowEmailPanel = new HorizontalPanel();
- allowEmailCheckBox = new CheckBox("Allow Email Address");
- allowEmailCheckBox.setValue(info.getAllowEmail());
- allowEmailPanel.add(allowEmailCheckBox);
- Image allowEmailInfo = new Image(ServiceUserPlugin.RESOURCES.info());
- allowEmailInfo.setTitle(
- "Whether it is allowed to provide an email address "
- + "for a service user. E.g. having an email address allows a service user "
- + "to push commits and tags.");
- allowEmailPanel.add(allowEmailInfo);
- add(allowEmailPanel);
-
- Panel allowHttpPasswordPanel = new HorizontalPanel();
- allowHttpPasswordCheckBox = new CheckBox("Allow HTTP password");
- allowHttpPasswordCheckBox.setValue(info.getAllowHttpPassword());
- allowHttpPasswordPanel.add(allowHttpPasswordCheckBox);
- Image allowHttpPasswordInfo = new Image(ServiceUserPlugin.RESOURCES.info());
- allowHttpPasswordInfo.setTitle(
- "Whether it is allowed to generate an HTTP password "
- + "for a service user. E.g. having an HTTP password allows a service user "
- + "to use the Gerrit REST API.");
- allowHttpPasswordPanel.add(allowHttpPasswordInfo);
- add(allowHttpPasswordPanel);
-
- Panel allowOwnerPanel = new HorizontalPanel();
- allowOwnerCheckBox = new CheckBox("Allow Owner Group");
- allowOwnerCheckBox.setValue(info.getAllowOwner());
- allowOwnerPanel.add(allowOwnerCheckBox);
- Image allowOwnerInfo = new Image(ServiceUserPlugin.RESOURCES.info());
- allowOwnerInfo.setTitle("Whether it is allowed to set an owner group " + "for a service user.");
- allowOwnerPanel.add(allowOwnerInfo);
- add(allowOwnerPanel);
-
- Panel createNotesPanel = new HorizontalPanel();
- createNotesCheckBox = new CheckBox("Create Git Notes");
- createNotesCheckBox.setValue(info.getCreateNotes());
- createNotesPanel.add(createNotesCheckBox);
- Image createNotesInfo = new Image(ServiceUserPlugin.RESOURCES.info());
- createNotesInfo.setTitle(
- "Whether commits of a service user should be "
- + "annotated by a Git note that contains information about the current "
- + "owners of the service user. This allows to find a real person that "
- + "is responsible for this commit. To get such a Git note for each commit "
- + "of a service user the 'Forge Committer' access right must be blocked "
- + "for service users.");
- createNotesPanel.add(createNotesInfo);
- add(createNotesPanel);
-
- Panel createNotesAsyncPanel = new HorizontalPanel();
- createNotesAsyncCheckBox = new CheckBox("Create Git Notes Asynchronously");
- createNotesAsyncCheckBox.setValue(info.getCreateNotesAsync());
- createNotesAsyncCheckBox.setEnabled(info.getCreateNotes());
- createNotesAsyncPanel.add(createNotesAsyncCheckBox);
- Image createNotesAsyncInfo = new Image(ServiceUserPlugin.RESOURCES.info());
- createNotesAsyncInfo.setTitle(
- "Whether the Git notes on commits that are "
- + "pushed by a service user should be created asynchronously.");
- createNotesAsyncPanel.add(createNotesAsyncInfo);
- add(createNotesAsyncPanel);
-
- createNotesCheckBox.addValueChangeHandler(
- new ValueChangeHandler<Boolean>() {
- @Override
- public void onValueChange(ValueChangeEvent<Boolean> event) {
- createNotesAsyncCheckBox.setEnabled(event.getValue());
- }
- });
-
- saveButton = new Button("Save");
- saveButton.addStyleName("serviceuser-saveButton");
- saveButton.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- doSave();
- }
- });
-
- blockedUsernamesPanel =
- new StringListPanel("Blocked Usernames", "Username", info.getBlockedNames(), saveButton);
- blockedUsernamesPanel.setInfo(
- "List of usernames which are "
- + "forbidden to be used as name for a service user. "
- + "The blocked usernames are case insensitive.");
- add(blockedUsernamesPanel);
-
- groupsPanel =
- new StringListPanel("Groups", "Group Name", info.getGroups().keySet(), saveButton);
- groupsPanel.setInfo(
- "Names of groups to which newly created " + "service users should be added automatically.");
- add(groupsPanel);
-
- HorizontalPanel buttons = new HorizontalPanel();
- add(buttons);
-
- buttons.add(saveButton);
- saveButton.setEnabled(false);
- OnEditEnabler onEditEnabler = new OnEditEnabler(saveButton, infoMsgTxt);
- onEditEnabler.listenTo(onSuccessMsgTxt);
- onEditEnabler.listenTo(allowEmailCheckBox);
- onEditEnabler.listenTo(allowHttpPasswordCheckBox);
- onEditEnabler.listenTo(allowOwnerCheckBox);
- onEditEnabler.listenTo(createNotesCheckBox);
- onEditEnabler.listenTo(createNotesAsyncCheckBox);
-
- infoMsgTxt.setFocus(true);
- saveButton.setEnabled(false);
- }
-
- private void doSave() {
- ConfigInfo in = ConfigInfo.create();
- in.setInfoMessage(infoMsgTxt.getValue());
- in.setOnSuccessMessage(onSuccessMsgTxt.getValue());
- in.setAllowEmail(allowEmailCheckBox.getValue());
- in.setAllowHttpPassword(allowHttpPasswordCheckBox.getValue());
- in.setAllowOwner(allowOwnerCheckBox.getValue());
- in.setCreateNotes(createNotesCheckBox.getValue());
- if (createNotesAsyncCheckBox.isEnabled()) {
- in.setCreateNotesAsync(createNotesAsyncCheckBox.getValue());
- }
- in.setBlockedNames(blockedUsernamesPanel.getValues());
- in.setGroups(groupsPanel.getValues());
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "config")
- .put(
- in,
- new AsyncCallback<JavaScriptObject>() {
-
- @Override
- public void onSuccess(JavaScriptObject result) {
- saveButton.setEnabled(false);
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/SshKeyHelpPanel.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/SshKeyHelpPanel.java
deleted file mode 100644
index 9845b23..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/SshKeyHelpPanel.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.user.client.ui.DisclosurePanel;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.HTML;
-
-public class SshKeyHelpPanel extends FlowPanel {
-
- SshKeyHelpPanel() {
- DisclosurePanel dp = new DisclosurePanel("How to generate an SSH Key");
- StringBuilder b = new StringBuilder();
- b.append("<ol>")
- .append("<li>From the Terminal or Git Bash, run <em>ssh-keygen</em></li>")
- .append("<li>")
- .append(
- "Enter a path for the key, e.g. <em>id_rsa</em>. If you are generating the key<br />")
- .append("on your local system take care to not overwrite your own SSH key.")
- .append("</li>")
- .append("<li>")
- .append("Enter a passphrase only if the service where you intend to use this<br />")
- .append("service user is able to deal with passphrases, otherwise leave it blank.<br />")
- .append("Remember this passphrase, as you will need it to unlock the key.")
- .append("</li>")
- .append("<li>")
- .append(
- "Open <em>id_rsa.pub</em> and copy & paste the contents into the box below.<br />")
- .append("Note that <em>id_rsa.pub</em> is your public key and can be shared,<br />")
- .append("while <em>id_rsa</em> is your private key and should be kept secret.")
- .append("</li>")
- .append("</ol>");
- dp.add(new HTML(b.toString()));
- add(dp);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/SshKeyInfo.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/SshKeyInfo.java
deleted file mode 100644
index 52a7044..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/SshKeyInfo.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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 SshKeyInfo extends JavaScriptObject {
- public final native int seq() /*-{ return this.seq || 0; }-*/;
-
- public final native String sshPublicKey() /*-{ return this.ssh_public_key; }-*/;
-
- public final native String encodedKey() /*-{ return this.encoded_key; }-*/;
-
- public final native String algorithm() /*-{ return this.algorithm; }-*/;
-
- public final native String comment() /*-{ return this.comment; }-*/;
-
- public final native boolean isValid() /*-{ return this['valid'] ? true : false; }-*/;
-
- protected SshKeyInfo() {}
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/SshPanel.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/SshPanel.java
deleted file mode 100644
index 10acc65..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/SshPanel.java
+++ /dev/null
@@ -1,382 +0,0 @@
-// 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.gerrit.plugin.client.Plugin;
-import com.google.gerrit.plugin.client.rpc.NoContent;
-import com.google.gerrit.plugin.client.rpc.RestApi;
-import com.google.gwt.core.client.JsArray;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FlexTable;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.HasHorizontalAlignment;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.Panel;
-import com.google.gwt.user.client.ui.VerticalPanel;
-import com.google.gwtexpui.clippy.client.CopyableLabel;
-import com.google.gwtexpui.globalkey.client.NpTextArea;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
-class SshPanel extends Composite {
- private final String serviceUser;
-
- private SshKeyTable keys;
-
- private Button showAddKeyBlock;
- private Panel addKeyBlock;
- private Button closeAddKeyBlock;
- private Button clearNew;
- private Button addNew;
- private NpTextArea addTxt;
- private Button deleteKey;
-
- private Panel serverKeys;
-
- private int loadCount;
-
- SshPanel(String serviceUser) {
- this.serviceUser = serviceUser;
-
- FlowPanel body = new FlowPanel();
-
- showAddKeyBlock = new Button("Add Key ...");
- showAddKeyBlock.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- showAddKeyBlock(true);
- }
- });
-
- keys = new SshKeyTable();
- body.add(keys);
- {
- final FlowPanel fp = new FlowPanel();
- deleteKey = new Button("Delete");
- deleteKey.setEnabled(false);
- deleteKey.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- keys.deleteChecked();
- }
- });
- fp.add(deleteKey);
- fp.add(showAddKeyBlock);
- body.add(fp);
- }
-
- addKeyBlock = new VerticalPanel();
- addKeyBlock.setVisible(false);
- addKeyBlock.setStyleName("serviceuser-addSshKeyPanel");
- addKeyBlock.add(new Label("Add SSH Public Key"));
- addKeyBlock.add(new SshKeyHelpPanel());
-
- addTxt = new NpTextArea();
- addTxt.setVisibleLines(12);
- addTxt.setCharacterWidth(80);
- addTxt.setSpellCheck(false);
- addKeyBlock.add(addTxt);
-
- final HorizontalPanel buttons = new HorizontalPanel();
- addKeyBlock.add(buttons);
-
- clearNew = new Button("Clear");
- clearNew.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- addTxt.setText("");
- addTxt.setFocus(true);
- }
- });
- buttons.add(clearNew);
-
- addNew = new Button("Add");
- addNew.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- doAddNew();
- }
- });
- buttons.add(addNew);
-
- closeAddKeyBlock = new Button("Close");
- closeAddKeyBlock.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- showAddKeyBlock(false);
- }
- });
- buttons.add(closeAddKeyBlock);
- buttons.setCellWidth(closeAddKeyBlock, "100%");
- buttons.setCellHorizontalAlignment(closeAddKeyBlock, HasHorizontalAlignment.ALIGN_RIGHT);
-
- body.add(addKeyBlock);
-
- serverKeys = new FlowPanel();
- body.add(serverKeys);
-
- initWidget(body);
- }
-
- void setKeyTableVisible(final boolean on) {
- keys.setVisible(on);
- deleteKey.setVisible(on);
- closeAddKeyBlock.setVisible(on);
- }
-
- void doAddNew() {
- final String txt = addTxt.getText();
- if (txt != null && txt.length() > 0) {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(serviceUser)
- .view("sshkeys")
- .post(
- txt,
- new AsyncCallback<SshKeyInfo>() {
- @Override
- public void onSuccess(SshKeyInfo k) {
- addTxt.setText("");
- keys.addOneKey(k);
- if (!keys.isVisible()) {
- showAddKeyBlock(false);
- setKeyTableVisible(true);
- keys.updateDeleteButton();
- }
- }
-
- @Override
- public void onFailure(final Throwable caught) {
- // never invoked
- }
- });
- }
- }
-
- @Override
- protected void onLoad() {
- super.onLoad();
- refreshSshKeys();
- }
-
- private void refreshSshKeys() {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(serviceUser)
- .view("sshkeys")
- .get(
- new AsyncCallback<JsArray<SshKeyInfo>>() {
- @Override
- public void onSuccess(JsArray<SshKeyInfo> result) {
- keys.display(Natives.asList(result));
- if (result.length() == 0 && keys.isVisible()) {
- showAddKeyBlock(true);
- }
- if (++loadCount == 2) {
- display();
- }
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-
- void display() {}
-
- private void showAddKeyBlock(boolean show) {
- showAddKeyBlock.setVisible(!show);
- addKeyBlock.setVisible(show);
- }
-
- private class SshKeyTable extends FlexTable {
- private final Map<Integer, SshKeyInfo> sshKeyInfos;
- private ValueChangeHandler<Boolean> updateDeleteHandler;
-
- SshKeyTable() {
- this.sshKeyInfos = new HashMap<>();
- setStyleName("serviceuser-sshKeyTable");
- setWidth("");
- setText(0, 2, "Status");
- setText(0, 3, "Algorithm");
- setText(0, 4, "Key");
- setText(0, 5, "Comment");
-
- FlexCellFormatter fmt = getFlexCellFormatter();
- fmt.addStyleName(0, 1, "iconHeader");
- fmt.addStyleName(0, 2, "dataHeader");
- fmt.addStyleName(0, 3, "dataHeader");
- fmt.addStyleName(0, 4, "dataHeader");
- fmt.addStyleName(0, 5, "dataHeader");
-
- fmt.addStyleName(0, 1, "topMostCell");
- fmt.addStyleName(0, 2, "topMostCell");
- fmt.addStyleName(0, 3, "topMostCell");
- fmt.addStyleName(0, 4, "topMostCell");
- fmt.addStyleName(0, 5, "topMostCell");
-
- updateDeleteHandler =
- new ValueChangeHandler<Boolean>() {
- @Override
- public void onValueChange(ValueChangeEvent<Boolean> event) {
- updateDeleteButton();
- }
- };
- }
-
- void deleteChecked() {
- final HashSet<Integer> sequenceNumbers = new HashSet<>();
- for (int row = 1; row < getRowCount(); row++) {
- SshKeyInfo k = getRowItem(row);
- if (k != null && ((CheckBox) getWidget(row, 1)).getValue()) {
- sequenceNumbers.add(k.seq());
- }
- }
- if (sequenceNumbers.isEmpty()) {
- updateDeleteButton();
- } else {
- for (int seq : sequenceNumbers) {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "serviceusers")
- .id(serviceUser)
- .view("sshkeys")
- .id(seq)
- .delete(
- new AsyncCallback<NoContent>() {
- @Override
- public void onSuccess(NoContent result) {
- for (int row = 1; row < getRowCount(); ) {
- SshKeyInfo k = getRowItem(row);
- if (k != null && sequenceNumbers.contains(k.seq())) {
- removeRow(row);
- } else {
- row++;
- }
- }
- if (getRowCount() == 1) {
- display(Collections.<SshKeyInfo>emptyList());
- } else {
- updateDeleteButton();
- }
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
- }
- }
-
- void display(List<SshKeyInfo> result) {
- if (result.isEmpty()) {
- setKeyTableVisible(false);
- showAddKeyBlock(true);
- } else {
- while (1 < getRowCount()) removeRow(getRowCount() - 1);
- for (SshKeyInfo k : result) {
- addOneKey(k);
- }
- setKeyTableVisible(true);
- deleteKey.setEnabled(false);
- }
- }
-
- void addOneKey(SshKeyInfo k) {
- FlexCellFormatter fmt = getFlexCellFormatter();
- int row = getRowCount();
- insertRow(row);
- getCellFormatter().addStyleName(row, 0, "iconCell");
- getCellFormatter().addStyleName(row, 0, "leftMostCell");
-
- CheckBox sel = new CheckBox();
- sel.addValueChangeHandler(updateDeleteHandler);
-
- setWidget(row, 1, sel);
- if (k.isValid()) {
- setText(row, 2, "");
- fmt.removeStyleName(row, 2, "serviceuser-sshKeyPanelInvalid");
- } else {
- setText(row, 2, "Invalid Key");
- fmt.addStyleName(row, 2, "serviceuser-sshKeyPanelInvalid");
- }
- setText(row, 3, k.algorithm());
-
- CopyableLabel keyLabel = new CopyableLabel(k.sshPublicKey());
- keyLabel.setPreviewText(elide(k.encodedKey(), 40));
- setWidget(row, 4, keyLabel);
-
- setText(row, 5, k.comment());
-
- fmt.addStyleName(row, 1, "iconCell");
- fmt.addStyleName(row, 4, "serviceuser-sshKeyPanelEncodedKey");
- for (int c = 2; c <= 5; c++) {
- fmt.addStyleName(row, c, "dataCell");
- }
-
- setRowItem(row, k);
- }
-
- void updateDeleteButton() {
- boolean on = false;
- for (int row = 1; row < getRowCount(); row++) {
- CheckBox sel = (CheckBox) getWidget(row, 1);
- if (sel.getValue()) {
- on = true;
- break;
- }
- }
- deleteKey.setEnabled(on);
- }
-
- private SshKeyInfo getRowItem(int row) {
- return sshKeyInfos.get(row);
- }
-
- private void setRowItem(int row, SshKeyInfo sshKeyInfo) {
- sshKeyInfos.put(row, sshKeyInfo);
- }
- }
-
- static String elide(String s, int len) {
- if (s == null || s.length() < len || len <= 10) {
- return s;
- }
- return s.substring(0, len - 10) + "..." + s.substring(s.length() - 10);
- }
-}
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
deleted file mode 100644
index c2fff99..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/client/StringListPanel.java
+++ /dev/null
@@ -1,202 +0,0 @@
-// 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.Image;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwtexpui.globalkey.client.NpTextBox;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-public class StringListPanel extends FlowPanel {
- private final NpTextBox input;
- private final StringListTable t;
- private final Button deleteButton;
- private final HorizontalPanel titlePanel;
- private Image info;
-
- StringListPanel(String title, String fieldName, JsArrayString values, final FocusWidget w) {
- this(title, fieldName, Natives.asList(values), w);
- }
-
- StringListPanel(String title, String fieldName, Collection<String> values, final FocusWidget w) {
- titlePanel = new HorizontalPanel();
- Label titleLabel = new Label(title);
- titleLabel.setStyleName("serviceuser-smallHeading");
- titlePanel.add(titleLabel);
- add(titlePanel);
- 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);
- }
-
- void setInfo(String msg) {
- if (info == null) {
- info = new Image(ServiceUserPlugin.RESOURCES.info());
- titlePanel.add(info);
- }
- info.setTitle(msg);
- }
-
- 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(Collection<String> values) {
- int row = 1;
- for (String v : values) {
- populate(row, v);
- row++;
- }
- }
-
- List<String> getValues() {
- List<String> values = new ArrayList<>();
- 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
deleted file mode 100644
index c996fa0..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/public/serviceuser.css
+++ /dev/null
@@ -1,141 +0,0 @@
-.serviceuser-panel {
- border-spacing: 0px 5px;
-}
-
-.serviceuser-createButton, .serviceuser-saveButton {
- margin-left: 10px !important;
-}
-
-.serviceuser-serviceUserTable,
-.serviceuser-sshKeyTable,
-.serviceuser-stringListTable {
- border-collapse: separate;
- border-spacing: 0;
-}
-
-.serviceuser-serviceUserTable .leftMostCell,
-.serviceuser-sshKeyTable .leftMostCell,
-.serviceuser-stringListTable .leftMostCell {
- border-left: 1px solid #EEE;
-}
-
-.serviceuser-serviceUserTable .topMostCell,
-.serviceuser-sshKeyTable .topMostCell,
-.serviceuser-stringListTable .topMostCell {
- border-top: 1px solid #EEE;
-}
-
-.serviceuser-serviceUserTable .dataHeader,
-.serviceuser-sshKeyTable .dataHeader,
-.serviceuser-stringListTable .dataHeader {
- border: 1px solid #FFF;
- padding: 2px 6px 1px;
- background-color: #EEE;
- font-style: italic;
- white-space: nowrap;
- color: textColor;
-}
-
-.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-stringListTable .dataCell {
- padding-left: 5px;
- padding-right: 5px;
- border-right: 1px solid #EEE;
- border-bottom: 1px solid #EEE;
- vertical-align: middle;
- height: 20px;
-}
-
-.serviceuser-sshKeyTable .iconCell,
-.serviceuser-stringListTable .iconCell {
- width: 1px;
- padding: 0px;
- vertical-align: middle;
- border-bottom: 1px solid #EEE;
-}
-
-.serviceuser-sshKeyPanelEncodedKey {
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
- font-family: mono-font;
- font-size: small;
-}
-
-.serviceuser-sshKeyPanelInvalid {
- white-space: nowrap;
- color: red;
- font-weight: bold;
-}
-
-.serviceuser-addSshKeyPanel {
- margin-top: 10px;
- background-color: #EEE;
- padding: 5px 5px 5px 5px;
-}
-
-.serviceuser-serviceUserInfoTable {
- margin-bottom: 10px;
-}
-
-.serviceuser-editButton,
-.serviceuser-deleteButton,
-.serviceuser-generateButton {
- float: right;
- cursor: pointer;
- margin-left: 2px;
-}
-
-.serviceuser-toggleButton {
- position: relative;
- height: 19px;
- width: 140px;
- background: #FFF;
- color: #000;
- text-shadow: none;
- border: 1px solid #EEE !important;
-}
-.serviceuser-toggleButton .html-face {
- position: absolute;
- top: 0;
- width: 68px;
- height: 17px;
- line-height: 17px;
- text-align: center;
- border-width: 1px;
-}
-
-.serviceuser-toggleButton-up,
-.serviceuser-toggleButton-up-hovering,
-.serviceuser-toggleButton-up-disabled,
-.serviceuser-toggleButton-down,
-.serviceuser-toggleButton-down-hovering,
-.serviceuser-toggleButton-down-disabled {
- padding: 0;
- border: 0;
-}
-.serviceuser-toggleButton-up .html-face,
-.serviceuser-toggleButton-up-hovering .html-face {
- left: 0;
- background: #FCB;
- border-style: outset;
-}
-.serviceuser-toggleButton-down .html-face,
-.serviceuser-toggleButton-down-hovering .html-face {
- right: 0;
- background: #BFC;
- border-style: inset;
-}
-
-.serviceuser-smallHeading {
- margin-top: 5px;
- font-weight: bold;
-}
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index e5ad4c7..17a4e29 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -6,8 +6,8 @@
in Jenkins. A service user is not able to login into the Gerrit WebUI
and it cannot push commits or tags.
-This plugin supports the creation of service users via [SSH](cmd-create.md),
-[REST](rest-api-config.md) and in the [WebUI](#webui).
+This plugin supports the creation of service users via [SSH](cmd-create.md) and
+[REST](rest-api-config.md).
To create a service user a user must be a member of a group that is
granted the 'Create Service User' capability (provided by this plugin)
@@ -20,12 +20,6 @@
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
-----------------------
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index 3dd3a01..49709ef 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -19,6 +19,13 @@
bazel-bin/plugins/@PLUGIN@/@PLUGIN@.jar
```
+To execute the tests run either one of:
+
+```
+ bazel test --test_tag_filters=@PLUGIN@ //...
+ bazel test plugins/@PLUGIN@:@PLUGIN@_tests
+```
+
This project can be imported into the Eclipse IDE.
Add the plugin name to the `CUSTOM_PLUGINS` set in
Gerrit core in `tools/bzl/plugins.bzl`, and execute:
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 1380b73..f52421e 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -29,8 +29,8 @@
<a id="onSuccessMessage">
`plugin.@PLUGIN@.onSuccessMessage`
-: HTML formatted message that should be displayed after a service
- user was successfully created.
+: Message that should be displayed after a service user was
+ successfully created.
<a id="allowEmail">
`plugin.@PLUGIN@.allowEmail`
diff --git a/src/main/resources/Documentation/rest-api-config.md b/src/main/resources/Documentation/rest-api-config.md
index 302be07..3999e60 100644
--- a/src/main/resources/Documentation/rest-api-config.md
+++ b/src/main/resources/Documentation/rest-api-config.md
@@ -706,8 +706,8 @@
* _info_: HTML formatted message that should be displayed on the
service user creation screen.
-* _on\_success_: HTML formatted message that should be displayed after
- a service user was successfully created.
+* _on\_success_: Message that should be displayed after a service user
+ was successfully created.
* _allow\_email_: Whether it is allowed to provide an email address for
a service user (not set if `false`).
* _allow\_http\_password_: Whether it is allowed to generate an HTTP
@@ -733,8 +733,8 @@
* _info_: HTML formatted message that should be displayed on the
service user creation screen.
-* _on\_success_: HTML formatted message that should be displayed after
- a service user was successfully created.
+* _on\_success_: Message that should be displayed after a service user
+ was successfully created.
* _allow\_email_: Whether it is allowed to provide an email address for
a service user (not set if `false`).
* _allow\_http\_password_: Whether it is allowed to generate an HTTP
diff --git a/src/main/resources/static/gr-serviceuser-create.html b/src/main/resources/static/gr-serviceuser-create.html
new file mode 100644
index 0000000..763c47d
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-create.html
@@ -0,0 +1,91 @@
+<!--
+@license
+Copyright (C) 2019 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.
+-->
+
+<dom-module id="gr-serviceuser-create">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-subpage-styles"></style>
+ <style include="gr-form-styles"></style>
+ <style>
+ main {
+ margin: 2em auto;
+ max-width: 50em;
+ }
+ </style>
+ <main class="gr-form-styles read-only">
+ <div class="topHeader">
+ <h2>Create Service User</h2>
+ </div>
+ <fieldset id="infoMessage"
+ hidden$="[[!_infoMessageEnabled]]">
+ </fieldset>
+ <fieldset>
+ <section>
+ <span class="title">Username</span>
+ <span class="value">
+ <input id="serviceUserNameInput"
+ bind-value="{{_newUsername}}"
+ is="iron-input"
+ type="text"
+ on-keyup="_validateData">
+ </span>
+ </section>
+ <section hidden$="[[!_emailEnabled]]">
+ <span class="title">Email</span>
+ <span class="value">
+ <input id="serviceUserEmailInput"
+ bind-value="{{_newEmail}}"
+ is="iron-input"
+ type="text"
+ on-keyup="_validateData">
+ </span>
+ </section>
+ </fieldset>
+ <fieldset>
+ <section>
+ <span class="title">Public SSH key</span>
+ <span class="value">
+ <iron-autogrow-textarea id="newKey"
+ bind-value="{{_newKey}}"
+ placeholder="New SSH Key"
+ on-keyup="_validateData">
+ </iron-autogrow-textarea>
+ </span>
+ </section>
+ </fieldset>
+ <gr-button id="createButton"
+ on-click="_handleCreateServiceUser"
+ disabled="[[!_enableButton]]">
+ Create
+ </gr-button>
+ <gr-overlay id="successDialogOverlay" with-backdrop>
+ <gr-dialog id="successDialog"
+ confirm-label="OK"
+ cancel-label=""
+ on-confirm="_forwardToDetails"
+ confirm-on-enter>
+ <div slot="header">
+ Success
+ </div>
+ <div id="successMessage" slot="main">
+ </div>
+ </gr-dialog>
+ </gr-overlay>
+ </main>
+ </template>
+ <script src="gr-serviceuser-create.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-serviceuser-create.js b/src/main/resources/static/gr-serviceuser-create.js
new file mode 100644
index 0000000..df5d9a6
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-create.js
@@ -0,0 +1,150 @@
+/**
+ * @license
+ * Copyright (C) 2016 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.
+ */
+
+(function() {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-serviceuser-create',
+ _legacyUndefinedCheck: true,
+
+ properties: {
+ _infoMessageEnabled: {
+ type: Boolean,
+ value: false,
+ },
+ _infoMessage: String,
+ _successMessageEnabled: {
+ type: Boolean,
+ value: false,
+ },
+ _successMessage: String,
+ _newUsername: String,
+ _emailEnabled: {
+ type: Boolean,
+ value: false,
+ },
+ _newEmail: String,
+ _newKey: String,
+ _dataValid: {
+ type: Boolean,
+ value: false,
+ },
+ _isAdding: {
+ type: Boolean,
+ value: false,
+ },
+ _enableButton: {
+ type: Boolean,
+ value: false,
+ },
+ _accountId: String,
+ },
+
+ attached() {
+ this._getConfig();
+ },
+
+ _forwardToDetails() {
+ page.show(
+ this.plugin.screenUrl()
+ + '/user/'
+ + this._accountId);
+ },
+
+ _getConfig() {
+ return this.plugin.restApi('/config/server/serviceuser~config/').get('')
+ .then(config => {
+ if (!config) {
+ return;
+ }
+
+ if (config.info && config.info != '') {
+ this._infoMessageEnabled = true;
+ this._infoMessage = config.info;
+ this.$.infoMessage.innerHTML = this._infoMessage;
+ }
+
+ if (config.on_success && config.on_success != '') {
+ this._successMessageEnabled = true;
+ this._successMessage = config.on_success;
+ this.$.successMessage.innerHTML = this._successMessage;
+ }
+
+ this._emailEnabled = config.allow_email;
+ });
+ },
+
+ _validateData() {
+ this._dataValid = this._validateName(this._newUsername)
+ && this._validateEmail(this._newEmail)
+ && this._validateKey(this._newKey);
+ this._computeButtonEnabled();
+ },
+
+ _validateName(username) {
+ if (username && username.trim().length > 0) {
+ return true;
+ }
+
+ return false;
+ },
+
+ _validateEmail(email) {
+ if (!email || email.trim().length == 0 || email.includes('@')) {
+ return true;
+ }
+
+ return false;
+ },
+
+ _validateKey(key) {
+ if (!key || !key.trim()) {
+ return false;
+ }
+
+ return true;
+ },
+
+ _computeButtonEnabled() {
+ this._enableButton = this._dataValid && !this._isAdding;
+ },
+
+ _handleCreateServiceUser() {
+ this._isAdding = true;
+ this._computeButtonEnabled();
+ const body = {
+ ssh_key: this._newKey.trim(),
+ email: this._newEmail ? this._newEmail.trim() : null,
+ };
+ return this.plugin.restApi('/config/server/serviceuser~serviceusers/')
+ .post(this._newUsername, body)
+ .then(response => {
+ this._accountId = response._account_id;
+ if (this._successMessage) {
+ this.$.successDialogOverlay.open();
+ } else {
+ this._forwardToDetails();
+ }
+ }).catch(response => {
+ this.fire('show-error', {message: response});
+ this._isAdding = false;
+ this._computeButtonEnabled();
+ });
+ },
+ });
+})();
diff --git a/src/main/resources/static/gr-serviceuser-detail.html b/src/main/resources/static/gr-serviceuser-detail.html
new file mode 100644
index 0000000..28d1d93
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-detail.html
@@ -0,0 +1,163 @@
+<!--
+@license
+Copyright (C) 2019 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.
+-->
+
+<link rel="import" href="./gr-serviceuser-ssh-panel.html">
+<link rel="import" href="./gr-serviceuser-http-password.html">
+
+<dom-module id="gr-serviceuser-detail">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-subpage-styles"></style>
+ <style include="gr-form-styles"></style>
+ <style>
+ div.serviceuser-detail {
+ margin: 2em auto;
+ max-width: 50em;
+ }
+
+ h1#Title {
+ margin-bottom: 1em;
+ }
+
+ p#ownerChangeWarning {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ }
+
+ span#gr_serviceuser_activity {
+ border-radius: 1em;
+ width: 10em;
+ padding: 0.3em;
+ font-weight: bold;
+ text-align: center;
+ }
+
+ span.value {
+ width: 50%;
+ }
+
+ input.wide {
+ width: 100%;
+ }
+
+ span.Active {
+ background-color: #9fcc6b;
+ }
+
+ span.Inactive {
+ background-color: #f7a1ad;
+ }
+ </style>
+ <div class="serviceuser-detail">
+ <main class="gr-form-styles read-only">
+ <div id="loading"
+ class$="[[_computeLoadingClass(_loading)]]">
+ Loading...
+ </div>
+ <div id="loadedContent"
+ class$="[[_computeLoadingClass(_loading)]]">
+ <h1 id="Title">Service User "[[_serviceUser.name]]"</h1>
+ <div id="form">
+ <fieldset>
+ <fieldset>
+ <h2 id="accountState">Account State</h2>
+ <section>
+ <span class="title">Current State</span>
+ <span id="gr_serviceuser_activity"
+ class$="value [[_active(_serviceUser)]]">
+ [[_active(_serviceUser)]]
+ </span>
+ </section>
+ <gr-button id="statusToggleButton" on-click="_toggleStatus" disabled="[[_loading]]">
+ [[_statusButtonText]]</gr-button>
+ </fieldset>
+ <fieldset>
+ <h2 id="userDataHeader">User Data</h2>
+ <section>
+ <span class="title">Username</span>
+ <span class="value">[[_serviceUser.username]]</span>
+ </section>
+ <section>
+ <span class="title">Full Name</span>
+ <span class="value">
+ <input id="serviceUserFullNameInput" class="wide" bind-value="{{_newFullName}}"
+ is="iron-input" type="text" disabled="[[_changingPrefs]]"
+ placeholder$="[[_serviceUser.name]]" on-keyup="_computePrefsChanged">
+ </span>
+ </section>
+ <section>
+ <span class="title">Email Address</span>
+ <span class="value" hidden$="[[!_allowEmail]]">
+ <input id="serviceUserEmailInput" class="wide" bind-value="{{_newEmail}}"
+ is="iron-input" type="text" disabled="[[_changingPrefs]]"
+ placeholder="[[_serviceUser.email]]" on-keyup="_computePrefsChanged">
+ </span>
+ <span class="value" hidden$="[[_allowEmail]]">[[_serviceUser.email]]</span>
+ </section>
+ <section>
+ <span class="title">Owner Group</span>
+ <span class="value" hidden$="[[!_allowOwner]]">
+ <gr-autocomplete id="serviceUserOwnerInput" text="{{_getOwnerGroup(_serviceUser)}}"
+ value="{{_newOwner}}" query="[[_query]]" disabled="[[_changingPrefs]]"
+ on-commit="_computePrefsChanged" on-keyup="_computePrefsChanged">
+ [[_getOwnerGroup(_serviceUser)]]
+ </gr-autocomplete>
+ </span>
+ <span class="value" hidden$="[[_allowOwner]]">[[_getOwnerGroup(_serviceUser)]]</span>
+ </section>
+ <p id="ownerChangeWarning" class="style-scope gr-settings-view" hidden$="[[!_newOwner]]">
+ [[_ownerChangeWarning]]
+ </p>
+ <gr-button id="savePrefs" on-click="_handleSavePreferences" disabled="[[!_prefsChanged]]">
+ Save changes
+ </gr-button>
+ </fieldset>
+ <fieldset>
+ <h2 id="creationHeader">Creation</h2>
+ <section>
+ <span class="title">Created By</span>
+ <span class="value">[[_getCreator(_serviceUser)]]</span>
+ </section>
+ <section>
+ <span class="title">Created At</span>
+ <span class="value">[[_serviceUser.created_at]]</span>
+ </section>
+ </fieldset>
+ <fieldset>
+ <fieldset>
+ <h2 id="credentialsHeader">Credentials</h2>
+ </fieldset>
+ <fieldset hidden$="[[!_allowHttpPassword]]">
+ <h3 id="HTTPCredentials">HTTP Credentials</h3>
+ <fieldset>
+ <gr-serviceuser-http-password id="httpPass">
+ </gr-http-password>
+ </fieldset>
+ </fieldset>
+ <fieldset>
+ <h3 id="SSHKeys">SSH keys</h3>
+ <gr-serviceuser-ssh-panel id="sshEditor"></gr-serviceuser-ssh-panel>
+ </fieldset>
+ </fieldset>
+ </fieldset>
+ </div>
+ </div>
+ </main>
+ </div>
+ </template>
+ <script src="gr-serviceuser-detail.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-serviceuser-detail.js b/src/main/resources/static/gr-serviceuser-detail.js
new file mode 100644
index 0000000..95aded2
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-detail.js
@@ -0,0 +1,345 @@
+// Copyright (C) 2019 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.
+
+(function() {
+ 'use strict';
+
+ const NOT_FOUND_MESSAGE = 'Not Found';
+
+ Polymer({
+ is: 'gr-serviceuser-detail',
+ _legacyUndefinedCheck: true,
+
+ properties: {
+ _restApi: Object,
+ _serviceUserId: String,
+ _serviceUser: Object,
+ _loading: {
+ type: Boolean,
+ value: true,
+ },
+ _statusButtonText: {
+ type: String,
+ value: 'Activate',
+ },
+ _prefsChanged: {
+ type: Boolean,
+ value: false,
+ },
+ _changingPrefs: {
+ type: Boolean,
+ value: false,
+ },
+ _isAdmin: {
+ type: Boolean,
+ value: false,
+ },
+ _allowEmail: {
+ type: Boolean,
+ value: false,
+ },
+ _allowOwner: {
+ type: Boolean,
+ value: false,
+ },
+ _allowHttpPassword: {
+ type: Boolean,
+ value: false,
+ },
+ _newFullName: String,
+ _newEmail: String,
+ _availableOwners: Array,
+ _newOwner: String,
+ _ownerChangeWarning: String,
+ _query: {
+ type: Function,
+ value() {
+ return this._getGroupSuggestions.bind(this);
+ },
+ },
+ },
+
+ behaviors: [
+ Gerrit.ListViewBehavior,
+ ],
+
+ attached() {
+ this._extractUserId();
+ this._loadServiceUser();
+ },
+
+ _loadServiceUser() {
+ if (!this._serviceUserId) { return; }
+
+ const promises = [];
+
+ promises.push(this._getPluginConfig());
+ promises.push(this._getServiceUser());
+
+ Promise.all(promises).then(() => {
+ this.$.sshEditor.loadData(this._restApi, this._serviceUser);
+ this.$.httpPass.loadData(this._restApi, this._serviceUser);
+
+ this.fire('title-change', {title: this._serviceUser.name});
+ this._computeStatusButtonText();
+ this._loading = false;
+ this._newFullName = this._serviceUser.name;
+ this._newEmail = this._serviceUser.email;
+ });
+ },
+
+ _computeLoadingClass(loading) {
+ return loading ? 'loading' : '';
+ },
+
+ _extractUserId() {
+ this._serviceUserId = this.baseURI.split('/').pop();
+ },
+
+ _getPermissions() {
+ return this.plugin.restApi('/accounts/self/capabilities/').get('')
+ .then(capabilities => {
+ this._isAdmin = capabilities && capabilities.administrateServer;
+ });
+ },
+
+ _getPluginConfig() {
+ return Promise.resolve(this._getPermissions()).then(() => {
+ this.plugin.restApi('/config/server/serviceuser~config/').get('')
+ .then(config => {
+ if (!config) {
+ return;
+ }
+ this._allowEmail = config.allow_email || this._isAdmin;
+ this._allowOwner = config.allow_owner || this._isAdmin;
+ this._allowHttpPassword = config.allow_http_password
+ || this._isAdmin;
+ });
+ });
+ },
+
+ _getServiceUser() {
+ this._restApi = this.plugin.restApi(
+ '/config/server/serviceuser~serviceusers/');
+ return this._restApi.get(this._serviceUserId)
+ .then(serviceUser => {
+ if (!serviceUser) {
+ this._serviceUser = {};
+ return;
+ }
+ this._serviceUser = serviceUser;
+ });
+ },
+
+ _active(serviceUser) {
+ if (!serviceUser) {
+ return NOT_FOUND_MESSAGE;
+ }
+
+ return serviceUser.inactive === true ? 'Inactive' : 'Active';
+ },
+
+ _computeStatusButtonText() {
+ if (!this._serviceUser) {
+ return;
+ }
+
+ this._statusButtonText = this._serviceUser.inactive === true
+ ? 'Activate'
+ : 'Deactivate';
+ },
+
+ _toggleStatus() {
+ if (this._serviceUser.inactive === true) {
+ this._restApi.put(`${this._serviceUser._account_id}/active`)
+ .then(() => {
+ this._loadServiceUser();
+ });
+ } else {
+ this._restApi.delete(`${this._serviceUser._account_id}/active`)
+ .then(() => {
+ this._loadServiceUser();
+ });
+ }
+ },
+
+ _getCreator(serviceUser) {
+ if (!serviceUser || !serviceUser.created_by) {
+ return NOT_FOUND_MESSAGE;
+ }
+
+ if (serviceUser.created_by.username != undefined) {
+ return serviceUser.created_by.username;
+ }
+
+ if (serviceUser.created_by._account_id != -1) {
+ return serviceUser.created_by._account_id;
+ }
+
+ return NOT_FOUND_MESSAGE;
+ },
+
+ _getOwnerGroup(serviceUser) {
+ return serviceUser && serviceUser.owner
+ ? serviceUser.owner.name
+ : NOT_FOUND_MESSAGE;
+ },
+
+ _isEmailValid(email) {
+ if (!email) {
+ return false;
+ }
+ return email.includes('@');
+ },
+
+ _getGroupSuggestions(input) {
+ let query;
+ if (!input || input === this._getOwnerGroup(this._serviceUser)) {
+ query = '';
+ } else {
+ query = `?suggest=${input}`;
+ }
+
+ return this.plugin.restApi('/a/groups/').get(query)
+ .then(response => {
+ const groups = [];
+ for (const key in response) {
+ if (!response.hasOwnProperty(key)) { continue; }
+ groups.push({
+ name: key,
+ value: decodeURIComponent(response[key].id),
+ });
+ }
+ this._availableOwners = groups;
+ return groups;
+ });
+ },
+
+ _isOwnerValid(owner) {
+ if (!owner) {
+ return false;
+ }
+
+ return this._getOwnerName(owner);
+ },
+
+ _isNewOwner() {
+ return this._getOwnerName(this._newOwner)
+ === this._getOwnerGroup(this._serviceUser);
+ },
+
+ _getOwnerName(id) {
+ return this._availableOwners.find(o => { return o.value === id; }).name;
+ },
+
+ _computeOwnerWarning() {
+ let message = 'If ';
+ message += this._getOwnerGroup(this._serviceUser) != NOT_FOUND_MESSAGE
+ ? 'the owner group is changed' : 'an owner group is set';
+ message += ' only members of the ';
+ message += this._getOwnerGroup(this._serviceUser) != NOT_FOUND_MESSAGE
+ ? 'new ' : '';
+ message += 'owner group can see and administrate the service user.';
+ message += this._getOwnerGroup(this._serviceUser) != NOT_FOUND_MESSAGE
+ ? '' : ' The creator of the service user can no'
+ + ' longer see and administrate the service user if she/he'
+ + ' is not member of the owner group.';
+ this._ownerChangeWarning = message;
+ },
+
+ _computePrefsChanged() {
+ if (this.loading || this._changingPrefs) {
+ return;
+ }
+
+ if (!this._newOwner && !this._newEmail && !this._newFullName) {
+ this._prefsChanged = false;
+ return;
+ }
+
+ if (this._newEmail && !this._isEmailValid(this._newEmail)) {
+ this._prefsChanged = false;
+ return;
+ }
+
+ if (this._newOwner
+ && (this._isNewOwner() || !this._isOwnerValid(this._newOwner))) {
+ this._prefsChanged = false;
+ return;
+ }
+
+ if (this._newOwner) {
+ this._computeOwnerWarning();
+ }
+
+ this._prefsChanged = true;
+ },
+
+ _applyNewFullName() {
+ return this._restApi
+ .put(`${this._serviceUser._account_id}/name`,
+ {name: this._newFullName})
+ .then(() => {
+ this.$.serviceUserFullNameInput.value = '';
+ });
+ },
+
+ _applyNewEmail(email) {
+ if (!this._isEmailValid(email)) {
+ return;
+ }
+ return this._restApi
+ .put(`${this._serviceUser._account_id}/email`, {email})
+ .then(() => {
+ this.$.serviceUserEmailInput.value = '';
+ });
+ },
+
+ _applyNewOwner(owner) {
+ if (this._isNewOwner() || !this._isOwnerValid(this._newOwner)) {
+ return;
+ }
+ return this._restApi
+ .put(`${this._serviceUser._account_id}/owner`, {group: owner})
+ .then(() => {
+ this.$.serviceUserOwnerInput.text = this._getOwnerGroup(
+ this._serviceUser);
+ });
+ },
+
+ _handleSavePreferences() {
+ const promises = [];
+ this._changingPrefs = true;
+
+ if (this._newFullName) {
+ promises.push(this._applyNewFullName());
+ }
+
+ if (this._newEmail) {
+ promises.push(this._applyNewEmail(this._newEmail));
+ }
+
+ if (this._newOwner) {
+ promises.push(this._applyNewOwner(this._newOwner));
+ }
+
+ Promise.all(promises).then(() => {
+ this._changingPrefs = false;
+ this._prefsChanged = false;
+ this._ownerChangeWarning = '';
+ this._loadServiceUser();
+ });
+ },
+ });
+})();
diff --git a/src/main/resources/static/gr-serviceuser-http-password.html b/src/main/resources/static/gr-serviceuser-http-password.html
new file mode 100644
index 0000000..8cebbe5
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-http-password.html
@@ -0,0 +1,81 @@
+<!--
+@license
+Copyright (C) 2019 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.
+-->
+
+<dom-module id="gr-serviceuser-http-password">
+ <template>
+ <style include="shared-styles">
+ .password {
+ font-family: var(--monospace-font-family);
+ }
+
+ #generatedPasswordOverlay {
+ padding: 2em;
+ width: 50em;
+ }
+
+ #generatedPasswordDisplay {
+ margin: 1em 0;
+ }
+
+ #generatedPasswordDisplay .value {
+ font-family: var(--monospace-font-family);
+ }
+
+ #passwordWarning {
+ font-style: italic;
+ text-align: center;
+ }
+
+ .closeButton {
+ bottom: 2em;
+ position: absolute;
+ right: 2em;
+ }
+ </style>
+ <style include="gr-form-styles"></style>
+ <div class="gr-form-styles">
+ <div>
+ <section>
+ <span class="title">Username</span>
+ <span class="value">[[_serviceUser.username]]</span>
+ </section>
+ <gr-button id="generateButton"
+ on-click="_handleGenerateTap">Generate new password</gr-button>
+ <gr-button id="deleteButton"
+ on-click="_handleDelete">Delete password</gr-button>
+ </div>
+ </div>
+ <gr-overlay id="generatedPasswordOverlay"
+ on-iron-overlay-closed="_generatedPasswordOverlayClosed"
+ with-backdrop>
+ <div class="gr-form-styles">
+ <section id="generatedPasswordDisplay">
+ <span class="title">New Password:</span>
+ <span class="value">[[_generatedPassword]]</span>
+ </section>
+ <section id="passwordWarning">
+ This password will not be displayed again.<br>
+ If you lose it, you will need to generate a new one.
+ </section>
+ <gr-button link
+ class="closeButton"
+ on-click="_closeOverlay">Close</gr-button>
+ </div>
+ </gr-overlay>
+ </template>
+ <script src="gr-serviceuser-http-password.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-serviceuser-http-password.js b/src/main/resources/static/gr-serviceuser-http-password.js
new file mode 100644
index 0000000..87e1543
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-http-password.js
@@ -0,0 +1,60 @@
+/**
+ * @license
+ * Copyright (C) 2019 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.
+ */
+
+(function() {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-serviceuser-http-password',
+ _legacyUndefinedCheck: true,
+
+ properties: {
+ _restApi: Object,
+ _serviceUser: Object,
+ _generatedPassword: String,
+ _passwordUrl: String,
+ },
+
+ loadData(restApi, serviceUser) {
+ this._restApi = restApi;
+ this._serviceUser = serviceUser;
+ },
+
+ _handleGenerateTap() {
+ this._generatedPassword = 'Generating...';
+ this.$.generatedPasswordOverlay.open();
+ this._restApi
+ .put(`${this._serviceUser._account_id}/password.http`,
+ {generate: true})
+ .then(newPassword => {
+ this._generatedPassword = newPassword;
+ });
+ },
+
+ _closeOverlay() {
+ this.$.generatedPasswordOverlay.close();
+ },
+
+ _generatedPasswordOverlayClosed() {
+ this._generatedPassword = '';
+ },
+
+ _handleDelete() {
+ this._restApi.delete(`${this._serviceUser._account_id}/password.http`);
+ },
+ });
+})();
diff --git a/src/main/resources/static/gr-serviceuser-list.html b/src/main/resources/static/gr-serviceuser-list.html
new file mode 100644
index 0000000..e927d63
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-list.html
@@ -0,0 +1,84 @@
+<!--
+@license
+Copyright (C) 2019 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.
+-->
+
+<dom-module id="gr-serviceuser-list">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-table-styles"></style>
+ <style>
+ .topHeader {
+ padding: 8px;
+ }
+
+ #topContainer {
+ align-items: center;
+ display: flex;
+ height: 3rem;
+ justify-content: space-between;
+ margin: 0 1em;
+ }
+ </style>
+ <div class="topHeader">
+ <h2>Service Users</h2>
+ </div>
+ <div id="topContainer">
+ <div></div>
+ <div id="createNewContainer"
+ class$="[[_computeCreateClass(createNew)]]">
+ <gr-button primary
+ link
+ id="createNew"
+ on-click="_createNewServiceUser">
+ Create New
+ </gr-button>
+ </div>
+ </div>
+ <table id="list"
+ class="genericList">
+ <tr class="headerRow">
+ <th class="name topHeader">Username</th>
+ <th class="fullName topHeader">Full Name</th>
+ <th class="email topHeader">Email</th>
+ <th class="owner topHeader">Owner</th>
+ <th class="createdBy topHeader">Created By</th>
+ <th class="createdAt topHeader">Created At</th>
+ <th class="accountState topHeader">Account State</th>
+ </tr>
+ <tr id="loading"
+ class$="loadingMsg [[computeLoadingClass(_loading)]]">
+ <td>Loading...</td>
+ </tr>
+ <tbody class$="[[computeLoadingClass(_loading)]]">
+ <template is="dom-repeat"
+ items="[[_serviceUsers]]">
+ <tr class="table">
+ <td class="name">
+ <a href$="[[_computeServiceUserUrl(item._account_id)]]">[[item.username]]</a>
+ </td>
+ <td class="fullName">[[item.name]]</td>
+ <td class="email">[[item.email]]</td>
+ <td class="owner">[[_getOwnerGroup(item)]]</td>
+ <td class="createdBy">[[_getCreator(item)]]</td>
+ <td class="createdAt">[[item.created_at]]</td>
+ <td class="accountState">[[_active(item)]]</td>
+ </tr>
+ </template>
+ </tbody>
+ </table>
+ </template>
+ <script src="gr-serviceuser-list.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-serviceuser-list.js b/src/main/resources/static/gr-serviceuser-list.js
new file mode 100644
index 0000000..8f35dd4
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-list.js
@@ -0,0 +1,95 @@
+// Copyright (C) 2019 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.
+
+(function() {
+ 'use strict';
+
+ const NOT_FOUND_MESSAGE = 'Not Found';
+
+ Polymer({
+ is: 'gr-serviceuser-list',
+ _legacyUndefinedCheck: true,
+
+ properties: {
+ _serviceUsers: Array,
+ _loading: {
+ type: Boolean,
+ value: true,
+ },
+ },
+
+ behaviors: [
+ Gerrit.ListViewBehavior,
+ ],
+
+ attached() {
+ this.fire('title-change', {title: 'Service Users'});
+ this._getServiceUsers();
+ },
+
+ _getServiceUsers() {
+ return this.plugin.restApi('/config/server/serviceuser~serviceusers/')
+ .get('')
+ .then(serviceUsers => {
+ if (!serviceUsers) {
+ this._serviceUsers = [];
+ return;
+ }
+ this._serviceUsers = Object.keys(serviceUsers)
+ .map(key => {
+ const serviceUser = serviceUsers[key];
+ serviceUser.username = key;
+ return serviceUser;
+ });
+ this._loading = false;
+ });
+ },
+
+ _active(item) {
+ if (!item) {
+ return NOT_FOUND_MESSAGE;
+ }
+
+ return item.inactive === true ? 'Inactive' : 'Active';
+ },
+
+ _getCreator(item) {
+ if (!item || !item.created_by) {
+ return NOT_FOUND_MESSAGE;
+ }
+
+ if (item.created_by.username != undefined) {
+ return item.created_by.username;
+ }
+
+ if (item.created_by._account_id != -1) {
+ return item.created_by._account_id;
+ }
+
+ return NOT_FOUND_MESSAGE;
+ },
+
+ _getOwnerGroup(item) {
+ return item && item.owner ? item.owner.name : NOT_FOUND_MESSAGE;
+ },
+
+ _computeServiceUserUrl(id) {
+ return `${this.plugin.screenUrl()}/user/${id}`;
+ },
+
+ _createNewServiceUser() {
+ page.show(this.plugin.screenUrl() + '/create');
+ },
+ });
+})();
diff --git a/src/main/resources/static/gr-serviceuser-ssh-panel.html b/src/main/resources/static/gr-serviceuser-ssh-panel.html
new file mode 100644
index 0000000..2906a10
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-ssh-panel.html
@@ -0,0 +1,132 @@
+<!--
+@license
+Copyright (C) 2019 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.
+-->
+
+<dom-module id="gr-serviceuser-ssh-panel">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-form-styles">
+ .statusHeader {
+ width: 4em;
+ }
+
+ .keyHeader {
+ width: 7.5em;
+ }
+
+ #viewKeyOverlay {
+ padding: 2em;
+ width: 50em;
+ }
+
+ .publicKey {
+ font-family: var(--monospace-font-family);
+ overflow-x: scroll;
+ overflow-wrap: break-word;
+ width: 30em;
+ }
+
+ .closeButton {
+ bottom: 2em;
+ position: absolute;
+ right: 2em;
+ }
+
+ #existing {
+ margin-bottom: 1em;
+ }
+
+ #existing .commentColumn {
+ min-width: 27em;
+ width: auto;
+ }
+ </style>
+ <div class="gr-form-styles">
+ <fieldset id="existing">
+ <table>
+ <thead>
+ <tr>
+ <th class="commentColumn">Comment</th>
+ <th class="statusHeader">Status</th>
+ <th class="keyHeader">Public key</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <template is="dom-repeat"
+ items="[[_keys]]"
+ as="key">
+ <tr>
+ <td class="commentColumn">[[key.comment]]</td>
+ <td>[[_getStatusLabel(key.valid)]]</td>
+ <td>
+ <gr-button link
+ on-click="_showKey"
+ data-index$="[[index]]"
+ link>Click to View</gr-button>
+ </td>
+ <td>
+ <gr-button link
+ data-index$="[[index]]"
+ on-click="_handleDeleteKey">Delete</gr-button>
+ </td>
+ </tr>
+ </template>
+ </tbody>
+ </table>
+ <gr-overlay id="viewKeyOverlay"
+ with-backdrop>
+ <fieldset>
+ <section>
+ <span class="title">Algorithm</span>
+ <span class="value">[[_keyToView.algorithm]]</span>
+ </section>
+ <section>
+ <span class="title">Public key</span>
+ <span class="value publicKey">[[_keyToView.encoded_key]]</span>
+ </section>
+ <section>
+ <span class="title">Comment</span>
+ <span class="value">[[_keyToView.comment]]</span>
+ </section>
+ </fieldset>
+ <gr-button class="closeButton"
+ on-click="_closeOverlay">Close</gr-button>
+ </gr-overlay>
+ </fieldset>
+ <fieldset>
+ <section>
+ <span class="title">New SSH key</span>
+ <span class="value">
+ <iron-autogrow-textarea id="newKey"
+ autocomplete="on"
+ bind-value="{{_newKey}}"
+ placeholder="New SSH Key">
+ </iron-autogrow-textarea>
+ </span>
+ </section>
+ <gr-button id="addButton"
+ link
+ disabled$="[[_computeAddButtonDisabled(_newKey)]]"
+ on-click="_handleAddKey">
+ Add new SSH key
+ </gr-button>
+ </fieldset>
+ </div>
+ <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
+ </template>
+ <script src="gr-serviceuser-ssh-panel.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-serviceuser-ssh-panel.js b/src/main/resources/static/gr-serviceuser-ssh-panel.js
new file mode 100644
index 0000000..e1e8dd0
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-ssh-panel.js
@@ -0,0 +1,101 @@
+/**
+ * @license
+ * Copyright (C) 2016 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.
+ */
+
+(function() {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-serviceuser-ssh-panel',
+ _legacyUndefinedCheck: true,
+
+ properties: {
+ _restApi: Object,
+ _serviceUser: Object,
+ _keys: Array,
+ /** @type {?} */
+ _keyToView: Object,
+ _newKey: {
+ type: String,
+ value: '',
+ },
+ _keysToRemove: {
+ type: Array,
+ value() { return []; },
+ },
+ },
+
+ loadData(restApi, serviceUser) {
+ this._restApi = restApi;
+ this._serviceUser = serviceUser;
+ return this._restApi.get(`${this._serviceUser._account_id}/sshkeys`)
+ .then(keys => {
+ if (!keys) {
+ this._keys = [];
+ return;
+ }
+ this._keys = keys;
+ });
+ },
+
+ _getStatusLabel(isValid) {
+ return isValid ? 'Valid' : 'Invalid';
+ },
+
+ _showKey(e) {
+ const el = Polymer.dom(e).localTarget;
+ const index = parseInt(el.getAttribute('data-index'), 10);
+ this._keyToView = this._keys[index];
+ this.$.viewKeyOverlay.open();
+ },
+
+ _closeOverlay() {
+ this.$.viewKeyOverlay.close();
+ },
+
+ _handleDeleteKey(e) {
+ const el = Polymer.dom(e).localTarget;
+ const index = parseInt(el.getAttribute('data-index'), 10);
+ this.push('_keysToRemove', this._keys[index]);
+
+ const promises = this._keysToRemove.map(key => {
+ this._restApi.delete(`${this._serviceUser._account_id}/sshkeys/${key.seq}`);
+ });
+
+ return Promise.all(promises).then(() => {
+ this.splice('_keys', index, 1);
+ this._keysToRemove = [];
+ });
+ },
+
+ _handleAddKey() {
+ this.$.addButton.disabled = true;
+ this.$.newKey.disabled = true;
+ return this._restApi.post(`${this._serviceUser._account_id}/sshkeys`,
+ this._newKey.trim(), null, 'plain/text')
+ .then(key => {
+ this.push('_keys', key);
+ }).catch(() => {
+ this.$.addButton.disabled = false;
+ this.$.newKey.disabled = false;
+ });
+ },
+
+ _computeAddButtonDisabled(newKey) {
+ return !newKey.length;
+ },
+ });
+})();
diff --git a/src/main/resources/static/gr-serviceuser.html b/src/main/resources/static/gr-serviceuser.html
new file mode 100644
index 0000000..92714a2
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser.html
@@ -0,0 +1,46 @@
+<!--
+@license
+Copyright (C) 2019 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.
+-->
+
+
+<link rel="import"
+ href="./gr-serviceuser-list.html">
+<link rel="import"
+ href="./gr-serviceuser-detail.html">
+<link rel="import"
+ href="./gr-serviceuser-create.html">
+
+<dom-module id="gr-serviceuser">
+ <script>
+ Gerrit.install(plugin => {
+ plugin.restApi('/accounts/self/capabilities/').get('')
+ .then(capabilities => {
+ if (capabilities
+ && (capabilities.administrateServer
+ || capabilities['serviceuser-createServiceUser'])) {
+ plugin.screen('list', 'gr-serviceuser-list');
+ plugin.screen('user', 'gr-serviceuser-detail');
+ plugin.screen('create', 'gr-serviceuser-create');
+ }
+ plugin.admin()
+ .addMenuLink(
+ 'Service Users',
+ '/x/serviceuser/list',
+ 'serviceuser-createServiceUser');
+ });
+ });
+ </script>
+</dom-module>
diff --git a/src/test/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidatorTest.java b/src/test/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidatorTest.java
new file mode 100644
index 0000000..619ab98
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/serviceuser/SshKeyValidatorTest.java
@@ -0,0 +1,60 @@
+// Copyright (C) 2019 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class SshKeyValidatorTest {
+
+ private final String[] VALID_PUBLIC_KEYS = {
+ "---- BEGIN SSH2 PUBLIC KEY ----\n"
+ + " Comment: comment\n"
+ + " AAAAB3NzaC1\n"
+ + " ---- END SSH2 PUBLIC KEY ----",
+ "---- BEGIN PUBLIC KEY ----\n"
+ + " Comment: comment\n"
+ + " AAAAB3NzaC1\n"
+ + " ---- END PUBLIC KEY ----",
+ "-----BEGIN RSA PUBLIC KEY-----\nMIIBC\n-----END RSA PUBLIC KEY-----",
+ "ssh-rsa AAAAB3NzaC1",
+ "ssh-dss AAAAB3NzaC1",
+ "ssh-ed25519 AAAAB3NzaC1",
+ "ecdsa-sha2-nistp256 AAAAB3NzaC1"
+ };
+
+ private final String[] INVALID_PUBLIC_KEYS = {
+ "---- BEGIN SSH2 PUBLIC KEY ----\n Comment: comment\n AAAAB3NzaC1\n",
+ "-----BEGIN PRIVATE KEY-----\nMIIBC\n-----END PRIVATE KEY-----",
+ "AAAAB3NzaC1\n ---- END SSH2 PUBLIC KEY ----",
+ "",
+ "invalid key"
+ };
+
+ @Test
+ public void testValidateSshKeyFormat_Valid() {
+ for (String keyToTest : VALID_PUBLIC_KEYS) {
+ assertThat(SshKeyValidator.validateFormat(keyToTest)).isTrue();
+ }
+ }
+
+ @Test
+ public void testValidateSshKeyFormat_Invalid() {
+ for (String keyToTest : INVALID_PUBLIC_KEYS) {
+ assertThat(SshKeyValidator.validateFormat(keyToTest)).isFalse();
+ }
+ }
+}
diff --git a/tools/bzl/junit.bzl b/tools/bzl/junit.bzl
new file mode 100644
index 0000000..240c448
--- /dev/null
+++ b/tools/bzl/junit.bzl
@@ -0,0 +1,5 @@
+load(
+ "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
+ _junit_tests = "junit_tests",
+)
+junit_tests = _junit_tests
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
index 9568c84..4d2dbdd 100644
--- a/tools/bzl/plugin.bzl
+++ b/tools/bzl/plugin.bzl
@@ -1,10 +1,10 @@
load(
"@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl",
_gerrit_plugin = "gerrit_plugin",
- _gwt_plugin_deps = "GWT_PLUGIN_DEPS",
_plugin_deps = "PLUGIN_DEPS",
+ _plugin_test_deps = "PLUGIN_TEST_DEPS",
)
gerrit_plugin = _gerrit_plugin
-GWT_PLUGIN_DEPS = _gwt_plugin_deps
PLUGIN_DEPS = _plugin_deps
+PLUGIN_TEST_DEPS = _plugin_test_deps
diff --git a/tools/eclipse/BUILD b/tools/eclipse/BUILD
index 9b694c1..a38b222 100644
--- a/tools/eclipse/BUILD
+++ b/tools/eclipse/BUILD
@@ -1,16 +1,10 @@
load("//tools/bzl:classpath.bzl", "classpath_collector")
-load(
- "//tools/bzl:plugin.bzl",
- "GWT_PLUGIN_DEPS",
- "PLUGIN_DEPS",
-)
+load("//tools/bzl:plugin.bzl", "PLUGIN_DEPS")
classpath_collector(
name = "main_classpath_collect",
testonly = 1,
- deps = PLUGIN_DEPS + GWT_PLUGIN_DEPS + [
- "//external:gwt-dev",
- "//external:gwt-user",
+ deps = PLUGIN_DEPS + [
"//:serviceuser__plugin",
],
)