mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 03:57:51 +02:00
Add RegistryLock SQL schema (#243)
* Add RegistryLock SQL schema * Refactor a bit * Move registrylock -> domain * Clearing up lock workflow * Add more docs and remove LockStatus * Responses to CR * Add repoId javadoc * Add registry lock to persistence xml file * Quote rather than backtick * Remove unnecessary check * File TODO * Remove uniqueness constraint on verification code * Remove import * add index * Add to SQL generation task * Move fields around to be the same order as Hibernate's generated sql
This commit is contained in:
parent
97ee4c3778
commit
1e7d4bded9
4 changed files with 270 additions and 0 deletions
|
@ -0,0 +1,237 @@
|
||||||
|
// Copyright 2019 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.schema.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static google.registry.util.DateTimeUtils.toJodaDateTime;
|
||||||
|
import static google.registry.util.DateTimeUtils.toZonedDateTime;
|
||||||
|
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||||
|
|
||||||
|
import google.registry.model.Buildable;
|
||||||
|
import google.registry.model.ImmutableObject;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.EnumType;
|
||||||
|
import javax.persistence.Enumerated;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Index;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a registry lock/unlock object, meaning that the domain is locked on the registry
|
||||||
|
* level.
|
||||||
|
*
|
||||||
|
* <p>Registry locks must be requested through the registrar console by a lock-enabled contact, then
|
||||||
|
* confirmed through email within a certain length of time. Until that confirmation is processed,
|
||||||
|
* the completion time will remain null and the lock will have no effect. The same applies for
|
||||||
|
* unlock actions.
|
||||||
|
*
|
||||||
|
* <p>Note that there will be at most one row per domain with a null copmleted time -- this means
|
||||||
|
* that there is at most one pending action per domain. This is enforced at the logic level.
|
||||||
|
*
|
||||||
|
* <p>Note as well that in the case of a retry of a write after an unexpected success, the unique
|
||||||
|
* constraint on {@link #verificationCode} means that the second write will fail.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(
|
||||||
|
// Unique constraint to get around Hibernate's failure to handle
|
||||||
|
// auto-increment field in composite primary key.
|
||||||
|
indexes =
|
||||||
|
@Index(
|
||||||
|
name = "idx_registry_lock_repo_id_revision_id",
|
||||||
|
columnList = "repo_id, revision_id",
|
||||||
|
unique = true))
|
||||||
|
public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||||
|
|
||||||
|
/** Describes the action taken by the user. */
|
||||||
|
public enum Action {
|
||||||
|
LOCK,
|
||||||
|
UNLOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "revision_id", nullable = false)
|
||||||
|
private Long revisionId;
|
||||||
|
|
||||||
|
/** EPP repo ID of the domain in question. */
|
||||||
|
@Column(name = "repo_id", nullable = false)
|
||||||
|
private String repoId;
|
||||||
|
|
||||||
|
// TODO (b/140568328): remove this when everything is in Cloud SQL and we can join on "domain"
|
||||||
|
@Column(name = "domain_name", nullable = false)
|
||||||
|
private String domainName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the registrar that performed the action -- this may be the admin ID if this action
|
||||||
|
* was performed by a superuser.
|
||||||
|
*/
|
||||||
|
@Column(name = "registrar_id", nullable = false)
|
||||||
|
private String registrarId;
|
||||||
|
|
||||||
|
/** The POC that performed the action, or null if it was a superuser. */
|
||||||
|
@Column(name = "registrar_poc_id")
|
||||||
|
private String registrarPocId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock action is immutable and describes whether the action performed was a lock or an unlock.
|
||||||
|
*/
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Column(name = "action", nullable = false)
|
||||||
|
private Action action;
|
||||||
|
|
||||||
|
/** Creation timestamp is when the lock/unlock is first requested. */
|
||||||
|
@Column(name = "creation_timestamp", nullable = false)
|
||||||
|
private ZonedDateTime creationTimestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completion timestamp is when the user has verified the lock/unlock, when this object de facto
|
||||||
|
* becomes immutable. If this field is null, it means that the lock has not been verified yet (and
|
||||||
|
* thus not been put into effect).
|
||||||
|
*/
|
||||||
|
@Column(name = "completion_timestamp")
|
||||||
|
private ZonedDateTime completionTimestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user must provide the random verification code in order to complete the lock and move the
|
||||||
|
* status from PENDING to COMPLETED.
|
||||||
|
*/
|
||||||
|
@Column(name = "verification_code", nullable = false)
|
||||||
|
private String verificationCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True iff this action was taken by a superuser, in response to something like a URS request. In
|
||||||
|
* this case, the action was performed by a registry admin rather than a registrar.
|
||||||
|
*/
|
||||||
|
@Column(name = "is_superuser", nullable = false)
|
||||||
|
private boolean isSuperuser;
|
||||||
|
|
||||||
|
public String getRepoId() {
|
||||||
|
return repoId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDomainName() {
|
||||||
|
return domainName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegistrarId() {
|
||||||
|
return registrarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegistrarPocId() {
|
||||||
|
return registrarPocId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime getCreationTimestamp() {
|
||||||
|
return toJodaDateTime(creationTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime getCompletionTimestamp() {
|
||||||
|
return toJodaDateTime(completionTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVerificationCode() {
|
||||||
|
return verificationCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuperuser() {
|
||||||
|
return isSuperuser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getRevisionId() {
|
||||||
|
return revisionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder asBuilder() {
|
||||||
|
return new Builder(clone(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builder for {@link google.registry.schema.domain.RegistryLock}. */
|
||||||
|
public static class Builder extends Buildable.Builder<RegistryLock> {
|
||||||
|
public Builder() {}
|
||||||
|
|
||||||
|
private Builder(RegistryLock instance) {
|
||||||
|
super(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RegistryLock build() {
|
||||||
|
checkArgumentNotNull(getInstance().repoId, "Repo ID cannot be null");
|
||||||
|
checkArgumentNotNull(getInstance().domainName, "Domain name cannot be null");
|
||||||
|
checkArgumentNotNull(getInstance().registrarId, "Registrar ID cannot be null");
|
||||||
|
checkArgumentNotNull(getInstance().action, "Action cannot be null");
|
||||||
|
checkArgumentNotNull(getInstance().creationTimestamp, "Creation timestamp cannot be null");
|
||||||
|
checkArgumentNotNull(getInstance().verificationCode, "Verification codecannot be null");
|
||||||
|
checkArgument(
|
||||||
|
getInstance().registrarPocId != null || getInstance().isSuperuser,
|
||||||
|
"Registrar POC ID must be provided if superuser is false");
|
||||||
|
return super.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setRepoId(String repoId) {
|
||||||
|
getInstance().repoId = repoId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setDomainName(String domainName) {
|
||||||
|
getInstance().domainName = domainName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setRegistrarId(String registrarId) {
|
||||||
|
getInstance().registrarId = registrarId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setRegistrarPocId(String registrarPocId) {
|
||||||
|
getInstance().registrarPocId = registrarPocId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setAction(Action action) {
|
||||||
|
getInstance().action = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setCreationTimestamp(DateTime creationTimestamp) {
|
||||||
|
getInstance().creationTimestamp = toZonedDateTime(creationTimestamp);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setCompletionTimestamp(DateTime lockTimestamp) {
|
||||||
|
getInstance().completionTimestamp = toZonedDateTime(lockTimestamp);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setVerificationCode(String verificationCode) {
|
||||||
|
getInstance().verificationCode = verificationCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder isSuperuser(boolean isSuperuser) {
|
||||||
|
getInstance().isSuperuser = isSuperuser;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ import google.registry.model.eppcommon.Trid;
|
||||||
import google.registry.model.transfer.BaseTransferObject;
|
import google.registry.model.transfer.BaseTransferObject;
|
||||||
import google.registry.model.transfer.TransferData;
|
import google.registry.model.transfer.TransferData;
|
||||||
import google.registry.persistence.NomulusNamingStrategy;
|
import google.registry.persistence.NomulusNamingStrategy;
|
||||||
|
import google.registry.schema.domain.RegistryLock;
|
||||||
import google.registry.schema.tld.PremiumList;
|
import google.registry.schema.tld.PremiumList;
|
||||||
import google.registry.schema.tmch.ClaimsList;
|
import google.registry.schema.tmch.ClaimsList;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -68,6 +69,7 @@ public class GenerateSqlSchemaCommand implements Command {
|
||||||
GracePeriod.class,
|
GracePeriod.class,
|
||||||
Period.class,
|
Period.class,
|
||||||
PremiumList.class,
|
PremiumList.class,
|
||||||
|
RegistryLock.class,
|
||||||
TransferData.class,
|
TransferData.class,
|
||||||
Trid.class);
|
Trid.class);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
* Use Hibernate's ServiceRegistry for bootstrapping (not JPA-compliant)
|
* Use Hibernate's ServiceRegistry for bootstrapping (not JPA-compliant)
|
||||||
-->
|
-->
|
||||||
<class>google.registry.model.domain.DomainBase</class>
|
<class>google.registry.model.domain.DomainBase</class>
|
||||||
|
<class>google.registry.schema.domain.RegistryLock</class>
|
||||||
<class>google.registry.schema.tmch.ClaimsList</class>
|
<class>google.registry.schema.tmch.ClaimsList</class>
|
||||||
<class>google.registry.model.transfer.BaseTransferObject</class>
|
<class>google.registry.model.transfer.BaseTransferObject</class>
|
||||||
<class>google.registry.schema.tld.PremiumList</class>
|
<class>google.registry.schema.tld.PremiumList</class>
|
||||||
|
|
30
db/src/main/resources/sql/schema/registry_lock.sql
Normal file
30
db/src/main/resources/sql/schema/registry_lock.sql
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
-- Copyright 2019 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.
|
||||||
|
|
||||||
|
CREATE TABLE "RegistryLock" (
|
||||||
|
revision_id BIGSERIAL NOT NULL,
|
||||||
|
action TEXT NOT NULL,
|
||||||
|
completion_timestamp TIMESTAMPTZ,
|
||||||
|
creation_timestamp TIMESTAMPTZ NOT NULL,
|
||||||
|
domain_name TEXT NOT NULL,
|
||||||
|
is_superuser BOOLEAN NOT NULL,
|
||||||
|
registrar_id TEXT NOT NULL,
|
||||||
|
registrar_poc_id TEXT,
|
||||||
|
repo_id TEXT NOT NULL,
|
||||||
|
verification_code TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (revision_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE IF EXISTS "RegistryLock"
|
||||||
|
ADD CONSTRAINT idx_registry_lock_repo_id_revision_id UNIQUE (repo_id, revision_id);
|
Loading…
Add table
Reference in a new issue