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.change; 16 : 17 : import com.google.gerrit.entities.Change; 18 : import com.google.gerrit.entities.Project; 19 : import com.google.gerrit.extensions.registration.DynamicMap; 20 : import com.google.gerrit.extensions.restapi.IdString; 21 : import com.google.gerrit.extensions.restapi.ResourceConflictException; 22 : import com.google.gerrit.extensions.restapi.ResourceNotFoundException; 23 : import com.google.gerrit.extensions.restapi.RestApiException; 24 : import com.google.gerrit.extensions.restapi.RestCollection; 25 : import com.google.gerrit.extensions.restapi.RestView; 26 : import com.google.gerrit.extensions.restapi.TopLevelResource; 27 : import com.google.gerrit.server.CurrentUser; 28 : import com.google.gerrit.server.change.ChangeFinder; 29 : import com.google.gerrit.server.change.ChangeResource; 30 : import com.google.gerrit.server.notedb.ChangeNotes; 31 : import com.google.gerrit.server.permissions.ChangePermission; 32 : import com.google.gerrit.server.permissions.PermissionBackend; 33 : import com.google.gerrit.server.permissions.PermissionBackendException; 34 : import com.google.gerrit.server.project.ProjectCache; 35 : import com.google.gerrit.server.project.ProjectState; 36 : import com.google.inject.Inject; 37 : import com.google.inject.Provider; 38 : import com.google.inject.Singleton; 39 : import java.io.IOException; 40 : import java.util.List; 41 : import java.util.Optional; 42 : 43 : @Singleton 44 : public class ChangesCollection implements RestCollection<TopLevelResource, ChangeResource> { 45 : private final Provider<CurrentUser> user; 46 : private final Provider<QueryChanges> queryFactory; 47 : private final DynamicMap<RestView<ChangeResource>> views; 48 : private final ChangeFinder changeFinder; 49 : private final ChangeResource.Factory changeResourceFactory; 50 : private final PermissionBackend permissionBackend; 51 : private final ProjectCache projectCache; 52 : 53 : @Inject 54 : public ChangesCollection( 55 : Provider<CurrentUser> user, 56 : Provider<QueryChanges> queryFactory, 57 : DynamicMap<RestView<ChangeResource>> views, 58 : ChangeFinder changeFinder, 59 : ChangeResource.Factory changeResourceFactory, 60 : PermissionBackend permissionBackend, 61 149 : ProjectCache projectCache) { 62 149 : this.user = user; 63 149 : this.queryFactory = queryFactory; 64 149 : this.views = views; 65 149 : this.changeFinder = changeFinder; 66 149 : this.changeResourceFactory = changeResourceFactory; 67 149 : this.permissionBackend = permissionBackend; 68 149 : this.projectCache = projectCache; 69 149 : } 70 : 71 : @Override 72 : public QueryChanges list() { 73 3 : return queryFactory.get(); 74 : } 75 : 76 : @Override 77 : public DynamicMap<RestView<ChangeResource>> views() { 78 13 : return views; 79 : } 80 : 81 : @Override 82 : public ChangeResource parse(TopLevelResource root, IdString id) 83 : throws RestApiException, PermissionBackendException, IOException { 84 90 : List<ChangeNotes> notes = changeFinder.find(id.encoded(), 2); 85 90 : if (notes.isEmpty()) { 86 3 : throw new ResourceNotFoundException(id); 87 90 : } else if (notes.size() != 1) { 88 2 : throw new ResourceNotFoundException("Multiple changes found for " + id); 89 : } 90 : 91 90 : ChangeNotes change = notes.get(0); 92 90 : if (!canRead(change)) { 93 5 : throw new ResourceNotFoundException(id); 94 : } 95 90 : checkProjectStatePermitsRead(change.getProjectName()); 96 90 : return changeResourceFactory.create(change, user.get()); 97 : } 98 : 99 : public ChangeResource parse(Change.Id id) 100 : throws ResourceConflictException, ResourceNotFoundException, PermissionBackendException { 101 32 : List<ChangeNotes> notes = changeFinder.find(id); 102 32 : if (notes.isEmpty()) { 103 1 : throw new ResourceNotFoundException(toIdString(id)); 104 32 : } else if (notes.size() != 1) { 105 0 : throw new ResourceNotFoundException("Multiple changes found for " + id); 106 : } 107 : 108 32 : ChangeNotes change = notes.get(0); 109 32 : if (!canRead(change)) { 110 1 : throw new ResourceNotFoundException(toIdString(id)); 111 : } 112 32 : checkProjectStatePermitsRead(change.getProjectName()); 113 32 : return changeResourceFactory.create(change, user.get()); 114 : } 115 : 116 : private static IdString toIdString(Change.Id id) { 117 1 : return IdString.fromDecoded(id.toString()); 118 : } 119 : 120 : public ChangeResource parse(ChangeNotes notes, CurrentUser user) { 121 0 : return changeResourceFactory.create(notes, user); 122 : } 123 : 124 : private boolean canRead(ChangeNotes notes) throws PermissionBackendException { 125 91 : if (!permissionBackend.currentUser().change(notes).test(ChangePermission.READ)) { 126 5 : return false; 127 : } 128 91 : Optional<ProjectState> projectState = projectCache.get(notes.getProjectName()); 129 91 : if (!projectState.isPresent()) { 130 0 : return false; 131 : } 132 91 : return projectState.get().statePermitsRead(); 133 : } 134 : 135 : private void checkProjectStatePermitsRead(Project.NameKey project) 136 : throws ResourceNotFoundException, ResourceConflictException { 137 91 : projectCache 138 91 : .get(project) 139 91 : .orElseThrow(() -> new ResourceNotFoundException("project not found: " + project.get())) 140 91 : .checkStatePermitsRead(); 141 91 : } 142 : }