changeset 3:593345584d21 default tip

replace ad-hoc commands "subscribe" and "unsubscribe" with a single "update" command
author souliane <souliane@mailoo.org>
date Wed, 02 Sep 2015 14:02:50 +0200
parents 77b77f48c975
children
files salut.py
diffstat 1 files changed, 88 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- 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