Do not check visibility of parent when creating project

A project can be visible to a user but not necessarily its parent. To
be consistent, a user with create-project permission should be able to
create a project with a parent that exists even if the parent is not
visible to the user.

Here is an example when this case is happening. On a Gerrit server where
All-projects is only visible to administrators and create-project
permission is granted to non-administrators, when a non-administrator
tries to create a project with All-Projects (which is the default when
parent is not specified) as its parent, it was failing before this
change with "Not found: All-Projects".

Change-Id: Id93370ab108f377f643b55efdf781dfd2c66f220
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
index 37d350a..1d659cc 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
@@ -274,6 +274,26 @@
     assertCreateFails(in, ResourceConflictException.class);
   }
 
+  @Test
+  public void testCreateProjectWithCreateProjectCapabilityAndParentNotVisible()
+      throws Exception {
+    Project parent = projectCache.get(allProjects).getProject();
+    parent.setState(com.google.gerrit.extensions.client.ProjectState.HIDDEN);
+    allowGlobalCapabilities(SystemGroupBackend.REGISTERED_USERS,
+        GlobalCapability.CREATE_PROJECT);
+    try {
+      setApiUser(user);
+      ProjectInput in = new ProjectInput();
+      in.name = name("newProject");
+      ProjectInfo p = gApi.projects().create(in).get();
+      assertThat(p.name).isEqualTo(in.name);
+    } finally {
+      parent.setState(com.google.gerrit.extensions.client.ProjectState.ACTIVE);
+      removeGlobalCapabilities(SystemGroupBackend.REGISTERED_USERS,
+          GlobalCapability.CREATE_PROJECT);
+    }
+  }
+
   private AccountGroup.UUID groupUuid(String groupName) {
     return groupCache.get(new AccountGroup.NameKey(groupName)).getGroupUUID();
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
index 41bc288..c04878f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
@@ -161,7 +161,8 @@
 
     String parentName = MoreObjects.firstNonNull(
         Strings.emptyToNull(input.parent), allProjects.get());
-    args.newParent = projectsCollection.get().parse(parentName).getControl();
+    args.newParent =
+        projectsCollection.get().parse(parentName, false).getControl();
     args.createEmptyCommit = input.createEmptyCommit;
     args.permissionsOnly = input.permissionsOnly;
     args.projectDescription = Strings.emptyToNull(input.description);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java
index 0ffbe3e..51603fc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java
@@ -63,7 +63,7 @@
   @Override
   public ProjectResource parse(TopLevelResource parent, IdString id)
       throws ResourceNotFoundException, IOException {
-    ProjectResource rsrc = _parse(id.get());
+    ProjectResource rsrc = _parse(id.get(), true);
     if (rsrc == null) {
       throw new ResourceNotFoundException(id);
     }
@@ -81,7 +81,24 @@
    */
   public ProjectResource parse(String id)
       throws UnprocessableEntityException, IOException {
-    ProjectResource rsrc = _parse(id);
+    return parse(id, true);
+  }
+
+  /**
+   * Parses a project ID from a request body and returns the project.
+   *
+   * @param id ID of the project, can be a project name
+   * @param checkVisibility Whether to check or not that project is visible to
+   *        the calling user
+   * @return the project
+   * @throws UnprocessableEntityException thrown if the project ID cannot be
+   *         resolved or if the project is not visible to the calling user and
+   *         checkVisibility is true.
+   * @throws IOException thrown when there is an error.
+   */
+  public ProjectResource parse(String id, boolean checkVisibility)
+      throws UnprocessableEntityException, IOException {
+    ProjectResource rsrc = _parse(id, checkVisibility);
     if (rsrc == null) {
       throw new UnprocessableEntityException(String.format(
           "Project Not Found: %s", id));
@@ -89,7 +106,8 @@
     return rsrc;
   }
 
-  private ProjectResource _parse(String id) throws IOException {
+  private ProjectResource _parse(String id, boolean checkVisibility)
+      throws IOException {
     if (id.endsWith(Constants.DOT_GIT_EXT)) {
       id = id.substring(0, id.length() - Constants.DOT_GIT_EXT.length());
     }
@@ -101,7 +119,7 @@
     } catch (NoSuchProjectException e) {
       return null;
     }
-    if (!ctl.isVisible() && !ctl.isOwner()) {
+    if (checkVisibility && !ctl.isVisible() && !ctl.isOwner()) {
       return null;
     }
     return new ProjectResource(ctl);