def validate(self, value): """The document must either have a digital file or be preserved in paper form. XXX: This validator is a hack, since it validates field values across schemata using request.form instead of `value`. """ # Bail if not called during a regular add form if self.request.form == {}: return # Mails are always available in digital form if IMail.providedBy(self.context): return form = self.view.parentForm if getattr(form, 'skip_validate_file_field', False): return if not any([ self.has_file(), self.is_preserved_as_paper(), self.has_referenced_document() ]): raise Invalid( _(u'error_file_and_preserved_as_paper', default=u"You don't select a file and document is also not " u"preserved in paper_form, please correct it."))
def cancel(self, obj): """Cancels a single document checkout. """ if IMail.providedBy(obj): msg = _(u'msg_cancel_checkout_on_mail_not_possible', default=u'Could not cancel checkout on document ${title}, ' 'mails does not support the checkin checkout process.', mapping={'title': obj.Title().decode('utf-8')}) api.portal.show_message( message=msg, request=self.request, type='error') return # check out the document manager = getMultiAdapter((obj, self.request), ICheckinCheckoutManager) # is cancel allowed for this document? if not manager.is_cancel_allowed(): msg = _(u'Could not cancel checkout on document ${title}', mapping=dict(title=obj.Title().decode('utf-8'))) api.portal.show_message( message=msg, request=self.request, type='error') else: manager.cancel() # notify the user msg = _(u'Cancel checkout: ${title}', mapping={'title': obj.Title().decode('utf-8')}) api.portal.show_message( message=msg, request=self.request, type='info')
def validate(self, value): """The document must either have a digital file or be preserved in paper form. XXX: This validator is a hack, since it validates field values across schemata using request.form instead of `value`. """ # Bail if not called during a regular add form if self.request.form == {}: return # Mails are always available in digital form if IMail.providedBy(self.context): return form = self.view.parentForm if getattr(form, 'skip_validate_file_field', False): return if not any([self.has_file(), self.is_preserved_as_paper(), self.has_referenced_document()]): raise Invalid( _(u'error_file_and_preserved_as_paper', default=u"You don't select a file and document is also not " u"preserved in paper_form, please correct it."))
def cancel(self, obj): """Cancels a single document checkout. """ if IMail.providedBy(obj): msg = _(u'msg_cancel_checkout_on_mail_not_possible', default=u'Could not cancel checkout on document ${title}, ' 'mails does not support the checkin checkout process.', mapping={'title': obj.Title().decode('utf-8')}) api.portal.show_message(message=msg, request=self.request, type='error') return # check out the document manager = getMultiAdapter((obj, self.request), ICheckinCheckoutManager) # is cancel allowed for this document? if not manager.is_cancel_allowed(): msg = _(u'Could not cancel checkout on document ${title}.', mapping=dict(title=obj.Title().decode('utf-8'))) api.portal.show_message(message=msg, request=self.request, type='error') else: manager.cancel() # notify the user msg = _(u'Cancel checkout: ${title}', mapping={'title': obj.Title().decode('utf-8')}) api.portal.show_message(message=msg, request=self.request, type='info')
def test_returns_none_if_document_has_no_file(self): self.login(self.regular_user) IMail(self.mail_eml).message = None adapter = getMultiAdapter((self.mail_eml, self.request), IBumblebeeOverlay) self.assertIsNone(adapter.get_file())
def create_mail(self, text='', objs=[], only_links=''): """Create the mail and attach the the files. For object without a file it include a Link to the Object in to the message""" attachment_parts = [] msg = MIMEMultipart() msg['Date'] = formatdate(localtime=True) # iterate over object list (which can include documents and mails), # create attachement parts for them and prepare docs_links docs_links = '%s:\r\n' % (translate( _('label_documents', default=u'Documents'), context=self.request)) for obj in objs: if IMail.providedBy(obj): obj_file = obj.message else: obj_file = obj.file if only_links or not obj_file: # rewrite the url with clients public url url = '%s/%s' % (get_current_client().public_url, '/'.join( obj.getPhysicalPath()[2:])) docs_links = '%s\r\n - %s (%s)' % (docs_links, obj.title, url) continue docs_links = '%s\r\n - %s (%s)' % ( docs_links, obj.title, translate(_('label_see_attachment', default=u'see attachment'), context=self.request)) mimetype = obj_file.contentType if not mimetype: mimetype = 'application/octet-stream' maintype, subtype = obj_file.contentType.split('/', 1) part = MIMEBase(maintype, subtype) part.set_payload(obj_file.data) Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % obj_file.filename) attachment_parts.append(part) # First, create the text part and attach it to the message ... text = '%s\r\n\r\n%s\r\n' % (text.encode( CHARSET, 'ignore'), docs_links.encode(CHARSET)) if not isinstance(text, unicode): text = text.decode('utf8') msg.attach(MIMEText(text, 'plain', CHARSET)) # ... then attach all the attachment parts for part in attachment_parts: msg.attach(part) return msg
def test_handles_non_ascii_characters_in_filename(self): self.login(self.regular_user) IMail(self.mail).message.filename = u'GEVER - \xdcbernahme.msg' adapter = getMultiAdapter((self.mail, self.request), IBumblebeeOverlay) self.assertEqual( u'http://nohost/plone/ordnungssystem/fuhrung/vertrage-und-vereinbarungen/dossier-1/document-11/bumblebee-open-pdf?filename=GEVER%20-%20%C3%9Cbernahme.pdf', adapter.get_open_as_pdf_url())
def create_mail(self, text="", objs=[], only_links=""): """Create the mail and attach the the files. For object without a file it include a Link to the Object in to the message""" attachment_parts = [] msg = MIMEMultipart() msg["Date"] = formatdate(localtime=True) # iterate over object list (which can include documents and mails), # create attachement parts for them and prepare docs_links docs_links = "%s:\r\n" % (translate(_("label_documents", default=u"Documents"), context=self.request)) for obj in objs: if IMail.providedBy(obj): obj_file = obj.message else: obj_file = obj.file if only_links or not obj_file: # rewrite the url with clients public url url = "%s/%s" % (get_current_client().public_url, "/".join(obj.getPhysicalPath()[2:])) docs_links = "%s\r\n - %s (%s)" % (docs_links, obj.title, url) continue docs_links = "%s\r\n - %s (%s)" % ( docs_links, obj.title, translate(_("label_see_attachment", default=u"see attachment"), context=self.request), ) mimetype = obj_file.contentType if not mimetype: mimetype = "application/octet-stream" maintype, subtype = obj_file.contentType.split("/", 1) part = MIMEBase(maintype, subtype) part.set_payload(obj_file.data) Encoders.encode_base64(part) part.add_header("Content-Disposition", 'attachment; filename="%s"' % obj_file.filename) attachment_parts.append(part) # First, create the text part and attach it to the message ... text = "%s\r\n\r\n%s\r\n" % (text.encode(CHARSET, "ignore"), docs_links.encode(CHARSET)) if not isinstance(text, unicode): text = text.decode("utf8") msg.attach(MIMEText(text, "plain", CHARSET)) # ... then attach all the attachment parts for part in attachment_parts: msg.attach(part) return msg
def test_handles_non_ascii_characters_in_filename(self): self.login(self.regular_user) IMail(self.mail_eml).message.filename = u'GEVER - \xdcbernahme.msg' view = api.content.get_view('tabbedview_view-overview', self.mail_eml, self.request) expected_url = ( u'http://nohost/plone/ordnungssystem/fuhrung' u'/vertrage-und-vereinbarungen/dossier-1/document-29' u'/bumblebee-open-pdf?filename=GEVER%20-%20%C3%9Cbernahme.pdf' ) self.assertEqual(expected_url, view.get_open_as_pdf_url())
def validate(self, value): if value: if self.request.get( 'form.widgets.documents_as_links') != ['selected']: registry = queryUtility(IRegistry) reg_proxy = registry.forInterface(ISendDocumentConf) total = 0 for obj in value: #check if its a mail if IMail.providedBy(obj): total += obj.message.getSize() elif obj.file: total += obj.file.getSize() if total > (reg_proxy.max_size * 1000000): raise FilesTooLarge() else: raise schema.interfaces.RequiredMissing()
def _handle_store_batch(self, brains): """This function stores the documents and their versions in bumblebee. It decides if a document has to be updated depending on its conversion timestamp and updates the timestamp after storing the document. Track the checksums locally by batch first and only add them to the global set once the transaction has been commited. Otherwise we would skip storing objects in case a conflict occurs. """ batch_checksums = set() objs_to_store = [] for brain in brains: obj = brain.getObject() if not self.needs_update(obj, self.timestamp): continue self._prepare_store_batch(obj, objs_to_store, batch_checksums) # don't attempt to store versions for mails, mails should not have # versions. in some cases they do nevertheless and then iterating # over versions may fail utterly. we don't like that thus we # avoid that it happens. # XXX should be fixed properly by making sure mails don't have # versions, ever. if IMail.providedBy(obj): continue for versiondata in self.prtool.getHistory(obj): self._prepare_store_batch(versiondata.object, objs_to_store, batch_checksums) self._store_batch(objs_to_store) for obj in objs_to_store: self.set_conversion_timestamp(obj, self.timestamp) return batch_checksums
def _handle_store_batch(self, brains): """This function stores the documents and their versions in bumblebee. It decides if a document has to be updated depending on its conversion timestamp and updates the timestamp after storing the document. Track the checksums locally by batch first and only add them to the global set once the transaction has been commited. Otherwise we would skip storing objects in case a conflict occurs. """ batch_checksums = set() objs_to_store = [] for brain in brains: obj = brain.getObject() if not self.needs_update(obj, self.timestamp): continue self._prepare_store_batch(obj, objs_to_store, batch_checksums) # don't attempt to store versions for mails, mails should not have # versions. in some cases they do nevertheless and then iterating # over versions may fail utterly. we don't like that thus we # avoid that it happens. # XXX should be fixed properly by making sure mails don't have # versions, ever. if IMail.providedBy(obj): continue for versiondata in self.prtool.getHistory(obj): self._prepare_store_batch( versiondata.object, objs_to_store, batch_checksums) self._store_batch(objs_to_store) for obj in objs_to_store: self.set_conversion_timestamp(obj, self.timestamp) return batch_checksums
def recursive_find_uncatalogued_mails(parent, catalog, max_depth=None, depth=0): """Recursively traverse content starting at parent and find uncatalogued mails. """ if max_depth and depth > max_depth: return if not hasattr(parent, 'objectItems'): return try: items = parent.objectItems() except: return for ident, item in items: if IMail.providedBy(item): path = '/'.join(item.getPhysicalPath()) nof_results = len(catalog.unrestrictedSearchResults({'path': path})) if nof_results != 1: print "{} result(s) for: {}".format(nof_results, path) recursive_find_uncatalogued_mails(item, catalog, max_depth=max_depth, depth=depth+1)
def create_mail(self, text='', objs=[], only_links=''): """Create the mail and attach the the files. For object without a file it include a Link to the Object in to the message""" attachment_parts = [] msg = MIMEMultipart() msg['Date'] = formatdate(localtime=True) # iterate over object list (which can include documents and mails), # create attachement parts for them and prepare docs_links docs_links = '%s:\r\n' % (translate( _('label_documents', default=u'Documents'), context=self.request)) for obj in objs: if IMail.providedBy(obj): obj_file = obj.message else: obj_file = obj.file if only_links or not obj_file: # rewrite the url with current adminunit's public url url = '%s/%s' % ( get_current_admin_unit().public_url, '/'.join(obj.getPhysicalPath()[2:])) docs_links = '%s\r\n - %s (%s)' % ( docs_links, obj.title, url) continue docs_links = '%s\r\n - %s (%s)' % ( docs_links, obj.title, translate( _('label_see_attachment', default=u'see attachment'), context=self.request)) mimetype = obj_file.contentType if not mimetype: mimetype = 'application/octet-stream' maintype, subtype = obj_file.contentType.split('/', 1) part = MIMEBase(maintype, subtype) part.set_payload(obj_file.data) if mimetype != 'message/rfc822': Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % obj_file.filename) attachment_parts.append(part) # First, create the text part and attach it to the message ... text = '%s\r\n\r\n%s\r\n' % ( text.encode(CHARSET, 'ignore'), docs_links.encode(CHARSET)) if not isinstance(text, unicode): text = text.decode('utf8') msg.attach(MIMEText(text, 'plain', CHARSET)) # ... then attach all the attachment parts for part in attachment_parts: msg.attach(part) return msg
def test_returns_false_if_mail_has_no_file(self): self.login(self.regular_user) IMail(self.mail).message = None adapter = getMultiAdapter((self.mail, self.request), IBumblebeeOverlay) self.assertFalse(adapter.has_file())
from zope.lifecycleevent.interfaces import IObjectCreatedEvent from zope.lifecycleevent.interfaces import IObjectModifiedEvent import os import re from plone.namedfile.interfaces import HAVE_BLOBS if HAVE_BLOBS: from plone.namedfile import NamedBlobFile as NamedFile else: from plone.namedfile import NamedFile IMail.setTaggedValue(FIELDSETS_KEY, [ Fieldset('common', label=base_mf(u'fieldset_common', u'Common'), fields=[u'message']) ]) class IOGMailMarker(Interface): """Marker Interface for opengever mails.""" class IOGMail(form.Schema): """Opengever specific behavior, which add a title Field to the form.""" form.fieldset( u'common', label=base_mf(u'fieldset_common', u'Common'),
if HAVE_BLOBS: from plone.namedfile import NamedBlobFile as NamedFile else: from plone.namedfile import NamedFile MESSAGE_SOURCE_DRAG_DROP_UPLOAD = 'upload' MESSAGE_SOURCE_MAILIN = 'mailin' NO_SUBJECT_FALLBACK_ID = 'no_subject' NO_SUBJECT_TITLE_FALLBACK = '[No Subject]' IMail.setTaggedValue(FIELDSETS_KEY, [ Fieldset('common', label=base_mf(u'fieldset_common', u'Common'), fields=[u'message']) ]) class IOGMailMarker(Interface): """Marker Interface for opengever mails.""" def get_message_source_vocabulary(): terms = [ SimpleTerm(MESSAGE_SOURCE_MAILIN, title=_('label_message_source_mailin', default='Mail-in')), SimpleTerm(MESSAGE_SOURCE_DRAG_DROP_UPLOAD, title=_('label_message_source_d_n_d_upload',
def change_mail_data(self, mail, data): old_file = IMail(self.mail).message IMail(self.mail).message = NamedBlobFile(data=data, filename=old_file.filename)
def test_factory(self): fti = queryUtility(IDexterityFTI, name='ftw.mail.mail') factory = fti.factory new_object = createObject(factory) self.failUnless(IMail.providedBy(new_object)) self.assertEquals(u'no_subject', new_object.title)
def test_adding(self): mail = create(Builder('mail')) self.failUnless(IMail.providedBy(mail)) self.assertEquals(u'no_subject', mail.title)