diff --git a/src/main/java/de/srsoftware/widerhall/Constants.java b/src/main/java/de/srsoftware/widerhall/Constants.java index 9ec1e0c..8db0b68 100644 --- a/src/main/java/de/srsoftware/widerhall/Constants.java +++ b/src/main/java/de/srsoftware/widerhall/Constants.java @@ -2,6 +2,7 @@ package de.srsoftware.widerhall; public class Constants { public static final String ADMIN = "Admin"; + public static final String BASE_URL = "base_url"; public static final String EMAIL = "email"; public static final String ERROR = "error"; public static final String HOST = "host"; @@ -14,11 +15,11 @@ public class Constants { public static final String PASSWORD = "password"; public static final Object PORT = "port"; public static final String PROTOCOL = "mail.store.protocol"; + public static final String STATE = "state"; public static final String USER = "user"; public static final String VARCHAR = "VARCHAR(255)"; - public static final String BASE_URL = "base_url"; public static final String DB = "database"; public static final String BASE = "base"; public static final String CONFIG = "configuration"; diff --git a/src/main/java/de/srsoftware/widerhall/data/Database.java b/src/main/java/de/srsoftware/widerhall/data/Database.java index e2307df..99b4980 100644 --- a/src/main/java/de/srsoftware/widerhall/data/Database.java +++ b/src/main/java/de/srsoftware/widerhall/data/Database.java @@ -143,6 +143,7 @@ public class Database { private Database assertTables() throws SQLException { if (!tableExists(User.TABLE_NAME)) User.createTable(); if (!tableExists(MailingList.TABLE_NAME)) MailingList.createTable(); + if (!tableExists(ListMember.TABLE_NAME)) ListMember.createTable(); return this; } diff --git a/src/main/java/de/srsoftware/widerhall/data/ListMember.java b/src/main/java/de/srsoftware/widerhall/data/ListMember.java new file mode 100644 index 0000000..e51842f --- /dev/null +++ b/src/main/java/de/srsoftware/widerhall/data/ListMember.java @@ -0,0 +1,33 @@ +package de.srsoftware.widerhall.data; + +import java.sql.SQLException; + +import static de.srsoftware.widerhall.Constants.INT; +import static de.srsoftware.widerhall.Constants.VARCHAR; + +public class ListMember { + public static final String TABLE_NAME = "ListMembers"; + private static final String LIST_EMAIL = "list_email"; + private static final String USER_EMAIL = "user_email"; + private static final String STATE = "state"; + private final String listEmail; + private final String userEmail; + private final int state; + + public ListMember(String listEmail, String userEmail, int state){ + this.listEmail = listEmail; + this.userEmail = userEmail; + this.state = state; + } + + public static void createTable() throws SQLException { + var sql = new StringBuilder() + .append("CREATE TABLE ").append(TABLE_NAME) + .append(" (") + .append(LIST_EMAIL).append(" ").append(VARCHAR).append(", ") + .append(USER_EMAIL).append(" ").append(VARCHAR).append(", ") + .append(STATE).append(" ").append(INT).append(", ") + .append("PRIMARY KEY (").append(LIST_EMAIL).append(", ").append(USER_EMAIL).append("));"); + Database.open().query(sql.toString()).run(); + } +} diff --git a/src/main/java/de/srsoftware/widerhall/data/MailingList.java b/src/main/java/de/srsoftware/widerhall/data/MailingList.java index 694d036..bb3d7d6 100644 --- a/src/main/java/de/srsoftware/widerhall/data/MailingList.java +++ b/src/main/java/de/srsoftware/widerhall/data/MailingList.java @@ -4,6 +4,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import static de.srsoftware.widerhall.Constants.*; @@ -18,17 +20,29 @@ public class MailingList { private static final String SMTP_PORT = "smtp_port"; private static final String SMTP_USER = "smtp_user"; private static final String SMTP_PASS = "smtp_pass"; + private static final int ENABLED = 1; private final String name; private final String email; public static final String TABLE_NAME = "Lists"; + private final String imapPass,smtpPass,imapHost,smtpHost,imapUser,smtpUser; + private final int imapPort,smtpPort,state; - public MailingList(String email, String name){ + public MailingList(String email, String name, String imapHost, int imapPort, String imapUser, String imapPass, String smtpHost, int smtpPort, String smtpUser, String smtpPass, int state){ this.email = email; this.name = name; + this.imapHost = imapHost; + this.imapPort = imapPort; + this.imapUser = imapUser; + this.imapPass = imapPass; + this.smtpHost = smtpHost; + this.smtpPort = smtpPort; + this.smtpUser = smtpUser; + this.smtpPass = smtpPass; + this.state = state; } - public static MailingList create(String email, String name) throws SQLException { - return new MailingList(email,name).save(); + public static MailingList create(String email, String name, String imapHost, int imapPort, String imapUser, String imapPass, String smtpHost, int smtpPort, String smtpUser, String smtpPass) throws SQLException { + return new MailingList(email,name,imapHost,imapPort,imapUser,imapPass,smtpHost,smtpPort,smtpUser,smtpPass,ENABLED).save(); } public static void createTable() throws SQLException { @@ -36,22 +50,75 @@ public class MailingList { .append("CREATE TABLE ").append(TABLE_NAME) .append(" (") .append(EMAIL).append(" ").append(VARCHAR).append(" NOT NULL PRIMARY KEY, ") - .append(NAME).append(" ").append(VARCHAR) - .append(IMAP_HOST).append(" ").append(VARCHAR) - .append(IMAP_PORT).append(" ").append(INT) - .append(IMAP_USER).append(" ").append(VARCHAR) - .append(IMAP_PASS).append(" ").append(VARCHAR) - .append(SMTP_HOST).append(" ").append(VARCHAR) - .append(SMTP_PORT).append(" ").append(INT) - .append(SMTP_USER).append(" ").append(VARCHAR) - .append(SMTP_PASS).append(" ").append(VARCHAR) + .append(NAME).append(" ").append(VARCHAR).append(", ") + .append(IMAP_HOST).append(" ").append(VARCHAR).append(", ") + .append(IMAP_PORT).append(" ").append(INT).append(", ") + .append(IMAP_USER).append(" ").append(VARCHAR).append(", ") + .append(IMAP_PASS).append(" ").append(VARCHAR).append(", ") + .append(SMTP_HOST).append(" ").append(VARCHAR).append(", ") + .append(SMTP_PORT).append(" ").append(INT).append(", ") + .append(SMTP_USER).append(" ").append(VARCHAR).append(", ") + .append(SMTP_PASS).append(" ").append(VARCHAR).append(", ") + .append(STATE).append(" ").append(INT) .append(");"); Database.open().query(sql.toString()).run(); } + public static List listsOf(User user) { + var list = new ArrayList(); + try { + var rs = Database.open().query("SELECT * FROM "+TABLE_NAME).exec(); + while (rs.next()){ + var email = rs.getString(EMAIL); + var name = rs.getString(NAME); + var imapHost = rs.getString(IMAP_HOST); + var imapPort = rs.getInt(IMAP_PORT); + var imapUser = rs.getString(IMAP_USER); + var imapPass = rs.getString(IMAP_PASS); + var smtpHost = rs.getString(SMTP_HOST); + var smtpPort = rs.getInt(SMTP_PORT); + var smtpUser = rs.getString(SMTP_USER); + var smtpPass = rs.getString(SMTP_PASS); + var state = rs.getInt(STATE); + list.add(new MailingList(email,name,imapHost,imapPort,imapUser,imapPass,smtpHost,smtpPort,smtpUser,smtpPass,state)); + } + } catch (SQLException e) { + LOG.warn("Listing mailing lists failed: ",e); + } + return list; + } + + + public Map safeMap() { + return Map.of(EMAIL,email,NAME,name, + IMAP_HOST,imapHost,IMAP_PORT,imapPort,IMAP_USER,imapUser, + SMTP_HOST,smtpHost,SMTP_PORT,smtpPort,SMTP_USER,smtpUser, + STATE,stateName(state)); + } + + private static String stateName(int state) { + switch (state){ + case ENABLED: + return "enabled"; + default: + return "disabled"; + } + } + private MailingList save() throws SQLException { Database.open().insertInto(TABLE_NAME) - .values(Map.of(EMAIL,email,NAME,name)) + .values(Map.ofEntries( + Map.entry(EMAIL,email), + Map.entry(NAME,name), + Map.entry(IMAP_HOST,imapHost), + Map.entry(IMAP_PORT,imapPort), + Map.entry(IMAP_USER,imapUser), + Map.entry(IMAP_PASS,imapPass), + Map.entry(SMTP_HOST,smtpHost), + Map.entry(SMTP_PORT,smtpPort), + Map.entry(SMTP_USER,smtpUser), + Map.entry(SMTP_PASS,smtpPass), + Map.entry(STATE,state))) .run(); return this; } diff --git a/src/main/java/de/srsoftware/widerhall/data/User.java b/src/main/java/de/srsoftware/widerhall/data/User.java index d37f0e1..6f02199 100644 --- a/src/main/java/de/srsoftware/widerhall/data/User.java +++ b/src/main/java/de/srsoftware/widerhall/data/User.java @@ -100,9 +100,6 @@ public class User { throw new InvalidKeyException(); } - public Map map() { - return Map.of(EMAIL,email,NAME,name); - } private boolean matching(String password) { return hashedPass.equals(Util.sha256(password+salt)); @@ -124,11 +121,14 @@ public class User { return false; } + public Map safeMap(){ + return Map.of(NAME,name,EMAIL,email,PASSWORD,hashedPassword() == null ? "no" : "yes"); + } + private User save() throws SQLException { Database.open().insertInto(TABLE_NAME) .values(Map.of(EMAIL,email,NAME,name,SALT,salt,HASHED_PASS,hashedPass)) .run(); return this; } - } diff --git a/src/main/java/de/srsoftware/widerhall/web/Rest.java b/src/main/java/de/srsoftware/widerhall/web/Rest.java index 5c68b6d..efc1637 100644 --- a/src/main/java/de/srsoftware/widerhall/web/Rest.java +++ b/src/main/java/de/srsoftware/widerhall/web/Rest.java @@ -1,5 +1,6 @@ package de.srsoftware.widerhall.web; +import de.srsoftware.widerhall.data.MailingList; import de.srsoftware.widerhall.data.User; import org.json.simple.JSONObject; import org.slf4j.Logger; @@ -10,15 +11,14 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.Collection; import java.util.List; -import java.util.Map; import static de.srsoftware.widerhall.Constants.*; 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 USER_LIST = "user/list"; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { @@ -31,13 +31,18 @@ public class Rest extends HttpServlet { JSONObject json = new JSONObject(); if (o instanceof User user){ var path = req.getPathInfo(); - json.put(USER,safeMapUser(user)); + json.put(USER,user.safeMap()); path = path == null ? INDEX : path.substring(1); switch (path) { case USER_LIST: - json.put("users", (user.is(ADMIN) ? User.list() : List.of(user)).stream().map(Rest::safeMapUser).toList()); + json.put("users", (user.is(ADMIN) ? User.list() : List.of(user)).stream().map(User::safeMap).toList()); + break; + case LIST_LIST: + json.put("lists", MailingList.listsOf(user).stream().map(MailingList::safeMap).toList()); + break; + default: + json.put(ERROR,t("No handler for path '{}'!",path)); break; - } } else { json.put(ERROR,"Not logged in!"); @@ -49,8 +54,4 @@ public class Rest extends HttpServlet { return t("Failed to handle request: {}",e.getMessage()); } } - - private static Map safeMapUser(User user){ - return Map.of(NAME,user.name(),EMAIL,user.email(),PASSWORD,user.hashedPassword() == null ? "no" : "yes"); - } } diff --git a/src/main/java/de/srsoftware/widerhall/web/Web.java b/src/main/java/de/srsoftware/widerhall/web/Web.java index 4f496ec..0f87626 100644 --- a/src/main/java/de/srsoftware/widerhall/web/Web.java +++ b/src/main/java/de/srsoftware/widerhall/web/Web.java @@ -2,6 +2,7 @@ package de.srsoftware.widerhall.web; import de.srsoftware.widerhall.Configuration; import de.srsoftware.widerhall.Util; +import de.srsoftware.widerhall.data.MailingList; import de.srsoftware.widerhall.data.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,11 +24,19 @@ import static de.srsoftware.widerhall.Constants.*; import static de.srsoftware.widerhall.Util.t; public class Web extends HttpServlet { - + private static final String ADD_LIST = "add_list"; private static final Logger LOG = LoggerFactory.getLogger(Web.class); private static final String LOGIN = "login"; private static final String LOGOUT = "logout"; private static final String REGISTER = "register"; + private static final String IMAP_HOST = "imap_host"; + private static final String IMAP_PORT = "imap_port"; + private static final String IMAP_USER = "imap_user"; + private static final String IMAP_PASS = "imap_pass"; + private static final String SMTP_HOST = "smtp_host"; + private static final String SMTP_PORT = "smtp_port"; + private static final String SMTP_USER = "smtp_user"; + private static final String SMTP_PASS = "smtp_pass"; private final String baseDir; private STGroup templates; private static final String WEB_ROOT = "/web"; @@ -38,6 +47,77 @@ public class Web extends HttpServlet { loadTemplates(); } + private String addList(HttpServletRequest req, HttpServletResponse resp) { + + var user = req.getSession().getAttribute(USER); + if (user == null) return redirectTo(LOGIN,resp); + var data = new HashMap(); + data.put(USER,user); + + var name = req.getParameter(NAME); + data.put(NAME,name); + + var email = req.getParameter(EMAIL); + data.put(EMAIL,email); + + var imapHost = req.getParameter(IMAP_HOST); + data.put(IMAP_HOST,imapHost); + var imapUser = req.getParameter(IMAP_USER); + data.put(IMAP_USER,imapUser); + var imapPass = req.getParameter(IMAP_PASS); + var smtpHost = req.getParameter(SMTP_HOST); + data.put(SMTP_HOST,smtpHost); + var smtpUser = req.getParameter(SMTP_USER); + data.put(SMTP_USER,smtpUser); + var smtpPass = req.getParameter(SMTP_PASS); + + Integer imapPort = 993; + data.put(IMAP_PORT,imapPort); + + Integer smtpPort = 465; + data.put(SMTP_PORT,smtpPort); + + if (name == null || name.isBlank() || email == null || email.isBlank()) { + data.put(ERROR,"List name and address are required!"); + 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); + } + + + try { + imapPort = Integer.parseInt(req.getParameter(IMAP_PORT)); + data.put(IMAP_PORT,imapPort); + } catch (NumberFormatException nfe){ + data.put(ERROR,t("'{}' is not a proper port number!",req.getParameter(IMAP_PORT))); + return loadTemplate(ADD_LIST,data,resp); + } + + if (smtpHost == null || smtpHost.isBlank() || smtpUser == null || smtpUser.isBlank() || smtpPass == null || smtpPass.isBlank()) { + data.put(ERROR,"SMTP credentials are required!"); + return loadTemplate(ADD_LIST,data,resp); + } + + try { + smtpPort = Integer.parseInt(req.getParameter(SMTP_PORT)); + data.put(SMTP_PORT,smtpPort); + } catch (NumberFormatException nfe){ + data.put(ERROR,t("'{}' is not a proper port number!",req.getParameter(SMTP_PORT))); + return loadTemplate(ADD_LIST,data,resp); + } + + try { + MailingList.create(email,name,imapHost,imapPort,imapUser,imapPass,smtpHost,smtpPort,smtpUser,smtpPass); + return redirectTo(INDEX,resp); + } catch (SQLException e) { + return t("Failed to create list '{}': {}",name,e.getMessage()); + } + } + + @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String error = handleGet(req, resp); @@ -80,7 +160,7 @@ public class Web extends HttpServlet { var o = req.getSession().getAttribute("user"); if (o instanceof User user){ var data = new HashMap(); - data.put(USER,user.map()); + data.put(USER,user.safeMap()); data.put(NOTES,notes); return loadTemplate(path,data,resp); } @@ -116,6 +196,8 @@ public class Web extends HttpServlet { return handleLogin(req,resp); case REGISTER: return registerUser(req,resp); + case ADD_LIST: + return addList(req,resp); } return t("No handler for path {}!",path); diff --git a/static/templates/add_list.st b/static/templates/add_list.st index be19384..bd91f0a 100644 --- a/static/templates/add_list.st +++ b/static/templates/add_list.st @@ -27,38 +27,38 @@
IMAP protocol
SMTP protocol
diff --git a/static/templates/js.st b/static/templates/js.st index 4c457a4..27ff0c1 100644 --- a/static/templates/js.st +++ b/static/templates/js.st @@ -1,7 +1,38 @@ +function dropList(email){ + console.log('dopList('+email+')'); +} +function loadListList(){ + $.getJSON("/api/list/list", showListList); +} + function loadUserList(){ $.getJSON("/api/user/list", showUserList); } +function showListList(data){ + for (let i in data.lists){ + let list = data.lists[i]; + let row = $(''); + let drop = $('