Commit 2df5554b authored by Jérome Perrin's avatar Jérome Perrin

Review SMS API

Implement the remaining tasks from nexedi/erp5!173 and fix [#20170709-17309B6](https://nexedi.erp5.net/bug_module/20170709-17309B6)

Backport of nexedi/erp5!580

/reviewed-on https://lab.nexedi.com/nexedi/erp5-capago/merge_requests/16
parents 86316c84 eb6d3df4
"""Save the message id of the relative document""" """Save the message id of the relative document"""
if document_relative_url: if document_relative_url:
document = context.getPortalObject().restrictedTraverse(document_relative_url) document = context.getPortalObject().restrictedTraverse(document_relative_url)
document.edit(destination_reference=message_id_list[0], document.edit(destination_reference=message_id,
gateway = gateway_relative_url) gateway=gateway_relative_url)
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>message_id_list, document_relative_url=None, gateway_relative_url=None, **kw</string> </value> <value> <string>message_id, document_relative_url=None, gateway_relative_url=None, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -4,42 +4,29 @@ ...@@ -4,42 +4,29 @@
""" """
#Get recipients #Get recipients
if not to_url: recipient_phone_list = [
recipient_phone_list = [person.getDefaultMobileTelephoneValue() for person in context.getDestinationValueList()] person.getDefaultMobileTelephoneValue() for person in context.getDestinationValueList()]
if None in recipient_phone_list: if None in recipient_phone_list:
raise ValueError("All recipients should have a default mobile phone") raise ValueError("All recipients should have a default mobile phone")
to_url = [phone.asURL() for phone in recipient_phone_list] to_url = [phone.asURL() for phone in recipient_phone_list]
if None in to_url: if None in to_url:
raise ValueError("All recipients should have a valid default mobile phone number") raise ValueError("All recipients should have a valid default mobile phone number")
#Get sender body = context.getTextContent()
if not from_url:
if context.getSourceValue():
sender_phone = context.getSourceValue().getDefaultMobileTelephoneValue()
if not sender_phone:
raise ValueError("The sender(%s) should have a default mobile phone" % context.getSourceValue())
#We use title of sender
from_title = sender_phone.getTitle()
from_url = sender_phone.asURL()
if not body:
body = context.getTextContent()
if not context.getStartDate(): if not context.getStartDate():
context.setStartDate(DateTime()) context.setStartDate(DateTime())
context.portal_sms.activate( for recipient in context.getDestinationList():
context.portal_sms.activate(
activity="SQLQueue", activity="SQLQueue",
# We do not retry these activities not to send SMS multiple times # We do not retry these activities not to send SMS multiple times
max_retry=0, max_retry=0,
conflict_retry=False, conflict_retry=False,
).send( ).send(
text=body, text=body,
recipient=to_url, sender=context.getSource(),
sender=from_url, recipient=recipient,
sender_title=from_title,
message_type="MULTITEXT",
test=download,
document_relative_url=context.getRelativeUrl(), document_relative_url=context.getRelativeUrl(),
**kw) )
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>from_url=None, from_title=None, to_url=None, reply_url=None, subject=None, body=None, attachment_format=None, attachment_list=None,download=False,**kw</string> </value> <value> <string>from_url=None, from_title=None, to_url=None, reply_url=None, subject=None, body=None, attachment_format=None, attachment_list=None, download=False, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>_proxy_roles</string> </key> <key> <string>_proxy_roles</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SMS Tool" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_Transient_Objects_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Author</string>
<string>Associate</string>
<string>Assignee</string>
<string>Manager</string>
<string>Auditor</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Author</string>
<string>Associate</string>
<string>Assignee</string>
<string>Manager</string>
<string>Auditor</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Access_future_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Access_session_data_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Author</string>
<string>Associate</string>
<string>Assignee</string>
<string>Manager</string>
<string>Auditor</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Author</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_folders_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Author</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Copy_or_Move_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Author</string>
<string>Associate</string>
<string>Assignee</string>
<string>Manager</string>
<string>Auditor</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Delete_objects_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_FTP_access_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_List_folder_contents_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Author</string>
<string>Associate</string>
<string>Assignee</string>
<string>Manager</string>
<string>Auditor</string>
</tuple>
</value>
</item>
<item>
<key> <string>_List_portal_members_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Manage_properties_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Reply_to_item_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Review_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Search_ZCatalog_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Set_own_properties_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Undo_changes_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Use_mailhost_services_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_History_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Author</string>
<string>Associate</string>
<string>Assignee</string>
<string>Manager</string>
<string>Auditor</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Associate</string>
<string>Assignee</string>
<string>Manager</string>
<string>Auditor</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_management_screens_Permission</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>portal_sms</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
portal_sms
\ No newline at end of file
...@@ -55,50 +55,28 @@ class DummyGateway(XMLObject): ...@@ -55,50 +55,28 @@ class DummyGateway(XMLObject):
add_permission = Permissions.AddPortalContent add_permission = Permissions.AddPortalContent
zope.interface.implements(interfaces.ISmsGateway) zope.interface.implements(
interfaces.ISmsSendingGateway,
interfaces.ISmsReceivingGateway)
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properi ties # Declarative properties
property_sheets = ( PropertySheet.Base property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject , PropertySheet.XMLObject
, PropertySheet.Reference , PropertySheet.Reference
, PropertySheet.SMSGateway , PropertySheet.SMSGateway
) )
security.declarePublic('getAllowedMessageType')
def getAllowedMessageType(self):
"""List of all message type"""
return ['text',]
security.declareProtected(Permissions.ManagePortal, 'send') security.declareProtected(Permissions.ManagePortal, 'send')
def send(self, text,recipient,sender=None, sender_title=None, def send(self, text, recipient, sender):
message_type="text",test=False,**kw): """Send a short message.
"""Send a message.
Parameters:
text -- message
recipient -- phone url of destination_reference. Could be a list
sender -- phone url of source
sender_title -- Use it as source if the gateway has title mode enable
message_type -- Only 'text' is available today
test -- Force the test mode
Kw Parameters:
quality -- Quality of the SMS (default,n)
Return message id
""" """
#Check messsage type
# XXX does it make sense to check message type in dummy gateway ? -jerome
#if message_type not in self.getAllowedMessageType():
# raise ValueError, "Type of message in not allowed"
#Send message (or test) #Send message (or test)
if test or self.isSimulationMode(): if self.isSimulationMode():
return None return None
else:
return self._generateRandomMessageId() return self._generateRandomMessageId()
security.declareProtected(Permissions.ManagePortal, 'getMessageStatus') security.declareProtected(Permissions.ManagePortal, 'getMessageStatus')
......
...@@ -61,7 +61,9 @@ class EssendexGateway(XMLObject): ...@@ -61,7 +61,9 @@ class EssendexGateway(XMLObject):
add_permission = Permissions.AddPortalContent add_permission = Permissions.AddPortalContent
zope.interface.implements(interfaces.ISmsGateway) zope.interface.implements(
interfaces.ISmsSendingGateway,
interfaces.ISmsReceivingGateway)
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
...@@ -75,10 +77,6 @@ class EssendexGateway(XMLObject): ...@@ -75,10 +77,6 @@ class EssendexGateway(XMLObject):
) )
api_url = "https://www.esendex.com/secure/messenger/formpost" api_url = "https://www.esendex.com/secure/messenger/formpost"
security.declarePublic('getAllowedMessageType')
def getAllowedMessageType(self):
"""List of all message type"""
return ['text', 'binary', 'smartMessage', 'unicode']
security.declarePrivate("_fetchPageAsDict") security.declarePrivate("_fetchPageAsDict")
def _fetchPageAsDict(self,page): def _fetchPageAsDict(self,page):
...@@ -132,32 +130,17 @@ class EssendexGateway(XMLObject): ...@@ -132,32 +130,17 @@ class EssendexGateway(XMLObject):
return timedelta.seconds + (timedelta.days * 24 * 60 * 60) return timedelta.seconds + (timedelta.days * 24 * 60 * 60)
security.declareProtected(Permissions.ManagePortal, 'send') security.declareProtected(Permissions.ManagePortal, 'send')
def send(self, text,recipient,sender=None, sender_title=None, def send(self, text, recipient, sender):
message_type="text",test=False,**kw):
"""Send a message. """Send a message.
Parameters:
text -- message
recipient -- phone url of destination_reference. Could be a list
sender -- phone url of source
sender_title -- Use it as source if the gateway has title mode enable
message_type -- Only 'text' is available today
test -- Force the test mode
Kw Parameters:
validity_period -- Validity Period of SMS (default,0)
Return message id (or list if multiple recipient)
""" """
traverse = self.getPortalObject().restrictedTraverse
message_type = self.getProperty('essendex_message_type', 'text')
assert message_type in ('text', 'binary', 'smartMessage', 'unicode')
if message_type not in self.getAllowedMessageType(): validity_period = self.getProperty('essendex_validity_period', 0)
raise ValueError, "Type of message in not allowed"
validity_period = kw.get('validity_period',0) recipient = self._transformPhoneUrlToGatewayNumber(
traverse(recipient).getDefaultMobileTelephoneValue().asURL())
if not isinstance(recipient, str):
recipient = ",".join([self._transformPhoneUrlToGatewayNumber(x) for x in recipient])
else:
recipient = self._transformPhoneUrlToGatewayNumber(recipient)
base_url = self.api_url + "/SendSMS.aspx" base_url = self.api_url + "/SendSMS.aspx"
params = {'Username': self.getGatewayUser(), params = {'Username': self.getGatewayUser(),
...@@ -170,16 +153,13 @@ class EssendexGateway(XMLObject): ...@@ -170,16 +153,13 @@ class EssendexGateway(XMLObject):
'PlainText': 1, 'PlainText': 1,
} }
if self.isTitleMode():
params['Originator'] = traverse(sender).getDefaultMobileTelephoneValue().getTitle()
else:
params['Originator'] = self._transformPhoneUrlToGatewayNumber(
traverse(sender).getDefaultMobileTelephoneValue().asURL()) or self.getDefaultSender()
if self.isSimulationMode():
if sender_title and self.isTitleMode():
params['Originator'] = sender_title
elif sender:
params['Originator'] = self._transformPhoneUrlToGatewayNumber(sender)
elif self.getDefaultSender():
params['Originator'] = self.getDefaultSender()
if test or self.isSimulationMode():
params['Test'] = 1 params['Test'] = 1
LOG("EssendexGateway", INFO, params) LOG("EssendexGateway", INFO, params)
......
...@@ -57,7 +57,9 @@ class MobytGateway(XMLObject): ...@@ -57,7 +57,9 @@ class MobytGateway(XMLObject):
add_permission = Permissions.AddPortalContent add_permission = Permissions.AddPortalContent
zope.interface.implements(interfaces.ISmsGateway) zope.interface.implements(
interfaces.ISmsSendingGateway,
interfaces.ISmsReceivingGateway)
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
...@@ -72,13 +74,7 @@ class MobytGateway(XMLObject): ...@@ -72,13 +74,7 @@ class MobytGateway(XMLObject):
# see https://web.archive.org/web/20111125005954/http://www.mobyt.fr/doc/mobyt_module_http.pdf # see https://web.archive.org/web/20111125005954/http://www.mobyt.fr/doc/mobyt_module_http.pdf
# for documentation of this old API # for documentation of this old API
api_url = "http://multilevel.mobyt.fr/sms" api_url = "https://multilevel.mobyt.fr/sms"
security.declarePublic('getAllowedMessageType')
def getAllowedMessageType(self):
"""List of all message type"""
# `text` is here for compatibility, but the API always expected uppercase
return ['text', 'TEXT', 'MULTITEXT', 'WAPPUSH', 'UCS2', 'MULTIUCS2']
security.declarePrivate("_fetchSendResponseAsDict") security.declarePrivate("_fetchSendResponseAsDict")
def _fetchSendResponseAsDict(self,page): def _fetchSendResponseAsDict(self,page):
...@@ -141,41 +137,23 @@ class MobytGateway(XMLObject): ...@@ -141,41 +137,23 @@ class MobytGateway(XMLObject):
return phone return phone
security.declareProtected(Permissions.ManagePortal, 'send') security.declareProtected(Permissions.ManagePortal, 'send')
def send(self, text,recipient,sender=None, sender_title=None, def send(self, text, recipient, sender):
message_type="text",test=False,**kw):
"""Send a message. """Send a message.
Parameters:
text -- message
recipient -- phone url of destination_reference. Could be a list
sender -- phone url of source
sender_title -- Use it as source if the gateway has title mode enable
message_type -- see getAllowedMessageType
test -- Force the test mode
Kw Parameters:
quality -- Quality of the SMS (default,n)
Return message id
""" """
traverse = self.getPortalObject().restrictedTraverse
#Check messsage type #Check messsage type
if message_type not in self.getAllowedMessageType(): message_type = self.getProperty('mobyt_message_type', 'MULTITEXT')
raise ValueError, "Type of message in not allowed" if message_type not in ('TEXT', 'MULTITEXT', 'WAPPUSH', 'UCS2', 'MULTIUCS2'):
raise ValueError("Type of message in not allowed")
#Check message qualit #Check message quality
quality = kw.get('quality','n') #Allow sender personalization and status of SMS quality = self.getProperty('mobyt_quality', 'n') #Allow sender personalization and status of SMS
assert quality in ['n','l','ll'], "Unknown quality : '%s'" % quality assert quality in ('n','l','ll'), "Unknown quality : '%s'" % quality
#Recipients #Recipient
if not isinstance(recipient, str): recipient = self._transformPhoneUrlToGatewayNumber(
recipient_count = len(recipient) traverse(recipient).getDefaultMobileTelephoneValue().asURL())
recipient = ",".join([self._transformPhoneUrlToGatewayNumber(x) for x in recipient])
else:
recipient = self._transformPhoneUrlToGatewayNumber(recipient)
recipient_count = 1
if recipient_count > 1:
base_url = self.api_url + "/batch.php" #Multi recipient
else:
base_url = self.api_url + "/send.php" base_url = self.api_url + "/send.php"
#Common params #Common params
...@@ -186,22 +164,19 @@ class MobytGateway(XMLObject): ...@@ -186,22 +164,19 @@ class MobytGateway(XMLObject):
"qty" : quality, "qty" : quality,
"return_id": 1} "return_id": 1}
#Define sender if self.isTitleMode():
if sender_title and self.isTitleMode() and quality == 'n': params['sender'] = traverse(sender).getDefaultMobileTelephoneValue().getTitle()
params['sender'] = sender_title else:
elif sender: params['sender'] = self._transformPhoneUrlToGatewayNumber(
params['sender'] = self._transformPhoneUrlToGatewayNumber(sender) traverse(sender).getDefaultMobileTelephoneValue().asURL()) or self.getDefaultSender()
elif self.getDefaultSender():
params['sender'] = self.getDefaultSender()
#Define type of message #Define type of message
if message_type != "text": if message_type != "text":
assert quality == 'n', "This type of message require top level messsage quality" assert quality == 'n', "This type of message require top level messsage quality"
assert message_type in self.getAllowedMessageType(), "Unknown message type"
params['operation'] = message_type params['operation'] = message_type
#Send message (or test) #Send message (or test)
if test or self.isSimulationMode(): if self.isSimulationMode():
LOG("MobytGateway", INFO, params) LOG("MobytGateway", INFO, params)
result = {'status': "Test"} result = {'status': "Test"}
else: else:
......
...@@ -50,24 +50,22 @@ class SMSTool(BaseTool): ...@@ -50,24 +50,22 @@ class SMSTool(BaseTool):
manage_overview = DTMLFile('explainSMSTool', _dtmldir ) manage_overview = DTMLFile('explainSMSTool', _dtmldir )
security.declareProtected(ManagePortal, 'send') security.declareProtected(ManagePortal, 'send')
def send(self, text,recipient, sender=None, sender_title=None, def send(self, text, recipient, sender, gateway_reference='default',
message_type="text", test=False, gateway_reference='default', document_relative_url=None, activate_kw=None):
document_relative_url=None, activate_kw=None, **kw): """Send the message
"""
gateway_reference: send message throught the gateway with this reference.
document_relative_url (optional) : allows to send back result to a document document_relative_url (optional) : allows to send back result to a document
activate_kw (optional) : Call SMSTool_afterSend if founded in activity with activate_kw (optional) : Call SMSTool_afterSend if founded in activity with
message_id_list and document_relative_url message_id and document_relative_url
""" """
gateway = self.find(gateway_reference) gateway = self._findGateway(gateway_reference)
message_id_list = gateway.send(text=text, message_id = gateway.send(
text=text,
recipient=recipient, recipient=recipient,
sender=sender, sender=sender)
sender_title=sender_title,
message_type=message_type,
test=test,
**kw)
if getattr(self, 'SMSTool_afterSend'): if getattr(self, 'SMSTool_afterSend'):
# We need to use activities in order to avoid any conflict # We need to use activities in order to avoid any conflict
...@@ -75,31 +73,32 @@ class SMSTool(BaseTool): ...@@ -75,31 +73,32 @@ class SMSTool(BaseTool):
if activate_kw is not None: if activate_kw is not None:
send_activate_kw.update(**activate_kw) send_activate_kw.update(**activate_kw)
self.activate(**send_activate_kw).SMSTool_afterSend( self.activate(**send_activate_kw).SMSTool_afterSend(
message_id_list, message_id,
document_relative_url=document_relative_url, document_relative_url=document_relative_url,
gateway_relative_url=gateway.getRelativeUrl(),**kw) gateway_relative_url=gateway.getRelativeUrl())
security.declareProtected(ManagePortal, 'getMessageStatus') security.declareProtected(ManagePortal, 'getMessageStatus')
def getMessageStatus(self,message_id, gateway_reference='default'): def getMessageStatus(self,message_id, gateway_reference='default'):
gateway = self.find(gateway_reference) gateway = self._findGateway(gateway_reference)
return gateway.getMessageStatus(message_id) return gateway.getMessageStatus(message_id)
security.declarePublic('isSendByTitleAllowed') security.declarePublic('isSendByTitleAllowed')
def isSendByTitleAllowed(self, gateway_reference='default'): def isSendByTitleAllowed(self, gateway_reference='default'):
"""Define the support or not to use the title of the telephone instead of """Define the support or not to use the title of the telephone instead of
the number when send a message.""" the number when send a message."""
gateway = self.find(gateway_reference) gateway = self._findGateway(gateway_reference)
return gateway.isTitleMode() return gateway.isTitleMode()
security.declarePublic('find') def _findGateway(self, gateway_reference='default'):
def find(self,gateway_reference='default'): """Search the gateway by its reference"""
"""Search the gateway by his reference"""
result = self.searchFolder(reference=gateway_reference) result = self.getPortalObject().portal_catalog.unrestrictedSearchResults(
if len(result) > 0: parent_uid=self.getUid(),
return result[0].getObject() reference=gateway_reference)
else: if result:
raise ValueError, "Impossible to find gateway with reference %s" % gateway_reference result, = result # ensure only one gateway with this reference
return result.getObject()
raise ValueError("Impossible to find gateway with reference %s" % gateway_reference)
...@@ -29,25 +29,33 @@ ...@@ -29,25 +29,33 @@
from zope.interface import Interface from zope.interface import Interface
class ISmsGateway(Interface): class ISmsSendingGateway(Interface):
"""SMS Gateway allow sending Short Messages to phones.
"""
def send(text, recipient, def send(text, recipient, sender):
sender=None, sender_title=None,
message_type="text", test=False, **kw):
"""Send a message. """Send a message.
TODO: write * text: the message as an utf-8 encoded string
* recipient: relative URL of recipient person or organisation. Recipient must have a defaut mobile phone
* sender: relative URL of sender person or organisation.
TODO: is getAllowedMessageType part of this API ? On most implementations, returns a message-id that can be later passed to
shouldn't we rely on content_type ? ( text/plain -> SMS, text/html -> MMS ? ) getMessageStatus to check the status of the message.
""" """
def receive(REQUEST):
"""Public handler to push notification from the gateway"""
def getAllowedMessageType():
"""List of all allowed message type when sending a message."""
def getMessageStatus(message_id): def getMessageStatus(message_id):
"""Retrieve the status of a message """Retrieve the status of a message
Should return x in ['sent', 'delivered', 'queued', 'failed']""" Should return x in ['sent', 'delivered', 'queued', 'failed']"""
class ISmsReceivingGateway(Interface):
"""Gateway to subscribe to events fired when Short Messages are send to SMS interface.
"""
def receive(REQUEST):
"""Public handler to push notifications from the gateway
REQUEST parameters are service provider dependent.
"""
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import unittest
import os
from zope.interface.verify import verifyObject
from DateTime import DateTime
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
class ShortMessageTestCase(ERP5TypeTestCase):
def getBusinessTemplateList(self):
return ('erp5_full_text_mroonga_catalog',
'erp5_core_proxy_field_legacy',
'erp5_base',
'erp5_crm',
'erp5_short_message'
)
class TestShortMessageGateway(ShortMessageTestCase):
def _verifyGatewayPortalType(self, portal_type):
import Products.ERP5Type.interfaces
gateway = self.portal.portal_sms.newContent(portal_type=portal_type)
verifyObject(Products.ERP5Type.interfaces.ISmsSendingGateway, gateway)
verifyObject(Products.ERP5Type.interfaces.ISmsReceivingGateway, gateway)
def test_EssendexGateway(self):
self._verifyGatewayPortalType('Essendex Gateway')
def test_MobytGateway(self):
self._verifyGatewayPortalType('Mobyt Gateway')
def test_DummyGateway(self):
self._verifyGatewayPortalType('Dummy Gateway')
class TestShortMessageSending(ShortMessageTestCase):
def beforeTearDown(self):
self.abort()
self.tic()
for module in (
self.portal.portal_sms,
self.portal.person_module,
self.portal.event_module ):
module.manage_delObjects(list(module.objectIds()))
self.tic()
def test_ShortMessage_start(self):
gateway = self.portal.portal_sms.newContent(
reference='default',
portal_type='Dummy Gateway')
self.tic()
sender = self.portal.person_module.newContent(
portal_type='Person',
default_mobile_telephone_telephone_number='1234')
recipient = self.portal.person_module.newContent(
portal_type='Person',
default_mobile_telephone_telephone_number='5678')
short_message = self.portal.event_module.newContent(
portal_type="Short Message",
source_value=sender,
destination_value=recipient,
text_content='Hello')
short_message.start()
self.tic()
# sending message should have updated the document with message id and gateway
self.assertTrue(short_message.getDestinationReference())
self.assertEqual(gateway, short_message.getGatewayValue())
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestShortMessageGateway))
suite.addTest(unittest.makeSuite(TestShortMessageSending))
return suite
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