changeset 1037:6e975c6b0faf

core, memory, bridge, plugin misc_register_account: move registerNewAccount to a new plugin: - the bridge method has been removed, now a plugin takes care of it with XMLUI callback system - TODO: xmpp.RegisteringAuthenticator still needs to be fixed
author souliane <souliane@mailoo.org>
date Fri, 16 May 2014 00:58:20 +0200
parents 35048cafb18d
children d732bb68b326
files frontends/src/bridge/DBus.py src/bridge/DBus.py src/bridge/bridge_constructor/bridge_template.ini src/core/sat_main.py src/core/xmpp.py src/memory/params.py src/plugins/plugin_misc_register_account.py src/test/helpers.py
diffstat 8 files changed, 131 insertions(+), 95 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/bridge/DBus.py	Fri May 16 00:53:09 2014 +0200
+++ b/frontends/src/bridge/DBus.py	Fri May 16 00:58:20 2014 +0200
@@ -204,9 +204,6 @@
     def paramsRegisterApp(self, xml, security_limit=-1, app=''):
         return self.db_core_iface.paramsRegisterApp(xml, security_limit, app)
 
-    def registerNewAccount(self, login, password, email, host, port=5222):
-        return unicode(self.db_core_iface.registerNewAccount(login, password, email, host, port))
-
     def saveParamsTemplate(self, filename):
         return self.db_core_iface.saveParamsTemplate(filename)
 
--- a/src/bridge/DBus.py	Fri May 16 00:53:09 2014 +0200
+++ b/src/bridge/DBus.py	Fri May 16 00:58:20 2014 +0200
@@ -404,12 +404,6 @@
         return self._callback("paramsRegisterApp", unicode(xml), security_limit, unicode(app))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
-                         in_signature='ssssi', out_signature='s',
-                         async_callbacks=None)
-    def registerNewAccount(self, login, password, email, host, port=5222):
-        return self._callback("registerNewAccount", unicode(login), unicode(password), unicode(email), unicode(host), port)
-
-    @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='b',
                          async_callbacks=None)
     def saveParamsTemplate(self, filename):
--- a/src/bridge/bridge_constructor/bridge_template.ini	Fri May 16 00:53:09 2014 +0200
+++ b/src/bridge/bridge_constructor/bridge_template.ini	Fri May 16 00:58:20 2014 +0200
@@ -228,20 +228,6 @@
  - ProfileUnknownError: the profile name is unknown
  - ConnectedProfileError: a connected profile would not be deleted
 
-[registerNewAccount]
-deprecated=
-type=method
-category=core
-sig_in=ssssi
-sig_out=s
-param_4_default=5222
-doc=Register a new account on a given server
-doc_param_0=login: login of the account
-doc_param_1=password: password of the account
-doc_param_2=email: email of the account
-doc_param_3=host: host of the server to register to
-doc_param_4=port: port of the server to register to
-
 [connect]
 type=method
 category=core
--- a/src/core/sat_main.py	Fri May 16 00:53:09 2014 +0200
+++ b/src/core/sat_main.py	Fri May 16 00:58:20 2014 +0200
@@ -20,7 +20,7 @@
 from sat.core.i18n import _, languageSwitch
 from twisted.application import service
 from twisted.internet import defer
-from twisted.words.protocols.jabber import jid, xmlstream
+from twisted.words.protocols.jabber import jid
 from twisted.words.xish import domish
 from twisted.internet import reactor
 from wokkel.xmppim import RosterItem
@@ -102,7 +102,6 @@
         self.bridge.register("getEntityData", lambda _jid, keys, profile: self.memory.getEntityData(jid.JID(_jid), keys, profile))
         self.bridge.register("asyncCreateProfile", self.memory.asyncCreateProfile)
         self.bridge.register("asyncDeleteProfile", self.memory.asyncDeleteProfile)
