Projet

Général

Profil

« Précédent | Suivant » 

Révision c62aae38

Ajouté par Jérôme Schneider il y a plus de 9 ans

backends: complete rewrite of the interface

The old interface was to specific for sqlalchemy this new one allow to
write new backends

WARNING: this commit could break compability for some filter which uses
the old interface

Voir les différences:

mandaye/auth/authform.py
24 24
from mandaye.response import template_response
25 25
from mandaye.server import get_response
26 26

  
27
from mandaye.backends.default import backend
27
from mandaye.backends.default import Association
28 28

  
29 29
try:
30 30
    from Crypto.Cipher import AES
......
203 203
        if config.encrypt_sp_password:
204 204
            password = self.encrypt_pwd(post_values[self.form_values['password_field']])
205 205
            post_values[self.form_values['password_field']] = password
206
        service_provider = backend.ManagerServiceProvider.get_or_create(self.site_name)
207
        idp_user = backend.ManagerIDPUser.get_or_create(unique_id)
208
        sp_user = backend.ManagerSPUser.get(sp_login, idp_user, service_provider)
209
        if sp_user:
210
            sp_user.post_values = post_values
211
            backend.ManagerSPUser.save()
212
        else:
213
            sp_user = backend.ManagerSPUser.create(sp_login, post_values,
214
                    idp_user, service_provider)
206

  
207
        asso_id = Association.update_or_create(self.site_name, sp_login,
208
                post_values, unique_id)
215 209
        env['beaker.session']['unique_id'] = unique_id
216
        env['beaker.session'][self.site_name] = sp_user.id
210
        env['beaker.session'][self.site_name] = asso_id
217 211
        env['beaker.session'].save()
218 212

  
219 213
    def associate_submit(self, env, values, request, response):
......
253 247
            qs['type'] = 'badlogin'
254 248
            return _302(self.urls.get('associate_url') + "?%s" % urllib.urlencode(qs))
255 249

  
256
    def _login_sp_user(self, sp_user, env, condition, values):
250
    def _login_sp_user(self, association, env, condition, values):
257 251
        """ Log in sp user
258 252
        """
259
        if not sp_user.login:
253
        if not association['sp_login']:
260 254
            return _500(env['PATH_INFO'],
261 255
                    'Invalid values for AuthFormDispatcher.login')
262
        post_values = copy.copy(sp_user.post_values)
256
        post_values = copy.copy(association['sp_post_values'])
263 257
        if config.encrypt_sp_password:
264 258
            password = self.decrypt_pwd(post_values[self.form_values['password_field']])
265 259
            post_values[self.form_values['password_field']] = password
266 260
        response = self.replay(env, post_values)
267 261
        qs = parse_qs(env['QUERY_STRING'])
268 262
        if condition and eval(condition):
269
            sp_user.last_connection = datetime.now()
270
            backend.ManagerSPUser.save()
271
            env['beaker.session'][self.site_name] = sp_user.id
263
            Association.update_last_connection(association['id'])
264
            env['beaker.session'][self.site_name] = association['id']
272 265
            env['beaker.session'].save()
273 266
            if qs.has_key('next_url'):
274 267
                return _302(qs['next_url'][0], response.cookies)
......
295 288

  
296 289
        logger.debug('User %s successfully login' % env['beaker.session']['unique_id'])
297 290

  
298
        idp_user = backend.ManagerIDPUser.get_or_create(unique_id)
299
        service_provider = backend.ManagerServiceProvider.get_or_create(self.site_name)
300
        sp_user = backend.ManagerSPUser.get_last_connected(idp_user, service_provider)
301
        if not sp_user:
291
        association = Association.get_last_connected(self.site_name, unique_id)
292
        if not association:
302 293
            logger.debug('User %s is not associate' % env['beaker.session']['unique_id'])
303 294
            return _302(self.urls.get('associate_url') + "?type=first")
304
        return self._login_sp_user(sp_user, env, values['condition'], values)
