diff options
Diffstat (limited to 'java/com/google/gerrit/server/restapi/project/ProjectsCollection.java')
-rw-r--r-- | java/com/google/gerrit/server/restapi/project/ProjectsCollection.java | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java new file mode 100644 index 0000000000..ed317aadc9 --- /dev/null +++ b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java @@ -0,0 +1,175 @@ +// 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 com.google.common.collect.ListMultimap; +import com.google.common.flogger.FluentLogger; +import com.google.gerrit.common.Nullable; +import com.google.gerrit.common.ProjectUtil; +import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.IdString; +import com.google.gerrit.extensions.restapi.NeedsParams; +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.RestCollection; +import com.google.gerrit.extensions.restapi.RestView; +import com.google.gerrit.extensions.restapi.TopLevelResource; +import com.google.gerrit.extensions.restapi.UnprocessableEntityException; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.OutputFormat; +import com.google.gerrit.server.permissions.PermissionBackend; +import com.google.gerrit.server.permissions.PermissionBackendException; +import com.google.gerrit.server.permissions.ProjectPermission; +import com.google.gerrit.server.project.ProjectCache; +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; + +@Singleton +public class ProjectsCollection + implements RestCollection<TopLevelResource, ProjectResource>, NeedsParams { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + private final DynamicMap<RestView<ProjectResource>> views; + private final Provider<ListProjects> list; + private final Provider<QueryProjects> queryProjects; + private final ProjectCache projectCache; + private final PermissionBackend permissionBackend; + private final Provider<CurrentUser> user; + + private boolean hasQuery; + + @Inject + public ProjectsCollection( + DynamicMap<RestView<ProjectResource>> views, + Provider<ListProjects> list, + Provider<QueryProjects> queryProjects, + ProjectCache projectCache, + PermissionBackend permissionBackend, + Provider<CurrentUser> user) { + this.views = views; + this.list = list; + this.queryProjects = queryProjects; + this.projectCache = projectCache; + this.permissionBackend = permissionBackend; + this.user = user; + } + + @Override + public void setParams(ListMultimap<String, String> params) throws BadRequestException { + // The --query option is defined in QueryProjects + this.hasQuery = params.containsKey("query"); + } + + @Override + public RestView<TopLevelResource> list() { + if (hasQuery) { + return queryProjects.get(); + } + return list.get().setFormat(OutputFormat.JSON); + } + + @Override + public ProjectResource parse(TopLevelResource parent, IdString id) + throws RestApiException, IOException, PermissionBackendException { + ProjectResource rsrc = _parse(id.get(), true); + if (rsrc == null) { + throw new ResourceNotFoundException(id); + } + return rsrc; + } + + /** + * Parses a project ID from a request body and returns the project. + * + * @param id ID of the project, can be a project name + * @return the project + * @throws RestApiException thrown if the project ID cannot be resolved or if the project is not + * visible to the calling user + * @throws IOException thrown when there is an error. + * @throws PermissionBackendException + */ + public ProjectResource parse(String id) + throws RestApiException, IOException, PermissionBackendException { + return parse(id, true); + } + + /** + * Parses a project ID from a request body and returns the project. + * + * @param id ID of the project, can be a project name + * @param checkAccess if true, check the project is accessible by the current user + * @return the project + * @throws RestApiException thrown if the project ID cannot be resolved or if the project is not + * visible to the calling user and checkVisibility is true. + * @throws IOException thrown when there is an error. + * @throws PermissionBackendException + */ + public ProjectResource parse(String id, boolean checkAccess) + throws RestApiException, IOException, PermissionBackendException { + ProjectResource rsrc = _parse(id, checkAccess); + if (rsrc == null) { + throw new UnprocessableEntityException(String.format("Project Not Found: %s", id)); + } + return rsrc; + } + + @Nullable + private ProjectResource _parse(String id, boolean checkAccess) + throws IOException, PermissionBackendException, ResourceConflictException { + id = ProjectUtil.sanitizeProjectName(id); + + Project.NameKey nameKey = new Project.NameKey(id); + ProjectState state = projectCache.checkedGet(nameKey); + if (state == null) { + return null; + } + + logger.atFine().log("Project %s has state %s", nameKey, state.getProject().getState()); + + if (checkAccess) { + // Hidden projects(permitsRead = false) should only be accessible by the project owners. + // WRITE_CONFIG is checked here because it's only allowed to project owners (ACCESS may also + // be allowed for other users). Allowing project owners to access here will help them to view + // and update the config of hidden projects easily. + if (state.statePermitsRead()) { + try { + permissionBackend.currentUser().project(nameKey).check(ProjectPermission.ACCESS); + } catch (AuthException e) { + return null; + } + } else { + try { + permissionBackend.currentUser().project(nameKey).check(ProjectPermission.WRITE_CONFIG); + } catch (AuthException e) { + state.checkStatePermitsRead(); + } + } + } + return new ProjectResource(state, user.get()); + } + + @Override + public DynamicMap<RestView<ProjectResource>> views() { + return views; + } +} |