Project

General

Profile

0001-misc-redirect-form-def-data-URL-to-include-category-.patch

Frédéric Péters, 21 October 2022 02:31 PM

Download (12.2 KB)

View differences:

Subject: [PATCH] misc: redirect form{def,data} URL to include category slug
 (#69546)

 tests/form_pages/test_all.py      | 92 ++++++++++++++++++++++++++++++-
 wcs/backoffice/data_management.py |  1 +
 wcs/backoffice/submission.py      |  1 +
 wcs/carddef.py                    |  2 +-
 wcs/formdata.py                   |  7 ++-
 wcs/formdef.py                    |  4 +-
 wcs/forms/common.py               | 12 ++++
 wcs/forms/root.py                 | 32 ++++++++++-
 wcs/root.py                       |  2 +-
 9 files changed, 145 insertions(+), 8 deletions(-)
tests/form_pages/test_all.py
175 175
    assert 'Draft' in resp
176 176
    assert '<a href="/test/%s"' % draft.id in resp
177 177
    resp = app.get('/test/%s' % formdata.id)
178
    resp.status_int = 200
178
    assert resp.location == 'http://example.net/test/1/'
179 179
    resp = app.get('/test/%s/' % draft.id, status=302)
180
    assert resp.location.startswith('http://example.net/foobar/test/%s/' % draft.id)
181
    resp = resp.follow(status=302)
182
    assert resp.location.startswith('http://example.net/foobar/test/?mt=')
180 183
    resp = resp.follow(status=200)
181 184

  
182 185
    # disable formdef: formdatas are still visible and accessible, drafts are not
......
189 192
    assert '<a href="test/%s"' % draft.id not in resp
190 193
    resp = app.get('/test/%s/' % formdata.id)
191 194
    resp = app.get('/test/%s/' % draft.id, status=302)
195
    assert resp.location.startswith('http://example.net/foobar/test/%s/' % draft.id)
196
    resp = resp.follow(status=302)
197
    assert resp.location.startswith('http://example.net/foobar/test/?mt=')
192 198
    resp = resp.follow(status=403)
193 199

  
194 200

  
......
9863 9869
    resp = resp.follow()
9864 9870

  
9865 9871
    assert 'HELLO GLOBAL INTERACTIVE ACTION' in resp.text
9872

  
9873

  
9874
def test_category_redirection(pub):
9875
    FormDef.wipe()
9876
    formdef = FormDef()
9877
    formdef.name = 'test category redirection'
9878
    formdef.fields = []
9879
    formdef.store()
9880

  
9881
    get_app(pub).get(formdef.get_url())
9882

  
9883
    Category.wipe()
9884
    cat = Category(name='foo')
9885
    cat.store()
9886

  
9887
    cat2 = Category(name='bar')
9888
    cat2.store()
9889

  
9890
    formdef.category_id = cat.id
9891
    formdef.store()
9892

  
9893
    formdata = formdef.data_class()()
9894
    formdata.just_created()
9895
    formdata.store()
9896

  
9897
    resp = get_app(pub).get(formdef.get_url(), status=302)
9898
    assert resp.location == 'http://example.net/foo/test-category-redirection/'
9899
    resp = resp.follow()
9900

  
9901
    resp = get_app(pub).get(formdef.get_url() + '?test=toto', status=302)
9902
    assert resp.location == 'http://example.net/foo/test-category-redirection/?test=toto'
9903

  
9904
    get_app(pub).get('/bar/test-category-redirection/', status=404)
9905

  
9906
    resp = get_app(pub).get(formdata.get_url(), status=302)
9907
    assert (
9908
        urllib.parse.urlparse(resp.location).path
9909
        == urllib.parse.urlparse(formdata.get_url(include_category=True)).path
9910
    )
9911
    resp = get_app(pub).get(formdata.get_url() + '?test=toto', status=302)
9912
    assert (
9913
        urllib.parse.urlparse(resp.location).path
9914
        == urllib.parse.urlparse(formdata.get_url(include_category=True)).path
9915
    )
9916
    assert urllib.parse.urlparse(resp.location).query == 'test=toto'
9917

  
9918
    # check with formdef and category with same slug
9919
    formdef = FormDef()
9920
    formdef.name = 'bar'
9921
    formdef.fields = []
9922
    formdef.category_id = cat2.id
9923
    formdef.store()
9924

  
9925
    formdata2 = formdef.data_class()()
9926
    formdata2.just_created()
9927
    formdata2.store()
9928

  
9929
    resp = get_app(pub).get('/bar/', status=302)  # redirect even if category with same slug
9930
    assert resp.location == 'http://example.net/bar/bar/'
9931
    resp = get_app(pub).get('/bar/bar/', status=200)  # get formpage when full url is used
9932
    assert resp.pyquery('#steps')  # make sure it's a form page
9933
    resp = get_app(pub).get('/bar/bar/bar/', status=404)  # do not allow to go deeper
9934

  
9935
    resp = get_app(pub).get(formdata2.get_url(), status=302)
9936
    assert (
9937
        urllib.parse.urlparse(resp.location).path
9938
        == urllib.parse.urlparse(formdata2.get_url(include_category=True)).path
9939
    )
9940

  
9941
    # check other pages are ok with and without category slug
9942
    get_app(pub).get('/bar/qrcode', status=200)
9943
    get_app(pub).get('/bar/bar/qrcode', status=200)
9944

  
9945
    # check another formdef in same category is ok
9946
    formdef = FormDef()
9947
    formdef.name = 'bar2'
9948
    formdef.fields = []
9949
    formdef.category_id = cat2.id
9950
    formdef.store()
9951

  
9952
    resp = get_app(pub).get('/bar2/', status=302)
9953
    assert resp.location == 'http://example.net/bar/bar2/'
9954
    resp = get_app(pub).get('/bar/bar2/', status=200)
9955
    assert resp.pyquery('#steps')  # make sure it's a form page
wcs/backoffice/data_management.py
128 128
    search_label = _('Search in card content')
129 129
    formdef_view_label = _('View Card')
130 130
    has_json_export_support = True
131
    ensure_parent_category_in_url = False
131 132

  
132 133
    @property
133 134
    def add(self):
wcs/backoffice/submission.py
110 110
    steps_templates = ['wcs/formdata_steps.html']
111 111
    has_channel_support = True
112 112
    has_user_support = True
113
    ensure_parent_category_in_url = False
113 114

  
114 115
    def __init__(self, *args, **kwargs):
115 116
        super().__init__(*args, **kwargs)
wcs/carddef.py
120 120

  
121 121
        return workflow
122 122

  
123
    def get_url(self, backoffice=False):
123
    def get_url(self, backoffice=False, **kwargs):
124 124
        # always return backoffice URL
125 125
        base_url = get_publisher().get_backoffice_url() + '/data'
126 126
        return '%s/%s/' % (base_url, self.url_name)
wcs/formdata.py
793 793
        self.status = status
794 794
        self.store()
795 795

  
796
    def get_url(self, backoffice=False):
797
        return '%s%s/' % (self.formdef.get_url(backoffice=backoffice), self.id)
796
    def get_url(self, backoffice=False, include_category=False):
797
        return '%s%s/' % (
798
            self.formdef.get_url(backoffice=backoffice, include_category=include_category),
799
            self.id,
800
        )
798 801

  
799 802
    def get_backoffice_url(self):
800 803
        return self.get_url(backoffice=True)
wcs/formdef.py
776 776
    def slug(self, value):
777 777
        self.url_name = value
778 778

  
779
    def get_url(self, backoffice=False, preview=False):
779
    def get_url(self, backoffice=False, preview=False, include_category=False):
780 780
        if backoffice:
781 781
            base_url = get_publisher().get_backoffice_url() + '/management'
782 782
        elif preview:
783 783
            base_url = get_publisher().get_frontoffice_url() + '/preview'
784 784
        else:
785 785
            base_url = get_publisher().get_frontoffice_url()
786
        if include_category and self.category_id:
787
            return '%s/%s/%s/' % (base_url, self.category.slug, self.url_name)
786 788
        return '%s/%s/' % (base_url, self.url_name)
787 789

  
788 790
    def get_api_url(self):
wcs/forms/common.py
275 275
        return r.getvalue()
276 276

  
277 277
    def _q_index(self):
278
        if (
279
            self.formdef.category_id
280
            and self.parent_view
281
            and self.parent_view.ensure_parent_category_in_url
282
            and get_request().get_method() == 'GET'
283
            and not self.parent_view.parent_category
284
        ):
285
            url = self.filled.get_url(include_category=True)
286
            if get_request().get_query():
287
                url += '?' + get_request().get_query()
288
            return redirect(url)
289

  
278 290
        if self.filled.is_draft():
279 291
            return self.restore_draft()
280 292

  
wcs/forms/root.py
273 273
    ]
