Only email support for package non-compliance (#1900)

* Only email support for package non-compliance

* Fix import

* Always use longs
This commit is contained in:
sarahcaseybot 2023-01-17 14:22:15 -05:00 committed by GitHub
parent 5e7b02a064
commit 4067f7c3e4
4 changed files with 84 additions and 82 deletions

View file

@ -13,11 +13,11 @@
// limitations under the License. // limitations under the License.
package google.registry.batch; package google.registry.batch;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.END_OF_TIME;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.flogger.FluentLogger; import com.google.common.flogger.FluentLogger;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
@ -25,7 +25,6 @@ import google.registry.config.RegistryConfig.Config;
import google.registry.model.domain.token.AllocationToken; import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.PackagePromotion; import google.registry.model.domain.token.PackagePromotion;
import google.registry.model.registrar.Registrar; import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.request.Action; import google.registry.request.Action;
import google.registry.request.Action.Service; import google.registry.request.Action.Service;
import google.registry.request.auth.Auth; import google.registry.request.auth.Auth;
@ -88,10 +87,10 @@ public class CheckPackagesComplianceAction implements Runnable {
private void checkPackages() { private void checkPackages() {
ImmutableList<PackagePromotion> packages = tm().loadAllOf(PackagePromotion.class); ImmutableList<PackagePromotion> packages = tm().loadAllOf(PackagePromotion.class);
ImmutableList.Builder<PackagePromotion> packagesOverCreateLimitBuilder = ImmutableMap.Builder<PackagePromotion, Long> packagesOverCreateLimitBuilder =
new ImmutableList.Builder<>(); new ImmutableMap.Builder<>();
ImmutableList.Builder<PackagePromotion> packagesOverActiveDomainsLimitBuilder = ImmutableMap.Builder<PackagePromotion, Long> packagesOverActiveDomainsLimitBuilder =
new ImmutableList.Builder<>(); new ImmutableMap.Builder<>();
for (PackagePromotion packagePromo : packages) { for (PackagePromotion packagePromo : packages) {
Long creates = Long creates =
(Long) (Long)
@ -103,12 +102,12 @@ public class CheckPackagesComplianceAction implements Runnable {
.setParameter("lastBilling", packagePromo.getNextBillingDate().minusYears(1)) .setParameter("lastBilling", packagePromo.getNextBillingDate().minusYears(1))
.getSingleResult(); .getSingleResult();
if (creates > packagePromo.getMaxCreates()) { if (creates > packagePromo.getMaxCreates()) {
int overage = Ints.saturatedCast(creates) - packagePromo.getMaxCreates(); long overage = creates - packagePromo.getMaxCreates();
logger.atInfo().log( logger.atInfo().log(
"Package with package token %s has exceeded their max domain creation limit" "Package with package token %s has exceeded their max domain creation limit"
+ " by %d name(s).", + " by %d name(s).",
packagePromo.getToken().getKey(), overage); packagePromo.getToken().getKey(), overage);
packagesOverCreateLimitBuilder.add(packagePromo); packagesOverCreateLimitBuilder.put(packagePromo, creates);
} }
Long activeDomains = Long activeDomains =
@ -125,20 +124,20 @@ public class CheckPackagesComplianceAction implements Runnable {
"Package with package token %s has exceed their max active domains limit by" "Package with package token %s has exceed their max active domains limit by"
+ " %d name(s).", + " %d name(s).",
packagePromo.getToken().getKey(), overage); packagePromo.getToken().getKey(), overage);
packagesOverActiveDomainsLimitBuilder.add(packagePromo); packagesOverActiveDomainsLimitBuilder.put(packagePromo, activeDomains);
} }
} }
handlePackageCreationOverage(packagesOverCreateLimitBuilder.build()); handlePackageCreationOverage(packagesOverCreateLimitBuilder.build());
handleActiveDomainOverage(packagesOverActiveDomainsLimitBuilder.build()); handleActiveDomainOverage(packagesOverActiveDomainsLimitBuilder.build());
} }
private void handlePackageCreationOverage(ImmutableList<PackagePromotion> overageList) { private void handlePackageCreationOverage(ImmutableMap<PackagePromotion, Long> overageList) {
if (overageList.isEmpty()) { if (overageList.isEmpty()) {
logger.atInfo().log("Found no packages over their create limit."); logger.atInfo().log("Found no packages over their create limit.");
return; return;
} }
logger.atInfo().log("Found %d packages over their create limit.", overageList.size()); logger.atInfo().log("Found %d packages over their create limit.", overageList.size());
for (PackagePromotion packagePromotion : overageList) { for (PackagePromotion packagePromotion : overageList.keySet()) {
AllocationToken packageToken = tm().loadByKey(packagePromotion.getToken()); AllocationToken packageToken = tm().loadByKey(packagePromotion.getToken());
Optional<Registrar> registrar = Optional<Registrar> registrar =
Registrar.loadByRegistrarIdCached( Registrar.loadByRegistrarIdCached(
@ -147,9 +146,11 @@ public class CheckPackagesComplianceAction implements Runnable {
String body = String body =
String.format( String.format(
packageCreateLimitEmailBody, packageCreateLimitEmailBody,
registrar.get().getRegistrarName(), packagePromotion.getId(),
packageToken.getToken(), packageToken.getToken(),
registrySupportEmail); registrar.get().getRegistrarName(),
packagePromotion.getMaxCreates(),
overageList.get(packagePromotion));
sendNotification(packageToken, packageCreateLimitEmailSubject, body, registrar.get()); sendNotification(packageToken, packageCreateLimitEmailSubject, body, registrar.get());
} else { } else {
throw new IllegalStateException( throw new IllegalStateException(
@ -158,13 +159,13 @@ public class CheckPackagesComplianceAction implements Runnable {
} }
} }
private void handleActiveDomainOverage(ImmutableList<PackagePromotion> overageList) { private void handleActiveDomainOverage(ImmutableMap<PackagePromotion, Long> overageList) {
if (overageList.isEmpty()) { if (overageList.isEmpty()) {
logger.atInfo().log("Found no packages over their active domains limit."); logger.atInfo().log("Found no packages over their active domains limit.");
return; return;
} }
logger.atInfo().log("Found %d packages over their active domains limit.", overageList.size()); logger.atInfo().log("Found %d packages over their active domains limit.", overageList.size());
for (PackagePromotion packagePromotion : overageList) { for (PackagePromotion packagePromotion : overageList.keySet()) {
int daysSinceLastNotification = int daysSinceLastNotification =
packagePromotion packagePromotion
.getLastNotificationSent() .getLastNotificationSent()
@ -176,15 +177,18 @@ public class CheckPackagesComplianceAction implements Runnable {
continue; continue;
} else if (daysSinceLastNotification < FORTY_DAYS) { } else if (daysSinceLastNotification < FORTY_DAYS) {
// Send an upgrade email if last email was between 30 and 40 days ago // Send an upgrade email if last email was between 30 and 40 days ago
sendActiveDomainOverageEmail(/* warning= */ false, packagePromotion); sendActiveDomainOverageEmail(
/* warning= */ false, packagePromotion, overageList.get(packagePromotion));
} else { } else {
// Send a warning email // Send a warning email
sendActiveDomainOverageEmail(/* warning= */ true, packagePromotion); sendActiveDomainOverageEmail(
/* warning= */ true, packagePromotion, overageList.get(packagePromotion));
} }
} }
} }
private void sendActiveDomainOverageEmail(boolean warning, PackagePromotion packagePromotion) { private void sendActiveDomainOverageEmail(
boolean warning, PackagePromotion packagePromotion, long activeDomains) {
String emailSubject = String emailSubject =
warning ? packageDomainLimitWarningEmailSubject : packageDomainLimitUpgradeEmailSubject; warning ? packageDomainLimitWarningEmailSubject : packageDomainLimitUpgradeEmailSubject;
String emailTemplate = String emailTemplate =
@ -197,9 +201,11 @@ public class CheckPackagesComplianceAction implements Runnable {
String body = String body =
String.format( String.format(
emailTemplate, emailTemplate,
registrar.get().getRegistrarName(), packagePromotion.getId(),
packageToken.getToken(), packageToken.getToken(),
registrySupportEmail); registrar.get().getRegistrarName(),
packagePromotion.getMaxDomains(),
activeDomains);
sendNotification(packageToken, emailSubject, body, registrar.get()); sendNotification(packageToken, emailSubject, body, registrar.get());
tm().put(packagePromotion.asBuilder().setLastNotificationSent(clock.nowUtc()).build()); tm().put(packagePromotion.asBuilder().setLastNotificationSent(clock.nowUtc()).build());
} else { } else {
@ -212,15 +218,9 @@ public class CheckPackagesComplianceAction implements Runnable {
AllocationToken packageToken, String subject, String body, Registrar registrar) { AllocationToken packageToken, String subject, String body, Registrar registrar) {
logger.atInfo().log( logger.atInfo().log(
String.format( String.format(
"Compliance email sent to the %s registrar regarding the package with token" + " %s.", "Compliance email sent to support regarding the %s registrar and the package with token"
+ " %s.",
registrar.getRegistrarName(), packageToken.getToken())); registrar.getRegistrarName(), packageToken.getToken()));
sendEmailUtils.sendEmail( sendEmailUtils.sendEmail(subject, body, ImmutableList.of(registrySupportEmail));
subject,
body,
Optional.of(registrySupportEmail),
registrar.getContacts().stream()
.filter(c -> c.getTypes().contains(RegistrarPoc.Type.ADMIN))
.map(RegistrarPoc::getEmailAddress)
.collect(toImmutableList()));
} }
} }

View file

@ -538,52 +538,53 @@ sslCertificateValidation:
# Configuration options for the package compliance monitoring # Configuration options for the package compliance monitoring
packageMonitoring: packageMonitoring:
# Email subject text to notify partners their package has exceeded the limit for domain creates # Email subject text to notify tech support that a package has exceeded the limit for domain creates
packageCreateLimitEmailSubject: "NOTICE: Your package is being upgraded" packageCreateLimitEmailSubject: "ACTION REQUIRED: Package needs to be upgraded"
# Email body text template notify partners their package has exceeded the limit for domain creates # Email body text template notify support that a package has exceeded the limit for domain creates
packageCreateLimitEmailBody: > packageCreateLimitEmailBody: >
Dear %1$s, Dear Support,
We are contacting you to inform you that your package with the package token A package has exceeded its max create limit and needs to be upgraded to the
%2$s has exceeded its limit for annual domain creations. next tier.
Your package will now be upgraded to the next tier.
If you have any questions or require additional support, please contact us Package ID: %1$s
at %3$s. Package Token: %2$s
Registrar: %3$s
Regards, Current Max Create Limit: %4$s
Example Registry Creates Completed: %5$s
# Email subject text to notify partners their package has exceeded the limit for current active domains and warn them their package will be upgraded in 30 days # Email subject text to notify support that a package has exceeded the limit
packageDomainLimitWarningEmailSubject: "WARNING: Your package has exceeded the domain limit" # for current active domains and a warning needs to be sent
# Email body text template to warn partners their package has exceeded the limit for active domains and will be upgraded in 30 days packageDomainLimitWarningEmailSubject: "ACTION REQUIRED: Package has exceeded the domain limit - send warning"
# Email body text template to inform support that a package has exceeded the
# limit for active domains and a warning needs to be sent that the package
# will be upgraded in 30 days
packageDomainLimitWarningEmailBody: > packageDomainLimitWarningEmailBody: >
Dear %1$s, Dear Support,
We are contacting you to inform you that your package with the package token
%2$s has exceeded its limit for active domains.
Your package will be upgraded to the next tier in 30 days if the number of active domains does not return below the limit.
If you have any questions or require additional support, please contact us
at %3$s.
Regards,
Example Registry
# Email subject text to notify partners their package has exceeded the limit
# for current active domains for more than 30 days and will be upgraded
packageDomainLimitUpgradeEmailSubject: "NOTICE: Your package is being upgraded"
# Email body text template to warn partners their package has exceeded the
# limit for active domains for more than 30 days and will be upgraded
packageDomainLimitUpgradeEmailBody: >
Dear %1$s,
We are contacting you to inform you that your package with the package token A package has exceeded its max domain limit. Please send a warning to the
%2$s has exceeded its limit for active domains. registrar that their package will be upgraded to the next tier in 30 days if
Your package will now be upgraded to the next tier. the number of active domains does not return below the limit.
Package ID: %1$s
Package Token: %2$s
Registrar: %3$s
Active Domain Limit: %4$s
Current Active Domains: %5$s
If you have any questions or require additional support, please contact us # Email subject text to notify support that a package has exceeded the limit
at %3$s. # for current active domains for more than 30 days and needs to be upgraded
packageDomainLimitUpgradeEmailSubject: "ACTION REQUIRED: Package has exceeded the domain limit - upgrade package"
Regards, # Email body text template to inform support that a package has exceeded the
Example Registry # limit for active domains for more than 30 days and needs to be upgraded
packageDomainLimitUpgradeEmailBody: >
Dear Support,
A package has exceeded its max domain limit for over 30 days and needs to be
upgraded to the next tier.
Package ID: %1$s
Package Token: %2$s
Registrar: %3$s
Active Domain Limit: %4$s
Current Active Domains: %5$s

View file

@ -74,6 +74,10 @@ public class PackagePromotion extends ImmutableObject implements Buildable {
/** Date the last warning email was sent that the package has exceeded the maxDomains limit. */ /** Date the last warning email was sent that the package has exceeded the maxDomains limit. */
@Nullable DateTime lastNotificationSent; @Nullable DateTime lastNotificationSent;
public long getId() {
return packagePromotionId;
}
public VKey<AllocationToken> getToken() { public VKey<AllocationToken> getToken() {
return token; return token;
} }

View file

@ -60,11 +60,12 @@ public class CheckPackagesComplianceActionTest {
private static final String CREATE_LIMIT_EMAIL_SUBJECT = "create limit subject"; private static final String CREATE_LIMIT_EMAIL_SUBJECT = "create limit subject";
private static final String DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT = "domain limit warning subject"; private static final String DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT = "domain limit warning subject";
private static final String DOMAIN_LIMIT_UPGRADE_EMAIL_SUBJECT = "domain limit upgrade subject"; private static final String DOMAIN_LIMIT_UPGRADE_EMAIL_SUBJECT = "domain limit upgrade subject";
private static final String CREATE_LIMIT_EMAIL_BODY = "create limit body %1$s %2$s %3$s"; private static final String CREATE_LIMIT_EMAIL_BODY =
"create limit body %1$s %2$s %3$s %4$s %5$s";
private static final String DOMAIN_LIMIT_WARNING_EMAIL_BODY = private static final String DOMAIN_LIMIT_WARNING_EMAIL_BODY =
"domain limit warning body %1$s %2$s %3$s"; "domain limit warning body %1$s %2$s %3$s %4$s %5$s";
private static final String DOMAIN_LIMIT_UPGRADE_EMAIL_BODY = private static final String DOMAIN_LIMIT_UPGRADE_EMAIL_BODY =
"domain limit upgrade body %1$s %2$s %3$s"; "domain limit upgrade body %1$s %2$s %3$s %4$s %5$s";
private static final String SUPPORT_EMAIL = "registry@test.com"; private static final String SUPPORT_EMAIL = "registry@test.com";
@RegisterExtension @RegisterExtension
@ -177,8 +178,7 @@ public class CheckPackagesComplianceActionTest {
EmailMessage emailMessage = emailCaptor.getValue(); EmailMessage emailMessage = emailCaptor.getValue();
assertThat(emailMessage.subject()).isEqualTo(CREATE_LIMIT_EMAIL_SUBJECT); assertThat(emailMessage.subject()).isEqualTo(CREATE_LIMIT_EMAIL_SUBJECT);
assertThat(emailMessage.body()) assertThat(emailMessage.body())
.isEqualTo( .isEqualTo(String.format(CREATE_LIMIT_EMAIL_BODY, 1, "abc123", "The Registrar", 1, 2));
String.format(CREATE_LIMIT_EMAIL_BODY, "The Registrar", "abc123", SUPPORT_EMAIL));
} }
@Test @Test
@ -364,8 +364,7 @@ public class CheckPackagesComplianceActionTest {
assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT); assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT);
assertThat(emailMessage.body()) assertThat(emailMessage.body())
.isEqualTo( .isEqualTo(
String.format( String.format(DOMAIN_LIMIT_WARNING_EMAIL_BODY, 1, "abc123", "The Registrar", 1, 2));
DOMAIN_LIMIT_WARNING_EMAIL_BODY, "The Registrar", "abc123", SUPPORT_EMAIL));
PackagePromotion packageAfterCheck = PackagePromotion packageAfterCheck =
tm().transact(() -> PackagePromotion.loadByTokenString(token.getToken()).get()); tm().transact(() -> PackagePromotion.loadByTokenString(token.getToken()).get());
assertThat(packageAfterCheck.getLastNotificationSent().get()).isEqualTo(clock.nowUtc()); assertThat(packageAfterCheck.getLastNotificationSent().get()).isEqualTo(clock.nowUtc());
@ -514,8 +513,7 @@ public class CheckPackagesComplianceActionTest {
assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT); assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT);
assertThat(emailMessage.body()) assertThat(emailMessage.body())
.isEqualTo( .isEqualTo(
String.format( String.format(DOMAIN_LIMIT_WARNING_EMAIL_BODY, 1, "abc123", "The Registrar", 1, 2));
DOMAIN_LIMIT_WARNING_EMAIL_BODY, "The Registrar", "abc123", SUPPORT_EMAIL));
PackagePromotion packageAfterCheck = PackagePromotion packageAfterCheck =
tm().transact(() -> PackagePromotion.loadByTokenString(token.getToken()).get()); tm().transact(() -> PackagePromotion.loadByTokenString(token.getToken()).get());
assertThat(packageAfterCheck.getLastNotificationSent().get()).isEqualTo(clock.nowUtc()); assertThat(packageAfterCheck.getLastNotificationSent().get()).isEqualTo(clock.nowUtc());
@ -558,8 +556,7 @@ public class CheckPackagesComplianceActionTest {
assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_UPGRADE_EMAIL_SUBJECT); assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_UPGRADE_EMAIL_SUBJECT);
assertThat(emailMessage.body()) assertThat(emailMessage.body())
.isEqualTo( .isEqualTo(
String.format( String.format(DOMAIN_LIMIT_UPGRADE_EMAIL_BODY, 1, "abc123", "The Registrar", 1, 2));
DOMAIN_LIMIT_UPGRADE_EMAIL_BODY, "The Registrar", "abc123", SUPPORT_EMAIL));
PackagePromotion packageAfterCheck = PackagePromotion packageAfterCheck =
tm().transact(() -> PackagePromotion.loadByTokenString(token.getToken()).get()); tm().transact(() -> PackagePromotion.loadByTokenString(token.getToken()).get());
assertThat(packageAfterCheck.getLastNotificationSent().get()).isEqualTo(clock.nowUtc()); assertThat(packageAfterCheck.getLastNotificationSent().get()).isEqualTo(clock.nowUtc());