Drupal: zpráva od uživatele se před uložením prožene přes XSLT případně Tidy.
1.1 --- a/src/org/sonews/storage/DrupalMessage.java Thu Oct 20 09:59:04 2011 +0200
1.2 +++ b/src/org/sonews/storage/DrupalMessage.java Thu Oct 20 10:50:58 2011 +0200
1.3 @@ -43,6 +43,7 @@
1.4 import javax.mail.internet.MimeMessage;
1.5 import javax.mail.internet.MimeMultipart;
1.6 import javax.xml.transform.Transformer;
1.7 +import javax.xml.transform.TransformerException;
1.8 import javax.xml.transform.TransformerFactory;
1.9 import javax.xml.transform.stream.StreamResult;
1.10 import javax.xml.transform.stream.StreamSource;
1.11 @@ -76,7 +77,7 @@
1.12 * @param rs ResultSet containing message data. No {@link ResultSet#next()} will be called, just values from current row will be read.
1.13 * @param constructBody true if whole message should be constructed | false if we need only message headers (body will be dummy).
1.14 */
1.15 - public DrupalMessage(ResultSet rs, String myDomain, boolean constructBody) throws SQLException, UnsupportedEncodingException, MessagingException {
1.16 + public DrupalMessage(ResultSet rs, String myDomain, boolean constructBody) throws SQLException, UnsupportedEncodingException, MessagingException, TransformerException, IOException {
1.17 super(Session.getDefaultInstance(System.getProperties()));
1.18
1.19 groupID = rs.getLong("group_id");
1.20 @@ -99,7 +100,13 @@
1.21
1.22 /** XHTML part */
1.23 MimeBodyPart htmlPart = new MimeBodyPart();
1.24 - String xhtmlText = readXhtmlText(rs);
1.25 + String xhtmlText = readXhtmlText(
1.26 + rs.getString("text"),
1.27 + rs.getString("subject"),
1.28 + rs.getInt("parent_id"),
1.29 + rs.getString("urlBase"),
1.30 + rs.getString("wwwRead"),
1.31 + rs.getString("wwwPost"));
1.32 htmlPart.setContent(xhtmlText, XHTML_CONTENT_TYPE);
1.33
1.34 /** Plain text part */
1.35 @@ -172,60 +179,72 @@
1.36 }
1.37 }
1.38
1.39 - private String readXhtmlText(ResultSet rs) {
1.40 + private String readXhtmlText(String text, String subject, long parentId, String urlBase, String wwwRead, String wwwPost) throws TransformerException, IOException {
1.41 /**
1.42 * TODO:
1.43 * - znovupoužívat XSL transformér
1.44 * - používat cache, ukládat si vygenerované články
1.45 */
1.46 + String inputText = makeSimpleXHTML(text);
1.47 +
1.48 + TransformerFactory tf = TransformerFactory.newInstance();
1.49 + Transformer paragraphTransformer = tf.newTransformer(new StreamSource(Resource.getAsStream("helpers/mimeXhtmlPart-make-paragraphs.xsl")));
1.50 +
1.51 + String paragraphedText;
1.52 + boolean tidyWasUsed = false;
1.53 try {
1.54 - String inputText = makeSimpleXHTML(rs.getString("text"));
1.55 + StringReader input = new StringReader(inputText);
1.56 + StringWriter output = new StringWriter(2 * inputText.length());
1.57 + paragraphTransformer.transform(new StreamSource(input), new StreamResult(output));
1.58 + paragraphedText = output.toString();
1.59 + } catch (Exception e) {
1.60 + log.log(Level.FINER, "HTML input was shitty – Tidy had to be called.", e);
1.61 + StringReader input = new StringReader(tidyXhtml(inputText));
1.62 + StringWriter output = new StringWriter(2 * inputText.length());
1.63 + paragraphTransformer.transform(new StreamSource(input), new StreamResult(output));
1.64 + paragraphedText = output.toString();
1.65 + tidyWasUsed = true;
1.66 + }
1.67
1.68 - TransformerFactory tf = TransformerFactory.newInstance();
1.69 - Transformer paragraphTransformer = tf.newTransformer(new StreamSource(Resource.getAsStream("helpers/mimeXhtmlPart-make-paragraphs.xsl")));
1.70 + Transformer xhtmlTransformer = tf.newTransformer(new StreamSource(Resource.getAsStream("helpers/mimeXhtmlPart.xsl")));
1.71 + xhtmlTransformer.setParameter("isRoot", (parentId == 0));
1.72 + xhtmlTransformer.setParameter("title", subject);
1.73 + xhtmlTransformer.setParameter("urlBase", urlBase);
1.74 + xhtmlTransformer.setParameter("wwwRead", wwwRead);
1.75 + xhtmlTransformer.setParameter("wwwPost", wwwPost);
1.76 + xhtmlTransformer.setParameter("headComment", String.format("Drupal-NNTP bridge. Transformed: %1$tc. Tidy had to be used: %2$b", new Date(), tidyWasUsed));
1.77 + StringReader input = new StringReader(paragraphedText);
1.78 + StringWriter output = new StringWriter(2 * paragraphedText.length());
1.79 + xhtmlTransformer.transform(new StreamSource(input), new StreamResult(output));
1.80
1.81 - String paragraphedText;
1.82 - boolean tidyWasUsed = false;
1.83 - try {
1.84 - StringReader input = new StringReader(inputText);
1.85 - StringWriter output = new StringWriter(2 * inputText.length());
1.86 - paragraphTransformer.transform(new StreamSource(input), new StreamResult(output));
1.87 - paragraphedText = output.toString();
1.88 - } catch (Exception e) {
1.89 - log.log(Level.FINER, "HTML input was shitty – Tidy had to be called.", e);
1.90 - StringReader input = new StringReader(tidyXhtml(inputText));
1.91 - StringWriter output = new StringWriter(2 * inputText.length());
1.92 - paragraphTransformer.transform(new StreamSource(input), new StreamResult(output));
1.93 - paragraphedText = output.toString();
1.94 - tidyWasUsed = true;
1.95 - }
1.96 -
1.97 - Transformer xhtmlTransformer = tf.newTransformer(new StreamSource(Resource.getAsStream("helpers/mimeXhtmlPart.xsl")));
1.98 - xhtmlTransformer.setParameter("isRoot", (rs.getInt("parent_id") == 0));
1.99 - xhtmlTransformer.setParameter("title", rs.getString("subject"));
1.100 - xhtmlTransformer.setParameter("urlBase", rs.getString("urlBase"));
1.101 - xhtmlTransformer.setParameter("wwwRead", rs.getString("wwwRead"));
1.102 - xhtmlTransformer.setParameter("wwwPost", rs.getString("wwwPost"));
1.103 - xhtmlTransformer.setParameter("headComment", String.format("Drupal-NNTP bridge. Transformed: %1$tc. Tidy had to be used: %2$b", new Date(), tidyWasUsed));
1.104 - StringReader input = new StringReader(paragraphedText);
1.105 - StringWriter output = new StringWriter(2 * paragraphedText.length());
1.106 - xhtmlTransformer.transform(new StreamSource(input), new StreamResult(output));
1.107 -
1.108 - return output.toString();
1.109 - } catch (Exception e) {
1.110 - /**
1.111 - * TODO: lepší ošetření chyby
1.112 - */
1.113 - log.log(Level.WARNING, "Error while transforming article to XHTML", e);
1.114 - return makeSimpleXHTML("<p>Při transformaci příspěvku bohužel došlo k chybě.</p>");
1.115 - }
1.116 + return output.toString();
1.117 }
1.118
1.119 + /**
1.120 + * Does not parse XML works just with text.
1.121 + * @param body XHTML fragment that should be put between <body> and </body>
1.122 + * @return simple XHTML document (body wrapped in html and body tags)
1.123 + */
1.124 private static String makeSimpleXHTML(String body) {
1.125 return "<html xmlns=\"http://www.w3.org/1999/xhtml\"><body>" + body + "</body></html>";
1.126 }
1.127
1.128 /**
1.129 + * Does not parse XML works just with text.
1.130 + * @param xhtml whole XHTML page
1.131 + * @return content between <body> and </body> tags.
1.132 + */
1.133 + private static String makeFragmentXHTML(String xhtml) {
1.134 + final String startTag = "<body>";
1.135 + final String endTag = "</body>";
1.136 +
1.137 + int start = xhtml.indexOf(startTag) + startTag.length();
1.138 + int end = xhtml.lastIndexOf(endTag);
1.139 +
1.140 + return xhtml.substring(start, end);
1.141 + }
1.142 +
1.143 + /**
1.144 * TODO: refaktorovat, přesunout
1.145 */
1.146 private static String tidyXhtml(String inputText) throws IOException {
1.147 @@ -425,4 +444,33 @@
1.148 writeTo(baos, skipHeaders.toArray(new String[skipHeaders.size()]));
1.149 return baos.toByteArray();
1.150 }
1.151 +
1.152 + /**
1.153 + * Transforms message content to valid XHTML and strips html and body tags.
1.154 + * When receiving message from user through NNTP
1.155 + * this method is used to get text that should be saved into databse.
1.156 + * @return XHTML fragment – content between <body> and </body> tags.
1.157 + */
1.158 + public String getBodyXhtmlFragment() throws StorageBackendException {
1.159 + /**
1.160 + * TODO: podporovat i zprávy přímo v HTML a multipart.
1.161 + */
1.162 + try {
1.163 + Object c = getContent();
1.164 + if (isMimeType("text/plain") && c instanceof String) {
1.165 + String xhtml = readXhtmlText(
1.166 + (String) c,
1.167 + getSubject(),
1.168 + getParentID(),
1.169 + null,
1.170 + null,
1.171 + null);
1.172 + return makeFragmentXHTML(xhtml);
1.173 + } else {
1.174 + throw new StorageBackendException("Only text/plain messages are supported for now – post it as plain text please.");
1.175 + }
1.176 + } catch (Exception e) {
1.177 + throw new StorageBackendException(e);
1.178 + }
1.179 + }
1.180 }
2.1 --- a/src/org/sonews/storage/impl/DrupalDatabase.java Thu Oct 20 09:59:04 2011 +0200
2.2 +++ b/src/org/sonews/storage/impl/DrupalDatabase.java Thu Oct 20 10:50:58 2011 +0200
2.3 @@ -414,26 +414,16 @@
2.4 if (parentID == null || groupID == null) {
2.5 throw new StorageBackendException("No valid In-Reply-To header was found → rejecting posted message.");
2.6 } else {
2.7 - if (m.isMimeType("text/plain")) {
2.8 - Object content = m.getContent();
2.9 - if (content instanceof String) {
2.10 - String subject = m.getSubject();
2.11 - String text = (String) content;
2.12
2.13 - /**
2.14 - * TODO: validovat a transformovat text
2.15 - * (v současné době se o to stará až Drupal při výstupu)
2.16 - */
2.17 - if (subject == null || subject.length() < 1) {
2.18 - subject = text.substring(0, Math.min(10, text.length()));
2.19 - }
2.20 + String subject = m.getSubject();
2.21 + String text = m.getBodyXhtmlFragment();
2.22
2.23 - insertArticle(article.getAuthenticatedUser(), subject, text, parentID, groupID);
2.24 - log.log(Level.INFO, "User ''{0}'' has posted an article", article.getAuthenticatedUser());
2.25 - }
2.26 - } else {
2.27 - throw new StorageBackendException("Only text/plain messages are supported for now – post it as plain text please.");
2.28 + if (subject == null || subject.length() < 1) {
2.29 + subject = text.substring(0, Math.min(10, text.length()));
2.30 }
2.31 +
2.32 + insertArticle(article.getAuthenticatedUser(), subject, text, parentID, groupID);
2.33 + log.log(Level.INFO, "User ''{0}'' has posted an article", article.getAuthenticatedUser());
2.34 }
2.35 } catch (Exception e) {
2.36 throw new StorageBackendException(e);