274 274

  
275 275
    do_not_call_in_templates = True
276
    ensure_parent_category_in_url = True
276 277
    filling_templates = ['wcs/front/formdata_filling.html', 'wcs/formdata_filling.html']
277 278
    validation_templates = ['wcs/front/formdata_validation.html', 'wcs/formdata_validation.html']
278 279
    steps_templates = ['wcs/front/formdata_steps.html', 'wcs/formdata_steps.html']
279 280
    sidebox_templates = ['wcs/front/formdata_sidebox.html', 'wcs/formdata_sidebox.html']
280 281
    formdef_class = FormDef
281 282

  
282
    def __init__(self, component):
283
    def __init__(self, component, parent_category=None):
283 284
        try:
284 285
            self.formdef = self.formdef_class.get_by_urlname(component)
285 286
        except KeyError:
286 287
            raise errors.TraversalError()
287 288

  
289
        self.parent_category = parent_category
290
        if self.parent_category and self.formdef.category_id != self.parent_category.id:
291
            raise errors.TraversalError()
292

  
288 293
        self.substvars = {}
289 294
        get_publisher().substitutions.feed(self)
290 295
        get_publisher().substitutions.feed(self.formdef)
......
941 946
        self._pages = None
942 947

  
943 948
    def _q_index(self):
949
        if (
950
            self.ensure_parent_category_in_url
951
            and get_request().get_method() == 'GET'
952
            and self.formdef.category_id
953
            and not self.parent_category
954
        ):
955
            url = self.formdef.get_url(include_category=True)
956
            if get_request().get_query():
957
                url += '?' + get_request().get_query()
958
            return redirect(url)
944 959
        self.check_access()
945 960
        authentication_context_check_result = self.check_authentication_context()
946 961
        if authentication_context_check_result:
......
1762 1777
        return PublicFormStatusPage
1763 1778

  
1764 1779
    def _q_lookup(self, component):
1780
        if (
1781
            self.ensure_parent_category_in_url
1782
            and get_request().get_method() == 'GET'
1783
            and not self.parent_category
1784
        ):
1785
            # handle special case where there's a formdef and a category with the same
1786
            # slug; recurse into self with parent_category set to avoid the redirect to
1787
            # full URL step.
1788
            category = Category.get_by_slug(self.formdef.url_name, ignore_errors=True)
1789
            formdef = self.formdef_class.get_by_urlname(component, ignore_errors=True)
1790
            if category and formdef:
1791
                return self.__class__(component, parent_category=category)
1792

  
1765 1793
        try:
1766 1794
            filled = self.formdef.data_class().get(component)
1767 1795
        except KeyError:
......
2109 2137
        return ApiCategoriesDirectory()._q_index()
2110 2138

  
2111 2139
    def _q_lookup(self, component):
2112
        return FormPage(component)
2140
        return FormPage(component, parent_category=self.category)
2113 2141

  
2114 2142

  
2115 2143
class PublicFormStatusPage(FormStatusPage):
wcs/root.py
415 415
        except KeyError:
416 416
            pass
417 417
        else:
418
            # redirect to category if there's not a formdef with same slug
418
            # display category unless there's a formdef with same slug
419 419
            try:
420 420
                FormDef.get_by_urlname(component)
421 421
            except KeyError:
422
-