diff --git a/.gitignore b/.gitignore
index 9f758d2..89546fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@ archive
target
config/config.json
*.sqlite3
-jquery-3.6.0.min.js
\ No newline at end of file
+jquery-3.6.0.min.js
+src/main/resources/logback-test.xml
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 4856ed2..6b9afda 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
org.example
Widerhall
- 0.2.31
+ 0.2.32
diff --git a/src/main/java/de/srsoftware/widerhall/Constants.java b/src/main/java/de/srsoftware/widerhall/Constants.java
index fc3ca19..dae10b7 100644
--- a/src/main/java/de/srsoftware/widerhall/Constants.java
+++ b/src/main/java/de/srsoftware/widerhall/Constants.java
@@ -28,8 +28,7 @@ public class Constants {
public static final String SUBJECT = "subject";
public static final String TEXT = "text";
public static final String TOKEN = "token";
+ public static final String URL = "url";
public static final String USER = "user";
public static final String VARCHAR = "VARCHAR(255)";
-
-
}
diff --git a/src/main/java/de/srsoftware/widerhall/data/ListMember.java b/src/main/java/de/srsoftware/widerhall/data/ListMember.java
index f17f8b7..967f967 100644
--- a/src/main/java/de/srsoftware/widerhall/data/ListMember.java
+++ b/src/main/java/de/srsoftware/widerhall/data/ListMember.java
@@ -1,9 +1,13 @@
package de.srsoftware.widerhall.data;
+import de.srsoftware.widerhall.Configuration;
import de.srsoftware.widerhall.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.stringtemplate.v4.ST;
+import javax.mail.MessagingException;
+import java.io.UnsupportedEncodingException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
@@ -87,7 +91,7 @@ public class ListMember {
* @return
* @throws SQLException
*/
- public static User confirm(String token) throws SQLException {
+ public static ListMember confirm(String token) throws SQLException {
var rs = Database.open().select(TABLE_NAME).where(TOKEN,token).compile().exec();
if (rs.next()){
var lm = ListMember.from(rs);
@@ -103,12 +107,25 @@ public class ListMember {
.compile()
.run();
}
- return lm.user;
+ return lm;
}
return null;
}
-
+ public void sendConfirmationMail(ST template) throws SQLException, MessagingException {
+ var subject = t("[{}] Subscription complete!",list.name());
+ var data = new HashMap();
+ data.put(USER,user.safeMap());
+ data.put(LIST,list.minimalMap());
+ data.put(URL,Configuration.instance().baseUrl()+"/web/index");
+ if (list.isOpenForSubscribers()) data.put("open_list",true);
+ var text = template.add("data",data).render();
+ try {
+ list.smtp().send(list.email(),list.name(),user.email(),subject,text);
+ } catch (UnsupportedEncodingException e) {
+ LOG.warn("Failed to send list subscription confirmation!",e);
+ }
+ }
/**
* Create a new list member entry in the database.
* If the member has the state AWAITING_CONFIRMATION, a token is assigned with the member, too.
diff --git a/src/main/java/de/srsoftware/widerhall/data/MailingList.java b/src/main/java/de/srsoftware/widerhall/data/MailingList.java
index 5d3fcd0..33ad39c 100644
--- a/src/main/java/de/srsoftware/widerhall/data/MailingList.java
+++ b/src/main/java/de/srsoftware/widerhall/data/MailingList.java
@@ -7,6 +7,7 @@ import de.srsoftware.widerhall.mail.ProblemListener;
import de.srsoftware.widerhall.mail.SmtpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.stringtemplate.v4.ST;
import javax.mail.*;
import javax.mail.internet.AddressException;
@@ -60,6 +61,7 @@ public class MailingList implements MessageHandler, ProblemListener {
private static final int DEFAULT_STATE = STATE_PENDING|STATE_HIDE_RECEIVERS|STATE_PUBLIC_ARCHIVE;
private static final String RETAINED_FOLDER = "retained";
private static final String LAST_ERROR = "last_error";
+ private static final String LIST_NAME = "list_name";
private String email, name, lastError;
private int state;
private SmtpClient smtp;
@@ -532,21 +534,6 @@ public class MailingList implements MessageHandler, ProblemListener {
return this;
}
- /**
- * send an email to a potential subscriber asking for confirmation
- * @param user
- * @param token
- * @throws MessagingException
- * @throws UnsupportedEncodingException
- */
- private void sendConfirmationRequest(User user, String token) throws MessagingException, UnsupportedEncodingException {
- var subject = t("Please confirm your list subscription");
- var config = Configuration.instance();
- var url = new StringBuilder(config.baseUrl()).append("/web/confirm?token=").append(token);
- var text = t("Please go to {} in order to complete your list subscription!",url);
- smtp.send(email(),name(),user.email(),subject,text);
- }
-
private void sentRetentionNotification(String senderEmail) {
try {
var receivers = members()
@@ -641,17 +628,24 @@ public class MailingList implements MessageHandler, ProblemListener {
* @throws SQLException
* @throws MessagingException
*/
- public void requestSubscription(User user, boolean skipConfirmation) throws SQLException, MessagingException {
+ public void requestSubscription(User user, boolean skipConfirmation, ST template) throws SQLException, MessagingException {
var state = skipConfirmation ? ListMember.STATE_SUBSCRIBER : ListMember.STATE_AWAITING_CONFIRMATION;
var member = ListMember.create(this,user,state);
if (skipConfirmation) return;
try {
- sendConfirmationRequest(user, member.token());
+ var config = Configuration.instance();
+ var url = new StringBuilder(config.baseUrl()).append("/web/confirm?token=").append(member.token()).toString();
+ var subject = t("[{}] Please confirm your list subscription",name());
+ var text = template.add(URL,url).add(LIST_NAME,name()).render();
+ smtp.send(email(),name(),user.email(),subject,text);
} catch (UnsupportedEncodingException e) {
throw new MessagingException(t("Failed to send email to {}",user.email()),e);
}
}
+ protected SmtpClient smtp(){
+ return smtp;
+ }
private String stamp() {
return "["+name+"]";
diff --git a/src/main/java/de/srsoftware/widerhall/web/TemplateServlet.java b/src/main/java/de/srsoftware/widerhall/web/TemplateServlet.java
index 43eacbf..bd55559 100644
--- a/src/main/java/de/srsoftware/widerhall/web/TemplateServlet.java
+++ b/src/main/java/de/srsoftware/widerhall/web/TemplateServlet.java
@@ -1,6 +1,7 @@
package de.srsoftware.widerhall.web;
import de.srsoftware.widerhall.Configuration;
+import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STRawGroupDir;
@@ -8,7 +9,6 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Map;
@@ -24,6 +24,10 @@ public abstract class TemplateServlet extends HttpServlet {
loadTemplates();
}
+ protected ST getTemplate(String name){
+ return templates.getInstanceOf(name);
+ }
+
protected String loadFile(String filename, HttpServletResponse resp) {
var path = String.join(File.separator,baseDir,"static",filename);
var file = new File(path);
diff --git a/src/main/java/de/srsoftware/widerhall/web/Web.java b/src/main/java/de/srsoftware/widerhall/web/Web.java
index 2e76d6f..792547b 100644
--- a/src/main/java/de/srsoftware/widerhall/web/Web.java
+++ b/src/main/java/de/srsoftware/widerhall/web/Web.java
@@ -142,8 +142,12 @@ public class Web extends TemplateServlet {
try {
var token = req.getParameter(TOKEN);
if (token== null || token.isBlank()) return t("Invalid or missing token!");
- var user = ListMember.confirm(token);
- if (user != null) return loadTemplate(INDEX,Map.of(USER,user.safeMap(),NOTES,"Confirmed list subscription!"),resp);
+ var listMember = ListMember.confirm(token);
+ if (listMember != null) {
+ listMember.sendConfirmationMail(getTemplate("confirmation_mail"));
+
+ return loadTemplate(INDEX,Map.of(USER,listMember.user().safeMap(),NOTES,"Confirmed list subscription!"),resp);
+ }
return t("Unknown user or token");
} catch (Exception e) {
LOG.debug("Failed to confirm list membership:",e);
@@ -517,7 +521,7 @@ public class Web extends TemplateServlet {
}
try {
- list.requestSubscription(user,skipConfirmation);
+ list.requestSubscription(user,skipConfirmation,getTemplate("subscribe_mail"));
if (skipConfirmation) {
data.put(NOTES, t("Successfully subscribed '{}' to '{}'.", user.email(), list.email()));
} else {
diff --git a/static/templates/confirmation_mail.st b/static/templates/confirmation_mail.st
new file mode 100644
index 0000000..9b1afb8
--- /dev/null
+++ b/static/templates/confirmation_mail.st
@@ -0,0 +1,17 @@
+Welcome, «data.user.name»!
+
+You successfully subscribed to the "«data.list.name»" Mailing list!
+
+«if(data.open_list)»
+This is an open list. This means you may, at any time, send emails to «data.list.email» and we will forward your mail to the other subscribers.
+«else»
+This is a moderated list. This means, you (and all other subscribers) will receive any mails sent by a moderator. However, if you write (answer) messages to the list, only the moderators will receive your mail.
+«endif»
+
+If you want to answer exclusively to the author of an email you received via the list, you may find the respective address in the subject line of the received email.
+
+If you wish to leave the list, you may, at any time, go to «data.url» and un-subscribe.
+
+best wishes,
+
+Stephan Richter (the software author)
\ No newline at end of file
diff --git a/static/templates/subscribe_mail.st b/static/templates/subscribe_mail.st
new file mode 100644
index 0000000..d28fe7b
--- /dev/null
+++ b/static/templates/subscribe_mail.st
@@ -0,0 +1,6 @@
+Welcome to the "«list_name»" Mailing list subscription!
+
+Someone, probably you, tried to register your email address!
+If that was you, go to «url» in order to complete your list subscription.
+
+If you did not wish to subscribe to the list, you may ignore this mail.
\ No newline at end of file