-        self.bridge.register("registerNewAccount", self.registerNewAccount)
         self.bridge.register("connect", self.connect)
         self.bridge.register("asyncConnect", self.asyncConnect)
         self.bridge.register("disconnect", self.disconnect)
@@ -413,52 +412,6 @@
             raise exceptions.ProfileKeyUnknownError
         return [self.profiles[profile]]
 
-    def registerNewAccount(self, login, password, email, server, port=5222, id_=None, profile_key=C.PROF_KEY_NONE):
-        """Connect to a server and create a new account using in-band registration"""
-        profile = self.memory.getProfileName(profile_key)
-        assert(profile)
-
-        next_id = id_ or self.get_next_id()  # the id is used to send server's answer
-        serverRegistrer = xmlstream.XmlStreamFactory(xmpp.RegisteringAuthenticator(self, server, login, password, email, next_id, profile))
-        connector = reactor.connectTCP(server, port, serverRegistrer)
-        serverRegistrer.clientConnectionLost = lambda conn, reason: connector.disconnect()
-
-        return next_id
-
-    def registerNewAccountCB(self, data, profile):
-        # FIXME: to be removed/redone elsewhere
-        user = jid.parse(self.memory.getParamA("JabberID", "Connection", profile_key=profile))[0]
-        server = self.memory.getParamA("Server", "Connection", profile_key=profile)
-        d = self.memory.asyncGetParamA("Password", "Connection", profile_key=profile)
-
-        def gotPassword(password):
-            if not user or not password or not server:
-                raise exceptions.DataError(_("No user, password or server given, can't register new account."))
-
-            # FIXME: to be fixed with XMLUI dialogs once their implemented
-            confirm_id = sat_next_id()
-            self.__private_data[confirm_id] = (id, profile)
-
-            self.askConfirmation(
-                confirm_id, "YES/NO",
-                {"message": _("Are you sure to register new account [%(user)s] to server %(server)s ?") % {'user': user, 'server': server, 'profile': profile}},
-                self.regisConfirmCB, profile)
-            print "===============+++++++++++ REGISTER NEW ACCOUNT++++++++++++++============"
-
-        d.addCallback(gotPassword)
-
-    def regisConfirmCB(self, id, accepted, data, profile):
-        print _("register Confirmation CB ! (%s)") % str(accepted)
-        action_id, profile = self.__private_data[id]
-        del self.__private_data[id]
-        if accepted:
-            user = jid.parse(self.memory.getParamA("JabberID", "Connection", profile_key=profile))[0]
-            server = self.memory.getParamA("Server", "Connection", profile_key=profile)
-            d = self.memory.asyncGetParamA("Password", "Connection", profile_key=profile)
-            d.addCallback(lambda password: self.registerNewAccount(user, password, None, server, id=action_id))
-        else:
-            self.actionResult(action_id, "SUPPRESS", {}, profile)
-
     ## Client management ##
 
     def setParam(self, name, value, category, security_limit, profile_key):
--- a/src/core/xmpp.py	Fri May 16 00:53:09 2014 +0200
+++ b/src/core/xmpp.py	Fri May 16 00:58:20 2014 +0200
@@ -17,7 +17,7 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from sat.core.i18n import _
+from sat.core.i18n import _, D_
 from sat.core.constants import Const as C
 from twisted.internet import task, defer
 from twisted.words.protocols.jabber import jid, xmlstream
@@ -412,20 +412,19 @@
 
 class RegisteringAuthenticator(xmlstream.ConnectAuthenticator):
 
-    def __init__(self, host, jabber_host, user_login, user_pass, email, answer_id, profile):
+    def __init__(self, host, jabber_host, user_login, user_pass, email, deferred, profile):
         xmlstream.ConnectAuthenticator.__init__(self, jabber_host)
         self.host = host
         self.jabber_host = jabber_host
         self.user_login = user_login
         self.user_pass = user_pass
         self.user_email = email
-        self.answer_id = answer_id
+        self.deferred = deferred
         self.profile = profile
