From f37fabe21b43471b0192b2e76f3ebda317d878d2 Mon Sep 17 00:00:00 2001
From: Stephan Richter
Date: Sat, 30 Apr 2022 12:21:51 +0200
Subject: [PATCH] working on dropping old mails
---
doc/data structure.dia | 90 +++++++++++++++++++
pom.xml | 2 +-
.../srsoftware/widerhall/data/Database.java | 22 +++++
.../widerhall/data/MailingList.java | 36 ++++++--
.../srsoftware/widerhall/mail/ImapClient.java | 26 +++++-
.../de/srsoftware/widerhall/web/Rest.java | 1 +
.../java/de/srsoftware/widerhall/web/Web.java | 3 +-
static/templates/inspect.st | 21 +++--
static/templates/js.st | 2 +-
9 files changed, 184 insertions(+), 19 deletions(-)
diff --git a/doc/data structure.dia b/doc/data structure.dia
index 97d23ed..19e48b5 100644
--- a/doc/data structure.dia
+++ b/doc/data structure.dia
@@ -1740,5 +1740,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #hold_time#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #last_error#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index e500570..1a45dd5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
org.example
Widerhall
- 0.2.52
+ 0.2.53
diff --git a/src/main/java/de/srsoftware/widerhall/data/Database.java b/src/main/java/de/srsoftware/widerhall/data/Database.java
index f2eaffb..9942bd3 100644
--- a/src/main/java/de/srsoftware/widerhall/data/Database.java
+++ b/src/main/java/de/srsoftware/widerhall/data/Database.java
@@ -11,6 +11,7 @@ import java.sql.SQLException;
import java.util.*;
import static de.srsoftware.widerhall.Util.t;
+import static de.srsoftware.widerhall.data.MailingList.HOLD_TIME;
/**
* @author Stephan Richter, 2022
@@ -280,9 +281,30 @@ public class Database {
if (!tableExists(MailingList.TABLE_NAME)) MailingList.createTable();
if (!tableExists(ListMember.TABLE_NAME)) ListMember.createTable();
if (!tableExists(Post.TABLE_NAME)) Post.createTable();
+ if (!columnExists(MailingList.TABLE_NAME,HOLD_TIME)) MailingList.createHoldTimeColumn();
return this;
}
+ private boolean columnExists(String tableName, String columnName) throws SQLException {
+ var rs = Database.open().select("pragma_table_info('"+tableName+"')","COUNT(*) AS num").where("name",columnName).compile().exec();
+ try {
+ if (rs.next()) return rs.getInt("num") > 0;
+ } finally {
+ rs.close();
+ }
+ return false;
+ }
+
+ public void createColumn(String tableName, String colName, String...typeArgs) throws SQLException {
+ var sql = new StringBuilder("ALTER TABLE ")
+ .append(tableName)
+ .append(" ADD COLUMN ")
+ .append(colName)
+ .append(" ")
+ .append(String.join(" ",typeArgs));
+ new Request(sql).compile().run();
+ }
+
/**
* prepare a deletion statement
* @param tableName
diff --git a/src/main/java/de/srsoftware/widerhall/data/MailingList.java b/src/main/java/de/srsoftware/widerhall/data/MailingList.java
index 6c2d98c..cfd410a 100644
--- a/src/main/java/de/srsoftware/widerhall/data/MailingList.java
+++ b/src/main/java/de/srsoftware/widerhall/data/MailingList.java
@@ -12,6 +12,7 @@ import org.stringtemplate.v4.ST;
import javax.mail.*;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
+import javax.xml.crypto.Data;
import java.io.*;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -27,14 +28,16 @@ import static de.srsoftware.widerhall.data.User.PERMISSION_ADMIN;
* this class encapsulates a MailingList db object
*/
public class MailingList implements MessageHandler, ProblemListener {
- public static final String KEY_FORWARD_FROM = "forward_from";
+ public static final String KEY_ARCHIVE = "archive";
+ public static final String KEY_DELETE_MESSAGES = "delete_messages";
public static final String KEY_FORWARD_ATTACHED = "forward_attached";
+ public static final String KEY_FORWARD_FROM = "forward_from";
public static final String KEY_HIDE_RECEIVERS = "hide_receivers";
- public static final String KEY_REPLY_TO_LIST = "reply_to_list";
+ public static final String KEY_MODS_CAN_EDIT_MODS = "edit_mods";
public static final String KEY_OPEN_FOR_GUESTS = "open_for_guests";
public static final String KEY_OPEN_FOR_SUBSCRIBERS = "open_for_subscribers";
- public static final String KEY_ARCHIVE = "archive";
- public static final String KEY_MODS_CAN_EDIT_MODS = "edit_mods";
+ public static final String KEY_REPLY_TO_LIST = "reply_to_list";
+ public static final String HOLD_TIME = "hold_time";
private static final Logger LOG = LoggerFactory.getLogger(MailingList.class);
private static final String IMAP_HOST = "imap_host";
private static final String IMAP_PORT = "imap_port";
@@ -68,6 +71,7 @@ public class MailingList implements MessageHandler, ProblemListener {
private ImapClient imap;
private static final HashMap cache = new HashMap<>();
+ private Integer holdTime = null;
/**
* create a new ML object
@@ -123,6 +127,10 @@ public class MailingList implements MessageHandler, ProblemListener {
return new MailingList(email, name, imapHost, imapPort, imapUser, imapPass, inbox, smtpHost, smtpPort, smtpUser, smtpPass, DEFAULT_STATE).save();
}
+ public static void createHoldTimeColumn() throws SQLException {
+ Database.open().createColumn(TABLE_NAME,HOLD_TIME,INT);
+ }
+
/**
* create underlying db table
* @throws SQLException
@@ -148,6 +156,20 @@ public class MailingList implements MessageHandler, ProblemListener {
Database.open().query(sql).compile().run();
}
+ public void deleteMessages(boolean enable, String daysString) {
+ try {
+ holdTime = enable ? Integer.parseInt(daysString) : null;
+ Database.open().update(TABLE_NAME).set(HOLD_TIME, holdTime).run();
+ } catch (SQLException throwables) {
+ LOG.warn("Failed to update {} setting!",HOLD_TIME);
+ }
+ }
+
+ private void dropOldMails() throws MessagingException {
+ if (holdTime == null) return;
+ imap.dropMailsOlderThan(holdTime);
+ }
+
public String email() {
return email;
}
@@ -226,6 +248,10 @@ public class MailingList implements MessageHandler, ProblemListener {
return setFlag(STATE_HIDE_RECEIVERS,hide);
}
+ public Integer holdTime() {
+ return holdTime;
+ }
+
/**
* test, whether the current ML is subscribable by a given user
* @param user
@@ -435,7 +461,7 @@ public class MailingList implements MessageHandler, ProblemListener {
} catch (SQLException e){
LOG.warn("Failed to process message '{}'",subject,e);
}
-
+ dropOldMails();
}
public MailingList openForGuests(boolean open) throws SQLException {
diff --git a/src/main/java/de/srsoftware/widerhall/mail/ImapClient.java b/src/main/java/de/srsoftware/widerhall/mail/ImapClient.java
index 59e0383..d09a3df 100644
--- a/src/main/java/de/srsoftware/widerhall/mail/ImapClient.java
+++ b/src/main/java/de/srsoftware/widerhall/mail/ImapClient.java
@@ -6,6 +6,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.mail.*;
+import java.time.Duration;
+import java.util.Date;
import java.util.HashSet;
import java.util.Properties;
@@ -73,9 +75,7 @@ public class ImapClient {
private void handleMessages() throws MessagingException {
LOG.debug("Reading email of {}:",username);
- if (!inbox.isOpen()){
- inbox.open(IMAPFolder.READ_WRITE);
- }
+ if (!inbox.isOpen()) inbox.open(IMAPFolder.READ_WRITE);
for (Message message : inbox.getMessages()){
if (message.isSet(Flags.Flag.SEEN)) continue;
handle(message);
@@ -145,6 +145,26 @@ public class ImapClient {
return this;
}
+ public void dropMailsOlderThan(Integer holdTime) throws MessagingException {
+ var now = new Date();
+ if (holdTime == null) return;
+ LOG.debug("Removing mails older than {} days:",holdTime);
+ if (!inbox.isOpen()) inbox.open(IMAPFolder.READ_WRITE);
+ for (Message message : inbox.getMessages()){
+ Date receivedDate = message.getReceivedDate();
+ Duration duration = Duration.between(receivedDate.toInstant(),now.toInstant());
+ var days = duration.toDays();
+ LOG.info("Message {} is {} days old!");
+ if (days > holdTime){
+ Folder folder = message.getFolder();
+ if (!folder.isOpen()) folder.open(Folder.READ_WRITE);
+ message.setFlag(Flags.Flag.DELETED, true);
+ }
+ }
+ inbox.expunge();
+ }
+
+
public String host(){
return host;
}
diff --git a/src/main/java/de/srsoftware/widerhall/web/Rest.java b/src/main/java/de/srsoftware/widerhall/web/Rest.java
index 2b64ca5..1d35b1f 100644
--- a/src/main/java/de/srsoftware/widerhall/web/Rest.java
+++ b/src/main/java/de/srsoftware/widerhall/web/Rest.java
@@ -309,6 +309,7 @@ public class Rest extends HttpServlet {
if (list.isOpenForSubscribers()) map.put(KEY_OPEN_FOR_SUBSCRIBERS,true);
if (list.hasState(MailingList.STATE_PUBLIC_ARCHIVE)) map.put(KEY_ARCHIVE,true);
if (list.hasState(STATE_MODS_CAN_EDIT_MODS)) map.put(KEY_MODS_CAN_EDIT_MODS,true);
+ if (list.holdTime() != null) map.put(KEY_DELETE_MESSAGES,list.holdTime());
return map;
}
diff --git a/src/main/java/de/srsoftware/widerhall/web/Web.java b/src/main/java/de/srsoftware/widerhall/web/Web.java
index bd7d718..ba2dc62 100644
--- a/src/main/java/de/srsoftware/widerhall/web/Web.java
+++ b/src/main/java/de/srsoftware/widerhall/web/Web.java
@@ -408,7 +408,8 @@ public class Web extends TemplateServlet {
.modsMayNominateMods(Util.getCheckbox(req, KEY_MODS_CAN_EDIT_MODS))
.openForGuests(Util.getCheckbox(req,KEY_OPEN_FOR_GUESTS))
.openForSubscribers(Util.getCheckbox(req,KEY_OPEN_FOR_SUBSCRIBERS))
- .archive(Util.getCheckbox(req,KEY_ARCHIVE));
+ .archive(Util.getCheckbox(req,KEY_ARCHIVE))
+ .deleteMessages(Util.getCheckbox(req,KEY_DELETE_MESSAGES),req.getParameter(HOLD_TIME));
data.put(NOTES,t("Sucessfully updated MailingList!"));
} catch (SQLException e){
LOG.warn("Failed to update MailingList:",e);
diff --git a/static/templates/inspect.st b/static/templates/inspect.st
index 906669e..daf3a18 100644
--- a/static/templates/inspect.st
+++ b/static/templates/inspect.st
@@ -17,43 +17,48 @@
✓ Oweners and Moderators
diff --git a/static/templates/js.st b/static/templates/js.st
index c49b452..d9836af 100644
--- a/static/templates/js.st
+++ b/static/templates/js.st
@@ -103,7 +103,7 @@ function showListArchiveSummary(data){
}
function showListDetail(data){
- var options = ['forward_from','forward_attached','hide_receivers','reply_to_list','open_for_guests','open_for_subscribers','archive','edit_mods'];
+ var options = ['forward_from','forward_attached','hide_receivers','reply_to_list','open_for_guests','open_for_subscribers','archive','edit_mods','delete_messages'];
options.forEach(function(option,index,array){
console.log(option,'→',data[option]);
if (data[option]) $('input[name="'+option+'"]').prop('checked',true);