# HG changeset patch # User František Kučera # Date 1319100658 -7200 # Node ID a788bf0e10801af0a670d359e5e15337cc3503d5 # Parent d843b4fee5dc222eafb777655d122adcb45278bf Drupal: zpráva od uživatele se před uložením prožene přes XSLT případně Tidy. diff -r d843b4fee5dc -r a788bf0e1080 src/org/sonews/storage/DrupalMessage.java --- a/src/org/sonews/storage/DrupalMessage.java Thu Oct 20 09:59:04 2011 +0200 +++ b/src/org/sonews/storage/DrupalMessage.java Thu Oct 20 10:50:58 2011 +0200 @@ -43,6 +43,7 @@ import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; @@ -76,7 +77,7 @@ * @param rs ResultSet containing message data. No {@link ResultSet#next()} will be called, just values from current row will be read. * @param constructBody true if whole message should be constructed | false if we need only message headers (body will be dummy). */ - public DrupalMessage(ResultSet rs, String myDomain, boolean constructBody) throws SQLException, UnsupportedEncodingException, MessagingException { + public DrupalMessage(ResultSet rs, String myDomain, boolean constructBody) throws SQLException, UnsupportedEncodingException, MessagingException, TransformerException, IOException { super(Session.getDefaultInstance(System.getProperties())); groupID = rs.getLong("group_id"); @@ -99,7 +100,13 @@ /** XHTML part */ MimeBodyPart htmlPart = new MimeBodyPart(); - String xhtmlText = readXhtmlText(rs); + String xhtmlText = readXhtmlText( + rs.getString("text"), + rs.getString("subject"), + rs.getInt("parent_id"), + rs.getString("urlBase"), + rs.getString("wwwRead"), + rs.getString("wwwPost")); htmlPart.setContent(xhtmlText, XHTML_CONTENT_TYPE); /** Plain text part */ @@ -172,60 +179,72 @@ } } - private String readXhtmlText(ResultSet rs) { + private String readXhtmlText(String text, String subject, long parentId, String urlBase, String wwwRead, String wwwPost) throws TransformerException, IOException { /** * TODO: * - znovupoužívat XSL transformér * - používat cache, ukládat si vygenerované články */ + String inputText = makeSimpleXHTML(text); + + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer paragraphTransformer = tf.newTransformer(new StreamSource(Resource.getAsStream("helpers/mimeXhtmlPart-make-paragraphs.xsl"))); + + String paragraphedText; + boolean tidyWasUsed = false; try { - String inputText = makeSimpleXHTML(rs.getString("text")); + StringReader input = new StringReader(inputText); + StringWriter output = new StringWriter(2 * inputText.length()); + paragraphTransformer.transform(new StreamSource(input), new StreamResult(output)); + paragraphedText = output.toString(); + } catch (Exception e) { + log.log(Level.FINER, "HTML input was shitty – Tidy had to be called.", e); + StringReader input = new StringReader(tidyXhtml(inputText)); + StringWriter output = new StringWriter(2 * inputText.length()); + paragraphTransformer.transform(new StreamSource(input), new StreamResult(output)); + paragraphedText = output.toString(); + tidyWasUsed = true; + } - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer paragraphTransformer = tf.newTransformer(new StreamSource(Resource.getAsStream("helpers/mimeXhtmlPart-make-paragraphs.xsl"))); + Transformer xhtmlTransformer = tf.newTransformer(new StreamSource(Resource.getAsStream("helpers/mimeXhtmlPart.xsl"))); + xhtmlTransformer.setParameter("isRoot", (parentId == 0)); + xhtmlTransformer.setParameter("title", subject); + xhtmlTransformer.setParameter("urlBase", urlBase); + xhtmlTransformer.setParameter("wwwRead", wwwRead); + xhtmlTransformer.setParameter("wwwPost", wwwPost); + xhtmlTransformer.setParameter("headComment", String.format("Drupal-NNTP bridge. Transformed: %1$tc. Tidy had to be used: %2$b", new Date(), tidyWasUsed)); + StringReader input = new StringReader(paragraphedText); + StringWriter output = new StringWriter(2 * paragraphedText.length()); + xhtmlTransformer.transform(new StreamSource(input), new StreamResult(output)); - String paragraphedText; - boolean tidyWasUsed = false; - try { - StringReader input = new StringReader(inputText); - StringWriter output = new StringWriter(2 * inputText.length()); - paragraphTransformer.transform(new StreamSource(input), new StreamResult(output)); - paragraphedText = output.toString(); - } catch (Exception e) { - log.log(Level.FINER, "HTML input was shitty – Tidy had to be called.", e); - StringReader input = new StringReader(tidyXhtml(inputText)); - StringWriter output = new StringWriter(2 * inputText.length()); - paragraphTransformer.transform(new StreamSource(input), new StreamResult(output)); - paragraphedText = output.toString(); - tidyWasUsed = true; - } - - Transformer xhtmlTransformer = tf.newTransformer(new StreamSource(Resource.getAsStream("helpers/mimeXhtmlPart.xsl"))); - xhtmlTransformer.setParameter("isRoot", (rs.getInt("parent_id") == 0)); - xhtmlTransformer.setParameter("title", rs.getString("subject")); - xhtmlTransformer.setParameter("urlBase", rs.getString("urlBase")); - xhtmlTransformer.setParameter("wwwRead", rs.getString("wwwRead")); - xhtmlTransformer.setParameter("wwwPost", rs.getString("wwwPost")); - xhtmlTransformer.setParameter("headComment", String.format("Drupal-NNTP bridge. Transformed: %1$tc. Tidy had to be used: %2$b", new Date(), tidyWasUsed)); - StringReader input = new StringReader(paragraphedText); - StringWriter output = new StringWriter(2 * paragraphedText.length()); - xhtmlTransformer.transform(new StreamSource(input), new StreamResult(output)); - - return output.toString(); - } catch (Exception e) { - /** - * TODO: lepší ošetření chyby - */ - log.log(Level.WARNING, "Error while transforming article to XHTML", e); - return makeSimpleXHTML("

