unittest_views_basecontrollers.py 30.9 KB
Newer Older
1
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2
3
4
5
6
7
8
9
10
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
#
# CubicWeb is free software: you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 of the License, or (at your option)
# any later version.
#
11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
12
13
14
15
16
17
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
18
"""cubicweb.web.views.basecontrollers unit tests"""
Adrien Di Mascio's avatar
Adrien Di Mascio committed
19

20
21
from __future__ import with_statement

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

24
25
from cubicweb import Binary, NoSelectableObject, ValidationError
from cubicweb.view import STRICT_DOCTYPE
26
from cubicweb.devtools.testlib import CubicWebTC
27
from cubicweb.utils import json_dumps
Sylvain Thénault's avatar
Sylvain Thénault committed
28
from cubicweb.uilib import rql_for_eid
29
from cubicweb.web import INTERNAL_FIELD_VALUE, Redirect, RequestError
30
from cubicweb.entities.authobjs import CWUser
Sylvain Thénault's avatar
Sylvain Thénault committed
31
from cubicweb.web.views.autoform import get_pending_inserts, get_pending_deletes
Sylvain Thénault's avatar
Sylvain Thénault committed
32
33
u = unicode

Sylvain Thénault's avatar
Sylvain Thénault committed
34
35
def req_form(user):
    return {'eid': [str(user.eid)],
36
            '_cw_entity_fields:%s' % user.eid: '_cw_generic_field',
Sylvain Thénault's avatar
Sylvain Thénault committed
37
38
            '__type:%s' % user.eid: user.__regid__
            }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
39

40
class EditControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
41
    def setUp(self):
42
        CubicWebTC.setUp(self)
43
        self.assertTrue('users' in self.schema.eschema('CWGroup').get_groups('read'))
44

Adrien Di Mascio's avatar
Adrien Di Mascio committed
45
    def tearDown(self):
46
        CubicWebTC.tearDown(self)
47
        self.assertTrue('users' in self.schema.eschema('CWGroup').get_groups('read'))
48

Adrien Di Mascio's avatar
Adrien Di Mascio committed
49
50
51
    def test_noparam_edit(self):
        """check behaviour of this controller without any form parameter
        """
52
53
54
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(self.request())
        self.assertEqual(cm.exception.errors, {None: u'no selected entities'})
55

Adrien Di Mascio's avatar
Adrien Di Mascio committed
56
57
    def test_validation_unique(self):
        """test creation of two linked entities
58
        """
Adrien Di Mascio's avatar
Adrien Di Mascio committed
59
        user = self.user()
60
61
        req = self.request()
        req.form = {'eid': 'X', '__type:X': 'CWUser',
62
                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
63
64
65
                    'login-subject:X': u'admin',
                    'upassword-subject:X': u'toto',
                    'upassword-subject-confirm:X': u'toto',
66
                    }
67
68
69
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
        self.assertEqual(cm.exception.errors, {'login-subject': 'the value "admin" is already used, use another one'})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
70
71
72
73
74

    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
75
        basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X in_group G, X eid %(x)s', {'x': user.eid})]
76
        groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')]
Sylvain Thénault's avatar
Sylvain Thénault committed
77
        groups = [u(eid) for eid in groupeids]
78
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
79
        eid = u(user.eid)
80
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
81
            'eid': eid, '__type:'+eid: 'CWUser',
82
            '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
83
84
85
86
            '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
87
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
88
        path, params = self.expect_redirect_publish(req, 'edit')
89
        e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0)
90
91
92
93
        self.assertEqual(e.firstname, u'Sylvain')
        self.assertEqual(e.surname, u'Th\xe9nault')
        self.assertEqual(e.login, user.login)
        self.assertEqual([g.eid for g in e.in_group], groupeids)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
94
95
96

    def test_user_can_change_its_password(self):
        req = self.request()
97
98
        user = self.create_user(req, 'user')
        cnx = self.login('user')
Sylvain Thénault's avatar
Sylvain Thénault committed
99
        eid = u(user.eid)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
100
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
101
102
            'eid': eid, '__maineid' : eid,
            '__type:'+eid: 'CWUser',
103
            '_cw_entity_fields:'+eid: 'upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
104
105
            'upassword-subject:'+eid: 'tournicoton',
            'upassword-subject-confirm:'+eid: 'tournicoton',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
106
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
107
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
108
        cnx.commit() # commit to check we don't get late validation error for instance
109
        self.assertEqual(path, 'cwuser/user')
110
        self.assertFalse('vid' in params)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
111

Sylvain Thénault's avatar
Sylvain Thénault committed
112
    def test_user_editing_itself_no_relation(self):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
113
114
115
116
        """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
117
        groupeids = [g.eid for g in user.in_group]
118
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
119
        eid = u(user.eid)
120
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
121
122
            'eid':       eid,
            '__type:'+eid:    'CWUser',
123
            '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
124
125
126
            '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
127
            }
Sylvain Thénault's avatar
Sylvain Thénault committed
128
        path, params = self.expect_redirect_publish(req, 'edit')
129
        e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0)
130
131
132
133
134
        self.assertEqual(e.login, user.login)
        self.assertEqual(e.firstname, u'Th\xe9nault')
        self.assertEqual(e.surname, u'Sylvain')
        self.assertEqual([g.eid for g in e.in_group], groupeids)
        self.assertEqual(e.cw_adapt_to('IWorkflowable').state, 'activated')
135
136


Adrien Di Mascio's avatar
Adrien Di Mascio committed
137
    def test_create_multiple_linked(self):
138
        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
139
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
140
        req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
141

142
                    '__type:X': 'CWUser',
143
                    '_cw_entity_fields:X': 'login-subject,upassword-subject,surname-subject,in_group-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
144
145
146
147
                    '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),
148

149
                    '__type:Y': 'EmailAddress',
150
                    '_cw_entity_fields:Y': 'address-subject,use_email-object',
Sylvain Thénault's avatar
Sylvain Thénault committed
151
152
                    'address-subject:Y': u'dima@logilab.fr',
                    'use_email-object:Y': 'X',
153
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
154
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
155
        # should be redirected on the created person
156
        self.assertEqual(path, 'cwuser/adim')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
157
        e = self.execute('Any P WHERE P surname "Di Mascio"').get_entity(0, 0)
158
        self.assertEqual(e.surname, 'Di Mascio')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
159
        email = e.use_email[0]
160
        self.assertEqual(email.address, 'dima@logilab.fr')
161

Adrien Di Mascio's avatar
Adrien Di Mascio committed
162
    def test_edit_multiple_linked(self):
163
        req = self.request()
164
        peid = u(self.create_user(req, 'adim').eid)
Sylvain Thénault's avatar
Sylvain Thénault committed
165
        req.form = {'eid': [peid, 'Y'], '__maineid': peid,
166

Sylvain Thénault's avatar
Sylvain Thénault committed
167
                    '__type:'+peid: u'CWUser',
168
                    '_cw_entity_fields:'+peid: u'surname-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
169
                    'surname-subject:'+peid: u'Di Masci',
170

Sylvain Thénault's avatar
Sylvain Thénault committed
171
                    '__type:Y': u'EmailAddress',
172
                    '_cw_entity_fields:Y': u'address-subject,use_email-object',
Sylvain Thénault's avatar
Sylvain Thénault committed
173
174
                    'address-subject:Y': u'dima@logilab.fr',
                    'use_email-object:Y': peid,
175
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
176
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
177
        # should be redirected on the created person
178
        self.assertEqual(path, 'cwuser/adim')
Sylvain Thénault's avatar
Sylvain Thénault committed
179
        e = self.execute('Any P WHERE P surname "Di Masci"').get_entity(0, 0)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
180
        email = e.use_email[0]
181
        self.assertEqual(email.address, 'dima@logilab.fr')
182

Sylvain Thénault's avatar
Sylvain Thénault committed
183
        emaileid = u(email.eid)
184
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
185
186
187
        req.form = {'eid': [peid, emaileid],

                    '__type:'+peid: u'CWUser',
188
                    '_cw_entity_fields:'+peid: u'surname-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
189
190
191
                    'surname-subject:'+peid: u'Di Masci',

                    '__type:'+emaileid: u'EmailAddress',
192
                    '_cw_entity_fields:'+emaileid: u'address-subject,use_email-object',
Sylvain Thénault's avatar
Sylvain Thénault committed
193
194
195
196
                    'address-subject:'+emaileid: u'adim@logilab.fr',
                    'use_email-object:'+emaileid: peid,
                    }
        path, params = self.expect_redirect_publish(req, 'edit')
197
        email.cw_clear_all_caches()
198
        self.assertEqual(email.address, 'adim@logilab.fr')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
199

200

Adrien Di Mascio's avatar
Adrien Di Mascio committed
201
202
    def test_password_confirm(self):
        """test creation of two linked entities
203
        """
Adrien Di Mascio's avatar
Adrien Di Mascio committed
204
        user = self.user()
205
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
206
207
        req.form = {'eid': 'X',
                    '__cloned_eid:X': u(user.eid), '__type:X': 'CWUser',
208
                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
209
210
                    'login-subject:X': u'toto',
                    'upassword-subject:X': u'toto',
211
                    }
212
213
214
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
        self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'})
215
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
216
        req.form = {'__cloned_eid:X': u(user.eid),
217
                    'eid': 'X', '__type:X': 'CWUser',
218
                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
219
220
221
                    'login-subject:X': u'toto',
                    'upassword-subject:X': u'toto',
                    'upassword-subject-confirm:X': u'tutu',
222
                    }
223
224
225
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
        self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
226
227
228


    def test_interval_bound_constraint_success(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
229
        feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
Adrien Di Mascio's avatar
Adrien Di Mascio committed
230
                            {'data': Binary('yo')})[0][0]
231
        self.commit()
232
        req = self.request(rollbackfirst=True)
233
234
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
235
                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
236
237
                    'amount-subject:X': u'-10',
                    'described_by_test-subject:X': u(feid),
238
                }
239
240
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
241
        self.assertEqual(cm.exception.errors, {'amount-subject': 'value -10 must be >= 0'})
242
        req = self.request(rollbackfirst=True)
243
244
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
245
                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
246
247
                    'amount-subject:X': u'110',
                    'described_by_test-subject:X': u(feid),
248
                    }
249
250
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
251
        self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'})
252
        req = self.request(rollbackfirst=True)
253
254
        req.form = {'eid': ['X'],
                    '__type:X': 'Salesterm',
255
                    '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
256
257
                    'amount-subject:X': u'10',
                    'described_by_test-subject:X': u(feid),
258
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
259
        self.expect_redirect_publish(req, 'edit')
260
        # should be redirected on the created
Adrien Di Mascio's avatar
Adrien Di Mascio committed
261
262
        #eid = params['rql'].split()[-1]
        e = self.execute('Salesterm X').get_entity(0, 0)
263
        self.assertEqual(e.amount, 10)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
264
265
266

    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
267
        tmpgroup = self.request().create_entity('CWGroup', name=u"test")
Adrien Di Mascio's avatar
Adrien Di Mascio committed
268
        user = self.user()
Sylvain Thénault's avatar
Sylvain Thénault committed
269
        req = self.request(**req_form(user))
270
        req.session.data['pending_insert'] = set([(user.eid, 'in_group', tmpgroup.eid)])
Sylvain Thénault's avatar
Sylvain Thénault committed
271
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
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})]
274
275
        self.assertItemsEqual(usergroups, ['managers', 'test'])
        self.assertEqual(get_pending_inserts(req), [])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
276
277
278
279
280


    def test_req_pending_delete(self):
        """make sure req's pending deletions are taken into account"""
        user = self.user()
281
        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
282
283
284
285
                                {'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
286
        self.assertItemsEqual(usergroups, ['managers', 'test'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
287
        # now try to delete the relation
Sylvain Thénault's avatar
Sylvain Thénault committed
288
        req = self.request(**req_form(user))
289
        req.session.data['pending_delete'] = set([(user.eid, 'in_group', groupeid)])
Sylvain Thénault's avatar
Sylvain Thénault committed
290
        path, params = self.expect_redirect_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
291
292
        usergroups = [gname for gname, in
                      self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
293
294
        self.assertItemsEqual(usergroups, ['managers'])
        self.assertEqual(get_pending_deletes(req), [])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
295
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
            'eid': 'A', '__maineid' : 'A',
301
            '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
302
303
            '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')
311
        self.assertTrue(path.startswith('blogentry/'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
312
        eid = path.split('/')[1]
313
        self.assertEqual(params['vid'], 'edition')
314
        self.assertNotEqual(int(eid), 4012)
315
316
317
        self.assertEqual(params['__redirectrql'], redirectrql)
        self.assertEqual(params['__redirectvid'], 'primary')
        self.assertEqual(params['__redirectparams'], 'toto=tutu&tata=titi')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
318
319
320

    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
            'eid': 'A', '__maineid' : 'A',
324
            '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
325
326
            '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')
333
334
335
336
337
        self.assertEqual(path, 'view')
        self.assertEqual(params['rql'], redirectrql)
        self.assertEqual(params['vid'], 'primary')
        self.assertEqual(params['tata'], 'titi')
        self.assertEqual(params['toto'], 'tutu')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
338
339

    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')
345
        self.assertEqual(path, 'blogentry')
Sylvain Thénault's avatar
Sylvain Thénault committed
346
        self.assertIn('_cwmsgid', params)
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})
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')
355
        self.assertEqual(path, 'cwuser/admin')
Sylvain Thénault's avatar
Sylvain Thénault committed
356
        self.assertIn('_cwmsgid', params)
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')
365
        self.assertEqual(path, 'view')
Sylvain Thénault's avatar
Sylvain Thénault committed
366
        self.assertIn('_cwmsgid', params)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
367

368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
    def test_simple_copy(self):
        req = self.request()
        blog = req.create_entity('Blog', title=u'my-blog')
        blogentry = req.create_entity('BlogEntry', title=u'entry1',
                                      content=u'content1', entry_of=blog)
        req = self.request()
        req.form = {'__maineid' : 'X', 'eid': 'X',
                    '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
                    '_cw_entity_fields:X': 'title-subject,content-subject',
                    'title-subject:X': u'entry1-copy',
                    'content-subject:X': u'content1',
                    }
        self.expect_redirect_publish(req, 'edit')
        blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
        self.assertEqual(blogentry2.entry_of[0].eid, blog.eid)

    def test_skip_copy_for(self):
        req = self.request()
        blog = req.create_entity('Blog', title=u'my-blog')
        blogentry = req.create_entity('BlogEntry', title=u'entry1',
                                      content=u'content1', entry_of=blog)
        blogentry.__class__.cw_skip_copy_for = [('entry_of', 'subject')]
        try:
            req = self.request()
            req.form = {'__maineid' : 'X', 'eid': 'X',
                        '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
                        '_cw_entity_fields:X': 'title-subject,content-subject',
                        'title-subject:X': u'entry1-copy',
                        'content-subject:X': u'content1',
                        }
            self.expect_redirect_publish(req, 'edit')
            blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
            # entry_of should not be copied
            self.assertEqual(len(blogentry2.entry_of), 0)
        finally:
            blogentry.__class__.cw_skip_copy_for = []

Adrien Di Mascio's avatar
Adrien Di Mascio committed
405
    def test_nonregr_eetype_etype_editing(self):
406
        """non-regression test checking that a manager user can edit a CWEType entity
Adrien Di Mascio's avatar
Adrien Di Mascio committed
407
        """
408
        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
409
410
411
412
        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)
413
414
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
415
416
            'eid':      cwetypeeid,
            '__type:'+cwetypeeid:  'CWEType',
417
            '_cw_entity_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
418
            'name-subject:'+cwetypeeid:     u'CWEType',
Sylvain Thénault's avatar
Sylvain Thénault committed
419
            'final-subject:'+cwetypeeid:    '',
Sylvain Thénault's avatar
Sylvain Thénault committed
420
421
            'description-subject:'+cwetypeeid:     u'users group',
            'read_permission-subject:'+cwetypeeid:  groups,
422
            }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
