web/test/unittest_views_basecontrollers.py
changeset 9846 67c1b77b44be
parent 9675 8aabfefc8a81
child 10016 984505da8b89
equal deleted inserted replaced
9845:9c3ec404534f 9846:67c1b77b44be
     1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     1 # copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     3 #
     3 #
     4 # This file is part of CubicWeb.
     4 # This file is part of CubicWeb.
     5 #
     5 #
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
    21 # parse_qs is deprecated in cgi and has been moved to urlparse in Python 2.6
    21 # parse_qs is deprecated in cgi and has been moved to urlparse in Python 2.6
    22 try:
    22 try:
    23     from urlparse import parse_qs as url_parse_query
    23     from urlparse import parse_qs as url_parse_query
    24 except ImportError:
    24 except ImportError:
    25     from cgi import parse_qs as url_parse_query
    25     from cgi import parse_qs as url_parse_query
    26 from logilab.common.testlib import unittest_main, mock_object
    26 from logilab.common.testlib import unittest_main
    27 from logilab.common.decorators import monkeypatch
    27 from logilab.common.decorators import monkeypatch
    28 
    28 
    29 from cubicweb import Binary, NoSelectableObject, ValidationError
    29 from cubicweb import Binary, NoSelectableObject, ValidationError
    30 from cubicweb.view import STRICT_DOCTYPE
       
    31 from cubicweb.devtools.testlib import CubicWebTC
    30 from cubicweb.devtools.testlib import CubicWebTC
    32 from cubicweb.utils import json_dumps
    31 from cubicweb.utils import json_dumps
    33 from cubicweb.uilib import rql_for_eid
    32 from cubicweb.uilib import rql_for_eid
    34 from cubicweb.web import INTERNAL_FIELD_VALUE, Redirect, RequestError, RemoteCallFailed
    33 from cubicweb.web import Redirect, RemoteCallFailed
    35 import cubicweb.server.session
    34 import cubicweb.server.session
    36 from cubicweb.server.session import Connection as OldConnection
    35 from cubicweb.server.session import Connection as OldConnection
    37 from cubicweb.entities.authobjs import CWUser
       
    38 from cubicweb.web.views.autoform import get_pending_inserts, get_pending_deletes
    36 from cubicweb.web.views.autoform import get_pending_inserts, get_pending_deletes
    39 from cubicweb.web.views.basecontrollers import JSonController, xhtmlize, jsonize
    37 from cubicweb.web.views.basecontrollers import JSonController, xhtmlize, jsonize
    40 from cubicweb.web.views.ajaxcontroller import ajaxfunc, AjaxFunction
    38 from cubicweb.web.views.ajaxcontroller import ajaxfunc, AjaxFunction
    41 import cubicweb.transaction as tx
    39 import cubicweb.transaction as tx
    42 from cubicweb.server.hook import Hook, Operation
    40 from cubicweb.server.hook import Hook, Operation
    43 from cubicweb.predicates import is_instance
    41 from cubicweb.predicates import is_instance
    44 
    42 
    45 u = unicode
       
    46 
       
    47 def req_form(user):
    43 def req_form(user):
    48     return {'eid': [str(user.eid)],
    44     return {'eid': [str(user.eid)],
    49             '_cw_entity_fields:%s' % user.eid: '_cw_generic_field',
    45             '_cw_entity_fields:%s' % user.eid: '_cw_generic_field',
    50             '__type:%s' % user.eid: user.__regid__
    46             '__type:%s' % user.eid: user.__regid__
    51             }
    47             }
    52 
    48 
       
    49 
    53 class EditControllerTC(CubicWebTC):
    50 class EditControllerTC(CubicWebTC):
       
    51 
    54     def setUp(self):
    52     def setUp(self):
    55         CubicWebTC.setUp(self)
    53         CubicWebTC.setUp(self)
    56         self.assertIn('users', self.schema.eschema('CWGroup').get_groups('read'))
    54         self.assertIn('users', self.schema.eschema('CWGroup').get_groups('read'))
    57 
    55 
    58     def tearDown(self):
    56     def tearDown(self):
    60         self.assertIn('users', self.schema.eschema('CWGroup').get_groups('read'))
    58         self.assertIn('users', self.schema.eschema('CWGroup').get_groups('read'))
    61 
    59 
    62     def test_noparam_edit(self):
    60     def test_noparam_edit(self):
    63         """check behaviour of this controller without any form parameter
    61         """check behaviour of this controller without any form parameter
    64         """
    62         """
    65         with self.assertRaises(ValidationError) as cm:
    63         with self.admin_access.web_request() as req:
    66             self.ctrl_publish(self.request())
    64             with self.assertRaises(ValidationError) as cm:
    67         self.assertEqual(cm.exception.errors, {None: u'no selected entities'})
    65                 self.ctrl_publish(req)
       
    66             self.assertEqual(cm.exception.errors, {None: u'no selected entities'})
    68 
    67 
    69     def test_validation_unique(self):
    68     def test_validation_unique(self):
    70         """test creation of two linked entities
    69         """test creation of two linked entities
    71         """
    70         """
    72         user = self.user()
    71         with self.admin_access.web_request() as req:
    73         req = self.request()
    72             req.form = {'eid': 'X', '__type:X': 'CWUser',
    74         req.form = {'eid': 'X', '__type:X': 'CWUser',
    73                         '_cw_entity_fields:X': 'login-subject,upassword-subject',
    75                     '_cw_entity_fields:X': 'login-subject,upassword-subject',
    74                         'login-subject:X': u'admin',
    76                     'login-subject:X': u'admin',
    75                         'upassword-subject:X': u'toto',
    77                     'upassword-subject:X': u'toto',
    76                         'upassword-subject-confirm:X': u'toto',
    78                     'upassword-subject-confirm:X': u'toto',
       
    79                     }
    77                     }
    80         with self.assertRaises(ValidationError) as cm:
    78             with self.assertRaises(ValidationError) as cm:
    81             self.ctrl_publish(req)
    79                 self.ctrl_publish(req)
    82         cm.exception.translate(unicode)
    80                 cm.exception.translate(unicode)
    83         self.assertEqual(cm.exception.errors, {'login-subject': 'the value "admin" is already used, use another one'})
    81                 self.assertEqual({'login-subject': 'the value "admin" is already used, use another one'},
       
    82                                  cm.exception.errors)
    84 
    83 
    85     def test_user_editing_itself(self):
    84     def test_user_editing_itself(self):
    86         """checking that a manager user can edit itself
    85         """checking that a manager user can edit itself
    87         """
    86         """
    88         user = self.user()
    87         with self.admin_access.web_request() as req:
    89         basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X in_group G, X eid %(x)s', {'x': user.eid})]
    88             user = req.user
    90         groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')]
    89             groupeids = [eid for eid, in req.execute('CWGroup G WHERE G name '
    91         groups = [u(eid) for eid in groupeids]
    90                                                      'in ("managers", "users")')]
    92         req = self.request()
    91             groups = [unicode(eid) for eid in groupeids]
    93         eid = u(user.eid)
    92             eid = unicode(user.eid)
    94         req.form = {
    93             req.form = {
    95             'eid': eid, '__type:'+eid: 'CWUser',
    94                 'eid': eid, '__type:'+eid: 'CWUser',
    96             '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject',
    95                 '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject',
    97             'login-subject:'+eid:     u(user.login),
    96                 'login-subject:'+eid:     unicode(user.login),
    98             'surname-subject:'+eid: u'Th\xe9nault',
    97                 'surname-subject:'+eid: u'Th\xe9nault',
    99             'firstname-subject:'+eid:   u'Sylvain',
    98                 'firstname-subject:'+eid:   u'Sylvain',
   100             'in_group-subject:'+eid:  groups,
    99                 'in_group-subject:'+eid:  groups,
   101             }
   100                 }
   102         path, params = self.expect_redirect_handle_request(req, 'edit')
   101             self.expect_redirect_handle_request(req, 'edit')
   103         e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0)
   102             e = req.execute('Any X WHERE X eid %(x)s',
   104         self.assertEqual(e.firstname, u'Sylvain')
   103                             {'x': user.eid}).get_entity(0, 0)
   105         self.assertEqual(e.surname, u'Th\xe9nault')
   104             self.assertEqual(e.firstname, u'Sylvain')
   106         self.assertEqual(e.login, user.login)
   105             self.assertEqual(e.surname, u'Th\xe9nault')
   107         self.assertEqual([g.eid for g in e.in_group], groupeids)
   106             self.assertEqual(e.login, user.login)
       
   107             self.assertEqual([g.eid for g in e.in_group], groupeids)
   108 
   108 
   109     def test_user_can_change_its_password(self):
   109     def test_user_can_change_its_password(self):
   110         req = self.request()
   110         with self.admin_access.repo_cnx() as cnx:
   111         user = self.create_user(req, 'user')
   111             self.create_user(cnx, 'user')
   112         cnx = self.login('user')
   112             cnx.commit()
   113         eid = u(user.eid)
   113         with self.new_access('user').web_request() as req:
   114         req.form = {
   114             eid = unicode(req.user.eid)
   115             'eid': eid, '__maineid' : eid,
   115             req.form = {
   116             '__type:'+eid: 'CWUser',
   116                 'eid': eid, '__maineid' : eid,
   117             '_cw_entity_fields:'+eid: 'upassword-subject',
   117                 '__type:'+eid: 'CWUser',
   118             'upassword-subject:'+eid: 'tournicoton',
   118                 '_cw_entity_fields:'+eid: 'upassword-subject',
   119             'upassword-subject-confirm:'+eid: 'tournicoton',
   119                 'upassword-subject:'+eid: 'tournicoton',
   120             }
   120                 'upassword-subject-confirm:'+eid: 'tournicoton',
   121         path, params = self.expect_redirect_handle_request(req, 'edit')
   121                 }
   122         cnx.commit() # commit to check we don't get late validation error for instance
   122             path, params = self.expect_redirect_handle_request(req, 'edit')
   123         self.assertEqual(path, 'cwuser/user')
   123             req.cnx.commit() # commit to check we don't get late validation error for instance
   124         self.assertNotIn('vid', params)
   124             self.assertEqual(path, 'cwuser/user')
       
   125             self.assertNotIn('vid', params)
   125 
   126 
   126     def test_user_editing_itself_no_relation(self):
   127     def test_user_editing_itself_no_relation(self):
   127         """checking we can edit an entity without specifying some required
   128         """checking we can edit an entity without specifying some required
   128         relations (meaning no changes)
   129         relations (meaning no changes)
   129         """
   130         """
   130         user = self.user()
   131         with self.admin_access.web_request() as req:
   131         groupeids = [g.eid for g in user.in_group]
   132             user = req.user
   132         req = self.request()
   133             groupeids = [g.eid for g in user.in_group]
   133         eid = u(user.eid)
   134             eid = unicode(user.eid)
   134         req.form = {
   135             req.form = {
   135             'eid':       eid,
   136                 'eid':       eid,
   136             '__type:'+eid:    'CWUser',
   137                 '__type:'+eid:    'CWUser',
   137             '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject',
   138                 '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject',
   138             'login-subject:'+eid:     u(user.login),
   139                 'login-subject:'+eid:     unicode(user.login),
   139             'firstname-subject:'+eid: u'Th\xe9nault',
   140                 'firstname-subject:'+eid: u'Th\xe9nault',
   140             'surname-subject:'+eid:   u'Sylvain',
   141                 'surname-subject:'+eid:   u'Sylvain',
   141             }
   142                 }
   142         path, params = self.expect_redirect_handle_request(req, 'edit')
   143             self.expect_redirect_handle_request(req, 'edit')
   143         e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0)
   144             e = req.execute('Any X WHERE X eid %(x)s',
   144         self.assertEqual(e.login, user.login)
   145                             {'x': user.eid}).get_entity(0, 0)
   145         self.assertEqual(e.firstname, u'Th\xe9nault')
   146             self.assertEqual(e.login, user.login)
   146         self.assertEqual(e.surname, u'Sylvain')
   147             self.assertEqual(e.firstname, u'Th\xe9nault')
   147         self.assertEqual([g.eid for g in e.in_group], groupeids)
   148             self.assertEqual(e.surname, u'Sylvain')
   148         self.assertEqual(e.cw_adapt_to('IWorkflowable').state, 'activated')
   149             self.assertEqual([g.eid for g in e.in_group], groupeids)
       
   150             self.assertEqual(e.cw_adapt_to('IWorkflowable').state, 'activated')
   149 
   151 
   150 
   152 
   151     def test_create_multiple_linked(self):
   153     def test_create_multiple_linked(self):
   152         gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
   154         with self.admin_access.web_request() as req:
   153         req = self.request()
   155             gueid = req.execute('CWGroup G WHERE G name "users"')[0][0]
   154         req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
   156             req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
   155 
   157                         '__type:X': 'CWUser',
   156                     '__type:X': 'CWUser',
   158                         '_cw_entity_fields:X': 'login-subject,upassword-subject,surname-subject,in_group-subject',
   157                     '_cw_entity_fields:X': 'login-subject,upassword-subject,surname-subject,in_group-subject',
   159                         'login-subject:X': u'adim',
   158                     'login-subject:X': u'adim',
   160                         'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
   159                     'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
   161                         'surname-subject:X': u'Di Mascio',
   160                     'surname-subject:X': u'Di Mascio',
   162                         'in_group-subject:X': unicode(gueid),
   161                     'in_group-subject:X': u(gueid),
   163 
   162 
   164                         '__type:Y': 'EmailAddress',
   163                     '__type:Y': 'EmailAddress',
   165                         '_cw_entity_fields:Y': 'address-subject,use_email-object',
   164                     '_cw_entity_fields:Y': 'address-subject,use_email-object',
   166                         'address-subject:Y': u'dima@logilab.fr',
   165                     'address-subject:Y': u'dima@logilab.fr',
   167                         'use_email-object:Y': 'X',
   166                     'use_email-object:Y': 'X',
   168                         }
   167                     }
   169             path, _params = self.expect_redirect_handle_request(req, 'edit')
   168         path, params = self.expect_redirect_handle_request(req, 'edit')
   170             # should be redirected on the created person
   169         # should be redirected on the created person
   171             self.assertEqual(path, 'cwuser/adim')
   170         self.assertEqual(path, 'cwuser/adim')
   172             e = req.execute('Any P WHERE P surname "Di Mascio"').get_entity(0, 0)
   171         e = self.execute('Any P WHERE P surname "Di Mascio"').get_entity(0, 0)
   173             self.assertEqual(e.surname, 'Di Mascio')
   172         self.assertEqual(e.surname, 'Di Mascio')
   174             email = e.use_email[0]
   173         email = e.use_email[0]
   175             self.assertEqual(email.address, 'dima@logilab.fr')
   174         self.assertEqual(email.address, 'dima@logilab.fr')
       
   175 
   176 
   176     def test_create_mandatory_inlined(self):
   177     def test_create_mandatory_inlined(self):
   177         req = self.request()
   178         with self.admin_access.web_request() as req:
   178         req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
   179             req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
   179 
   180 
   180                     '__type:X': 'Salesterm',
   181                         '__type:X': 'Salesterm',
   181                     '_cw_entity_fields:X': '',
   182                         '_cw_entity_fields:X': '',
   182 
   183 
   183                     '__type:Y': 'File',
   184                         '__type:Y': 'File',
   184                     '_cw_entity_fields:Y': 'data-subject,described_by_test-object',
   185                         '_cw_entity_fields:Y': 'data-subject,described_by_test-object',
   185                     'data-subject:Y': (u'coucou.txt', Binary('coucou')),
   186                         'data-subject:Y': (u'coucou.txt', Binary('coucou')),
   186                     'described_by_test-object:Y': 'X',
   187                         'described_by_test-object:Y': 'X',
   187                     }
   188                         }
   188         path, params = self.expect_redirect_handle_request(req, 'edit')
   189             path, _params = self.expect_redirect_handle_request(req, 'edit')
   189         self.assertTrue(path.startswith('salesterm/'), path)
   190             self.assertTrue(path.startswith('salesterm/'), path)
   190         eid = path.split('/')[1]
   191             eid = path.split('/')[1]
   191         salesterm = req.entity_from_eid(eid)
   192             salesterm = req.entity_from_eid(eid)
   192         # The NOT NULL constraint of mandatory relation implies that the File
   193             # The NOT NULL constraint of mandatory relation implies that the File
   193         # must be created before the Salesterm, otherwise Salesterm insertion
   194             # must be created before the Salesterm, otherwise Salesterm insertion
   194         # will fail.
   195             # will fail.
   195         # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
   196             # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
   196         # insertion does not fail and we have to check dumbly that File is
   197             # insertion does not fail and we have to check dumbly that File is
   197         # created before.
   198             # created before.
   198         self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
   199             self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
   199 
   200 
   200     def test_create_mandatory_inlined2(self):
   201     def test_create_mandatory_inlined2(self):
   201         req = self.request()
   202         with self.admin_access.web_request() as req:
   202         req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
   203             req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
   203 
   204 
   204                     '__type:X': 'Salesterm',
   205                         '__type:X': 'Salesterm',
   205                     '_cw_entity_fields:X': 'described_by_test-subject',
   206                         '_cw_entity_fields:X': 'described_by_test-subject',
   206                     'described_by_test-subject:X': 'Y',
   207                         'described_by_test-subject:X': 'Y',
   207 
   208 
   208                     '__type:Y': 'File',
   209                         '__type:Y': 'File',
   209                     '_cw_entity_fields:Y': 'data-subject',
   210                         '_cw_entity_fields:Y': 'data-subject',
   210                     'data-subject:Y': (u'coucou.txt', Binary('coucou')),
   211                         'data-subject:Y': (u'coucou.txt', Binary('coucou')),
   211                     }
   212                         }
   212         path, params = self.expect_redirect_handle_request(req, 'edit')
   213             path, _params = self.expect_redirect_handle_request(req, 'edit')
   213         self.assertTrue(path.startswith('salesterm/'), path)
   214             self.assertTrue(path.startswith('salesterm/'), path)
   214         eid = path.split('/')[1]
   215             eid = path.split('/')[1]
   215         salesterm = req.entity_from_eid(eid)
   216             salesterm = req.entity_from_eid(eid)
   216         # The NOT NULL constraint of mandatory relation implies that the File
   217             # The NOT NULL constraint of mandatory relation implies that the File
   217         # must be created before the Salesterm, otherwise Salesterm insertion
   218             # must be created before the Salesterm, otherwise Salesterm insertion
   218         # will fail.
   219             # will fail.
   219         # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
   220             # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
   220         # insertion does not fail and we have to check dumbly that File is
   221             # insertion does not fail and we have to check dumbly that File is
   221         # created before.
   222             # created before.
   222         self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
   223             self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
   223 
   224 
   224     def test_edit_mandatory_inlined3_object(self):
   225     def test_edit_mandatory_inlined3_object(self):
   225         # non regression test for #3120495. Without the fix, leads to
   226         # non regression test for #3120495. Without the fix, leads to
   226         # "unhashable type: 'list'" error
   227         # "unhashable type: 'list'" error
   227         req = self.request()
   228         with self.admin_access.web_request() as req:
   228         cwrelation = u(req.execute('CWEType X WHERE X name "CWSource"')[0][0])
   229             cwrelation = unicode(req.execute('CWEType X WHERE X name "CWSource"')[0][0])
   229         req.form = {'eid': [cwrelation], '__maineid' : cwrelation,
   230             req.form = {'eid': [cwrelation], '__maineid' : cwrelation,
   230 
   231 
   231                     '__type:'+cwrelation: 'CWEType',
   232                         '__type:'+cwrelation: 'CWEType',
   232                     '_cw_entity_fields:'+cwrelation: 'to_entity-object',
   233                         '_cw_entity_fields:'+cwrelation: 'to_entity-object',
   233                     'to_entity-object:'+cwrelation: [9999, 9998],
   234                         'to_entity-object:'+cwrelation: [9999, 9998],
   234                     }
   235                         }
   235         with self.session.deny_all_hooks_but():
   236             with req.cnx.deny_all_hooks_but():
   236             path, params = self.expect_redirect_handle_request(req, 'edit')
   237                 path, _params = self.expect_redirect_handle_request(req, 'edit')
   237         self.assertTrue(path.startswith('cwetype/CWSource'), path)
   238             self.assertTrue(path.startswith('cwetype/CWSource'), path)
   238 
   239 
   239     def test_edit_multiple_linked(self):
   240     def test_edit_multiple_linked(self):
   240         req = self.request()
   241         with self.admin_access.web_request() as req:
   241         peid = u(self.create_user(req, 'adim').eid)
   242             peid = unicode(self.create_user(req, 'adim').eid)
   242         req.form = {'eid': [peid, 'Y'], '__maineid': peid,
   243             req.form = {'eid': [peid, 'Y'], '__maineid': peid,
   243 
   244 
   244                     '__type:'+peid: u'CWUser',
   245                         '__type:'+peid: u'CWUser',
   245                     '_cw_entity_fields:'+peid: u'surname-subject',
   246                         '_cw_entity_fields:'+peid: u'surname-subject',
   246                     'surname-subject:'+peid: u'Di Masci',
   247                         'surname-subject:'+peid: u'Di Masci',
   247 
   248 
   248                     '__type:Y': u'EmailAddress',
   249                         '__type:Y': u'EmailAddress',
   249                     '_cw_entity_fields:Y': u'address-subject,use_email-object',
   250                         '_cw_entity_fields:Y': u'address-subject,use_email-object',
   250                     'address-subject:Y': u'dima@logilab.fr',
   251                         'address-subject:Y': u'dima@logilab.fr',
   251                     'use_email-object:Y': peid,
   252                         'use_email-object:Y': peid,
   252                     }
   253                         }
   253         path, params = self.expect_redirect_handle_request(req, 'edit')
   254             path, _params = self.expect_redirect_handle_request(req, 'edit')
   254         # should be redirected on the created person
   255             # should be redirected on the created person
   255         self.assertEqual(path, 'cwuser/adim')
   256             self.assertEqual(path, 'cwuser/adim')
   256         e = self.execute('Any P WHERE P surname "Di Masci"').get_entity(0, 0)
   257             e = req.execute('Any P WHERE P surname "Di Masci"').get_entity(0, 0)
   257         email = e.use_email[0]
   258             email = e.use_email[0]
   258         self.assertEqual(email.address, 'dima@logilab.fr')
   259             self.assertEqual(email.address, 'dima@logilab.fr')
   259 
   260 
   260         emaileid = u(email.eid)
   261         # with self.admin_access.web_request() as req:
   261         req = self.request()
   262             emaileid = unicode(email.eid)
   262         req.form = {'eid': [peid, emaileid],
   263             req.form = {'eid': [peid, emaileid],
   263 
   264 
   264                     '__type:'+peid: u'CWUser',
   265                         '__type:'+peid: u'CWUser',
   265                     '_cw_entity_fields:'+peid: u'surname-subject',
   266                         '_cw_entity_fields:'+peid: u'surname-subject',
   266                     'surname-subject:'+peid: u'Di Masci',
   267                         'surname-subject:'+peid: u'Di Masci',
   267 
   268 
   268                     '__type:'+emaileid: u'EmailAddress',
   269                         '__type:'+emaileid: u'EmailAddress',
   269                     '_cw_entity_fields:'+emaileid: u'address-subject,use_email-object',
   270                         '_cw_entity_fields:'+emaileid: u'address-subject,use_email-object',
   270                     'address-subject:'+emaileid: u'adim@logilab.fr',
   271                         'address-subject:'+emaileid: u'adim@logilab.fr',
   271                     'use_email-object:'+emaileid: peid,
   272                         'use_email-object:'+emaileid: peid,
   272                     }
   273                         }
   273         path, params = self.expect_redirect_handle_request(req, 'edit')
   274             self.expect_redirect_handle_request(req, 'edit')
   274         email.cw_clear_all_caches()
   275             email.cw_clear_all_caches()
   275         self.assertEqual(email.address, 'adim@logilab.fr')
   276             self.assertEqual(email.address, 'adim@logilab.fr')
   276 
       
   277 
   277 
   278     def test_password_confirm(self):
   278     def test_password_confirm(self):
   279         """test creation of two linked entities
   279         """test creation of two linked entities
   280         """
   280         """
   281         user = self.user()
   281         with self.admin_access.web_request() as req:
   282         req = self.request()
   282             user = req.user
   283         req.form = {'eid': 'X',
   283             req.form = {'eid': 'X',
   284                     '__cloned_eid:X': u(user.eid), '__type:X': 'CWUser',
   284                         '__cloned_eid:X': unicode(user.eid), '__type:X': 'CWUser',
   285                     '_cw_entity_fields:X': 'login-subject,upassword-subject',
   285                         '_cw_entity_fields:X': 'login-subject,upassword-subject',
   286                     'login-subject:X': u'toto',
   286                         'login-subject:X': u'toto',
   287                     'upassword-subject:X': u'toto',
   287                         'upassword-subject:X': u'toto',
       
   288                         }
       
   289             with self.assertRaises(ValidationError) as cm:
       
   290                 self.ctrl_publish(req)
       
   291             self.assertEqual({'upassword-subject': u'password and confirmation don\'t match'},
       
   292                              cm.exception.errors)
       
   293             req.form = {'__cloned_eid:X': unicode(user.eid),
       
   294                         'eid': 'X', '__type:X': 'CWUser',
       
   295                         '_cw_entity_fields:X': 'login-subject,upassword-subject',
       
   296                         'login-subject:X': u'toto',
       
   297                         'upassword-subject:X': u'toto',
       
   298                         'upassword-subject-confirm:X': u'tutu',
       
   299                         }
       
   300             with self.assertRaises(ValidationError) as cm:
       
   301                 self.ctrl_publish(req)
       
   302             self.assertEqual({'upassword-subject': u'password and confirmation don\'t match'},
       
   303                              cm.exception.errors)
       
   304 
       
   305 
       
   306     def test_interval_bound_constraint_success(self):
       
   307         with self.admin_access.repo_cnx() as cnx:
       
   308             feid = cnx.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
       
   309                                {'data': Binary('yo')})[0][0]
       
   310             cnx.commit()
       
   311 
       
   312         with self.admin_access.web_request(rollbackfirst=True) as req:
       
   313             req.form = {'eid': ['X'],
       
   314                         '__type:X': 'Salesterm',
       
   315                         '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
       
   316                         'amount-subject:X': u'-10',
       
   317                         'described_by_test-subject:X': unicode(feid),
   288                     }
   318                     }
   289         with self.assertRaises(ValidationError) as cm:
   319             with self.assertRaises(ValidationError) as cm:
   290             self.ctrl_publish(req)
   320                 self.ctrl_publish(req)
   291         self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'})
   321             cm.exception.translate(unicode)
   292         req = self.request()
   322             self.assertEqual({'amount-subject': 'value -10 must be >= 0'},
   293         req.form = {'__cloned_eid:X': u(user.eid),
   323                              cm.exception.errors)
   294                     'eid': 'X', '__type:X': 'CWUser',
   324 
   295                     '_cw_entity_fields:X': 'login-subject,upassword-subject',
   325         with self.admin_access.web_request(rollbackfirst=True) as req:
   296                     'login-subject:X': u'toto',
   326             req.form = {'eid': ['X'],
   297                     'upassword-subject:X': u'toto',
   327                         '__type:X': 'Salesterm',
   298                     'upassword-subject-confirm:X': u'tutu',
   328                         '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
   299                     }
   329                         'amount-subject:X': u'110',
   300         with self.assertRaises(ValidationError) as cm:
   330                         'described_by_test-subject:X': unicode(feid),
   301             self.ctrl_publish(req)
   331                         }
   302         self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'})
   332             with self.assertRaises(ValidationError) as cm:
   303 
   333                 self.ctrl_publish(req)
   304 
   334             cm.exception.translate(unicode)
   305     def test_interval_bound_constraint_success(self):
   335             self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'})
   306         feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
   336 
   307                             {'data': Binary('yo')})[0][0]
   337         with self.admin_access.web_request(rollbackfirst=True) as req:
   308         self.commit()
   338             req.form = {'eid': ['X'],
   309         req = self.request(rollbackfirst=True)
   339                         '__type:X': 'Salesterm',
   310         req.form = {'eid': ['X'],
   340                         '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
   311                     '__type:X': 'Salesterm',
   341                         'amount-subject:X': u'10',
   312                     '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
   342                         'described_by_test-subject:X': unicode(feid),
   313                     'amount-subject:X': u'-10',
   343                         }
   314                     'described_by_test-subject:X': u(feid),
   344             self.expect_redirect_handle_request(req, 'edit')
   315                 }
   345             # should be redirected on the created
   316         with self.assertRaises(ValidationError) as cm:
   346             #eid = params['rql'].split()[-1]
   317             self.ctrl_publish(req)
   347             e = req.execute('Salesterm X').get_entity(0, 0)
   318         cm.exception.translate(unicode)
   348             self.assertEqual(e.amount, 10)
   319         self.assertEqual(cm.exception.errors, {'amount-subject': 'value -10 must be >= 0'})
       
   320         req = self.request(rollbackfirst=True)
       
   321         req.form = {'eid': ['X'],
       
   322                     '__type:X': 'Salesterm',
       
   323                     '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
       
   324                     'amount-subject:X': u'110',
       
   325                     'described_by_test-subject:X': u(feid),
       
   326                     }
       
   327         with self.assertRaises(ValidationError) as cm:
       
   328             self.ctrl_publish(req)
       
   329         cm.exception.translate(unicode)
       
   330         self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'})
       
   331 
       
   332         req = self.request(rollbackfirst=True)
       
   333         req.form = {'eid': ['X'],
       
   334                     '__type:X': 'Salesterm',
       
   335                     '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
       
   336                     'amount-subject:X': u'10',
       
   337                     'described_by_test-subject:X': u(feid),
       
   338                     }
       
   339         self.expect_redirect_handle_request(req, 'edit')
       
   340         # should be redirected on the created
       
   341         #eid = params['rql'].split()[-1]
       
   342         e = self.execute('Salesterm X').get_entity(0, 0)
       
   343         self.assertEqual(e.amount, 10)
       
   344 
   349 
   345     def test_interval_bound_constraint_validateform(self):
   350     def test_interval_bound_constraint_validateform(self):
   346         """Test the FormValidatorController controller on entity with
   351         """Test the FormValidatorController controller on entity with
   347         constrained attributes"""
   352         constrained attributes"""
   348         feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
   353         with self.admin_access.repo_cnx() as cnx:
   349                             {'data': Binary('yo')})[0][0]
   354             feid = cnx.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
   350         seid = self.request().create_entity('Salesterm', amount=0, described_by_test=feid).eid
   355                                {'data': Binary('yo')})[0][0]
   351         self.commit()
   356             seid = cnx.create_entity('Salesterm', amount=0, described_by_test=feid).eid
       
   357             cnx.commit()
   352 
   358 
   353         # ensure a value that violate a constraint is properly detected
   359         # ensure a value that violate a constraint is properly detected
   354         req = self.request(rollbackfirst=True)
   360         with self.admin_access.web_request(rollbackfirst=True) as req:
   355         req.form = {'eid': [unicode(seid)],
   361             req.form = {'eid': [unicode(seid)],
   356                     '__type:%s'%seid: 'Salesterm',
   362                         '__type:%s'%seid: 'Salesterm',
   357                     '_cw_entity_fields:%s'%seid: 'amount-subject',
   363                         '_cw_entity_fields:%s'%seid: 'amount-subject',
   358                     'amount-subject:%s'%seid: u'-10',
   364                         'amount-subject:%s'%seid: u'-10',
   359                 }
   365                     }
   360         self.assertEqual('''<script type="text/javascript">
   366             self.assertMultiLineEqual('''<script type="text/javascript">
   361  window.parent.handleFormValidationResponse('entityForm', null, null, [false, [%s, {"amount-subject": "value -10 must be >= 0"}], null], null);
   367  window.parent.handleFormValidationResponse('entityForm', null, null, [false, [%s, {"amount-subject": "value -10 must be >= 0"}], null], null);
   362 </script>'''%seid, self.ctrl_publish(req, 'validateform'))
   368 </script>'''%seid, self.ctrl_publish(req, 'validateform'))
   363 
   369 
   364         # ensure a value that comply a constraint is properly processed
   370         # ensure a value that comply a constraint is properly processed
   365         req = self.request(rollbackfirst=True)
   371         with self.admin_access.web_request(rollbackfirst=True) as req:
   366         req.form = {'eid': [unicode(seid)],
   372             req.form = {'eid': [unicode(seid)],
   367                     '__type:%s'%seid: 'Salesterm',
   373                         '__type:%s'%seid: 'Salesterm',
   368                     '_cw_entity_fields:%s'%seid: 'amount-subject',
   374                         '_cw_entity_fields:%s'%seid: 'amount-subject',
   369                     'amount-subject:%s'%seid: u'20',
   375                         'amount-subject:%s'%seid: u'20',
   370                 }
   376                     }
   371         self.assertEqual('''<script type="text/javascript">
   377             self.assertMultiLineEqual('''<script type="text/javascript">
   372  window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
   378  window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
   373 </script>''', self.ctrl_publish(req, 'validateform'))
   379 </script>''', self.ctrl_publish(req, 'validateform'))
   374         self.assertEqual(20, self.execute('Any V WHERE X amount V, X eid %(eid)s', {'eid': seid})[0][0])
   380             self.assertEqual(20, req.execute('Any V WHERE X amount V, X eid %(eid)s',
   375 
   381                                              {'eid': seid})[0][0])
   376         req = self.request(rollbackfirst=True)
   382 
   377         req.form = {'eid': ['X'],
   383         with self.admin_access.web_request(rollbackfirst=True) as req:
   378                     '__type:X': 'Salesterm',
   384             req.form = {'eid': ['X'],
   379                     '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
   385                         '__type:X': 'Salesterm',
   380                     'amount-subject:X': u'0',
   386                         '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
   381                     'described_by_test-subject:X': u(feid),
   387                         'amount-subject:X': u'0',
   382                 }
   388                         'described_by_test-subject:X': unicode(feid),
   383 
   389                     }
   384         # ensure a value that is modified in an operation on a modify
   390 
   385         # hook works as it should (see
   391             # ensure a value that is modified in an operation on a modify
   386         # https://www.cubicweb.org/ticket/2509729 )
   392             # hook works as it should (see
   387         class MyOperation(Operation):
   393             # https://www.cubicweb.org/ticket/2509729 )
   388             def precommit_event(self):
   394             class MyOperation(Operation):
   389                 self.entity.cw_set(amount=-10)
   395                 def precommit_event(self):
   390         class ValidationErrorInOpAfterHook(Hook):
   396                     self.entity.cw_set(amount=-10)
   391             __regid__ = 'valerror-op-after-hook'
   397             class ValidationErrorInOpAfterHook(Hook):
   392             __select__ = Hook.__select__ & is_instance('Salesterm')
   398                 __regid__ = 'valerror-op-after-hook'
   393             events = ('after_add_entity',)
   399                 __select__ = Hook.__select__ & is_instance('Salesterm')
   394             def __call__(self):
   400                 events = ('after_add_entity',)
   395                 MyOperation(self._cw, entity=self.entity)
   401                 def __call__(self):
   396 
   402                     MyOperation(self._cw, entity=self.entity)
   397         with self.temporary_appobjects(ValidationErrorInOpAfterHook):
   403 
   398             self.assertEqual('''<script type="text/javascript">
   404             with self.temporary_appobjects(ValidationErrorInOpAfterHook):
       
   405                 self.assertMultiLineEqual('''<script type="text/javascript">
   399  window.parent.handleFormValidationResponse('entityForm', null, null, [false, ["X", {"amount-subject": "value -10 must be >= 0"}], null], null);
   406  window.parent.handleFormValidationResponse('entityForm', null, null, [false, ["X", {"amount-subject": "value -10 must be >= 0"}], null], null);
   400 </script>''', self.ctrl_publish(req, 'validateform'))
   407 </script>''', self.ctrl_publish(req, 'validateform'))
   401 
   408 
   402         self.assertEqual('''<script type="text/javascript">
   409             self.assertMultiLineEqual('''<script type="text/javascript">
   403  window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
   410  window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
   404 </script>''', self.ctrl_publish(req, 'validateform'))
   411 </script>''', self.ctrl_publish(req, 'validateform'))
   405 
   412 
   406     def test_req_pending_insert(self):
   413     def test_req_pending_insert(self):
   407         """make sure req's pending insertions are taken into account"""
   414         """make sure req's pending insertions are taken into account"""
   408         tmpgroup = self.request().create_entity('CWGroup', name=u"test")
   415         with self.admin_access.web_request() as req:
   409         user = self.user()
   416             tmpgroup = req.create_entity('CWGroup', name=u"test")
   410         req = self.request(**req_form(user))
   417             user = req.user
   411         req.session.data['pending_insert'] = set([(user.eid, 'in_group', tmpgroup.eid)])
   418             req.cnx.commit()
   412         path, params = self.expect_redirect_handle_request(req, 'edit')
   419         with self.admin_access.web_request(**req_form(user)) as req:
   413         usergroups = [gname for gname, in
   420             req.session.data['pending_insert'] = set([(user.eid, 'in_group', tmpgroup.eid)])
   414                       self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
   421             self.expect_redirect_handle_request(req, 'edit')
   415         self.assertCountEqual(usergroups, ['managers', 'test'])
   422             usergroups = [gname for gname, in
   416         self.assertEqual(get_pending_inserts(req), [])
   423                           req.execute('Any N WHERE G name N, U in_group G, U eid %(u)s',
       
   424                                       {'u': user.eid})]
       
   425             self.assertCountEqual(usergroups, ['managers', 'test'])
       
   426             self.assertEqual(get_pending_inserts(req), [])
   417 
   427 
   418     def test_req_pending_delete(self):
   428     def test_req_pending_delete(self):
   419         """make sure req's pending deletions are taken into account"""
   429         """make sure req's pending deletions are taken into account"""
   420         user = self.user()
   430         with self.admin_access.web_request() as req:
   421         groupeid = self.execute('INSERT CWGroup G: G name "test", U in_group G WHERE U eid %(x)s',
   431             user = req.user
   422                                 {'x': user.eid})[0][0]
   432             groupeid = req.execute('INSERT CWGroup G: G name "test", U in_group G WHERE U eid %(x)s',
   423         usergroups = [gname for gname, in
   433                                     {'x': user.eid})[0][0]
   424                       self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
   434             usergroups = [gname for gname, in
   425         # just make sure everything was set correctly
   435                           req.execute('Any N WHERE G name N, U in_group G, U eid %(u)s',
   426         self.assertCountEqual(usergroups, ['managers', 'test'])
   436                                       {'u': user.eid})]
   427         # now try to delete the relation
   437             # just make sure everything was set correctly
   428         req = self.request(**req_form(user))
   438             self.assertCountEqual(usergroups, ['managers', 'test'])
   429         req.session.data['pending_delete'] = set([(user.eid, 'in_group', groupeid)])
   439             req.cnx.commit()
   430         path, params = self.expect_redirect_handle_request(req, 'edit')
   440             # now try to delete the relation
   431         usergroups = [gname for gname, in
   441         with self.admin_access.web_request(**req_form(user)) as req:
   432                       self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
   442             req.session.data['pending_delete'] = set([(user.eid, 'in_group', groupeid)])
   433         self.assertCountEqual(usergroups, ['managers'])
   443             self.expect_redirect_handle_request(req, 'edit')
   434         self.assertEqual(get_pending_deletes(req), [])
   444             usergroups = [gname for gname, in
       
   445                           req.execute('Any N WHERE G name N, U in_group G, U eid %(u)s',
       
   446                                       {'u': user.eid})]
       
   447             self.assertCountEqual(usergroups, ['managers'])
       
   448             self.assertEqual(get_pending_deletes(req), [])
   435 
   449 
   436     def test_redirect_apply_button(self):
   450     def test_redirect_apply_button(self):
   437         redirectrql = rql_for_eid(4012) # whatever
   451         with self.admin_access.web_request() as req:
   438         req = self.request()
   452             redirectrql = rql_for_eid(4012) # whatever
   439         req.form = {
   453             req.form = {
   440             'eid': 'A', '__maineid' : 'A',
   454                 'eid': 'A', '__maineid' : 'A',
   441             '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
   455                 '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
   442             'content-subject:A': u'"13:03:43"',
   456                 'content-subject:A': u'"13:03:43"',
   443             'title-subject:A': u'huuu',
   457                 'title-subject:A': u'huuu',
   444             '__redirectrql': redirectrql,
   458                 '__redirectrql': redirectrql,
   445             '__redirectvid': 'primary',
   459                 '__redirectvid': 'primary',
   446             '__redirectparams': 'toto=tutu&tata=titi',
   460                 '__redirectparams': 'toto=tutu&tata=titi',
   447             '__form_id': 'edition',
   461                 '__form_id': 'edition',
   448             '__action_apply': '',
   462                 '__action_apply': '',
   449             }
   463                 }
   450         path, params = self.expect_redirect_handle_request(req, 'edit')
   464             path, params = self.expect_redirect_handle_request(req, 'edit')
   451         self.assertTrue(path.startswith('blogentry/'))
   465             self.assertTrue(path.startswith('blogentry/'))
   452         eid = path.split('/')[1]
   466             eid = path.split('/')[1]
   453         self.assertEqual(params['vid'], 'edition')
   467             self.assertEqual(params['vid'], 'edition')
   454         self.assertNotEqual(int(eid), 4012)
   468             self.assertNotEqual(int(eid), 4012)
   455         self.assertEqual(params['__redirectrql'], redirectrql)
   469             self.assertEqual(params['__redirectrql'], redirectrql)
   456         self.assertEqual(params['__redirectvid'], 'primary')
   470             self.assertEqual(params['__redirectvid'], 'primary')
   457         self.assertEqual(params['__redirectparams'], 'toto=tutu&tata=titi')
   471             self.assertEqual(params['__redirectparams'], 'toto=tutu&tata=titi')
   458 
   472 
   459     def test_redirect_ok_button(self):
   473     def test_redirect_ok_button(self):
   460         redirectrql = rql_for_eid(4012) # whatever
   474         with self.admin_access.web_request() as req:
   461         req = self.request()
   475             redirectrql = rql_for_eid(4012) # whatever
   462         req.form = {
   476             req.form = {
   463             'eid': 'A', '__maineid' : 'A',
   477                 'eid': 'A', '__maineid' : 'A',
   464             '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
   478                 '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
   465             'content-subject:A': u'"13:03:43"',
   479                 'content-subject:A': u'"13:03:43"',
   466             'title-subject:A': u'huuu',
   480                 'title-subject:A': u'huuu',
   467             '__redirectrql': redirectrql,
   481                 '__redirectrql': redirectrql,
   468             '__redirectvid': 'primary',
   482                 '__redirectvid': 'primary',
   469             '__redirectparams': 'toto=tutu&tata=titi',
   483                 '__redirectparams': 'toto=tutu&tata=titi',
   470             '__form_id': 'edition',
   484                 '__form_id': 'edition',
   471             }
   485                 }
   472         path, params = self.expect_redirect_handle_request(req, 'edit')
   486             path, params = self.expect_redirect_handle_request(req, 'edit')
   473         self.assertEqual(path, 'view')
   487             self.assertEqual(path, 'view')
   474         self.assertEqual(params['rql'], redirectrql)
   488             self.assertEqual(params['rql'], redirectrql)
   475         self.assertEqual(params['vid'], 'primary')
   489             self.assertEqual(params['vid'], 'primary')
   476         self.assertEqual(params['tata'], 'titi')
   490             self.assertEqual(params['tata'], 'titi')
   477         self.assertEqual(params['toto'], 'tutu')
   491             self.assertEqual(params['toto'], 'tutu')
   478 
   492 
   479     def test_redirect_delete_button(self):
   493     def test_redirect_delete_button(self):
   480         req = self.request()
   494         with self.admin_access.web_request() as req:
   481         eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
   495             eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
   482         req.form = {'eid': u(eid), '__type:%s'%eid: 'BlogEntry',
   496             req.form = {'eid': unicode(eid), '__type:%s'%eid: 'BlogEntry',
   483                     '__action_delete': ''}
   497                         '__action_delete': ''}
   484         path, params = self.expect_redirect_handle_request(req, 'edit')
   498             path, params = self.expect_redirect_handle_request(req, 'edit')
   485         self.assertEqual(path, 'blogentry')
   499             self.assertEqual(path, 'blogentry')
   486         self.assertIn('_cwmsgid', params)
   500             self.assertIn('_cwmsgid', params)
   487         eid = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
   501             eid = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
   488         self.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s',
   502             req.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s',
   489                      {'x': self.session.user.eid, 'e': eid})
   503                         {'x': self.session.user.eid, 'e': eid})
   490         self.commit()
   504             req.cnx.commit()
   491         req = req
   505             req.form = {'eid': unicode(eid), '__type:%s'%eid: 'EmailAddress',
   492         req.form = {'eid': u(eid), '__type:%s'%eid: 'EmailAddress',
   506                         '__action_delete': ''}
   493                     '__action_delete': ''}
   507             path, params = self.expect_redirect_handle_request(req, 'edit')
   494         path, params = self.expect_redirect_handle_request(req, 'edit')
   508             self.assertEqual(path, 'cwuser/admin')
   495         self.assertEqual(path, 'cwuser/admin')
   509             self.assertIn('_cwmsgid', params)
   496         self.assertIn('_cwmsgid', params)
   510             eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
   497         eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
   511             eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
   498         eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
   512             req.form = {'eid': [unicode(eid1), unicode(eid2)],
   499         req = self.request()
   513                         '__type:%s'%eid1: 'BlogEntry',
   500         req.form = {'eid': [u(eid1), u(eid2)],
   514                         '__type:%s'%eid2: 'EmailAddress',
   501                     '__type:%s'%eid1: 'BlogEntry',
   515                         '__action_delete': ''}
   502                     '__type:%s'%eid2: 'EmailAddress',
   516             path, params = self.expect_redirect_handle_request(req, 'edit')
   503                     '__action_delete': ''}
   517             self.assertEqual(path, 'view')
   504         path, params = self.expect_redirect_handle_request(req, 'edit')
   518             self.assertIn('_cwmsgid', params)
   505         self.assertEqual(path, 'view')
       
   506         self.assertIn('_cwmsgid', params)
       
   507 
   519 
   508     def test_simple_copy(self):
   520     def test_simple_copy(self):
   509         req = self.request()
   521         with self.admin_access.web_request() as req:
   510         blog = req.create_entity('Blog', title=u'my-blog')
   522             blog = req.create_entity('Blog', title=u'my-blog')
   511         blogentry = req.create_entity('BlogEntry', title=u'entry1',
   523             blogentry = req.create_entity('BlogEntry', title=u'entry1',
   512                                       content=u'content1', entry_of=blog)
   524                                           content=u'content1', entry_of=blog)
   513         req = self.request()
       
   514         req.form = {'__maineid' : 'X', 'eid': 'X',
       
   515                     '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
       
   516                     '_cw_entity_fields:X': 'title-subject,content-subject',
       
   517                     'title-subject:X': u'entry1-copy',
       
   518                     'content-subject:X': u'content1',
       
   519                     }
       
   520         self.expect_redirect_handle_request(req, 'edit')
       
   521         blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
       
   522         self.assertEqual(blogentry2.entry_of[0].eid, blog.eid)
       
   523 
       
   524     def test_skip_copy_for(self):
       
   525         req = self.request()
       
   526         blog = req.create_entity('Blog', title=u'my-blog')
       
   527         blogentry = req.create_entity('BlogEntry', title=u'entry1',
       
   528                                       content=u'content1', entry_of=blog)
       
   529         blogentry.__class__.cw_skip_copy_for = [('entry_of', 'subject')]
       
   530         try:
       
   531             req = self.request()
       
   532             req.form = {'__maineid' : 'X', 'eid': 'X',
   525             req.form = {'__maineid' : 'X', 'eid': 'X',
   533                         '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
   526                         '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
   534                         '_cw_entity_fields:X': 'title-subject,content-subject',
   527                         '_cw_entity_fields:X': 'title-subject,content-subject',
   535                         'title-subject:X': u'entry1-copy',
   528                         'title-subject:X': u'entry1-copy',
   536                         'content-subject:X': u'content1',
   529                         'content-subject:X': u'content1',
   537                         }
   530                         }
   538             self.expect_redirect_handle_request(req, 'edit')
   531             self.expect_redirect_handle_request(req, 'edit')
   539             blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
   532             blogentry2 = req.find('BlogEntry', title=u'entry1-copy').one()
   540             # entry_of should not be copied
   533             self.assertEqual(blogentry2.entry_of[0].eid, blog.eid)
   541             self.assertEqual(len(blogentry2.entry_of), 0)
   534 
   542         finally:
   535     def test_skip_copy_for(self):
   543             blogentry.__class__.cw_skip_copy_for = []
   536         with self.admin_access.web_request() as req:
       
   537             blog = req.create_entity('Blog', title=u'my-blog')
       
   538             blogentry = req.create_entity('BlogEntry', title=u'entry1',
       
   539                                           content=u'content1', entry_of=blog)
       
   540             blogentry.__class__.cw_skip_copy_for = [('entry_of', 'subject')]
       
   541             try:
       
   542                 req.form = {'__maineid' : 'X', 'eid': 'X',
       
   543                             '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
       
   544                             '_cw_entity_fields:X': 'title-subject,content-subject',
       
   545                             'title-subject:X': u'entry1-copy',
       
   546                             'content-subject:X': u'content1',
       
   547                             }
       
   548                 self.expect_redirect_handle_request(req, 'edit')
       
   549                 blogentry2 = req.find('BlogEntry', title=u'entry1-copy').one()
       
   550                 # entry_of should not be copied
       
   551                 self.assertEqual(len(blogentry2.entry_of), 0)
       
   552             finally:
       
   553                 blogentry.__class__.cw_skip_copy_for = []
   544 
   554 
   545     def test_nonregr_eetype_etype_editing(self):
   555     def test_nonregr_eetype_etype_editing(self):
   546         """non-regression test checking that a manager user can edit a CWEType entity
   556         """non-regression test checking that a manager user can edit a CWEType entity
   547         """
   557         """
   548         groupeids = sorted(eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")'))
   558         with self.admin_access.web_request() as req:
   549         groups = [u(eid) for eid in groupeids]
   559             groupeids = sorted(eid
   550         cwetypeeid = self.execute('CWEType X WHERE X name "CWEType"')[0][0]
   560                                for eid, in req.execute('CWGroup G '
   551         basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X read_permission G, X eid %(x)s', {'x': cwetypeeid})]
   561                                                        'WHERE G name in ("managers", "users")'))
   552         cwetypeeid = u(cwetypeeid)
   562             groups = [unicode(eid) for eid in groupeids]
   553         req = self.request()
   563             cwetypeeid = req.execute('CWEType X WHERE X name "CWEType"')[0][0]
   554         req.form = {
   564             basegroups = [unicode(eid)
   555             'eid':      cwetypeeid,
   565                           for eid, in req.execute('CWGroup G '
   556             '__type:'+cwetypeeid:  'CWEType',
   566                                                   'WHERE X read_permission G, X eid %(x)s',
   557             '_cw_entity_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject',
   567                                                   {'x': cwetypeeid})]
   558             'name-subject:'+cwetypeeid:     u'CWEType',
   568             cwetypeeid = unicode(cwetypeeid)
   559             'final-subject:'+cwetypeeid:    '',
   569             req.form = {
   560             'description-subject:'+cwetypeeid:     u'users group',
   570                 'eid':      cwetypeeid,
   561             'read_permission-subject:'+cwetypeeid:  groups,
   571                 '__type:'+cwetypeeid:  'CWEType',
       
   572                 '_cw_entity_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject',
       
   573                 'name-subject:'+cwetypeeid:     u'CWEType',
       
   574                 'final-subject:'+cwetypeeid:    '',
       
   575                 'description-subject:'+cwetypeeid:     u'users group',
       
   576                 'read_permission-subject:'+cwetypeeid:  groups,
   562             }
   577             }
   563         try:
   578             try:
   564             path, params = self.expect_redirect_handle_request(req, 'edit')
   579                 self.expect_redirect_handle_request(req, 'edit')
   565             e = self.execute('Any X WHERE X eid %(x)s', {'x': cwetypeeid}).get_entity(0, 0)
   580                 e = req.execute('Any X WHERE X eid %(x)s', {'x': cwetypeeid}).get_entity(0, 0)
   566             self.assertEqual(e.name, 'CWEType')
   581                 self.assertEqual(e.name, 'CWEType')
   567             self.assertEqual(sorted(g.eid for g in e.read_permission), groupeids)
   582                 self.assertEqual(sorted(g.eid for g in e.read_permission), groupeids)
   568         finally:
   583             finally:
   569             # restore
   584                 # restore
   570             self.execute('SET X read_permission Y WHERE X name "CWEType", Y eid IN (%s), NOT X read_permission Y' % (','.join(basegroups)))
   585                 req.execute('SET X read_permission Y WHERE X name "CWEType", '
   571             self.commit()
   586                             'Y eid IN (%s), NOT X read_permission Y' % (','.join(basegroups)))
       
   587                 req.cnx.commit()
   572 
   588 
   573     def test_nonregr_strange_text_input(self):
   589     def test_nonregr_strange_text_input(self):
   574         """non-regression test checking text input containing "13:03:43"
   590         """non-regression test checking text input containing "13:03:43"
   575 
   591 
   576         this seems to be postgres (tsearch?) specific
   592         this seems to be postgres (tsearch?) specific
   577         """
   593         """
   578         req = self.request()
   594         with self.admin_access.web_request() as req:
   579         req.form = {
   595             req.form = {
   580             'eid': 'A', '__maineid' : 'A',
   596                 'eid': 'A', '__maineid' : 'A',
   581             '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'title-subject,content-subject',
   597                 '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'title-subject,content-subject',
   582             'title-subject:A': u'"13:03:40"',
   598                 'title-subject:A': u'"13:03:40"',
   583             'content-subject:A': u'"13:03:43"',}
   599                 'content-subject:A': u'"13:03:43"',}
   584         path, params = self.expect_redirect_handle_request(req, 'edit')
   600             path, _params = self.expect_redirect_handle_request(req, 'edit')
   585         self.assertTrue(path.startswith('blogentry/'))
   601             self.assertTrue(path.startswith('blogentry/'))
   586         eid = path.split('/')[1]
   602             eid = path.split('/')[1]
   587         e = self.execute('Any C, T WHERE C eid %(x)s, C content T', {'x': eid}).get_entity(0, 0)
   603             e = req.execute('Any C, T WHERE C eid %(x)s, C content T', {'x': eid}).get_entity(0, 0)
   588         self.assertEqual(e.title, '"13:03:40"')
   604             self.assertEqual(e.title, '"13:03:40"')
   589         self.assertEqual(e.content, '"13:03:43"')
   605             self.assertEqual(e.content, '"13:03:43"')
   590 
   606 
   591 
   607 
   592     def test_nonregr_multiple_empty_email_addr(self):
   608     def test_nonregr_multiple_empty_email_addr(self):
   593         gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
   609         with self.admin_access.web_request() as req:
   594         req = self.request()
   610             gueid = req.execute('CWGroup G WHERE G name "users"')[0][0]
   595         req.form = {'eid': ['X', 'Y'],
   611             req.form = {'eid': ['X', 'Y'],
   596 
   612 
   597                     '__type:X': 'CWUser',
   613                         '__type:X': 'CWUser',
   598                     '_cw_entity_fields:X': 'login-subject,upassword-subject,in_group-subject',
   614                         '_cw_entity_fields:X': 'login-subject,upassword-subject,in_group-subject',
   599                     'login-subject:X': u'adim',
   615                         'login-subject:X': u'adim',
   600                     'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
   616                         'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
   601                     'in_group-subject:X': `gueid`,
   617                         'in_group-subject:X': `gueid`,
   602 
   618 
   603                     '__type:Y': 'EmailAddress',
   619                         '__type:Y': 'EmailAddress',
   604                     '_cw_entity_fields:Y': 'address-subject,alias-subject,use_email-object',
   620                         '_cw_entity_fields:Y': 'address-subject,alias-subject,use_email-object',
   605                     'address-subject:Y': u'',
   621                         'address-subject:Y': u'',
   606                     'alias-subject:Y': u'',
   622                         'alias-subject:Y': u'',
   607                     'use_email-object:Y': 'X',
   623                         'use_email-object:Y': 'X',
   608                     }
   624                         }
   609         with self.assertRaises(ValidationError) as cm:
   625             with self.assertRaises(ValidationError) as cm:
   610             self.ctrl_publish(req)
   626                 self.ctrl_publish(req)
   611         self.assertEqual(cm.exception.errors, {'address-subject': u'required field'})
   627             self.assertEqual(cm.exception.errors, {'address-subject': u'required field'})
   612 
   628 
   613     def test_nonregr_copy(self):
   629     def test_nonregr_copy(self):
   614         user = self.user()
   630         with self.admin_access.web_request() as req:
   615         req = self.request()
   631             user = req.user
   616         req.form = {'__maineid' : 'X', 'eid': 'X',
   632             req.form = {'__maineid' : 'X', 'eid': 'X',
   617                     '__cloned_eid:X': user.eid, '__type:X': 'CWUser',
   633                         '__cloned_eid:X': user.eid, '__type:X': 'CWUser',
   618                     '_cw_entity_fields:X': 'login-subject,upassword-subject',
   634                         '_cw_entity_fields:X': 'login-subject,upassword-subject',
   619                     'login-subject:X': u'toto',
   635                         'login-subject:X': u'toto',
   620                     'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
   636                         'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
   621                     }
   637                         }
   622         path, params = self.expect_redirect_handle_request(req, 'edit')
   638             path, _params = self.expect_redirect_handle_request(req, 'edit')
   623         self.assertEqual(path, 'cwuser/toto')
   639             self.assertEqual(path, 'cwuser/toto')
   624         e = self.execute('Any X WHERE X is CWUser, X login "toto"').get_entity(0, 0)
   640             e = req.execute('Any X WHERE X is CWUser, X login "toto"').get_entity(0, 0)
   625         self.assertEqual(e.login, 'toto')
   641             self.assertEqual(e.login, 'toto')
   626         self.assertEqual(e.in_group[0].name, 'managers')
   642             self.assertEqual(e.in_group[0].name, 'managers')
   627 
   643 
   628 
   644 
   629     def test_nonregr_rollback_on_validation_error(self):
   645     def test_nonregr_rollback_on_validation_error(self):
   630         req = self.request()
   646         with self.admin_access.web_request() as req:
   631         p = self.create_user(req, "doe")
   647             p = self.create_user(req, "doe")
   632         # do not try to skip 'primary_email' for this test
   648             # do not try to skip 'primary_email' for this test
   633         old_skips = p.__class__.skip_copy_for
   649             old_skips = p.__class__.skip_copy_for
   634         p.__class__.skip_copy_for = ()
   650             p.__class__.skip_copy_for = ()
   635         try:
       
   636             e = self.request().create_entity('EmailAddress', address=u'doe@doe.com')
       
   637             self.execute('SET P use_email E, P primary_email E WHERE P eid %(p)s, E eid %(e)s',
       
   638                          {'p' : p.eid, 'e' : e.eid})
       
   639             req = self.request()
       
   640             req.form = {'eid': 'X',
       
   641                         '__cloned_eid:X': p.eid, '__type:X': 'CWUser',
       
   642                         '_cw_entity_fields:X': 'login-subject,surname-subject',
       
   643                         'login-subject': u'dodo',
       
   644                         'surname-subject:X': u'Boom',
       
   645                         '__errorurl' : "whatever but required",
       
   646                         }
       
   647             # try to emulate what really happens in the web application
       
   648             # 1/ validate form => EditController.publish raises a ValidationError
       
   649             #    which fires a Redirect
       
   650             # 2/ When re-publishing the copy form, the publisher implicitly commits
       
   651             try:
   651             try:
   652                 self.app_handle_request(req, 'edit')
   652                 e = req.create_entity('EmailAddress', address=u'doe@doe.com')
   653             except Redirect:
   653                 req.execute('SET P use_email E, P primary_email E WHERE P eid %(p)s, E eid %(e)s',
   654                 req = self.request()
   654                             {'p' : p.eid, 'e' : e.eid})
   655                 req.form['rql'] = 'Any X WHERE X eid %s' % p.eid
   655                 req.form = {'eid': 'X',
   656                 req.form['vid'] = 'copy'
   656                             '__cloned_eid:X': p.eid, '__type:X': 'CWUser',
   657                 self.app_handle_request(req, 'view')
   657                             '_cw_entity_fields:X': 'login-subject,surname-subject',
   658             rset = self.execute('CWUser P WHERE P surname "Boom"')
   658                             'login-subject': u'dodo',
   659             self.assertEqual(len(rset), 0)
   659                             'surname-subject:X': u'Boom',
   660         finally:
   660                             '__errorurl' : "whatever but required",
   661             p.__class__.skip_copy_for = old_skips
   661                             }
       
   662                 # try to emulate what really happens in the web application
       
   663                 # 1/ validate form => EditController.publish raises a ValidationError
       
   664                 #    which fires a Redirect
       
   665                 # 2/ When re-publishing the copy form, the publisher implicitly commits
       
   666                 try:
       
   667                     self.app_handle_request(req, 'edit')
       
   668                 except Redirect:
       
   669                     req.form['rql'] = 'Any X WHERE X eid %s' % p.eid
       
   670                     req.form['vid'] = 'copy'
       
   671                     self.app_handle_request(req, 'view')
       
   672                 rset = req.execute('CWUser P WHERE P surname "Boom"')
       
   673                 self.assertEqual(len(rset), 0)
       
   674             finally:
       
   675                 p.__class__.skip_copy_for = old_skips
   662 
   676 
   663     def test_regr_inlined_forms(self):
   677     def test_regr_inlined_forms(self):
   664         self.schema['described_by_test'].inlined = False
   678         with self.admin_access.web_request() as req:
   665         try:
       
   666             req = self.request()
       
   667             req.data['eidmap'] = {}
       
   668             req.data['pending_others'] = set()
       
   669             req.data['pending_inlined'] = {}
       
   670             req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
       
   671 
       
   672                         '__type:X': 'Salesterm',
       
   673                         '_cw_entity_fields:X': 'described_by_test-subject',
       
   674                         'described_by_test-subject:X': 'Y',
       
   675 
       
   676                         '__type:Y': 'File',
       
   677                         '_cw_entity_fields:Y': 'data-subject',
       
   678                         'data-subject:Y': (u'coucou.txt', Binary('coucou')),
       
   679                         }
       
   680             values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2))
       
   681                                  for eid in req.edited_eids())
       
   682             editctrl = self.vreg['controllers'].select('edit', req)
       
   683             # don't call publish to enforce select order
       
   684             editctrl.errors = []
       
   685             editctrl._to_create = {}
       
   686             editctrl.edit_entity(values_by_eid['X']) # #3064653 raise ValidationError
       
   687             editctrl.edit_entity(values_by_eid['Y'])
       
   688         finally:
       
   689             self.schema['described_by_test'].inlined = False
   679             self.schema['described_by_test'].inlined = False
       
   680             try:
       
   681                 req.data['eidmap'] = {}
       
   682                 req.data['pending_others'] = set()
       
   683                 req.data['pending_inlined'] = {}
       
   684                 req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
       
   685 
       
   686                             '__type:X': 'Salesterm',
       
   687                             '_cw_entity_fields:X': 'described_by_test-subject',
       
   688                             'described_by_test-subject:X': 'Y',
       
   689 
       
   690                             '__type:Y': 'File',
       
   691                             '_cw_entity_fields:Y': 'data-subject',
       
   692                             'data-subject:Y': (u'coucou.txt', Binary('coucou')),
       
   693                             }
       
   694                 values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2))
       
   695                                      for eid in req.edited_eids())
       
   696                 editctrl = self.vreg['controllers'].select('edit', req)
       
   697                 # don't call publish to enforce select order
       
   698                 editctrl.errors = []
       
   699                 editctrl._to_create = {}
       
   700                 editctrl.edit_entity(values_by_eid['X']) # #3064653 raise ValidationError
       
   701                 editctrl.edit_entity(values_by_eid['Y'])
       
   702             finally:
       
   703                 self.schema['described_by_test'].inlined = False
   690 
   704 
   691 
   705 
   692 class ReportBugControllerTC(CubicWebTC):
   706 class ReportBugControllerTC(CubicWebTC):
   693 
   707 
   694     def test_usable_by_guest(self):
   708     def test_usable_by_guest(self):
   695         self.login('anon')
   709         with self.new_access('anon').web_request() as req:
   696         self.assertRaises(NoSelectableObject,
   710             self.assertRaises(NoSelectableObject,
   697                           self.vreg['controllers'].select, 'reportbug', self.request())
   711                               self.vreg['controllers'].select, 'reportbug', req)
   698         self.vreg['controllers'].select('reportbug', self.request(description='hop'))
   712         with self.new_access('anon').web_request(description='hop') as req:
       
   713             self.vreg['controllers'].select('reportbug', req)
   699 
   714 
   700 
   715 
   701 class AjaxControllerTC(CubicWebTC):
   716 class AjaxControllerTC(CubicWebTC):
   702     tested_controller = 'ajax'
   717     tested_controller = 'ajax'
   703 
   718 
   704     def ctrl(self, req=None):
   719     def ctrl(self, req=None):
   705         req = req or self.request(url='http://whatever.fr/')
   720         req = req or self.request(url='http://whatever.fr/')
   706         return self.vreg['controllers'].select(self.tested_controller, req)
   721         return self.vreg['controllers'].select(self.tested_controller, req)
   707 
   722 
   708     def setup_database(self):
   723     def setup_database(self):
   709         req = self.request()
   724         with self.admin_access.repo_cnx() as cnx:
   710         self.pytag = req.create_entity('Tag', name=u'python')
   725             self.pytag = cnx.create_entity('Tag', name=u'python')
   711         self.cubicwebtag = req.create_entity('Tag', name=u'cubicweb')
   726             self.cubicwebtag = cnx.create_entity('Tag', name=u'cubicweb')
   712         self.john = self.create_user(req, u'John')
   727             self.john = self.create_user(cnx, u'John')
   713 
   728             cnx.commit()
   714 
   729 
   715     ## tests ##################################################################
   730     ## tests ##################################################################
   716     def test_simple_exec(self):
   731     def test_simple_exec(self):
   717         req = self.request(rql='CWUser P WHERE P login "John"',
   732         with self.admin_access.web_request(rql='CWUser P WHERE P login "John"',
   718                            pageid='123', fname='view')
   733                                            pageid='123', fname='view') as req:
   719         ctrl = self.ctrl(req)
   734             ctrl = self.ctrl(req)
   720         rset = self.john.as_rset()
   735             rset = self.john.as_rset()
   721         rset.req = req
   736             rset.req = req
   722         source = ctrl.publish()
   737             source = ctrl.publish()
   723         self.assertTrue(source.startswith('<div>'))
   738             self.assertTrue(source.startswith('<div>'))
   724 
   739 
   725 #     def test_json_exec(self):
   740 #     def test_json_exec(self):
   726 #         rql = 'Any T,N WHERE T is Tag, T name N'
   741 #         rql = 'Any T,N WHERE T is Tag, T name N'
   727 #         ctrl = self.ctrl(self.request(mode='json', rql=rql, pageid='123'))
   742 #         ctrl = self.ctrl(self.request(mode='json', rql=rql, pageid='123'))
   728 #         self.assertEqual(ctrl.publish(),
   743 #         self.assertEqual(ctrl.publish(),
   729 #                           json_dumps(self.execute(rql).rows))
   744 #                           json_dumps(self.execute(rql).rows))
   730 
   745 
   731     def test_remote_add_existing_tag(self):
   746     def test_remote_add_existing_tag(self):
   732         self.remote_call('tag_entity', self.john.eid, ['python'])
   747         with self.remote_calling('tag_entity', self.john.eid, ['python']) as (_, req):
   733         self.assertCountEqual(
   748             self.assertCountEqual(
   734             [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
   749                 [tname for tname, in req.execute('Any N WHERE T is Tag, T name N')],
   735             ['python', 'cubicweb'])
   750                 ['python', 'cubicweb'])
   736         self.assertEqual(
   751             self.assertEqual(
   737             self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
   752                 req.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
   738             [['python']])
   753                 [['python']])
   739 
   754 
   740     def test_remote_add_new_tag(self):
   755     def test_remote_add_new_tag(self):
   741         self.remote_call('tag_entity', self.john.eid, ['javascript'])
   756         with self.remote_calling('tag_entity', self.john.eid, ['javascript']) as (_, req):
   742         self.assertCountEqual(
   757             self.assertCountEqual(
   743             [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
   758                 [tname for tname, in req.execute('Any N WHERE T is Tag, T name N')],
   744             ['python', 'cubicweb', 'javascript'])
   759                 ['python', 'cubicweb', 'javascript'])
   745         self.assertEqual(
   760             self.assertEqual(
   746             self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
   761                 req.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
   747             [['javascript']])
   762                 [['javascript']])
   748 
   763 
   749     def test_pending_insertion(self):
   764     def test_pending_insertion(self):
   750         res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '13']])
   765         with self.remote_calling('add_pending_inserts', [['12', 'tags', '13']]) as (_, req):
   751         deletes = get_pending_deletes(req)
   766             deletes = get_pending_deletes(req)
   752         self.assertEqual(deletes, [])
   767             self.assertEqual(deletes, [])
   753         inserts = get_pending_inserts(req)
   768             inserts = get_pending_inserts(req)
   754         self.assertEqual(inserts, ['12:tags:13'])
   769             self.assertEqual(inserts, ['12:tags:13'])
   755         res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
   770         with self.remote_calling('add_pending_inserts', [['12', 'tags', '14']]) as (_, req):
   756         deletes = get_pending_deletes(req)
   771             deletes = get_pending_deletes(req)
   757         self.assertEqual(deletes, [])
   772             self.assertEqual(deletes, [])
   758         inserts = get_pending_inserts(req)
   773             inserts = get_pending_inserts(req)
   759         self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
   774             self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
   760         inserts = get_pending_inserts(req, 12)
   775             inserts = get_pending_inserts(req, 12)
   761         self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
   776             self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
   762         inserts = get_pending_inserts(req, 13)
   777             inserts = get_pending_inserts(req, 13)
   763         self.assertEqual(inserts, ['12:tags:13'])
   778             self.assertEqual(inserts, ['12:tags:13'])
   764         inserts = get_pending_inserts(req, 14)
   779             inserts = get_pending_inserts(req, 14)
   765         self.assertEqual(inserts, ['12:tags:14'])
   780             self.assertEqual(inserts, ['12:tags:14'])
   766         req.remove_pending_operations()
   781             req.remove_pending_operations()
   767 
   782 
   768     def test_pending_deletion(self):
   783     def test_pending_deletion(self):
   769         res, req = self.remote_call('add_pending_delete', ['12', 'tags', '13'])
   784         with self.remote_calling('add_pending_delete', ['12', 'tags', '13']) as (_, req):
   770         inserts = get_pending_inserts(req)
   785             inserts = get_pending_inserts(req)
   771         self.assertEqual(inserts, [])
   786             self.assertEqual(inserts, [])
   772         deletes = get_pending_deletes(req)
   787             deletes = get_pending_deletes(req)
   773         self.assertEqual(deletes, ['12:tags:13'])
   788             self.assertEqual(deletes, ['12:tags:13'])
   774         res, req = self.remote_call('add_pending_delete', ['12', 'tags', '14'])
   789         with self.remote_calling('add_pending_delete', ['12', 'tags', '14']) as (_, req):
   775         inserts = get_pending_inserts(req)
   790             inserts = get_pending_inserts(req)
   776         self.assertEqual(inserts, [])
   791             self.assertEqual(inserts, [])
   777         deletes = get_pending_deletes(req)
   792             deletes = get_pending_deletes(req)
   778         self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
   793             self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
   779         deletes = get_pending_deletes(req, 12)
   794             deletes = get_pending_deletes(req, 12)
   780         self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
   795             self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
   781         deletes = get_pending_deletes(req, 13)
   796             deletes = get_pending_deletes(req, 13)
   782         self.assertEqual(deletes, ['12:tags:13'])
   797             self.assertEqual(deletes, ['12:tags:13'])
   783         deletes = get_pending_deletes(req, 14)
   798             deletes = get_pending_deletes(req, 14)
   784         self.assertEqual(deletes, ['12:tags:14'])
   799             self.assertEqual(deletes, ['12:tags:14'])
   785         req.remove_pending_operations()
   800             req.remove_pending_operations()
   786 
   801 
   787     def test_remove_pending_operations(self):
   802     def test_remove_pending_operations(self):
   788         self.remote_call('add_pending_delete', ['12', 'tags', '13'])
   803         with self.remote_calling('add_pending_delete', ['12', 'tags', '13']):
   789         _, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
   804             pass
   790         inserts = get_pending_inserts(req)
   805         with self.remote_calling('add_pending_inserts', [['12', 'tags', '14']]) as (_, req):
   791         self.assertEqual(inserts, ['12:tags:14'])
   806             inserts = get_pending_inserts(req)
   792         deletes = get_pending_deletes(req)
   807             self.assertEqual(inserts, ['12:tags:14'])
   793         self.assertEqual(deletes, ['12:tags:13'])
   808             deletes = get_pending_deletes(req)
   794         req.remove_pending_operations()
   809             self.assertEqual(deletes, ['12:tags:13'])
   795         self.assertEqual(get_pending_deletes(req), [])
   810             req.remove_pending_operations()
   796         self.assertEqual(get_pending_inserts(req), [])
   811             self.assertEqual(get_pending_deletes(req), [])
   797 
   812             self.assertEqual(get_pending_inserts(req), [])
   798 
   813 
   799     def test_add_inserts(self):
   814     def test_add_inserts(self):
   800         res, req = self.remote_call('add_pending_inserts',
   815         with self.remote_calling('add_pending_inserts',
   801                                     [('12', 'tags', '13'), ('12', 'tags', '14')])
   816                                  [('12', 'tags', '13'), ('12', 'tags', '14')]) as (_, req):
   802         inserts = get_pending_inserts(req)
   817             inserts = get_pending_inserts(req)
   803         self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
   818             self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
   804         req.remove_pending_operations()
   819             req.remove_pending_operations()
   805 
   820 
   806 
   821 
   807     # silly tests
   822     # silly tests
   808     def test_external_resource(self):
   823     def test_external_resource(self):
   809         self.assertEqual(self.remote_call('external_resource', 'RSS_LOGO')[0],
   824         with self.remote_calling('external_resource', 'RSS_LOGO') as (res, _):
   810                           json_dumps(self.config.uiprops['RSS_LOGO']))
   825             self.assertEqual(json_dumps(self.config.uiprops['RSS_LOGO']),
       
   826                              res)
       
   827 
   811     def test_i18n(self):
   828     def test_i18n(self):
   812         self.assertEqual(self.remote_call('i18n', ['bimboom'])[0],
   829         with self.remote_calling('i18n', ['bimboom']) as (res, _):
   813                           json_dumps(['bimboom']))
   830             self.assertEqual(json_dumps(['bimboom']), res)
   814 
   831 
   815     def test_format_date(self):
   832     def test_format_date(self):
   816         self.assertEqual(self.remote_call('format_date', '2007-01-01 12:00:00')[0],
   833         with self.remote_calling('format_date', '2007-01-01 12:00:00') as (res, _):
   817                           json_dumps('2007/01/01'))
   834             self.assertEqual(json_dumps('2007/01/01'), res)
   818 
   835 
   819     def test_ajaxfunc_noparameter(self):
   836     def test_ajaxfunc_noparameter(self):
   820         @ajaxfunc
   837         @ajaxfunc
   821         def foo(self, x, y):
   838         def foo(self, x, y):
   822             return 'hello'
   839             return 'hello'
   824         appobject = foo.__appobject__
   841         appobject = foo.__appobject__
   825         self.assertTrue(issubclass(appobject, AjaxFunction))
   842         self.assertTrue(issubclass(appobject, AjaxFunction))
   826         self.assertEqual(appobject.__regid__, 'foo')
   843         self.assertEqual(appobject.__regid__, 'foo')
   827         self.assertEqual(appobject.check_pageid, False)
   844         self.assertEqual(appobject.check_pageid, False)
   828         self.assertEqual(appobject.output_type, None)
   845         self.assertEqual(appobject.output_type, None)
   829         req = self.request()
   846         with self.admin_access.web_request() as req:
   830         f = appobject(req)
   847             f = appobject(req)
   831         self.assertEqual(f(12, 13), 'hello')
   848             self.assertEqual(f(12, 13), 'hello')
   832 
   849 
   833     def test_ajaxfunc_checkpageid(self):
   850     def test_ajaxfunc_checkpageid(self):
   834         @ajaxfunc(check_pageid=True)
   851         @ajaxfunc(check_pageid=True)
   835         def foo(self, x, y):
   852         def foo(self, x, y):
   836             return 'hello'
   853             return 'hello'
   839         self.assertTrue(issubclass(appobject, AjaxFunction))
   856         self.assertTrue(issubclass(appobject, AjaxFunction))
   840         self.assertEqual(appobject.__regid__, 'foo')
   857         self.assertEqual(appobject.__regid__, 'foo')
   841         self.assertEqual(appobject.check_pageid, True)
   858         self.assertEqual(appobject.check_pageid, True)
   842         self.assertEqual(appobject.output_type, None)
   859         self.assertEqual(appobject.output_type, None)
   843         # no pageid
   860         # no pageid
   844         req = self.request()
   861         with self.admin_access.web_request() as req:
   845         f = appobject(req)
   862             f = appobject(req)
   846         self.assertRaises(RemoteCallFailed, f, 12, 13)
   863             self.assertRaises(RemoteCallFailed, f, 12, 13)
   847 
   864 
   848     def test_ajaxfunc_json(self):
   865     def test_ajaxfunc_json(self):
   849         @ajaxfunc(output_type='json')
   866         @ajaxfunc(output_type='json')
   850         def foo(self, x, y):
   867         def foo(self, x, y):
   851             return x + y
   868             return x + y
   854         self.assertTrue(issubclass(appobject, AjaxFunction))
   871         self.assertTrue(issubclass(appobject, AjaxFunction))
   855         self.assertEqual(appobject.__regid__, 'foo')
   872         self.assertEqual(appobject.__regid__, 'foo')
   856         self.assertEqual(appobject.check_pageid, False)
   873         self.assertEqual(appobject.check_pageid, False)
   857         self.assertEqual(appobject.output_type, 'json')
   874         self.assertEqual(appobject.output_type, 'json')
   858         # no pageid
   875         # no pageid
   859         req = self.request()
   876         with self.admin_access.web_request() as req:
   860         f = appobject(req)
   877             f = appobject(req)
   861         self.assertEqual(f(12, 13), '25')
   878             self.assertEqual(f(12, 13), '25')
   862 
   879 
   863 
   880 
   864 class JSonControllerTC(AjaxControllerTC):
   881 class JSonControllerTC(AjaxControllerTC):
   865     # NOTE: this class performs the same tests as AjaxController but with
   882     # NOTE: this class performs the same tests as AjaxController but with
   866     #       deprecated 'json' controller (i.e. check backward compatibility)
   883     #       deprecated 'json' controller (i.e. check backward compatibility)
   877             # remove functions added dynamically during tests
   894             # remove functions added dynamically during tests
   878             if funcname.startswith('js_') and funcname not in self.exposed_remote_funcs:
   895             if funcname.startswith('js_') and funcname not in self.exposed_remote_funcs:
   879                 delattr(JSonController, funcname)
   896                 delattr(JSonController, funcname)
   880 
   897 
   881     def test_monkeypatch_jsoncontroller(self):
   898     def test_monkeypatch_jsoncontroller(self):
   882         self.assertRaises(RemoteCallFailed, self.remote_call, 'foo')
   899         with self.assertRaises(RemoteCallFailed):
       
   900             with self.remote_calling('foo'):
       
   901                 pass
   883         @monkeypatch(JSonController)
   902         @monkeypatch(JSonController)
   884         def js_foo(self):
   903         def js_foo(self):
   885             return u'hello'
   904             return u'hello'
   886         res, req = self.remote_call('foo')
   905         with self.remote_calling('foo') as (res, _):
   887         self.assertEqual(res, u'hello')
   906             self.assertEqual(res, u'hello')
   888 
   907 
   889     def test_monkeypatch_jsoncontroller_xhtmlize(self):
   908     def test_monkeypatch_jsoncontroller_xhtmlize(self):
   890         self.assertRaises(RemoteCallFailed, self.remote_call, 'foo')
   909         with self.assertRaises(RemoteCallFailed):
       
   910             with self.remote_calling('foo'):
       
   911                 pass
   891         @monkeypatch(JSonController)
   912         @monkeypatch(JSonController)
   892         @xhtmlize
   913         @xhtmlize
   893         def js_foo(self):
   914         def js_foo(self):
   894             return u'hello'
   915             return u'hello'
   895         res, req = self.remote_call('foo')
   916         with self.remote_calling('foo') as (res, _):
   896         self.assertEqual(u'<div>hello</div>', res)
   917             self.assertEqual(u'<div>hello</div>', res)
   897 
   918 
   898     def test_monkeypatch_jsoncontroller_jsonize(self):
   919     def test_monkeypatch_jsoncontroller_jsonize(self):
   899         self.assertRaises(RemoteCallFailed, self.remote_call, 'foo')
   920         with self.assertRaises(RemoteCallFailed):
       
   921             with self.remote_calling('foo'):
       
   922                 pass
   900         @monkeypatch(JSonController)
   923         @monkeypatch(JSonController)
   901         @jsonize
   924         @jsonize
   902         def js_foo(self):
   925         def js_foo(self):
   903             return 12
   926             return 12
   904         res, req = self.remote_call('foo')
   927         with self.remote_calling('foo') as (res, _):
   905         self.assertEqual(res, '12')
   928             self.assertEqual(res, '12')
   906 
   929 
   907     def test_monkeypatch_jsoncontroller_stdfunc(self):
   930     def test_monkeypatch_jsoncontroller_stdfunc(self):
   908         @monkeypatch(JSonController)
   931         @monkeypatch(JSonController)
   909         @jsonize
   932         @jsonize
   910         def js_reledit_form(self):
   933         def js_reledit_form(self):
   911             return 12
   934             return 12
   912         res, req = self.remote_call('reledit_form')
   935         with self.remote_calling('reledit_form') as (res, _):
   913         self.assertEqual(res, '12')
   936             self.assertEqual(res, '12')
   914 
   937 
   915 
   938 
   916 class UndoControllerTC(CubicWebTC):
   939 class UndoControllerTC(CubicWebTC):
   917 
   940 
   918     def setUp(self):
   941     def setUp(self):
   924 
   947 
   925     def tearDown(self):
   948     def tearDown(self):
   926         super(UndoControllerTC, self).tearDown()
   949         super(UndoControllerTC, self).tearDown()
   927         cubicweb.server.session.Connection = OldConnection
   950         cubicweb.server.session.Connection = OldConnection
   928 
   951 
   929 
       
   930     def setup_database(self):
   952     def setup_database(self):
   931         req = self.request()
   953         with self.admin_access.repo_cnx() as cnx:
   932         self.toto = self.create_user(req, 'toto', password='toto', groups=('users',),
   954             self.toto = self.create_user(cnx, 'toto',
   933                                      commit=False)
   955                                          password='toto',
   934         self.txuuid_toto = self.commit()
   956                                          groups=('users',),
   935         self.toto_email = self.session.create_entity('EmailAddress',
   957                                          commit=False)
   936                                        address=u'toto@logilab.org',
   958             self.txuuid_toto = cnx.commit()
   937                                        reverse_use_email=self.toto)
   959             self.toto_email = cnx.create_entity('EmailAddress',
   938         self.txuuid_toto_email = self.commit()
   960                                                 address=u'toto@logilab.org',
       
   961                                                 reverse_use_email=self.toto)
       
   962             self.txuuid_toto_email = cnx.commit()
   939 
   963 
   940     def test_no_such_transaction(self):
   964     def test_no_such_transaction(self):
   941         req = self.request()
   965         with self.admin_access.web_request() as req:
   942         txuuid = u"12345acbd"
   966             txuuid = u"12345acbd"
   943         req.form['txuuid'] = txuuid
   967             req.form['txuuid'] = txuuid
   944         controller = self.vreg['controllers'].select('undo', req)
   968             controller = self.vreg['controllers'].select('undo', req)
   945         with self.assertRaises(tx.NoSuchTransaction) as cm:
   969             with self.assertRaises(tx.NoSuchTransaction) as cm:
   946             result = controller.publish(rset=None)
   970                 result = controller.publish(rset=None)
   947         self.assertEqual(cm.exception.txuuid, txuuid)
   971             self.assertEqual(cm.exception.txuuid, txuuid)
   948 
   972 
   949     def assertURLPath(self, url, expected_path, expected_params=None):
   973     def assertURLPath(self, url, expected_path, expected_params=None):
   950         """ This assert that the path part of `url` matches  expected path
   974         """ This assert that the path part of `url` matches  expected path
   951 
   975 
   952         TODO : implement assertion on the expected_params too
   976         TODO : implement assertion on the expected_params too
   953         """
   977         """
   954         req = self.request()
   978         with self.admin_access.web_request() as req:
   955         scheme, netloc, path, query, fragment = urlsplit(url)
   979             scheme, netloc, path, query, fragment = urlsplit(url)
   956         query_dict = url_parse_query(query)
   980             query_dict = url_parse_query(query)
   957         expected_url = urljoin(req.base_url(), expected_path)
   981             expected_url = urljoin(req.base_url(), expected_path)
   958         self.assertEqual( urlunsplit((scheme, netloc, path, None, None)), expected_url)
   982             self.assertEqual( urlunsplit((scheme, netloc, path, None, None)), expected_url)
   959 
   983 
   960     def test_redirect_redirectpath(self):
   984     def test_redirect_redirectpath(self):
   961         "Check that the potential __redirectpath is honored"
   985         "Check that the potential __redirectpath is honored"
   962         req = self.request()
   986         with self.admin_access.web_request() as req:
   963         txuuid = self.txuuid_toto_email
   987             txuuid = self.txuuid_toto_email
   964         req.form['txuuid'] = txuuid
   988             req.form['txuuid'] = txuuid
   965         rpath = "toto"
   989             rpath = "toto"
   966         req.form['__redirectpath'] = rpath
   990             req.form['__redirectpath'] = rpath
   967         controller = self.vreg['controllers'].select('undo', req)
   991             controller = self.vreg['controllers'].select('undo', req)
   968         with self.assertRaises(Redirect) as cm:
   992             with self.assertRaises(Redirect) as cm:
   969             result = controller.publish(rset=None)
   993                 result = controller.publish(rset=None)
   970         self.assertURLPath(cm.exception.location, rpath)
   994             self.assertURLPath(cm.exception.location, rpath)
   971 
   995 
   972     def test_redirect_default(self):
   996     def test_redirect_default(self):
   973         req = self.request()
   997         with self.admin_access.web_request() as req:
   974         txuuid = self.txuuid_toto_email
   998             txuuid = self.txuuid_toto_email
   975         req.form['txuuid'] = txuuid
   999             req.form['txuuid'] = txuuid
   976         req.session.data['breadcrumbs'] = [ urljoin(req.base_url(), path)
  1000             req.session.data['breadcrumbs'] = [ urljoin(req.base_url(), path)
   977                                             for path in ('tata', 'toto',)]
  1001                                                 for path in ('tata', 'toto',)]
   978         controller = self.vreg['controllers'].select('undo', req)
  1002             controller = self.vreg['controllers'].select('undo', req)
   979         with self.assertRaises(Redirect) as cm:
  1003             with self.assertRaises(Redirect) as cm:
   980             result = controller.publish(rset=None)
  1004                 result = controller.publish(rset=None)
   981         self.assertURLPath(cm.exception.location, 'toto')
  1005             self.assertURLPath(cm.exception.location, 'toto')
   982 
  1006 
   983 
  1007 
   984 class LoginControllerTC(CubicWebTC):
  1008 class LoginControllerTC(CubicWebTC):
   985 
  1009 
   986     def test_login_with_dest(self):
  1010     def test_login_with_dest(self):
   987         req = self.request()
  1011         with self.admin_access.web_request() as req:
   988         req.form = {'postlogin_path': 'elephants/babar'}
  1012             req.form = {'postlogin_path': 'elephants/babar'}
   989         with self.assertRaises(Redirect) as cm:
  1013             with self.assertRaises(Redirect) as cm:
   990             self.ctrl_publish(req, ctrl='login')
  1014                 self.ctrl_publish(req, ctrl='login')
   991         self.assertEqual(req.build_url('elephants/babar'), cm.exception.location)
  1015             self.assertEqual(req.build_url('elephants/babar'), cm.exception.location)
   992 
  1016 
   993     def test_login_no_dest(self):
  1017     def test_login_no_dest(self):
   994         req = self.request()
  1018         with self.admin_access.web_request() as req:
   995         with self.assertRaises(Redirect) as cm:
  1019             with self.assertRaises(Redirect) as cm:
   996             self.ctrl_publish(req, ctrl='login')
  1020                 self.ctrl_publish(req, ctrl='login')
   997         self.assertEqual(req.base_url(), cm.exception.location)
  1021             self.assertEqual(req.base_url(), cm.exception.location)
   998 
  1022 
   999 if __name__ == '__main__':
  1023 if __name__ == '__main__':
  1000     unittest_main()
  1024     unittest_main()