Browse Source

added new state bits to MailingList, implemented form for editing those

drop_old_mail
Stephan Richter 2 years ago
parent
commit
7bf492e469
  1. 16
      config/logback.xml
  2. 2
      pom.xml
  3. 45
      src/main/java/de/srsoftware/widerhall/data/MailingList.java
  4. 40
      src/main/java/de/srsoftware/widerhall/web/Rest.java
  5. 14
      src/main/java/de/srsoftware/widerhall/web/Web.java
  6. 2
      src/main/resources/logback.xml
  7. 69
      static/templates/inspect.st
  8. 11
      static/templates/js.st

16
config/logback.xml

@ -1,16 +0,0 @@
<configuration scan="true" scanPeriod="30 seconds" debug="true">
<!-- scan="true" enables automatic updates if config file changes, see http://logback.qos.ch/manual/configuration.html -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5}: %msg%n
</pattern>
</encoder>
</appender>
<root level="WARN">
<appender-ref ref="STDOUT" />
</root>
<logger name="de.srsoftware" level="DEBUG" />
</configuration>

2
pom.xml

@ -6,7 +6,7 @@
<groupId>org.example</groupId> <groupId>org.example</groupId>
<artifactId>Widerhall</artifactId> <artifactId>Widerhall</artifactId>
<version>0.2.13</version> <version>0.2.14</version>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>

45
src/main/java/de/srsoftware/widerhall/data/MailingList.java

