Skip to content

Commit

Permalink
feature(#528): usertask notifications (#539)
Browse files Browse the repository at this point in the history
closes #528 

**Changes**

- create usertask notification api
  • Loading branch information
lmoesle authored Feb 14, 2025
1 parent aecc131 commit 3707515
Show file tree
Hide file tree
Showing 40 changed files with 587 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .run/MiranumPlatformSDU.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" IS_EXECUTABLE="false" />
<ENTRY IS_ENABLED="true" PARSER="env" IS_EXECUTABLE="false" PATH="examples/single-deployment-unit-example/single-deployment-stack/.env" />
<ENTRY IS_ENABLED="true" PARSER="env" IS_EXECUTABLE="false" PATH="examples/stack/.env" />
</ENTRIES>
</extension>
<method v="2">
Expand Down
9 changes: 9 additions & 0 deletions examples/single-deployment-unit-example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

<!-- Camunda -->
<dependency>
Expand Down Expand Up @@ -75,6 +79,11 @@
<artifactId>miranum-engine-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.miragon.miranum</groupId>
<artifactId>miranum-engine-user</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.miragon.miranum</groupId>
<artifactId>miranum-deployment-server-embedded-starter</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.miragon.miranum.platform.example.adapter.in.miranum;

import io.miragon.miranum.platform.example.application.domain.Notification;
import io.miragon.miranum.platform.example.application.port.in.NotificationInPort;
import io.miragon.miranum.platform.tasklist.application.port.out.task.TaskNotificationOutPort;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.delegate.DelegateTask;
import org.springframework.stereotype.Component;

import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class UsertaskNotificationAdapter implements TaskNotificationOutPort {

private final NotificationInPort notificationInPort;

@Override
public void notifyAssignee(final String assignee, final String eventName, final DelegateTask task) {
// example implementation
notificationInPort.notifyUsers(List.of(assignee), Notification.builder()
.eventName(eventName)
.taskName(task.getName())
.build());
}

@Override
public void notifyCandidateUsers(final List<String> candidateUsers, final String eventName, final DelegateTask task) {
// example implementation
notificationInPort.notifyUsers(candidateUsers, Notification.builder()
.eventName(eventName)
.taskName(task.getName())
.build());
}

@Override
public void notifyCandidateGroups(final List<String> candidateGroups, final String eventName, final DelegateTask task) {
// example implementation
notificationInPort.notifyGroup(candidateGroups, Notification.builder()
.eventName(eventName)
.taskName(task.getName())
.build());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.miragon.miranum.platform.example.adapter.out.email;

import io.miragon.miranum.platform.example.application.domain.SendNotification;
import io.miragon.miranum.platform.example.application.port.out.SendNotificationOutPort;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Component;

import java.util.Properties;

@Slf4j
@Component
public class EmailAdapter implements SendNotificationOutPort {

private final JavaMailSender mailSender;

public EmailAdapter() throws jakarta.mail.MessagingException {
final JavaMailSenderImpl mailSender = new JavaMailSenderImpl();

final int timeout = 30000; // 30 seconds
Properties properties = mailSender.getJavaMailProperties();
properties.put("mail.smtp.connectiontimeout", timeout);
properties.put("mail.smtp.timeout", timeout);
properties.put("mail.smtp.writetimeout", timeout);

mailSender.testConnection();

this.mailSender = mailSender;
}


@Override
public void notify(final SendNotification sendNotification) {
try {
final MimeMessage mimeMessage = this.mailSender.createMimeMessage();

mimeMessage.setFrom(new InternetAddress("[email protected]"));
mimeMessage.setRecipients(Message.RecipientType.TO, InternetAddress.parse(String.join(",", sendNotification.receivers())));
mimeMessage.setSubject(sendNotification.subject());
mimeMessage.setText(sendNotification.body());

this.mailSender.send(mimeMessage);
} catch (final MessagingException e) {
log.error("Error sending email", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.miragon.miranum.platform.example.application;

import io.miragon.miranum.platform.example.application.domain.Notification;
import io.miragon.miranum.platform.example.application.domain.SendNotification;
import io.miragon.miranum.platform.example.application.port.in.NotificationInPort;
import io.miragon.miranum.platform.example.application.port.out.SendNotificationOutPort;
import io.miragon.miranum.platform.user.application.port.in.UserApi;
import io.miragon.miranum.platform.user.domain.User;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
@RequiredArgsConstructor
public class UsertaskNotificationUseCase implements NotificationInPort {

private final SendNotificationOutPort sendNotificationOutPort;
private final UserApi userApi;

@Override
public void notifyUsers(final List<String> users, final Notification notification) {
// don't send notification for create and complete events
if(notification.getEventName().equalsIgnoreCase("create") || notification.getEventName().equalsIgnoreCase("complete")) {
return;
}

final List<User> receivers = new ArrayList<>();
users.forEach(user -> receivers.add(userApi.getUserByUserName(user)));

sendNotificationOutPort.notify(SendNotification.builder()
.receivers(receivers.stream().map(User::getEmail).toList())
.subject(notification.getTitle())
.body(notification.getMessage())
.build());
}

@Override
public void notifyGroup(final List<String> groups, final Notification notification) {
// don't send notification for assignment events
if (notification.getEventName().equalsIgnoreCase("assignment")) {
return;
}

final List<User> receivers = new ArrayList<>();
groups.forEach(group -> receivers.addAll(userApi.getUsersByGroup(group)));

sendNotificationOutPort.notify(SendNotification.builder()
.receivers(receivers.stream().map(User::getEmail).toList())
.subject(notification.getTitle())
.body(notification.getMessage())
.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.miragon.miranum.platform.example.application.domain;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class Notification {

private String eventName;
private String taskName;

public String getTitle() {
return eventName.equalsIgnoreCase("create") || eventName.equalsIgnoreCase("assignment") ?
String.format("Task %s was assigned to you", taskName) :
String.format("Task %s was completed", taskName);
}

public String getMessage() {
return eventName.equalsIgnoreCase("create") || eventName.equalsIgnoreCase("assignment") ?
"You have a new Task":
"Task was completed";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.miragon.miranum.platform.example.application.domain;

import lombok.Builder;

import java.util.List;

@Builder
public record SendNotification(
List<String> receivers,
String subject,
String body
) { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.miragon.miranum.platform.example.application.port.in;

import io.miragon.miranum.platform.example.application.domain.Notification;

import java.util.List;

public interface NotificationInPort {

void notifyUsers(final List<String> users, final Notification notification);

void notifyGroup(final List<String> groups, final Notification notification);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.miragon.miranum.platform.example.application.port.out;

import io.miragon.miranum.platform.example.application.domain.SendNotification;

public interface SendNotificationOutPort {

void notify(final SendNotification sendNotification);

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package io.miragon.miranum.platform.example.shared.security;

import io.miragon.miranum.platform.example.engine.sso.GrantedAuthoritiesExtractor;
import io.miragon.miranum.platform.example.engine.sso.TokenParsingOAuth2UserService;
import io.miragon.miranum.platform.example.engine.sso.TokenParsingOidcUserService;
import io.miragon.miranum.platform.example.engine.sso.rest.RestExceptionHandler;
import io.miragon.miranum.platform.example.engine.sso.webapp.OAuthContainerBasedAuthenticationProvider;
import io.miragon.miranum.platform.example.engine.sso.webapp.OAuthLogoutHandler;
import io.miragon.miranum.platform.example.shared.sso.GrantedAuthoritiesExtractor;
import io.miragon.miranum.platform.example.shared.sso.TokenParsingOAuth2UserService;
import io.miragon.miranum.platform.example.shared.sso.TokenParsingOidcUserService;
import io.miragon.miranum.platform.example.shared.sso.rest.RestExceptionHandler;
import io.miragon.miranum.platform.example.shared.sso.webapp.OAuthContainerBasedAuthenticationProvider;
import io.miragon.miranum.platform.example.shared.sso.webapp.OAuthLogoutHandler;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.DispatcherType;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@


package io.miragon.miranum.platform.example.engine.sso;
package io.miragon.miranum.platform.example.shared.sso;

import io.miragon.miranum.platform.example.engine.sso.rest.ServiceAccountAuthenticationProvider;
import io.miragon.miranum.platform.example.shared.sso.rest.ServiceAccountAuthenticationProvider;
import org.camunda.bpm.engine.IdentityService;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.miragon.miranum.platform.example.engine.sso;
package io.miragon.miranum.platform.example.shared.sso;

import io.miragon.miranum.platform.example.engine.sso.rest.ServiceAccountAuthenticationProvider;
import io.miragon.miranum.platform.example.shared.sso.rest.ServiceAccountAuthenticationProvider;
import jakarta.servlet.*;
import org.camunda.bpm.engine.IdentityService;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.miragon.miranum.platform.example.engine.sso;
package io.miragon.miranum.platform.example.shared.sso;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -11,7 +11,6 @@
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.security.Principal;
import java.util.*;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.miragon.miranum.platform.example.engine.sso;
package io.miragon.miranum.platform.example.shared.sso;

import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.miragon.miranum.platform.example.engine.sso;
package io.miragon.miranum.platform.example.shared.sso;

import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.miragon.miranum.platform.example.engine.sso.init;
package io.miragon.miranum.platform.example.shared.sso.init;

import org.camunda.bpm.engine.AuthorizationService;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -46,5 +46,5 @@ public AuthenticationInitializer(
AuthorizationHelper.setupGroupDeploymentPermissions(authorizationService, workerRole);

}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.miragon.miranum.platform.example.engine.sso.init;
package io.miragon.miranum.platform.example.shared.sso.init;

import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.AuthorizationService;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.miragon.miranum.platform.example.engine.sso.rest;
package io.miragon.miranum.platform.example.shared.sso.rest;

import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


package io.miragon.miranum.platform.example.engine.sso.rest;
package io.miragon.miranum.platform.example.shared.sso.rest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AbstractAuthenticationToken;
Expand All @@ -10,9 +10,12 @@
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static io.miragon.miranum.platform.example.engine.sso.GrantedAuthoritiesExtractor.SPRING_ROLE_PREFIX;
import static io.miragon.miranum.platform.example.shared.sso.GrantedAuthoritiesExtractor.SPRING_ROLE_PREFIX;

/**
* User authentication provider.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.miragon.miranum.platform.example.engine.sso.webapp;
package io.miragon.miranum.platform.example.shared.sso.webapp;

import io.miragon.miranum.platform.example.engine.sso.GrantedAuthoritiesExtractor;
import io.miragon.miranum.platform.example.shared.sso.GrantedAuthoritiesExtractor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.camunda.bpm.engine.ProcessEngine;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.miragon.miranum.platform.example.engine.sso.webapp;
package io.miragon.miranum.platform.example.shared.sso.webapp;

import org.apache.commons.lang3.StringUtils;
import org.camunda.bpm.engine.identity.*;
Expand All @@ -21,7 +21,7 @@
import java.util.Map;
import java.util.Objects;

import static io.miragon.miranum.platform.example.engine.sso.GrantedAuthoritiesExtractor.SPRING_ROLE_PREFIX;
import static io.miragon.miranum.platform.example.shared.sso.GrantedAuthoritiesExtractor.SPRING_ROLE_PREFIX;
import static java.util.stream.Collectors.toList;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.miragon.miranum.platform.example.engine.sso.webapp;
package io.miragon.miranum.platform.example.shared.sso.webapp;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.miragon.miranum.platform.example.engine.sso.webapp;
package io.miragon.miranum.platform.example.shared.sso.webapp;

import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.persistence.GenericManagerFactory;
Expand Down
Loading

0 comments on commit 3707515

Please sign in to comment.