unittest_views_basecontrollers.py 29.1 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
from logilab.common.testlib import unittest_main, mock_object
Adrien Di Mascio's avatar
Adrien Di Mascio committed
10

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

Sylvain Thénault's avatar
Sylvain Thénault committed
20
21
22
23
24
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
25

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

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

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

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

    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
59
        basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X in_group G, X eid %(x)s', {'x': user.eid})]
60
        groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')]
Sylvain Thénault's avatar
Sylvain Thénault committed
61
        groups = [u(eid) for eid in groupeids]
62
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
63
        eid = u(user.eid)
64
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
65
66
67
68
69
70
            '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
71
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
72
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
73
        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
74
75
        self.assertEquals(e.firstname, u'Sylvain')
        self.assertEquals(e.surname, u'Th\xe9nault')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
76
77
78
79
80
81
82
        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
83
        eid = u(user.eid)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
84
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
85
86
87
88
89
            '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
90
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
91
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
92
        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
93
        self.assertEquals(path, 'cwuser/user')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
94
95
        self.failIf('vid' in params)

Sylvain Thénault's avatar
Sylvain Thénault committed
96
    def test_user_editing_itself_no_relation(self):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
97
98
99
100
        """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
101
        groupeids = [g.eid for g in user.in_group]
102
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
103
        eid = u(user.eid)
104
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
105
106
107
108
109
110
            '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
111
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
112
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
113
114
115
116
117
        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
118
        self.assertEquals(e.state, 'activated')
119
120


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

126
                    '__type:X': 'CWUser',
Sylvain Thénault's avatar
Sylvain Thénault committed
127
128
129
130
131
                    '_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),
132

133
                    '__type:Y': 'EmailAddress',
Sylvain Thénault's avatar
Sylvain Thénault committed
134
135
136
                    '_cw_edited_fields:Y': 'address-subject,use_email-object',
                    'address-subject:Y': u'dima@logilab.fr',
                    'use_email-object:Y': 'X',
137
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
138
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
139
        # should be redirected on the created person
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
140
        self.assertEquals(path, 'cwuser/adim')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
141
142
143
144
        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')
145

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

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

Sylvain Thénault's avatar
Sylvain Thénault committed
155
156
157
158
                    '__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,
159
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
160
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
161
        # should be redirected on the created person
Sylvain Thénault's avatar
Sylvain Thénault committed
162
163
        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
164
165
        email = e.use_email[0]
        self.assertEquals(email.address, 'dima@logilab.fr')
166

Sylvain Thénault's avatar
Sylvain Thénault committed
167
        emaileid = u(email.eid)
168
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
169
170
171
172
173
174
175
176
177
178
179
180
181
        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
182
183
        self.assertEquals(email.address, 'adim@logilab.fr')

184

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


    def test_interval_bound_constraint_success(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
211
        feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
212
                            {'data': Binary('yo')})[0][0]
213
214
215
        req = self.request()
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
Sylvain Thénault's avatar
Sylvain Thénault committed
216
217
218
                    '_cw_edited_fields:X': 'amount-subject,described_by_test-subject',
                    'amount-subject:X': u'-10',
                    'described_by_test-subject:X': u(feid),
219
                }
Sylvain Thénault's avatar
Sylvain Thénault committed
220
        ex = self.assertRaises(ValidationError, self.ctrl_publish, req)
221
        self.assertEquals(ex.errors, {'amount-subject': 'value [0;100] constraint failed for value -10'})
222
223
224
        req = self.request()
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
Sylvain Thénault's avatar
Sylvain Thénault committed
225
226
227
                    '_cw_edited_fields:X': 'amount-subject,described_by_test-subject',
                    'amount-subject:X': u'110',
                    'described_by_test-subject:X': u(feid),
228
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
229
        ex = self.assertRaises(ValidationError, self.ctrl_publish, req)
230
        self.assertEquals(ex.errors, {'amount-subject': 'value [0;100] constraint failed for value 110'})
231
232
233
        req = self.request()
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
Sylvain Thénault's avatar
Sylvain Thénault committed
234
235
236
                    '_cw_edited_fields:X': 'amount-subject,described_by_test-subject',
                    'amount-subject:X': u'10',
                    'described_by_test-subject:X': u(feid),
237
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
238
        self.expect_redirect_publish(req, 'edit')
239
        # should be redirected on the created
Adrien Di Mascio's avatar
Adrien Di Mascio committed
240
241
242
243
244
245
        #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
246
        tmpgroup = self.request().create_entity('CWGroup', name=u"test")
Adrien Di Mascio's avatar
Adrien Di Mascio committed
247
        user = self.user()
Sylvain Thénault's avatar
Sylvain Thénault committed
248
        req = self.request(**req_form(user))
249
        req.set_session_data('pending_insert', set([(user.eid, 'in_group', tmpgroup.eid)]))
Sylvain Thénault's avatar
Sylvain Thénault committed
250
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
251
252
253
        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
254
        self.assertEquals(get_pending_inserts(req), [])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
255
256
257
258
259


    def test_req_pending_delete(self):
        """make sure req's pending deletions are taken into account"""
        user = self.user()
