From ed33c7424d3d1f80c9115dce1658d763af69eede Mon Sep 17 00:00:00 2001 From: gbrodman Date: Fri, 21 Mar 2025 10:46:16 -0400 Subject: [PATCH] Add and use new SimpleConsoleUpdateHistory table (#2712) This changes the code to only save console histories of this type. We keep the old Java code (and, necessarily, the corresponding SQL code) for now because there's no harm in doing so and we want to avoid hastily deleting too much. --- .../model/console/ConsoleUpdateHistory.java | 10 +- .../console/SimpleConsoleUpdateHistory.java | 153 ++++++++++++++++++ .../ui/server/console/ConsoleApiAction.java | 4 +- .../console/ConsoleEppPasswordAction.java | 12 +- .../console/ConsoleUpdateRegistrarAction.java | 7 +- .../ui/server/console/RegistrarsAction.java | 9 +- .../domains/ConsoleBulkDomainAction.java | 24 +++ .../ConsoleBulkDomainDeleteActionType.java | 6 + .../ConsoleBulkDomainSuspendActionType.java | 6 + .../ConsoleBulkDomainUnsuspendActionType.java | 6 + .../domains/ConsoleDomainActionType.java | 4 + .../console/settings/SecurityAction.java | 9 +- .../settings/WhoisRegistrarFieldsAction.java | 7 +- .../main/resources/META-INF/persistence.xml | 1 + .../console/ConsoleEppActionHistoryTest.java | 2 +- .../SimpleConsoleUpdateHistoryTest.java | 62 +++++++ .../integration/SqlIntegrationTestSuite.java | 4 +- .../console/ConsoleEppPasswordActionTest.java | 15 +- .../ConsoleUpdateRegistrarActionTest.java | 10 +- .../server/console/RegistrarsActionTest.java | 10 +- .../domains/ConsoleBulkDomainActionTest.java | 15 ++ .../console/settings/SecurityActionTest.java | 10 +- .../WhoisRegistrarFieldsActionTest.java | 9 +- .../sql/er_diagram/brief_er_diagram.html | 4 +- .../sql/er_diagram/full_er_diagram.html | 4 +- .../sql/schema/db-schema.sql.generated | 33 +++- 26 files changed, 366 insertions(+), 70 deletions(-) create mode 100644 core/src/main/java/google/registry/model/console/SimpleConsoleUpdateHistory.java create mode 100644 core/src/test/java/google/registry/model/console/SimpleConsoleUpdateHistoryTest.java diff --git a/core/src/main/java/google/registry/model/console/ConsoleUpdateHistory.java b/core/src/main/java/google/registry/model/console/ConsoleUpdateHistory.java index a4fb4497d..2a29dac83 100644 --- a/core/src/main/java/google/registry/model/console/ConsoleUpdateHistory.java +++ b/core/src/main/java/google/registry/model/console/ConsoleUpdateHistory.java @@ -41,10 +41,12 @@ import org.joda.time.DateTime; public abstract class ConsoleUpdateHistory extends ImmutableObject implements Buildable { public enum Type { - EPP_ACTION, - POC_CREATE, - POC_UPDATE, - POC_DELETE, + DOMAIN_DELETE, + DOMAIN_SUSPEND, + DOMAIN_UNSUSPEND, + EPP_PASSWORD_UPDATE, + REGISTRAR_CREATE, + REGISTRAR_SECURITY_UPDATE, REGISTRAR_UPDATE, USER_CREATE, USER_DELETE, diff --git a/core/src/main/java/google/registry/model/console/SimpleConsoleUpdateHistory.java b/core/src/main/java/google/registry/model/console/SimpleConsoleUpdateHistory.java new file mode 100644 index 000000000..b172bc9e4 --- /dev/null +++ b/core/src/main/java/google/registry/model/console/SimpleConsoleUpdateHistory.java @@ -0,0 +1,153 @@ +// Copyright 2025 The Nomulus Authors. All Rights Reserved. +// +// 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 google.registry.model.console; + +import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; + +import google.registry.model.Buildable; +import google.registry.model.ImmutableObject; +import google.registry.model.annotations.IdAllocation; +import google.registry.persistence.WithVKey; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.util.Optional; +import org.joda.time.DateTime; + +@Entity +@WithVKey(Long.class) +@Table( + name = "ConsoleUpdateHistory", + indexes = { + @Index(columnList = "actingUser", name = "idx_console_update_history_acting_user"), + @Index(columnList = "type", name = "idx_console_update_history_type"), + @Index(columnList = "modificationTime", name = "idx_console_update_history_modification_time") + }) +// TODO: rename this to ConsoleUpdateHistory when that class is removed +public class SimpleConsoleUpdateHistory extends ImmutableObject implements Buildable { + + @Id @IdAllocation @Column Long revisionId; + + @Column(nullable = false) + DateTime modificationTime; + + /** The HTTP method (e.g. POST, PUT) used to make this modification. */ + @Column(nullable = false) + String method; + + /** The type of modification. */ + @Column(nullable = false) + @Enumerated(EnumType.STRING) + ConsoleUpdateHistory.Type type; + + /** The URL of the action that was used to make the modification. */ + @Column(nullable = false) + String url; + + /** An optional further description of the action. */ + String description; + + /** The user that performed the modification. */ + @JoinColumn(name = "actingUser", referencedColumnName = "emailAddress", nullable = false) + @ManyToOne + User actingUser; + + public Long getRevisionId() { + return revisionId; + } + + public DateTime getModificationTime() { + return modificationTime; + } + + public Optional getDescription() { + return Optional.ofNullable(description); + } + + public String getMethod() { + return method; + } + + public ConsoleUpdateHistory.Type getType() { + return type; + } + + public String getUrl() { + return url; + } + + public User getActingUser() { + return actingUser; + } + + @Override + public Builder asBuilder() { + return new Builder(clone(this)); + } + + public static class Builder extends Buildable.Builder { + public Builder() {} + + private Builder(SimpleConsoleUpdateHistory instance) { + super(instance); + } + + @Override + public SimpleConsoleUpdateHistory build() { + checkArgumentNotNull(getInstance().modificationTime, "Modification time must be specified"); + checkArgumentNotNull(getInstance().actingUser, "Acting user must be specified"); + checkArgumentNotNull(getInstance().url, "URL must be specified"); + checkArgumentNotNull(getInstance().method, "HTTP method must be specified"); + checkArgumentNotNull(getInstance().type, "ConsoleUpdateHistory type must be specified"); + return super.build(); + } + + public Builder setModificationTime(DateTime modificationTime) { + getInstance().modificationTime = modificationTime; + return this; + } + + public Builder setActingUser(User actingUser) { + getInstance().actingUser = actingUser; + return this; + } + + public Builder setUrl(String url) { + getInstance().url = url; + return this; + } + + public Builder setMethod(String method) { + getInstance().method = method; + return this; + } + + public Builder setDescription(String description) { + getInstance().description = description; + return this; + } + + public Builder setType(ConsoleUpdateHistory.Type type) { + getInstance().type = type; + return this; + } + } +} diff --git a/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java b/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java index f2ff52459..969c8f9b4 100644 --- a/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java +++ b/core/src/main/java/google/registry/ui/server/console/ConsoleApiAction.java @@ -37,7 +37,7 @@ import google.registry.batch.CloudTasksUtils; import google.registry.config.RegistryConfig; import google.registry.export.sheet.SyncRegistrarsSheetAction; import google.registry.model.console.ConsolePermission; -import google.registry.model.console.ConsoleUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.registrar.Registrar; import google.registry.model.registrar.RegistrarPoc; @@ -262,7 +262,7 @@ public abstract class ConsoleApiAction implements Runnable { } } - protected void finishAndPersistConsoleUpdateHistory(ConsoleUpdateHistory.Builder builder) { + protected void finishAndPersistConsoleUpdateHistory(SimpleConsoleUpdateHistory.Builder builder) { builder.setActingUser(consoleApiParams.authResult().user().get()); builder.setUrl(consoleApiParams.request().getRequestURI()); builder.setMethod(consoleApiParams.request().getMethod()); diff --git a/core/src/main/java/google/registry/ui/server/console/ConsoleEppPasswordAction.java b/core/src/main/java/google/registry/ui/server/console/ConsoleEppPasswordAction.java index 790f3e0c3..9817886d5 100644 --- a/core/src/main/java/google/registry/ui/server/console/ConsoleEppPasswordAction.java +++ b/core/src/main/java/google/registry/ui/server/console/ConsoleEppPasswordAction.java @@ -28,7 +28,7 @@ import com.google.gson.annotations.Expose; import google.registry.flows.EppException.AuthenticationErrorException; import google.registry.flows.PasswordOnlyTransportCredentials; import google.registry.model.console.ConsoleUpdateHistory; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.registrar.Registrar; import google.registry.request.Action; @@ -107,14 +107,10 @@ public class ConsoleEppPasswordAction extends ConsoleApiAction { Registrar updatedRegistrar = registrar.asBuilder().setPassword(eppRequestBody.newPassword()).build(); tm().put(updatedRegistrar); - EppPasswordData sanitizedData = - new EppPasswordData( - eppRequestBody.registrarId, "********", "••••••••", "••••••••"); finishAndPersistConsoleUpdateHistory( - new RegistrarUpdateHistory.Builder() - .setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE) - .setRegistrar(updatedRegistrar) - .setRequestBody(consoleApiParams.gson().toJson(sanitizedData))); + new SimpleConsoleUpdateHistory.Builder() + .setType(ConsoleUpdateHistory.Type.EPP_PASSWORD_UPDATE) + .setDescription(registrar.getRegistrarId())); sendExternalUpdates( ImmutableMap.of("password", new DiffUtils.DiffPair("********", "••••••••")), registrar, diff --git a/core/src/main/java/google/registry/ui/server/console/ConsoleUpdateRegistrarAction.java b/core/src/main/java/google/registry/ui/server/console/ConsoleUpdateRegistrarAction.java index 7082ddd36..476c9aa9c 100644 --- a/core/src/main/java/google/registry/ui/server/console/ConsoleUpdateRegistrarAction.java +++ b/core/src/main/java/google/registry/ui/server/console/ConsoleUpdateRegistrarAction.java @@ -24,7 +24,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import google.registry.model.console.ConsolePermission; import google.registry.model.console.ConsoleUpdateHistory; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.registrar.Registrar; import google.registry.request.Action; @@ -102,10 +102,9 @@ public class ConsoleUpdateRegistrarAction extends ConsoleApiAction { tm().put(updatedRegistrar); finishAndPersistConsoleUpdateHistory( - new RegistrarUpdateHistory.Builder() + new SimpleConsoleUpdateHistory.Builder() .setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE) - .setRegistrar(updatedRegistrar) - .setRequestBody(consoleApiParams.gson().toJson(registrarParam))); + .setDescription(updatedRegistrar.getRegistrarId())); sendExternalUpdatesIfNecessary( EmailInfo.create( existingRegistrar.get(), diff --git a/core/src/main/java/google/registry/ui/server/console/RegistrarsAction.java b/core/src/main/java/google/registry/ui/server/console/RegistrarsAction.java index 96aeb0e4b..f0772dc2b 100644 --- a/core/src/main/java/google/registry/ui/server/console/RegistrarsAction.java +++ b/core/src/main/java/google/registry/ui/server/console/RegistrarsAction.java @@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Streams; import google.registry.model.console.ConsolePermission; import google.registry.model.console.ConsoleUpdateHistory; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.registrar.Registrar; import google.registry.model.registrar.RegistrarBase; @@ -174,10 +174,9 @@ public class RegistrarsAction extends ConsoleApiAction { registrar.getRegistrarId()); tm().putAll(registrar, contact); finishAndPersistConsoleUpdateHistory( - new RegistrarUpdateHistory.Builder() - .setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE) - .setRegistrar(registrar) - .setRequestBody(consoleApiParams.gson().toJson(registrar))); + new SimpleConsoleUpdateHistory.Builder() + .setType(ConsoleUpdateHistory.Type.REGISTRAR_CREATE) + .setDescription(registrar.getRegistrarId())); }); } diff --git a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainAction.java b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainAction.java index 64b4e97f9..199918d96 100644 --- a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainAction.java +++ b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainAction.java @@ -15,6 +15,7 @@ package google.registry.ui.server.console.domains; import static com.google.common.collect.ImmutableMap.toImmutableMap; +import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static jakarta.servlet.http.HttpServletResponse.SC_OK; import static java.nio.charset.StandardCharsets.UTF_8; @@ -25,6 +26,7 @@ import google.registry.flows.EppController; import google.registry.flows.EppRequestSource; import google.registry.flows.PasswordOnlyTransportCredentials; import google.registry.flows.StatelessRequestSessionMetadata; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.eppcommon.ProtocolDefinition; import google.registry.model.eppoutput.EppOutput; @@ -93,11 +95,29 @@ public class ConsoleBulkDomainAction extends ConsoleApiAction { domainList.domainList.stream() .collect( toImmutableMap(d -> d, d -> executeEpp(actionType.getXmlContentsToRun(d), user))); + handleHistoryAdditions(result, actionType); // Front end should parse situations where only some commands worked consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(result)); consoleApiParams.response().setStatus(SC_OK); } + private void handleHistoryAdditions( + ImmutableMap result, ConsoleDomainActionType actionType) { + if (result.values().stream().noneMatch(ConsoleEppOutput::isSuccess)) { + return; + } + tm().transact( + () -> + result.entrySet().stream() + .filter(e -> e.getValue().isSuccess()) + .forEach( + e -> + finishAndPersistConsoleUpdateHistory( + new SimpleConsoleUpdateHistory.Builder() + .setDescription(e.getKey()) + .setType(actionType.getConsoleUpdateHistoryType())))); + } + private ConsoleEppOutput executeEpp(String xml, User user) { return ConsoleEppOutput.fromEppOutput( eppController.handleEppCommand( @@ -115,5 +135,9 @@ public class ConsoleBulkDomainAction extends ConsoleApiAction { Result result = eppOutput.getResponse().getResult(); return new ConsoleEppOutput(result.getMsg(), result.getCode().code); } + + boolean isSuccess() { + return responseCode < 2000; + } } } diff --git a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainDeleteActionType.java b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainDeleteActionType.java index 84f1327b1..b42dbaa08 100644 --- a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainDeleteActionType.java +++ b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainDeleteActionType.java @@ -16,6 +16,7 @@ package google.registry.ui.server.console.domains; import com.google.gson.JsonElement; import google.registry.model.console.ConsolePermission; +import google.registry.model.console.ConsoleUpdateHistory; /** An action that will run a delete EPP command on the given domain. */ public class ConsoleBulkDomainDeleteActionType extends ConsoleDomainActionType { @@ -54,4 +55,9 @@ public class ConsoleBulkDomainDeleteActionType extends ConsoleDomainActionType { public ConsolePermission getNecessaryPermission() { return ConsolePermission.EXECUTE_EPP_COMMANDS; } + + @Override + public ConsoleUpdateHistory.Type getConsoleUpdateHistoryType() { + return ConsoleUpdateHistory.Type.DOMAIN_DELETE; + } } diff --git a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainSuspendActionType.java b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainSuspendActionType.java index b690438dd..71b56fe43 100644 --- a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainSuspendActionType.java +++ b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainSuspendActionType.java @@ -16,6 +16,7 @@ package google.registry.ui.server.console.domains; import com.google.gson.JsonElement; import google.registry.model.console.ConsolePermission; +import google.registry.model.console.ConsoleUpdateHistory; /** An action that will suspend the given domain, assigning all 5 server*Prohibited statuses. */ public class ConsoleBulkDomainSuspendActionType extends ConsoleDomainActionType { @@ -64,4 +65,9 @@ public class ConsoleBulkDomainSuspendActionType extends ConsoleDomainActionType public ConsolePermission getNecessaryPermission() { return ConsolePermission.SUSPEND_DOMAIN; } + + @Override + public ConsoleUpdateHistory.Type getConsoleUpdateHistoryType() { + return ConsoleUpdateHistory.Type.DOMAIN_SUSPEND; + } } diff --git a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainUnsuspendActionType.java b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainUnsuspendActionType.java index 0d3a959e1..9ae158406 100644 --- a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainUnsuspendActionType.java +++ b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleBulkDomainUnsuspendActionType.java @@ -16,6 +16,7 @@ package google.registry.ui.server.console.domains; import com.google.gson.JsonElement; import google.registry.model.console.ConsolePermission; +import google.registry.model.console.ConsoleUpdateHistory; /** An action that will unsuspend the given domain, removing all 5 server*Prohibited statuses. */ public class ConsoleBulkDomainUnsuspendActionType extends ConsoleDomainActionType { @@ -64,4 +65,9 @@ public class ConsoleBulkDomainUnsuspendActionType extends ConsoleDomainActionTyp public ConsolePermission getNecessaryPermission() { return ConsolePermission.SUSPEND_DOMAIN; } + + @Override + public ConsoleUpdateHistory.Type getConsoleUpdateHistoryType() { + return ConsoleUpdateHistory.Type.DOMAIN_UNSUSPEND; + } } diff --git a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleDomainActionType.java b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleDomainActionType.java index 47fdd953e..cbf528b31 100644 --- a/core/src/main/java/google/registry/ui/server/console/domains/ConsoleDomainActionType.java +++ b/core/src/main/java/google/registry/ui/server/console/domains/ConsoleDomainActionType.java @@ -18,6 +18,7 @@ import com.google.common.escape.Escaper; import com.google.common.xml.XmlEscapers; import com.google.gson.JsonElement; import google.registry.model.console.ConsolePermission; +import google.registry.model.console.ConsoleUpdateHistory; /** * A type of EPP action to perform on domain(s), run by the {@link ConsoleBulkDomainAction}. @@ -68,6 +69,9 @@ public abstract class ConsoleDomainActionType { /** Returns the permission necessary to successfully perform this action. */ public abstract ConsolePermission getNecessaryPermission(); + /** Returns the type of history / audit logging object to save. */ + public abstract ConsoleUpdateHistory.Type getConsoleUpdateHistoryType(); + /** Returns the XML template contents for this action. */ protected abstract String getXmlTemplate(); diff --git a/core/src/main/java/google/registry/ui/server/console/settings/SecurityAction.java b/core/src/main/java/google/registry/ui/server/console/settings/SecurityAction.java index d4603e0f4..6f23f7dc7 100644 --- a/core/src/main/java/google/registry/ui/server/console/settings/SecurityAction.java +++ b/core/src/main/java/google/registry/ui/server/console/settings/SecurityAction.java @@ -26,7 +26,7 @@ import google.registry.flows.certs.CertificateChecker; import google.registry.flows.certs.CertificateChecker.InsecureCertificateException; import google.registry.model.console.ConsolePermission; import google.registry.model.console.ConsoleUpdateHistory; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.registrar.Registrar; import google.registry.request.Action; @@ -120,10 +120,9 @@ public class SecurityAction extends ConsoleApiAction { Registrar updatedRegistrar = updatedRegistrarBuilder.build(); tm().put(updatedRegistrar); finishAndPersistConsoleUpdateHistory( - new RegistrarUpdateHistory.Builder() - .setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE) - .setRegistrar(updatedRegistrar) - .setRequestBody(consoleApiParams.gson().toJson(registrar.get()))); + new SimpleConsoleUpdateHistory.Builder() + .setType(ConsoleUpdateHistory.Type.REGISTRAR_SECURITY_UPDATE) + .setDescription(registrarId)); sendExternalUpdatesIfNecessary( EmailInfo.create(savedRegistrar, updatedRegistrar, ImmutableSet.of(), ImmutableSet.of())); diff --git a/core/src/main/java/google/registry/ui/server/console/settings/WhoisRegistrarFieldsAction.java b/core/src/main/java/google/registry/ui/server/console/settings/WhoisRegistrarFieldsAction.java index 7c90427d8..356e1e7b5 100644 --- a/core/src/main/java/google/registry/ui/server/console/settings/WhoisRegistrarFieldsAction.java +++ b/core/src/main/java/google/registry/ui/server/console/settings/WhoisRegistrarFieldsAction.java @@ -23,7 +23,7 @@ import static jakarta.servlet.http.HttpServletResponse.SC_OK; import google.registry.model.console.ConsolePermission; import google.registry.model.console.ConsoleUpdateHistory; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.registrar.Registrar; import google.registry.request.Action; @@ -107,10 +107,9 @@ public class WhoisRegistrarFieldsAction extends ConsoleApiAction { .build(); tm().put(newRegistrar); finishAndPersistConsoleUpdateHistory( - new RegistrarUpdateHistory.Builder() + new SimpleConsoleUpdateHistory.Builder() .setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE) - .setRegistrar(newRegistrar) - .setRequestBody(consoleApiParams.gson().toJson(registrar.get()))); + .setDescription(newRegistrar.getRegistrarId())); sendExternalUpdatesIfNecessary( EmailInfo.create( savedRegistrar, diff --git a/core/src/main/resources/META-INF/persistence.xml b/core/src/main/resources/META-INF/persistence.xml index 77d690e0a..ee8777230 100644 --- a/core/src/main/resources/META-INF/persistence.xml +++ b/core/src/main/resources/META-INF/persistence.xml @@ -50,6 +50,7 @@ google.registry.model.console.ConsoleEppActionHistory google.registry.model.console.RegistrarPocUpdateHistory google.registry.model.console.RegistrarUpdateHistory + google.registry.model.console.SimpleConsoleUpdateHistory google.registry.model.console.User google.registry.model.console.UserUpdateHistory google.registry.model.contact.ContactHistory diff --git a/core/src/test/java/google/registry/model/console/ConsoleEppActionHistoryTest.java b/core/src/test/java/google/registry/model/console/ConsoleEppActionHistoryTest.java index 53bcdd669..59ce65c94 100644 --- a/core/src/test/java/google/registry/model/console/ConsoleEppActionHistoryTest.java +++ b/core/src/test/java/google/registry/model/console/ConsoleEppActionHistoryTest.java @@ -53,7 +53,7 @@ public class ConsoleEppActionHistoryTest extends EntityTestCase { DomainHistory domainHistory = getOnlyElement(DatabaseHelper.loadAllOf(DomainHistory.class)); ConsoleEppActionHistory history = new ConsoleEppActionHistory.Builder() - .setType(ConsoleUpdateHistory.Type.EPP_ACTION) + .setType(ConsoleUpdateHistory.Type.DOMAIN_DELETE) .setActingUser(user) .setModificationTime(fakeClock.nowUtc()) .setMethod("POST") diff --git a/core/src/test/java/google/registry/model/console/SimpleConsoleUpdateHistoryTest.java b/core/src/test/java/google/registry/model/console/SimpleConsoleUpdateHistoryTest.java new file mode 100644 index 000000000..784d560f5 --- /dev/null +++ b/core/src/test/java/google/registry/model/console/SimpleConsoleUpdateHistoryTest.java @@ -0,0 +1,62 @@ +// Copyright 2025 The Nomulus Authors. All Rights Reserved. +// +// 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 google.registry.model.console; + +import static com.google.common.truth.Truth.assertThat; +import static google.registry.testing.DatabaseHelper.createTld; +import static google.registry.testing.DatabaseHelper.loadByEntity; +import static google.registry.testing.DatabaseHelper.persistActiveContact; +import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources; +import static google.registry.testing.DatabaseHelper.persistResource; + +import google.registry.model.EntityTestCase; +import google.registry.testing.DatabaseHelper; +import google.registry.util.DateTimeUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class SimpleConsoleUpdateHistoryTest extends EntityTestCase { + SimpleConsoleUpdateHistoryTest() { + super(JpaEntityCoverageCheck.ENABLED); + } + + @BeforeEach + void beforeEach() { + createTld("tld"); + persistDomainWithDependentResources( + "example", + "tld", + persistActiveContact("contact1234"), + fakeClock.nowUtc(), + fakeClock.nowUtc(), + DateTimeUtils.END_OF_TIME); + } + + @Test + void testPersistence() { + User user = persistResource(DatabaseHelper.createAdminUser("email@email.com")); + SimpleConsoleUpdateHistory history = + new SimpleConsoleUpdateHistory.Builder() + .setType(ConsoleUpdateHistory.Type.DOMAIN_SUSPEND) + .setActingUser(user) + .setMethod("POST") + .setUrl("/console-api/bulk-domain") + .setDescription("example.tld") + .setModificationTime(fakeClock.nowUtc()) + .build(); + persistResource(history); + assertThat(loadByEntity(history)).isEqualTo(history); + } +} diff --git a/core/src/test/java/google/registry/schema/integration/SqlIntegrationTestSuite.java b/core/src/test/java/google/registry/schema/integration/SqlIntegrationTestSuite.java index ccf1aceeb..527be6b54 100644 --- a/core/src/test/java/google/registry/schema/integration/SqlIntegrationTestSuite.java +++ b/core/src/test/java/google/registry/schema/integration/SqlIntegrationTestSuite.java @@ -27,6 +27,7 @@ import google.registry.model.common.FeatureFlagTest; import google.registry.model.console.ConsoleEppActionHistoryTest; import google.registry.model.console.RegistrarPocUpdateHistoryTest; import google.registry.model.console.RegistrarUpdateHistoryTest; +import google.registry.model.console.SimpleConsoleUpdateHistoryTest; import google.registry.model.console.UserTest; import google.registry.model.console.UserUpdateHistoryTest; import google.registry.model.contact.ContactTest; @@ -113,12 +114,13 @@ import org.junit.runner.RunWith; RegistrarDaoTest.class, RegistrarPocUpdateHistoryTest.class, RegistrarUpdateHistoryTest.class, - TldTest.class, ReservedListDaoTest.class, RegistryLockDaoTest.class, ServerSecretTest.class, + SimpleConsoleUpdateHistoryTest.class, SignedMarkRevocationListDaoTest.class, Spec11ThreatMatchTest.class, + TldTest.class, TmchCrlTest.class, UserTest.class, UserUpdateHistoryTest.class, diff --git a/core/src/test/java/google/registry/ui/server/console/ConsoleEppPasswordActionTest.java b/core/src/test/java/google/registry/ui/server/console/ConsoleEppPasswordActionTest.java index 89ed1fa63..49737f9ba 100644 --- a/core/src/test/java/google/registry/ui/server/console/ConsoleEppPasswordActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/ConsoleEppPasswordActionTest.java @@ -32,8 +32,9 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSetMultimap; import com.google.gson.Gson; import google.registry.flows.PasswordOnlyTransportCredentials; +import google.registry.model.console.ConsoleUpdateHistory; import google.registry.model.console.GlobalRole; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.console.UserRoles; import google.registry.model.registrar.Registrar; @@ -138,14 +139,10 @@ class ConsoleEppPasswordActionTest { createAction("TheRegistrar", "foobar", "randomPassword", "randomPassword"); action.run(); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK); - assertDoesNotThrow( - () -> { - credentials.validate(loadRegistrar("TheRegistrar"), "randomPassword"); - }); - assertThat(loadSingleton(RegistrarUpdateHistory.class).get().getRequestBody()) - .isEqualTo( - "{\"registrarId\":\"TheRegistrar\",\"oldPassword\":\"********\",\"newPassword\":" - + "\"••••••••\",\"newPasswordRepeat\":\"••••••••\"}"); + assertDoesNotThrow(() -> credentials.validate(loadRegistrar("TheRegistrar"), "randomPassword")); + SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get(); + assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.EPP_PASSWORD_UPDATE); + assertThat(history.getDescription()).hasValue("TheRegistrar"); } private ConsoleEppPasswordAction createAction( diff --git a/core/src/test/java/google/registry/ui/server/console/ConsoleUpdateRegistrarActionTest.java b/core/src/test/java/google/registry/ui/server/console/ConsoleUpdateRegistrarActionTest.java index 456e3d5f3..e2361d955 100644 --- a/core/src/test/java/google/registry/ui/server/console/ConsoleUpdateRegistrarActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/ConsoleUpdateRegistrarActionTest.java @@ -15,7 +15,6 @@ package google.registry.ui.server.console; import static com.google.common.truth.Truth.assertThat; -import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects; import static google.registry.model.registrar.RegistrarPocBase.Type.WHOIS; import static google.registry.testing.DatabaseHelper.createTlds; import static google.registry.testing.DatabaseHelper.loadSingleton; @@ -30,8 +29,9 @@ import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.gson.Gson; +import google.registry.model.console.ConsoleUpdateHistory; import google.registry.model.console.GlobalRole; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.console.UserRoles; import google.registry.model.registrar.Registrar; @@ -108,9 +108,9 @@ class ConsoleUpdateRegistrarActionTest { assertThat(newRegistrar.getAllowedTlds()).containsExactly("app", "dev"); assertThat(newRegistrar.isRegistryLockAllowed()).isFalse(); assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK); - assertAboutImmutableObjects() - .that(newRegistrar) - .hasFieldsEqualTo(loadSingleton(RegistrarUpdateHistory.class).get().getRegistrar()); + SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get(); + assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE); + assertThat(history.getDescription()).hasValue("TheRegistrar"); } @Test diff --git a/core/src/test/java/google/registry/ui/server/console/RegistrarsActionTest.java b/core/src/test/java/google/registry/ui/server/console/RegistrarsActionTest.java index d5ae005d2..c6f040487 100644 --- a/core/src/test/java/google/registry/ui/server/console/RegistrarsActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/RegistrarsActionTest.java @@ -15,7 +15,6 @@ package google.registry.ui.server.console; import static com.google.common.truth.Truth.assertThat; -import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects; import static google.registry.testing.DatabaseHelper.loadAllOf; import static google.registry.testing.DatabaseHelper.loadRegistrar; import static google.registry.testing.DatabaseHelper.loadSingleton; @@ -30,9 +29,10 @@ import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; +import google.registry.model.console.ConsoleUpdateHistory; import google.registry.model.console.GlobalRole; import google.registry.model.console.RegistrarRole; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.console.UserRoles; import google.registry.model.registrar.Registrar; @@ -186,9 +186,9 @@ class RegistrarsActionTest { .findAny() .isPresent()) .isTrue(); - assertAboutImmutableObjects() - .that(r) - .isEqualExceptFields(loadSingleton(RegistrarUpdateHistory.class).get().getRegistrar()); + SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get(); + assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.REGISTRAR_CREATE); + assertThat(history.getDescription()).hasValue("regIdTest"); } @Test diff --git a/core/src/test/java/google/registry/ui/server/console/domains/ConsoleBulkDomainActionTest.java b/core/src/test/java/google/registry/ui/server/console/domains/ConsoleBulkDomainActionTest.java index e808d948e..69df63afd 100644 --- a/core/src/test/java/google/registry/ui/server/console/domains/ConsoleBulkDomainActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/domains/ConsoleBulkDomainActionTest.java @@ -19,6 +19,7 @@ import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATAS import static google.registry.model.common.FeatureFlag.FeatureStatus.INACTIVE; import static google.registry.testing.DatabaseHelper.createTld; import static google.registry.testing.DatabaseHelper.loadByEntity; +import static google.registry.testing.DatabaseHelper.loadSingleton; import static google.registry.testing.DatabaseHelper.persistActiveContact; import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources; import static google.registry.testing.DatabaseHelper.persistResource; @@ -38,8 +39,10 @@ import google.registry.flows.DaggerEppTestComponent; import google.registry.flows.EppController; import google.registry.flows.EppTestComponent; import google.registry.model.common.FeatureFlag; +import google.registry.model.console.ConsoleUpdateHistory; import google.registry.model.console.GlobalRole; import google.registry.model.console.RegistrarRole; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.console.UserRoles; import google.registry.model.domain.Domain; @@ -120,6 +123,9 @@ public class ConsoleBulkDomainActionTest { {"example.tld":{"message":"Command completed successfully; action pending",\ "responseCode":1001}}"""); assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35)); + SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get(); + assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_DELETE); + assertThat(history.getDescription()).hasValue("example.tld"); } @Test @@ -145,6 +151,9 @@ public class ConsoleBulkDomainActionTest { {"example.tld":{"message":"Command completed successfully","responseCode":1000}}"""); assertThat(loadByEntity(domain).getStatusValues()) .containsAtLeastElementsIn(serverSuspensionStatuses); + SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get(); + assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_SUSPEND); + assertThat(history.getDescription()).hasValue("example.tld"); } @Test @@ -172,6 +181,9 @@ public class ConsoleBulkDomainActionTest { """ {"example.tld":{"message":"Command completed successfully","responseCode":1000}}"""); assertThat(loadByEntity(domain).getStatusValues()).containsNoneIn(serverSuspensionStatuses); + SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get(); + assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_UNSUSPEND); + assertThat(history.getDescription()).hasValue("example.tld"); } @Test @@ -194,6 +206,9 @@ public class ConsoleBulkDomainActionTest { "nonexistent.tld":{"message":"The domain with given ID (nonexistent.tld) doesn\\u0027t exist.",\ "responseCode":2303}}"""); assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35)); + SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get(); + assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_DELETE); + assertThat(history.getDescription()).hasValue("example.tld"); } @Test diff --git a/core/src/test/java/google/registry/ui/server/console/settings/SecurityActionTest.java b/core/src/test/java/google/registry/ui/server/console/settings/SecurityActionTest.java index e7bda7b48..11d827582 100644 --- a/core/src/test/java/google/registry/ui/server/console/settings/SecurityActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/settings/SecurityActionTest.java @@ -15,7 +15,6 @@ package google.registry.ui.server.console.settings; import static com.google.common.truth.Truth.assertThat; -import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects; import static google.registry.testing.CertificateSamples.SAMPLE_CERT2; import static google.registry.testing.DatabaseHelper.loadRegistrar; import static google.registry.testing.DatabaseHelper.loadSingleton; @@ -30,7 +29,8 @@ import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.ImmutableSortedMap; import com.google.gson.Gson; import google.registry.flows.certs.CertificateChecker; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.ConsoleUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.registrar.Registrar; import google.registry.persistence.transaction.JpaTestExtensions; import google.registry.request.Action; @@ -101,9 +101,9 @@ class SecurityActionTest { .isEqualTo("GNd6ZP8/n91t9UTnpxR8aH7aAW4+CpvufYx9ViGbcMY"); assertThat(r.getIpAddressAllowList().get(0).getIp()).isEqualTo("192.168.1.1"); assertThat(r.getIpAddressAllowList().get(0).getNetmask()).isEqualTo(32); - assertAboutImmutableObjects() - .that(loadSingleton(RegistrarUpdateHistory.class).get().getRegistrar()) - .hasFieldsEqualTo(r); + SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get(); + assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.REGISTRAR_SECURITY_UPDATE); + assertThat(history.getDescription()).hasValue("registrarId"); } private SecurityAction createAction(AuthResult authResult, String registrarId) diff --git a/core/src/test/java/google/registry/ui/server/console/settings/WhoisRegistrarFieldsActionTest.java b/core/src/test/java/google/registry/ui/server/console/settings/WhoisRegistrarFieldsActionTest.java index 298f68cf9..200f65d89 100644 --- a/core/src/test/java/google/registry/ui/server/console/settings/WhoisRegistrarFieldsActionTest.java +++ b/core/src/test/java/google/registry/ui/server/console/settings/WhoisRegistrarFieldsActionTest.java @@ -27,8 +27,9 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Maps; import com.google.gson.Gson; +import google.registry.model.console.ConsoleUpdateHistory; import google.registry.model.console.RegistrarRole; -import google.registry.model.console.RegistrarUpdateHistory; +import google.registry.model.console.SimpleConsoleUpdateHistory; import google.registry.model.console.User; import google.registry.model.console.UserRoles; import google.registry.model.registrar.Registrar; @@ -131,9 +132,9 @@ public class WhoisRegistrarFieldsActionTest { .that(newRegistrar) .isEqualExceptFields( oldRegistrar, "whoisServer", "url", "localizedAddress", "phoneNumber", "faxNumber"); - assertAboutImmutableObjects() - .that(loadSingleton(RegistrarUpdateHistory.class).get().getRegistrar()) - .hasFieldsEqualTo(newRegistrar); + SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get(); + assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE); + assertThat(history.getDescription()).hasValue("TheRegistrar"); } @Test diff --git a/db/src/main/resources/sql/er_diagram/brief_er_diagram.html b/db/src/main/resources/sql/er_diagram/brief_er_diagram.html index 4cb28c0c9..91f21d391 100644 --- a/db/src/main/resources/sql/er_diagram/brief_er_diagram.html +++ b/db/src/main/resources/sql/er_diagram/brief_er_diagram.html @@ -261,7 +261,7 @@ td.section { generated on - 2025-03-07 18:24:45 + 2025-03-10 15:53:40 last flyway file @@ -280,7 +280,7 @@ td.section { generated by SchemaCrawler 16.25.2 generated on - 2025-03-07 18:24:45 + 2025-03-10 15:53:40 diff --git a/db/src/main/resources/sql/er_diagram/full_er_diagram.html b/db/src/main/resources/sql/er_diagram/full_er_diagram.html index 575c0c7c4..d947102f1 100644 --- a/db/src/main/resources/sql/er_diagram/full_er_diagram.html +++ b/db/src/main/resources/sql/er_diagram/full_er_diagram.html @@ -261,7 +261,7 @@ td.section { </tr> <tr> <td class="property_name">generated on</td> - <td class="property_value">2025-03-07 18:24:42</td> + <td class="property_value">2025-03-10 15:53:36</td> </tr> <tr> <td class="property_name">last flyway file</td> @@ -280,7 +280,7 @@ td.section { <text text-anchor="start" x="5321" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">generated by</text> <text text-anchor="start" x="5404" y="-29.8" font-family="Helvetica,sans-Serif" font-size="14.00">SchemaCrawler 16.25.2</text> <text text-anchor="start" x="5320" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">generated on</text> - <text text-anchor="start" x="5404" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">2025-03-07 18:24:42</text> + <text text-anchor="start" x="5404" y="-10.8" font-family="Helvetica,sans-Serif" font-size="14.00">2025-03-10 15:53:36</text> <polygon fill="none" stroke="#888888" points="5317,-4 5317,-44 5553,-44 5553,-4 5317,-4" /> <!-- allocationtoken_a08ccbef --> <g id="node1" class="node"> <title> diff --git a/db/src/main/resources/sql/schema/db-schema.sql.generated b/db/src/main/resources/sql/schema/db-schema.sql.generated index f887e8b32..9b1706df8 100644 --- a/db/src/main/resources/sql/schema/db-schema.sql.generated +++ b/db/src/main/resources/sql/schema/db-schema.sql.generated @@ -139,7 +139,7 @@ history_method text not null, history_modification_time timestamp(6) with time zone not null, history_request_body text, - history_type text not null check (history_type in ('EPP_ACTION','POC_CREATE','POC_UPDATE','POC_DELETE','REGISTRAR_UPDATE','USER_CREATE','USER_DELETE','USER_UPDATE')), + history_type text not null check (history_type in ('DOMAIN_DELETE','DOMAIN_SUSPEND','DOMAIN_UNSUSPEND','EPP_PASSWORD_UPDATE','REGISTRAR_CREATE','REGISTRAR_SECURITY_UPDATE','REGISTRAR_UPDATE','USER_CREATE','USER_DELETE','USER_UPDATE')), history_url text not null, history_entry_class text not null, repo_id text not null, @@ -148,6 +148,17 @@ primary key (history_revision_id) ); + create table "ConsoleUpdateHistory" ( + revision_id bigint not null, + description text, + method text not null, + modification_time timestamp(6) with time zone not null, + type text not null check (type in ('DOMAIN_DELETE','DOMAIN_SUSPEND','DOMAIN_UNSUSPEND','EPP_PASSWORD_UPDATE','REGISTRAR_CREATE','REGISTRAR_SECURITY_UPDATE','REGISTRAR_UPDATE','USER_CREATE','USER_DELETE','USER_UPDATE')), + url text not null, + acting_user text not null, + primary key (revision_id) + ); + create table "Contact" ( repo_id text not null, update_timestamp timestamp(6) with time zone, @@ -693,7 +704,7 @@ history_method text not null, history_modification_time timestamp(6) with time zone not null, history_request_body text, - history_type text not null check (history_type in ('EPP_ACTION','POC_CREATE','POC_UPDATE','POC_DELETE','REGISTRAR_UPDATE','USER_CREATE','USER_DELETE','USER_UPDATE')), + history_type text not null check (history_type in ('DOMAIN_DELETE','DOMAIN_SUSPEND','DOMAIN_UNSUSPEND','EPP_PASSWORD_UPDATE','REGISTRAR_CREATE','REGISTRAR_SECURITY_UPDATE','REGISTRAR_UPDATE','USER_CREATE','USER_DELETE','USER_UPDATE')), history_url text not null, email_address text not null, registrar_id text not null, @@ -717,7 +728,7 @@ history_method text not null, history_modification_time timestamp(6) with time zone not null, history_request_body text, - history_type text not null check (history_type in ('EPP_ACTION','POC_CREATE','POC_UPDATE','POC_DELETE','REGISTRAR_UPDATE','USER_CREATE','USER_DELETE','USER_UPDATE')), + history_type text not null check (history_type in ('DOMAIN_DELETE','DOMAIN_SUSPEND','DOMAIN_UNSUSPEND','EPP_PASSWORD_UPDATE','REGISTRAR_CREATE','REGISTRAR_SECURITY_UPDATE','REGISTRAR_UPDATE','USER_CREATE','USER_DELETE','USER_UPDATE')), history_url text not null, allowed_tlds text[], billing_account_map hstore, @@ -906,7 +917,7 @@ history_method text not null, history_modification_time timestamp(6) with time zone not null, history_request_body text, - history_type text not null check (history_type in ('EPP_ACTION','POC_CREATE','POC_UPDATE','POC_DELETE','REGISTRAR_UPDATE','USER_CREATE','USER_DELETE','USER_UPDATE')), + history_type text not null check (history_type in ('DOMAIN_DELETE','DOMAIN_SUSPEND','DOMAIN_UNSUSPEND','EPP_PASSWORD_UPDATE','REGISTRAR_CREATE','REGISTRAR_SECURITY_UPDATE','REGISTRAR_UPDATE','USER_CREATE','USER_DELETE','USER_UPDATE')), history_url text not null, email_address text not null, registry_lock_email_address text, @@ -1010,6 +1021,15 @@ create index IDXiahqo1d1fqdfknywmj2xbxl7t on "ConsoleEppActionHistory" (revision_id); + create index idx_console_update_history_acting_user + on "ConsoleUpdateHistory" (acting_user); + + create index idx_console_update_history_type + on "ConsoleUpdateHistory" (type); + + create index idx_console_update_history_modification_time + on "ConsoleUpdateHistory" (modification_time); + create index IDX3y752kr9uh4kh6uig54vemx0l on "Contact" (creation_time); @@ -1228,6 +1248,11 @@ foreign key (history_acting_user) references "User"; + alter table if exists "ConsoleUpdateHistory" + add constraint FKnhl1eolgix64u90xv3pj6xa3x + foreign key (acting_user) + references "User"; + alter table if exists "DelegationSignerData" add constraint FKtr24j9v14ph2mfuw2gsmt12kq foreign key (domain_repo_id)