diff --git a/core/src/main/java/google/registry/batch/CheckPackagesComplianceAction.java b/core/src/main/java/google/registry/batch/CheckPackagesComplianceAction.java index 1da52311df2..5e5945cdc1c 100644 --- a/core/src/main/java/google/registry/batch/CheckPackagesComplianceAction.java +++ b/core/src/main/java/google/registry/batch/CheckPackagesComplianceAction.java @@ -13,11 +13,11 @@ // limitations under the License. package google.registry.batch; -import static com.google.common.collect.ImmutableList.toImmutableList; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.util.DateTimeUtils.END_OF_TIME; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.flogger.FluentLogger; import com.google.common.primitives.Ints; @@ -25,7 +25,6 @@ import google.registry.model.domain.token.AllocationToken; import google.registry.model.domain.token.PackagePromotion; import google.registry.model.registrar.Registrar; -import google.registry.model.registrar.RegistrarPoc; import google.registry.request.Action; import google.registry.request.Action.Service; import google.registry.request.auth.Auth; @@ -88,10 +87,10 @@ public void run() { private void checkPackages() { ImmutableList packages = tm().loadAllOf(PackagePromotion.class); - ImmutableList.Builder packagesOverCreateLimitBuilder = - new ImmutableList.Builder<>(); - ImmutableList.Builder packagesOverActiveDomainsLimitBuilder = - new ImmutableList.Builder<>(); + ImmutableMap.Builder packagesOverCreateLimitBuilder = + new ImmutableMap.Builder<>(); + ImmutableMap.Builder packagesOverActiveDomainsLimitBuilder = + new ImmutableMap.Builder<>(); for (PackagePromotion packagePromo : packages) { Long creates = (Long) @@ -103,12 +102,12 @@ private void checkPackages() { .setParameter("lastBilling", packagePromo.getNextBillingDate().minusYears(1)) .getSingleResult(); if (creates > packagePromo.getMaxCreates()) { - int overage = Ints.saturatedCast(creates) - packagePromo.getMaxCreates(); + long overage = creates - packagePromo.getMaxCreates(); logger.atInfo().log( "Package with package token %s has exceeded their max domain creation limit" + " by %d name(s).", packagePromo.getToken().getKey(), overage); - packagesOverCreateLimitBuilder.add(packagePromo); + packagesOverCreateLimitBuilder.put(packagePromo, creates); } Long activeDomains = @@ -125,20 +124,20 @@ private void checkPackages() { "Package with package token %s has exceed their max active domains limit by" + " %d name(s).", packagePromo.getToken().getKey(), overage); - packagesOverActiveDomainsLimitBuilder.add(packagePromo); + packagesOverActiveDomainsLimitBuilder.put(packagePromo, activeDomains); } } handlePackageCreationOverage(packagesOverCreateLimitBuilder.build()); handleActiveDomainOverage(packagesOverActiveDomainsLimitBuilder.build()); } - private void handlePackageCreationOverage(ImmutableList overageList) { + private void handlePackageCreationOverage(ImmutableMap overageList) { if (overageList.isEmpty()) { logger.atInfo().log("Found no packages over their create limit."); return; } 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()); Optional registrar = Registrar.loadByRegistrarIdCached( @@ -147,9 +146,11 @@ private void handlePackageCreationOverage(ImmutableList overag String body = String.format( packageCreateLimitEmailBody, - registrar.get().getRegistrarName(), + packagePromotion.getId(), packageToken.getToken(), - registrySupportEmail); + registrar.get().getRegistrarName(), + packagePromotion.getMaxCreates(), + overageList.get(packagePromotion)); sendNotification(packageToken, packageCreateLimitEmailSubject, body, registrar.get()); } else { throw new IllegalStateException( @@ -158,13 +159,13 @@ private void handlePackageCreationOverage(ImmutableList overag } } - private void handleActiveDomainOverage(ImmutableList overageList) { + private void handleActiveDomainOverage(ImmutableMap overageList) { if (overageList.isEmpty()) { logger.atInfo().log("Found no packages over their active domains limit."); return; } logger.atInfo().log("Found %d packages over their active domains limit.", overageList.size()); - for (PackagePromotion packagePromotion : overageList) { + for (PackagePromotion packagePromotion : overageList.keySet()) { int daysSinceLastNotification = packagePromotion .getLastNotificationSent() @@ -176,15 +177,18 @@ private void handleActiveDomainOverage(ImmutableList overageLi continue; } else if (daysSinceLastNotification < FORTY_DAYS) { // 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 { // 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 = warning ? packageDomainLimitWarningEmailSubject : packageDomainLimitUpgradeEmailSubject; String emailTemplate = @@ -197,9 +201,11 @@ private void sendActiveDomainOverageEmail(boolean warning, PackagePromotion pack String body = String.format( emailTemplate, - registrar.get().getRegistrarName(), + packagePromotion.getId(), packageToken.getToken(), - registrySupportEmail); + registrar.get().getRegistrarName(), + packagePromotion.getMaxDomains(), + activeDomains); sendNotification(packageToken, emailSubject, body, registrar.get()); tm().put(packagePromotion.asBuilder().setLastNotificationSent(clock.nowUtc()).build()); } else { @@ -212,15 +218,9 @@ private void sendNotification( AllocationToken packageToken, String subject, String body, Registrar registrar) { logger.atInfo().log( 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())); - sendEmailUtils.sendEmail( - subject, - body, - Optional.of(registrySupportEmail), - registrar.getContacts().stream() - .filter(c -> c.getTypes().contains(RegistrarPoc.Type.ADMIN)) - .map(RegistrarPoc::getEmailAddress) - .collect(toImmutableList())); + sendEmailUtils.sendEmail(subject, body, ImmutableList.of(registrySupportEmail)); } } diff --git a/core/src/main/java/google/registry/config/files/default-config.yaml b/core/src/main/java/google/registry/config/files/default-config.yaml index 223a3eb39b6..ae41e6e5c4d 100644 --- a/core/src/main/java/google/registry/config/files/default-config.yaml +++ b/core/src/main/java/google/registry/config/files/default-config.yaml @@ -538,52 +538,53 @@ sslCertificateValidation: # Configuration options for the package compliance monitoring packageMonitoring: - # Email subject text to notify partners their package has exceeded the limit for domain creates - packageCreateLimitEmailSubject: "NOTICE: Your package is being upgraded" - # Email body text template 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: "ACTION REQUIRED: Package needs to be upgraded" + # Email body text template notify support that a package has exceeded the limit for domain creates packageCreateLimitEmailBody: > - Dear %1$s, - - We are contacting you to inform you that your package with the package token - %2$s has exceeded its limit for annual domain creations. - Your package will now be upgraded to the next tier. + Dear Support, - If you have any questions or require additional support, please contact us - at %3$s. + A package has exceeded its max create limit and needs to be upgraded to the + next tier. - Regards, - Example Registry - - # 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 - packageDomainLimitWarningEmailSubject: "WARNING: Your package has exceeded the domain limit" - # Email body text template to warn partners their package has exceeded the limit for active domains and will be upgraded in 30 days + Package ID: %1$s + Package Token: %2$s + Registrar: %3$s + Current Max Create Limit: %4$s + Creates Completed: %5$s + + # Email subject text to notify support that a package has exceeded the limit + # for current active domains and a warning needs to be sent + 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: > - Dear %1$s, - - 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 + Dear Support, + + A package has exceeded its max domain limit. Please send a warning to the + registrar that their package will be upgraded to the next tier in 30 days if + 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 + + # Email subject text to notify support that a package has exceeded the limit + # 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" + # Email body text template to inform support that a package has exceeded the + # limit for active domains for more than 30 days and needs to be upgraded packageDomainLimitUpgradeEmailBody: > - 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 now be upgraded to the next tier. - - If you have any questions or require additional support, please contact us - at %3$s. - - Regards, - Example Registry + 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 diff --git a/core/src/main/java/google/registry/model/domain/token/PackagePromotion.java b/core/src/main/java/google/registry/model/domain/token/PackagePromotion.java index 1d043d47a96..88af4471e49 100644 --- a/core/src/main/java/google/registry/model/domain/token/PackagePromotion.java +++ b/core/src/main/java/google/registry/model/domain/token/PackagePromotion.java @@ -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. */ @Nullable DateTime lastNotificationSent; + public long getId() { + return packagePromotionId; + } + public VKey getToken() { return token; } diff --git a/core/src/test/java/google/registry/batch/CheckPackagesComplianceActionTest.java b/core/src/test/java/google/registry/batch/CheckPackagesComplianceActionTest.java index 740bde1730f..29fde5e31fb 100644 --- a/core/src/test/java/google/registry/batch/CheckPackagesComplianceActionTest.java +++ b/core/src/test/java/google/registry/batch/CheckPackagesComplianceActionTest.java @@ -60,11 +60,12 @@ public class CheckPackagesComplianceActionTest { 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_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 = - "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 = - "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"; @RegisterExtension @@ -177,8 +178,7 @@ void testSuccess_onePackageOverCreateLimit() throws Exception { EmailMessage emailMessage = emailCaptor.getValue(); assertThat(emailMessage.subject()).isEqualTo(CREATE_LIMIT_EMAIL_SUBJECT); assertThat(emailMessage.body()) - .isEqualTo( - String.format(CREATE_LIMIT_EMAIL_BODY, "The Registrar", "abc123", SUPPORT_EMAIL)); + .isEqualTo(String.format(CREATE_LIMIT_EMAIL_BODY, 1, "abc123", "The Registrar", 1, 2)); } @Test @@ -364,8 +364,7 @@ void testSuccess_onePackageOverActiveDomainsLimit() { assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT); assertThat(emailMessage.body()) .isEqualTo( - String.format( - DOMAIN_LIMIT_WARNING_EMAIL_BODY, "The Registrar", "abc123", SUPPORT_EMAIL)); + String.format(DOMAIN_LIMIT_WARNING_EMAIL_BODY, 1, "abc123", "The Registrar", 1, 2)); PackagePromotion packageAfterCheck = tm().transact(() -> PackagePromotion.loadByTokenString(token.getToken()).get()); assertThat(packageAfterCheck.getLastNotificationSent().get()).isEqualTo(clock.nowUtc()); @@ -514,8 +513,7 @@ void testSuccess_packageOverActiveDomainsLimitAlreadySentWarningEmailOver40DaysA assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_WARNING_EMAIL_SUBJECT); assertThat(emailMessage.body()) .isEqualTo( - String.format( - DOMAIN_LIMIT_WARNING_EMAIL_BODY, "The Registrar", "abc123", SUPPORT_EMAIL)); + String.format(DOMAIN_LIMIT_WARNING_EMAIL_BODY, 1, "abc123", "The Registrar", 1, 2)); PackagePromotion packageAfterCheck = tm().transact(() -> PackagePromotion.loadByTokenString(token.getToken()).get()); assertThat(packageAfterCheck.getLastNotificationSent().get()).isEqualTo(clock.nowUtc()); @@ -558,8 +556,7 @@ void testSuccess_packageOverActiveDomainsLimitAlreadySentWarning30DaysAgo_SendsU assertThat(emailMessage.subject()).isEqualTo(DOMAIN_LIMIT_UPGRADE_EMAIL_SUBJECT); assertThat(emailMessage.body()) .isEqualTo( - String.format( - DOMAIN_LIMIT_UPGRADE_EMAIL_BODY, "The Registrar", "abc123", SUPPORT_EMAIL)); + String.format(DOMAIN_LIMIT_UPGRADE_EMAIL_BODY, 1, "abc123", "The Registrar", 1, 2)); PackagePromotion packageAfterCheck = tm().transact(() -> PackagePromotion.loadByTokenString(token.getToken()).get()); assertThat(packageAfterCheck.getLastNotificationSent().get()).isEqualTo(clock.nowUtc());