restructuring, working on password reset email

next steps:
- create reset url and add it to the translation fill map
- implement message translation
- implement otp validation and login
This commit is contained in:
2025-07-08 15:39:48 +02:00
parent 3e91565fb6
commit 7a5bb50ee2
24 changed files with 245 additions and 178 deletions

View File

@@ -2,8 +2,8 @@
package de.srsoftware.umbrella.message;
import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.message.model.Settings;
import de.srsoftware.umbrella.user.model.UmbrellaUser;
public interface MessageDb {
public Settings getSettings(UmbrellaUser user) throws UmbrellaException;

View File

@@ -4,17 +4,15 @@ package de.srsoftware.umbrella.message;
import static de.srsoftware.tools.PathHandler.CONTENT_TYPE;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.message.Constants.*;
import static de.srsoftware.umbrella.user.Constants.PASS;
import static java.lang.System.Logger.Level.*;
import de.srsoftware.configuration.Configuration;
import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.core.api.Translator;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.message.model.CombinedMessage;
import de.srsoftware.umbrella.message.model.Envelope;
import de.srsoftware.umbrella.message.model.PostBox;
import de.srsoftware.umbrella.user.model.UmbrellaUser;
import de.srsoftware.umbrella.user.model.User;
import jakarta.activation.DataHandler;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
@@ -31,7 +29,7 @@ import java.util.function.Function;
public class MessageSystem implements PostBox {
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.message.model.Message message){}
private record Receiver(UmbrellaUser user, de.srsoftware.umbrella.message.model.Message message){}
private class SubmissionTask extends TimerTask{
@@ -98,11 +96,11 @@ public class MessageSystem implements PostBox {
private synchronized void processMessages(Integer scheduledHour) {
LOG.log(INFO,"Running {0}…",scheduledHour == null ? "instantly" : "scheduled at "+scheduledHour);
var queue = new ArrayList<>(this.queue);
var dueRecipients = new ArrayList<User>();
List<User> recipients = queue.stream().map(Envelope::receivers).flatMap(Set::stream).filter(Objects::nonNull).distinct().toList();
var dueRecipients = new ArrayList<UmbrellaUser>();
List<UmbrellaUser> recipients = queue.stream().map(Envelope::receivers).flatMap(Set::stream).filter(Objects::nonNull).distinct().toList();
{ // for known users: get notification preferences, fallback to _immediately_ for unknown users
for (User recv : recipients) {
for (UmbrellaUser recv : recipients) {
if (recv instanceof UmbrellaUser uu) {
try {
if (!db.getSettings(uu).sendAt(scheduledHour)) continue;
@@ -156,17 +154,17 @@ public class MessageSystem implements PostBox {
}
private void send(CombinedMessage message, User receiver, Date date) throws MessagingException {
private void send(CombinedMessage message, UmbrellaUser receiver, Date date) throws MessagingException {
LOG.log(TRACE,"Sending combined message to {0}…",receiver);
session = session();
MimeMessage msg = new MimeMessage(session);
msg.addHeader(CONTENT_TYPE, "text/markdown; charset=UTF-8");
msg.addHeader("format", "flowed");
msg.addHeader("Content-Transfer-Encoding", "8bit");
msg.setFrom(message.sender().email());
msg.setFrom(message.sender().email().toString());
msg.setSubject(message.subject(), UTF8);
msg.setSentDate(date);
var toEmail = debugAddress != null ? debugAddress : receiver.email();
var toEmail = debugAddress != null ? debugAddress : receiver.email().toString();
msg.setRecipients(Message.RecipientType.TO, toEmail);
if (message.attachments().isEmpty()){

View File

@@ -10,8 +10,8 @@ import static java.lang.System.Logger.Level.WARNING;
import static java.text.MessageFormat.format;
import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.message.model.Settings;
import de.srsoftware.umbrella.user.model.UmbrellaUser;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;

View File

@@ -5,7 +5,7 @@ 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.user.model.UmbrellaUser;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -44,7 +44,7 @@ public class CombinedMessage {
body.append("# ").append(message.subject()).append(":\n\n");
body.append(message.body());
}
attachments.addAll(message.attachments());
if (message.attachments() != null) attachments.addAll(message.attachments());
mergedMessages.add(message);
}

View File

@@ -7,7 +7,8 @@ import static de.srsoftware.umbrella.message.Constants.*;
import static java.text.MessageFormat.format;
import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.user.model.User;
import de.srsoftware.umbrella.core.model.EmailAddress;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -17,28 +18,38 @@ import org.json.JSONObject;
public class Envelope {
private Message message;
private Set<User> receivers;
private Set<UmbrellaUser> receivers;
public Envelope(Message message, HashSet<User> receivers) {
public Envelope(Message message, UmbrellaUser receiver){
this(message,new HashSet<>(Set.of(receiver)));
}
public Envelope(Message message, HashSet<UmbrellaUser> receivers) {
this.message = message;
this.receivers = receivers;
}
/**
* TODO: this is legacy, move to legacy module!
* @param json
* @return
* @throws UmbrellaException
*/
public static Envelope from(JSONObject json) throws UmbrellaException {
if (!json.has(RECEIVERS)) throw new UmbrellaException(400,ERROR_MISSING_FIELD,RECEIVERS);
var message = Message.from(json);
var obj = json.get(RECEIVERS);
if (obj instanceof JSONObject) obj = new JSONArray(List.of(obj));
if (!(obj instanceof JSONArray receiverList)) throw new UmbrellaException(400,ERROR_INVALID_FIELD,RECEIVERS,JSONARRAY);
var receivers = new HashSet<User>();
var receivers = new HashSet<UmbrellaUser>();
for (var o : receiverList){
if (!(o instanceof JSONObject receiverData)) throw new UmbrellaException(400,ERROR_INVALID_FIELD,"entries of "+RECEIVERS,JSONOBJECT);
receivers.add(User.of(receiverData));
receivers.add(UmbrellaUser.of(receiverData));
}
return new Envelope(message,receivers);
}
public boolean isFor(User receiver) {
public boolean isFor(UmbrellaUser receiver) {
return receivers.contains(receiver);
}
@@ -46,12 +57,12 @@ public class Envelope {
return message;
}
public Set<User> receivers(){
public Set<UmbrellaUser> receivers(){
return receivers;
}
@Override
public String toString() {
return format("{0} (to: {1}), subject: {2}",getClass().getSimpleName(),receivers.stream().map(User::email).collect(Collectors.joining(", ")),message.subject());
return format("{0} (to: {1}), subject: {2}",getClass().getSimpleName(),receivers.stream().map(UmbrellaUser::email).map(EmailAddress::toString).collect(Collectors.joining(", ")),message.subject());
}
}

View File

@@ -7,16 +7,12 @@ import static de.srsoftware.umbrella.message.Constants.*;
import static java.text.MessageFormat.format;
import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.user.model.UmbrellaUser;
import de.srsoftware.umbrella.user.model.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.util.*;
import org.json.JSONArray;
import org.json.JSONObject;
public record Message(UmbrellaUser sender, String subject, String body, List<Attachment> attachments) {
public record Message(UmbrellaUser sender, String subject, String body, Map<String,String> fills, List<Attachment> attachments) {
public static Message from(JSONObject json) throws UmbrellaException {
for (var key : Set.of(SENDER, SUBJECT, BODY)) {
if (!json.has(key)) throw new UmbrellaException(400,ERROR_MISSING_FIELD,key);
@@ -25,7 +21,7 @@ public record Message(UmbrellaUser sender, String subject, String body, List<Att
if (!(json.get(SUBJECT) instanceof String subject && isSet(subject))) throw new UmbrellaException(400,ERROR_INVALID_FIELD, SUBJECT,STRING);
if (!(json.get(BODY) instanceof String body && isSet(body))) throw new UmbrellaException(400,ERROR_INVALID_FIELD, BODY,STRING);
var user = User.of(senderObject);
var user = UmbrellaUser.of(senderObject);
if (!(user instanceof UmbrellaUser sender)) throw new UmbrellaException(400,"Sender is not an umbrella user!");
var attachments = new ArrayList<Attachment>();
if (json.has(ATTACHMENTS)){
@@ -39,7 +35,7 @@ public record Message(UmbrellaUser sender, String subject, String body, List<Att
}
}
}
return new Message(sender,subject,body,attachments);
return new Message(sender,subject,body,null, attachments);
}
@Override