@ -28,6 +28,13 @@ import static de.srsoftware.widerhall.data.User.PERMISSION_ADMIN;
* this class encapsulates a MailingList db object * this class encapsulates a MailingList db object
*/ */
public class MailingList implements MessageHandler { public class MailingList implements MessageHandler {
public static final String KEY_FORWARD_FROM = "forward_from";
public static final String KEY_FORWARD_ATTACHED = "forward_attached";
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_OPEN_FOR_GUESTS = "open_for_guests";
public static final String KEY_OPEN_FOR_SUBSCRIBERS = "open_for_subscribers";
public static final String KEY_ARCHIVE = "archive";
private static final Logger LOG = LoggerFactory.getLogger(MailingList.class); private static final Logger LOG = LoggerFactory.getLogger(MailingList.class);
private static final String IMAP_HOST = "imap_host"; private static final String IMAP_HOST = "imap_host";
private static final String IMAP_PORT = "imap_port"; private static final String IMAP_PORT = "imap_port";
@ -47,10 +54,11 @@ public class MailingList implements MessageHandler {
public static final int STATE_REPLY_TO_LIST = 32; // set REPLY TO field to list address? public static final int STATE_REPLY_TO_LIST = 32; // set REPLY TO field to list address?
public static final int STATE_OPEN_FOR_GUESTS = 64; // allow anyone to send via this list? public static final int STATE_OPEN_FOR_GUESTS = 64; // allow anyone to send via this list?
public static final int STATE_PUBLIC_ARCHIVE = 128; // save received messages in archive? public static final int STATE_PUBLIC_ARCHIVE = 128; // save received messages in archive?
public static final int STATE_OPEN_FOR_MODS = 256; // allow mods to send via this list? public static final int STATE_OPEN_FOR_SUBSCRIBERS = 256; // allow mods to send via this list?
public static final int STATE_MODS_CAN_CREATE_MODS = 512; // allow mods to make subscribers to mods?
private static final int VISIBLE = 1; private static final int VISIBLE = 1;
private static final int HIDDEN = 0; private static final int HIDDEN = 0;
private static final int DEFAULT_STATE = STATE_PENDING|STATE_HIDE_RECEIVERS|STATE_PUBLIC_ARCHIVE|STATE_OPEN_FOR_MODS; 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 RETAINED_FOLDER = "retained";
private final String name; private final String name;
private final String email; private final String email;
@ -227,6 +235,20 @@ public class MailingList implements MessageHandler {
return setFlag(STATE_HIDE_RECEIVERS,hide); return setFlag(STATE_HIDE_RECEIVERS,hide);
} }
public boolean isAllowedSender(String senderEmail){
if (senderEmail == null || senderEmail.isBlank()) return false;
try {
var user = User.load(senderEmail);
if (user == null) return this.isOpenForGuests();
var member = ListMember.load(this,user);
if (member == null) return this.isOpenForGuests();
if (member.isModerator()) return true;
if (member.isSubscriber()) return this.isOpenForSubscribers();
} catch (SQLException e) {
LOG.warn("Failed to load User for {}",senderEmail,e);
}
return this.isOpenForGuests();
}
/** /**
* test, whether the current ML is subscribable by a given user * test, whether the current ML is subscribable by a given user
* @param user * @param user
@ -244,6 +266,14 @@ public class MailingList implements MessageHandler {
} }
} }
public boolean isOpenForGuests(){
return hasState(STATE_OPEN_FOR_GUESTS);
}
public boolean isOpenForSubscribers(){
return hasState(STATE_OPEN_FOR_GUESTS|STATE_OPEN_FOR_SUBSCRIBERS);
}
/** /**
* Load a ML object by it's identifying email address. * Load a ML object by it's identifying email address.
* This is a cached method: if the ML has been loaded before, the already-loaded object will be returned. * This is a cached method: if the ML has been loaded before, the already-loaded object will be returned.
@ -334,7 +364,7 @@ public class MailingList implements MessageHandler {
Address from = message.getFrom()[0]; Address from = message.getFrom()[0];
if (from instanceof InternetAddress internetAddress){ if (from instanceof InternetAddress internetAddress){
var senderEmail = ((InternetAddress) from).getAddress(); var senderEmail = ((InternetAddress) from).getAddress();
if (!hasState(STATE_OPEN_FOR_GUESTS) && !this.hashMember(senderEmail)){ if (!isAllowedSender(senderEmail)) {
retainMessage(message); retainMessage(message);
sentRetentionNotification(senderEmail); sentRetentionNotification(senderEmail);
return; return;
@ -344,10 +374,14 @@ public class MailingList implements MessageHandler {
forward(message); forward(message);
} }
public MailingList open(boolean open) throws SQLException { public MailingList openForGuests(boolean open) throws SQLException {
return setFlag(STATE_OPEN_FOR_GUESTS,open); return setFlag(STATE_OPEN_FOR_GUESTS,open);
} }
public MailingList openForSubscribers(boolean open) throws SQLException {
return setFlag(STATE_OPEN_FOR_SUBSCRIBERS,open);
}
/** /**
* provide the set of mailing lists that are publicy open to subscriptions * provide the set of mailing lists that are publicy open to subscriptions
* @return * @return
@ -490,7 +524,8 @@ public class MailingList implements MessageHandler {
if (hasState(STATE_FORWARD_ATTACHED)) map.put("forward_attached",HIDDEN); if (hasState(STATE_FORWARD_ATTACHED)) map.put("forward_attached",HIDDEN);
if (hasState(STATE_HIDE_RECEIVERS)) map.put("hide_receivers",HIDDEN); if (hasState(STATE_HIDE_RECEIVERS)) map.put("hide_receivers",HIDDEN);
if (hasState(STATE_REPLY_TO_LIST)) map.put("reply_to_list",HIDDEN); if (hasState(STATE_REPLY_TO_LIST)) map.put("reply_to_list",HIDDEN);
if (hasState(STATE_OPEN_FOR_GUESTS)) map.put("open",VISIBLE); if (hasState(STATE_OPEN_FOR_GUESTS)) map.put("open_for_guests",HIDDEN);
if (hasState(STATE_OPEN_FOR_SUBSCRIBERS)) map.put("open_for_subscribers",HIDDEN);
if (hasState(STATE_PUBLIC_ARCHIVE)) map.put("archive",VISIBLE); if (hasState(STATE_PUBLIC_ARCHIVE)) map.put("archive",VISIBLE);
return map; return map;
} }

40
src/main/java/de/srsoftware/widerhall/web/Rest.java

@ -21,6 +21,7 @@ import java.util.Map;
import static de.srsoftware.widerhall.Constants.*; import static de.srsoftware.widerhall.Constants.*;
import static de.srsoftware.widerhall.Util.t; import static de.srsoftware.widerhall.Util.t;
import static de.srsoftware.widerhall.data.MailingList.*;
public class Rest extends HttpServlet { public class Rest extends HttpServlet {
private static final Logger LOG = LoggerFactory.getLogger(Rest.class); private static final Logger LOG = LoggerFactory.getLogger(Rest.class);
@ -56,6 +57,19 @@ public class Rest extends HttpServlet {
return Map.of(SUCCESS,"Updated user permissions"); return Map.of(SUCCESS,"Updated user permissions");
} }
private List<? extends Object> archive(HttpServletRequest req) {
var list = Util.getMailingList(req);
if (list != null){
try {
return Post.find(list).stream().map(Post::safeMap).toList();
} catch (SQLException e) {
e.printStackTrace();
}
}
LOG.debug("list: {}",list.email());
return List.of();
}
@Override @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String error = handleGet(req, resp); String error = handleGet(req, resp);
@ -144,18 +158,7 @@ public class Rest extends HttpServlet {
} }
} }
private List<? extends Object> archive(HttpServletRequest req) {
var list = Util.getMailingList(req);
if (list != null){
try {
return Post.find(list).stream().map(Post::safeMap).toList();
} catch (SQLException e) {
e.printStackTrace();
}
}
LOG.debug("list: {}",list.email());
return List.of();
}
public String handlePost(HttpServletRequest req, HttpServletResponse resp){ public String handlePost(HttpServletRequest req, HttpServletResponse resp){
@ -232,12 +235,13 @@ public class Rest extends HttpServlet {
private Map listDetail(MailingList list, User user) { private Map listDetail(MailingList list, User user) {
if (list == null) return Map.of(ERROR,"no list email provided!"); if (list == null) return Map.of(ERROR,"no list email provided!");
var map = new HashMap<>(); var map = new HashMap<>();
if (list.hasState(MailingList.STATE_FORWARD_FROM)) map.put("forward_from",true); if (list.hasState(MailingList.STATE_FORWARD_FROM)) map.put(KEY_FORWARD_FROM,true);
if (list.hasState(MailingList.STATE_FORWARD_ATTACHED)) map.put("forward_attached",true); if (list.hasState(MailingList.STATE_FORWARD_ATTACHED)) map.put(KEY_FORWARD_ATTACHED,true);
if (list.hasState(MailingList.STATE_HIDE_RECEIVERS)) map.put("hide_receivers",true); if (list.hasState(MailingList.STATE_HIDE_RECEIVERS)) map.put(KEY_HIDE_RECEIVERS,true);
if (list.hasState(MailingList.STATE_REPLY_TO_LIST)) map.put("reply_to_list",true); if (list.hasState(MailingList.STATE_REPLY_TO_LIST)) map.put(KEY_REPLY_TO_LIST,true);
if (list.hasState(MailingList.STATE_OPEN_FOR_GUESTS)) map.put("open",true); if (list.isOpenForGuests()) map.put(KEY_OPEN_FOR_GUESTS,true);
if (list.hasState(MailingList.STATE_PUBLIC_ARCHIVE)) map.put("archive",true); if (list.isOpenForSubscribers()) map.put(KEY_OPEN_FOR_SUBSCRIBERS,true);
if (list.hasState(MailingList.STATE_PUBLIC_ARCHIVE)) map.put(KEY_ARCHIVE,true);
return map; return map;
} }

14
src/main/java/de/srsoftware/widerhall/web/Web.java

@ -21,6 +21,7 @@ import java.util.Map;
import static de.srsoftware.widerhall.Constants.*; import static de.srsoftware.widerhall.Constants.*;
import static de.srsoftware.widerhall.Util.t; import static de.srsoftware.widerhall.Util.t;
import static de.srsoftware.widerhall.data.MailingList.*;
public class Web extends TemplateServlet { public class Web extends TemplateServlet {
public static final String WEB_ROOT = "/web"; public static final String WEB_ROOT = "/web";
@ -300,12 +301,13 @@ public class Web extends TemplateServlet {
if (!error){ if (!error){
try { try {
list.forwardFrom(Util.getCheckbox(req, "forward_from")) list.forwardFrom(Util.getCheckbox(req, KEY_FORWARD_FROM))
.forwardAttached(Util.getCheckbox(req, "forward_attached")) .forwardAttached(Util.getCheckbox(req, KEY_FORWARD_ATTACHED))
.hideReceivers(Util.getCheckbox(req, "hide_receivers")) .hideReceivers(Util.getCheckbox(req, KEY_HIDE_RECEIVERS))
.replyToList(Util.getCheckbox(req, "reply_to_list")) .replyToList(Util.getCheckbox(req, KEY_REPLY_TO_LIST))
.open(Util.getCheckbox(req,"open")) .openForGuests(Util.getCheckbox(req,KEY_OPEN_FOR_GUESTS))
.archive(Util.getCheckbox(req,"archive")); .openForSubscribers(Util.getCheckbox(req,KEY_OPEN_FOR_SUBSCRIBERS))
.archive(Util.getCheckbox(req,KEY_ARCHIVE));
data.put(NOTES,t("Sucessfully updated MailingList!")); data.put(NOTES,t("Sucessfully updated MailingList!"));
} catch (SQLException e){ } catch (SQLException e){
LOG.warn("Failed to update MailingList:",e); LOG.warn("Failed to update MailingList:",e);

2
src/main/resources/logback.xml

@ -11,6 +11,6 @@
<appender-ref ref="STDOUT" /> <appender-ref ref="STDOUT" />
</root> </root>
<logger name="de.srsoftware" level="INFO" /> <logger name="de.srsoftware" level="DEBUG" />
</configuration> </configuration>

69
static/templates/inspect.st

@ -11,37 +11,54 @@
«userinfo()» «userinfo()»
«messages()» «messages()»
<h1>Widerhall '«data.list»' Details</h1> <h1>Widerhall '«data.list»' Details</h1>
«listmembers()»
<form method="POST"> <form method="POST">
<fieldset> <fieldset>
<legend>Options for «data.list»</legend> <legend>Settings</legend>
<label> <fieldset>
<input type="checkbox" name="forward_from"> <legend>Forward permissions</legend>
Forward using original sender <p>
</label> Who is allowed to distribute mails via «data.list»?
<label> </p>
<input type="checkbox" name="reply_to_list"> Oweners and Moderators
Set list adddress in "ReplyTo" header <label>
</label> <input type="checkbox" name="open_for_subscribers">
<label> All subscribers
<input type="checkbox" name="open"> </label>
Allow non-members to send mails via list (Danger!) <label>
</label> <input type="checkbox" name="open_for_guests">
<label> Everyone (i.e. non members, DANGER!)
<input type="checkbox" name="forward_attached"> </label>
Append original message as attachment </fieldset>
</label> <fieldset>
<label> <legend>Forward options</legend>
<input type="checkbox" name="hide_receivers"> <label>
Hide receivers (using BCC) <input type="checkbox" name="forward_from">
</label> Forward using original sender
<label> </label>
<input type="checkbox" name="archive"> <label>
Collect messages in public archive <input type="checkbox" name="reply_to_list">
</label> Set list adddress in "ReplyTo" header
</label>
<label>
<input type="checkbox" name="forward_attached">
Append original message as attachment
</label>
<label>
<input type="checkbox" name="hide_receivers">
Hide receivers (using BCC)
</label>
</fieldset>
<fieldset>
<legend>Archive options</legend>
<label>
<input type="checkbox" name="archive">
Collect messages in public archive
</label>
</fieldset>
<button type="submit">Save</button> <button type="submit">Save</button>
</fieldset> </fieldset>
</form> </form>
«listmembers()»
<script type="text/javascript"> <script type="text/javascript">
loadListDetail('«data.list»'); loadListDetail('«data.list»');
</script> </script>

11
static/templates/js.st

@ -74,12 +74,11 @@ function showListArchive(data){
} }
function showListDetail(data){ function showListDetail(data){
if (data.forward_from) $('input[name="forward_from"]').prop('checked',true); var options = ['forward_from','forward_attached','hide_receivers','reply_to_list','open_for_guests','open_for_subscribers','archive'];
if (data.forward_attached) $('input[name="forward_attached"]').prop('checked',true); options.forEach(function(option,index,array){
if (data.hide_receivers) $('input[name="hide_receivers"]').prop('checked',true); console.log(option,'→',data[option]);
if (data.reply_to_list) $('input[name="reply_to_list"]').prop('checked',true); if (data[option]) $('input[name="'+option+'"]').prop('checked',true);
if (data.open) $('input[name="open"]').prop('checked',true); });
if (data.archive) $('input[name="archive"]').prop('checked',true);
} }
function showListOfEditableLists(data){ function showListOfEditableLists(data){

Loading…
Cancel
Save