unittest_views_basecontrollers.py 28.7 KB
Newer Older
1
2
3
"""cubicweb.web.views.basecontrollers unit tests

:organization: Logilab
4
:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
5
6
7
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
"""
Adrien Di Mascio's avatar
Adrien Di Mascio committed
8
9
import simplejson

10
from logilab.common.testlib import unittest_main, mock_object
Adrien Di Mascio's avatar
Adrien Di Mascio committed
11

12
13
from cubicweb import Binary, NoSelectableObject, ValidationError
from cubicweb.view import STRICT_DOCTYPE
14
from cubicweb.devtools.testlib import CubicWebTC
Sylvain Thénault's avatar
Sylvain Thénault committed
15
from cubicweb.uilib import rql_for_eid
Adrien Di Mascio's avatar
Adrien Di Mascio committed
16
from cubicweb.web import INTERNAL_FIELD_VALUE, Redirect, RequestError
17
from cubicweb.entities.authobjs import CWUser
Sylvain Thénault's avatar
Sylvain Thénault committed
18
from cubicweb.web.views.editviews import get_pending_inserts, get_pending_deletes
Sylvain Thénault's avatar
Sylvain Thénault committed
19
20
u = unicode

Sylvain Thénault's avatar
Sylvain Thénault committed
21
22
23
24
25
def req_form(user):
    return {'eid': [str(user.eid)],
            '_cw_edited_fields:%s' % user.eid: '_cw_generic_field',
            '__type:%s' % user.eid: user.__regid__
            }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
26

27
class EditControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
28
    def setUp(self):
29
        CubicWebTC.setUp(self)
30
        self.failUnless('users' in self.schema.eschema('CWGroup').get_groups('read'))
31

Adrien Di Mascio's avatar
Adrien Di Mascio committed
32
    def tearDown(self):
33
        CubicWebTC.tearDown(self)
34
        self.failUnless('users' in self.schema.eschema('CWGroup').get_groups('read'))
35

Adrien Di Mascio's avatar
Adrien Di Mascio committed
36
37
38
    def test_noparam_edit(self):
        """check behaviour of this controller without any form parameter
        """
Sylvain Thénault's avatar
Sylvain Thénault committed
39
40
        ex = self.assertRaises(ValidationError, self.ctrl_publish, self.request())
        self.assertEquals(ex.errors, {None: u'no selected entities'})
41

Adrien Di Mascio's avatar
Adrien Di Mascio committed
42
43
    def test_validation_unique(self):
        """test creation of two linked entities
44
        """
Adrien Di Mascio's avatar
Adrien Di Mascio committed
45
        user = self.user()
46
47
        req = self.request()
        req.form = {'eid': 'X', '__type:X': 'CWUser',
Sylvain Thénault's avatar
Sylvain Thénault committed
48
49
50
51
                    '_cw_edited_fields:X': 'login-subject,upassword-subject',
                    'login-subject:X': u'admin',
                    'upassword-subject:X': u'toto',
                    'upassword-subject-confirm:X': u'toto',
52
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
53
54
        ex = self.assertRaises(ValidationError, self.ctrl_publish, req)
        self.assertEquals(ex.errors, {'login': 'the value "admin" is already used, use another one'})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
55
56
57
58
59

    def test_user_editing_itself(self):
        """checking that a manager user can edit itself
        """
        user = self.user()
Sylvain Thénault's avatar
Sylvain Thénault committed
60
        basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X in_group G, X eid %(x)s', {'x': user.eid})]
61
        groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')]
Sylvain Thénault's avatar
Sylvain Thénault committed
62
        groups = [u(eid) for eid in groupeids]
63
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
64
        eid = u(user.eid)
65
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
66
67
68
69
70
71
            'eid': eid, '__type:'+eid: 'CWUser',
            '_cw_edited_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject',
            'login-subject:'+eid:     u(user.login),
            'surname-subject:'+eid: u'Th\xe9nault',
            'firstname-subject:'+eid:   u'Sylvain',
            'in_group-subject:'+eid:  groups,
Adrien Di Mascio's avatar
Adrien Di Mascio committed
72
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
73
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
74
        e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}, 'x').get_entity(0, 0)
