ask for comment when refusing a validation (#4496)
This commit is contained in:
parent
5e4a7c2d67
commit
9ebef0ab14
|
@ -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')
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
|
|
Reference in New Issue