From 85141684d004535e1f2a826e6a6fe4d97cbd6a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Schneider?= Date: Fri, 23 Sep 2011 08:49:32 +0200 Subject: [PATCH] Improve README and finish duonet support * mandaye/auth/authform.py: update to support duonet replay * README.rst: improve the quick launch text * mandaye/filters/vincennes.py: filters for Duonet * mandaye/models.py: add birthdate for duonet * mandayectl: improve the cmd line management --- README.rst | 8 +++- mandaye/auth/authform.py | 38 ++++++++++++------- mandaye/configs/duonet_vincennes.py | 59 +++++++++++++++++------------ mandaye/filters/vincennes.py | 9 +++-- mandaye/models.py | 5 ++- mandayectl | 8 +++- 6 files changed, 79 insertions(+), 48 deletions(-) diff --git a/README.rst b/README.rst index c525570..ac92d37 100644 --- a/README.rst +++ b/README.rst @@ -68,11 +68,15 @@ or easy_install:: Quick Start ----------- +Configure mandaye/config.py + Then launch the following commands:: - TODO + ./mandayectl --createdb + ./mandayectl --start You should see the following output:: - TODO + Database created + Starting Mandaye x.x.x.x:xx ... diff --git a/mandaye/auth/authform.py b/mandaye/auth/authform.py index 020c5d9..95a156e 100644 --- a/mandaye/auth/authform.py +++ b/mandaye/auth/authform.py @@ -49,24 +49,26 @@ this keys: form_url, form_attrs, username_field and password_field") self.form_url = form_values['form_url'] self.form_values = form_values - def replay(self, env, username, password, **kwargs): + def replay(self, env, username, password, extra_values={}): """ replay the login / password + env: WSGI env with beaker session and the target + extra_values: dict with the field name (key) and the field value (value) """ if not "://" in self.form_url: - self.form_url = env['target'].geturl() + self.form_url + self.form_url = env['target'].geturl() + '/' + self.form_url cj = CookieJar() request = HTTPRequest() login = get_response(env, request, self.form_url, cj) if login.code == 502: return login soup = BeautifulSoup(login.msg) - form = soup.find('form', **self.form_values['form_attrs']) + form = soup.find('form', self.form_values['form_attrs']) if not self.form_values.has_key('from_action'): action = form['action'] else: action = self.form_values['form_action'] if not "://" in action: - action = env['target'].geturl() + action + action = env['target'].geturl() + '/' + action if not form: logging.warning("%s %s: can't find login form on %s" % (self.env['HTTP_HOST'], self.env['PATH_INFO'], self.form_url)) @@ -77,32 +79,33 @@ this keys: form_url, form_attrs, username_field and password_field") headers.load_from_dict(self.form_values['form_headers']) params = {} for input in form.findAll('input'): - if input['type'] != "submit" and input['type'] != 'button' \ - and input.has_key('name'): + if input.has_key('name'): if input.has_key('value'): params[input['name']] = input['value'] else: params[input['name']] = '' params[self.form_values['username_field']] = username params[self.form_values['password_field']] = password - for key, value in kwargs: + for key, value in extra_values.iteritems(): params[key] = value params = urllib.urlencode(params) request = HTTPRequest(cookies, headers, "POST", params) return get_response(env, request, action, cj) - def associate(self, env, values, request): - """ Render the associate page - """ - return template_response(values['template'], values) - def associate_submit(self, env, values, condition, request, response): """ Associate your login / password with Mandaye """ pseudo = env['beaker.session'].get('pseudo') if request.msg: post = parse_qs(request.msg.read(), request) - response = self.replay(env, post['username'][0], post['password'][0]) + if not post.has_key('username') or not post.has_key('password'): + return get_response(env, HTTPRequest(), values.get('failed_url')) + # TODO: generized this part (use a generic key / value table) + extra_values = {} + if post.has_key('birthdate'): + birthdate_field = self.form_values['birthdate_field'] + extra_values = {birthdate_field: post['birthdate'][0]} + response = self.replay(env, post['username'][0], post['password'][0], extra_values) if eval(condition): if not pseudo: return _302(values.get('connection_url')) @@ -125,6 +128,9 @@ this keys: form_url, form_attrs, username_field and password_field") ext_user.login = post['username'][0] ext_user.password = post['password'][0] ext_user.local_user = local_user + # TODO: generalize this + if post.has_key('birthdate'): + ext_user.birthdate = post['birthdate'][0] mandaye.sql_session.commit() return _302(values.get('connection_url')) @@ -145,7 +151,11 @@ this keys: form_url, form_attrs, username_field and password_field") if not ext_user.login or not ext_user.password: return _500(env['PATH_INFO'], 'Invalid values for AuthFormDispatcher.login') - response = self.replay(env, ext_user.login, ext_user.password) + # TODO: generized this condition + extra_values = {} + if ext_user.birthdate: + extra_values = { self.form_values['birthdate_field']: ext_user.birthdate } + response = self.replay(env, ext_user.login, ext_user.password, extra_values) if condition and eval(condition): return response else: diff --git a/mandaye/configs/duonet_vincennes.py b/mandaye/configs/duonet_vincennes.py index 6669f67..85651dd 100644 --- a/mandaye/configs/duonet_vincennes.py +++ b/mandaye/configs/duonet_vincennes.py @@ -11,12 +11,13 @@ filters = Duonet() form_values = { 'form_url': 'Connect.aspx?key=CV4j27Em0dM%3d', - 'form_attrs': { 'name': 'form1', }, + 'form_attrs': { 'name': 'form1' }, 'username_field': 'txtNomFoyer', 'birthdate_field': 'txtDateNaissance', 'password_field': 'txtCode', } + authform = AuthForm(auth_vincennes, form_values) @@ -26,7 +27,7 @@ duonet_mapping = [ 'method': 'GET', 'response': [{ 'filter': authform.login, - 'values': { 'associate_url': '/vincennes/associate' }, + 'values': { 'associate_url': '/associate' }, 'condition': 'response.code==302', },] }, @@ -42,29 +43,29 @@ duonet_mapping = [ }, }] }, -# { -# 'path': r'/vincennes/associate$', -# 'method': 'POST', -# 'response': [ -# { -# 'filter': authform.associate_submit, -# 'values': { -# 'site_name': 'espace_famille', -# 'connection_url': '/vincennes/connection', -# 'failed_url': 'https://vincennes.espace-famille.net/vincennes/index.do' -# }, -# 'condition': "response.code==302" -# }, -# { -# 'filter': filters.resp_associate, -# 'values': { -# 'action': '/vincennes/associate', -# 'template': 'famille_associate.html', -# 'error_msg': "Code famille et/ou mot de passe incorrects", -# }, -# }, -# ] -# }, + { + 'path': r'/associate$', + 'method': 'POST', + 'response': [ + { + 'filter': authform.associate_submit, + 'values': { + 'site_name': 'conservatoire', + 'connection_url': '/vincennes/connection', + 'failed_url': 'https://extranet.duonet.fr/Connect.aspx?key=CV4j27Em0dM%3d' + }, + 'condition': "response.code==302" + }, + { + 'filter': filters.resp_associate, + 'values': { + 'action': '/associate', + 'template': 'duonet_associate.html', + 'error_msg': "Identifiants incorrects", + }, + }, + ] + }, { 'path': r'/vincennes/connection$', 'method': 'GET', @@ -84,6 +85,14 @@ duonet_mapping = [ 'filter': filters.resp_login_page, 'values': {'connection_url': '/vincennes/connection'}}] }, + { + 'path': r'/$', + 'method': 'GET', + 'target': 'https://extranet.duonet.fr/Connect.aspx?key=CV4j27Em0dM%3d', + 'on_response': [{ + 'filter': filters.resp_login_page, + 'values': {'connection_url': '/vincennes/connection'}}] + }, ] diff --git a/mandaye/filters/vincennes.py b/mandaye/filters/vincennes.py index 3103a9c..2be115f 100644 --- a/mandaye/filters/vincennes.py +++ b/mandaye/filters/vincennes.py @@ -1,10 +1,15 @@ -import ipdb +import mandaye import re +from urlparse import parse_qs from BeautifulSoup import BeautifulSoup +from mandaye.models import Site, ExtUser, LocalUser +from mandaye.server import get_response from mandaye.response import serve_template +from mandaye.http import HTTPRequest +from mandaye.response import _500, _302, _401 def biblio_html_login_page(env, values, request, response): """ msg: response message body @@ -83,5 +88,3 @@ class Duonet: response.msg = str(soup) return response - def associate_submit(self, env, values, request, response): - pass diff --git a/mandaye/models.py b/mandaye/models.py index fadca23..069c2d0 100644 --- a/mandaye/models.py +++ b/mandaye/models.py @@ -26,7 +26,7 @@ class LocalUser(Base): id = Column(Integer, primary_key=True) login = Column(String(150), nullable=True, unique=True) - password = Column(String, nullable=True) + password = Column(String(25), nullable=True) fullname = Column(String(150), nullable=True) def __init__(self, login=None, password=None, fullname=None): @@ -48,7 +48,8 @@ class ExtUser(Base): id = Column(Integer, primary_key=True) login = Column(String(80), nullable=True) - password = Column(String, nullable=True) + password = Column(String(25), nullable=True) + birthdate = Column(String(15), nullable=True) local_user_id = Column(Integer, ForeignKey('local_users.id')) site_id = Column(Integer, ForeignKey('sites.id')) diff --git a/mandayectl b/mandayectl index 4abba7f..2b9d63c 100755 --- a/mandayectl +++ b/mandayectl @@ -12,7 +12,8 @@ from mandaye import config from mandaye import server def get_cmd_options(): - parser = OptionParser() + usage = "usage: %prog [-d, --daemon] start|stop|createdb" + parser = OptionParser(usage=usage) parser.add_option("--start", dest="start", default=False, @@ -42,6 +43,8 @@ def get_cmd_options(): parser.error("you can't use options start and stop at the same time") if options.daemon and not options.start and not options.stop: parser.error("You must use option start or stop") + if not options.start and not options.stop and not options.createdb: + parser.error("You must use option start | stop | createdb") return options def main(): @@ -53,9 +56,10 @@ def main(): from sqlalchemy import create_engine engine = create_engine(config.db_url) Base.metadata.create_all(engine) + print "Database created" if options.start: - logging.info("Starting Mandaye %s:%d .." % (config.host, config.port)) + print "Starting Mandaye %s:%d .." % (config.host, config.port) server.serve() if __name__ == "__main__":