comparison src/plugins/plugin_xep_0050.py @ 1110:36c1bbb8ca24

plugin XEP-0050: notes are now managed: - a note without payload in a completed command appear in a dialog. If there is a unique note, it's level is used, else info dialog is used with merged notes - if there is a data form payload, notes are added to form's instructions
author Goffi <goffi@goffi.org>
date Wed, 20 Aug 2014 21:22:06 +0200
parents c0ef97002ef4
children 069ad98b360d
comparison
equal deleted inserted replaced
1109:0a448c947038 1110:36c1bbb8ca24
240 240
241 options = [(item.nodeIdentifier, item.name) for item in items] 241 options = [(item.nodeIdentifier, item.name) for item in items]
242 form_ui.addList("node", options) 242 form_ui.addList("node", options)
243 return form_ui 243 return form_ui
244 244
245 def _getDataLvl(self, type_):
246 """Return the constant corresponding to <note/> type attribute value
247
248 @param type_: note type (see XEP-0050 ยง4.3)
249 @return: a C.XMLUI_DATA_LVL_* constant
250 """
251 if type_ == 'error':
252 return C.XMLUI_DATA_LVL_ERROR
253 elif type_ == 'warn':
254 return C.XMLUI_DATA_LVL_WARNING
255 else:
256 if type_ != 'info':
257 log.warning(_("Invalid note type [%s], using info") % type_)
258 return C.XMLUI_DATA_LVL_INFO
259
260 def _mergeNotes(self, notes):
261 """Merge notes with level prefix (e.g. "ERROR: the message")
262
263 @param notes (list): list of tuple (level, message)
264 @return: list of messages
265 """
266 lvl_map = {C.XMLUI_DATA_LVL_INFO: '',
267 C.XMLUI_DATA_LVL_WARNING: "%s: " % _("WARNING"),
268 C.XMLUI_DATA_LVL_ERROR: "%s: " % _("ERROR")
269 }
270 return [u"%s%s" % (lvl_map[lvl], msg) for lvl, msg in notes]
271
245 def _commandsAnswer2XMLUI(self, iq_elt, session_id, session_data): 272 def _commandsAnswer2XMLUI(self, iq_elt, session_id, session_data):
246 """ 273 """
247 Convert command answer to an ui for frontend 274 Convert command answer to an ui for frontend
248 @param iq_elt: command result 275 @param iq_elt: command result
249 @param session_id: id of the session used with the frontend 276 @param session_id: id of the session used with the frontend
260 else: 287 else:
261 return None 288 return None
262 remote_session_id = command_elt.getAttribute('sessionid') 289 remote_session_id = command_elt.getAttribute('sessionid')
263 if remote_session_id: 290 if remote_session_id:
264 session_data['remote_id'] = remote_session_id 291 session_data['remote_id'] = remote_session_id
265 data_elt = command_elt.elements(data_form.NS_X_DATA, 'x').next() 292 notes = []
293 for note_elt in command_elt.elements(NS_COMMANDS, 'note'):
294 notes.append((self._getDataLvl(note_elt.getAttribute('type', 'info')),
295 unicode(note_elt)))
296 try:
297 data_elt = command_elt.elements(data_form.NS_X_DATA, 'x').next()
298 except StopIteration:
299 if status != XEP_0050.STATUS.COMPLETED:
300 log.warning(_("No known payload found in ad-hoc command result, aborting"))
301 del self.requesting[session_id]
302 return xml_tools.XMLUI(C.XMLUI_DIALOG,
303 dialog_opt = {C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE,
304 C.XMLUI_DATA_MESS: _("No payload found"),
305 C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_ERROR,
306 }
307 )
308 if not notes:
309 # the status is completed, and we have no note to show
310 return None
311
312 # if we have only one note, we show a dialog with the level of the note
313 # if we have more, we show a dialog with "info" level, and all notes merged
314 dlg_level = notes[0][0] if len(notes) == 1 else C.XMLUI_DATA_LVL_INFO
315 return xml_tools.XMLUI(
316 C.XMLUI_DIALOG,
317 dialog_opt = {C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE,
318 C.XMLUI_DATA_MESS: u'\n'.join(self._mergeNotes(notes)),
319 C.XMLUI_DATA_LVL: dlg_level,
320 },
321 session_id = session_id
322 )
323
266 if session_id is None: 324 if session_id is None:
267 return xml_tools.dataFormResult2XMLUI(data_elt) 325 return xml_tools.dataFormResult2XMLUI(data_elt)
268 form = data_form.Form.fromElement(data_elt) 326 form = data_form.Form.fromElement(data_elt)
269 return xml_tools.dataForm2XMLUI(form, self.__requesting_id, session_id=session_id) 327 # we add any present note to the instructions
328 form.instructions.extend(self._mergeNotes(notes))
329 return xml_tools.dataForm2XMLUI(form, self.__requesting_id, session_id=session_id)
270 330
271 def _requestingEntity(self, data, profile): 331 def _requestingEntity(self, data, profile):
272 """ 332 """
273 request and entity and create XMLUI accordingly 333 request and entity and create XMLUI accordingly
274 @param data: data returned by previous XMLUI (first one must come from self._commandsMenu) 334 @param data: data returned by previous XMLUI (first one must come from self._commandsMenu)
300 # TODO: send error dialog 360 # TODO: send error dialog
301 return defer.succeed({}) 361 return defer.succeed({})
302 session_id = data["session_id"] 362 session_id = data["session_id"]
303 entity = session_data['jid'] 363 entity = session_data['jid']
304 try: 364 try:
305 node = session_data['node'] 365 session_data['node']
306 # node has already been received 366 # node has already been received
307 except KeyError: 367 except KeyError:
308 # it's the first time we know the node, we save it in session data 368 # it's the first time we know the node, we save it in session data
309 node = session_data['node'] = data[xml_tools.SAT_FORM_PREFIX+'node'] 369 session_data['node'] = data[xml_tools.SAT_FORM_PREFIX+'node']
310 370
311 client = self.host.getClient(profile) 371 client = self.host.getClient(profile)
312 372
313 # we request execute node's command 373 # we request execute node's command
314 iq_elt = compat.IQ(client.xmlstream, 'set') 374 iq_elt = compat.IQ(client.xmlstream, 'set')
400 d.addCallback(self._items2XMLUI) 460 d.addCallback(self._items2XMLUI)
401 return d 461 return d
402 462
403 def addAdHocCommand(self, callback, label, node="", features = None, timeout = 600, allowed_jids = None, allowed_groups = None, 463 def addAdHocCommand(self, callback, label, node="", features = None, timeout = 600, allowed_jids = None, allowed_groups = None,
404 allowed_magics = None, forbidden_jids = None, forbidden_groups = None, profile_key=C.PROF_KEY_NONE): 464 allowed_magics = None, forbidden_jids = None, forbidden_groups = None, profile_key=C.PROF_KEY_NONE):
405 """ 465 """Add an ad-hoc command for the current profile
406
407 Add an ad-hoc command for the current profile
408 466
409 @param callback: method associated with this ad-hoc command which return the payload data (see AdHocCommand._sendAnswer), can return a deferred 467 @param callback: method associated with this ad-hoc command which return the payload data (see AdHocCommand._sendAnswer), can return a deferred
410 @param label: label associated with this command on the main menu 468 @param label: label associated with this command on the main menu
411 @param node: disco item node associated with this command. None or "" to use autogenerated node 469 @param node: disco item node associated with this command. None or "" to use autogenerated node
412 @param features: features associated with the payload (list of strings), usualy data form 470 @param features: features associated with the payload (list of strings), usualy data form