Při transformaci příspěvku bohužel došlo k chybě.

"); - } + return output.toString(); } + /** + * Does not parse XML works just with text. + * @param body XHTML fragment that should be put between <body> and </body> + * @return simple XHTML document (body wrapped in html and body tags) + */ private static String makeSimpleXHTML(String body) { return "" + body + ""; } /** + * Does not parse XML works just with text. + * @param xhtml whole XHTML page + * @return content between <body> and </body> tags. + */ + private static String makeFragmentXHTML(String xhtml) { + final String startTag = ""; + final String endTag = ""; + + int start = xhtml.indexOf(startTag) + startTag.length(); + int end = xhtml.lastIndexOf(endTag); + + return xhtml.substring(start, end); + } + + /** * TODO: refaktorovat, přesunout */ private static String tidyXhtml(String inputText) throws IOException { @@ -425,4 +444,33 @@ writeTo(baos, skipHeaders.toArray(new String[skipHeaders.size()])); return baos.toByteArray(); } + + /** + * Transforms message content to valid XHTML and strips html and body tags. + * When receiving message from user through NNTP + * this method is used to get text that should be saved into databse. + * @return XHTML fragment – content between <body> and </body> tags. + */ + public String getBodyXhtmlFragment() throws StorageBackendException { + /** + * TODO: podporovat i zprávy přímo v HTML a multipart. + */ + try { + Object c = getContent(); + if (isMimeType("text/plain") && c instanceof String) { + String xhtml = readXhtmlText( + (String) c, + getSubject(), + getParentID(), + null, + null, + null); + return makeFragmentXHTML(xhtml); + } else { + throw new StorageBackendException("Only text/plain messages are supported for now – post it as plain text please."); + } + } catch (Exception e) { + throw new StorageBackendException(e); + } + } } diff -r d843b4fee5dc -r a788bf0e1080 src/org/sonews/storage/impl/DrupalDatabase.java --- a/src/org/sonews/storage/impl/DrupalDatabase.java Thu Oct 20 09:59:04 2011 +0200 +++ b/src/org/sonews/storage/impl/DrupalDatabase.java Thu Oct 20 10:50:58 2011 +0200 @@ -414,26 +414,16 @@ if (parentID == null || groupID == null) { throw new StorageBackendException("No valid In-Reply-To header was found → rejecting posted message."); } else { - if (m.isMimeType("text/plain")) { - Object content = m.getContent(); - if (content instanceof String) { - String subject = m.getSubject(); - String text = (String) content; - /** - * TODO: validovat a transformovat text - * (v současné době se o to stará až Drupal při výstupu) - */ - if (subject == null || subject.length() < 1) { - subject = text.substring(0, Math.min(10, text.length())); - } + String subject = m.getSubject(); + String text = m.getBodyXhtmlFragment(); - insertArticle(article.getAuthenticatedUser(), subject, text, parentID, groupID); - log.log(Level.INFO, "User ''{0}'' has posted an article", article.getAuthenticatedUser()); - } - } else { - throw new StorageBackendException("Only text/plain messages are supported for now – post it as plain text please."); + if (subject == null || subject.length() < 1) { + subject = text.substring(0, Math.min(10, text.length())); } + + insertArticle(article.getAuthenticatedUser(), subject, text, parentID, groupID); + log.log(Level.INFO, "User ''{0}'' has posted an article", article.getAuthenticatedUser()); } } catch (Exception e) { throw new StorageBackendException(e);