LCOV - code coverage report
Current view: top level - httpd/raw - IndexHtmlUtil.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 55 70 78.6 %
Date: 2022-11-19 15:00:39 Functions: 6 6 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2019 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.httpd.raw;
      16             : 
      17             : import static com.google.gerrit.httpd.raw.IndexPreloadingUtil.RequestedPage;
      18             : import static com.google.template.soy.data.ordainers.GsonOrdainer.serializeObject;
      19             : import static java.util.stream.Collectors.toSet;
      20             : 
      21             : import com.google.common.base.Strings;
      22             : import com.google.common.collect.ImmutableMap;
      23             : import com.google.common.flogger.FluentLogger;
      24             : import com.google.gerrit.common.Nullable;
      25             : import com.google.gerrit.common.UsedAt;
      26             : import com.google.gerrit.common.UsedAt.Project;
      27             : import com.google.gerrit.extensions.api.GerritApi;
      28             : import com.google.gerrit.extensions.api.accounts.AccountApi;
      29             : import com.google.gerrit.extensions.api.config.Server;
      30             : import com.google.gerrit.extensions.client.ListOption;
      31             : import com.google.gerrit.extensions.restapi.AuthException;
      32             : import com.google.gerrit.extensions.restapi.RestApiException;
      33             : import com.google.gerrit.json.OutputFormat;
      34             : import com.google.gerrit.server.experiments.ExperimentFeatures;
      35             : import com.google.gson.Gson;
      36             : import com.google.template.soy.data.SanitizedContent;
      37             : import java.net.URI;
      38             : import java.net.URISyntaxException;
      39             : import java.util.Arrays;
      40             : import java.util.Collections;
      41             : import java.util.HashMap;
      42             : import java.util.HashSet;
      43             : import java.util.Map;
      44             : import java.util.Set;
      45             : import java.util.function.Function;
      46             : 
      47             : /** Helper for generating parts of {@code index.html}. */
      48             : @UsedAt(Project.GOOGLE)
      49             : public class IndexHtmlUtil {
      50           1 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      51             : 
      52           1 :   private static final Gson GSON = OutputFormat.JSON_COMPACT.newGson();
      53             :   /**
      54             :    * Returns both static and dynamic parameters of {@code index.html}. The result is to be used when
      55             :    * rendering the soy template.
      56             :    */
      57             :   public static ImmutableMap<String, Object> templateData(
      58             :       GerritApi gerritApi,
      59             :       ExperimentFeatures experimentFeatures,
      60             :       String canonicalURL,
      61             :       String cdnPath,
      62             :       String faviconPath,
      63             :       Map<String, String[]> urlParameterMap,
      64             :       Function<String, SanitizedContent> urlInScriptTagOrdainer,
      65             :       String requestedURL)
      66             :       throws URISyntaxException, RestApiException {
      67           1 :     ImmutableMap.Builder<String, Object> data = ImmutableMap.builder();
      68           1 :     data.putAll(
      69           1 :             staticTemplateData(
      70             :                 canonicalURL, cdnPath, faviconPath, urlParameterMap, urlInScriptTagOrdainer))
      71           1 :         .putAll(dynamicTemplateData(gerritApi, requestedURL));
      72           1 :     Set<String> enabledExperiments = new HashSet<>();
      73           1 :     enabledExperiments.addAll(experimentFeatures.getEnabledExperimentFeatures());
      74             :     // Add all experiments enabled through url
      75           1 :     enabledExperiments.addAll(IndexHtmlUtil.experimentData(urlParameterMap));
      76           1 :     if (!enabledExperiments.isEmpty()) {
      77           1 :       data.put("enabledExperiments", serializeObject(GSON, enabledExperiments).toString());
      78             :     }
      79           1 :     return data.build();
      80             :   }
      81             : 
      82             :   /** Returns dynamic parameters of {@code index.html}. */
      83             :   public static ImmutableMap<String, Object> dynamicTemplateData(
      84             :       GerritApi gerritApi, String requestedURL) throws RestApiException, URISyntaxException {
      85           1 :     ImmutableMap.Builder<String, Object> data = ImmutableMap.builder();
      86           1 :     Map<String, SanitizedContent> initialData = new HashMap<>();
      87           1 :     Server serverApi = gerritApi.config().server();
      88           1 :     initialData.put("\"/config/server/info\"", serializeObject(GSON, serverApi.getInfo()));
      89           1 :     initialData.put("\"/config/server/version\"", serializeObject(GSON, serverApi.getVersion()));
      90           1 :     initialData.put("\"/config/server/top-menus\"", serializeObject(GSON, serverApi.topMenus()));
      91             : 
      92           1 :     String requestedPath = IndexPreloadingUtil.getPath(requestedURL);
      93           1 :     IndexPreloadingUtil.RequestedPage page = IndexPreloadingUtil.parseRequestedPage(requestedPath);
      94           1 :     switch (page) {
      95             :       case CHANGE:
      96             :       case DIFF:
      97           1 :         data.put(
      98           1 :             "defaultChangeDetailHex", ListOption.toHex(IndexPreloadingUtil.CHANGE_DETAIL_OPTIONS));
      99           1 :         data.put(
     100             :             "changeRequestsPath",
     101           1 :             IndexPreloadingUtil.computeChangeRequestsPath(requestedPath, page).get());
     102           1 :         data.put("changeNum", IndexPreloadingUtil.computeChangeNum(requestedPath, page).get());
     103           1 :         break;
     104             :       case DASHBOARD:
     105             :         // Dashboard is preloaded queries are added later when we check user is authenticated.
     106             :       case PAGE_WITHOUT_PRELOADING:
     107             :         break;
     108             :     }
     109             : 
     110             :     try {
     111           0 :       AccountApi accountApi = gerritApi.accounts().self();
     112           0 :       initialData.put("\"/accounts/self/detail\"", serializeObject(GSON, accountApi.get()));
     113           0 :       initialData.put(
     114           0 :           "\"/accounts/self/preferences\"", serializeObject(GSON, accountApi.getPreferences()));
     115           0 :       initialData.put(
     116             :           "\"/accounts/self/preferences.diff\"",
     117           0 :           serializeObject(GSON, accountApi.getDiffPreferences()));
     118           0 :       initialData.put(
     119             :           "\"/accounts/self/preferences.edit\"",
     120           0 :           serializeObject(GSON, accountApi.getEditPreferences()));
     121           0 :       data.put("userIsAuthenticated", true);
     122           0 :       if (page == RequestedPage.DASHBOARD) {
     123           0 :         data.put("defaultDashboardHex", ListOption.toHex(IndexPreloadingUtil.DASHBOARD_OPTIONS));
     124           0 :         data.put("dashboardQuery", IndexPreloadingUtil.computeDashboardQueryList(serverApi));
     125             :       }
     126           1 :     } catch (AuthException e) {
     127           1 :       logger.atFine().log("Can't inline account-related data because user is unauthenticated");
     128             :       // Don't render data
     129           0 :     }
     130             : 
     131           1 :     data.put("gerritInitialData", initialData);
     132           1 :     return data.build();
     133             :   }
     134             : 
     135             :   /** Returns experimentData to be used in {@code index.html}. */
     136             :   public static Set<String> experimentData(Map<String, String[]> urlParameterMap) {
     137             :     // Allow enable experiments with url
     138             :     // ?experiment=a&experiment=b should result in:
     139             :     // "experiment" => [a,b]
     140           1 :     if (urlParameterMap.containsKey("experiment")) {
     141           1 :       return Arrays.asList(urlParameterMap.get("experiment")).stream().collect(toSet());
     142             :     }
     143             : 
     144           1 :     return Collections.emptySet();
     145             :   }
     146             : 
     147             :   /** Returns all static parameters of {@code index.html}. */
     148             :   static Map<String, Object> staticTemplateData(
     149             :       String canonicalURL,
     150             :       String cdnPath,
     151             :       String faviconPath,
     152             :       Map<String, String[]> urlParameterMap,
     153             :       Function<String, SanitizedContent> urlInScriptTagOrdainer)
     154             :       throws URISyntaxException {
     155           1 :     String canonicalPath = computeCanonicalPath(canonicalURL);
     156             : 
     157           1 :     String staticPath = "";
     158           1 :     if (cdnPath != null) {
     159           1 :       staticPath = cdnPath;
     160           1 :     } else if (canonicalPath != null) {
     161           1 :       staticPath = canonicalPath;
     162             :     }
     163             : 
     164           1 :     SanitizedContent sanitizedStaticPath = urlInScriptTagOrdainer.apply(staticPath);
     165           1 :     ImmutableMap.Builder<String, Object> data = ImmutableMap.builder();
     166             : 
     167           1 :     if (canonicalPath != null) {
     168           1 :       data.put("canonicalPath", canonicalPath);
     169             :     }
     170           1 :     if (sanitizedStaticPath != null) {
     171           1 :       data.put("staticResourcePath", sanitizedStaticPath);
     172             :     }
     173           1 :     if (faviconPath != null) {
     174           1 :       data.put("faviconPath", faviconPath);
     175             :     }
     176             : 
     177           1 :     if (urlParameterMap.containsKey("ce")) {
     178           0 :       data.put("polyfillCE", "true");
     179             :     }
     180           1 :     if (urlParameterMap.containsKey("gf")) {
     181           1 :       data.put("useGoogleFonts", "true");
     182             :     }
     183             : 
     184           1 :     return data.build();
     185             :   }
     186             : 
     187             :   private static String computeCanonicalPath(@Nullable String canonicalURL)
     188             :       throws URISyntaxException {
     189           1 :     if (Strings.isNullOrEmpty(canonicalURL)) {
     190           0 :       return "";
     191             :     }
     192             : 
     193             :     // If we serving from a sub-directory rather than root, determine the path
     194             :     // from the cannonical web URL.
     195           1 :     URI uri = new URI(canonicalURL);
     196           1 :     return uri.getPath().replaceAll("/$", "");
     197             :   }
     198             : 
     199             :   private IndexHtmlUtil() {}
     200             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750