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;
@ -765,4 +766,4 @@ enum google.registry.model.transfer.TransferStatus {
PENDING;
SERVER_APPROVED;
SERVER_CANCELLED;
}
}