# HG changeset patch # User souliane # Date 1441195370 -7200 # Node ID 593345584d2152463a726c9e8101d35cc9fe3856 # Parent 77b77f48c975537d4115ce1171e831386206312d replace ad-hoc commands "subscribe" and "unsubscribe" with a single "update" command diff -r 77b77f48c975 -r 593345584d21 salut.py --- a/salut.py Thu Jul 23 21:05:51 2015 +0200 +++ b/salut.py Wed Sep 02 14:02:50 2015 +0200 @@ -3,6 +3,7 @@ # SAT plugin for account creation (experimental) # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Jérôme Poisson (goffi@goffi.org) +# Copyright (C) 2015 Adrien Cossa (souliane@mailoo.org) # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -34,17 +35,15 @@ NS_COMMANDS = "http://jabber.org/protocol/commands" NS_SEARCH = 'jabber:iq:search' QUERY_SEARCH = "/query[@xmlns='jabber:iq:search']" -SUBSCRIBE_CMD = "/iq[@type='set']/command[@xmlns='"+NS_COMMANDS+"' and @node='subscribe']" -UNSUBSCRIBE_CMD = "/iq[@type='set']/command[@xmlns='"+NS_COMMANDS+"' and @node='unsubscribe']" -INSTRUCTIONS = _(u'This is a minimal directory for the Libervia demo (Salut à Toi project). For testing purpose only.') +UPDATE_CMD = "/iq[@type='set']/command[@xmlns='"+NS_COMMANDS+"' and @node='update']" +INSTRUCTIONS = _(u'Update your subscription to the Jabber search directory.') FORM_INSTRUCTIONS = [INSTRUCTIONS] - -SUBSCRIBE_TXT = _(u"Please give some words about you, then submit to be registered on the directory") -SUBSCRIBE_DONE = _("You are now registered on the directory") -UNSUBSCRIBE_DONE = _("You have been removed from the directory") +SUBSCRIBE_DONE = _("You registration to the directory has been updated.") +UNSUBSCRIBE_DONE = _("You have been removed from the directory.") DB_CREATE = ['PRAGMA user_version=0', 'CREATE TABLE directory (jid TEXT PRIMARY KEY, description TEXT)'] + class SalutGateway(XMPPHandler, IQHandlerMixin): implements(iwokkel.IDisco) @@ -64,14 +63,17 @@ print "Connected!" self.xmlstream.addObserver("/iq[@type='get']" + QUERY_SEARCH, self.handleFieldsRequest) self.xmlstream.addObserver("/iq[@type='set']" + QUERY_SEARCH, self.handleSearchRequest) - self.xmlstream.addObserver(SUBSCRIBE_CMD, self.onSubscribe) - self.xmlstream.addObserver(UNSUBSCRIBE_CMD, self.onUnsubscribe) + self.xmlstream.addObserver(UPDATE_CMD, self.onUpdate) self.discoHandler.setHandlerParent(self.parent) def connectionLost(self, reason): print "Disconnected!" def handleFieldsRequest(self, request): + """Respond to a fields request with the fields' list. + + @param request (domish.Element): the request to respond to + """ result = domish.Element((None, 'iq')) result['type'] = 'result' result['id'] = request['id'] @@ -83,13 +85,16 @@ formNamespace=NS_SEARCH) form.addField(data_form.Field('fixed', label=_('Enter part of description or jid to find somebody,'))) form.addField(data_form.Field('fixed', label=('let empty to have a full list of people'))) - form.addField(data_form.Field('text-single', 'jid', label=_('jid'))) + form.addField(data_form.Field('text-single', 'jid', label=_('Jabber ID'))) form.addField(data_form.Field('text-single', 'description', label=_('Description'))) query_elt.addChild(form.toElement()) self.xmlstream.send(result) def handleSearchRequest(self, request): - query = ["SELECT jid, description FROM directory"] + """Respond to a search request with the search results. + + @param request (domish.Element): the request to respond to + """ args = OrderedDict() try: query_elt = request.elements(NS_SEARCH, 'query').next() @@ -106,13 +111,7 @@ else: if value: args[col] = value - - if args: - query.append("WHERE") - query.append(" AND ".join(("%s LIKE ?" % col for col in args))) - - row_iter = self.db.execute(' '.join(query), tuple(['%'+arg+'%' for arg in args.values()])) - + result = domish.Element((None, 'iq')) result['type'] = 'result' result['id'] = request['id'] @@ -127,7 +126,8 @@ description_field_elt = reported_elt.addElement('field') description_field_elt['label'] = 'Description' description_field_elt['var'] = 'description' - for row in row_iter: + + for row in self._getSubscriptions(args): for col, value in zip(('jid', 'description'), row): item_elt = x_form_elt.addElement('item') field_elt = item_elt.addElement('field') @@ -137,14 +137,56 @@ query_elt.addChild(x_form_elt) self.xmlstream.send(result) - def onSubscribe(self, request): + def _getSubscriptions(self, args=None): + """Retrieve the subscriptions to the directory. + + @param args (OrderedDict): arguments to filter the request + @return: list[(boolean, unicode)] + """ + query = ["SELECT jid, description FROM directory"] + + if args: + query.append("WHERE") + query.append(" AND ".join(("%s LIKE ?" % col for col in args))) + + return self.db.execute(' '.join(query), tuple(['%'+arg+'%' for arg in args.values()])) + + def _getSubscription(self, jid): + """Retrieve the subscription of the given JID. + + @param jid (jid.JID): JID to search for + @return: (boolean, unicode) + """ + return self._getSubscriptions(OrderedDict({'jid': jid.userhost()})).fetchone() + + def _setSubscription(self, from_jid, subscribed, description): + """Set the subscription of the given JID. + + @param from_jid (jid.JID): JID to subscribe (or unsubscribe) + @param subscribed (boolean): set to True to subscribe and False to unsubscribe + @param description (unicode): description + """ + if subscribed: + self.db.execute('REPLACE INTO directory(jid,description) VALUES (?,?)', (from_jid.userhost(), description)) + else: + self.db.execute('DELETE FROM directory WHERE jid=?', (from_jid.userhost(),)) + self.db.connection.commit() + + def onUpdate(self, request): + """Process the request to update a subscription. + + @param request (domish.Element): the update request + """ result = domish.Element((None, 'iq')) result['type'] = 'result' result['id'] = request['id'] result['to'] = request['from'] - from_ = jid.JID(request['from']) + from_jid = jid.JID(request['from']) + request_cmd = request.elements(NS_COMMANDS, 'command').next() command_elt = result.addElement('command', NS_COMMANDS) + command_elt['node'] = request_cmd['node'] + try: session_id = request_cmd['sessionid'] except KeyError: @@ -154,48 +196,38 @@ # first request, we send the form command_elt['status'] = 'executing' session_id = str(uuid.uuid4()) - actions_elt = command_elt.addElement('actions') - actions_elt['execute'] = 'next' - actions_elt.addElement('next') - form = data_form.Form('form', instructions=FORM_INSTRUCTIONS, title=_('Directory subscription')) - infos = data_form.Field('fixed', value=SUBSCRIBE_TXT) - desc = data_form.Field('text-single', 'description', label=_(u"Some words about you")) - form.addField(infos) - form.addField(desc) + actions_elt = command_elt.addElement("actions") + actions_elt['execute'] = 'complete' + actions_elt.addElement('complete') + + subscription = self._getSubscription(from_jid) + subscribed, desc = ('true', subscription[1]) if subscription else ('false', '') + + form = data_form.Form('form', title=_('Directory subscription'), + instructions=FORM_INSTRUCTIONS, + formNamespace=NS_SEARCH) + form.addField(data_form.Field('boolean', 'subscribed', label=_('Subscribed'), values=[subscribed])) + form.addField(data_form.Field('text-single', 'description', label=_(u"Some words about you"), values=[desc])) command_elt.addChild(form.toElement()) else: - req_forms = request_cmd.elements(data_form.NS_X_DATA, 'x') - try: - req_form = req_forms.next() - parsed_form = data_form.Form.fromElement(req_form) - description = parsed_form['description'] + try: + request_form = request_cmd.elements(data_form.NS_X_DATA).next() except (StopIteration, KeyError): raise ValueError # TODO: properly cancel the command - self.db.execute('REPLACE INTO directory(jid,description) VALUES (?,?)', (from_.userhost(), description)) - self.db.connection.commit() + parsed_form = data_form.Form.fromElement(request_form) + subscribed = parsed_form['subscribed'] in ("true", "1") + description = parsed_form['description'] + self._setSubscription(from_jid, subscribed, description) + command_elt['status'] = 'completed' note_elt = command_elt.addElement('note') note_elt['type'] = 'info' - note_elt.addContent(SUBSCRIBE_DONE) - command_elt['sessionid'] = session_id - command_elt['node'] = request_cmd['node'] - self.xmlstream.send(result) + if subscribed: + note_elt.addContent(SUBSCRIBE_DONE) + else: + note_elt.addContent(UNSUBSCRIBE_DONE) - def onUnsubscribe(self, request): - result = domish.Element((None, 'iq')) - result['type'] = 'result' - result['id'] = request['id'] - result['to'] = request['from'] - from_ = jid.JID(request['from']) - request_cmd = request.elements(NS_COMMANDS, 'command').next() - command_elt = result.addElement('command', NS_COMMANDS) - self.db.execute('DELETE FROM directory WHERE jid=?', (from_.userhost(),)) - self.db.connection.commit() - command_elt['status'] = 'completed' - note_elt = command_elt.addElement('note') - note_elt['type'] = 'info' - note_elt.addContent(UNSUBSCRIBE_DONE) - command_elt['node'] = request_cmd['node'] + command_elt['sessionid'] = session_id self.xmlstream.send(result) def getDiscoInfo(self, requestor, target, nodeIdentifier=''): @@ -207,6 +239,5 @@ def getDiscoItems(self, requestor, target, nodeIdentifier=''): ret = [] if nodeIdentifier == NS_COMMANDS: - ret.append(disco.DiscoItem(target, "subscribe", "Subscribe to the directory")) - ret.append(disco.DiscoItem(target, "unsubscribe", "Unsubscribe from the directory")) + ret.append(disco.DiscoItem(target, "update", "Update your subscription to the directory")) return ret