0001-sms-remove-all-but-passerelle-provider-39088.patch
tests/admin_pages/test_workflow.py | ||
---|---|---|
486 | 486 |
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd: |
487 | 487 |
pub.site_options.write(fd) |
488 | 488 | |
489 |
pub.cfg['sms'] = {'mode': 'foobar'}
|
|
489 |
pub.cfg['sms'] = {'passerelle_url': 'xx', 'sender': 'xx'}
|
|
490 | 490 |
pub.write_cfg() |
491 | 491 |
workflow.criticality_levels = [WorkflowCriticalityLevel(name='green')] |
492 | 492 |
workflow.store() |
... | ... | |
814 | 814 |
workflow.add_status(name='baz') |
815 | 815 |
workflow.store() |
816 | 816 | |
817 |
pub.cfg['sms'] = {'mode': 'foobar'}
|
|
817 |
pub.cfg['sms'] = {'passerelle_url': 'xx', 'sender': 'xx'}
|
|
818 | 818 |
pub.write_cfg() |
819 | 819 | |
820 | 820 |
app = login(get_app(pub)) |
tests/backoffice_pages/test_all.py | ||
---|---|---|
3419 | 3419 |
user_view_resp = app.get('/backoffice/management/users/%s/' % user.id) |
3420 | 3420 |
assert 'Send tracking code' in user_view_resp.text |
3421 | 3421 | |
3422 |
pub.cfg['sms'] = {'mode': 'none'}
|
|
3422 |
pub.cfg['sms'] = {} |
|
3423 | 3423 |
pub.write_cfg() |
3424 | 3424 |
resp = user_view_resp.click('Send tracking code') |
3425 | 3425 |
assert not 'sms' in resp.form.fields |
... | ... | |
3431 | 3431 |
assert emails.get('Tracking Code reminder')['email_rcpt'] == [user.email] |
3432 | 3432 |
assert form_class.get(number31.id).tracking_code in emails.get('Tracking Code reminder')['payload'] |
3433 | 3433 | |
3434 |
pub.cfg['sms'] = {'mode': 'xx'}
|
|
3434 |
pub.cfg['sms'] = {'passerelle_url': 'xx', 'sender': 'xx'}
|
|
3435 | 3435 |
pub.write_cfg() |
3436 | 3436 |
resp = user_view_resp.click('Send tracking code', index=0) |
3437 | 3437 |
resp.form['method'].value = 'SMS' |
tests/test_workflows.py | ||
---|---|---|
2341 | 2341 | |
2342 | 2342 | |
2343 | 2343 |
def test_sms(pub, sms_mocking): |
2344 |
pub.cfg['sms'] = {'mode': 'xxx'}
|
|
2344 |
pub.cfg['sms'] = {'sender': 'xxx', 'passerelle_url': 'http://passerelle.invalid/'}
|
|
2345 | 2345 |
formdef = FormDef() |
2346 | 2346 |
formdef.name = 'baz' |
2347 | 2347 |
formdef.fields = [] |
tests/utilities.py | ||
---|---|---|
398 | 398 |
return len(self.requests) |
399 | 399 | |
400 | 400 | |
401 |
class SMSMocking(wcs.qommon.sms.MobytSMS): |
|
402 |
def get_sms_class(self, mode): |
|
403 |
if mode == 'none': |
|
404 |
return None |
|
405 |
return self |
|
406 | ||
407 |
def send(self, sender, destinations, text, quality=None): |
|
401 |
class SMSMocking(wcs.qommon.sms.PasserelleSMS): |
|
402 |
def get_sms_class(self): |
|
403 |
sms_cfg = get_publisher().cfg.get('sms', {}) |
|
404 |
if sms_cfg.get('sender') and sms_cfg.get('passerelle_url'): |
|
405 |
return self |
|
406 |
return None |
|
407 | ||
408 |
def send(self, sender, destinations, text): |
|
408 | 409 |
self.sms.append({'sender': sender, 'destinations': destinations, 'text': text}) |
409 | 410 | |
410 |
def get_sms_left(self, type='standard'): |
|
411 |
raise NotImplementedError |
|
412 | ||
413 |
def get_money_left(self): |
|
414 |
raise NotImplementedError |
|
415 | ||
416 | 411 |
def __enter__(self): |
417 | 412 |
self.sms = [] |
418 | 413 |
self.wcs_get_sms_class = wcs.qommon.sms.SMS.get_sms_class |
wcs/admin/settings.py | ||
---|---|---|
425 | 425 |
'template', 'emails', 'debug_options', 'language', |
426 | 426 |
('import', 'p_import'), 'export', 'identification', 'sitename', |
427 | 427 |
'sms', 'certificates', 'texts', 'install_theme', |
428 |
'session', 'download_theme', 'smstest', 'postgresql',
|
|
428 |
'session', 'download_theme', 'postgresql', |
|
429 | 429 |
('admin-permissions', 'admin_permissions'), 'geolocation', |
430 | 430 |
'theme_preview', 'filetypes', |
431 | 431 |
('user-template', 'user_template'), |
... | ... | |
1101 | 1101 |
r = TemplateIO(html=True) |
1102 | 1102 |
r += htmltext('<h2>%s</h2>') % _('SMS Options') |
1103 | 1103 |
sms_cfg = get_cfg('sms', {}) |
1104 |
mode = sms_cfg.get('mode', 'none') |
|
1105 |
sms = SMS.get_sms_class(mode) |
|
1106 |
if sms: |
|
1107 |
r += htmltext('<ul>') |
|
1108 |
try: |
|
1109 |
try: |
|
1110 |
r += htmltext('<li>%s %s</li>') % (_('SMS Credit:'), sms.get_money_left()) |
|
1111 |
except NotImplementedError: |
|
1112 |
pass |
|
1113 |
try: |
|
1114 |
r += htmltext('<li>%s %s</li>') % (_('SMS Left:'), sms.get_sms_left()) |
|
1115 |
except NotImplementedError: |
|
1116 |
pass |
|
1117 |
except errors.SMSError: |
|
1118 |
r += htmltext("<p>%s</li>") % _("Connection with SMS provider failed") |
|
1119 |
r += htmltext('</ul>') |
|
1120 | ||
1121 | 1104 |
form = Form(enctype='multipart/form-data') |
1122 |
form.add(SingleSelectWidget, 'mode', title = _('SMS Mode'), |
|
1123 |
value = mode, |
|
1124 |
options = [(str('none'), _('No support'), str('none'))]+ |
|
1125 |
[(str(k), _(SMS.providers.get(k)[0]), str(k)) for k in SMS.providers.keys()]) |
|
1126 | ||
1105 |
form.add(StringWidget, 'sender', title=_('Sender (number of name)'), |
|
1106 |
value=sms_cfg.get('sender')) |
|
1107 |
form.add(StringWidget, 'passerelle_url', title=_('URL'), |
|
1108 |
value=sms_cfg.get('passerelle_url')) |
|
1127 | 1109 |
form.add_submit('submit', _('Submit')) |
1128 | 1110 |
form.add_submit('cancel', _('Cancel')) |
1129 | 1111 | |
1130 | 1112 |
if form.get_widget('cancel').parse(): |
1131 | 1113 |
return redirect('.') |
1132 | 1114 | |
1133 |
if sms: |
|
1134 |
for widget, name, title in sms.parameters: |
|
1135 |
form.add(widget, name, title=_(title), |
|
1136 |
value=sms_cfg.get(name, ''), |
|
1137 |
required=True) |
|
1138 |
if form.get_submit() and not form.has_errors(): |
|
1139 |
cfg_submit(form, 'sms', ['mode'] + [x[1] for x in sms.parameters]) |
|
1140 |
if mode != form.get_widget('mode').parse(): |
|
1141 |
return redirect('sms') |
|
1142 |
else: |
|
1143 |
return redirect('.') |
|
1144 |
elif mode != form.get_widget('mode').parse(): |
|
1145 |
cfg_submit(form, 'sms', ['mode',]) |
|
1146 |
return redirect('sms') |
|
1147 |
else: |
|
1148 |
if form.get_submit() and form.get_widget('mode').parse() == str('none'): |
|
1149 |
return redirect('.') |
|
1150 | ||
1151 | 1115 |
if form.get_submit() and not form.has_errors(): |
1152 |
cfg_submit(form, 'sms', ['mode',]) |
|
1153 |
return redirect('sms') |
|
1154 |
else: |
|
1155 |
r += form.render() |
|
1156 | ||
1157 |
if mode != 'none': |
|
1158 |
r += htmltext('<p><a href="smstest">%s</a></p>') % _('SMS Test') |
|
1159 | ||
1160 |
return r.getvalue() |
|
1161 | ||
1162 | ||
1163 |
def smstest(self): |
|
1164 |
form = Form(enctype='multipart/form-data', action='smstest') |
|
1165 |
form.add(StringWidget, 'sender', title=_('Sender'), required=True) |
|
1166 |
form.add(StringWidget, 'destinations', title=_('Destinations'), required=True) |
|
1167 |
form.add(StringWidget, 'text', title=_('Text'), required=True) |
|
1168 |
form.add_submit('submit', _('Submit')) |
|
1169 |
form.add_submit('cancel', _('Cancel')) |
|
1170 | ||
1171 |
if form.get_widget('cancel').parse(): |
|
1172 |
return redirect('sms') |
|
1116 |
cfg_submit(form, 'sms', ['sender', 'passerelle_url']) |
|
1117 |
return redirect('.') |
|
1173 | 1118 | |
1174 |
get_response().breadcrumb.append(('sms', _('SMS'))) |
|
1175 |
get_response().breadcrumb.append(('smstest', _('SMS Test'))) |
|
1176 |
html_top('settings', title = _('SMS Test')) |
|
1177 |
r = TemplateIO(html=True) |
|
1178 |
r += htmltext('<h2>%s</h2>') % _('SMS Test') |
|
1179 | 1119 |
r += form.render() |
1180 | ||
1181 |
if form.get_submit() and not form.has_errors(): |
|
1182 |
sms_cfg = get_cfg('sms', {}) |
|
1183 |
mode = sms_cfg.get('mode', 'none') |
|
1184 |
sms = SMS.get_sms_class(mode) |
|
1185 | ||
1186 |
sender = str(form.get_widget('sender').parse()) |
|
1187 |
destinations = str(form.get_widget('destinations').parse()).split(str(',')) |
|
1188 |
text = str(form.get_widget('text').parse()) |
|
1189 | ||
1190 |
try: |
|
1191 |
sms.send(sender, destinations, text) |
|
1192 |
except Exception as e: |
|
1193 |
r += htmltext('<pre>') |
|
1194 |
r += repr(e) |
|
1195 |
r += htmltext('</pre>') |
|
1196 |
else: |
|
1197 |
r += htmltext('<p>') |
|
1198 |
r += _('The SMS has been sent successfully.') |
|
1199 |
r += htmltext('</p>') |
|
1200 | ||
1201 | 1120 |
return r.getvalue() |
1202 | 1121 | |
1203 | 1122 |
def postgresql(self): |
wcs/backoffice/management.py | ||
---|---|---|
146 | 146 |
value=submitter_email) |
147 | 147 |
sms_class = None |
148 | 148 |
if get_publisher().use_sms_feature: |
149 |
sms_cfg = get_cfg('sms', {}) |
|
150 |
mode = sms_cfg.get('mode', 'none') |
|
151 |
sms_class = sms.SMS.get_sms_class(mode) |
|
149 |
sms_class = sms.SMS.get_sms_class() |
|
152 | 150 |
if sms_class: |
153 | 151 |
form.add(StringWidget, 'sms', title=_('SMS Number'), required=False) |
154 | 152 |
form.add(RadiobuttonsWidget, 'method', |
... | ... | |
180 | 178 |
if sms_class and form.get_widget('method').parse() == 'sms': |
181 | 179 |
# send sms |
182 | 180 |
sitename = get_cfg('misc', {}).get('sitename') or 'w.c.s.' |
181 |
sms_cfg = get_cfg('sms', {}) |
|
183 | 182 |
sender = sms_cfg.get('sender', sitename)[:11] |
184 | 183 |
message = Template(message).render(data) |
185 | 184 |
try: |
wcs/qommon/sms.py | ||
---|---|---|
24 | 24 |
from wcs.wscalls import call_webservice |
25 | 25 | |
26 | 26 | |
27 |
class MobytSMS(object): |
|
28 |
"""This class allows to send a SMS using Mobyt provider""" |
|
29 |
parameters = [ |
|
30 |
(StringWidget, 'sender', N_('Sender (number or name)')), |
|
31 |
(StringWidget, 'mobyt_username', N_('Username')), |
|
32 |
(PasswordWidget, 'mobyt_password', N_('Password')), |
|
33 |
] |
|
34 | ||
35 |
def __init__(self): |
|
36 |
sms_cfg = get_cfg('sms', {}) |
|
37 |
self.user = sms_cfg.get('mobyt_username', '') |
|
38 |
self.password = sms_cfg.get('mobyt_password', '') |
|
39 | ||
40 |
def send(self, sender, destinations, text, quality='l'): |
|
41 |
""" Send a sms using Mobyt provider""" |
|
42 |
rcpt = "" |
|
43 |
for dest in destinations: |
|
44 |
rcpt += "%s," % dest |
|
45 |
rcpt = rcpt[:len(rcpt) - 1] |
|
46 |
params = urllib.urlencode({ |
|
47 |
'user': self.user, |
|
48 |
'pass': self.password, |
|
49 |
'rcpt': rcpt, |
|
50 |
'data': text, |
|
51 |
'sender': sender, |
|
52 |
'qty': quality |
|
53 |
}) |
|
54 |
try: |
|
55 |
r = misc.urlopen("http://multilevel.mobyt.fr/sms/batch.php", params) |
|
56 |
except misc.ConnectionError as e: |
|
57 |
raise errors.SMSError("failed to POST to mobyt.fr (%s)" % e) |
|
58 |
answer = r.read() |
|
59 |
r.close() |
|
60 |
if answer[:2] == "KO": |
|
61 |
raise errors.SMSError(answer[3:]) |
|
62 | ||
63 |
def get_credit(self, type): |
|
64 |
params = urllib.urlencode({ |
|
65 |
'user': self.user, |
|
66 |
'pass': self.password, |
|
67 |
'type': type |
|
68 |
}) |
|
69 |
try: |
|
70 |
r = misc.urlopen("http://multilevel.mobyt.fr/sms/credit.php", params) |
|
71 |
except misc.ConnectionError as e: |
|
72 |
raise errors.SMSError("failed to POST to mobyt.fr (%s)" % e) |
|
73 |
answer = r.read() |
|
74 |
r.close() |
|
75 |
if answer[:2] == "KO": |
|
76 |
raise errors.SMSError(answer[3:]) |
|
77 |
else: |
|
78 |
return answer[3:] |
|
79 | ||
80 |
def get_sms_left(self, type="standard"): |
|
81 |
""" |
|
82 |
type (mobyt provider): standard, lowcost or top |
|
83 |
""" |
|
84 |
if type == "standard": |
|
85 |
return self.get_credit("l") |
|
86 |
elif type == "lowcost": |
|
87 |
return self.get_credit("ll") |
|
88 |
elif type == "top": |
|
89 |
return self.get_credit("n") |
|
90 |
else: |
|
91 |
raise errors.SMSError("%s is invalid type for provider Mobyt" % type) |
|
92 | ||
93 |
def get_money_left(self): |
|
94 |
""" return money left in euros """ |
|
95 |
return self.get_credit("credit") |
|
96 | ||
97 | ||
98 |
class OxydSMS(object): |
|
99 |
"""This class allows to send a SMS using Oxyd provider""" |
|
100 |
parameters = [ |
|
101 |
(StringWidget, 'oxyd_username', N_('Username')), |
|
102 |
(PasswordWidget, 'oxyd_password', N_('Password')), |
|
103 |
(StringWidget, 'oxyd_default_country_code', N_('Default Country Code')), |
|
104 |
] |
|
105 | ||
106 |
def __init__(self): |
|
107 |
sms_cfg = get_cfg('sms', {}) |
|
108 |
self.user = sms_cfg.get('oxyd_username', '') |
|
109 |
self.password = sms_cfg.get('oxyd_password', '') |
|
110 |
self.default_country_code = sms_cfg.get('oxyd_default_country_code') |
|
111 |
if not self.default_country_code: |
|
112 |
self.default_country_code = '33' # arbitrary |
|
113 | ||
114 |
def send(self, sender, destinations, text, quality=None): |
|
115 |
"""Send a SMS using Oxyd provider""" |
|
116 |
# unfortunately it lacks a batch API... |
|
117 |
for dest in destinations: |
|
118 |
# oxyd needs the number prefixed by the country code, this is |
|
119 |
# really unfortunate. |
|
120 |
number = ''.join(re.findall(r'\d', dest)) |
|
121 |
if dest.startswith('+'): |
|
122 |
pass # it already is fully qualified |
|
123 |
elif number.startswith('00'): |
|
124 |
# assumes 00 is international access code, remove it |
|
125 |
number = number[2:] |
|
126 |
elif number.startswith('0'): |
|
127 |
# local prefix, remove 0 and add default country code |
|
128 |
number = self.default_country_code + number[1:] |
|
129 |
params = urllib.urlencode({ |
|
130 |
'id': self.user, |
|
131 |
'pass': self.password, |
|
132 |
'num': number, |
|
133 |
'sms': text, |
|
134 |
'flash': '0' |
|
135 |
}) |
|
136 |
try: |
|
137 |
r = misc.urlopen('http://sms.oxyd.fr/send.php', params) |
|
138 |
except misc.ConnectionError as e: |
|
139 |
# XXX: add proper handling of errors |
|
140 |
raise errors.SMSError("failed to POST to oxyd.fr (%s)" % e) |
|
141 |
r.close() |
|
142 | ||
143 |
def get_sms_left(self, type='standard'): |
|
144 |
raise NotImplementedError |
|
145 | ||
146 |
def get_money_left(self): |
|
147 |
raise NotImplementedError |
|
148 | ||
149 | ||
150 |
class ChoositSMS(object): |
|
151 |
"""This class allows to send a SMS using the Choosit provider |
|
152 | ||
153 |
http://sms.choosit.com/documentation_technique.html |
|
154 |
""" |
|
155 |
parameters = [ |
|
156 |
(StringWidget, 'choosit_key', N_('Key')), |
|
157 |
(StringWidget, 'choosit_default_country_code', N_('Default Country Code')), |
|
158 |
] |
|
159 | ||
160 |
def __init__(self): |
|
161 |
sms_cfg = get_cfg('sms', {}) |
|
162 |
self.key = sms_cfg.get('choosit_key', '') |
|
163 |
self.default_country_code = sms_cfg.get('choosit_default_country_code') |
|
164 |
if not self.default_country_code: |
|
165 |
self.default_country_code = '33' # arbitrary |
|
166 | ||
167 |
def send(self, sender, destinations, text, quality=None): |
|
168 |
"""Send a SMS using the Choosit provider""" |
|
169 |
# unfortunately it lacks a batch API... |
|
170 |
for dest in destinations: |
|
171 |
# choosit needs the number prefixed by the country code, this is |
|
172 |
# really unfortunate. |
|
173 |
number = ''.join(re.findall(r'\d', dest)) |
|
174 |
if dest.startswith('+'): |
|
175 |
pass # it already is fully qualified |
|
176 |
elif number.startswith('00'): |
|
177 |
# assumes 00 is international access code, remove it |
|
178 |
number = number[2:] |
|
179 |
elif number.startswith('0'): |
|
180 |
# local prefix, remove 0 and add default country code |
|
181 |
number = self.default_country_code + number[1:] |
|
182 |
params = urllib.urlencode({ |
|
183 |
'key': self.key, |
|
184 |
'recipient': number, |
|
185 |
'content': text[:160], |
|
186 |
}) |
|
187 |
try: |
|
188 |
r = misc.urlopen('http://sms.choosit.com/webservice', params) |
|
189 |
except misc.ConnectionError as e: |
|
190 |
# XXX: add proper handling of errors |
|
191 |
raise errors.SMSError("failed to POST to choosit.com (%s)" % e) |
|
192 |
r.close() |
|
193 | ||
194 |
def get_sms_left(self, type='standard'): |
|
195 |
raise NotImplementedError |
|
196 | ||
197 |
def get_money_left(self): |
|
198 |
raise NotImplementedError |
|
199 | ||
200 | ||
201 | 27 |
class PasserelleSMS(object): |
202 |
"""This class allows to send a SMS using Passerelle |
|
203 |
""" |
|
204 |
parameters = [ |
|
205 |
(StringWidget, 'sender', N_('Sender (number or name)')), |
|
206 |
(StringWidget, 'passerelle_url', N_('URL')), |
|
207 |
] |
|
208 | ||
209 | 28 |
TIMEOUT = 10 |
210 | 29 | |
211 | 30 |
def __init__(self): |
... | ... | |
214 | 33 |
self.url = sms_cfg.get('passerelle_url', '') |
215 | 34 | |
216 | 35 |
def send(self, sender, destinations, text, quality=None): |
217 |
"""Send a SMS using the Choosit provider""" |
|
218 | 36 |
sender = sender or self.sender |
219 | 37 |
payload = { |
220 | 38 |
'from': sender, |
... | ... | |
227 | 45 |
get_logger().debug('sms %r sent using passerelle to %r, result: %r', |
228 | 46 |
text, destinations, data) |
229 | 47 | |
230 |
def get_sms_left(self, type='standard'): |
|
231 |
raise NotImplementedError |
|
232 | ||
233 |
def get_money_left(self): |
|
234 |
raise NotImplementedError |
|
235 | ||
236 | 48 | |
237 | 49 |
class SMS(object): |
238 |
providers = { |
|
239 |
'mobyt': (N_('Mobyt provider'), MobytSMS), |
|
240 |
'oxyd': (N_('Oxyd provider'), OxydSMS), |
|
241 |
'choosit': (N_('Choosit provider'), ChoositSMS), |
|
242 |
'passerelle': (N_('Passerelle provider'), PasserelleSMS), |
|
243 |
} |
|
244 | 50 | |
245 | 51 |
@classmethod |
246 |
def get_sms_class(cls, provider_id): |
|
247 |
if not provider_id: |
|
248 |
sms_cfg = get_cfg('sms', {}) |
|
249 |
provider_id = sms_cfg.get('mode', '') |
|
250 |
if provider_id in cls.providers: |
|
251 |
return cls.providers.get(provider_id)[1]() |
|
252 |
else: |
|
253 |
return None |
|
52 |
def get_sms_class(cls): |
|
53 |
sms_cfg = get_cfg('sms', {}) |
|
54 |
if sms_cfg.get('sender') and sms_cfg.get('passerelle_url'): |
|
55 |
return PasserelleSMS() |
|
56 |
return None |
wcs/workflows.py | ||
---|---|---|
2826 | 2826 | |
2827 | 2827 |
@classmethod |
2828 | 2828 |
def is_available(cls, workflow=None): |
2829 |
sms_mode = get_cfg('sms', {}).get('mode') or 'none'
|
|
2830 |
return sms_mode != 'none'
|
|
2829 |
sms_cfg = get_cfg('sms', {})
|
|
2830 |
return bool(sms_cfg.get('sender') and sms_cfg.get('passerelle_url'))
|
|
2831 | 2831 | |
2832 | 2832 |
def get_parameters(self): |
2833 | 2833 |
return ('to', 'body', 'condition') |
... | ... | |
2868 | 2868 | |
2869 | 2869 |
sms_cfg = get_cfg('sms', {}) |
2870 | 2870 |
sender = sms_cfg.get('sender', 'AuQuotidien')[:11] |
2871 |
mode = sms_cfg.get('mode', 'none') |
|
2872 | 2871 |
try: |
2873 |
sms.SMS.get_sms_class(mode).send(sender, destinations, sms_body)
|
|
2872 |
sms.SMS.get_sms_class().send(sender, destinations, sms_body) |
|
2874 | 2873 |
except errors.SMSError as e: |
2875 | 2874 |
get_logger().error(e) |
2876 | 2875 | |
2877 |
- |