This change cannot be deployed OOTB: you must upgrade by 3.5.2+ first, and run copy-approvals. Change-Id: Ia2e49da4d801a21a3db59e2d5b054eeb46d7dc79 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6505 Tested-by: BuildkiteCI Reviewed-by: tazjin <tazjin@tvl.su>
		
			
				
	
	
		
			215 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 585077e751107729b7a2dd495a3b17c677a3f528 Mon Sep 17 00:00:00 2001
 | |
| From: Luke Granger-Brown <git@lukegb.com>
 | |
| 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 ce22ae8e59..952ba1fef4 100644
 | |
| --- a/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java
 | |
| +++ b/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java
 | |
| @@ -40,6 +40,7 @@ import java.util.Arrays;
 | |
|  import java.util.Collections;
 | |
|  import java.util.HashMap;
 | |
|  import java.util.Map;
 | |
| +import java.util.Optional;
 | |
|  import java.util.Set;
 | |
|  import java.util.function.Function;
 | |
|  
 | |
| @@ -61,13 +62,14 @@ public class IndexHtmlUtil {
 | |
|        String faviconPath,
 | |
|        Map<String, String[]> urlParameterMap,
 | |
|        Function<String, SanitizedContent> urlInScriptTagOrdainer,
 | |
| -      String requestedURL)
 | |
| +      String requestedURL,
 | |
| +      TitleComputer titleComputer)
 | |
|        throws URISyntaxException, RestApiException {
 | |
|      ImmutableMap.Builder<String, Object> data = ImmutableMap.builder();
 | |
|      data.putAll(
 | |
|              staticTemplateData(
 | |
|                  canonicalURL, cdnPath, faviconPath, urlParameterMap, urlInScriptTagOrdainer))
 | |
| -        .putAll(dynamicTemplateData(gerritApi, requestedURL));
 | |
| +        .putAll(dynamicTemplateData(gerritApi, requestedURL, titleComputer));
 | |
|      Set<String> enabledExperiments = experimentFeatures.getEnabledExperimentFeatures();
 | |
|  
 | |
|      if (!enabledExperiments.isEmpty()) {
 | |
| @@ -78,7 +80,8 @@ public class IndexHtmlUtil {
 | |
|  
 | |
|    /** Returns dynamic parameters of {@code index.html}. */
 | |
|    public static ImmutableMap<String, Object> dynamicTemplateData(
 | |
| -      GerritApi gerritApi, String requestedURL) throws RestApiException, URISyntaxException {
 | |
| +      GerritApi gerritApi, String requestedURL, TitleComputer titleComputer)
 | |
| +		  throws RestApiException, URISyntaxException {
 | |
|      ImmutableMap.Builder<String, Object> data = ImmutableMap.builder();
 | |
|      Map<String, SanitizedContent> initialData = new HashMap<>();
 | |
|      Server serverApi = gerritApi.config().server();
 | |
| @@ -131,6 +134,10 @@ public class IndexHtmlUtil {
 | |
|      }
 | |
|  
 | |
|      data.put("gerritInitialData", initialData);
 | |
| +
 | |
| +    Optional<String> 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..36eb0c990c 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<String, SanitizedContent> 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 8e8a9d27f0..a0fb168554 100644
 | |
| --- a/java/com/google/gerrit/httpd/raw/StaticModule.java
 | |
| +++ b/java/com/google/gerrit/httpd/raw/StaticModule.java
 | |
| @@ -226,10 +226,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<ChangesCollection> changes) {
 | |
| +    this.changes = changes;
 | |
| +  }
 | |
| +
 | |
| +  public Optional<String> 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<Change.Id> changeId = tryExtractChange(url.getPath());
 | |
| +    if (changeId.isPresent()) {
 | |
| +      return titleFromChangeId(changeId.get());
 | |
| +    }
 | |
| +
 | |
| +    return Optional.empty();
 | |
| +  }
 | |
| +
 | |
| +  private static final Pattern extractChangeIdRegex = Pattern.compile("^/(?:c/.*/\\+/)?(?<changeId>[0-9]+)(?:/[0-9]+)?(?:/.*)?$");
 | |
| +  private final Provider<ChangesCollection> changes;
 | |
| +
 | |
| +  private Optional<Change.Id> tryExtractChange(String path) {
 | |
| +    Matcher m = extractChangeIdRegex.matcher(path);
 | |
| +    if (!m.matches()) {
 | |
| +      return Optional.empty();
 | |
| +    }
 | |
| +    return Change.Id.tryParse(m.group("changeId"));
 | |
| +  }
 | |
| +
 | |
| +  private Optional<String> 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 8c97a49e81..129092dc7e 100644
 | |
| --- a/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy
 | |
| +++ b/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy
 | |
| @@ -32,10 +32,12 @@
 | |
|    {@param? defaultDashboardHex: ?}
 | |
|    {@param? dashboardQuery: ?}
 | |
|    {@param? userIsAuthenticated: ?}
 | |
| +  {@param? title: ?}
 | |
|    <!DOCTYPE html>{\n}
 | |
|    <html lang="en">{\n}
 | |
|    <meta charset="utf-8">{\n}
 | |
| -  <meta name="description" content="Gerrit Code Review">{\n}
 | |
| +  {if $title}<title>{$title} · Gerrit Code Review</title>{\n}{/if}
 | |
| +  <meta name="description" content="{if $title}{$title} · {/if}Gerrit Code Review">{\n}
 | |
|    <meta name="referrer" content="never">{\n}
 | |
|    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">{\n}
 | |
|  
 | |
| -- 
 | |
| 2.36.0
 | |
| 
 |