Allow admins to configure URL aliases
This allows to map plugin screens into the Gerrit URL namespace, e.g.:
[urlAlias "MyPluginScreen"]
match = /myscreen/(.*)
token = /x/myplugin/myscreen/$1
This can also be used to replace Gerrit screens with plugin screens,
e.g. to replace change screen:
[urlAlias "MyChangeScreen"]
match = /c/(.*)
token = /x/myplugin/c/$1
Defining URL aliases is similar to defining comment links. This is why
a similar representation in the gerrit.config was chosen.
Change-Id: Ie4a3b69703629051f7627eeb0c479dfc964f27ae
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
@@ -3767,6 +3767,46 @@ on the server. One or more groups can be set.
|
|||||||
If no groups are added, any user will be allowed to execute
|
If no groups are added, any user will be allowed to execute
|
||||||
'upload-pack' on the server.
|
'upload-pack' on the server.
|
||||||
|
|
||||||
|
[[urlAlias]]
|
||||||
|
=== Section urlAlias
|
||||||
|
|
||||||
|
URL aliases define regular expressions for URL tokens that are mapped
|
||||||
|
to target URL tokens.
|
||||||
|
|
||||||
|
Each URL alias must be specified in its own subsection. The subsection
|
||||||
|
name should be a descriptive name. It must be unique, but is not
|
||||||
|
interpreted in any way.
|
||||||
|
|
||||||
|
The URL aliases are applied in no particular order. The first matching
|
||||||
|
URL alias is used and further matches are ignored.
|
||||||
|
|
||||||
|
URL aliases can be used to map plugin screens into the Gerrit URL
|
||||||
|
namespace, or to replace Gerrit screens by plugin screens.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
----
|
||||||
|
[urlAlias "MyPluginScreen"]
|
||||||
|
match = /myscreen/(.*)
|
||||||
|
token = /x/myplugin/myscreen/$1
|
||||||
|
[urlAlias "MyChangeScreen"]
|
||||||
|
match = /c/(.*)
|
||||||
|
token = /x/myplugin/c/$1
|
||||||
|
----
|
||||||
|
|
||||||
|
[[urlAlias.match]]urlAlias.match::
|
||||||
|
+
|
||||||
|
A regular expression for a URL token.
|
||||||
|
+
|
||||||
|
The matched URL token is replaced by `urlAlias.token`.
|
||||||
|
|
||||||
|
[[urlAlias.token]]urlAlias.token::
|
||||||
|
+
|
||||||
|
The target URL token.
|
||||||
|
+
|
||||||
|
It can contain placeholders for the groups matched by the
|
||||||
|
`urlAlias.match` regular expression: `$1` for the first matched group,
|
||||||
|
`$2` for the second matched group, etc.
|
||||||
|
|
||||||
[[submodule]]
|
[[submodule]]
|
||||||
=== Section submodule
|
=== Section submodule
|
||||||
|
|||||||
@@ -1788,6 +1788,10 @@ public class MyPlugin extends PluginEntryPoint {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
By defining an link:config-gerrit.html#urlAlias[urlAlias] Gerrit
|
||||||
|
administrators can map plugin screens into the Gerrit URL namespace or
|
||||||
|
even replace Gerrit screens by plugin screens.
|
||||||
|
|
||||||
[[settings-screen]]
|
[[settings-screen]]
|
||||||
== Plugin Settings Screen
|
== Plugin Settings Screen
|
||||||
|
|
||||||
|
|||||||
@@ -1352,6 +1352,11 @@ entity. Not set if SSHD is disabled.
|
|||||||
Information about the configuration from the
|
Information about the configuration from the
|
||||||
link:config-gerrit.html#suggest[suggest] section as link:#suggest-info[
|
link:config-gerrit.html#suggest[suggest] section as link:#suggest-info[
|
||||||
SuggestInfo] entity.
|
SuggestInfo] entity.
|
||||||
|
|`url_aliases` |optional|
|
||||||
|
A map of URL aliases, where a regular expression for an URL token is
|
||||||
|
mapped to a target URL token. The target URL token can contain
|
||||||
|
placeholders for the groups matched by the regular expression: `$1` for
|
||||||
|
the first matched group, `$2` for the second matched group, etc.
|
||||||
|`user` ||
|
|`user` ||
|
||||||
Information about the configuration from the
|
Information about the configuration from the
|
||||||
link:config-gerrit.html#user[user] section as link:#user-config-info[
|
link:config-gerrit.html#user[user] section as link:#user-config-info[
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ import com.google.gerrit.reviewdb.client.Project;
|
|||||||
import com.google.gwt.core.client.GWT;
|
import com.google.gwt.core.client.GWT;
|
||||||
import com.google.gwt.core.client.RunAsyncCallback;
|
import com.google.gwt.core.client.RunAsyncCallback;
|
||||||
import com.google.gwt.http.client.URL;
|
import com.google.gwt.http.client.URL;
|
||||||
|
import com.google.gwt.regexp.shared.MatchResult;
|
||||||
|
import com.google.gwt.regexp.shared.RegExp;
|
||||||
import com.google.gwt.user.client.Window;
|
import com.google.gwt.user.client.Window;
|
||||||
import com.google.gwtorm.client.KeyUtil;
|
import com.google.gwtorm.client.KeyUtil;
|
||||||
|
|
||||||
@@ -204,7 +206,9 @@ public class Dispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void select(final String token) {
|
private static void select(String token) {
|
||||||
|
token = Gerrit.getUrlAliasMatcher().replace(token);
|
||||||
|
|
||||||
if (matchPrefix(QUERY, token)) {
|
if (matchPrefix(QUERY, token)) {
|
||||||
query(token);
|
query(token);
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ public class Gerrit implements EntryPoint {
|
|||||||
private static String myHost;
|
private static String myHost;
|
||||||
private static ServerInfo myServerInfo;
|
private static ServerInfo myServerInfo;
|
||||||
private static AccountPreferencesInfo myPrefs;
|
private static AccountPreferencesInfo myPrefs;
|
||||||
|
private static UrlAliasMatcher urlAliasMatcher;
|
||||||
private static boolean hasDocumentation;
|
private static boolean hasDocumentation;
|
||||||
private static String docUrl;
|
private static String docUrl;
|
||||||
private static HostPageData.Theme myTheme;
|
private static HostPageData.Theme myTheme;
|
||||||
@@ -294,6 +295,10 @@ public class Gerrit implements EntryPoint {
|
|||||||
return myServerInfo;
|
return myServerInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UrlAliasMatcher getUrlAliasMatcher() {
|
||||||
|
return urlAliasMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
/** Site theme information (site specific colors)/ */
|
/** Site theme information (site specific colors)/ */
|
||||||
public static HostPageData.Theme getTheme() {
|
public static HostPageData.Theme getTheme() {
|
||||||
return myTheme;
|
return myTheme;
|
||||||
@@ -446,6 +451,7 @@ public class Gerrit implements EntryPoint {
|
|||||||
@Override
|
@Override
|
||||||
public void onSuccess(ServerInfo info) {
|
public void onSuccess(ServerInfo info) {
|
||||||
myServerInfo = info;
|
myServerInfo = info;
|
||||||
|
urlAliasMatcher = new UrlAliasMatcher(info.urlAliases());
|
||||||
String du = info.gerrit().docUrl();
|
String du = info.gerrit().docUrl();
|
||||||
if (du != null && !du.isEmpty()) {
|
if (du != null && !du.isEmpty()) {
|
||||||
hasDocumentation = true;
|
hasDocumentation = true;
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// 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.google.gerrit.client;
|
||||||
|
|
||||||
|
import com.google.gwt.regexp.shared.RegExp;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class UrlAliasMatcher {
|
||||||
|
private final Map<RegExp, String> globalUrlAliases;
|
||||||
|
|
||||||
|
UrlAliasMatcher(Map<String, String> globalUrlAliases) {
|
||||||
|
this.globalUrlAliases = new HashMap<>();
|
||||||
|
if (globalUrlAliases != null) {
|
||||||
|
for (Map.Entry<String, String> e : globalUrlAliases.entrySet()) {
|
||||||
|
this.globalUrlAliases.put(RegExp.compile(e.getKey()), e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String replace(String token) {
|
||||||
|
for (Map.Entry<RegExp, String> e : globalUrlAliases.entrySet()) {
|
||||||
|
RegExp pat = e.getKey();
|
||||||
|
if (pat.exec(token) != null) {
|
||||||
|
return pat.replace(token, e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,8 +14,15 @@
|
|||||||
|
|
||||||
package com.google.gerrit.client.config;
|
package com.google.gerrit.client.config;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.rpc.NativeMap;
|
||||||
|
import com.google.gerrit.client.rpc.NativeString;
|
||||||
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
import com.google.gwt.core.client.JavaScriptObject;
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class ServerInfo extends JavaScriptObject {
|
public class ServerInfo extends JavaScriptObject {
|
||||||
public final native AuthInfo auth() /*-{ return this.auth; }-*/;
|
public final native AuthInfo auth() /*-{ return this.auth; }-*/;
|
||||||
public final native ChangeConfigInfo change() /*-{ return this.change; }-*/;
|
public final native ChangeConfigInfo change() /*-{ return this.change; }-*/;
|
||||||
@@ -29,6 +36,18 @@ public class ServerInfo extends JavaScriptObject {
|
|||||||
public final native UserConfigInfo user() /*-{ return this.user; }-*/;
|
public final native UserConfigInfo user() /*-{ return this.user; }-*/;
|
||||||
public final native ReceiveInfo receive() /*-{ return this.receive; }-*/;
|
public final native ReceiveInfo receive() /*-{ return this.receive; }-*/;
|
||||||
|
|
||||||
|
public final Map<String, String> urlAliases() {
|
||||||
|
Map<String, String> urlAliases = new HashMap<>();
|
||||||
|
for (String k : Natives.keys(_urlAliases())) {
|
||||||
|
urlAliases.put(k, urlAliasToken(k));
|
||||||
|
}
|
||||||
|
return urlAliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final native String urlAliasToken(String n) /*-{ return this.url_aliases[n]; }-*/;
|
||||||
|
private final native NativeMap<NativeString> _urlAliases() /*-{ return this.url_aliases; }-*/;
|
||||||
|
|
||||||
|
|
||||||
public final boolean hasContactStore() {
|
public final boolean hasContactStore() {
|
||||||
return contactStore() != null;
|
return contactStore() != null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class GetServerInfo implements RestReadView<ConfigResource> {
|
public class GetServerInfo implements RestReadView<ConfigResource> {
|
||||||
|
private final static String URL_ALIAS = "urlAlias";
|
||||||
|
private final static String KEY_MATCH = "match";
|
||||||
|
private final static String KEY_TOKEN = "token";
|
||||||
|
|
||||||
private final Config config;
|
private final Config config;
|
||||||
private final AuthConfig authConfig;
|
private final AuthConfig authConfig;
|
||||||
private final Realm realm;
|
private final Realm realm;
|
||||||
@@ -102,6 +106,10 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
|
|||||||
info.plugin = getPluginInfo();
|
info.plugin = getPluginInfo();
|
||||||
info.sshd = getSshdInfo(config);
|
info.sshd = getSshdInfo(config);
|
||||||
info.suggest = getSuggestInfo(config);
|
info.suggest = getSuggestInfo(config);
|
||||||
|
|
||||||
|
Map<String, String> urlAliases = getUrlAliasesInfo(config);
|
||||||
|
info.urlAliases = !urlAliases.isEmpty() ? urlAliases : null;
|
||||||
|
|
||||||
info.user = getUserInfo(anonymousCowardName);
|
info.user = getUserInfo(anonymousCowardName);
|
||||||
info.receive = getReceiveInfo(config);
|
info.receive = getReceiveInfo(config);
|
||||||
return info;
|
return info;
|
||||||
@@ -267,6 +275,15 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getUrlAliasesInfo(Config cfg) {
|
||||||
|
Map<String, String> urlAliases = new HashMap<>();
|
||||||
|
for (String subsection : cfg.getSubsections(URL_ALIAS)) {
|
||||||
|
urlAliases.put(cfg.getString(URL_ALIAS, subsection, KEY_MATCH),
|
||||||
|
cfg.getString(URL_ALIAS, subsection, KEY_TOKEN));
|
||||||
|
}
|
||||||
|
return urlAliases;
|
||||||
|
}
|
||||||
|
|
||||||
private SshdInfo getSshdInfo(Config cfg) {
|
private SshdInfo getSshdInfo(Config cfg) {
|
||||||
String[] addr = cfg.getStringList("sshd", null, "listenAddress");
|
String[] addr = cfg.getStringList("sshd", null, "listenAddress");
|
||||||
if (addr.length == 1 && isOff(addr[0])) {
|
if (addr.length == 1 && isOff(addr[0])) {
|
||||||
@@ -313,6 +330,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
|
|||||||
public PluginConfigInfo plugin;
|
public PluginConfigInfo plugin;
|
||||||
public SshdInfo sshd;
|
public SshdInfo sshd;
|
||||||
public SuggestInfo suggest;
|
public SuggestInfo suggest;
|
||||||
|
public Map<String, String> urlAliases;
|
||||||
public UserConfigInfo user;
|
public UserConfigInfo user;
|
||||||
public ReceiveInfo receive;
|
public ReceiveInfo receive;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user