Line data Source code
1 : // Copyright (C) 2017 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.account; 16 : 17 : import com.google.gerrit.entities.Account; 18 : import com.google.gerrit.extensions.events.AccountActivationListener; 19 : import com.google.gerrit.extensions.restapi.ResourceConflictException; 20 : import com.google.gerrit.extensions.restapi.ResourceNotFoundException; 21 : import com.google.gerrit.extensions.restapi.Response; 22 : import com.google.gerrit.extensions.restapi.RestApiException; 23 : import com.google.gerrit.server.ServerInitiated; 24 : import com.google.gerrit.server.plugincontext.PluginSetContext; 25 : import com.google.gerrit.server.validators.AccountActivationValidationListener; 26 : import com.google.gerrit.server.validators.ValidationException; 27 : import com.google.inject.Inject; 28 : import com.google.inject.Provider; 29 : import com.google.inject.Singleton; 30 : import java.io.IOException; 31 : import java.util.Optional; 32 : import java.util.concurrent.atomic.AtomicBoolean; 33 : import java.util.concurrent.atomic.AtomicReference; 34 : import org.eclipse.jgit.errors.ConfigInvalidException; 35 : 36 : /** Toggler for account active state. */ 37 : @Singleton 38 : public class SetInactiveFlag { 39 : private final PluginSetContext<AccountActivationValidationListener> 40 : accountActivationValidationListeners; 41 : private final Provider<AccountsUpdate> accountsUpdateProvider; 42 : private final PluginSetContext<AccountActivationListener> accountActivationListeners; 43 : 44 : @Inject 45 : SetInactiveFlag( 46 : PluginSetContext<AccountActivationValidationListener> accountActivationValidationListeners, 47 : @ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider, 48 151 : PluginSetContext<AccountActivationListener> accountActivationListeners) { 49 151 : this.accountActivationValidationListeners = accountActivationValidationListeners; 50 151 : this.accountsUpdateProvider = accountsUpdateProvider; 51 151 : this.accountActivationListeners = accountActivationListeners; 52 151 : } 53 : 54 : public Response<?> deactivate(Account.Id accountId) 55 : throws RestApiException, IOException, ConfigInvalidException { 56 7 : AtomicBoolean alreadyInactive = new AtomicBoolean(false); 57 7 : AtomicReference<Optional<RestApiException>> exception = new AtomicReference<>(Optional.empty()); 58 7 : Optional<AccountState> updatedAccount = 59 : accountsUpdateProvider 60 7 : .get() 61 7 : .update( 62 : "Deactivate Account via API", 63 : accountId, 64 : (a, u) -> { 65 7 : if (!a.account().isActive()) { 66 1 : alreadyInactive.set(true); 67 : } else { 68 : try { 69 7 : accountActivationValidationListeners.runEach( 70 1 : l -> l.validateDeactivation(a), ValidationException.class); 71 1 : } catch (ValidationException e) { 72 1 : exception.set(Optional.of(new ResourceConflictException(e.getMessage(), e))); 73 1 : return; 74 7 : } 75 7 : u.setActive(false); 76 : } 77 7 : }); 78 7 : if (!updatedAccount.isPresent()) { 79 0 : throw new ResourceNotFoundException("account not found"); 80 : } 81 : 82 7 : if (exception.get().isPresent()) { 83 1 : throw exception.get().get(); 84 : } 85 7 : if (alreadyInactive.get()) { 86 1 : throw new ResourceConflictException("account not active"); 87 : } 88 : 89 : // At this point the account got set inactive and no errors occurred 90 : 91 7 : int id = accountId.get(); 92 7 : accountActivationListeners.runEach(l -> l.onAccountDeactivated(id)); 93 : 94 7 : return Response.none(); 95 : } 96 : 97 : public Response<String> activate(Account.Id accountId) 98 : throws RestApiException, IOException, ConfigInvalidException { 99 2 : AtomicBoolean alreadyActive = new AtomicBoolean(false); 100 2 : AtomicReference<Optional<RestApiException>> exception = new AtomicReference<>(Optional.empty()); 101 2 : Optional<AccountState> updatedAccount = 102 : accountsUpdateProvider 103 2 : .get() 104 2 : .update( 105 : "Activate Account via API", 106 : accountId, 107 : (a, u) -> { 108 2 : if (a.account().isActive()) { 109 2 : alreadyActive.set(true); 110 : } else { 111 : try { 112 1 : accountActivationValidationListeners.runEach( 113 1 : l -> l.validateActivation(a), ValidationException.class); 114 1 : } catch (ValidationException e) { 115 1 : exception.set(Optional.of(new ResourceConflictException(e.getMessage(), e))); 116 1 : return; 117 1 : } 118 1 : u.setActive(true); 119 : } 120 2 : }); 121 2 : if (!updatedAccount.isPresent()) { 122 0 : throw new ResourceNotFoundException("account not found"); 123 : } 124 : 125 2 : if (exception.get().isPresent()) { 126 1 : throw exception.get().get(); 127 : } 128 : 129 : Response<String> res; 130 2 : if (alreadyActive.get()) { 131 2 : res = Response.ok(); 132 : } else { 133 1 : res = Response.created(); 134 : 135 1 : int id = accountId.get(); 136 1 : accountActivationListeners.runEach(l -> l.onAccountActivated(id)); 137 : } 138 2 : return res; 139 : } 140 : }