package de.srsoftware.widerhall.data; import de.srsoftware.widerhall.Configuration; import de.srsoftware.widerhall.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.internet.InternetAddress; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import static de.srsoftware.widerhall.Constants.*; import static de.srsoftware.widerhall.Constants.VARCHAR; public class Post { public static final Logger LOG = LoggerFactory.getLogger(Post.class); public static final String TABLE_NAME = "Posts"; private static final String FROM_ADDR = "from_addr"; private static final String FROM_NAME = "from_name"; private static final String PARENT = "parent"; private static final String LONG = "LONG"; private static final String DATE = "date"; private static final String FILE = "file"; private static HashMap cache = new HashMap<>(); private String id, fromAddr, fromName, subject, filename; private MailingList list; private Post parent; private Long timestamp; public Post(String id, MailingList list, String fromAddr, String fromName, String subject, Long timestamp){ this.id = id; this.list = list; this.fromAddr = fromAddr; this.fromName = fromName; this.subject = subject; this.timestamp = timestamp; this.filename = generateFilename(); } public static Post create(MailingList list, Message message){ try { var id = message.getHeader("Message-ID")[0].replace("<", "").replace(">", ""); var addr = ((InternetAddress) message.getFrom()[0]); var fromEmail = addr.getAddress(); var fromName = addr.getPersonal(); if (fromName == null || fromName.isBlank()) fromName = fromEmail.split("@")[0] + "@xxxxxx"; var subject = message.getSubject(); var text = Util.getText(message); var time = message.getSentDate().getTime(); Post post = new Post(id,list,fromEmail,fromName,subject,time); var file = post.file(); file.getParentFile().mkdirs(); Files.writeString(file.toPath(),text, StandardCharsets.UTF_8); return post.save(); } catch (MessagingException | IOException | SQLException e) { LOG.warn("Failed to create post from {}",message); } return null; } /** * create posts table * @throws SQLException */ public static void createTable() throws SQLException { var sql = new StringBuilder() .append("CREATE TABLE ").append(TABLE_NAME) .append(" (") .append(ID).append(" ").append(VARCHAR).append(" NOT NULL PRIMARY KEY, ") .append(LIST).append(" ").append(VARCHAR).append(", ") .append(FROM_ADDR).append(" ").append(VARCHAR).append(", ") .append(FROM_NAME).append(" ").append(VARCHAR).append(", ") .append(PARENT).append(" ").append(VARCHAR).append(", ") .append(SUBJECT).append(" ").append(VARCHAR).append(", ") .append(DATE).append(" ").append(LONG).append(", ") .append(FILE).append(" ").append(VARCHAR) .append(");"); Database.open().query(sql).compile().run(); } public File file(){ return new File(filename); } public static ArrayList find(MailingList list, String month) throws SQLException { var rs = Database.open() .select(TABLE_NAME,"*","strftime('%Y-%m',date/1000,'unixepoch') as month") .where(LIST,list.email()) .where(MONTH,month) .sort(DATE) .compile() .exec(); try { var result = new ArrayList(); while (rs.next()) result.add(Post.from(rs)); return result; } finally { rs.close(); } } private static Post from(ResultSet rs) { try { var id = rs.getString(ID); var post = cache.get(id); if (post == null) { var list = MailingList.load(rs.getString(LIST)); post = new Post(id, list, rs.getString(FROM_ADDR), rs.getString(FROM_NAME), rs.getString(SUBJECT), rs.getLong(DATE)); post.filename = rs.getString(FILE); cache.put(id,post); } return post; } catch (SQLException e){ LOG.debug("Failed to load Post from database!",e); } return null; } private String generateFilename() { return Configuration.instance().archiveDir()+File.separator+id+".txt"; } public String id() { return id; } public static Post load(String id) throws SQLException { var rs = Database.open().select(TABLE_NAME).where(ID,id).compile().exec(); try { if (rs.next()) return Post.from(rs); } finally { rs.close(); } return null; } public Map map() { return Map.of(ID,id, LIST,list.email(), FROM_ADDR,fromAddr, FROM_NAME,fromName, SUBJECT,subject, DATE,timestamp, FILE,filename); } public Map safeMap() { return Map.of(ID,id, LIST,list.name(), FROM_NAME,fromName, SUBJECT,Util.dropEmail(subject), DATE, new Timestamp(timestamp).toString()); } private Post save() throws SQLException { Database.open().insertInto(TABLE_NAME).values(map()).compile().run(); return this; } public static Map summarize(MailingList list) throws SQLException { var sql = new StringBuilder("SELECT count(*) as count,strftime('%Y-%m',date/1000,'unixepoch') as month FROM Posts WHERE list = ? GROUP BY month ORDER BY month;"); var map = new TreeMap(); var rs = Database.open().query(sql).compile(list.email()).exec(); while (rs.next()) map.put(rs.getString("month"),rs.getInt("count")); rs.close(); return map; } public long timestamp(){ return timestamp; } }