260
        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
261
262
263
264
265
266
                                {'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
267
        req = self.request(**req_form(user))
268
        req.set_session_data('pending_delete', set([(user.eid, 'in_group', groupeid)]))
Sylvain Thénault's avatar
Sylvain Thénault committed
269
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
270
271
272
        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
273
        self.assertEquals(get_pending_deletes(req), [])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
274

Sylvain Thénault's avatar
Sylvain Thénault committed
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
    # 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
294

Adrien Di Mascio's avatar
Adrien Di Mascio committed
295
296
    def test_redirect_apply_button(self):
        redirectrql = rql_for_eid(4012) # whatever
297
298
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
299
300
301
302
            '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',
303
304
305
306
307
308
            '__redirectrql': redirectrql,
            '__redirectvid': 'primary',
            '__redirectparams': 'toto=tutu&tata=titi',
            '__form_id': 'edition',
            '__action_apply': '',
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
309
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
310
311
312
313
314
315
316
317
318
319
        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
320
321
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
322
323
324
325
            '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',
326
327
328
329
330
            '__redirectrql': redirectrql,
            '__redirectvid': 'primary',
            '__redirectparams': 'toto=tutu&tata=titi',
            '__form_id': 'edition',
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
331
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
332
333
334
335
336
337
338
        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):
339
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
340
        eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
Sylvain Thénault's avatar
Sylvain Thénault committed
341
        req.form = {'eid': u(eid), '__type:%s'%eid: 'BlogEntry',
342
                    '__action_delete': ''}
Sylvain Thénault's avatar
Sylvain Thénault committed
343
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
344
        self.assertEquals(path, 'blogentry')
Sylvain Thénault's avatar
Sylvain Thénault committed
345
        self.assertIn('_cwmsgid', params)
Sylvain Thénault's avatar
Sylvain Thénault committed
346
        eid = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
Adrien Di Mascio's avatar
Adrien Di Mascio committed
347
        self.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s',
348
                     {'x': self.session.user.eid, 'e': eid}, 'x')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
349
        self.commit()
Sylvain Thénault's avatar
Sylvain Thénault committed
350
        req = req
Sylvain Thénault's avatar
Sylvain Thénault committed
351
        req.form = {'eid': u(eid), '__type:%s'%eid: 'EmailAddress',
352
                    '__action_delete': ''}
Sylvain Thénault's avatar
Sylvain Thénault committed
353
        path, params = self.expect_redirect_publish(req, 'edit')
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
354
        self.assertEquals(path, 'cwuser/admin')
Sylvain Thénault's avatar
Sylvain Thénault committed
355
        self.assertIn('_cwmsgid', params)
Sylvain Thénault's avatar
Sylvain Thénault committed
356
357
        eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
        eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
