From f49c50ca9a84ca374b7bd91c171bbea0457f2c7a Mon Sep 17 00:00:00 2001 From: Luke Granger-Brown Date: Thu, 2 Jul 2020 23:03:02 +0100 Subject: [PATCH 3/3] Add titles to CLs over HTTP --- .../gerrit/httpd/raw/IndexHtmlUtil.java | 13 +++- .../google/gerrit/httpd/raw/IndexServlet.java | 8 ++- .../google/gerrit/httpd/raw/StaticModule.java | 5 +- .../gerrit/httpd/raw/TitleComputer.java | 67 +++++++++++++++++++ .../gerrit/httpd/raw/PolyGerritIndexHtml.soy | 4 +- 5 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 java/com/google/gerrit/httpd/raw/TitleComputer.java diff --git a/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java b/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java index 72bfe40c3b..439bd73b44 100644 --- a/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java +++ b/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java @@ -41,6 +41,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -62,13 +63,14 @@ public class IndexHtmlUtil { String faviconPath, Map urlParameterMap, Function urlInScriptTagOrdainer, - String requestedURL) + String requestedURL, + TitleComputer titleComputer) throws URISyntaxException, RestApiException { ImmutableMap.Builder data = ImmutableMap.builder(); data.putAll( staticTemplateData( canonicalURL, cdnPath, faviconPath, urlParameterMap, urlInScriptTagOrdainer)) - .putAll(dynamicTemplateData(gerritApi, requestedURL)); + .putAll(dynamicTemplateData(gerritApi, requestedURL, titleComputer)); Set enabledExperiments = new HashSet<>(); enabledExperiments.addAll(experimentFeatures.getEnabledExperimentFeatures()); // Add all experiments enabled through url @@ -81,7 +83,8 @@ public class IndexHtmlUtil { /** Returns dynamic parameters of {@code index.html}. */ public static ImmutableMap dynamicTemplateData( - GerritApi gerritApi, String requestedURL) throws RestApiException, URISyntaxException { + GerritApi gerritApi, String requestedURL, TitleComputer titleComputer) + throws RestApiException, URISyntaxException { ImmutableMap.Builder data = ImmutableMap.builder(); Map initialData = new HashMap<>(); Server serverApi = gerritApi.config().server(); @@ -129,6 +132,10 @@ public class IndexHtmlUtil { } data.put("gerritInitialData", initialData); + + Optional title = titleComputer.computeTitle(requestedURL); + title.ifPresent(s -> data.put("title", s)); + return data.build(); } diff --git a/java/com/google/gerrit/httpd/raw/IndexServlet.java b/java/com/google/gerrit/httpd/raw/IndexServlet.java index fcb821e5ae..e1464b992b 100644 --- a/java/com/google/gerrit/httpd/raw/IndexServlet.java +++ b/java/com/google/gerrit/httpd/raw/IndexServlet.java @@ -48,13 +48,15 @@ public class IndexServlet extends HttpServlet { private final ExperimentFeatures experimentFeatures; private final SoySauce soySauce; private final Function urlOrdainer; + private TitleComputer titleComputer; IndexServlet( @Nullable String canonicalUrl, @Nullable String cdnPath, @Nullable String faviconPath, GerritApi gerritApi, - ExperimentFeatures experimentFeatures) { + ExperimentFeatures experimentFeatures, + TitleComputer titleComputer) { this.canonicalUrl = canonicalUrl; this.cdnPath = cdnPath; this.faviconPath = faviconPath; @@ -69,6 +71,7 @@ public class IndexServlet extends HttpServlet { (s) -> UnsafeSanitizedContentOrdainer.ordainAsSafe( s, SanitizedContent.ContentKind.TRUSTED_RESOURCE_URI); + this.titleComputer = titleComputer; } @Override @@ -86,7 +89,8 @@ public class IndexServlet extends HttpServlet { faviconPath, parameterMap, urlOrdainer, - getRequestUrl(req)); + getRequestUrl(req), + titleComputer); renderer = soySauce.renderTemplate("com.google.gerrit.httpd.raw.Index").setData(templateData); } catch (URISyntaxException | RestApiException e) { throw new IOException(e); diff --git a/java/com/google/gerrit/httpd/raw/StaticModule.java b/java/com/google/gerrit/httpd/raw/StaticModule.java index 15dcf42e0e..9f56bf33ce 100644 --- a/java/com/google/gerrit/httpd/raw/StaticModule.java +++ b/java/com/google/gerrit/httpd/raw/StaticModule.java @@ -241,10 +241,11 @@ public class StaticModule extends ServletModule { @CanonicalWebUrl @Nullable String canonicalUrl, @GerritServerConfig Config cfg, GerritApi gerritApi, - ExperimentFeatures experimentFeatures) { + ExperimentFeatures experimentFeatures, + TitleComputer titleComputer) { String cdnPath = options.devCdn().orElse(cfg.getString("gerrit", null, "cdnPath")); String faviconPath = cfg.getString("gerrit", null, "faviconPath"); - return new IndexServlet(canonicalUrl, cdnPath, faviconPath, gerritApi, experimentFeatures); + return new IndexServlet(canonicalUrl, cdnPath, faviconPath, gerritApi, experimentFeatures, titleComputer); } @Provides diff --git a/java/com/google/gerrit/httpd/raw/TitleComputer.java b/java/com/google/gerrit/httpd/raw/TitleComputer.java new file mode 100644 index 0000000000..8fd2053ad0 --- /dev/null +++ b/java/com/google/gerrit/httpd/raw/TitleComputer.java @@ -0,0 +1,67 @@ +package com.google.gerrit.httpd.raw; + +import com.google.common.flogger.FluentLogger; +import com.google.gerrit.entities.Change; +import com.google.gerrit.extensions.restapi.ResourceConflictException; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.server.change.ChangeResource; +import com.google.gerrit.server.permissions.PermissionBackendException; +import com.google.gerrit.server.restapi.change.ChangesCollection; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Singleton +public class TitleComputer { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + @Inject + public TitleComputer(Provider changes) { + this.changes = changes; + } + + public Optional computeTitle(String requestedURI) { + URL url = null; + try { + url = new URL(requestedURI); + } catch (MalformedURLException e) { + logger.atWarning().log("Failed to turn %s into a URL.", requestedURI); + return Optional.empty(); + } + + // Try to turn this into a change. + Optional changeId = tryExtractChange(url.getPath()); + if (changeId.isPresent()) { + return titleFromChangeId(changeId.get()); + } + + return Optional.empty(); + } + + private static final Pattern extractChangeIdRegex = Pattern.compile("^/(?:c/.*/\\+/)?(?[0-9]+)(?:/[0-9]+)?(?:/.*)?$"); + private final Provider changes; + + private Optional tryExtractChange(String path) { + Matcher m = extractChangeIdRegex.matcher(path); + if (!m.matches()) { + return Optional.empty(); + } + return Change.Id.tryParse(m.group("changeId")); + } + + private Optional titleFromChangeId(Change.Id changeId) { + ChangesCollection changesCollection = changes.get(); + try { + ChangeResource changeResource = changesCollection.parse(changeId); + return Optional.of(changeResource.getChange().getSubject()); + } catch (ResourceConflictException | ResourceNotFoundException | PermissionBackendException e) { + return Optional.empty(); + } + } +} diff --git a/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy b/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy index dbfef44dfe..347ee75aab 100644 --- a/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy +++ b/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy @@ -33,10 +33,12 @@ {@param? defaultDashboardHex: ?} {@param? dashboardQuery: ?} {@param? userIsAuthenticated: ?} + {@param? title: ?} {\n} {\n} {\n} - {\n} + {if $title}{$title} · Gerrit Code Review{\n}{/if} + {\n} {\n} {\n} -- 2.37.3