Merge branch 'stable-2.16'

* stable-2.16:
  Disable inputs in configuration screen for non-owners
  Fix REST API calls for projects with '/' in the name
  Add configuration menu to the repo-config screen in new UI

Change-Id: I292baaa0dc4946e1f8e646577bd3a4ee8abac48a
diff --git a/BUILD b/BUILD
index 2d4dd7d..823f272 100644
--- a/BUILD
+++ b/BUILD
@@ -7,6 +7,7 @@
     manifest_entries = [
         "Gerrit-PluginName: reviewers-by-blame",
         "Gerrit-Module: com.googlesource.gerrit.plugins.reviewersbyblame.ReviewersByBlameModule",
+        "Gerrit-HttpModule: com.googlesource.gerrit.plugins.reviewersbyblame.HttpModule",
         "Implementation-Title: Reviewers By Blame",
         "Implementation-URL: https://gerrit.googlesource.com/plugins/reviewers-by-blame",
     ],
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/HttpModule.java
new file mode 100644
index 0000000..25d3d7c
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/HttpModule.java
@@ -0,0 +1,29 @@
+// 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.reviewersbyblame;
+
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.webui.JavaScriptPlugin;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
+import com.google.gerrit.httpd.plugins.HttpPluginModule;
+
+public class HttpModule extends HttpPluginModule {
+
+  @Override
+  protected void configureServlets() {
+    DynamicSet.bind(binder(), WebUiPlugin.class)
+        .toInstance(new JavaScriptPlugin("gr-reviewers-by-blame.html"));
+  }
+}
diff --git a/src/main/resources/static/gr-reviewers-by-blame-config.html b/src/main/resources/static/gr-reviewers-by-blame-config.html
new file mode 100644
index 0000000..3cdca3e
--- /dev/null
+++ b/src/main/resources/static/gr-reviewers-by-blame-config.html
@@ -0,0 +1,82 @@
+<!--
+@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-reviewers-by-blame-config">
+  <template>
+    <style include="shared-styles"></style>
+    <style include="gr-form-styles"></style>
+    <style>
+      .sectionTitle {
+        padding-top: 2em;
+      }
+    </style>
+    <fieldset class="gr-form-styles">
+      <h2 class="sectionTitle">Reviewers-By-Blame Options</h2>
+      <section>
+        <span class="title">Ignore file regex</span>
+        <span class="value">
+          <iron-input bind-value="{{_changedConfig.ignoreFileRegEx.value}}">
+            <input id="ignoreFileRegEx"
+                   value="{{_changedConfig.ignoreFileRegEx.value::input}}"
+                   type="text"
+                   on-input="_handlePrefsChanged"
+                   disabled$="[[readOnly]]">
+          </iron-input>
+        </span>
+        <span class="value">
+          [[_formatInheritedValue(_appliedConfig.ignoreFileRegEx.inherited_value)]]
+        </span>
+      </section>
+      <section>
+        <span class="title">Ignore regex</span>
+        <span class="value">
+          <iron-input bind-value="{{_changedConfig.ignoreSubjectRegEx.value}}">
+            <input id="ignoreSubjectRegEx"
+                   value="{{_changedConfig.ignoreSubjectRegEx.value::input}}"
+                   type="text"
+                   on-input="_handlePrefsChanged"
+                   disabled$="[[readOnly]]">
+          </iron-input>
+        </span>
+        <span class="value">
+          [[_formatInheritedValue(_appliedConfig.ignoreSubjectRegEx.inherited_value)]]
+        </span>
+      </section>
+      <section>
+        <span class="title">Max reviewers</span>
+        <span class="value">
+          <iron-input bind-value="{{_changedConfig._maxReviewers.value}}">
+            <input id="maxReviewers"
+                   value="{{_changedConfig.maxReviewers.value::input}}"
+                   prevent-invalid-input
+                   allowed-pattern="[0-9]"
+                   type="number"
+                   on-keypress="_handlePrefsChanged"
+                   on-change="_handlePrefsChanged"
+                   disabled$="[[readOnly]]">
+          </iron-input>
+        </span>
+        <span class="value">
+          [[_formatInheritedValue(_appliedConfig.maxReviewers.inherited_value)]]
+        </span>
+      </section>
+      <gr-button id="saveButton"
+                 on-click="_handlePrefsSave"
+                 disabled="[[!_prefsChanged]]">
+        Save Changes
+      </gr-button>
+    </fieldset>
+  </template>
+  <script src="gr-reviewers-by-blame-config.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-reviewers-by-blame-config.js b/src/main/resources/static/gr-reviewers-by-blame-config.js
new file mode 100644
index 0000000..5957f94
--- /dev/null
+++ b/src/main/resources/static/gr-reviewers-by-blame-config.js
@@ -0,0 +1,82 @@
+// 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-reviewers-by-blame-config',
+
+    properties: {
+      repoName: String,
+      _appliedConfig: Object,
+      _changedConfig: Object,
+      _prefsChanged: {
+        type: Boolean,
+        value: false,
+      },
+      _projectRestApi: Object,
+      readOnly: {
+        type: Boolean,
+        value: true,
+      },
+    },
+
+    attached() {
+      this._projectRestApi = this.plugin.restApi('/projects/');
+
+      this._getPreferences().then(() => {
+        this._changedConfig = Object.assign({}, this._appliedConfig);
+      });
+    },
+
+    _getPreferences() {
+      return this._projectRestApi.get(`${encodeURIComponent(this.repoName)}/config`)
+        .then(config => {
+          if (!config) {
+            return;
+          }
+
+          if (config.plugin_config
+            && config.plugin_config['reviewers-by-blame']) {
+            this._appliedConfig = config.plugin_config['reviewers-by-blame'];
+          }
+        })
+    },
+
+    _handlePrefsChanged() {
+      this._prefsChanged = true;
+    },
+
+    _handlePrefsSave() {
+      let body = { plugin_config_values: {} };
+      body.plugin_config_values['reviewers-by-blame'] = this._changedConfig;
+
+      this._projectRestApi.put(`${encodeURIComponent(this.repoName)}/config`, body)
+        .then(() => {
+          this._prefsChanged = false;
+        }).catch(response => {
+          this.fire('show-error', { message: response });
+        });
+    },
+
+    _formatInheritedValue(value) {
+      if (value) {
+        return `inherited: ${value}`;
+      }
+
+      return '';
+    },
+  });
+})();
diff --git a/src/main/resources/static/gr-reviewers-by-blame.html b/src/main/resources/static/gr-reviewers-by-blame.html
new file mode 100644
index 0000000..b5d2046
--- /dev/null
+++ b/src/main/resources/static/gr-reviewers-by-blame.html
@@ -0,0 +1,26 @@
+<!--
+@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-reviewers-by-blame-config.html">
+
+<dom-module id="gr-reviewers-by-blame">
+  <script>
+    Gerrit.install(plugin => {
+      plugin.registerCustomComponent('repo-config', 'gr-reviewers-by-blame-config');
+    });
+  </script>
+</dom-module>