diff --git a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/ProjectEvent.java b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/ProjectEvent.java index 702ee70a..78534b3a 100644 --- a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/ProjectEvent.java +++ b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/ProjectEvent.java @@ -1,8 +1,6 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.messagebus.events; -import static de.srsoftware.umbrella.core.ModuleRegistry.projectService; -import static de.srsoftware.umbrella.core.ModuleRegistry.taskService; import static de.srsoftware.umbrella.core.constants.Field.*; import static de.srsoftware.umbrella.core.constants.Module.PROJECT; import static de.srsoftware.umbrella.core.model.Translatable.t; @@ -11,7 +9,6 @@ import static de.srsoftware.umbrella.messagebus.events.Event.EventType.MEMBER_AD import de.srsoftware.umbrella.core.constants.Field; import de.srsoftware.umbrella.core.model.*; import java.util.Collection; -import java.util.List; import java.util.Map; diff --git a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/TaskEvent.java b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/TaskEvent.java index 222c5bab..5b5e240d 100644 --- a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/TaskEvent.java +++ b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/TaskEvent.java @@ -9,7 +9,6 @@ import static de.srsoftware.umbrella.core.constants.Module.TASK; import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.messagebus.events.Event.EventType.MEMBER_ADDED; -import de.srsoftware.umbrella.core.ModuleRegistry; import de.srsoftware.umbrella.core.constants.Field; import de.srsoftware.umbrella.core.model.*; import java.util.Collection; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Envelope.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Envelope.java index ca537c72..14d96517 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Envelope.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Envelope.java @@ -17,16 +17,16 @@ import java.util.stream.Collectors; import org.json.JSONArray; import org.json.JSONObject; -public class Envelope { - private final Message message; +public class Envelope { + private final Message message; private final Set receivers; private final LocalDateTime time; - public Envelope(Message message, User receiver){ + public Envelope(Message message, User receiver){ this(message,new HashSet<>(Set.of(receiver))); } - public Envelope(Message message, HashSet receivers) { + public Envelope(Message message, HashSet receivers) { this.message = message; this.receivers = receivers; time = LocalDateTime.now(); @@ -40,7 +40,7 @@ public class Envelope { */ public static Envelope from(JSONObject json) throws UmbrellaException { if (!json.has(RECEIVERS)) throw missingField(RECEIVERS); - var message = Message.from(json); + var message = TranslatedMessage.from(json); var obj = json.get(RECEIVERS); if (obj instanceof JSONObject) obj = new JSONArray(List.of(obj)); if (!(obj instanceof JSONArray receiverList)) throw invalidField(RECEIVERS, t(JSONARRAY)); @@ -67,7 +67,7 @@ public class Envelope { return receivers.contains(receiver); } - public Message message(){ + public Message message(){ return message; } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Message.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Message.java index bd79cca2..f4e174cf 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Message.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Message.java @@ -1,50 +1,35 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.tools.Optionals.isSet; -import static de.srsoftware.umbrella.core.constants.Constants.JSONOBJECT; -import static de.srsoftware.umbrella.core.constants.Field.*; -import static de.srsoftware.umbrella.core.constants.Text.STRING; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; -import static de.srsoftware.umbrella.core.model.Translatable.t; import static java.text.MessageFormat.format; -import de.srsoftware.tools.Mappable; -import de.srsoftware.umbrella.core.exceptions.UmbrellaException; -import java.util.*; -import org.json.JSONArray; -import org.json.JSONObject; +import java.util.Collection; +import java.util.Objects; -public record Message(UmbrellaUser sender, Translatable subject, Translatable body, List attachments) { - @Override - public boolean equals(Object o) { - if (!(o instanceof Message message)) return false; - return Objects.equals(sender, message.sender) && Objects.equals(subject, message.subject) && Objects.equals(body, message.body) && Objects.equals(attachments, message.attachments); +public abstract class Message { + private final Collection attachments; + private final T body, subject; + private final UmbrellaUser sender; + + public Message(UmbrellaUser sender, T subject, T body, Collection attachments){ + this.sender = sender; + this.subject = subject; + this.body = body; + this.attachments = attachments; } - public static Message from(JSONObject json) throws UmbrellaException { - for (var key : Set.of(SENDER, SUBJECT, BODY)) { - if (!json.has(key)) throw missingField(key); - } - if (!(json.get(SENDER) instanceof JSONObject senderObject)) throw invalidField(SENDER, t(JSONOBJECT)); - if (!(json.get(SUBJECT) instanceof String subject && isSet(subject))) throw invalidField(SUBJECT,t(STRING)); - if (!(json.get(BODY) instanceof String body && isSet(body))) throw invalidField(BODY,t(STRING)); + public Collection attachments(){ + return attachments; + } - var user = UmbrellaUser.of(senderObject); - if (!(user instanceof UmbrellaUser sender)) throw new UmbrellaException(400, t("Sender is not an umbrella user!")); - var attachments = new ArrayList(); - if (json.has(ATTACHMENTS)){ - var jsonAttachments = json.get(ATTACHMENTS); - if (jsonAttachments instanceof JSONObject obj) jsonAttachments = new JSONArray(List.of(obj)); - if (jsonAttachments instanceof JSONArray arr){ - for (var att : arr){ - if (!(att instanceof JSONObject o)) throw new UmbrellaException(400, t("Attachments contains entry that is not an object: {entry}","entry",att)); - var attachment = Attachment.of(o); - attachments.add(attachment); - } - } - } - return new Message(sender,new UnTranslatable(subject),new UnTranslatable(body),attachments); + public T body(){ + return body; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Message message)) return false; + return Objects.equals(sender, message.sender) && Objects.equals(subject, message.subject) && Objects.equals(body, message.body) && Objects.equals(attachments, message.attachments); } @Override @@ -52,6 +37,14 @@ public record Message(UmbrellaUser sender, Translatable subject, Translatable bo return Objects.hash(subject, body, attachments); } + public UmbrellaUser sender(){ + return sender; + } + + public T subject(){ + return subject; + } + @Override public String toString() { return format("{0}(from: {1}), subject: {2}",getClass().getSimpleName(),sender,subject); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/TranslatableMessage.java b/core/src/main/java/de/srsoftware/umbrella/core/model/TranslatableMessage.java new file mode 100644 index 00000000..339222aa --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/TranslatableMessage.java @@ -0,0 +1,14 @@ +/* © SRSoftware 2025 */ +package de.srsoftware.umbrella.core.model; + +import java.util.Collection; + +public class TranslatableMessage extends Message { + public TranslatableMessage(UmbrellaUser sender, Translatable subject, Translatable body, Collection attachments) { + super(sender, subject, body, attachments); + } + + public TranslatedMessage translate(String lang){ + return new TranslatedMessage(sender(),subject().translate(lang),body().translate(lang),attachments()); + } +} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/TranslatedMessage.java b/core/src/main/java/de/srsoftware/umbrella/core/model/TranslatedMessage.java new file mode 100644 index 00000000..9ab6b0f5 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/TranslatedMessage.java @@ -0,0 +1,50 @@ +/* © SRSoftware 2025 */ +package de.srsoftware.umbrella.core.model; + +import static de.srsoftware.tools.Optionals.isSet; +import static de.srsoftware.umbrella.core.constants.Constants.JSONOBJECT; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.ATTACHMENTS; +import static de.srsoftware.umbrella.core.constants.Text.STRING; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidField; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingField; +import static de.srsoftware.umbrella.core.model.Translatable.t; + +import de.srsoftware.umbrella.core.exceptions.UmbrellaException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import org.json.JSONArray; +import org.json.JSONObject; + +public class TranslatedMessage extends Message { + public TranslatedMessage(UmbrellaUser sender, String subject, String body, Collection attachments) { + super(sender, subject, body, attachments); + } + + public static TranslatedMessage from(JSONObject json) throws UmbrellaException { + for (var key : Set.of(SENDER, SUBJECT, BODY)) { + if (!json.has(key)) throw missingField(key); + } + if (!(json.get(SENDER) instanceof JSONObject senderObject)) throw invalidField(SENDER, t(JSONOBJECT)); + if (!(json.get(SUBJECT) instanceof String subject && isSet(subject))) throw invalidField(SUBJECT,t(STRING)); + if (!(json.get(BODY) instanceof String body && isSet(body))) throw invalidField(BODY,t(STRING)); + + var user = UmbrellaUser.of(senderObject); + if (!(user instanceof UmbrellaUser sender)) throw new UmbrellaException(400, t("Sender is not an umbrella user!")); + var attachments = new ArrayList(); + if (json.has(ATTACHMENTS)){ + var jsonAttachments = json.get(ATTACHMENTS); + if (jsonAttachments instanceof JSONObject obj) jsonAttachments = new JSONArray(List.of(obj)); + if (jsonAttachments instanceof JSONArray arr){ + for (var att : arr){ + if (!(att instanceof JSONObject o)) throw new UmbrellaException(400, t("Attachments contains entry that is not an object: {entry}","entry",att)); + var attachment = Attachment.of(o); + attachments.add(attachment); + } + } + } + return new TranslatedMessage(sender,subject,body,attachments); + } +} diff --git a/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java b/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java index e6d9d5b1..fbc96689 100644 --- a/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java +++ b/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java @@ -577,7 +577,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { LOG.log(WARNING,e); } var attachment = new Attachment(doc.number()+".pdf",rendered.mimeType(),rendered.bytes()); - var message = new Message(user,new UnTranslatable(subject),new UnTranslatable(content),List.of(attachment)); + var message = new TranslatedMessage(user,subject,content,List.of(attachment)); var envelope = new Envelope(message,new User(doc.customer().shortName(),new EmailAddress(email),doc.customer().language())); postBox().send(envelope); db.save(doc.set(SENT)); diff --git a/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java b/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java index 32261f32..ca8bcaec 100644 --- a/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java +++ b/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java @@ -25,10 +25,7 @@ import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.ModuleRegistry; import de.srsoftware.umbrella.core.api.PostBox; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; -import de.srsoftware.umbrella.core.model.Envelope; -import de.srsoftware.umbrella.core.model.Token; -import de.srsoftware.umbrella.core.model.UmbrellaUser; -import de.srsoftware.umbrella.core.model.User; +import de.srsoftware.umbrella.core.model.*; import de.srsoftware.umbrella.message.model.*; import de.srsoftware.umbrella.messagebus.EventListener; import de.srsoftware.umbrella.messagebus.events.Event; @@ -44,7 +41,6 @@ import jakarta.mail.util.ByteArrayDataSource; import java.io.IOException; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; - import org.json.JSONArray; import org.json.JSONObject; @@ -52,7 +48,7 @@ public class MessageSystem extends BaseHandler implements PostBox, EventListener public static final System.Logger LOG = System.getLogger(MessageSystem.class.getSimpleName()); private final Timer timer = new Timer(); - private record Receiver(User user, de.srsoftware.umbrella.core.model.Message message){} + private record Receiver(User user, Message message){} private class SubmissionTask extends TimerTask{ @@ -176,7 +172,7 @@ public class MessageSystem extends BaseHandler implements PostBox, EventListener public void onEvent(Event event) { for (var user : event.audience()){ if (debugAddress != null && !debugAddress.equals(user.email().toString())) continue; - var message = new de.srsoftware.umbrella.core.model.Message(event.initiator(),event.subject(),event.describe(),null); + var message = new TranslatableMessage(event.initiator(),event.subject(),event.describe(),null); var envelope = new Envelope(message,user); send(envelope); } @@ -251,23 +247,24 @@ public class MessageSystem extends BaseHandler implements PostBox, EventListener if (scheduledHour != null) new SubmissionTask(scheduledHour).schedule(); } - private boolean sendMessage(HttpExchange ex, UmbrellaUser user, Envelope envelope) throws IOException { + private boolean sendMessage(HttpExchange ex, UmbrellaUser user, Envelope envelope) throws IOException { var message = envelope.message(); - var sender = message.sender().name(); - var subject = message.subject().translate(user.language()); - var body = message.body().translate(user.language()); + if (message instanceof TranslatableMessage tm) message = tm.translate(user.language()); return sendContent(ex,Map.of( - SENDER,sender, - SUBJECT,subject, - BODY,body + SENDER,message.sender(), + SUBJECT,message.subject(), + BODY,message.body() )); } - private static JSONObject summary(Envelope envelope, String lang) { - var sender = envelope.message().sender().name(); - var subject = envelope.message().subject().translate(lang); + private static JSONObject summary(Envelope envelope, String lang) { + var message = envelope.message(); + if (message instanceof TranslatableMessage tm) message = tm.translate(lang); + + var sender = message.sender().name(); + var subject = message.subject(); var time = envelope.time().format(TIME_FORMATTER); - var hash = envelope.hashCode(); + var hash = envelope.hashCode(); return new JSONObject(Map.of(SENDER,sender,SUBJECT,subject,TIMESTAMP,time,HASH,hash)); } diff --git a/messages/src/main/java/de/srsoftware/umbrella/message/model/CombinedMessage.java b/messages/src/main/java/de/srsoftware/umbrella/message/model/CombinedMessage.java index 14223f98..ef2e924c 100644 --- a/messages/src/main/java/de/srsoftware/umbrella/message/model/CombinedMessage.java +++ b/messages/src/main/java/de/srsoftware/umbrella/message/model/CombinedMessage.java @@ -15,7 +15,7 @@ public class CombinedMessage { private final StringBuilder combinedBody = new StringBuilder(); private final User receiver; private String combinedSubject = null; - private final List mergedMessages = new ArrayList<>(); + private final List> mergedMessages = new ArrayList<>(); private final Translatable subjectForCombinedMessage; private UmbrellaUser sender = null; @@ -25,11 +25,12 @@ public class CombinedMessage { this.receiver = receiver; } - public void merge(Message message) { + public void merge(Message message) { LOG.log(TRACE,"Merging {0} into combined message…",message); var lang = receiver.language(); - var body = message.body().translate(lang); - var subject = message.subject().translate(lang); + if (message instanceof TranslatableMessage tm) message = tm.translate(lang); + var body = message.body(); + var subject = message.subject().toString(); switch (mergedMessages.size()){ case 0: combinedBody.append(body); @@ -57,7 +58,7 @@ public class CombinedMessage { return combinedBody.toString(); } - public List messages() { + public List> messages() { return mergedMessages; } diff --git a/translations/src/main/java/de/srsoftware/umbrella/translations/Translations.java b/translations/src/main/java/de/srsoftware/umbrella/translations/Translations.java index 9ad5975c..893af362 100644 --- a/translations/src/main/java/de/srsoftware/umbrella/translations/Translations.java +++ b/translations/src/main/java/de/srsoftware/umbrella/translations/Translations.java @@ -18,7 +18,6 @@ import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Optional; - import org.json.JSONObject; public class Translations extends PathHandler implements Translator { diff --git a/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java b/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java index 6f0af6b7..4fb900f4 100644 --- a/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java +++ b/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java @@ -506,8 +506,8 @@ public class UserModule extends BaseHandler implements UserService { var url = url(ex).replace("/api/user/reset_pw","/user/reset/pw")+"?token="+token; var subject = t("Your token to create a new password"); var content = t("To receive a new password, open the following link: {url}",URL,url); - var message = new Message(user,subject,content,null); - var envelope = new Envelope(message,user); + var message = new TranslatableMessage(user,subject,content,null); + var envelope = new Envelope<>(message,user); postBox().send(envelope); } catch (UmbrellaException e){ return send(ex,e);