diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt index 8efff67342..2b44855f31 100644 --- a/Documentation/rest-api-accounts.txt +++ b/Documentation/rest-api-accounts.txt @@ -1874,6 +1874,71 @@ returned. The labels are lexicographically sorted. ] ---- +[[list-contributor-agreements]] +=== List Contributor Agreements +-- +'GET /accounts/link:#account-id[\{account-id\}]/agreements' +-- + +Gets a list of the user's signed contributor agreements. + +.Request +---- + GET /a/accounts/self/agreements HTTP/1.0 +---- + +As response the user's signed agreements are returned as a list +of link:#contributor-agreement-info[ContributorAgreementInfo] entities. + +.Response +---- + HTTP/1.1 200 OK + Content-Disposition: attachment + Content-Type: application/json; charset=UTF-8 + + )]}' + [ + { + "name": "Individual", + "description": "If you are going to be contributing code on your own, this is the one you want. You can sign this one online.", + "url": "static/cla_individual.html" + } + ] +---- + +[[sign-contributor-agreement]] +=== Sign Contributor Agreement +-- +'PUT /accounts/link:#account-id[\{account-id\}]/agreements' +-- + +Signs a contributor agreement. + +The contributor agreement must be provided in the request body as +a link:#contributor-agreement-input[ContributorAgreementInput]. + +.Request +---- + PUT /accounts/self/agreements HTTP/1.0 + Content-Type: application/json; charset=UTF-8 + + { + "name": "Individual" + } +---- + +As response the contributor agreement name is returned. + +.Response +---- + HTTP/1.1 200 OK + Content-Disposition: attachment + Content-Type: application/json; charset=UTF-8 + + )]}' + "Individual" +---- + [[ids]] == IDs @@ -2060,6 +2125,31 @@ link:access-control.html#capability_viewPlugins[View Plugins] capability. link:access-control.html#capability_viewQueue[View Queue] capability. |================================= +[[contributor-agreement-info]] +=== ContributorAgreementInfo + +The `ContributorAgreementInfo` entity contains information about a +contributor agreement. + +[options="header",cols="1,6"] +|================================= +|Field Name |Description +|`name` |The name of the agreement. +|`description` |The description of the agreement. +|`url` |The URL of the agreement. +|================================= + +[[contributor-agreement-input]] +=== ContributorAgreementInput +The `ContributorAgreementInput` entity contains information about a +new contributor agreement. + +[options="header",cols="1,6"] +|================================= +|Field Name |Description +|`name` |The name of the agreement. +|================================= + [[diff-preferences-info]] === DiffPreferencesInfo The `DiffPreferencesInfo` entity contains information about the diff diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java index 3608577d5b..ae480c767c 100644 --- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java +++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java @@ -309,6 +309,10 @@ public abstract class AbstractDaemonTest { return cfg.getBoolean("change", null, "submitWholeTopic", false); } + protected boolean isContributorAgreementsEnabled() { + return cfg.getBoolean("auth", null, "contributorAgreements", false); + } + protected void beforeTest(Description description) throws Exception { GerritServer.Description classDesc = GerritServer.Description.forTestClass(description, configName); diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java new file mode 100644 index 0000000000..f676c0f390 --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java @@ -0,0 +1,132 @@ +// Copyright (C) 2016 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.api.accounts; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.TruthJUnit.assume; + +import com.google.common.collect.ImmutableList; +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.common.data.ContributorAgreement; +import com.google.gerrit.common.data.GroupReference; +import com.google.gerrit.common.data.PermissionRule; +import com.google.gerrit.extensions.api.groups.GroupApi; +import com.google.gerrit.extensions.common.AgreementInfo; +import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.MethodNotAllowedException; +import com.google.gerrit.extensions.restapi.UnprocessableEntityException; +import com.google.gerrit.reviewdb.client.AccountGroup; +import com.google.gerrit.server.git.ProjectConfig; +import com.google.gerrit.testutil.ConfigSuite; + +import org.eclipse.jgit.lib.Config; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +public class AgreementsIT extends AbstractDaemonTest { + private ContributorAgreement ca; + private ContributorAgreement ca2; + + @ConfigSuite.Config + public static Config enableAgreementsConfig() { + Config cfg = new Config(); + cfg.setBoolean("auth", null, "contributorAgreements", true); + return cfg; + } + + @Before + public void setUp() throws Exception { + String g = createGroup("cla-test-group"); + GroupApi groupApi = gApi.groups().id(g); + groupApi.description("CLA test group"); + AccountGroup caGroup = groupCache.get( + new AccountGroup.UUID(groupApi.detail().id)); + GroupReference groupRef = GroupReference.forGroup(caGroup); + PermissionRule rule = new PermissionRule(groupRef); + rule.setAction(PermissionRule.Action.ALLOW); + ca = new ContributorAgreement("cla-test"); + ca.setDescription("description"); + ca.setAgreementUrl("agreement-url"); + ca.setAutoVerify(groupRef); + ca.setAccepted(ImmutableList.of(rule)); + + ca2 = new ContributorAgreement("cla-test-no-auto-verify"); + ca2.setDescription("description"); + ca2.setAgreementUrl("agreement-url"); + + ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig(); + cfg.replace(ca); + cfg.replace(ca2); + saveProjectConfig(allProjects, cfg); + setApiUser(user); + } + + @Test + public void signNonExistingAgreement() throws Exception { + assume().that(isContributorAgreementsEnabled()).isTrue(); + exception.expect(UnprocessableEntityException.class); + exception.expectMessage("contributor agreement not found"); + gApi.accounts().self().signAgreement("does-not-exist"); + } + + @Test + public void signAgreementNoAutoVerify() throws Exception { + assume().that(isContributorAgreementsEnabled()).isTrue(); + exception.expect(BadRequestException.class); + exception.expectMessage("cannot enter a non-autoVerify agreement"); + gApi.accounts().self().signAgreement(ca2.getName()); + } + + @Test + public void signAgreement() throws Exception { + assume().that(isContributorAgreementsEnabled()).isTrue(); + + // List of agreements is initially empty + List result = gApi.accounts().self().listAgreements(); + assertThat(result).isEmpty(); + + // Sign the agreement + gApi.accounts().self().signAgreement(ca.getName()); + result = gApi.accounts().self().listAgreements(); + assertThat(result).hasSize(1); + AgreementInfo info = result.get(0); + assertThat(info.name).isEqualTo(ca.getName()); + assertThat(info.description).isEqualTo(ca.getDescription()); + assertThat(info.url).isEqualTo(ca.getAgreementUrl()); + + // Signing the same agreement again has no effect + gApi.accounts().self().signAgreement(ca.getName()); + result = gApi.accounts().self().listAgreements(); + assertThat(result).hasSize(1); + } + + @Test + public void agreementsDisabledSign() throws Exception { + assume().that(isContributorAgreementsEnabled()).isFalse(); + exception.expect(MethodNotAllowedException.class); + exception.expectMessage("contributor agreements disabled"); + gApi.accounts().self().signAgreement(ca.getName()); + } + + @Test + public void agreementsDisabledList() throws Exception { + assume().that(isContributorAgreementsEnabled()).isFalse(); + exception.expect(MethodNotAllowedException.class); + exception.expectMessage("contributor agreements disabled"); + gApi.accounts().self().listAgreements(); + } +} diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java index 6ea77efaba..c1cb3ec2a8 100644 --- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java @@ -20,6 +20,7 @@ import com.google.gerrit.extensions.client.EditPreferencesInfo; import com.google.gerrit.extensions.client.GeneralPreferencesInfo; import com.google.gerrit.extensions.client.ProjectWatchInfo; import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.AgreementInfo; import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.GpgKeyInfo; import com.google.gerrit.extensions.common.SshKeyInfo; @@ -70,6 +71,9 @@ public interface AccountApi { throws RestApiException; GpgKeyApi gpgKey(String id) throws RestApiException; + List listAgreements() throws RestApiException; + void signAgreement(String agreementName) throws RestApiException; + /** * A default implementation which allows source compatibility * when adding new methods to the interface. @@ -197,5 +201,15 @@ public interface AccountApi { public Map listGpgKeys() throws RestApiException { throw new NotImplementedException(); } + + @Override + public List listAgreements() throws RestApiException { + throw new NotImplementedException(); + } + + @Override + public void signAgreement(String agreementName) throws RestApiException { + throw new NotImplementedException(); + } } } diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AgreementInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AgreementInfo.java new file mode 100644 index 0000000000..6ec5b1dd4b --- /dev/null +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AgreementInfo.java @@ -0,0 +1,21 @@ +// Copyright (C) 2016 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.common; + +public class AgreementInfo { + public String name; + public String description; + public String url; +} diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AgreementInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AgreementInput.java new file mode 100644 index 0000000000..060367be17 --- /dev/null +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AgreementInput.java @@ -0,0 +1,24 @@ +// Copyright (C) 2016 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.common; + +import com.google.gerrit.extensions.restapi.DefaultInput; + +/** This entity contains information for registering a new contributor agreement. */ +public class AgreementInput { + /* The agreement name. */ + @DefaultInput + public String name; +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAgreements.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAgreements.java new file mode 100644 index 0000000000..f9e18c58d3 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAgreements.java @@ -0,0 +1,103 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.account; + +import com.google.gerrit.common.data.ContributorAgreement; +import com.google.gerrit.common.data.PermissionRule; +import com.google.gerrit.common.data.PermissionRule.Action; +import com.google.gerrit.extensions.common.AgreementInfo; +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.MethodNotAllowedException; +import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.extensions.restapi.RestReadView; +import com.google.gerrit.reviewdb.client.AccountGroup; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.config.GerritServerConfig; +import com.google.gerrit.server.project.ProjectCache; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import org.eclipse.jgit.lib.Config; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@Singleton +public class GetAgreements implements RestReadView { + private static final Logger log = + LoggerFactory.getLogger(GetAgreements.class); + + private final Provider self; + private final ProjectCache projectCache; + private final IdentifiedUser.GenericFactory identifiedUserFactory; + private final boolean agreementsEnabled; + + @Inject + GetAgreements(Provider self, + ProjectCache projectCache, + IdentifiedUser.GenericFactory identifiedUserFactory, + @GerritServerConfig Config config) { + this.self = self; + this.projectCache = projectCache; + this.identifiedUserFactory = identifiedUserFactory; + this.agreementsEnabled = + config.getBoolean("auth", "contributorAgreements", false); + } + + @Override + public List apply(AccountResource resource) + throws RestApiException { + if (!agreementsEnabled) { + throw new MethodNotAllowedException("contributor agreements disabled"); + } + + if (self.get() != resource.getUser()) { + throw new AuthException("not allowed to get contributor agreements"); + } + + IdentifiedUser user = + identifiedUserFactory.create(self.get().getAccountId()); + + List results = new ArrayList<>(); + Collection cas = + projectCache.getAllProjects().getConfig().getContributorAgreements(); + for (ContributorAgreement ca : cas) { + List groupIds = new ArrayList<>(); + for (PermissionRule rule : ca.getAccepted()) { + if ((rule.getAction() == Action.ALLOW) && (rule.getGroup() != null)) { + if (rule.getGroup().getUUID() != null) { + groupIds.add(rule.getGroup().getUUID()); + } else { + log.warn("group \"" + rule.getGroup().getName() + "\" does not " + + " exist, referenced in CLA \"" + ca.getName() + "\""); + } + } + } + + if (user.getEffectiveGroups().containsAnyOf(groupIds)) { + AgreementInfo info = new AgreementInfo(); + info.name = ca.getName(); + info.description = ca.getDescription(); + info.url = ca.getAgreementUrl(); + results.add(info); + } + } + return results; + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java index 9604322cf4..5b4a2004d1 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java @@ -82,6 +82,9 @@ public class Module extends RestApiModule { put(ACCOUNT_KIND, "preferences.edit").to(SetEditPreferences.class); get(CAPABILITY_KIND).to(GetCapabilities.CheckOne.class); + get(ACCOUNT_KIND, "agreements").to(GetAgreements.class); + put(ACCOUNT_KIND, "agreements").to(PutAgreement.class); + child(ACCOUNT_KIND, "starred.changes").to(StarredChanges.class); put(STARRED_CHANGE_KIND).to(StarredChanges.Put.class); delete(STARRED_CHANGE_KIND).to(StarredChanges.Delete.class); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAgreement.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAgreement.java new file mode 100644 index 0000000000..d0f8ffdbea --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAgreement.java @@ -0,0 +1,108 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.account; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.gerrit.common.data.ContributorAgreement; +import com.google.gerrit.extensions.common.AgreementInput; +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.BadRequestException; +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.UnprocessableEntityException; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.AccountGroup; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.config.GerritServerConfig; +import com.google.gerrit.server.extensions.events.AgreementSignup; +import com.google.gerrit.server.group.AddMembers; +import com.google.gerrit.server.project.ProjectCache; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import java.io.IOException; +import org.eclipse.jgit.lib.Config; + +@Singleton +public class PutAgreement + implements RestModifyView { + private final ProjectCache projectCache; + private final GroupCache groupCache; + private final Provider self; + private final AgreementSignup agreementSignup; + private final AddMembers addMembers; + private final boolean agreementsEnabled; + + @Inject + PutAgreement(ProjectCache projectCache, + GroupCache groupCache, + Provider self, + AgreementSignup agreementSignup, + AddMembers addMembers, + @GerritServerConfig Config config) { + this.projectCache = projectCache; + this.groupCache = groupCache; + this.self = self; + this.agreementSignup = agreementSignup; + this.addMembers = addMembers; + this.agreementsEnabled = + config.getBoolean("auth", "contributorAgreements", false); + } + + @Override + public Object apply(AccountResource resource, AgreementInput input) + throws IOException, OrmException, RestApiException { + if (!agreementsEnabled) { + throw new MethodNotAllowedException("contributor agreements disabled"); + } + + if (self.get() != resource.getUser()) { + throw new AuthException("not allowed to enter contributor agreement"); + } + + String agreementName = Strings.nullToEmpty(input.name); + ContributorAgreement ca = projectCache.getAllProjects().getConfig() + .getContributorAgreement(agreementName); + if (ca == null) { + throw new UnprocessableEntityException("contributor agreement not found"); + } + + if (ca.getAutoVerify() == null) { + throw new BadRequestException("cannot enter a non-autoVerify agreement"); + } + + AccountGroup.UUID uuid = ca.getAutoVerify().getUUID(); + if (uuid == null) { + throw new ResourceConflictException("autoverify group uuid not found"); + } + + AccountGroup group = groupCache.get(uuid); + if (group == null) { + throw new ResourceConflictException("autoverify group not found"); + } + + Account account = self.get().getAccount(); + addMembers.addMembers(group.getId(), ImmutableList.of(account.getId())); + agreementSignup.fire(account, agreementName); + + return agreementName; + } + +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java index 78e31a9a30..2af9f1d7db 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java @@ -25,6 +25,8 @@ import com.google.gerrit.extensions.client.EditPreferencesInfo; import com.google.gerrit.extensions.client.GeneralPreferencesInfo; import com.google.gerrit.extensions.client.ProjectWatchInfo; import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.AgreementInfo; +import com.google.gerrit.extensions.common.AgreementInput; import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.GpgKeyInfo; import com.google.gerrit.extensions.common.SshKeyInfo; @@ -38,6 +40,7 @@ import com.google.gerrit.server.account.AddSshKey; import com.google.gerrit.server.account.CreateEmail; import com.google.gerrit.server.account.DeleteSshKey; import com.google.gerrit.server.account.DeleteWatchedProjects; +import com.google.gerrit.server.account.GetAgreements; import com.google.gerrit.server.account.GetAvatar; import com.google.gerrit.server.account.GetDiffPreferences; import com.google.gerrit.server.account.GetEditPreferences; @@ -45,6 +48,7 @@ import com.google.gerrit.server.account.GetPreferences; import com.google.gerrit.server.account.GetSshKeys; import com.google.gerrit.server.account.GetWatchedProjects; import com.google.gerrit.server.account.PostWatchedProjects; +import com.google.gerrit.server.account.PutAgreement; import com.google.gerrit.server.account.SetDiffPreferences; import com.google.gerrit.server.account.SetEditPreferences; import com.google.gerrit.server.account.SetPreferences; @@ -93,6 +97,8 @@ public class AccountApiImpl implements AccountApi { private final AddSshKey addSshKey; private final DeleteSshKey deleteSshKey; private final SshKeys sshKeys; + private final GetAgreements getAgreements; + private final PutAgreement putAgreement; @Inject AccountApiImpl(AccountLoader.Factory ailf, @@ -118,6 +124,8 @@ public class AccountApiImpl implements AccountApi { AddSshKey addSshKey, DeleteSshKey deleteSshKey, SshKeys sshKeys, + GetAgreements getAgreements, + PutAgreement putAgreement, @Assisted AccountResource account) { this.account = account; this.accountLoaderFactory = ailf; @@ -143,6 +151,8 @@ public class AccountApiImpl implements AccountApi { this.deleteSshKey = deleteSshKey; this.sshKeys = sshKeys; this.gpgApiAdapter = gpgApiAdapter; + this.getAgreements = getAgreements; + this.putAgreement = putAgreement; } @Override @@ -374,4 +384,21 @@ public class AccountApiImpl implements AccountApi { throw new RestApiException("Cannot get PGP key", e); } } + + @Override + public List listAgreements() throws RestApiException { + return getAgreements.apply(account); + } + + @Override + public void signAgreement(String agreementName) throws RestApiException { + try { + AgreementInput input = new AgreementInput(); + input.name = agreementName; + putAgreement.apply(account, input); + } catch (IOException | OrmException e) { + throw new RestApiException("Cannot sign agreement", e); + } + } + }