Mercurial > libervia-web
diff libervia.tac @ 46:c3ee630914ba
Account creation
* browser side:
- login dialog has been extended to manage subscription
* server side:
- SATActionIDHandler to manage replies to action
- account is created on subscribtion form, a password is created, and 2 emails are send (one to user, one to administrator)
- access of main microblog is set to open
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 26 May 2011 16:43:30 +0200 |
parents | 7f106052326f |
children | 72c51a4839cc |
line wrap: on
line diff
--- a/libervia.tac Wed May 25 15:45:16 2011 +0200 +++ b/libervia.tac Thu May 26 16:43:30 2011 +0200 @@ -19,11 +19,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. """ +#You need do adapt the following consts to your server +_REG_EMAIL_FROM = "NOREPLY@libervia.org" +_REG_EMAIL_SERVER = "localhost" +_REG_ADMIN_EMAIL = "goffi@goffi.org" +_NEW_ACCOUNT_SERVER = "localhost" +_NEW_ACCOUNT_DOMAIN = "tazar.int" +_NEW_ACCOUNT_RESOURCE = "libervia" + from twisted.application import internet, service from twisted.internet import glib2reactor glib2reactor.install() from twisted.internet import reactor, defer - +from twisted.mail.smtp import sendmail from twisted.web import server from twisted.web import error as weberror from twisted.web.static import File @@ -33,6 +41,8 @@ from txjsonrpc.web import jsonrpc from txjsonrpc import jsonrpclib from sat_frontends.bridge.DBus import DBusBridgeFrontend,BridgeExceptionNoService +from email.mime.text import MIMEText +from logging import debug, info, warning, error import re import glob import os.path @@ -75,6 +85,34 @@ if not self.__lock: server.Session.touch(self) +class SATActionIDHandler(object): + """Manage SàT action id lifecycle""" + ID_LIFETIME = 30 #after this time (in seconds), id will be suppressed and action result will be ignored + + def __init__(self): + self.waiting_ids = {} + + def waitForId(self, id, callback, *args, **kwargs): + """Wait for an action result + @param id: id to wait for + @param callback: method to call when action gave a result back + @param *args: additional argument to pass to callback + @param **kwargs: idem""" + self.waiting_ids[id] = (callback, args, kwargs) + reactor.callLater(self.ID_LIFETIME, self.purgeID, id) + + def purgeID(self, id): + """Called when an id has not be handled in time""" + if id in self.waiting_ids: + warning ("action of id %s has not been managed, id is now ignored" % id) + del self.waiting_ids[id] + + def actionResultCb(self, answer_type, id, data): + """Manage the actionResult signal""" + if id in self.waiting_ids: + callback, args, kwargs = self.waiting_ids[id] + del self.waiting_ids[id] + callback(answer_type, id, data, *args, **kwargs) class MethodHandler(jsonrpc.JSONRPC): @@ -232,6 +270,9 @@ - ALREADY WAITING: a request has already be made for this profile - server.NOT_DONE_YET: the profile is being processed, the return value will be given by self._logged or self._logginError """ + if 'new_account' in request.args: + return self._registerNewAccount(request.args) + try: _login = request.args['login'][0] if _login.startswith('@'): @@ -256,6 +297,94 @@ self.sat_host.bridge.connect(_login) return server.NOT_DONE_YET + def _postAccountCreation(self, answer_type, id, data, profile): + """Called when a account has just been created, + setup stuff has microblog access""" + def _connected(ignore): + mblog_d = defer.Deferred() + self.sat_host.bridge.setMicroblogAccess("open", profile, lambda: mblog_d.callback(None), mblog_d.errback) + mblog_d.addBoth(lambda ignore: self.sat_host.bridge.disconnect(profile)) + + d = defer.Deferred() + self.sat_host.bridge.asyncConnect(profile, lambda: d.callback(None), d.errback) + d.addCallback(_connected) + + def _registerNewAccount(self, args): + """Create a new account, or return error + @param args: dict of args as given by the form + @return: "REGISTRATION" in case of success""" + try: + profile = login = args['login'][0] + email = args['email'][0] + except KeyError: + return "BAD REQUEST" + if not re.match(r'^[a-z0-9_-]+$', login, re.IGNORECASE) or \ + not re.match(r'^.+@.+\..+', email, re.IGNORECASE): + return "BAD REQUEST" + #_charset = [chr(i) for i in range(0x21,0x7F)] #XXX: this charset seems to have some issues with openfire + _charset = [chr(i) for i in range(0x30,0x3A) + range(0x41,0x5B) + range (0x61,0x7B)] + import random + random.seed() + password = ''.join([random.choice(_charset) for i in range(15)]) + + if login in self.sat_host.bridge.getProfilesList(): #FIXME: must use a deferred + create a new profile check method + return "ALREADY EXISTS" + + #we now create the profile + self.sat_host.bridge.createProfile(login) + #FIXME: values must be in a config file instead of hardcoded + self.sat_host.bridge.setParam("JabberID", "%s@%s/%s" % (login, _NEW_ACCOUNT_DOMAIN, _NEW_ACCOUNT_RESOURCE), "Connection", profile) + self.sat_host.bridge.setParam("Server", _NEW_ACCOUNT_SERVER, "Connection", profile) + self.sat_host.bridge.setParam("Password", password, "Connection", profile) + #and the account + action_id = self.sat_host.bridge.registerNewAccount(login, password, email, "tazar.int", 5222) + self.sat_host.action_handler.waitForId(action_id, self._postAccountCreation, profile) + + #time to send the email + + _email_host = _REG_EMAIL_SERVER + _email_from = _REG_EMAIL_FROM + + def email_ok(ignore): + print ("Account creation email sent to %s" % email) + + def email_ko(ignore): + #TODO: return error code to user + error ("Failed to send email to %s" % email) + + body = (u"""Welcome to Libervia, a Salut à Toi project part + +/!\\ WARNING, THIS IS ONLY A TECHNICAL DEMO, DON'T USE THIS ACCOUNT FOR ANY SERIOUS PURPOSE /!\\ + +Here are your connection informations: +login: %(login)s +password: %(password)s + +Any feedback welcome + +Cheers +Goffi""" % { 'login': login, 'password': password }).encode('utf-8') + msg = MIMEText(body, 'plain', 'UTF-8') + msg['Subject'] = 'Libervia account created' + msg['From'] = _email_from + msg['To'] = email + + d = sendmail(_email_host, _email_from, email, msg.as_string()) + d.addCallbacks(email_ok, email_ko) + + #email to the administrator + + body = (u"""New account created: %(login)s [%(email)s]""" % { 'login': login, 'email': email }).encode('utf-8') + msg = MIMEText(body, 'plain', 'UTF-8') + msg['Subject'] = 'Libervia new account created' + msg['From'] = _email_from + msg['To'] = _REG_ADMIN_EMAIL + + d = sendmail(_email_host, _email_from, email, msg.as_string()) + d.addCallbacks(email_ok, email_ko) + print "rturn REGISTRATION" + return "REGISTRATION" + def __cleanWaiting(self, login): """Remove login from waiting queue""" try: @@ -405,6 +534,7 @@ self.signal_handler.plugRegister(_register) self.sessions = {} #key = session value = user self.prof_connected = set() #Profiles connected + self.action_handler = SATActionIDHandler() ## bridge ## try: self.bridge=DBusBridgeFrontend() @@ -413,6 +543,7 @@ sys.exit(1) self.bridge.register("connected", self.signal_handler.connected) self.bridge.register("connectionError", self.signal_handler.connectionError) + self.bridge.register("actionResult", self.action_handler.actionResultCb, "request") for signal_name in ['presenceUpdate', 'personalEvent', 'newMessage', 'roomJoined', 'roomUserJoined', 'roomUserLeft', 'tarotGameStarted', 'tarotGameNew', 'tarotGameChooseContrat', 'tarotGameShowCards', 'tarotGameInvalidCards', 'tarotGameCardsPlayed', 'tarotGameYourTurn', 'tarotGameScore']: self.bridge.register(signal_name, self.signal_handler.getGenericCb(signal_name))