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 1a45dd5..072e79f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.example Widerhall - 0.2.53 + 0.2.55 diff --git a/src/main/java/de/srsoftware/widerhall/data/Database.java b/src/main/java/de/srsoftware/widerhall/data/Database.java index 402725b..ea706cd 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 f222baf..6f78d7a 100644 --- a/src/main/java/de/srsoftware/widerhall/data/MailingList.java +++ b/src/main/java/de/srsoftware/widerhall/data/MailingList.java @@ -12,8 +12,7 @@ import org.stringtemplate.v4.ST; import javax.mail.*; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; -import javax.ws.rs.HEAD; -import java.io.*; +import java.io.UnsupportedEncodingException; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; @@ -28,14 +27,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"; @@ -69,6 +70,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 @@ -124,6 +126,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 @@ -149,6 +155,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; } @@ -227,6 +247,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 @@ -437,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 2d1be42..835c9ea 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; @@ -72,10 +74,8 @@ public class ImapClient { } private void handleMessages() throws MessagingException { - LOG.debug("Lese E-Mail von {}:",username); - if (!inbox.isOpen()){ - inbox.open(IMAPFolder.READ_WRITE); - } + LOG.debug("Reading email of {}:",username); + 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,27 @@ public class ImapClient { return this; } + public void dropMailsOlderThan(Integer holdTime) throws MessagingException { + var now = new Date(); + if (holdTime == null) return; + LOG.info("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){ + LOG.info("…removing"); + 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 9986426..a7e91fb 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 7de10bb..cb84a6e 100644 --- a/src/main/java/de/srsoftware/widerhall/web/Web.java +++ b/src/main/java/de/srsoftware/widerhall/web/Web.java @@ -409,7 +409,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("Mailing-Liste aktualisiert!")); } catch (SQLException e){ LOG.warn("Aktualisierung der Mailing-Liste fehlgeschlagen:",e); diff --git a/static/templates/inspect.st b/static/templates/inspect.st index eef6df4..d23f690 100644 --- a/static/templates/inspect.st +++ b/static/templates/inspect.st @@ -17,43 +17,48 @@

✓ Besitzer und Moderatoren
Weiterleitungs-Optionen
andere Optionen +
diff --git a/static/templates/js.st b/static/templates/js.st index be4b7b7..65ec8cf 100644 --- a/static/templates/js.st +++ b/static/templates/js.st @@ -103,11 +103,12 @@ 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); }); + if (data['delete_messages']) $('input[name="hold_time"]').val(data['delete_messages']); } function showListOfModeratedLists(data){