-        print _("Registration asked for"), user_login, user_pass, jabber_host
+        log.debug(_("Registration asked for %(user)s@%(host)s") % {'user': user_login, 'host': jabber_host})
 
     def connectionMade(self):
-        print "connectionMade"
-
+        log.debug(_("Connection made with %s" % self.jabber_host))
         self.xmlstream.namespace = "jabber:client"
         self.xmlstream.sendHeader()
 
@@ -439,27 +438,17 @@
         if self.user_email:
             _email = query.addElement('email')
             _email.addContent(self.user_email)
-        iq.send(self.jabber_host).addCallbacks(self.registrationAnswer, self.registrationFailure)
+        d = iq.send(self.jabber_host).addCallbacks(self.registrationAnswer, self.registrationFailure)
+        d.chainDeferred(self.deferred)
 
     def registrationAnswer(self, answer):
-        log.debug(_("registration answer: %s") % answer.toXml())
-        answer_type = "SUCCESS"
-        answer_data = {"message": _("Registration successfull")}
-        self.host.bridge.actionResult(answer_type, self.answer_id, answer_data, self.profile)
+        log.debug(_("Registration answer: %s") % answer.toXml())
         self.xmlstream.sendFooter()
 
     def registrationFailure(self, failure):
         log.info(_("Registration failure: %s") % str(failure.value))
-        answer_type = "ERROR"
-        answer_data = {}
-        if failure.value.condition == 'conflict':
-            answer_data['reason'] = 'conflict'
-            answer_data = {"message": _("Username already exists, please choose an other one")}
-        else:
-            answer_data['reason'] = 'unknown'
-            answer_data = {"message": _("Registration failed (%s)") % str(failure.value.condition)}
-        self.host.bridge.actionResult(answer_type, self.answer_id, answer_data, self.profile)
         self.xmlstream.sendFooter()
+        raise failure.value
 
 
 class SatVersionHandler(generic.VersionHandler):
--- a/src/memory/params.py	Fri May 16 00:53:09 2014 +0200
+++ b/src/memory/params.py	Fri May 16 00:58:20 2014 +0200
@@ -135,7 +135,6 @@
         self.default_profile = None
         self.params = {}
         self.params_gen = {}
-        host.registerCallback(host.registerNewAccountCB, with_data=True, force_id="registerNewAccount")
 
     def asyncCreateProfile(self, profile):
         """Create a new profile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/plugin_misc_register_account.py	Fri May 16 00:58:20 2014 +0200
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# SàT plugin for registering a new XMPP account
+# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
+# Copyright (C) 2013, 2014 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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from sat.core.i18n import _, D_
+from sat.core.log import getLogger
+log = getLogger(__name__)
+from sat.core.constants import Const as C
+from twisted.words.protocols.jabber import jid, xmlstream
+from sat.core import xmpp
+from sat.memory.memory import Sessions
+from twisted.internet import reactor, defer
+from sat.tools import xml_tools
+from sat.tools.xml_tools import SAT_FORM_PREFIX, SAT_PARAM_SEPARATOR
+
+
+PLUGIN_INFO = {
+    "name": "Register Account Plugin",
+    "import_name": "REGISTER-ACCOUNT",
+    "type": "MISC",
+    "protocols": [],
+    "dependencies": [],
+    "recommendations": [],
+    "main": "RegisterAccount",
+    "handler": "no",
+    "description": _(u"""Register XMPP account""")
+}
+
+
+class RegisterAccount(object):
+
+    def __init__(self, host):
+        log.info(_(u"Plugin Register Account initialization"))
+        self.host = host
+        self._sessions = Sessions()
+        host.registerCallback(self.registerNewAccountCB, with_data=True, force_id="registerNewAccount")
+        self.__register_account_id = host.registerCallback(self._registerConfirmation, with_data=True)
+
+    def registerNewAccountCB(self, data, profile):
+        """Called when the use click on the "New account" button."""
+        session_data = {}
+        for param in ('JabberID', 'Password', 'Port', 'Server'):
+            try:
+                session_data[param] = data["%s%s%s%s" % (SAT_FORM_PREFIX, "Connection", SAT_PARAM_SEPARATOR, param)]
+            except KeyError:
+                if param == 'Port':
+                    session_data[param] = 5222
+
+        for param in ('JabberID', 'Password', 'Server'):
+            if not session_data[param]:
+                form_ui = xml_tools.XMLUI("popup", title=D_("Missing values"))
+                form_ui.addText(D_("No user, password or server given: can't register new account."))
+                return  {'xmlui': form_ui.toXml()}
+
+        user = jid.parse(session_data['JabberID'])[0]
+        session_id, dummy = self._sessions.newSession(session_data, profile)
+        form_ui = xml_tools.XMLUI("form", title=D_("Register new account"), submit_id=self.__register_account_id, session_id=session_id)
+        form_ui.addText(D_("Do you want to register a new XMPP account [%(user)s] on server %(server)s ?") % {'user': user, 'server': session_data['Server']})
+        return  {'xmlui': form_ui.toXml()}
+
+    def _registerConfirmation(self, data, profile):
+        """Save the related parameters and proceed the registration."""
+        session_data = self._sessions.profileGet(data['session_id'], profile)
+
+        self.host.memory.setParam("JabberID", session_data["JabberID"], "Connection", profile_key=profile)
+        self.host.memory.setParam("Password", session_data["Password"], "Connection", profile_key=profile)
+        self.host.memory.setParam("Server", session_data["Server"], "Connection", profile_key=profile)
+        self.host.memory.setParam("Port", session_data["Port"], "Connection", profile_key=profile)
+
+        user = jid.parse(session_data['JabberID'])[0]
+        return self._registerNewAccount(user, session_data["Password"], None, session_data["Server"], profile_key=profile)
+
+    def _registerNewAccount(self, user, password, email, host, port=5222, profile_key=C.PROF_KEY_NONE):
+        """Connect to a server and create a new account using in-band registration.
+        @param user: login of the account
+        @param password: password of the account
+        @param email: email of the account
+        @param host: host of the server to register to
+        @param port: port of the server to register to
+        @param profile_key: %(doc_profile_key)s
+        """
+        profile = self.host.memory.getProfileName(profile_key)
+
+        d = defer.Deferred()
+        serverRegistrer = xmlstream.XmlStreamFactory(xmpp.RegisteringAuthenticator(self, host, user, password, email, d, profile))
+        connector = reactor.connectTCP(host, port, serverRegistrer)
+        serverRegistrer.clientConnectionLost = lambda conn, reason: connector.disconnect()
+
+        def cb(dummy):
+            xmlui = xml_tools.XMLUI("popup", title=D_("Confirmation"))
+            xmlui.addText(D_("Registration successful."))
+            return ({'xmlui': xmlui.toXml()})
+
+        def eb(failure):
+            xmlui = xml_tools.XMLUI("popup", title=D_("Failure"))
+            xmlui.addText(D_("Registration failed: %s") % failure.getErrorMessage())
+            try:
+                if failure.value.condition == 'conflict':
+                    xmlui.addText(D_("Username already exists, please choose an other one."))
+            except AttributeError:
+                pass
+            return ({'xmlui': xmlui.toXml()})
+
+        d.addCallbacks(cb, eb)
+        return d
--- a/src/test/helpers.py	Fri May 16 00:53:09 2014 +0200
+++ b/src/test/helpers.py	Fri May 16 00:58:20 2014 +0200
@@ -81,9 +81,6 @@
     def registerCallback(self, callback, *args, **kwargs):
         pass
 
-    def registerNewAccountCB(self, data, profile):
-        pass
-
     def sendMessage(self, to_s, msg, subject=None, mess_type='auto', extra={}, profile_key='@NONE@'):
         self.sendAndStoreMessage({"to": JID(to_s)})