Projet

Général

Profil

0001-backoffice-add-tracking-code-form-for-agents-8755.patch

Frédéric Péters, 23 octobre 2015 13:32

Télécharger (10,6 ko)

Voir les différences:

Subject: [PATCH] backoffice: add tracking code form for agents (#8755)

 tests/test_backoffice_pages.py      | 48 +++++++++++++++++++++++++++++++++
 wcs/api.py                          |  4 +++
 wcs/backoffice/management.py        | 53 ++++++++++++++++++++++++++++++++++---
 wcs/qommon/static/css/dc2/admin.css |  5 ++++
 4 files changed, 107 insertions(+), 3 deletions(-)
tests/test_backoffice_pages.py
787 787
    assert resp.body.count('<tr') == 20
788 788
    assert 'http://example.net/backoffice/management/other-form/' in resp.body
789 789
    assert not 'http://example.net/backoffice/management/form-title/' in resp.body
790

  
791
def test_tracking_code_access(pub):
792
    create_user(pub)
793
    create_environment(pub, set_receiver=False)
794

  
795
    formdef = FormDef.get_by_urlname('form-title')
796
    formdef.enable_tracking_codes = True
797
    formdef.store()
798
    formdata, formdata2 = formdef.data_class().select()[:2]
799
    code = pub.tracking_code_class()
800
    code.formdata = formdata
801

  
802
    app = login(get_app(pub))
803
    resp = app.get('/backoffice/management/')
804
    assert 'id="tracking-code"' in resp.body
805
    resp.forms[0]['code'] = formdata.tracking_code
806
    resp = resp.forms[0].submit()
807
    assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
808
    resp = resp.follow()
809
    assert 'The form has been recorded' in resp.body
810
    assert 'This form has been accessed via its tracking code' in resp.body
811

  
812
    # check there's no access to other formdata
813
    app.get('http://example.net/backoffice/management/form-title/%s/' % formdata2.id, status=403)
814

  
815
    resp = app.get('/backoffice/management/')
816
    resp.forms[0]['code'] = 'AAAAAAAA'
817
    resp = resp.forms[0].submit()
818
    assert resp.location == 'http://example.net/backoffice/management/'
819
    resp = resp.follow()
820
    assert 'No such code' in resp.body
821

  
822
    if pub.is_using_postgresql():
823
        # try it from the global listing
824
        resp = app.get('/backoffice/management/listing')
825
        assert 'id="tracking-code"' in resp.body
826
        resp.forms[0]['code'] = formdata.tracking_code
827
        resp = resp.forms[0].submit()
828
        assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
829
        resp = resp.follow()
830
        assert 'The form has been recorded' in resp.body
831

  
832
        resp = app.get('/backoffice/management/listing')
833
        resp.forms[0]['code'] = 'AAAAAAAA'
834
        resp = resp.forms[0].submit()
835
        assert resp.location == 'http://example.net/backoffice/management/listing'
836
        resp = resp.follow()
837
        assert 'No such code' in resp.body
wcs/api.py
161 161
            self.formdef = FormDef.get_by_urlname(component)
162 162
        except KeyError:
163 163
            raise TraversalError()
164
        # check access for all paths, to block access to formdata that would
165
        # otherwise be accessible if the user is the submitter.
166
        self.check_access()
164 167

  
168
    def check_access(self):
165 169
        api_user = get_user_from_api_query_string()
166 170
        if not api_user:
167 171
            if get_request().user and get_request().user.is_admin:
wcs/backoffice/management.py
47 47

  
48 48

  
49 49
class ManagementDirectory(Directory):
50
    _q_exports = ['', 'listing', 'statistics']
50
    _q_exports = ['', 'listing', 'statistics', 'code']
51 51

  
52 52
    def is_accessible(self, user):
53 53
        return user.can_go_in_backoffice()
......
60 60
        html_top('management', _('Management'))
61 61
        get_response().filter['sidebar'] = self.get_sidebar()
62 62
        r = TemplateIO(html=True)
63
        r += get_session().display_message()
63 64

  
64 65
        user = get_request().user
65 66

  
......
121 122
            r += htmltext('<li><a href="listing">%s</a></li>') % _('Global View')
122 123
        r += htmltext('</ul>')
123 124
        r += htmltext('</div>')
125
        r += self.get_tracking_code_sidebox()
126
        return r.getvalue()
127

  
128
    def code(self):
129
        code = get_request().form.get('code')
130
        try:
131
            tracking_code = get_publisher().tracking_code_class.get(code)
132
        except KeyError:
133
            get_session().message = ('error', _('No such code'))
134
            return redirect(get_request().form.get('back') or '.')
135
        formdata = tracking_code.formdata
136
        get_session().mark_anonymous_formdata(formdata)
137
        return redirect(formdata.get_url(backoffice=True))
138

  
139
    def get_tracking_code_sidebox(self, back_place=''):
140
        r = TemplateIO(html=True)
141
        if any((x for x in FormDef.select() if x.enable_tracking_codes)):
142
            r += htmltext('<div id="tracking-code">')
143
            r += htmltext('<h3>%s</h3>' % _('Tracking Code'))
144
            r += htmltext('<form action="code">')
145
            r += htmltext('<input type="hidden" name="back" value="%s"/>') % back_place
146
            r += htmltext('<input size="12" name="code" pattern="[A-Za-z]{8}" placeholder="%s"/>'
147
                    ) % _('ex: RPQDFVCD')
148
            r += htmltext('<button>%s</button>') % _('Load')
149
            r += htmltext('</form>')
150
            r += htmltext('</div>')
124 151
        return r.getvalue()
125 152

  
126 153
    def get_global_listing_sidebar(self, limit=None, offset=None):
......
142 169
        form.add_submit('submit', _('Submit'))
143 170

  
144 171
        r = TemplateIO(html=True)
172
        r += self.get_tracking_code_sidebox('listing')
145 173
        r += htmltext('<div>')
146 174
        r += htmltext('<h3>%s</h3>') % _('Filters')
147 175
        r += form.render()
......
362 390
        get_response().filter['sidebar'] = self.get_global_listing_sidebar()
363 391
        rt = TemplateIO(html=True)
364 392
        rt += htmltext('<h2>%s</h2>') % _('Global View')
393
        rt += get_session().display_message()
365 394
        rt += r.getvalue()
366 395
        r = rt
367 396
        return rt.getvalue()
......
379 408
            self.formdef = FormDef.get_by_urlname(component)
380 409
        except KeyError:
381 410
            raise errors.TraversalError()
411
        get_response().breadcrumb.append( (component + '/', self.formdef.name) )
382 412

  
413
    def check_access(self):
383 414
        session = get_session()
384 415
        user = get_request().user
385 416
        if user is None and get_publisher().user_class.count() == 0:
......
392 423
                raise errors.AccessForbiddenError()
393 424
            else:
394 425
                raise errors.AccessUnauthorizedError()
395
        get_response().breadcrumb.append( (component + '/', self.formdef.name) )
396 426

  
397 427
    def get_formdata_sidebar(self, qs=''):
398 428
        r = TemplateIO(html=True)
......
645 675

  
646 676
        return criterias
647 677

  
648

  
649 678
    def _q_index(self):
679
        self.check_access()
650 680
        get_logger().info('backoffice - form %s - listing' % self.formdef.name)
651 681

  
652 682
        fields = self.get_fields_from_query()
......
689 719
        return r.getvalue()
690 720

  
691 721
    def pending(self):
722
        self.check_access()
692 723
        get_logger().info('backoffice - form %s - pending' % self.formdef.name)
693 724
        get_response().breadcrumb.append( ('pending', _('Pending Forms')) )
694 725
        html_top('management', '%s - %s' % (_('Pending Forms'), self.formdef.name))
......
759 790
        return elements
760 791

  
761 792
    def csv(self):
793
        self.check_access()
762 794
        fields = self.get_fields_from_query()
763 795
        selected_filter = self.get_filter_from_query()
764 796
        user = get_request().user
......
808 840
            return exporter.output.getvalue()
809 841

  
810 842
    def export(self):
843
        self.check_access()
811 844
        if get_request().form.get('download'):
812 845
            return self.export_download()
813 846

  
......
852 885
        return job.file_content
853 886

  
854 887
    def xls(self):
888
        self.check_access()
855 889
        if xlwt is None:
856 890
            raise errors.TraversalError()
857 891

  
......
913 947
            return exporter.output.getvalue()
914 948

  
915 949
    def ods(self):
950
        self.check_access()
916 951
        fields = self.get_fields_from_query()
917 952
        selected_filter = self.get_filter_from_query()
918 953
        user = get_request().user
......
971 1006
            return exporter.output.getvalue()
972 1007

  
973 1008
    def json(self):
1009
        self.check_access()
974 1010
        get_response().set_content_type('application/json')
975 1011
        from wcs.api import get_user_from_api_query_string
976 1012
        user = get_user_from_api_query_string() or get_request().user
......
1005 1041
        return r.getvalue()
1006 1042

  
1007 1043
    def stats(self):
1044
        self.check_access()
1008 1045
        get_logger().info('backoffice - form %s - stats' % self.formdef.name)
1009 1046
        html_top('management', '%s - %s' % (_('Form'), self.formdef.name))
1010 1047
        r = TemplateIO(html=True)
......
1199 1236
        get_response().filter['sidebar'] = self.get_sidebar()
1200 1237
        return self.status()
1201 1238

  
1239
    def receipt(self, *args, **kwargs):
1240
        r = TemplateIO(html=True)
1241
        if get_session() and get_session().is_anonymous_submitter(self.filled):
1242
            r += htmltext('<div class="infonotice">')
1243
            r += _('This form has been accessed via its tracking code, it is '
1244
                   'therefore displayed like you were its owner.')
1245
            r += htmltext('</div>')
1246
        r += super(FormBackOfficeStatusPage, self).receipt(*args, **kwargs)
1247
        return r.getvalue()
1248

  
1202 1249
    def get_sidebar(self):
1203 1250
        return self.get_extra_context_bar()
1204 1251

  
wcs/qommon/static/css/dc2/admin.css
1092 1092
	transform: rotate(2deg);
1093 1093
}
1094 1094

  
1095
div#tracking-code button {
1096
	position: relative;
1097
	top: -2px;
1098
}
1099

  
1095 1100
@media print {
1096 1101
	div#sidebar {
1097 1102
		display: none;
1098
-