LCOV - code coverage report
Current view: top level - server/restapi/config - GetServerInfo.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 132 173 76.3 %
Date: 2022-11-19 15:00:39 Functions: 18 22 81.8 %

          Line data    Source code
       1             : // Copyright (C) 2015 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.server.restapi.config;
      16             : 
      17             : import static java.util.stream.Collectors.toList;
      18             : 
      19             : import com.google.common.base.CharMatcher;
      20             : import com.google.common.base.Strings;
      21             : import com.google.common.collect.Lists;
      22             : import com.google.gerrit.common.Nullable;
      23             : import com.google.gerrit.entities.ContributorAgreement;
      24             : import com.google.gerrit.extensions.common.AccountDefaultDisplayName;
      25             : import com.google.gerrit.extensions.common.AccountsInfo;
      26             : import com.google.gerrit.extensions.common.AuthInfo;
      27             : import com.google.gerrit.extensions.common.ChangeConfigInfo;
      28             : import com.google.gerrit.extensions.common.DownloadInfo;
      29             : import com.google.gerrit.extensions.common.DownloadSchemeInfo;
      30             : import com.google.gerrit.extensions.common.GerritInfo;
      31             : import com.google.gerrit.extensions.common.PluginConfigInfo;
      32             : import com.google.gerrit.extensions.common.ReceiveInfo;
      33             : import com.google.gerrit.extensions.common.ServerInfo;
      34             : import com.google.gerrit.extensions.common.SshdInfo;
      35             : import com.google.gerrit.extensions.common.SuggestInfo;
      36             : import com.google.gerrit.extensions.common.UserConfigInfo;
      37             : import com.google.gerrit.extensions.config.CloneCommand;
      38             : import com.google.gerrit.extensions.config.DownloadCommand;
      39             : import com.google.gerrit.extensions.config.DownloadScheme;
      40             : import com.google.gerrit.extensions.restapi.Response;
      41             : import com.google.gerrit.extensions.restapi.RestReadView;
      42             : import com.google.gerrit.extensions.webui.WebUiPlugin;
      43             : import com.google.gerrit.server.EnableSignedPush;
      44             : import com.google.gerrit.server.account.AccountVisibilityProvider;
      45             : import com.google.gerrit.server.account.Realm;
      46             : import com.google.gerrit.server.avatar.AvatarProvider;
      47             : import com.google.gerrit.server.change.ArchiveFormatInternal;
      48             : import com.google.gerrit.server.change.MergeabilityComputationBehavior;
      49             : import com.google.gerrit.server.config.AllProjectsName;
      50             : import com.google.gerrit.server.config.AllUsersName;
      51             : import com.google.gerrit.server.config.AnonymousCowardName;
      52             : import com.google.gerrit.server.config.AuthConfig;
      53             : import com.google.gerrit.server.config.ConfigResource;
      54             : import com.google.gerrit.server.config.ConfigUtil;
      55             : import com.google.gerrit.server.config.GerritServerConfig;
      56             : import com.google.gerrit.server.config.SitePaths;
      57             : import com.google.gerrit.server.documentation.QueryDocumentationExecutor;
      58             : import com.google.gerrit.server.index.change.ChangeField;
      59             : import com.google.gerrit.server.index.change.ChangeIndexCollection;
      60             : import com.google.gerrit.server.permissions.PermissionBackendException;
      61             : import com.google.gerrit.server.plugincontext.PluginItemContext;
      62             : import com.google.gerrit.server.plugincontext.PluginMapContext;
      63             : import com.google.gerrit.server.plugincontext.PluginSetContext;
      64             : import com.google.gerrit.server.project.ProjectCache;
      65             : import com.google.gerrit.server.restapi.change.AllowedFormats;
      66             : import com.google.gerrit.server.submit.MergeSuperSet;
      67             : import com.google.inject.Inject;
      68             : import java.nio.file.Files;
      69             : import java.util.ArrayList;
      70             : import java.util.Arrays;
      71             : import java.util.Collection;
      72             : import java.util.HashMap;
      73             : import java.util.List;
      74             : import java.util.concurrent.TimeUnit;
      75             : import org.eclipse.jgit.lib.Config;
      76             : 
      77             : public class GetServerInfo implements RestReadView<ConfigResource> {
      78             :   private final Config config;
      79             :   private final AccountVisibilityProvider accountVisibilityProvider;
      80             :   private final AccountDefaultDisplayName accountDefaultDisplayName;
      81             :   private final AuthConfig authConfig;
      82             :   private final Realm realm;
      83             :   private final PluginMapContext<DownloadScheme> downloadSchemes;
      84             :   private final PluginMapContext<DownloadCommand> downloadCommands;
      85             :   private final PluginMapContext<CloneCommand> cloneCommands;
      86             :   private final PluginSetContext<WebUiPlugin> plugins;
      87             :   private final AllowedFormats archiveFormats;
      88             :   private final AllProjectsName allProjectsName;
      89             :   private final AllUsersName allUsersName;
      90             :   private final String anonymousCowardName;
      91             :   private final PluginItemContext<AvatarProvider> avatar;
      92             :   private final boolean enableSignedPush;
      93             :   private final QueryDocumentationExecutor docSearcher;
      94             :   private final ProjectCache projectCache;
      95             :   private final AgreementJson agreementJson;
      96             :   private final ChangeIndexCollection indexes;
      97             :   private final SitePaths sitePaths;
      98             : 
      99             :   @Inject
     100             :   public GetServerInfo(
     101             :       @GerritServerConfig Config config,
     102             :       AccountVisibilityProvider accountVisibilityProvider,
     103             :       AccountDefaultDisplayName accountDefaultDisplayName,
     104             :       AuthConfig authConfig,
     105             :       Realm realm,
     106             :       PluginMapContext<DownloadScheme> downloadSchemes,
     107             :       PluginMapContext<DownloadCommand> downloadCommands,
     108             :       PluginMapContext<CloneCommand> cloneCommands,
     109             :       PluginSetContext<WebUiPlugin> webUiPlugins,
     110             :       AllowedFormats archiveFormats,
     111             :       AllProjectsName allProjectsName,
     112             :       AllUsersName allUsersName,
     113             :       @AnonymousCowardName String anonymousCowardName,
     114             :       PluginItemContext<AvatarProvider> avatar,
     115             :       @EnableSignedPush boolean enableSignedPush,
     116             :       QueryDocumentationExecutor docSearcher,
     117             :       ProjectCache projectCache,
     118             :       AgreementJson agreementJson,
     119             :       ChangeIndexCollection indexes,
     120         149 :       SitePaths sitePaths) {
     121         149 :     this.config = config;
     122         149 :     this.accountVisibilityProvider = accountVisibilityProvider;
     123         149 :     this.accountDefaultDisplayName = accountDefaultDisplayName;
     124         149 :     this.authConfig = authConfig;
     125         149 :     this.realm = realm;
     126         149 :     this.downloadSchemes = downloadSchemes;
     127         149 :     this.downloadCommands = downloadCommands;
     128         149 :     this.cloneCommands = cloneCommands;
     129         149 :     this.plugins = webUiPlugins;
     130         149 :     this.archiveFormats = archiveFormats;
     131         149 :     this.allProjectsName = allProjectsName;
     132         149 :     this.allUsersName = allUsersName;
     133         149 :     this.anonymousCowardName = anonymousCowardName;
     134         149 :     this.avatar = avatar;
     135         149 :     this.enableSignedPush = enableSignedPush;
     136         149 :     this.docSearcher = docSearcher;
     137         149 :     this.projectCache = projectCache;
     138         149 :     this.agreementJson = agreementJson;
     139         149 :     this.indexes = indexes;
     140         149 :     this.sitePaths = sitePaths;
     141         149 :   }
     142             : 
     143             :   @Override
     144             :   public Response<ServerInfo> apply(ConfigResource rsrc) throws PermissionBackendException {
     145           3 :     ServerInfo info = new ServerInfo();
     146           3 :     info.accounts = getAccountsInfo();
     147           3 :     info.auth = getAuthInfo();
     148           3 :     info.change = getChangeInfo();
     149           3 :     info.download = getDownloadInfo();
     150           3 :     info.gerrit = getGerritInfo();
     151           3 :     info.noteDbEnabled = true;
     152           3 :     info.plugin = getPluginInfo();
     153           3 :     info.defaultTheme = getDefaultTheme();
     154           3 :     info.sshd = getSshdInfo();
     155           3 :     info.suggest = getSuggestInfo();
     156             : 
     157           3 :     info.user = getUserInfo();
     158           3 :     info.receive = getReceiveInfo();
     159           3 :     info.submitRequirementDashboardColumns = getSubmitRequirementDashboardColumns();
     160           3 :     return Response.ok(info);
     161             :   }
     162             : 
     163             :   private AccountsInfo getAccountsInfo() {
     164           3 :     AccountsInfo info = new AccountsInfo();
     165           3 :     info.visibility = accountVisibilityProvider.get();
     166           3 :     info.defaultDisplayName = accountDefaultDisplayName;
     167           3 :     return info;
     168             :   }
     169             : 
     170             :   private AuthInfo getAuthInfo() throws PermissionBackendException {
     171           3 :     AuthInfo info = new AuthInfo();
     172           3 :     info.authType = authConfig.getAuthType();
     173           3 :     info.useContributorAgreements = toBoolean(authConfig.isUseContributorAgreements());
     174           3 :     info.editableAccountFields = new ArrayList<>(realm.getEditableFields());
     175           3 :     info.switchAccountUrl = authConfig.getSwitchAccountUrl();
     176           3 :     info.gitBasicAuthPolicy = authConfig.getGitBasicAuthPolicy();
     177             : 
     178           3 :     if (info.useContributorAgreements != null) {
     179           2 :       Collection<ContributorAgreement> agreements =
     180           2 :           projectCache.getAllProjects().getConfig().getContributorAgreements().values();
     181           2 :       if (!agreements.isEmpty()) {
     182           1 :         info.contributorAgreements = Lists.newArrayListWithCapacity(agreements.size());
     183           1 :         for (ContributorAgreement agreement : agreements) {
     184           1 :           info.contributorAgreements.add(agreementJson.format(agreement));
     185           1 :         }
     186             :       }
     187             :     }
     188             : 
     189           3 :     switch (info.authType) {
     190             :       case LDAP:
     191             :       case LDAP_BIND:
     192           0 :         info.registerUrl = authConfig.getRegisterUrl();
     193           0 :         info.registerText = authConfig.getRegisterText();
     194           0 :         info.editFullNameUrl = authConfig.getEditFullNameUrl();
     195           0 :         break;
     196             : 
     197             :       case CUSTOM_EXTENSION:
     198           0 :         info.registerUrl = authConfig.getRegisterUrl();
     199           0 :         info.registerText = authConfig.getRegisterText();
     200           0 :         info.editFullNameUrl = authConfig.getEditFullNameUrl();
     201           0 :         info.httpPasswordUrl = authConfig.getHttpPasswordUrl();
     202           0 :         break;
     203             : 
     204             :       case HTTP:
     205             :       case HTTP_LDAP:
     206           1 :         info.loginUrl = authConfig.getLoginUrl();
     207           1 :         info.loginText = authConfig.getLoginText();
     208           1 :         break;
     209             : 
     210             :       case CLIENT_SSL_CERT_LDAP:
     211             :       case DEVELOPMENT_BECOME_ANY_ACCOUNT:
     212             :       case OAUTH:
     213             :       case OPENID:
     214             :       case OPENID_SSO:
     215             :         break;
     216             :     }
     217           3 :     return info;
     218             :   }
     219             : 
     220             :   private ChangeConfigInfo getChangeInfo() {
     221           3 :     ChangeConfigInfo info = new ChangeConfigInfo();
     222           3 :     info.allowBlame = toBoolean(config.getBoolean("change", "allowBlame", true));
     223           3 :     boolean hasAssigneeInIndex =
     224           3 :         indexes.getSearchIndex().getSchema().hasField(ChangeField.ASSIGNEE_SPEC);
     225           3 :     info.showAssigneeInChangesTable =
     226           3 :         toBoolean(
     227           3 :             config.getBoolean("change", "showAssigneeInChangesTable", false) && hasAssigneeInIndex);
     228           3 :     info.updateDelay =
     229           3 :         (int) ConfigUtil.getTimeUnit(config, "change", null, "updateDelay", 300, TimeUnit.SECONDS);
     230           3 :     info.submitWholeTopic = toBoolean(MergeSuperSet.wholeTopicEnabled(config));
     231           3 :     info.disablePrivateChanges =
     232           3 :         toBoolean(this.config.getBoolean("change", null, "disablePrivateChanges", false));
     233           3 :     info.mergeabilityComputationBehavior =
     234           3 :         MergeabilityComputationBehavior.fromConfig(config).name();
     235           3 :     info.enableAttentionSet =
     236           3 :         toBoolean(this.config.getBoolean("change", null, "enableAttentionSet", true));
     237           3 :     info.enableAssignee =
     238           3 :         toBoolean(this.config.getBoolean("change", null, "enableAssignee", false));
     239           3 :     return info;
     240             :   }
     241             : 
     242             :   private DownloadInfo getDownloadInfo() {
     243           3 :     DownloadInfo info = new DownloadInfo();
     244           3 :     info.schemes = new HashMap<>();
     245           3 :     downloadSchemes.runEach(
     246             :         extension -> {
     247           0 :           DownloadScheme scheme = extension.get();
     248           0 :           if (scheme.isEnabled() && scheme.getUrl("${project}") != null) {
     249           0 :             info.schemes.put(extension.getExportName(), getDownloadSchemeInfo(scheme));
     250             :           }
     251           0 :         });
     252           3 :     info.archives =
     253           3 :         archiveFormats.getAllowed().stream()
     254           3 :             .map(ArchiveFormatInternal::getShortName)
     255           3 :             .collect(toList());
     256           3 :     return info;
     257             :   }
     258             : 
     259             :   private DownloadSchemeInfo getDownloadSchemeInfo(DownloadScheme scheme) {
     260           0 :     DownloadSchemeInfo info = new DownloadSchemeInfo();
     261           0 :     info.url = scheme.getUrl("${project}");
     262           0 :     info.isAuthRequired = toBoolean(scheme.isAuthRequired());
     263           0 :     info.isAuthSupported = toBoolean(scheme.isAuthSupported());
     264             : 
     265           0 :     info.commands = new HashMap<>();
     266           0 :     downloadCommands.runEach(
     267             :         extension -> {
     268           0 :           String commandName = extension.getExportName();
     269           0 :           DownloadCommand command = extension.get();
     270           0 :           String c = command.getCommand(scheme, "${project}", "${ref}");
     271           0 :           if (c != null) {
     272           0 :             info.commands.put(commandName, c);
     273             :           }
     274           0 :         });
     275             : 
     276           0 :     info.cloneCommands = new HashMap<>();
     277           0 :     cloneCommands.runEach(
     278             :         extension -> {
     279           0 :           String commandName = extension.getExportName();
     280           0 :           CloneCommand command = extension.getProvider().get();
     281           0 :           String c = command.getCommand(scheme, "${project-path}/${project-base-name}");
     282           0 :           if (c != null) {
     283           0 :             c =
     284           0 :                 c.replaceAll(
     285             :                     "\\$\\{project-path\\}/\\$\\{project-base-name\\}", "\\$\\{project\\}");
     286           0 :             info.cloneCommands.put(commandName, c);
     287             :           }
     288           0 :         });
     289             : 
     290           0 :     return info;
     291             :   }
     292             : 
     293             :   private GerritInfo getGerritInfo() {
     294           3 :     GerritInfo info = new GerritInfo();
     295           3 :     info.allProjects = allProjectsName.get();
     296           3 :     info.allUsers = allUsersName.get();
     297           3 :     info.reportBugUrl = config.getString("gerrit", null, "reportBugUrl");
     298           3 :     info.docUrl = getDocUrl();
     299           3 :     info.docSearch = docSearcher.isAvailable();
     300           3 :     info.editGpgKeys =
     301           3 :         toBoolean(enableSignedPush && config.getBoolean("gerrit", null, "editGpgKeys", true));
     302           3 :     info.primaryWeblinkName = config.getString("gerrit", null, "primaryWeblinkName");
     303           3 :     info.instanceId = config.getString("gerrit", null, "instanceId");
     304           3 :     return info;
     305             :   }
     306             : 
     307             :   @Nullable
     308             :   private String getDocUrl() {
     309           3 :     String docUrl = config.getString("gerrit", null, "docUrl");
     310           3 :     if (Strings.isNullOrEmpty(docUrl)) {
     311           3 :       return null;
     312             :     }
     313           0 :     return CharMatcher.is('/').trimTrailingFrom(docUrl) + '/';
     314             :   }
     315             : 
     316             :   private PluginConfigInfo getPluginInfo() {
     317           3 :     PluginConfigInfo info = new PluginConfigInfo();
     318           3 :     info.hasAvatars = toBoolean(avatar.hasImplementation());
     319           3 :     info.jsResourcePaths = new ArrayList<>();
     320           3 :     plugins.runEach(
     321             :         plugin -> {
     322           1 :           String path =
     323           1 :               String.format(
     324           1 :                   "plugins/%s/%s", plugin.getPluginName(), plugin.getJavaScriptResourcePath());
     325           1 :           info.jsResourcePaths.add(path);
     326           1 :         });
     327           3 :     return info;
     328             :   }
     329             : 
     330             :   private static final String DEFAULT_THEME = "/static/" + SitePaths.THEME_FILENAME;
     331             :   private static final String DEFAULT_THEME_JS = "/static/" + SitePaths.THEME_JS_FILENAME;
     332             : 
     333             :   @Nullable
     334             :   private String getDefaultTheme() {
     335           3 :     if (config.getString("theme", null, "enableDefault") == null) {
     336             :       // If not explicitly enabled or disabled, check for the existence of the theme file.
     337           3 :       return Files.exists(sitePaths.site_theme_js)
     338           0 :           ? DEFAULT_THEME_JS
     339           3 :           : Files.exists(sitePaths.site_theme) ? DEFAULT_THEME : null;
     340             :     }
     341           0 :     if (config.getBoolean("theme", null, "enableDefault", true)) {
     342             :       // Return non-null theme path without checking for file existence. Even if the file doesn't
     343             :       // exist under the site path, it may be served from a CDN (in which case it's up to the admin
     344             :       // to also pass a proper asset path to the index Soy template).
     345           0 :       return DEFAULT_THEME_JS;
     346             :     }
     347           0 :     return null;
     348             :   }
     349             : 
     350             :   @Nullable
     351             :   private SshdInfo getSshdInfo() {
     352           3 :     String[] addr = config.getStringList("sshd", null, "listenAddress");
     353           3 :     if (addr.length == 1 && isOff(addr[0])) {
     354           2 :       return null;
     355             :     }
     356           1 :     return new SshdInfo();
     357             :   }
     358             : 
     359             :   private static boolean isOff(String listenHostname) {
     360           3 :     return "off".equalsIgnoreCase(listenHostname)
     361           1 :         || "none".equalsIgnoreCase(listenHostname)
     362           3 :         || "no".equalsIgnoreCase(listenHostname);
     363             :   }
     364             : 
     365             :   private SuggestInfo getSuggestInfo() {
     366           3 :     SuggestInfo info = new SuggestInfo();
     367           3 :     info.from = config.getInt("suggest", "from", 0);
     368           3 :     return info;
     369             :   }
     370             : 
     371             :   private UserConfigInfo getUserInfo() {
     372           3 :     UserConfigInfo info = new UserConfigInfo();
     373           3 :     info.anonymousCowardName = anonymousCowardName;
     374           3 :     return info;
     375             :   }
     376             : 
     377             :   private ReceiveInfo getReceiveInfo() {
     378           3 :     ReceiveInfo info = new ReceiveInfo();
     379           3 :     info.enableSignedPush = enableSignedPush;
     380           3 :     return info;
     381             :   }
     382             : 
     383             :   private List<String> getSubmitRequirementDashboardColumns() {
     384           3 :     return Arrays.asList(config.getStringList("dashboard", null, "submitRequirementColumns"));
     385             :   }
     386             : 
     387             :   @Nullable
     388             :   private static Boolean toBoolean(boolean v) {
     389           3 :     return v ? Boolean.TRUE : null;
     390             :   }
     391             : }

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