diff --git a/ticketing-eventing/README.md b/ticketing-eventing/README.md
index 149c45bb..9ce35b48 100644
--- a/ticketing-eventing/README.md
+++ b/ticketing-eventing/README.md
@@ -24,7 +24,7 @@ Open **Event-Service** via Swagger (http://localhost:8080/swagger-ui/index.html)
- User: zammad
- Password: password
- Method: POST `/api/event`
-- X-Zammad-Trigger: `Trigger Name`
+- X-Zammad-Trigger: `T2805_Event_Nachricht_In_Postkorb`
- X-Zammad-Delivery: `myID`
- Request Body:
```json
@@ -33,7 +33,7 @@ Open **Event-Service** via Swagger (http://localhost:8080/swagger-ui/index.html)
"status": "closed",
"status_id": "1",
"anliegenart": "technischer Bürgersupport",
- "lhmExtId": "33caabe6-317c-4c2d-8bf7-6c36230599db"
+ "lhmextid": "33caabe6-317c-4c2d-8bf7-6c36230599db"
}
```
diff --git a/ticketing-eventing/eventing-service/src/main/resources/application-local.yml b/ticketing-eventing/eventing-service/src/main/resources/application-local.yml
index 046f0de8..8be36479 100644
--- a/ticketing-eventing/eventing-service/src/main/resources/application-local.yml
+++ b/ticketing-eventing/eventing-service/src/main/resources/application-local.yml
@@ -37,5 +37,7 @@ logging:
dbs:
eventing:
trigger-mapping:
- - trigger-name: "Trigger Name"
+ - trigger-name: "T2800_Event_Statusaenderung"
action: "state_changed"
+ - trigger-name: "T2805_Event_Nachricht_In_Postkorb"
+ action: "send_to_postbox"
diff --git a/ticketing-eventing/mail-handler-service/pom.xml b/ticketing-eventing/mail-handler-service/pom.xml
index b16871a0..59e4ac58 100644
--- a/ticketing-eventing/mail-handler-service/pom.xml
+++ b/ticketing-eventing/mail-handler-service/pom.xml
@@ -43,7 +43,7 @@
2025.0.0
- 0.1.0
+ 0.2.0
8.1
diff --git a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/adapter/out/mail/MailAdapter.java b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/adapter/out/mail/MailAdapter.java
index 2062213a..ff7d4c5e 100644
--- a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/adapter/out/mail/MailAdapter.java
+++ b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/adapter/out/mail/MailAdapter.java
@@ -1,31 +1,59 @@
package de.muenchen.oss.dbs.ticketing.eventing.mailhandler.adapter.out.mail;
import de.muenchen.oss.dbs.ticketing.eventing.mailhandler.application.port.out.SendMailOutPort;
+import jakarta.activation.DataSource;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
+import jakarta.mail.util.ByteArrayDataSource;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
+@Slf4j
public class MailAdapter implements SendMailOutPort {
private final JavaMailSender mailSender;
private final MailProperties mailProperties;
@Override
- public void sendMail(final String recipient, final String subject, final String body) {
+ public void sendMail(final MailMessage mailMessage) {
final MimeMessage mimeMessage = mailSender.createMimeMessage();
- final MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, "utf-8");
try {
+ final MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "utf-8");
helper.setFrom(mailProperties.getFromAddress());
- helper.setTo(recipient);
- helper.setSubject(subject);
- helper.setText(body, true);
+ helper.setTo(mailMessage.getRecipient());
+ helper.setSubject(mailMessage.getSubject());
+ helper.setText(mailMessage.getBody(), true);
+ for (final Map.Entry entry : mailMessage.getAttachments().entrySet()) {
+ //TODO is there a way to do this with streaming? The following line loads the attachment into RAM...
+ final DataSource dataSource = new ByteArrayDataSource(entry.getValue(), "application/octet-stream");
+ helper.addAttachment(entry.getKey(), dataSource);
+ //maybe like this?
+ //helper.addAttachment(e.getKey(), new InputStreamSourceImpl(e.getValue()));
+ }
mailSender.send(mimeMessage);
- } catch (MessagingException e) {
+ } catch (final MessagingException | IOException e) {
throw new RuntimeException(e);
}
}
+
+ // private class InputStreamSourceImpl implements InputStreamSource {
+ // private final InputStream inputStream;
+ //
+ // public InputStreamSourceImpl(InputStream inputStream) {
+ // this.inputStream = inputStream;
+ // }
+ //
+ // @Override
+ // public InputStream getInputStream() {
+ // return inputStream;
+ // }
+ // }
+
}
diff --git a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/adapter/out/mail/MailMessage.java b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/adapter/out/mail/MailMessage.java
new file mode 100644
index 00000000..9703ddb9
--- /dev/null
+++ b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/adapter/out/mail/MailMessage.java
@@ -0,0 +1,15 @@
+package de.muenchen.oss.dbs.ticketing.eventing.mailhandler.adapter.out.mail;
+
+import java.io.InputStream;
+import java.util.Map;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class MailMessage {
+ private String recipient;
+ private String subject;
+ private String body;
+ private Map attachments;
+}
diff --git a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/application/port/out/SendMailOutPort.java b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/application/port/out/SendMailOutPort.java
index 9ef8a4d5..65b60f1d 100644
--- a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/application/port/out/SendMailOutPort.java
+++ b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/application/port/out/SendMailOutPort.java
@@ -1,5 +1,7 @@
package de.muenchen.oss.dbs.ticketing.eventing.mailhandler.application.port.out;
+import de.muenchen.oss.dbs.ticketing.eventing.mailhandler.adapter.out.mail.MailMessage;
+
public interface SendMailOutPort {
- void sendMail(String recipient, String subject, String body);
+ void sendMail(MailMessage mailMessage);
}
diff --git a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/application/usecase/EventHandlingUseCase.java b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/application/usecase/EventHandlingUseCase.java
index 8ce294f3..495dbcc3 100644
--- a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/application/usecase/EventHandlingUseCase.java
+++ b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/application/usecase/EventHandlingUseCase.java
@@ -1,15 +1,20 @@
package de.muenchen.oss.dbs.ticketing.eventing.mailhandler.application.usecase;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import de.muenchen.oss.dbs.ticketing.eai.client.model.ArticleAttachment;
import de.muenchen.oss.dbs.ticketing.eai.client.model.ArticleInternal;
import de.muenchen.oss.dbs.ticketing.eai.client.model.TicketInternal;
+import de.muenchen.oss.dbs.ticketing.eai.client.model.UpdateTicketDTO;
import de.muenchen.oss.dbs.ticketing.eventing.handlercore.application.port.in.EventHandlerInPort;
import de.muenchen.oss.dbs.ticketing.eventing.handlercore.application.port.out.TicketingOutPort;
import de.muenchen.oss.dbs.ticketing.eventing.handlercore.domain.model.Event;
+import de.muenchen.oss.dbs.ticketing.eventing.mailhandler.adapter.out.mail.MailMessage;
import de.muenchen.oss.dbs.ticketing.eventing.mailhandler.application.port.out.SendMailOutPort;
import de.muenchen.oss.dbs.ticketing.eventing.mailhandler.config.MailHandlerProperties;
+import de.muenchen.oss.dbs.ticketing.eventing.mailhandler.exceptions.NoValidArticleException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
@@ -22,6 +27,12 @@
public class EventHandlingUseCase implements EventHandlerInPort {
private static final String INTERNAL_ATTACHMENTS_ARTICLE_TITLE = "Interner Artikel für interne Anhänge.";
private static final String FORM_ATTACHMENT_NAME = "XML-Daten.xml";
+ public static final String TICKETING_VERTRAUENSNIVEAU = "ticketingVertrauensniveau";
+ public static final String LEGACY_POSTKORB_HANDLE = "legacyPostkorbHandle";
+ public static final String ACCOUNT_SOURCE = "accountSource";
+
+ public static final String TO_POSTBOX_DEFAULT = "send";
+ public static final String TO_POSTBOX_HIGH = "send_high_authLevel";
private final XmlMapper xmlMapper = new XmlMapper();
private final MailHandlerProperties mailHandlerProperties;
@@ -36,52 +47,94 @@ public void handleEvent(final Event event) {
return;
}
log.info("Handling event");
- // find event ticket
- final TicketInternal ticket = ticketingOutPort.getTicket(event.ticket());
- // get parsed form
- final Map form = getParsedForm(ticket);
- // send mail
- final String subject = buildSubject(ticket, form);
- final String body = buildBody(ticket);
- sendMailOutport.sendMail(
- mailHandlerProperties.getRecipient(), subject, body);
- log.info("Handled event successfully");
+ try {
+ // find event ticket
+ final TicketInternal ticket = ticketingOutPort.getTicket(event.ticket());
+ //check if ticket should be sent
+ if (!isRelevantTicket(ticket)) {
+ log.debug("Ticket not relevant");
+ return;
+ }
+ // get parsed form
+ final Map form = getParsedForm(ticket);
+ //find relevant article
+ final ArticleInternal article = findRelevantArticle(ticket);
+ sendMail(ticket, form, article);
+
+ //reset flag sende_nachricht_nach_extern
+ resetTicket(ticket);
+
+ log.info("Event handled successfully");
+ } catch (NoValidArticleException e) {
+ log.error(e.getMessage());
+ log.error("Event NOT handled successfully");
+ }
}
private boolean isRelevantEvent(final Event event) {
log.debug("checking event: " + event);
return
- // state was changed
- mailHandlerProperties.getStateChangeAction().equals(event.action()) &&
- // new state is closed
- mailHandlerProperties.getClosedState().equals(event.status()) &&
- // is relevant anliegen
+ // state was changed by trigger send-to-postbox
+ mailHandlerProperties.getTicketChangeAction().equals(event.action()) &&
+ // is relevant anliegen
mailHandlerProperties.getRelevantTicketTypes().contains(event.anliegenart()) &&
// user does have an lhmExtId (i.e. BayernID or BundID user)
event.lhmExtId() != null && !event.lhmExtId().isEmpty();
}
- private String buildSubject(final TicketInternal ticket, final Map form) {
- return "[%s;%s;%s;%s] Ihr Anliegen '%s' wurde abschließend bearbeitet"
- .formatted(
- form.get("legacyPostkorbHandle"),
- form.get("accountSource"),
- form.get("ticketingVertrauensniveau"),
- "Dummy",
- ticket.getTitle());
+ private boolean isRelevantTicket(final TicketInternal ticket) {
+ log.debug("Checking value of sende_nachricht_nach_extern: " + ticket.getSendeNachrichtNachExtern());
+ return TO_POSTBOX_DEFAULT.equals(ticket.getSendeNachrichtNachExtern()) || TO_POSTBOX_HIGH.equals(ticket.getSendeNachrichtNachExtern());
}
- private String buildBody(final TicketInternal ticket) {
+ private ArticleInternal findRelevantArticle(final TicketInternal ticket) throws NoValidArticleException {
assert ticket.getArticles() != null;
return ticket.getArticles().stream()
- // only public articles of type "web" or "note"
+ // find last public articles of type "note"
.filter(i -> Boolean.FALSE.equals(i.getInternal()) &&
- (ArticleInternal.TypeEnum.WEB.equals(i.getType()) || ArticleInternal.TypeEnum.NOTE.equals(i.getType())))
- // format single article
- .map(i -> "Titel: %s
Body: %s".formatted(i.getSubject(), i.getBody()))
- // build body
- .collect(Collectors.joining("
"));
+ ArticleInternal.TypeEnum.NOTE.equals(i.getType()))
+ .reduce((first, second) -> second)
+ .orElseThrow(() -> new NoValidArticleException("no valid article found in ticket " + ticket.getId()));
+ }
+
+ private void sendMail(final TicketInternal ticket, final Map form, final ArticleInternal article) {
+ final String recipient = mailHandlerProperties.getRecipient();
+ final String subject = buildSubject(ticket, form);
+ log.debug("Created subject: " + subject);
+ final String body = buildBody(article);
+ log.debug("Created body: " + body);
+ final Map attachments = buildAttachments(article);
+ sendMailOutport.sendMail(new MailMessage(recipient, subject, body, attachments));
+ }
+ private String buildSubject(final TicketInternal ticket, final Map form) {
+ final String authlevel;
+ if (form.get(TICKETING_VERTRAUENSNIVEAU) == null) {
+ log.error("no ticketingVertrauensniveau found in ticket " + ticket.getId() + " - setting level1");
+ authlevel = "level1";
+ } else {
+ authlevel = TO_POSTBOX_HIGH.equals(ticket.getSendeNachrichtNachExtern()) ? "level3" : String.valueOf(form.get(TICKETING_VERTRAUENSNIVEAU));
+ }
+
+ return "[%s;%s;%s;%s] Neue Nachricht zu Ihrem Anliegen '%s'"
+ .formatted(
+ form.get(LEGACY_POSTKORB_HANDLE),
+ form.get(ACCOUNT_SOURCE),
+ authlevel,
+ "Zammad-Eventing",
+ ticket.getTitle());
+ }
+
+ private String buildBody(final ArticleInternal article) {
+ return article.getBody();
+ }
+
+ private Map buildAttachments(final ArticleInternal article) {
+ if (article.getAttachments() == null) {
+ return new HashMap<>();
+ }
+ return article.getAttachments().stream().collect(Collectors.toMap(ArticleAttachment::getFilename,
+ a -> ticketingOutPort.getAttachmentContent(article.getTicketId(), article.getId(), a.getId())));
}
private Map getParsedForm(final TicketInternal ticket) {
@@ -109,4 +162,12 @@ private Map getParsedForm(final TicketInternal ticket) {
throw new RuntimeException(e);
}
}
+
+ private void resetTicket(final TicketInternal ticket) {
+ final UpdateTicketDTO updateTicketDTO = new UpdateTicketDTO();
+ updateTicketDTO.setId(ticket.getId());
+ updateTicketDTO.setDirektkennwort(ticket.getDirektkennwort());
+ updateTicketDTO.setSendeNachrichtNachExtern(null);
+ ticketingOutPort.updateTicket(updateTicketDTO);
+ }
}
diff --git a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/config/MailHandlerProperties.java b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/config/MailHandlerProperties.java
index db90aed9..f581bf32 100644
--- a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/config/MailHandlerProperties.java
+++ b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/config/MailHandlerProperties.java
@@ -18,9 +18,7 @@ public class MailHandlerProperties {
@NotBlank
private String recipient;
@NotBlank
- private String stateChangeAction;
- @NotBlank
- private String closedState;
+ private String ticketChangeAction;
@NotNull
private List relevantTicketTypes;
}
diff --git a/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/exceptions/NoValidArticleException.java b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/exceptions/NoValidArticleException.java
new file mode 100644
index 00000000..405dea25
--- /dev/null
+++ b/ticketing-eventing/mail-handler-service/src/main/java/de/muenchen/oss/dbs/ticketing/eventing/mailhandler/exceptions/NoValidArticleException.java
@@ -0,0 +1,13 @@
+package de.muenchen.oss.dbs.ticketing.eventing.mailhandler.exceptions;
+
+import java.io.Serial;
+
+public class NoValidArticleException extends Exception {
+ // Default access modifier is private
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ public NoValidArticleException(final String s) {
+ super(s);
+ }
+}
diff --git a/ticketing-eventing/mail-handler-service/src/main/resources/application-local.yml b/ticketing-eventing/mail-handler-service/src/main/resources/application-local.yml
index 22cc2f0a..57a5df93 100644
--- a/ticketing-eventing/mail-handler-service/src/main/resources/application-local.yml
+++ b/ticketing-eventing/mail-handler-service/src/main/resources/application-local.yml
@@ -23,13 +23,13 @@ spring:
client:
provider:
zammad:
- issuer-uri: TODO
+ issuer-uri: https://ssodev.muenchen.de/auth/realms/KM81
registration:
zammad:
provider: zammad
authorization-grant-type: client_credentials
- client-id: TODO
- client-secret: TODO
+ client-id: mpdz-ticketing-fk
+ client-secret: V8zmjkcqgXE9xIWhljjVT45Bxli2c02B
dbs:
eai:
diff --git a/ticketing-eventing/mail-handler-service/src/main/resources/application.yml b/ticketing-eventing/mail-handler-service/src/main/resources/application.yml
index 85fd19d4..957eac92 100644
--- a/ticketing-eventing/mail-handler-service/src/main/resources/application.yml
+++ b/ticketing-eventing/mail-handler-service/src/main/resources/application.yml
@@ -22,14 +22,15 @@ spring:
json:
trusted:
packages: '*'
+ codec:
+ max-in-memory-size: 5MB
dbs:
eventing:
mail:
smtp:
from-address: ${spring.mail.username}
- state-change-action: "state_changed"
- closed-state: "closed"
+ ticket-change-action: "send_to_postbox"
server:
shutdown: "graceful"