Add autoRenewEndTime field to Domain entity (#765)

* Add autoRenewEndTime field to Domain entity

This is the first step towards allowing administrators to selectively disable autorenew.
This commit is contained in:
Ben McIlwain 2020-08-13 10:40:11 -04:00 committed by GitHub
parent 83dadc77d1
commit a5bad9a2a4
9 changed files with 103 additions and 20 deletions

View file

@ -25,6 +25,11 @@
<property name="tld" direction="asc"/>
<property name="creationTime" direction="desc"/>
</datastore-index>
<!-- For finding non-autorenewing domains to be deleted. -->
<datastore-index kind="DomainBase" ancestor="false" source="manual">
<property name="autorenewEndTime" direction="asc"/>
<property name="deletionTime" direction="asc"/>
</datastore-index>
<!-- For finding host resources by registrar. -->
<datastore-index kind="HostResource" ancestor="false" source="manual">
<property name="currentSponsorClientId" direction="asc"/>

View file

@ -16,7 +16,6 @@ package google.registry.model.domain;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
import google.registry.model.EppResource;
import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.annotations.ExternalMessagingName;
@ -31,10 +30,13 @@ import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.joda.time.DateTime;
/**
@ -47,16 +49,17 @@ import org.joda.time.DateTime;
* @see <a href="https://tools.ietf.org/html/rfc5731">RFC 5731</a>
*/
@ReportedOn
@Entity
@javax.persistence.Entity(name = "Domain")
@javax.persistence.Table(
@com.googlecode.objectify.annotation.Entity
@Entity(name = "Domain")
@Table(
name = "Domain",
indexes = {
@javax.persistence.Index(columnList = "creationTime"),
@javax.persistence.Index(columnList = "currentSponsorRegistrarId"),
@javax.persistence.Index(columnList = "deletionTime"),
@javax.persistence.Index(columnList = "domainName"),
@javax.persistence.Index(columnList = "tld")
@Index(columnList = "creationTime"),
@Index(columnList = "currentSponsorRegistrarId"),
@Index(columnList = "deletionTime"),
@Index(columnList = "domainName"),
@Index(columnList = "tld"),
@Index(columnList = "autorenewEndTime")
})
@WithStringVKey
@ExternalMessagingName("domain")

View file

@ -252,11 +252,27 @@ public class DomainContent extends EppResource
*/
DateTime lastTransferTime;
/**
* When the domain's autorenewal status will expire.
*
* <p>This will be null for the vast majority of domains because all domains autorenew
* indefinitely by default and autorenew can only be countermanded by administrators, typically
* for reasons of the URS process or termination of a registrar for nonpayment.
*
* <p>When a domain is scheduled to not autorenew, this field is set to the current value of its
* {@link #registrationExpirationTime}, after which point the next invocation of a periodic
* cronjob will explicitly delete the domain. This field is a DateTime and not a boolean because
* of edge cases that occur during the autorenew grace period. We need to be able to tell the
* difference domains that have reached their life and must be deleted now, and domains that
* happen to be in the autorenew grace period now but should be deleted in roughly a year.
*/
@Nullable @Index DateTime autorenewEndTime;
@OnLoad
void load() {
// Reconstitute all of the contacts so that they have VKeys.
allContacts =
allContacts.stream().map(contact -> contact.reconstitute()).collect(toImmutableSet());
allContacts.stream().map(DesignatedContact::reconstitute).collect(toImmutableSet());
setContactFields(allContacts, true);
// We have to return the cloned object here because the original object's
@ -275,8 +291,7 @@ public class DomainContent extends EppResource
@PostLoad
void postLoad() {
// Reconstitute the contact list.
ImmutableSet.Builder<DesignatedContact> contactsBuilder =
new ImmutableSet.Builder<DesignatedContact>();
ImmutableSet.Builder<DesignatedContact> contactsBuilder = new ImmutableSet.Builder<>();
if (registrantContact != null) {
contactsBuilder.add(
@ -323,6 +338,10 @@ public class DomainContent extends EppResource
return smdId;
}
public Optional<DateTime> getAutorenewEndTime() {
return Optional.ofNullable(autorenewEndTime);
}
@Override
public DomainTransferData getTransferData() {
return Optional.ofNullable(transferData).orElse(DomainTransferData.EMPTY);
@ -835,6 +854,11 @@ public class DomainContent extends EppResource
return thisCastToDerived();
}
public B setAutorenewEndTime(Optional<DateTime> autorenewEndTime) {
getInstance().autorenewEndTime = autorenewEndTime.orElse(null);
return thisCastToDerived();
}
@Override
public B setTransferData(DomainTransferData transferData) {
getInstance().transferData = transferData;

View file

@ -14,14 +14,33 @@
package google.registry.tools;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import google.registry.model.SchemaVersion;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
/** Generates the schema file used for model versioning. */
@Parameters(commandDescription = "Generate a model schema file")
final class GetSchemaCommand implements Command {
@Parameter(
names = {"-o", "--out_file"},
description = "Name of the output file.")
String outFile;
@Override
public void run() {
System.out.println(SchemaVersion.getSchema());
public void run() throws IOException {
String schema = SchemaVersion.getSchema();
if (outFile == null) {
System.out.println(schema);
} else {
File file = new File(outFile);
file.createNewFile(); // Create the output file if it doesn't already exist.
Files.write(file.toPath(), schema.getBytes(UTF_8));
}
}
}

View file

@ -55,6 +55,7 @@ import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.persistence.VKey;
import java.util.Optional;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
@ -66,12 +67,11 @@ public class DomainBaseTest extends EntityTestCase {
private DomainBase domain;
private VKey<BillingEvent.OneTime> oneTimeBillKey;
private VKey<BillingEvent.Recurring> recurringBillKey;
private VKey<DomainBase> domainKey;
@BeforeEach
void setUp() {
createTld("com");
domainKey = VKey.from(Key.create(null, DomainBase.class, "4-COM"));
VKey<DomainBase> domainKey = VKey.from(Key.create(null, DomainBase.class, "4-COM"));
VKey<HostResource> hostKey =
persistResource(
new HostResource.Builder()
@ -158,6 +158,7 @@ public class DomainBaseTest extends EntityTestCase {
fakeClock.nowUtc().plusDays(1),
"registrar",
null))
.setAutorenewEndTime(Optional.of(fakeClock.nowUtc().plusYears(2)))
.build()));
}
@ -176,7 +177,8 @@ public class DomainBaseTest extends EntityTestCase {
"nsHosts",
"currentSponsorClientId",
"deletionTime",
"tld");
"tld",
"autorenewEndTime");
}
@Test

View file

@ -185,6 +185,7 @@ class google.registry.model.domain.DomainBase {
java.util.Set<google.registry.model.eppcommon.StatusValue> status;
java.util.Set<google.registry.persistence.VKey<google.registry.model.host.HostResource>> nsHosts;
java.util.Set<java.lang.String> subordinateHosts;
org.joda.time.DateTime autorenewEndTime;
org.joda.time.DateTime deletionTime;
org.joda.time.DateTime lastEppUpdateTime;
org.joda.time.DateTime lastTransferTime;

View file

@ -0,0 +1,17 @@
-- Copyright 2020 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.
ALTER TABLE "Domain" ADD COLUMN autorenew_end_time timestamptz;
ALTER TABLE "DomainHistory" ADD COLUMN autorenew_end_time timestamptz;
CREATE INDEX IDXlrq7v63pc21uoh3auq6eybyhl ON "Domain" (autorenew_end_time);

View file

@ -233,6 +233,7 @@ create sequence history_id_sequence start 1 increment 1;
auth_info_repo_id text,
auth_info_value text,
billing_recurrence_id int8,
autorenew_end_time timestamptz,
autorenew_poll_message_id int8,
billing_contact text,
deletion_poll_message_id int8,
@ -283,6 +284,7 @@ create sequence history_id_sequence start 1 increment 1;
auth_info_repo_id text,
auth_info_value text,
billing_recurrence_id int8,
autorenew_end_time timestamptz,
autorenew_poll_message_id int8,
billing_contact text,
deletion_poll_message_id int8,
@ -591,6 +593,7 @@ create index IDXhsjqiy2lyobfymplb28nm74lm on "Domain" (current_sponsor_registrar
create index IDX5mnf0wn20tno4b9do88j61klr on "Domain" (deletion_time);
create index IDXc5aw4pk1vkd6ymhvkpanmoadv on "Domain" (domain_name);
create index IDXrwl38wwkli1j7gkvtywi9jokq on "Domain" (tld);
create index IDXlrq7v63pc21uoh3auq6eybyhl on "Domain" (autorenew_end_time);
create index IDXrh4xmrot9bd63o382ow9ltfig on "DomainHistory" (creation_time);
create index IDXaro1omfuaxjwmotk3vo00trwm on "DomainHistory" (history_registrar_id);
create index IDXsu1nam10cjes9keobapn5jvxj on "DomainHistory" (history_type);

View file

@ -401,7 +401,8 @@ CREATE TABLE public."Domain" (
update_timestamp timestamp with time zone,
billing_recurrence_id bigint,
autorenew_poll_message_id bigint,
deletion_poll_message_id bigint
deletion_poll_message_id bigint,
autorenew_end_time timestamp with time zone
);
@ -464,7 +465,8 @@ CREATE TABLE public."DomainHistory" (
last_epp_update_time timestamp with time zone,
statuses text[],
update_timestamp timestamp with time zone,
domain_repo_id text NOT NULL
domain_repo_id text NOT NULL,
autorenew_end_time timestamp with time zone
);
@ -1386,6 +1388,13 @@ CREATE INDEX idxkjt9yaq92876dstimd93hwckh ON public."Domain" USING btree (curren
CREATE INDEX idxknk8gmj7s47q56cwpa6rmpt5l ON public."HostHistory" USING btree (history_type);
--
-- Name: idxlrq7v63pc21uoh3auq6eybyhl; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX idxlrq7v63pc21uoh3auq6eybyhl ON public."Domain" USING btree (autorenew_end_time);
--
-- Name: idxn1f711wicdnooa2mqb7g1m55o; Type: INDEX; Schema: public; Owner: -
--