Philipp Hörist pushed to branch master at gajim / python-nbxmpp
Commits:
-
30f65e21
by Philipp Hörist at 2019-08-05T08:09:30Z
-
d1e511bf
by Philipp Hörist at 2019-08-05T08:58:16Z
-
d33c50ad
by Philipp Hörist at 2019-08-05T09:01:43Z
5 changed files:
- nbxmpp/protocol.py
- nbxmpp/simplexml.py
- nbxmpp/structs.py
- nbxmpp/util.py
- + test/unit/test_error_parsing.py
Changes:
| ... | ... | @@ -1084,11 +1084,27 @@ class Protocol(Node): |
| 1084 | 1084 |
of the error (otherwise)
|
| 1085 | 1085 |
"""
|
| 1086 | 1086 |
errtag = self.getTag('error')
|
| 1087 |
- if errtag:
|
|
| 1088 |
- for tag in errtag.getChildren():
|
|
| 1089 |
- if tag.getName() != 'text':
|
|
| 1090 |
- return tag.getName()
|
|
| 1091 |
- return errtag.getData()
|
|
| 1087 |
+ if errtag is None:
|
|
| 1088 |
+ return
|
|
| 1089 |
+ for tag in errtag.getChildren():
|
|
| 1090 |
+ if tag.getName() != 'text' and tag.getNamespace() == NS_STANZAS:
|
|
| 1091 |
+ return tag.getName()
|
|
| 1092 |
+ |
|
| 1093 |
+ def getAppError(self):
|
|
| 1094 |
+ errtag = self.getTag('error')
|
|
| 1095 |
+ if errtag is None:
|
|
| 1096 |
+ return
|
|
| 1097 |
+ for tag in errtag.getChildren():
|
|
| 1098 |
+ if tag.getName() != 'text' and tag.getNamespace() != NS_STANZAS:
|
|
| 1099 |
+ return tag.getName()
|
|
| 1100 |
+ |
|
| 1101 |
+ def getAppErrorNamespace(self):
|
|
| 1102 |
+ errtag = self.getTag('error')
|
|
| 1103 |
+ if errtag is None:
|
|
| 1104 |
+ return
|
|
| 1105 |
+ for tag in errtag.getChildren():
|
|
| 1106 |
+ if tag.getName() != 'text' and tag.getNamespace() != NS_STANZAS:
|
|
| 1107 |
+ return tag.getNamespace()
|
|
| 1092 | 1108 |
|
| 1093 | 1109 |
def getErrorMsg(self):
|
| 1094 | 1110 |
"""
|
| ... | ... | @@ -431,6 +431,14 @@ class Node: |
| 431 | 431 |
except Exception:
|
| 432 | 432 |
self.addChild(tag, attrs, payload = [str(val)])
|
| 433 | 433 |
|
| 434 |
+ def getXmlLang(self):
|
|
| 435 |
+ lang = self.attrs.get('xml:lang')
|
|
| 436 |
+ if lang is not None:
|
|
| 437 |
+ return lang
|
|
| 438 |
+ |
|
| 439 |
+ if self.parent is not None:
|
|
| 440 |
+ return self.parent.getXmlLang()
|
|
| 441 |
+ |
|
| 434 | 442 |
def has_attr(self, key):
|
| 435 | 443 |
"""
|
| 436 | 444 |
Check if node have attribute "key"
|
| ... | ... | @@ -309,11 +309,52 @@ class OMEMOBundle(namedtuple('OMEMOBundle', 'spk spk_signature ik otpks')): |
| 309 | 309 |
return random.SystemRandom().choice(self.otpks)
|
| 310 | 310 |
|
| 311 | 311 |
|
| 312 |
-class CommonError(namedtuple('CommonError', 'type message jid')):
|
|
| 312 |
+class CommonError:
|
|
| 313 |
+ def __init__(self, stanza):
|
|
| 314 |
+ self._error_node = stanza.getTag('error')
|
|
| 315 |
+ self.condition = stanza.getError()
|
|
| 316 |
+ self.app_condition = stanza.getAppError()
|
|
| 317 |
+ self.type = stanza.getErrorType()
|
|
| 318 |
+ self.jid = stanza.getFrom()
|
|
| 319 |
+ self.id = stanza.getID()
|
|
| 320 |
+ self._text = {}
|
|
| 321 |
+ |
|
| 322 |
+ error = stanza.getTag('error')
|
|
| 323 |
+ if error is not None:
|
|
| 324 |
+ text_elements = error.getTags('text', namespace=NS_STANZAS)
|
|
| 325 |
+ for element in text_elements:
|
|
| 326 |
+ lang = element.getXmlLang()
|
|
| 327 |
+ text = element.getData()
|
|
| 328 |
+ self._text[lang] = text
|
|
| 329 |
+ |
|
| 330 |
+ def get_text(self, pref_lang=None):
|
|
| 331 |
+ if pref_lang is not None:
|
|
| 332 |
+ text = self._text.get(pref_lang)
|
|
| 333 |
+ if text is not None:
|
|
| 334 |
+ return text
|
|
| 335 |
+ |
|
| 336 |
+ if self._text:
|
|
| 337 |
+ text = self._text.get('en')
|
|
| 338 |
+ if text is not None:
|
|
| 339 |
+ return text
|
|
| 340 |
+ |
|
| 341 |
+ text = self._text.get(None)
|
|
| 342 |
+ if text is not None:
|
|
| 343 |
+ return text
|
|
| 344 |
+ return self._text.popitem()[1]
|
|
| 345 |
+ return ''
|
|
| 346 |
+ |
|
| 347 |
+ def set_text(self, lang, text):
|
|
| 348 |
+ self._text[lang] = text
|
|
| 349 |
+ |
|
| 313 | 350 |
def __str__(self):
|
| 314 |
- if self.message is not None:
|
|
| 315 |
- return 'Error from %s %s: %s' % (self.jid, self.type, self.message)
|
|
| 316 |
- return 'Error from %s: %s' % (self.jid, self.type)
|
|
| 351 |
+ condition = self.condition
|
|
| 352 |
+ if self.app_condition is not None:
|
|
| 353 |
+ condition = '%s (%s)' % (self.condition, self.app_condition)
|
|
| 354 |
+ text = self.get_text('en') or ''
|
|
| 355 |
+ if text:
|
|
| 356 |
+ text = ' - %s' % text
|
|
| 357 |
+ return 'Error from %s: %s%s' % (self.jid, condition, text)
|
|
| 317 | 358 |
|
| 318 | 359 |
|
| 319 | 360 |
class TuneData(namedtuple('TuneData', 'artist length rating source title track uri')):
|
| ... | ... | @@ -138,14 +138,19 @@ def to_xs_boolean(value): |
| 138 | 138 |
'Cant convert %s to xs:boolean' % value)
|
| 139 | 139 |
|
| 140 | 140 |
|
| 141 |
-def raise_error(log_method, stanza, type_=None, message=None):
|
|
| 142 |
- if message is not None:
|
|
| 143 |
- message = str(message)
|
|
| 144 |
- if type_ is None:
|
|
| 145 |
- type_ = stanza.getError()
|
|
| 146 |
- message = stanza.getErrorMsg()
|
|
| 147 |
- jid = stanza.getFrom()
|
|
| 148 |
- error = CommonError(type_, message, jid)
|
|
| 141 |
+error_classes = {}
|
|
| 142 |
+ |
|
| 143 |
+def error_factory(stanza):
|
|
| 144 |
+ app_namespace = stanza.getAppErrorNamespace()
|
|
| 145 |
+ return error_classes.get(app_namespace, CommonError)(stanza)
|
|
| 146 |
+ |
|
| 147 |
+ |
|
| 148 |
+def raise_error(log_method, stanza, condition=None, text=None):
|
|
| 149 |
+ error = error_factory(stanza)
|
|
| 150 |
+ if text is not None:
|
|
| 151 |
+ error.set_text('en', str(text))
|
|
| 152 |
+ if condition is not None:
|
|
| 153 |
+ error.condition = str(condition)
|
|
| 149 | 154 |
log_method(error)
|
| 150 | 155 |
if log_method.__name__ in ('warning', 'error'):
|
| 151 | 156 |
log_method(stanza)
|
| 1 |
+import unittest
|
|
| 2 |
+ |
|
| 3 |
+from nbxmpp.protocol import Iq
|
|
| 4 |
+from nbxmpp.util import error_factory
|
|
| 5 |
+ |
|
| 6 |
+ |
|
| 7 |
+class TestErrorParsing(unittest.TestCase):
|
|
| 8 |
+ |
|
| 9 |
+ def test_error_parsing(self):
|
|
| 10 |
+ stanza = '''
|
|
| 11 |
+ <iq from='upload.montague.tld'
|
|
| 12 |
+ id='step_03'
|
|
| 13 |
+ to='romeo@montague.tld/garden'
|
|
| 14 |
+ type='error'>
|
|
| 15 |
+ <error type='modify'>
|
|
| 16 |
+ <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' />
|
|
| 17 |
+ <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File too large. The maximum file size is 20000 bytes</text>
|
|
| 18 |
+ <text xml:lang='de' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File zu groß. Erlaubt sind 20000 bytes</text>
|
|
| 19 |
+ <file-too-large xmlns='urn:xmpp:http:upload:0'>
|
|
| 20 |
+ <max-file-size>20000</max-file-size>
|
|
| 21 |
+ </file-too-large>
|
|
| 22 |
+ </error>
|
|
| 23 |
+ </iq>'''
|
|
| 24 |
+ |
|
| 25 |
+ error = error_factory(Iq(node=stanza))
|
|
| 26 |
+ self.assertEqual(error.condition, 'not-acceptable')
|
|
| 27 |
+ self.assertEqual(error.app_condition, 'file-too-large')
|
|
| 28 |
+ self.assertEqual(error.get_text(), 'File too large. The maximum file size is 20000 bytes')
|
|
| 29 |
+ self.assertEqual(error.get_text('de'), 'File zu groß. Erlaubt sind 20000 bytes')
|
|
| 30 |
+ self.assertEqual(error.type, 'modify')
|
|
| 31 |
+ self.assertEqual(error.id, 'step_03')
|
|
| 32 |
+ self.assertEqual(error.jid, 'upload.montague.tld')
|