Add PolyGerrit UI for creating a service user
Change-Id: I0df465587e29ae21ff6b475c11e80cb3434637f9
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 e955f43..85da7b0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.serviceuser;
+import com.google.common.base.Strings;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.RestReadView;
@@ -61,6 +62,8 @@
public ConfigInfo apply(ConfigResource rsrc) throws PermissionBackendException {
PluginConfig cfg = cfgFactory.getFromGerritConfig(pluginName);
ConfigInfo info = new ConfigInfo();
+ info.info = Strings.emptyToNull(cfg.getString("infoMessage"));
+ info.onSuccess = Strings.emptyToNull(cfg.getString("onSuccessMessage"));
info.allowEmail = toBoolean(cfg.getBoolean("allowEmail", false));
info.allowHttpPassword = toBoolean(cfg.getBoolean("allowHttpPassword", false));
info.allowOwner = toBoolean(cfg.getBoolean("allowOwner", false));
@@ -92,6 +95,8 @@
}
public class ConfigInfo {
+ public String info;
+ public String onSuccess;
public Boolean allowEmail;
public Boolean allowHttpPassword;
public Boolean allowOwner;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutConfig.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutConfig.java
index 8b45918..09a559e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutConfig.java
@@ -40,6 +40,8 @@
@Singleton
class PutConfig implements RestModifyView<ConfigResource, Input> {
public static class Input {
+ public String info;
+ public String onSuccess;
public Boolean allowEmail;
public Boolean allowHttpPassword;
public Boolean allowOwner;
@@ -71,6 +73,12 @@
throws IOException, ConfigInvalidException, UnprocessableEntityException {
FileBasedConfig cfg = new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.DETECTED);
cfg.load();
+ if (input.info != null) {
+ cfg.setString("plugin", pluginName, "infoMessage", Strings.emptyToNull(input.info));
+ }
+ if (input.onSuccess != null) {
+ cfg.setString("plugin", pluginName, "onSuccessMessage", Strings.emptyToNull(input.onSuccess));
+ }
if (input.allowEmail != null) {
setBoolean(cfg, "allowEmail", input.allowEmail);
}
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 0793bb6..f52421e 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -22,6 +22,16 @@
should be automatically added. Multiple groups can be specified by
having multiple `plugin.@PLUGIN@.group` entries.
+<a id="infoMessage">
+`plugin.@PLUGIN@.infoMessage`
+: HTML formatted message that should be displayed on the service user
+ creation screen.
+
+<a id="onSuccessMessage">
+`plugin.@PLUGIN@.onSuccessMessage`
+: Message that should be displayed after a service user was
+ successfully created.
+
<a id="allowEmail">
`plugin.@PLUGIN@.allowEmail`
: Whether it is allowed for service user owners to set email
diff --git a/src/main/resources/Documentation/rest-api-config.md b/src/main/resources/Documentation/rest-api-config.md
index 8497fcd..3999e60 100644
--- a/src/main/resources/Documentation/rest-api-config.md
+++ b/src/main/resources/Documentation/rest-api-config.md
@@ -704,6 +704,10 @@
The `ConfigInfo` entity contains the configuration of the @PLUGIN@
plugin.
+* _info_: HTML formatted message that should be displayed on the
+ service user creation screen.
+* _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
@@ -727,6 +731,10 @@
The `ConfigInput` entity contains updates for the configuration of the
@PLUGIN@ plugin.
+* _info_: HTML formatted message that should be displayed on the
+ service user creation screen.
+* _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..b6b71fe
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-create.html
@@ -0,0 +1,78 @@
+<!--
+@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-tap="_handleCreateServiceUser"
+ disabled="[[!_enableButton]]">
+ Create
+ </gr-button>
+ </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..bc04de5
--- /dev/null
+++ b/src/main/resources/static/gr-serviceuser-create.js
@@ -0,0 +1,142 @@
+/**
+ * @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,
+ },
+ },
+
+ attached() {
+ this._getConfig();
+ },
+
+ _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._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 => {
+ if (this._successMessage) {
+ this.fire('show-alert', {message: this._successMessage});
+ }
+ page.show(
+ this.plugin.screenUrl()
+ + '/user/'
+ + response._account_id);
+ }).catch(response => {
+ this.fire('show-error', {message: response});
+ this._isAdding = false;
+ this._computeButtonEnabled();
+ });
+ },
+ });
+})();
diff --git a/src/main/resources/static/gr-serviceuser-list.html b/src/main/resources/static/gr-serviceuser-list.html
index 5557202..052e9f4 100644
--- a/src/main/resources/static/gr-serviceuser-list.html
+++ b/src/main/resources/static/gr-serviceuser-list.html
@@ -23,10 +23,30 @@
.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-tap="_createNewServiceUser">
+ Create New
+ </gr-button>
+ </div>
+ </div>
<table id="list"
class="genericList">
<tr class="headerRow">
diff --git a/src/main/resources/static/gr-serviceuser-list.js b/src/main/resources/static/gr-serviceuser-list.js
index b7ef602..8f35dd4 100644
--- a/src/main/resources/static/gr-serviceuser-list.js
+++ b/src/main/resources/static/gr-serviceuser-list.js
@@ -87,5 +87,9 @@
_computeServiceUserUrl(id) {
return `${this.plugin.screenUrl()}/user/${id}`;
},
+
+ _createNewServiceUser() {
+ page.show(this.plugin.screenUrl() + '/create');
+ },
});
})();
diff --git a/src/main/resources/static/gr-serviceuser.html b/src/main/resources/static/gr-serviceuser.html
index deb277e..92714a2 100644
--- a/src/main/resources/static/gr-serviceuser.html
+++ b/src/main/resources/static/gr-serviceuser.html
@@ -20,6 +20,8 @@
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>
@@ -31,6 +33,7 @@
|| capabilities['serviceuser-createServiceUser'])) {
plugin.screen('list', 'gr-serviceuser-list');
plugin.screen('user', 'gr-serviceuser-detail');
+ plugin.screen('create', 'gr-serviceuser-create');
}
plugin.admin()
.addMenuLink(