Project

General

Profile

0001-backoffice-move-management-of-submitted-forms-to-a-s.patch

Frédéric Péters, 06 May 2015 12:00 AM

Download (19 KB)

View differences:

Subject: [PATCH] backoffice: move management of submitted forms to a
 subdirectory (#7151)

 tests/test_backoffice_pages.py |  26 ++--
 tests/test_formdata.py         |   2 +-
 wcs/backoffice/root.py         | 281 ++++++++++++++++++++++-------------------
 wcs/formdef.py                 |   2 +-
 4 files changed, 167 insertions(+), 144 deletions(-)
tests/test_backoffice_pages.py
134 134
    create_superuser(pub)
135 135
    create_environment()
136 136
    app = login(get_app(pub))
137
    resp = app.get('/backoffice/form-title/')
137
    resp = app.get('/backoffice/management/form-title/')
138 138
    assert resp.body.count('data-link') == 17
139 139

  
140 140
    # check status filter <select>
141
    resp = app.get('/backoffice/form-title/')
141
    resp = app.get('/backoffice/management/form-title/')
142 142
    resp.forms[0]['filter'] = 'all'
143 143
    resp = resp.forms[0].submit()
144 144
    if getattr(pub, 'pgconn', None):
......
148 148
        assert resp.body.count('data-link') == 50
149 149

  
150 150
    # check status filter <select>
151
    resp = app.get('/backoffice/form-title/')
151
    resp = app.get('/backoffice/management/form-title/')
152 152
    resp.forms[0]['filter'] = 'done'
153 153
    resp = resp.forms[0].submit()
154 154
    if getattr(pub, 'pgconn', None):
......
162 162
    create_superuser(pub)
163 163
    create_environment()
164 164
    app = login(get_app(pub))
165
    resp = app.get('/backoffice/form-title/')
165
    resp = app.get('/backoffice/management/form-title/')
166 166
    assert resp.body.count('</th>') == 6 # five columns
167 167
    resp.forms[0]['1'].checked = False
168 168
    resp = resp.forms[0].submit()
......
174 174
    create_superuser(pub)
175 175
    create_environment()
176 176
    app = login(get_app(pub))
177
    resp = app.get('/backoffice/form-title/')
177
    resp = app.get('/backoffice/management/form-title/')
178 178
    assert resp.forms[0]['filter-status'].checked == True
179 179
    resp.forms[0]['filter-status'].checked = False
180 180
    resp.forms[0]['filter-2'].checked = True
......
200 200
    create_superuser(pub)
201 201
    create_environment()
202 202
    app = login(get_app(pub))
203
    resp = app.get('/backoffice/form-title/')
203
    resp = app.get('/backoffice/management/form-title/')
204 204
    resp = resp.click('CSV Export')
205 205
    assert resp.headers['content-type'].startswith('text/')
206 206
    assert len(resp.body.splitlines()) == 18 # 17 + header line
207 207

  
208
    resp = app.get('/backoffice/form-title/')
208
    resp = app.get('/backoffice/management/form-title/')
209 209
    resp.forms[0]['filter'] = 'all'
210 210
    resp = resp.forms[0].submit()
211 211
    resp = resp.click('CSV Export')
......
215 215
    create_superuser(pub)
216 216
    create_environment()
217 217
    app = login(get_app(pub))
218
    resp = app.get('/backoffice/form-title/')
218
    resp = app.get('/backoffice/management/form-title/')
219 219
    resp = resp.click('Open Document Format Export')
220 220
    assert resp.headers['content-type'] == 'application/vnd.oasis.opendocument.spreadsheet'
221 221
    assert 'filename=form-title.ods' in resp.headers['content-disposition']
......
225 225
    create_superuser(pub)
226 226
    create_environment()
227 227
    app = login(get_app(pub))
228
    resp = app.get('/backoffice/form-title/')
228
    resp = app.get('/backoffice/management/form-title/')
229 229
    resp = resp.click('Statistics')
230 230
    assert 'Total number of records: 50' in resp.body
231 231
    assert 'New: 17' in resp.body
......
243 243
    create_superuser(pub)
244 244
    create_environment()
245 245
    app = login(get_app(pub))
246
    resp = app.get('/backoffice/form-title/')
246
    resp = app.get('/backoffice/management/form-title/')
247 247
    resp = resp.click('Statistics')
248 248
    assert 'filter' not in resp.forms[0].fields # status is not displayed by default
249 249

  
......
273 273
    create_superuser(pub)
274 274
    create_environment()
275 275
    app = login(get_app(pub))
276
    resp = app.get('/backoffice/form-title/')
276
    resp = app.get('/backoffice/management/form-title/')
277 277
    resp = resp.click('Statistics')
278 278

  
279 279
    resp.forms[0]['filter-2'].checked = True
......
296 296
    form_class = FormDef.get_by_urlname('form-title').data_class()
297 297
    number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0].id
298 298
    app = login(get_app(pub))
299
    resp = app.get('/backoffice/form-title/')
299
    resp = app.get('/backoffice/management/form-title/')
300 300
    resp = resp.click(href='%s/' % number31)
301 301
    assert (' with the number %s.' % number31) in resp.body
302 302
    resp.forms[0]['comment'] = 'HELLO WORLD'
......
343 343
    assert new_formdata_count == formdata_count+1
344 344

  
345 345
    formdata = [x for x in formdef.data_class().select() if x.data['1'] == 'XYZ'][0]
346
    assert resp.location == 'http://example.net/backoffice/form-title/%s/' % formdata.id
346
    assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
347 347
    resp = resp.follow()
348 348
    assert 'The form has been recorded' in resp.body
349 349
    assert 'XYZ' in resp.body
tests/test_formdata.py
56 56
    assert substvars.get('form_number') == '1'
57 57
    assert substvars.get('form_number_raw') == '1'
58 58
    assert substvars.get('form_url').endswith('/foobar/1/')
59
    assert substvars.get('form_url_backoffice').endswith('/backoffice/foobar/1/')
59
    assert substvars.get('form_url_backoffice').endswith('/backoffice/management/foobar/1/')
60 60
    assert substvars.get('form_status_url').endswith('/foobar/1/status')
61 61

  
62 62
def test_display_id(pub):
wcs/backoffice/root.py
248 248
        return is_accessible('workflows')
249 249

  
250 250

  
251
class RootDirectory(BackofficeRootDirectory):
252
    _q_exports = ['', 'management', 'pending', 'statistics']
253

  
254
    bounces = wcs.admin.bounces.BouncesDirectory()
255
    categories = wcs.admin.categories.CategoriesDirectory()
256
    forms = wcs.admin.forms.FormsDirectory()
257
    logger = wcs.admin.logger.LoggerDirectory()
258
    roles = wcs.admin.roles.RolesDirectory()
259
    settings = wcs.admin.settings.SettingsDirectory()
260
    users = wcs.admin.users.UsersDirectory()
261
    workflows = wcs.admin.workflows.WorkflowsDirectory()
262
    submission = submission.SubmissionDirectory()
263

  
264
    menu_items = [
265
        ('management', N_('Pending Forms')),
266
        ('submission/', N_('Submission')),
267
        ('forms/', N_('Forms Workshop')),
268
        ('workflows/', N_('Workflows Workshop')),
269
        ('users/', N_('Users')),
270
        ('roles/', N_('Roles')),
271
        ('categories/', N_('Categories')),
272
        ('logger/', N_('Logs'), logger.is_visible),
273
        ('bounces/', N_('Bounces'), bounces.is_visible),
274
        ('settings/', N_('Settings')),
275
        ('/', N_('WCS Form Server'))
276
    ]
277

  
278
    def check_admin_for_all(self):
279
        admin_for_all_file_path = os.path.join(get_publisher().app_dir, 'ADMIN_FOR_ALL')
280
        if not os.path.exists(os.path.join(admin_for_all_file_path)):
281
            return False
282
        admin_for_all_contents = open(admin_for_all_file_path).read()
283
        if not admin_for_all_contents:
284
            # empty file, access is granted to everybody
285
            return True
286
        if get_request().get_environ('REMOTE_ADDR', '') in admin_for_all_contents.splitlines():
287
            # if the file is not empty it should contain the list of authorized
288
            # IP addresses.
289
            return True
290
        return False
251
class ManagementDirectory(Directory):
252
    _q_exports = ['', 'statistics']
291 253

  
292
    def _q_access(self):
293
        get_response().breadcrumb.append( ('backoffice/', _('Back Office')) )
294
        req = get_request()
295

  
296
        if self.check_admin_for_all():
297
            get_response().filter['admin_for_all'] = True
298
            return
299

  
300
        if get_publisher().user_class.count() > 0:
301
            user = req.user
302
            if not user:
303
                raise errors.AccessUnauthorizedError(
304
                        public_msg = _('Access to backoffice is restricted to authorized persons only. '\
305
                                       'Please login.'))
306
            if not user.can_go_in_backoffice():
307
                raise errors.AccessForbiddenError()
308

  
309
        get_response().filter['in_backoffice'] = True
310

  
311
    def get_intro_text(self):
312
        return _('''Welcome.''')
313

  
314
    def generate_header_menu(self, selected=None):
315
        s = ['<ul id="menu">\n']
316
        for menu_item in self.get_menu_items():
317
            if not 'icon' in menu_item:
318
                continue
319
            if menu_item.get('slug') == selected:
320
                s.append('<li class="active">')
321
            else:
322
                s.append('<li>')
323
            s.append('<a href="%(url)s">%(label)s</a></li>\n' % menu_item)
324
        s.append('</ul>\n')
325
        return ''.join(s)
254
    def _q_traverse(self, path):
255
        get_response().breadcrumb.append(('management/', _('Management')))
256
        return super(ManagementDirectory, self)._q_traverse(path)
326 257

  
327 258
    def _q_index(self):
328
        html_top('/')
329
        r = TemplateIO(html=True)
330
        r += htmltext('<div class="bo-block"><p>%s</p></div>') % self.get_intro_text()
331

  
332
        menu_items = self.get_menu_items()
333
        r += htmltext('<ul class="apps">')
334
        for menu_item in menu_items:
335
            if not 'icon' in menu_item:
336
                continue
337
            r += htmltext('<li class="zone-%(icon)s"><a href="%(url)s">%(label)s</a></li>') % menu_item
338
        for menu_item in menu_items:
339
            if 'icon' in menu_item:
340
                continue
341
            r += htmltext('<li class="zone-no-icon"><a href="%(url)s">%(label)s</a></li>') % menu_item
342
        r += htmltext('</ul>')
343
        r += htmltext('<br class="clear">')
344

  
345
        r += htmltext('<p id="for-more-info"></p>')
346

  
347
        get_response().filter['sidebar'] = str(self.get_sidebar())
348

  
349
        return r.getvalue()
350

  
351

  
352
    def get_sidebar(self):
353
        from qommon.admin.menu import get_vc_version
354
        from wcs.admin.root import gpl
355
        r = TemplateIO(html=True)
356

  
357
        r += htmltext('<div class="bo-block">')
358
        r += htmltext('<ul id="sidebar-actions">')
359
        r += htmltext('<li><a href="statistics">%s</a></li>') % _('Global statistics')
360
        r += htmltext('</ul>')
361
        r += htmltext('</div>')
362

  
363
        version = get_vc_version()
364
        if version:
365
            r += htmltext('<div class="bo-block"><p class="version-info">')
366
            r += _('Version:')
367
            r += ' '
368
            r += version
369
            r += htmltext('</p></div>')
370

  
371
        r += htmltext('<div class="bo-block">')
372
        r += gpl()
373
        r += htmltext('</div>')
374

  
375
        return r.getvalue()
376

  
377
    def management(self):
378
        get_response().breadcrumb.append(('management', _('Pending Forms')))
379 259
        html_top('management', _('Pending Forms'))
380 260
        get_response().filter['sidebar'] = self.get_sidebar()
381 261
        r = TemplateIO(html=True)
......
430 310

  
431 311
        return r.getvalue()
432 312

  
313
    def get_sidebar(self):
314
        r = TemplateIO(html=True)
315
        r += htmltext('<div class="bo-block">')
316
        r += htmltext('<ul id="sidebar-actions">')
317
        r += htmltext('<li><a href="statistics">%s</a></li>') % _('Global statistics')
318
        r += htmltext('</ul>')
319
        r += htmltext('</div>')
320
        return r.getvalue()
433 321

  
434 322
    def get_stats_sidebar(self):
435 323
        get_response().add_javascript(['jquery.js'])
......
466 354

  
467 355
        return r.getvalue()
468 356

  
469

  
470 357
    def statistics(self):
471 358
        html_top('management', _('Global statistics'))
472 359
        get_response().breadcrumb.append(('statistics', _('Global statistics')))
......
511 398

  
512 399
        return r.getvalue()
513 400

  
514

  
515 401
    def category_global_stats(self, title, category_formdefs, counts):
516 402
        r = TemplateIO(html=True)
517 403
        category_formdefs_ids = [x.id for x in category_formdefs]
......
535 421
        r += htmltext('</div>')
536 422
        return r.getvalue()
537 423

  
538

  
539 424
    def display_forms(self, forms_list):
540 425
        r = TemplateIO(html=True)
541 426
        r += htmltext('<ul>')
......
563 448
        r += htmltext('</ul>')
564 449
        return r.getvalue()
565 450

  
451
    def _q_lookup(self, component):
452
        return FormPage(component)
453

  
454

  
455
class RootDirectory(BackofficeRootDirectory):
456
    _q_exports = ['', 'pending', 'statistics']
457

  
458
    bounces = wcs.admin.bounces.BouncesDirectory()
459
    categories = wcs.admin.categories.CategoriesDirectory()
460
    forms = wcs.admin.forms.FormsDirectory()
461
    logger = wcs.admin.logger.LoggerDirectory()
462
    roles = wcs.admin.roles.RolesDirectory()
463
    settings = wcs.admin.settings.SettingsDirectory()
464
    users = wcs.admin.users.UsersDirectory()
465
    workflows = wcs.admin.workflows.WorkflowsDirectory()
466
    submission = submission.SubmissionDirectory()
467
    management = ManagementDirectory()
468

  
469
    menu_items = [
470
        ('management/', N_('Pending Forms')),
471
        ('submission/', N_('Submission')),
472
        ('forms/', N_('Forms Workshop')),
473
        ('workflows/', N_('Workflows Workshop')),
474
        ('users/', N_('Users')),
475
        ('roles/', N_('Roles')),
476
        ('categories/', N_('Categories')),
477
        ('logger/', N_('Logs'), logger.is_visible),
478
        ('bounces/', N_('Bounces'), bounces.is_visible),
479
        ('settings/', N_('Settings')),
480
    ]
481

  
482
    def _q_traverse(self, path):
483
        get_response().add_javascript(['jquery.js'])
484
        return super(RootDirectory, self)._q_traverse(path)
485

  
486
    def check_admin_for_all(self):
487
        admin_for_all_file_path = os.path.join(get_publisher().app_dir, 'ADMIN_FOR_ALL')
488
        if not os.path.exists(os.path.join(admin_for_all_file_path)):
489
            return False
490
        admin_for_all_contents = open(admin_for_all_file_path).read()
491
        if not admin_for_all_contents:
492
            # empty file, access is granted to everybody
493
            return True
494
        if get_request().get_environ('REMOTE_ADDR', '') in admin_for_all_contents.splitlines():
495
            # if the file is not empty it should contain the list of authorized
496
            # IP addresses.
497
            return True
498
        return False
499

  
500
    def _q_access(self):
501
        get_response().breadcrumb.append( ('backoffice/', _('Back Office')) )
502
        req = get_request()
503

  
504
        if self.check_admin_for_all():
505
            get_response().filter['admin_for_all'] = True
506
            return
507

  
508
        if get_publisher().user_class.count() > 0:
509
            user = req.user
510
            if not user:
511
                raise errors.AccessUnauthorizedError(
512
                        public_msg = _('Access to backoffice is restricted to authorized persons only. '\
513
                                       'Please login.'))
514
            if not user.can_go_in_backoffice():
515
                raise errors.AccessForbiddenError()
516

  
517
        get_response().filter['in_backoffice'] = True
518

  
519
    def get_intro_text(self):
520
        return _('''Welcome.''')
521

  
522
    def generate_header_menu(self, selected=None):
523
        s = ['<ul id="menu">\n']
524
        for menu_item in self.get_menu_items():
525
            if not 'icon' in menu_item:
526
                continue
527
            if menu_item.get('slug') == selected:
528
                s.append('<li class="active">')
529
            else:
530
                s.append('<li>')
531
            s.append('<a href="%(url)s">%(label)s</a></li>\n' % menu_item)
532
        s.append('</ul>\n')
533
        return ''.join(s)
534

  
535
    def _q_index(self):
536
        html_top('/')
537
        r = TemplateIO(html=True)
538
        r += htmltext('<div class="bo-block"><p>%s</p></div>') % self.get_intro_text()
539

  
540
        menu_items = self.get_menu_items()
541
        r += htmltext('<ul class="apps">')
542
        for menu_item in menu_items:
543
            if not 'icon' in menu_item:
544
                continue
545
            r += htmltext('<li class="zone-%(icon)s"><a href="%(url)s">%(label)s</a></li>') % menu_item
546
        for menu_item in menu_items:
547
            if 'icon' in menu_item:
548
                continue
549
            r += htmltext('<li class="zone-no-icon"><a href="%(url)s">%(label)s</a></li>') % menu_item
550
        r += htmltext('</ul>')
551
        r += htmltext('<br class="clear">')
552

  
553
        r += htmltext('<p id="for-more-info"></p>')
554

  
555
        get_response().filter['sidebar'] = str(self.get_sidebar())
556

  
557
        return r.getvalue()
558

  
559
    def get_sidebar(self):
560
        from qommon.admin.menu import get_vc_version
561
        from wcs.admin.root import gpl
562
        r = TemplateIO(html=True)
563

  
564
        r += htmltext('<div class="bo-block">')
565
        r += htmltext('<ul id="sidebar-actions">')
566
        r += htmltext('<li><a href="management/statistics">%s</a></li>') % _('Global statistics')
567
        r += htmltext('</ul>')
568
        r += htmltext('</div>')
569

  
570
        version = get_vc_version()
571
        if version:
572
            r += htmltext('<div class="bo-block"><p class="version-info">')
573
            r += _('Version:')
574
            r += ' '
575
            r += version
576
            r += htmltext('</p></div>')
577

  
578
        r += htmltext('<div class="bo-block">')
579
        r += gpl()
580
        r += htmltext('</div>')
581

  
582
        return r.getvalue()
583

  
566 584
    def pending(self):
567 585
        # kept as a redirection for compatibility with possible bookmarks
568 586
        return redirect('.')
569 587

  
588
    def statistics(self):
589
        return redirect('management/statistics')
590

  
570 591
    def _q_lookup(self, component):
571 592
        if component in [str(x[0]).strip('/') for x in self.menu_items]:
572 593
            if not is_accessible(component):
573 594
                raise errors.AccessForbiddenError()
574 595
            return getattr(self, component)
575
        return FormPage(component)
596
        if FormDef.has_key(component):
597
            return redirect('management/%s/' % component)
598
        return super(RootDirectory, self)._q_lookup(component)
576 599

  
577 600
    def get_menu_items(self):
578 601
        if not get_request().user:
wcs/formdef.py
331 331

  
332 332
    def get_url(self, backoffice = False):
333 333
        if backoffice:
334
            base_url = get_publisher().get_backoffice_url()
334
            base_url = get_publisher().get_backoffice_url() + '/management'
335 335
        else:
336 336
            base_url = get_publisher().get_frontoffice_url()
337 337
        return '%s/%s/' % (base_url, self.url_name)
338
-