diff --git a/imio/dms/mail/browser/actionspanel.py b/imio/dms/mail/browser/actionspanel.py index a8bfe21c8..fe433d9fb 100644 --- a/imio/dms/mail/browser/actionspanel.py +++ b/imio/dms/mail/browser/actionspanel.py @@ -106,7 +106,7 @@ def assignable_users(self): def sortTransitions(self, lst): """Sort transitions following transitions list order""" - lst.sort(lambda x, y: cmp(self.tr_order.get(x["id"], 99), self.tr_order.get(y["id"], 99))) + lst.sort(lambda x, y: cmp(self.tr_order.get(x["id"], 99), self.tr_order.get(y["id"], 99))) # noqa F821 @ram.cache(actionspanelview_cachekey) def DmsIMActionsPanelView__call__( @@ -183,6 +183,7 @@ def __init__(self, context, request): # self.ACCEPTABLE_ACTIONS = ['copy', 'paste', 'delete'] self.ACCEPTABLE_ACTIONS = ["delete"] self.SECTIONS_TO_RENDER += ( + "render_duplicate_button", "render_create_from_template_button", "render_create_new_message", "render_send_email", @@ -190,7 +191,7 @@ def __init__(self, context, request): def sortTransitions(self, lst): """Sort transitions following transitions list order""" - lst.sort(lambda x, y: cmp(self.tr_order[x["id"]], self.tr_order[y["id"]])) + lst.sort(lambda x, y: cmp(self.tr_order[x["id"]], self.tr_order[y["id"]])) # noqa F821 def may_create_from_template(self): """ @@ -207,6 +208,17 @@ def render_create_from_template_button(self): return ViewPageTemplateFile("templates/actions_panel_create_from_template.pt")(self) return "" + def may_duplicate(self): + """Method that check if special 'duplicate' action has to be displayed.""" + if self.member.has_permission("Add portal content", self.portal["outgoing-mail"]): + return True + return False + + def render_duplicate_button(self): + if self.may_duplicate(): + return ViewPageTemplateFile("templates/actions_panel_duplicate.pt")(self) + return "" + def may_create_new_message(self): if ( self.context.is_email() @@ -296,7 +308,7 @@ def __init__(self, context, request): def sortTransitions(self, lst): """Sort transitions following transitions list order""" - lst.sort(lambda x, y: cmp(self.tr_order[x["id"]], self.tr_order[y["id"]])) + lst.sort(lambda x, y: cmp(self.tr_order[x["id"]], self.tr_order[y["id"]])) # noqa F821 @ram.cache(actionspanelview_cachekey) def DmsTaskActionsPanelView__call__( diff --git a/imio/dms/mail/browser/configure.zcml b/imio/dms/mail/browser/configure.zcml index 80666ecfb..3a8bad4b6 100644 --- a/imio/dms/mail/browser/configure.zcml +++ b/imio/dms/mail/browser/configure.zcml @@ -18,6 +18,13 @@ class=".views.CreateFromTemplateForm" /> + + + + \ No newline at end of file diff --git a/imio/dms/mail/browser/templates/actions_panel_duplicate.pt b/imio/dms/mail/browser/templates/actions_panel_duplicate.pt new file mode 100644 index 000000000..b78000a89 --- /dev/null +++ b/imio/dms/mail/browser/templates/actions_panel_duplicate.pt @@ -0,0 +1,10 @@ + + + + + + + diff --git a/imio/dms/mail/browser/views.py b/imio/dms/mail/browser/views.py index e95e0ee3c..9720a46c0 100644 --- a/imio/dms/mail/browser/views.py +++ b/imio/dms/mail/browser/views.py @@ -6,6 +6,8 @@ from imio.dms.mail import _ from imio.dms.mail import _tr from imio.dms.mail import PMH_ENABLED +from imio.dms.mail.browser.settings import IImioDmsMailConfig +from imio.dms.mail.browser.settings import omail_duplicate_fields from imio.dms.mail.browser.table import CKTemplatesTable from imio.dms.mail.browser.table import PersonnelTable from imio.dms.mail.dmsfile import IImioDmsFile @@ -19,11 +21,16 @@ from imio.helpers.fancytree.views import BaseRenderFancyTree from imio.helpers.workflow import do_transitions from imio.helpers.xhtml import object_link +from imio.pyutils.utils import safe_encode from plone import api from Products.CMFPlone.utils import safe_unicode from Products.Five import BrowserView from Products.PageTemplates.Expressions import SecureModuleImporter from unidecode import unidecode # unidecode_expect_nonascii not yet available in used version +from z3c.form import button +from z3c.form.field import Fields +from z3c.form.form import Form +from zope import schema from zope.annotation import IAnnotations from zope.component import getMultiAdapter from zope.i18n import translate @@ -70,6 +77,65 @@ def redirect_url(self, uid): return "{}/persistent-document-generation?{}".format(url, "&".join(params)) +class OMDuplicateForm(Form): + + """Duplicate an outgoing mail.""" + label = _(u"Duplicate mail") + ignoreContext = True + + def update(self): + """Handle fields.""" + om_fields = api.portal.get_registry_record("omail_fields", IImioDmsMailConfig, []) + om_fields = [dic["field_name"] for dic in om_fields] + matching = {u"category": "IClassificationFolder.classification_categories", + u"folder": "IClassificationFolder.classification_folders", + u"reply_to": "reply_to", + u"link_to_duplicated": "reply_to"} + to_show = api.portal.get_registry_record("omail_duplicate_display_fields", IImioDmsMailConfig, []) + to_true = api.portal.get_registry_record("omail_duplicate_true_default_values", IImioDmsMailConfig, []) + for term in omail_duplicate_fields: + if ((term.value in matching and matching[term.value] not in om_fields) or + (term.value not in to_show and term.value not in to_true)): + continue + self.fields += Fields( + schema.Bool( + __name__=safe_encode(term.value), + title=term.title, + default=term.value in to_true, + )) + super(OMDuplicateForm, self).update() + + def updateWidgets(self, prefix=None): + super(OMDuplicateForm, self).updateWidgets() + + # we hide fields not to show + to_show = api.portal.get_registry_record("omail_duplicate_display_fields", IImioDmsMailConfig, []) + for term in omail_duplicate_fields: + if term.value not in to_show: + self.widgets[term.value].mode = "hidden" + + @button.buttonAndHandler(_('Duplicate'), name='duplicate') + def handleApply(self, action): + data, errors = self.extractData() + + if errors: + self.status = self.formErrorsMessage + return + + # Duplicate the mail + odm_utils = getMultiAdapter((self.context, self.request), name="odm-utils") + duplicated_mail = odm_utils.duplicate( + keep_category=data.get('category', False), + keep_folder=data.get('folder', False), + keep_reply_to=data.get('reply_to', False), + keep_dms_files=data.get('dms_files', False), + keep_annexes=data.get('annexes', False), + link_to_duplicated=data.get('link_to_duplicated', False), + ) + + self.request.response.redirect(duplicated_mail.absolute_url()+"/edit") + + def parse_query(text): """Copied from plone.app.vocabularies.catalog.parse_query but cleaned.""" for char in "?-+*()": diff --git a/imio/dms/mail/skins/imio_dms_mail/imiodmsmail.css.dtml b/imio/dms/mail/skins/imio_dms_mail/imiodmsmail.css.dtml index fe4c3b6bb..c8e515049 100644 --- a/imio/dms/mail/skins/imio_dms_mail/imiodmsmail.css.dtml +++ b/imio/dms/mail/skins/imio_dms_mail/imiodmsmail.css.dtml @@ -471,6 +471,10 @@ dl.portletWidgetCollection div.portlet_add_icons a { background-image: url('&dtml-portal_url;/++resource++imio.dms.mail/models_icon.png'); } +.apButtonAction_duplicate { + background-image: url('&dtml-portal_url;/++resource++imio.dms.mail/copy.svg'); +} + .apButtonAction_sendemail { background-image: url('&dtml-portal_url;/++resource++imio.dms.mail/send_email.svg'); background-size: 18px 18px; diff --git a/imio/dms/mail/subscribers.py b/imio/dms/mail/subscribers.py index 2390c21ff..d7eca2495 100644 --- a/imio/dms/mail/subscribers.py +++ b/imio/dms/mail/subscribers.py @@ -72,6 +72,7 @@ # from zope.component.interfaces import ComponentLookupError from zope.annotation import IAnnotations from zope.component import getAdapter +from zope.component import getMultiAdapter from zope.component import getSiteManager from zope.component import getUtility from zope.component import queryUtility @@ -384,6 +385,16 @@ def dmsoutgoingmail_transition(mail, event): mail.portal_catalog.reindexObject(mail, idxs=("in_out_date",), update_metadata=0) +def dmsoutgoingmail_modified(mail, event): + annot = IAnnotations(mail).get('imio.dms.mail', {}) + copy_dms_files_from = annot.get('copy_dms_files_from') + if copy_dms_files_from: + del annot['copy_dms_files_from'] + original_mail = uuidToObject(copy_dms_files_from, unrestricted=True) + odm_utils = getMultiAdapter((mail, mail.REQUEST), name="odm-utils") + odm_utils.copy_dms_files(original_mail) + + def dv_handle_file_creation(obj, event): """Intermediate function to avoid converting some files in documentviewer""" if obj.portal_type in DV_AVOIDED_TYPES: diff --git a/imio/dms/mail/subscribers.zcml b/imio/dms/mail/subscribers.zcml index 7e357c39f..bde5b4cb2 100644 --- a/imio/dms/mail/subscribers.zcml +++ b/imio/dms/mail/subscribers.zcml @@ -98,6 +98,12 @@ handler=".subscribers.dmsoutgoingmail_transition" /> + + 1 + if requires_mailing and not annot.get('need_mailing'): + continue + + # Generate a new document from the same template + template_uid = annot.get('template_uid') + generation_view = getMultiAdapter((self.context, self.request), name="persistent-document-generation") + pod_template = generation_view.get_pod_template(template_uid) + # Skip if it's a mailing loop template + if IMailingLoopTemplate.providedBy(pod_template): + continue + generation_view.pod_template = pod_template + generation_view.output_format = 'odt' + generation_view.generate_persistent_doc(pod_template, 'odt') + used_template_uids.add(template_uid) + class Dummy(object): """dummy class that allows setting attributes"""