Sylvain Thénault's avatar
Sylvain Thénault committed
75
76
        self.assertEquals(e.firstname, u'Sylvain')
        self.assertEquals(e.surname, u'Th\xe9nault')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
77
78
79
80
81
82
83
        self.assertEquals(e.login, user.login)
        self.assertEquals([g.eid for g in e.in_group], groupeids)

    def test_user_can_change_its_password(self):
        user = self.create_user('user')
        cnx = self.login('user')
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
84
        eid = u(user.eid)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
85
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
86
87
88
89
90
            'eid': eid, '__maineid' : eid,
            '__type:'+eid: 'CWUser',
            '_cw_edited_fields:'+eid: 'upassword-subject',
            'upassword-subject:'+eid: 'tournicoton',
            'upassword-subject-confirm:'+eid: 'tournicoton',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
91
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
92
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
93
        cnx.commit() # commit to check we don't get late validation error for instance
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
94
        self.assertEquals(path, 'cwuser/user')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
95
96
        self.failIf('vid' in params)

Sylvain Thénault's avatar
Sylvain Thénault committed
97
    def test_user_editing_itself_no_relation(self):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
98
99
100
101
        """checking we can edit an entity without specifying some required
        relations (meaning no changes)
        """
        user = self.user()
Sylvain Thénault's avatar
Sylvain Thénault committed
102
        groupeids = [g.eid for g in user.in_group]
103
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
104
        eid = u(user.eid)
105
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
106
107
108
109
110
111
            'eid':       eid,
            '__type:'+eid:    'CWUser',
            '_cw_edited_fields:'+eid: 'login-subject,firstname-subject,surname-subject',
            'login-subject:'+eid:     u(user.login),
            'firstname-subject:'+eid: u'Th\xe9nault',
            'surname-subject:'+eid:   u'Sylvain',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
112
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
113
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
114
115
116
117
118
        e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}, 'x').get_entity(0, 0)
        self.assertEquals(e.login, user.login)
        self.assertEquals(e.firstname, u'Th\xe9nault')
        self.assertEquals(e.surname, u'Sylvain')
        self.assertEquals([g.eid for g in e.in_group], groupeids)
Sylvain Thénault's avatar
Sylvain Thénault committed
119
        self.assertEquals(e.state, 'activated')
120
121


Adrien Di Mascio's avatar
Adrien Di Mascio committed
122
    def test_create_multiple_linked(self):
123
        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
124
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
125
        req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
126

127
                    '__type:X': 'CWUser',
Sylvain Thénault's avatar
Sylvain Thénault committed
128
129
130
131
132
                    '_cw_edited_fields:X': 'login-subject,upassword-subject,surname-subject,in_group-subject',
                    'login-subject:X': u'adim',
                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
                    'surname-subject:X': u'Di Mascio',
                    'in_group-subject:X': u(gueid),
133

134
                    '__type:Y': 'EmailAddress',
Sylvain Thénault's avatar
Sylvain Thénault committed
135
136
137
                    '_cw_edited_fields:Y': 'address-subject,use_email-object',
                    'address-subject:Y': u'dima@logilab.fr',
                    'use_email-object:Y': 'X',
138
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
139
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
140
        # should be redirected on the created person
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
141
        self.assertEquals(path, 'cwuser/adim')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
142
143
144
145
        e = self.execute('Any P WHERE P surname "Di Mascio"').get_entity(0, 0)
        self.assertEquals(e.surname, 'Di Mascio')
        email = e.use_email[0]
        self.assertEquals(email.address, 'dima@logilab.fr')
146

