Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Paul Graydon
erp5
Commits
f72afbba
Commit
f72afbba
authored
Jun 12, 2020
by
Arnaud Fontaine
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP: NotificationTool
parent
55e1ba56
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
280 additions
and
89 deletions
+280
-89
bt5/erp5_crm/DocumentTemplateItem/portal_components/document.erp5.Acknowledgement.py
...teItem/portal_components/document.erp5.Acknowledgement.py
+1
-1
product/ERP5/Document/File.py
product/ERP5/Document/File.py
+1
-1
product/ERP5/Tool/__init__.py
product/ERP5/Tool/__init__.py
+2
-1
product/ERP5/__init__.py
product/ERP5/__init__.py
+1
-2
product/ERP5/bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.EmailDocument.py
...lateItem/portal_components/document.erp5.EmailDocument.py
+7
-14
product/ERP5/bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.EmailDocument.xml
...ateItem/portal_components/document.erp5.EmailDocument.xml
+110
-0
product/ERP5/bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.Event.py
...mentTemplateItem/portal_components/document.erp5.Event.py
+1
-1
product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.NotificationTool.py
...plateItem/portal_components/tool.erp5.NotificationTool.py
+44
-51
product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.NotificationTool.xml
...lateItem/portal_components/tool.erp5.NotificationTool.xml
+110
-0
product/ERP5/bootstrap/erp5_core/bt/template_document_id_list
...uct/ERP5/bootstrap/erp5_core/bt/template_document_id_list
+1
-0
product/ERP5/bootstrap/erp5_core/bt/template_tool_component_id_list
...P5/bootstrap/erp5_core/bt/template_tool_component_id_list
+1
-0
product/ERP5/dtml/explainNotificationTool.dtml
product/ERP5/dtml/explainNotificationTool.dtml
+0
-17
product/ERP5/tests/testERP5Interfaces.py
product/ERP5/tests/testERP5Interfaces.py
+1
-1
No files found.
bt5/erp5_crm/DocumentTemplateItem/portal_components/document.erp5.Acknowledgement.py
View file @
f72afbba
...
...
@@ -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.D
ocument.EmailDocument
import
EmailDocumentProxyMixin
from
erp5.component.d
ocument.EmailDocument
import
EmailDocumentProxyMixin
from
erp5.component.document.Event
import
Event
class
Acknowledgement
(
EmailDocumentProxyMixin
,
Event
):
...
...
product/ERP5/Document/File.py
View file @
f72afbba
...
...
@@ -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.D
ocument.EmailDocument
import
MimeTypeException
from
erp5.component.d
ocument.EmailDocument
import
MimeTypeException
# return a tuple (mime_type, data)
content
=
None
mime_type
=
self
.
getContentType
()
...
...
product/ERP5/Tool/__init__.py
View file @
f72afbba
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'
)
product/ERP5/__init__.py
View file @
f72afbba
...
...
@@ -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
=
()
...
...
product/ERP5/
Document/
EmailDocument.py
→
product/ERP5/
bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.
EmailDocument.py
View file @
f72afbba
...
...
@@ -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):
"""
...
...
product/ERP5/bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.EmailDocument.xml
0 → 100644
View file @
f72afbba
<?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>
product/ERP5/bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.Event.py
View file @
f72afbba
...
...
@@ -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.D
ocument.EmailDocument
import
EmailDocument
from
erp5.component.d
ocument.EmailDocument
import
EmailDocument
class
AcknowledgeableMixin
:
"""
...
...
product/ERP5/
Tool/
NotificationTool.py
→
product/ERP5/
bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.
NotificationTool.py
View file @
f72afbba
...
...
@@ -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
):
...
...
product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.NotificationTool.xml
0 → 100644
View file @
f72afbba
<?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>
product/ERP5/bootstrap/erp5_core/bt/template_document_id_list
View file @
f72afbba
...
...
@@ -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
...
...
product/ERP5/bootstrap/erp5_core/bt/template_tool_component_id_list
View file @
f72afbba
...
...
@@ -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
...
...
product/ERP5/dtml/explainNotificationTool.dtml
deleted
100644 → 0
View file @
55e1ba56
<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>
product/ERP5/tests/testERP5Interfaces.py
View file @
f72afbba
...
...
@@ -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.D
ocument.EmailDocument'
,
'EmailDocument'
),
'IDocument'
),
((
'
erp5.component.d
ocument.EmailDocument'
,
'EmailDocument'
),
'IDocument'
),
((
'erp5.component.document.Event'
,
'Event'
),
'IDocument'
),
# IAmountList
((
'Products.ERP5.GeneratedAmountList'
,
'GeneratedAmountList'
),
'IAmountList'
),
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment