Support retrieving project access rights via REST

By GET on /access/?project=<project-name> it is now possible to
retrieve the access rights of a project via REST.

Having /access/ instead of /projects/<project-name>/access allows to
retrieve the access rights for multiple projects at once by specifying
the 'project' option multiple times.

In future this REST endpoint may be extended to only return the access
rights for a certain user or group by supporting a 'user' and 'group'
option.

Change-Id: Ibc57b2c006472a9f70699ae69e72f60317819bef
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin 2013-06-24 16:46:34 +02:00
parent 42248a08a6
commit 87340e6bb7
10 changed files with 837 additions and 0 deletions

View File

@ -0,0 +1,376 @@
Gerrit Code Review - /access/ REST API
======================================
This page describes the access rights related REST endpoints.
Please also take note of the general information on the
link:rest-api.html[REST API].
[[access-endpoints]]
Access Rights Endpoints
-----------------------
[[list-access]]
List Access Rights
~~~~~~~~~~~~~~~~~~
[verse]
'GET /access/?project=link:rest-api-projects.html#project-name[\{project-name\}]'
Lists the access rights for projects. The projects for which the access
rights should be returned must be specified as `project` options. The
`project` can be specified multiple times.
As result a map is returned that maps the project name to
link:#project-access-info[ProjectAccessInfo] entities.
The entries in the map are sorted by project name.
.Request
----
GET /access/?project=MyProject&project=All-Projects HTTP/1.0
----
.Response
----
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
)]}'
{
"All-Projects": {
"revision": "edd453d18e08640e67a8c9a150cec998ed0ac9aa",
"local": {
"GLOBAL_CAPABILITIES": {
"permissions": {
"priority": {
"rules": {
"15bfcd8a6de1a69c50b30cedcdcc951c15703152": {
"action": "BATCH"
}
}
},
"streamEvents": {
"rules": {
"15bfcd8a6de1a69c50b30cedcdcc951c15703152": {
"action": "ALLOW"
}
}
},
"administrateServer": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
}
}
}
}
},
"refs/meta/config": {
"permissions": {
"submit": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
},
"global:Project-Owners": {
"action": "ALLOW"
}
}
},
"label-Code-Review": {
"label": "Code-Review",
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW",
"min": -2,
"max": 2
},
"global:Project-Owners": {
"action": "ALLOW",
"min": -2,
"max": 2
}
}
},
"read": {
"exclusive": true,
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
},
"global:Project-Owners": {
"action": "ALLOW"
}
}
},
"push": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
},
"global:Project-Owners": {
"action": "ALLOW"
}
}
}
}
},
"refs/for/refs/*": {
"permissions": {
"pushMerge": {
"rules": {
"global:Registered-Users": {
"action": "ALLOW"
}
}
},
"push": {
"rules": {
"global:Registered-Users": {
"action": "ALLOW"
}
}
}
}
},
"refs/tags/*": {
"permissions": {
"pushSignedTag": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
},
"global:Project-Owners": {
"action": "ALLOW"
}
}
},
"pushTag": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
},
"global:Project-Owners": {
"action": "ALLOW"
}
}
}
}
},
"refs/heads/*": {
"permissions": {
"forgeCommitter": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
},
"global:Project-Owners": {
"action": "ALLOW"
}
}
},
"forgeAuthor": {
"rules": {
"global:Registered-Users": {
"action": "ALLOW"
}
}
},
"submit": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
},
"global:Project-Owners": {
"action": "ALLOW"
}
}
},
"editTopicName": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW",
"force": true
},
"global:Project-Owners": {
"action": "ALLOW",
"force": true
}
}
},
"label-Code-Review": {
"label": "Code-Review",
"rules": {
"global:Registered-Users": {
"action": "ALLOW",
"min": -1,
"max": 1
},
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW",
"min": -2,
"max": 2
},
"global:Project-Owners": {
"action": "ALLOW",
"min": -2,
"max": 2
}
}
},
"create": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
},
"global:Project-Owners": {
"action": "ALLOW"
}
}
},
"push": {
"rules": {
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
},
"global:Project-Owners": {
"action": "ALLOW"
}
}
}
}
},
"refs/*": {
"permissions": {
"read": {
"rules": {
"global:Anonymous-Users": {
"action": "ALLOW"
},
"53a4f647a89ea57992571187d8025f830625192a": {
"action": "ALLOW"
}
}
}
}
}
},
"owner_of": [
"GLOBAL_CAPABILITIES",
"refs/meta/config",
"refs/for/refs/*",
"refs/tags/*",
"refs/heads/*",
"refs/*"
],
"can_upload": true,
"can_add": true,
"config_visible": true
},
"MyProject": {
"revision": "61157ed63e14d261b6dca40650472a9b0bd88474",
"inherits_from": {
"kind": "gerritcodereview#project",
"id": "All-Projects",
"name": "All-Projects",
"description": "Access inherited by all other projects."
},
"local": {},
"owner_of": [
"refs/*"
],
"can_upload": true,
"can_add": true,
"config_visible": true
}
}
----
[[access-section-info]]
AccessSectionInfo
~~~~~~~~~~~~~~~~~
The `AccessSectionInfo` describes the access rights that are assigned
on a ref.
[options="header",width="50%",cols="1,^1,5"]
|==================================
|Field Name ||Description
|`permissions` ||
The permissions assigned on the ref of this access section as a map
that maps the permission names to link:#permission-info[PermissionInfo]
entities.
|==================================
[[permission-info]]
PermissionInfo
~~~~~~~~~~~~~~
The `PermissionInfo` entity contains information about an assigned
permission.
[options="header",width="50%",cols="1,^1,5"]
|==================================
|Field Name ||Description
|`label` |optional|
The name of the label. Not set if it's not a label permission.
|`exclusive` |not set if `false`|
Whether this permission is assigned exclusively.
|`rules` ||
The rules assigned for this permission as a map that maps the UUIDs of
the groups for which the permission are assigned to
link:#permission-info[PermissionRuleInfo] entities.
|==================================
[[permission-rule-info]]
PermissionRuleInfo
~~~~~~~~~~~~~~~~~~
The `PermissionRuleInfo` entity contains information about a permission
rule that is assigned to group.
[options="header",width="50%",cols="1,^1,5"]
|==================================
|Field Name ||Description
|`action` ||
The action of this rule. For normal permissions this can be `ALLOW`,
`DENY` or `BLOCK`. Special values for global capabilities are
`INTERACTIVE` and `BATCH`.
|`force` |not set if `false`|
Whether the force flag is set.
|`min` |
not set if range if empty (from `0` to `0`) or not set|
The min value of the permission range.
|`max` |
not set if range if empty (from `0` to `0`) or not set|
The max value of the permission range.
|==================================
[[project-access-info]]
ProjectAccessInfo
~~~~~~~~~~~~~~~~~
The `ProjectAccessInfo` entity contains information about the access
rights for a project.
[options="header",width="50%",cols="1,^1,5"]
|==================================
|Field Name ||Description
|`revision` ||
The revision of the `refs/meta/config` branch from which the access
rights were loaded.
|`inherits_from` |not set for the `All-Project` project|
The parent project from which permissions are inherited as a
link:rest-api-projects.html#project-info[ProjectInfo] entity.
|`local` ||
The local access rights of the project as a map that maps the refs to
link:#access-section-info[AccessSectionInfo] entities.
|`owner_of` ||The list of refs owned by the calling user.
|`can_upload` |not set if `false`|
Whether the calling user can upload to any ref.
|`can_add` |not set if `false`|
Whether the calling user can add any ref.
|`config_visible` |not set if `false`|
Whether the calling user can see the `refs/meta/config` branch of the
project.
|==================================
GERRIT
------
Part of link:index.html[Gerrit Code Review]

View File

@ -9,6 +9,8 @@ See also: link:dev-rest-api.html[REST API Developers' Notes].
Endpoints
---------
link:rest-api-access.html[/access/]::
Access Right related REST endpoints
link:rest-api-accounts.html[/accounts/]::
Account related REST endpoints
link:rest-api-changes.html[/changes/]::

View File

@ -24,6 +24,7 @@ import com.google.gerrit.httpd.raw.LegacyGerritServlet;
import com.google.gerrit.httpd.raw.SshInfoServlet;
import com.google.gerrit.httpd.raw.StaticServlet;
import com.google.gerrit.httpd.raw.ToolServlet;
import com.google.gerrit.httpd.rpc.access.AccessRestApiServlet;
import com.google.gerrit.httpd.rpc.account.AccountsRestApiServlet;
import com.google.gerrit.httpd.rpc.change.ChangesRestApiServlet;
import com.google.gerrit.httpd.rpc.change.DeprecatedChangeQueryServlet;
@ -101,6 +102,7 @@ class UrlModule extends ServletModule {
filter("/a/*").through(RequireIdentifiedUserFilter.class);
serveRegex("^/(?:a/)?tools/(.*)$").with(ToolServlet.class);
serveRegex("^/(?:a/)?access/(.*)$").with(AccessRestApiServlet.class);
serveRegex("^/(?:a/)?accounts/(.*)$").with(AccountsRestApiServlet.class);
serveRegex("^/(?:a/)?changes/(.*)$").with(ChangesRestApiServlet.class);
serveRegex("^/(?:a/)?config/(.*)$").with(ConfigRestApiServlet.class);

View File

@ -0,0 +1,32 @@
// Copyright (C) 2013 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.httpd.rpc.access;
import com.google.gerrit.httpd.restapi.RestApiServlet;
import com.google.gerrit.server.access.AccessCollection;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@Singleton
public class AccessRestApiServlet extends RestApiServlet {
private static final long serialVersionUID = 1L;
@Inject
AccessRestApiServlet(RestApiServlet.Globals globals,
Provider<AccessCollection> access) {
super(globals, access);
}
}

View File

@ -0,0 +1,53 @@
// Copyright (C) 2013 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.access;
import com.google.gerrit.extensions.registration.DynamicMap;
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.inject.Inject;
import com.google.inject.Provider;
public class AccessCollection implements
RestCollection<TopLevelResource, AccessResource> {
private final Provider<ListAccess> list;
private final DynamicMap<RestView<AccessResource>> views;
@Inject
AccessCollection(Provider<ListAccess> list,
DynamicMap<RestView<AccessResource>> views) {
this.list = list;
this.views = views;
}
@Override
public RestView<TopLevelResource> list() {
return list.get();
}
@Override
public AccessResource parse(TopLevelResource parent, IdString id)
throws ResourceNotFoundException {
throw new ResourceNotFoundException(id);
}
@Override
public DynamicMap<RestView<AccessResource>> views() {
return views;
}
}

View File

@ -0,0 +1,24 @@
// Copyright (C) 2013 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.access;
import com.google.gerrit.extensions.restapi.RestResource;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.inject.TypeLiteral;
public class AccessResource implements RestResource {
public static final TypeLiteral<RestView<AccessResource>> ACCESS_KIND =
new TypeLiteral<RestView<AccessResource>>() {};
}

View File

@ -0,0 +1,306 @@
// Copyright (C) 2013 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.access;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.data.RefConfigSection;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.group.GroupJson;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.ProjectJson;
import com.google.gerrit.server.project.ProjectJson.ProjectInfo;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.project.RefControl;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.kohsuke.args4j.Option;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ListAccess implements RestReadView<TopLevelResource> {
@Option(name = "--project", aliases = {"-p"}, metaVar = "PROJECT",
usage = "projects for which the access rights should be returned")
private List<String> projects = Lists.newArrayList();
private final Provider<CurrentUser> self;
private final ProjectControl.GenericFactory projectControlFactory;
private final ProjectCache projectCache;
private final ProjectJson projectJson;
private final MetaDataUpdate.Server metaDataUpdateFactory;
private final GroupControl.Factory groupControlFactory;
private final GroupBackend groupBackend;
private final AllProjectsName allProjectsName;
@Inject
public ListAccess(Provider<CurrentUser> self,
ProjectControl.GenericFactory projectControlFactory,
ProjectCache projectCache, ProjectJson projectJson,
MetaDataUpdate.Server metaDataUpdateFactory,
GroupControl.Factory groupControlFactory, GroupBackend groupBackend,
GroupJson groupJson, AllProjectsName allProjectsName) {
this.self = self;
this.projectControlFactory = projectControlFactory;
this.projectCache = projectCache;
this.projectJson = projectJson;
this.metaDataUpdateFactory = metaDataUpdateFactory;
this.groupControlFactory = groupControlFactory;
this.groupBackend = groupBackend;
this.allProjectsName = allProjectsName;
}
@Override
public Map<String, ProjectAccessInfo> apply(TopLevelResource resource)
throws ResourceNotFoundException, ResourceConflictException, IOException {
Map<String, ProjectAccessInfo> access = Maps.newTreeMap();
for (String p: projects) {
Project.NameKey projectName = new Project.NameKey(p);
ProjectControl pc = open(projectName);
ProjectConfig config;
try {
// Load the current configuration from the repository, ensuring it's the most
// recent version available. If it differs from what was in the project
// state, force a cache flush now.
//
MetaDataUpdate md = metaDataUpdateFactory.create(projectName);
try {
config = ProjectConfig.read(md);
if (config.updateGroupNames(groupBackend)) {
md.setMessage("Update group names\n");
config.commit(md);
projectCache.evict(config.getProject());
pc = open(projectName);
} else if (config.getRevision() != null
&& !config.getRevision().equals(
pc.getProjectState().getConfig().getRevision())) {
projectCache.evict(config.getProject());
pc = open(projectName);
}
} catch (ConfigInvalidException e) {
throw new ResourceConflictException(e.getMessage());
} finally {
md.close();
}
} catch (RepositoryNotFoundException e) {
throw new ResourceNotFoundException(p);
}
access.put(p, new ProjectAccessInfo(pc, config));
}
return access;
}
private ProjectControl open(Project.NameKey projectName)
throws ResourceNotFoundException, IOException {
try {
return projectControlFactory.validateFor(projectName,
ProjectControl.OWNER | ProjectControl.VISIBLE, self.get());
} catch (NoSuchProjectException e) {
throw new ResourceNotFoundException(projectName.get());
}
}
public class ProjectAccessInfo {
public String revision;
public ProjectInfo inheritsFrom;
public Map<String, AccessSectionInfo> local;
public Set<String> ownerOf;
public Boolean canUpload;
public Boolean canAdd;
public Boolean configVisible;
public ProjectAccessInfo(ProjectControl pc, ProjectConfig config) {
final RefControl metaConfigControl =
pc.controlForRef(GitRepositoryManager.REF_CONFIG);
local = Maps.newHashMap();
ownerOf = Sets.newHashSet();
Map<AccountGroup.UUID, Boolean> visibleGroups =
new HashMap<AccountGroup.UUID, Boolean>();
for (AccessSection section : config.getAccessSections()) {
String name = section.getName();
if (AccessSection.GLOBAL_CAPABILITIES.equals(name)) {
if (pc.isOwner()) {
local.put(name, new AccessSectionInfo(section));
ownerOf.add(name);
} else if (metaConfigControl.isVisible()) {
local.put(section.getName(), new AccessSectionInfo(section));
}
} else if (RefConfigSection.isValid(name)) {
RefControl rc = pc.controlForRef(name);
if (rc.isOwner()) {
local.put(name, new AccessSectionInfo(section));
ownerOf.add(name);
} else if (metaConfigControl.isVisible()) {
local.put(name, new AccessSectionInfo(section));
} else if (rc.isVisible()) {
// Filter the section to only add rules describing groups that
// are visible to the current-user. This includes any group the
// user is a member of, as well as groups they own or that
// are visible to all users.
AccessSection dst = null;
for (Permission srcPerm : section.getPermissions()) {
Permission dstPerm = null;
for (PermissionRule srcRule : srcPerm.getRules()) {
AccountGroup.UUID group = srcRule.getGroup().getUUID();
if (group == null) {
continue;
}
Boolean canSeeGroup = visibleGroups.get(group);
if (canSeeGroup == null) {
try {
canSeeGroup = groupControlFactory.controlFor(group).isVisible();
} catch (NoSuchGroupException e) {
canSeeGroup = Boolean.FALSE;
}
visibleGroups.put(group, canSeeGroup);
}
if (canSeeGroup) {
if (dstPerm == null) {
if (dst == null) {
dst = new AccessSection(name);
local.put(name, new AccessSectionInfo(dst));
}
dstPerm = dst.getPermission(srcPerm.getName(), true);
}
dstPerm.add(srcRule);
}
}
}
}
}
}
if (ownerOf.isEmpty() && pc.isOwnerAnyRef()) {
// Special case: If the section list is empty, this project has no current
// access control information. Rely on what ProjectControl determines
// is ownership, which probably means falling back to site administrators.
ownerOf.add(AccessSection.ALL);
}
if (config.getRevision() != null) {
revision = config.getRevision().name();
}
ProjectState parent =
Iterables.getFirst(pc.getProjectState().parents(), null);
if (parent != null) {
inheritsFrom = projectJson.format(parent.getProject());
}
if (pc.getProject().getNameKey().equals(allProjectsName)) {
if (pc.isOwner()) {
ownerOf.add(AccessSection.GLOBAL_CAPABILITIES);
}
}
canUpload = toBoolean(pc.isOwner()
|| (metaConfigControl.isVisible() && metaConfigControl.canUpload()));
canAdd = toBoolean(pc.canAddRefs());
configVisible = pc.isOwner() || metaConfigControl.isVisible();
}
}
public class AccessSectionInfo {
public Map<String, PermissionInfo> permissions;
public AccessSectionInfo(AccessSection section) {
permissions = Maps.newHashMap();
for (Permission p : section.getPermissions()) {
permissions.put(p.getName(), new PermissionInfo(p));
}
}
}
public class PermissionInfo {
public String label;
public Boolean exclusive;
public Map<String, PermissionRuleInfo> rules;
public PermissionInfo(Permission permission) {
label = permission.getLabel();
exclusive = toBoolean(permission.getExclusiveGroup());
rules = Maps.newHashMap();
for (PermissionRule r : permission.getRules()) {
rules.put(r.getGroup().getUUID().get(), new PermissionRuleInfo(r));
}
}
}
public class PermissionRuleInfo {
public PermissionRule.Action action;
public Boolean force;
public Integer min;
public Integer max;
public PermissionRuleInfo(PermissionRule rule) {
action = rule.getAction();
force = toBoolean(rule.getForce());
if (hasRange(rule)) {
min = rule.getMin();
max = rule.getMax();
}
}
private boolean hasRange(PermissionRule rule) {
return (!(rule.getMin() == null || rule.getMin() == 0))
|| (!(rule.getMax() == null || rule.getMax() == 0));
}
}
private static Boolean toBoolean(boolean value) {
return value ? true : null;
}
}

View File

@ -0,0 +1,29 @@
// Copyright (C) 2013 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.access;
import static com.google.gerrit.server.access.AccessResource.ACCESS_KIND;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.RestApiModule;
public class Module extends RestApiModule {
@Override
protected void configure() {
bind(AccessCollection.class);
DynamicMap.mapOf(binder(), ACCESS_KIND);
}
}

View File

@ -238,6 +238,7 @@ public class GerritGlobalModule extends FactoryModule {
bind(AccountControl.Factory.class);
install(new AuditModule());
install(new com.google.gerrit.server.access.Module());
install(new com.google.gerrit.server.account.Module());
install(new com.google.gerrit.server.change.Module());
install(new com.google.gerrit.server.config.Module());

View File

@ -70,6 +70,18 @@ public class ProjectControl {
}
return p.controlFor(user);
}
public ProjectControl validateFor(Project.NameKey nameKey, int need,
CurrentUser user) throws NoSuchProjectException, IOException {
final ProjectControl c = controlFor(nameKey, user);
if ((need & VISIBLE) == VISIBLE && c.isVisible()) {
return c;
}
if ((need & OWNER) == OWNER && c.isOwner()) {
return c;
}
throw new NoSuchProjectException(nameKey);
}
}
public static class Factory {