diff --git a/java/com/google/gerrit/extensions/restapi/AcceptsCreate.java b/java/com/google/gerrit/extensions/restapi/AcceptsCreate.java deleted file mode 100644 index 994e7f28f1..0000000000 --- a/java/com/google/gerrit/extensions/restapi/AcceptsCreate.java +++ /dev/null @@ -1,34 +0,0 @@ -// 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.extensions.restapi; - -/** - * Optional interface for {@link RestCollection}. - * - *

Collections that implement this interface can accept a {@code PUT} or {@code POST} when the - * parse method throws {@link ResourceNotFoundException}. - */ -public interface AcceptsCreate

{ - /** - * Handle creation of a child resource. - * - * @param parent parent collection handle. - * @param id id of the resource being created. - * @return a view to perform the creation. The create method must embed the id into the newly - * returned view object, as it will not be passed. - * @throws RestApiException the view cannot be constructed. - */ - RestModifyView create(P parent, IdString id) throws RestApiException; -} diff --git a/java/com/google/gerrit/extensions/restapi/RestApiModule.java b/java/com/google/gerrit/extensions/restapi/RestApiModule.java index 0db28917b8..783df0b7ff 100644 --- a/java/com/google/gerrit/extensions/restapi/RestApiModule.java +++ b/java/com/google/gerrit/extensions/restapi/RestApiModule.java @@ -28,6 +28,7 @@ public abstract class RestApiModule extends FactoryModule { protected static final String PUT = "PUT"; protected static final String DELETE = "DELETE"; protected static final String POST = "POST"; + protected static final String CREATE = "CREATE"; protected ReadViewBinder get(TypeLiteral> viewType) { return new ReadViewBinder<>(view(viewType, GET, "/")); @@ -45,6 +46,11 @@ public abstract class RestApiModule extends FactoryModule { return new ModifyViewBinder<>(view(viewType, DELETE, "/")); } + protected

CreateViewBinder create( + TypeLiteral> viewType) { + return new CreateViewBinder<>(createView(viewType, CREATE, "/")); + } + protected ReadViewBinder get( TypeLiteral> viewType, String name) { return new ReadViewBinder<>(view(viewType, GET, name)); @@ -75,6 +81,12 @@ public abstract class RestApiModule extends FactoryModule { return bind(viewType).annotatedWith(export(method, name)); } + protected

+ LinkedBindingBuilder> createView( + TypeLiteral> viewType, String method, String name) { + return bind(viewType).annotatedWith(export(method, name)); + } + private static Export export(String method, String name) { if (name.length() > 1 && name.startsWith("/")) { // Views may be bound as "/" to mean the resource itself, or @@ -137,6 +149,33 @@ public abstract class RestApiModule extends FactoryModule { } } + public static class CreateViewBinder { + private final LinkedBindingBuilder> binder; + + private CreateViewBinder(LinkedBindingBuilder> binder) { + this.binder = binder; + } + + public

> ScopedBindingBuilder to( + Class impl) { + return binder.to(impl); + } + + public

> void toInstance(T impl) { + binder.toInstance(impl); + } + + public

> + ScopedBindingBuilder toProvider(Class> providerType) { + return binder.toProvider(providerType); + } + + public

> + ScopedBindingBuilder toProvider(Provider provider) { + return binder.toProvider(provider); + } + } + public static class ChildCollectionBinder

{ private final LinkedBindingBuilder> binder; diff --git a/java/com/google/gerrit/extensions/restapi/RestCreateView.java b/java/com/google/gerrit/extensions/restapi/RestCreateView.java new file mode 100644 index 0000000000..5278deb0a9 --- /dev/null +++ b/java/com/google/gerrit/extensions/restapi/RestCreateView.java @@ -0,0 +1,45 @@ +// Copyright (C) 2018 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.extensions.restapi; + +/** + * RestView that supports accepting input and creating a resource. + * + *

The input must be supplied as JSON as the body of the HTTP request. Create views can be + * invoked by the HTTP methods {@code PUT} and {@code POST}. + * + *

The RestCreateView is only invoked when the parse method of the {@code RestCollection} throws + * {@link ResourceNotFoundException}, and hence the resource doesn't exist yet. + * + * @param

type of the parent resource + * @param type of the child resource that is created + * @param type of input the JSON parser will parse the input into. + */ +public interface RestCreateView

+ extends RestView { + + /** + * Process the view operation by creating the resource. + * + * @param parentResource parent resource of the resource that should be created + * @param input input after parsing from request. + * @return result to return to the client. Use {@link BinaryResult} to avoid automatic conversion + * to JSON. + * @throws RestApiException if the resource creation is rejected + * @throws Exception the implementation of the view failed. The exception will be logged and HTTP + * 500 Internal Server Error will be returned to the client. + */ + Object apply(P parentResource, IdString id, I input) throws Exception; +} diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java index 546bb9fd8b..1196e470f7 100644 --- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java +++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java @@ -68,7 +68,6 @@ import com.google.gerrit.common.RawInputUtil; import com.google.gerrit.common.TimeUtil; import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.extensions.registration.DynamicMap; -import com.google.gerrit.extensions.restapi.AcceptsCreate; import com.google.gerrit.extensions.restapi.AcceptsDelete; import com.google.gerrit.extensions.restapi.AcceptsPost; import com.google.gerrit.extensions.restapi.AuthException; @@ -88,6 +87,7 @@ import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestCollection; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.extensions.restapi.RestResource; @@ -323,11 +323,15 @@ public class RestApiServlet extends HttpServlet { checkPreconditions(req); } } catch (ResourceNotFoundException e) { - if (rc instanceof AcceptsCreate && path.isEmpty() && (isPost(req) || isPut(req))) { - @SuppressWarnings("unchecked") - AcceptsCreate ac = (AcceptsCreate) rc; - viewData = new ViewData(null, ac.create(rsrc, id)); + if (!path.isEmpty() || (!isPost(req) && !isPut(req))) { + throw e; + } + + RestView createView = rc.views().get("gerrit", "CREATE./"); + if (createView != null) { + viewData = new ViewData(null, createView); status = SC_CREATED; + path.add(id); } else { throw e; } @@ -365,12 +369,20 @@ public class RestApiServlet extends HttpServlet { checkPreconditions(req); viewData = new ViewData(null, null); } catch (ResourceNotFoundException e) { - if (c instanceof AcceptsCreate && path.isEmpty() && (isPost(req) || isPut(req))) { - @SuppressWarnings("unchecked") - AcceptsCreate ac = (AcceptsCreate) c; - viewData = new ViewData(viewData.pluginName, ac.create(rsrc, id)); - status = SC_CREATED; - } else if (c instanceof AcceptsDelete && path.isEmpty() && isDelete(req)) { + if (!path.isEmpty()) { + throw e; + } + + if (isPost(req) || isPut(req)) { + RestView createView = c.views().get("gerrit", "CREATE./"); + if (createView != null) { + viewData = new ViewData(null, createView); + status = SC_CREATED; + path.add(id); + } else { + throw e; + } + } else if (c instanceof AcceptsDelete && isDelete(req)) { @SuppressWarnings("unchecked") AcceptsDelete ac = (AcceptsDelete) c; viewData = new ViewData(viewData.pluginName, ac.delete(rsrc, id)); @@ -409,6 +421,19 @@ public class RestApiServlet extends HttpServlet { ServletUtils.consumeRequestBody(is); } } + } else if (viewData.view instanceof RestCreateView) { + @SuppressWarnings("unchecked") + RestCreateView m = + (RestCreateView) viewData.view; + + Type type = inputType(m); + inputRequestBody = parseRequest(req, type); + result = m.apply(rsrc, path.get(0), inputRequestBody); + if (inputRequestBody instanceof RawInput) { + try (InputStream is = req.getInputStream()) { + ServletUtils.consumeRequestBody(is); + } + } } else { throw new ResourceNotFoundException(); } @@ -735,6 +760,24 @@ public class RestApiServlet extends HttpServlet { return ((ParameterizedType) supertype).getActualTypeArguments()[1]; } + private static Type inputType(RestCreateView m) { + // MyCreateView implements RestCreateView + TypeLiteral typeLiteral = TypeLiteral.get(m.getClass()); + + // RestCreateView + // This is smart enough to resolve even when there are intervening subclasses, even if they have + // reordered type arguments. + TypeLiteral supertypeLiteral = typeLiteral.getSupertype(RestCreateView.class); + + Type supertype = supertypeLiteral.getType(); + checkState( + supertype instanceof ParameterizedType, + "supertype of %s is not parameterized: %s", + typeLiteral, + supertypeLiteral); + return ((ParameterizedType) supertype).getActualTypeArguments()[2]; + } + private Object parseRequest(HttpServletRequest req, Type type) throws IOException, BadRequestException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InstantiationException, diff --git a/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java b/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java index ead73c496f..2d6ef2cc88 100644 --- a/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java +++ b/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java @@ -111,7 +111,7 @@ public class AccountApiImpl implements AccountApi { private final Stars.Get starsGet; private final Stars.Post starsPost; private final GetEmails getEmails; - private final CreateEmail.Factory createEmailFactory; + private final CreateEmail createEmail; private final DeleteEmail deleteEmail; private final GpgApiAdapter gpgApiAdapter; private final GetSshKeys getSshKeys; @@ -151,7 +151,7 @@ public class AccountApiImpl implements AccountApi { Stars.Get starsGet, Stars.Post starsPost, GetEmails getEmails, - CreateEmail.Factory createEmailFactory, + CreateEmail createEmail, DeleteEmail deleteEmail, GpgApiAdapter gpgApiAdapter, GetSshKeys getSshKeys, @@ -190,7 +190,7 @@ public class AccountApiImpl implements AccountApi { this.starsGet = starsGet; this.starsPost = starsPost; this.getEmails = getEmails; - this.createEmailFactory = createEmailFactory; + this.createEmail = createEmail; this.deleteEmail = deleteEmail; this.getSshKeys = getSshKeys; this.addSshKey = addSshKey; @@ -341,9 +341,8 @@ public class AccountApiImpl implements AccountApi { @Override public void starChange(String changeId) throws RestApiException { try { - ChangeResource rsrc = changes.parse(TopLevelResource.INSTANCE, IdString.fromUrl(changeId)); - starredChangesCreate.setChange(rsrc); - starredChangesCreate.apply(account, new StarredChanges.EmptyInput()); + starredChangesCreate.apply( + account, IdString.fromUrl(changeId), new StarredChanges.EmptyInput()); } catch (Exception e) { throw asRestApiException("Cannot star change", e); } @@ -412,7 +411,7 @@ public class AccountApiImpl implements AccountApi { public void addEmail(EmailInput input) throws RestApiException { AccountResource.Email rsrc = new AccountResource.Email(account.getUser(), input.email); try { - createEmailFactory.create(input.email).apply(rsrc, input); + createEmail.apply(rsrc, IdString.fromDecoded(input.email), input); } catch (Exception e) { throw asRestApiException("Cannot add email", e); } @@ -432,7 +431,7 @@ public class AccountApiImpl implements AccountApi { public EmailApi createEmail(EmailInput input) throws RestApiException { AccountResource.Email rsrc = new AccountResource.Email(account.getUser(), input.email); try { - createEmailFactory.create(input.email).apply(rsrc, input); + createEmail.apply(rsrc, IdString.fromDecoded(input.email), input); return email(rsrc.getEmail()); } catch (Exception e) { throw asRestApiException("Cannot create email", e); diff --git a/java/com/google/gerrit/server/api/accounts/AccountsImpl.java b/java/com/google/gerrit/server/api/accounts/AccountsImpl.java index 44b6610d77..ca5aca4c75 100644 --- a/java/com/google/gerrit/server/api/accounts/AccountsImpl.java +++ b/java/com/google/gerrit/server/api/accounts/AccountsImpl.java @@ -45,7 +45,7 @@ public class AccountsImpl implements Accounts { private final AccountApiImpl.Factory api; private final PermissionBackend permissionBackend; private final Provider self; - private final CreateAccount.Factory createAccount; + private final CreateAccount createAccount; private final Provider queryAccountsProvider; @Inject @@ -54,7 +54,7 @@ public class AccountsImpl implements Accounts { AccountApiImpl.Factory api, PermissionBackend permissionBackend, Provider self, - CreateAccount.Factory createAccount, + CreateAccount createAccount, Provider queryAccountsProvider) { this.accounts = accounts; this.api = api; @@ -99,9 +99,13 @@ public class AccountsImpl implements Accounts { throw new BadRequestException("AccountInput must specify username"); } try { - CreateAccount impl = createAccount.create(in.username); - permissionBackend.currentUser().checkAny(GlobalPermission.fromAnnotation(impl.getClass())); - AccountInfo info = impl.apply(TopLevelResource.INSTANCE, in).value(); + permissionBackend + .currentUser() + .checkAny(GlobalPermission.fromAnnotation(createAccount.getClass())); + AccountInfo info = + createAccount + .apply(TopLevelResource.INSTANCE, IdString.fromDecoded(in.username), in) + .value(); return id(info._accountId); } catch (Exception e) { throw asRestApiException("Cannot create account " + in.username, e); diff --git a/java/com/google/gerrit/server/api/groups/GroupsImpl.java b/java/com/google/gerrit/server/api/groups/GroupsImpl.java index 247be44bf2..bac6649928 100644 --- a/java/com/google/gerrit/server/api/groups/GroupsImpl.java +++ b/java/com/google/gerrit/server/api/groups/GroupsImpl.java @@ -49,7 +49,7 @@ class GroupsImpl implements Groups { private final Provider listGroups; private final Provider queryGroups; private final PermissionBackend permissionBackend; - private final CreateGroup.Factory createGroup; + private final CreateGroup createGroup; private final GroupApiImpl.Factory api; @Inject @@ -60,7 +60,7 @@ class GroupsImpl implements Groups { Provider listGroups, Provider queryGroups, PermissionBackend permissionBackend, - CreateGroup.Factory createGroup, + CreateGroup createGroup, GroupApiImpl.Factory api) { this.accounts = accounts; this.groups = groups; @@ -90,9 +90,11 @@ class GroupsImpl implements Groups { throw new BadRequestException("GroupInput must specify name"); } try { - CreateGroup impl = createGroup.create(in.name); - permissionBackend.currentUser().checkAny(GlobalPermission.fromAnnotation(impl.getClass())); - GroupInfo info = impl.apply(TopLevelResource.INSTANCE, in); + permissionBackend + .currentUser() + .checkAny(GlobalPermission.fromAnnotation(createGroup.getClass())); + GroupInfo info = + createGroup.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(in.name), in); return id(info.id); } catch (Exception e) { throw asRestApiException("Cannot create group " + in.name, e); diff --git a/java/com/google/gerrit/server/api/projects/BranchApiImpl.java b/java/com/google/gerrit/server/api/projects/BranchApiImpl.java index 78b34b878a..b3506fc5d7 100644 --- a/java/com/google/gerrit/server/api/projects/BranchApiImpl.java +++ b/java/com/google/gerrit/server/api/projects/BranchApiImpl.java @@ -46,7 +46,7 @@ public class BranchApiImpl implements BranchApi { } private final BranchesCollection branches; - private final CreateBranch.Factory createBranchFactory; + private final CreateBranch createBranch; private final DeleteBranch deleteBranch; private final FilesCollection filesCollection; private final GetBranch getBranch; @@ -58,7 +58,7 @@ public class BranchApiImpl implements BranchApi { @Inject BranchApiImpl( BranchesCollection branches, - CreateBranch.Factory createBranchFactory, + CreateBranch createBranch, DeleteBranch deleteBranch, FilesCollection filesCollection, GetBranch getBranch, @@ -67,7 +67,7 @@ public class BranchApiImpl implements BranchApi { @Assisted ProjectResource project, @Assisted String ref) { this.branches = branches; - this.createBranchFactory = createBranchFactory; + this.createBranch = createBranch; this.deleteBranch = deleteBranch; this.filesCollection = filesCollection; this.getBranch = getBranch; @@ -80,7 +80,7 @@ public class BranchApiImpl implements BranchApi { @Override public BranchApi create(BranchInput input) throws RestApiException { try { - createBranchFactory.create(ref).apply(project, input); + createBranch.apply(project, IdString.fromDecoded(ref), input); return this; } catch (Exception e) { throw asRestApiException("Cannot create branch", e); diff --git a/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java b/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java index 46d9180319..1065bffde0 100644 --- a/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java +++ b/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java @@ -88,7 +88,7 @@ public class ProjectApiImpl implements ProjectApi { } private final PermissionBackend permissionBackend; - private final CreateProject.Factory createProjectFactory; + private final CreateProject createProject; private final ProjectApiImpl.Factory projectApi; private final ProjectsCollection projects; private final GetDescription getDescription; @@ -122,7 +122,7 @@ public class ProjectApiImpl implements ProjectApi { @AssistedInject ProjectApiImpl( PermissionBackend permissionBackend, - CreateProject.Factory createProjectFactory, + CreateProject createProject, ProjectApiImpl.Factory projectApi, ProjectsCollection projects, GetDescription getDescription, @@ -153,7 +153,7 @@ public class ProjectApiImpl implements ProjectApi { @Assisted ProjectResource project) { this( permissionBackend, - createProjectFactory, + createProject, projectApi, projects, getDescription, @@ -188,7 +188,7 @@ public class ProjectApiImpl implements ProjectApi { @AssistedInject ProjectApiImpl( PermissionBackend permissionBackend, - CreateProject.Factory createProjectFactory, + CreateProject createProject, ProjectApiImpl.Factory projectApi, ProjectsCollection projects, GetDescription getDescription, @@ -219,7 +219,7 @@ public class ProjectApiImpl implements ProjectApi { @Assisted String name) { this( permissionBackend, - createProjectFactory, + createProject, projectApi, projects, getDescription, @@ -253,7 +253,7 @@ public class ProjectApiImpl implements ProjectApi { private ProjectApiImpl( PermissionBackend permissionBackend, - CreateProject.Factory createProjectFactory, + CreateProject createProject, ProjectApiImpl.Factory projectApi, ProjectsCollection projects, GetDescription getDescription, @@ -284,7 +284,7 @@ public class ProjectApiImpl implements ProjectApi { SetParent setParent, String name) { this.permissionBackend = permissionBackend; - this.createProjectFactory = createProjectFactory; + this.createProject = createProject; this.projectApi = projectApi; this.projects = projects; this.getDescription = getDescription; @@ -330,9 +330,10 @@ public class ProjectApiImpl implements ProjectApi { if (in.name != null && !name.equals(in.name)) { throw new BadRequestException("name must match input.name"); } - CreateProject impl = createProjectFactory.create(name); - permissionBackend.currentUser().checkAny(GlobalPermission.fromAnnotation(impl.getClass())); - impl.apply(TopLevelResource.INSTANCE, in); + permissionBackend + .currentUser() + .checkAny(GlobalPermission.fromAnnotation(createProject.getClass())); + createProject.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(name), in); return projectApi.create(projects.parse(name)); } catch (Exception e) { throw asRestApiException("Cannot create project: " + e.getMessage(), e); diff --git a/java/com/google/gerrit/server/api/projects/TagApiImpl.java b/java/com/google/gerrit/server/api/projects/TagApiImpl.java index 03e2162297..005486a870 100644 --- a/java/com/google/gerrit/server/api/projects/TagApiImpl.java +++ b/java/com/google/gerrit/server/api/projects/TagApiImpl.java @@ -39,7 +39,7 @@ public class TagApiImpl implements TagApi { } private final ListTags listTags; - private final CreateTag.Factory createTagFactory; + private final CreateTag createTag; private final DeleteTag deleteTag; private final TagsCollection tags; private final String ref; @@ -48,13 +48,13 @@ public class TagApiImpl implements TagApi { @Inject TagApiImpl( ListTags listTags, - CreateTag.Factory createTagFactory, + CreateTag createTag, DeleteTag deleteTag, TagsCollection tags, @Assisted ProjectResource project, @Assisted String ref) { this.listTags = listTags; - this.createTagFactory = createTagFactory; + this.createTag = createTag; this.deleteTag = deleteTag; this.tags = tags; this.project = project; @@ -64,7 +64,7 @@ public class TagApiImpl implements TagApi { @Override public TagApi create(TagInput input) throws RestApiException { try { - createTagFactory.create(ref).apply(project, input); + createTag.apply(project, IdString.fromDecoded(ref), input); return this; } catch (Exception e) { throw asRestApiException("Cannot create tag", e); diff --git a/java/com/google/gerrit/server/plugins/InstallPlugin.java b/java/com/google/gerrit/server/plugins/InstallPlugin.java index ee9099eca3..f1c1fe75b4 100644 --- a/java/com/google/gerrit/server/plugins/InstallPlugin.java +++ b/java/com/google/gerrit/server/plugins/InstallPlugin.java @@ -19,8 +19,10 @@ import com.google.gerrit.extensions.annotations.RequiresCapability; import com.google.gerrit.extensions.common.InstallPluginInput; import com.google.gerrit.extensions.common.PluginInfo; import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.inject.Inject; @@ -91,6 +93,26 @@ public class InstallPlugin implements RestModifyView { + private final PluginLoader loader; + private final Provider install; + + @Inject + Create(PluginLoader loader, Provider install) { + this.loader = loader; + this.install = install; + } + + @Override + public Response apply( + TopLevelResource parentResource, IdString id, InstallPluginInput input) throws Exception { + loader.checkRemoteAdminEnabled(); + return install.get().setName(id.get()).setCreated(true).apply(parentResource, input); + } + } + @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) static class Overwrite implements RestModifyView { private final Provider install; diff --git a/java/com/google/gerrit/server/plugins/PluginRestApiModule.java b/java/com/google/gerrit/server/plugins/PluginRestApiModule.java index cad0e1e616..8dbea781d1 100644 --- a/java/com/google/gerrit/server/plugins/PluginRestApiModule.java +++ b/java/com/google/gerrit/server/plugins/PluginRestApiModule.java @@ -27,6 +27,7 @@ public class PluginRestApiModule extends RestApiModule { requireBinding(Key.get(PluginUser.Factory.class)); bind(PluginsCollection.class); DynamicMap.mapOf(binder(), PLUGIN_KIND); + create(PLUGIN_KIND).to(InstallPlugin.Create.class); put(PLUGIN_KIND).to(InstallPlugin.Overwrite.class); delete(PLUGIN_KIND).to(DisablePlugin.class); get(PLUGIN_KIND, "status").to(GetStatus.class); diff --git a/java/com/google/gerrit/server/plugins/PluginsCollection.java b/java/com/google/gerrit/server/plugins/PluginsCollection.java index 0d2a0188e4..7cc006e5bb 100644 --- a/java/com/google/gerrit/server/plugins/PluginsCollection.java +++ b/java/com/google/gerrit/server/plugins/PluginsCollection.java @@ -15,10 +15,8 @@ package com.google.gerrit.server.plugins; import com.google.gerrit.extensions.registration.DynamicMap; -import com.google.gerrit.extensions.restapi.AcceptsCreate; import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; -import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestCollection; import com.google.gerrit.extensions.restapi.RestView; import com.google.gerrit.extensions.restapi.TopLevelResource; @@ -27,24 +25,18 @@ import com.google.inject.Provider; import com.google.inject.Singleton; @Singleton -public class PluginsCollection - implements RestCollection, AcceptsCreate { +public class PluginsCollection implements RestCollection { private final DynamicMap> views; private final PluginLoader loader; private final Provider list; - private final Provider install; @Inject public PluginsCollection( - DynamicMap> views, - PluginLoader loader, - Provider list, - Provider install) { + DynamicMap> views, PluginLoader loader, Provider list) { this.views = views; this.loader = loader; this.list = list; - this.install = install; } @Override @@ -66,12 +58,6 @@ public class PluginsCollection return new PluginResource(p); } - @Override - public InstallPlugin create(TopLevelResource parent, IdString id) throws RestApiException { - loader.checkRemoteAdminEnabled(); - return install.get().setName(id.get()).setCreated(true); - } - @Override public DynamicMap> views() { return views; diff --git a/java/com/google/gerrit/server/restapi/account/AccountsCollection.java b/java/com/google/gerrit/server/restapi/account/AccountsCollection.java index 6cec565912..370833cd31 100644 --- a/java/com/google/gerrit/server/restapi/account/AccountsCollection.java +++ b/java/com/google/gerrit/server/restapi/account/AccountsCollection.java @@ -16,11 +16,9 @@ package com.google.gerrit.server.restapi.account; import com.google.gerrit.common.Nullable; 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.RestApiException; import com.google.gerrit.extensions.restapi.RestCollection; import com.google.gerrit.extensions.restapi.RestView; import com.google.gerrit.extensions.restapi.TopLevelResource; @@ -40,15 +38,13 @@ import java.io.IOException; import org.eclipse.jgit.errors.ConfigInvalidException; @Singleton -public class AccountsCollection - implements RestCollection, AcceptsCreate { +public class AccountsCollection implements RestCollection { private final Provider self; private final AccountResolver resolver; private final AccountControl.Factory accountControlFactory; private final IdentifiedUser.GenericFactory userFactory; private final Provider list; private final DynamicMap> views; - private final CreateAccount.Factory createAccountFactory; @Inject public AccountsCollection( @@ -57,15 +53,13 @@ public class AccountsCollection AccountControl.Factory accountControlFactory, IdentifiedUser.GenericFactory userFactory, Provider list, - DynamicMap> views, - CreateAccount.Factory createAccountFactory) { + DynamicMap> views) { this.self = self; this.resolver = resolver; this.accountControlFactory = accountControlFactory; this.userFactory = userFactory; this.list = list; this.views = views; - this.createAccountFactory = createAccountFactory; } @Override @@ -159,9 +153,4 @@ public class AccountsCollection public DynamicMap> views() { return views; } - - @Override - public CreateAccount create(TopLevelResource parent, IdString username) throws RestApiException { - return createAccountFactory.create(username.get()); - } } diff --git a/java/com/google/gerrit/server/restapi/account/CreateAccount.java b/java/com/google/gerrit/server/restapi/account/CreateAccount.java index 404b3d3462..b1581abbaf 100644 --- a/java/com/google/gerrit/server/restapi/account/CreateAccount.java +++ b/java/com/google/gerrit/server/restapi/account/CreateAccount.java @@ -29,9 +29,10 @@ import com.google.gerrit.extensions.api.accounts.AccountInput; import com.google.gerrit.extensions.common.AccountInfo; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.Response; -import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.extensions.restapi.UnprocessableEntityException; import com.google.gerrit.reviewdb.client.Account; @@ -40,6 +41,7 @@ import com.google.gerrit.server.Sequences; import com.google.gerrit.server.UserInitiated; import com.google.gerrit.server.account.AccountExternalIdCreator; import com.google.gerrit.server.account.AccountLoader; +import com.google.gerrit.server.account.AccountResource; import com.google.gerrit.server.account.AccountsUpdate; import com.google.gerrit.server.account.VersionedAuthorizedKeys; import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException; @@ -52,7 +54,6 @@ import com.google.gerrit.server.ssh.SshKeyCache; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Provider; -import com.google.inject.assistedinject.Assisted; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; @@ -61,11 +62,8 @@ import java.util.Set; import org.eclipse.jgit.errors.ConfigInvalidException; @RequiresCapability(GlobalCapability.CREATE_ACCOUNT) -public class CreateAccount implements RestModifyView { - public interface Factory { - CreateAccount create(String username); - } - +public class CreateAccount + implements RestCreateView { private final Sequences seq; private final GroupsCollection groupsCollection; private final VersionedAuthorizedKeys.Accessor authorizedKeys; @@ -75,7 +73,6 @@ public class CreateAccount implements RestModifyView externalIdCreators; private final Provider groupsUpdate; private final OutgoingEmailValidator validator; - private final String username; @Inject CreateAccount( @@ -87,8 +84,7 @@ public class CreateAccount implements RestModifyView externalIdCreators, @UserInitiated Provider groupsUpdate, - OutgoingEmailValidator validator, - @Assisted String username) { + OutgoingEmailValidator validator) { this.seq = seq; this.groupsCollection = groupsCollection; this.authorizedKeys = authorizedKeys; @@ -98,23 +94,23 @@ public class CreateAccount implements RestModifyView apply(TopLevelResource rsrc, @Nullable AccountInput input) + public Response apply( + TopLevelResource rsrc, IdString id, @Nullable AccountInput input) throws BadRequestException, ResourceConflictException, UnprocessableEntityException, OrmException, IOException, ConfigInvalidException { - return apply(input != null ? input : new AccountInput()); + return apply(id, input != null ? input : new AccountInput()); } - public Response apply(AccountInput input) + public Response apply(IdString id, AccountInput input) throws BadRequestException, ResourceConflictException, UnprocessableEntityException, OrmException, IOException, ConfigInvalidException { + String username = id.get(); if (input.username != null && !username.equals(input.username)) { throw new BadRequestException("username must match URL"); } - if (!ExternalId.isValidUsername(username)) { throw new BadRequestException( "Username '" + username + "' must contain only letters, numbers, _, - or ."); @@ -122,19 +118,19 @@ public class CreateAccount implements RestModifyView groups = parseGroups(input.groups); - Account.Id id = new Account.Id(seq.nextAccountId()); + Account.Id accountId = new Account.Id(seq.nextAccountId()); List extIds = new ArrayList<>(); if (input.email != null) { if (!validator.isValid(input.email)) { throw new BadRequestException("invalid email address"); } - extIds.add(ExternalId.createEmail(id, input.email)); + extIds.add(ExternalId.createEmail(accountId, input.email)); } - extIds.add(ExternalId.createUsername(username, id, input.httpPassword)); + extIds.add(ExternalId.createUsername(username, accountId, input.httpPassword)); for (AccountExternalIdCreator c : externalIdCreators) { - extIds.addAll(c.create(id, username, input.email)); + extIds.addAll(c.create(accountId, username, input.email)); } try { @@ -142,7 +138,7 @@ public class CreateAccount implements RestModifyView u.setFullName(input.name).setPreferredEmail(input.email).addExternalIds(extIds)); } catch (DuplicateExternalIdKeyException e) { if (e.getDuplicateKey().isScheme(SCHEME_USERNAME)) { @@ -159,7 +155,7 @@ public class CreateAccount implements RestModifyView { +public class CreateEmail + implements RestCreateView { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - public interface Factory { - CreateEmail create(String email); - } - private final Provider self; private final Realm realm; private final PermissionBackend permissionBackend; @@ -61,7 +58,6 @@ public class CreateEmail implements RestModifyView private final RegisterNewEmailSender.Factory registerNewEmailFactory; private final PutPreferred putPreferred; private final OutgoingEmailValidator validator; - private final String email; private final boolean isDevMode; @Inject @@ -73,8 +69,7 @@ public class CreateEmail implements RestModifyView AccountManager accountManager, RegisterNewEmailSender.Factory registerNewEmailFactory, PutPreferred putPreferred, - OutgoingEmailValidator validator, - @Assisted String email) { + OutgoingEmailValidator validator) { this.self = self; this.realm = realm; this.permissionBackend = permissionBackend; @@ -82,12 +77,11 @@ public class CreateEmail implements RestModifyView this.registerNewEmailFactory = registerNewEmailFactory; this.putPreferred = putPreferred; this.validator = validator; - this.email = email != null ? email.trim() : null; this.isDevMode = authConfig.getAuthType() == DEVELOPMENT_BECOME_ANY_ACCOUNT; } @Override - public Response apply(AccountResource rsrc, EmailInput input) + public Response apply(AccountResource rsrc, IdString id, EmailInput input) throws RestApiException, OrmException, EmailException, MethodNotAllowedException, IOException, ConfigInvalidException, PermissionBackendException { if (input == null) { @@ -102,13 +96,15 @@ public class CreateEmail implements RestModifyView throw new MethodNotAllowedException("realm does not allow adding emails"); } - return apply(rsrc.getUser(), input); + return apply(rsrc.getUser(), id, input); } /** To be used from plugins that want to create emails without permission checks. */ - public Response apply(IdentifiedUser user, EmailInput input) + public Response apply(IdentifiedUser user, IdString id, EmailInput input) throws RestApiException, OrmException, EmailException, MethodNotAllowedException, IOException, ConfigInvalidException, PermissionBackendException { + String email = id.get().trim(); + if (input == null) { input = new EmailInput(); } diff --git a/java/com/google/gerrit/server/restapi/account/EmailsCollection.java b/java/com/google/gerrit/server/restapi/account/EmailsCollection.java index 8694da04b6..434b9d6174 100644 --- a/java/com/google/gerrit/server/restapi/account/EmailsCollection.java +++ b/java/com/google/gerrit/server/restapi/account/EmailsCollection.java @@ -16,7 +16,6 @@ package com.google.gerrit.server.restapi.account; import com.google.common.base.Strings; 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.ChildCollection; import com.google.gerrit.extensions.restapi.IdString; @@ -33,27 +32,22 @@ import com.google.inject.Provider; import com.google.inject.Singleton; @Singleton -public class EmailsCollection - implements ChildCollection, - AcceptsCreate { +public class EmailsCollection implements ChildCollection { private final DynamicMap> views; private final GetEmails list; private final Provider self; private final PermissionBackend permissionBackend; - private final CreateEmail.Factory createEmailFactory; @Inject EmailsCollection( DynamicMap> views, GetEmails list, Provider self, - PermissionBackend permissionBackend, - CreateEmail.Factory createEmailFactory) { + PermissionBackend permissionBackend) { this.views = views; this.list = list; this.self = self; this.permissionBackend = permissionBackend; - this.createEmailFactory = createEmailFactory; } @Override @@ -85,9 +79,4 @@ public class EmailsCollection public DynamicMap> views() { return views; } - - @Override - public CreateEmail create(AccountResource parent, IdString email) { - return createEmailFactory.create(email.get()); - } } diff --git a/java/com/google/gerrit/server/restapi/account/Module.java b/java/com/google/gerrit/server/restapi/account/Module.java index ca5f08e434..7b09bc9cae 100644 --- a/java/com/google/gerrit/server/restapi/account/Module.java +++ b/java/com/google/gerrit/server/restapi/account/Module.java @@ -43,6 +43,7 @@ public class Module extends RestApiModule { DynamicMap.mapOf(binder(), STARRED_CHANGE_KIND); DynamicMap.mapOf(binder(), STAR_KIND); + create(ACCOUNT_KIND).to(CreateAccount.class); put(ACCOUNT_KIND).to(PutAccount.class); get(ACCOUNT_KIND).to(GetAccount.class); get(ACCOUNT_KIND, "detail").to(GetDetail.class); @@ -58,6 +59,7 @@ public class Module extends RestApiModule { put(ACCOUNT_KIND, "active").to(PutActive.class); delete(ACCOUNT_KIND, "active").to(DeleteActive.class); child(ACCOUNT_KIND, "emails").to(EmailsCollection.class); + create(EMAIL_KIND).to(CreateEmail.class); get(EMAIL_KIND).to(GetEmail.class); put(EMAIL_KIND).to(PutEmail.class); delete(EMAIL_KIND).to(DeleteEmail.class); @@ -93,6 +95,7 @@ public class Module extends RestApiModule { put(ACCOUNT_KIND, "agreements").to(PutAgreement.class); child(ACCOUNT_KIND, "starred.changes").to(StarredChanges.class); + create(STARRED_CHANGE_KIND).to(StarredChanges.Create.class); put(STARRED_CHANGE_KIND).to(StarredChanges.Put.class); delete(STARRED_CHANGE_KIND).to(StarredChanges.Delete.class); bind(StarredChanges.Create.class); @@ -104,8 +107,6 @@ public class Module extends RestApiModule { get(ACCOUNT_KIND, "external.ids").to(GetExternalIds.class); post(ACCOUNT_KIND, "external.ids:delete").to(DeleteExternalIds.class); - factory(CreateAccount.Factory.class); - factory(CreateEmail.Factory.class); factory(AccountsUpdate.Factory.class); } diff --git a/java/com/google/gerrit/server/restapi/account/StarredChanges.java b/java/com/google/gerrit/server/restapi/account/StarredChanges.java index e804b64a6d..e049539855 100644 --- a/java/com/google/gerrit/server/restapi/account/StarredChanges.java +++ b/java/com/google/gerrit/server/restapi/account/StarredChanges.java @@ -16,7 +16,6 @@ package com.google.gerrit.server.restapi.account; import com.google.common.flogger.FluentLogger; 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.BadRequestException; import com.google.gerrit.extensions.restapi.ChildCollection; @@ -25,6 +24,7 @@ import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.extensions.restapi.RestView; @@ -49,24 +49,20 @@ import java.io.IOException; @Singleton public class StarredChanges - implements ChildCollection, - AcceptsCreate { + implements ChildCollection { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private final ChangesCollection changes; private final DynamicMap> views; - private final Provider createProvider; private final StarredChangesUtil starredChangesUtil; @Inject StarredChanges( ChangesCollection changes, DynamicMap> views, - Provider createProvider, StarredChangesUtil starredChangesUtil) { this.changes = changes; this.views = views; - this.createProvider = createProvider; this.starredChangesUtil = starredChangesUtil; } @@ -101,42 +97,40 @@ public class StarredChanges }; } - @Override - public RestModifyView create(AccountResource parent, IdString id) - throws RestApiException { - try { - return createProvider.get().setChange(changes.parse(TopLevelResource.INSTANCE, id)); - } catch (ResourceNotFoundException e) { - throw new UnprocessableEntityException(String.format("change %s not found", id.get())); - } catch (OrmException | PermissionBackendException | IOException e) { - logger.atSevere().withCause(e).log("cannot resolve change"); - throw new UnprocessableEntityException("internal server error"); - } - } - @Singleton - public static class Create implements RestModifyView { + public static class Create + implements RestCreateView { private final Provider self; + private final ChangesCollection changes; private final StarredChangesUtil starredChangesUtil; - private ChangeResource change; @Inject - Create(Provider self, StarredChangesUtil starredChangesUtil) { + Create( + Provider self, + ChangesCollection changes, + StarredChangesUtil starredChangesUtil) { this.self = self; + this.changes = changes; this.starredChangesUtil = starredChangesUtil; } - public Create setChange(ChangeResource change) { - this.change = change; - return this; - } - @Override - public Response apply(AccountResource rsrc, EmptyInput in) + public Response apply(AccountResource rsrc, IdString id, EmptyInput in) throws RestApiException, OrmException, IOException { if (!self.get().hasSameAccountId(rsrc.getUser())) { throw new AuthException("not allowed to add starred change"); } + + ChangeResource change; + try { + change = changes.parse(TopLevelResource.INSTANCE, id); + } catch (ResourceNotFoundException e) { + throw new UnprocessableEntityException(String.format("change %s not found", id.get())); + } catch (OrmException | PermissionBackendException | IOException e) { + logger.atSevere().withCause(e).log("cannot resolve change"); + throw new UnprocessableEntityException("internal server error"); + } + try { starredChangesUtil.star( self.get().getAccountId(), diff --git a/java/com/google/gerrit/server/restapi/change/ChangeEdits.java b/java/com/google/gerrit/server/restapi/change/ChangeEdits.java index b7a029b89d..1e24a7f523 100644 --- a/java/com/google/gerrit/server/restapi/change/ChangeEdits.java +++ b/java/com/google/gerrit/server/restapi/change/ChangeEdits.java @@ -19,7 +19,6 @@ import com.google.gerrit.extensions.common.DiffWebLinkInfo; import com.google.gerrit.extensions.common.EditInfo; import com.google.gerrit.extensions.common.Input; import com.google.gerrit.extensions.registration.DynamicMap; -import com.google.gerrit.extensions.restapi.AcceptsCreate; import com.google.gerrit.extensions.restapi.AcceptsDelete; import com.google.gerrit.extensions.restapi.AcceptsPost; import com.google.gerrit.extensions.restapi.AuthException; @@ -33,6 +32,7 @@ import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.extensions.restapi.RestView; @@ -72,11 +72,9 @@ import org.kohsuke.args4j.Option; @Singleton public class ChangeEdits implements ChildCollection, - AcceptsCreate, AcceptsPost, AcceptsDelete { private final DynamicMap> views; - private final Create.Factory createFactory; private final DeleteFile.Factory deleteFileFactory; private final Provider detail; private final ChangeEditUtil editUtil; @@ -85,13 +83,11 @@ public class ChangeEdits @Inject ChangeEdits( DynamicMap> views, - Create.Factory createFactory, Provider detail, ChangeEditUtil editUtil, Post post, DeleteFile.Factory deleteFileFactory) { this.views = views; - this.createFactory = createFactory; this.detail = detail; this.editUtil = editUtil; this.post = post; @@ -118,11 +114,6 @@ public class ChangeEdits return new ChangeEditResource(rsrc, edit.get(), id.get()); } - @Override - public Create create(ChangeResource parent, IdString id) throws RestApiException { - return createFactory.create(id.get()); - } - @Override public Post post(ChangeResource parent) throws RestApiException { return post; @@ -141,26 +132,20 @@ public class ChangeEdits return deleteFileFactory.create(id.get()); } - public static class Create implements RestModifyView { - - interface Factory { - Create create(String path); - } - + public static class Create + implements RestCreateView { private final Put putEdit; - private final String path; @Inject - Create(Put putEdit, @Assisted String path) { + Create(Put putEdit) { this.putEdit = putEdit; - this.path = path; } @Override - public Response apply(ChangeResource resource, Put.Input input) + public Response apply(ChangeResource resource, IdString id, Put.Input input) throws AuthException, ResourceConflictException, IOException, OrmException, PermissionBackendException { - putEdit.apply(resource, path, input.content); + putEdit.apply(resource, id.get(), input.content); return Response.none(); } } diff --git a/java/com/google/gerrit/server/restapi/change/Module.java b/java/com/google/gerrit/server/restapi/change/Module.java index 7955fa59d6..d27b136ef1 100644 --- a/java/com/google/gerrit/server/restapi/change/Module.java +++ b/java/com/google/gerrit/server/restapi/change/Module.java @@ -165,6 +165,7 @@ public class Module extends RestApiModule { get(FILE_KIND, "blame").to(GetBlame.class); child(CHANGE_KIND, "edit").to(ChangeEdits.class); + create(CHANGE_EDIT_KIND).to(ChangeEdits.Create.class); delete(CHANGE_KIND, "edit").to(DeleteChangeEdit.class); child(CHANGE_KIND, "edit:publish").to(PublishChangeEdit.class); child(CHANGE_KIND, "edit:rebase").to(RebaseChangeEdit.class); @@ -180,7 +181,6 @@ public class Module extends RestApiModule { get(CHANGE_MESSAGE_KIND).to(GetChangeMessage.class); factory(AccountLoader.Factory.class); - factory(ChangeEdits.Create.Factory.class); factory(ChangeEdits.DeleteFile.Factory.class); factory(ChangeInserter.Factory.class); factory(ChangeResource.Factory.class); diff --git a/java/com/google/gerrit/server/restapi/group/AddMembers.java b/java/com/google/gerrit/server/restapi/group/AddMembers.java index 84fbbb7d3f..3e2d1e7de1 100644 --- a/java/com/google/gerrit/server/restapi/group/AddMembers.java +++ b/java/com/google/gerrit/server/restapi/group/AddMembers.java @@ -23,8 +23,10 @@ import com.google.gerrit.extensions.client.AuthType; import com.google.gerrit.extensions.common.AccountInfo; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.DefaultInput; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.MethodNotAllowedException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.UnprocessableEntityException; import com.google.gerrit.reviewdb.client.Account; @@ -211,22 +213,20 @@ public class AddMembers implements RestModifyView { return result; } - public static class PutMember implements RestModifyView { - + public static class CreateMember implements RestCreateView { private final AddMembers put; - private final String id; - public PutMember(AddMembers put, String id) { + @Inject + public CreateMember(AddMembers put) { this.put = put; - this.id = id; } @Override - public AccountInfo apply(GroupResource resource, Input input) + public AccountInfo apply(GroupResource resource, IdString id, Input input) throws AuthException, MethodNotAllowedException, ResourceNotFoundException, OrmException, IOException, ConfigInvalidException { AddMembers.Input in = new AddMembers.Input(); - in._oneMember = id; + in._oneMember = id.get(); try { List list = put.apply(resource, in); if (list.size() == 1) { diff --git a/java/com/google/gerrit/server/restapi/group/AddSubgroups.java b/java/com/google/gerrit/server/restapi/group/AddSubgroups.java index d0be5ac61a..21b698192a 100644 --- a/java/com/google/gerrit/server/restapi/group/AddSubgroups.java +++ b/java/com/google/gerrit/server/restapi/group/AddSubgroups.java @@ -23,8 +23,10 @@ import com.google.gerrit.common.errors.NoSuchGroupException; import com.google.gerrit.extensions.common.GroupInfo; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.DefaultInput; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.MethodNotAllowedException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.UnprocessableEntityException; import com.google.gerrit.reviewdb.client.AccountGroup; @@ -127,22 +129,21 @@ public class AddSubgroups implements RestModifyView { groupsUpdateProvider.get().updateGroup(parentGroupUuid, groupUpdate); } - public static class PutSubgroup implements RestModifyView { - + public static class CreateSubgroup + implements RestCreateView { private final AddSubgroups addSubgroups; - private final String id; - public PutSubgroup(AddSubgroups addSubgroups, String id) { + @Inject + public CreateSubgroup(AddSubgroups addSubgroups) { this.addSubgroups = addSubgroups; - this.id = id; } @Override - public GroupInfo apply(GroupResource resource, Input input) + public GroupInfo apply(GroupResource resource, IdString id, Input input) throws AuthException, MethodNotAllowedException, ResourceNotFoundException, OrmException, IOException, ConfigInvalidException { AddSubgroups.Input in = new AddSubgroups.Input(); - in.groups = ImmutableList.of(id); + in.groups = ImmutableList.of(id.get()); try { List list = addSubgroups.apply(resource, in); if (list.size() == 1) { diff --git a/java/com/google/gerrit/server/restapi/group/CreateGroup.java b/java/com/google/gerrit/server/restapi/group/CreateGroup.java index 79f9688699..6ecb5aa499 100644 --- a/java/com/google/gerrit/server/restapi/group/CreateGroup.java +++ b/java/com/google/gerrit/server/restapi/group/CreateGroup.java @@ -26,9 +26,10 @@ import com.google.gerrit.extensions.common.GroupInfo; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; -import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.extensions.restapi.UnprocessableEntityException; import com.google.gerrit.extensions.restapi.Url; @@ -42,6 +43,7 @@ import com.google.gerrit.server.account.CreateGroupArgs; import com.google.gerrit.server.account.GroupCache; import com.google.gerrit.server.account.GroupUUID; import com.google.gerrit.server.config.GerritServerConfig; +import com.google.gerrit.server.group.GroupResource; import com.google.gerrit.server.group.InternalGroup; import com.google.gerrit.server.group.InternalGroupDescription; import com.google.gerrit.server.group.SystemGroupBackend; @@ -54,7 +56,6 @@ import com.google.gwtorm.server.OrmDuplicateKeyException; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Provider; -import com.google.inject.assistedinject.Assisted; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -67,11 +68,7 @@ import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.PersonIdent; @RequiresCapability(GlobalCapability.CREATE_GROUP) -public class CreateGroup implements RestModifyView { - public interface Factory { - CreateGroup create(@Assisted String name); - } - +public class CreateGroup implements RestCreateView { private final Provider self; private final PersonIdent serverIdent; private final Provider groupsUpdateProvider; @@ -82,7 +79,6 @@ public class CreateGroup implements RestModifyView private final AddMembers addMembers; private final SystemGroupBackend systemGroupBackend; private final boolean defaultVisibleToAll; - private final String name; private final Sequences sequences; @Inject @@ -97,7 +93,6 @@ public class CreateGroup implements RestModifyView AddMembers addMembers, SystemGroupBackend systemGroupBackend, @GerritServerConfig Config cfg, - @Assisted String name, Sequences sequences) { this.self = self; this.serverIdent = serverIdent; @@ -109,7 +104,6 @@ public class CreateGroup implements RestModifyView this.addMembers = addMembers; this.systemGroupBackend = systemGroupBackend; this.defaultVisibleToAll = cfg.getBoolean("groups", "newGroupsVisibleToAll", false); - this.name = name; this.sequences = sequences; } @@ -124,10 +118,11 @@ public class CreateGroup implements RestModifyView } @Override - public GroupInfo apply(TopLevelResource resource, GroupInput input) + public GroupInfo apply(TopLevelResource resource, IdString id, GroupInput input) throws AuthException, BadRequestException, UnprocessableEntityException, ResourceConflictException, OrmException, IOException, ConfigInvalidException, ResourceNotFoundException { + String name = id.get(); if (input == null) { input = new GroupInput(); } diff --git a/java/com/google/gerrit/server/restapi/group/GroupsCollection.java b/java/com/google/gerrit/server/restapi/group/GroupsCollection.java index fba1f1fbf4..40a11c7e38 100644 --- a/java/com/google/gerrit/server/restapi/group/GroupsCollection.java +++ b/java/com/google/gerrit/server/restapi/group/GroupsCollection.java @@ -18,13 +18,11 @@ import com.google.common.collect.ListMultimap; import com.google.gerrit.common.data.GroupDescription; import com.google.gerrit.common.data.GroupReference; 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.BadRequestException; import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.NeedsParams; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; -import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestCollection; import com.google.gerrit.extensions.restapi.RestView; import com.google.gerrit.extensions.restapi.TopLevelResource; @@ -44,13 +42,10 @@ import com.google.inject.Provider; import java.util.Optional; public class GroupsCollection - implements RestCollection, - AcceptsCreate, - NeedsParams { + implements RestCollection, NeedsParams { private final DynamicMap> views; private final Provider list; private final Provider queryGroups; - private final CreateGroup.Factory createGroup; private final GroupControl.Factory groupControlFactory; private final GroupBackend groupBackend; private final GroupCache groupCache; @@ -63,7 +58,6 @@ public class GroupsCollection DynamicMap> views, Provider list, Provider queryGroups, - CreateGroup.Factory createGroup, GroupControl.Factory groupControlFactory, GroupBackend groupBackend, GroupCache groupCache, @@ -71,7 +65,6 @@ public class GroupsCollection this.views = views; this.list = list; this.queryGroups = queryGroups; - this.createGroup = createGroup; this.groupControlFactory = groupControlFactory; this.groupBackend = groupBackend; this.groupCache = groupCache; @@ -199,11 +192,6 @@ public class GroupsCollection return null; } - @Override - public CreateGroup create(TopLevelResource root, IdString name) throws RestApiException { - return createGroup.create(name.get()); - } - @Override public DynamicMap> views() { return views; diff --git a/java/com/google/gerrit/server/restapi/group/MembersCollection.java b/java/com/google/gerrit/server/restapi/group/MembersCollection.java index cf2e0b8338..fec14436fe 100644 --- a/java/com/google/gerrit/server/restapi/group/MembersCollection.java +++ b/java/com/google/gerrit/server/restapi/group/MembersCollection.java @@ -16,7 +16,6 @@ package com.google.gerrit.server.restapi.group; import com.google.gerrit.common.data.GroupDescription; 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.ChildCollection; import com.google.gerrit.extensions.restapi.IdString; @@ -27,7 +26,6 @@ import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.group.GroupResource; import com.google.gerrit.server.group.MemberResource; import com.google.gerrit.server.restapi.account.AccountsCollection; -import com.google.gerrit.server.restapi.group.AddMembers.PutMember; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Provider; @@ -36,23 +34,19 @@ import java.io.IOException; import org.eclipse.jgit.errors.ConfigInvalidException; @Singleton -public class MembersCollection - implements ChildCollection, AcceptsCreate { +public class MembersCollection implements ChildCollection { private final DynamicMap> views; private final Provider list; private final AccountsCollection accounts; - private final AddMembers put; @Inject MembersCollection( DynamicMap> views, Provider list, - AccountsCollection accounts, - AddMembers put) { + AccountsCollection accounts) { this.views = views; this.list = list; this.accounts = accounts; - this.put = put; } @Override @@ -78,11 +72,6 @@ public class MembersCollection return group.getMembers().contains(user.getAccountId()); } - @Override - public PutMember create(GroupResource group, IdString id) { - return new PutMember(put, id.get()); - } - @Override public DynamicMap> views() { return views; diff --git a/java/com/google/gerrit/server/restapi/group/Module.java b/java/com/google/gerrit/server/restapi/group/Module.java index fa1e5c7796..741c3da774 100644 --- a/java/com/google/gerrit/server/restapi/group/Module.java +++ b/java/com/google/gerrit/server/restapi/group/Module.java @@ -24,7 +24,9 @@ import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.ServerInitiated; import com.google.gerrit.server.UserInitiated; import com.google.gerrit.server.group.db.GroupsUpdate; +import com.google.gerrit.server.restapi.group.AddMembers.CreateMember; import com.google.gerrit.server.restapi.group.AddMembers.UpdateMember; +import com.google.gerrit.server.restapi.group.AddSubgroups.CreateSubgroup; import com.google.gerrit.server.restapi.group.AddSubgroups.UpdateSubgroup; import com.google.gerrit.server.restapi.group.DeleteMembers.DeleteMember; import com.google.gerrit.server.restapi.group.DeleteSubgroups.DeleteSubgroup; @@ -40,6 +42,7 @@ public class Module extends RestApiModule { DynamicMap.mapOf(binder(), MEMBER_KIND); DynamicMap.mapOf(binder(), SUBGROUP_KIND); + create(GROUP_KIND).to(CreateGroup.class); get(GROUP_KIND).to(GetGroup.class); put(GROUP_KIND).to(PutGroup.class); get(GROUP_KIND, "detail").to(GetDetail.class); @@ -62,16 +65,17 @@ public class Module extends RestApiModule { get(GROUP_KIND, "log.audit").to(GetAuditLog.class); child(GROUP_KIND, "members").to(MembersCollection.class); + create(MEMBER_KIND).to(CreateMember.class); get(MEMBER_KIND).to(GetMember.class); put(MEMBER_KIND).to(UpdateMember.class); delete(MEMBER_KIND).to(DeleteMember.class); child(GROUP_KIND, "groups").to(SubgroupsCollection.class); + create(SUBGROUP_KIND).to(CreateSubgroup.class); get(SUBGROUP_KIND).to(GetSubgroup.class); put(SUBGROUP_KIND).to(UpdateSubgroup.class); delete(SUBGROUP_KIND).to(DeleteSubgroup.class); - factory(CreateGroup.Factory.class); factory(GroupsUpdate.Factory.class); } diff --git a/java/com/google/gerrit/server/restapi/group/SubgroupsCollection.java b/java/com/google/gerrit/server/restapi/group/SubgroupsCollection.java index 83520f17a7..cebc27a407 100644 --- a/java/com/google/gerrit/server/restapi/group/SubgroupsCollection.java +++ b/java/com/google/gerrit/server/restapi/group/SubgroupsCollection.java @@ -16,7 +16,6 @@ package com.google.gerrit.server.restapi.group; import com.google.gerrit.common.data.GroupDescription; 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.ChildCollection; import com.google.gerrit.extensions.restapi.IdString; @@ -25,28 +24,23 @@ import com.google.gerrit.extensions.restapi.RestView; import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.server.group.GroupResource; import com.google.gerrit.server.group.SubgroupResource; -import com.google.gerrit.server.restapi.group.AddSubgroups.PutSubgroup; import com.google.inject.Inject; import com.google.inject.Singleton; @Singleton -public class SubgroupsCollection - implements ChildCollection, AcceptsCreate { +public class SubgroupsCollection implements ChildCollection { private final DynamicMap> views; private final ListSubgroups list; private final GroupsCollection groupsCollection; - private final AddSubgroups addSubgroups; @Inject SubgroupsCollection( DynamicMap> views, ListSubgroups list, - GroupsCollection groupsCollection, - AddSubgroups addSubgroups) { + GroupsCollection groupsCollection) { this.views = views; this.list = list; this.groupsCollection = groupsCollection; - this.addSubgroups = addSubgroups; } @Override @@ -73,11 +67,6 @@ public class SubgroupsCollection return parent.getSubgroups().contains(member.getGroupUUID()); } - @Override - public PutSubgroup create(GroupResource group, IdString id) { - return new PutSubgroup(addSubgroups, id.get()); - } - @Override public DynamicMap> views() { return views; diff --git a/java/com/google/gerrit/server/restapi/project/BranchesCollection.java b/java/com/google/gerrit/server/restapi/project/BranchesCollection.java index f8ff7b9f8b..389cc2f1a2 100644 --- a/java/com/google/gerrit/server/restapi/project/BranchesCollection.java +++ b/java/com/google/gerrit/server/restapi/project/BranchesCollection.java @@ -15,7 +15,6 @@ package com.google.gerrit.server.restapi.project; 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.ChildCollection; import com.google.gerrit.extensions.restapi.IdString; @@ -39,26 +38,22 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; @Singleton -public class BranchesCollection - implements ChildCollection, AcceptsCreate { +public class BranchesCollection implements ChildCollection { private final DynamicMap> views; private final Provider list; private final PermissionBackend permissionBackend; private final GitRepositoryManager repoManager; - private final CreateBranch.Factory createBranchFactory; @Inject BranchesCollection( DynamicMap> views, Provider list, PermissionBackend permissionBackend, - GitRepositoryManager repoManager, - CreateBranch.Factory createBranchFactory) { + GitRepositoryManager repoManager) { this.views = views; this.list = list; this.permissionBackend = permissionBackend; this.repoManager = repoManager; - this.createBranchFactory = createBranchFactory; } @Override @@ -98,9 +93,4 @@ public class BranchesCollection public DynamicMap> views() { return views; } - - @Override - public CreateBranch create(ProjectResource parent, IdString name) { - return createBranchFactory.create(name.get()); - } } diff --git a/java/com/google/gerrit/server/restapi/project/CreateBranch.java b/java/com/google/gerrit/server/restapi/project/CreateBranch.java index 0296c9c4e6..4c7b27a06c 100644 --- a/java/com/google/gerrit/server/restapi/project/CreateBranch.java +++ b/java/com/google/gerrit/server/restapi/project/CreateBranch.java @@ -21,8 +21,9 @@ import com.google.gerrit.extensions.api.projects.BranchInfo; import com.google.gerrit.extensions.api.projects.BranchInput; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.ResourceConflictException; -import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.server.IdentifiedUser; @@ -31,6 +32,7 @@ import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.permissions.PermissionBackend; import com.google.gerrit.server.permissions.PermissionBackendException; import com.google.gerrit.server.permissions.RefPermission; +import com.google.gerrit.server.project.BranchResource; import com.google.gerrit.server.project.CreateRefControl; import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.ProjectResource; @@ -39,7 +41,6 @@ import com.google.gerrit.server.project.RefValidationHelper; import com.google.gerrit.server.util.MagicBranch; import com.google.inject.Inject; import com.google.inject.Provider; -import com.google.inject.assistedinject.Assisted; import java.io.IOException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.lib.Constants; @@ -50,20 +51,15 @@ import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.ReceiveCommand; -public class CreateBranch implements RestModifyView { +public class CreateBranch implements RestCreateView { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - public interface Factory { - CreateBranch create(String ref); - } - private final Provider identifiedUser; private final PermissionBackend permissionBackend; private final GitRepositoryManager repoManager; private final GitReferenceUpdated referenceUpdated; private final RefValidationHelper refCreationValidator; private final CreateRefControl createRefControl; - private String ref; @Inject CreateBranch( @@ -72,21 +68,20 @@ public class CreateBranch implements RestModifyView { + private final Provider setDefault; + + @Option(name = "--inherited", usage = "set dashboard inherited by children") + private boolean inherited; + + @Inject + CreateDashboard(Provider setDefault) { + this.setDefault = setDefault; + } + + @Override + public Response apply(ProjectResource parent, IdString id, SetDashboardInput input) + throws RestApiException, IOException, PermissionBackendException { + parent.getProjectState().checkStatePermitsWrite(); + if (!DashboardsCollection.isDefaultDashboard(id)) { + throw new ResourceNotFoundException(id); + } + SetDefaultDashboard set = setDefault.get(); + set.inherited = inherited; + return set.apply( + DashboardResource.projectDefault(parent.getProjectState(), parent.getUser()), input); + } +} diff --git a/java/com/google/gerrit/server/restapi/project/CreateProject.java b/java/com/google/gerrit/server/restapi/project/CreateProject.java index 3a9a0e7659..09fd91442f 100644 --- a/java/com/google/gerrit/server/restapi/project/CreateProject.java +++ b/java/com/google/gerrit/server/restapi/project/CreateProject.java @@ -37,10 +37,11 @@ import com.google.gerrit.extensions.events.NewProjectCreatedListener; import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.RestApiException; -import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.BooleanProjectConfig; @@ -64,13 +65,13 @@ import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectConfig; import com.google.gerrit.server.project.ProjectJson; import com.google.gerrit.server.project.ProjectNameLockManager; +import com.google.gerrit.server.project.ProjectResource; import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.restapi.group.GroupsCollection; import com.google.gerrit.server.validators.ProjectCreationValidationListener; import com.google.gerrit.server.validators.ValidationException; import com.google.inject.Inject; import com.google.inject.Provider; -import com.google.inject.assistedinject.Assisted; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -89,13 +90,10 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.ReceiveCommand; @RequiresCapability(GlobalCapability.CREATE_PROJECT) -public class CreateProject implements RestModifyView { +public class CreateProject + implements RestCreateView { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - public interface Factory { - CreateProject create(String name); - } - private final Provider projectsCollection; private final Provider groupsCollection; private final DynamicSet projectCreationValidationListeners; @@ -114,7 +112,6 @@ public class CreateProject implements RestModifyView lockManager; - private final String name; @Inject CreateProject( @@ -135,8 +132,7 @@ public class CreateProject implements RestModifyView putConfig, AllProjectsName allProjects, AllUsersName allUsers, - DynamicItem lockManager, - @Assisted String name) { + DynamicItem lockManager) { this.projectsCollection = projectsCollection; this.groupsCollection = groupsCollection; this.projectCreationValidationListeners = projectCreationValidationListeners; @@ -155,12 +151,12 @@ public class CreateProject implements RestModifyView apply(TopLevelResource resource, ProjectInput input) + public Response apply(TopLevelResource resource, IdString id, ProjectInput input) throws RestApiException, IOException, ConfigInvalidException, PermissionBackendException { + String name = id.get(); if (input == null) { input = new ProjectInput(); } diff --git a/java/com/google/gerrit/server/restapi/project/CreateTag.java b/java/com/google/gerrit/server/restapi/project/CreateTag.java index b09d8706b4..b2fdff28be 100644 --- a/java/com/google/gerrit/server/restapi/project/CreateTag.java +++ b/java/com/google/gerrit/server/restapi/project/CreateTag.java @@ -23,10 +23,11 @@ import com.google.gerrit.extensions.api.projects.TagInfo; import com.google.gerrit.extensions.api.projects.TagInput; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.MethodNotAllowedException; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.RestApiException; -import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.restapi.RestCreateView; import com.google.gerrit.server.WebLinks; import com.google.gerrit.server.extensions.events.GitReferenceUpdated; import com.google.gerrit.server.git.GitRepositoryManager; @@ -38,8 +39,8 @@ import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.ProjectResource; import com.google.gerrit.server.project.RefUtil; import com.google.gerrit.server.project.RefUtil.InvalidRevisionException; +import com.google.gerrit.server.project.TagResource; import com.google.inject.Inject; -import com.google.inject.assistedinject.Assisted; import java.io.IOException; import java.util.TimeZone; import org.eclipse.jgit.api.Git; @@ -52,19 +53,13 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; -public class CreateTag implements RestModifyView { +public class CreateTag implements RestCreateView { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - - public interface Factory { - CreateTag create(String ref); - } - private final PermissionBackend permissionBackend; private final GitRepositoryManager repoManager; private final TagCache tagCache; private final GitReferenceUpdated referenceUpdated; private final WebLinks links; - private String ref; @Inject CreateTag( @@ -72,19 +67,18 @@ public class CreateTag implements RestModifyView { GitRepositoryManager repoManager, TagCache tagCache, GitReferenceUpdated referenceUpdated, - WebLinks webLinks, - @Assisted String ref) { + WebLinks webLinks) { this.permissionBackend = permissionBackend; this.repoManager = repoManager; this.tagCache = tagCache; this.referenceUpdated = referenceUpdated; this.links = webLinks; - this.ref = ref; } @Override - public TagInfo apply(ProjectResource resource, TagInput input) + public TagInfo apply(ProjectResource resource, IdString id, TagInput input) throws RestApiException, IOException, PermissionBackendException, NoSuchProjectException { + String ref = id.get(); if (input == null) { input = new TagInput(); } diff --git a/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java b/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java index b7589cfe0a..07691e7251 100644 --- a/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java +++ b/java/com/google/gerrit/server/restapi/project/DashboardsCollection.java @@ -25,14 +25,12 @@ import com.google.gerrit.common.Nullable; import com.google.gerrit.extensions.api.projects.DashboardInfo; import com.google.gerrit.extensions.api.projects.DashboardSectionInfo; 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.ChildCollection; import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.RestApiException; -import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.RestView; import com.google.gerrit.extensions.restapi.Url; import com.google.gerrit.reviewdb.client.Project; @@ -60,14 +58,12 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; @Singleton -public class DashboardsCollection - implements ChildCollection, AcceptsCreate { +public class DashboardsCollection implements ChildCollection { public static final String DEFAULT_DASHBOARD_NAME = "default"; private final GitRepositoryManager gitManager; private final DynamicMap> views; private final Provider list; - private final Provider createDefault; private final PermissionBackend permissionBackend; @Inject @@ -75,12 +71,10 @@ public class DashboardsCollection GitRepositoryManager gitManager, DynamicMap> views, Provider list, - Provider createDefault, PermissionBackend permissionBackend) { this.gitManager = gitManager; this.views = views; this.list = list; - this.createDefault = createDefault; this.permissionBackend = permissionBackend; } @@ -97,16 +91,6 @@ public class DashboardsCollection return list.get(); } - @Override - public RestModifyView create(ProjectResource parent, IdString id) - throws RestApiException { - parent.getProjectState().checkStatePermitsWrite(); - if (isDefaultDashboard(id)) { - return createDefault.get(); - } - throw new ResourceNotFoundException(id); - } - @Override public DashboardResource parse(ProjectResource parent, IdString id) throws RestApiException, IOException, ConfigInvalidException, PermissionBackendException { diff --git a/java/com/google/gerrit/server/restapi/project/Module.java b/java/com/google/gerrit/server/restapi/project/Module.java index 17a675d618..d2e59cd783 100644 --- a/java/com/google/gerrit/server/restapi/project/Module.java +++ b/java/com/google/gerrit/server/restapi/project/Module.java @@ -41,6 +41,7 @@ public class Module extends RestApiModule { DynamicMap.mapOf(binder(), COMMIT_KIND); DynamicMap.mapOf(binder(), TAG_KIND); + create(PROJECT_KIND).to(CreateProject.class); put(PROJECT_KIND).to(PutProject.class); get(PROJECT_KIND).to(GetProject.class); get(PROJECT_KIND, "description").to(GetDescription.class); @@ -69,11 +70,11 @@ public class Module extends RestApiModule { post(PROJECT_KIND, "index").to(Index.class); child(PROJECT_KIND, "branches").to(BranchesCollection.class); + create(BRANCH_KIND).to(CreateBranch.class); put(BRANCH_KIND).to(PutBranch.class); get(BRANCH_KIND).to(GetBranch.class); delete(BRANCH_KIND).to(DeleteBranch.class); post(PROJECT_KIND, "branches:delete").to(DeleteBranches.class); - factory(CreateBranch.Factory.class); get(BRANCH_KIND, "mergeable").to(CheckMergeability.class); factory(RefValidationHelper.Factory.class); get(BRANCH_KIND, "reflog").to(GetReflog.class); @@ -86,17 +87,17 @@ public class Module extends RestApiModule { child(COMMIT_KIND, "files").to(FilesInCommitCollection.class); child(PROJECT_KIND, "tags").to(TagsCollection.class); + create(TAG_KIND).to(CreateTag.class); get(TAG_KIND).to(GetTag.class); put(TAG_KIND).to(PutTag.class); delete(TAG_KIND).to(DeleteTag.class); post(PROJECT_KIND, "tags:delete").to(DeleteTags.class); - factory(CreateTag.Factory.class); child(PROJECT_KIND, "dashboards").to(DashboardsCollection.class); + create(DASHBOARD_KIND).to(CreateDashboard.class); get(DASHBOARD_KIND).to(GetDashboard.class); put(DASHBOARD_KIND).to(SetDashboard.class); delete(DASHBOARD_KIND).to(DeleteDashboard.class); - factory(CreateProject.Factory.class); get(PROJECT_KIND, "config").to(GetConfig.class); put(PROJECT_KIND, "config").to(PutConfig.class); diff --git a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java index 1ba993cce5..dafc2fab6f 100644 --- a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java +++ b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java @@ -17,7 +17,6 @@ package com.google.gerrit.server.restapi.project; import com.google.common.collect.ListMultimap; import com.google.gerrit.common.Nullable; 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.BadRequestException; import com.google.gerrit.extensions.restapi.IdString; @@ -46,16 +45,13 @@ import org.eclipse.jgit.lib.Constants; @Singleton public class ProjectsCollection - implements RestCollection, - AcceptsCreate, - NeedsParams { + implements RestCollection, NeedsParams { private final DynamicMap> views; private final Provider list; private final Provider queryProjects; private final ProjectCache projectCache; private final PermissionBackend permissionBackend; private final Provider user; - private final CreateProject.Factory createProjectFactory; private boolean hasQuery; @@ -66,7 +62,6 @@ public class ProjectsCollection Provider queryProjects, ProjectCache projectCache, PermissionBackend permissionBackend, - CreateProject.Factory factory, Provider user) { this.views = views; this.list = list; @@ -74,7 +69,6 @@ public class ProjectsCollection this.projectCache = projectCache; this.permissionBackend = permissionBackend; this.user = user; - this.createProjectFactory = factory; } @Override @@ -179,9 +173,4 @@ public class ProjectsCollection public DynamicMap> views() { return views; } - - @Override - public CreateProject create(TopLevelResource parent, IdString name) throws RestApiException { - return createProjectFactory.create(name.get()); - } } diff --git a/java/com/google/gerrit/server/restapi/project/SetDefaultDashboard.java b/java/com/google/gerrit/server/restapi/project/SetDefaultDashboard.java index ba91e0ef3b..68fef53425 100644 --- a/java/com/google/gerrit/server/restapi/project/SetDefaultDashboard.java +++ b/java/com/google/gerrit/server/restapi/project/SetDefaultDashboard.java @@ -49,7 +49,7 @@ class SetDefaultDashboard implements RestModifyView { - private final Provider setDefault; - - @Option(name = "--inherited", usage = "set dashboard inherited by children") - private boolean inherited; - - @Inject - CreateDefault(Provider setDefault) { - this.setDefault = setDefault; - } - - @Override - public Response apply(ProjectResource resource, SetDashboardInput input) - throws RestApiException, IOException, PermissionBackendException { - SetDefaultDashboard set = setDefault.get(); - set.inherited = inherited; - return set.apply( - DashboardResource.projectDefault(resource.getProjectState(), resource.getUser()), input); - } - } } diff --git a/java/com/google/gerrit/server/restapi/project/TagsCollection.java b/java/com/google/gerrit/server/restapi/project/TagsCollection.java index fdace77afd..a129bda834 100644 --- a/java/com/google/gerrit/server/restapi/project/TagsCollection.java +++ b/java/com/google/gerrit/server/restapi/project/TagsCollection.java @@ -15,7 +15,6 @@ package com.google.gerrit.server.restapi.project; import com.google.gerrit.extensions.registration.DynamicMap; -import com.google.gerrit.extensions.restapi.AcceptsCreate; import com.google.gerrit.extensions.restapi.ChildCollection; import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; @@ -30,20 +29,14 @@ import com.google.inject.Singleton; import java.io.IOException; @Singleton -public class TagsCollection - implements ChildCollection, AcceptsCreate { +public class TagsCollection implements ChildCollection { private final DynamicMap> views; private final Provider list; - private final CreateTag.Factory createTagFactory; @Inject - public TagsCollection( - DynamicMap> views, - Provider list, - CreateTag.Factory createTagFactory) { + public TagsCollection(DynamicMap> views, Provider list) { this.views = views; this.list = list; - this.createTagFactory = createTagFactory; } @Override @@ -62,9 +55,4 @@ public class TagsCollection public DynamicMap> views() { return views; } - - @Override - public CreateTag create(ProjectResource resource, IdString name) { - return createTagFactory.create(name.get()); - } } diff --git a/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java b/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java index 9dc9a50008..c83660d252 100644 --- a/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java +++ b/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java @@ -20,6 +20,7 @@ import com.google.common.collect.Lists; import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.extensions.annotations.RequiresCapability; import com.google.gerrit.extensions.api.accounts.AccountInput; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.reviewdb.client.AccountGroup; @@ -66,7 +67,7 @@ final class CreateAccountCommand extends SshCommand { @Argument(index = 0, required = true, metaVar = "USERNAME", usage = "name of the user account") private String username; - @Inject private CreateAccount.Factory createAccountFactory; + @Inject private CreateAccount createAccount; @Override protected void run() throws OrmException, IOException, ConfigInvalidException, UnloggedFailure { @@ -78,7 +79,7 @@ final class CreateAccountCommand extends SshCommand { input.httpPassword = httpPassword; input.groups = Lists.transform(groups, AccountGroup.Id::toString); try { - createAccountFactory.create(username).apply(TopLevelResource.INSTANCE, input); + createAccount.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(username), input); } catch (RestApiException e) { throw die(e.getMessage()); } diff --git a/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java b/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java index 5a83b01318..03f9616e4d 100644 --- a/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java +++ b/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java @@ -91,7 +91,7 @@ final class CreateGroupCommand extends SshCommand { initialGroups.add(id); } - @Inject private CreateGroup.Factory createGroupFactory; + @Inject private CreateGroup createGroup; @Inject private GroupsCollection groups; @@ -126,7 +126,8 @@ final class CreateGroupCommand extends SshCommand { input.ownerId = String.valueOf(ownerGroupId.get()); } - GroupInfo group = createGroupFactory.create(groupName).apply(TopLevelResource.INSTANCE, input); + GroupInfo group = + createGroup.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(groupName), input); return groups.parse(TopLevelResource.INSTANCE, IdString.fromUrl(group.id)); } diff --git a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java index 379fc6864a..852969f9df 100644 --- a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java +++ b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java @@ -29,6 +29,7 @@ import com.google.gerrit.extensions.common.Input; import com.google.gerrit.extensions.common.NameInput; import com.google.gerrit.extensions.common.SshKeyInfo; 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.RestApiException; import com.google.gerrit.reviewdb.client.Account; @@ -119,7 +120,7 @@ final class SetAccountCommand extends SshCommand { @Inject private IdentifiedUser.GenericFactory genericUserFactory; - @Inject private CreateEmail.Factory createEmailFactory; + @Inject private CreateEmail createEmail; @Inject private GetEmails getEmails; @@ -269,7 +270,7 @@ final class SetAccountCommand extends SshCommand { in.email = email; in.noConfirmation = true; try { - createEmailFactory.create(email).apply(rsrc, in); + createEmail.apply(rsrc, IdString.fromDecoded(email), in); } catch (EmailException e) { throw die(e.getMessage()); } diff --git a/javatests/com/google/gerrit/acceptance/rest/account/CreateAccountIT.java b/javatests/com/google/gerrit/acceptance/rest/account/CreateAccountIT.java new file mode 100644 index 0000000000..aca6c4cbac --- /dev/null +++ b/javatests/com/google/gerrit/acceptance/rest/account/CreateAccountIT.java @@ -0,0 +1,34 @@ +// Copyright (C) 2018 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.acceptance.rest.account; + +import static com.google.common.truth.Truth8.assertThat; + +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.RestResponse; +import com.google.gerrit.extensions.api.accounts.AccountInput; +import org.junit.Test; + +public class CreateAccountIT extends AbstractDaemonTest { + @Test + public void createAccountRestApi() throws Exception { + AccountInput input = new AccountInput(); + input.username = "foo"; + assertThat(accountCache.getByUsername(input.username)).isEmpty(); + RestResponse r = adminRestSession.put("/accounts/" + input.username, input); + r.assertCreated(); + assertThat(accountCache.getByUsername(input.username)).isPresent(); + } +} diff --git a/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java b/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java index 7657e2e47a..4d499f0c4a 100644 --- a/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java +++ b/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java @@ -29,6 +29,7 @@ import com.google.gerrit.extensions.api.changes.ReviewInput; import com.google.gerrit.extensions.common.ChangeInput; import com.google.gerrit.extensions.common.GroupInfo; import com.google.gerrit.extensions.common.SuggestedReviewerInfo; +import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.reviewdb.client.AccountGroup; @@ -42,7 +43,7 @@ import org.junit.Before; import org.junit.Test; public class SuggestReviewersIT extends AbstractDaemonTest { - @Inject private CreateGroup.Factory createGroupFactory; + @Inject private CreateGroup createGroup; private InternalGroup group1; private InternalGroup group2; @@ -490,7 +491,8 @@ public class SuggestReviewersIT extends AbstractDaemonTest { } private InternalGroup newGroup(String name) throws Exception { - GroupInfo group = createGroupFactory.create(name(name)).apply(TopLevelResource.INSTANCE, null); + GroupInfo group = + createGroup.apply(TopLevelResource.INSTANCE, IdString.fromDecoded(name(name)), null); return group(new AccountGroup.UUID(group.id)); } diff --git a/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java b/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java index 48dc99488b..0b7758eead 100644 --- a/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java +++ b/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java @@ -15,12 +15,14 @@ package com.google.gerrit.acceptance.rest.project; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth8.assertThat; +import static com.google.gerrit.reviewdb.client.RefNames.REFS_HEADS; import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS; import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; import com.google.gerrit.acceptance.AbstractDaemonTest; import com.google.gerrit.acceptance.GerritConfig; -import com.google.gerrit.acceptance.NoHttpd; +import com.google.gerrit.acceptance.RestResponse; import com.google.gerrit.common.data.Permission; import com.google.gerrit.extensions.api.projects.BranchApi; import com.google.gerrit.extensions.api.projects.BranchInfo; @@ -35,7 +37,6 @@ import com.google.gerrit.reviewdb.client.RefNames; import org.junit.Before; import org.junit.Test; -@NoHttpd public class CreateBranchIT extends AbstractDaemonTest { private Branch.NameKey testBranch; @@ -44,6 +45,19 @@ public class CreateBranchIT extends AbstractDaemonTest { testBranch = new Branch.NameKey(project, "test"); } + @Test + public void createBranchRestApi() throws Exception { + BranchInput input = new BranchInput(); + input.ref = "foo"; + assertThat(gApi.projects().name(project.get()).branches().get().stream().map(i -> i.ref)) + .doesNotContain(REFS_HEADS + input.ref); + RestResponse r = + adminRestSession.put("/projects/" + project.get() + "/branches/" + input.ref, input); + r.assertCreated(); + assertThat(gApi.projects().name(project.get()).branches().get().stream().map(i -> i.ref)) + .contains(REFS_HEADS + input.ref); + } + @Test public void createBranch_Forbidden() throws Exception { setApiUser(user);