ask for comment when refusing a validation (#4496)

This commit is contained in:
Frédéric Péters 2014-10-08 14:51:24 +02:00
parent 5e4a7c2d67
commit 9ebef0ab14
6 changed files with 150 additions and 2 deletions

View File

@ -8,6 +8,8 @@ from plone.dexterity.browser.add import DefaultAddForm
from plone.dexterity.interfaces import IDexterityFTI
from plone.dexterity.utils import addContentToContainer, getAdditionalSchemata
from zope.annotation.interfaces import IAnnotations
from pfwbged.policy import _
@ -43,6 +45,12 @@ class AskValidation(DefaultAddForm):
def add(self, object):
fti = getUtility(IDexterityFTI, name=self.portal_type)
container = aq_parent(aq_inner(self.context))
# annotate the validation task with the related version, it can later
# be used to match the task against the correct version.
annotations = IAnnotations(object)
annotations['related_version_id'] = self.context.id
new_object = addContentToContainer(container, object)
# execute transition on version
api.content.transition(self.context, transition='submit')

View File

@ -97,6 +97,13 @@
permission="zope2.View"
/>
<browser:page
name="refuse"
for="collective.dms.basecontent.dmsfile.IDmsFile"
class=".refuse.WfCommentView"
permission="zope2.View"
/>
<browser:view
name="importGroupFolders"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"

View File

@ -0,0 +1,123 @@
# -*- encoding: utf-8 -*-
from datetime import datetime
from zope.interface import Interface
from zope import schema
from zope.component import createObject, queryUtility
from z3c.form import form, button
from z3c.form.field import Fields
from z3c.form.interfaces import HIDDEN_MODE
from Acquisition import aq_inner, aq_parent
from zope.annotation.interfaces import IAnnotations
from plone.z3cform.layout import FormWrapper
from Products.Five.browser import BrowserView
from Products.CMFCore.utils import getToolByName
from plone import api
from plone.app.discussion.interfaces import ICommentingTool, IConversation
from .. import _
class IComment(Interface):
workflow_action = schema.Text(
title=_(u"Workflow action"),
required=True)
comment = schema.Text(
title=_(u"Comment"),
description=_(u"You can enter a note."),
required=False)
class WfCommentForm(form.AddForm):
fields = Fields(IComment)
fields['workflow_action'].mode = HIDDEN_MODE
next_url = None
def updateActions(self):
super(WfCommentForm, self).updateActions()
self.actions["save"].addClass("context")
self.actions["cancel"].addClass("standalone")
def updateWidgets(self):
super(WfCommentForm, self).updateWidgets()
if 'workflow_action' in self.request:
self.widgets['workflow_action'].value = (
self.request['workflow_action'])
@button.buttonAndHandler(_(u'Refuse'), name='save')
def handleAdd(self, action):
data, errors = self.extractData()
if errors:
self.status = self.formErrorsMessage
return
self._finishedAdd = True
comment = data['comment'] or u""
comment = comment.strip()
if comment:
portal_membership = getToolByName(self.context, 'portal_membership')
# Member
member = portal_membership.getAuthenticatedMember()
username = member.getUserName()
email = member.getProperty('email')
fullname = member.getProperty('fullname')
if not fullname or fullname == '':
fullname = member.getUserName()
# memberdata is stored as utf-8 encoded strings
elif isinstance(fullname, str):
fullname = unicode(fullname, 'utf-8')
if email and isinstance(email, str):
email = unicode(email, 'utf-8')
# add comment to validation objects
catalog = api.portal.get_tool('portal_catalog')
container_path = '/'.join(aq_parent(self.context).getPhysicalPath())
tasks = catalog.searchResults({'path': {'query': container_path},
'portal_type': 'validation', 'review_state': 'todo'})
for validation_object in tasks:
annotations = IAnnotations(validation_object.getObject())
if not 'related_version_id' in annotations:
continue
if annotations['related_version_id'] != self.context.id:
continue
comment_object = createObject('plone.Comment')
comment_object.creator = username
comment_object.author_username = username
comment_object.author_name = fullname
comment_object.author_email = email
comment_object.creation_date = datetime.utcnow()
comment_object.modification_date = datetime.utcnow()
comment_object.text = comment
conversation = IConversation(validation_object.getObject())
conversation.addComment(comment_object)
api.content.transition(obj=self.context, transition=data['workflow_action'])
self.context.reindexObject(idxs=['review_state'])
self.next_url = aq_parent(self.context).absolute_url()
@button.buttonAndHandler(_(u'Cancel'), name='cancel')
def handleCancel(self, action):
self._finishedAdd = True
self.next_url = aq_parent(self.context).absolute_url()
def nextURL(self):
return self.next_url
class WfCommentView(FormWrapper, BrowserView):
form = WfCommentForm
def __init__(self, context, request):
BrowserView.__init__(self, context, request)
FormWrapper.__init__(self, context, request)

View File

@ -151,7 +151,8 @@ class CustomMenu(menu.WorkflowMenu):
description = ''
if action['id'] in ('submit', 'ask_opinion', 'attribute', 'to_process'):
if action['id'] in ('submit', 'ask_opinion', 'attribute',
'to_process', 'refuse'):
cssClass += " overlay-form-reload"
transition = action.get('transition', None)

View File

@ -148,7 +148,7 @@
</guard>
</transition>
<transition transition_id="refuse" title="Refuse" new_state="draft" trigger="USER" before_script="" after_script="" i18n:attributes="title">
<action url="" category="workflow" icon="" i18n:translate="">Refuse</action>
<action url="%(content_url)s/@@refuse?workflow_action=refuse" category="workflow" icon="" i18n:translate="">Refuse</action>
<guard>
<guard-expression>here/@@can_validate_or_refuse</guard-expression>
</guard>

View File

@ -1,4 +1,5 @@
import logging
import datetime
from Acquisition import aq_chain, aq_parent
from five import grok
@ -18,6 +19,7 @@ from plone import api
from plone.stringinterp.adapters import _recursiveGetMembersFromIds
from Products.DCWorkflow.interfaces import IAfterTransitionEvent
from plone.app.discussion.interfaces import ICommentingTool, IConversation
from collective.z3cform.rolefield.field import LocalRolesToPrincipalsDataManager
@ -404,6 +406,13 @@ def email_notification_of_refused_task(context, event):
translate(_('Document Address: %s'), context=context.REQUEST) % document.absolute_url() + \
'\n\n'
conversation = IConversation(context)
if conversation and conversation.getComments():
last_comment = list(conversation.getComments())[-1]
if (datetime.datetime.utcnow() - last_comment.creation_date).seconds < 120:
# comment less than two minutes ago, include it.
body += translate(_('Note:'), context=context.REQUEST) + '\n\n' + last_comment.text
body = body.encode('utf-8')
try: