unittest_views_basecontrollers.py 29.9 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
Adrien Di Mascio's avatar
Adrien Di Mascio committed
18

Sylvain Thénault's avatar
Sylvain Thénault committed
19
20
u = unicode

Adrien Di Mascio's avatar
Adrien Di Mascio committed
21

22
class EditControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
23
    def setUp(self):
24
        CubicWebTC.setUp(self)
25
        self.failUnless('users' in self.schema.eschema('CWGroup').get_groups('read'))
26

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

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

Adrien Di Mascio's avatar
Adrien Di Mascio committed
37
38
    def test_validation_unique(self):
        """test creation of two linked entities
39
        """
Adrien Di Mascio's avatar
Adrien Di Mascio committed
40
        user = self.user()
41
42
        req = self.request()
        req.form = {'eid': 'X', '__type:X': 'CWUser',
Sylvain Thénault's avatar
Sylvain Thénault committed
43
44
45
46
                    '_cw_edited_fields:X': 'login-subject,upassword-subject',
                    'login-subject:X': u'admin',
                    'upassword-subject:X': u'toto',
                    'upassword-subject-confirm:X': u'toto',
47
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
48
49
        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
50
51
52
53
54

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

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


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

122
                    '__type:X': 'CWUser',
Sylvain Thénault's avatar
Sylvain Thénault committed
123
124
125
126
127
                    '_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),
128

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

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

Sylvain Thénault's avatar
Sylvain Thénault committed
147
148
149
                    '__type:'+peid: u'CWUser',
                    '_cw_edited_fields:'+peid: u'surname-subject',
                    'surname-subject:'+peid: u'Di Masci',
150

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

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

180

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


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


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

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

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

    def test_nonregr_egroup_etype_editing(self):
364
        """non-regression test checking that a manager user can edit a CWEType entity (CWGroup)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
365
        """
366
        groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name "managers"')]
Sylvain Thénault's avatar
Sylvain Thénault committed
367
368
369
        groups = [u(eid) for eid in groupeids]
        cwetypeeid = u(self.execute('CWEType X WHERE X name "CWGroup"')[0][0])
        basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X read_permission G, X eid %(x)s', {'x': cwetypeeid})]
370
371
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
372
373
374
375
376
377
378
            'eid':      cwetypeeid,
            '__type:'+cwetypeeid:   'CWEType',
            '_cw_edited_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject',
            'name-subject:'+cwetypeeid:     u'CWGroup',
            #'final-subject:'+cwetypeeid:    False,
            'description-subject:'+cwetypeeid:     u'users group',
            'read_permission-subject:'+cwetypeeid:  groups,
379
            }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
380
        try:
Sylvain Thénault's avatar
Sylvain Thénault committed
381
382
            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)
383
            self.assertEquals(e.name, 'CWGroup')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
384
385
386
            self.assertEquals([g.eid for g in e.read_permission], groupeids)
        finally:
            # restore
387
            self.execute('SET X read_permission Y WHERE X name "CWGroup", Y eid IN (%s), NOT X read_permission Y' % (','.join(basegroups)))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
388
            self.commit()
389

Adrien Di Mascio's avatar
Adrien Di Mascio committed
390
    def test_nonregr_eetype_etype_editing(self):
391
        """non-regression test checking that a manager user can edit a CWEType entity (CWEType)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
392
        """
393
        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
394
395
396
397
        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)
398
399
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
400
401
402
403
404
405
406
            '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,
407
            }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
408
        try:
Sylvain Thénault's avatar
Sylvain Thénault committed
409
410
            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)
411
            self.assertEquals(e.name, 'CWEType')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
412
413
414
            self.assertEquals(sorted(g.eid for g in e.read_permission), groupeids)
        finally:
            # restore
415
            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
416
            self.commit()
417

Adrien Di Mascio's avatar
Adrien Di Mascio committed
418
419
420
421
    def test_nonregr_strange_text_input(self):
        """non-regression test checking text input containing "13:03:43"

        this seems to be postgres (tsearch?) specific
422
        """
423
424
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
425
426
427
428
429
            '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
430
431
432
433
434
435
436
437
        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):
438
        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
439
440
        req = self.request()
        req.form = {'eid': ['X', 'Y'],
441

442
                    '__type:X': 'CWUser',
Sylvain Thénault's avatar
Sylvain Thénault committed
443
444
445
446
                    '_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`,
447

448
                    '__type:Y': 'EmailAddress',
Sylvain Thénault's avatar
Sylvain Thénault committed
449
450
451
452
                    '_cw_edited_fields:Y': 'address-subject,alias-subject,use_email-object',
                    'address-subject:Y': u'',
                    'alias-subject:Y': u'',
                    'use_email-object:Y': 'X',
453
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
454
455
        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
456
457
458

    def test_nonregr_copy(self):
        user = self.user()
459
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
460
461
462
463
464
        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',
465
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
466
        path, params = self.expect_redirect_publish(req, 'edit')
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
467
        self.assertEquals(path, 'cwuser/toto')
468
        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
469
470
471
472
473
474
475
476
477
478
        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
479
            e = self.request().create_entity('EmailAddress', address=u'doe@doe.com')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
480
481
            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})
482
            req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
