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.TransferData;
|
||||
import google.registry.persistence.NomulusNamingStrategy;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.schema.tld.PremiumList;
|
||||
import google.registry.schema.tmch.ClaimsList;
|
||||
import java.io.IOException;
|
||||
|
@ -68,6 +69,7 @@ public class GenerateSqlSchemaCommand implements Command {
|
|||
GracePeriod.class,
|
||||
Period.class,
|
||||
PremiumList.class,
|
||||
RegistryLock.class,
|
||||
TransferData.class,
|
||||
Trid.class);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* Use Hibernate's ServiceRegistry for bootstrapping (not JPA-compliant)
|
||||
-->
|
||||
<class>google.registry.model.domain.DomainBase</class>
|
||||
<class>google.registry.schema.domain.RegistryLock</class>
|
||||
<class>google.registry.schema.tmch.ClaimsList</class>
|
||||
<class>google.registry.model.transfer.BaseTransferObject</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