Line data Source code
1 : // Copyright (C) 2013 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.group; 16 : 17 : import com.google.common.base.Strings; 18 : import com.google.common.collect.ImmutableList; 19 : import com.google.common.collect.Lists; 20 : import com.google.common.collect.Sets; 21 : import com.google.gerrit.entities.AccountGroup; 22 : import com.google.gerrit.entities.GroupDescription; 23 : import com.google.gerrit.exceptions.NoSuchGroupException; 24 : import com.google.gerrit.extensions.common.GroupInfo; 25 : import com.google.gerrit.extensions.restapi.AuthException; 26 : import com.google.gerrit.extensions.restapi.DefaultInput; 27 : import com.google.gerrit.extensions.restapi.IdString; 28 : import com.google.gerrit.extensions.restapi.ResourceNotFoundException; 29 : import com.google.gerrit.extensions.restapi.Response; 30 : import com.google.gerrit.extensions.restapi.RestCollectionCreateView; 31 : import com.google.gerrit.extensions.restapi.RestModifyView; 32 : import com.google.gerrit.extensions.restapi.UnprocessableEntityException; 33 : import com.google.gerrit.server.UserInitiated; 34 : import com.google.gerrit.server.account.GroupControl; 35 : import com.google.gerrit.server.group.GroupResolver; 36 : import com.google.gerrit.server.group.GroupResource; 37 : import com.google.gerrit.server.group.SubgroupResource; 38 : import com.google.gerrit.server.group.db.GroupDelta; 39 : import com.google.gerrit.server.group.db.GroupsUpdate; 40 : import com.google.gerrit.server.permissions.PermissionBackendException; 41 : import com.google.gerrit.server.restapi.group.AddSubgroups.Input; 42 : import com.google.inject.Inject; 43 : import com.google.inject.Provider; 44 : import com.google.inject.Singleton; 45 : import java.io.IOException; 46 : import java.util.ArrayList; 47 : import java.util.LinkedHashSet; 48 : import java.util.List; 49 : import java.util.Set; 50 : import org.eclipse.jgit.errors.ConfigInvalidException; 51 : 52 : @Singleton 53 : public class AddSubgroups implements RestModifyView<GroupResource, Input> { 54 4 : public static class Input { 55 : @DefaultInput String _oneGroup; 56 : 57 : public List<String> groups; 58 : 59 : public static Input fromGroups(List<String> groups) { 60 4 : Input in = new Input(); 61 4 : in.groups = groups; 62 4 : return in; 63 : } 64 : 65 : static Input init(Input in) { 66 4 : if (in == null) { 67 0 : in = new Input(); 68 : } 69 4 : if (in.groups == null) { 70 1 : in.groups = Lists.newArrayListWithCapacity(1); 71 : } 72 4 : if (!Strings.isNullOrEmpty(in._oneGroup)) { 73 0 : in.groups.add(in._oneGroup); 74 : } 75 4 : return in; 76 : } 77 : } 78 : 79 : private final GroupResolver groupResolver; 80 : private final Provider<GroupsUpdate> groupsUpdateProvider; 81 : private final GroupJson json; 82 : 83 : @Inject 84 : public AddSubgroups( 85 : GroupResolver groupResolver, 86 : @UserInitiated Provider<GroupsUpdate> groupsUpdateProvider, 87 146 : GroupJson json) { 88 146 : this.groupResolver = groupResolver; 89 146 : this.groupsUpdateProvider = groupsUpdateProvider; 90 146 : this.json = json; 91 146 : } 92 : 93 : @Override 94 : public Response<List<GroupInfo>> apply(GroupResource resource, Input input) 95 : throws NotInternalGroupException, AuthException, UnprocessableEntityException, 96 : ResourceNotFoundException, IOException, ConfigInvalidException, 97 : PermissionBackendException { 98 4 : GroupDescription.Internal group = 99 4 : resource.asInternalGroup().orElseThrow(NotInternalGroupException::new); 100 4 : input = Input.init(input); 101 : 102 4 : GroupControl control = resource.getControl(); 103 4 : if (!control.canAddGroup()) { 104 0 : throw new AuthException(String.format("Cannot add groups to group %s", group.getName())); 105 : } 106 : 107 4 : List<GroupInfo> result = new ArrayList<>(); 108 4 : Set<AccountGroup.UUID> subgroupUuids = new LinkedHashSet<>(); 109 4 : for (String subgroupIdentifier : input.groups) { 110 4 : GroupDescription.Basic subgroup = groupResolver.parse(subgroupIdentifier); 111 4 : subgroupUuids.add(subgroup.getGroupUUID()); 112 4 : result.add(json.format(subgroup)); 113 4 : } 114 : 115 4 : AccountGroup.UUID groupUuid = group.getGroupUUID(); 116 : try { 117 4 : addSubgroups(groupUuid, subgroupUuids); 118 0 : } catch (NoSuchGroupException e) { 119 0 : throw new ResourceNotFoundException(String.format("Group %s not found", groupUuid), e); 120 4 : } 121 4 : return Response.ok(result); 122 : } 123 : 124 : private void addSubgroups( 125 : AccountGroup.UUID parentGroupUuid, Set<AccountGroup.UUID> newSubgroupUuids) 126 : throws NoSuchGroupException, IOException, ConfigInvalidException { 127 : GroupDelta groupDelta = 128 4 : GroupDelta.builder() 129 4 : .setSubgroupModification(subgroupUuids -> Sets.union(subgroupUuids, newSubgroupUuids)) 130 4 : .build(); 131 4 : groupsUpdateProvider.get().updateGroup(parentGroupUuid, groupDelta); 132 4 : } 133 : 134 : @Singleton 135 : public static class CreateSubgroup 136 : implements RestCollectionCreateView<GroupResource, SubgroupResource, Input> { 137 : private final AddSubgroups addSubgroups; 138 : 139 : @Inject 140 138 : public CreateSubgroup(AddSubgroups addSubgroups) { 141 138 : this.addSubgroups = addSubgroups; 142 138 : } 143 : 144 : @Override 145 : public Response<GroupInfo> apply(GroupResource resource, IdString id, Input input) 146 : throws Exception { 147 0 : AddSubgroups.Input in = new AddSubgroups.Input(); 148 0 : in.groups = ImmutableList.of(id.get()); 149 : try { 150 0 : List<GroupInfo> list = addSubgroups.apply(resource, in).value(); 151 0 : if (list.size() == 1) { 152 0 : return Response.created(list.get(0)); 153 : } 154 0 : throw new IllegalStateException(); 155 0 : } catch (UnprocessableEntityException e) { 156 0 : throw new ResourceNotFoundException(id, e); 157 : } 158 : } 159 : } 160 : 161 : @Singleton 162 : public static class UpdateSubgroup implements RestModifyView<SubgroupResource, Input> { 163 : private final Provider<GetSubgroup> get; 164 : 165 : @Inject 166 138 : public UpdateSubgroup(Provider<GetSubgroup> get) { 167 138 : this.get = get; 168 138 : } 169 : 170 : @Override 171 : public Response<GroupInfo> apply(SubgroupResource resource, Input input) 172 : throws PermissionBackendException { 173 : // Do nothing, the group is already included. 174 1 : return get.get().apply(resource); 175 : } 176 : } 177 : }