295
        return self._login_sp_user(association, env, values['condition'], values)
305 296

  
306 297
    def logout(self, env, values, request, response):
307 298
        """ Destroy the Beaker session
......
348 339
        if not qs.has_key('id') and not unique_id:
349 340
            return _401('Access denied: beaker session invalid or not qs id')
350 341
        if qs.has_key('id'):
351
            id = qs['id'][0]
352
            sp_user = backend.ManagerSPUser.get_by_id(id)
342
            asso_id = qs['id'][0]
343
            association = Association.get_by_id(asso_id)
353 344
        else:
354
            service_provider = backend.ManagerServiceProvider.get(self.site_name)
355
            idp_user = backend.ManagerIDPUser.get(unique_id)
356
            sp_user = backend.ManagerSPUser.get_last_connected(idp_user, service_provider)
357
        if not sp_user:
345
            association = Association.get_last_connected(self.site_name, unique_id)
346
        if not association:
358 347
            return _302(self.urls.get('associate_url'))
359
        return self._login_sp_user(sp_user, env, 'response.code==302', values)
348
        return self._login_sp_user(association, env, 'response.code==302', values)
360 349

  
361 350
    def disassociate(self, env, values, request, response):
362 351
        """ Disassociate an account with the Mandaye account
......
376 365
        if qs.has_key('next_url'):
377 366
            next_url = qs['next_url'][0]
378 367
        if qs.has_key('id'):
379
            sp_id = qs['id'][0]
380
            sp_user = backend.ManagerSPUser.get_by_id(sp_id)
381
            if sp_user:
382
                backend.ManagerSPUser.delete(sp_user)
383
                if backend.ManagerSPUser.get_sp_users(unique_id, self.site_name):
368
            asso_id = qs['id'][0]
369
            if Association.has_id(asso_id):
370
                Association.delete(asso_id)
371
                if Association.get(self.site_name, unique_id):
384 372
                    env['QUERY_STRING'] = ''
385 373
                    return self.change_user(env, values, request, response)
386 374
            else:
387 375
                return _401('Access denied: bad id')
388 376
        elif qs.has_key('sp_name'):
389 377
            sp_name = qs['sp_name'][0]
390
            for sp_user in \
391
                    backend.ManagerSPUser.get_sp_users(unique_id, sp_name):
392
                backend.ManagerSPUser.delete(sp_user)
378
            for asso in \
379
                    Association.get(sp_name, unique_id):
380
                Association.delete(asso['id'])
393 381
        else:
394 382
            return _401('Access denied: no id or sp name')
395 383
        values['next_url'] = next_url
mandaye/backends/default.py
4 4
from mandaye import config
5 5
from mandaye.exceptions import ImproperlyConfigured
6 6

  
7
class DefaultManagerIDPUser:
8

  
9
    @staticmethod
10
    def get(unique_id, idp_id='default'):
11
        pass
12

  
13
    @staticmethod
14
    def create(unique_id, idp_id='default'):
15
        pass
16

  
17
    @staticmethod
18
    def get_or_create(unique_id, idp_id='default'):
19
        pass
20

  
21
    @staticmethod
22
    def delete(idp_user):
23
        pass
24

  
25
    @staticmethod
26
    def save(idp_user):
27
        pass
28

  
29
class DefaultManagerSPUser:
30

  
31
    @staticmethod
32
    def get(login, idp_user, service_provider):
33
        pass
34

  
35
    @staticmethod
36
    def get_by_id(id):
37
        pass
7
def import_backend(path):
8
    try:
9
        mod = import_module(path)
10
    except ImportError, e:
11
        raise ImproperlyConfigured('Error importing backend %s: "%s"' % (path, e))
12
    return mod
38 13

  
39
    @staticmethod
40
    def get_last_connected(idp_user, service_provider):
41
        pass
14
storage_conn = None
15
if config.storage_backend == "mandaye.backends.sql":
16
    from sqlalchemy import create_engine
17
    from sqlalchemy.orm import sessionmaker, scoped_session
