Compare commits
24 Commits
Author | SHA1 | Date |
---|---|---|
Nicolas Demonte | e23e31aca0 | |
Nicolas Demonte | 656681290a | |
Nicolas Demonte | f960f15ed2 | |
Nicolas Demonte | e638aa2caf | |
Nicolas Demonte | 5982a97bbb | |
Nicolas Demonte | a60881fac6 | |
Nicolas Demonte | 20e957d2a4 | |
Nicolas Demonte | d82a32792c | |
Nicolas Demonte | 998f04473c | |
Laurent Lasudry | 9171319411 | |
Nicolas Demonte | e1b3003109 | |
Nicolas Demonte | ef4ffcc5fa | |
Nicolas Demonte | c555b03dec | |
Nicolas Demonte | 3987ec9e82 | |
Nicolas Demonte | fb769655c1 | |
Nicolas Demonte | d24bb396d1 | |
Nicolas Demonte | 6530bedf9a | |
Nicolas Demonte | dd1fe898df | |
Nicolas Demonte | 9e3ced236e | |
Nicolas Demonte | f85614073d | |
Nicolas Demonte | ec6af89840 | |
Nicolas Demonte | 7720ab11bd | |
Nicolas Demonte | 4213ecfd77 | |
Nicolas Demonte | 9be18c4b00 |
3
setup.py
3
setup.py
|
@ -51,8 +51,10 @@ setup(
|
|||
'collective.edm.listing',
|
||||
'collective.externaleditor',
|
||||
'collective.onlogin',
|
||||
'collective.select2',
|
||||
'collective.solr',
|
||||
'collective.task',
|
||||
'collective.taskqueue',
|
||||
'five.grok',
|
||||
'pfwbged.basecontent',
|
||||
'pfwbged.collection',
|
||||
|
@ -62,6 +64,7 @@ setup(
|
|||
'plone.app.contenttypes',
|
||||
'z3c.jbot',
|
||||
'Products.AROfficeTransforms',
|
||||
'collective.impersonate',
|
||||
],
|
||||
extras_require={
|
||||
'test': [
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import pickle
|
||||
from copy import deepcopy
|
||||
|
||||
from Products.Five.browser import BrowserView
|
||||
|
||||
import z3c.form
|
||||
from collective.taskqueue import taskqueue
|
||||
from z3c.form import button
|
||||
|
||||
import zope.event
|
||||
from zope.component import getUtility
|
||||
from zope.i18nmessageid.message import MessageFactory
|
||||
|
||||
from plone import api
|
||||
|
@ -13,33 +19,14 @@ from plone.stringinterp.adapters import _recursiveGetMembersFromIds
|
|||
from collective.task import _
|
||||
|
||||
|
||||
class AddInformation(DefaultAddForm):
|
||||
"""Custom add information view"""
|
||||
|
||||
portal_type = "information"
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
return self.request.getURL() + '?documents=' + self.request.documents
|
||||
|
||||
@button.buttonAndHandler(_('Add'), name='add')
|
||||
def handleAdd(self, action):
|
||||
data, errors = self.extractData()
|
||||
if errors:
|
||||
self.status = self.formErrorsMessage
|
||||
return
|
||||
|
||||
for document_id in self.request.documents.split(','):
|
||||
base_document = api.content.get(str(document_id))
|
||||
self.add_info(base_document, data)
|
||||
|
||||
self._finishedAdd = True
|
||||
return
|
||||
|
||||
def add_info(self, base_document, data):
|
||||
class BackgroundAddInformationView(BrowserView):
|
||||
def __call__(self):
|
||||
base_document = self.context
|
||||
data = pickle.load(self.request.stdin)
|
||||
portal = api.portal.get()
|
||||
objs = []
|
||||
seen = {}
|
||||
|
||||
for responsible in data['responsible']:
|
||||
group = api.group.get(responsible)
|
||||
if group is not None:
|
||||
|
@ -63,4 +50,28 @@ class AddInformation(DefaultAddForm):
|
|||
createContentInContainer(base_document, 'information', **_data)
|
||||
seen[responsible] = True
|
||||
|
||||
print 'seen:', seen
|
||||
|
||||
class AddInformation(DefaultAddForm):
|
||||
"""Custom add information view"""
|
||||
|
||||
portal_type = "information"
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
return self.request.getURL() + '?documents=' + self.request.documents
|
||||
|
||||
@button.buttonAndHandler(_('Add'), name='add')
|
||||
def handleAdd(self, action):
|
||||
data, errors = self.extractData()
|
||||
if errors:
|
||||
self.status = self.formErrorsMessage
|
||||
return
|
||||
|
||||
for document_id in self.request.documents.split(','):
|
||||
taskqueue.add(
|
||||
'{}/background_add_information'.format(document_id),
|
||||
payload=pickle.dumps(data),
|
||||
)
|
||||
|
||||
self._finishedAdd = True
|
||||
return
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Products.Five.browser import BrowserView
|
||||
from collective.task import _
|
||||
from collective.taskqueue import taskqueue
|
||||
from plone import api
|
||||
from plone.dexterity.browser.add import DefaultAddForm
|
||||
from plone.dexterity.utils import createContentInContainer
|
||||
from z3c.form import button
|
||||
from z3c.relationfield.relation import RelationValue
|
||||
from zope.component import getUtility
|
||||
from zope.intid import IIntIds
|
||||
|
||||
|
||||
class BackgroundAddLinkView(BrowserView):
|
||||
def __call__(self):
|
||||
base_document = self.context
|
||||
folder_path = self.request.form['folder']
|
||||
portal = api.portal.get()
|
||||
folder = portal.restrictedTraverse(folder_path)
|
||||
intids = getUtility(IIntIds)
|
||||
relation = RelationValue(to_id=intids.getId(folder))
|
||||
|
||||
new_link = createContentInContainer(
|
||||
base_document,
|
||||
'pfwbgedlink',
|
||||
folder=relation,
|
||||
)
|
||||
|
||||
|
||||
class AddLinks(DefaultAddForm):
|
||||
"Add multiple pfwbgedlinks"
|
||||
|
||||
portal_type = "pfwbgedlink"
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return u"Classer dans un dossier"
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
return self.request.getURL() + '?documents=' + self.request.documents
|
||||
|
||||
@button.buttonAndHandler(_('Add'), name='add')
|
||||
def handleAdd(self, action):
|
||||
data, errors = self.extractData()
|
||||
if errors:
|
||||
self.status = self.formErrorsMessage
|
||||
return
|
||||
|
||||
folder_path = data['folder'].absolute_url_path().lstrip("/")
|
||||
|
||||
for document_id in self.request.documents.split(','):
|
||||
taskqueue.add(
|
||||
'{}/background_add_link'.format(document_id),
|
||||
params={'folder': folder_path},
|
||||
)
|
||||
|
||||
self._finishedAdd = True
|
||||
return
|
|
@ -1,19 +1,53 @@
|
|||
import pickle
|
||||
|
||||
from Products.Five.browser import BrowserView
|
||||
|
||||
from zope.i18n import translate
|
||||
|
||||
from collective.taskqueue import taskqueue
|
||||
from copy import deepcopy
|
||||
from plone import api
|
||||
from plone.dexterity.browser.add import DefaultAddForm
|
||||
from plone.dexterity.utils import addContentToContainer, getAdditionalSchemata
|
||||
from plone.dexterity.utils import createContent
|
||||
from z3c.form.interfaces import HIDDEN_MODE
|
||||
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
import zope.event
|
||||
import zope.lifecycleevent
|
||||
|
||||
from z3c.form import button
|
||||
from pfwbged.policy import _
|
||||
|
||||
|
||||
class BackgroundAskValidationView(BrowserView):
|
||||
def __call__(self):
|
||||
base_document = self.context
|
||||
data = pickle.load(self.request.stdin)
|
||||
|
||||
for child in reversed(base_document.values()):
|
||||
if child.portal_type == 'dmsmainfile':
|
||||
last_version = child
|
||||
break
|
||||
|
||||
_data = deepcopy(data)
|
||||
_data['title'] = translate(
|
||||
_(u"Validation application for version ${version}",
|
||||
mapping={'version': last_version.Title()}),
|
||||
context=self.request)
|
||||
_data['ITarget.target'] = last_version
|
||||
|
||||
new_validation = createContent('validation', **_data)
|
||||
addContentToContainer(base_document, new_validation)
|
||||
|
||||
# annotate the validation task with the related version, it can later
|
||||
# be used to match the task against the correct version.
|
||||
annotations = IAnnotations(new_validation)
|
||||
annotations['related_version_id'] = last_version.id
|
||||
|
||||
# execute transition on version
|
||||
api.content.transition(last_version, transition='submit')
|
||||
last_version.reindexObject(idxs=['review_state'])
|
||||
|
||||
|
||||
class AskValidations(DefaultAddForm):
|
||||
"""Ask validation custom add form
|
||||
"""
|
||||
|
@ -49,34 +83,10 @@ class AskValidations(DefaultAddForm):
|
|||
return
|
||||
|
||||
for document_id in self.request.documents.split(','):
|
||||
base_document = api.content.get(str(document_id))
|
||||
self.ask_validation(base_document, data)
|
||||
taskqueue.add(
|
||||
'{}/background_ask_validation'.format(document_id),
|
||||
payload=pickle.dumps(data),
|
||||
)
|
||||
|
||||
self._finishedAdd = True
|
||||
return
|
||||
|
||||
def ask_validation(self, base_document, data):
|
||||
for child in reversed(base_document.values()):
|
||||
if child.portal_type == 'dmsmainfile':
|
||||
last_version = child
|
||||
break
|
||||
|
||||
_data = deepcopy(data)
|
||||
_data['title'] = translate(
|
||||
_(u"Validation application for version ${version}",
|
||||
mapping={'version': last_version.Title()}),
|
||||
context=self.request)
|
||||
_data['ITarget.target'] = last_version
|
||||
|
||||
new_validation = self.create(_data)
|
||||
zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(new_validation))
|
||||
addContentToContainer(base_document, new_validation)
|
||||
|
||||
# annotate the validation task with the related version, it can later
|
||||
# be used to match the task against the correct version.
|
||||
annotations = IAnnotations(new_validation)
|
||||
annotations['related_version_id'] = last_version.id
|
||||
|
||||
# execute transition on version
|
||||
api.content.transition(last_version, transition='submit')
|
||||
last_version.reindexObject(idxs=['review_state'])
|
||||
|
|
|
@ -64,6 +64,14 @@
|
|||
permission="cmf.AddPortalContent"
|
||||
/>
|
||||
|
||||
<browser:page
|
||||
name="background_add_information"
|
||||
class=".add_multi_information.BackgroundAddInformationView"
|
||||
for="*"
|
||||
permission="cmf.AddPortalContent"
|
||||
layer="collective.taskqueue.interfaces.ITaskQueueLayer"
|
||||
/>
|
||||
|
||||
<browser:page
|
||||
name="multi_attribute_task"
|
||||
for="*"
|
||||
|
@ -71,6 +79,29 @@
|
|||
permission="cmf.AddPortalContent"
|
||||
/>
|
||||
|
||||
<browser:page
|
||||
name="background_attribute_task"
|
||||
class=".multi_attribute_task.BackgroundAttributeTaskView"
|
||||
for="*"
|
||||
permission="cmf.AddPortalContent"
|
||||
layer="collective.taskqueue.interfaces.ITaskQueueLayer"
|
||||
/>
|
||||
|
||||
<browser:page
|
||||
name="add_multi_link"
|
||||
for="*"
|
||||
class=".add_multi_link.AddLinks"
|
||||
permission="cmf.AddPortalContent"
|
||||
/>
|
||||
|
||||
<browser:page
|
||||
name="background_add_link"
|
||||
class=".add_multi_link.BackgroundAddLinkView"
|
||||
for="*"
|
||||
permission="cmf.AddPortalContent"
|
||||
layer="collective.taskqueue.interfaces.ITaskQueueLayer"
|
||||
/>
|
||||
|
||||
<browser:page
|
||||
name="ask_multi_validation"
|
||||
for="*"
|
||||
|
@ -78,6 +109,16 @@
|
|||
permission="cmf.AddPortalContent"
|
||||
/>
|
||||
|
||||
|
||||
<browser:page
|
||||
name="background_ask_validation"
|
||||
class=".ask_multi_validation.BackgroundAskValidationView"
|
||||
for="*"
|
||||
permission="cmf.AddPortalContent"
|
||||
layer="collective.taskqueue.interfaces.ITaskQueueLayer"
|
||||
/>
|
||||
|
||||
|
||||
<!-- Custom comments viewlet for IBaseTask -->
|
||||
<browser:viewlet
|
||||
name="plone.comments"
|
||||
|
@ -174,4 +215,21 @@
|
|||
permission="cmf.ManagePortal"
|
||||
/>
|
||||
|
||||
<!-- Outgoing mail add form -->
|
||||
<adapter
|
||||
for="Products.CMFCore.interfaces.IFolderish
|
||||
zope.publisher.interfaces.browser.IDefaultBrowserLayer
|
||||
plone.dexterity.interfaces.IDexterityFTI"
|
||||
provides="zope.publisher.interfaces.browser.IBrowserPage"
|
||||
factory="pfwbged.policy.browser.create_outgoing_mail.AddView"
|
||||
name="dmsoutgoingmail"
|
||||
/>
|
||||
|
||||
<class class="pfwbged.policy.browser.create_outgoing_mail.AddView">
|
||||
<require
|
||||
permission="cmf.AddPortalContent"
|
||||
interface="zope.publisher.interfaces.browser.IBrowserPage"
|
||||
/>
|
||||
</class>
|
||||
|
||||
</configure>
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
from five import grok
|
||||
from pfwbged.basecontent.types import INoteForBoard
|
||||
from plone import api
|
||||
from zc.relation.interfaces import ICatalog
|
||||
from zope.component import getUtility
|
||||
from zope.intid.interfaces import IIntIds
|
||||
|
||||
|
||||
class CanCreateBoardDecision(grok.View):
|
||||
"""Create a board decision from a note for board"""
|
||||
|
||||
grok.name('can_create_board_decision')
|
||||
grok.context(INoteForBoard)
|
||||
grok.require("zope2.View")
|
||||
|
||||
def in_gestion_sg(self):
|
||||
return any([group for group in api.group.get_groups(user=api.user.get_current()) if
|
||||
group.id == 'Gestion-secretariat-general'])
|
||||
|
||||
def board_decision_created(self):
|
||||
"""Return true if a board decision has been created for this note for board"""
|
||||
intids = getUtility(IIntIds)
|
||||
catalog = getUtility(ICatalog)
|
||||
try:
|
||||
note_intid = intids.getId(self.context)
|
||||
except KeyError:
|
||||
return False
|
||||
else:
|
||||
return any(catalog.findRelations({'to_id': note_intid,
|
||||
'from_attribute': 'related_docs'}))
|
||||
|
||||
def render(self):
|
||||
if not self.in_gestion_sg():
|
||||
return False
|
||||
|
||||
if self.board_decision_created():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class CreateBoardDecision(grok.View):
|
||||
"""Create a board decision from a note for board"""
|
||||
|
||||
grok.name('create_board_decision')
|
||||
grok.context(INoteForBoard)
|
||||
grok.require("zope2.View")
|
||||
|
||||
def render(self):
|
||||
note = self.context
|
||||
|
||||
values_params = [
|
||||
u'form.widgets.IBasic.title={}'.format(
|
||||
note.title,
|
||||
),
|
||||
u'form.widgets.related_docs:list={}'.format(
|
||||
u'/'.join(note.getPhysicalPath()),
|
||||
),
|
||||
]
|
||||
|
||||
list_fields = {
|
||||
'treated_by': 'IPfwbDocument.treated_by',
|
||||
'treating_groups': 'treating_groups',
|
||||
'recipient_groups': 'recipient_groups',
|
||||
'keywords': 'IPfwbDocument.keywords',
|
||||
}
|
||||
for field_id, field_param_id in list_fields.items():
|
||||
field = getattr(note, field_id, []) or []
|
||||
for item in field:
|
||||
values_params.append(
|
||||
u'form.widgets.{}:list={}'.format(field_param_id, item)
|
||||
)
|
||||
|
||||
documents_folder_url = api.portal.get()['documents'].absolute_url()
|
||||
encoded_params = "&".join(values_params).encode('utf-8')
|
||||
url = '{0}/++add++pfwb.boarddecision?{1}'.format(
|
||||
documents_folder_url,
|
||||
encoded_params,
|
||||
)
|
||||
self.request.response.redirect(url)
|
|
@ -1,18 +1,21 @@
|
|||
import zope
|
||||
|
||||
from Acquisition import aq_parent
|
||||
|
||||
from five import grok
|
||||
|
||||
from plone import api
|
||||
|
||||
from collective.dms.mailcontent.dmsmail import IDmsIncomingMail
|
||||
from collective.task.content.task import ITask
|
||||
from pfwbged.basecontent.types import IBoardDecision
|
||||
from plone.api.exc import InvalidParameterError
|
||||
from plone.dexterity.browser import add
|
||||
|
||||
|
||||
class NoIDmsIncomingMailFound(Exception):
|
||||
"""No IDmsIncomingMail found"""
|
||||
|
||||
|
||||
class CreateOutgoingMail(grok.View):
|
||||
class CreateOutgoingMailFromTask(grok.View):
|
||||
|
||||
grok.name("create_outgoing_mail")
|
||||
grok.context(ITask)
|
||||
|
@ -59,9 +62,91 @@ form.widgets.treating_groups=%(treating_groups)s""" % values
|
|||
values_url += '&' + 'form.widgets.recipient_groups:list=%s' % principal
|
||||
|
||||
folder_url = api.portal.get()['documents'].absolute_url()
|
||||
if incomingmail.portal_type == 'pfwb.apfincomingmail':
|
||||
outgoing_add_url = '/++add++pfwb.apfoutgoingmail?'
|
||||
else:
|
||||
outgoing_add_url = "/++add++dmsoutgoingmail?"
|
||||
url = folder_url + outgoing_add_url + values_url.encode('utf-8')
|
||||
url = folder_url + "/++add++dmsoutgoingmail?" + values_url.encode('utf-8')
|
||||
self.request.response.redirect(url)
|
||||
|
||||
|
||||
class CreateOutgoingMailFromBoardDecision(grok.View):
|
||||
|
||||
grok.name("create_outgoing_mail")
|
||||
grok.context(IBoardDecision)
|
||||
grok.require("zope2.View")
|
||||
|
||||
def render(self):
|
||||
decision = self.context
|
||||
|
||||
values_params = [
|
||||
u'form.widgets.related_docs:list={}'.format(
|
||||
u'/'.join(decision.getPhysicalPath()),
|
||||
),
|
||||
]
|
||||
|
||||
list_fields = {
|
||||
'treated_by': 'IPfwbDocument.treated_by',
|
||||
'treating_groups': 'treating_groups',
|
||||
'recipient_groups': 'recipient_groups',
|
||||
'keywords': 'IPfwbDocument.keywords',
|
||||
}
|
||||
for field_id, field_param_id in list_fields.items():
|
||||
field = getattr(decision, field_id, []) or []
|
||||
for item in field:
|
||||
values_params.append(
|
||||
u'form.widgets.{}:list={}'.format(field_param_id, item)
|
||||
)
|
||||
|
||||
documents_folder_url = api.portal.get()['documents'].absolute_url()
|
||||
if self.request.form.get('follow_up'):
|
||||
values_params.append('follow_up=1')
|
||||
encoded_params = "&".join(values_params).encode('utf-8')
|
||||
url = '{0}/++add++dmsoutgoingmail?{1}'.format(
|
||||
documents_folder_url,
|
||||
encoded_params,
|
||||
)
|
||||
self.request.response.redirect(url)
|
||||
|
||||
|
||||
class AddForm(add.DefaultAddForm):
|
||||
|
||||
portal_type = "dmsoutgoingmail"
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
base_action = super(AddForm, self).action
|
||||
return '{}?follow_up=1'.format(base_action)
|
||||
|
||||
def createAndAdd(self, data):
|
||||
obj = self.create(data)
|
||||
zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(obj))
|
||||
self.add(obj)
|
||||
self.transition_board_decision() # addition to base method
|
||||
return obj
|
||||
|
||||
def transition_board_decision(self):
|
||||
"""
|
||||
If the created mail is a follow-up (GET parameter),
|
||||
search for board decisions in processing state among related documents,
|
||||
transition the first one found to answered.
|
||||
"""
|
||||
|
||||
follow_up = self.request.form.get('follow_up', False)
|
||||
if not follow_up:
|
||||
return
|
||||
|
||||
related_docs = getattr(
|
||||
self.widgets.get('related_docs'),
|
||||
'value',
|
||||
[],
|
||||
)
|
||||
portal = api.portal.get()
|
||||
for related_doc_path in related_docs:
|
||||
related_doc = portal.restrictedTraverse(related_doc_path.split('/'))
|
||||
if IBoardDecision.providedBy(related_doc) and api.content.get_state(related_doc) == 'processing':
|
||||
try:
|
||||
api.content.transition(related_doc, 'answer')
|
||||
break
|
||||
except InvalidParameterError: # answer transition is not available
|
||||
pass
|
||||
|
||||
|
||||
class AddView(add.DefaultAddView):
|
||||
form = AddForm
|
||||
|
|
|
@ -1,21 +1,46 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pickle
|
||||
from copy import deepcopy
|
||||
import z3c.form
|
||||
from z3c.form import button
|
||||
|
||||
import zope.event
|
||||
from zope.i18nmessageid.message import MessageFactory
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser import BrowserView
|
||||
|
||||
from plone import api
|
||||
from plone.dexterity.browser.add import DefaultAddForm
|
||||
from plone.dexterity.utils import createContentInContainer
|
||||
from plone.stringinterp.adapters import _recursiveGetMembersFromIds
|
||||
|
||||
from collective.task import _
|
||||
from collective.task.content.task import ITask
|
||||
from collective.task.browser.attribute_task import find_nontask
|
||||
from collective.taskqueue import taskqueue
|
||||
|
||||
|
||||
class BackgroundAttributeTaskView(BrowserView):
|
||||
def __call__(self):
|
||||
base_task = self.context
|
||||
data = pickle.load(self.request.stdin)
|
||||
|
||||
seen = {}
|
||||
nontask = find_nontask(base_task)
|
||||
portal_workflow = getToolByName(nontask, 'portal_workflow')
|
||||
transitions = portal_workflow.getTransitionsFor(nontask)
|
||||
transition_ids = [t['id'] for t in transitions]
|
||||
|
||||
for responsible in data['responsible']:
|
||||
if responsible in seen:
|
||||
continue
|
||||
_data = deepcopy(data)
|
||||
_data['responsible'] = [responsible]
|
||||
new_task = createContentInContainer(base_task, 'task', **_data)
|
||||
seen[responsible] = True
|
||||
|
||||
for responsible in data['responsible']:
|
||||
nontask.manage_addLocalRoles(responsible, ['Editor',])
|
||||
if 'attribute' in transition_ids:
|
||||
portal_workflow.doActionFor(nontask, 'attribute')
|
||||
nontask.reindexObjectSecurity()
|
||||
nontask.reindexObject(idxs=['allowedRolesAndUsers'])
|
||||
|
||||
|
||||
class AttributeTasks(DefaultAddForm):
|
||||
|
@ -53,31 +78,11 @@ class AttributeTasks(DefaultAddForm):
|
|||
self.status = self.formErrorsMessage
|
||||
return
|
||||
|
||||
for task_id in self.request.documents.split(','):
|
||||
base_task = api.content.get(str(task_id))
|
||||
self.attribute_task(base_task, data)
|
||||
for document_id in self.request.documents.split(','):
|
||||
taskqueue.add(
|
||||
'{}/background_attribute_task'.format(document_id),
|
||||
payload=pickle.dumps(data),
|
||||
)
|
||||
|
||||
self._finishedAdd = True
|
||||
return
|
||||
|
||||
def attribute_task(self, base_task, data):
|
||||
seen = {}
|
||||
nontask = find_nontask(base_task)
|
||||
portal_workflow = getToolByName(nontask, 'portal_workflow')
|
||||
transitions = portal_workflow.getTransitionsFor(nontask)
|
||||
transition_ids = [t['id'] for t in transitions]
|
||||
|
||||
for responsible in data['responsible']:
|
||||
if responsible in seen:
|
||||
continue
|
||||
_data = deepcopy(data)
|
||||
_data['responsible'] = [responsible]
|
||||
new_task = createContentInContainer(base_task, 'task', **_data)
|
||||
seen[responsible] = True
|
||||
|
||||
for responsible in data['responsible']:
|
||||
nontask.manage_addLocalRoles(responsible, ['Editor',])
|
||||
if 'attribute' in transition_ids:
|
||||
portal_workflow.doActionFor(nontask, 'attribute')
|
||||
nontask.reindexObjectSecurity()
|
||||
nontask.reindexObject(idxs=['allowedRolesAndUsers'])
|
||||
|
|
|
@ -1,35 +1,38 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import random
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from DateTime import DateTime
|
||||
from email import encoders
|
||||
from email.mime.base import MIMEBase
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email import encoders
|
||||
|
||||
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 zope.annotation.interfaces import IAnnotations
|
||||
|
||||
from Acquisition import aq_inner, aq_parent
|
||||
|
||||
from plone.z3cform.layout import FormWrapper
|
||||
from Acquisition import aq_parent
|
||||
from DateTime import DateTime
|
||||
from Products.Five.browser import BrowserView
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
|
||||
from collective.select2.field import Select2MultiField
|
||||
from pfwbged.policy import _
|
||||
from plone import api
|
||||
from plone.z3cform.layout import FormWrapper
|
||||
from z3c.form import button
|
||||
from z3c.form import form
|
||||
from z3c.form.field import Fields
|
||||
from zope import schema
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
from zope.interface import Interface
|
||||
|
||||
from .. import _
|
||||
|
||||
class IMail(Interface):
|
||||
recipients = schema.Text(title=_(u"Recipients"), required=True,
|
||||
description=_(u"Email addresses of the recipients, one per line"))
|
||||
recipients = Select2MultiField(
|
||||
title=_(u"Recipients"),
|
||||
description=_(u"Email addresses of the recipients"),
|
||||
search_view=lambda x: '{}/select2-ldap-emails-search'.format(x),
|
||||
placeholder=_(u"Select a value here"),
|
||||
required=True,
|
||||
value_type=schema.TextLine(
|
||||
title=_(u"Recipients"),
|
||||
),
|
||||
)
|
||||
|
||||
subject = schema.TextLine(title=_(u"Subject"), required=True)
|
||||
comment = schema.Text(
|
||||
title=_(u"Comment"),
|
||||
|
@ -58,7 +61,7 @@ class MailForm(form.AddForm):
|
|||
self._finishedAdd = True
|
||||
|
||||
subject = data['subject']
|
||||
recipients = data['recipients'].splitlines()
|
||||
recipients = data['recipients']
|
||||
comment = data.get('comment')
|
||||
|
||||
msg = MIMEMultipart()
|
||||
|
|
|
@ -5,3 +5,7 @@
|
|||
.template-view .overlay-ajax .empty.field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.select2-drop {
|
||||
z-index: 11000 !important; /* only necessary for Firefox; no explanation found. */
|
||||
}
|
||||
|
|
|
@ -7,7 +7,13 @@ $(document).ready(function(){
|
|||
noform: function(el) {return jQuery.plonepopups.noformerrorshow(el, 'reload');},
|
||||
config: {
|
||||
closeOnClick: false,
|
||||
closeOnEsc: false
|
||||
closeOnEsc: false,
|
||||
onLoad : function (e) {
|
||||
$('.pb-ajax .select2-multi-widget').select2Widget({
|
||||
multiple: true
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
$(document).find('.overlay-form-redirect').prepOverlay({
|
||||
|
|
|
@ -14,10 +14,6 @@
|
|||
|
||||
<div id="documents-table-view" tal:attributes="data-types view/document_types">
|
||||
|
||||
<div class="criteria-content" style="display:block;">
|
||||
Rechercher : <input name="text-criteria-fulltext">
|
||||
</div>
|
||||
|
||||
<div style="display: none;">
|
||||
<input id="sort_on" value="created"/>
|
||||
<input id="sort_order" type="checkbox" checked="checked"/>
|
||||
|
@ -45,8 +41,6 @@ $.querywidget.updateSearch = function (stay_on_page) {
|
|||
$.map($('#documents-table-view').data('types').split(';'), function(a) {
|
||||
query += "query.v:records:list=" + a + "&";
|
||||
});
|
||||
query += "query.i:records=SearchableText&query.o:records=plone.app.querystring.operation.string.contains&query.v:records=";
|
||||
query += $('input[name="text-criteria-fulltext"]').val();
|
||||
query += '&sort_on=' + $('#sort_on').val();
|
||||
if ($('#sort_order:checked').length > 0) {
|
||||
query += '&sort_order=reverse';
|
||||
|
@ -59,11 +53,6 @@ $.querywidget.updateSearch = function (stay_on_page) {
|
|||
|
||||
$(function() {
|
||||
$.querywidget.updateSearch();
|
||||
|
||||
$('input[name="text-criteria-fulltext"]').on('keyup', function() {
|
||||
$.querywidget.updateSearch();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
</metal:main>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<grok:grok package="." />
|
||||
|
||||
<include package=".browser" />
|
||||
<include package=".subscribers" />
|
||||
|
||||
<include package="collective.dms.basecontent" />
|
||||
<include package="collective.dms.batchimport" />
|
||||
|
@ -28,12 +29,14 @@
|
|||
<include package="collective.task" />
|
||||
<include package="collective.onlogin" />
|
||||
<include package="collective.solr" />
|
||||
<include package="collective.select2" />
|
||||
<include package="pfwbged.basecontent" />
|
||||
<include package="pfwbged.collection" />
|
||||
<include package="pfwbged.folder" />
|
||||
<include package="pfwbged.theme" />
|
||||
|
||||
<include package="plone.app.contenttypes" />
|
||||
<include package="collective.impersonate" />
|
||||
|
||||
|
||||
<!--
|
||||
|
@ -82,4 +85,19 @@
|
|||
replacement=".monkey.patchedNamedBlobFileInit"
|
||||
/>
|
||||
|
||||
|
||||
<include package="borg.localrole" />
|
||||
|
||||
<adapter
|
||||
for="collective.dms.mailcontent.dmsmail.IDmsIncomingMail"
|
||||
provides="borg.localrole.interfaces.ILocalRoleProvider"
|
||||
factory=".localrole.LocalRoleAdapter"
|
||||
/>
|
||||
|
||||
<adapter
|
||||
for="collective.dms.mailcontent.dmsmail.IDmsOutgoingMail"
|
||||
provides="borg.localrole.interfaces.ILocalRoleProvider"
|
||||
factory=".localrole.LocalRoleAdapter"
|
||||
/>
|
||||
|
||||
</configure>
|
||||
|
|
|
@ -54,7 +54,7 @@ msgstr "Actions"
|
|||
#: ../browser/add_multi_information.py:25
|
||||
#: ../browser/multi_attribute_task.py:41
|
||||
msgid "Add"
|
||||
msgstr ""
|
||||
msgstr "Ajouter"
|
||||
|
||||
#: ../menu.py:332
|
||||
msgid "Add ${title}"
|
||||
|
@ -152,9 +152,9 @@ msgstr "Adresse du document : %s"
|
|||
msgid "Document: %s"
|
||||
msgstr "Document : %s"
|
||||
|
||||
#: ../browser/send_by_email.py:32
|
||||
msgid "Email addresses of the recipients, one per line"
|
||||
msgstr "Adresses électroniques des destinataires, une par ligne"
|
||||
#: ../browser/send_by_email.py:35
|
||||
msgid "Email addresses of the recipients"
|
||||
msgstr "Adresses électroniques des destinataires"
|
||||
|
||||
#: ../browser/send_by_email.py:97
|
||||
msgid "Error sending email"
|
||||
|
@ -176,10 +176,18 @@ msgstr "Dossiers"
|
|||
msgid "Installs the pfwbged.policy add-on."
|
||||
msgstr ""
|
||||
|
||||
#: ../upgrades/registry.py:17
|
||||
msgid "Mail reader user group"
|
||||
msgstr "Groupe de lecture du courrier"
|
||||
|
||||
#: ../menu.py:205
|
||||
msgid "Mark document as read"
|
||||
msgstr "Marquer le document comme lu"
|
||||
|
||||
#: ../upgrades/registry.py:18
|
||||
msgid "Members of this group can read all incoming and outgoing mails on the platform."
|
||||
msgstr "Les membres de ce groupe ont un accès en lecture sur tous les courriers entrants et sortants"
|
||||
|
||||
#: ../customize.py:42
|
||||
msgid "My Tasks"
|
||||
msgstr "Mes tâches"
|
||||
|
@ -200,7 +208,11 @@ msgstr "Note :"
|
|||
msgid "One document is not mentioned for your information anymore"
|
||||
msgstr "Une note pour information vous concernant a été supprimée"
|
||||
|
||||
#: ../subscribers/document.py:549
|
||||
#: ../subscribers/document.py:429
|
||||
msgid "One of the tasks you requested has been marked as done"
|
||||
msgstr "Une tâche demandée par vous a été marquée comme faite"
|
||||
|
||||
#: ../subscribers/document.py:625
|
||||
msgid "One of your tasks has been cancelled"
|
||||
msgstr "Une de vos tâches a été annulée"
|
||||
|
||||
|
@ -253,7 +265,11 @@ msgstr "Enregistrer"
|
|||
msgid "Save As..."
|
||||
msgstr "Enregistrer sous…"
|
||||
|
||||
#: ../browser/send_by_email.py:52
|
||||
#: ../browser/send_by_email.py:29
|
||||
msgid "Select a value here"
|
||||
msgstr "Sélectionner une valeur ici"
|
||||
|
||||
#: ../browser/send_by_email.py:55
|
||||
msgid "Send"
|
||||
msgstr "Envoyer"
|
||||
|
||||
|
|
|
@ -16,12 +16,10 @@ msgstr ""
|
|||
"X-is-fallback-for: fr-fr fr-be fr-ca\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Answer"
|
||||
msgstr "Répondre"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Answered"
|
||||
msgstr "Répondu"
|
||||
|
@ -34,12 +32,10 @@ msgstr "Demander un avis"
|
|||
msgid "Ask validation"
|
||||
msgstr "Demander une validation"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Assigning"
|
||||
msgstr "À attribuer"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Back to assigning"
|
||||
msgstr "Retour à attribuer"
|
||||
|
@ -48,7 +44,10 @@ msgstr "Retour à attribuer"
|
|||
msgid "Back to draft"
|
||||
msgstr "Retour à la rédaction"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/private_public_workflow/definition.xml
|
||||
msgid "Back to private"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Back to registering"
|
||||
msgstr "Retour à indicater"
|
||||
|
@ -84,7 +83,6 @@ msgstr "Annuler le refus"
|
|||
msgid "Cancel validation"
|
||||
msgstr "Annuler la validation"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "Considered"
|
||||
|
@ -135,7 +133,6 @@ msgstr "Rendre obsolète"
|
|||
msgid "My Folder"
|
||||
msgstr "Mon dossier"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "No action"
|
||||
|
@ -145,6 +142,10 @@ msgstr "Sans suite"
|
|||
msgid "Obsolete"
|
||||
msgstr "Obsolète"
|
||||
|
||||
#: ../profiles/default/workflows/private_public_workflow/definition.xml
|
||||
msgid "Private"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "Process"
|
||||
msgstr "Traiter"
|
||||
|
@ -153,13 +154,17 @@ msgstr "Traiter"
|
|||
msgid "Processed"
|
||||
msgstr "Traité"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "Processing"
|
||||
msgstr "En cours de traitement"
|
||||
|
||||
#: ../profiles/default/workflows/private_public_workflow/definition.xml
|
||||
msgid "Publish"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/appendix_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/private_public_workflow/definition.xml
|
||||
msgid "Published"
|
||||
msgstr "Publiée"
|
||||
|
||||
|
@ -194,12 +199,10 @@ msgstr "Envoyer à la corbeille"
|
|||
msgid "Sent"
|
||||
msgstr "Envoyé"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "To assign"
|
||||
msgstr "À attribuer"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "To process"
|
||||
|
|
|
@ -154,8 +154,8 @@ msgstr ""
|
|||
msgid "Document: %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../browser/send_by_email.py:32
|
||||
msgid "Email addresses of the recipients, one per line"
|
||||
#: ../browser/send_by_email.py:35
|
||||
msgid "Email addresses of the recipients"
|
||||
msgstr ""
|
||||
|
||||
#: ../browser/send_by_email.py:97
|
||||
|
@ -178,10 +178,18 @@ msgstr ""
|
|||
msgid "Installs the pfwbged.policy add-on."
|
||||
msgstr ""
|
||||
|
||||
#: ../upgrades/registry.py:17
|
||||
msgid "Mail reader user group"
|
||||
msgstr ""
|
||||
|
||||
#: ../menu.py:205
|
||||
msgid "Mark document as read"
|
||||
msgstr ""
|
||||
|
||||
#: ../upgrades/registry.py:18
|
||||
msgid "Members of this group can read all incoming and outgoing mails on the platform."
|
||||
msgstr ""
|
||||
|
||||
#: ../customize.py:42
|
||||
msgid "My Tasks"
|
||||
msgstr ""
|
||||
|
@ -202,7 +210,11 @@ msgstr ""
|
|||
msgid "One document is not mentioned for your information anymore"
|
||||
msgstr ""
|
||||
|
||||
#: ../subscribers/document.py:549
|
||||
#: ../subscribers/document.py:429
|
||||
msgid "One of the tasks you requested has been marked as done"
|
||||
msgstr ""
|
||||
|
||||
#: ../subscribers/document.py:625
|
||||
msgid "One of your tasks has been cancelled"
|
||||
msgstr ""
|
||||
|
||||
|
@ -255,7 +267,11 @@ msgstr ""
|
|||
msgid "Save As..."
|
||||
msgstr ""
|
||||
|
||||
#: ../browser/send_by_email.py:52
|
||||
#: ../browser/send_by_email.py:29
|
||||
msgid "Select a value here"
|
||||
msgstr ""
|
||||
|
||||
#: ../browser/send_by_email.py:55
|
||||
msgid "Send"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -17,12 +17,10 @@ msgstr ""
|
|||
"Preferred-Encodings: utf-8 latin1\n"
|
||||
"Domain: plone\n"
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Answer"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Answered"
|
||||
msgstr ""
|
||||
|
@ -35,12 +33,10 @@ msgstr ""
|
|||
msgid "Ask validation"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Assigning"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Back to assigning"
|
||||
msgstr ""
|
||||
|
@ -49,7 +45,10 @@ msgstr ""
|
|||
msgid "Back to draft"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/private_public_workflow/definition.xml
|
||||
msgid "Back to private"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Back to registering"
|
||||
msgstr ""
|
||||
|
@ -74,7 +73,6 @@ msgstr ""
|
|||
msgid "Cancel validation"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "Considered"
|
||||
|
@ -125,7 +123,6 @@ msgstr ""
|
|||
msgid "My Folder"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "No action"
|
||||
|
@ -135,6 +132,10 @@ msgstr ""
|
|||
msgid "Obsolete"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/private_public_workflow/definition.xml
|
||||
msgid "Private"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "Process"
|
||||
msgstr ""
|
||||
|
@ -143,13 +144,17 @@ msgstr ""
|
|||
msgid "Processed"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "Processing"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/private_public_workflow/definition.xml
|
||||
msgid "Publish"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/appendix_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/private_public_workflow/definition.xml
|
||||
msgid "Published"
|
||||
msgstr ""
|
||||
|
||||
|
@ -161,7 +166,6 @@ msgstr ""
|
|||
msgid "Refuse"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "Registering"
|
||||
msgstr ""
|
||||
|
@ -184,12 +188,10 @@ msgstr ""
|
|||
msgid "Sent"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
msgid "To assign"
|
||||
msgstr ""
|
||||
|
||||
#: ../profiles/default/workflows/incomingapfmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/incomingmail_workflow/definition.xml
|
||||
#: ../profiles/default/workflows/pfwbgeddocument_workflow/definition.xml
|
||||
msgid "To process"
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from borg.localrole.interfaces import ILocalRoleProvider
|
||||
from plone import api
|
||||
from zope.interface import implements
|
||||
|
||||
|
||||
class LocalRoleAdapter(object):
|
||||
implements(ILocalRoleProvider)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
@property
|
||||
def accepted_group(self):
|
||||
try:
|
||||
return api.portal.get_registry_record('pfwbged.mail_reader_group')
|
||||
except api.exc.InvalidParameterError:
|
||||
return ''
|
||||
|
||||
def getRoles(self, principal):
|
||||
"""Grant permission for principal"""
|
||||
if principal == self.accepted_group:
|
||||
return ('Reader',)
|
||||
else:
|
||||
return ()
|
||||
|
||||
def getAllRoles(self):
|
||||
"""Grant permissions"""
|
||||
return [(self.accepted_group, ('Reader',))]
|
|
@ -446,11 +446,13 @@ class CustomMenu(menu.WorkflowMenu):
|
|||
action['title'] = _(u"Create signed version for version ${version}",
|
||||
mapping={'version': context.Title()})
|
||||
cssClass += " overlay-form-reload"
|
||||
elif action['id'] == 'create_outgoing_mail':
|
||||
elif action['id'] in (
|
||||
'create_outgoing_mail',
|
||||
'create_board_decision',
|
||||
'delete',
|
||||
):
|
||||
# make it overlay !
|
||||
cssClass += ' overlay-form-redirect'
|
||||
elif action['id'] == 'delete':
|
||||
cssClass += " overlay-form-redirect"
|
||||
|
||||
if action['allowed']:
|
||||
aid = action['id']
|
||||
|
@ -563,14 +565,6 @@ class CustomMenu(menu.WorkflowMenu):
|
|||
# wf actions on informations
|
||||
actions.extend(self.getWorkflowActionsForType(context, request, 'information'))
|
||||
|
||||
if context.portal_type in ('pfwb.boarddecision',):
|
||||
# ideally this condition would be part of the task action
|
||||
# condition_expr, but that would require to get down from there
|
||||
# back to the document; it's much easier to just hide it from
|
||||
# here.
|
||||
actions = [x for x in actions if \
|
||||
x.get('extra').get('id') != 'plone-contentmenu-actions-create_outgoing_mail']
|
||||
|
||||
if ICollection.providedBy(context):
|
||||
# edition of collections is done inline, remove edit action but add
|
||||
# save and save as
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<metadata>
|
||||
<version>5</version>
|
||||
<version>9</version>
|
||||
<dependencies>
|
||||
<dependency>profile-collective.dms.basecontent:default</dependency>
|
||||
<dependency>profile-collective.dms.batchimport:default</dependency>
|
||||
|
@ -18,5 +18,6 @@
|
|||
<dependency>profile-plone.app.contenttypes:default</dependency>
|
||||
<dependency>profile-plone.app.dexterity:default</dependency>
|
||||
<dependency>profile-Products.AROfficeTransforms:default</dependency>
|
||||
<dependency>profile-collective.impersonate:default</dependency>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
|
|
@ -99,4 +99,12 @@
|
|||
</field>
|
||||
<value>False</value>
|
||||
</record>
|
||||
<record name="pfwbged.mail_reader_group">
|
||||
<field type="plone.registry.field.ASCIILine">
|
||||
<title>Mail reader user group</title>
|
||||
<description>Members of this group can read all incoming and outgoing mails on the platform.</description>
|
||||
<required>False</required>
|
||||
</field>
|
||||
<value>lecture-courriers</value>
|
||||
</record>
|
||||
</registry>
|
|
@ -2,7 +2,6 @@
|
|||
<rolemap>
|
||||
<roles>
|
||||
<role name="Greffier"/>
|
||||
<role name="SecretariatGeneralAPF"/>
|
||||
</roles>
|
||||
<permissions>
|
||||
<permission name="Add portal content" acquire="True">
|
||||
|
@ -30,7 +29,6 @@
|
|||
<role name="Reviewer"/>
|
||||
<role name="Site Administrator"/>
|
||||
<role name="Greffier"/>
|
||||
<role name="SecretariatGeneralAPF"/>
|
||||
</permission>
|
||||
</permissions>
|
||||
</rolemap>
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
name="title">Contains workflow definitions for your portal</property>
|
||||
<object name="appendix_workflow" meta_type="Workflow"/>
|
||||
<object name="incomingmail_workflow" meta_type="Workflow"/>
|
||||
<object name="incomingapfmail_workflow" meta_type="Workflow"/>
|
||||
<object name="outgoingmail_workflow" meta_type="Workflow"/>
|
||||
<object name="pfwbgeddocument_workflow" meta_type="Workflow"/>
|
||||
<object name="pfwbgedfolder_workflow" meta_type="Workflow"/>
|
||||
<object name="pfwbgedmainfolder_workflow" meta_type="Workflow"/>
|
||||
<object name="private_public_workflow" meta_type="Workflow"/>
|
||||
<object name="versionnote_workflow" meta_type="Workflow"/>
|
||||
<bindings>
|
||||
<default>
|
||||
|
@ -18,7 +18,7 @@
|
|||
<bound-workflow workflow_id=""/>
|
||||
</type>
|
||||
<type type_id="pfwbgedcollection">
|
||||
<bound-workflow workflow_id="one_state_workflow"/>
|
||||
<bound-workflow workflow_id="private_public_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwbgedlink">
|
||||
<bound-workflow workflow_id=""/>
|
||||
|
@ -53,17 +53,26 @@
|
|||
<type type_id="pfwb.boarddecision">
|
||||
<bound-workflow workflow_id="incomingmail_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwb.apfincomingmail">
|
||||
<bound-workflow workflow_id="incomingapfmail_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwb.apfoutgoingmail">
|
||||
<bound-workflow workflow_id="outgoingmail_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwb.medicalcertificate">
|
||||
<bound-workflow workflow_id="incomingmail_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwb.invoice">
|
||||
<bound-workflow workflow_id="incomingmail_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwb.memorandum">
|
||||
<bound-workflow workflow_id="outgoingmail_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwb.notice">
|
||||
<bound-workflow workflow_id="outgoingmail_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwb.informationnote">
|
||||
<bound-workflow workflow_id="outgoingmail_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwb.copnote">
|
||||
<bound-workflow workflow_id="outgoingmail_workflow"/>
|
||||
</type>
|
||||
<type type_id="pfwb.copminutes">
|
||||
<bound-workflow workflow_id="outgoingmail_workflow"/>
|
||||
</type>
|
||||
</bindings>
|
||||
</object>
|
||||
|
|
|
@ -1,290 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<dc-workflow workflow_id="incomingmail_workflow"
|
||||
title="Workflow for Incoming Mail"
|
||||
description=""
|
||||
state_variable="review_state"
|
||||
initial_state="registering"
|
||||
manager_bypass="True"
|
||||
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
|
||||
i18n:domain="plone">
|
||||
<permission>Access contents information</permission>
|
||||
<permission>Delete objects</permission>
|
||||
<permission>Modify portal content</permission>
|
||||
<permission>View</permission>
|
||||
<state state_id="answered" title="Answered" i18n:attributes="title">
|
||||
<permission-map name="Access contents information" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Delete objects" acquired="False">
|
||||
</permission-map>
|
||||
<permission-map name="Modify portal content" acquired="False">
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="View" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
</state>
|
||||
<state state_id="assigning" title="Assigning" i18n:attributes="title">
|
||||
<exit-transition transition_id="back_to_registering"/>
|
||||
<exit-transition transition_id="directly_noaction"/>
|
||||
<exit-transition transition_id="to_process"/>
|
||||
<permission-map name="Access contents information" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>SecretariatGeneralApf</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Delete objects" acquired="False">
|
||||
</permission-map>
|
||||
<permission-map name="Modify portal content" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>SecretariatGeneralApf</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="View" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>SecretariatGeneralApf</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
</state>
|
||||
<state state_id="noaction" title="No action" i18n:attributes="title">
|
||||
<exit-transition transition_id="back_to_assigning"/>
|
||||
<permission-map name="Access contents information" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Delete objects" acquired="False">
|
||||
</permission-map>
|
||||
<permission-map name="Modify portal content" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="View" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
</state>
|
||||
<state state_id="considered" title="Considered" i18n:attributes="title">
|
||||
<exit-transition transition_id="back_to_assigning"/>
|
||||
<permission-map name="Access contents information" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Delete objects" acquired="False">
|
||||
</permission-map>
|
||||
<permission-map name="Modify portal content" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="View" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
</state>
|
||||
<state state_id="processing" title="Processing" i18n:attributes="title">
|
||||
<exit-transition transition_id="answer"/>
|
||||
<exit-transition transition_id="to_noaction"/>
|
||||
<exit-transition transition_id="to_considered"/>
|
||||
<permission-map name="Access contents information" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Delete objects" acquired="False">
|
||||
</permission-map>
|
||||
<permission-map name="Modify portal content" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="View" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
</state>
|
||||
<state state_id="registering" title="Registering" i18n:attributes="title">
|
||||
<exit-transition transition_id="to_assign"/>
|
||||
<permission-map name="Access contents information" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>SecretariatGeneralApf</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Delete objects" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Modify portal content" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="View" acquired="False">
|
||||
<permission-role>Editor</permission-role>
|
||||
<permission-role>SecretariatGeneralApf</permission-role>
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
<permission-role>Reader</permission-role>
|
||||
<permission-role>Reviewer</permission-role>
|
||||
<permission-role>Site Administrator</permission-role>
|
||||
</permission-map>
|
||||
</state>
|
||||
<transition transition_id="answer" title="" new_state="answered" trigger="USER" before_script="" after_script="">
|
||||
<action url="%(content_url)s/content_status_modify?workflow_action=answer" category="workflow" icon="" i18n:translate="">Answer</action>
|
||||
<guard>
|
||||
<guard-role>Editor</guard-role>
|
||||
<guard-role>Manager</guard-role>
|
||||
<guard-expression>here/@@can_answer</guard-expression>
|
||||
</guard>
|
||||
</transition>
|
||||
<transition transition_id="back_to_assigning" title="" new_state="assigning" trigger="USER" before_script="" after_script="">
|
||||
<action url="%(content_url)s/content_status_modify?workflow_action=back_to_assigning" category="workflow" icon="" i18n:translate="">Back to assigning</action>
|
||||
<guard>
|
||||
<guard-role>Reviewer</guard-role>
|
||||
<guard-role>Manager</guard-role>
|
||||
</guard>
|
||||
</transition>
|
||||
<transition transition_id="back_to_registering" title="" new_state="registering" trigger="USER" before_script="" after_script="">
|
||||
<action url="%(content_url)s/content_status_modify?workflow_action=back_to_registering" category="workflow" icon="" i18n:translate="">Back to registering</action>
|
||||
<guard>
|
||||
<guard-expression>here/@@can_return_to_registering_or_process</guard-expression>
|
||||
</guard>
|
||||
</transition>
|
||||
<transition transition_id="directly_noaction" title="" new_state="noaction" trigger="USER" before_script="" after_script="">
|
||||
<action url="%(content_url)s/content_status_modify?workflow_action=directly_noaction" category="workflow" icon="" i18n:translate="">No action</action>
|
||||
<guard>
|
||||
<guard-role>Reviewer</guard-role>
|
||||
<guard-role>Manager</guard-role>
|
||||
</guard>
|
||||
</transition>
|
||||
<transition transition_id="to_assign" title="" new_state="assigning" trigger="USER" before_script="" after_script="">
|
||||
<action url="%(content_url)s/content_status_modify?workflow_action=to_assign" category="workflow" icon="" i18n:translate="">To assign</action>
|
||||
<guard>
|
||||
<guard-role>Editor</guard-role>
|
||||
<guard-role>Manager</guard-role>
|
||||
<guard-role>Owner</guard-role>
|
||||
<guard-role>Reviewer</guard-role>
|
||||
</guard>
|
||||
</transition>
|
||||
<transition transition_id="to_noaction" title="" new_state="noaction" trigger="USER" before_script="" after_script="">
|
||||
<action url="%(content_url)s/content_status_modify?workflow_action=to_noaction" category="workflow" icon="" i18n:translate="">No action</action>
|
||||
<guard>
|
||||
<guard-role>Editor</guard-role>
|
||||
<guard-role>Manager</guard-role>
|
||||
</guard>
|
||||
</transition>
|
||||
<transition transition_id="to_considered" title="" new_state="considered" trigger="USER" before_script="" after_script="">
|
||||
<action url="%(content_url)s/content_status_modify?workflow_action=to_considered" category="workflow" icon="" i18n:translate="">Considered</action>
|
||||
<guard>
|
||||
<guard-role>Editor</guard-role>
|
||||
<guard-role>Manager</guard-role>
|
||||
</guard>
|
||||
</transition>
|
||||
<transition transition_id="to_process" title="" new_state="processing" trigger="USER" before_script="" after_script="">
|
||||
<action url="%(content_url)s/@@to_process?workflow_action=to_process" category="workflow" icon="" i18n:translate="">To process</action>
|
||||
<guard>
|
||||
<guard-role>SecretariatGeneralApf</guard-role>
|
||||
<guard-role>Manager</guard-role>
|
||||
<guard-role>Reviewer</guard-role>
|
||||
</guard>
|
||||
</transition>
|
||||
<variable variable_id="action" for_catalog="False" for_status="True" update_always="True">
|
||||
<description>Previous transition</description>
|
||||
<default>
|
||||
<expression>transition/getId|nothing</expression>
|
||||
</default>
|
||||
<guard>
|
||||
</guard>
|
||||
</variable>
|
||||
<variable variable_id="actor" for_catalog="False" for_status="True" update_always="True">
|
||||
<description>The ID of the user who performed the previous transition</description>
|
||||
<default>
|
||||
<expression>user/getId</expression>
|
||||
</default>
|
||||
<guard>
|
||||
</guard>
|
||||
</variable>
|
||||
<variable variable_id="comments" for_catalog="False" for_status="True" update_always="True">
|
||||
<description>Comment about the last transition</description>
|
||||
<default>
|
||||
<expression>python:state_change.kwargs.get('comment', '')</expression>
|
||||
</default>
|
||||
<guard>
|
||||
</guard>
|
||||
</variable>
|
||||
<variable variable_id="review_history" for_catalog="False" for_status="False" update_always="False">
|
||||
<description>Provides access to workflow history</description>
|
||||
<default>
|
||||
<expression>state_change/getHistory</expression>
|
||||
</default>
|
||||
<guard>
|
||||
<guard-permission>Request review</guard-permission>
|
||||
<guard-permission>Review portal content</guard-permission>
|
||||
</guard>
|
||||
</variable>
|
||||
<variable variable_id="time" for_catalog="False" for_status="True" update_always="True">
|
||||
<description>When the previous transition was performed</description>
|
||||
<default>
|
||||
<expression>state_change/getDateTime</expression>
|
||||
</default>
|
||||
<guard>
|
||||
</guard>
|
||||
</variable>
|
||||
</dc-workflow>
|
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0"?>
|
||||
<dc-workflow workflow_id="private_public_workflow"
|
||||
title="Private Public Workflow"
|
||||
description="Accessible by owner and managers when private, by everyone when published"
|
||||
state_variable="review_state"
|
||||
initial_state="private"
|
||||
manager_bypass="True"
|
||||
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
|
||||
i18n:domain="plone">
|
||||
<permission>Access contents information</permission>
|
||||
<permission>Delete objects</permission>
|
||||
<permission>Modify portal content</permission>
|
||||
<permission>View</permission>
|
||||
<state state_id="private" title="Private" i18n:attributes="title">
|
||||
<exit-transition transition_id="publish"/>
|
||||
<permission-map name="View" acquired="False">
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Access contents information" acquired="False">
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Modify portal content" acquired="False">
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Delete objects" acquired="False">
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
</permission-map>
|
||||
</state>
|
||||
<state state_id="published" title="Published" i18n:attributes="title">
|
||||
<exit-transition transition_id="back_to_private"/>
|
||||
<permission-map name="View" acquired="False">
|
||||
<permission-role>Anonymous</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Access contents information" acquired="False">
|
||||
<permission-role>Anonymous</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Modify portal content" acquired="False">
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
</permission-map>
|
||||
<permission-map name="Delete objects" acquired="False">
|
||||
<permission-role>Manager</permission-role>
|
||||
<permission-role>Owner</permission-role>
|
||||
</permission-map>
|
||||
</state>
|
||||
<transition transition_id="back_to_private" title="Back to private" new_state="private" trigger="USER" before_script="" after_script="" i18n:attributes="title">
|
||||
<action url="" category="workflow" icon="" i18n:translate="">Back to private</action>
|
||||
<guard>
|
||||
<guard-role>Manager</guard-role>
|
||||
<guard-role>Owner</guard-role>
|
||||
</guard>
|
||||
</transition>
|
||||
<transition transition_id="publish" title="Publish" new_state="published" trigger="USER" before_script="" after_script="" i18n:attributes="title">
|
||||
<action url="" category="workflow" icon="" i18n:translate="">Publish</action>
|
||||
<guard>
|
||||
<guard-role>Manager</guard-role>
|
||||
<guard-role>Owner</guard-role>
|
||||
</guard>
|
||||
</transition>
|
||||
<variable variable_id="action" for_catalog="False" for_status="True" update_always="True">
|
||||
<description>Previous transition</description>
|
||||
<default>
|
||||
<expression>transition/getId|nothing</expression>
|
||||
</default>
|
||||
<guard>
|
||||
</guard>
|
||||
</variable>
|
||||
<variable variable_id="actor" for_catalog="False" for_status="True" update_always="True">
|
||||
<description>The ID of the user who performed the last transition</description>
|
||||
<default>
|
||||
<expression>user/getId</expression>
|
||||
</default>
|
||||
<guard>
|
||||
</guard>
|
||||
</variable>
|
||||
<variable variable_id="comments" for_catalog="False" for_status="True" update_always="True">
|
||||
<description>Comment about the last transition</description>
|
||||
<default>
|
||||
<expression>python:state_change.kwargs.get('comment', '')</expression>
|
||||
</default>
|
||||
<guard>
|
||||
</guard>
|
||||
</variable>
|
||||
<variable variable_id="review_history" for_catalog="False" for_status="False" update_always="False">
|
||||
<description>Provides access to workflow history</description>
|
||||
<default>
|
||||
<expression>state_change/getHistory</expression>
|
||||
</default>
|
||||
<guard>
|
||||
<guard-permission>Request review</guard-permission>
|
||||
<guard-permission>Review portal content</guard-permission>
|
||||
</guard>
|
||||
</variable>
|
||||
<variable variable_id="time" for_catalog="False" for_status="True" update_always="True">
|
||||
<description>When the previous transition was performed</description>
|
||||
<default>
|
||||
<expression>state_change/getDateTime</expression>
|
||||
</default>
|
||||
<guard>
|
||||
</guard>
|
||||
</variable>
|
||||
</dc-workflow>
|
|
@ -94,6 +94,8 @@ def create_tasks_collections(context):
|
|||
item_count=item_count,
|
||||
query=query,
|
||||
)
|
||||
api.content.transition(collection, 'publish')
|
||||
|
||||
role = u'responsible'
|
||||
id = '%s-%s' % (type, role)
|
||||
if id not in container:
|
||||
|
@ -108,6 +110,8 @@ def create_tasks_collections(context):
|
|||
item_count=item_count,
|
||||
query=query,
|
||||
)
|
||||
api.content.transition(collection, 'publish')
|
||||
|
||||
# opinions
|
||||
type = u'opinion'
|
||||
role = u'enquirer'
|
||||
|
@ -124,6 +128,8 @@ def create_tasks_collections(context):
|
|||
item_count=item_count,
|
||||
query=query,
|
||||
)
|
||||
api.content.transition(collection, 'publish')
|
||||
|
||||
role = u'responsible'
|
||||
id = '%s-%s' % (type, role)
|
||||
if id not in container:
|
||||
|
@ -138,6 +144,8 @@ def create_tasks_collections(context):
|
|||
item_count=item_count,
|
||||
query=query,
|
||||
)
|
||||
api.content.transition(collection, 'publish')
|
||||
|
||||
# validations
|
||||
type = u'validation'
|
||||
role = u'enquirer'
|
||||
|
@ -154,6 +162,8 @@ def create_tasks_collections(context):
|
|||
item_count=item_count,
|
||||
query=query,
|
||||
)
|
||||
api.content.transition(collection, 'publish')
|
||||
|
||||
role = u'responsible'
|
||||
id = '%s-%s' % (type, role)
|
||||
if id not in container:
|
||||
|
@ -168,6 +178,8 @@ def create_tasks_collections(context):
|
|||
item_count=item_count,
|
||||
query=query,
|
||||
)
|
||||
api.content.transition(collection, 'publish')
|
||||
|
||||
# informations
|
||||
sort_on = u'created'
|
||||
type = u'information'
|
||||
|
@ -185,6 +197,8 @@ def create_tasks_collections(context):
|
|||
item_count=item_count,
|
||||
query=query,
|
||||
)
|
||||
api.content.transition(collection, 'publish')
|
||||
|
||||
role = u'responsible'
|
||||
id = '%s-%s' % (type, role)
|
||||
if id not in container:
|
||||
|
@ -199,6 +213,8 @@ def create_tasks_collections(context):
|
|||
item_count=item_count,
|
||||
query=query,
|
||||
)
|
||||
api.content.transition(collection, 'publish')
|
||||
|
||||
|
||||
|
||||
def setup_folder_portlets(folder):
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<configure
|
||||
xmlns="http://namespaces.zope.org/zope"
|
||||
xmlns:i18n="http://namespaces.zope.org/i18n"
|
||||
xmlns:browser="http://namespaces.zope.org/browser"
|
||||
xmlns:plone="http://namespaces.plone.org/plone"
|
||||
i18n_domain="pfwbged.policy">
|
||||
|
||||
<browser:page
|
||||
name="background_delete_tasks"
|
||||
class=".document.BackgroundDeleteTasksView"
|
||||
permission="zope2.View"
|
||||
for="*"
|
||||
layer="collective.taskqueue.interfaces.ITaskQueueLayer"
|
||||
/>
|
||||
|
||||
</configure>
|
|
@ -1,7 +1,12 @@
|
|||
import logging
|
||||
import os
|
||||
import datetime
|
||||
import pickle
|
||||
|
||||
from Acquisition import aq_chain, aq_parent
|
||||
from Products.Five import BrowserView
|
||||
from collective.taskqueue import taskqueue
|
||||
from collective.task.indexers import get_document
|
||||
from five import grok
|
||||
from DateTime import DateTime
|
||||
|
||||
|
@ -45,6 +50,24 @@ except ImportError:
|
|||
IAsyncService = None
|
||||
|
||||
|
||||
def build_absolute_url(obj):
|
||||
"""
|
||||
Used within taskqueue requests,
|
||||
because they don't have a good SERVER_URL,
|
||||
and thus absolute_url calls are wrong.
|
||||
"""
|
||||
|
||||
root_url = os.getenv("ROOT_URL", None)
|
||||
if root_url:
|
||||
portal_path = api.portal.get().getPhysicalPath()
|
||||
obj_path = obj.getPhysicalPath()
|
||||
relative_path = obj_path[len(portal_path):]
|
||||
absolute_path = (root_url,) + relative_path
|
||||
return "/".join(absolute_path)
|
||||
else:
|
||||
return obj.absolute_url() # no choice left
|
||||
|
||||
|
||||
def has_pfwbgeddocument_workflow(obj):
|
||||
wtool = api.portal.get_tool('portal_workflow')
|
||||
return 'pfwbgeddocument_workflow' in wtool.getChainFor(obj)
|
||||
|
@ -55,8 +78,6 @@ def has_incomingmail_workflow(obj):
|
|||
chain = wtool.getChainFor(obj)
|
||||
if 'incomingmail_workflow' in chain:
|
||||
return True
|
||||
if 'incomingapfmail_workflow' in chain:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
@ -130,11 +151,28 @@ def delete_tasks(context, event):
|
|||
query = {'to_id': version_intid,
|
||||
'from_interfaces_flattened': IBaseTask,
|
||||
'from_attribute': 'target'}
|
||||
for rv in catalog.findRelations(query):
|
||||
obj = rv.from_object
|
||||
#obj.aq_parent.manage_delObjects([obj.getId()]) # we don't want to verify Delete object permission on object
|
||||
del aq_parent(obj)[obj.getId()]
|
||||
reindex_after_version_changes(aq_parent(context))
|
||||
task_paths = [rv.from_path for rv in catalog.findRelations(query)]
|
||||
taskqueue.add(
|
||||
'{}/background_delete_tasks'.format(api.portal.get().absolute_url_path()),
|
||||
payload=pickle.dumps(task_paths),
|
||||
)
|
||||
|
||||
|
||||
class BackgroundDeleteTasksView(BrowserView):
|
||||
|
||||
def __call__(self):
|
||||
portal = api.portal.get()
|
||||
document = None
|
||||
for task_path in pickle.load(self.request.stdin):
|
||||
try:
|
||||
task = portal.unrestrictedTraverse(task_path)
|
||||
except KeyError:
|
||||
continue
|
||||
if task:
|
||||
document = get_document(task)
|
||||
del document[task.getId()]
|
||||
if document:
|
||||
reindex_after_version_changes(document)
|
||||
|
||||
|
||||
@grok.subscribe(IDmsFile, IObjectAddedEvent)
|
||||
|
@ -230,11 +268,15 @@ def version_note_finished(context, event):
|
|||
portal_catalog = api.portal.get_tool('portal_catalog')
|
||||
document = context.getParentNode()
|
||||
state = api.content.get_state(obj=document)
|
||||
# if parent is an outgoing mail, change its state to ready_to_send
|
||||
if document.portal_type in ('dmsoutgoingmail', 'pfwb.apfoutgoingmail') and state == 'writing':
|
||||
|
||||
# if parent is an outgoing mail, memorandum or notice,
|
||||
# change its state to ready_to_send
|
||||
types_to_finish = ['dmsoutgoingmail', 'pfwb.memorandum', 'pfwb.notice']
|
||||
if document.portal_type in types_to_finish and state == 'writing':
|
||||
with api.env.adopt_user('admin'):
|
||||
api.content.transition(obj=document, transition='finish')
|
||||
document.reindexObject(idxs=['review_state'])
|
||||
|
||||
elif IPfwbDocument.providedBy(document) and has_pfwbgeddocument_workflow(document):
|
||||
if state == 'processing':
|
||||
with api.env.adopt_user('admin'):
|
||||
|
@ -382,6 +424,53 @@ def email_notification_of_tasks_sync(context, event, document, absolute_url, tar
|
|||
log.exception(e)
|
||||
|
||||
|
||||
@grok.subscribe(ITask, IAfterTransitionEvent)
|
||||
def email_notification_of_done_tasks(context, event):
|
||||
if event.transition and event.transition.id == 'mark-as-done':
|
||||
document = None
|
||||
for obj in aq_chain(context):
|
||||
obj = aq_parent(obj)
|
||||
if IDmsDocument.providedBy(obj):
|
||||
document = obj
|
||||
break
|
||||
if not document:
|
||||
return
|
||||
absolute_url = build_absolute_url(document)
|
||||
|
||||
recipient_emails = []
|
||||
for recipient in _recursiveGetMembersFromIds(api.portal.get(), (context.enquirer or [])):
|
||||
email = recipient.getProperty('email', None)
|
||||
if email:
|
||||
recipient_emails.append(email)
|
||||
|
||||
if not recipient_emails:
|
||||
return
|
||||
|
||||
email_from = api.user.get_current().email or api.portal.get().getProperty(
|
||||
'email_from_address') or 'admin@localhost'
|
||||
|
||||
subject = '%s - %s' % (context.title, document.title)
|
||||
|
||||
body = translate(_('One of the tasks you requested has been marked as done'), context=context.REQUEST) + \
|
||||
'\n\n' + \
|
||||
translate(_('Title: %s'), context=context.REQUEST) % context.title + \
|
||||
'\n\n' + \
|
||||
translate(_('Document: %s'), context=context.REQUEST) % document.title + \
|
||||
'\n\n' + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % absolute_url + \
|
||||
'\n\n\n\n-- \n' + \
|
||||
translate(_('Sent by GED'))
|
||||
body = body.encode('utf-8')
|
||||
|
||||
for recipient_email in recipient_emails:
|
||||
try:
|
||||
context.MailHost.send(body, recipient_email, email_from, subject, charset='utf-8')
|
||||
except Exception as e:
|
||||
# do not abort transaction in case of email error
|
||||
log = logging.getLogger('pfwbged.policy')
|
||||
log.exception(e)
|
||||
|
||||
|
||||
@grok.subscribe(IBaseTask, IObjectAddedEvent)
|
||||
def email_notification_of_tasks(context, event):
|
||||
# go up in the acquisition chain to find the document, this cannot be done
|
||||
|
@ -395,7 +484,7 @@ def email_notification_of_tasks(context, event):
|
|||
break
|
||||
if not document:
|
||||
return
|
||||
absolute_url = document.absolute_url()
|
||||
absolute_url = build_absolute_url(document)
|
||||
|
||||
# request is also required to get the target language
|
||||
target_language = negotiate(context.REQUEST)
|
||||
|
@ -438,6 +527,7 @@ def email_notification_of_validation_reversal(context, event):
|
|||
break
|
||||
if not document:
|
||||
return
|
||||
absolute_url = build_absolute_url(document)
|
||||
|
||||
email_enquirer = None
|
||||
for enquirer in (context.enquirer or []):
|
||||
|
@ -460,7 +550,7 @@ def email_notification_of_validation_reversal(context, event):
|
|||
'\n\n' + \
|
||||
translate(_('Document: %s'), context=context.REQUEST) % document.title + \
|
||||
'\n\n' + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % document.absolute_url()
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % absolute_url
|
||||
|
||||
body += '\n\n\n-- \n' + translate(_('Sent by GED'))
|
||||
body = body.encode('utf-8')
|
||||
|
@ -487,6 +577,7 @@ def email_notification_of_refused_task(context, event):
|
|||
break
|
||||
if not document:
|
||||
return
|
||||
absolute_url = build_absolute_url(document)
|
||||
|
||||
email_enquirer = None
|
||||
for enquirer in (context.enquirer or []):
|
||||
|
@ -509,7 +600,7 @@ def email_notification_of_refused_task(context, event):
|
|||
'\n\n' + \
|
||||
translate(_('Document: %s'), context=context.REQUEST) % document.title + \
|
||||
'\n\n' + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % document.absolute_url() + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % absolute_url + \
|
||||
'\n\n'
|
||||
|
||||
conversation = IConversation(context)
|
||||
|
@ -540,7 +631,7 @@ def email_notification_of_canceled_subtask(context, event):
|
|||
break
|
||||
if not document:
|
||||
return
|
||||
absolute_url = document.absolute_url()
|
||||
absolute_url = build_absolute_url(document)
|
||||
|
||||
recipient_emails = []
|
||||
for recipient in _recursiveGetMembersFromIds(api.portal.get(), (context.responsible or [])):
|
||||
|
@ -562,7 +653,7 @@ def email_notification_of_canceled_subtask(context, event):
|
|||
'\n\n' + \
|
||||
translate(_('Document: %s'), context=context.REQUEST) % document.title + \
|
||||
'\n\n' + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % document.absolute_url() + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % absolute_url + \
|
||||
'\n\n\n\n-- \n' + \
|
||||
translate(_('Sent by GED'))
|
||||
body = body.encode('utf-8')
|
||||
|
@ -586,7 +677,7 @@ def email_notification_of_canceled_information(context, event):
|
|||
break
|
||||
if not document:
|
||||
return
|
||||
absolute_url = document.absolute_url()
|
||||
absolute_url = build_absolute_url(document)
|
||||
|
||||
responsible = context.responsible[0]
|
||||
principal = api.user.get(responsible)
|
||||
|
@ -604,7 +695,7 @@ def email_notification_of_canceled_information(context, event):
|
|||
'\n\n' + \
|
||||
translate(_('Document: %s'), context=context.REQUEST) % document.title + \
|
||||
'\n\n' + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % document.absolute_url() + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % absolute_url + \
|
||||
'\n\n\n\n-- \n' + \
|
||||
translate(_('Sent by GED'))
|
||||
body = body.encode('utf-8')
|
||||
|
@ -627,7 +718,7 @@ def email_notification_of_canceled_validation(context, event):
|
|||
break
|
||||
if not document:
|
||||
return
|
||||
absolute_url = document.absolute_url()
|
||||
absolute_url = build_absolute_url(document)
|
||||
|
||||
recipient_emails = []
|
||||
for recipient in _recursiveGetMembersFromIds(api.portal.get(), (context.responsible or [])):
|
||||
|
@ -655,7 +746,7 @@ def email_notification_of_canceled_validation(context, event):
|
|||
'\n\n' + \
|
||||
translate(_('Document: %s'), context=context.REQUEST) % document.title + \
|
||||
'\n\n' + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % document.absolute_url() + \
|
||||
translate(_('Document Address: %s'), context=context.REQUEST) % absolute_url + \
|
||||
'\n\n\n\n-- \n' + \
|
||||
translate(_('Sent by GED'))
|
||||
body = body.encode('utf-8')
|
||||
|
|
|
@ -54,4 +54,48 @@
|
|||
|
||||
</genericsetup:upgradeSteps>
|
||||
|
||||
<genericsetup:upgradeStep
|
||||
title="Refresh addable types in Documents folder"
|
||||
description=""
|
||||
source="5"
|
||||
destination="6"
|
||||
profile="pfwbged.policy:default"
|
||||
handler=".types.refresh_documents_addable_types"
|
||||
/>
|
||||
|
||||
<genericsetup:upgradeStep
|
||||
title="Remove APF content types"
|
||||
description=""
|
||||
source="6"
|
||||
destination="7"
|
||||
profile="pfwbged.policy:default"
|
||||
handler=".types.remove_apf_content_types"
|
||||
/>
|
||||
|
||||
<genericsetup:upgradeStep
|
||||
title="Setup mail reader group"
|
||||
description=""
|
||||
source="7"
|
||||
destination="8"
|
||||
profile="pfwbged.policy:default"
|
||||
handler=".registry.setup_mail_reader_group"
|
||||
/>
|
||||
|
||||
<genericsetup:upgradeSteps
|
||||
source="8"
|
||||
destination="9"
|
||||
profile="pfwbged.policy:default">
|
||||
|
||||
<genericsetup:upgradeStep
|
||||
title="Update saved search workflow"
|
||||
description=""
|
||||
handler=".workflow.update_saved_search_workflow"
|
||||
/>
|
||||
|
||||
<genericsetup:upgradeDepends
|
||||
title="Reimport workflows"
|
||||
import_steps="workflow" />
|
||||
|
||||
</genericsetup:upgradeSteps>
|
||||
|
||||
</configure>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
from pfwbged.policy import _
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from plone.registry import field
|
||||
from plone.registry import Record
|
||||
from plone import api
|
||||
from zope.component import getUtility
|
||||
|
||||
|
||||
def setup_mail_reader_group(context):
|
||||
record_id = u'pfwbged.mail_reader_group'
|
||||
group_id = "lecture-courriers"
|
||||
group_name = u"Lecture courriers"
|
||||
|
||||
registry = getUtility(IRegistry)
|
||||
if record_id not in registry.records:
|
||||
group = field.ASCIILine(
|
||||
title=_(u"Mail reader user group"),
|
||||
description=_(u"Members of this group can read all incoming and outgoing mails on the platform."),
|
||||
required=True,
|
||||
default=group_id,
|
||||
)
|
||||
registry.records[record_id] = Record(group)
|
||||
|
||||
if not api.group.get(group_id):
|
||||
api.group.create(group_id, group_name)
|
|
@ -0,0 +1,40 @@
|
|||
from Products.CMFCore.utils import getToolByName
|
||||
from pfwbged.policy.setuphandlers import setup_constrains
|
||||
from plone import api
|
||||
|
||||
|
||||
def setup_constrains_on_documents_folder():
|
||||
portal = api.portal.get()
|
||||
types_tool = getToolByName(portal, 'portal_types')
|
||||
fti = types_tool.getTypeInfo('pfwbgedfolder')
|
||||
setup_constrains(
|
||||
portal['documents'],
|
||||
[
|
||||
x for x in fti.allowed_content_types
|
||||
if x not in ('pfwbgedfolder', 'pfwbgedlink',)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def refresh_documents_addable_types(context):
|
||||
context.runImportStepFromProfile('profile-pfwbged.basecontent:default',
|
||||
'typeinfo')
|
||||
context.runImportStepFromProfile('profile-pfwbged.folder:default',
|
||||
'typeinfo')
|
||||
context.runImportStepFromProfile('profile-pfwbged.policy:default',
|
||||
'workflow')
|
||||
|
||||
setup_constrains_on_documents_folder()
|
||||
|
||||
|
||||
def remove_apf_content_types(context):
|
||||
context.runImportStepFromProfile('profile-pfwbged.basecontent:default',
|
||||
'typeinfo')
|
||||
context.runImportStepFromProfile('profile-pfwbged.folder:default',
|
||||
'typeinfo')
|
||||
context.runImportStepFromProfile('profile-pfwbged.policy:default',
|
||||
'workflow')
|
||||
context.runImportStepFromProfile('profile-pfwbged.policy:default',
|
||||
'rolemap')
|
||||
|
||||
setup_constrains_on_documents_folder()
|
|
@ -76,25 +76,44 @@ def update_refused_version_state(context):
|
|||
version.reindexObject(idxs=['allowedRolesAndUsers', 'review_state'])
|
||||
|
||||
|
||||
def refresh_workflow_permissions(context, workflow_id):
|
||||
def refresh_workflow_permissions(context, workflow_id, folder_path=None):
|
||||
if not folder_path:
|
||||
folder_path = '/'.join(api.portal.get().getPhysicalPath())
|
||||
portal_workflow = api.portal.get_tool('portal_workflow')
|
||||
portal_catalog = api.portal.get_tool('portal_catalog')
|
||||
workflow = portal_workflow.getWorkflowById(workflow_id)
|
||||
portal = api.portal.get()
|
||||
folder_path = '/'.join(portal['documents'].getPhysicalPath())
|
||||
|
||||
for dx_type, wf_ids in portal_workflow._chains_by_type.items():
|
||||
if workflow_id in wf_ids:
|
||||
query = {'path': {
|
||||
'query': folder_path},
|
||||
'portal_type': dx_type}
|
||||
query = {
|
||||
'path': {'query': folder_path},
|
||||
'portal_type': dx_type,
|
||||
}
|
||||
results = portal_catalog.unrestrictedSearchResults(query)
|
||||
for brain in results:
|
||||
obj = brain.getObject()
|
||||
workflow.updateRoleMappingsFor(obj)
|
||||
obj.reindexObjectSecurity()
|
||||
obj.reindexObject(idxs=['allowedRolesAndUsers'])
|
||||
obj.reindexObject(idxs=['allowedRolesAndUsers', 'review_state'])
|
||||
|
||||
|
||||
def incomingmail_deletion_permissions(context):
|
||||
refresh_workflow_permissions(context, "incomingmail_workflow")
|
||||
folder_path = '/'.join(api.portal.get()['documents'].getPhysicalPath())
|
||||
refresh_workflow_permissions(context, "incomingmail_workflow", folder_path)
|
||||
|
||||
|
||||
def update_saved_search_workflow(context):
|
||||
refresh_workflow_permissions(context, "private_public_workflow")
|
||||
|
||||
# publish the communal searches in /Members
|
||||
query = {
|
||||
'path': {
|
||||
'query': '/'.join(api.portal.get().Members.getPhysicalPath()),
|
||||
'depth': 1,
|
||||
},
|
||||
'portal_type': 'pfwbgedcollection',
|
||||
'review_state': 'private',
|
||||
}
|
||||
portal_catalog = api.portal.get_tool('portal_catalog')
|
||||
for brain in portal_catalog.unrestrictedSearchResults(query):
|
||||
api.content.transition(brain.getObject(), 'publish')
|
||||
|
|
Reference in New Issue