1.1 --- a/src/org/sonews/storage/impl/DrupalDatabase.java Wed Oct 19 21:40:51 2011 +0200
1.2 +++ b/src/org/sonews/storage/impl/DrupalDatabase.java Thu Oct 20 09:59:04 2011 +0200
1.3 @@ -28,12 +28,13 @@
1.4 import java.util.logging.Level;
1.5 import java.util.logging.Logger;
1.6 import org.sonews.config.Config;
1.7 -import org.sonews.daemon.Connections;
1.8 import org.sonews.feed.Subscription;
1.9 import org.sonews.storage.Article;
1.10 import org.sonews.storage.ArticleHead;
1.11 import org.sonews.storage.DrupalArticle;
1.12 import org.sonews.storage.DrupalMessage;
1.13 +import static org.sonews.storage.DrupalMessage.parseArticleID;
1.14 +import static org.sonews.storage.DrupalMessage.parseGroupID;
1.15 import org.sonews.storage.Group;
1.16 import org.sonews.storage.Storage;
1.17 import org.sonews.storage.StorageBackendException;
1.18 @@ -68,6 +69,18 @@
1.19 String password = Config.inst().get(Config.LEVEL_FILE, Config.STORAGE_PASSWORD, "");
1.20 conn = DriverManager.getConnection(url, username, password);
1.21
1.22 + /**
1.23 + * Kódování češtiny:
1.24 + * SET NAMES utf8 → dobrá čeština
1.25 + * Client characterset: utf8
1.26 + * Conn. characterset: utf8
1.27 + * SET CHARACTER SET utf8; → dobrá čeština jen pro SLECT, ale při volání funkce se zmrší
1.28 + * Client characterset: utf8
1.29 + * Conn. characterset: latin1
1.30 + *
1.31 + * Správné řešení:
1.32 + * V JDBC URL musí být: ?useUnicode=true&characterEncoding=UTF-8
1.33 + */
1.34 conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
1.35 if (conn.getTransactionIsolation() != Connection.TRANSACTION_SERIALIZABLE) {
1.36 log.warning("Database is NOT fully serializable!");
1.37 @@ -98,40 +111,6 @@
1.38 }
1.39 }
1.40
1.41 - /**
1.42 - *
1.43 - * @param messageID <{0}-{1}-{2}@domain.tld> where {0} is nntp_id and {1} is group_id and {2} is group_name
1.44 - * @return array where [0] = nntp_id and [1] = group_id and [2] = group_name or returns null if messageID is invalid
1.45 - */
1.46 - private static String[] parseMessageID(String messageID) {
1.47 - if (messageID.matches("<[0-9]+\\-[0-9]+\\-[a-z0-9\\.]+@.+>")) {
1.48 - return messageID.substring(1).split("@")[0].split("\\-");
1.49 - } else {
1.50 - return null;
1.51 - }
1.52 - }
1.53 -
1.54 - private static Long parseArticleID(String messageID) {
1.55 - String[] localPart = parseMessageID(messageID);
1.56 - if (localPart == null) {
1.57 - return null;
1.58 - } else {
1.59 - return Long.parseLong(localPart[0]);
1.60 - }
1.61 - }
1.62 -
1.63 - private static Long parseGroupID(String messageID) {
1.64 - String[] localPart = parseMessageID(messageID);
1.65 - if (localPart == null) {
1.66 - return null;
1.67 - } else {
1.68 - return Long.parseLong(localPart[1]);
1.69 - // If needed:
1.70 - // parseGroupName() will be same as this method, just with:
1.71 - // return localPart[2];
1.72 - }
1.73 - }
1.74 -
1.75 @Override
1.76 public List<Group> getGroups() throws StorageBackendException {
1.77 PreparedStatement ps = null;
1.78 @@ -397,7 +376,8 @@
1.79 * (but should not be thrown if only bad thing is wrong username or password)
1.80 */
1.81 @Override
1.82 - public boolean authenticateUser(String username, char[] password) throws StorageBackendException {
1.83 + public boolean authenticateUser(String username,
1.84 + char[] password) throws StorageBackendException {
1.85 PreparedStatement ps = null;
1.86 ResultSet rs = null;
1.87 try {
1.88 @@ -414,14 +394,81 @@
1.89 }
1.90 }
1.91
1.92 + /**
1.93 + * Validates article and if OK, calls {@link #insertArticle(java.lang.String, java.lang.String, java.lang.String, java.lang.Long, java.lang.Long) }
1.94 + * @param article
1.95 + * @throws StorageBackendException
1.96 + */
1.97 @Override
1.98 - public void addArticle(Article art) throws StorageBackendException {
1.99 - if (art.getAuthenticatedUser() == null) {
1.100 + public void addArticle(Article article) throws StorageBackendException {
1.101 + if (article.getAuthenticatedUser() == null) {
1.102 log.log(Level.SEVERE, "User was not authenticated, so his article was rejected.");
1.103 throw new StorageBackendException("User must be authenticated to post articles");
1.104 } else {
1.105 + try {
1.106 + DrupalMessage m = new DrupalMessage(article);
1.107
1.108 - log.log(Level.INFO, "User ''{0}'' has posted an article", art.getAuthenticatedUser());
1.109 + Long parentID = m.getParentID();
1.110 + Long groupID = m.getGroupID();
1.111 +
1.112 + if (parentID == null || groupID == null) {
1.113 + throw new StorageBackendException("No valid In-Reply-To header was found → rejecting posted message.");
1.114 + } else {
1.115 + if (m.isMimeType("text/plain")) {
1.116 + Object content = m.getContent();
1.117 + if (content instanceof String) {
1.118 + String subject = m.getSubject();
1.119 + String text = (String) content;
1.120 +
1.121 + /**
1.122 + * TODO: validovat a transformovat text
1.123 + * (v současné době se o to stará až Drupal při výstupu)
1.124 + */
1.125 + if (subject == null || subject.length() < 1) {
1.126 + subject = text.substring(0, Math.min(10, text.length()));
1.127 + }
1.128 +
1.129 + insertArticle(article.getAuthenticatedUser(), subject, text, parentID, groupID);
1.130 + log.log(Level.INFO, "User ''{0}'' has posted an article", article.getAuthenticatedUser());
1.131 + }
1.132 + } else {
1.133 + throw new StorageBackendException("Only text/plain messages are supported for now – post it as plain text please.");
1.134 + }
1.135 + }
1.136 + } catch (Exception e) {
1.137 + throw new StorageBackendException(e);
1.138 + }
1.139 + }
1.140 + }
1.141 +
1.142 + /**
1.143 + * Physically stores article in database.
1.144 + * @param subject
1.145 + * @param text
1.146 + * @param parentID
1.147 + * @param groupID
1.148 + */
1.149 + private void insertArticle(String sender, String subject, String text, Long parentID, Long groupID) throws StorageBackendException {
1.150 + PreparedStatement ps = null;
1.151 + ResultSet rs = null;
1.152 + try {
1.153 + ps = conn.prepareStatement("SELECT nntp_post_article(?, ?, ?, ?, ?)");
1.154 +
1.155 + ps.setString(1, sender);
1.156 + ps.setString(2, subject);
1.157 + ps.setString(3, text);
1.158 + ps.setLong(4, parentID);
1.159 + ps.setLong(5, groupID);
1.160 +
1.161 + rs = ps.executeQuery();
1.162 + rs.next();
1.163 +
1.164 + Long articleID = rs.getLong(1);
1.165 + log.log(Level.INFO, "Article was succesfully stored as {0}", articleID);
1.166 + } catch (Exception e) {
1.167 + throw new StorageBackendException(e);
1.168 + } finally {
1.169 + close(null, ps, rs);
1.170 }
1.171 }
1.172