From ca547ff308fc576e5821e56b16059953073e0abf Mon Sep 17 00:00:00 2001 From: Edwin Kempin Date: Tue, 22 Nov 2016 16:50:10 +0100 Subject: [PATCH] Add REST endpoint to reindex a single account This may become handy to fix single accounts that are stale in the index. Change-Id: If4c1787a26a564c19d1c4c1896afa89120ef4813 Signed-off-by: Edwin Kempin --- Documentation/rest-api-accounts.txt | 18 ++++++ .../acceptance/api/accounts/AccountIT.java | 17 ++++++ .../extensions/api/accounts/AccountApi.java | 7 +++ .../google/gerrit/server/account/Index.java | 56 +++++++++++++++++++ .../google/gerrit/server/account/Module.java | 1 + .../server/api/accounts/AccountApiImpl.java | 12 ++++ .../account/AbstractQueryAccountsTest.java | 20 +++++++ 7 files changed, 131 insertions(+) create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/account/Index.java diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt index 77ca75a7ff..54941c1804 100644 --- a/Documentation/rest-api-accounts.txt +++ b/Documentation/rest-api-accounts.txt @@ -1941,6 +1941,24 @@ As response the contributor agreement name is returned. "Individual" ---- +[[index-account]] +=== Index Account +-- +'POST /accounts/link:#account-id[\{account-id\}]/index' +-- + +Adds or updates the account in the secondary index. + +.Request +---- + POST /accounts/1000096/index HTTP/1.0 +---- + +.Response +---- + HTTP/1.1 204 No Content +---- + [[ids]] == IDs diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java index 93525a4f33..6ad20ffcb8 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java @@ -675,6 +675,23 @@ public class AccountIT extends AbstractDaemonTest { assertThat(info.get(1).seq).isEqualTo(3); } + // reindex is tested by {@link AbstractQueryAccountsTest#reindex} + @Test + public void reindexPermissions() throws Exception { + // admin can reindex any account + setApiUser(admin); + gApi.accounts().id(user.username).index(); + + // user can reindex own account + setApiUser(user); + gApi.accounts().self().index(); + + // user cannot reindex any account + exception.expect(AuthException.class); + exception.expectMessage("not allowed to index account"); + gApi.accounts().id(admin.username).index(); + } + private void assertSequenceNumbers(List sshKeys) { int seq = 1; for (SshKeyInfo key : sshKeys) { 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 c1cb3ec2a8..8f7f93cf12 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 @@ -74,6 +74,8 @@ public interface AccountApi { List listAgreements() throws RestApiException; void signAgreement(String agreementName) throws RestApiException; + void index() throws RestApiException; + /** * A default implementation which allows source compatibility * when adding new methods to the interface. @@ -211,5 +213,10 @@ public interface AccountApi { public void signAgreement(String agreementName) throws RestApiException { throw new NotImplementedException(); } + + @Override + public void index() throws RestApiException { + throw new NotImplementedException(); + } } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Index.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Index.java new file mode 100644 index 0000000000..b8cdf766d7 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Index.java @@ -0,0 +1,56 @@ +//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.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.Response; +import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.account.Index.Input; +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; + +@Singleton +public class Index implements RestModifyView { + public static class Input { + } + + private final AccountCache accountCache; + private final Provider self; + + @Inject + Index(AccountCache accountCache, + Provider self) { + this.accountCache = accountCache; + this.self = self; + } + + @Override + public Response apply(AccountResource rsrc, Input input) + throws IOException, AuthException, OrmException { + if (self.get() != rsrc.getUser() + && !self.get().getCapabilities().canModifyAccount()) { + throw new AuthException("not allowed to index account"); + } + + // evicting the account from the cache, reindexes the account + accountCache.evict(rsrc.getUser().getAccountId()); + return Response.none(); + } +} 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 5b4a2004d1..8c5228f7b9 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 @@ -40,6 +40,7 @@ public class Module extends RestApiModule { put(ACCOUNT_KIND).to(PutAccount.class); get(ACCOUNT_KIND).to(GetAccount.class); get(ACCOUNT_KIND, "detail").to(GetDetail.class); + post(ACCOUNT_KIND, "index").to(Index.class); get(ACCOUNT_KIND, "name").to(GetName.class); put(ACCOUNT_KIND, "name").to(PutName.class); delete(ACCOUNT_KIND, "name").to(PutName.class); 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 2af9f1d7db..1bca929beb 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 @@ -47,6 +47,7 @@ import com.google.gerrit.server.account.GetEditPreferences; 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.Index; import com.google.gerrit.server.account.PostWatchedProjects; import com.google.gerrit.server.account.PutAgreement; import com.google.gerrit.server.account.SetDiffPreferences; @@ -99,6 +100,7 @@ public class AccountApiImpl implements AccountApi { private final SshKeys sshKeys; private final GetAgreements getAgreements; private final PutAgreement putAgreement; + private final Index index; @Inject AccountApiImpl(AccountLoader.Factory ailf, @@ -126,6 +128,7 @@ public class AccountApiImpl implements AccountApi { SshKeys sshKeys, GetAgreements getAgreements, PutAgreement putAgreement, + Index index, @Assisted AccountResource account) { this.account = account; this.accountLoaderFactory = ailf; @@ -153,6 +156,7 @@ public class AccountApiImpl implements AccountApi { this.gpgApiAdapter = gpgApiAdapter; this.getAgreements = getAgreements; this.putAgreement = putAgreement; + this.index = index; } @Override @@ -401,4 +405,12 @@ public class AccountApiImpl implements AccountApi { } } + @Override + public void index() throws RestApiException { + try { + index.apply(account, new Index.Input()); + } catch (IOException | OrmException e) { + throw new RestApiException("Cannot index account", e); + } + } } diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java index f7b3b11d6a..83f83bba4d 100644 --- a/gerrit-server/src/test/java/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java +++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java @@ -56,6 +56,7 @@ import org.junit.Test; import org.junit.rules.TestName; import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -355,6 +356,25 @@ public abstract class AbstractQueryAccountsTest extends GerritServerTests { assertQuery("username:" + user1.username, user1); } + // reindex permissions are tested by {@link AccountIT#reindexPermissions} + @Test + public void reindex() throws Exception { + AccountInfo user1 = newAccountWithFullName("tester", "Test Usre"); + + // update account in the database so that account index is stale + String newName = "Test User"; + Account account = db.accounts().get(new Account.Id(user1._accountId)); + account.setFullName(newName); + db.accounts().update(Collections.singleton(account)); + + assertQuery("name:" + quote(user1.name), user1); + assertQuery("name:" + quote(newName)); + + gApi.accounts().id(user1.username).index(); + assertQuery("name:" + quote(user1.name)); + assertQuery("name:" + quote(newName), user1); + } + protected AccountInfo newAccount(String username) throws Exception { return newAccountWithEmail(username, null); }