feat: add notification channels for email and webhooks
This commit is contained in:
1 parent
959b400f5a
commit
aec31a4555
9 files changed
+162
No files matched your search
@@ -0,0 +1,23 @@
|
|||||||
|
package com.slotline.notification;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class EmailNotificationChannel implements NotificationChannel {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(EmailNotificationChannel.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "email";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deliver(NotificationMessage message) {
|
||||||
|
log.info("[email] user={} type={} resource='{}' [{} - {}] :: {}",
|
||||||
|
message.recipientUserId(), message.type(), message.resourceName(),
|
||||||
|
message.startTime(), message.endTime(), message.summary());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.slotline.notification;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class HttpWebhookGateway implements WebhookGateway {
|
||||||
|
|
||||||
|
private final HttpClient httpClient = HttpClient.newBuilder()
|
||||||
|
.connectTimeout(Duration.ofSeconds(5))
|
||||||
|
.build();
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public HttpWebhookGateway(ObjectMapper objectMapper) {
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void post(String url, NotificationMessage message) {
|
||||||
|
try {
|
||||||
|
String body = objectMapper.writeValueAsString(message);
|
||||||
|
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.timeout(Duration.ofSeconds(5))
|
||||||
|
.POST(HttpRequest.BodyPublishers.ofString(body))
|
||||||
|
.build();
|
||||||
|
httpClient.send(request, HttpResponse.BodyHandlers.discarding());
|
||||||
|
} catch (Exception failure) {
|
||||||
|
throw new WebhookDeliveryException(url, failure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.slotline.notification;
|
||||||
|
|
||||||
|
public interface NotificationChannel {
|
||||||
|
|
||||||
|
String name();
|
||||||
|
|
||||||
|
void deliver(NotificationMessage message);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.slotline.notification;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public record NotificationMessage(
|
||||||
|
NotificationType type,
|
||||||
|
Long organizationId,
|
||||||
|
Long recipientUserId,
|
||||||
|
Long resourceId,
|
||||||
|
String resourceName,
|
||||||
|
Instant startTime,
|
||||||
|
Instant endTime,
|
||||||
|
String summary) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.slotline.notification;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class NotificationService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(NotificationService.class);
|
||||||
|
|
||||||
|
private final List<NotificationChannel> channels;
|
||||||
|
|
||||||
|
public NotificationService(List<NotificationChannel> channels) {
|
||||||
|
this.channels = channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispatch(NotificationMessage message) {
|
||||||
|
for (NotificationChannel channel : channels) {
|
||||||
|
try {
|
||||||
|
channel.deliver(message);
|
||||||
|
} catch (RuntimeException failure) {
|
||||||
|
log.warn("Notification channel '{}' failed to deliver {} for user {}",
|
||||||
|
channel.name(), message.type(), message.recipientUserId(), failure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.slotline.notification;
|
||||||
|
|
||||||
|
public enum NotificationType {
|
||||||
|
RESERVATION_CREATED,
|
||||||
|
RESERVATION_CANCELLED,
|
||||||
|
WAITLIST_PROMOTED
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.slotline.notification;
|
||||||
|
|
||||||
|
public class WebhookDeliveryException extends RuntimeException {
|
||||||
|
|
||||||
|
public WebhookDeliveryException(String url, Throwable cause) {
|
||||||
|
super("Failed to deliver webhook to " + url, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.slotline.notification;
|
||||||
|
|
||||||
|
public interface WebhookGateway {
|
||||||
|
|
||||||
|
void post(String url, NotificationMessage message);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.slotline.notification;
|
||||||
|
|
||||||
|
import com.slotline.config.SlotlineProperties;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ConditionalOnProperty(prefix = "slotline.notifications.webhook", name = "url")
|
||||||
|
public class WebhookNotificationChannel implements NotificationChannel {
|
||||||
|
|
||||||
|
private final WebhookGateway gateway;
|
||||||
|
private final String url;
|
||||||
|
|
||||||
|
public WebhookNotificationChannel(WebhookGateway gateway, SlotlineProperties properties) {
|
||||||
|
this.gateway = gateway;
|
||||||
|
this.url = properties.getNotifications().getWebhook().getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "webhook";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deliver(NotificationMessage message) {
|
||||||
|
gateway.post(url, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user