Skip to content

Commit

Permalink
RHCLOUD-29084 Support event types subscribed by default in connectors (
Browse files Browse the repository at this point in the history
…RedHatInsights#2323)


Co-authored-by: Guillaume Duval <[email protected]>
  • Loading branch information
gwenneg and g-duval authored Nov 9, 2023
1 parent 0c31141 commit 81e8980
Show file tree
Hide file tree
Showing 19 changed files with 500 additions and 571 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.redhat.cloud.notifications.connector.CloudEventDataExtractor;
import com.redhat.cloud.notifications.connector.email.constants.ExchangeProperty;
import com.redhat.cloud.notifications.connector.email.model.settings.RecipientSettings;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import jakarta.enterprise.context.ApplicationScoped;
import org.apache.camel.Exchange;
Expand All @@ -29,10 +30,15 @@ public void extract(final Exchange exchange, final JsonObject cloudEventData) {
.map(jsonSetting -> jsonSetting.mapTo(RecipientSettings.class))
.toList();

final List<String> subscribers = cloudEventData.getJsonArray("subscribers")
final Set<String> subscribers = cloudEventData.getJsonArray("subscribers", JsonArray.of())
.stream()
.map(String.class::cast)
.toList();
.collect(toSet());

final Set<String> unsubscribers = cloudEventData.getJsonArray("unsubscribers", JsonArray.of())
.stream()
.map(String.class::cast)
.collect(toSet());

final Set<String> emails = recipientSettings.stream()
.filter(settings -> settings.getEmails() != null)
Expand All @@ -43,6 +49,7 @@ public void extract(final Exchange exchange, final JsonObject cloudEventData) {
exchange.setProperty(ExchangeProperty.RENDERED_SUBJECT, cloudEventData.getString("email_subject"));
exchange.setProperty(ExchangeProperty.RECIPIENT_SETTINGS, recipientSettings);
exchange.setProperty(ExchangeProperty.SUBSCRIBERS, subscribers);
exchange.setProperty(ExchangeProperty.UNSUBSCRIBERS, unsubscribers);
exchange.setProperty(ExchangeProperty.EMAIL_RECIPIENTS, emails);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,15 @@ public class ExchangeProperty {
*/
public static final String SINGLE_EMAIL_PER_USER = "single_email_per_user";
/**
* Holds the list of subscribers that have a subscription to the event type
* Holds the list of usernames who subscribed to the event type
* that triggered the notification.
*/
public static final String SUBSCRIBERS = "subscribers";
/**
* Holds the list of usernames who unsubscribed from the event type
* that triggered the notification.
*/
public static final String UNSUBSCRIBERS = "unsubscribers";
/**
* Holds the rendered body contents, ready to be sent in an email.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ public class RecipientsResolverPreparer implements Processor {
@Override
public void process(final Exchange exchange) throws JsonProcessingException {
List<RecipientSettings> recipientSettings = exchange.getProperty(ExchangeProperty.RECIPIENT_SETTINGS, List.class);
List<String> subscribers = exchange.getProperty(ExchangeProperty.SUBSCRIBERS, List.class);
Set<String> subscribers = exchange.getProperty(ExchangeProperty.SUBSCRIBERS, Set.class);
Set<String> unsubscribers = exchange.getProperty(ExchangeProperty.UNSUBSCRIBERS, Set.class);
final String orgId = exchange.getProperty(ORG_ID, String.class);

RecipientsQuery recipientsQuery = new RecipientsQuery();
recipientsQuery.subscribers = Set.copyOf(subscribers);
recipientsQuery.subscribers = subscribers;
recipientsQuery.unsubscribers = unsubscribers;
recipientsQuery.orgId = orgId;
recipientsQuery.recipientSettings = Set.copyOf(recipientSettings);
recipientsQuery.subscribedByDefault = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ public class RecipientsQuery {

public Set<String> subscribers;

public Set<String> unsubscribers;

public boolean subscribedByDefault;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static com.redhat.cloud.notifications.connector.email.constants.ExchangeProperty.RENDERED_BODY;
import static com.redhat.cloud.notifications.connector.email.constants.ExchangeProperty.RENDERED_SUBJECT;
import static com.redhat.cloud.notifications.connector.email.constants.ExchangeProperty.SUBSCRIBERS;
import static com.redhat.cloud.notifications.connector.email.constants.ExchangeProperty.UNSUBSCRIBERS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertIterableEquals;

Expand Down Expand Up @@ -65,14 +66,16 @@ void testExtract() {
recipientSettingsList.add(recipientSettings2);
recipientSettingsList.add(recipientSettings3);

final List<String> subscribers = List.of("a", "b", "c");
final Set<String> subscribers = Set.of("a", "b", "c");
final Set<String> unsubscribers = Set.of("d", "e", "f");
final String emailBody = "fake email body";
final String emailSubject = "fake email subject";

// Prepare the JSON object.
final JsonObject payload = new JsonObject();
payload.put("recipient_settings", recipientSettingsList);
payload.put("subscribers", subscribers);
payload.put("unsubscribers", unsubscribers);
payload.put("email_body", emailBody);
payload.put("email_subject", emailSubject);

Expand All @@ -87,7 +90,8 @@ void testExtract() {
assertEquals(emailBody, exchange.getProperty(RENDERED_BODY, String.class));
assertEquals(emailSubject, exchange.getProperty(RENDERED_SUBJECT, String.class));
assertIterableEquals(recipientSettingsList, exchange.getProperty(RECIPIENT_SETTINGS, List.class));
assertIterableEquals(subscribers, exchange.getProperty(SUBSCRIBERS, List.class));
assertEquals(subscribers, exchange.getProperty(SUBSCRIBERS, Set.class));
assertEquals(unsubscribers, exchange.getProperty(UNSUBSCRIBERS, Set.class));
assertEquals(Set.of("[email protected]", "[email protected]", "[email protected]"), exchange.getProperty(EMAIL_RECIPIENTS, Set.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void testMultipleRecipientSettingsSameUserSendSingleEmail() throws Exception {
recipientSettingsList.add(recipientSettings);
recipientSettingsList.add(recipientSettings2);

final List<String> subscribers = List.of("user1", "user2");
final Set<String> subscribers = Set.of("user1", "user2");

final String emailBody = "emailBody";
final String emailSubject = "emailSubject";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ void testMultipleRecipientSettingsSameUserSendSingleEmail() throws Exception {
recipientSettingsList.add(recipientSettings);
recipientSettingsList.add(recipientSettings2);

final List<String> subscribers = List.of("user1", "user2");
final Set<String> subscribers = Set.of("user1", "user2");

final String emailBody = "emailBody";
final String emailSubject = "emailSubject";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,4 @@ public Set<com.redhat.cloud.notifications.processors.email.connector.dto.Recipie
.map(com.redhat.cloud.notifications.processors.email.connector.dto.RecipientSettings::new)
.collect(Collectors.toSet());
}

/**
* Gets a list of the email subscribers which should get an email for the
* given event.
* @param event the event the users are subscribed to.
* @return a list of {@link java.util.UUID}s in the {@link String} shape.
*/
protected List<String> getSubscribers(final Event event, final SubscriptionType subscriptionType) {
final EventType eventType = event.getEventType();

if (subscriptionType.isSubscribedByDefault()) {
return subscriptionRepository.getUnsubscribers(event.getOrgId(), eventType.getId(), subscriptionType);
} else {
return subscriptionRepository.getSubscribers(event.getOrgId(), eventType.getId(), subscriptionType);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.redhat.cloud.notifications.db.repositories.DrawerNotificationRepository;
import com.redhat.cloud.notifications.db.repositories.EndpointRepository;
import com.redhat.cloud.notifications.db.repositories.EventRepository;
import com.redhat.cloud.notifications.db.repositories.SubscriptionRepository;
import com.redhat.cloud.notifications.db.repositories.TemplateRepository;
import com.redhat.cloud.notifications.models.DrawerEntry;
import com.redhat.cloud.notifications.models.DrawerEntryPayload;
Expand All @@ -17,7 +18,6 @@
import com.redhat.cloud.notifications.models.IntegrationTemplate;
import com.redhat.cloud.notifications.models.NotificationHistory;
import com.redhat.cloud.notifications.models.NotificationStatus;
import com.redhat.cloud.notifications.models.SubscriptionType;
import com.redhat.cloud.notifications.processors.ConnectorSender;
import com.redhat.cloud.notifications.processors.SystemEndpointTypeProcessor;
import com.redhat.cloud.notifications.processors.email.connector.dto.RecipientSettings;
Expand Down Expand Up @@ -46,6 +46,7 @@
import static com.redhat.cloud.notifications.events.EndpointProcessor.DELAYED_EXCEPTION_MSG;
import static com.redhat.cloud.notifications.models.IntegrationTemplate.TemplateKind.ALL;
import static com.redhat.cloud.notifications.models.NotificationHistory.getHistoryStub;
import static com.redhat.cloud.notifications.models.SubscriptionType.DRAWER;

@ApplicationScoped
public class DrawerProcessor extends SystemEndpointTypeProcessor {
Expand Down Expand Up @@ -85,6 +86,9 @@ public class DrawerProcessor extends SystemEndpointTypeProcessor {
@Inject
ConnectorSender connectorSender;

@Inject
SubscriptionRepository subscriptionRepository;

@Override
public void process(Event event, List<Endpoint> endpoints) {
if (!featureFlipper.isDrawerEnabled()) {
Expand All @@ -107,20 +111,21 @@ public void process(Event event, List<Endpoint> endpoints) {
if (featureFlipper.isDrawerConnectorEnabled()) {
DrawerEntryPayload drawerEntryPayload = buildJsonPayloadFromEvent(event);

final Set<String> subscribers = Set.copyOf(getSubscribers(event, SubscriptionType.DRAWER));
final Set<String> unsubscribers =
Set.copyOf(subscriptionRepository.getUnsubscribers(event.getOrgId(), event.getEventType().getId(), DRAWER));
final Set<RecipientSettings> recipientSettings = extractAndTransformRecipientSettings(event, endpoints);

// Prepare all the data to be sent to the connector.
final DrawerNotificationToConnector drawerNotificationToConnector = new DrawerNotificationToConnector(
event.getOrgId(),
drawerEntryPayload,
recipientSettings,
subscribers
unsubscribers
);

connectorSender.send(event, endpoint, JsonObject.mapFrom(drawerNotificationToConnector));
} else {
Set<User> userList = getRecipientList(event, endpoints, SubscriptionType.DRAWER);
Set<User> userList = getRecipientList(event, endpoints, DRAWER);
if (null == userList || userList.isEmpty()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.redhat.cloud.notifications.processors.email;

import com.redhat.cloud.notifications.db.repositories.EndpointRepository;
import com.redhat.cloud.notifications.db.repositories.SubscriptionRepository;
import com.redhat.cloud.notifications.db.repositories.TemplateRepository;
import com.redhat.cloud.notifications.models.Endpoint;
import com.redhat.cloud.notifications.models.EndpointType;
import com.redhat.cloud.notifications.models.Event;
import com.redhat.cloud.notifications.models.InstantEmailTemplate;
import com.redhat.cloud.notifications.models.SubscriptionType;
import com.redhat.cloud.notifications.processors.ConnectorSender;
import com.redhat.cloud.notifications.processors.SystemEndpointTypeProcessor;
import com.redhat.cloud.notifications.processors.email.connector.dto.EmailNotification;
Expand All @@ -18,10 +18,13 @@
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static com.redhat.cloud.notifications.models.SubscriptionType.INSTANT;

@ApplicationScoped
public class EmailProcessor extends SystemEndpointTypeProcessor {
@Inject
Expand All @@ -39,6 +42,9 @@ public class EmailProcessor extends SystemEndpointTypeProcessor {
@Inject
TemplateService templateService;

@Inject
SubscriptionRepository subscriptionRepository;

@Override
public void process(final Event event, final List<Endpoint> endpoints) {

Expand All @@ -52,16 +58,26 @@ public void process(final Event event, final List<Endpoint> endpoints) {
return;
}

// Get the set of user IDs that should receive an email notification for
// the given event.
final List<String> subscribers = this.getSubscribers(event, SubscriptionType.INSTANT);
Set<String> subscribers;
Set<String> unsubscribers;
if (event.getEventType().isSubscribedByDefault()) {
subscribers = Collections.emptySet();
unsubscribers = Set.copyOf(subscriptionRepository.getUnsubscribers(event.getOrgId(), event.getEventType().getId(), INSTANT));
} else {
subscribers = Set.copyOf(subscriptionRepository.getSubscribers(event.getOrgId(), event.getEventType().getId(), INSTANT));
unsubscribers = Collections.emptySet();
}

final Set<RecipientSettings> recipientSettings = this.extractAndTransformRecipientSettings(event, endpoints);

// When the user preferences are not ignored and there are no
// subscribers to the event, there's no need to further process the
// recipient settings because no email will be sent from them.
recipientSettings.removeIf(settings -> !settings.isIgnoreUserPreferences() && subscribers.isEmpty());
/*
* When:
* - the event type is NOT subscribed by default
* - the user preferences are NOT ignored
* - there are no subscribers to the event type
* Then, there's no need to further process the recipient settings because no email will be sent from them.
*/
recipientSettings.removeIf(settings -> !event.getEventType().isSubscribedByDefault() && !settings.isIgnoreUserPreferences() && subscribers.isEmpty());

// If we removed all recipient settings, it means no email will be sent from the event and we can exit this method.
if (recipientSettings.isEmpty()) {
Expand All @@ -87,7 +103,8 @@ public void process(final Event event, final List<Endpoint> endpoints) {
subject,
event.getOrgId(),
recipientSettings,
subscribers
subscribers,
unsubscribers
);

final JsonObject payload = JsonObject.mapFrom(emailNotification);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -318,7 +319,9 @@ private void processAggregateEmailsByAggregationKey(AggregationCommand aggregati
final EmailNotification emailNotification = new EmailNotification(
bodyStr, subjectStr,
event.getOrgId(),
recipientSettings, recipientsUsernames
recipientSettings,
recipientsUsernames,
Collections.emptySet()
);

connectorSender.send(event, endpoint, JsonObject.mapFrom(emailNotification));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
* @param recipientSettings the collection of recipient settings extracted from
* both the event and the related endpoints to the
* event.
* @param subscribers the list of user {@link java.util.UUID}s which were
* subscribed to the event.
* @param subscribers the list of usernames who subscribed to the event type.
* @param unsubscribers the list of usernames who unsubscribed from the event type.
*/
public record EmailNotification(
@JsonProperty("email_body") String emailBody,
@JsonProperty("email_subject") String emailSubject,
@JsonProperty("orgId") String orgId,
@JsonProperty("recipient_settings") Collection<RecipientSettings> recipientSettings,
@JsonProperty("subscribers") Collection<String> subscribers
@JsonProperty("subscribers") Collection<String> subscribers,
@JsonProperty("unsubscribers") Collection<String> unsubscribers
) { }
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ public class RecipientsQuery {

public Set<String> subscribers;

public Set<String> unsubscribers;

public boolean subscribedByDefault;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toSet;

@QuarkusTest
public class EmailProcessorTest {
Expand Down Expand Up @@ -367,7 +368,7 @@ void testSuccess() {
final String resultEmailBody = payload.getString("email_body");
final String resultEmailSubject = payload.getString("email_subject");
final String resultOrgId = payload.getString("orgId");
final List<String> resultSubscribers = payload.getJsonArray("subscribers").stream().map(String.class::cast).toList();
final Set<String> resultSubscribers = payload.getJsonArray("subscribers").stream().map(String.class::cast).collect(toSet());
final Set<RecipientSettings> resultRecipientSettings = payload.getJsonArray("recipient_settings")
.stream()
.map(JsonObject.class::cast)
Expand All @@ -378,15 +379,15 @@ void testSuccess() {
jsonRs.getBoolean("admins_only"),
jsonRs.getBoolean("ignore_user_preferences"),
(groupUUID == null) ? null : UUID.fromString(groupUUID),
jsonRs.getJsonArray("users").stream().map(String.class::cast).collect(Collectors.toSet()),
jsonRs.getJsonArray("emails").stream().map(String.class::cast).collect(Collectors.toSet())
jsonRs.getJsonArray("users").stream().map(String.class::cast).collect(toSet()),
jsonRs.getJsonArray("emails").stream().map(String.class::cast).collect(toSet())
);
}).collect(Collectors.toSet());
}).collect(toSet());

Assertions.assertEquals(stubbedRenderedBody, resultEmailBody, "the rendered email's body from the email notification does not match the stubbed email body");
Assertions.assertEquals(stubbedRenderedSubject, resultEmailSubject, "the rendered email's subject from the email notification does not match the stubbed email subject");
Assertions.assertEquals(event.getOrgId(), resultOrgId, "the organization ID from the email notification does not match the one set in the stubbed event");
Assertions.assertIterableEquals(subscribers, resultSubscribers, "the subscribers set in the email notification do not match the stubbed ones");
Assertions.assertEquals(Set.copyOf(subscribers), resultSubscribers, "the subscribers set in the email notification do not match the stubbed ones");

final Set<RecipientSettings> recipientSettings = this.emailProcessor.extractAndTransformRecipientSettings(event, endpoints);
Assertions.assertIterableEquals(recipientSettings, resultRecipientSettings, "the recipient settings set in the email notification do not match the stubbed ones");
Expand Down
Loading

0 comments on commit 81e8980

Please sign in to comment.