merge r46437 and r46946 from davisagli-features: respect the per-comment mime_type setting, and use the old cooked text/html from legacy comments when migrating
svn path=/plone.app.discussion/trunk/; revision=48356
This commit is contained in:
parent
bf5946367a
commit
eb004aab44
13
CHANGES.txt
13
CHANGES.txt
@ -4,6 +4,19 @@ Changelog
|
||||
2.0b1 (Unreleased)
|
||||
------------------
|
||||
|
||||
- Use the cooked text of legacy comments when migrating.
|
||||
[davisagli]
|
||||
|
||||
- Make sure that comment text is transformed to plain text when indexing.
|
||||
[davisagli]
|
||||
|
||||
- Move logic for transforming comment text to the Comment class's getText
|
||||
method. Use a comment instance's mime_type attribute in preference to the
|
||||
global setting for the source mimetype. Use text/x-html-safe as the target
|
||||
mimetype to make sure the safe HTML filter is applied, in case the source is
|
||||
untrusted HTML.
|
||||
[davisagli]
|
||||
|
||||
- Provide a filter_callback option to the migration view, so that a custom
|
||||
policy for which comments get migrated can be implemented.
|
||||
[davisagli]
|
||||
|
@ -80,7 +80,7 @@
|
||||
|
||||
<div class="commentBody">
|
||||
|
||||
<span tal:replace="structure python:view.cook(reply.getText())" />
|
||||
<span tal:replace="structure reply/getText" />
|
||||
|
||||
<div class="commentActions">
|
||||
<form name="delete"
|
||||
|
@ -271,17 +271,6 @@ class CommentsViewlet(ViewletBase):
|
||||
|
||||
# view methods
|
||||
|
||||
def cook(self, text):
|
||||
transforms = getToolByName(self, 'portal_transforms')
|
||||
targetMimetype = 'text/html'
|
||||
registry = queryUtility(IRegistry)
|
||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||
mimetype = settings.text_transform
|
||||
return transforms.convertTo(targetMimetype,
|
||||
text,
|
||||
context=self,
|
||||
mimetype=mimetype).getData()
|
||||
|
||||
def can_reply(self):
|
||||
"""Returns true if current user has the 'Reply to item' permission.
|
||||
"""
|
||||
|
@ -70,7 +70,8 @@ class View(BrowserView):
|
||||
# create a reply object
|
||||
comment = CommentFactory()
|
||||
comment.title = reply.Title()
|
||||
comment.text = reply.text
|
||||
comment.text = reply.cooked_text
|
||||
comment.mime_type = 'text/html'
|
||||
comment.creator = reply.Creator()
|
||||
|
||||
email = reply.getProperty('email', None)
|
||||
|
@ -110,7 +110,7 @@
|
||||
tal:content="item/in_response_to" />
|
||||
</td>
|
||||
<td>
|
||||
<span tal:replace="structure python:view.cook(item.Description)" />
|
||||
<span tal:replace="structure item/Description" />
|
||||
<a href=""
|
||||
tal:attributes="href string:${item/getURL}/getText"
|
||||
tal:condition="python:item.Description.endswith('[...]')"
|
||||
|
@ -2,7 +2,6 @@ from Acquisition import aq_inner, aq_parent
|
||||
|
||||
from Products.Five.browser import BrowserView
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile
|
||||
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
|
||||
@ -37,9 +36,6 @@ class View(BrowserView):
|
||||
sort_order='reverse')
|
||||
return self.template()
|
||||
|
||||
def cook(self, text):
|
||||
return text
|
||||
|
||||
def moderation_enabled(self):
|
||||
"""Returns true if a 'review workflow' is enabled on 'Discussion Item'
|
||||
content type. A 'review workflow' is characterized by implementing
|
||||
|
@ -77,14 +77,14 @@ def creator(object):
|
||||
@indexer(IComment)
|
||||
def description(object):
|
||||
# Return the first 25 words of the comment text and append ' [...]'
|
||||
text = join(object.text.split()[:MAX_DESCRIPTION])
|
||||
if len(object.text.split()) > 25:
|
||||
text = join(object.getText(targetMimetype='text/plain').split()[:MAX_DESCRIPTION])
|
||||
if len(object.getText().split()) > 25:
|
||||
text += " [...]"
|
||||
return text
|
||||
|
||||
@indexer(IComment)
|
||||
def searchable_text(object):
|
||||
return object.text
|
||||
return object.getText(targetMimetype='text/plain')
|
||||
|
||||
@indexer(IComment)
|
||||
def in_response_to(object):
|
||||
|
@ -79,7 +79,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
|
||||
title = u""
|
||||
|
||||
mime_type = "text/plain"
|
||||
mime_type = None
|
||||
text = u""
|
||||
|
||||
creator = None
|
||||
@ -113,10 +113,26 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
"""
|
||||
return self.id
|
||||
|
||||
def getText(self):
|
||||
def getText(self, targetMimetype=None):
|
||||
"""The body text of a comment.
|
||||
"""
|
||||
return self.text
|
||||
transforms = getToolByName(self, 'portal_transforms')
|
||||
|
||||
if targetMimetype is None:
|
||||
targetMimetype = 'text/x-html-safe'
|
||||
|
||||
sourceMimetype = getattr(self, 'mime_type', None)
|
||||
if sourceMimetype is None:
|
||||
registry = queryUtility(IRegistry)
|
||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||
sourceMimetype = settings.text_transform
|
||||
text = self.text
|
||||
if isinstance(text, unicode):
|
||||
text = text.encode('utf8')
|
||||
return transforms.convertTo(targetMimetype,
|
||||
text,
|
||||
context=self,
|
||||
mimetype=sourceMimetype).getData()
|
||||
|
||||
def Title(self):
|
||||
"""The title of the comment.
|
||||
|
@ -123,6 +123,44 @@ class CommentTest(PloneTestCase):
|
||||
comment1 = createObject('plone.Comment')
|
||||
self.assertEquals(comment1.Type(), 'Comment')
|
||||
|
||||
def test_getText(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = """First paragraph
|
||||
|
||||
Second paragraph"""
|
||||
self.assertEquals(comment1.getText(),
|
||||
"<p>First paragraph<br /><br /> Second paragraph</p>")
|
||||
|
||||
def test_getText_escapes_HTML(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = """<b>Got HTML?</b>"""
|
||||
self.assertEquals(comment1.getText(),
|
||||
"<p><b>Got HTML?</b></p>")
|
||||
|
||||
def test_getText_with_non_ascii_characters(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = u"""Umlaute sind ä, ö und ü."""
|
||||
self.assertEquals(comment1.getText(),
|
||||
'<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>')
|
||||
|
||||
def test_getText_doesnt_link(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = "Go to http://www.plone.org"
|
||||
self.assertEquals(comment1.getText(),
|
||||
"<p>Go to http://www.plone.org</p>")
|
||||
|
||||
def test_getText_uses_comment_mime_type(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = "Go to http://www.plone.org"
|
||||
comment1.mime_type = 'text/x-web-intelligent'
|
||||
self.assertEquals(comment1.getText(),
|
||||
'Go to <a href="http://www.plone.org" rel="nofollow">http://www.plone.org</a>')
|
||||
|
||||
def test_getText_w_custom_targetMimetype(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = 'para'
|
||||
self.assertEquals(comment1.getText(targetMimetype='text/plain'), 'para')
|
||||
|
||||
def test_traversal(self):
|
||||
# make sure comments are traversable, have an id, absolute_url and
|
||||
# physical path
|
||||
|
@ -228,28 +228,6 @@ class TestCommentsViewlet(PloneTestCase):
|
||||
settings = registry.forInterface(IDiscussionSettings)
|
||||
settings.globally_enabled = True
|
||||
|
||||
def test_cook(self):
|
||||
text = """First paragraph
|
||||
|
||||
Second paragraph"""
|
||||
self.assertEquals(self.viewlet.cook(text),
|
||||
"<p>First paragraph<br /><br /> Second paragraph</p>")
|
||||
|
||||
def test_cook_no_html(self):
|
||||
text = """<b>Got HTML?</b>"""
|
||||
self.assertEquals(self.viewlet.cook(text),
|
||||
"<p><b>Got HTML?</b></p>")
|
||||
|
||||
def test_cook_with_no_ascii_characters(self):
|
||||
text = """Umlaute sind ä, ö und ü."""
|
||||
self.assertEquals(self.viewlet.cook(text),
|
||||
"<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>")
|
||||
|
||||
def test_cook_links(self):
|
||||
text = "Go to http://www.plone.org"
|
||||
self.assertEquals(self.viewlet.cook(text),
|
||||
"<p>Go to http://www.plone.org</p>")
|
||||
|
||||
def test_can_reply(self):
|
||||
# Portal owner can reply
|
||||
self.failUnless(self.viewlet.can_reply())
|
||||
|
@ -69,7 +69,8 @@ class MigrationTest(PloneTestCase):
|
||||
comment1 = conversation.values()[0]
|
||||
self.assert_(IComment.providedBy(comment1))
|
||||
self.assertEquals(comment1.Title(), 'Jim on Document 1')
|
||||
self.assertEquals(comment1.text, 'My Text')
|
||||
self.assertEquals(comment1.text, '<p>My Text</p>\n')
|
||||
self.assertEquals(comment1.mime_type, 'text/html')
|
||||
self.assertEquals(comment1.Creator(), 'Jim')
|
||||
self.assertEquals(comment1.creation_date,
|
||||
datetime(2003, 3, 11, 9, 28, 6))
|
||||
|
Loading…
Reference in New Issue
Block a user