358
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
359
        req.form = {'eid': [u(eid1), u(eid2)],
360
361
362
                    '__type:%s'%eid1: 'BlogEntry',
                    '__type:%s'%eid2: 'EmailAddress',
                    '__action_delete': ''}
Sylvain Thénault's avatar
Sylvain Thénault committed
363
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
364
        self.assertEquals(path, 'view')
Sylvain Thénault's avatar
Sylvain Thénault committed
365
        self.assertIn('_cwmsgid', params)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
366
367

    def test_nonregr_eetype_etype_editing(self):
368
        """non-regression test checking that a manager user can edit a CWEType entity
Adrien Di Mascio's avatar
Adrien Di Mascio committed
369
        """
370
        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
371
372
373
374
        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)
375
376
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
377
378
379
380
            'eid':      cwetypeeid,
            '__type:'+cwetypeeid:  'CWEType',
            '_cw_edited_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject',
            'name-subject:'+cwetypeeid:     u'CWEType',
Sylvain Thénault's avatar
Sylvain Thénault committed
381
            'final-subject:'+cwetypeeid:    '',
Sylvain Thénault's avatar
Sylvain Thénault committed
382
383
            'description-subject:'+cwetypeeid:     u'users group',
            'read_permission-subject:'+cwetypeeid:  groups,
384
            }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
385
        try:
Sylvain Thénault's avatar
Sylvain Thénault committed
386
387
            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)
388
            self.assertEquals(e.name, 'CWEType')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
389
390
391
            self.assertEquals(sorted(g.eid for g in e.read_permission), groupeids)
        finally:
            # restore
392
            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
393
            self.commit()
394

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

        this seems to be postgres (tsearch?) specific
