// 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.account;

import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AcceptsCreate;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
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.Account;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;

public class AccountsCollection implements
    RestCollection<TopLevelResource, AccountResource>,
    AcceptsCreate<TopLevelResource>{
  private final Provider<CurrentUser> self;
  private final AccountResolver resolver;
  private final AccountControl.Factory accountControlFactory;
  private final IdentifiedUser.GenericFactory userFactory;
  private final DynamicMap<RestView<AccountResource>> views;
  private final CreateAccount.Factory createAccountFactory;

  @Inject
  AccountsCollection(Provider<CurrentUser> self,
      AccountResolver resolver,
      AccountControl.Factory accountControlFactory,
      IdentifiedUser.GenericFactory userFactory,
      DynamicMap<RestView<AccountResource>> views,
      CreateAccount.Factory createAccountFactory) {
    this.self = self;
    this.resolver = resolver;
    this.accountControlFactory = accountControlFactory;
    this.userFactory = userFactory;
    this.views = views;
    this.createAccountFactory = createAccountFactory;
  }

  @Override
  public AccountResource parse(TopLevelResource root, IdString id)
      throws ResourceNotFoundException, AuthException, OrmException {
    IdentifiedUser user = parseId(id.get());
    if (user == null) {
      throw new ResourceNotFoundException(id);
    } else if (!accountControlFactory.get().canSee(user.getAccount())) {
      throw new ResourceNotFoundException(id);
    }
    return new AccountResource(user);
  }

  /**
   * Parses a account ID from a request body and returns the user.
   *
   * @param id ID of the account, can be a string of the format
   *        "Full Name <email@example.com>", just the email address, a full name
   *        if it is unique, an account ID, a user name or 'self' for the
   *        calling user
   * @return the user, never null.
   * @throws UnprocessableEntityException thrown if the account ID cannot be
   *         resolved or if the account is not visible to the calling user
   */
  public IdentifiedUser parse(String id) throws AuthException,
      UnprocessableEntityException, OrmException {
    IdentifiedUser user = parseId(id);
    if (user == null) {
      throw new UnprocessableEntityException(String.format(
          "Account Not Found: %s", id));
    }
    return user;
  }

  /**
   * Parses an account ID and returns the user without making any permission
   * check whether the current user can see the account.
   *
   * @param id ID of the account, can be a string of the format
   *        "Full Name <email@example.com>", just the email address, a full name
   *        if it is unique, an account ID, a user name or 'self' for the
   *        calling user
   * @return the user, null if no user is found for the given account ID
   * @throws AuthException thrown if 'self' is used as account ID and the
   *         current user is not authenticated
   * @throws OrmException
   */
  public IdentifiedUser parseId(String id) throws AuthException, OrmException {
    if (id.equals("self")) {
      CurrentUser user = self.get();
      if (user.isIdentifiedUser()) {
        return (IdentifiedUser) user;
      } else if (user instanceof AnonymousUser) {
        throw new AuthException("Authentication required");
      } else {
        return null;
      }
    }

    Account match = resolver.find(id);
    if (match == null) {
      return null;
    }
    return userFactory.create(match.getId());
  }

  @Override
  public RestView<TopLevelResource> list() throws ResourceNotFoundException {
    throw new ResourceNotFoundException();
  }

  @Override
  public DynamicMap<RestView<AccountResource>> views() {
    return views;
  }

  @SuppressWarnings("unchecked")
  @Override
  public CreateAccount create(TopLevelResource parent, IdString username) {
    return createAccountFactory.create(username.get());
  }
}

@@ -3713,24 +3713,198 @@
  %25s%22, id));%0A
+    %7D else if (!accountControlFactory.get().canSee(user.getAccount())) %7B%0A      throw new UnprocessableEntityException(String.format(%0A          %22Account Not Found: %25s%22, id));%0A
     %7D%0A    re

Check that account is visible when parsing account ID from request body