diff --git a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/WikiEvent.java b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/WikiEvent.java index 984958d5..9747f11f 100644 --- a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/WikiEvent.java +++ b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/WikiEvent.java @@ -7,7 +7,6 @@ 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.constants.Field; -import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; import java.util.Collection; import java.util.Map; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/Util.java b/core/src/main/java/de/srsoftware/umbrella/core/Util.java index a6c03005..cfb4265f 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/Util.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/Util.java @@ -7,6 +7,7 @@ import static de.srsoftware.tools.PathHandler.GET; import static de.srsoftware.tools.PathHandler.POST; import static de.srsoftware.tools.Strings.hex; import static de.srsoftware.umbrella.core.Errors.INVALID_URL; +import static de.srsoftware.umbrella.core.constants.Constants.TIME_FORMATTER; import static de.srsoftware.umbrella.core.constants.Field.*; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.serverError; import static java.lang.System.Logger.Level.*; @@ -200,7 +201,7 @@ public class Util { plantumlJar = file; } - public static LocalDateTime dateTimeOf(long epocSecs){ - return LocalDateTime.ofInstant(Instant.ofEpochSecond(epocSecs), ZoneId.systemDefault()); + public static String dateTimeOf(long epochMilis){ + return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMilis), ZoneId.systemDefault()).format(TIME_FORMATTER); } } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/constants/Constants.java b/core/src/main/java/de/srsoftware/umbrella/core/constants/Constants.java index 6749edea..97f903a5 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/constants/Constants.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Constants.java @@ -21,7 +21,7 @@ public class Constants { public static final String NO_CACHE = "no-cache"; public static final String NONE = "none"; public static final String TABLE_SETTINGS = "settings"; - public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"); + public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public static final String UMBRELLA = "Umbrella"; public static final String UTF8 = UTF_8.displayName(); 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 0e14c5c0..35d8c279 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 @@ -10,7 +10,6 @@ import static de.srsoftware.umbrella.core.model.Translatable.t; import static java.text.MessageFormat.format; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; -import java.time.LocalDateTime; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -22,7 +21,6 @@ import org.json.JSONObject; public class Envelope> { private final T message; private final Set receivers; - private LocalDateTime time; private final long id; public Envelope(long id, T message, User receiver){ @@ -32,7 +30,6 @@ public class Envelope> { public Envelope(long id, T message, Collection receivers) { this.message = message; this.receivers = new HashSet<>(receivers); - time = LocalDateTime.now(); this.id = id; } @@ -60,12 +57,12 @@ public class Envelope> { @Override public final boolean equals(Object o) { if (!(o instanceof Envelope envelope)) return false; - return message.equals(envelope.message) && time.equals(envelope.time); + return message.equals(envelope.message) && id == envelope.id; } @Override public int hashCode() { - return 31 * message.hashCode() + time.hashCode(); + return message.hashCode(); } public long id(){ @@ -84,15 +81,6 @@ public class Envelope> { return receivers; } - public Envelope time(LocalDateTime timestamp){ - this.time = timestamp; - return this; - } - - public LocalDateTime time(){ - return time; - } - @Override public String toString() { return format("{0} (to: {1}), subject: {2}",getClass().getSimpleName(),receivers.stream().map(User::email).map(EmailAddress::toString).collect(Collectors.joining(", ")),message.subject()); 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 f4e174cf..f07b5aba 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 @@ -10,12 +10,14 @@ public abstract class Message { private final Collection attachments; private final T body, subject; private final UmbrellaUser sender; + private long utcTime; public Message(UmbrellaUser sender, T subject, T body, Collection attachments){ this.sender = sender; this.subject = subject; this.body = body; this.attachments = attachments; + this.utcTime = System.currentTimeMillis(); } public Collection attachments(){ @@ -49,4 +51,13 @@ public abstract class Message { public String toString() { return format("{0}(from: {1}), subject: {2}",getClass().getSimpleName(),sender,subject); } + + public long utcTime() { + return utcTime; + } + + public Message utcTime(long newValue){ + utcTime = newValue; + return this; + } } 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 index 339222aa..bce46c3d 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/TranslatableMessage.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/TranslatableMessage.java @@ -9,6 +9,8 @@ public class TranslatableMessage extends Message { } public TranslatedMessage translate(String lang){ - return new TranslatedMessage(sender(),subject().translate(lang),body().translate(lang),attachments()); + var translated = new TranslatedMessage(sender(),subject().translate(lang),body().translate(lang),attachments()); + translated.utcTime(this.utcTime()); + return translated; } } 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 4277742a..febe3e6d 100644 --- a/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java +++ b/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java @@ -39,6 +39,8 @@ import jakarta.mail.internet.MimeMessage; import jakarta.mail.internet.MimeMultipart; import jakarta.mail.util.ByteArrayDataSource; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneId; import java.util.*; import org.json.JSONArray; import org.json.JSONObject; @@ -189,12 +191,12 @@ public class MessageSystem extends BaseHandler implements PostBox, EventListener private boolean markRead(HttpExchange ex, UmbrellaUser user, String path) { try { - var hash = Integer.parseInt(path); - var envelope = queue.markRead(hash, user); + var id = Integer.parseInt(path); + var envelope = queue.markRead(id, user); if (envelope.isPresent()) return sendMessage(ex,user,envelope.get()); return notFound(ex); } catch (NumberFormatException | IOException e) { - throw invalidField(HASH,LONG); + throw invalidField(ID,LONG); } } @@ -221,9 +223,9 @@ public class MessageSystem extends BaseHandler implements PostBox, EventListener try { var envelopes = queue.getEnvelopesFor(receiver); - envelopes.stream().forEach(combined::merge); + envelopes.stream().map(Envelope::message).forEach(combined::merge); send(combined,date); - envelopes.forEach(env -> queue.markRead(env.hashCode(),receiver)); + envelopes.forEach(env -> queue.markRead(env.id(),receiver)); } catch (Exception ex){ LOG.log(WARNING,"Failed to deliver mail ({0}) to {1}.",combined.subject(),receiver,ex); for (var message : combined.messages()) exceptions.computeIfAbsent(new Receiver(receiver,message), k -> new ArrayList<>()).add(ex); @@ -328,7 +330,7 @@ public class MessageSystem extends BaseHandler implements PostBox, EventListener var sender = message.sender().name(); var subject = message.subject(); - var time = envelope.time().format(TIME_FORMATTER); + var time = Instant.ofEpochMilli(message.utcTime()).atZone(ZoneId.systemDefault()).toLocalDateTime().format(TIME_FORMATTER); var id = envelope.id(); return new JSONObject(Map.of(SENDER,sender,SUBJECT,subject,TIMESTAMP,time,ID,id)); } diff --git a/messages/src/main/java/de/srsoftware/umbrella/message/SqliteMessageDb.java b/messages/src/main/java/de/srsoftware/umbrella/message/SqliteMessageDb.java index d3df9220..e34968b1 100644 --- a/messages/src/main/java/de/srsoftware/umbrella/message/SqliteMessageDb.java +++ b/messages/src/main/java/de/srsoftware/umbrella/message/SqliteMessageDb.java @@ -14,11 +14,9 @@ import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.message.Constants.*; import static de.srsoftware.umbrella.message.model.Schedule.schedule; import static java.text.MessageFormat.format; -import static java.time.ZoneOffset.UTC; import de.srsoftware.tools.jdbc.Query; import de.srsoftware.umbrella.core.BaseDb; -import de.srsoftware.umbrella.core.Util; import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; @@ -162,7 +160,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} INTEGER PRIMARY KEY, {2} VARCHAR(255) NOT N var messageId = rs.getLong(ID); var sender = userService().loadUser(rs.getLong(SENDER_USER_ID)); var msg = new TranslatedMessage(sender,rs.getString(SUBJECT),rs.getString(BODY), attachments.get(messageId)); - var envelope = new Envelope<>(messageId, msg, user).time(Util.dateTimeOf(rs.getLong(TIMESTAMP))); + var envelope = new Envelope<>(messageId, msg, user); envelopes.add(envelope); } rs.close(); @@ -224,8 +222,8 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} INTEGER PRIMARY KEY, {2} VARCHAR(255) NOT N @Override public void push(Envelope envelope) { - var timestamp = envelope.time().toEpochSecond(UTC); var message = envelope.message(); + var timestamp = message.utcTime(); var sender = message.sender().id(); var subject = message.subject(); var body = message.body(); 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 a198d518..67d72d6d 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 @@ -1,12 +1,12 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.message.model; +import static de.srsoftware.umbrella.core.Util.dateTimeOf; import static java.lang.System.Logger.Level.DEBUG; import static java.lang.System.Logger.Level.TRACE; import static java.text.MessageFormat.format; import de.srsoftware.umbrella.core.model.*; -import java.time.format.DateTimeFormatter; import java.util.*; public class CombinedMessage { @@ -20,7 +20,6 @@ public class CombinedMessage { private final List> mergedMessages = new ArrayList<>(); private final Translatable subjectForCombinedMessage; private UmbrellaUser sender = null; - private static DateTimeFormatter DT_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public CombinedMessage(Translatable subjectForCombinedMessage, User receiver){ LOG.log(DEBUG,"Creating combined message for {0}…",receiver); @@ -29,9 +28,8 @@ public class CombinedMessage { this.lang = receiver.language(); } - public void merge(Envelope envelope) { - LOG.log(TRACE,"Merging {0} into combined message…",envelope); - var message = envelope.message(); + public void merge(Message message) { + LOG.log(TRACE,"Merging {0} into combined message…",message); if (message instanceof TranslatableMessage tm) message = tm.translate(lang); var body = message.body(); @@ -43,11 +41,11 @@ public class CombinedMessage { combinedSubject = subject; break; case 1: - combinedBody.insert(0,format("# {0} @ {1}\n→ {2}:\n\n",sender,envelope.time().format(DT_FORMAT),subject)); // insert sender and subject of first message right before the body of the first message + combinedBody.insert(0,format("# {0} @ {1}\n→ {2}:\n\n",sender, dateTimeOf(message.utcTime()),subject)); // insert sender and subject of first message right before the body of the first message combinedSubject = subjectForCombinedMessage.translate(lang); // no break here, we need to append the subject and content default: - combinedBody.append("\n\n━━━━━━━━━━━━━━━━━━━━━\n\n# ").append(message.sender()).append(" @ ").append(envelope.time().format(DT_FORMAT)).append("\n→ ").append(subject).append(":\n\n"); + combinedBody.append("\n\n━━━━━━━━━━━━━━━━━━━━━\n\n# ").append(message.sender()).append(" @ ").append(dateTimeOf(message.utcTime())).append("\n→ ").append(subject).append(":\n\n"); combinedBody.append(body); } if (message.attachments() != null) attachments.addAll(message.attachments());