LCOV - code coverage report
Current view: top level - server/restapi/project - DashboardsCollection.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 76 88 86.4 %
Date: 2022-11-19 15:00:39 Functions: 13 14 92.9 %

          Line data    Source code
       1             : // Copyright (C) 2012 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.project;
      16             : 
      17             : import static com.google.gerrit.entities.RefNames.REFS_DASHBOARDS;
      18             : 
      19             : import com.google.common.base.Joiner;
      20             : import com.google.common.base.MoreObjects;
      21             : import com.google.common.base.Splitter;
      22             : import com.google.common.base.Strings;
      23             : import com.google.common.collect.Lists;
      24             : import com.google.gerrit.common.Nullable;
      25             : import com.google.gerrit.entities.Project;
      26             : import com.google.gerrit.extensions.api.projects.DashboardInfo;
      27             : import com.google.gerrit.extensions.api.projects.DashboardSectionInfo;
      28             : import com.google.gerrit.extensions.registration.DynamicMap;
      29             : import com.google.gerrit.extensions.restapi.AuthException;
      30             : import com.google.gerrit.extensions.restapi.ChildCollection;
      31             : import com.google.gerrit.extensions.restapi.IdString;
      32             : import com.google.gerrit.extensions.restapi.ResourceConflictException;
      33             : import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
      34             : import com.google.gerrit.extensions.restapi.RestApiException;
      35             : import com.google.gerrit.extensions.restapi.RestView;
      36             : import com.google.gerrit.extensions.restapi.Url;
      37             : import com.google.gerrit.server.CurrentUser;
      38             : import com.google.gerrit.server.UrlEncoded;
      39             : import com.google.gerrit.server.git.GitRepositoryManager;
      40             : import com.google.gerrit.server.permissions.PermissionBackend;
      41             : import com.google.gerrit.server.permissions.PermissionBackendException;
      42             : import com.google.gerrit.server.permissions.RefPermission;
      43             : import com.google.gerrit.server.project.DashboardResource;
      44             : import com.google.gerrit.server.project.ProjectResource;
      45             : import com.google.gerrit.server.project.ProjectState;
      46             : import com.google.inject.Inject;
      47             : import com.google.inject.Provider;
      48             : import com.google.inject.Singleton;
      49             : import java.io.IOException;
      50             : import java.util.List;
      51             : import org.eclipse.jgit.errors.AmbiguousObjectException;
      52             : import org.eclipse.jgit.errors.ConfigInvalidException;
      53             : import org.eclipse.jgit.errors.IncorrectObjectTypeException;
      54             : import org.eclipse.jgit.errors.RepositoryNotFoundException;
      55             : import org.eclipse.jgit.lib.BlobBasedConfig;
      56             : import org.eclipse.jgit.lib.Config;
      57             : import org.eclipse.jgit.lib.ObjectId;
      58             : import org.eclipse.jgit.lib.Repository;
      59             : 
      60             : @Singleton
      61             : public class DashboardsCollection implements ChildCollection<ProjectResource, DashboardResource> {
      62             :   public static final String DEFAULT_DASHBOARD_NAME = "default";
      63             : 
      64             :   private final GitRepositoryManager gitManager;
      65             :   private final DynamicMap<RestView<DashboardResource>> views;
      66             :   private final Provider<ListDashboards> list;
      67             :   private final PermissionBackend permissionBackend;
      68             : 
      69             :   @Inject
      70             :   DashboardsCollection(
      71             :       GitRepositoryManager gitManager,
      72             :       DynamicMap<RestView<DashboardResource>> views,
      73             :       Provider<ListDashboards> list,
      74         144 :       PermissionBackend permissionBackend) {
      75         144 :     this.gitManager = gitManager;
      76         144 :     this.views = views;
      77         144 :     this.list = list;
      78         144 :     this.permissionBackend = permissionBackend;
      79         144 :   }
      80             : 
      81             :   public static boolean isDefaultDashboard(@Nullable String id) {
      82           2 :     return DEFAULT_DASHBOARD_NAME.equals(id);
      83             :   }
      84             : 
      85             :   public static boolean isDefaultDashboard(@Nullable IdString id) {
      86           2 :     return id != null && isDefaultDashboard(id.toString());
      87             :   }
      88             : 
      89             :   @Override
      90             :   public RestView<ProjectResource> list() throws ResourceNotFoundException {
      91           1 :     return list.get();
      92             :   }
      93             : 
      94             :   @Override
      95             :   public DashboardResource parse(ProjectResource parent, IdString id)
      96             :       throws RestApiException, IOException, ConfigInvalidException, PermissionBackendException {
      97           2 :     parent.getProjectState().checkStatePermitsRead();
      98           2 :     if (isDefaultDashboard(id)) {
      99           2 :       return DashboardResource.projectDefault(parent.getProjectState(), parent.getUser());
     100             :     }
     101             : 
     102             :     DashboardInfo info;
     103             :     try {
     104           2 :       info = newDashboardInfo(id.get());
     105           0 :     } catch (InvalidDashboardId e) {
     106           0 :       throw new ResourceNotFoundException(id, e);
     107           2 :     }
     108             : 
     109           2 :     for (ProjectState ps : parent.getProjectState().tree()) {
     110             :       try {
     111           2 :         return parse(ps, parent.getProjectState(), parent.getUser(), info);
     112           0 :       } catch (AmbiguousObjectException | ConfigInvalidException | IncorrectObjectTypeException e) {
     113           0 :         throw new ResourceNotFoundException(id, e);
     114           1 :       } catch (ResourceNotFoundException e) {
     115           1 :         continue;
     116             :       }
     117             :     }
     118           1 :     throw new ResourceNotFoundException(id);
     119             :   }
     120             : 
     121             :   public static String normalizeDashboardRef(String ref) {
     122           2 :     if (!ref.startsWith(REFS_DASHBOARDS)) {
     123           1 :       return REFS_DASHBOARDS + ref;
     124             :     }
     125           1 :     return ref;
     126             :   }
     127             : 
     128             :   private DashboardResource parse(
     129             :       ProjectState parent, ProjectState current, CurrentUser user, DashboardInfo info)
     130             :       throws ResourceNotFoundException, IOException, AmbiguousObjectException,
     131             :           IncorrectObjectTypeException, ConfigInvalidException, PermissionBackendException,
     132             :           ResourceConflictException {
     133           2 :     String ref = normalizeDashboardRef(info.ref);
     134             :     try {
     135           2 :       permissionBackend.user(user).project(parent.getNameKey()).ref(ref).check(RefPermission.READ);
     136           0 :     } catch (AuthException e) {
     137             :       // Don't leak the project's existence
     138           0 :       throw new ResourceNotFoundException(info.id, e);
     139           2 :     }
     140           2 :     if (!Repository.isValidRefName(ref)) {
     141           0 :       throw new ResourceNotFoundException(info.id);
     142             :     }
     143             : 
     144           2 :     current.checkStatePermitsRead();
     145             : 
     146           2 :     try (Repository git = gitManager.openRepository(parent.getNameKey())) {
     147           2 :       ObjectId objId = git.resolve(ref + ":" + info.path);
     148           2 :       if (objId == null) {
     149           1 :         throw new ResourceNotFoundException(info.id);
     150             :       }
     151           2 :       BlobBasedConfig cfg = new BlobBasedConfig(null, git, objId);
     152           2 :       return new DashboardResource(current, user, ref, info.path, cfg, false);
     153           0 :     } catch (RepositoryNotFoundException e) {
     154           0 :       throw new ResourceNotFoundException(info.id, e);
     155             :     }
     156             :   }
     157             : 
     158             :   @Override
     159             :   public DynamicMap<RestView<DashboardResource>> views() {
     160           1 :     return views;
     161             :   }
     162             : 
     163             :   public static DashboardInfo newDashboardInfo(String ref, String path) {
     164           2 :     DashboardInfo info = new DashboardInfo();
     165           2 :     info.ref = ref;
     166           2 :     info.path = path;
     167           2 :     info.id = Joiner.on(':').join(Url.encode(ref), Url.encode(path));
     168           2 :     return info;
     169             :   }
     170             : 
     171             :   public static class InvalidDashboardId extends Exception {
     172             :     private static final long serialVersionUID = 1L;
     173             : 
     174             :     public InvalidDashboardId(String id) {
     175           0 :       super(id);
     176           0 :     }
     177             :   }
     178             : 
     179             :   static DashboardInfo newDashboardInfo(String id) throws InvalidDashboardId {
     180           2 :     DashboardInfo info = new DashboardInfo();
     181           2 :     List<String> parts = Lists.newArrayList(Splitter.on(':').limit(2).split(id));
     182           2 :     if (parts.size() != 2) {
     183           0 :       throw new InvalidDashboardId(id);
     184             :     }
     185           2 :     info.id = id;
     186           2 :     info.ref = parts.get(0);
     187           2 :     info.path = parts.get(1);
     188           2 :     return info;
     189             :   }
     190             : 
     191             :   static DashboardInfo parse(
     192             :       Project definingProject,
     193             :       String refName,
     194             :       String path,
     195             :       Config config,
     196             :       String project,
     197             :       boolean setDefault) {
     198           2 :     DashboardInfo info = newDashboardInfo(refName, path);
     199           2 :     info.project = project;
     200           2 :     info.definingProject = definingProject.getName();
     201           2 :     String title = config.getString("dashboard", null, "title");
     202           2 :     info.title = replace(project, title == null ? info.path : title);
     203           2 :     info.description = replace(project, config.getString("dashboard", null, "description"));
     204           2 :     info.foreach = config.getString("dashboard", null, "foreach");
     205             : 
     206           2 :     if (setDefault) {
     207           2 :       String id = refName + ":" + path;
     208           2 :       info.isDefault = id.equals(defaultOf(definingProject)) ? true : null;
     209             :     }
     210             : 
     211           2 :     UrlEncoded u = new UrlEncoded("/dashboard/");
     212           2 :     u.put("title", MoreObjects.firstNonNull(info.title, info.path));
     213           2 :     if (info.foreach != null) {
     214           1 :       u.put("foreach", replace(project, info.foreach));
     215             :     }
     216           2 :     for (String name : config.getSubsections("section")) {
     217           2 :       DashboardSectionInfo s = new DashboardSectionInfo();
     218           2 :       s.name = name;
     219           2 :       s.query = config.getString("section", name, "query");
     220           2 :       u.put(s.name, replace(project, s.query));
     221           2 :       info.sections.add(s);
     222           2 :     }
     223           2 :     info.url = u.toString().replace("%3A", ":");
     224             : 
     225           2 :     return info;
     226             :   }
     227             : 
     228             :   @Nullable
     229             :   private static String replace(String project, String input) {
     230           2 :     return input == null ? input : input.replace("${project}", project);
     231             :   }
     232             : 
     233             :   private static String defaultOf(Project proj) {
     234           2 :     final String defaultId =
     235           2 :         MoreObjects.firstNonNull(
     236           2 :             proj.getLocalDefaultDashboard(), Strings.nullToEmpty(proj.getDefaultDashboard()));
     237           2 :     if (defaultId.startsWith(REFS_DASHBOARDS)) {
     238           1 :       return defaultId.substring(REFS_DASHBOARDS.length());
     239             :     }
     240           1 :     return defaultId;
     241             :   }
     242             : }

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