399
        """
400
401
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
402
403
404
405
406
            '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
407
408
409
410
411
412
413
414
        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):
415
        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
416
417
        req = self.request()
        req.form = {'eid': ['X', 'Y'],
418

419
                    '__type:X': 'CWUser',
Sylvain Thénault's avatar
Sylvain Thénault committed
420
421
422
423
                    '_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`,
424

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

    def test_nonregr_copy(self):
        user = self.user()
436
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
437
438
439
440
441
        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',
442
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
443
        path, params = self.expect_redirect_publish(req, 'edit')
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
444
        self.assertEquals(path, 'cwuser/toto')
445
        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
446
447
448
449
450
451
452
453
454
455
        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
456
            e = self.request().create_entity('EmailAddress', address=u'doe@doe.com')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
457
458
            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})
459
            req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
460
461
462
463
464
            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',
465
                        '__errorurl' : "whatever but required",
Sylvain Thénault's avatar
Sylvain Thénault committed
466
                        }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
467
468
469
470
471
            # 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
472
                self.app_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
473
            except Redirect:
Sylvain Thénault's avatar
Sylvain Thénault committed
474
                req = self.request()
475
476
                req.form['rql'] = 'Any X WHERE X eid %s' % p.eid
                req.form['vid'] = 'copy'
Sylvain Thénault's avatar
Sylvain Thénault committed
477
                self.app_publish(req, 'view')
478
            rset = self.execute('CWUser P WHERE P surname "Boom"')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
479
480
481
482
483
            self.assertEquals(len(rset), 0)
        finally:
            p.__class__.skip_copy_for = old_skips


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

    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()
491
        req.form['url'] = 'http://www.logilab.fr/'
492
        controller = self.vreg['controllers'].select('embed', req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
493
494
495
        result = controller.publish(rset=None)


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

    def test_usable_by_guets(self):
499
        self.login('anon')
Sylvain Thénault's avatar
Sylvain Thénault committed
500
501
502
        self.assertRaises(NoSelectableObject,
                          self.vreg['controllers'].select, 'reportbug', self.request())
        self.vreg['controllers'].select('reportbug', self.request(description='hop'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
503
504


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

    def test_not_usable_by_guets(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
508
509
510
511
512
513
        self.assertRaises(NoSelectableObject,
                          self.vreg['controllers'].select, 'sendmail', self.request())
        self.vreg['controllers'].select('sendmail',
                                        self.request(subject='toto',
                                                     recipient='toto@logilab.fr',
                                                     mailbody='hop'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
514
        self.login('anon')
515
516
        self.assertRaises(NoSelectableObject,
                          self.vreg['controllers'].select, 'sendmail', self.request())
517

Adrien Di Mascio's avatar
Adrien Di Mascio committed
518
519


520
class JSONControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
521
522
523

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

    def setup_database(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
527
528
529
        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
530
531
532
533
534
        self.john = self.create_user(u'John')


    ## tests ##################################################################
    def test_simple_exec(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
535
536
537
538
        req = self.request(rql='CWUser P WHERE P login "John"',
                           pageid='123', fname='view')
        ctrl = self.ctrl(req)
        rset = self.john.as_rset()
539
        rset.req = req
540
541
542
543
544
545
546
        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
547

sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
548
549
550
551
#     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(),
552
#                           json.dumps(self.execute(rql).rows))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
553
554
555
556
557

    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'])
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
                          [['python']])
560

Adrien Di Mascio's avatar
Adrien Di Mascio committed
561
562
563
564
    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'])
565
        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
566
567
568
                          [['javascript']])

    def test_pending_insertion(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
569
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '13']])
Sylvain Thénault's avatar
Sylvain Thénault committed
570
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
571
        self.assertEquals(deletes, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
572
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
573
        self.assertEquals(inserts, ['12:tags:13'])
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
574
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Sylvain Thénault's avatar
Sylvain Thénault committed
575
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
576
        self.assertEquals(deletes, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
577
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
578
        self.assertEquals(inserts, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
579
        inserts = get_pending_inserts(req, 12)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
580
        self.assertEquals(inserts, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
581
        inserts = get_pending_inserts(req, 13)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
582
        self.assertEquals(inserts, ['12:tags:13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
583
        inserts = get_pending_inserts(req, 14)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
584
585
586
587
588
        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
589
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
590
        self.assertEquals(inserts, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
591
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
592
593
        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
594
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
595
        self.assertEquals(inserts, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
596
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
597
        self.assertEquals(deletes, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
598
        deletes = get_pending_deletes(req, 12)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
599
        self.assertEquals(deletes, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
600
        deletes = get_pending_deletes(req, 13)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
601
        self.assertEquals(deletes, ['12:tags:13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
602
        deletes = get_pending_deletes(req, 14)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
603
604
605
606
607
        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
608
        _, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Sylvain Thénault's avatar
Sylvain Thénault committed
609
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
610
        self.assertEquals(inserts, ['12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
611
        deletes = get_pending_deletes(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
612
613
        self.assertEquals(deletes, ['12:tags:13'])
        req.remove_pending_operations()
Sylvain Thénault's avatar
Sylvain Thénault committed
614
615
        self.assertEquals(get_pending_deletes(req), [])
        self.assertEquals(get_pending_inserts(req), [])
616

Adrien Di Mascio's avatar
Adrien Di Mascio committed
617
618
619
620

    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
621
        inserts = get_pending_inserts(req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
622
623
        self.assertEquals(inserts, ['12:tags:13', '12:tags:14'])
        req.remove_pending_operations()
624

Adrien Di Mascio's avatar
Adrien Di Mascio committed
625
626
627
628

    # silly tests
    def test_external_resource(self):
        self.assertEquals(self.remote_call('external_resource', 'RSS_LOGO')[0],
629
                          json.dumps(self.request().external_resource('RSS_LOGO')))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
630
631
    def test_i18n(self):
        self.assertEquals(self.remote_call('i18n', ['bimboom'])[0],
632
                          json.dumps(['bimboom']))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
633
634

    def test_format_date(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
635
        self.assertEquals(self.remote_call('format_date', '2007-01-01 12:00:00')[0],
636
                          json.dumps('2007/01/01'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
637
638


639
640


Adrien Di Mascio's avatar
Adrien Di Mascio committed
641
642
if __name__ == '__main__':
    unittest_main()