diff --git a/src/main/java/de/srsoftware/widerhall/data/Database.java b/src/main/java/de/srsoftware/widerhall/data/Database.java index c8e4288..f5b2d20 100644 --- a/src/main/java/de/srsoftware/widerhall/data/Database.java +++ b/src/main/java/de/srsoftware/widerhall/data/Database.java @@ -127,6 +127,53 @@ public class Database { return sql.toString(); } + @Override + public String toString() { + StringBuffer sql = new StringBuffer(this.sql); + + if (!setValues.isEmpty()){ + var keys = new ArrayList(); + var expressions = new ArrayList(); + for (var entry : setValues.entrySet()) expressions.add(entry.getKey()+" = entry.getValue()"); + sql.append(" SET ").append(String.join(", ",expressions)); + } + + if (!values.isEmpty()){ + var keys = new ArrayList(); + var vals = new ArrayList(); + for (var entry : values.entrySet()) { + keys.add(entry.getKey()); + vals.add(entry.getValue().toString()); + } + sql.append("(") + .append(String.join(", ",keys)) + .append(")") + .append(" VALUES ") + .append("(") + .append(String.join(",",vals)) + .append(")"); + } + + if (!where.isEmpty()){ + var clauses = new ArrayList(); + sql.append(" WHERE "); + + for (var entry : where.entrySet()) clauses.add("("+entry.getKey()+" IN ("+String.join(", ",entry.getValue().stream().map(Object::toString).toList())+"))"); + sql.append(String.join(" AND ",clauses)); + } + + return "Request{" + "sql=" + sql + '}'; + } + + public Request values(Map newValues) { + values.putAll(newValues); + return this; + } + + public Request values(String key, Object value) { + values.put(key,value); + return this; + } public Request where(String key, Object ... values) { for (var val : values) where(key,val); @@ -145,15 +192,6 @@ public class Database { return this; } - public Request values(Map newValues) { - values.putAll(newValues); - return this; - } - - public Request values(String key, Object value) { - values.put(key,value); - return this; - } } public Database(Connection connection) { diff --git a/src/main/java/de/srsoftware/widerhall/data/ListMember.java b/src/main/java/de/srsoftware/widerhall/data/ListMember.java index e990437..80dcb3e 100644 --- a/src/main/java/de/srsoftware/widerhall/data/ListMember.java +++ b/src/main/java/de/srsoftware/widerhall/data/ListMember.java @@ -5,6 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.stringtemplate.v4.ST; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; @@ -73,10 +74,9 @@ public class ListMember { public static Set listsOwnedBy(User user) { var list = new HashSet(); try { - var rs = Database.open().select(TABLE_NAME,LIST_EMAIL) - .where(USER_EMAIL,user.email()) - .where(STATE,STATE_OWNER) - .exec(); + var request = Database.open().select(TABLE_NAME, LIST_EMAIL, STATE+" & "+STATE_OWNER+" as "+STATE); + if (!user.is(ADMIN)) request = request.where(USER_EMAIL, user.email()).where(STATE, STATE_OWNER); + var rs = request.exec(); while (rs.next()) list.add(rs.getString(LIST_EMAIL)); } catch (SQLException e) { LOG.warn("Listing memberships lists failed: ",e); diff --git a/src/main/java/de/srsoftware/widerhall/data/MailingList.java b/src/main/java/de/srsoftware/widerhall/data/MailingList.java index 811be90..4652e2c 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 org.slf4j.LoggerFactory; import javax.mail.MessagingException; import java.io.UnsupportedEncodingException; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; @@ -92,14 +93,28 @@ public class MailingList { return openLists().stream().filter(ml -> ml.email.equals(list)).count() > 0; } - public static Set listsOf(User user) { - var list = openLists(); - Set keys = (user.is(ADMIN)) ? null : ListMember.listsOwnedBy(user); - if (keys == null || keys.isEmpty()) return list; - for (String key : keys) list.add(load(key)); + public static Set editableBy(User user) { + var list = new HashSet(); + for (String key : ListMember.listsOwnedBy(user)) list.add(load(key)); return list; } + private static MailingList from(ResultSet rs) throws SQLException { + String email = rs.getString(EMAIL); + var ml = lists.get(email); + if (ml == null) lists.put(email,ml = new MailingList(rs.getString(EMAIL), + rs.getString(NAME), + rs.getString(IMAP_HOST), + rs.getInt(IMAP_PORT), + rs.getString(IMAP_USER), + rs.getString(IMAP_PASS), + rs.getString(SMTP_HOST), + rs.getInt(SMTP_PORT), + rs.getString(SMTP_USER), + rs.getString(SMTP_PASS), + rs.getInt(STATE))); + return ml; + } public static MailingList load(String listEmail) { var ml = lists.get(listEmail); @@ -108,26 +123,22 @@ public class MailingList { .select(TABLE_NAME) .where(EMAIL,listEmail) .exec(); - if (rs.next()){ - ml = new MailingList(rs.getString(EMAIL), - rs.getString(NAME), - rs.getString(IMAP_HOST), - rs.getInt(IMAP_PORT), - rs.getString(IMAP_USER), - rs.getString(IMAP_PASS), - rs.getString(SMTP_HOST), - rs.getInt(SMTP_PORT), - rs.getString(SMTP_USER), - rs.getString(SMTP_PASS), - rs.getInt(STATE)); - lists.put(listEmail,ml); - } + if (rs.next()) lists.put(listEmail,ml = MailingList.from(rs)); } catch (SQLException e) { LOG.debug("Failed to load MailingList: ",e); } return ml; } + public HashMap minimalMap() { + var map = new HashMap(); + String[] parts = email.split("@", 2); + map.put(EMAIL,Map.of(PREFIX,parts[0],DOMAIN,parts[1])); + map.put(NAME, name); + map.put(STATE, stateString(state)); + return map; + } + public String name(){ return name; } @@ -151,17 +162,13 @@ public class MailingList { public Map safeMap() { - var map = new HashMap(); - String[] parts = email.split("@", 2); - map.put(EMAIL,Map.of(PREFIX,parts[0],DOMAIN,parts[1])); - map.put(NAME, name); + var map = minimalMap(); if (imapHost != null) map.put(IMAP_HOST, imapHost); if (imapPort != 0) map.put(IMAP_PORT, imapPort); if (imapUser != null) map.put(IMAP_USER, imapUser); if (smtp.host() != null) map.put(SMTP_HOST, smtp.host()); if (smtp.port() != 0) map.put(SMTP_PORT, smtp.port()); if (smtp.username() != null) map.put(SMTP_USER, smtp.username()); - map.put(STATE, stateString(state)); return map; } @@ -200,6 +207,32 @@ public class MailingList { return String.join(", ", states); } + public static Set subscribable() { + return subscribable(null); + } + + public static Set subscribable(User user) { + try { + if (user == null) return openLists(); + if (user.is(ADMIN)) { + var rs = Database.open().select(TABLE_NAME).exec(); + var result = new HashSet(); + while (rs.next()) result.add(MailingList.from(rs)); + rs.close(); + return result; + } + var listEmails = ListMember.listsOwnedBy(user); + var rs = Database.open().select(TABLE_NAME).where(EMAIL, listEmails).exec(); + var result = openLists(); + while (rs.next()) result.add(MailingList.from(rs)); + rs.close(); + return result; + } catch (SQLException e) { + LOG.warn("Failed to read subscribable mailinglists for {}",user,e); + return Set.of(); + } + } + public void requestSubscription(User user, boolean skipConfirmation) throws SQLException, MessagingException { var state = skipConfirmation ? ListMember.STATE_SUBSCRIBER : ListMember.STATE_AWAITING_CONFIRMATION; var member = ListMember.create(this,user,state); @@ -218,4 +251,6 @@ public class MailingList { var text = t("If you received this mail, the SMTP settings of your mailing list are correct."); smtp.login().send(email(),name(),user.email(),subject,text); } + + } diff --git a/src/main/java/de/srsoftware/widerhall/web/Rest.java b/src/main/java/de/srsoftware/widerhall/web/Rest.java index 54363b2..4475ab0 100644 --- a/src/main/java/de/srsoftware/widerhall/web/Rest.java +++ b/src/main/java/de/srsoftware/widerhall/web/Rest.java @@ -25,13 +25,14 @@ import static de.srsoftware.widerhall.Util.t; public class Rest extends HttpServlet { private static final Logger LOG = LoggerFactory.getLogger(Rest.class); - private static final String LIST_LIST = "list/list"; private static final String LIST_DISABLE = "list/disable"; + private static final String LIST_EDITABLE = "list/editable"; private static final String LIST_ENABLE = "list/enable"; private static final String LIST_HIDE = "list/hide"; private static final String LIST_MEMBERS = "list/members"; private static final String LIST_SHOW = "list/show"; private static final String LIST_TEST = "list/test"; + private static final String LIST_SUBSCRIBABLE = "list/subscribable"; private static final String USER_LIST = "user/list"; private static final String MEMBERS = "members"; private static final String SUCCESS = "success"; @@ -64,17 +65,19 @@ public class Rest extends HttpServlet { json.put(ERROR,"failed to load user list"); } break; - case LIST_LIST: - json.put("lists", MailingList.listsOf(user).stream().map(MailingList::safeMap).toList()); + case LIST_EDITABLE: + json.put("lists", MailingList.editableBy(user).stream().map(MailingList::safeMap).toList()); break; + case LIST_SUBSCRIBABLE: + json.put("lists", MailingList.subscribable(user).stream().map(MailingList::minimalMap).toList()); default: json.put(ERROR,t("No handler for path '{}'!",path)); break; } } else { switch (path) { - case LIST_LIST: - json.put("lists", MailingList.openLists().stream().map(MailingList::safeMap).toList()); + case LIST_SUBSCRIBABLE: + json.put("lists", MailingList.subscribable().stream().map(MailingList::minimalMap).toList()); break; default: json.put(ERROR,"Not logged in!"); diff --git a/src/main/java/de/srsoftware/widerhall/web/Web.java b/src/main/java/de/srsoftware/widerhall/web/Web.java index 1dddb2c..f72468a 100644 --- a/src/main/java/de/srsoftware/widerhall/web/Web.java +++ b/src/main/java/de/srsoftware/widerhall/web/Web.java @@ -90,6 +90,11 @@ public class Web extends HttpServlet { return loadTemplate(ADD_LIST,data,resp); } + if (!Util.isEmail(email)){ + data.put(ERROR,t("List email ({}) is not a valid email address!",email)); + return loadTemplate(ADD_LIST,data,resp); + } + if (imapHost == null || imapHost.isBlank() || imapUser == null || imapUser.isBlank() || imapPass == null || imapPass.isBlank()) { data.put(ERROR,"IMAP credentials are required!"); return loadTemplate(ADD_LIST,data,resp); diff --git a/static/templates/js.st b/static/templates/js.st index 0c034fd..349eb1c 100644 --- a/static/templates/js.st +++ b/static/templates/js.st @@ -14,12 +14,12 @@ function hideList(listEmail){ $.post('/api/list/hide',{list:listEmail},showListResult,'json'); } -function loadListAdminList(){ - $.getJSON('/api/list/list', showListAdminList); +function loadListOfEditableLists(){ + $.getJSON('/api/list/editable', showListOfEditableLists); } -function loadListList(){ - $.getJSON('/api/list/list', showListList); +function loadListOfSubscribableLists(){ + $.getJSON('/api/list/subscribable', showListList); } function loadMembers(listEmail){ @@ -38,7 +38,7 @@ function showList(listEmail){ $.post('/api/list/show',{list:listEmail},showListResult,'json'); } -function showListAdminList(data){ +function showListOfEditableLists(data){ for (let i in data.lists){ let list = data.lists[i]; let row = $(''); diff --git a/static/templates/listadminlist.st b/static/templates/listadminlist.st index f9d199b..1ddb358 100644 --- a/static/templates/listadminlist.st +++ b/static/templates/listadminlist.st @@ -21,6 +21,6 @@ Add new mailing list \ No newline at end of file diff --git a/static/templates/listlist.st b/static/templates/listlist.st index 357fa4c..44b32e5 100644 --- a/static/templates/listlist.st +++ b/static/templates/listlist.st @@ -9,6 +9,6 @@ \ No newline at end of file