Nuke trailing white space
svn path=/plone.app.discussion/trunk/; revision=46366
This commit is contained in:
parent
aff8a3709c
commit
a2a17085a3
@ -39,7 +39,7 @@ Captcha = factory(Captcha)
|
|||||||
|
|
||||||
class CaptchaExtender(extensible.FormExtender):
|
class CaptchaExtender(extensible.FormExtender):
|
||||||
"""Extends the comment form with a Captcha. This Captcha extender is only
|
"""Extends the comment form with a Captcha. This Captcha extender is only
|
||||||
registered when a plugin is installed that provides the
|
registered when a plugin is installed that provides the
|
||||||
"plone.app.discussion-captcha" feature.
|
"plone.app.discussion-captcha" feature.
|
||||||
"""
|
"""
|
||||||
adapts(Interface, IDefaultBrowserLayer, CommentForm) # context, request, form
|
adapts(Interface, IDefaultBrowserLayer, CommentForm) # context, request, form
|
||||||
@ -72,4 +72,4 @@ class CaptchaExtender(extensible.FormExtender):
|
|||||||
self.form.fields['captcha'].widgetFactory = NorobotsFieldWidget
|
self.form.fields['captcha'].widgetFactory = NorobotsFieldWidget
|
||||||
else:
|
else:
|
||||||
self.form.fields['captcha'].mode = interfaces.HIDDEN_MODE
|
self.form.fields['captcha'].mode = interfaces.HIDDEN_MODE
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
<configure
|
<configure
|
||||||
xmlns="http://namespaces.zope.org/zope"
|
xmlns="http://namespaces.zope.org/zope"
|
||||||
xmlns:meta="http://namespaces.zope.org/meta"
|
xmlns:meta="http://namespaces.zope.org/meta"
|
||||||
xmlns:zcml="http://namespaces.zope.org/zcml"
|
xmlns:zcml="http://namespaces.zope.org/zcml"
|
||||||
i18n_domain="plone.app.discussion">
|
i18n_domain="plone.app.discussion">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Plone 3 fixes
|
Plone 3 fixes
|
||||||
|
|
||||||
Plone 3 / Zope 2.10 does not recognize the meta:provides feature.
|
Plone 3 / Zope 2.10 does not recognize the meta:provides feature.
|
||||||
Therefore we claim to provide this feature when a suitable package is
|
Therefore we claim to provide this feature when a suitable package is
|
||||||
installed.
|
installed.
|
||||||
-->
|
-->
|
||||||
<configure zcml:condition="installed plone.formwidget.captcha">
|
<configure zcml:condition="installed plone.formwidget.captcha">
|
||||||
<meta:provides feature="plone.app.discussion-captcha" />
|
<meta:provides feature="plone.app.discussion-captcha" />
|
||||||
@ -21,11 +21,11 @@
|
|||||||
|
|
||||||
<!-- Captcha comment form extender -->
|
<!-- Captcha comment form extender -->
|
||||||
<configure zcml:condition="have plone.app.discussion-captcha">
|
<configure zcml:condition="have plone.app.discussion-captcha">
|
||||||
<!--
|
<!--
|
||||||
Register the Captcha form extender and validator only if there are
|
Register the Captcha form extender and validator only if there are
|
||||||
plugins installed that declare to implement a Captcha solution for
|
plugins installed that declare to implement a Captcha solution for
|
||||||
plone.app.discussion (e.g. plone.formwidget.captcha and
|
plone.app.discussion (e.g. plone.formwidget.captcha and
|
||||||
plone.formwidget.recaptcha).
|
plone.formwidget.recaptcha).
|
||||||
-->
|
-->
|
||||||
<adapter
|
<adapter
|
||||||
factory=".captcha.Captcha"
|
factory=".captcha.Captcha"
|
||||||
@ -44,7 +44,7 @@
|
|||||||
<adapter
|
<adapter
|
||||||
factory="collective.akismet.validator.AkismetValidator"
|
factory="collective.akismet.validator.AkismetValidator"
|
||||||
provides="z3c.form.interfaces.IValidator"
|
provides="z3c.form.interfaces.IValidator"
|
||||||
/>
|
/>
|
||||||
</configure>
|
</configure>
|
||||||
|
|
||||||
</configure>
|
</configure>
|
||||||
|
@ -5,15 +5,15 @@ from Products.Five.browser import BrowserView
|
|||||||
class View(BrowserView):
|
class View(BrowserView):
|
||||||
"""Comment View.
|
"""Comment View.
|
||||||
|
|
||||||
When the view of a comment object is called directly, redirect to the
|
When the view of a comment object is called directly, redirect to the
|
||||||
the page (content object) and the location (HTML-anchor) where the comment
|
the page (content object) and the location (HTML-anchor) where the comment
|
||||||
has been posted.
|
has been posted.
|
||||||
|
|
||||||
Redirect from the comment object URL
|
Redirect from the comment object URL
|
||||||
"/path/to/object/++conversation++default/123456789" to the content object
|
"/path/to/object/++conversation++default/123456789" to the content object
|
||||||
where the comment has been posted appended by an HTML anchor that points to
|
where the comment has been posted appended by an HTML anchor that points to
|
||||||
the comment "/path/to/object#comment-123456789".
|
the comment "/path/to/object#comment-123456789".
|
||||||
|
|
||||||
Context is the comment object. The parent of the comment object is the
|
Context is the comment object. The parent of the comment object is the
|
||||||
conversation. The parent of the conversation is the content object where
|
conversation. The parent of the conversation is the content object where
|
||||||
the comment has been posted.
|
the comment has been posted.
|
||||||
@ -24,4 +24,4 @@ class View(BrowserView):
|
|||||||
self.request.response.redirect(
|
self.request.response.redirect(
|
||||||
aq_parent(aq_parent(context)).absolute_url() +
|
aq_parent(aq_parent(context)).absolute_url() +
|
||||||
'#' + str(context.id)
|
'#' + str(context.id)
|
||||||
)
|
)
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
tal:attributes="src portrait_url;
|
tal:attributes="src portrait_url;
|
||||||
alt reply/Creator" />
|
alt reply/Creator" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="documentByLine" i18n:domain="plone.app.discussion">
|
<div class="documentByLine" i18n:domain="plone.app.discussion">
|
||||||
<tal:name>
|
<tal:name>
|
||||||
<a href=""
|
<a href=""
|
||||||
@ -72,16 +72,16 @@
|
|||||||
<span tal:condition="not: reply/Creator">Anonymous</span>
|
<span tal:condition="not: reply/Creator">Anonymous</span>
|
||||||
</tal:name>
|
</tal:name>
|
||||||
<tal:posted i18n:translate="label_says">says:</tal:posted>
|
<tal:posted i18n:translate="label_says">says:</tal:posted>
|
||||||
<div class="commentDate"
|
<div class="commentDate"
|
||||||
tal:content="python:view.format_time(reply.modification_date)">
|
tal:content="python:view.format_time(reply.modification_date)">
|
||||||
8/23/2001 12:40:44 PM
|
8/23/2001 12:40:44 PM
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="commentBody">
|
<div class="commentBody">
|
||||||
|
|
||||||
<span tal:replace="structure python:view.cook(reply.getText())" />
|
<span tal:replace="structure python:view.cook(reply.getText())" />
|
||||||
|
|
||||||
<div class="commentActions">
|
<div class="commentActions">
|
||||||
<form name="delete"
|
<form name="delete"
|
||||||
action=""
|
action=""
|
||||||
@ -96,7 +96,7 @@
|
|||||||
i18n:attributes="value label_delete;"
|
i18n:attributes="value label_delete;"
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Workflow actions (e.g. 'publish') -->
|
<!-- Workflow actions (e.g. 'publish') -->
|
||||||
<form name=""
|
<form name=""
|
||||||
action=""
|
action=""
|
||||||
@ -115,7 +115,7 @@
|
|||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<button class="context reply-to-comment-button hide allowMultiSubmit"
|
<button class="context reply-to-comment-button hide allowMultiSubmit"
|
||||||
|
@ -41,10 +41,10 @@ from plone.z3cform import z2
|
|||||||
from plone.z3cform.widget import SingleCheckBoxWidget
|
from plone.z3cform.widget import SingleCheckBoxWidget
|
||||||
from plone.z3cform.fieldsets import extensible
|
from plone.z3cform.fieldsets import extensible
|
||||||
|
|
||||||
# starting from 0.6.0 version plone.z3cform has IWrappedForm interface
|
# starting from 0.6.0 version plone.z3cform has IWrappedForm interface
|
||||||
try:
|
try:
|
||||||
from plone.z3cform.interfaces import IWrappedForm
|
from plone.z3cform.interfaces import IWrappedForm
|
||||||
HAS_WRAPPED_FORM = True
|
HAS_WRAPPED_FORM = True
|
||||||
except ImportError: # pragma: no cover
|
except ImportError: # pragma: no cover
|
||||||
HAS_WRAPPED_FORM = False
|
HAS_WRAPPED_FORM = False
|
||||||
|
|
||||||
@ -87,48 +87,48 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
|||||||
# Widgets
|
# Widgets
|
||||||
self.widgets['in_reply_to'].mode = interfaces.HIDDEN_MODE
|
self.widgets['in_reply_to'].mode = interfaces.HIDDEN_MODE
|
||||||
self.widgets['text'].addClass("autoresize")
|
self.widgets['text'].addClass("autoresize")
|
||||||
self.widgets['user_notification'].label = _(u"")
|
self.widgets['user_notification'].label = _(u"")
|
||||||
|
|
||||||
# Anonymous / Logged-in
|
# Anonymous / Logged-in
|
||||||
portal_membership = getToolByName(self.context, 'portal_membership')
|
portal_membership = getToolByName(self.context, 'portal_membership')
|
||||||
if not portal_membership.isAnonymousUser():
|
if not portal_membership.isAnonymousUser():
|
||||||
self.widgets['author_name'].mode = interfaces.HIDDEN_MODE
|
self.widgets['author_name'].mode = interfaces.HIDDEN_MODE
|
||||||
self.widgets['author_email'].mode = interfaces.HIDDEN_MODE
|
self.widgets['author_email'].mode = interfaces.HIDDEN_MODE
|
||||||
|
|
||||||
# Todo: Since we are not using the author_email field in the
|
# Todo: Since we are not using the author_email field in the
|
||||||
# current state, we hide it by default. But we keep the field for
|
# current state, we hide it by default. But we keep the field for
|
||||||
# integrators or later use.
|
# integrators or later use.
|
||||||
self.widgets['author_email'].mode = interfaces.HIDDEN_MODE
|
self.widgets['author_email'].mode = interfaces.HIDDEN_MODE
|
||||||
|
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||||
portal_membership = getToolByName(self.context, 'portal_membership')
|
portal_membership = getToolByName(self.context, 'portal_membership')
|
||||||
|
|
||||||
if not settings.user_notification_enabled or portal_membership.isAnonymousUser():
|
if not settings.user_notification_enabled or portal_membership.isAnonymousUser():
|
||||||
self.widgets['user_notification'].mode = interfaces.HIDDEN_MODE
|
self.widgets['user_notification'].mode = interfaces.HIDDEN_MODE
|
||||||
|
|
||||||
def updateActions(self):
|
def updateActions(self):
|
||||||
super(CommentForm, self).updateActions()
|
super(CommentForm, self).updateActions()
|
||||||
self.actions['cancel'].addClass("standalone")
|
self.actions['cancel'].addClass("standalone")
|
||||||
self.actions['cancel'].addClass("hide")
|
self.actions['cancel'].addClass("hide")
|
||||||
self.actions['comment'].addClass("context")
|
self.actions['comment'].addClass("context")
|
||||||
|
|
||||||
@button.buttonAndHandler(_(u"add_comment_button", default=u"Comment"),
|
@button.buttonAndHandler(_(u"add_comment_button", default=u"Comment"),
|
||||||
name='comment')
|
name='comment')
|
||||||
def handleComment(self, action):
|
def handleComment(self, action):
|
||||||
context = aq_inner(self.context)
|
context = aq_inner(self.context)
|
||||||
wf = getToolByName(context, 'portal_workflow')
|
wf = getToolByName(context, 'portal_workflow')
|
||||||
|
|
||||||
data, errors = self.extractData()
|
data, errors = self.extractData()
|
||||||
if errors:
|
if errors:
|
||||||
return
|
return
|
||||||
|
|
||||||
text = u""
|
text = u""
|
||||||
author_name = u""
|
author_name = u""
|
||||||
author_email = u""
|
author_email = u""
|
||||||
user_notification = None
|
user_notification = None
|
||||||
|
|
||||||
# Captcha check for anonymous users (if Captcha is enabled and
|
# Captcha check for anonymous users (if Captcha is enabled and
|
||||||
# anonymous commenting is allowed)
|
# anonymous commenting is allowed)
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||||
@ -138,10 +138,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
|||||||
portal_membership.isAnonymousUser():
|
portal_membership.isAnonymousUser():
|
||||||
if not 'captcha' in data:
|
if not 'captcha' in data:
|
||||||
data['captcha'] = u""
|
data['captcha'] = u""
|
||||||
captcha = CaptchaValidator(self.context,
|
captcha = CaptchaValidator(self.context,
|
||||||
self.request,
|
self.request,
|
||||||
None,
|
None,
|
||||||
ICaptcha['captcha'],
|
ICaptcha['captcha'],
|
||||||
None)
|
None)
|
||||||
captcha.validate(data['captcha'])
|
captcha.validate(data['captcha'])
|
||||||
|
|
||||||
@ -156,10 +156,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
|||||||
author_email = data['author_email']
|
author_email = data['author_email']
|
||||||
if 'user_notification' in data:
|
if 'user_notification' in data:
|
||||||
user_notification = data['user_notification']
|
user_notification = data['user_notification']
|
||||||
|
|
||||||
# The add-comment view is called on the conversation object
|
# The add-comment view is called on the conversation object
|
||||||
conversation = IConversation(self.__parent__)
|
conversation = IConversation(self.__parent__)
|
||||||
|
|
||||||
# Check if conversation is enabled on this content object
|
# Check if conversation is enabled on this content object
|
||||||
if not conversation.enabled():
|
if not conversation.enabled():
|
||||||
raise Unauthorized, "Discussion is not enabled for this content\
|
raise Unauthorized, "Discussion is not enabled for this content\
|
||||||
@ -175,10 +175,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
|||||||
comment.text = text
|
comment.text = text
|
||||||
|
|
||||||
portal_membership = getToolByName(self.context, 'portal_membership')
|
portal_membership = getToolByName(self.context, 'portal_membership')
|
||||||
|
|
||||||
can_reply = getSecurityManager().checkPermission('Reply to item',
|
can_reply = getSecurityManager().checkPermission('Reply to item',
|
||||||
context)
|
context)
|
||||||
|
|
||||||
if portal_membership.isAnonymousUser() and \
|
if portal_membership.isAnonymousUser() and \
|
||||||
settings.anonymous_comments:
|
settings.anonymous_comments:
|
||||||
# Anonymous Users
|
# Anonymous Users
|
||||||
@ -211,7 +211,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
|||||||
"""Anonymous user tries to post a comment, but
|
"""Anonymous user tries to post a comment, but
|
||||||
anonymous commenting is disabled. Or user
|
anonymous commenting is disabled. Or user
|
||||||
does not have the 'reply to item' permission.""" # pragma: no cover
|
does not have the 'reply to item' permission.""" # pragma: no cover
|
||||||
|
|
||||||
# Check if the added comment is a reply to an existing comment
|
# Check if the added comment is a reply to an existing comment
|
||||||
# or just a regular reply to the content object.
|
# or just a regular reply to the content object.
|
||||||
if data['in_reply_to']:
|
if data['in_reply_to']:
|
||||||
@ -221,11 +221,11 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
|||||||
# Add a comment to the conversation
|
# Add a comment to the conversation
|
||||||
comment_id = conversation.addComment(comment)
|
comment_id = conversation.addComment(comment)
|
||||||
|
|
||||||
# If a user posts a comment and moderation is enabled, a message is
|
# If a user posts a comment and moderation is enabled, a message is
|
||||||
# shown to the user that his/her comment awaits moderation. If the user
|
# shown to the user that his/her comment awaits moderation. If the user
|
||||||
# has 'review comments' permission, he/she is redirected directly
|
# has 'review comments' permission, he/she is redirected directly
|
||||||
# to the comment.
|
# to the comment.
|
||||||
can_review = getSecurityManager().checkPermission('Review comments',
|
can_review = getSecurityManager().checkPermission('Review comments',
|
||||||
context)
|
context)
|
||||||
comment_review_state = wf.getInfoFor(comment, 'review_state')
|
comment_review_state = wf.getInfoFor(comment, 'review_state')
|
||||||
if comment_review_state == 'pending' and not can_review:
|
if comment_review_state == 'pending' and not can_review:
|
||||||
@ -254,8 +254,8 @@ class CommentsViewlet(ViewletBase):
|
|||||||
super(CommentsViewlet, self).update()
|
super(CommentsViewlet, self).update()
|
||||||
z2.switch_on(self, request_layer=IFormLayer)
|
z2.switch_on(self, request_layer=IFormLayer)
|
||||||
self.form = self.form(aq_inner(self.context), self.request)
|
self.form = self.form(aq_inner(self.context), self.request)
|
||||||
if HAS_WRAPPED_FORM:
|
if HAS_WRAPPED_FORM:
|
||||||
alsoProvides(self.form, IWrappedForm)
|
alsoProvides(self.form, IWrappedForm)
|
||||||
self.form.update()
|
self.form.update()
|
||||||
|
|
||||||
# view methods
|
# view methods
|
||||||
@ -265,16 +265,16 @@ class CommentsViewlet(ViewletBase):
|
|||||||
targetMimetype = 'text/html'
|
targetMimetype = 'text/html'
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||||
mimetype = settings.text_transform
|
mimetype = settings.text_transform
|
||||||
return transforms.convertTo(targetMimetype,
|
return transforms.convertTo(targetMimetype,
|
||||||
text,
|
text,
|
||||||
context=self,
|
context=self,
|
||||||
mimetype=mimetype).getData()
|
mimetype=mimetype).getData()
|
||||||
|
|
||||||
def can_reply(self):
|
def can_reply(self):
|
||||||
"""Returns true if current user has the 'Reply to item' permission.
|
"""Returns true if current user has the 'Reply to item' permission.
|
||||||
"""
|
"""
|
||||||
return getSecurityManager().checkPermission('Reply to item',
|
return getSecurityManager().checkPermission('Reply to item',
|
||||||
aq_inner(self.context))
|
aq_inner(self.context))
|
||||||
|
|
||||||
def can_manage(self):
|
def can_manage(self):
|
||||||
@ -282,13 +282,13 @@ class CommentsViewlet(ViewletBase):
|
|||||||
not want any API changes in beta releases.
|
not want any API changes in beta releases.
|
||||||
"""
|
"""
|
||||||
return self.can_review()
|
return self.can_review()
|
||||||
|
|
||||||
def can_review(self):
|
def can_review(self):
|
||||||
"""Returns true if current user has the 'Review comments' permission.
|
"""Returns true if current user has the 'Review comments' permission.
|
||||||
"""
|
"""
|
||||||
return getSecurityManager().checkPermission('Review comments',
|
return getSecurityManager().checkPermission('Review comments',
|
||||||
aq_inner(self.context))
|
aq_inner(self.context))
|
||||||
|
|
||||||
def is_discussion_allowed(self):
|
def is_discussion_allowed(self):
|
||||||
context = aq_inner(self.context)
|
context = aq_inner(self.context)
|
||||||
conversation = IConversation(context)
|
conversation = IConversation(context)
|
||||||
@ -301,7 +301,7 @@ class CommentsViewlet(ViewletBase):
|
|||||||
"""
|
"""
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||||
|
|
||||||
if settings.text_transform == "text/x-web-intelligent":
|
if settings.text_transform == "text/x-web-intelligent":
|
||||||
message = translate(Message(COMMENT_DESCRIPTION_INTELLIGENT_TEXT))
|
message = translate(Message(COMMENT_DESCRIPTION_INTELLIGENT_TEXT))
|
||||||
else:
|
else:
|
||||||
@ -356,7 +356,7 @@ class CommentsViewlet(ViewletBase):
|
|||||||
r = r.copy()
|
r = r.copy()
|
||||||
r['workflow_status'] = workflow_status
|
r['workflow_status'] = workflow_status
|
||||||
yield r
|
yield r
|
||||||
|
|
||||||
# Return all direct replies
|
# Return all direct replies
|
||||||
if conversation.total_comments > 0:
|
if conversation.total_comments > 0:
|
||||||
if workflow_actions:
|
if workflow_actions:
|
||||||
@ -395,11 +395,11 @@ class CommentsViewlet(ViewletBase):
|
|||||||
return settings.show_commenter_image
|
return settings.show_commenter_image
|
||||||
|
|
||||||
def is_anonymous(self):
|
def is_anonymous(self):
|
||||||
portal_membership = getToolByName(self.context,
|
portal_membership = getToolByName(self.context,
|
||||||
'portal_membership',
|
'portal_membership',
|
||||||
None)
|
None)
|
||||||
return portal_membership.isAnonymousUser()
|
return portal_membership.isAnonymousUser()
|
||||||
|
|
||||||
def login_action(self):
|
def login_action(self):
|
||||||
return '%s/login_form?came_from=%s' % \
|
return '%s/login_form?came_from=%s' % \
|
||||||
(self.navigation_root_url,
|
(self.navigation_root_url,
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
class=".moderation.ModerateCommentsEnabled"
|
class=".moderation.ModerateCommentsEnabled"
|
||||||
permission="zope2.View"
|
permission="zope2.View"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Delete comment view -->
|
<!-- Delete comment view -->
|
||||||
<browser:page
|
<browser:page
|
||||||
for="plone.app.discussion.interfaces.IComment"
|
for="plone.app.discussion.interfaces.IComment"
|
||||||
@ -131,4 +131,4 @@
|
|||||||
permission="cmf.ManagePortal"
|
permission="cmf.ManagePortal"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</configure>
|
</configure>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
lang="en"
|
lang="en"
|
||||||
metal:use-macro="here/prefs_main_template/macros/master"
|
metal:use-macro="here/prefs_main_template/macros/master"
|
||||||
i18n:domain="plone">
|
i18n:domain="plone">
|
||||||
|
|
||||||
<metal:block fill-slot="top_slot"
|
<metal:block fill-slot="top_slot"
|
||||||
tal:define="dummy python:request.set('disable_border',1)" />
|
tal:define="dummy python:request.set('disable_border',1)" />
|
||||||
|
|
||||||
@ -17,14 +17,14 @@
|
|||||||
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="content"
|
<div id="content"
|
||||||
tal:attributes="class view/settings"
|
tal:attributes="class view/settings"
|
||||||
metal:fill-slot="prefs_configlet_content">
|
metal:fill-slot="prefs_configlet_content">
|
||||||
|
|
||||||
<script type="text/javascript"
|
<script type="text/javascript"
|
||||||
tal:attributes="src string:${context/portal_url}/++resource++plone.app.discussion.javascripts/controlpanel.js">
|
tal:attributes="src string:${context/portal_url}/++resource++plone.app.discussion.javascripts/controlpanel.js">
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<dl class="portalMessage warning"
|
<dl class="portalMessage warning"
|
||||||
tal:condition="view/mailhost_warning">
|
tal:condition="view/mailhost_warning">
|
||||||
<dt i18n:translate="">
|
<dt i18n:translate="">
|
||||||
@ -63,24 +63,24 @@
|
|||||||
to choose a workflow for the 'Discussion Item' type.
|
to choose a workflow for the 'Discussion Item' type.
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<div metal:use-macro="context/global_statusmessage/macros/portal_message">
|
<div metal:use-macro="context/global_statusmessage/macros/portal_message">
|
||||||
Portal status message
|
Portal status message
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href=""
|
<a href=""
|
||||||
id="setup-link"
|
id="setup-link"
|
||||||
tal:attributes="href string:$portal_url/plone_control_panel"
|
tal:attributes="href string:$portal_url/plone_control_panel"
|
||||||
i18n:translate="">
|
i18n:translate="">
|
||||||
Site Setup
|
Site Setup
|
||||||
</a> ›
|
</a> ›
|
||||||
|
|
||||||
<h1 class="documentFirstHeading" tal:content="view/label">View Title</h1>
|
<h1 class="documentFirstHeading" tal:content="view/label">View Title</h1>
|
||||||
|
|
||||||
<div id="layout-contents">
|
<div id="layout-contents">
|
||||||
<span tal:replace="structure view/contents" />
|
<span tal:replace="structure view/contents" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -21,7 +21,7 @@ from zope.component import getMultiAdapter, queryUtility
|
|||||||
|
|
||||||
from z3c.form import button
|
from z3c.form import button
|
||||||
from z3c.form.browser.checkbox import SingleCheckBoxFieldWidget
|
from z3c.form.browser.checkbox import SingleCheckBoxFieldWidget
|
||||||
|
|
||||||
from plone.app.discussion.interfaces import IDiscussionSettings, _
|
from plone.app.discussion.interfaces import IDiscussionSettings, _
|
||||||
|
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
|||||||
description = _(u"help_discussion_settings_editform",
|
description = _(u"help_discussion_settings_editform",
|
||||||
default=u"Some discussion related settings are not located "
|
default=u"Some discussion related settings are not located "
|
||||||
"in the Discussion Control Panel.\n"
|
"in the Discussion Control Panel.\n"
|
||||||
"To enable comments for a specific content type, "
|
"To enable comments for a specific content type, "
|
||||||
"go to the Types Control Panel of this type and "
|
"go to the Types Control Panel of this type and "
|
||||||
"choose \"Allow comments\".\n"
|
"choose \"Allow comments\".\n"
|
||||||
"To enable the moderation workflow for comments, "
|
"To enable the moderation workflow for comments, "
|
||||||
@ -73,18 +73,18 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
|||||||
self.status = self.formErrorsMessage
|
self.status = self.formErrorsMessage
|
||||||
return
|
return
|
||||||
changes = self.applyChanges(data)
|
changes = self.applyChanges(data)
|
||||||
IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"),
|
IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"),
|
||||||
"info")
|
"info")
|
||||||
self.context.REQUEST.RESPONSE.redirect("@@discussion-settings")
|
self.context.REQUEST.RESPONSE.redirect("@@discussion-settings")
|
||||||
|
|
||||||
@button.buttonAndHandler(_('Cancel'), name='cancel')
|
@button.buttonAndHandler(_('Cancel'), name='cancel')
|
||||||
def handleCancel(self, action):
|
def handleCancel(self, action):
|
||||||
IStatusMessage(self.request).addStatusMessage(_(u"Edit cancelled"),
|
IStatusMessage(self.request).addStatusMessage(_(u"Edit cancelled"),
|
||||||
"info")
|
"info")
|
||||||
self.request.response.redirect("%s/%s" % (self.context.absolute_url(),
|
self.request.response.redirect("%s/%s" % (self.context.absolute_url(),
|
||||||
self.control_panel_view))
|
self.control_panel_view))
|
||||||
|
|
||||||
|
|
||||||
class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
||||||
"""Discussion settings control panel.
|
"""Discussion settings control panel.
|
||||||
"""
|
"""
|
||||||
@ -100,22 +100,22 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
|||||||
wftool = getToolByName(self.context, "portal_workflow", None)
|
wftool = getToolByName(self.context, "portal_workflow", None)
|
||||||
wf = wftool.getChainForPortalType('Discussion Item')
|
wf = wftool.getChainForPortalType('Discussion Item')
|
||||||
output = []
|
output = []
|
||||||
|
|
||||||
# Globally enabled
|
# Globally enabled
|
||||||
if settings.globally_enabled:
|
if settings.globally_enabled:
|
||||||
output.append("globally_enabled")
|
output.append("globally_enabled")
|
||||||
|
|
||||||
# Comment moderation
|
# Comment moderation
|
||||||
if 'one_state_workflow' not in wf and \
|
if 'one_state_workflow' not in wf and \
|
||||||
'comment_review_workflow' not in wf:
|
'comment_review_workflow' not in wf:
|
||||||
output.append("moderation_custom")
|
output.append("moderation_custom")
|
||||||
elif settings.moderation_enabled:
|
elif settings.moderation_enabled:
|
||||||
output.append("moderation_enabled")
|
output.append("moderation_enabled")
|
||||||
|
|
||||||
# Anonymous comments
|
# Anonymous comments
|
||||||
if settings.anonymous_comments:
|
if settings.anonymous_comments:
|
||||||
output.append("anonymous_comments")
|
output.append("anonymous_comments")
|
||||||
|
|
||||||
# Invalid mail setting
|
# Invalid mail setting
|
||||||
ctrlOverview = getMultiAdapter((self.context, self.request),
|
ctrlOverview = getMultiAdapter((self.context, self.request),
|
||||||
name='overview-controlpanel')
|
name='overview-controlpanel')
|
||||||
@ -127,7 +127,7 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
|||||||
discussion_workflow = wftool.getChainForPortalType('Discussion Item')[0]
|
discussion_workflow = wftool.getChainForPortalType('Discussion Item')[0]
|
||||||
if discussion_workflow:
|
if discussion_workflow:
|
||||||
output.append(discussion_workflow)
|
output.append(discussion_workflow)
|
||||||
|
|
||||||
# Merge all settings into one string
|
# Merge all settings into one string
|
||||||
return ' '.join(output)
|
return ' '.join(output)
|
||||||
|
|
||||||
@ -152,27 +152,27 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
|||||||
if 'one_state_workflow' in wf or 'comment_review_workflow' in wf:
|
if 'one_state_workflow' in wf or 'comment_review_workflow' in wf:
|
||||||
return
|
return
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def notify_configuration_changed(event):
|
def notify_configuration_changed(event):
|
||||||
"""Event subscriber that is called every time the configuration changed.
|
"""Event subscriber that is called every time the configuration changed.
|
||||||
"""
|
"""
|
||||||
portal = getSite()
|
portal = getSite()
|
||||||
wftool = getToolByName(portal, 'portal_workflow', None)
|
wftool = getToolByName(portal, 'portal_workflow', None)
|
||||||
|
|
||||||
if IRecordModifiedEvent.providedBy(event):
|
if IRecordModifiedEvent.providedBy(event):
|
||||||
# Discussion control panel setting changed
|
# Discussion control panel setting changed
|
||||||
if event.record.fieldName == 'moderation_enabled':
|
if event.record.fieldName == 'moderation_enabled':
|
||||||
# Moderation enabled has changed
|
# Moderation enabled has changed
|
||||||
if event.record.value == True:
|
if event.record.value == True:
|
||||||
# Enable moderation workflow
|
# Enable moderation workflow
|
||||||
wftool.setChainForPortalTypes(('Discussion Item',),
|
wftool.setChainForPortalTypes(('Discussion Item',),
|
||||||
'comment_review_workflow')
|
'comment_review_workflow')
|
||||||
else:
|
else:
|
||||||
# Disable moderation workflow
|
# Disable moderation workflow
|
||||||
wftool.setChainForPortalTypes(('Discussion Item',),
|
wftool.setChainForPortalTypes(('Discussion Item',),
|
||||||
'one_state_workflow')
|
'one_state_workflow')
|
||||||
|
|
||||||
if IConfigurationChangedEvent.providedBy(event):
|
if IConfigurationChangedEvent.providedBy(event):
|
||||||
# Types control panel setting changed
|
# Types control panel setting changed
|
||||||
if 'workflow' in event.data:
|
if 'workflow' in event.data:
|
||||||
|
@ -25,22 +25,22 @@ class View(BrowserView):
|
|||||||
out = []
|
out = []
|
||||||
self.total_comments_migrated = 0
|
self.total_comments_migrated = 0
|
||||||
self.total_comments_deleted = 0
|
self.total_comments_deleted = 0
|
||||||
|
|
||||||
dry_run = self.request.has_key("dry_run")
|
dry_run = self.request.has_key("dry_run")
|
||||||
|
|
||||||
# This is for testing only.
|
# This is for testing only.
|
||||||
# Do not use transactions during a test.
|
# Do not use transactions during a test.
|
||||||
test = self.request.has_key("test")
|
test = self.request.has_key("test")
|
||||||
|
|
||||||
if not test:
|
if not test:
|
||||||
transaction.begin() # pragma: no cover
|
transaction.begin() # pragma: no cover
|
||||||
|
|
||||||
catalog = getToolByName(context, 'portal_catalog')
|
catalog = getToolByName(context, 'portal_catalog')
|
||||||
|
|
||||||
def log(msg):
|
def log(msg):
|
||||||
# encode string before sending it to external world
|
# encode string before sending it to external world
|
||||||
if isinstance(msg, unicode):
|
if isinstance(msg, unicode):
|
||||||
msg = msg.encode('utf-8') # pragma: no cover
|
msg = msg.encode('utf-8') # pragma: no cover
|
||||||
context.plone_log(msg)
|
context.plone_log(msg)
|
||||||
out.append(msg)
|
out.append(msg)
|
||||||
|
|
||||||
@ -85,9 +85,9 @@ class View(BrowserView):
|
|||||||
|
|
||||||
# migrate all talkbacks of the reply
|
# migrate all talkbacks of the reply
|
||||||
talkback = getattr( reply, 'talkback', None )
|
talkback = getattr( reply, 'talkback', None )
|
||||||
no_replies_left = migrate_replies(context,
|
no_replies_left = migrate_replies(context,
|
||||||
new_in_reply_to,
|
new_in_reply_to,
|
||||||
talkback.getReplies(),
|
talkback.getReplies(),
|
||||||
depth=depth+1)
|
depth=depth+1)
|
||||||
if no_replies_left:
|
if no_replies_left:
|
||||||
# remove reply and talkback
|
# remove reply and talkback
|
||||||
@ -97,7 +97,7 @@ class View(BrowserView):
|
|||||||
log("%sremove %s" % (indent, reply.id))
|
log("%sremove %s" % (indent, reply.id))
|
||||||
self.total_comments_deleted += 1
|
self.total_comments_deleted += 1
|
||||||
|
|
||||||
# Return True when all comments on a certain level have been
|
# Return True when all comments on a certain level have been
|
||||||
# migrated.
|
# migrated.
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -113,14 +113,14 @@ class View(BrowserView):
|
|||||||
count_comments_old = len(catalog.searchResults(
|
count_comments_old = len(catalog.searchResults(
|
||||||
object_provides=IDiscussionResponse.\
|
object_provides=IDiscussionResponse.\
|
||||||
__identifier__))
|
__identifier__))
|
||||||
|
|
||||||
log("Found %s Discussion Item objects." % count_discussion_items)
|
log("Found %s Discussion Item objects." % count_discussion_items)
|
||||||
log("Found %s old discussion items." % count_comments_old)
|
log("Found %s old discussion items." % count_comments_old)
|
||||||
log("Found %s plone.app.discussion comments." % count_comments_pad)
|
log("Found %s plone.app.discussion comments." % count_comments_pad)
|
||||||
|
|
||||||
log("\n")
|
log("\n")
|
||||||
log("Start comment migration.")
|
log("Start comment migration.")
|
||||||
|
|
||||||
# This loop is necessary to get all contentish objects, but not
|
# This loop is necessary to get all contentish objects, but not
|
||||||
# the Discussion Items. This wouldn't be necessary if the
|
# the Discussion Items. This wouldn't be necessary if the
|
||||||
# zcatalog would support NOT expressions.
|
# zcatalog would support NOT expressions.
|
||||||
@ -138,7 +138,7 @@ class View(BrowserView):
|
|||||||
if replies:
|
if replies:
|
||||||
conversation = IConversation(obj)
|
conversation = IConversation(obj)
|
||||||
log("\n")
|
log("\n")
|
||||||
log("Migrate '%s' (%s)" % (obj.Title(),
|
log("Migrate '%s' (%s)" % (obj.Title(),
|
||||||
obj.absolute_url(relative=1)))
|
obj.absolute_url(relative=1)))
|
||||||
migrate_replies(context, 0, replies)
|
migrate_replies(context, 0, replies)
|
||||||
obj = aq_parent(talkback)
|
obj = aq_parent(talkback)
|
||||||
@ -152,23 +152,23 @@ class View(BrowserView):
|
|||||||
if not test: # pragma: no cover
|
if not test: # pragma: no cover
|
||||||
transaction.abort() # pragma: no cover
|
transaction.abort() # pragma: no cover
|
||||||
log("Abort transaction") # pragma: no cover
|
log("Abort transaction") # pragma: no cover
|
||||||
|
|
||||||
log("\n")
|
log("\n")
|
||||||
log("Comment migration finished.")
|
log("Comment migration finished.")
|
||||||
log("\n")
|
log("\n")
|
||||||
|
|
||||||
log("%s of %s comments migrated."
|
log("%s of %s comments migrated."
|
||||||
% (self.total_comments_migrated, count_comments_old))
|
% (self.total_comments_migrated, count_comments_old))
|
||||||
|
|
||||||
if self.total_comments_migrated != count_comments_old:
|
if self.total_comments_migrated != count_comments_old:
|
||||||
log("%s comments could not be migrated."
|
log("%s comments could not be migrated."
|
||||||
% (count_comments_old - self.total_comments_migrated)) # pragma: no cover
|
% (count_comments_old - self.total_comments_migrated)) # pragma: no cover
|
||||||
log("Please make sure your portal catalog is up-to-date.") # pragma: no cover
|
log("Please make sure your portal catalog is up-to-date.") # pragma: no cover
|
||||||
|
|
||||||
if dry_run and not test:
|
if dry_run and not test:
|
||||||
transaction.abort() # pragma: no cover
|
transaction.abort() # pragma: no cover
|
||||||
log("Dry run") # pragma: no cover
|
log("Dry run") # pragma: no cover
|
||||||
log("Abort transaction") # pragma: no cover
|
log("Abort transaction") # pragma: no cover
|
||||||
if not test:
|
if not test:
|
||||||
transaction.commit() # pragma: no cover
|
transaction.commit() # pragma: no cover
|
||||||
return '\n'.join(out)
|
return '\n'.join(out)
|
||||||
|
@ -33,11 +33,11 @@
|
|||||||
<a i18n:name="enable_comment_workflow"
|
<a i18n:name="enable_comment_workflow"
|
||||||
i18n:translate="message_enable_comment_workflow" href=""
|
i18n:translate="message_enable_comment_workflow" href=""
|
||||||
tal:attributes="href string:${context/portal_url}/@@types-controlpanel?type_id=Discussion Item">
|
tal:attributes="href string:${context/portal_url}/@@types-controlpanel?type_id=Discussion Item">
|
||||||
enable the 'Comment Review Workflow' for the Comment content
|
enable the 'Comment Review Workflow' for the Comment content
|
||||||
type</a> before you can moderate comments here.
|
type</a> before you can moderate comments here.
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<form tal:condition="not:items">
|
<form tal:condition="not:items">
|
||||||
<fieldset id="fieldset-moderate-comments" class="formPanel">
|
<fieldset id="fieldset-moderate-comments" class="formPanel">
|
||||||
<p id="no-comments-message" i18n:translate="message_nothing_to_moderate">
|
<p id="no-comments-message" i18n:translate="message_nothing_to_moderate">
|
||||||
@ -114,7 +114,7 @@
|
|||||||
<a href=""
|
<a href=""
|
||||||
tal:attributes="href string:${item/getURL}/getText"
|
tal:attributes="href string:${item/getURL}/getText"
|
||||||
tal:condition="python:item.Description.endswith('[...]')"
|
tal:condition="python:item.Description.endswith('[...]')"
|
||||||
i18n:translate="label_show_full_comment_text"
|
i18n:translate="label_show_full_comment_text"
|
||||||
class="show-full-comment-text">show full comment text</a>
|
class="show-full-comment-text">show full comment text</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="actions">
|
<td class="actions">
|
||||||
|
@ -11,14 +11,14 @@ from Products.statusmessages.interfaces import IStatusMessage
|
|||||||
from plone.app.discussion.interfaces import _
|
from plone.app.discussion.interfaces import _
|
||||||
from plone.app.discussion.interfaces import IComment
|
from plone.app.discussion.interfaces import IComment
|
||||||
|
|
||||||
# Begin ugly hack. It works around a ContentProviderLookupError:
|
# Begin ugly hack. It works around a ContentProviderLookupError:
|
||||||
# plone.htmlhead error caused by Zope 2 permissions.
|
# plone.htmlhead error caused by Zope 2 permissions.
|
||||||
# This error occured on Plone 3.3.x only!
|
# This error occured on Plone 3.3.x only!
|
||||||
#
|
#
|
||||||
# Source:
|
# Source:
|
||||||
# http://athenageek.wordpress.com/2008/01/08/
|
# http://athenageek.wordpress.com/2008/01/08/
|
||||||
# contentproviderlookuperror-plonehtmlhead/
|
# contentproviderlookuperror-plonehtmlhead/
|
||||||
#
|
#
|
||||||
# Bug report: https://bugs.launchpad.net/zope2/+bug/176566
|
# Bug report: https://bugs.launchpad.net/zope2/+bug/176566
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ def _getContext(self): # pragma: no cover
|
|||||||
while getattr(self, '_is_wrapperish', None):
|
while getattr(self, '_is_wrapperish', None):
|
||||||
self = self.aq_parent
|
self = self.aq_parent
|
||||||
return self
|
return self
|
||||||
|
|
||||||
ZopeTwoPageTemplateFile._getContext = _getContext # pragma: no cover
|
ZopeTwoPageTemplateFile._getContext = _getContext # pragma: no cover
|
||||||
# End ugly hack.
|
# End ugly hack.
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ class View(BrowserView):
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
def moderation_enabled(self):
|
def moderation_enabled(self):
|
||||||
"""Returns true if a 'review workflow' is enabled on 'Discussion Item'
|
"""Returns true if a 'review workflow' is enabled on 'Discussion Item'
|
||||||
content type. A 'review workflow' is characterized by implementing
|
content type. A 'review workflow' is characterized by implementing
|
||||||
a 'pending' workflow state.
|
a 'pending' workflow state.
|
||||||
"""
|
"""
|
||||||
@ -78,7 +78,7 @@ class View(BrowserView):
|
|||||||
class ModerateCommentsEnabled(BrowserView):
|
class ModerateCommentsEnabled(BrowserView):
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
"""Returns true if a 'review workflow' is enabled on 'Discussion Item'
|
"""Returns true if a 'review workflow' is enabled on 'Discussion Item'
|
||||||
content type. A 'review workflow' is characterized by implementing
|
content type. A 'review workflow' is characterized by implementing
|
||||||
a 'pending' workflow state.
|
a 'pending' workflow state.
|
||||||
"""
|
"""
|
||||||
@ -91,26 +91,26 @@ class ModerateCommentsEnabled(BrowserView):
|
|||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
class DeleteComment(BrowserView):
|
class DeleteComment(BrowserView):
|
||||||
"""Delete a comment from a conversation.
|
"""Delete a comment from a conversation.
|
||||||
|
|
||||||
This view is always called directly on the comment object:
|
This view is always called directly on the comment object:
|
||||||
|
|
||||||
http://nohost/front-page/++conversation++default/1286289644723317/\
|
http://nohost/front-page/++conversation++default/1286289644723317/\
|
||||||
@@moderate-delete-comment
|
@@moderate-delete-comment
|
||||||
|
|
||||||
Each table row (comment) in the moderation view contains a hidden input
|
Each table row (comment) in the moderation view contains a hidden input
|
||||||
field with the absolute URL of the content object:
|
field with the absolute URL of the content object:
|
||||||
|
|
||||||
<input type="hidden"
|
<input type="hidden"
|
||||||
value="http://nohost/front-page/++conversation++default/\
|
value="http://nohost/front-page/++conversation++default/\
|
||||||
1286289644723317"
|
1286289644723317"
|
||||||
name="selected_obj_paths:list">
|
name="selected_obj_paths:list">
|
||||||
|
|
||||||
This absolute URL is called from a jQuery method that is bind to the
|
This absolute URL is called from a jQuery method that is bind to the
|
||||||
'delete' button of the table row. See javascripts/moderation.js for more
|
'delete' button of the table row. See javascripts/moderation.js for more
|
||||||
details.
|
details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
@ -132,23 +132,23 @@ class DeleteComment(BrowserView):
|
|||||||
|
|
||||||
class PublishComment(BrowserView):
|
class PublishComment(BrowserView):
|
||||||
"""Publish a comment.
|
"""Publish a comment.
|
||||||
|
|
||||||
This view is always called directly on the comment object:
|
This view is always called directly on the comment object:
|
||||||
|
|
||||||
http://nohost/front-page/++conversation++default/1286289644723317/\
|
http://nohost/front-page/++conversation++default/1286289644723317/\
|
||||||
@@moderate-publish-comment
|
@@moderate-publish-comment
|
||||||
|
|
||||||
Each table row (comment) in the moderation view contains a hidden input
|
Each table row (comment) in the moderation view contains a hidden input
|
||||||
field with the absolute URL of the content object:
|
field with the absolute URL of the content object:
|
||||||
|
|
||||||
<input type="hidden"
|
<input type="hidden"
|
||||||
value="http://nohost/front-page/++conversation++default/\
|
value="http://nohost/front-page/++conversation++default/\
|
||||||
1286289644723317"
|
1286289644723317"
|
||||||
name="selected_obj_paths:list">
|
name="selected_obj_paths:list">
|
||||||
|
|
||||||
This absolute URL is called from a jQuery method that is bind to the
|
This absolute URL is called from a jQuery method that is bind to the
|
||||||
'delete' button of the table row. See javascripts/moderation.js for more
|
'delete' button of the table row. See javascripts/moderation.js for more
|
||||||
details.
|
details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
@ -171,24 +171,24 @@ class PublishComment(BrowserView):
|
|||||||
|
|
||||||
class BulkActionsView(BrowserView):
|
class BulkActionsView(BrowserView):
|
||||||
"""Bulk actions (unapprove, approve, delete, mark as spam).
|
"""Bulk actions (unapprove, approve, delete, mark as spam).
|
||||||
|
|
||||||
Each table row of the moderation view has a checkbox with the absolute
|
Each table row of the moderation view has a checkbox with the absolute
|
||||||
path (without host and port) of the comment objects:
|
path (without host and port) of the comment objects:
|
||||||
|
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
name="paths:list"
|
name="paths:list"
|
||||||
value="/plone/front-page/++conversation++default/\
|
value="/plone/front-page/++conversation++default/\
|
||||||
1286289644723317"
|
1286289644723317"
|
||||||
id="cb_1286289644723317" />
|
id="cb_1286289644723317" />
|
||||||
|
|
||||||
If checked, the comment path will occur in the 'paths' variable of
|
If checked, the comment path will occur in the 'paths' variable of
|
||||||
the request when the bulk actions view is called. The bulk action
|
the request when the bulk actions view is called. The bulk action
|
||||||
(delete, publish, etc.) will be applied to all comments that are
|
(delete, publish, etc.) will be applied to all comments that are
|
||||||
included.
|
included.
|
||||||
|
|
||||||
The paths have to be 'traversable':
|
The paths have to be 'traversable':
|
||||||
|
|
||||||
/plone/front-page/++conversation++default/1286289644723317
|
/plone/front-page/++conversation++default/1286289644723317
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -219,11 +219,11 @@ class BulkActionsView(BrowserView):
|
|||||||
|
|
||||||
def publish(self):
|
def publish(self):
|
||||||
"""Publishes all comments in the paths variable.
|
"""Publishes all comments in the paths variable.
|
||||||
|
|
||||||
Expects a list of absolute paths (without host and port):
|
Expects a list of absolute paths (without host and port):
|
||||||
|
|
||||||
/Plone/startseite/++conversation++default/1286200010610352
|
/Plone/startseite/++conversation++default/1286200010610352
|
||||||
|
|
||||||
"""
|
"""
|
||||||
context = aq_inner(self.context)
|
context = aq_inner(self.context)
|
||||||
for path in self.paths:
|
for path in self.paths:
|
||||||
@ -240,12 +240,12 @@ class BulkActionsView(BrowserView):
|
|||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
"""Deletes all comments in the paths variable.
|
"""Deletes all comments in the paths variable.
|
||||||
|
|
||||||
Expects a list of absolute paths (without host and port):
|
Expects a list of absolute paths (without host and port):
|
||||||
|
|
||||||
/Plone/startseite/++conversation++default/1286200010610352
|
/Plone/startseite/++conversation++default/1286200010610352
|
||||||
|
|
||||||
"""
|
"""
|
||||||
context = aq_inner(self.context)
|
context = aq_inner(self.context)
|
||||||
for path in self.paths:
|
for path in self.paths:
|
||||||
comment = context.restrictedTraverse(path)
|
comment = context.restrictedTraverse(path)
|
||||||
|
@ -18,21 +18,21 @@ class ConversationNamespace(object):
|
|||||||
(unnamed) adapter. This is to work around a bug in OFS.Traversable which
|
(unnamed) adapter. This is to work around a bug in OFS.Traversable which
|
||||||
does not allow traversal to namespaces with an empty string name.
|
does not allow traversal to namespaces with an empty string name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
implements(ITraversable)
|
implements(ITraversable)
|
||||||
adapts(Interface, IBrowserRequest)
|
adapts(Interface, IBrowserRequest)
|
||||||
|
|
||||||
def __init__(self, context, request=None):
|
def __init__(self, context, request=None):
|
||||||
self.context = context
|
self.context = context
|
||||||
self.request = request
|
self.request = request
|
||||||
|
|
||||||
def traverse(self, name, ignore):
|
def traverse(self, name, ignore):
|
||||||
|
|
||||||
if name == "default":
|
if name == "default":
|
||||||
name = u""
|
name = u""
|
||||||
|
|
||||||
conversation = queryAdapter(self.context, IConversation, name=name)
|
conversation = queryAdapter(self.context, IConversation, name=name)
|
||||||
if conversation is None:
|
if conversation is None:
|
||||||
raise TraversalError(name) # pragma: no cover
|
raise TraversalError(name) # pragma: no cover
|
||||||
|
|
||||||
return conversation
|
return conversation
|
||||||
|
@ -49,7 +49,7 @@ class CaptchaValidator(validator.SimpleFieldValidator):
|
|||||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||||
|
|
||||||
if settings.captcha in ('captcha', 'recaptcha', 'norobots'):
|
if settings.captcha in ('captcha', 'recaptcha', 'norobots'):
|
||||||
captcha = getMultiAdapter((aq_inner(self.context), self.request),
|
captcha = getMultiAdapter((aq_inner(self.context), self.request),
|
||||||
name=settings.captcha)
|
name=settings.captcha)
|
||||||
if not captcha.verify(input=value):
|
if not captcha.verify(input=value):
|
||||||
if settings.captcha == 'norobots':
|
if settings.captcha == 'norobots':
|
||||||
@ -61,6 +61,6 @@ class CaptchaValidator(validator.SimpleFieldValidator):
|
|||||||
|
|
||||||
|
|
||||||
# Register Captcha validator for the Captcha field in the ICaptcha Form
|
# Register Captcha validator for the Captcha field in the ICaptcha Form
|
||||||
validator.WidgetValidatorDiscriminators(CaptchaValidator,
|
validator.WidgetValidatorDiscriminators(CaptchaValidator,
|
||||||
field=ICaptcha['captcha'])
|
field=ICaptcha['captcha'])
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ except: # pragma: no cover
|
|||||||
|
|
||||||
COMMENT_TITLE = _(u"comment_title",
|
COMMENT_TITLE = _(u"comment_title",
|
||||||
default=u"${creator} on ${content}")
|
default=u"${creator} on ${content}")
|
||||||
|
|
||||||
MAIL_NOTIFICATION_MESSAGE = _(u"mail_notification_message",
|
MAIL_NOTIFICATION_MESSAGE = _(u"mail_notification_message",
|
||||||
default=u"A comment on '${title}' "
|
default=u"A comment on '${title}' "
|
||||||
"has been posted here: ${link}")
|
"has been posted here: ${link}")
|
||||||
@ -95,7 +95,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
|||||||
|
|
||||||
author_name = None
|
author_name = None
|
||||||
author_email = None
|
author_email = None
|
||||||
|
|
||||||
user_notification = None
|
user_notification = None
|
||||||
|
|
||||||
# Note: we want to use zope.component.createObject() to instantiate
|
# Note: we want to use zope.component.createObject() to instantiate
|
||||||
@ -127,13 +127,13 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
|||||||
"""The title of the comment.
|
"""The title of the comment.
|
||||||
"""
|
"""
|
||||||
if not self.creator:
|
if not self.creator:
|
||||||
creator = translate(Message(_(u"label_anonymous",
|
creator = translate(Message(_(u"label_anonymous",
|
||||||
default=u"Anonymous")))
|
default=u"Anonymous")))
|
||||||
else:
|
else:
|
||||||
creator = self.creator
|
creator = self.creator
|
||||||
creator = creator
|
creator = creator
|
||||||
|
|
||||||
# Fetch the content object (the parent of the comment is the
|
# Fetch the content object (the parent of the comment is the
|
||||||
# conversation, the parent of the conversation is the content object).
|
# conversation, the parent of the conversation is the content object).
|
||||||
content = aq_base(self.__parent__.__parent__)
|
content = aq_base(self.__parent__.__parent__)
|
||||||
title = translate(
|
title = translate(
|
||||||
@ -141,7 +141,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
|||||||
mapping={'creator': creator,
|
mapping={'creator': creator,
|
||||||
'content': safe_unicode(content.Title())}))
|
'content': safe_unicode(content.Title())}))
|
||||||
return title
|
return title
|
||||||
|
|
||||||
def Creator(self):
|
def Creator(self):
|
||||||
"""The name of the person who wrote the comment.
|
"""The name of the person who wrote the comment.
|
||||||
"""
|
"""
|
||||||
@ -176,8 +176,8 @@ def notify_content_object(obj, event):
|
|||||||
"""Tell the content object when a comment is added
|
"""Tell the content object when a comment is added
|
||||||
"""
|
"""
|
||||||
content_obj = aq_parent(aq_parent(obj))
|
content_obj = aq_parent(aq_parent(obj))
|
||||||
content_obj.reindexObject(idxs=('total_comments',
|
content_obj.reindexObject(idxs=('total_comments',
|
||||||
'last_comment_date',
|
'last_comment_date',
|
||||||
'commentators',))
|
'commentators',))
|
||||||
|
|
||||||
def notify_content_object_deleted(obj, event):
|
def notify_content_object_deleted(obj, event):
|
||||||
@ -189,14 +189,14 @@ def notify_content_object_deleted(obj, event):
|
|||||||
for comment in conversation.getComments():
|
for comment in conversation.getComments():
|
||||||
del conversation[comment.id]
|
del conversation[comment.id]
|
||||||
|
|
||||||
def notify_user(obj, event):
|
def notify_user(obj, event):
|
||||||
"""Tell users when a comment has been added.
|
"""Tell users when a comment has been added.
|
||||||
|
|
||||||
This method composes and sends emails to all users that have added a
|
This method composes and sends emails to all users that have added a
|
||||||
comment to this conversation and enabled user notification.
|
comment to this conversation and enabled user notification.
|
||||||
|
|
||||||
This requires the user_notification setting to be enabled in the
|
This requires the user_notification setting to be enabled in the
|
||||||
discussion control panel.
|
discussion control panel.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Check if user notification is enabled
|
# Check if user notification is enabled
|
||||||
@ -268,36 +268,36 @@ def notify_user(obj, event):
|
|||||||
|
|
||||||
def notify_moderator(obj, event):
|
def notify_moderator(obj, event):
|
||||||
"""Tell the moderator when a comment needs attention.
|
"""Tell the moderator when a comment needs attention.
|
||||||
|
|
||||||
This method sends an email to the site admin (mail control panel setting)
|
This method sends an email to the site admin (mail control panel setting)
|
||||||
if comment moderation is enabled and a new comment has been added that
|
if comment moderation is enabled and a new comment has been added that
|
||||||
needs to be approved.
|
needs to be approved.
|
||||||
|
|
||||||
This requires the moderator_notification to be enabled in the discussion
|
This requires the moderator_notification to be enabled in the discussion
|
||||||
control panel and the comment_review_workflow enabled for the comment
|
control panel and the comment_review_workflow enabled for the comment
|
||||||
content type.
|
content type.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Check if moderator notification is enabled
|
# Check if moderator notification is enabled
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||||
if not settings.moderator_notification_enabled:
|
if not settings.moderator_notification_enabled:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if the current workflow implements a pending state.
|
# Check if the current workflow implements a pending state.
|
||||||
wf_tool = getToolByName(obj, 'portal_workflow')
|
wf_tool = getToolByName(obj, 'portal_workflow')
|
||||||
comment_workflow = wf_tool.getChainForPortalType('Discussion Item')[0]
|
comment_workflow = wf_tool.getChainForPortalType('Discussion Item')[0]
|
||||||
comment_workflow = wf_tool[comment_workflow]
|
comment_workflow = wf_tool[comment_workflow]
|
||||||
if 'pending' not in comment_workflow.states:
|
if 'pending' not in comment_workflow.states:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get informations that are necessary to send an email
|
# Get informations that are necessary to send an email
|
||||||
mail_host = getToolByName(obj, 'MailHost')
|
mail_host = getToolByName(obj, 'MailHost')
|
||||||
portal_url = getToolByName(obj, 'portal_url')
|
portal_url = getToolByName(obj, 'portal_url')
|
||||||
portal = portal_url.getPortalObject()
|
portal = portal_url.getPortalObject()
|
||||||
sender = portal.getProperty('email_from_address')
|
sender = portal.getProperty('email_from_address')
|
||||||
mto = portal.getProperty('email_from_address')
|
mto = portal.getProperty('email_from_address')
|
||||||
|
|
||||||
# Check if a sender address is available
|
# Check if a sender address is available
|
||||||
if not sender:
|
if not sender:
|
||||||
return
|
return
|
||||||
@ -305,7 +305,7 @@ def notify_moderator(obj, event):
|
|||||||
conversation = aq_parent(obj)
|
conversation = aq_parent(obj)
|
||||||
content_object = aq_parent(conversation)
|
content_object = aq_parent(conversation)
|
||||||
|
|
||||||
# Compose email
|
# Compose email
|
||||||
#comment = conversation.getComments().next()
|
#comment = conversation.getComments().next()
|
||||||
subject = translate(_(u"A comment has been posted."), context=obj.REQUEST)
|
subject = translate(_(u"A comment has been posted."), context=obj.REQUEST)
|
||||||
message = translate(Message(MAIL_NOTIFICATION_MESSAGE,
|
message = translate(Message(MAIL_NOTIFICATION_MESSAGE,
|
||||||
@ -327,10 +327,10 @@ def notify_moderator(obj, event):
|
|||||||
message)
|
message)
|
||||||
else: # pragma: no cover
|
else: # pragma: no cover
|
||||||
try:
|
try:
|
||||||
mail_host.secureSend(message,
|
mail_host.secureSend(message,
|
||||||
mto,
|
mto,
|
||||||
sender,
|
sender,
|
||||||
subject=subject,
|
subject=subject,
|
||||||
charset='utf-8')
|
charset='utf-8')
|
||||||
except SMTPException, e:
|
except SMTPException, e:
|
||||||
logger.error('SMTP exception (%s) while trying to send an ' +
|
logger.error('SMTP exception (%s) while trying to send an ' +
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
<five:registerPackage package="." />
|
<five:registerPackage package="." />
|
||||||
|
|
||||||
<include package="plone.indexer" />
|
<include package="plone.indexer" />
|
||||||
|
|
||||||
<!-- XXX: Excluding plone.app.uuid for Plone 3 is only a temporary 'fix'.
|
<!-- XXX: Excluding plone.app.uuid for Plone 3 is only a temporary 'fix'.
|
||||||
plone.app.uuid causes the IObjectAddedEvent to be fired twice on
|
plone.app.uuid causes the IObjectAddedEvent to be fired twice on
|
||||||
Plone 3. This causes the email notifications to be send twice.
|
Plone 3. This causes the email notifications to be send twice.
|
||||||
|
|
||||||
This means that https://dev.plone.org/plone/ticket/10652 is fixed only
|
This means that https://dev.plone.org/plone/ticket/10652 is fixed only
|
||||||
for Plone 4.
|
for Plone 4.
|
||||||
-->
|
-->
|
||||||
@ -29,7 +29,7 @@
|
|||||||
<include package=".browser" />
|
<include package=".browser" />
|
||||||
|
|
||||||
<i18n:registerTranslations directory="locales" />
|
<i18n:registerTranslations directory="locales" />
|
||||||
|
|
||||||
<!-- Register the installation GenericSetup extension profile -->
|
<!-- Register the installation GenericSetup extension profile -->
|
||||||
<genericsetup:registerProfile
|
<genericsetup:registerProfile
|
||||||
name="default"
|
name="default"
|
||||||
@ -59,7 +59,7 @@
|
|||||||
<require attributes="Title Creator getId getText" permission="zope2.View" />
|
<require attributes="Title Creator getId getText" permission="zope2.View" />
|
||||||
</class>
|
</class>
|
||||||
|
|
||||||
|
|
||||||
<!-- XXX: Excluding plone.uuid for Plone 3 is only a temporary 'fix'.
|
<!-- XXX: Excluding plone.uuid for Plone 3 is only a temporary 'fix'.
|
||||||
See the comment above -->
|
See the comment above -->
|
||||||
<configure zcml:condition="have plone-4">
|
<configure zcml:condition="have plone-4">
|
||||||
|
@ -484,6 +484,6 @@ class CommentReplies(ConversationReplies):
|
|||||||
comment.in_reply_to = self.comment_id
|
comment.in_reply_to = self.comment_id
|
||||||
return self.conversation.addComment(comment)
|
return self.conversation.addComment(comment)
|
||||||
|
|
||||||
# Dict API is inherited, written in terms of self.conversation and
|
# Dict API is inherited, written in terms of self.conversation and
|
||||||
# self.children
|
# self.children
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class IDiscussionSettings(Interface):
|
|||||||
required=False,
|
required=False,
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
anonymous_comments = schema.Bool(
|
anonymous_comments = schema.Bool(
|
||||||
title=_(u"label_anonymous_comments",
|
title=_(u"label_anonymous_comments",
|
||||||
default="Enable anonymous comments"),
|
default="Enable anonymous comments"),
|
||||||
@ -43,7 +43,7 @@ class IDiscussionSettings(Interface):
|
|||||||
required=False,
|
required=False,
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
moderation_enabled = schema.Bool(
|
moderation_enabled = schema.Bool(
|
||||||
title=_(u"label_moderation_enabled",
|
title=_(u"label_moderation_enabled",
|
||||||
default="Enable comment moderation"),
|
default="Enable comment moderation"),
|
||||||
@ -70,7 +70,7 @@ class IDiscussionSettings(Interface):
|
|||||||
"'Intelligent text' converts plain text into HTML " +
|
"'Intelligent text' converts plain text into HTML " +
|
||||||
"where line breaks and indentation is preserved, " +
|
"where line breaks and indentation is preserved, " +
|
||||||
"and web and email addresses are made into " +
|
"and web and email addresses are made into " +
|
||||||
"clickable links."),
|
"clickable links."),
|
||||||
required=True,
|
required=True,
|
||||||
default='text/plain',
|
default='text/plain',
|
||||||
vocabulary='plone.app.discussion.vocabularies.TextTransformVocabulary',
|
vocabulary='plone.app.discussion.vocabularies.TextTransformVocabulary',
|
||||||
@ -100,7 +100,7 @@ class IDiscussionSettings(Interface):
|
|||||||
required=False,
|
required=False,
|
||||||
default=True,
|
default=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
moderator_notification_enabled = schema.Bool(
|
moderator_notification_enabled = schema.Bool(
|
||||||
title=_(u"label_moderator_notification_enabled",
|
title=_(u"label_moderator_notification_enabled",
|
||||||
default=u"Enable moderator email notification"),
|
default=u"Enable moderator email notification"),
|
||||||
|
@ -12,18 +12,18 @@
|
|||||||
zope.lifecycleevent.interfaces.IObjectAddedEvent"
|
zope.lifecycleevent.interfaces.IObjectAddedEvent"
|
||||||
handler=".comment.notify_user"
|
handler=".comment.notify_user"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<subscriber
|
<subscriber
|
||||||
for="plone.app.discussion.interfaces.IComment
|
for="plone.app.discussion.interfaces.IComment
|
||||||
zope.lifecycleevent.interfaces.IObjectAddedEvent"
|
zope.lifecycleevent.interfaces.IObjectAddedEvent"
|
||||||
handler=".comment.notify_moderator"
|
handler=".comment.notify_moderator"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</configure>
|
</configure>
|
||||||
|
|
||||||
|
|
||||||
<!-- Plone 4 Event Subscribers -->
|
<!-- Plone 4 Event Subscribers -->
|
||||||
|
|
||||||
<configure zcml:condition="installed zope.app.container">
|
<configure zcml:condition="installed zope.app.container">
|
||||||
|
|
||||||
<subscriber
|
<subscriber
|
||||||
|
@ -15,7 +15,7 @@ def patchedClearFindAndRebuild(self):
|
|||||||
with an indexObject method), and reindexes them.
|
with an indexObject method), and reindexes them.
|
||||||
This may take a long time.
|
This may take a long time.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def indexObject(obj, path):
|
def indexObject(obj, path):
|
||||||
|
|
||||||
if (base_hasattr(obj, 'indexObject') and
|
if (base_hasattr(obj, 'indexObject') and
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<componentregistry>
|
<componentregistry>
|
||||||
<utilities>
|
<utilities>
|
||||||
<utility
|
<utility
|
||||||
interface="plone.app.discussion.interfaces.ICommentingTool"
|
interface="plone.app.discussion.interfaces.ICommentingTool"
|
||||||
object="portal_discussion"
|
object="portal_discussion"
|
||||||
/>
|
/>
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
<guard>
|
<guard>
|
||||||
</guard>
|
</guard>
|
||||||
</variable>
|
</variable>
|
||||||
|
|
||||||
<variable variable_id="actor" for_catalog="False"
|
<variable variable_id="actor" for_catalog="False"
|
||||||
for_status="True" update_always="True">
|
for_status="True" update_always="True">
|
||||||
<description i18n:translate="">
|
<description i18n:translate="">
|
||||||
@ -91,7 +91,7 @@
|
|||||||
<guard>
|
<guard>
|
||||||
</guard>
|
</guard>
|
||||||
</variable>
|
</variable>
|
||||||
|
|
||||||
<variable variable_id="comments" for_catalog="False"
|
<variable variable_id="comments" for_catalog="False"
|
||||||
for_status="True" update_always="True">
|
for_status="True" update_always="True">
|
||||||
<description i18n:translate="">
|
<description i18n:translate="">
|
||||||
@ -103,7 +103,7 @@
|
|||||||
<guard>
|
<guard>
|
||||||
</guard>
|
</guard>
|
||||||
</variable>
|
</variable>
|
||||||
|
|
||||||
<variable variable_id="review_history" for_catalog="False"
|
<variable variable_id="review_history" for_catalog="False"
|
||||||
for_status="False" update_always="False">
|
for_status="False" update_always="False">
|
||||||
<description i18n:translate="">
|
<description i18n:translate="">
|
||||||
@ -117,7 +117,7 @@
|
|||||||
<guard-permission>Review portal content</guard-permission>
|
<guard-permission>Review portal content</guard-permission>
|
||||||
</guard>
|
</guard>
|
||||||
</variable>
|
</variable>
|
||||||
|
|
||||||
<variable variable_id="time" for_catalog="False"
|
<variable variable_id="time" for_catalog="False"
|
||||||
for_status="True" update_always="True">
|
for_status="True" update_always="True">
|
||||||
<description i18n:translate="">
|
<description i18n:translate="">
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
<guard>
|
<guard>
|
||||||
</guard>
|
</guard>
|
||||||
</variable>
|
</variable>
|
||||||
|
|
||||||
<variable variable_id="actor" for_catalog="False"
|
<variable variable_id="actor" for_catalog="False"
|
||||||
for_status="True" update_always="True">
|
for_status="True" update_always="True">
|
||||||
<description i18n:translate="">
|
<description i18n:translate="">
|
||||||
@ -64,7 +64,7 @@
|
|||||||
<guard>
|
<guard>
|
||||||
</guard>
|
</guard>
|
||||||
</variable>
|
</variable>
|
||||||
|
|
||||||
<variable variable_id="comments" for_catalog="False"
|
<variable variable_id="comments" for_catalog="False"
|
||||||
for_status="True" update_always="True">
|
for_status="True" update_always="True">
|
||||||
<description i18n:translate="">
|
<description i18n:translate="">
|
||||||
@ -76,7 +76,7 @@
|
|||||||
<guard>
|
<guard>
|
||||||
</guard>
|
</guard>
|
||||||
</variable>
|
</variable>
|
||||||
|
|
||||||
<variable variable_id="review_history" for_catalog="False"
|
<variable variable_id="review_history" for_catalog="False"
|
||||||
for_status="False" update_always="False">
|
for_status="False" update_always="False">
|
||||||
<description i18n:translate="">
|
<description i18n:translate="">
|
||||||
@ -90,7 +90,7 @@
|
|||||||
<guard-permission>Review portal content</guard-permission>
|
<guard-permission>Review portal content</guard-permission>
|
||||||
</guard>
|
</guard>
|
||||||
</variable>
|
</variable>
|
||||||
|
|
||||||
<variable variable_id="time" for_catalog="False"
|
<variable variable_id="time" for_catalog="False"
|
||||||
for_status="True" update_always="True">
|
for_status="True" update_always="True">
|
||||||
<description i18n:translate="">
|
<description i18n:translate="">
|
||||||
|
@ -42,12 +42,12 @@
|
|||||||
zope.lifecycleevent.interfaces.IObjectRemovedEvent"
|
zope.lifecycleevent.interfaces.IObjectRemovedEvent"
|
||||||
handler=".comment.notify_content_object_deleted"
|
handler=".comment.notify_content_object_deleted"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</configure>
|
</configure>
|
||||||
|
|
||||||
|
|
||||||
<!-- Plone 4 Event Subscribers -->
|
<!-- Plone 4 Event Subscribers -->
|
||||||
|
|
||||||
<configure zcml:condition="installed zope.app.container">
|
<configure zcml:condition="installed zope.app.container">
|
||||||
|
|
||||||
<subscriber
|
<subscriber
|
||||||
@ -88,7 +88,7 @@
|
|||||||
</configure>
|
</configure>
|
||||||
|
|
||||||
<!-- Control panel event subscribers -->
|
<!-- Control panel event subscribers -->
|
||||||
|
|
||||||
<subscriber
|
<subscriber
|
||||||
for="plone.app.controlpanel.interfaces.IConfigurationChangedEvent"
|
for="plone.app.controlpanel.interfaces.IConfigurationChangedEvent"
|
||||||
handler=".browser.controlpanel.notify_configuration_changed"
|
handler=".browser.controlpanel.notify_configuration_changed"
|
||||||
@ -97,6 +97,6 @@
|
|||||||
<subscriber
|
<subscriber
|
||||||
for="plone.registry.interfaces.IRecordModifiedEvent"
|
for="plone.registry.interfaces.IRecordModifiedEvent"
|
||||||
handler=".browser.controlpanel.notify_configuration_changed"
|
handler=".browser.controlpanel.notify_configuration_changed"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</configure>
|
</configure>
|
||||||
|
@ -23,12 +23,12 @@ class PloneAppDiscussion(PloneSandboxLayer):
|
|||||||
USER_WITH_FULLNAME_PASSWORD = 'secret'
|
USER_WITH_FULLNAME_PASSWORD = 'secret'
|
||||||
MANAGER_USER_NAME = 'manager'
|
MANAGER_USER_NAME = 'manager'
|
||||||
MANAGER_USER_PASSWORD = 'secret'
|
MANAGER_USER_PASSWORD = 'secret'
|
||||||
|
|
||||||
def setUpZope(self, app, configurationContext):
|
def setUpZope(self, app, configurationContext):
|
||||||
# Load ZCML
|
# Load ZCML
|
||||||
import plone.app.discussion
|
import plone.app.discussion
|
||||||
xmlconfig.file('configure.zcml',
|
xmlconfig.file('configure.zcml',
|
||||||
plone.app.discussion,
|
plone.app.discussion,
|
||||||
context=configurationContext)
|
context=configurationContext)
|
||||||
|
|
||||||
def setUpPloneSite(self, portal):
|
def setUpPloneSite(self, portal):
|
||||||
@ -55,8 +55,8 @@ class PloneAppDiscussion(PloneSandboxLayer):
|
|||||||
['Member'],
|
['Member'],
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
mtool = getToolByName(portal, 'portal_membership', None)
|
mtool = getToolByName(portal, 'portal_membership', None)
|
||||||
mtool.addMember('jim', 'Jim', ['Member'], [])
|
mtool.addMember('jim', 'Jim', ['Member'], [])
|
||||||
mtool.getMemberById('jim').setMemberProperties({"fullname": 'Jim Fult\xc3\xb8rn'})
|
mtool.getMemberById('jim').setMemberProperties({"fullname": 'Jim Fult\xc3\xb8rn'})
|
||||||
|
|
||||||
acl_users.userFolderAddUser(
|
acl_users.userFolderAddUser(
|
||||||
@ -68,8 +68,8 @@ class PloneAppDiscussion(PloneSandboxLayer):
|
|||||||
|
|
||||||
PLONE_APP_DISCUSSION_FIXTURE = PloneAppDiscussion()
|
PLONE_APP_DISCUSSION_FIXTURE = PloneAppDiscussion()
|
||||||
PLONE_APP_DISCUSSION_INTEGRATION_TESTING = IntegrationTesting(
|
PLONE_APP_DISCUSSION_INTEGRATION_TESTING = IntegrationTesting(
|
||||||
bases=(PLONE_APP_DISCUSSION_FIXTURE,),
|
bases=(PLONE_APP_DISCUSSION_FIXTURE,),
|
||||||
name="PloneAppDiscussion:Integration")
|
name="PloneAppDiscussion:Integration")
|
||||||
PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING = FunctionalTesting(
|
PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING = FunctionalTesting(
|
||||||
bases=(PLONE_APP_DISCUSSION_FIXTURE,),
|
bases=(PLONE_APP_DISCUSSION_FIXTURE,),
|
||||||
name="PloneAppDiscussion:Functional")
|
name="PloneAppDiscussion:Functional")
|
||||||
|
@ -19,13 +19,13 @@ class CatalogSetupTest(PloneTestCase):
|
|||||||
layer = DiscussionLayer
|
layer = DiscussionLayer
|
||||||
|
|
||||||
def test_catalog_installed(self):
|
def test_catalog_installed(self):
|
||||||
self.failUnless('total_comments' in
|
self.failUnless('total_comments' in
|
||||||
self.portal.portal_catalog.indexes())
|
self.portal.portal_catalog.indexes())
|
||||||
self.failUnless('commentators' in
|
self.failUnless('commentators' in
|
||||||
self.portal.portal_catalog.indexes())
|
self.portal.portal_catalog.indexes())
|
||||||
self.failUnless('total_comments' in
|
self.failUnless('total_comments' in
|
||||||
self.portal.portal_catalog.schema())
|
self.portal.portal_catalog.schema())
|
||||||
self.failUnless('in_response_to' in
|
self.failUnless('in_response_to' in
|
||||||
self.portal.portal_catalog.schema())
|
self.portal.portal_catalog.schema())
|
||||||
|
|
||||||
def test_collection_criteria_installed(self):
|
def test_collection_criteria_installed(self):
|
||||||
@ -44,8 +44,8 @@ class ConversationCatalogTest(PloneTestCase):
|
|||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
# First we need to create some content.
|
# First we need to create some content.
|
||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
self.portal.invokeFactory(id='doc1',
|
self.portal.invokeFactory(id='doc1',
|
||||||
Title='Document 1',
|
Title='Document 1',
|
||||||
type_name='Document')
|
type_name='Document')
|
||||||
|
|
||||||
self.catalog = getToolByName(self.portal, 'portal_catalog')
|
self.catalog = getToolByName(self.portal, 'portal_catalog')
|
||||||
@ -64,7 +64,7 @@ class ConversationCatalogTest(PloneTestCase):
|
|||||||
self.comment_id = new_comment1_id
|
self.comment_id = new_comment1_id
|
||||||
|
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
||||||
portal_type = "Document"
|
portal_type = "Document"
|
||||||
)
|
)
|
||||||
@ -88,7 +88,7 @@ class ConversationCatalogTest(PloneTestCase):
|
|||||||
'++conversation++default/%s' % new_comment2_id)
|
'++conversation++default/%s' % new_comment2_id)
|
||||||
comment2.reindexObject()
|
comment2.reindexObject()
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
||||||
portal_type = "Document"
|
portal_type = "Document"
|
||||||
)
|
)
|
||||||
@ -97,7 +97,7 @@ class ConversationCatalogTest(PloneTestCase):
|
|||||||
|
|
||||||
def test_last_comment_date(self):
|
def test_last_comment_date(self):
|
||||||
self.failUnless(self.doc1_brain.has_key('last_comment_date'))
|
self.failUnless(self.doc1_brain.has_key('last_comment_date'))
|
||||||
self.assertEquals(self.doc1_brain.last_comment_date,
|
self.assertEquals(self.doc1_brain.last_comment_date,
|
||||||
datetime(2006, 9, 17, 14, 18, 12))
|
datetime(2006, 9, 17, 14, 18, 12))
|
||||||
|
|
||||||
# Add another comment and check if last comment date is updated.
|
# Add another comment and check if last comment date is updated.
|
||||||
@ -113,31 +113,31 @@ class ConversationCatalogTest(PloneTestCase):
|
|||||||
'++conversation++default/%s' % new_comment2_id)
|
'++conversation++default/%s' % new_comment2_id)
|
||||||
comment2.reindexObject()
|
comment2.reindexObject()
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
||||||
portal_type = "Document"
|
portal_type = "Document"
|
||||||
)
|
)
|
||||||
doc1_brain = brains[0]
|
doc1_brain = brains[0]
|
||||||
self.assertEquals(doc1_brain.last_comment_date,
|
self.assertEquals(doc1_brain.last_comment_date,
|
||||||
datetime(2009, 9, 17, 14, 18, 12))
|
datetime(2009, 9, 17, 14, 18, 12))
|
||||||
|
|
||||||
# Remove the comment again
|
# Remove the comment again
|
||||||
del self.conversation[new_comment2_id]
|
del self.conversation[new_comment2_id]
|
||||||
|
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
||||||
portal_type = "Document"
|
portal_type = "Document"
|
||||||
)
|
)
|
||||||
doc1_brain = brains[0]
|
doc1_brain = brains[0]
|
||||||
|
|
||||||
self.assertEquals(doc1_brain.last_comment_date,
|
self.assertEquals(doc1_brain.last_comment_date,
|
||||||
datetime(2006, 9, 17, 14, 18, 12))
|
datetime(2006, 9, 17, 14, 18, 12))
|
||||||
|
|
||||||
# remove all comments
|
# remove all comments
|
||||||
del self.conversation[self.new_comment1_id]
|
del self.conversation[self.new_comment1_id]
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
||||||
portal_type = "Document"
|
portal_type = "Document"
|
||||||
)
|
)
|
||||||
@ -161,7 +161,7 @@ class ConversationCatalogTest(PloneTestCase):
|
|||||||
comment2.reindexObject()
|
comment2.reindexObject()
|
||||||
|
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
||||||
portal_type = "Document"
|
portal_type = "Document"
|
||||||
)
|
)
|
||||||
@ -172,7 +172,7 @@ class ConversationCatalogTest(PloneTestCase):
|
|||||||
# remove one comments
|
# remove one comments
|
||||||
del self.conversation[new_comment2_id]
|
del self.conversation[new_comment2_id]
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
||||||
portal_type = "Document"
|
portal_type = "Document"
|
||||||
)
|
)
|
||||||
@ -182,7 +182,7 @@ class ConversationCatalogTest(PloneTestCase):
|
|||||||
# remove all comments
|
# remove all comments
|
||||||
del self.conversation[self.new_comment1_id]
|
del self.conversation[self.new_comment1_id]
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
||||||
portal_type = "Document"
|
portal_type = "Document"
|
||||||
)
|
)
|
||||||
@ -191,7 +191,7 @@ class ConversationCatalogTest(PloneTestCase):
|
|||||||
|
|
||||||
def test_conversation_indexes_not_in_comments(self):
|
def test_conversation_indexes_not_in_comments(self):
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
'/'.join(self.portal.doc1.getPhysicalPath()) },
|
||||||
portal_type = "Discussion Item"
|
portal_type = "Discussion Item"
|
||||||
)
|
)
|
||||||
@ -208,8 +208,8 @@ class CommentCatalogTest(PloneTestCase):
|
|||||||
"""Create a document with a comment.
|
"""Create a document with a comment.
|
||||||
"""
|
"""
|
||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
self.portal.invokeFactory(id='doc1',
|
self.portal.invokeFactory(id='doc1',
|
||||||
title='Document 1',
|
title='Document 1',
|
||||||
type_name='Document')
|
type_name='Document')
|
||||||
self.catalog = getToolByName(self.portal, 'portal_catalog')
|
self.catalog = getToolByName(self.portal, 'portal_catalog')
|
||||||
|
|
||||||
@ -226,13 +226,13 @@ class CommentCatalogTest(PloneTestCase):
|
|||||||
self.comment = self.portal.doc1.restrictedTraverse(
|
self.comment = self.portal.doc1.restrictedTraverse(
|
||||||
'++conversation++default/%s' % new_comment1_id)
|
'++conversation++default/%s' % new_comment1_id)
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.comment.getPhysicalPath()) })
|
'/'.join(self.comment.getPhysicalPath()) })
|
||||||
self.comment_brain = brains[0]
|
self.comment_brain = brains[0]
|
||||||
|
|
||||||
def test_title(self):
|
def test_title(self):
|
||||||
self.assertEquals(self.comment_brain.Title, 'Jim on Document 1')
|
self.assertEquals(self.comment_brain.Title, 'Jim on Document 1')
|
||||||
|
|
||||||
def test_no_name_title(self):
|
def test_no_name_title(self):
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
comment.text = 'Comment text'
|
comment.text = 'Comment text'
|
||||||
@ -242,7 +242,7 @@ class CommentCatalogTest(PloneTestCase):
|
|||||||
comment = self.portal.doc1.restrictedTraverse(
|
comment = self.portal.doc1.restrictedTraverse(
|
||||||
'++conversation++default/%s' % cid)
|
'++conversation++default/%s' % cid)
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(comment.getPhysicalPath()) })
|
'/'.join(comment.getPhysicalPath()) })
|
||||||
comment_brain = brains[0]
|
comment_brain = brains[0]
|
||||||
self.assertEquals(comment_brain.Title, "Anonymous on Document 1")
|
self.assertEquals(comment_brain.Title, "Anonymous on Document 1")
|
||||||
@ -266,13 +266,13 @@ class CommentCatalogTest(PloneTestCase):
|
|||||||
|
|
||||||
def test_add_comment(self):
|
def test_add_comment(self):
|
||||||
self.failUnless(self.comment_brain)
|
self.failUnless(self.comment_brain)
|
||||||
|
|
||||||
def test_delete_comment(self):
|
def test_delete_comment(self):
|
||||||
# Make sure a comment is removed from the catalog as well when it is
|
# Make sure a comment is removed from the catalog as well when it is
|
||||||
# deleted.
|
# deleted.
|
||||||
del self.conversation[self.comment_id]
|
del self.conversation[self.comment_id]
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
path = {'query' :
|
path = {'query' :
|
||||||
'/'.join(self.comment.getPhysicalPath()) })
|
'/'.join(self.comment.getPhysicalPath()) })
|
||||||
self.assertEquals(len(brains), 0)
|
self.assertEquals(len(brains), 0)
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ class CommentCatalogTest(PloneTestCase):
|
|||||||
self.portal.manage_delObjects(["doc1"])
|
self.portal.manage_delObjects(["doc1"])
|
||||||
brains = self.catalog.searchResults(portal_type = 'Discussion Item')
|
brains = self.catalog.searchResults(portal_type = 'Discussion Item')
|
||||||
self.assertEquals(len(brains), 0)
|
self.assertEquals(len(brains), 0)
|
||||||
|
|
||||||
def test_clear_and_rebuild_catalog(self):
|
def test_clear_and_rebuild_catalog(self):
|
||||||
# Clear and rebuild catalog
|
# Clear and rebuild catalog
|
||||||
self.catalog.clearFindAndRebuild()
|
self.catalog.clearFindAndRebuild()
|
||||||
@ -353,7 +353,7 @@ class CommentCatalogTest(PloneTestCase):
|
|||||||
self.assertEquals(len(brains), 6)
|
self.assertEquals(len(brains), 6)
|
||||||
|
|
||||||
def test_collection(self):
|
def test_collection(self):
|
||||||
self.portal.invokeFactory(id='topic', type_name='Topic')
|
self.portal.invokeFactory(id='topic', type_name='Topic')
|
||||||
topic = self.portal.topic
|
topic = self.portal.topic
|
||||||
crit = topic.addCriterion('Type', 'ATSimpleStringCriterion')
|
crit = topic.addCriterion('Type', 'ATSimpleStringCriterion')
|
||||||
crit.setValue('Comment')
|
crit.setValue('Comment')
|
||||||
|
@ -37,7 +37,7 @@ class CommentTest(PloneTestCase):
|
|||||||
self.catalog = getToolByName(self.portal, 'portal_catalog')
|
self.catalog = getToolByName(self.portal, 'portal_catalog')
|
||||||
self.document_brain = self.catalog.searchResults(
|
self.document_brain = self.catalog.searchResults(
|
||||||
portal_type = 'Document')[0]
|
portal_type = 'Document')[0]
|
||||||
|
|
||||||
def test_factory(self):
|
def test_factory(self):
|
||||||
comment1 = createObject('plone.Comment')
|
comment1 = createObject('plone.Comment')
|
||||||
self.assert_(IComment.providedBy(comment1))
|
self.assert_(IComment.providedBy(comment1))
|
||||||
@ -71,7 +71,7 @@ class CommentTest(PloneTestCase):
|
|||||||
conversation.addComment(comment1)
|
conversation.addComment(comment1)
|
||||||
comment_brain = self.catalog.searchResults(
|
comment_brain = self.catalog.searchResults(
|
||||||
portal_type = 'Discussion Item')[0]
|
portal_type = 'Discussion Item')[0]
|
||||||
|
|
||||||
# comment should only have a UID if plone.uuid is present
|
# comment should only have a UID if plone.uuid is present
|
||||||
try:
|
try:
|
||||||
from plone.uuid.interfaces import IUUID
|
from plone.uuid.interfaces import IUUID
|
||||||
@ -80,7 +80,7 @@ class CommentTest(PloneTestCase):
|
|||||||
self.failIf(comment_brain.UID)
|
self.failIf(comment_brain.UID)
|
||||||
else:
|
else:
|
||||||
self.failUnless(comment_brain.UID)
|
self.failUnless(comment_brain.UID)
|
||||||
|
|
||||||
def test_uid_is_unique(self):
|
def test_uid_is_unique(self):
|
||||||
conversation = IConversation(self.portal.doc1)
|
conversation = IConversation(self.portal.doc1)
|
||||||
comment1 = createObject('plone.Comment')
|
comment1 = createObject('plone.Comment')
|
||||||
@ -89,12 +89,12 @@ class CommentTest(PloneTestCase):
|
|||||||
conversation.addComment(comment2)
|
conversation.addComment(comment2)
|
||||||
brains = self.catalog.searchResults(
|
brains = self.catalog.searchResults(
|
||||||
portal_type = 'Discussion Item')
|
portal_type = 'Discussion Item')
|
||||||
|
|
||||||
# make sure uids are either both None (i.e. without plone.uuid),
|
# make sure uids are either both None (i.e. without plone.uuid),
|
||||||
# or not equal
|
# or not equal
|
||||||
if brains[0].UID != None or brains[1].UID != None:
|
if brains[0].UID != None or brains[1].UID != None:
|
||||||
self.assertNotEquals(brains[0].UID, brains[1].UID)
|
self.assertNotEquals(brains[0].UID, brains[1].UID)
|
||||||
|
|
||||||
def test_comment_uid_differs_from_content_uid(self):
|
def test_comment_uid_differs_from_content_uid(self):
|
||||||
conversation = IConversation(self.portal.doc1)
|
conversation = IConversation(self.portal.doc1)
|
||||||
comment1 = createObject('plone.Comment')
|
comment1 = createObject('plone.Comment')
|
||||||
|
@ -4,7 +4,7 @@ import time
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from AccessControl import Unauthorized
|
from AccessControl import Unauthorized
|
||||||
|
|
||||||
from zope.component import createObject, queryUtility
|
from zope.component import createObject, queryUtility
|
||||||
|
|
||||||
from OFS.Image import Image
|
from OFS.Image import Image
|
||||||
@ -31,7 +31,7 @@ from Products.PloneTestCase.ptc import PloneTestCase
|
|||||||
|
|
||||||
from plone.app.discussion.browser.comments import CommentsViewlet
|
from plone.app.discussion.browser.comments import CommentsViewlet
|
||||||
from plone.app.discussion.browser.comments import CommentForm
|
from plone.app.discussion.browser.comments import CommentForm
|
||||||
from plone.app.discussion.interfaces import IConversation
|
from plone.app.discussion.interfaces import IConversation
|
||||||
from plone.app.discussion.tests.layer import DiscussionLayer
|
from plone.app.discussion.tests.layer import DiscussionLayer
|
||||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||||
|
|
||||||
@ -44,8 +44,8 @@ class TestCommentForm(PloneTestCase):
|
|||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
typetool = self.portal.portal_types
|
typetool = self.portal.portal_types
|
||||||
typetool.constructContent('Document', self.portal, 'doc1')
|
typetool.constructContent('Document', self.portal, 'doc1')
|
||||||
self.dtool = getToolByName(self.portal,
|
self.dtool = getToolByName(self.portal,
|
||||||
'portal_discussion',
|
'portal_discussion',
|
||||||
None)
|
None)
|
||||||
self.dtool.overrideDiscussionFor(self.portal.doc1, False)
|
self.dtool.overrideDiscussionFor(self.portal.doc1, False)
|
||||||
self.mtool = getToolByName(self.folder, 'portal_membership', None)
|
self.mtool = getToolByName(self.folder, 'portal_membership', None)
|
||||||
@ -57,11 +57,11 @@ class TestCommentForm(PloneTestCase):
|
|||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
settings = registry.forInterface(IDiscussionSettings)
|
settings = registry.forInterface(IDiscussionSettings)
|
||||||
settings.globally_enabled = True
|
settings.globally_enabled = True
|
||||||
|
|
||||||
def test_add_comment(self):
|
def test_add_comment(self):
|
||||||
"""Post a comment as logged-in user.
|
"""Post a comment as logged-in user.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Allow discussion
|
# Allow discussion
|
||||||
self.dtool.overrideDiscussionFor(self.portal.doc1, True)
|
self.dtool.overrideDiscussionFor(self.portal.doc1, True)
|
||||||
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
|
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
|
||||||
@ -72,99 +72,99 @@ class TestCommentForm(PloneTestCase):
|
|||||||
alsoProvides(request, IFormLayer)
|
alsoProvides(request, IFormLayer)
|
||||||
alsoProvides(request, IAttributeAnnotatable)
|
alsoProvides(request, IAttributeAnnotatable)
|
||||||
return request
|
return request
|
||||||
|
|
||||||
provideAdapter(adapts=(Interface, IBrowserRequest),
|
provideAdapter(adapts=(Interface, IBrowserRequest),
|
||||||
provides=Interface,
|
provides=Interface,
|
||||||
factory=CommentForm,
|
factory=CommentForm,
|
||||||
name=u"comment-form")
|
name=u"comment-form")
|
||||||
|
|
||||||
# The form should return an error if the comment text field is empty
|
# The form should return an error if the comment text field is empty
|
||||||
request = make_request(form={})
|
request = make_request(form={})
|
||||||
|
|
||||||
commentForm = getMultiAdapter((self.context, request),
|
commentForm = getMultiAdapter((self.context, request),
|
||||||
name=u"comment-form")
|
name=u"comment-form")
|
||||||
commentForm.update()
|
commentForm.update()
|
||||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||||
|
|
||||||
self.assertEquals(len(errors), 1)
|
self.assertEquals(len(errors), 1)
|
||||||
self.failIf(commentForm.handleComment(commentForm, "foo"))
|
self.failIf(commentForm.handleComment(commentForm, "foo"))
|
||||||
|
|
||||||
# The form is submitted successfully, if the required text field is
|
# The form is submitted successfully, if the required text field is
|
||||||
# filled out
|
# filled out
|
||||||
request = make_request(form={'form.widgets.text': u'bar'})
|
request = make_request(form={'form.widgets.text': u'bar'})
|
||||||
|
|
||||||
commentForm = getMultiAdapter((self.context, request),
|
commentForm = getMultiAdapter((self.context, request),
|
||||||
name=u"comment-form")
|
name=u"comment-form")
|
||||||
commentForm.update()
|
commentForm.update()
|
||||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||||
|
|
||||||
self.assertEquals(len(errors), 0)
|
self.assertEquals(len(errors), 0)
|
||||||
self.failIf(commentForm.handleComment(commentForm, "foo"))
|
self.failIf(commentForm.handleComment(commentForm, "foo"))
|
||||||
|
|
||||||
def test_add_anonymous_comment(self):
|
def test_add_anonymous_comment(self):
|
||||||
"""Add a comment as anonymous.
|
"""Add a comment as anonymous.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Allow discussion
|
# Allow discussion
|
||||||
self.dtool.overrideDiscussionFor(self.portal.doc1, True)
|
self.dtool.overrideDiscussionFor(self.portal.doc1, True)
|
||||||
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
|
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
|
||||||
|
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||||
settings.anonymous_comments = True
|
settings.anonymous_comments = True
|
||||||
|
|
||||||
# Logout
|
# Logout
|
||||||
self.logout()
|
self.logout()
|
||||||
|
|
||||||
def make_request(form={}):
|
def make_request(form={}):
|
||||||
request = TestRequest()
|
request = TestRequest()
|
||||||
request.form.update(form)
|
request.form.update(form)
|
||||||
alsoProvides(request, IFormLayer)
|
alsoProvides(request, IFormLayer)
|
||||||
alsoProvides(request, IAttributeAnnotatable)
|
alsoProvides(request, IAttributeAnnotatable)
|
||||||
return request
|
return request
|
||||||
|
|
||||||
provideAdapter(adapts=(Interface, IBrowserRequest),
|
provideAdapter(adapts=(Interface, IBrowserRequest),
|
||||||
provides=Interface,
|
provides=Interface,
|
||||||
factory=CommentForm,
|
factory=CommentForm,
|
||||||
name=u"comment-form")
|
name=u"comment-form")
|
||||||
|
|
||||||
# Post an anonymous comment and provide a name
|
# Post an anonymous comment and provide a name
|
||||||
request = make_request(form={'form.widgets.name': u'john doe',
|
request = make_request(form={'form.widgets.name': u'john doe',
|
||||||
'form.widgets.text': u'bar'})
|
'form.widgets.text': u'bar'})
|
||||||
|
|
||||||
commentForm = getMultiAdapter((self.context, request),
|
commentForm = getMultiAdapter((self.context, request),
|
||||||
name=u"comment-form")
|
name=u"comment-form")
|
||||||
commentForm.update()
|
commentForm.update()
|
||||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||||
|
|
||||||
self.assertEquals(len(errors), 0)
|
self.assertEquals(len(errors), 0)
|
||||||
self.failIf(commentForm.handleComment(commentForm, "action"))
|
self.failIf(commentForm.handleComment(commentForm, "action"))
|
||||||
|
|
||||||
def test_can_not_add_comments_if_discussion_is_not_allowed(self):
|
def test_can_not_add_comments_if_discussion_is_not_allowed(self):
|
||||||
"""Make sure that comments can't be posted if discussion is disabled.
|
"""Make sure that comments can't be posted if discussion is disabled.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Discussion is disabled by default
|
# Discussion is disabled by default
|
||||||
|
|
||||||
def make_request(form={}):
|
def make_request(form={}):
|
||||||
request = TestRequest()
|
request = TestRequest()
|
||||||
request.form.update(form)
|
request.form.update(form)
|
||||||
alsoProvides(request, IFormLayer)
|
alsoProvides(request, IFormLayer)
|
||||||
alsoProvides(request, IAttributeAnnotatable)
|
alsoProvides(request, IAttributeAnnotatable)
|
||||||
return request
|
return request
|
||||||
|
|
||||||
provideAdapter(adapts=(Interface, IBrowserRequest),
|
provideAdapter(adapts=(Interface, IBrowserRequest),
|
||||||
provides=Interface,
|
provides=Interface,
|
||||||
factory=CommentForm,
|
factory=CommentForm,
|
||||||
name=u"comment-form")
|
name=u"comment-form")
|
||||||
|
|
||||||
request = make_request(form={'form.widgets.text': u'bar'})
|
request = make_request(form={'form.widgets.text': u'bar'})
|
||||||
|
|
||||||
commentForm = getMultiAdapter((self.context, request),
|
commentForm = getMultiAdapter((self.context, request),
|
||||||
name=u"comment-form")
|
name=u"comment-form")
|
||||||
commentForm.update()
|
commentForm.update()
|
||||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||||
|
|
||||||
# No form errors, but raise unauthorized because discussion is not
|
# No form errors, but raise unauthorized because discussion is not
|
||||||
# allowed
|
# allowed
|
||||||
self.assertEquals(len(errors), 0)
|
self.assertEquals(len(errors), 0)
|
||||||
@ -172,52 +172,52 @@ class TestCommentForm(PloneTestCase):
|
|||||||
commentForm.handleComment,
|
commentForm.handleComment,
|
||||||
commentForm,
|
commentForm,
|
||||||
"foo")
|
"foo")
|
||||||
|
|
||||||
def test_anonymous_can_not_add_comments_if_discussion_is_not_allowed(self):
|
def test_anonymous_can_not_add_comments_if_discussion_is_not_allowed(self):
|
||||||
"""Make sure that anonymous users can't post comments if anonymous
|
"""Make sure that anonymous users can't post comments if anonymous
|
||||||
comments are disabled.
|
comments are disabled.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Anonymous comments are disabled by default
|
# Anonymous comments are disabled by default
|
||||||
|
|
||||||
self.logout()
|
self.logout()
|
||||||
|
|
||||||
def make_request(form={}):
|
def make_request(form={}):
|
||||||
request = TestRequest()
|
request = TestRequest()
|
||||||
request.form.update(form)
|
request.form.update(form)
|
||||||
alsoProvides(request, IFormLayer)
|
alsoProvides(request, IFormLayer)
|
||||||
alsoProvides(request, IAttributeAnnotatable)
|
alsoProvides(request, IAttributeAnnotatable)
|
||||||
return request
|
return request
|
||||||
|
|
||||||
provideAdapter(adapts=(Interface, IBrowserRequest),
|
provideAdapter(adapts=(Interface, IBrowserRequest),
|
||||||
provides=Interface,
|
provides=Interface,
|
||||||
factory=CommentForm,
|
factory=CommentForm,
|
||||||
name=u"comment-form")
|
name=u"comment-form")
|
||||||
|
|
||||||
request = make_request(form={'form.widgets.text': u'bar'})
|
request = make_request(form={'form.widgets.text': u'bar'})
|
||||||
|
|
||||||
commentForm = getMultiAdapter((self.context, request),
|
commentForm = getMultiAdapter((self.context, request),
|
||||||
name=u"comment-form")
|
name=u"comment-form")
|
||||||
commentForm.update()
|
commentForm.update()
|
||||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||||
|
|
||||||
self.assertEquals(len(errors), 0)
|
self.assertEquals(len(errors), 0)
|
||||||
self.assertRaises(Unauthorized,
|
self.assertRaises(Unauthorized,
|
||||||
commentForm.handleComment,
|
commentForm.handleComment,
|
||||||
commentForm,
|
commentForm,
|
||||||
"foo")
|
"foo")
|
||||||
|
|
||||||
|
|
||||||
class TestCommentsViewlet(PloneTestCase):
|
class TestCommentsViewlet(PloneTestCase):
|
||||||
|
|
||||||
layer = DiscussionLayer
|
layer = DiscussionLayer
|
||||||
|
|
||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
typetool = self.portal.portal_types
|
typetool = self.portal.portal_types
|
||||||
typetool.constructContent('Document', self.portal, 'doc1')
|
typetool.constructContent('Document', self.portal, 'doc1')
|
||||||
self.portal_discussion = getToolByName(self.portal,
|
self.portal_discussion = getToolByName(self.portal,
|
||||||
'portal_discussion',
|
'portal_discussion',
|
||||||
None)
|
None)
|
||||||
self.mtool = getToolByName(self.folder, 'portal_membership')
|
self.mtool = getToolByName(self.folder, 'portal_membership')
|
||||||
self.memberdata = self.portal.portal_memberdata
|
self.memberdata = self.portal.portal_memberdata
|
||||||
@ -229,29 +229,29 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
settings = registry.forInterface(IDiscussionSettings)
|
settings = registry.forInterface(IDiscussionSettings)
|
||||||
settings.globally_enabled = True
|
settings.globally_enabled = True
|
||||||
|
|
||||||
def test_cook(self):
|
def test_cook(self):
|
||||||
text = """First paragraph
|
text = """First paragraph
|
||||||
|
|
||||||
Second paragraph"""
|
Second paragraph"""
|
||||||
self.assertEquals(self.viewlet.cook(text),
|
self.assertEquals(self.viewlet.cook(text),
|
||||||
"<p>First paragraph<br /> <br /> Second paragraph</p>")
|
"<p>First paragraph<br /><br /> Second paragraph</p>")
|
||||||
|
|
||||||
def test_cook_no_html(self):
|
def test_cook_no_html(self):
|
||||||
text = """<b>Got HTML?</b>"""
|
text = """<b>Got HTML?</b>"""
|
||||||
self.assertEquals(self.viewlet.cook(text),
|
self.assertEquals(self.viewlet.cook(text),
|
||||||
"<p><b>Got HTML?</b></p>")
|
"<p><b>Got HTML?</b></p>")
|
||||||
|
|
||||||
def test_cook_with_no_ascii_characters(self):
|
def test_cook_with_no_ascii_characters(self):
|
||||||
text = """Umlaute sind ä, ö und ü."""
|
text = """Umlaute sind ä, ö und ü."""
|
||||||
self.assertEquals(self.viewlet.cook(text),
|
self.assertEquals(self.viewlet.cook(text),
|
||||||
"<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>")
|
"<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>")
|
||||||
|
|
||||||
def test_cook_links(self):
|
def test_cook_links(self):
|
||||||
text = "Go to http://www.plone.org"
|
text = "Go to http://www.plone.org"
|
||||||
self.assertEquals(self.viewlet.cook(text),
|
self.assertEquals(self.viewlet.cook(text),
|
||||||
"<p>Go to http://www.plone.org</p>")
|
"<p>Go to http://www.plone.org</p>")
|
||||||
|
|
||||||
def test_can_reply(self):
|
def test_can_reply(self):
|
||||||
# Portal owner can reply
|
# Portal owner can reply
|
||||||
self.failUnless(self.viewlet.can_reply())
|
self.failUnless(self.viewlet.can_reply())
|
||||||
@ -268,7 +268,7 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
# The reviewer role has the 'Review comments' permission
|
# The reviewer role has the 'Review comments' permission
|
||||||
self.portal.acl_users._doAddUser('reviewer', 'secret', ['Reviewer'], [])
|
self.portal.acl_users._doAddUser('reviewer', 'secret', ['Reviewer'], [])
|
||||||
self.login('reviewer')
|
self.login('reviewer')
|
||||||
self.failUnless(self.viewlet.can_review())
|
self.failUnless(self.viewlet.can_review())
|
||||||
|
|
||||||
def test_can_manage(self):
|
def test_can_manage(self):
|
||||||
"""We keep this method for backward compatibility. This method has been
|
"""We keep this method for backward compatibility. This method has been
|
||||||
@ -283,8 +283,8 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
# The reviewer role has the 'Review comments' permission
|
# The reviewer role has the 'Review comments' permission
|
||||||
self.portal.acl_users._doAddUser('reviewer', 'secret', ['Reviewer'], [])
|
self.portal.acl_users._doAddUser('reviewer', 'secret', ['Reviewer'], [])
|
||||||
self.login('reviewer')
|
self.login('reviewer')
|
||||||
self.failUnless(self.viewlet.can_manage())
|
self.failUnless(self.viewlet.can_manage())
|
||||||
|
|
||||||
def test_is_discussion_allowed(self):
|
def test_is_discussion_allowed(self):
|
||||||
# By default, discussion is disabled
|
# By default, discussion is disabled
|
||||||
self.failIf(self.viewlet.is_discussion_allowed())
|
self.failIf(self.viewlet.is_discussion_allowed())
|
||||||
@ -309,12 +309,11 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
|
|
||||||
# Make sure the comment description is changes accordingly
|
# Make sure the comment description is changes accordingly
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.viewlet.comment_transform_message(),
|
self.viewlet.comment_transform_message(),
|
||||||
"You can add a comment by filling out the form below. " +
|
"You can add a comment by filling out the form below. " +
|
||||||
"Plain text formatting. Web and email addresses are transformed " +
|
"Plain text formatting. Web and email addresses are transformed " +
|
||||||
"into clickable links.")
|
"into clickable links.")
|
||||||
|
|
||||||
|
|
||||||
def test_has_replies(self):
|
def test_has_replies(self):
|
||||||
self.assertEquals(self.viewlet.has_replies(), False)
|
self.assertEquals(self.viewlet.has_replies(), False)
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
@ -331,7 +330,7 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
conversation.addComment(comment)
|
conversation.addComment(comment)
|
||||||
conversation.addComment(comment)
|
conversation.addComment(comment)
|
||||||
replies = self.viewlet.get_replies()
|
replies = self.viewlet.get_replies()
|
||||||
self.assertEquals(len(tuple(replies)), 2)
|
self.assertEquals(len(tuple(replies)), 2)
|
||||||
replies = self.viewlet.get_replies()
|
replies = self.viewlet.get_replies()
|
||||||
replies.next()
|
replies.next()
|
||||||
replies.next()
|
replies.next()
|
||||||
@ -344,7 +343,7 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
conversation = IConversation(self.portal.doc1)
|
conversation = IConversation(self.portal.doc1)
|
||||||
c1 = conversation.addComment(comment)
|
c1 = conversation.addComment(comment)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
len(tuple(self.viewlet.get_replies(workflow_actions=True))), 1)
|
len(tuple(self.viewlet.get_replies(workflow_actions=True))), 1)
|
||||||
# Enable moderation workflow
|
# Enable moderation workflow
|
||||||
self.portal.portal_workflow.setChainForPortalTypes(
|
self.portal.portal_workflow.setChainForPortalTypes(
|
||||||
('Discussion Item',),
|
('Discussion Item',),
|
||||||
@ -356,8 +355,8 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
'publish')
|
'publish')
|
||||||
self.assertEquals(reply['actions'][0]['url'],
|
self.assertEquals(reply['actions'][0]['url'],
|
||||||
'http://nohost/plone/doc1/++conversation++default/%s' % int(c1) +
|
'http://nohost/plone/doc1/++conversation++default/%s' % int(c1) +
|
||||||
'/content_status_modify?workflow_action=publish')
|
'/content_status_modify?workflow_action=publish')
|
||||||
|
|
||||||
def test_get_commenter_home_url(self):
|
def test_get_commenter_home_url(self):
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
comment.text = 'Comment text'
|
comment.text = 'Comment text'
|
||||||
@ -369,17 +368,17 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
|
|
||||||
def test_get_commenter_home_url_is_none(self):
|
def test_get_commenter_home_url_is_none(self):
|
||||||
self.failIf(self.viewlet.get_commenter_home_url())
|
self.failIf(self.viewlet.get_commenter_home_url())
|
||||||
|
|
||||||
def test_get_commenter_portrait(self):
|
def test_get_commenter_portrait(self):
|
||||||
|
|
||||||
# Add a user with a member image
|
# Add a user with a member image
|
||||||
self.mtool.addMember('jim', 'Jim', ['Member'], [])
|
self.mtool.addMember('jim', 'Jim', ['Member'], [])
|
||||||
self.memberdata._setPortrait(Image(id='jim',
|
self.memberdata._setPortrait(Image(id='jim',
|
||||||
file=dummy.File(),
|
file=dummy.File(),
|
||||||
title=''), 'jim')
|
title=''), 'jim')
|
||||||
self.assertEqual(self.memberdata._getPortrait('jim').getId(),
|
self.assertEqual(self.memberdata._getPortrait('jim').getId(),
|
||||||
'jim')
|
'jim')
|
||||||
self.assertEqual(self.memberdata._getPortrait('jim').meta_type,
|
self.assertEqual(self.memberdata._getPortrait('jim').meta_type,
|
||||||
'Image')
|
'Image')
|
||||||
|
|
||||||
# Add a conversation with a comment
|
# Add a conversation with a comment
|
||||||
@ -395,13 +394,13 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
portrait_url = self.viewlet.get_commenter_portrait('jim')
|
portrait_url = self.viewlet.get_commenter_portrait('jim')
|
||||||
|
|
||||||
# Check if the correct member image URL is returned
|
# Check if the correct member image URL is returned
|
||||||
self.assertEquals(portrait_url,
|
self.assertEquals(portrait_url,
|
||||||
'http://nohost/plone/portal_memberdata/portraits/jim')
|
'http://nohost/plone/portal_memberdata/portraits/jim')
|
||||||
|
|
||||||
def test_get_commenter_portrait_is_none(self):
|
def test_get_commenter_portrait_is_none(self):
|
||||||
self.assertEquals(self.viewlet.get_commenter_portrait(),
|
self.assertEquals(self.viewlet.get_commenter_portrait(),
|
||||||
'defaultUser.gif')
|
'defaultUser.gif')
|
||||||
|
|
||||||
def test_get_commenter_portrait_without_userimage(self):
|
def test_get_commenter_portrait_without_userimage(self):
|
||||||
|
|
||||||
# Create a user without a user image
|
# Create a user without a user image
|
||||||
@ -431,14 +430,14 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
'anonymous_comments'] = True
|
'anonymous_comments'] = True
|
||||||
# Test if anonymous discussion is allowed for the viewlet
|
# Test if anonymous discussion is allowed for the viewlet
|
||||||
self.failUnless(self.viewlet.anonymous_discussion_allowed())
|
self.failUnless(self.viewlet.anonymous_discussion_allowed())
|
||||||
|
|
||||||
def test_show_commenter_image(self):
|
def test_show_commenter_image(self):
|
||||||
self.failUnless(self.viewlet.show_commenter_image())
|
self.failUnless(self.viewlet.show_commenter_image())
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
registry['plone.app.discussion.interfaces.IDiscussionSettings.' +
|
registry['plone.app.discussion.interfaces.IDiscussionSettings.' +
|
||||||
'show_commenter_image'] = False
|
'show_commenter_image'] = False
|
||||||
self.failIf(self.viewlet.show_commenter_image())
|
self.failIf(self.viewlet.show_commenter_image())
|
||||||
|
|
||||||
def test_is_anonymous(self):
|
def test_is_anonymous(self):
|
||||||
self.failIf(self.viewlet.is_anonymous())
|
self.failIf(self.viewlet.is_anonymous())
|
||||||
self.logout()
|
self.logout()
|
||||||
@ -447,8 +446,8 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
def test_login_action(self):
|
def test_login_action(self):
|
||||||
self.viewlet.update()
|
self.viewlet.update()
|
||||||
self.assertEquals(self.viewlet.login_action(),
|
self.assertEquals(self.viewlet.login_action(),
|
||||||
'http://nohost/plone/login_form?came_from=http%3A//nohost')
|
'http://nohost/plone/login_form?came_from=http%3A//nohost')
|
||||||
|
|
||||||
def test_format_time(self):
|
def test_format_time(self):
|
||||||
python_time = datetime(2009, 02, 01, 23, 32, 03, 57)
|
python_time = datetime(2009, 02, 01, 23, 32, 03, 57)
|
||||||
# Python Time must be utc time. There seems to be no too simple way
|
# Python Time must be utc time. There seems to be no too simple way
|
||||||
@ -464,5 +463,6 @@ class TestCommentsViewlet(PloneTestCase):
|
|||||||
localized_time = self.viewlet.format_time(python_time)
|
localized_time = self.viewlet.format_time(python_time)
|
||||||
self.assertEquals(localized_time, "Feb 01, 2009 11:32 PM")
|
self.assertEquals(localized_time, "Feb 01, 2009 11:32 PM")
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
||||||
|
@ -27,9 +27,9 @@ class RegistryTest(PloneTestCase):
|
|||||||
def test_registry_registered(self):
|
def test_registry_registered(self):
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
self.failUnless(registry.forInterface(IDiscussionSettings))
|
self.failUnless(registry.forInterface(IDiscussionSettings))
|
||||||
|
|
||||||
def test_discussion_controlpanel_view(self):
|
def test_discussion_controlpanel_view(self):
|
||||||
view = getMultiAdapter((self.portal, self.portal.REQUEST),
|
view = getMultiAdapter((self.portal, self.portal.REQUEST),
|
||||||
name="discussion-settings")
|
name="discussion-settings")
|
||||||
view = view.__of__(self.portal)
|
view = view.__of__(self.portal)
|
||||||
self.failUnless(view())
|
self.failUnless(view())
|
||||||
@ -45,7 +45,7 @@ class RegistryTest(PloneTestCase):
|
|||||||
self.failUnless('globally_enabled' in IDiscussionSettings)
|
self.failUnless('globally_enabled' in IDiscussionSettings)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.registry['plone.app.discussion.interfaces.' +
|
self.registry['plone.app.discussion.interfaces.' +
|
||||||
'IDiscussionSettings.globally_enabled'],
|
'IDiscussionSettings.globally_enabled'],
|
||||||
False)
|
False)
|
||||||
|
|
||||||
def test_anonymous_comments(self):
|
def test_anonymous_comments(self):
|
||||||
@ -59,16 +59,16 @@ class RegistryTest(PloneTestCase):
|
|||||||
self.failUnless('moderation_enabled' in IDiscussionSettings)
|
self.failUnless('moderation_enabled' in IDiscussionSettings)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.registry['plone.app.discussion.interfaces.' +
|
self.registry['plone.app.discussion.interfaces.' +
|
||||||
'IDiscussionSettings.moderation_enabled'],
|
'IDiscussionSettings.moderation_enabled'],
|
||||||
False)
|
False)
|
||||||
|
|
||||||
def test_text_transform(self):
|
def test_text_transform(self):
|
||||||
self.failUnless('text_transform' in IDiscussionSettings)
|
self.failUnless('text_transform' in IDiscussionSettings)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.registry['plone.app.discussion.interfaces.' +
|
self.registry['plone.app.discussion.interfaces.' +
|
||||||
'IDiscussionSettings.text_transform'],
|
'IDiscussionSettings.text_transform'],
|
||||||
'text/plain')
|
'text/plain')
|
||||||
|
|
||||||
def test_captcha(self):
|
def test_captcha(self):
|
||||||
# Check globally_enabled record
|
# Check globally_enabled record
|
||||||
self.failUnless('captcha' in IDiscussionSettings)
|
self.failUnless('captcha' in IDiscussionSettings)
|
||||||
@ -79,12 +79,12 @@ class RegistryTest(PloneTestCase):
|
|||||||
def test_show_commenter_image(self):
|
def test_show_commenter_image(self):
|
||||||
# Check show_commenter_image record
|
# Check show_commenter_image record
|
||||||
self.failUnless('show_commenter_image' in IDiscussionSettings)
|
self.failUnless('show_commenter_image' in IDiscussionSettings)
|
||||||
self.assertEquals(self.registry['plone.app.discussion.interfaces.' +
|
self.assertEquals(self.registry['plone.app.discussion.interfaces.' +
|
||||||
'IDiscussionSettings.show_commenter_image'], True)
|
'IDiscussionSettings.show_commenter_image'], True)
|
||||||
|
|
||||||
def test_moderator_notification_enabled(self):
|
def test_moderator_notification_enabled(self):
|
||||||
# Check show_commenter_image record
|
# Check show_commenter_image record
|
||||||
self.failUnless('moderator_notification_enabled' in
|
self.failUnless('moderator_notification_enabled' in
|
||||||
IDiscussionSettings)
|
IDiscussionSettings)
|
||||||
self.assertEquals(self.registry['plone.app.discussion.interfaces.' +
|
self.assertEquals(self.registry['plone.app.discussion.interfaces.' +
|
||||||
'IDiscussionSettings.moderator_notification_enabled'], False)
|
'IDiscussionSettings.moderator_notification_enabled'], False)
|
||||||
@ -108,39 +108,39 @@ class ConfigurationChangedSubscriberTest(PloneTestCase):
|
|||||||
# Set up the registry
|
# Set up the registry
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
self.settings = registry.forInterface(IDiscussionSettings, check=False)
|
self.settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||||
|
|
||||||
def test_moderation_enabled_in_discussion_control_panel_changed(self):
|
def test_moderation_enabled_in_discussion_control_panel_changed(self):
|
||||||
"""Make sure the 'Discussion Item' workflow is changed properly, when
|
"""Make sure the 'Discussion Item' workflow is changed properly, when
|
||||||
the 'comment_moderation' setting in the discussion control panel
|
the 'comment_moderation' setting in the discussion control panel
|
||||||
changes.
|
changes.
|
||||||
"""
|
"""
|
||||||
# By default the one_state_workflow without moderation is enabled
|
# By default the one_state_workflow without moderation is enabled
|
||||||
self.assertEquals(('one_state_workflow',),
|
self.assertEquals(('one_state_workflow',),
|
||||||
self.portal.portal_workflow.getChainForPortalType(
|
self.portal.portal_workflow.getChainForPortalType(
|
||||||
'Discussion Item'))
|
'Discussion Item'))
|
||||||
|
|
||||||
# Enable moderation in the discussion control panel
|
# Enable moderation in the discussion control panel
|
||||||
self.settings.moderation_enabled = True
|
self.settings.moderation_enabled = True
|
||||||
|
|
||||||
# Make sure the comment_review_workflow with moderation enabled is
|
# Make sure the comment_review_workflow with moderation enabled is
|
||||||
# enabled
|
# enabled
|
||||||
self.assertEquals(('comment_review_workflow',),
|
self.assertEquals(('comment_review_workflow',),
|
||||||
self.portal.portal_workflow.getChainForPortalType(
|
self.portal.portal_workflow.getChainForPortalType(
|
||||||
'Discussion Item'))
|
'Discussion Item'))
|
||||||
# And back
|
# And back
|
||||||
self.settings.moderation_enabled = False
|
self.settings.moderation_enabled = False
|
||||||
self.assertEquals(('one_state_workflow',),
|
self.assertEquals(('one_state_workflow',),
|
||||||
self.portal.portal_workflow.getChainForPortalType(
|
self.portal.portal_workflow.getChainForPortalType(
|
||||||
'Discussion Item'))
|
'Discussion Item'))
|
||||||
|
|
||||||
def test_change_workflow_in_types_control_panel(self):
|
def test_change_workflow_in_types_control_panel(self):
|
||||||
"""Make sure the setting in the discussion control panel is changed
|
"""Make sure the setting in the discussion control panel is changed
|
||||||
accordingly, when the workflow for the 'Discussion Item' changed in
|
accordingly, when the workflow for the 'Discussion Item' changed in
|
||||||
the types control panel.
|
the types control panel.
|
||||||
"""
|
"""
|
||||||
# By default, moderation is disabled
|
# By default, moderation is disabled
|
||||||
self.settings.moderation_enabled = False
|
self.settings.moderation_enabled = False
|
||||||
|
|
||||||
# Enable the 'comment_review_workflow' with moderation enabled
|
# Enable the 'comment_review_workflow' with moderation enabled
|
||||||
self.portal.portal_workflow.setChainForPortalTypes(
|
self.portal.portal_workflow.setChainForPortalTypes(
|
||||||
('Discussion Item',),
|
('Discussion Item',),
|
||||||
@ -159,11 +159,11 @@ class ConfigurationChangedSubscriberTest(PloneTestCase):
|
|||||||
self.portal.portal_workflow.setChainForPortalTypes(
|
self.portal.portal_workflow.setChainForPortalTypes(
|
||||||
('Discussion Item',),
|
('Discussion Item',),
|
||||||
('intranet_workflow',))
|
('intranet_workflow',))
|
||||||
|
|
||||||
# Setting has not changed. A Custom workflow disables the
|
# Setting has not changed. A Custom workflow disables the
|
||||||
# enable_moderation checkbox in the discussion control panel. The
|
# enable_moderation checkbox in the discussion control panel. The
|
||||||
# setting itself remains unchanged.
|
# setting itself remains unchanged.
|
||||||
self.settings.moderation_enabled = True
|
self.settings.moderation_enabled = True
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
||||||
|
@ -29,20 +29,20 @@ class ConversationTest(PloneTestCase):
|
|||||||
typetool = self.portal.portal_types
|
typetool = self.portal.portal_types
|
||||||
typetool.constructContent('Document', self.portal, 'doc1')
|
typetool.constructContent('Document', self.portal, 'doc1')
|
||||||
self.typetool = typetool
|
self.typetool = typetool
|
||||||
self.portal_discussion = getToolByName(self.portal,
|
self.portal_discussion = getToolByName(self.portal,
|
||||||
'portal_discussion',
|
'portal_discussion',
|
||||||
None)
|
None)
|
||||||
# Allow discussion
|
# Allow discussion
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
settings = registry.forInterface(IDiscussionSettings)
|
settings = registry.forInterface(IDiscussionSettings)
|
||||||
settings.globally_enabled = True
|
settings.globally_enabled = True
|
||||||
|
|
||||||
def test_add_comment(self):
|
def test_add_comment(self):
|
||||||
# Create a conversation. In this case we doesn't assign it to an
|
# Create a conversation. In this case we doesn't assign it to an
|
||||||
# object, as we just want to check the Conversation object API.
|
# object, as we just want to check the Conversation object API.
|
||||||
conversation = IConversation(self.portal.doc1)
|
conversation = IConversation(self.portal.doc1)
|
||||||
|
|
||||||
# Add a comment. Note: in real life, we always create comments via the
|
# Add a comment. Note: in real life, we always create comments via the
|
||||||
# factory to allow different factories to be swapped in
|
# factory to allow different factories to be swapped in
|
||||||
|
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
@ -59,7 +59,7 @@ class ConversationTest(PloneTestCase):
|
|||||||
self.assertEquals(len(list(conversation.getComments())), 1)
|
self.assertEquals(len(list(conversation.getComments())), 1)
|
||||||
self.assertEquals(len(tuple(conversation.getThreads())), 1)
|
self.assertEquals(len(tuple(conversation.getThreads())), 1)
|
||||||
self.assertEquals(conversation.total_comments, 1)
|
self.assertEquals(conversation.total_comments, 1)
|
||||||
self.assert_(conversation.last_comment_date - datetime.utcnow() <
|
self.assert_(conversation.last_comment_date - datetime.utcnow() <
|
||||||
timedelta(seconds=1))
|
timedelta(seconds=1))
|
||||||
|
|
||||||
def test_delete_comment(self):
|
def test_delete_comment(self):
|
||||||
@ -67,7 +67,7 @@ class ConversationTest(PloneTestCase):
|
|||||||
# object, as we just want to check the Conversation object API.
|
# object, as we just want to check the Conversation object API.
|
||||||
conversation = IConversation(self.portal.doc1)
|
conversation = IConversation(self.portal.doc1)
|
||||||
|
|
||||||
# Add a comment. Note: in real life, we always create comments via the
|
# Add a comment. Note: in real life, we always create comments via the
|
||||||
# factory to allow different factories to be swapped in
|
# factory to allow different factories to be swapped in
|
||||||
|
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
@ -148,7 +148,7 @@ class ConversationTest(PloneTestCase):
|
|||||||
], list(conversation.getThreads()))
|
], list(conversation.getThreads()))
|
||||||
|
|
||||||
def test_delete_comment_when_content_object_is_deleted(self):
|
def test_delete_comment_when_content_object_is_deleted(self):
|
||||||
# Make sure all comments of a content object are deleted when the
|
# Make sure all comments of a content object are deleted when the
|
||||||
# object itself is deleted.
|
# object itself is deleted.
|
||||||
conversation = IConversation(self.portal.doc1)
|
conversation = IConversation(self.portal.doc1)
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
@ -157,11 +157,11 @@ class ConversationTest(PloneTestCase):
|
|||||||
|
|
||||||
# Delete the content object
|
# Delete the content object
|
||||||
self.portal.manage_delObjects(['doc1'])
|
self.portal.manage_delObjects(['doc1'])
|
||||||
|
|
||||||
# Make sure the comment has been deleted as well
|
# Make sure the comment has been deleted as well
|
||||||
self.assertEquals(len(list(conversation.getComments())), 0)
|
self.assertEquals(len(list(conversation.getComments())), 0)
|
||||||
self.assertEquals(len(tuple(conversation.getThreads())), 0)
|
self.assertEquals(len(tuple(conversation.getThreads())), 0)
|
||||||
self.assertEquals(conversation.total_comments, 0)
|
self.assertEquals(conversation.total_comments, 0)
|
||||||
|
|
||||||
def test_allow_discussion(self):
|
def test_allow_discussion(self):
|
||||||
# This is not a real test! It's only there to understand the
|
# This is not a real test! It's only there to understand the
|
||||||
@ -188,20 +188,20 @@ class ConversationTest(PloneTestCase):
|
|||||||
portal_discussion = getToolByName(self.portal, 'portal_discussion')
|
portal_discussion = getToolByName(self.portal, 'portal_discussion')
|
||||||
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
||||||
self.portal.doc1), False)
|
self.portal.doc1), False)
|
||||||
self.assertEquals(self.portal.doc1.getTypeInfo().allowDiscussion(),
|
self.assertEquals(self.portal.doc1.getTypeInfo().allowDiscussion(),
|
||||||
False)
|
False)
|
||||||
|
|
||||||
# The allow discussion flag is None by default
|
# The allow discussion flag is None by default
|
||||||
self.failIf(getattr(self.portal.doc1, 'allow_discussion', None))
|
self.failIf(getattr(self.portal.doc1, 'allow_discussion', None))
|
||||||
|
|
||||||
# But isDiscussionAllowedFor, also checks if discussion is allowed on
|
# But isDiscussionAllowedFor, also checks if discussion is allowed on
|
||||||
# the content type. So we allow discussion on the Document content
|
# the content type. So we allow discussion on the Document content
|
||||||
# type and check if the Document object allows discussion now.
|
# type and check if the Document object allows discussion now.
|
||||||
document_fti = getattr(portal_types, 'Document')
|
document_fti = getattr(portal_types, 'Document')
|
||||||
document_fti.manage_changeProperties(allow_discussion = True)
|
document_fti.manage_changeProperties(allow_discussion = True)
|
||||||
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
||||||
self.portal.doc1), True)
|
self.portal.doc1), True)
|
||||||
self.assertEquals(self.portal.doc1.getTypeInfo().allowDiscussion(),
|
self.assertEquals(self.portal.doc1.getTypeInfo().allowDiscussion(),
|
||||||
True)
|
True)
|
||||||
|
|
||||||
# We can also override the allow_discussion locally
|
# We can also override the allow_discussion locally
|
||||||
@ -209,16 +209,16 @@ class ConversationTest(PloneTestCase):
|
|||||||
# Check if the Document discussion is disabled
|
# Check if the Document discussion is disabled
|
||||||
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
||||||
self.portal.doc1), False)
|
self.portal.doc1), False)
|
||||||
# Check that the local allow_discussion flag is now explicitly set to
|
# Check that the local allow_discussion flag is now explicitly set to
|
||||||
# False
|
# False
|
||||||
self.assertEquals(getattr(self.portal.doc1, 'allow_discussion', None),
|
self.assertEquals(getattr(self.portal.doc1, 'allow_discussion', None),
|
||||||
False)
|
False)
|
||||||
|
|
||||||
# Disallow discussion on the Document content type again
|
# Disallow discussion on the Document content type again
|
||||||
document_fti.manage_changeProperties(allow_discussion = False)
|
document_fti.manage_changeProperties(allow_discussion = False)
|
||||||
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
||||||
self.portal.doc1), False)
|
self.portal.doc1), False)
|
||||||
self.assertEquals(self.portal.doc1.getTypeInfo().allowDiscussion(),
|
self.assertEquals(self.portal.doc1.getTypeInfo().allowDiscussion(),
|
||||||
False)
|
False)
|
||||||
|
|
||||||
# Now we override allow_discussion again (True) for the Document
|
# Now we override allow_discussion again (True) for the Document
|
||||||
@ -226,14 +226,14 @@ class ConversationTest(PloneTestCase):
|
|||||||
self.portal_discussion.overrideDiscussionFor(self.portal.doc1, True)
|
self.portal_discussion.overrideDiscussionFor(self.portal.doc1, True)
|
||||||
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
self.assertEquals(portal_discussion.isDiscussionAllowedFor(
|
||||||
self.portal.doc1), True)
|
self.portal.doc1), True)
|
||||||
self.assertEquals(getattr(self.portal.doc1, 'allow_discussion', None),
|
self.assertEquals(getattr(self.portal.doc1, 'allow_discussion', None),
|
||||||
True)
|
True)
|
||||||
|
|
||||||
def test_comments_enabled_on_doc_in_subfolder(self):
|
def test_comments_enabled_on_doc_in_subfolder(self):
|
||||||
typetool = self.portal.portal_types
|
typetool = self.portal.portal_types
|
||||||
typetool.constructContent('Folder', self.portal, 'folder1')
|
typetool.constructContent('Folder', self.portal, 'folder1')
|
||||||
typetool.constructContent('Document', self.portal.folder1, 'doc2')
|
typetool.constructContent('Document', self.portal.folder1, 'doc2')
|
||||||
|
|
||||||
folder = self.portal.folder1
|
folder = self.portal.folder1
|
||||||
folder.allowDiscussion(False)
|
folder.allowDiscussion(False)
|
||||||
self.assertFalse(hasattr(aq_base(folder), 'allow_discussion'))
|
self.assertFalse(hasattr(aq_base(folder), 'allow_discussion'))
|
||||||
@ -241,11 +241,11 @@ class ConversationTest(PloneTestCase):
|
|||||||
self.assertTrue(aq_base(folder).allow_discussion)
|
self.assertTrue(aq_base(folder).allow_discussion)
|
||||||
folder.allowDiscussion(False)
|
folder.allowDiscussion(False)
|
||||||
self.assertFalse(aq_base(folder).allow_discussion)
|
self.assertFalse(aq_base(folder).allow_discussion)
|
||||||
|
|
||||||
doc = self.portal.folder1.doc2
|
doc = self.portal.folder1.doc2
|
||||||
conversation = IConversation(doc)
|
conversation = IConversation(doc)
|
||||||
self.assertEquals(conversation.enabled(), False)
|
self.assertEquals(conversation.enabled(), False)
|
||||||
|
|
||||||
# We have to allow discussion on Document content type, since
|
# We have to allow discussion on Document content type, since
|
||||||
# otherwise allow_discussion will always return False
|
# otherwise allow_discussion will always return False
|
||||||
portal_types = getToolByName(self.portal, 'portal_types')
|
portal_types = getToolByName(self.portal, 'portal_types')
|
||||||
@ -409,7 +409,7 @@ class ConversationTest(PloneTestCase):
|
|||||||
# object, as we just want to check the Conversation object API.
|
# object, as we just want to check the Conversation object API.
|
||||||
conversation = IConversation(self.portal.doc1)
|
conversation = IConversation(self.portal.doc1)
|
||||||
|
|
||||||
# Add a comment. Note: in real life, we always create comments via the
|
# Add a comment. Note: in real life, we always create comments via the
|
||||||
# factory to allow different factories to be swapped in
|
# factory to allow different factories to be swapped in
|
||||||
|
|
||||||
comment1 = createObject('plone.Comment')
|
comment1 = createObject('plone.Comment')
|
||||||
@ -571,9 +571,9 @@ class ConversationTest(PloneTestCase):
|
|||||||
new_comment3_id = conversation.addComment(comment3)
|
new_comment3_id = conversation.addComment(comment3)
|
||||||
|
|
||||||
# check if the latest comment is exactly one day old
|
# check if the latest comment is exactly one day old
|
||||||
self.assert_(conversation.last_comment_date < datetime.utcnow() -
|
self.assert_(conversation.last_comment_date < datetime.utcnow() -
|
||||||
timedelta(hours=23, minutes=59, seconds=59))
|
timedelta(hours=23, minutes=59, seconds=59))
|
||||||
self.assert_(conversation.last_comment_date >
|
self.assert_(conversation.last_comment_date >
|
||||||
datetime.utcnow() - timedelta(days=1, seconds=1))
|
datetime.utcnow() - timedelta(days=1, seconds=1))
|
||||||
|
|
||||||
# remove the latest comment
|
# remove the latest comment
|
||||||
@ -581,9 +581,9 @@ class ConversationTest(PloneTestCase):
|
|||||||
|
|
||||||
# check if the latest comment has been updated
|
# check if the latest comment has been updated
|
||||||
# the latest comment should be exactly two days old
|
# the latest comment should be exactly two days old
|
||||||
self.assert_(conversation.last_comment_date < datetime.utcnow() -
|
self.assert_(conversation.last_comment_date < datetime.utcnow() -
|
||||||
timedelta(days=1, hours=23, minutes=59, seconds=59))
|
timedelta(days=1, hours=23, minutes=59, seconds=59))
|
||||||
self.assert_(conversation.last_comment_date > datetime.utcnow() -
|
self.assert_(conversation.last_comment_date > datetime.utcnow() -
|
||||||
timedelta(days=2, seconds=1))
|
timedelta(days=2, seconds=1))
|
||||||
|
|
||||||
# remove the latest comment again
|
# remove the latest comment again
|
||||||
@ -591,9 +591,9 @@ class ConversationTest(PloneTestCase):
|
|||||||
|
|
||||||
# check if the latest comment has been updated
|
# check if the latest comment has been updated
|
||||||
# the latest comment should be exactly four days old
|
# the latest comment should be exactly four days old
|
||||||
self.assert_(conversation.last_comment_date < datetime.utcnow() -
|
self.assert_(conversation.last_comment_date < datetime.utcnow() -
|
||||||
timedelta(days=3, hours=23, minutes=59, seconds=59))
|
timedelta(days=3, hours=23, minutes=59, seconds=59))
|
||||||
self.assert_(conversation.last_comment_date > datetime.utcnow() -
|
self.assert_(conversation.last_comment_date > datetime.utcnow() -
|
||||||
timedelta(days=4, seconds=2))
|
timedelta(days=4, seconds=2))
|
||||||
|
|
||||||
def test_get_comments_full(self):
|
def test_get_comments_full(self):
|
||||||
@ -678,15 +678,15 @@ class ConversationTest(PloneTestCase):
|
|||||||
'++conversation++default')
|
'++conversation++default')
|
||||||
self.assert_(IConversation.providedBy(conversation))
|
self.assert_(IConversation.providedBy(conversation))
|
||||||
|
|
||||||
self.assertEquals(('', 'plone', 'doc1', '++conversation++default'),
|
self.assertEquals(('', 'plone', 'doc1', '++conversation++default'),
|
||||||
conversation.getPhysicalPath())
|
conversation.getPhysicalPath())
|
||||||
# XXX: conversation.absolute_url() returns different values dependent
|
# XXX: conversation.absolute_url() returns different values dependent
|
||||||
# on the Plone version used.
|
# on the Plone version used.
|
||||||
# Plone 3.3:
|
# Plone 3.3:
|
||||||
#self.assertEquals('plone/doc1/%2B%2Bconversation%2B%2Bdefault',
|
#self.assertEquals('plone/doc1/%2B%2Bconversation%2B%2Bdefault',
|
||||||
#conversation.absolute_url())
|
#conversation.absolute_url())
|
||||||
# Plone 4:
|
# Plone 4:
|
||||||
#self.assertEquals('http://nohost/plone/doc1/++conversation++default',
|
#self.assertEquals('http://nohost/plone/doc1/++conversation++default',
|
||||||
#conversation.absolute_url())
|
#conversation.absolute_url())
|
||||||
|
|
||||||
def test_parent(self):
|
def test_parent(self):
|
||||||
|
@ -9,9 +9,9 @@ try:
|
|||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
import pprint
|
import pprint
|
||||||
import interlude
|
import interlude
|
||||||
|
|
||||||
from plone.testing import layered
|
from plone.testing import layered
|
||||||
|
|
||||||
from plone.app.discussion.testing import \
|
from plone.app.discussion.testing import \
|
||||||
PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING
|
PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING
|
||||||
PLONE4 = True
|
PLONE4 = True
|
||||||
@ -26,7 +26,7 @@ normal_testfiles = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
if PLONE4:
|
if PLONE4:
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
suite.addTests([
|
suite.addTests([
|
||||||
@ -41,9 +41,9 @@ if PLONE4:
|
|||||||
return suite
|
return suite
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
return unittest.TestSuite([])
|
return unittest.TestSuite([])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main(defaultTest='test_suite')
|
unittest.main(defaultTest='test_suite')
|
||||||
|
@ -17,14 +17,14 @@ from plone.indexer.delegate import DelegatingIndexerFactory
|
|||||||
|
|
||||||
from plone.app.discussion import catalog
|
from plone.app.discussion import catalog
|
||||||
|
|
||||||
LONG_TEXT = """Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
|
LONG_TEXT = """Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
|
||||||
diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
|
diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
|
||||||
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
|
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
|
||||||
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
|
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
|
||||||
amet."""
|
amet."""
|
||||||
|
|
||||||
LONG_TEXT_CUT = """Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
|
LONG_TEXT_CUT = """Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
|
||||||
diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
|
diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
|
||||||
sed diam voluptua. At [...]"""
|
sed diam voluptua. At [...]"""
|
||||||
|
|
||||||
|
|
||||||
@ -37,8 +37,8 @@ class ConversationIndexersTest(PloneTestCase):
|
|||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
# First we need to create some content.
|
# First we need to create some content.
|
||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
self.portal.invokeFactory(id='doc1',
|
self.portal.invokeFactory(id='doc1',
|
||||||
title='Document 1',
|
title='Document 1',
|
||||||
type_name='Document')
|
type_name='Document')
|
||||||
|
|
||||||
# Create a conversation.
|
# Create a conversation.
|
||||||
@ -71,7 +71,7 @@ class ConversationIndexersTest(PloneTestCase):
|
|||||||
self.conversation = conversation
|
self.conversation = conversation
|
||||||
|
|
||||||
def test_conversation_total_comments(self):
|
def test_conversation_total_comments(self):
|
||||||
self.assert_(isinstance(catalog.total_comments,
|
self.assert_(isinstance(catalog.total_comments,
|
||||||
DelegatingIndexerFactory))
|
DelegatingIndexerFactory))
|
||||||
self.assertEquals(catalog.total_comments(self.portal.doc1)(), 3)
|
self.assertEquals(catalog.total_comments(self.portal.doc1)(), 3)
|
||||||
del self.conversation[self.new_id1]
|
del self.conversation[self.new_id1]
|
||||||
@ -81,12 +81,12 @@ class ConversationIndexersTest(PloneTestCase):
|
|||||||
self.assertEquals(catalog.total_comments(self.portal.doc1)(), 0)
|
self.assertEquals(catalog.total_comments(self.portal.doc1)(), 0)
|
||||||
|
|
||||||
def test_conversation_last_comment_date(self):
|
def test_conversation_last_comment_date(self):
|
||||||
self.assert_(isinstance(catalog.last_comment_date,
|
self.assert_(isinstance(catalog.last_comment_date,
|
||||||
DelegatingIndexerFactory))
|
DelegatingIndexerFactory))
|
||||||
self.assertEquals(catalog.last_comment_date(self.portal.doc1)(),
|
self.assertEquals(catalog.last_comment_date(self.portal.doc1)(),
|
||||||
datetime(2009, 4, 12, 11, 12, 12))
|
datetime(2009, 4, 12, 11, 12, 12))
|
||||||
del self.conversation[self.new_id3]
|
del self.conversation[self.new_id3]
|
||||||
self.assertEquals(catalog.last_comment_date(self.portal.doc1)(),
|
self.assertEquals(catalog.last_comment_date(self.portal.doc1)(),
|
||||||
datetime(2007, 12, 13, 4, 18, 12))
|
datetime(2007, 12, 13, 4, 18, 12))
|
||||||
del self.conversation[self.new_id2]
|
del self.conversation[self.new_id2]
|
||||||
del self.conversation[self.new_id1]
|
del self.conversation[self.new_id1]
|
||||||
@ -94,11 +94,12 @@ class ConversationIndexersTest(PloneTestCase):
|
|||||||
|
|
||||||
def test_conversation_commentators(self):
|
def test_conversation_commentators(self):
|
||||||
pass
|
pass
|
||||||
#self.assertEquals(catalog.commentators(self.portal.doc1)(),
|
#self.assertEquals(catalog.commentators(self.portal.doc1)(),
|
||||||
# ('Jim', 'Emma', 'Lukas'))
|
# ('Jim', 'Emma', 'Lukas'))
|
||||||
#self.assert_(isinstance(catalog.commentators,
|
#self.assert_(isinstance(catalog.commentators,
|
||||||
# DelegatingIndexerFactory))
|
# DelegatingIndexerFactory))
|
||||||
|
|
||||||
|
|
||||||
class CommentIndexersTest(PloneTestCase):
|
class CommentIndexersTest(PloneTestCase):
|
||||||
|
|
||||||
layer = DiscussionLayer
|
layer = DiscussionLayer
|
||||||
@ -106,15 +107,15 @@ class CommentIndexersTest(PloneTestCase):
|
|||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
# First we need to create some content.
|
# First we need to create some content.
|
||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
self.portal.invokeFactory(id='doc1',
|
self.portal.invokeFactory(id='doc1',
|
||||||
title='Document 1',
|
title='Document 1',
|
||||||
type_name='Document')
|
type_name='Document')
|
||||||
|
|
||||||
# Create a conversation. In this case we doesn't assign it to an
|
# Create a conversation. In this case we doesn't assign it to an
|
||||||
# object, as we just want to check the Conversation object API.
|
# object, as we just want to check the Conversation object API.
|
||||||
conversation = IConversation(self.portal.doc1)
|
conversation = IConversation(self.portal.doc1)
|
||||||
|
|
||||||
# Add a comment. Note: in real life, we always create comments via the
|
# Add a comment. Note: in real life, we always create comments via the
|
||||||
# factory to allow different factories to be swapped in
|
# factory to allow different factories to be swapped in
|
||||||
|
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
@ -132,7 +133,7 @@ class CommentIndexersTest(PloneTestCase):
|
|||||||
self.assert_(isinstance(catalog.title, DelegatingIndexerFactory))
|
self.assert_(isinstance(catalog.title, DelegatingIndexerFactory))
|
||||||
|
|
||||||
def test_description(self):
|
def test_description(self):
|
||||||
self.assertEquals(catalog.description(self.comment)(),
|
self.assertEquals(catalog.description(self.comment)(),
|
||||||
'Lorem ipsum dolor sit amet.')
|
'Lorem ipsum dolor sit amet.')
|
||||||
self.assert_(isinstance(catalog.description, DelegatingIndexerFactory))
|
self.assert_(isinstance(catalog.description, DelegatingIndexerFactory))
|
||||||
|
|
||||||
@ -144,23 +145,23 @@ class CommentIndexersTest(PloneTestCase):
|
|||||||
comment_long.text = LONG_TEXT
|
comment_long.text = LONG_TEXT
|
||||||
|
|
||||||
self.conversation.addComment(comment_long)
|
self.conversation.addComment(comment_long)
|
||||||
self.assertEquals(catalog.description(comment_long)(),
|
self.assertEquals(catalog.description(comment_long)(),
|
||||||
LONG_TEXT_CUT.replace("\n", ""))
|
LONG_TEXT_CUT.replace("\n", " "))
|
||||||
|
|
||||||
def test_dates(self):
|
def test_dates(self):
|
||||||
# Test if created, modified, effective etc. are set correctly
|
# Test if created, modified, effective etc. are set correctly
|
||||||
self.assertEquals(catalog.created(self.comment)(),
|
self.assertEquals(catalog.created(self.comment)(),
|
||||||
DateTime(2006, 9, 17, 14, 18, 12))
|
DateTime(2006, 9, 17, 14, 18, 12))
|
||||||
self.assertEquals(catalog.effective(self.comment)(),
|
self.assertEquals(catalog.effective(self.comment)(),
|
||||||
DateTime(2006, 9, 17, 14, 18, 12))
|
DateTime(2006, 9, 17, 14, 18, 12))
|
||||||
self.assertEquals(catalog.modified(self.comment)(),
|
self.assertEquals(catalog.modified(self.comment)(),
|
||||||
DateTime(2008, 3, 12, 7, 32, 52))
|
DateTime(2008, 3, 12, 7, 32, 52))
|
||||||
|
|
||||||
def test_searchable_text(self):
|
def test_searchable_text(self):
|
||||||
# Test if searchable text is a concatenation of title and comment text
|
# Test if searchable text is a concatenation of title and comment text
|
||||||
self.assertEquals(catalog.searchable_text(self.comment)(),
|
self.assertEquals(catalog.searchable_text(self.comment)(),
|
||||||
('Lorem ipsum dolor sit amet.'))
|
('Lorem ipsum dolor sit amet.'))
|
||||||
self.assert_(isinstance(catalog.searchable_text,
|
self.assert_(isinstance(catalog.searchable_text,
|
||||||
DelegatingIndexerFactory))
|
DelegatingIndexerFactory))
|
||||||
|
|
||||||
def test_creator(self):
|
def test_creator(self):
|
||||||
@ -171,5 +172,6 @@ class CommentIndexersTest(PloneTestCase):
|
|||||||
# object the comment was added to
|
# object the comment was added to
|
||||||
self.assertEquals(catalog.in_response_to(self.comment)(), 'Document 1')
|
self.assertEquals(catalog.in_response_to(self.comment)(), 'Document 1')
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
||||||
|
@ -18,11 +18,11 @@ from plone.app.discussion.interfaces import IConversation, IComment
|
|||||||
class MigrationTest(PloneTestCase):
|
class MigrationTest(PloneTestCase):
|
||||||
|
|
||||||
layer = DiscussionLayer
|
layer = DiscussionLayer
|
||||||
|
|
||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
self.portal.invokeFactory(id='doc',
|
self.portal.invokeFactory(id='doc',
|
||||||
title='Document 1',
|
title='Document 1',
|
||||||
type_name='Document')
|
type_name='Document')
|
||||||
# Create a document
|
# Create a document
|
||||||
self.discussion = getToolByName(self.portal, 'portal_discussion', None)
|
self.discussion = getToolByName(self.portal, 'portal_discussion', None)
|
||||||
@ -35,7 +35,7 @@ class MigrationTest(PloneTestCase):
|
|||||||
request.set("test", True)
|
request.set("test", True)
|
||||||
context = getattr(self.portal, 'doc')
|
context = getattr(self.portal, 'doc')
|
||||||
self.view = View(context, request)
|
self.view = View(context, request)
|
||||||
self.workflow.setChainForPortalTypes(('Discussion Item',),
|
self.workflow.setChainForPortalTypes(('Discussion Item',),
|
||||||
'comment_review_workflow')
|
'comment_review_workflow')
|
||||||
|
|
||||||
self.doc = self.portal.doc
|
self.doc = self.portal.doc
|
||||||
@ -59,7 +59,7 @@ class MigrationTest(PloneTestCase):
|
|||||||
self.view()
|
self.view()
|
||||||
|
|
||||||
# Make sure a conversation has been created
|
# Make sure a conversation has been created
|
||||||
self.failUnless('plone.app.discussion:conversation' in
|
self.failUnless('plone.app.discussion:conversation' in
|
||||||
IAnnotations(self.doc))
|
IAnnotations(self.doc))
|
||||||
conversation = IConversation(self.doc)
|
conversation = IConversation(self.doc)
|
||||||
|
|
||||||
@ -71,9 +71,9 @@ class MigrationTest(PloneTestCase):
|
|||||||
self.assertEquals(comment1.Title(), 'Jim on Document 1')
|
self.assertEquals(comment1.Title(), 'Jim on Document 1')
|
||||||
self.assertEquals(comment1.text, 'My Text')
|
self.assertEquals(comment1.text, 'My Text')
|
||||||
self.assertEquals(comment1.Creator(), 'Jim')
|
self.assertEquals(comment1.Creator(), 'Jim')
|
||||||
self.assertEquals(comment1.creation_date,
|
self.assertEquals(comment1.creation_date,
|
||||||
datetime(2003, 3, 11, 9, 28, 6))
|
datetime(2003, 3, 11, 9, 28, 6))
|
||||||
self.assertEquals(comment1.modification_date,
|
self.assertEquals(comment1.modification_date,
|
||||||
datetime(2009, 7, 12, 19, 38, 7))
|
datetime(2009, 7, 12, 19, 38, 7))
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
[{'comment': comment1, 'depth': 0, 'id': long(comment1.id)},]
|
[{'comment': comment1, 'depth': 0, 'id': long(comment1.id)},]
|
||||||
|
@ -22,7 +22,7 @@ class ModerationViewTest(PloneTestCase):
|
|||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
typetool = self.portal.portal_types
|
typetool = self.portal.portal_types
|
||||||
typetool.constructContent('Document', self.portal, 'doc1')
|
typetool.constructContent('Document', self.portal, 'doc1')
|
||||||
|
|
||||||
self.portal_discussion = getToolByName(self.portal,
|
self.portal_discussion = getToolByName(self.portal,
|
||||||
'portal_discussion',
|
'portal_discussion',
|
||||||
None)
|
None)
|
||||||
@ -66,7 +66,7 @@ class ModerationViewTest(PloneTestCase):
|
|||||||
'++conversation++default/%s' % new_id_3)
|
'++conversation++default/%s' % new_id_3)
|
||||||
|
|
||||||
def test_moderation_enabled(self):
|
def test_moderation_enabled(self):
|
||||||
"""Make sure that moderation_enabled returns true if the comment
|
"""Make sure that moderation_enabled returns true if the comment
|
||||||
workflow implements a 'pending' state.
|
workflow implements a 'pending' state.
|
||||||
"""
|
"""
|
||||||
# The one_state_workflow does not have a 'pending' state
|
# The one_state_workflow does not have a 'pending' state
|
||||||
@ -81,10 +81,10 @@ class ModerationViewTest(PloneTestCase):
|
|||||||
def test_old_comments_not_shown_in_moderation_view(self):
|
def test_old_comments_not_shown_in_moderation_view(self):
|
||||||
# Create an old comment and make sure it is not shown
|
# Create an old comment and make sure it is not shown
|
||||||
# in the moderation view.
|
# in the moderation view.
|
||||||
|
|
||||||
# Create old comment
|
# Create old comment
|
||||||
discussion = getToolByName(self.portal, 'portal_discussion', None)
|
discussion = getToolByName(self.portal, 'portal_discussion', None)
|
||||||
discussion.overrideDiscussionFor(self.portal.doc1, 1)
|
discussion.overrideDiscussionFor(self.portal.doc1, 1)
|
||||||
talkback = discussion.getDiscussionFor(self.portal.doc1)
|
talkback = discussion.getDiscussionFor(self.portal.doc1)
|
||||||
self.portal.doc1.talkback.createReply('My Title', 'My Text', Creator='Jim')
|
self.portal.doc1.talkback.createReply('My Title', 'My Text', Creator='Jim')
|
||||||
reply = talkback.getReplies()[0]
|
reply = talkback.getReplies()[0]
|
||||||
@ -96,7 +96,7 @@ class ModerationViewTest(PloneTestCase):
|
|||||||
self.failUnless('Jim' in reply.listCreators())
|
self.failUnless('Jim' in reply.listCreators())
|
||||||
self.assertEquals(talkback.replyCount(self.portal.doc1), 1)
|
self.assertEquals(talkback.replyCount(self.portal.doc1), 1)
|
||||||
self.assertEquals(reply.inReplyTo(), self.portal.doc1)
|
self.assertEquals(reply.inReplyTo(), self.portal.doc1)
|
||||||
|
|
||||||
# Make sure only the two new comments are shown
|
# Make sure only the two new comments are shown
|
||||||
self.view()
|
self.view()
|
||||||
self.assertEquals(len(self.view.comments), 3)
|
self.assertEquals(len(self.view.comments), 3)
|
||||||
@ -110,10 +110,10 @@ class ModerationBulkActionsViewTest(PloneTestCase):
|
|||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
typetool = self.portal.portal_types
|
typetool = self.portal.portal_types
|
||||||
typetool.constructContent('Document', self.portal, 'doc1')
|
typetool.constructContent('Document', self.portal, 'doc1')
|
||||||
self.wf = getToolByName(self.portal,
|
self.wf = getToolByName(self.portal,
|
||||||
'portal_workflow',
|
'portal_workflow',
|
||||||
None)
|
None)
|
||||||
|
|
||||||
self.request = self.app.REQUEST
|
self.request = self.app.REQUEST
|
||||||
self.context = self.portal
|
self.context = self.portal
|
||||||
self.portal.portal_workflow.setChainForPortalTypes(
|
self.portal.portal_workflow.setChainForPortalTypes(
|
||||||
@ -149,7 +149,7 @@ class ModerationBulkActionsViewTest(PloneTestCase):
|
|||||||
'++conversation++default/%s' % new_id_3)
|
'++conversation++default/%s' % new_id_3)
|
||||||
|
|
||||||
self.conversation = conversation
|
self.conversation = conversation
|
||||||
|
|
||||||
def test_default_bulkaction(self):
|
def test_default_bulkaction(self):
|
||||||
# Make sure no error is raised when no bulk actions has been supplied
|
# Make sure no error is raised when no bulk actions has been supplied
|
||||||
self.request = self.app.REQUEST
|
self.request = self.app.REQUEST
|
||||||
@ -158,14 +158,14 @@ class ModerationBulkActionsViewTest(PloneTestCase):
|
|||||||
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
|
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
|
||||||
view = BulkActionsView(self.context, self.request)
|
view = BulkActionsView(self.context, self.request)
|
||||||
self.failIf(view())
|
self.failIf(view())
|
||||||
|
|
||||||
def test_retract(self):
|
def test_retract(self):
|
||||||
self.request = self.app.REQUEST
|
self.request = self.app.REQUEST
|
||||||
self.context = self.portal
|
self.context = self.portal
|
||||||
self.request.set('form.select.BulkAction', 'retract')
|
self.request.set('form.select.BulkAction', 'retract')
|
||||||
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
|
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
|
||||||
view = BulkActionsView(self.context, self.request)
|
view = BulkActionsView(self.context, self.request)
|
||||||
|
|
||||||
self.assertRaises(NotImplementedError,
|
self.assertRaises(NotImplementedError,
|
||||||
view)
|
view)
|
||||||
|
|
||||||
@ -173,10 +173,10 @@ class ModerationBulkActionsViewTest(PloneTestCase):
|
|||||||
self.request = self.app.REQUEST
|
self.request = self.app.REQUEST
|
||||||
self.context = self.portal
|
self.context = self.portal
|
||||||
self.request.set('form.select.BulkAction', 'publish')
|
self.request.set('form.select.BulkAction', 'publish')
|
||||||
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
|
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
|
||||||
view = BulkActionsView(self.context, self.request)
|
view = BulkActionsView(self.context, self.request)
|
||||||
view()
|
view()
|
||||||
|
|
||||||
# Count published comments
|
# Count published comments
|
||||||
published_comments = 0
|
published_comments = 0
|
||||||
for r in self.conversation.getThreads():
|
for r in self.conversation.getThreads():
|
||||||
@ -184,17 +184,17 @@ class ModerationBulkActionsViewTest(PloneTestCase):
|
|||||||
workflow_status = self.wf.getInfoFor(comment_obj, 'review_state')
|
workflow_status = self.wf.getInfoFor(comment_obj, 'review_state')
|
||||||
if workflow_status == 'published':
|
if workflow_status == 'published':
|
||||||
published_comments += 1
|
published_comments += 1
|
||||||
|
|
||||||
# Make sure the comment has been published
|
# Make sure the comment has been published
|
||||||
self.assertEquals(published_comments, 1)
|
self.assertEquals(published_comments, 1)
|
||||||
|
|
||||||
def test_mark_as_spam(self):
|
def test_mark_as_spam(self):
|
||||||
self.request = self.app.REQUEST
|
self.request = self.app.REQUEST
|
||||||
self.context = self.portal
|
self.context = self.portal
|
||||||
self.request.set('form.select.BulkAction', 'mark_as_spam')
|
self.request.set('form.select.BulkAction', 'mark_as_spam')
|
||||||
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
|
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
|
||||||
view = BulkActionsView(self.context, self.request)
|
view = BulkActionsView(self.context, self.request)
|
||||||
|
|
||||||
self.assertRaises(NotImplementedError,
|
self.assertRaises(NotImplementedError,
|
||||||
view)
|
view)
|
||||||
|
|
||||||
@ -204,14 +204,14 @@ class ModerationBulkActionsViewTest(PloneTestCase):
|
|||||||
|
|
||||||
# Initially we have three comments
|
# Initially we have three comments
|
||||||
self.assertEquals(self.conversation.total_comments, 3)
|
self.assertEquals(self.conversation.total_comments, 3)
|
||||||
|
|
||||||
# Delete two comments with bulk actions
|
# Delete two comments with bulk actions
|
||||||
self.request.set('form.select.BulkAction', 'delete')
|
self.request.set('form.select.BulkAction', 'delete')
|
||||||
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath()),
|
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath()),
|
||||||
'/'.join(self.comment3.getPhysicalPath())])
|
'/'.join(self.comment3.getPhysicalPath())])
|
||||||
view = BulkActionsView(self.context, self.request)
|
view = BulkActionsView(self.context, self.request)
|
||||||
view()
|
view()
|
||||||
|
|
||||||
# Make sure that the two comments have been deleted
|
# Make sure that the two comments have been deleted
|
||||||
self.assertEquals(self.conversation.total_comments, 1)
|
self.assertEquals(self.conversation.total_comments, 1)
|
||||||
comment = self.conversation.getComments().next()
|
comment = self.conversation.getComments().next()
|
||||||
|
@ -50,9 +50,9 @@ class TestUserNotificationUnit(PloneTestCase):
|
|||||||
self.portal.MailHost = self.portal._original_MailHost
|
self.portal.MailHost = self.portal._original_MailHost
|
||||||
sm = getSiteManager(context=self.portal)
|
sm = getSiteManager(context=self.portal)
|
||||||
sm.unregisterUtility(provided=IMailHost)
|
sm.unregisterUtility(provided=IMailHost)
|
||||||
sm.registerUtility(aq_base(self.portal._original_MailHost),
|
sm.registerUtility(aq_base(self.portal._original_MailHost),
|
||||||
provided=IMailHost)
|
provided=IMailHost)
|
||||||
|
|
||||||
def test_notify_user(self):
|
def test_notify_user(self):
|
||||||
# Add a comment with user notification enabled. Add another comment
|
# Add a comment with user notification enabled. Add another comment
|
||||||
# and make sure an email is send to the user of the first comment.
|
# and make sure an email is send to the user of the first comment.
|
||||||
@ -74,7 +74,7 @@ class TestUserNotificationUnit(PloneTestCase):
|
|||||||
# We expect the headers to be properly header encoded (7-bit):
|
# We expect the headers to be properly header encoded (7-bit):
|
||||||
#>>> 'Subject: =?utf-8?q?Some_t=C3=A4st_subject=2E?=' in msg
|
#>>> 'Subject: =?utf-8?q?Some_t=C3=A4st_subject=2E?=' in msg
|
||||||
#True
|
#True
|
||||||
# # The output should be encoded in a reasonable manner
|
# # The output should be encoded in a reasonable manner
|
||||||
# (in this case quoted-printable):
|
# (in this case quoted-printable):
|
||||||
#>>> msg
|
#>>> msg
|
||||||
#'...Another t=C3=A4st message...You are receiving this mail \
|
#'...Another t=C3=A4st message...You are receiving this mail \
|
||||||
@ -97,9 +97,9 @@ class TestUserNotificationUnit(PloneTestCase):
|
|||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
comment.text = 'Comment text'
|
comment.text = 'Comment text'
|
||||||
self.conversation.addComment(comment)
|
self.conversation.addComment(comment)
|
||||||
|
|
||||||
self.assertEquals(len(self.mailhost.messages), 0)
|
self.assertEquals(len(self.mailhost.messages), 0)
|
||||||
|
|
||||||
def test_do_not_notify_user_when_email_address_is_given(self):
|
def test_do_not_notify_user_when_email_address_is_given(self):
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
comment.text = 'Comment text'
|
comment.text = 'Comment text'
|
||||||
@ -109,7 +109,7 @@ class TestUserNotificationUnit(PloneTestCase):
|
|||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
comment.text = 'Comment text'
|
comment.text = 'Comment text'
|
||||||
self.conversation.addComment(comment)
|
self.conversation.addComment(comment)
|
||||||
|
|
||||||
self.assertEquals(len(self.mailhost.messages), 0)
|
self.assertEquals(len(self.mailhost.messages), 0)
|
||||||
|
|
||||||
def test_do_not_notify_user_when_no_sender_is_available(self):
|
def test_do_not_notify_user_when_no_sender_is_available(self):
|
||||||
@ -126,7 +126,7 @@ class TestUserNotificationUnit(PloneTestCase):
|
|||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
comment.text = 'Comment text'
|
comment.text = 'Comment text'
|
||||||
self.conversation.addComment(comment)
|
self.conversation.addComment(comment)
|
||||||
|
|
||||||
self.assertEquals(len(self.mailhost.messages), 0)
|
self.assertEquals(len(self.mailhost.messages), 0)
|
||||||
|
|
||||||
def test_notify_only_once(self):
|
def test_notify_only_once(self):
|
||||||
@ -179,13 +179,13 @@ class TestModeratorNotificationUnit(PloneTestCase):
|
|||||||
# We need to fake a valid mail setup
|
# We need to fake a valid mail setup
|
||||||
self.portal.email_from_address = "portal@plone.test"
|
self.portal.email_from_address = "portal@plone.test"
|
||||||
self.mailhost = self.portal.MailHost
|
self.mailhost = self.portal.MailHost
|
||||||
|
|
||||||
# Enable comment moderation
|
# Enable comment moderation
|
||||||
self.portal.portal_types['Document'].allow_discussion = True
|
self.portal.portal_types['Document'].allow_discussion = True
|
||||||
self.portal.portal_workflow.setChainForPortalTypes(
|
self.portal.portal_workflow.setChainForPortalTypes(
|
||||||
('Discussion Item',),
|
('Discussion Item',),
|
||||||
('comment_review_workflow',))
|
('comment_review_workflow',))
|
||||||
|
|
||||||
# Enable moderator notification setting
|
# Enable moderator notification setting
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
registry['plone.app.discussion.interfaces.IDiscussionSettings.' +
|
registry['plone.app.discussion.interfaces.IDiscussionSettings.' +
|
||||||
@ -201,9 +201,9 @@ class TestModeratorNotificationUnit(PloneTestCase):
|
|||||||
self.portal.MailHost = self.portal._original_MailHost
|
self.portal.MailHost = self.portal._original_MailHost
|
||||||
sm = getSiteManager(context=self.portal)
|
sm = getSiteManager(context=self.portal)
|
||||||
sm.unregisterUtility(provided=IMailHost)
|
sm.unregisterUtility(provided=IMailHost)
|
||||||
sm.registerUtility(aq_base(self.portal._original_MailHost),
|
sm.registerUtility(aq_base(self.portal._original_MailHost),
|
||||||
provided=IMailHost)
|
provided=IMailHost)
|
||||||
|
|
||||||
def test_notify_moderator(self):
|
def test_notify_moderator(self):
|
||||||
# Add a comment and make sure an email is send to the moderator.
|
# Add a comment and make sure an email is send to the moderator.
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
@ -213,7 +213,7 @@ class TestModeratorNotificationUnit(PloneTestCase):
|
|||||||
self.assertEquals(len(self.mailhost.messages), 1)
|
self.assertEquals(len(self.mailhost.messages), 1)
|
||||||
self.failUnless(self.mailhost.messages[0])
|
self.failUnless(self.mailhost.messages[0])
|
||||||
msg = self.mailhost.messages[0]
|
msg = self.mailhost.messages[0]
|
||||||
|
|
||||||
if not isinstance(msg, str):
|
if not isinstance(msg, str):
|
||||||
# Plone 3
|
# Plone 3
|
||||||
self.failUnless('portal@plone.test' in msg.mfrom)
|
self.failUnless('portal@plone.test' in msg.mfrom)
|
||||||
@ -221,17 +221,17 @@ class TestModeratorNotificationUnit(PloneTestCase):
|
|||||||
else:
|
else:
|
||||||
#Plone 4
|
#Plone 4
|
||||||
self.failUnless('To: portal@plone.test' in msg)
|
self.failUnless('To: portal@plone.test' in msg)
|
||||||
self.failUnless('From: portal@plone.test' in msg)
|
self.failUnless('From: portal@plone.test' in msg)
|
||||||
|
|
||||||
#We expect the headers to be properly header encoded (7-bit):
|
#We expect the headers to be properly header encoded (7-bit):
|
||||||
#>>> 'Subject: =?utf-8?q?Some_t=C3=A4st_subject=2E?=' in msg
|
#>>> 'Subject: =?utf-8?q?Some_t=C3=A4st_subject=2E?=' in msg
|
||||||
#True
|
#True
|
||||||
|
|
||||||
#The output should be encoded in a reasonable manner (in this case
|
#The output should be encoded in a reasonable manner (in this case
|
||||||
# quoted-printable):
|
# quoted-printable):
|
||||||
#>>> msg
|
#>>> msg
|
||||||
#'...Another t=C3=A4st message...You are receiving this mail because
|
#'...Another t=C3=A4st message...You are receiving this mail because
|
||||||
# T=C3=A4st user\ntest@plone.test...is sending feedback about the site
|
# T=C3=A4st user\ntest@plone.test...is sending feedback about the site
|
||||||
# you administer at...
|
# you administer at...
|
||||||
|
|
||||||
def test_do_not_notify_moderator_when_no_sender_is_available(self):
|
def test_do_not_notify_moderator_when_no_sender_is_available(self):
|
||||||
@ -243,9 +243,9 @@ class TestModeratorNotificationUnit(PloneTestCase):
|
|||||||
comment.text = 'Comment text'
|
comment.text = 'Comment text'
|
||||||
self.conversation.addComment(comment)
|
self.conversation.addComment(comment)
|
||||||
self.assertEquals(len(self.mailhost.messages), 0)
|
self.assertEquals(len(self.mailhost.messages), 0)
|
||||||
|
|
||||||
def test_do_not_notify_moderator_when_notification_is_disabled(self):
|
def test_do_not_notify_moderator_when_notification_is_disabled(self):
|
||||||
# Disable moderator notification setting and make sure no email is send
|
# Disable moderator notification setting and make sure no email is send
|
||||||
# to the moderator.
|
# to the moderator.
|
||||||
registry = queryUtility(IRegistry)
|
registry = queryUtility(IRegistry)
|
||||||
registry['plone.app.discussion.interfaces.IDiscussionSettings.' +
|
registry['plone.app.discussion.interfaces.IDiscussionSettings.' +
|
||||||
@ -263,7 +263,7 @@ class TestModeratorNotificationUnit(PloneTestCase):
|
|||||||
self.portal.portal_workflow.setChainForPortalTypes(
|
self.portal.portal_workflow.setChainForPortalTypes(
|
||||||
('Discussion Item',),
|
('Discussion Item',),
|
||||||
('one_state_workflow',))
|
('one_state_workflow',))
|
||||||
|
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
comment.text = 'Comment text'
|
comment.text = 'Comment text'
|
||||||
self.conversation.addComment(comment)
|
self.conversation.addComment(comment)
|
||||||
|
@ -14,8 +14,8 @@ class ToolTest(PloneTestCase):
|
|||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
# First we need to create some content.
|
# First we need to create some content.
|
||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
self.portal.invokeFactory(id='doc1',
|
self.portal.invokeFactory(id='doc1',
|
||||||
title='Document 1',
|
title='Document 1',
|
||||||
type_name='Document')
|
type_name='Document')
|
||||||
|
|
||||||
def test_tool_indexing(self):
|
def test_tool_indexing(self):
|
||||||
|
@ -23,7 +23,7 @@ class WorkflowSetupTest(PloneTestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
layer = DiscussionLayer
|
layer = DiscussionLayer
|
||||||
|
|
||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
"""Create a document and allow discussion.
|
"""Create a document and allow discussion.
|
||||||
"""
|
"""
|
||||||
@ -31,13 +31,13 @@ class WorkflowSetupTest(PloneTestCase):
|
|||||||
self.portal_discussion = self.portal.portal_discussion
|
self.portal_discussion = self.portal.portal_discussion
|
||||||
self.folder.invokeFactory('Document', 'doc1')
|
self.folder.invokeFactory('Document', 'doc1')
|
||||||
self.doc = self.folder.doc1
|
self.doc = self.folder.doc1
|
||||||
|
|
||||||
def test_workflows_installed(self):
|
def test_workflows_installed(self):
|
||||||
"""Make sure both comment workflows have been installed properly.
|
"""Make sure both comment workflows have been installed properly.
|
||||||
"""
|
"""
|
||||||
self.failUnless('one_state_workflow' in
|
self.failUnless('one_state_workflow' in
|
||||||
self.portal.portal_workflow.objectIds())
|
self.portal.portal_workflow.objectIds())
|
||||||
self.failUnless('comment_review_workflow' in
|
self.failUnless('comment_review_workflow' in
|
||||||
self.portal.portal_workflow.objectIds())
|
self.portal.portal_workflow.objectIds())
|
||||||
|
|
||||||
def test_default_workflow(self):
|
def test_default_workflow(self):
|
||||||
@ -46,7 +46,7 @@ class WorkflowSetupTest(PloneTestCase):
|
|||||||
self.assertEquals(('one_state_workflow',),
|
self.assertEquals(('one_state_workflow',),
|
||||||
self.portal.portal_workflow.getChainForPortalType(
|
self.portal.portal_workflow.getChainForPortalType(
|
||||||
'Discussion Item'))
|
'Discussion Item'))
|
||||||
|
|
||||||
def test_review_comments_permission(self):
|
def test_review_comments_permission(self):
|
||||||
#'Review comments' in self.portal.permissionsOfRole('Admin')
|
#'Review comments' in self.portal.permissionsOfRole('Admin')
|
||||||
|
|
||||||
@ -65,12 +65,12 @@ class PermissionsSetupTest(PloneTestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
layer = DiscussionLayer
|
layer = DiscussionLayer
|
||||||
|
|
||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
portal = self.portal
|
portal = self.portal
|
||||||
mtool = self.portal.portal_membership
|
mtool = self.portal.portal_membership
|
||||||
self.checkPermission = mtool.checkPermission
|
self.checkPermission = mtool.checkPermission
|
||||||
|
|
||||||
def test_reply_to_item_permission_assigned(self):
|
def test_reply_to_item_permission_assigned(self):
|
||||||
"""Make sure the 'Reply to item' permission is properly assigned.
|
"""Make sure the 'Reply to item' permission is properly assigned.
|
||||||
By default this permission is assigned to 'Member' and 'Manager'.
|
By default this permission is assigned to 'Member' and 'Manager'.
|
||||||
@ -96,7 +96,7 @@ class CommentOneStateWorkflowTest(PloneTestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
layer = DiscussionLayer
|
layer = DiscussionLayer
|
||||||
|
|
||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
"""Create a document with comments and enable the one.
|
"""Create a document with comments and enable the one.
|
||||||
"""
|
"""
|
||||||
@ -106,31 +106,31 @@ class CommentOneStateWorkflowTest(PloneTestCase):
|
|||||||
'one_state_workflow')
|
'one_state_workflow')
|
||||||
self.folder.invokeFactory('Document', 'doc1')
|
self.folder.invokeFactory('Document', 'doc1')
|
||||||
self.doc = self.folder.doc1
|
self.doc = self.folder.doc1
|
||||||
|
|
||||||
# Add a comment
|
# Add a comment
|
||||||
conversation = IConversation(self.folder.doc1)
|
conversation = IConversation(self.folder.doc1)
|
||||||
comment = createObject('plone.Comment')
|
comment = createObject('plone.Comment')
|
||||||
comment.text = 'Comment text'
|
comment.text = 'Comment text'
|
||||||
cid = conversation.addComment(comment)
|
cid = conversation.addComment(comment)
|
||||||
|
|
||||||
self.comment = self.folder.doc1.restrictedTraverse(\
|
self.comment = self.folder.doc1.restrictedTraverse(\
|
||||||
'++conversation++default/%s' % cid)
|
'++conversation++default/%s' % cid)
|
||||||
|
|
||||||
self.portal.acl_users._doAddUser('member', 'secret', ['Member'], [])
|
self.portal.acl_users._doAddUser('member', 'secret', ['Member'], [])
|
||||||
self.portal.acl_users._doAddUser('reviewer', 'secret', ['Reviewer'], [])
|
self.portal.acl_users._doAddUser('reviewer', 'secret', ['Reviewer'], [])
|
||||||
self.portal.acl_users._doAddUser('manager', 'secret', ['Manager'], [])
|
self.portal.acl_users._doAddUser('manager', 'secret', ['Manager'], [])
|
||||||
self.portal.acl_users._doAddUser('editor' , ' secret', ['Editor'],[])
|
self.portal.acl_users._doAddUser('editor' , ' secret', ['Editor'],[])
|
||||||
self.portal.acl_users._doAddUser('reader', 'secret', ['Reader'], [])
|
self.portal.acl_users._doAddUser('reader', 'secret', ['Reader'], [])
|
||||||
|
|
||||||
def test_initial_workflow_state(self):
|
def test_initial_workflow_state(self):
|
||||||
"""Make sure the initial workflow state of a comment is 'published'.
|
"""Make sure the initial workflow state of a comment is 'published'.
|
||||||
"""
|
"""
|
||||||
self.assertEqual(self.workflow.getInfoFor(self.doc, 'review_state'),
|
self.assertEqual(self.workflow.getInfoFor(self.doc, 'review_state'),
|
||||||
'published')
|
'published')
|
||||||
|
|
||||||
def test_view_comments(self):
|
def test_view_comments(self):
|
||||||
"""Make sure published comments can be viewed by everyone.
|
"""Make sure published comments can be viewed by everyone.
|
||||||
"""
|
"""
|
||||||
# Owner is allowed
|
# Owner is allowed
|
||||||
#self.login(default_user)
|
#self.login(default_user)
|
||||||
#self.failUnless(checkPerm(View, self.doc))
|
#self.failUnless(checkPerm(View, self.doc))
|
||||||
@ -149,14 +149,14 @@ class CommentOneStateWorkflowTest(PloneTestCase):
|
|||||||
# Reader is allowed
|
# Reader is allowed
|
||||||
self.login('reader')
|
self.login('reader')
|
||||||
self.failUnless(checkPerm(View, self.comment))
|
self.failUnless(checkPerm(View, self.comment))
|
||||||
|
|
||||||
|
|
||||||
class CommentReviewWorkflowTest(PloneTestCase):
|
class CommentReviewWorkflowTest(PloneTestCase):
|
||||||
"""Test the comment_review_workflow that ships with plone.app.discussion.
|
"""Test the comment_review_workflow that ships with plone.app.discussion.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
layer = DiscussionLayer
|
layer = DiscussionLayer
|
||||||
|
|
||||||
def afterSetUp(self):
|
def afterSetUp(self):
|
||||||
# Allow discussion and
|
# Allow discussion and
|
||||||
self.loginAsPortalOwner()
|
self.loginAsPortalOwner()
|
||||||
@ -217,7 +217,7 @@ class CommentReviewWorkflowTest(PloneTestCase):
|
|||||||
def test_publish(self):
|
def test_publish(self):
|
||||||
self.portal.REQUEST.form['comment_id'] = self.comment_id
|
self.portal.REQUEST.form['comment_id'] = self.comment_id
|
||||||
self.portal.REQUEST.form['workflow_action'] = 'publish'
|
self.portal.REQUEST.form['workflow_action'] = 'publish'
|
||||||
self.assertEquals('pending',
|
self.assertEquals('pending',
|
||||||
self.portal.portal_workflow.getInfoFor(
|
self.portal.portal_workflow.getInfoFor(
|
||||||
self.comment, 'review_state'))
|
self.comment, 'review_state'))
|
||||||
view = self.comment.restrictedTraverse('@@moderate-publish-comment')
|
view = self.comment.restrictedTraverse('@@moderate-publish-comment')
|
||||||
|
@ -15,18 +15,18 @@ from OFS.SimpleItem import SimpleItem
|
|||||||
|
|
||||||
|
|
||||||
class CommentingTool(UniqueObject, SimpleItem):
|
class CommentingTool(UniqueObject, SimpleItem):
|
||||||
|
|
||||||
interface.implements(ICommentingTool)
|
interface.implements(ICommentingTool)
|
||||||
|
|
||||||
meta_type = 'plone.app.discussion tool'
|
meta_type = 'plone.app.discussion tool'
|
||||||
id = 'portal_discussion'
|
id = 'portal_discussion'
|
||||||
|
|
||||||
def reindexObject(self, object):
|
def reindexObject(self, object):
|
||||||
"""Remove from catalog.
|
"""Remove from catalog.
|
||||||
"""
|
"""
|
||||||
catalog = getToolByName(self, 'portal_catalog')
|
catalog = getToolByName(self, 'portal_catalog')
|
||||||
return catalog.reindexObject(object)
|
return catalog.reindexObject(object)
|
||||||
|
|
||||||
indexObject = reindexObject
|
indexObject = reindexObject
|
||||||
|
|
||||||
def unindexObject(self, object):
|
def unindexObject(self, object):
|
||||||
@ -34,7 +34,7 @@ class CommentingTool(UniqueObject, SimpleItem):
|
|||||||
"""
|
"""
|
||||||
catalog = getToolByName(self, 'portal_catalog')
|
catalog = getToolByName(self, 'portal_catalog')
|
||||||
return catalog.unindexObject(object)
|
return catalog.unindexObject(object)
|
||||||
|
|
||||||
def uniqueValuesFor(self, name):
|
def uniqueValuesFor(self, name):
|
||||||
""" return unique values for FieldIndex name """
|
""" return unique values for FieldIndex name """
|
||||||
catalog = getToolByName(self, 'portal_catalog')
|
catalog = getToolByName(self, 'portal_catalog')
|
||||||
@ -47,14 +47,14 @@ class CommentingTool(UniqueObject, SimpleItem):
|
|||||||
"""
|
"""
|
||||||
catalog = getToolByName(self, 'portal_catalog')
|
catalog = getToolByName(self, 'portal_catalog')
|
||||||
object_provides = [IComment.__identifier__]
|
object_provides = [IComment.__identifier__]
|
||||||
|
|
||||||
if 'object_provides' in kw:
|
if 'object_provides' in kw:
|
||||||
kw_provides = kw['object_provides']
|
kw_provides = kw['object_provides']
|
||||||
if isinstance(str, kw_provides):
|
if isinstance(str, kw_provides):
|
||||||
object_provides.append(kw_provides)
|
object_provides.append(kw_provides)
|
||||||
else:
|
else:
|
||||||
object_provides.extend(kw_provides)
|
object_provides.extend(kw_provides)
|
||||||
|
|
||||||
if REQUEST is not None and 'object_provides' in REQUEST.form:
|
if REQUEST is not None and 'object_provides' in REQUEST.form:
|
||||||
rq_provides = REQUEST.form['object_provides']
|
rq_provides = REQUEST.form['object_provides']
|
||||||
del REQUEST.form['object_provides']
|
del REQUEST.form['object_provides']
|
||||||
@ -62,7 +62,7 @@ class CommentingTool(UniqueObject, SimpleItem):
|
|||||||
object_provides.append(rq_provides)
|
object_provides.append(rq_provides)
|
||||||
else:
|
else:
|
||||||
object_provides.extend(rq_provides)
|
object_provides.extend(rq_provides)
|
||||||
|
|
||||||
kw['object_provides'] = object_provides
|
kw['object_provides'] = object_provides
|
||||||
return catalog.searchResults(REQUEST, **kw)
|
return catalog.searchResults(REQUEST, **kw)
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ def index_object(obj, event):
|
|||||||
tool = queryUtility(ICommentingTool)
|
tool = queryUtility(ICommentingTool)
|
||||||
if tool is not None:
|
if tool is not None:
|
||||||
tool.indexObject(obj)
|
tool.indexObject(obj)
|
||||||
|
|
||||||
def unindex_object(obj, event):
|
def unindex_object(obj, event):
|
||||||
"""Unindex the object when removed
|
"""Unindex the object when removed
|
||||||
"""
|
"""
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
|
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
|
||||||
|
|
||||||
from plone.app.discussion.interfaces import _
|
from plone.app.discussion.interfaces import _
|
||||||
|
|
||||||
HAS_CAPTCHA = False
|
HAS_CAPTCHA = False
|
||||||
try:
|
try:
|
||||||
@ -55,17 +55,17 @@ def captcha_vocabulary(context):
|
|||||||
SimpleTerm(
|
SimpleTerm(
|
||||||
value='recaptcha',
|
value='recaptcha',
|
||||||
token='recaptcha',
|
token='recaptcha',
|
||||||
title='ReCaptcha'))
|
title='ReCaptcha'))
|
||||||
|
|
||||||
if HAS_AKISMET: # pragma: no cover
|
if HAS_AKISMET: # pragma: no cover
|
||||||
terms.append(
|
terms.append(
|
||||||
SimpleTerm(
|
SimpleTerm(
|
||||||
value='akismet',
|
value='akismet',
|
||||||
token='akismet',
|
token='akismet',
|
||||||
title='Akismet'))
|
title='Akismet'))
|
||||||
|
|
||||||
if HAS_NOROBOTS: # pragma: no cover
|
if HAS_NOROBOTS: # pragma: no cover
|
||||||
terms.append(
|
terms.append(
|
||||||
SimpleTerm(
|
SimpleTerm(
|
||||||
value='norobots',
|
value='norobots',
|
||||||
token='norobots',
|
token='norobots',
|
||||||
|
Loading…
Reference in New Issue
Block a user