All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.server.account.AccountConfig Maven / Gradle / Ivy

There is a newer version: 3.10.0-rc4
Show newest version
// Copyright (C) 2017 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.account;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.client.EditPreferencesInfo;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.account.ProjectWatches.NotifyType;
import com.google.gerrit.server.account.ProjectWatches.ProjectWatchKey;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.ValidationError;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.git.meta.VersionedMetaData;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gwtorm.server.OrmDuplicateKeyException;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;

/**
 * Reads/writes account data from/to a user branch in the {@code All-Users} repository.
 *
 * 

This is the low-level API for account creation and account updates. Most callers should use * {@link AccountsUpdate} for creating and updating accounts. * *

This class can read/write account properties, preferences (general, diff and edit preferences) * and project watches. * *

The following files are read/written: * *

    *
  • 'account.config': Contains the account properties. Parsing and writing it is delegated to * {@link AccountProperties}. *
  • 'preferences.config': Contains the preferences. Parsing and writing it is delegated to * {@link Preferences}. *
  • 'account.config': Contains the project watches. Parsing and writing it is delegated to * {@link ProjectWatches}. *
* *

The commit date of the first commit on the user branch is used as registration date of the * account. The first commit may be an empty commit (since all config files are optional). */ public class AccountConfig extends VersionedMetaData implements ValidationError.Sink { private final Account.Id accountId; private final AllUsersName allUsersName; private final Repository repo; private final String ref; private Optional loadedAccountProperties; private Optional externalIdsRev; private ProjectWatches projectWatches; private Preferences preferences; private Optional accountUpdate = Optional.empty(); private List validationErrors; public AccountConfig(Account.Id accountId, AllUsersName allUsersName, Repository allUsersRepo) { this.accountId = requireNonNull(accountId, "accountId"); this.allUsersName = requireNonNull(allUsersName, "allUsersName"); this.repo = requireNonNull(allUsersRepo, "allUsersRepo"); this.ref = RefNames.refsUsers(accountId); } @Override protected String getRefName() { return ref; } public AccountConfig load() throws IOException, ConfigInvalidException { load(allUsersName, repo); return this; } /** * Get the loaded account. * * @return the loaded account, {@link Optional#empty()} if load didn't find the account because it * doesn't exist * @throws IllegalStateException if the account was not loaded yet */ public Optional getLoadedAccount() { checkLoaded(); return loadedAccountProperties.map(AccountProperties::getAccount); } /** * Returns the revision of the {@code refs/meta/external-ids} branch. * *

This revision can be used to load the external IDs of the loaded account lazily via {@link * ExternalIds#byAccount(com.google.gerrit.reviewdb.client.Account.Id, ObjectId)}. * * @return revision of the {@code refs/meta/external-ids} branch, {@link Optional#empty()} if no * {@code refs/meta/external-ids} branch exists */ public Optional getExternalIdsRev() { checkLoaded(); return externalIdsRev; } /** * Get the project watches of the loaded account. * * @return the project watches of the loaded account */ public ImmutableMap> getProjectWatches() { checkLoaded(); return projectWatches.getProjectWatches(); } /** * Get the general preferences of the loaded account. * * @return the general preferences of the loaded account */ public GeneralPreferencesInfo getGeneralPreferences() { checkLoaded(); return preferences.getGeneralPreferences(); } /** * Get the diff preferences of the loaded account. * * @return the diff preferences of the loaded account */ public DiffPreferencesInfo getDiffPreferences() { checkLoaded(); return preferences.getDiffPreferences(); } /** * Get the edit preferences of the loaded account. * * @return the edit preferences of the loaded account */ public EditPreferencesInfo getEditPreferences() { checkLoaded(); return preferences.getEditPreferences(); } /** * Sets the account. This means the loaded account will be overwritten with the given account. * *

Changing the registration date of an account is not supported. * * @param account account that should be set * @throws IllegalStateException if the account was not loaded yet */ public AccountConfig setAccount(Account account) { checkLoaded(); this.loadedAccountProperties = Optional.of( new AccountProperties(account.getId(), account.getRegisteredOn(), new Config(), null)); this.accountUpdate = Optional.of( InternalAccountUpdate.builder() .setActive(account.isActive()) .setFullName(account.getFullName()) .setPreferredEmail(account.getPreferredEmail()) .setStatus(account.getStatus()) .build()); return this; } /** * Creates a new account. * * @return the new account * @throws OrmDuplicateKeyException if the user branch already exists */ public Account getNewAccount() throws OrmDuplicateKeyException { return getNewAccount(TimeUtil.nowTs()); } /** * Creates a new account. * * @return the new account * @throws OrmDuplicateKeyException if the user branch already exists */ Account getNewAccount(Timestamp registeredOn) throws OrmDuplicateKeyException { checkLoaded(); if (revision != null) { throw new OrmDuplicateKeyException(String.format("account %s already exists", accountId)); } this.loadedAccountProperties = Optional.of(new AccountProperties(accountId, registeredOn, new Config(), null)); return loadedAccountProperties.map(AccountProperties::getAccount).get(); } public AccountConfig setAccountUpdate(InternalAccountUpdate accountUpdate) { this.accountUpdate = Optional.of(accountUpdate); return this; } @Override protected void onLoad() throws IOException, ConfigInvalidException { if (revision != null) { rw.reset(); rw.markStart(revision); rw.sort(RevSort.REVERSE); Timestamp registeredOn = new Timestamp(rw.next().getCommitTime() * 1000L); Config accountConfig = readConfig(AccountProperties.ACCOUNT_CONFIG); loadedAccountProperties = Optional.of(new AccountProperties(accountId, registeredOn, accountConfig, revision)); projectWatches = new ProjectWatches(accountId, readConfig(ProjectWatches.WATCH_CONFIG), this); preferences = new Preferences( accountId, readConfig(Preferences.PREFERENCES_CONFIG), Preferences.readDefaultConfig(allUsersName, repo), this); projectWatches.parse(); preferences.parse(); } else { loadedAccountProperties = Optional.empty(); projectWatches = new ProjectWatches(accountId, new Config(), this); preferences = new Preferences( accountId, new Config(), Preferences.readDefaultConfig(allUsersName, repo), this); } Ref externalIdsRef = repo.exactRef(RefNames.REFS_EXTERNAL_IDS); externalIdsRev = Optional.ofNullable(externalIdsRef).map(Ref::getObjectId); } @Override public RevCommit commit(MetaDataUpdate update) throws IOException { RevCommit c = super.commit(update); loadedAccountProperties.get().setMetaId(c); return c; } @Override protected boolean onSave(CommitBuilder commit) throws IOException, ConfigInvalidException { checkLoaded(); if (!loadedAccountProperties.isPresent()) { return false; } if (revision != null) { if (Strings.isNullOrEmpty(commit.getMessage())) { commit.setMessage("Update account\n"); } } else { if (Strings.isNullOrEmpty(commit.getMessage())) { commit.setMessage("Create account\n"); } Timestamp registeredOn = loadedAccountProperties.get().getRegisteredOn(); commit.setAuthor(new PersonIdent(commit.getAuthor(), registeredOn)); commit.setCommitter(new PersonIdent(commit.getCommitter(), registeredOn)); } saveAccount(); saveProjectWatches(); savePreferences(); accountUpdate = Optional.empty(); return true; } private void saveAccount() throws IOException { if (accountUpdate.isPresent()) { saveConfig( AccountProperties.ACCOUNT_CONFIG, loadedAccountProperties.get().save(accountUpdate.get())); } } private void saveProjectWatches() throws IOException { if (accountUpdate.isPresent() && (!accountUpdate.get().getDeletedProjectWatches().isEmpty() || !accountUpdate.get().getUpdatedProjectWatches().isEmpty())) { Map> newProjectWatches = new HashMap<>(projectWatches.getProjectWatches()); accountUpdate.get().getDeletedProjectWatches().forEach(newProjectWatches::remove); accountUpdate.get().getUpdatedProjectWatches().forEach(newProjectWatches::put); saveConfig(ProjectWatches.WATCH_CONFIG, projectWatches.save(newProjectWatches)); } } private void savePreferences() throws IOException, ConfigInvalidException { if (!accountUpdate.isPresent() || (!accountUpdate.get().getGeneralPreferences().isPresent() && !accountUpdate.get().getDiffPreferences().isPresent() && !accountUpdate.get().getEditPreferences().isPresent())) { return; } saveConfig( Preferences.PREFERENCES_CONFIG, preferences.saveGeneralPreferences( accountUpdate.get().getGeneralPreferences(), accountUpdate.get().getDiffPreferences(), accountUpdate.get().getEditPreferences())); } private void checkLoaded() { checkState(loadedAccountProperties != null, "Account %s not loaded yet", accountId.get()); } /** * Get the validation errors, if any were discovered during parsing the account data. * * @return list of errors; empty list if there are no errors. */ public List getValidationErrors() { if (validationErrors != null) { return ImmutableList.copyOf(validationErrors); } return ImmutableList.of(); } @Override public void error(ValidationError error) { if (validationErrors == null) { validationErrors = new ArrayList<>(4); } validationErrors.add(error); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy