From 7954effbc8458cdce8736be5e5ac92909031e398 Mon Sep 17 00:00:00 2001 From: Kobe Cuppens Date: Mon, 29 Jul 2024 09:38:29 +0200 Subject: [PATCH] Fix: Structure mode toggle button disappearing from toolbar (#7970) * Fix: Structure mode toggle button disappearing from toolbar * fix: restore js files --- cms/admin/settingsadmin.py | 7 ++++- cms/static/cms/js/modules/cms.base.js | 12 ++------ .../cms/js/modules/cms.structureboard.js | 20 ++++++------- cms/tests/frontend/unit/cms.base.test.js | 30 +++++++++---------- .../frontend/unit/cms.structureboard.test.js | 2 +- cms/tests/test_toolbar.py | 12 ++++++++ cms/toolbar/toolbar.py | 6 +--- 7 files changed, 47 insertions(+), 42 deletions(-) diff --git a/cms/admin/settingsadmin.py b/cms/admin/settingsadmin.py index baa4ea4db99..9591051eb10 100644 --- a/cms/admin/settingsadmin.py +++ b/cms/admin/settingsadmin.py @@ -10,7 +10,7 @@ from django.db import transaction from django.http import HttpResponseRedirect, HttpResponse, HttpResponseBadRequest from django.http.request import QueryDict -from django.urls import path +from django.urls import path, resolve, Resolver404 from django.utils.html import conditional_escape from django.utils.translation import override @@ -85,6 +85,11 @@ def get_toolbar(self, request): origin_url = urlparse(cms_path) attached_obj = form_data.get('attached_obj') current_page = get_page_from_request(request, use_path=origin_url.path, clean_path=True) + + try: + request.resolver_match = resolve(origin_url.path) + except Resolver404: + pass if attached_obj and current_page and not (attached_obj == current_page): return HttpResponseBadRequest('Generic object does not match current page') diff --git a/cms/static/cms/js/modules/cms.base.js b/cms/static/cms/js/modules/cms.base.js index a3d87bd410a..cb7379dee48 100644 --- a/cms/static/cms/js/modules/cms.base.js +++ b/cms/static/cms/js/modules/cms.base.js @@ -280,8 +280,8 @@ export const Helpers = { }, /** - * Modifies the url with new params and sanitises - * the ampersand within the url for #3404. + * Modifies the url with new params and sanitises the url + * reversing any & to ampersand (introduced with #3404) * * @method makeURL * @param {String} url original url @@ -298,13 +298,7 @@ export const Helpers = { newUrl.addSearch(key, value); }); - return newUrl - .toString() - .split('#') - .map((part, i) => { - return i === 0 ? part.replace(/&/g, '&') : part; - }) - .join('#'); + return newUrl.toString(); }, /** diff --git a/cms/static/cms/js/modules/cms.structureboard.js b/cms/static/cms/js/modules/cms.structureboard.js index 6e3647f25ce..2f406c95da7 100644 --- a/cms/static/cms/js/modules/cms.structureboard.js +++ b/cms/static/cms/js/modules/cms.structureboard.js @@ -997,26 +997,24 @@ class StructureBoard { // refresh toolbar var currentMode = CMS.settings.mode; - this._loadToolbar() - .done(newToolbar => { - CMS.API.Toolbar._refreshMarkup($(newToolbar).find('.cms-toolbar')); - }) - .fail(() => Helpers.reloadBrowser()); - if (currentMode === 'structure') { this._requestcontent = null; if (this._loadedContent && action !== 'COPY') { this.updateContent(); + return; // Toolbar loaded } - return; - } - - // invalidate the content mode - if (action !== 'COPY') { + } else if (action !== 'COPY') { this._requestcontent = null; this.updateContent(); + return; // Toolbar loaded + } + this._loadToolbar() + .done(newToolbar => { + CMS.API.Toolbar._refreshMarkup($(newToolbar).find('.cms-toolbar')); + }) + .fail(() => Helpers.reloadBrowser()); } _propagateInvalidatedState(action, data) { diff --git a/cms/tests/frontend/unit/cms.base.test.js b/cms/tests/frontend/unit/cms.base.test.js index 5b6e4ee732f..dac61376da4 100644 --- a/cms/tests/frontend/unit/cms.base.test.js +++ b/cms/tests/frontend/unit/cms.base.test.js @@ -549,45 +549,45 @@ describe('cms.base.js', function() { var url; url = CMS.API.Helpers.makeURL('test', [['param', '1'], ['another', '2']]); - expect(url).toEqual('test?param=1&another=2'); + expect(url).toEqual('test?param=1&another=2'); url = CMS.API.Helpers.makeURL('test?param=1', [['another', '2']]); - expect(url).toEqual('test?param=1&another=2'); + expect(url).toEqual('test?param=1&another=2'); url = CMS.API.Helpers.makeURL('test?param=1&another=2', [['different', '3']]); - expect(url).toEqual('test?param=1&another=2&different=3'); + expect(url).toEqual('test?param=1&another=2&different=3'); - url = CMS.API.Helpers.makeURL('test?param=1&another=2', [['different', '3']]); - expect(url).toEqual('test?param=1&another=2&different=3'); + url = CMS.API.Helpers.makeURL('test?param=1&another=2', [['different', '3']]); + expect(url).toEqual('test?param=1&another=2&different=3'); - url = CMS.API.Helpers.makeURL('test?param=1&another=2&again=3', [['different', '3']]); - expect(url).toEqual('test?param=1&another=2&again=3&different=3'); + url = CMS.API.Helpers.makeURL('test?param=1&another=2&again=3', [['different', '3']]); + expect(url).toEqual('test?param=1&another=2&again=3&different=3'); }); it('replaces param values with new ones if they match', function() { var url; - url = CMS.API.Helpers.makeURL('test?param=1&another=2', [['another', '3']]); - expect(url).toEqual('test?param=1&another=3'); + url = CMS.API.Helpers.makeURL('test?param=1&another=2', [['another', '3']]); + expect(url).toEqual('test?param=1&another=3'); - url = CMS.API.Helpers.makeURL('test?param=1&another=2', [['another', '3'], ['param', '4']]); - expect(url).toEqual('test?another=3&param=4'); + url = CMS.API.Helpers.makeURL('test?param=1&another=2', [['another', '3'], ['param', '4']]); + expect(url).toEqual('test?another=3¶m=4'); }); it('understands hashes in the url', function() { var url; url = CMS.API.Helpers.makeURL('test#hash', [['param', '1'], ['another', '2']]); - expect(url).toEqual('test?param=1&another=2#hash'); + expect(url).toEqual('test?param=1&another=2#hash'); url = CMS.API.Helpers.makeURL('test#hash#with#hash', [['param', '1'], ['another', '2']]); - expect(url).toEqual('test?param=1&another=2#hash#with#hash'); + expect(url).toEqual('test?param=1&another=2#hash#with#hash'); url = CMS.API.Helpers.makeURL('test#', [['param', '1'], ['another', '2']]); - expect(url).toEqual('test?param=1&another=2'); + expect(url).toEqual('test?param=1&another=2'); url = CMS.API.Helpers.makeURL('test#hash&stuff', [['param', '1'], ['another', '2']]); - expect(url).toEqual('test?param=1&another=2#hash&stuff'); + expect(url).toEqual('test?param=1&another=2#hash&stuff'); url = CMS.API.Helpers.makeURL('test#hash&stuff', []); expect(url).toEqual('test#hash&stuff'); diff --git a/cms/tests/frontend/unit/cms.structureboard.test.js b/cms/tests/frontend/unit/cms.structureboard.test.js index 2f57ad87940..de9b5985db9 100644 --- a/cms/tests/frontend/unit/cms.structureboard.test.js +++ b/cms/tests/frontend/unit/cms.structureboard.test.js @@ -2125,7 +2125,7 @@ describe('CMS.StructureBoard', function() { expect($.ajax).toHaveBeenCalledWith({ url: jasmine.stringMatching( - /TOOLBAR_URL\?obj_id=100&obj_type=cms.page&cms_path=%2Fstructure*/ + /TOOLBAR_URL\?obj_id=100&obj_type=cms.page&cms_path=%2Fstructure*/ ) }); }); diff --git a/cms/tests/test_toolbar.py b/cms/tests/test_toolbar.py index 15b3780b690..4d6dab41b19 100644 --- a/cms/tests/test_toolbar.py +++ b/cms/tests/test_toolbar.py @@ -208,7 +208,19 @@ def test_toolbar_request_endpoint_validation(self): }, ) self.assertEqual(response.status_code, 200) + self.assertContains(response, "Clipboard") + response = self.client.get( + endpoint, + data={ + 'obj_id': page_content.pk, + 'obj_type': 'cms.pagecontent', + 'cms_path': get_object_edit_url(page_content)+"q" # Invalid + }, + ) + self.assertEqual(response.status_code, 200) + # No clipboard exposed to invalid cms_path + self.assertNotContains(response, "Clipboard") # Invalid app / model response = self.client.get( endpoint, diff --git a/cms/toolbar/toolbar.py b/cms/toolbar/toolbar.py index bd9fa52429b..60529bedaf6 100644 --- a/cms/toolbar/toolbar.py +++ b/cms/toolbar/toolbar.py @@ -163,11 +163,7 @@ def __init__(self, request, request_path=None, _async=False): try: # If the original view is decorated we try to extract the real function # module instead of the decorator's one - if decorator and getattr(decorator, 'func_closure', False): - # python 2 - self.app_name = decorator.func_closure[0].cell_contents.__module__ - elif decorator and getattr(decorator, '__closure__', False): - # python 3 + if decorator and getattr(decorator, '__closure__', False): self.app_name = decorator.__closure__[0].cell_contents.__module__ else: raise AttributeError()