From e180b84fbb6cc6e0a240aad2f3c6860fc2ecf60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Fri, 29 Jun 2012 12:42:43 +0200 Subject: [PATCH 1/2] add support for oxyd as sms provider (#1539) --- wcs/admin/settings.ptl | 61 +++++++++++----------- wcs/qommon/publisher.py | 2 +- wcs/qommon/sms.py | 130 ++++++++++++++++++++++++++++++++--------------- wcs/workflows.py | 2 +- 4 files changed, 122 insertions(+), 73 deletions(-) diff --git a/wcs/admin/settings.ptl b/wcs/admin/settings.ptl index 8415790..9fade43 100644 --- a/wcs/admin/settings.ptl +++ b/wcs/admin/settings.ptl @@ -670,13 +670,19 @@ class SettingsDirectory(QommonSettingsDirectory): html_top('settings', title = _('SMS')) '

%s

' % _('SMS Options') sms_cfg = get_cfg('sms', {}) - sms = SMS() mode = sms_cfg.get('mode', 'none') - if mode != 'none': + sms = SMS.get_sms_class(mode) + if sms: '' @@ -684,39 +690,36 @@ class SettingsDirectory(QommonSettingsDirectory): form = Form(enctype='multipart/form-data') form.add(SingleSelectWidget, 'mode', title = _('SMS Mode'), value = mode, - options = [ (str('none'), _('No support')), - (str('mobyt'), _('Mobyt provider')) ]) - - if mode == 'mobyt': - form.add(StringWidget, 'sender', title=_('Sender (number or name)'), - value = sms_cfg.get('sender', 'AuQuotidien'), - required = True) - form.add(StringWidget, 'mobyt_username', title=_('Username'), - value = sms_cfg.get('mobyt_username', ''), - required = True) - form.add(PasswordWidget, 'mobyt_password', title=_('Password'), - value = sms_cfg.get('mobyt_password', ''), - required = True) - sender = form.get_widget('sender').parse() - if sender and len(sender) > 11: - form.set_error("sender", "Too long (max : 11 characters)") - if form.get_submit() and not form.has_errors(): - cfg_submit(form, 'sms', ('mode', 'mobyt_username', 'mobyt_password', 'sender')) - if mode != form.get_widget('mode').parse(): - return redirect("sms") - elif mode != form.get_widget('mode').parse(): - cfg_submit(form, 'sms', ['mode',]) - return redirect("sms") + options = [('none', _('No support'), 'none')]+ + [(str(k), _(SMS.providers.get(k)[0]), str(k)) for k in SMS.providers.keys()]) form.add_submit('submit', _('Submit')) form.add_submit('cancel', _('Cancel')) if form.get_widget('cancel').parse(): return redirect('.') - + + if sms: + for widget, name, title in sms.parameters: + form.add(widget, name, title=_(title), + value=sms_cfg.get(name, ''), + required=True) + if form.get_submit() and not form.has_errors(): + cfg_submit(form, 'sms', ['mode'] + [x[1] for x in sms.parameters]) + if mode != form.get_widget('mode').parse(): + return redirect('sms') + else: + return redirect('.') + elif mode != form.get_widget('mode').parse(): + cfg_submit(form, 'sms', ['mode',]) + return redirect('sms') + else: + if form.get_submit() and form.get_widget('mode').parse() == str('none'): + return redirect('.') + if form.get_submit() and not form.has_errors(): cfg_submit(form, 'sms', ['mode',]) - return redirect("sms") + return redirect('sms') else: form.render() diff --git a/wcs/qommon/publisher.py b/wcs/qommon/publisher.py index cc4dd84..f34ff18 100644 --- a/wcs/qommon/publisher.py +++ b/wcs/qommon/publisher.py @@ -94,7 +94,7 @@ class QommonPublisher(Publisher): default_configuration_path = None auto_create_appdir = True missing_appdir_redirect = None - use_sms_feature = False + use_sms_feature = True app_translations = dict() def get_root_url(self): diff --git a/wcs/qommon/sms.py b/wcs/qommon/sms.py index fe49b70..3a395b3 100644 --- a/wcs/qommon/sms.py +++ b/wcs/qommon/sms.py @@ -14,29 +14,31 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, see . +import re import urllib2 import urllib - from quixote import get_publisher, redirect from qommon import errors from qommon import get_cfg +from qommon.form import StringWidget, PasswordWidget -class SMS: - """ This class allows to send a SMS using Mobyt provider """ - def __init__(self, provider = None): +class MobytSMS(): + """This class allows to send a SMS using Mobyt provider""" + parameters = [ + (StringWidget, 'sender', N_('Sender (number or name)')), + (StringWidget, 'mobyt_username', N_('Username')), + (PasswordWidget, 'mobyt_password', N_('Password')), + ] + + def __init__(self): sms_cfg = get_cfg('sms', {}) - if not provider: - self.provider = sms_cfg.get('mode', '') - self.user = None - self.password = None - if self.provider == "mobyt": - self.user = sms_cfg.get('mobyt_username', '') - self.password = sms_cfg.get('mobyt_password', '') - - def _mobyt_send(self, sender, destinations, text, quality='l'): + self.user = sms_cfg.get('mobyt_username', '') + self.password = sms_cfg.get('mobyt_password', '') + + def send(self, sender, destinations, text, quality='l'): """ Send a sms using Mobyt provider""" rcpt = "" for dest in destinations: @@ -59,7 +61,7 @@ class SMS: if answer[:2] == "KO": raise errors.SMSError(answer[3:]) - def _mobyt_credit(self, type): + def get_credit(self, type): """ """ params = urllib.urlencode({ 'user': self.user, @@ -76,41 +78,85 @@ class SMS: raise errors.SMSError(answer[3:]) else: return answer[3:] - - - def send(self, destinations, text, sender, quality=None): - """ - Send a sms - destinations : tuple with phone numbers (+YYXXXXXXXXX) - """ - if self.provider == "mobyt": - if not quality: - quality = 'l' - self._mobyt_send(sender, destinations, text, quality) - else: - raise errors.SMSError("Unknow SMS provider") def get_sms_left(self, type="standard"): """ type (mobyt provider) : standard, lowcost or top """ - if self.provider == "mobyt": - if type == "standard": - return self._mobyt_credit("l") - elif type == "lowcost": - return self._mobyt_credit("ll") - elif type == "top": - return self._mobyt_credit("n") - else: - raise errors.SMSError("%s is invalid type for provider Mobyt" % type) + if type == "standard": + return self.get_credit("l") + elif type == "lowcost": + return self.get_credit("ll") + elif type == "top": + return self.get_credit("n") else: - raise errors.SMSError("Unknow SMS provider") + raise errors.SMSError("%s is invalid type for provider Mobyt" % type) def get_money_left(self): """ return money left in euros """ - if self.provider == "mobyt": - return self._mobyt_credit("credit") + return self.get_credit("credit") + + +class OxydSMS: + """This class allows to send a SMS using Oxyd provider""" + parameters = [ + (StringWidget, 'oxyd_username', N_('Username')), + (PasswordWidget, 'oxyd_password', N_('Password')), + (StringWidget, 'oxyd_default_country_code', N_('Default Country Code')), + ] + + def __init__(self): + sms_cfg = get_cfg('sms', {}) + self.user = sms_cfg.get('oxyd_username', '') + self.password = sms_cfg.get('oxyd_password', '') + self.default_country_code = sms_cfg.get('oxyd_default_country_code') + if not self.default_country_code: + self.default_country_code = '33' # arbitrary + + def send(self, sender, destinations, text, quality=None): + """Send a SMS using Oxyd provider""" + # unfortunately it lacks a batch API... + for dest in destinations: + # oxyd needs the number prefixed by the country code, this is + # really unfortunate. + number = ''.join(re.findall('\d', dest)) + if dest.startswith('+'): + pass # it already is fully qualified + elif number.startswith('00'): + # assumes 00 is international access code, remove it + number = number[2:] + elif number.startswith('0'): + # local prefix, remove 0 and add default country code + number = self.default_country_code + number[1:] + try: + r = urllib2.urlopen('http://sms.oxyd.fr/send.php?id=%s&pass=%s&num=%s&sms=%s&flash=0' % ( + self.user, self.password, + number, + text)) + except Exception, e: + # XXX: add proper handling of errors + raise errors.SMSError('urlopen oxyd.fr failed : %s' % e) + r.close() + + def get_sms_left(self, type='standard'): + raise NotImplementedError + + def get_money_left(self): + raise NotImplementedError + + +class SMS: + providers = { + 'mobyt': (N_('Mobyt provider'), MobytSMS), + 'oxyd': (N_('Oxyd provider'), OxydSMS), + } + + def get_sms_class(cls, provider_id): + if not provider_id: + sms_cfg = get_cfg('sms', {}) + provider_id = sms_cfg.get('mode', '') + if provider_id in cls.providers: + return cls.providers.get(provider_id)[1]() else: - raise errors.SMSError("Unknow SMS provider") - - + return None + get_sms_class = classmethod(get_sms_class) diff --git a/wcs/workflows.py b/wcs/workflows.py index 3d5b592..3402e6c 100644 --- a/wcs/workflows.py +++ b/wcs/workflows.py @@ -844,7 +844,7 @@ class SendSMSWorkflowStatusItem(WorkflowStatusItem): sms_cfg = get_cfg('sms', {}) sender = sms_cfg.get('sender', 'AuQuotidien')[:11] try: - SMS().send([self.compute(x) for x in self.to], sms_body[:160], sender) + SMS.get_sms_class().send([self.compute(x) for x in self.to], sms_body[:160], sender) except errors.SMSError, e: get_logger().error(e) -- 1.7.10