mirror of
https://github.com/google/nomulus.git
synced 2025-05-29 08:50:09 +02:00
Support premium list updating in Cloud SQL (#422)
* Support premium list updating in Cloud SQL This also removes the requirement to specify --also_cloud_sql in nomulus premium list tooling, instead always persisting to Cloud SQL. It removes a non-USD premium label in the global test premium list (the Cloud SQL schema doesn't support a mix of currency units in a single premium list). And it adds a method to PremiumListDao to grab the most recent version of a given list. * Merge branch 'master' into premium-lists-always-cloud-sql * Revert test change * Create new PremiumListUtils class and refactor out existing method * Fix tests and update an existing premium price
This commit is contained in:
parent
c17a5c489c
commit
8f67c4b9cf
18 changed files with 199 additions and 165 deletions
|
@ -80,7 +80,7 @@ public class PremiumListDao {
|
||||||
* <p>Note that this does not load <code>PremiumList.labelsToPrices</code>! If you need to check
|
* <p>Note that this does not load <code>PremiumList.labelsToPrices</code>! If you need to check
|
||||||
* prices, use {@link #getPremiumPrice}.
|
* prices, use {@link #getPremiumPrice}.
|
||||||
*/
|
*/
|
||||||
static Optional<PremiumList> getLatestRevision(String premiumListName) {
|
public static Optional<PremiumList> getLatestRevision(String premiumListName) {
|
||||||
return jpaTm()
|
return jpaTm()
|
||||||
.transact(
|
.transact(
|
||||||
() ->
|
() ->
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
// 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.tld;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||||
|
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.ImmutableSortedSet;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.joda.money.CurrencyUnit;
|
||||||
|
|
||||||
|
/** Static utility methods for {@link PremiumList}. */
|
||||||
|
public class PremiumListUtils {
|
||||||
|
|
||||||
|
public static PremiumList parseToPremiumList(String name, String inputData) {
|
||||||
|
List<String> inputDataPreProcessed =
|
||||||
|
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
|
||||||
|
|
||||||
|
ImmutableMap<String, PremiumListEntry> prices =
|
||||||
|
new google.registry.model.registry.label.PremiumList.Builder()
|
||||||
|
.setName(name)
|
||||||
|
.build()
|
||||||
|
.parse(inputDataPreProcessed);
|
||||||
|
ImmutableSet<CurrencyUnit> currencies =
|
||||||
|
prices.values().stream()
|
||||||
|
.map(e -> e.getValue().getCurrencyUnit())
|
||||||
|
.distinct()
|
||||||
|
.collect(toImmutableSet());
|
||||||
|
checkArgument(
|
||||||
|
currencies.size() == 1,
|
||||||
|
"The Cloud SQL schema requires exactly one currency, but got: %s",
|
||||||
|
ImmutableSortedSet.copyOf(currencies));
|
||||||
|
CurrencyUnit currency = Iterables.getOnlyElement(currencies);
|
||||||
|
|
||||||
|
Map<String, BigDecimal> priceAmounts =
|
||||||
|
Maps.transformValues(prices, ple -> ple.getValue().getAmount());
|
||||||
|
return google.registry.schema.tld.PremiumList.create(name, currency, priceAmounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PremiumListUtils() {}
|
||||||
|
}
|
|
@ -16,7 +16,6 @@ package google.registry.tools;
|
||||||
|
|
||||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||||
import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX;
|
import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX;
|
||||||
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.ALSO_CLOUD_SQL_PARAM;
|
|
||||||
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.INPUT_PARAM;
|
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.INPUT_PARAM;
|
||||||
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.NAME_PARAM;
|
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.NAME_PARAM;
|
||||||
import static google.registry.util.ListNamingUtils.convertFilePathToName;
|
import static google.registry.util.ListNamingUtils.convertFilePathToName;
|
||||||
|
@ -58,12 +57,6 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
|
||||||
required = true)
|
required = true)
|
||||||
Path inputFile;
|
Path inputFile;
|
||||||
|
|
||||||
@Parameter(
|
|
||||||
names = {"--also_cloud_sql"},
|
|
||||||
description =
|
|
||||||
"Persist premium list to Cloud SQL in addition to Datastore; defaults to false.")
|
|
||||||
boolean alsoCloudSql;
|
|
||||||
|
|
||||||
protected AppEngineConnection connection;
|
protected AppEngineConnection connection;
|
||||||
protected int inputLineCount;
|
protected int inputLineCount;
|
||||||
|
|
||||||
|
@ -97,7 +90,6 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
|
||||||
public String execute() throws Exception {
|
public String execute() throws Exception {
|
||||||
ImmutableMap.Builder<String, String> params = new ImmutableMap.Builder<>();
|
ImmutableMap.Builder<String, String> params = new ImmutableMap.Builder<>();
|
||||||
params.put(NAME_PARAM, name);
|
params.put(NAME_PARAM, name);
|
||||||
params.put(ALSO_CLOUD_SQL_PARAM, Boolean.toString(alsoCloudSql));
|
|
||||||
String inputFileContents = new String(Files.readAllBytes(inputFile), UTF_8);
|
String inputFileContents = new String(Files.readAllBytes(inputFile), UTF_8);
|
||||||
String requestBody =
|
String requestBody =
|
||||||
Joiner.on('&').withKeyValueSeparator("=").join(
|
Joiner.on('&').withKeyValueSeparator("=").join(
|
||||||
|
|
|
@ -14,26 +14,13 @@
|
||||||
|
|
||||||
package google.registry.tools.server;
|
package google.registry.tools.server;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
|
||||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
|
||||||
import static com.google.common.flogger.LazyArgs.lazy;
|
import static com.google.common.flogger.LazyArgs.lazy;
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.ImmutableSortedSet;
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import google.registry.model.registry.label.PremiumList;
|
|
||||||
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
|
||||||
import google.registry.request.JsonResponse;
|
import google.registry.request.JsonResponse;
|
||||||
import google.registry.request.Parameter;
|
import google.registry.request.Parameter;
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.money.CurrencyUnit;
|
|
||||||
|
|
||||||
/** Abstract base class for actions that update premium lists. */
|
/** Abstract base class for actions that update premium lists. */
|
||||||
public abstract class CreateOrUpdatePremiumListAction implements Runnable {
|
public abstract class CreateOrUpdatePremiumListAction implements Runnable {
|
||||||
|
@ -44,7 +31,6 @@ public abstract class CreateOrUpdatePremiumListAction implements Runnable {
|
||||||
|
|
||||||
public static final String NAME_PARAM = "name";
|
public static final String NAME_PARAM = "name";
|
||||||
public static final String INPUT_PARAM = "inputData";
|
public static final String INPUT_PARAM = "inputData";
|
||||||
public static final String ALSO_CLOUD_SQL_PARAM = "alsoCloudSql";
|
|
||||||
|
|
||||||
@Inject JsonResponse response;
|
@Inject JsonResponse response;
|
||||||
|
|
||||||
|
@ -56,10 +42,6 @@ public abstract class CreateOrUpdatePremiumListAction implements Runnable {
|
||||||
@Parameter(INPUT_PARAM)
|
@Parameter(INPUT_PARAM)
|
||||||
String inputData;
|
String inputData;
|
||||||
|
|
||||||
@Inject
|
|
||||||
@Parameter(ALSO_CLOUD_SQL_PARAM)
|
|
||||||
boolean alsoCloudSql;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
@ -76,40 +58,15 @@ public abstract class CreateOrUpdatePremiumListAction implements Runnable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alsoCloudSql) {
|
try {
|
||||||
try {
|
saveToCloudSql();
|
||||||
saveToCloudSql();
|
} catch (Throwable e) {
|
||||||
} catch (Throwable e) {
|
logger.atSevere().withCause(e).log(
|
||||||
logger.atSevere().withCause(e).log(
|
"Unexpected error saving premium list to Cloud SQL from nomulus tool command");
|
||||||
"Unexpected error saving premium list to Cloud SQL from nomulus tool command");
|
response.setPayload(ImmutableMap.of("error", e.toString(), "status", "error"));
|
||||||
response.setPayload(ImmutableMap.of("error", e.toString(), "status", "error"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
google.registry.schema.tld.PremiumList parseInputToPremiumList() {
|
|
||||||
List<String> inputDataPreProcessed =
|
|
||||||
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
|
|
||||||
|
|
||||||
ImmutableMap<String, PremiumListEntry> prices =
|
|
||||||
new PremiumList.Builder().setName(name).build().parse(inputDataPreProcessed);
|
|
||||||
ImmutableSet<CurrencyUnit> currencies =
|
|
||||||
prices.values().stream()
|
|
||||||
.map(e -> e.getValue().getCurrencyUnit())
|
|
||||||
.distinct()
|
|
||||||
.collect(toImmutableSet());
|
|
||||||
checkArgument(
|
|
||||||
currencies.size() == 1,
|
|
||||||
"The Cloud SQL schema requires exactly one currency, but got: %s",
|
|
||||||
ImmutableSortedSet.copyOf(currencies));
|
|
||||||
CurrencyUnit currency = Iterables.getOnlyElement(currencies);
|
|
||||||
|
|
||||||
Map<String, BigDecimal> priceAmounts =
|
|
||||||
Maps.transformValues(prices, ple -> ple.getValue().getAmount());
|
|
||||||
return google.registry.schema.tld.PremiumList.create(name, currency, priceAmounts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Logs the premium list data at INFO, truncated if too long. */
|
/** Logs the premium list data at INFO, truncated if too long. */
|
||||||
void logInputData() {
|
void logInputData() {
|
||||||
logger.atInfo().log(
|
logger.atInfo().log(
|
||||||
|
|
|
@ -19,6 +19,7 @@ import static google.registry.model.registry.Registries.assertTldExists;
|
||||||
import static google.registry.model.registry.label.PremiumListUtils.doesPremiumListExist;
|
import static google.registry.model.registry.label.PremiumListUtils.doesPremiumListExist;
|
||||||
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
|
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
|
||||||
import static google.registry.request.Action.Method.POST;
|
import static google.registry.request.Action.Method.POST;
|
||||||
|
import static google.registry.schema.tld.PremiumListUtils.parseToPremiumList;
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -81,7 +82,7 @@ public class CreatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
||||||
logger.atInfo().log("Saving premium list to Cloud SQL for TLD %s", name);
|
logger.atInfo().log("Saving premium list to Cloud SQL for TLD %s", name);
|
||||||
// TODO(mcilwain): Call logInputData() here once Datastore persistence is removed.
|
// TODO(mcilwain): Call logInputData() here once Datastore persistence is removed.
|
||||||
|
|
||||||
google.registry.schema.tld.PremiumList premiumList = parseInputToPremiumList();
|
google.registry.schema.tld.PremiumList premiumList = parseToPremiumList(name, inputData);
|
||||||
PremiumListDao.saveNew(premiumList);
|
PremiumListDao.saveNew(premiumList);
|
||||||
|
|
||||||
String message =
|
String message =
|
||||||
|
|
|
@ -60,12 +60,6 @@ public class ToolsServerModule {
|
||||||
return extractRequiredParameter(req, CreatePremiumListAction.INPUT_PARAM);
|
return extractRequiredParameter(req, CreatePremiumListAction.INPUT_PARAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Parameter("alsoCloudSql")
|
|
||||||
static boolean provideAlsoCloudSql(HttpServletRequest req) {
|
|
||||||
return extractBooleanParameter(req, CreatePremiumListAction.ALSO_CLOUD_SQL_PARAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Parameter("premiumListName")
|
@Parameter("premiumListName")
|
||||||
static String provideName(HttpServletRequest req) {
|
static String provideName(HttpServletRequest req) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.tools.server;
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
|
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
|
||||||
import static google.registry.request.Action.Method.POST;
|
import static google.registry.request.Action.Method.POST;
|
||||||
|
import static google.registry.schema.tld.PremiumListUtils.parseToPremiumList;
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -24,6 +25,7 @@ import com.google.common.flogger.FluentLogger;
|
||||||
import google.registry.model.registry.label.PremiumList;
|
import google.registry.model.registry.label.PremiumList;
|
||||||
import google.registry.request.Action;
|
import google.registry.request.Action;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
|
import google.registry.schema.tld.PremiumListDao;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -68,10 +70,17 @@ public class UpdatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
||||||
response.setPayload(ImmutableMap.of("status", "success", "message", message));
|
response.setPayload(ImmutableMap.of("status", "success", "message", message));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(mcilwain): Implement this in a subsequent PR.
|
|
||||||
@Override
|
@Override
|
||||||
protected void saveToCloudSql() {
|
protected void saveToCloudSql() {
|
||||||
throw new UnsupportedOperationException(
|
logger.atInfo().log("Updating premium list '%s' in Cloud SQL.", name);
|
||||||
"Updating of premium lists in Cloud SQL is not supported yet");
|
// TODO(mcilwain): Add logInputData() call here once DB migration is complete.
|
||||||
|
google.registry.schema.tld.PremiumList premiumList = parseToPremiumList(name, inputData);
|
||||||
|
PremiumListDao.update(premiumList);
|
||||||
|
String message =
|
||||||
|
String.format(
|
||||||
|
"Updated premium list '%s' with %d entries.",
|
||||||
|
premiumList.getName(), premiumList.getLabelsToPrices().size());
|
||||||
|
logger.atInfo().log(message);
|
||||||
|
// TODO(mcilwain): Call response.setPayload() here once DB migration is complete.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,13 @@ import google.registry.model.registry.RegistryLockDaoTest;
|
||||||
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
|
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
|
||||||
import google.registry.schema.cursor.CursorDaoTest;
|
import google.registry.schema.cursor.CursorDaoTest;
|
||||||
import google.registry.schema.tld.PremiumListDaoTest;
|
import google.registry.schema.tld.PremiumListDaoTest;
|
||||||
|
import google.registry.schema.tld.PremiumListUtilsTest;
|
||||||
import google.registry.schema.tld.ReservedListDaoTest;
|
import google.registry.schema.tld.ReservedListDaoTest;
|
||||||
import google.registry.schema.tmch.ClaimsListDaoTest;
|
import google.registry.schema.tmch.ClaimsListDaoTest;
|
||||||
import google.registry.tools.CreateReservedListCommandTest;
|
import google.registry.tools.CreateReservedListCommandTest;
|
||||||
import google.registry.tools.UpdateReservedListCommandTest;
|
import google.registry.tools.UpdateReservedListCommandTest;
|
||||||
|
import google.registry.tools.server.CreatePremiumListActionTest;
|
||||||
|
import google.registry.tools.server.UpdatePremiumListActionTest;
|
||||||
import google.registry.ui.server.registrar.RegistryLockGetActionTest;
|
import google.registry.ui.server.registrar.RegistryLockGetActionTest;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Suite;
|
import org.junit.runners.Suite;
|
||||||
|
@ -41,10 +44,13 @@ import org.junit.runners.Suite.SuiteClasses;
|
||||||
ClaimsListDaoTest.class,
|
ClaimsListDaoTest.class,
|
||||||
CreateReservedListCommandTest.class,
|
CreateReservedListCommandTest.class,
|
||||||
CursorDaoTest.class,
|
CursorDaoTest.class,
|
||||||
|
CreatePremiumListActionTest.class,
|
||||||
PremiumListDaoTest.class,
|
PremiumListDaoTest.class,
|
||||||
|
PremiumListUtilsTest.class,
|
||||||
RegistryLockDaoTest.class,
|
RegistryLockDaoTest.class,
|
||||||
RegistryLockGetActionTest.class,
|
RegistryLockGetActionTest.class,
|
||||||
ReservedListDaoTest.class,
|
ReservedListDaoTest.class,
|
||||||
|
UpdatePremiumListActionTest.class,
|
||||||
UpdateReservedListCommandTest.class
|
UpdateReservedListCommandTest.class
|
||||||
})
|
})
|
||||||
public class SqlIntegrationTestSuite {}
|
public class SqlIntegrationTestSuite {}
|
||||||
|
|
|
@ -32,8 +32,8 @@ import google.registry.model.transaction.JpaTestRules;
|
||||||
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
|
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import org.joda.money.CurrencyUnit;
|
||||||
import org.joda.money.Money;
|
import org.joda.money.Money;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -66,13 +66,9 @@ public class PremiumListDaoTest {
|
||||||
jpaTm()
|
jpaTm()
|
||||||
.transact(
|
.transact(
|
||||||
() -> {
|
() -> {
|
||||||
PremiumList persistedList =
|
Optional<PremiumList> persistedListOpt = PremiumListDao.getLatestRevision("testname");
|
||||||
jpaTm()
|
assertThat(persistedListOpt).isPresent();
|
||||||
.getEntityManager()
|
PremiumList persistedList = persistedListOpt.get();
|
||||||
.createQuery(
|
|
||||||
"SELECT pl FROM PremiumList pl WHERE pl.name = :name", PremiumList.class)
|
|
||||||
.setParameter("name", "testname")
|
|
||||||
.getSingleResult();
|
|
||||||
assertThat(persistedList.getLabelsToPrices()).containsExactlyEntriesIn(TEST_PRICES);
|
assertThat(persistedList.getLabelsToPrices()).containsExactlyEntriesIn(TEST_PRICES);
|
||||||
assertThat(persistedList.getCreationTimestamp())
|
assertThat(persistedList.getCreationTimestamp())
|
||||||
.isEqualTo(jpaRule.getTxnClock().nowUtc());
|
.isEqualTo(jpaRule.getTxnClock().nowUtc());
|
||||||
|
@ -81,26 +77,40 @@ public class PremiumListDaoTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void update_worksSuccessfully() {
|
public void update_worksSuccessfully() {
|
||||||
PremiumListDao.saveNew(
|
PremiumListDao.saveNew(PremiumList.create("testname", CurrencyUnit.USD, TEST_PRICES));
|
||||||
|
Optional<PremiumList> persistedList = PremiumListDao.getLatestRevision("testname");
|
||||||
|
assertThat(persistedList).isPresent();
|
||||||
|
long firstRevisionId = persistedList.get().getRevisionId();
|
||||||
|
PremiumListDao.update(
|
||||||
PremiumList.create(
|
PremiumList.create(
|
||||||
"testname", USD, ImmutableMap.of("firstversion", BigDecimal.valueOf(123.45))));
|
"testname",
|
||||||
PremiumListDao.update(PremiumList.create("testname", USD, TEST_PRICES));
|
CurrencyUnit.USD,
|
||||||
|
ImmutableMap.of(
|
||||||
|
"update",
|
||||||
|
BigDecimal.valueOf(55343.12),
|
||||||
|
"new",
|
||||||
|
BigDecimal.valueOf(0.01),
|
||||||
|
"silver",
|
||||||
|
BigDecimal.valueOf(30.03))));
|
||||||
jpaTm()
|
jpaTm()
|
||||||
.transact(
|
.transact(
|
||||||
() -> {
|
() -> {
|
||||||
List<PremiumList> persistedLists =
|
Optional<PremiumList> updatedListOpt = PremiumListDao.getLatestRevision("testname");
|
||||||
jpaTm()
|
assertThat(updatedListOpt).isPresent();
|
||||||
.getEntityManager()
|
PremiumList updatedList = updatedListOpt.get();
|
||||||
.createQuery(
|
assertThat(updatedList.getLabelsToPrices())
|
||||||
"SELECT pl FROM PremiumList pl WHERE pl.name = :name ORDER BY"
|
.containsExactlyEntriesIn(
|
||||||
+ " pl.revisionId",
|
ImmutableMap.of(
|
||||||
PremiumList.class)
|
"update",
|
||||||
.setParameter("name", "testname")
|
BigDecimal.valueOf(55343.12),
|
||||||
.getResultList();
|
"new",
|
||||||
assertThat(persistedLists).hasSize(2);
|
BigDecimal.valueOf(0.01),
|
||||||
assertThat(persistedLists.get(1).getLabelsToPrices())
|
"silver",
|
||||||
.containsExactlyEntriesIn(TEST_PRICES);
|
BigDecimal.valueOf(30.03)));
|
||||||
assertThat(persistedLists.get(1).getCreationTimestamp())
|
assertThat(updatedList.getCreationTimestamp())
|
||||||
|
.isEqualTo(jpaRule.getTxnClock().nowUtc());
|
||||||
|
assertThat(updatedList.getRevisionId()).isGreaterThan(firstRevisionId);
|
||||||
|
assertThat(updatedList.getCreationTimestamp())
|
||||||
.isEqualTo(jpaRule.getTxnClock().nowUtc());
|
.isEqualTo(jpaRule.getTxnClock().nowUtc());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -116,7 +126,7 @@ public class PremiumListDaoTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void update_throwsWhenPremiumListDoesntExist() {
|
public void update_throwsWhenListDoesntExist() {
|
||||||
IllegalArgumentException thrown =
|
IllegalArgumentException thrown =
|
||||||
assertThrows(
|
assertThrows(
|
||||||
IllegalArgumentException.class,
|
IllegalArgumentException.class,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -12,43 +12,35 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package google.registry.tools.server;
|
package google.registry.schema.tld;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth8.assertThat;
|
import static google.registry.schema.tld.PremiumListUtils.parseToPremiumList;
|
||||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||||
|
|
||||||
import google.registry.schema.tld.PremiumList;
|
import google.registry.model.transaction.JpaTestRules;
|
||||||
|
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeJsonResponse;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
/** Unit tests for {@link CreateOrUpdatePremiumListAction}. */
|
/** Unit tests for {@link PremiumListUtils}. */
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class CreateOrUpdatePremiumListActionTest {
|
public class PremiumListUtilsTest {
|
||||||
|
|
||||||
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
|
|
||||||
private CreatePremiumListAction action;
|
@Rule
|
||||||
private FakeJsonResponse response;
|
public final JpaIntegrationTestRule jpaRule =
|
||||||
|
new JpaTestRules.Builder().buildIntegrationTestRule();
|
||||||
@Before
|
|
||||||
public void init() {
|
|
||||||
action = new CreatePremiumListAction();
|
|
||||||
response = new FakeJsonResponse();
|
|
||||||
action.response = response;
|
|
||||||
action.name = "testlist";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parseInputToPremiumList_works() {
|
public void parseInputToPremiumList_works() {
|
||||||
action.inputData = "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,USD 10\n";
|
PremiumList premiumList =
|
||||||
PremiumList premiumList = action.parseInputToPremiumList();
|
parseToPremiumList("testlist", "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,USD 10\n");
|
||||||
assertThat(premiumList.getName()).isEqualTo("testlist");
|
assertThat(premiumList.getName()).isEqualTo("testlist");
|
||||||
assertThat(premiumList.getLabelsToPrices())
|
assertThat(premiumList.getLabelsToPrices())
|
||||||
.containsExactly("foo", twoDigits(99.50), "bar", twoDigits(30), "baz", twoDigits(10));
|
.containsExactly("foo", twoDigits(99.50), "bar", twoDigits(30), "baz", twoDigits(10));
|
||||||
|
@ -56,9 +48,12 @@ public class CreateOrUpdatePremiumListActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parseInputToPremiumList_throwsOnInconsistentCurrencies() {
|
public void parseInputToPremiumList_throwsOnInconsistentCurrencies() {
|
||||||
action.inputData = "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,JPY 990\n";
|
|
||||||
IllegalArgumentException thrown =
|
IllegalArgumentException thrown =
|
||||||
assertThrows(IllegalArgumentException.class, () -> action.parseInputToPremiumList());
|
assertThrows(
|
||||||
|
IllegalArgumentException.class,
|
||||||
|
() ->
|
||||||
|
parseToPremiumList(
|
||||||
|
"testlist", "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,JPY 990\n"));
|
||||||
assertThat(thrown)
|
assertThat(thrown)
|
||||||
.hasMessageThat()
|
.hasMessageThat()
|
||||||
.isEqualTo("The Cloud SQL schema requires exactly one currency, but got: [JPY, USD]");
|
.isEqualTo("The Cloud SQL schema requires exactly one currency, but got: [JPY, USD]");
|
|
@ -16,9 +16,13 @@ package google.registry.tools;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.testing.DatastoreHelper.createTld;
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
|
import static google.registry.testing.DatastoreHelper.persistPremiumList;
|
||||||
|
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||||
|
|
||||||
import com.beust.jcommander.ParameterException;
|
import com.beust.jcommander.ParameterException;
|
||||||
|
import google.registry.model.registry.Registry;
|
||||||
|
import google.registry.model.registry.label.PremiumList;
|
||||||
import google.registry.testing.DeterministicStringGenerator;
|
import google.registry.testing.DeterministicStringGenerator;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -91,7 +95,14 @@ public class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomain
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_premiumDomain() throws Exception {
|
public void testSuccess_premiumJpyDomain() throws Exception {
|
||||||
|
createTld("baar");
|
||||||
|
persistPremiumList("baar", "parajiumu,JPY 96083");
|
||||||
|
persistResource(
|
||||||
|
Registry.get("baar")
|
||||||
|
.asBuilder()
|
||||||
|
.setPremiumList(PremiumList.getUncached("baar").get())
|
||||||
|
.build());
|
||||||
runCommandForced(
|
runCommandForced(
|
||||||
"--client=NewRegistrar",
|
"--client=NewRegistrar",
|
||||||
"--registrant=crr-admin",
|
"--registrant=crr-admin",
|
||||||
|
@ -99,10 +110,10 @@ public class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomain
|
||||||
"--techs=crr-tech",
|
"--techs=crr-tech",
|
||||||
"--period=3",
|
"--period=3",
|
||||||
"--force_premiums",
|
"--force_premiums",
|
||||||
"parajiumu.tld");
|
"parajiumu.baar");
|
||||||
eppVerifier.verifySent("domain_create_parajiumu_3yrs.xml");
|
eppVerifier.verifySent("domain_create_parajiumu_3yrs.xml");
|
||||||
assertInStdout(
|
assertInStdout(
|
||||||
"parajiumu.tld is premium at JPY 96083 per year; "
|
"parajiumu.baar is premium at JPY 96083 per year; "
|
||||||
+ "sending total cost for 3 year(s) of JPY 288249.");
|
+ "sending total cost for 3 year(s) of JPY 288249.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,13 +67,7 @@ public class CreatePremiumListCommandTest<C extends CreatePremiumListCommand>
|
||||||
verifySentParams(
|
verifySentParams(
|
||||||
connection,
|
connection,
|
||||||
servletPath,
|
servletPath,
|
||||||
ImmutableMap.of(
|
ImmutableMap.of("name", "foo", "inputData", generateInputData(premiumTermsPath)));
|
||||||
"name",
|
|
||||||
"foo",
|
|
||||||
"inputData",
|
|
||||||
generateInputData(premiumTermsPath),
|
|
||||||
"alsoCloudSql",
|
|
||||||
"false"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -84,28 +78,7 @@ public class CreatePremiumListCommandTest<C extends CreatePremiumListCommand>
|
||||||
connection,
|
connection,
|
||||||
servletPath,
|
servletPath,
|
||||||
ImmutableMap.of(
|
ImmutableMap.of(
|
||||||
"name",
|
"name", "example_premium_terms", "inputData", generateInputData(premiumTermsPath)));
|
||||||
"example_premium_terms",
|
|
||||||
"inputData",
|
|
||||||
generateInputData(premiumTermsPath),
|
|
||||||
"alsoCloudSql",
|
|
||||||
"false"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRun_alsoCloudSql() throws Exception {
|
|
||||||
runCommandForced("-i=" + premiumTermsPath, "-n=foo", "--also_cloud_sql");
|
|
||||||
assertInStdout("Successfully");
|
|
||||||
verifySentParams(
|
|
||||||
connection,
|
|
||||||
servletPath,
|
|
||||||
ImmutableMap.of(
|
|
||||||
"name",
|
|
||||||
"foo",
|
|
||||||
"inputData",
|
|
||||||
generateInputData(premiumTermsPath),
|
|
||||||
"alsoCloudSql",
|
|
||||||
"true"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -57,13 +57,7 @@ public class UpdatePremiumListCommandTest<C extends UpdatePremiumListCommand>
|
||||||
verifySentParams(
|
verifySentParams(
|
||||||
connection,
|
connection,
|
||||||
servletPath,
|
servletPath,
|
||||||
ImmutableMap.of(
|
ImmutableMap.of("name", "foo", "inputData", generateInputData(premiumTermsPath)));
|
||||||
"name",
|
|
||||||
"foo",
|
|
||||||
"inputData",
|
|
||||||
generateInputData(premiumTermsPath),
|
|
||||||
"alsoCloudSql",
|
|
||||||
"false"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -74,11 +68,6 @@ public class UpdatePremiumListCommandTest<C extends UpdatePremiumListCommand>
|
||||||
connection,
|
connection,
|
||||||
servletPath,
|
servletPath,
|
||||||
ImmutableMap.of(
|
ImmutableMap.of(
|
||||||
"name",
|
"name", "example_premium_terms", "inputData", generateInputData(premiumTermsPath)));
|
||||||
"example_premium_terms",
|
|
||||||
"inputData",
|
|
||||||
generateInputData(premiumTermsPath),
|
|
||||||
"alsoCloudSql",
|
|
||||||
"false"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
import google.registry.model.registry.label.PremiumList;
|
import google.registry.model.registry.label.PremiumList;
|
||||||
|
import google.registry.model.transaction.JpaTestRules;
|
||||||
|
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeJsonResponse;
|
import google.registry.testing.FakeJsonResponse;
|
||||||
import org.joda.money.Money;
|
import org.joda.money.Money;
|
||||||
|
@ -39,6 +41,10 @@ import org.junit.runners.JUnit4;
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class CreatePremiumListActionTest {
|
public class CreatePremiumListActionTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final JpaIntegrationTestRule jpaRule =
|
||||||
|
new JpaTestRules.Builder().buildIntegrationTestRule();
|
||||||
|
|
||||||
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
CreatePremiumListAction action;
|
CreatePremiumListAction action;
|
||||||
FakeJsonResponse response;
|
FakeJsonResponse response;
|
||||||
|
|
|
@ -17,14 +17,22 @@ package google.registry.tools.server;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth8.assertThat;
|
import static com.google.common.truth.Truth8.assertThat;
|
||||||
import static google.registry.model.registry.label.PremiumListUtils.getPremiumPrice;
|
import static google.registry.model.registry.label.PremiumListUtils.getPremiumPrice;
|
||||||
|
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||||
|
import static google.registry.schema.tld.PremiumListUtils.parseToPremiumList;
|
||||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||||
import static google.registry.testing.DatastoreHelper.loadPremiumListEntries;
|
import static google.registry.testing.DatastoreHelper.loadPremiumListEntries;
|
||||||
|
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
import google.registry.model.registry.label.PremiumList;
|
import google.registry.model.registry.label.PremiumList;
|
||||||
|
import google.registry.model.transaction.JpaTestRules;
|
||||||
|
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
|
||||||
|
import google.registry.schema.tld.PremiumListDao;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
|
import google.registry.testing.DatastoreHelper;
|
||||||
import google.registry.testing.FakeJsonResponse;
|
import google.registry.testing.FakeJsonResponse;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import org.joda.money.Money;
|
import org.joda.money.Money;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
@ -38,10 +46,11 @@ import org.junit.runners.JUnit4;
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class UpdatePremiumListActionTest {
|
public class UpdatePremiumListActionTest {
|
||||||
|
|
||||||
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
public final JpaIntegrationTestRule jpaRule =
|
||||||
.withDatastore()
|
new JpaTestRules.Builder().buildIntegrationTestRule();
|
||||||
.build();
|
|
||||||
|
|
||||||
UpdatePremiumListAction action;
|
UpdatePremiumListAction action;
|
||||||
FakeJsonResponse response;
|
FakeJsonResponse response;
|
||||||
|
@ -75,6 +84,9 @@ public class UpdatePremiumListActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_success() {
|
public void test_success() {
|
||||||
|
PremiumListDao.saveNew(
|
||||||
|
parseToPremiumList(
|
||||||
|
"foo", readResourceUtf8(DatastoreHelper.class, "default_premium_list_testdata.csv")));
|
||||||
action.name = "foo";
|
action.name = "foo";
|
||||||
action.inputData = "rich,USD 75\nricher,USD 5000\npoor, USD 0.99";
|
action.inputData = "rich,USD 75\nricher,USD 5000\npoor, USD 0.99";
|
||||||
action.run();
|
action.run();
|
||||||
|
@ -85,5 +97,19 @@ public class UpdatePremiumListActionTest {
|
||||||
assertThat(getPremiumPrice("richer", registry)).hasValue(Money.parse("USD 5000"));
|
assertThat(getPremiumPrice("richer", registry)).hasValue(Money.parse("USD 5000"));
|
||||||
assertThat(getPremiumPrice("poor", registry)).hasValue(Money.parse("USD 0.99"));
|
assertThat(getPremiumPrice("poor", registry)).hasValue(Money.parse("USD 0.99"));
|
||||||
assertThat(getPremiumPrice("diamond", registry)).isEmpty();
|
assertThat(getPremiumPrice("diamond", registry)).isEmpty();
|
||||||
|
|
||||||
|
jpaTm()
|
||||||
|
.transact(
|
||||||
|
() -> {
|
||||||
|
google.registry.schema.tld.PremiumList persistedList =
|
||||||
|
PremiumListDao.getLatestRevision("foo").get();
|
||||||
|
assertThat(persistedList.getLabelsToPrices())
|
||||||
|
.containsEntry("rich", new BigDecimal("75.00"));
|
||||||
|
assertThat(persistedList.getLabelsToPrices())
|
||||||
|
.containsEntry("richer", new BigDecimal("5000.00"));
|
||||||
|
assertThat(persistedList.getLabelsToPrices())
|
||||||
|
.containsEntry("poor", BigDecimal.valueOf(0.99));
|
||||||
|
assertThat(persistedList.getLabelsToPrices()).doesNotContainKey("diamond");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,4 +10,3 @@ palladium,USD 877
|
||||||
aluminum,USD 11
|
aluminum,USD 11
|
||||||
copper,USD 15
|
copper,USD 15
|
||||||
brass,USD 20
|
brass,USD 20
|
||||||
parajiumu,JPY 96083
|
|
||||||
|
|
|
|
@ -4,7 +4,7 @@
|
||||||
<create>
|
<create>
|
||||||
<domain:create
|
<domain:create
|
||||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||||
<domain:name>parajiumu.tld</domain:name>
|
<domain:name>parajiumu.baar</domain:name>
|
||||||
<domain:period unit="y">3</domain:period>
|
<domain:period unit="y">3</domain:period>
|
||||||
<domain:registrant>crr-admin</domain:registrant>
|
<domain:registrant>crr-admin</domain:registrant>
|
||||||
<domain:contact type="admin">crr-admin</domain:contact>
|
<domain:contact type="admin">crr-admin</domain:contact>
|
||||||
|
|
|
@ -29,7 +29,9 @@ public abstract class EmailMessage {
|
||||||
public abstract String body();
|
public abstract String body();
|
||||||
public abstract ImmutableList<InternetAddress> recipients();
|
public abstract ImmutableList<InternetAddress> recipients();
|
||||||
public abstract InternetAddress from();
|
public abstract InternetAddress from();
|
||||||
|
|
||||||
public abstract ImmutableList<InternetAddress> bccs();
|
public abstract ImmutableList<InternetAddress> bccs();
|
||||||
|
|
||||||
public abstract Optional<MediaType> contentType();
|
public abstract Optional<MediaType> contentType();
|
||||||
public abstract Optional<Attachment> attachment();
|
public abstract Optional<Attachment> attachment();
|
||||||
|
|
||||||
|
@ -55,11 +57,14 @@ public abstract class EmailMessage {
|
||||||
public abstract Builder setBody(String body);
|
public abstract Builder setBody(String body);
|
||||||
public abstract Builder setRecipients(Collection<InternetAddress> recipients);
|
public abstract Builder setRecipients(Collection<InternetAddress> recipients);
|
||||||
public abstract Builder setFrom(InternetAddress from);
|
public abstract Builder setFrom(InternetAddress from);
|
||||||
|
|
||||||
public abstract Builder setBccs(Collection<InternetAddress> bccs);
|
public abstract Builder setBccs(Collection<InternetAddress> bccs);
|
||||||
|
|
||||||
public abstract Builder setContentType(MediaType contentType);
|
public abstract Builder setContentType(MediaType contentType);
|
||||||
public abstract Builder setAttachment(Attachment attachment);
|
public abstract Builder setAttachment(Attachment attachment);
|
||||||
|
|
||||||
abstract ImmutableList.Builder<InternetAddress> recipientsBuilder();
|
abstract ImmutableList.Builder<InternetAddress> recipientsBuilder();
|
||||||
|
|
||||||
abstract ImmutableList.Builder<InternetAddress> bccsBuilder();
|
abstract ImmutableList.Builder<InternetAddress> bccsBuilder();
|
||||||
|
|
||||||
public Builder addRecipient(InternetAddress value) {
|
public Builder addRecipient(InternetAddress value) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue