14b00ff361
svn path=/plone.app.discussion/trunk/; revision=27702
369 lines
12 KiB
Python
369 lines
12 KiB
Python
from plone.app.content.browser.tableview import Table, TableKSSView
|
|
|
|
from Acquisition import aq_inner, aq_parent
|
|
|
|
from Products.Five.browser import BrowserView
|
|
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
|
|
|
from zope.app.pagetemplate import ViewPageTemplateFile as VPTF
|
|
|
|
from Products.CMFCore.utils import getToolByName
|
|
|
|
from zope.component import getMultiAdapter
|
|
from zope.interface import implements
|
|
from zope.i18n import translate
|
|
|
|
from AccessControl import Unauthorized
|
|
from Acquisition import aq_parent, aq_inner
|
|
from OFS.interfaces import IOrderedContainer
|
|
from Products.ATContentTypes.interface import IATTopic
|
|
from Products.CMFCore.utils import getToolByName
|
|
from Products.CMFPlone.utils import safe_unicode
|
|
from Products.Five import BrowserView
|
|
|
|
from plone.memoize import instance
|
|
from plone.app.content.browser.interfaces import IFolderContentsView
|
|
from plone.app.content.browser.tableview import Table, TableKSSView
|
|
|
|
from Products.CMFPlone.interfaces import IPloneSiteRoot
|
|
|
|
import urllib
|
|
|
|
class View(BrowserView):
|
|
"""Moderation View
|
|
"""
|
|
|
|
template = ViewPageTemplateFile('moderation.pt')
|
|
|
|
def __call__(self):
|
|
|
|
context = aq_inner(self.context)
|
|
|
|
self.state = self.request.get('review_state', 'pending')
|
|
self.transition = self.request.get('publish_transition', 'pending')
|
|
self.limit = self.request.get('limit', 100)
|
|
|
|
if self.request.has_key('form.button.FilterPending'):
|
|
self.comments = self.comments_pending()
|
|
elif self.request.has_key('form.button.FilterPublished'):
|
|
self.comments = self.comments_published()
|
|
else:
|
|
self.comments = self.comments_all()
|
|
return self.template()
|
|
|
|
def comments_table(self):
|
|
table = ReviewCommentsTable(aq_inner(self.context), self.request, self.comments, self.transition)
|
|
return table.render()
|
|
|
|
def comments_all(self, start=0, size=None):
|
|
|
|
self.state = self.request.get('review_state', 'pending')
|
|
self.transition = self.request.get('publish_transition', 'pending')
|
|
self.limit = self.request.get('limit', 100)
|
|
|
|
context = aq_inner(self.context)
|
|
catalog = getToolByName(context, 'portal_catalog')
|
|
|
|
return catalog(
|
|
portal_type='Discussion Item',
|
|
sort_on='created',
|
|
sort_limit=self.limit,
|
|
)
|
|
|
|
def comments_pending(self, start=0, size=None):
|
|
self.state = self.request.get('review_state', 'pending')
|
|
self.transition = self.request.get('publish_transition', 'publish')
|
|
self.limit = self.request.get('limit', 100)
|
|
|
|
context = aq_inner(self.context)
|
|
catalog = getToolByName(context, 'portal_catalog')
|
|
|
|
return catalog(
|
|
portal_type='Discussion Item',
|
|
review_state=self.state,
|
|
sort_on='created',
|
|
sort_limit=self.limit,
|
|
)
|
|
|
|
def comments_published(self, start=0, size=None):
|
|
|
|
self.state = self.request.get('review_state', 'pending')
|
|
self.transition = self.request.get('publish_transition', 'pending')
|
|
self.limit = self.request.get('limit', 100)
|
|
|
|
context = aq_inner(self.context)
|
|
catalog = getToolByName(context, 'portal_catalog')
|
|
|
|
return catalog(
|
|
portal_type='Discussion Item',
|
|
review_state='published',
|
|
sort_on='created',
|
|
sort_limit=self.limit,
|
|
)
|
|
|
|
def comments_spam(self, start=0, size=None):
|
|
return None
|
|
|
|
def cook(self, text):
|
|
return text
|
|
|
|
def comments_workflow_enabled(self):
|
|
return True
|
|
|
|
class ReviewTable(Table):
|
|
render = VPTF("table.pt")
|
|
batching = VPTF("batching.pt")
|
|
|
|
class ReviewCommentsTable(object):
|
|
"""The reviewcomments table renders the table and its actions.
|
|
"""
|
|
|
|
def __init__(self, context, request, content, transition, contentFilter={}, ):
|
|
self.context = context
|
|
self.request = request
|
|
self.contentFilter = contentFilter
|
|
self.content = content
|
|
self.transition = transition
|
|
|
|
url = context.absolute_url()
|
|
view_url = url + '/@@moderate-comments'
|
|
self.table = ReviewTable(request, url, view_url, self.items)
|
|
|
|
def render(self):
|
|
return self.table.render()
|
|
|
|
@property
|
|
def items(self):
|
|
"""
|
|
"""
|
|
context = aq_inner(self.context)
|
|
|
|
#self.state = self.request.get('review_state', 'pending')
|
|
#self.transition = self.request.get('publish_transition', 'pending')
|
|
#self.limit = self.request.get('limit', 100)
|
|
|
|
#catalog = getToolByName(context, 'portal_catalog')
|
|
|
|
#brains = catalog(
|
|
# portal_type='Discussion Item',
|
|
# sort_on='created',
|
|
# sort_limit=self.limit,
|
|
# )
|
|
|
|
brains = self.content
|
|
|
|
plone_utils = getToolByName(context, 'plone_utils')
|
|
plone_view = getMultiAdapter((context, self.request), name=u'plone')
|
|
portal_workflow = getToolByName(context, 'portal_workflow')
|
|
portal_properties = getToolByName(context, 'portal_properties')
|
|
portal_types = getToolByName(context, 'portal_types')
|
|
site_properties = portal_properties.site_properties
|
|
|
|
use_view_action = site_properties.getProperty('typesUseViewActionInListings', ())
|
|
browser_default = context.browserDefault()
|
|
|
|
results = []
|
|
|
|
for i, obj in enumerate(brains):
|
|
if (i + 1) % 2 == 0:
|
|
table_row_class = "draggable even"
|
|
else:
|
|
table_row_class = "draggable odd"
|
|
|
|
url = obj.getURL()
|
|
path = obj.getPath or "/".join(obj.getPhysicalPath())
|
|
icon = plone_view.getIcon(obj);
|
|
|
|
type_class = 'contenttype-' + plone_utils.normalizeString(
|
|
obj.portal_type)
|
|
|
|
review_state = obj.review_state
|
|
state_class = 'state-' + plone_utils.normalizeString(review_state)
|
|
relative_url = obj.getURL(relative=True)
|
|
|
|
type_title_msgid = portal_types[obj.portal_type].Title()
|
|
url_href_title = u'%s: %s' % (translate(type_title_msgid,
|
|
context=self.request),
|
|
safe_unicode(obj.Description))
|
|
|
|
modified = plone_view.toLocalizedTime(
|
|
obj.ModificationDate, long_format=1)
|
|
|
|
obj_type = obj.Type
|
|
#if obj_type in use_view_action:
|
|
# view_url = url + '/view'
|
|
#elif obj.is_folderish:
|
|
# view_url = url + "/moderate-comments"
|
|
#else:
|
|
# view_url = url
|
|
view_url = url + "/@@moderate-comments"
|
|
|
|
is_browser_default = len(browser_default[1]) == 1 and (
|
|
obj.id == browser_default[1][0])
|
|
|
|
results.append(dict(
|
|
url = url,
|
|
url_href_title = url_href_title,
|
|
id = obj.getId,
|
|
quoted_id = urllib.quote_plus(obj.getId),
|
|
path = path,
|
|
title_or_id = obj.pretty_title_or_id(),
|
|
obj_type = obj_type,
|
|
size = obj.getObjSize,
|
|
modified = modified,
|
|
icon = icon.html_tag(),
|
|
type_class = type_class,
|
|
wf_state = review_state,
|
|
transition = self.transition,
|
|
state_title = portal_workflow.getTitleForStateOnType(review_state,
|
|
obj_type),
|
|
state_class = state_class,
|
|
is_browser_default = is_browser_default,
|
|
folderish = obj.is_folderish,
|
|
relative_url = relative_url,
|
|
view_url = view_url,
|
|
table_row_class = table_row_class,
|
|
is_expired = context.isExpired(obj),
|
|
))
|
|
return results
|
|
|
|
@property
|
|
def orderable(self):
|
|
"""
|
|
"""
|
|
return IOrderedContainer.providedBy(aq_inner(self.context))
|
|
|
|
@property
|
|
def show_sort_column(self):
|
|
return self.orderable and self.editable
|
|
|
|
@property
|
|
def editable(self):
|
|
"""
|
|
"""
|
|
context_state = getMultiAdapter((aq_inner(self.context), self.request),
|
|
name=u'plone_context_state')
|
|
return context_state.is_editable()
|
|
|
|
@property
|
|
def buttons(self):
|
|
|
|
buttons = []
|
|
context = aq_inner(self.context)
|
|
portal_actions = getToolByName(context, 'portal_actions')
|
|
#button_actions = portal_actions.listActionInfos(object=context, categories=('folder_buttons', ))
|
|
button_actions = portal_actions.listActionInfos(object=context)
|
|
|
|
# Do not show buttons if there is no data, unless there is data to be
|
|
# pasted
|
|
if not len(self.items):
|
|
if self.context.cb_dataValid():
|
|
for button in button_actions:
|
|
if button['id'] == 'paste':
|
|
return [self.setbuttonclass(button)]
|
|
else:
|
|
return []
|
|
|
|
for button in button_actions:
|
|
# Make proper classes for our buttons
|
|
if button['id'] != 'paste' or context.cb_dataValid():
|
|
buttons.append(self.setbuttonclass(button))
|
|
return buttons
|
|
|
|
def setbuttonclass(self, button):
|
|
if button['id'] == 'paste':
|
|
button['cssclass'] = 'standalone'
|
|
else:
|
|
button['cssclass'] = 'context'
|
|
return button
|
|
|
|
|
|
|
|
class ReviewCommentsKSSView(TableKSSView):
|
|
table = ReviewCommentsTable
|
|
|
|
|
|
class DeleteComment(BrowserView):
|
|
"""Delete a comment from a conversation
|
|
"""
|
|
|
|
def __call__(self):
|
|
|
|
context = aq_inner(self.context)
|
|
comment_id = self.context.id
|
|
|
|
conversation = aq_parent(context)
|
|
|
|
del conversation[comment_id]
|
|
|
|
return context.REQUEST.RESPONSE.redirect(context.REQUEST.HTTP_REFERER)
|
|
|
|
class PublishComment(BrowserView):
|
|
"""Publish a comment
|
|
"""
|
|
|
|
def __call__(self):
|
|
|
|
comment = aq_inner(self.context)
|
|
comment_id = self.context.id
|
|
|
|
workflow_action = self.request.form['workflow_action']
|
|
portal_workflow = getToolByName(comment, 'portal_workflow')
|
|
portal_workflow.doActionFor(comment, workflow_action)
|
|
|
|
catalog = getToolByName(comment, 'portal_catalog')
|
|
catalog.reindexObject(comment)
|
|
|
|
return self.context.REQUEST.RESPONSE.redirect(self.context.REQUEST.HTTP_REFERER)
|
|
|
|
class BulkActionsView(BrowserView):
|
|
"""Bulk actions (unapprove, approve, delete, mark as spam).
|
|
"""
|
|
|
|
def __call__(self):
|
|
|
|
context = aq_inner(self.context)
|
|
|
|
if self.request.has_key('form.button.BulkAction'):
|
|
|
|
bulkaction = self.request.get('form.select.BulkAction')
|
|
|
|
paths = self.request.get('paths')
|
|
|
|
if bulkaction == '-1':
|
|
return self.context.REQUEST.RESPONSE.redirect(self.context.REQUEST.HTTP_REFERER)
|
|
elif bulkaction == 'retract':
|
|
self.retract(paths)
|
|
elif bulkaction == 'publish':
|
|
self.publish(paths)
|
|
elif bulkaction == 'mark_as_spam':
|
|
self.mark_as_spam(paths)
|
|
elif bulkaction == 'delete':
|
|
self.delete(paths)
|
|
else:
|
|
raise KeyError
|
|
|
|
return self.context.REQUEST.RESPONSE.redirect(self.context.REQUEST.HTTP_REFERER)
|
|
|
|
def retract(self, paths):
|
|
raise NotImplementedError
|
|
|
|
def publish(self, paths):
|
|
context = aq_inner(self.context)
|
|
for path in paths:
|
|
comment = context.restrictedTraverse(path)
|
|
portal_workflow = getToolByName(comment, 'portal_workflow')
|
|
portal_workflow.doActionFor(comment, 'publish')
|
|
catalog = getToolByName(comment, 'portal_catalog')
|
|
catalog.reindexObject(comment)
|
|
|
|
def mark_as_spam(self, paths):
|
|
raise NotImplementedError
|
|
|
|
def delete(self, paths):
|
|
context = aq_inner(self.context)
|
|
for path in paths:
|
|
comment = context.restrictedTraverse(path)
|
|
conversation = aq_parent(comment)
|
|
del conversation[comment.id]
|