18
    if not "sqlite" in config.db_url:
19
       storage_conn = scoped_session(
20
                sessionmaker(
21
                    bind=create_engine(config.db_url, pool_size=16,
22
                        pool_recycle=1800)
23
                    )
24
                )
25
    else:
26
        storage_conn = scoped_session(
27
                sessionmaker(
28
                    bind=create_engine(config.db_url)
29
                    )
30
                )
42 31

  
43
    @staticmethod
44
    def create(login, post_values, idp_user, service_provider):
45
        pass
32
backend = import_backend(config.storage_backend)
33
Association = backend.Association
46 34

  
47
    @staticmethod
48
    def get_or_create(login, post_values, idp_user, service_provider):
49
        pass
35
class AssociationExample(object):
36
    """
37
    association dictionnary return by the following methods:
38
    {
39
        'id': '', # identifier of your association (must be unique)
40
        'sp_name': '', # name of the service provider (defined in the mappers)
41
        'sp_login': '', # login on the service provider
42
        'sp_post_values': '', # the post values for sp login form
43
        'idp_unique_id:': '', # the unique identifier of the identity provider (ex.: a saml NameID)
44
        'idp_name':  '', # identity provide name
45
        'last_connection':  datetime.datetime, # last connection with this association
46
        'creation_date':  datetime.datetime, # creation date of this association
47
    }
48
    """
50 49

  
51 50
    @staticmethod
52
    def delete(sp_user):
51
    def get(sp_name, idp_unique_id, idp_name='dafault'):
52
        """ return a list of dict with associations that matching all of this options """
53 53
        pass
54 54

  
55 55
    @staticmethod
56
    def save(sp_user):
56
    def get_by_id(asso_id):
57
        """ return an dict of the association with the id or None if it doesn't exist """
57 58
        pass
58 59

  
59
class DefaultServiceProvider:
60

  
61 60
    @staticmethod
62
    def get(name):
61
    def has_id(asso_id):
62
        """ return a boolean """
63 63
        pass
64 64

  
65 65
    @staticmethod
66
    def create(name):
66
    def update_or_create(sp_name, sp_login, sp_post_values, idp_unique_id, idp_name):
67
        """ update or create an associtaion which match the following values
68
        return the association id
69
        """
67 70
        pass
68 71

  
69 72
    @staticmethod
70
    def get_or_create(name):
73
    def delete(asso_id):
74
        """ delete the association which has the following asso_id """
71 75
        pass
72 76

  
73 77
    @staticmethod
74
    def delete(service_provider):
78
    def get_last_connected(sp_name, idp_unique_id, idp_name='default'):
79
        """ get the last connecting association which match the parameters
80
        return a dict of the association
81
        """
75 82
        pass
76 83

  
77 84
    @staticmethod
78
    def save(service_provider):
85
    def update_last_connection(asso_id):
86
        """ update the association last conenction time with the current time
87
        return a dict of the association
88
        """
79 89
        pass
80

  
81
def import_backend(path):
82
    try:
83
        mod = import_module(path)
84
    except ImportError, e:
85
        raise ImproperlyConfigured('Error importing backend %s: "%s"' % (path, e))
86
    return mod
87

  
88
backend = import_backend(config.storage_backend)
89
ManagerServiceProvider = backend.ManagerServiceProvider
90
ManagerIDPUser = backend.ManagerIDPUser
91
ManagerSPUser = backend.ManagerSPUser
92

  
mandaye/backends/sql.py
1 1

  
2
import copy
3

  
2 4
from datetime import datetime
3 5

  
4
from mandaye.db import sql_session
6
from mandaye.backends.default import storage_conn
5 7
from mandaye.log import logger
6 8
from mandaye.models import IDPUser, SPUser, ServiceProvider
7 9

  
8
class ManagerIDPUserSQL:
9

  
10
    @staticmethod
11
    def get(unique_id, idp_id='default'):
12
        idp_user = sql_session().query(IDPUser).\
13
                filter_by(unique_id=unique_id,
14
                        idp_id='default').all()
15
        if len(idp_user) > 1:
16
            logger.critical('ManagerIDPUserSQL.get %s not unique' % unique_id)
17
            raise MandayeException(
18
                    'ManagerIDPUserSQL.get : %s is not unique' % unique_id)
19
        if idp_user:
20
            return idp_user[0]
21
        else:
22
            return None
23

  
24
    @staticmethod
25
    def create(unique_id, idp_id='default'):
26
        logger.info('Add idp user %s in db' % (unique_id))
27
        idp_user = IDPUser(
28
                    unique_id=unique_id,
29
                    idp_id=idp_id)
30
        sql_session().add(idp_user)
31
        return idp_user
32

  
33
    @staticmethod
34
    def get_or_create(unique_id, idp_id='default'):
35
        idp_user= ManagerIDPUserSQL.get(unique_id, idp_id)
36
        if idp_user:
37
            return idp_user
38
        else:
39
            return ManagerIDPUserSQL.create(unique_id, idp_id)
40

  
41
    @staticmethod
42
    def delete(idp_user):
43
        logger.info('Delete in db idp user %s' % idp_user.unique_id)
44
        sql_session().delete(idp_user)
45
        sql_session().commit()
46

  
47
    @staticmethod
48
    def save():
49
        sql_session().commit()
50

  
51
class ManagerSPUserSQL:
52

  
53
    @staticmethod
54
    def get(login, idp_user, service_provider):
55
        return sql_session().query(SPUser).\
10
class Association(object):
11
    """
12
    association dictionnary return by the following methods:
13
    {
14
        'id': '', # identifier of your association (must be unique)
15
        'sp_name': '', # name of the service provider (defined in the mappers)
16
        'sp_login': '', # login on the service provider
17
        'sp_post_values': '', # the post values for sp login form
18
        'idp_unique_id:': '', # the unique identifier of the identity provider (ex.: a saml NameID)
19
        'idp_name':  '', # identity provide name
20
        'last_connection':  datetime.datetime, # last connection with this association
21
        'creation_date':  datetime.datetime, # creation date of this association
22
    }
23
    """
24

  
25
    @staticmethod
26
    def sp_user2association(sp_user):
27
        return {
28
                'id': sp_user.id,
29
                'sp_name': sp_user.service_provider.name,
30
                'sp_login': sp_user.login,
31
                'sp_post_values': sp_user.post_values,
32
                'idp_unique_id': sp_user.idp_user.unique_id,
33
                'idp_name': sp_user.idp_user.idp_id,
34
                'last_connection': sp_user.last_connection,
35
                'creation_date': sp_user.creation_date
36
                }
37

  
38

  
39
    @staticmethod
40
    def get(sp_name, idp_unique_id, idp_name='dafault'):
41
        """ return a list of dict with associations that matching all of this options """
42
        associations = []
43
        sp_users = storage_conn.query(SPUser).\
56 44
                join(IDPUser).\
57 45
                join(ServiceProvider).\
58
                filter(SPUser.login==login).\
59
                filter(SPUser.idp_user==idp_user).\
60
                filter(SPUser.service_provider==service_provider).\
61
                first()
62

  
63
    @staticmethod
64
    def get_by_id(id):
65
        return sql_session().query(SPUser).\
66
                filter(SPUser.id==id).first()
67

  
68
    @staticmethod
69
    def get_last_connected(idp_user, service_provider):
70
        return sql_session().query(SPUser).\
71
                filter(SPUser.idp_user==idp_user).\
72
                filter(SPUser.service_provider==service_provider).\
73
                order_by(SPUser.last_connection.desc()).\
46
                filter(ServiceProvider.name==sp_name).\
47
                filter(IDPUser.unique_id==idp_unique_id).\
48
                filter(IDPUser.idp_id==idp_name).\
49
                all()
50
        for sp_user in sp_users:
51
            association = Association.sp_user2association(sp_user)
52
            associations.append(association)
53
        return associations
54

  
55
    @staticmethod
56
    def get_by_id(asso_id):
57
        """ return an dict of the association with the id or None if it doesn't exist """
58
        sp_user = storage_conn.query(SPUser).\
59
                filter(SPUser.id==asso_id).first()
60
        return Association.sp_user2association(sp_user)
61

  
62
    @staticmethod
63
    def has_id(asso_id):
64
        """ return a boolean """
65
        if storage_conn.query(SPUser).\
66
                filter(SPUser.id==asso_id).\
67
                count():
68
            return True
69
        return False
70

  
71
    @staticmethod
72
    def update_or_create(sp_name, sp_login, sp_post_values, idp_unique_id, idp_name='default'):
73
        """ update or create an associtaion which match the following values
74
        return the association id
75
        """
76
        sp_user = storage_conn.query(SPUser).\
77
                join(IDPUser).\
78
                join(ServiceProvider).\
79
                filter(SPUser.login==sp_login).\
80
                filter(ServiceProvider.name==sp_name).\
81
                filter(IDPUser.unique_id==idp_unique_id).\
82
                filter(IDPUser.idp_id==idp_name).\
74 83
                first()
75
    @staticmethod
76
    def get_sp_users(idp_unique_id, service_provider_name):
77
        return sql_session().query(SPUser).\
78
                    join(IDPUser).\
79
                    join(ServiceProvider).\
84
        if sp_user:
85
            sp_user.post_values = sp_post_values
86
            storage_conn.add(sp_user)
87
            logger.info('Modify association for %r (%r)', sp_login, idp_unique_id)
88
        else:
89
            service_provider = storage_conn.query(ServiceProvider).\
90
                    filter(ServiceProvider.name==sp_name).first()
91
            if not service_provider:
92
                logger.info('New service provider %r', sp_name)
93
                service_provider = ServiceProvider(name=sp_name)
94
                storage_conn.add(service_provider)
95
            idp_user = storage_conn.query(IDPUser).\
80 96
                    filter(IDPUser.unique_id==idp_unique_id).\
81
                    filter(ServiceProvider.name==service_provider_name).\
82
                    order_by(SPUser.last_connection.desc()).\
83
                    all()
84

  
85
    @staticmethod
86
    def create(login, post_values, idp_user, service_provider):
87
        sp_user = SPUser(
88
                    login = login,
89
                    post_values = post_values,
90
                    idp_user = idp_user,
91
                    service_provider = service_provider
97
                    filter(IDPUser.idp_id==idp_name).\
98
                    first()
99
            if not idp_user:
100
                logger.info('New IDP user %r', idp_unique_id)
101
                idp_user = IDPUser(
102
                        unique_id=idp_unique_id,
103
                        idp_id=idp_name
104
                        )
105
                storage_conn.add(idp_user)
106
            sp_user = SPUser(
107
                    login=sp_login,
108
                    post_values=sp_post_values,
109
                    idp_user=idp_user,
110
                    service_provider=service_provider
92 111
                    )
93
        logger.info('New association: %s with %s on site %s' % \
94
                    (login, idp_user.unique_id, service_provider.name))
95
        sql_session().add(sp_user)
96
        sql_session().commit()
97
        logger.debug('New SP user %s in db' % (login))
98
        return sp_user
99

  
100
    @staticmethod
101
    def get_or_create(login, post_values, idp_user, service_provider):
102
        sp_user = ManagerSPUserSQL.get(login, idp_user, service_provider)
112
            storage_conn.add(sp_user)
113
            try:
114
                storage_conn.commit()
115
            except:
116
                logger.error("update_or_create transaction failed so we rollback")
117
                storage_conn.rollback()
118
                raise
119
            logger.info('New association %r with %r', sp_login, idp_unique_id)
120
        return sp_user.id
121

  
122
    @staticmethod
123
    def delete(asso_id):
124
        """ delete the association which has the following asso_id """
125
        sp_user = storage_conn.query(SPUser).get(asso_id)
126
        if not sp_user:
127
            logger.warning("Association deletion failed: sp user %r doesn't exist", asso_id)
128
            return
129
        logger.info("Disassociate account %r (%r)", sp_user.login, sp_user.idp_user.unique_id)
130
        storage_conn.delete(sp_user)
131

  
132
    @staticmethod
133
    def get_last_connected(sp_name, idp_unique_id, idp_name='default'):
134
        """ get the last connecting association which match the parameters
135
        return a dict of the association
136
        """
137
        sp_user = storage_conn.query(SPUser).\
138
                filter(ServiceProvider.name==sp_name).\
139
                filter(IDPUser.unique_id==idp_unique_id).\
140
                filter(IDPUser.idp_id==idp_name).\
141
                order_by(SPUser.last_connection.desc()).\
142
                first()
103 143
        if sp_user:
104
            return sp_user
105
        else:
106
            return ManagerSPUserSQL.create(login, post_values,
107
                    idp_user, service_provider)
108
    @staticmethod
109
    def all():
110
        return sql_session().query(SPUser).all()
111

  
112
    @staticmethod
113
    def delete(sp_user):
114
        logger.debug('Disassociate account %s' % sp_user.login)
115
        sql_session().delete(sp_user)
116
        sql_session().commit()
117

  
118
    @staticmethod
119
    def save():
120
        sql_session().commit()
121

  
122
class ManagerServiceProviderSQL:
123

  
124
    @staticmethod
125
    def get(name):
126
        sp = sql_session().query(ServiceProvider).\
127
                filter_by(name=name)
128
        if sp:
129
            return sp.first()
144
            return Association.sp_user2association(sp_user)
130 145
        else:
131 146
            return None
132 147

  
133 148
    @staticmethod
134
    def create(name):
135
        logger.info('Add %s service provider into the db' % name)
136
        sp = ServiceProvider(name=name)
137
        sql_session().add(sp)
138
        sql_session().commit()
139
        return sp
140

  
141
    @staticmethod
142
    def get_or_create(name):
143
        sp = ManagerServiceProviderSQL.get(name)
144
        if sp:
145
            return sp
146
        else:
147
            return ManagerServiceProviderSQL.create(name)
148

  
149
    @staticmethod
150
    def delete(service_provider):
151
        logger.debug('Delete service provider %s' % service_provider.name)
152
        sql_session().delete(service_provider)
153
        sql_session().commit()
154

  
155
    @staticmethod
156
    def save():
157
        sql_session().commit()
158

  
159
ManagerServiceProvider = ManagerServiceProviderSQL
160
ManagerIDPUser = ManagerIDPUserSQL
161
ManagerSPUser = ManagerSPUserSQL
149
    def update_last_connection(asso_id):
150
        """ update the association last conenction time with the current time
151
        return None
152
        """
153
        sp_user = storage_conn.query(SPUser).get(asso_id)
154
        if not sp_user:
155
            logger.warning("Update last connecting failed: sp user %r doesn't exist", asso_id)
156
            return
157
        sp_user.last_connection = datetime.now()
158
        storage_conn.add(sp_user)
162 159

  
mandaye/db.py
1
from sqlalchemy import create_engine
2
from sqlalchemy.orm import sessionmaker, scoped_session
3

  
4
from mandaye import config
5

  
6
if not "sqlite" in config.db_url:
7
    sql_session = scoped_session(
8
            sessionmaker(
9
                bind=create_engine(config.db_url, pool_size=16,
10
                    pool_recycle=1800)
11
                )
12
            )
13
else:
14
    sql_session = scoped_session(
15
            sessionmaker(
16
                bind=create_engine(config.db_url)
17
                )
18
            )
mandaye/filters/default.py
1 1

  
2 2
import re
3 3
from mandaye import config
4
from mandaye.backends.default import ManagerSPUser
4
from mandaye.backends.default import Association
5 5
from mandaye.log import logger
6 6
from mandaye.response import template_response
7 7

  
......
80 80
            values['is_login'] = True
81 81
            site_name = env["mandaye.config"]["site_name"]
82 82
            if env['beaker.session'].get(site_name):
83
                logger.debug('toolbar there is one : %r' % \
84
                        ManagerSPUser.get_by_id(env['beaker.session'].get(site_name)))
85
                current_account = ManagerSPUser.get_by_id(env['beaker.session'].get(site_name))
83
                logger.debug('toolbar there is one : %r' %\
84
                        env['beaker.session'].get(site_name))
85
                current_account = Association.get_by_id(env['beaker.session'].get(site_name))
86 86
            else:
87 87
                logger.debug('toolbar: no account')
88 88
        values['account'] = current_account
mandaye/global_config.py
4 4
_PROJECT_PATH = os.path.join(os.path.dirname(__file__), '..')
5 5

  
6 6
# Choose storage
7
# Only mandaye.backends.sql at the moment
7
# Only sql at the moment
8 8
storage_backend = "mandaye.backends.sql"
9 9

  
10 10
## SQL Backend config
......
14 14
# dialect+driver://username:password@host:port/database
15 15
db_url = 'sqlite:///test.db'
16 16

  
17

  
17 18
# urllib2 debug mode
18 19
debug = False
19 20

  
mandaye/server.py
11 11
from urlparse import urlparse
12 12

  
13 13
from mandaye import config
14
from mandaye.exceptions import ImproperlyConfigured
14
from mandaye.backends.default import storage_conn
15 15
from mandaye.dispatcher import Dispatcher
16
from mandaye.exceptions import ImproperlyConfigured
16 17
from mandaye.log import logger, UuidFilter
17 18
from mandaye.handlers.default import MandayeRedirectHandler, MandayeErrorHandler
18 19
from mandaye.http import HTTPHeader, HTTPRequest, HTTPResponse
19 20
from mandaye.response import _404, _502, _500
20
from mandaye.db import sql_session
21 21

  
22 22

  
23 23
def get_response(env, request, url, cookiejar=None):
......
137 137
                        response = self.on_request(start_response)
138 138
            if not response:
139 139
                response = self.on_response(start_response, _404(env['PATH_INFO']))
140
            sql_session.commit()
140
            if config.storage_backend == 'mandaye.backends.sql':
141
                storage_conn.commit()
141 142
        except Exception, e:
142
            sql_session.rollback()
143
            if config.storage_backend == 'mandaye.backends.sql':
144
                storage_conn.rollback()
143 145
            if self.raven_client:
144 146
                self.raven_client.captureException()
145 147
            response = self.on_response(start_response, _500(env['PATH_INFO'], "Unhandled exception",
146 148
                exception=e, env=env))
147 149
        finally:
148
            sql_session.close()
150
            if config.storage_backend == 'mandaye.backends.sql':
151
                storage_conn.close()
149 152
        return response
150 153

  
151 154
    def _get_uuid(self):
mandaye/templates/toolbar.html
14 14
    </li>
15 15
    % if account:
16 16
    <li>
17
      <a href="javascript:mandaye_disassociate_logout('${urls['disassociate_url']}', '${account.login}', ${account.id})" title="Cliquer ici pour supprimer l'association entre ce compte et votre compte citoyen.">Me désassocier</a>
17
      <a href="javascript:mandaye_disassociate_logout('${urls['disassociate_url']}', '${account['login']}', ${account['id']})" title="Cliquer ici pour supprimer l'association entre ce compte et votre compte citoyen.">Me désassocier</a>
18 18
    </li>
19 19
    % endif
20 20
    % else:
requirements.txt
2 2
pycrypto>=2.0
3 3
lxml>=2.0
4 4
xtraceback>=0.3
5
sqlalchemy>=0.7,<0.8
5
sqlalchemy>=0.7,<1.0
6 6
alembic>=0.5.0
7 7
Mako>=0.4
8 8
python-entrouvert

Formats disponibles : Unified diff