diff --git a/openespi-datacustodian/src/main/java/org/greenbuttonalliance/espi/datacustodian/web/custodian/BatchNotificationController.java b/openespi-datacustodian/src/main/java/org/greenbuttonalliance/espi/datacustodian/web/custodian/BatchNotificationController.java index b6407f61..ca946202 100644 --- a/openespi-datacustodian/src/main/java/org/greenbuttonalliance/espi/datacustodian/web/custodian/BatchNotificationController.java +++ b/openespi-datacustodian/src/main/java/org/greenbuttonalliance/espi/datacustodian/web/custodian/BatchNotificationController.java @@ -22,6 +22,7 @@ import org.greenbuttonalliance.espi.common.domain.usage.ApplicationInformationEntity; import org.greenbuttonalliance.espi.common.service.ApplicationInformationService; import org.greenbuttonalliance.espi.common.service.NotificationService; +import org.greenbuttonalliance.espi.common.uri.EspiBatchUri; import org.springframework.core.env.Environment; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; @@ -31,14 +32,20 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import java.util.ArrayList; import java.util.List; -import java.util.stream.Stream; /** - * Custodian "Notify Third Party" page (#177). Lets an admin compose and send an ESPI - * {@code BatchList} (Atom) of resource URLs — ApplicationInformation, Authorization feed, - * Authorization entry, Subscription — to a Third Party notification endpoint, reusing the #158 - * notification contract via {@link NotificationService#notifyBatchList}. + * Custodian "Notify Third Party" page (#177, #181). The admin composes an ESPI {@code BatchList} + * (Atom) and POSTs it to a Third Party notification endpoint, reusing the #158 notification contract + * via {@link NotificationService#notifyBatchList}. + * + *

The admin selects which and how many of the available resource URLs to include + * (each has an "include" checkbox and an editable URL). The available set covers ApplicationInformation, + * the Authorization feed, an Authorization entry, and the two subscription formats — an energy + * subscription ({@code …/Batch/Subscription/{id}}) and a PII/customer subscription + * ({@code …/Batch/RetailCustomer/{id}}), built via {@link EspiBatchUri}. Only checked, non-blank URLs + * are marshalled into the BatchList.

*/ @Controller @PreAuthorize("hasRole('ROLE_CUSTODIAN')") @@ -77,13 +84,14 @@ public String form(Model model) { @PostMapping("/custodian/notifications/send") public String send(@ModelAttribute("notifyForm") NotifyForm form, RedirectAttributes redirectAttributes) { - List resources = Stream.of( - form.getApplicationInformationUrl(), - form.getAuthorizationFeedUrl(), - form.getAuthorizationEntryUrl(), - form.getSubscriptionUrl()) - .filter(u -> u != null && !u.isBlank()) - .toList(); + // Only the checked, non-blank URLs go into the BatchList — the admin chooses which/how many. + List resources = new ArrayList<>(); + addIf(resources, form.isIncludeApplicationInformation(), form.getApplicationInformationUrl()); + addIf(resources, form.isIncludeAuthorizationFeed(), form.getAuthorizationFeedUrl()); + addIf(resources, form.isIncludeAuthorizationEntry(), form.getAuthorizationEntryUrl()); + addIf(resources, form.isIncludeEnergySubscription(), form.getEnergySubscriptionUrl()); + addIf(resources, form.isIncludePiiSubscription(), form.getPiiSubscriptionUrl()); + try { notificationService.notifyBatchList(form.getNotificationUri(), resources); redirectAttributes.addFlashAttribute("message", @@ -94,11 +102,17 @@ public String send(@ModelAttribute("notifyForm") NotifyForm form, RedirectAttrib redirectAttributes.addFlashAttribute("message", "Failed to send BatchList: " + e.getMessage()); redirectAttributes.addFlashAttribute("messageType", "danger"); } - // Preserve what the admin typed so they can correct and resend. + // Preserve what the admin selected/typed so they can correct and resend. redirectAttributes.addFlashAttribute("notifyForm", form); return "redirect:/custodian/notifications"; } + private static void addIf(List resources, boolean include, String url) { + if (include && url != null && !url.isBlank()) { + resources.add(url.trim()); + } + } + private NotifyForm defaultForm(List apps) { String base = environment.getProperty("espi.datacustodian.base-url", "http://localhost:8081/DataCustodian"); @@ -112,27 +126,53 @@ private NotifyForm defaultForm(List apps) { f.setApplicationInformationUrl(resourceBase + "/ApplicationInformation/{applicationInformationId}"); f.setAuthorizationFeedUrl(resourceBase + "/Authorization"); f.setAuthorizationEntryUrl(resourceBase + "/Authorization/{authorizationId}"); - f.setSubscriptionUrl(resourceBase + "/Subscription/{subscriptionId}"); + // Two distinct ESPI subscription formats, built from the canonical URI builder (#160). + f.setEnergySubscriptionUrl(EspiBatchUri.batchSubscription(resourceBase, "{subscriptionId}")); + f.setPiiSubscriptionUrl(EspiBatchUri.batchRetailCustomer(resourceBase, "{retailCustomerId}")); return f; } - /** Backing form for the notify page. */ + /** Backing form: each candidate resource has an include flag + an editable URL. */ public static class NotifyForm { private String notificationUri; + + private boolean includeApplicationInformation = true; private String applicationInformationUrl; + private boolean includeAuthorizationFeed = true; private String authorizationFeedUrl; + private boolean includeAuthorizationEntry = true; private String authorizationEntryUrl; - private String subscriptionUrl; + private boolean includeEnergySubscription = true; + private String energySubscriptionUrl; + private boolean includePiiSubscription = true; + private String piiSubscriptionUrl; public String getNotificationUri() { return notificationUri; } - public void setNotificationUri(String notificationUri) { this.notificationUri = notificationUri; } + public void setNotificationUri(String v) { this.notificationUri = v; } + + public boolean isIncludeApplicationInformation() { return includeApplicationInformation; } + public void setIncludeApplicationInformation(boolean v) { this.includeApplicationInformation = v; } public String getApplicationInformationUrl() { return applicationInformationUrl; } public void setApplicationInformationUrl(String v) { this.applicationInformationUrl = v; } + + public boolean isIncludeAuthorizationFeed() { return includeAuthorizationFeed; } + public void setIncludeAuthorizationFeed(boolean v) { this.includeAuthorizationFeed = v; } public String getAuthorizationFeedUrl() { return authorizationFeedUrl; } public void setAuthorizationFeedUrl(String v) { this.authorizationFeedUrl = v; } + + public boolean isIncludeAuthorizationEntry() { return includeAuthorizationEntry; } + public void setIncludeAuthorizationEntry(boolean v) { this.includeAuthorizationEntry = v; } public String getAuthorizationEntryUrl() { return authorizationEntryUrl; } public void setAuthorizationEntryUrl(String v) { this.authorizationEntryUrl = v; } - public String getSubscriptionUrl() { return subscriptionUrl; } - public void setSubscriptionUrl(String v) { this.subscriptionUrl = v; } + + public boolean isIncludeEnergySubscription() { return includeEnergySubscription; } + public void setIncludeEnergySubscription(boolean v) { this.includeEnergySubscription = v; } + public String getEnergySubscriptionUrl() { return energySubscriptionUrl; } + public void setEnergySubscriptionUrl(String v) { this.energySubscriptionUrl = v; } + + public boolean isIncludePiiSubscription() { return includePiiSubscription; } + public void setIncludePiiSubscription(boolean v) { this.includePiiSubscription = v; } + public String getPiiSubscriptionUrl() { return piiSubscriptionUrl; } + public void setPiiSubscriptionUrl(String v) { this.piiSubscriptionUrl = v; } } } diff --git a/openespi-datacustodian/src/main/resources/templates/custodian/notifications.html b/openespi-datacustodian/src/main/resources/templates/custodian/notifications.html index 4c484270..a4eb9648 100644 --- a/openespi-datacustodian/src/main/resources/templates/custodian/notifications.html +++ b/openespi-datacustodian/src/main/resources/templates/custodian/notifications.html @@ -10,8 +10,8 @@

Notify Third Party

- Compose an ESPI BatchList of resource URLs and POST it to a Third Party's - notification endpoint. Leave a field blank to omit that resource. + Choose which resource URLs to include, then POST them as an ESPI BatchList to a + Third Party's notification endpoint. Only checked rows with a non-blank URL are sent.

Notify Third Party -
Registered third-party endpoints are suggested; you may edit.

-
BatchList resources
+
BatchList resources — select which to send
-
- - +
+
+ +
+ +
+ +
-
- - + +
+
+ +
+ +
+ +
-
- - + +
+
+ +
+ +
+ +
-
- - + +
+
+ +
+ +
+ +
+
+ +
+
+ +
+ +
+ +