483
484
485
486
487
            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',
488
                        '__errorurl' : "whatever but required",
Sylvain Thénault's avatar
Sylvain Thénault committed
489
                        }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
490
491
492
493
494
            # 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
495
                self.app_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
496
            except Redirect:
Sylvain Thénault's avatar
Sylvain Thénault committed
497
                req = self.request()
498
499
                req.form['rql'] = 'Any X WHERE X eid %s' % p.eid
                req.form['vid'] = 'copy'
Sylvain Thénault's avatar
Sylvain Thénault committed
500
                self.app_publish(req, 'view')
501
            rset = self.execute('CWUser P WHERE P surname "Boom"')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
502
503
504
505
506
            self.assertEquals(len(rset), 0)
        finally:
            p.__class__.skip_copy_for = old_skips


507
class EmbedControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
508
509
510
511
512
513
514

    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/'
515
        controller = self.vreg['controllers'].select('embed', req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
516
517
518
        result = controller.publish(rset=None)


519
class ReportBugControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
520
521

    def test_usable_by_guets(self):
522
523
        self.login('anon')
        self.vreg['controllers'].select('reportbug', self.request())
Adrien Di Mascio's avatar
Adrien Di Mascio committed
524
525


526
class SendMailControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
527
528
529

    def test_not_usable_by_guets(self):
        self.login('anon')
530
531
        self.assertRaises(NoSelectableObject,
                          self.vreg['controllers'].select, 'sendmail', self.request())
532

Adrien Di Mascio's avatar
Adrien Di Mascio committed
533
534


535
class JSONControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
536
537
538

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

    def setup_database(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
542
543
544
        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
545
546
547
548
549
        self.john = self.create_user(u'John')


    ## tests ##################################################################
    def test_simple_exec(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
550
551
552
553
        req = self.request(rql='CWUser P WHERE P login "John"',
                           pageid='123', fname='view')
        ctrl = self.ctrl(req)
        rset = self.john.as_rset()
554
        rset.req = req
555
556
557
558
559
560
561
        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
562

sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
563
564
565
566
567
#     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
568
569
570
571
572

    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'])
573
        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
574
                          [['python']])
575

Adrien Di Mascio's avatar
Adrien Di Mascio committed
576
577
578
579
    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'])
580
        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
581
582
583
                          [['javascript']])

    def test_pending_insertion(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
584
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '13']])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
585
586
587
588
        deletes = req.get_pending_deletes()
        self.assertEquals(deletes, [])
        inserts = req.get_pending_inserts()
        self.assertEquals(inserts, ['12:tags:13'])
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
589
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
        deletes = req.get_pending_deletes()
        self.assertEquals(deletes, [])
        inserts = req.get_pending_inserts()
        self.assertEquals(inserts, ['12:tags:13', '12:tags:14'])
        inserts = req.get_pending_inserts(12)
        self.assertEquals(inserts, ['12:tags:13', '12:tags:14'])
        inserts = req.get_pending_inserts(13)
        self.assertEquals(inserts, ['12:tags:13'])
        inserts = req.get_pending_inserts(14)
        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'])
        inserts = req.get_pending_inserts()
        self.assertEquals(inserts, [])
        deletes = req.get_pending_deletes()
        self.assertEquals(deletes, ['12:tags:13'])
        res, req = self.remote_call('add_pending_delete', ['12', 'tags', '14'])
        inserts = req.get_pending_inserts()
        self.assertEquals(inserts, [])
        deletes = req.get_pending_deletes()
        self.assertEquals(deletes, ['12:tags:13', '12:tags:14'])
        deletes = req.get_pending_deletes(12)
        self.assertEquals(deletes, ['12:tags:13', '12:tags:14'])
        deletes = req.get_pending_deletes(13)
        self.assertEquals(deletes, ['12:tags:13'])
        deletes = req.get_pending_deletes(14)
        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
623
        _, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
624
625
626
627
628
629
630
        inserts = req.get_pending_inserts()
        self.assertEquals(inserts, ['12:tags:14'])
        deletes = req.get_pending_deletes()
        self.assertEquals(deletes, ['12:tags:13'])
        req.remove_pending_operations()
        self.assertEquals(req.get_pending_deletes(), [])
        self.assertEquals(req.get_pending_inserts(), [])
631

Adrien Di Mascio's avatar
Adrien Di Mascio committed
632
633
634
635
636
637
638

    def test_add_inserts(self):
        res, req = self.remote_call('add_pending_inserts',
                                    [('12', 'tags', '13'), ('12', 'tags', '14')])
        inserts = req.get_pending_inserts()
        self.assertEquals(inserts, ['12:tags:13', '12:tags:14'])
        req.remove_pending_operations()
639

Adrien Di Mascio's avatar
Adrien Di Mascio committed
640
641
642
643
644
645
646
647
648
649

    # 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
650
        self.assertEquals(self.remote_call('format_date', '2007-01-01 12:00:00')[0],
Adrien Di Mascio's avatar
Adrien Di Mascio committed
651
652
653
                          simplejson.dumps('2007/01/01'))


654
655


Adrien Di Mascio's avatar
Adrien Di Mascio committed
656
657
if __name__ == '__main__':
    unittest_main()