diff options
Diffstat (limited to 'java/com/google/gerrit/server/restapi/project/DashboardsCollection.java')
-rw-r--r-- | java/com/google/gerrit/server/restapi/project/DashboardsCollection.java | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java b/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java new file mode 100644 index 0000000000..07691e7251 --- /dev/null +++ b/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java @@ -0,0 +1,241 @@ +// Copyright (C) 2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.restapi.project; + +import static com.google.gerrit.reviewdb.client.RefNames.REFS_DASHBOARDS; + +import com.google.common.base.Joiner; +import com.google.common.base.MoreObjects; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.gerrit.common.Nullable; +import com.google.gerrit.extensions.api.projects.DashboardInfo; +import com.google.gerrit.extensions.api.projects.DashboardSectionInfo; +import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.ChildCollection; +import com.google.gerrit.extensions.restapi.IdString; +import com.google.gerrit.extensions.restapi.ResourceConflictException; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.extensions.restapi.RestView; +import com.google.gerrit.extensions.restapi.Url; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.UrlEncoded; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.permissions.PermissionBackend; +import com.google.gerrit.server.permissions.PermissionBackendException; +import com.google.gerrit.server.permissions.RefPermission; +import com.google.gerrit.server.project.DashboardResource; +import com.google.gerrit.server.project.ProjectResource; +import com.google.gerrit.server.project.ProjectState; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import java.io.IOException; +import java.util.List; +import org.eclipse.jgit.errors.AmbiguousObjectException; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.eclipse.jgit.lib.BlobBasedConfig; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; + +@Singleton +public class DashboardsCollection implements ChildCollection<ProjectResource, DashboardResource> { + public static final String DEFAULT_DASHBOARD_NAME = "default"; + + private final GitRepositoryManager gitManager; + private final DynamicMap<RestView<DashboardResource>> views; + private final Provider<ListDashboards> list; + private final PermissionBackend permissionBackend; + + @Inject + DashboardsCollection( + GitRepositoryManager gitManager, + DynamicMap<RestView<DashboardResource>> views, + Provider<ListDashboards> list, + PermissionBackend permissionBackend) { + this.gitManager = gitManager; + this.views = views; + this.list = list; + this.permissionBackend = permissionBackend; + } + + public static boolean isDefaultDashboard(@Nullable String id) { + return DEFAULT_DASHBOARD_NAME.equals(id); + } + + public static boolean isDefaultDashboard(@Nullable IdString id) { + return id != null && isDefaultDashboard(id.toString()); + } + + @Override + public RestView<ProjectResource> list() throws ResourceNotFoundException { + return list.get(); + } + + @Override + public DashboardResource parse(ProjectResource parent, IdString id) + throws RestApiException, IOException, ConfigInvalidException, PermissionBackendException { + parent.getProjectState().checkStatePermitsRead(); + if (isDefaultDashboard(id)) { + return DashboardResource.projectDefault(parent.getProjectState(), parent.getUser()); + } + + DashboardInfo info; + try { + info = newDashboardInfo(id.get()); + } catch (InvalidDashboardId e) { + throw new ResourceNotFoundException(id); + } + + for (ProjectState ps : parent.getProjectState().tree()) { + try { + return parse(ps, parent.getProjectState(), parent.getUser(), info); + } catch (AmbiguousObjectException | ConfigInvalidException | IncorrectObjectTypeException e) { + throw new ResourceNotFoundException(id); + } catch (ResourceNotFoundException e) { + continue; + } + } + throw new ResourceNotFoundException(id); + } + + public static String normalizeDashboardRef(String ref) { + if (!ref.startsWith(REFS_DASHBOARDS)) { + return REFS_DASHBOARDS + ref; + } + return ref; + } + + private DashboardResource parse( + ProjectState parent, ProjectState current, CurrentUser user, DashboardInfo info) + throws ResourceNotFoundException, IOException, AmbiguousObjectException, + IncorrectObjectTypeException, ConfigInvalidException, PermissionBackendException, + ResourceConflictException { + String ref = normalizeDashboardRef(info.ref); + try { + permissionBackend.user(user).project(parent.getNameKey()).ref(ref).check(RefPermission.READ); + } catch (AuthException e) { + // Don't leak the project's existence + throw new ResourceNotFoundException(info.id); + } + if (!Repository.isValidRefName(ref)) { + throw new ResourceNotFoundException(info.id); + } + + current.checkStatePermitsRead(); + + try (Repository git = gitManager.openRepository(parent.getNameKey())) { + ObjectId objId = git.resolve(ref + ":" + info.path); + if (objId == null) { + throw new ResourceNotFoundException(info.id); + } + BlobBasedConfig cfg = new BlobBasedConfig(null, git, objId); + return new DashboardResource(current, user, ref, info.path, cfg, false); + } catch (RepositoryNotFoundException e) { + throw new ResourceNotFoundException(info.id); + } + } + + @Override + public DynamicMap<RestView<DashboardResource>> views() { + return views; + } + + public static DashboardInfo newDashboardInfo(String ref, String path) { + DashboardInfo info = new DashboardInfo(); + info.ref = ref; + info.path = path; + info.id = Joiner.on(':').join(Url.encode(ref), Url.encode(path)); + return info; + } + + public static class InvalidDashboardId extends Exception { + private static final long serialVersionUID = 1L; + + public InvalidDashboardId(String id) { + super(id); + } + } + + static DashboardInfo newDashboardInfo(String id) throws InvalidDashboardId { + DashboardInfo info = new DashboardInfo(); + List<String> parts = Lists.newArrayList(Splitter.on(':').limit(2).split(id)); + if (parts.size() != 2) { + throw new InvalidDashboardId(id); + } + info.id = id; + info.ref = parts.get(0); + info.path = parts.get(1); + return info; + } + + static DashboardInfo parse( + Project definingProject, + String refName, + String path, + Config config, + String project, + boolean setDefault) { + DashboardInfo info = newDashboardInfo(refName, path); + info.project = project; + info.definingProject = definingProject.getName(); + String title = config.getString("dashboard", null, "title"); + info.title = replace(project, title == null ? info.path : title); + info.description = replace(project, config.getString("dashboard", null, "description")); + info.foreach = config.getString("dashboard", null, "foreach"); + + if (setDefault) { + String id = refName + ":" + path; + info.isDefault = id.equals(defaultOf(definingProject)) ? true : null; + } + + UrlEncoded u = new UrlEncoded("/dashboard/"); + u.put("title", MoreObjects.firstNonNull(info.title, info.path)); + if (info.foreach != null) { + u.put("foreach", replace(project, info.foreach)); + } + for (String name : config.getSubsections("section")) { + DashboardSectionInfo s = new DashboardSectionInfo(); + s.name = name; + s.query = config.getString("section", name, "query"); + u.put(s.name, replace(project, s.query)); + info.sections.add(s); + } + info.url = u.toString().replace("%3A", ":"); + + return info; + } + + private static String replace(String project, String input) { + return input == null ? input : input.replace("${project}", project); + } + + private static String defaultOf(Project proj) { + final String defaultId = + MoreObjects.firstNonNull( + proj.getLocalDefaultDashboard(), Strings.nullToEmpty(proj.getDefaultDashboard())); + if (defaultId.startsWith(REFS_DASHBOARDS)) { + return defaultId.substring(REFS_DASHBOARDS.length()); + } + return defaultId; + } +} |