Adrien Di Mascio's avatar
Adrien Di Mascio committed
147
    def test_edit_multiple_linked(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
148
        peid = u(self.create_user('adim').eid)
149
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
150
        req.form = {'eid': [peid, 'Y'], '__maineid': peid,
151

Sylvain Thénault's avatar
Sylvain Thénault committed
152
153
154
                    '__type:'+peid: u'CWUser',
                    '_cw_edited_fields:'+peid: u'surname-subject',
                    'surname-subject:'+peid: u'Di Masci',
155

Sylvain Thénault's avatar
Sylvain Thénault committed
156
157
158
159
                    '__type:Y': u'EmailAddress',
                    '_cw_edited_fields:Y': u'address-subject,use_email-object',
                    'address-subject:Y': u'dima@logilab.fr',
                    'use_email-object:Y': peid,
160
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
161
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
162
        # should be redirected on the created person
Sylvain Thénault's avatar
Sylvain Thénault committed
163
164
        self.assertEquals(path, 'cwuser/adim')
        e = self.execute('Any P WHERE P surname "Di Masci"').get_entity(0, 0)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
165
166
        email = e.use_email[0]
        self.assertEquals(email.address, 'dima@logilab.fr')
167

Sylvain Thénault's avatar
Sylvain Thénault committed
168
        emaileid = u(email.eid)
169
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
170
171
172
173
174
175
176
177
178
179
180
181
182
        req.form = {'eid': [peid, emaileid],

                    '__type:'+peid: u'CWUser',
                    '_cw_edited_fields:'+peid: u'surname-subject',
                    'surname-subject:'+peid: u'Di Masci',

                    '__type:'+emaileid: u'EmailAddress',
                    '_cw_edited_fields:'+emaileid: u'address-subject,use_email-object',
                    'address-subject:'+emaileid: u'adim@logilab.fr',
                    'use_email-object:'+emaileid: peid,
                    }
        path, params = self.expect_redirect_publish(req, 'edit')
        email.clear_all_caches()
Adrien Di Mascio's avatar
Adrien Di Mascio committed
183
184
        self.assertEquals(email.address, 'adim@logilab.fr')

185

Adrien Di Mascio's avatar
Adrien Di Mascio committed
186
187
    def test_password_confirm(self):
        """test creation of two linked entities
188
        """
Adrien Di Mascio's avatar
Adrien Di Mascio committed
189
        user = self.user()
190
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
191
192
193
194
195
        req.form = {'eid': 'X',
                    '__cloned_eid:X': u(user.eid), '__type:X': 'CWUser',
                    '_cw_edited_fields:X': 'login-subject,upassword-subject',
                    'login-subject:X': u'toto',
                    'upassword-subject:X': u'toto',
196
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
197
        ex = self.assertRaises(ValidationError, self.ctrl_publish, req)
Sylvain Thénault's avatar
Sylvain Thénault committed
198
        self.assertEquals(ex.errors, {'upassword-subject': u'password and confirmation don\'t match'})
199
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
200
        req.form = {'__cloned_eid:X': u(user.eid),
201
                    'eid': 'X', '__type:X': 'CWUser',
Sylvain Thénault's avatar
Sylvain Thénault committed
202
203
204
205
                    '_cw_edited_fields:X': 'login-subject,upassword-subject',
                    'login-subject:X': u'toto',
                    'upassword-subject:X': u'toto',
                    'upassword-subject-confirm:X': u'tutu',
206
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
207
        ex = self.assertRaises(ValidationError, self.ctrl_publish, req)
Sylvain Thénault's avatar
Sylvain Thénault committed
208
        self.assertEquals(ex.errors, {'upassword-subject': u'password and confirmation don\'t match'})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
209
210
211


    def test_interval_bound_constraint_success(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
212
        feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
213
                            {'data': Binary('yo')})[0][0]
214
215
216
        req = self.request()
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
Sylvain Thénault's avatar
Sylvain Thénault committed
217
218
219
                    '_cw_edited_fields:X': 'amount-subject,described_by_test-subject',
                    'amount-subject:X': u'-10',
                    'described_by_test-subject:X': u(feid),
220
                }
Sylvain Thénault's avatar
Sylvain Thénault committed
221
222
        ex = self.assertRaises(ValidationError, self.ctrl_publish, req)
        self.assertEquals(ex.errors, {'amount': 'value [0;100] constraint failed for value -10'})
223
224
225
        req = self.request()
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
Sylvain Thénault's avatar
Sylvain Thénault committed
226
227
228
                    '_cw_edited_fields:X': 'amount-subject,described_by_test-subject',
                    'amount-subject:X': u'110',
                    'described_by_test-subject:X': u(feid),
229
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
230
231
        ex = self.assertRaises(ValidationError, self.ctrl_publish, req)
        self.assertEquals(ex.errors, {'amount': 'value [0;100] constraint failed for value 110'})
232
233
234
        req = self.request()
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
Sylvain Thénault's avatar
Sylvain Thénault committed
235
236
237
                    '_cw_edited_fields:X': 'amount-subject,described_by_test-subject',
                    'amount-subject:X': u'10',
                    'described_by_test-subject:X': u(feid),
238
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
239
        self.expect_redirect_publish(req, 'edit')
240
        # should be redirected on the created
Adrien Di Mascio's avatar
Adrien Di Mascio committed
241
242
243
244
245
246
        #eid = params['rql'].split()[-1]
        e = self.execute('Salesterm X').get_entity(0, 0)
        self.assertEquals(e.amount, 10)

    def test_req_pending_insert(self):
        """make sure req's pending insertions are taken into account"""
Sylvain Thénault's avatar
Sylvain Thénault committed
247
        tmpgroup = self.request().create_entity('CWGroup', name=u"test")
Adrien Di Mascio's avatar
Adrien Di Mascio committed
248
        user = self.user()
Sylvain Thénault's avatar
Sylvain Thénault committed
249
        req = self.request(**req_form(user))
250
        req.set_session_data('pending_insert', set([(user.eid, 'in_group', tmpgroup.eid)]))
Sylvain Thénault's avatar
Sylvain Thénault committed
251
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
252
253
254
        usergroups = [gname for gname, in
                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
        self.assertUnorderedIterableEquals(usergroups, ['managers', 'test'])
Sylvain Thénault's avatar
Sylvain Thénault committed
255
        self.assertEquals(get_pending_inserts(req), [])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
256
257
258
259
260


    def test_req_pending_delete(self):
        """make sure req's pending deletions are taken into account"""
        user = self.user()
261
        groupeid = self.execute('INSERT CWGroup G: G name "test", U in_group G WHERE U eid %(x)s',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
262
263
264
265
266
267
                                {'x': user.eid})[0][0]
        usergroups = [gname for gname, in
                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
        # just make sure everything was set correctly
        self.assertUnorderedIterableEquals(usergroups, ['managers', 'test'])
        # now try to delete the relation
Sylvain Thénault's avatar
Sylvain Thénault committed
268
        req = self.request(**req_form(user))
269
        req.set_session_data('pending_delete', set([(user.eid, 'in_group', groupeid)]))
Sylvain Thénault's avatar
Sylvain Thénault committed
270
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
271
272
273
        usergroups = [gname for gname, in
                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
        self.assertUnorderedIterableEquals(usergroups, ['managers'])
Sylvain Thénault's avatar
Sylvain Thénault committed
274
        self.assertEquals(get_pending_deletes(req), [])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
275

Sylvain Thénault's avatar
Sylvain Thénault committed
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
    # def test_custom_attribute_handler(self):
    #     def custom_login_edit(self, formparams, value, relations):
    #         formparams['login'] = value.upper()
    #         relations.append('X login %(login)s')
    #     CWUser.custom_login_edit = custom_login_edit
    #     try:
    #         user = self.user()
    #         eid = repr(user.eid)
    #         req = self.request()
    #         req.form = {
    #             'eid': eid,
    #             '__type:'+eid:  'CWUser',
    #             'login:'+eid: u'foo',
    #             }
    #         path, params = self.expect_redirect_publish(req, 'edit')
    #         rset = self.execute('Any L WHERE X eid %(x)s, X login L', {'x': user.eid}, 'x')
    #         self.assertEquals(rset[0][0], 'FOO')
    #     finally:
    #         del CWUser.custom_login_edit
295

Adrien Di Mascio's avatar
Adrien Di Mascio committed
296
297
    def test_redirect_apply_button(self):
        redirectrql = rql_for_eid(4012) # whatever
298
299
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
300
301
302
303
            'eid': 'A', '__maineid' : 'A',
            '__type:A': 'BlogEntry', '_cw_edited_fields:A': 'content-subject,title-subject',
            'content-subject:A': u'"13:03:43"',
            'title-subject:A': u'huuu',
304
305
306
307
308
309
            '__redirectrql': redirectrql,
            '__redirectvid': 'primary',
            '__redirectparams': 'toto=tutu&tata=titi',
            '__form_id': 'edition',
            '__action_apply': '',
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
310
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
311
312
313
314
315
316
317
318
319
320
        self.failUnless(path.startswith('blogentry/'))
        eid = path.split('/')[1]
        self.assertEquals(params['vid'], 'edition')
        self.assertNotEquals(int(eid), 4012)
        self.assertEquals(params['__redirectrql'], redirectrql)
        self.assertEquals(params['__redirectvid'], 'primary')
        self.assertEquals(params['__redirectparams'], 'toto=tutu&tata=titi')

    def test_redirect_ok_button(self):
        redirectrql = rql_for_eid(4012) # whatever
321
322
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
323
324
325
326
            'eid': 'A', '__maineid' : 'A',
            '__type:A': 'BlogEntry', '_cw_edited_fields:A': 'content-subject,title-subject',
            'content-subject:A': u'"13:03:43"',
            'title-subject:A': u'huuu',
327
328
329
330
331
            '__redirectrql': redirectrql,
            '__redirectvid': 'primary',
            '__redirectparams': 'toto=tutu&tata=titi',
            '__form_id': 'edition',
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
332
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
333
334
335
336
337
338
339
        self.assertEquals(path, 'view')
        self.assertEquals(params['rql'], redirectrql)
        self.assertEquals(params['vid'], 'primary')
        self.assertEquals(params['tata'], 'titi')
        self.assertEquals(params['toto'], 'tutu')

    def test_redirect_delete_button(self):
340
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
341
        eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
Sylvain Thénault's avatar
Sylvain Thénault committed
342
        req.form = {'eid': u(eid), '__type:%s'%eid: 'BlogEntry',
343
                    '__action_delete': ''}
Sylvain Thénault's avatar
Sylvain Thénault committed
344
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
345
346
        self.assertEquals(path, 'blogentry')
        self.assertEquals(params, {u'__message': u'entity deleted'})
Sylvain Thénault's avatar
Sylvain Thénault committed
347
        eid = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
Adrien Di Mascio's avatar
Adrien Di Mascio committed
348
        self.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s',
349
                     {'x': self.session.user.eid, 'e': eid}, 'x')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
350
        self.commit()
Sylvain Thénault's avatar
Sylvain Thénault committed
351
        req = req
Sylvain Thénault's avatar
Sylvain Thénault committed
352
        req.form = {'eid': u(eid), '__type:%s'%eid: 'EmailAddress',
353
                    '__action_delete': ''}
Sylvain Thénault's avatar
Sylvain Thénault committed
354
        path, params = self.expect_redirect_publish(req, 'edit')
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
355
        self.assertEquals(path, 'cwuser/admin')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
356
        self.assertEquals(params, {u'__message': u'entity deleted'})
Sylvain Thénault's avatar
Sylvain Thénault committed
357
358
        eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
        eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
359
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
360
        req.form = {'eid': [u(eid1), u(eid2)],
361
362
363
                    '__type:%s'%eid1: 'BlogEntry',
                    '__type:%s'%eid2: 'EmailAddress',
                    '__action_delete': ''}
Sylvain Thénault's avatar
Sylvain Thénault committed
364
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
365
366
367
368
        self.assertEquals(path, 'view')
        self.assertEquals(params, {u'__message': u'entities deleted'})

    def test_nonregr_eetype_etype_editing(self):
369
        """non-regression test checking that a manager user can edit a CWEType entity
Adrien Di Mascio's avatar
Adrien Di Mascio committed
370
        """
371
        groupeids = sorted(eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")'))
Sylvain Thénault's avatar
Sylvain Thénault committed
372
373
374
375
        groups = [u(eid) for eid in groupeids]
        cwetypeeid = self.execute('CWEType X WHERE X name "CWEType"')[0][0]
        basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X read_permission G, X eid %(x)s', {'x': cwetypeeid})]
        cwetypeeid = u(cwetypeeid)
376
377
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
378
379
380
381
382
383
384
            'eid':      cwetypeeid,
            '__type:'+cwetypeeid:  'CWEType',
            '_cw_edited_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject',
            'name-subject:'+cwetypeeid:     u'CWEType',
            #'final-subject:'+cwetypeeid:    False,
            'description-subject:'+cwetypeeid:     u'users group',
            'read_permission-subject:'+cwetypeeid:  groups,
385
            }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
386
        try:
Sylvain Thénault's avatar
Sylvain Thénault committed
387
388
            path, params = self.expect_redirect_publish(req, 'edit')
            e = self.execute('Any X WHERE X eid %(x)s', {'x': cwetypeeid}, 'x').get_entity(0, 0)
389
            self.assertEquals(e.name, 'CWEType')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
390
391
392
            self.assertEquals(sorted(g.eid for g in e.read_permission), groupeids)
        finally:
            # restore
393
            self.execute('SET X read_permission Y WHERE X name "CWEType", Y eid IN (%s), NOT X read_permission Y' % (','.join(basegroups)))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
394
            self.commit()
395

Adrien Di Mascio's avatar
Adrien Di Mascio committed
396
397
398
399
    def test_nonregr_strange_text_input(self):
        """non-regression test checking text input containing "13:03:43"

        this seems to be postgres (tsearch?) specific
400
        """
401
402
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
403
404
405
406
407
            'eid': 'A', '__maineid' : 'A',
            '__type:A': 'BlogEntry', '_cw_edited_fields:A': 'title-subject,content-subject',
            'title-subject:A': u'"13:03:40"',
            'content-subject:A': u'"13:03:43"',}
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
408
409
410
411
412
413
414
415
        self.failUnless(path.startswith('blogentry/'))
        eid = path.split('/')[1]
        e = self.execute('Any C, T WHERE C eid %(x)s, C content T', {'x': eid}, 'x').get_entity(0, 0)
        self.assertEquals(e.title, '"13:03:40"')
        self.assertEquals(e.content, '"13:03:43"')


    def test_nonregr_multiple_empty_email_addr(self):
416
        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
417
418
        req = self.request()
        req.form = {'eid': ['X', 'Y'],
419

420
                    '__type:X': 'CWUser',
Sylvain Thénault's avatar
Sylvain Thénault committed
421
422
423
424
                    '_cw_edited_fields:X': 'login-subject,upassword-subject,in_group-subject',
                    'login-subject:X': u'adim',
                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
                    'in_group-subject:X': `gueid`,
425

426
                    '__type:Y': 'EmailAddress',
Sylvain Thénault's avatar
Sylvain Thénault committed
427
428
429
430
                    '_cw_edited_fields:Y': 'address-subject,alias-subject,use_email-object',
                    'address-subject:Y': u'',
                    'alias-subject:Y': u'',
                    'use_email-object:Y': 'X',
431
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
432
433
        ex = self.assertRaises(ValidationError, self.ctrl_publish, req)
        self.assertEquals(ex.errors, {'address': u'required attribute'})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
434
435
436

    def test_nonregr_copy(self):
        user = self.user()
437
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
438
439
440
441
442
        req.form = {'__maineid' : 'X', 'eid': 'X',
                    '__cloned_eid:X': user.eid, '__type:X': 'CWUser',
                    '_cw_edited_fields:X': 'login-subject,upassword-subject',
                    'login-subject:X': u'toto',
                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
443
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
444
        path, params = self.expect_redirect_publish(req, 'edit')
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
445
        self.assertEquals(path, 'cwuser/toto')
446
        e = self.execute('Any X WHERE X is CWUser, X login "toto"').get_entity(0, 0)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
447
448
449
450
451
452
453
454
455
456
        self.assertEquals(e.login, 'toto')
        self.assertEquals(e.in_group[0].name, 'managers')


    def test_nonregr_rollback_on_validation_error(self):
        p = self.create_user("doe")
        # do not try to skip 'primary_email' for this test
        old_skips = p.__class__.skip_copy_for
        p.__class__.skip_copy_for = ()
        try:
Sylvain Thénault's avatar
Sylvain Thénault committed
457
            e = self.request().create_entity('EmailAddress', address=u'doe@doe.com')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
458
459
            self.execute('SET P use_email E, P primary_email E WHERE P eid %(p)s, E eid %(e)s',
                         {'p' : p.eid, 'e' : e.eid})
460
            req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
461
462
463
464
465
            req.form = {'eid': 'X',
                        '__cloned_eid:X': p.eid, '__type:X': 'CWUser',
                        '_cw_edited_fields:X': 'login-subject,surname-subject',
                        'login-subject': u'dodo',
                        'surname-subject:X': u'Boom',
466
                        '__errorurl' : "whatever but required",
Sylvain Thénault's avatar
Sylvain Thénault committed
467
                        }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
468
469
470
471
472
            # try to emulate what really happens in the web application
            # 1/ validate form => EditController.publish raises a ValidationError
            #    which fires a Redirect
            # 2/ When re-publishing the copy form, the publisher implicitly commits
            try:
Sylvain Thénault's avatar
Sylvain Thénault committed
473
                self.app_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
474
            except Redirect:
Sylvain Thénault's avatar
Sylvain Thénault committed
475
                req = self.request()
476
477
                req.form['rql'] = 'Any X WHERE X eid %s' % p.eid
                req.form['vid'] = 'copy'
Sylvain Thénault's avatar
Sylvain Thénault committed
478
                self.app_publish(req, 'view')
479
            rset = self.execute('CWUser P WHERE P surname "Boom"')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
480
481
482
483
484
            self.assertEquals(len(rset), 0)
        finally:
            p.__class__.skip_copy_for = old_skips


485
class EmbedControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
486
487
488
489
490
491
492

    def test_nonregr_embed_publish(self):
        # This test looks a bit stupid but at least it will probably
        # fail if the controller API changes and if EmbedController is not
        # updated (which is what happened before this test)
        req = self.request()
        req.form['url'] = 'http://intranet.logilab.fr/'
493
        controller = self.vreg['controllers'].select('embed', req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
494
495
496
        result = controller.publish(rset=None)


497
class ReportBugControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
498
499

    def test_usable_by_guets(self):
500
501
        self.login('anon')
        self.vreg['controllers'].select('reportbug', self.request())
Adrien Di Mascio's avatar
Adrien Di Mascio committed
502
503


504
class SendMailControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
505
506
507

    def test_not_usable_by_guets(self):
        self.login('anon')
508
509
        self.assertRaises(NoSelectableObject,
                          self.vreg['controllers'].select, 'sendmail', self.request())
510

Adrien Di Mascio's avatar
Adrien Di Mascio committed
511
512


513
class JSONControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
514
515
516

    def ctrl(self, req=None):
        req = req or self.request(url='http://whatever.fr/')
517
        return self.vreg['controllers'].select('json', req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
518
519

    def setup_database(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
520
521
522
        req = self.request()
        self.pytag = req.create_entity('Tag', name=u'python')
        self.cubicwebtag = req.create_entity('Tag', name=u'cubicweb')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
523
524
525
526
527
        self.john = self.create_user(u'John')


    ## tests ##################################################################
    def test_simple_exec(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
528
529
530
531
        req = self.request(rql='CWUser P WHERE P login "John"',
                           pageid='123', fname='view')
        ctrl = self.ctrl(req)
        rset = self.john.as_rset()
532
        rset.req = req
533
534
535
536
537
538
539
        source = ctrl.publish()
        self.failUnless(source.startswith('<?xml version="1.0"?>\n' + STRICT_DOCTYPE +
                                          u'<div xmlns="http://www.w3.org/1999/xhtml" xmlns:cubicweb="http://www.logilab.org/2008/cubicweb">')
                        )
        req.xhtml_browser = lambda: False
        source = ctrl.publish()
        self.failUnless(source.startswith('<div>'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
540

sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
541
542
543
544
545
#     def test_json_exec(self):
#         rql = 'Any T,N WHERE T is Tag, T name N'
#         ctrl = self.ctrl(self.request(mode='json', rql=rql, pageid='123'))
#         self.assertEquals(ctrl.publish(),
#                           simplejson.dumps(self.execute(rql).rows))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
546
547
548
549
550

    def test_remote_add_existing_tag(self):
        self.remote_call('tag_entity', self.john.eid, ['python'])
        self.assertUnorderedIterableEquals([tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
                             ['python', 'cubicweb'])
551
        self.assertEquals(self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
Adrien Di Mascio's avatar
Adrien Di Mascio committed
552
                          [['python']])
553

Adrien Di Mascio's avatar
Adrien Di Mascio committed
554
555
556
557
    def test_remote_add_new_tag(self):
        self.remote_call('tag_entity', self.john.eid, ['javascript'])
        self.assertUnorderedIterableEquals([tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
                             ['python', 'cubicweb', 'javascript'])
558
        self.assertEquals(self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
Adrien Di Mascio's avatar
Adrien Di Mascio committed
559
560
561
                          [['javascript']])

    def test_pending_insertion(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
562
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '13']])
Sylvain Thénault's avatar
Sylvain Thénault committed
563
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
564
        self.assertEquals(deletes, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
565
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
566
        self.assertEquals(inserts, ['12:tags:13'])
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
567
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Sylvain Thénault's avatar
Sylvain Thénault committed
568
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
569
        self.assertEquals(deletes, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
570
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
571
        self.assertEquals(inserts, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
572
        inserts = get_pending_inserts(req, 12)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
573
        self.assertEquals(inserts, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
574
        inserts = get_pending_inserts(req, 13)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
575
        self.assertEquals(inserts, ['12:tags:13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
576
        inserts = get_pending_inserts(req, 14)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
577
578
579
580
581
        self.assertEquals(inserts, ['12:tags:14'])
        req.remove_pending_operations()

    def test_pending_deletion(self):
        res, req = self.remote_call('add_pending_delete', ['12', 'tags', '13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
582
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
583
        self.assertEquals(inserts, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
584
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
585
586
        self.assertEquals(deletes, ['12:tags:13'])
        res, req = self.remote_call('add_pending_delete', ['12', 'tags', '14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
587
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
588
        self.assertEquals(inserts, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
589
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
590
        self.assertEquals(deletes, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
591
        deletes = get_pending_deletes(req, 12)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
592
        self.assertEquals(deletes, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
593
        deletes = get_pending_deletes(req, 13)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
594
        self.assertEquals(deletes, ['12:tags:13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
595
        deletes = get_pending_deletes(req, 14)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
596
597
598
599
600
        self.assertEquals(deletes, ['12:tags:14'])
        req.remove_pending_operations()

    def test_remove_pending_operations(self):
        self.remote_call('add_pending_delete', ['12', 'tags', '13'])
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
601
        _, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Sylvain Thénault's avatar
Sylvain Thénault committed
602
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
603
        self.assertEquals(inserts, ['12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
604
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
605
606
        self.assertEquals(deletes, ['12:tags:13'])
        req.remove_pending_operations()
Sylvain Thénault's avatar
Sylvain Thénault committed
607
608
        self.assertEquals(get_pending_deletes(req), [])
        self.assertEquals(get_pending_inserts(req), [])
609

Adrien Di Mascio's avatar
Adrien Di Mascio committed
610
611
612
613

    def test_add_inserts(self):
        res, req = self.remote_call('add_pending_inserts',
                                    [('12', 'tags', '13'), ('12', 'tags', '14')])
Sylvain Thénault's avatar
Sylvain Thénault committed
614
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
615
616
        self.assertEquals(inserts, ['12:tags:13', '12:tags:14'])
        req.remove_pending_operations()
617

Adrien Di Mascio's avatar
Adrien Di Mascio committed
618
619
620
621
622
623
624
625
626
627

    # silly tests
    def test_external_resource(self):
        self.assertEquals(self.remote_call('external_resource', 'RSS_LOGO')[0],
                          simplejson.dumps(self.request().external_resource('RSS_LOGO')))
    def test_i18n(self):
        self.assertEquals(self.remote_call('i18n', ['bimboom'])[0],
                          simplejson.dumps(['bimboom']))

    def test_format_date(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
628
        self.assertEquals(self.remote_call('format_date', '2007-01-01 12:00:00')[0],
Adrien Di Mascio's avatar
Adrien Di Mascio committed
629
630
631
                          simplejson.dumps('2007/01/01'))


632
633


Adrien Di Mascio's avatar
Adrien Di Mascio committed
634
635
if __name__ == '__main__':
    unittest_main()