Commit f72afbba authored by Arnaud Fontaine's avatar Arnaud Fontaine

WIP: NotificationTool

parent 55e1ba56
......@@ -30,7 +30,7 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
from Products.ERP5.Document.EmailDocument import EmailDocumentProxyMixin
from erp5.component.document.EmailDocument import EmailDocumentProxyMixin
from erp5.component.document.Event import Event
class Acknowledgement(EmailDocumentProxyMixin, Event):
......
......@@ -201,7 +201,7 @@ class File(Document, CMFFile):
security.declareProtected(Permissions.AccessContentsInformation, 'getMimeTypeAndContent')
def getMimeTypeAndContent(self):
"""This method returns a tuple which contains mimetype and content."""
from Products.ERP5.Document.EmailDocument import MimeTypeException
from erp5.component.document.EmailDocument import MimeTypeException
# return a tuple (mime_type, data)
content = None
mime_type = self.getContentType()
......
from AccessControl.SecurityInfo import allow_module
allow_module('Products.ERP5.Tool.NotificationTool')
allow_module('erp5.component.tool.NotificationTool')
allow_module('erp5.component.tool.erp5_version.NotificationTool')
......@@ -43,7 +43,7 @@ product_path = package_home( globals() )
# Define object classes and tools
from Tool import CategoryTool,TemplateTool,\
AlarmTool,\
TrashTool, ContributionTool, NotificationTool,\
TrashTool, ContributionTool,\
SolverTool
import ERP5Site
from Document import PythonScript, SQLMethod
......@@ -56,7 +56,6 @@ portal_tools = ( CategoryTool.CategoryTool,
AlarmTool.AlarmTool,
TrashTool.TrashTool,
ContributionTool.ContributionTool,
NotificationTool.NotificationTool,
SolverTool.SolverTool,
)
content_classes = ()
......
......@@ -27,25 +27,19 @@
#
##############################################################################
import re, types
from email.utils import formataddr
import re
from DateTime import DateTime
from AccessControl import ClassSecurityInfo, Unauthorized
from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
from Products.CMFCore.utils import _checkPermission
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.TextDocument import TextDocument
from Products.ERP5.Document.File import File
from Products.ERP5.Document.Document import ConversionError
from Products.ERP5.mixin.mail_message import MailMessageMixin, testCharsetAndConvert
from Products.ERP5.mixin.document_proxy import DocumentProxyMixin, DocumentProxyError
from Products.ERP5.Tool.NotificationTool import buildEmailMessage
from Products.ERP5Type.Utils import guessEncodingFromText
from MethodObject import Method
from zLOG import LOG, INFO
try:
from Products.MimetypesRegistry.common import MimeTypeException
from Products.MimetypesRegistry.common import MimeTypeException # pylint: disable=unused-import
except ImportError:
class MimeTypeException(Exception):
"""
......@@ -54,12 +48,11 @@ except ImportError:
"""
from email import message_from_string
from email.header import decode_header, HeaderParseError
from email.utils import parsedate_tz, mktime_tz
DEFAULT_TEXT_FORMAT = 'text/html'
COMMASPACE = ', '
_MARKER = []
_MARKER = ()
filename_regexp = 'name="([^"]*)"'
......@@ -255,11 +248,11 @@ class EmailDocument(TextDocument, MailMessageMixin):
else:
part_encoding = part.get_content_charset()
message_text = part.get_payload(decode=1)
text_result, encoding = testCharsetAndConvert(message_text,
text_result, _ = testCharsetAndConvert(message_text,
part.get_content_type(),
part_encoding)
if part.get_content_type() == 'text/html':
mime, text_result = self.convert(format='html',
_, text_result = self.convert(format='html',
text_content=text_result,
charset=part_encoding)
......@@ -287,7 +280,7 @@ class EmailDocument(TextDocument, MailMessageMixin):
else:
return part.get_content_type()
email_parser = re.compile('[ ;,<>\'"]*([^<> ;,\'"]+?\@[^<> ;,\'"]+)[ ;,<>\'"]*', re.IGNORECASE)
email_parser = re.compile(r'[ ;,<>\'"]*([^<> ;,\'"]+?\@[^<> ;,\'"]+)[ ;,<>\'"]*', re.IGNORECASE)
security.declareProtected(Permissions.AccessContentsInformation, 'getContentURLList')
def getContentURLList(self):
"""
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Document Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>EmailDocument</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5.Document.EmailDocument</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document.erp5.EmailDocument</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Document Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -33,7 +33,7 @@ from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
from Products.ERP5Type.Globals import InitializeClass
from erp5.component.document.Movement import Movement
from Products.ERP5.Document.EmailDocument import EmailDocument
from erp5.component.document.EmailDocument import EmailDocument
class AcknowledgeableMixin:
"""
......
......@@ -27,13 +27,10 @@
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Globals import DTMLFile
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type.Tool.BaseTool import BaseTool
from Products.ERP5Type import Permissions
from AccessControl import ModuleSecurityInfo
from zExceptions import Unauthorized
from Products.ERP5 import _dtmldir
from mimetypes import guess_type
from email.mime.multipart import MIMEMultipart
......@@ -48,7 +45,7 @@ from email import encoders
class ConversionError(Exception): pass
class MimeTypeException(Exception): pass
security = ModuleSecurityInfo('Products.ERP5.Tool.NotificationTool')
security = ModuleSecurityInfo(__name__)
security.declarePublic('buildEmailMessage',)
def buildAttachmentDictList(document_list, document_type_list=()):
......@@ -57,7 +54,6 @@ def buildAttachmentDictList(document_list, document_type_list=()):
for attachment in document_list:
mime_type = None
content = None
name = None
if not attachment.getPortalType() in document_type_list:
mime_type = 'application/pdf'
content = attachment.asPDF() # XXX - Not implemented yet
......@@ -149,7 +145,7 @@ def buildEmailMessage(from_url, to_url, msg=None,
# try to guess the mime type
if not attachment.has_key('mime_type'):
mime_type, encoding = guess_type( attachment_name )
mime_type, _ = guess_type( attachment_name )
if mime_type is not None:
attachment['mime_type'] = mime_type
else:
......@@ -208,9 +204,6 @@ class NotificationTool(BaseTool):
# Declarative Security
security = ClassSecurityInfo()
security.declareProtected( Permissions.ManagePortal, 'manage_overview' )
manage_overview = DTMLFile( 'explainNotificationTool', _dtmldir )
# low-level interface
def _sendEmailMessage(self, from_url, to_url, body=None, subject=None,
attachment_list=None, extra_headers=None,
......@@ -396,48 +389,48 @@ class NotificationTool(BaseTool):
# NOTE: this implementation should also make sure that the current
# buildEmailMessage method defined here and the Event.send method
# are merged once for all
if self.getNotifierList():
# CRM is installed - so we can lookup notification preferences
if notifier_list is None:
# Find which notifier to use on preferences
if priority_level not in ('low', 'medium', 'high'): # XXX Better naming required here
priority_level = 'high'
notifier_list = self.preferences.getPreference(
'preferred_%s_priority_nofitier_list' % priority_level)
event_list = []
for notifier in notifier_list:
event_module = self.getDefaultModule(notifier)
new_event = event_module.newContent(portal_type=notifier, temp_object=store_as_event)
event_list.append(new_event)
else:
# CRM is not installed - only notification by email is possible
# So create a temp object directly
new_event = self.newContent(temp_object=True, portal_type='Event', id='_')
event_list = [new_event]
if event in event_list:
# We try to build events using the same parameters as the one
# we were provided for notification.
# The handling of attachment is still an open question:
# either use relation (to prevent duplication) or keep
# a copy inside. It is probably a good idea to
# make attachment_list polymorphic in order to be able
# to provide different kinds of attachments can be provided
# Either document references or binary data.
event.build(sender=sender, recipient=recipient, subject=subject,
message=message, attachment_list=attachment_list,) # Rename here and add whatever
# parameter makes sense such
# as text format
event.send() # Make sure workflow transition is invoked if this is
# a persistent notification
# Aggregation could be handled by appending the notification
# to an existing message rather than creating a new one.
# Sending the message should be handled by the alarm based
# on a date value stored on the event. This probably required
# a new workflow state to represent events which are waiting
# for being sent automatically. (ie. scheduled sending)
#
#if self.getNotifierList():
# # CRM is installed - so we can lookup notification preferences
# if notifier_list is None:
# # Find which notifier to use on preferences
# if priority_level not in ('low', 'medium', 'high'): # XXX Better naming required here
# priority_level = 'high'
# notifier_list = self.preferences.getPreference(
# 'preferred_%s_priority_nofitier_list' % priority_level)
# event_list = []
# for notifier in notifier_list:
# event_module = self.getDefaultModule(notifier)
# new_event = event_module.newContent(portal_type=notifier, temp_object=store_as_event)
# event_list.append(new_event)
#else:
# # CRM is not installed - only notification by email is possible
# # So create a temp object directly
# new_event = self.newContent(temp_object=True, portal_type='Event', id='_')
# event_list = [new_event]
#
#if event in event_list:
# # We try to build events using the same parameters as the one
# # we were provided for notification.
# # The handling of attachment is still an open question:
# # either use relation (to prevent duplication) or keep
# # a copy inside. It is probably a good idea to
# # make attachment_list polymorphic in order to be able
# # to provide different kinds of attachments can be provided
# # Either document references or binary data.
# event.build(sender=sender, recipient=recipient, subject=subject,
# message=message, attachment_list=attachment_list,) # Rename here and add whatever
# # parameter makes sense such
# # as text format
# event.send() # Make sure workflow transition is invoked if this is
# # a persistent notification
#
# # Aggregation could be handled by appending the notification
# # to an existing message rather than creating a new one.
# # Sending the message should be handled by the alarm based
# # on a date value stored on the event. This probably required
# # a new workflow state to represent events which are waiting
# # for being sent automatically. (ie. scheduled sending)
security.declareProtected(Permissions.AccessContentsInformation, 'getNotifierList')
def getNotifierList(self):
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Tool Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>NotificationTool</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5.Tool.NotificationTool</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>tool.erp5.NotificationTool</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Tool Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -3,6 +3,7 @@ document.erp5.AppliedRule
document.erp5.Delivery
document.erp5.DeliveryCell
document.erp5.DeliveryLine
document.erp5.EmailDocument
document.erp5.Event
document.erp5.ImmobilisableItem
document.erp5.ImmobilisationDelivery
......
......@@ -7,6 +7,7 @@ tool.erp5.DiffTool
tool.erp5.DomainTool
tool.erp5.IdTool
tool.erp5.IntrospectionTool
tool.erp5.NotificationTool
tool.erp5.OrderTool
tool.erp5.PasswordTool
tool.erp5.RuleTool
......
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<p>Help on Notification Tool</p>
This tool is useful to manage notifications.
It is used as a central point to send messages from one
user to one or many users. The purpose of the tool
is to provide an API for sending messages which is
independent on how messages are actually going to be
sent and when.
This early implementation only provides asynchronous
email sending.
<dtml-var manage_page_footer>
......@@ -54,7 +54,7 @@ implements_tuple_list = [
(('Products.ERP5.Document.File', 'File'), 'IDocument'),
(('erp5.component.document.OOoDocument', 'OOoDocument'), 'IDocument'),
(('Products.ERP5.Document.TextDocument', 'TextDocument'), 'IDocument'),
(('Products.ERP5.Document.EmailDocument', 'EmailDocument'), 'IDocument'),
(('erp5.component.document.EmailDocument', 'EmailDocument'), 'IDocument'),
(('erp5.component.document.Event', 'Event'), 'IDocument'),
# IAmountList
(('Products.ERP5.GeneratedAmountList', 'GeneratedAmountList'), 'IAmountList'),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment