From 0a960d72ad4a8487fa3faad63d852ab94b4d2b30 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Thu, 16 May 2019 12:52:31 +0200 Subject: [PATCH 1/4] Show progress on number of users migrated during schema migration 146 This helps sites with a lot of users to estimate time needed for the migration. Change-Id: Ic3f354049f2cb578b6df72046d5117f5eafcdb69 --- .../java/com/google/gerrit/server/schema/Schema_146.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_146.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_146.java index 503ed7b0db..9ca61d9f4d 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_146.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_146.java @@ -80,6 +80,7 @@ public class Schema_146 extends SchemaVersion { ObjectInserter oi = repo.newObjectInserter()) { ObjectId emptyTree = emptyTree(oi); + int i = 0; for (Map.Entry e : scanAccounts(db).entrySet()) { String refName = RefNames.refsUsers(e.getKey()); Ref ref = repo.exactRef(refName); @@ -88,7 +89,12 @@ public class Schema_146 extends SchemaVersion { } else { createUserBranch(repo, oi, emptyTree, e.getKey(), e.getValue()); } + i++; + if (i % 100 == 0) { + ui.message(String.format("... migrated %d users", i)); + } } + ui.message(String.format("Migrated all %d users to schema 146", i)); } catch (IOException e) { throw new OrmException("Failed to rewrite user branches.", e); } From 04a1704113abd43dae7064af43f1b1e31158efce Mon Sep 17 00:00:00 2001 From: Paladox none Date: Mon, 22 Apr 2019 13:47:29 +0000 Subject: [PATCH 2/4] Send email notification when SSH key or GPG key is removed We already send a notification when a key is added. Also sending a notification when a key is removed will help to alert the user if their account was compromised and the key removed by an attacker. Also-by: David Pursehouse Change-Id: I84f4bc5df5b6a609c1a17bad7c4a327cd780aa10 --- Documentation/config-mail.txt | 6 + .../acceptance/api/accounts/AccountIT.java | 6 + .../gerrit/gpg/server/DeleteGpgKey.java | 22 ++- .../google/gerrit/gpg/server/PostGpgKeys.java | 23 ++- .../gerrit/pgm/init/SitePathInitializer.java | 2 + .../gerrit/server/account/DeleteSshKey.java | 25 ++- .../gerrit/server/mail/EmailModule.java | 2 + .../server/mail/send/DeleteKeySender.java | 150 ++++++++++++++++++ .../server/mail/send/MailSoyTofuProvider.java | 2 + .../google/gerrit/server/mail/DeleteKey.soy | 72 +++++++++ .../gerrit/server/mail/DeleteKeyHtml.soy | 66 ++++++++ 11 files changed, 368 insertions(+), 8 deletions(-) create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/mail/send/DeleteKeySender.java create mode 100644 gerrit-server/src/main/resources/com/google/gerrit/server/mail/DeleteKey.soy create mode 100644 gerrit-server/src/main/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy diff --git a/Documentation/config-mail.txt b/Documentation/config-mail.txt index 9eb31bfd9f..db5228dee1 100644 --- a/Documentation/config-mail.txt +++ b/Documentation/config-mail.txt @@ -65,6 +65,12 @@ The CommentFooter templates will determine the contents of the footer text that will be appended to emails related to a user submitting comments on changes. See `ChangeSubject.soy`, Comment and ChangeFooter. +=== DeleteKey.soy and DeleteKeyHtml.soy + +DeleteKey templates will determine the contents of the email related to SSH or GPG keys +being deleted from a user account. This notification is not sent when the key is +administratively deleted from another user account. + === DeleteVote.soy and DeleteVoteHtml.soy The DeleteVote templates will determine the contents of the email related to 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 80e43dee31..ec96c4b9fa 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 @@ -1602,9 +1602,12 @@ public class AccountIT extends AbstractDaemonTest { addGpgKey(key.getPublicKeyArmored()); assertKeys(key); + sender.clear(); gApi.accounts().self().gpgKey(id).delete(); accountIndexedCounter.assertReindexOf(admin); assertKeys(); + assertThat(sender.getMessages()).hasSize(1); + assertThat(sender.getMessages().get(0).body()).contains("GPG keys have been deleted"); exception.expect(ResourceNotFoundException.class); exception.expectMessage(id); @@ -1707,12 +1710,15 @@ public class AccountIT extends AbstractDaemonTest { assertThat(sender.getMessages().get(0).body()).contains("new SSH keys have been added"); // Delete second key + sender.clear(); gApi.accounts().self().deleteSshKey(2); info = gApi.accounts().self().listSshKeys(); assertThat(info).hasSize(2); assertThat(info.get(0).seq).isEqualTo(1); assertThat(info.get(1).seq).isEqualTo(3); accountIndexedCounter.assertReindexOf(admin); + assertThat(sender.getMessages()).hasSize(1); + assertThat(sender.getMessages().get(0).body()).contains("SSH keys have been deleted"); } // reindex is tested by {@link AbstractQueryAccountsTest#reindex} diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/DeleteGpgKey.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/DeleteGpgKey.java index baf5a58f06..212b419efa 100644 --- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/DeleteGpgKey.java +++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/DeleteGpgKey.java @@ -17,7 +17,9 @@ package com.google.gerrit.gpg.server; import static com.google.gerrit.gpg.PublicKeyStore.keyIdToString; import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GPGKEY; +import com.google.common.collect.ImmutableList; import com.google.common.io.BaseEncoding; +import com.google.gerrit.common.errors.EmailException; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.RestModifyView; @@ -26,6 +28,7 @@ import com.google.gerrit.gpg.server.DeleteGpgKey.Input; import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.account.externalids.ExternalId; import com.google.gerrit.server.account.externalids.ExternalIdsUpdate; +import com.google.gerrit.server.mail.send.DeleteKeySender; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Provider; @@ -36,22 +39,29 @@ import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.RefUpdate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DeleteGpgKey implements RestModifyView { + private static final Logger log = LoggerFactory.getLogger(DeleteGpgKey.class); + public static class Input {} private final Provider serverIdent; private final Provider storeProvider; private final ExternalIdsUpdate.User externalIdsUpdateFactory; + private final DeleteKeySender.Factory deleteKeySenderFactory; @Inject DeleteGpgKey( @GerritPersonIdent Provider serverIdent, Provider storeProvider, - ExternalIdsUpdate.User externalIdsUpdateFactory) { + ExternalIdsUpdate.User externalIdsUpdateFactory, + DeleteKeySender.Factory deleteKeySenderFactory) { this.serverIdent = serverIdent; this.storeProvider = storeProvider; this.externalIdsUpdateFactory = externalIdsUpdateFactory; + this.deleteKeySenderFactory = deleteKeySenderFactory; } @Override @@ -79,6 +89,16 @@ public class DeleteGpgKey implements RestModifyView { switch (saveResult) { case NO_CHANGE: case FAST_FORWARD: + try { + deleteKeySenderFactory + .create(rsrc.getUser(), ImmutableList.of(PublicKeyStore.keyToString(key))) + .send(); + } catch (EmailException e) { + log.error( + "Cannot send GPG key deletion message to {}", + rsrc.getUser().getAccount().getPreferredEmail(), + e); + } break; case FORCED: case IO_FAILURE: diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java index 77852adcca..979691e60f 100644 --- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java +++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java @@ -49,6 +49,7 @@ import com.google.gerrit.server.account.externalids.ExternalId; import com.google.gerrit.server.account.externalids.ExternalIds; import com.google.gerrit.server.account.externalids.ExternalIdsUpdate; import com.google.gerrit.server.mail.send.AddKeySender; +import com.google.gerrit.server.mail.send.DeleteKeySender; import com.google.gerrit.server.query.account.InternalAccountQuery; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; @@ -87,7 +88,8 @@ public class PostGpgKeys implements RestModifyView { private final Provider self; private final Provider storeProvider; private final GerritPublicKeyChecker.Factory checkerFactory; - private final AddKeySender.Factory addKeyFactory; + private final AddKeySender.Factory addKeySenderFactory; + private final DeleteKeySender.Factory deleteKeySenderFactory; private final Provider accountQueryProvider; private final ExternalIds externalIds; private final ExternalIdsUpdate.User externalIdsUpdateFactory; @@ -98,7 +100,8 @@ public class PostGpgKeys implements RestModifyView { Provider self, Provider storeProvider, GerritPublicKeyChecker.Factory checkerFactory, - AddKeySender.Factory addKeyFactory, + AddKeySender.Factory addKeySenderFactory, + DeleteKeySender.Factory deleteKeySenderFactory, Provider accountQueryProvider, ExternalIds externalIds, ExternalIdsUpdate.User externalIdsUpdateFactory) { @@ -106,7 +109,8 @@ public class PostGpgKeys implements RestModifyView { this.self = self; this.storeProvider = storeProvider; this.checkerFactory = checkerFactory; - this.addKeyFactory = addKeyFactory; + this.addKeySenderFactory = addKeySenderFactory; + this.deleteKeySenderFactory = deleteKeySenderFactory; this.accountQueryProvider = accountQueryProvider; this.externalIds = externalIds; this.externalIdsUpdateFactory = externalIdsUpdateFactory; @@ -225,13 +229,24 @@ public class PostGpgKeys implements RestModifyView { case FORCED: if (!addedKeys.isEmpty()) { try { - addKeyFactory.create(user, addedKeys).send(); + addKeySenderFactory.create(user, addedKeys).send(); } catch (EmailException e) { log.error( "Cannot send GPG key added message to " + user.getAccount().getPreferredEmail(), e); } } + if (!toRemove.isEmpty()) { + try { + deleteKeySenderFactory + .create(user, toRemove.stream().map(Fingerprint::toString).collect(toList())) + .send(); + } catch (EmailException e) { + log.error( + "Cannot send GPG key deleted message to " + user.getAccount().getPreferredEmail(), + e); + } + } break; case NO_CHANGE: break; diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java index 647bb6b058..a6333352cd 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java @@ -115,6 +115,8 @@ public class SitePathInitializer { extractMailExample("CommentHtml.soy"); extractMailExample("CommentFooter.soy"); extractMailExample("CommentFooterHtml.soy"); + extractMailExample("DeleteKey.soy"); + extractMailExample("DeleteKeyHtml.soy"); extractMailExample("DeleteReviewer.soy"); extractMailExample("DeleteReviewerHtml.soy"); extractMailExample("DeleteVote.soy"); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteSshKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteSshKey.java index 74616bf297..c22e345dda 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteSshKey.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteSshKey.java @@ -14,11 +14,14 @@ package com.google.gerrit.server.account; +import com.google.gerrit.common.errors.EmailException; 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.IdentifiedUser; import com.google.gerrit.server.account.DeleteSshKey.Input; +import com.google.gerrit.server.mail.send.DeleteKeySender; import com.google.gerrit.server.permissions.GlobalPermission; import com.google.gerrit.server.permissions.PermissionBackend; import com.google.gerrit.server.permissions.PermissionBackendException; @@ -30,26 +33,33 @@ import com.google.inject.Singleton; import java.io.IOException; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Singleton public class DeleteSshKey implements RestModifyView { + private static final Logger log = LoggerFactory.getLogger(DeleteSshKey.class); + public static class Input {} private final Provider self; private final PermissionBackend permissionBackend; private final VersionedAuthorizedKeys.Accessor authorizedKeys; private final SshKeyCache sshKeyCache; + private final DeleteKeySender.Factory deleteKeySenderFactory; @Inject DeleteSshKey( Provider self, PermissionBackend permissionBackend, VersionedAuthorizedKeys.Accessor authorizedKeys, - SshKeyCache sshKeyCache) { + SshKeyCache sshKeyCache, + DeleteKeySender.Factory deleteKeySenderFactory) { this.self = self; this.permissionBackend = permissionBackend; this.authorizedKeys = authorizedKeys; this.sshKeyCache = sshKeyCache; + this.deleteKeySenderFactory = deleteKeySenderFactory; } @Override @@ -60,8 +70,17 @@ public class DeleteSshKey implements RestModifyView gpgKeyFingerprints); + } + + private final PermissionBackend permissionBackend; + private final IdentifiedUser callingUser; + private final IdentifiedUser user; + private final AccountSshKey sshKey; + private final List gpgKeyFingerprints; + + @AssistedInject + public DeleteKeySender( + EmailArguments ea, + PermissionBackend permissionBackend, + IdentifiedUser callingUser, + @Assisted IdentifiedUser user, + @Assisted AccountSshKey sshKey) { + super(ea, "deletekey"); + this.permissionBackend = permissionBackend; + this.callingUser = callingUser; + this.user = user; + this.gpgKeyFingerprints = Collections.emptyList(); + this.sshKey = sshKey; + } + + @AssistedInject + public DeleteKeySender( + EmailArguments ea, + PermissionBackend permissionBackend, + IdentifiedUser callingUser, + @Assisted IdentifiedUser user, + @Assisted List gpgKeyFingerprints) { + super(ea, "deletekey"); + this.permissionBackend = permissionBackend; + this.callingUser = callingUser; + this.user = user; + this.gpgKeyFingerprints = gpgKeyFingerprints; + this.sshKey = null; + } + + @Override + protected void init() throws EmailException { + super.init(); + setHeader("Subject", String.format("[Gerrit Code Review] %s Keys Deleted", getKeyType())); + add(RecipientType.TO, new Address(getEmail())); + } + + @Override + protected boolean shouldSendMessage() { + if (user.equals(callingUser)) { + // Send email if the user self-removed a key; this notification is necessary to alert + // the user if their account was compromised and a key was unexpectedly deleted. + return true; + } + + try { + // Don't email if an administrator removed a key on behalf of the user. + permissionBackend.user(callingUser).check(GlobalPermission.ADMINISTRATE_SERVER); + return false; + } catch (AuthException | PermissionBackendException e) { + // Send email if a non-administrator modified the keys, e.g. by MODIFY_ACCOUNT. + return true; + } + } + + @Override + protected void format() throws EmailException { + appendText(textTemplate("DeleteKey")); + if (useHtml()) { + appendHtml(soyHtmlTemplate("DeleteKeyHtml")); + } + } + + public String getEmail() { + return user.getAccount().getPreferredEmail(); + } + + public String getUserNameEmail() { + return getUserNameEmailFor(user.getAccountId()); + } + + public String getKeyType() { + if (sshKey != null) { + return "SSH"; + } else if (gpgKeyFingerprints != null) { + return "GPG"; + } + throw new IllegalStateException("key type is not SSH or GPG"); + } + + public String getSshKey() { + return (sshKey != null) ? sshKey.getSshPublicKey() + "\n" : null; + } + + public String getGpgKeyFingerprints() { + if (!gpgKeyFingerprints.isEmpty()) { + return Joiner.on("\n").join(gpgKeyFingerprints); + } + return null; + } + + @Override + protected void setupSoyContext() { + super.setupSoyContext(); + soyContextEmailData.put("email", getEmail()); + soyContextEmailData.put("gpgKeyFingerprints", getGpgKeyFingerprints()); + soyContextEmailData.put("keyType", getKeyType()); + soyContextEmailData.put("sshKey", getSshKey()); + soyContextEmailData.put("userNameEmail", getUserNameEmail()); + } + + @Override + protected boolean supportsHtml() { + return true; + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/MailSoyTofuProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/MailSoyTofuProvider.java index b26727509d..81074fdf50 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/MailSoyTofuProvider.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/MailSoyTofuProvider.java @@ -47,6 +47,8 @@ public class MailSoyTofuProvider implements Provider { "CommentHtml.soy", "CommentFooter.soy", "CommentFooterHtml.soy", + "DeleteKey.soy", + "DeleteKeyHtml.soy", "DeleteReviewer.soy", "DeleteReviewerHtml.soy", "DeleteVote.soy", diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/DeleteKey.soy b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/DeleteKey.soy new file mode 100644 index 0000000000..0fc4bf820e --- /dev/null +++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/DeleteKey.soy @@ -0,0 +1,72 @@ +/** + * Copyright (C) 2019 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. + */ + +{namespace com.google.gerrit.server.mail.template} + +/** + * The .DeleteKey template will determine the contents of the email related to + * deleting a SSH or GPG key. + * @param email + */ +{template .DeleteKey autoescape="strict" kind="text"} + One or more {$email.keyType} keys have been deleted on Gerrit Code Review at + {sp}{$email.gerritHost}: + + {\n} + {\n} + + {if $email.sshKey} + {$email.sshKey} + {elseif $email.gpgKeyFingerprints} + {$email.gpgKeyFingerprints} + {/if} + + {\n} + {\n} + + + If this is not expected, please contact your Gerrit Administrators + immediately. + + {\n} + {\n} + + You can also manage your {$email.keyType} keys by visiting + {\n} + {if $email.sshKey} + {$email.gerritUrl}#/settings/ssh-keys + {elseif $email.gpgKey} + {$email.gerritUrl}#/settings/gpg-keys + {/if} + {\n} + {if $email.userNameEmail} + (while signed in as {$email.userNameEmail}) + {else} + (while signed in as {$email.email}) + {/if} + + {\n} + {\n} + + If clicking the link above does not work, copy and paste the URL in a new + browser window instead. + + {\n} + {\n} + + This is a send-only email address. Replies to this message will not be read + or answered. +{/template} diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy new file mode 100644 index 0000000000..acdadad76b --- /dev/null +++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2019 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. + */ + +{namespace com.google.gerrit.server.mail.template} + +/** + * @param email + */ +{template .DeleteKeyHtml autoescape="strict" kind="html"} +

+ One or more {$email.keyType} keys have been deleted on Gerrit Code Review + at {$email.gerritHost}: +

+ + {let $keyStyle kind="css"} + background: #f0f0f0; + border: 1px solid #ccc; + color: #555; + padding: 12px; + width: 400px; + {/let} + + {if $email.sshKey} +
{$email.sshKey}
+ {elseif $email.gpgKeyFingerprints} +
{$email.gpgKeyFingerprints}
+ {/if} + +

+ If this is not expected, please contact your Gerrit Administrators + immediately. +

+ +

+ You can also manage your {$email.keyType} keys by following{sp} + {if $email.sshKey} + this link + {elseif $email.gpgKeyFingerprints} + this link + {/if} + {sp} + {if $email.userNameEmail} + (while signed in as {$email.userNameEmail}) + {else} + (while signed in as {$email.email}) + {/if}. +

+ +

+ This is a send-only email address. Replies to this message will not be read + or answered. +

+{/template} From d189897aaa1c2ddb56f27ee8f53686cea5c94179 Mon Sep 17 00:00:00 2001 From: Paladox none Date: Mon, 22 Apr 2019 14:39:33 +0000 Subject: [PATCH 3/4] Send an email notification when the HTTP password is deleted or changed We already send a notification when an account's SSH/GPG keys are added or removed. Also send a notification when the HTTP password is changed or deleted. This will alert the user if their account is compromised and the HTTP password is altered by an attacker. Also-by: David Pursehouse Change-Id: Iaf0e7900c98f6e29b5d609fc7d43797e7e76d1ec --- Documentation/config-mail.txt | 5 ++ .../acceptance/api/accounts/AccountIT.java | 15 ++++ .../gerrit/pgm/init/SitePathInitializer.java | 2 + .../server/account/PutHttpPassword.java | 22 ++++- .../gerrit/server/mail/EmailModule.java | 2 + .../mail/send/HttpPasswordUpdateSender.java | 81 +++++++++++++++++++ .../server/mail/send/MailSoyTofuProvider.java | 2 + .../gerrit/server/mail/HttpPasswordUpdate.soy | 55 +++++++++++++ .../server/mail/HttpPasswordUpdateHtml.soy | 48 +++++++++++ 9 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/mail/send/HttpPasswordUpdateSender.java create mode 100644 gerrit-server/src/main/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy create mode 100644 gerrit-server/src/main/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy diff --git a/Documentation/config-mail.txt b/Documentation/config-mail.txt index db5228dee1..91c7abbe44 100644 --- a/Documentation/config-mail.txt +++ b/Documentation/config-mail.txt @@ -88,6 +88,11 @@ a user removing a reviewer (with a vote) from a change. It is a The Footer templates will determine the contents of the footer text appended to the end of all outgoing emails after the ChangeFooter and CommentFooter. +=== HttpPasswordUpdate.soy and HttpPasswordUpdateHtml.soy + +HttpPasswordUpdate templates will determine the contents of the email related to adding, +changing or deleting the HTTP password on a user account. + === Merged.soy and MergedHtml.soy The Merged templates will determine the contents of the email related to a 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 ec96c4b9fa..1e1fc1144b 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 @@ -1904,15 +1904,21 @@ public class AccountIT extends AbstractDaemonTest { @Test public void userCanGenerateNewHttpPassword() throws Exception { + sender.clear(); String newPassword = gApi.accounts().self().generateHttpPassword(); assertThat(newPassword).isNotNull(); + assertThat(sender.getMessages()).hasSize(1); + assertThat(sender.getMessages().get(0).body()).contains("HTTP password was added or updated"); } @Test public void adminCanGenerateNewHttpPasswordForUser() throws Exception { setApiUser(admin); + sender.clear(); String newPassword = gApi.accounts().id(user.username).generateHttpPassword(); assertThat(newPassword).isNotNull(); + assertThat(sender.getMessages()).hasSize(1); + assertThat(sender.getMessages().get(0).body()).contains("HTTP password was added or updated"); } @Test @@ -1939,7 +1945,10 @@ public class AccountIT extends AbstractDaemonTest { @Test public void userCanRemoveHttpPassword() throws Exception { setApiUser(user); + sender.clear(); assertThat(gApi.accounts().self().setHttpPassword(null)).isNull(); + assertThat(sender.getMessages()).hasSize(1); + assertThat(sender.getMessages().get(0).body()).contains("HTTP password was deleted"); } @Test @@ -1953,14 +1962,20 @@ public class AccountIT extends AbstractDaemonTest { public void adminCanExplicitlySetHttpPasswordForUser() throws Exception { setApiUser(admin); String httpPassword = "new-password-for-user"; + sender.clear(); assertThat(gApi.accounts().id(user.username).setHttpPassword(httpPassword)) .isEqualTo(httpPassword); + assertThat(sender.getMessages()).hasSize(1); + assertThat(sender.getMessages().get(0).body()).contains("HTTP password was added or updated"); } @Test public void adminCanRemoveHttpPasswordForUser() throws Exception { setApiUser(admin); + sender.clear(); assertThat(gApi.accounts().id(user.username).setHttpPassword(null)).isNull(); + assertThat(sender.getMessages()).hasSize(1); + assertThat(sender.getMessages().get(0).body()).contains("HTTP password was deleted"); } @Test diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java index a6333352cd..86daae20f1 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java @@ -124,6 +124,8 @@ public class SitePathInitializer { extractMailExample("Footer.soy"); extractMailExample("FooterHtml.soy"); extractMailExample("HeaderHtml.soy"); + extractMailExample("HttpPasswordUpdate.soy"); + extractMailExample("HttpPasswordUpdateHtml.soy"); extractMailExample("Merged.soy"); extractMailExample("MergedHtml.soy"); extractMailExample("NewChange.soy"); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java index ef953e635e..19b5a6656e 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java @@ -17,6 +17,7 @@ package com.google.gerrit.server.account; import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME; import com.google.common.base.Strings; +import com.google.gerrit.common.errors.EmailException; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; @@ -28,6 +29,7 @@ import com.google.gerrit.server.account.PutHttpPassword.Input; import com.google.gerrit.server.account.externalids.ExternalId; import com.google.gerrit.server.account.externalids.ExternalIds; import com.google.gerrit.server.account.externalids.ExternalIdsUpdate; +import com.google.gerrit.server.mail.send.HttpPasswordUpdateSender; import com.google.gerrit.server.permissions.GlobalPermission; import com.google.gerrit.server.permissions.PermissionBackend; import com.google.gerrit.server.permissions.PermissionBackendException; @@ -39,8 +41,12 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import org.apache.commons.codec.binary.Base64; import org.eclipse.jgit.errors.ConfigInvalidException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PutHttpPassword implements RestModifyView { + private static final Logger log = LoggerFactory.getLogger(PutHttpPassword.class); + public static class Input { public String httpPassword; public boolean generate; @@ -61,17 +67,20 @@ public class PutHttpPassword implements RestModifyView { private final PermissionBackend permissionBackend; private final ExternalIds externalIds; private final ExternalIdsUpdate.User externalIdsUpdate; + private final HttpPasswordUpdateSender.Factory httpPasswordUpdateSenderFactory; @Inject PutHttpPassword( Provider self, PermissionBackend permissionBackend, ExternalIds externalIds, - ExternalIdsUpdate.User externalIdsUpdate) { + ExternalIdsUpdate.User externalIdsUpdate, + HttpPasswordUpdateSender.Factory httpPasswordUpdateSenderFactory) { this.self = self; this.permissionBackend = permissionBackend; this.externalIds = externalIds; this.externalIdsUpdate = externalIdsUpdate; + this.httpPasswordUpdateSenderFactory = httpPasswordUpdateSenderFactory; } @Override @@ -111,6 +120,17 @@ public class PutHttpPassword implements RestModifyView { ExternalId.createWithPassword(extId.key(), extId.accountId(), extId.email(), newPassword); externalIdsUpdate.create().upsert(newExtId); + try { + httpPasswordUpdateSenderFactory + .create(user, newPassword == null ? "deleted" : "added or updated") + .send(); + } catch (EmailException e) { + log.error( + "Cannot send HttpPassword update message to {}", + user.getAccount().getPreferredEmail(), + e); + } + return Strings.isNullOrEmpty(newPassword) ? Response.none() : Response.ok(newPassword); } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailModule.java index 6b363c0925..cc3db75220 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailModule.java @@ -23,6 +23,7 @@ import com.google.gerrit.server.mail.send.CreateChangeSender; import com.google.gerrit.server.mail.send.DeleteKeySender; import com.google.gerrit.server.mail.send.DeleteReviewerSender; import com.google.gerrit.server.mail.send.DeleteVoteSender; +import com.google.gerrit.server.mail.send.HttpPasswordUpdateSender; import com.google.gerrit.server.mail.send.MergedSender; import com.google.gerrit.server.mail.send.RegisterNewEmailSender; import com.google.gerrit.server.mail.send.ReplacePatchSetSender; @@ -41,6 +42,7 @@ public class EmailModule extends FactoryModule { factory(DeleteKeySender.Factory.class); factory(DeleteReviewerSender.Factory.class); factory(DeleteVoteSender.Factory.class); + factory(HttpPasswordUpdateSender.Factory.class); factory(MergedSender.Factory.class); factory(RegisterNewEmailSender.Factory.class); factory(ReplacePatchSetSender.Factory.class); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/HttpPasswordUpdateSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/HttpPasswordUpdateSender.java new file mode 100644 index 0000000000..eb2ca25d44 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/HttpPasswordUpdateSender.java @@ -0,0 +1,81 @@ +// Copyright (C) 2019 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.mail.send; + +import com.google.gerrit.common.errors.EmailException; +import com.google.gerrit.extensions.api.changes.RecipientType; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.mail.Address; +import com.google.inject.assistedinject.Assisted; +import com.google.inject.assistedinject.AssistedInject; + +public class HttpPasswordUpdateSender extends OutgoingEmail { + public interface Factory { + HttpPasswordUpdateSender create(IdentifiedUser user, String operation); + } + + private final IdentifiedUser user; + private final String operation; + + @AssistedInject + public HttpPasswordUpdateSender( + EmailArguments ea, @Assisted IdentifiedUser user, @Assisted String operation) { + super(ea, "HttpPasswordUpdate"); + this.user = user; + this.operation = operation; + } + + @Override + protected void init() throws EmailException { + super.init(); + setHeader("Subject", "[Gerrit Code Review] HTTP password was " + operation); + add(RecipientType.TO, new Address(getEmail())); + } + + @Override + protected boolean shouldSendMessage() { + // Always send an email if the HTTP password is updated. + return true; + } + + @Override + protected void format() throws EmailException { + appendText(textTemplate("HttpPasswordUpdate")); + if (useHtml()) { + appendHtml(soyHtmlTemplate("HttpPasswordUpdateHtml")); + } + } + + public String getEmail() { + return user.getAccount().getPreferredEmail(); + } + + public String getUserNameEmail() { + return getUserNameEmailFor(user.getAccountId()); + } + + @Override + protected void setupSoyContext() { + super.setupSoyContext(); + soyContextEmailData.put("email", getEmail()); + soyContextEmailData.put("userNameEmail", getUserNameEmail()); + soyContextEmailData.put("operation", operation); + } + + @Override + protected boolean supportsHtml() { + return true; + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/MailSoyTofuProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/MailSoyTofuProvider.java index 81074fdf50..34a7085ae8 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/MailSoyTofuProvider.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/MailSoyTofuProvider.java @@ -56,6 +56,8 @@ public class MailSoyTofuProvider implements Provider { "Footer.soy", "FooterHtml.soy", "HeaderHtml.soy", + "HttpPasswordUpdate.soy", + "HttpPasswordUpdateHtml.soy", "Merged.soy", "MergedHtml.soy", "NewChange.soy", diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy new file mode 100644 index 0000000000..49fce7b454 --- /dev/null +++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2019 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. + */ + +{namespace com.google.gerrit.server.mail.template} + +/** + * The .HttpPasswordUpdate template will determine the contents of the email related to + * adding, changing or deleting the HTTP password. + * @param email + */ +{template .HttpPasswordUpdate autoescape="strict" kind="text"} + The HTTP password was {$email.operation} on Gerrit Code Review at + {sp}{$email.gerritHost}. + + If this is not expected, please contact your Gerrit Administrators + immediately. + + {\n} + {\n} + + You can also manage your HTTP password by visiting + {\n} + {$email.gerritUrl}#/settings/http-password + {\n} + {if $email.userNameEmail} + (while signed in as {$email.userNameEmail}) + {else} + (while signed in as {$email.email}) + {/if} + + {\n} + {\n} + + If clicking the link above does not work, copy and paste the URL in a new + browser window instead. + + {\n} + {\n} + + This is a send-only email address. Replies to this message will not be read + or answered. +{/template} diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy new file mode 100644 index 0000000000..0aac668222 --- /dev/null +++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2019 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. + */ + +{namespace com.google.gerrit.server.mail.template} + +/** + * @param email + */ +{template .HttpPasswordUpdateHtml autoescape="strict" kind="html"} +

+ The HTTP password was {$email.operation} on Gerrit Code Review + at {$email.gerritHost}. +

+ +

+ If this is not expected, please contact your Gerrit Administrators + immediately. +

+ +

+ You can also manage your HTTP password by following{sp} + this link + {sp} + {if $email.userNameEmail} + (while signed in as {$email.userNameEmail}) + {else} + (while signed in as {$email.email}) + {/if}. +

+ +

+ This is a send-only email address. Replies to this message will not be read + or answered. +

+{/template} From 23b2c4a206d91df513f5a8d31477c6ca8939f2ab Mon Sep 17 00:00:00 2001 From: Marco Miller Date: Thu, 16 May 2019 12:17:00 -0400 Subject: [PATCH 4/4] Elasticsearch: Exclude types from V7 which deprecates them Remove the use of the include_type_name parameter which started from V6. Before this change, warnings related to the V7 usage of that parameter showed in consoles. More in [1] about the include_type_name parameter for Elasticsearch 6.x (warning), 7.x (deprecation), and 8.x (deprecated). [1] https://www.elastic.co/guide/en/elasticsearch/reference/master/removal-of-types.html#_schedule_for_removal_of_mapping_types Bug: Issue 10496 Change-Id: I6fe26e097a618d71a781dbebae621b6515d6822e --- .../elasticsearch/AbstractElasticIndex.java | 18 +++++--- .../elasticsearch/ElasticChangeIndex.java | 34 +++++++-------- .../elasticsearch/ElasticQueryAdapter.java | 41 +++++++++++++------ .../gerrit/elasticsearch/ElasticVersion.java | 10 ++++- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java index 4f811b9ee6..2e30e596bb 100644 --- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java +++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java @@ -188,10 +188,15 @@ abstract class AbstractElasticIndex implements Index { } protected String getMappingsFor(String type, MappingProperties properties) { - JsonObject mappingType = new JsonObject(); - mappingType.add(type, gson.toJsonTree(properties)); JsonObject mappings = new JsonObject(); - mappings.add(MAPPINGS, gson.toJsonTree(mappingType)); + + if (client.adapter().omitType()) { + mappings.add(MAPPINGS, gson.toJsonTree(properties)); + } else { + JsonObject mappingType = new JsonObject(); + mappingType.add(type, gson.toJsonTree(properties)); + mappings.add(MAPPINGS, gson.toJsonTree(mappingType)); + } return gson.toJson(mappings); } @@ -229,11 +234,12 @@ abstract class AbstractElasticIndex implements Index { protected String getURI(String type, String request) throws UnsupportedEncodingException { String encodedIndexName = URLEncoder.encode(indexName, UTF_8.toString()); - if (SEARCH.equals(request) && client.adapter().omitTypeFromSearch()) { + if (SEARCH.equals(request) && client.adapter().omitType()) { return encodedIndexName + "/" + request; } - String encodedType = URLEncoder.encode(type, UTF_8.toString()); - return encodedIndexName + "/" + encodedType + "/" + request; + String encodedTypeIfAny = + client.adapter().omitType() ? "" : "/" + URLEncoder.encode(type, UTF_8.toString()); + return encodedIndexName + encodedTypeIfAny + "/" + request; } protected Response postRequest(String uri, Object payload) throws IOException { diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java index 264822e415..81a237bb77 100644 --- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java +++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java @@ -141,7 +141,7 @@ class ElasticChangeIndex extends AbstractElasticIndex BulkRequest bulk = new IndexRequest(getId(cd), indexName, adapter.getType(insertIndex), adapter) .add(new UpdateRequest<>(schema, cd)); - if (!adapter.usePostV5Type()) { + if (adapter.deleteToReplace()) { bulk.add(new DeleteRequest(cd.getId().toString(), indexName, deleteIndex, adapter)); } @@ -160,17 +160,19 @@ class ElasticChangeIndex extends AbstractElasticIndex throws QueryParseException { Set statuses = ChangeIndexRewriter.getPossibleStatus(p); List indexes = Lists.newArrayListWithCapacity(2); - if (client.adapter().usePostV5Type()) { - if (!Sets.intersection(statuses, OPEN_STATUSES).isEmpty() - || !Sets.intersection(statuses, CLOSED_STATUSES).isEmpty()) { - indexes.add(ElasticQueryAdapter.POST_V5_TYPE); - } - } else { - if (!Sets.intersection(statuses, OPEN_STATUSES).isEmpty()) { - indexes.add(OPEN_CHANGES); - } - if (!Sets.intersection(statuses, CLOSED_STATUSES).isEmpty()) { - indexes.add(CLOSED_CHANGES); + if (!client.adapter().omitType()) { + if (client.adapter().useV6Type()) { + if (!Sets.intersection(statuses, OPEN_STATUSES).isEmpty() + || !Sets.intersection(statuses, CLOSED_STATUSES).isEmpty()) { + indexes.add(ElasticQueryAdapter.V6_TYPE); + } + } else { + if (!Sets.intersection(statuses, OPEN_STATUSES).isEmpty()) { + indexes.add(OPEN_CHANGES); + } + if (!Sets.intersection(statuses, CLOSED_STATUSES).isEmpty()) { + indexes.add(CLOSED_CHANGES); + } } } return new QuerySource(indexes, p, opts); @@ -178,16 +180,16 @@ class ElasticChangeIndex extends AbstractElasticIndex @Override protected String getDeleteActions(Id c) { - if (client.adapter().usePostV5Type()) { - return delete(ElasticQueryAdapter.POST_V5_TYPE, c); + if (!client.adapter().useV5Type()) { + return delete(client.adapter().getType(), c); } return delete(OPEN_CHANGES, c) + delete(CLOSED_CHANGES, c); } @Override protected String getMappings() { - if (client.adapter().usePostV5Type()) { - return getMappingsFor(ElasticQueryAdapter.POST_V5_TYPE, mapping.changes); + if (!client.adapter().useV5Type()) { + return getMappingsFor(client.adapter().getType(), mapping.changes); } return gson.toJson(ImmutableMap.of(MAPPINGS, mapping)); } diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java index 85fbee8556..329913bede 100644 --- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java +++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java @@ -17,11 +17,12 @@ package com.google.gerrit.elasticsearch; import com.google.gson.JsonObject; public class ElasticQueryAdapter { - static final String POST_V5_TYPE = "_doc"; + static final String V6_TYPE = "_doc"; private final boolean ignoreUnmapped; - private final boolean usePostV5Type; - private final boolean omitTypeFromSearch; + private final boolean useV5Type; + private final boolean useV6Type; + private final boolean omitType; private final String searchFilteringName; private final String indicesExistParam; @@ -33,15 +34,16 @@ public class ElasticQueryAdapter { ElasticQueryAdapter(ElasticVersion version) { this.ignoreUnmapped = false; - this.usePostV5Type = version.isV6OrLater(); - this.omitTypeFromSearch = version.isV7OrLater(); + this.useV5Type = !version.isV6OrLater(); + this.useV6Type = version.isV6(); + this.omitType = version.isV7OrLater(); this.versionDiscoveryUrl = version.isV6OrLater() ? "/%s*" : "/%s*/_aliases"; this.searchFilteringName = "_source"; this.indicesExistParam = "?allow_no_indices=false"; this.exactFieldType = "keyword"; this.stringFieldType = "text"; this.indexProperty = "true"; - this.includeTypeNameParam = version.isV7OrLater() ? "?include_type_name=true" : ""; + this.includeTypeNameParam = version.isV6() ? "?include_type_name=true" : ""; } void setIgnoreUnmapped(JsonObject properties) { @@ -51,7 +53,7 @@ public class ElasticQueryAdapter { } public void setType(JsonObject properties, String type) { - if (!usePostV5Type) { + if (useV5Type) { properties.addProperty("_type", type); } } @@ -76,16 +78,31 @@ public class ElasticQueryAdapter { return indexProperty; } - boolean usePostV5Type() { - return usePostV5Type; + boolean deleteToReplace() { + return useV5Type; } - boolean omitTypeFromSearch() { - return omitTypeFromSearch; + boolean useV5Type() { + return useV5Type; + } + + boolean useV6Type() { + return useV6Type; + } + + boolean omitType() { + return omitType; + } + + String getType() { + return getType(""); } String getType(String type) { - return usePostV5Type() ? POST_V5_TYPE : type; + if (useV6Type()) { + return V6_TYPE; + } + return useV5Type() ? type : ""; } String getVersionDiscoveryUrl(String name) { diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticVersion.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticVersion.java index 6de4d972ba..2cd8dd60f2 100644 --- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticVersion.java +++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticVersion.java @@ -58,6 +58,10 @@ public enum ElasticVersion { return Joiner.on(", ").join(ElasticVersion.values()); } + public boolean isV6() { + return getMajor() == 6; + } + public boolean isV6OrLater() { return isAtLeastVersion(6); } @@ -67,7 +71,11 @@ public enum ElasticVersion { } private boolean isAtLeastVersion(int v) { - return Integer.valueOf(version.split("\\.")[0]) >= v; + return getMajor() >= v; + } + + private Integer getMajor() { + return Integer.valueOf(version.split("\\.")[0]); } @Override