mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 07:57:13 +02:00
Add MR to expand billing events into OneTimes
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=124837292
This commit is contained in:
parent
7cf4ddce97
commit
2a83d122ef
6 changed files with 69 additions and 8 deletions
|
@ -265,6 +265,12 @@
|
||||||
<url-pattern>/_dr/task/dnsRefreshForHostRename</url-pattern>
|
<url-pattern>/_dr/task/dnsRefreshForHostRename</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<!-- Mapreduce to expand recurring billing events into OneTimes. -->
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>backend-servlet</servlet-name>
|
||||||
|
<url-pattern>/_dr/task/expandRecurringBillingEvents</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<!-- Security config -->
|
<!-- Security config -->
|
||||||
<security-constraint>
|
<security-constraint>
|
||||||
<web-resource-collection>
|
<web-resource-collection>
|
||||||
|
|
|
@ -20,8 +20,6 @@ import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
|
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.annotation.Entity;
|
import com.googlecode.objectify.annotation.Entity;
|
||||||
import com.googlecode.objectify.annotation.Id;
|
import com.googlecode.objectify.annotation.Id;
|
||||||
|
@ -69,7 +67,12 @@ public class Cursor extends ImmutableObject {
|
||||||
*/
|
*/
|
||||||
RDE_UPLOAD_SFTP(Registry.class),
|
RDE_UPLOAD_SFTP(Registry.class),
|
||||||
|
|
||||||
/** Cursor for ensuring rolling transactional isolation of recurring billing expansion. */
|
/**
|
||||||
|
* Cursor for ensuring rolling transactional isolation of recurring billing expansion. The
|
||||||
|
* value of this cursor represents the exclusive upper bound on the range of billing times
|
||||||
|
* for which Recurring billing events have been expanded (i.e. the inclusive first billing time
|
||||||
|
* for the next expansion job).
|
||||||
|
*/
|
||||||
RECURRING_BILLING(EntityGroupRoot.class);
|
RECURRING_BILLING(EntityGroupRoot.class);
|
||||||
|
|
||||||
/** See the definition of scope on {@link #getScopeClass}. */
|
/** See the definition of scope on {@link #getScopeClass}. */
|
||||||
|
@ -120,16 +123,14 @@ public class Cursor extends ImmutableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a unique key for a given scope and cursor type. */
|
/** Creates a unique key for a given scope and cursor type. */
|
||||||
@VisibleForTesting
|
public static Key<Cursor> createKey(CursorType cursorType, ImmutableObject scope) {
|
||||||
static Key<Cursor> createKey(CursorType cursorType, ImmutableObject scope) {
|
|
||||||
Key<? extends ImmutableObject> scopeKey = Key.create(scope);
|
Key<? extends ImmutableObject> scopeKey = Key.create(scope);
|
||||||
checkValidCursorTypeForScope(cursorType, scopeKey);
|
checkValidCursorTypeForScope(cursorType, scopeKey);
|
||||||
return Key.create(getCrossTldKey(), Cursor.class, generateId(cursorType, scopeKey));
|
return Key.create(getCrossTldKey(), Cursor.class, generateId(cursorType, scopeKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a unique key for a given global cursor type. */
|
/** Creates a unique key for a given global cursor type. */
|
||||||
@VisibleForTesting
|
public static Key<Cursor> createGlobalKey(CursorType cursorType) {
|
||||||
static Key<Cursor> createGlobalKey(CursorType cursorType) {
|
|
||||||
checkArgument(
|
checkArgument(
|
||||||
cursorType.getScopeClass().equals(EntityGroupRoot.class),
|
cursorType.getScopeClass().equals(EntityGroupRoot.class),
|
||||||
"Cursor type is not a global cursor.");
|
"Cursor type is not a global cursor.");
|
||||||
|
|
|
@ -14,11 +14,11 @@ java_library(
|
||||||
"//java/com/google/common/net",
|
"//java/com/google/common/net",
|
||||||
"//java/google/registry/backup",
|
"//java/google/registry/backup",
|
||||||
"//java/google/registry/bigquery",
|
"//java/google/registry/bigquery",
|
||||||
|
"//java/google/registry/billing",
|
||||||
"//java/google/registry/config",
|
"//java/google/registry/config",
|
||||||
"//java/google/registry/cron",
|
"//java/google/registry/cron",
|
||||||
"//java/google/registry/dns",
|
"//java/google/registry/dns",
|
||||||
"//java/google/registry/dns/writer/api",
|
"//java/google/registry/dns/writer/api",
|
||||||
"//java/google/registry/dns/writer/dnsupdate",
|
|
||||||
"//java/google/registry/export",
|
"//java/google/registry/export",
|
||||||
"//java/google/registry/export/sheet",
|
"//java/google/registry/export/sheet",
|
||||||
"//java/google/registry/flows",
|
"//java/google/registry/flows",
|
||||||
|
@ -35,6 +35,7 @@ java_library(
|
||||||
"//java/google/registry/util",
|
"//java/google/registry/util",
|
||||||
"//third_party/java/bouncycastle",
|
"//third_party/java/bouncycastle",
|
||||||
"//third_party/java/dagger",
|
"//third_party/java/dagger",
|
||||||
|
"//third_party/java/joda_time",
|
||||||
"//third_party/java/jsr305_annotations",
|
"//third_party/java/jsr305_annotations",
|
||||||
"//third_party/java/jsr330_inject",
|
"//third_party/java/jsr330_inject",
|
||||||
"//third_party/java/servlet/servlet_api",
|
"//third_party/java/servlet/servlet_api",
|
||||||
|
|
|
@ -15,14 +15,20 @@
|
||||||
package google.registry.module.backend;
|
package google.registry.module.backend;
|
||||||
|
|
||||||
import static google.registry.model.registry.Registries.assertTldExists;
|
import static google.registry.model.registry.Registries.assertTldExists;
|
||||||
|
import static google.registry.request.RequestParameters.extractOptionalDatetimeParameter;
|
||||||
import static google.registry.request.RequestParameters.extractRequiredParameter;
|
import static google.registry.request.RequestParameters.extractRequiredParameter;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import google.registry.billing.ExpandRecurringBillingEventsAction;
|
||||||
import google.registry.request.Parameter;
|
import google.registry.request.Parameter;
|
||||||
import google.registry.request.RequestParameters;
|
import google.registry.request.RequestParameters;
|
||||||
|
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,4 +42,11 @@ public class BackendModule {
|
||||||
static String provideTld(HttpServletRequest req) {
|
static String provideTld(HttpServletRequest req) {
|
||||||
return assertTldExists(extractRequiredParameter(req, RequestParameters.PARAM_TLD));
|
return assertTldExists(extractRequiredParameter(req, RequestParameters.PARAM_TLD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Parameter("cursorTime")
|
||||||
|
static Optional<DateTime> provideCursorTime(HttpServletRequest req) {
|
||||||
|
return extractOptionalDatetimeParameter(
|
||||||
|
req, ExpandRecurringBillingEventsAction.PARAM_CURSOR_TIME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,6 +160,25 @@ public final class RequestParameters {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns first request parameter associated with {@code name} parsed as an
|
||||||
|
* <a href="https://goo.gl/pk5Q2k">ISO 8601</a> timestamp, e.g. {@code 1984-12-18TZ},
|
||||||
|
* {@code 2000-01-01T16:20:00Z}.
|
||||||
|
*
|
||||||
|
* @throws BadRequestException if request parameter is present but not a valid {@link DateTime}.
|
||||||
|
*/
|
||||||
|
public static Optional<DateTime> extractOptionalDatetimeParameter(
|
||||||
|
HttpServletRequest req, String name) {
|
||||||
|
String stringParam = req.getParameter(name);
|
||||||
|
try {
|
||||||
|
return isNullOrEmpty(stringParam)
|
||||||
|
? Optional.<DateTime>absent()
|
||||||
|
: Optional.of(DateTime.parse(stringParam));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new BadRequestException("Bad ISO 8601 timestamp: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns first request parameter associated with {@code name} parsed as an optional
|
* Returns first request parameter associated with {@code name} parsed as an optional
|
||||||
* {@link InetAddress} (which might be IPv6).
|
* {@link InetAddress} (which might be IPv6).
|
||||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.request;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.request.RequestParameters.extractBooleanParameter;
|
import static google.registry.request.RequestParameters.extractBooleanParameter;
|
||||||
import static google.registry.request.RequestParameters.extractEnumParameter;
|
import static google.registry.request.RequestParameters.extractEnumParameter;
|
||||||
|
import static google.registry.request.RequestParameters.extractOptionalDatetimeParameter;
|
||||||
import static google.registry.request.RequestParameters.extractOptionalParameter;
|
import static google.registry.request.RequestParameters.extractOptionalParameter;
|
||||||
import static google.registry.request.RequestParameters.extractRequiredDatetimeParameter;
|
import static google.registry.request.RequestParameters.extractRequiredDatetimeParameter;
|
||||||
import static google.registry.request.RequestParameters.extractRequiredMaybeEmptyParameter;
|
import static google.registry.request.RequestParameters.extractRequiredMaybeEmptyParameter;
|
||||||
|
@ -184,6 +185,26 @@ public class RequestParametersTest {
|
||||||
extractRequiredDatetimeParameter(req, "timeParam");
|
extractRequiredDatetimeParameter(req, "timeParam");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExtractOptionalDatetimeParameter_correctValue_works() throws Exception {
|
||||||
|
when(req.getParameter("timeParam")).thenReturn("2015-08-27T13:25:34.123Z");
|
||||||
|
assertThat(extractOptionalDatetimeParameter(req, "timeParam"))
|
||||||
|
.hasValue(DateTime.parse("2015-08-27T13:25:34.123Z"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExtractOptionalDatetimeParameter_badValue_throwsBadRequest() throws Exception {
|
||||||
|
when(req.getParameter("timeParam")).thenReturn("Tuesday at three o'clock");
|
||||||
|
thrown.expect(BadRequestException.class, "timeParam");
|
||||||
|
extractOptionalDatetimeParameter(req, "timeParam");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExtractOptionalDatetimeParameter_empty_returnsAbsent() throws Exception {
|
||||||
|
when(req.getParameter("timeParam")).thenReturn("");
|
||||||
|
assertThat(extractOptionalDatetimeParameter(req, "timeParam")).isAbsent();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExtractRequiredDatetimeParameter_noValue_throwsBadRequest() throws Exception {
|
public void testExtractRequiredDatetimeParameter_noValue_throwsBadRequest() throws Exception {
|
||||||
thrown.expect(BadRequestException.class, "timeParam");
|
thrown.expect(BadRequestException.class, "timeParam");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue