Project

General

Profile

0001-misc-redirect-form-URL-to-include-category-slug-6954.patch

Frédéric Péters, 17 October 2022 01:40 PM

Download (9.08 KB)

View differences:

Subject: [PATCH] misc: redirect form URL to include category slug (#69546)

 tests/form_pages/test_all.py      | 65 ++++++++++++++++++++++++++++++-
 wcs/backoffice/data_management.py |  1 +
 wcs/backoffice/submission.py      |  1 +
 wcs/formdef.py                    |  4 +-
 wcs/forms/root.py                 | 31 ++++++++++++++-
 wcs/root.py                       |  2 +-
 6 files changed, 99 insertions(+), 5 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/test/?mt=')
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/test/?mt=')
196
    resp = resp.follow(status=302)
192 197
    resp = resp.follow(status=403)
193 198

  
194 199

  
......
9838 9843
    resp = resp.follow()
9839 9844

  
9840 9845
    assert 'HELLO GLOBAL INTERACTIVE ACTION' in resp.text
9846

  
9847

  
9848
def test_category_redirection(pub):
9849
    FormDef.wipe()
9850
    formdef = FormDef()
9851
    formdef.name = 'test category redirection'
9852
    formdef.fields = []
9853
    formdef.store()
9854

  
9855
    get_app(pub).get(formdef.get_url())
9856

  
9857
    Category.wipe()
9858
    cat = Category(name='foo')
9859
    cat.store()
9860

  
9861
    cat2 = Category(name='bar')
9862
    cat2.store()
9863

  
9864
    formdef.category_id = cat.id
9865
    formdef.store()
9866

  
9867
    resp = get_app(pub).get(formdef.get_url(), status=302)
9868
    assert resp.location == 'http://example.net/foo/test-category-redirection/'
9869
    resp = resp.follow()
9870

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

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

  
9876
    # check with formdef and category with same slug
9877
    formdef = FormDef()
9878
    formdef.name = 'bar'
9879
    formdef.fields = []
9880
    formdef.category_id = cat2.id
9881
    formdef.store()
9882

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

  
9889
    # check other pages are ok with and without category slug
9890
    get_app(pub).get('/bar/qrcode', status=200)
9891
    get_app(pub).get('/bar/bar/qrcode', status=200)
9892

  
9893
    # check another formdef in same category is ok
9894
    formdef = FormDef()
9895
    formdef.name = 'bar2'
9896
    formdef.fields = []
9897
    formdef.category_id = cat2.id
9898
    formdef.store()
9899

  
9900
    resp = get_app(pub).get('/bar2/', status=302)
9901
    assert resp.location == 'http://example.net/bar/bar2/'
9902
    resp = get_app(pub).get('/bar/bar2/', status=200)
9903
    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/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/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:
......
1757 1772
        return PublicFormStatusPage
1758 1773

  
1759 1774
    def _q_lookup(self, component):
1775
        if (
1776
            self.ensure_parent_category_in_url
1777
            and get_request().get_method() == 'GET'
1778
            and not self.parent_category
1779
        ):
1780
            # handle special case where there's a formdef and a category with the same
1781
            # slug; recurse into self with parent_category set to avoid the redirect to
1782
            # full URL step.
1783
            category = Category.get_by_slug(self.formdef.url_name, ignore_errors=True)
1784
            if category:
1785
                return self.__class__(component, parent_category=category)
1786

  
1760 1787
        try:
1761 1788
            filled = self.formdef.data_class().get(component)
1762 1789
        except KeyError:
......
2104 2131
        return ApiCategoriesDirectory()._q_index()
2105 2132

  
2106 2133
    def _q_lookup(self, component):
2107
        return FormPage(component)
2134
        return FormPage(component, parent_category=self.category)
2108 2135

  
2109 2136

  
2110 2137
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
-