423
        try:
Sylvain Thénault's avatar
Sylvain Thénault committed
424
            path, params = self.expect_redirect_publish(req, 'edit')
425
            e = self.execute('Any X WHERE X eid %(x)s', {'x': cwetypeeid}).get_entity(0, 0)
426
427
            self.assertEqual(e.name, 'CWEType')
            self.assertEqual(sorted(g.eid for g in e.read_permission), groupeids)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
428
429
        finally:
            # restore
430
            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
431
            self.commit()
432

Adrien Di Mascio's avatar
Adrien Di Mascio committed
433
434
435
436
    def test_nonregr_strange_text_input(self):
        """non-regression test checking text input containing "13:03:43"

        this seems to be postgres (tsearch?) specific
437
        """
438
439
        req = self.request()
        req.form = {
Sylvain Thénault's avatar
Sylvain Thénault committed
440
            'eid': 'A', '__maineid' : 'A',
441
            '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'title-subject,content-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
442
443
444
            'title-subject:A': u'"13:03:40"',
            'content-subject:A': u'"13:03:43"',}
        path, params = self.expect_redirect_publish(req, 'edit')
445
        self.assertTrue(path.startswith('blogentry/'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
446
        eid = path.split('/')[1]
447
        e = self.execute('Any C, T WHERE C eid %(x)s, C content T', {'x': eid}).get_entity(0, 0)
448
449
        self.assertEqual(e.title, '"13:03:40"')
        self.assertEqual(e.content, '"13:03:43"')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
450
451
452


    def test_nonregr_multiple_empty_email_addr(self):
453
        gueid = self.execute('CWGroup G WHERE G name "users"')[0][0]
454
455
        req = self.request()
        req.form = {'eid': ['X', 'Y'],
456

457
                    '__type:X': 'CWUser',
458
                    '_cw_entity_fields:X': 'login-subject,upassword-subject,in_group-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
459
460
461
                    'login-subject:X': u'adim',
                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
                    'in_group-subject:X': `gueid`,
462

463
                    '__type:Y': 'EmailAddress',
464
                    '_cw_entity_fields:Y': 'address-subject,alias-subject,use_email-object',
Sylvain Thénault's avatar
Sylvain Thénault committed
465
466
467
                    'address-subject:Y': u'',
                    'alias-subject:Y': u'',
                    'use_email-object:Y': 'X',
468
                    }
469
470
471
        with self.assertRaises(ValidationError) as cm:
            self.ctrl_publish(req)
        self.assertEqual(cm.exception.errors, {'address-subject': u'required field'})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
472
473
474

    def test_nonregr_copy(self):
        user = self.user()
475
        req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
476
477
        req.form = {'__maineid' : 'X', 'eid': 'X',
                    '__cloned_eid:X': user.eid, '__type:X': 'CWUser',
478
                    '_cw_entity_fields:X': 'login-subject,upassword-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
479
480
                    'login-subject:X': u'toto',
                    'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
481
                    }
Sylvain Thénault's avatar
Sylvain Thénault committed
482
        path, params = self.expect_redirect_publish(req, 'edit')
483
        self.assertEqual(path, 'cwuser/toto')
484
        e = self.execute('Any X WHERE X is CWUser, X login "toto"').get_entity(0, 0)
485
486
        self.assertEqual(e.login, 'toto')
        self.assertEqual(e.in_group[0].name, 'managers')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
487
488
489


    def test_nonregr_rollback_on_validation_error(self):
490
491
        req = self.request()
        p = self.create_user(req, "doe")
Adrien Di Mascio's avatar
Adrien Di Mascio committed
492
493
494
495
        # 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
496
            e = self.request().create_entity('EmailAddress', address=u'doe@doe.com')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
497
498
            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})
499
            req = self.request()
Sylvain Thénault's avatar
Sylvain Thénault committed
500
501
            req.form = {'eid': 'X',
                        '__cloned_eid:X': p.eid, '__type:X': 'CWUser',
502
                        '_cw_entity_fields:X': 'login-subject,surname-subject',
Sylvain Thénault's avatar
Sylvain Thénault committed
503
504
                        'login-subject': u'dodo',
                        'surname-subject:X': u'Boom',
505
                        '__errorurl' : "whatever but required",
Sylvain Thénault's avatar
Sylvain Thénault committed
506
                        }
Adrien Di Mascio's avatar
Adrien Di Mascio committed
507
508
509
510
511
            # 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
512
                self.app_publish(req, 'edit')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
513
            except Redirect:
Sylvain Thénault's avatar
Sylvain Thénault committed
514
                req = self.request()
515
516
                req.form['rql'] = 'Any X WHERE X eid %s' % p.eid
                req.form['vid'] = 'copy'
Sylvain Thénault's avatar
Sylvain Thénault committed
517
                self.app_publish(req, 'view')
518
            rset = self.execute('CWUser P WHERE P surname "Boom"')
519
            self.assertEqual(len(rset), 0)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
520
521
522
523
        finally:
            p.__class__.skip_copy_for = old_skips


524
class EmbedControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
525
526
527
528
529
530

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


536
class ReportBugControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
537

538
    def test_usable_by_guest(self):
539
        self.login('anon')
Sylvain Thénault's avatar
Sylvain Thénault committed
540
541
542
        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
543
544


545
class SendMailControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
546

547
    def test_not_usable_by_guest(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
548
549
550
551
552
553
        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
554
        self.login('anon')
555
556
        self.assertRaises(NoSelectableObject,
                          self.vreg['controllers'].select, 'sendmail', self.request())
557

Adrien Di Mascio's avatar
Adrien Di Mascio committed
558
559


560
class JSONControllerTC(CubicWebTC):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
561
562
563

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

    def setup_database(self):
Sylvain Thénault's avatar
Sylvain Thénault committed
567
568
569
        req = self.request()
        self.pytag = req.create_entity('Tag', name=u'python')
        self.cubicwebtag = req.create_entity('Tag', name=u'cubicweb')
570
        self.john = self.create_user(req, u'John')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
571
572
573
574


    ## tests ##################################################################
    def test_simple_exec(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
575
576
577
578
        req = self.request(rql='CWUser P WHERE P login "John"',
                           pageid='123', fname='view')
        ctrl = self.ctrl(req)
        rset = self.john.as_rset()
579
        rset.req = req
580
        source = ctrl.publish()
581
        self.assertTrue(source.startswith('<?xml version="1.0"?>\n' + STRICT_DOCTYPE +
582
583
584
585
                                          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()
586
        self.assertTrue(source.startswith('<div>'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
587

sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
588
589
590
#     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'))
591
#         self.assertEqual(ctrl.publish(),
592
#                           json_dumps(self.execute(rql).rows))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
593
594
595

    def test_remote_add_existing_tag(self):
        self.remote_call('tag_entity', self.john.eid, ['python'])
596
        self.assertItemsEqual(
597
598
            [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
            ['python', 'cubicweb'])
599
        self.assertEqual(
600
601
            self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
            [['python']])
602

Adrien Di Mascio's avatar
Adrien Di Mascio committed
603
604
    def test_remote_add_new_tag(self):
        self.remote_call('tag_entity', self.john.eid, ['javascript'])
605
        self.assertItemsEqual(
606
607
            [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
            ['python', 'cubicweb', 'javascript'])
608
        self.assertEqual(
609
610
            self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows,
            [['javascript']])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
611
612

    def test_pending_insertion(self):
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
613
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '13']])
Sylvain Thénault's avatar
Sylvain Thénault committed
614
        deletes = get_pending_deletes(req)
615
        self.assertEqual(deletes, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
616
        inserts = get_pending_inserts(req)
617
        self.assertEqual(inserts, ['12:tags:13'])
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
618
        res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Sylvain Thénault's avatar
Sylvain Thénault committed
619
        deletes = get_pending_deletes(req)
620
        self.assertEqual(deletes, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
621
        inserts = get_pending_inserts(req)
622
        self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
623
        inserts = get_pending_inserts(req, 12)
624
        self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
625
        inserts = get_pending_inserts(req, 13)
626
        self.assertEqual(inserts, ['12:tags:13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
627
        inserts = get_pending_inserts(req, 14)
628
        self.assertEqual(inserts, ['12:tags:14'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
629
630
631
632
        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
633
        inserts = get_pending_inserts(req)
634
        self.assertEqual(inserts, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
635
        deletes = get_pending_deletes(req)
636
        self.assertEqual(deletes, ['12:tags:13'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
637
        res, req = self.remote_call('add_pending_delete', ['12', 'tags', '14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
638
        inserts = get_pending_inserts(req)
639
        self.assertEqual(inserts, [])
Sylvain Thénault's avatar
Sylvain Thénault committed
640
        deletes = get_pending_deletes(req)
641
        self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
642
        deletes = get_pending_deletes(req, 12)
643
        self.assertEqual(deletes, ['12:tags:13', '12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
644
        deletes = get_pending_deletes(req, 13)
645
        self.assertEqual(deletes, ['12:tags:13'])
Sylvain Thénault's avatar
Sylvain Thénault committed
646
        deletes = get_pending_deletes(req, 14)
647
        self.assertEqual(deletes, ['12:tags:14'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
648
649
650
651
        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
652
        _, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']])
Sylvain Thénault's avatar
Sylvain Thénault committed
653
        inserts = get_pending_inserts(req)
654
        self.assertEqual(inserts, ['12:tags:14'])
Sylvain Thénault's avatar
Sylvain Thénault committed
655
        deletes = get_pending_deletes(req)
656
        self.assertEqual(deletes, ['12:tags:13'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
657
        req.remove_pending_operations()
658
659
        self.assertEqual(get_pending_deletes(req), [])
        self.assertEqual(get_pending_inserts(req), [])
660

Adrien Di Mascio's avatar
Adrien Di Mascio committed
661
662
663
664

    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
665
        inserts = get_pending_inserts(req)
666
        self.assertEqual(inserts, ['12:tags:13', '12:tags:14'])
Adrien Di Mascio's avatar
Adrien Di Mascio committed
667
        req.remove_pending_operations()
668

Adrien Di Mascio's avatar
Adrien Di Mascio committed
669
670
671

    # silly tests
    def test_external_resource(self):
672
        self.assertEqual(self.remote_call('external_resource', 'RSS_LOGO')[0],
673
                          json_dumps(self.config.uiprops['RSS_LOGO']))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
674
    def test_i18n(self):
675
        self.assertEqual(self.remote_call('i18n', ['bimboom'])[0],
676
                          json_dumps(['bimboom']))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
677
678

    def test_format_date(self):
679
        self.assertEqual(self.remote_call('format_date', '2007-01-01 12:00:00')[0],
680
                          json_dumps('2007/01/01'))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
681
682


683
684


Adrien Di Mascio's avatar
Adrien Di Mascio committed
685
686
if __name__ == '__main__':
    unittest_main()