From 828c88cf6926b8c75d05463b92c201d563157b27 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Fri, 19 May 2023 11:46:42 +0200 Subject: [PATCH 01/13] feat: absolute urls --- CHANGES.rst | 3 ++- .../voltoplugin/editablefooter/restapi/get.py | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 99207e0..64739c0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,8 @@ Changelog 1.1.3 (unreleased) ------------------ -- Nothing changed yet. +- absolut-ize urls + [mamico] 1.1.2 (2023-03-17) diff --git a/src/redturtle/voltoplugin/editablefooter/restapi/get.py b/src/redturtle/voltoplugin/editablefooter/restapi/get.py index e802f7e..f004767 100644 --- a/src/redturtle/voltoplugin/editablefooter/restapi/get.py +++ b/src/redturtle/voltoplugin/editablefooter/restapi/get.py @@ -21,4 +21,12 @@ def reply(self): ) if not record: return [] - return json.loads(record) + data = json.loads(record) + portal_url = api.portal.get().absolute_url() + for el in data or []: + for item in el.get("items") or []: + if item.get("text") and item.get("text").get("data"): + item["text"]["data"] = item["text"]["data"].replace( + 'href="/', f'href="{portal_url}/' + ) + return data From 020aba5deb65779c64031b5efb74bd79b4b8361a Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Fri, 19 May 2023 13:57:05 +0200 Subject: [PATCH 02/13] tests --- .github/workflows/tests.yml | 2 +- .gitignore | 1 + base.cfg | 1 + .../voltoplugin/editablefooter/restapi/get.py | 16 +++++++--- .../tests/test_footer_columns_route.py | 32 +++++++++++-------- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0f47093..e740303 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,4 +36,4 @@ jobs: bin/code-analysis - name: Run tests run: | - bin/test + bin/test-coverage diff --git a/.gitignore b/.gitignore index 2318de2..a61569d 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ report.html .vscode/ .tox/ reports/ +pyvenv.cfg # excludes !.coveragerc !.editorconfig diff --git a/base.cfg b/base.cfg index ce20b0f..0cf3628 100644 --- a/base.cfg +++ b/base.cfg @@ -73,6 +73,7 @@ recipe = collective.recipe.template input = inline: #!/bin/bash export TZ=UTC + set -e ${buildout:directory}/bin/coverage run bin/test $* ${buildout:directory}/bin/coverage html ${buildout:directory}/bin/coverage report -m --fail-under=90 diff --git a/src/redturtle/voltoplugin/editablefooter/restapi/get.py b/src/redturtle/voltoplugin/editablefooter/restapi/get.py index f004767..8543e26 100644 --- a/src/redturtle/voltoplugin/editablefooter/restapi/get.py +++ b/src/redturtle/voltoplugin/editablefooter/restapi/get.py @@ -24,9 +24,15 @@ def reply(self): data = json.loads(record) portal_url = api.portal.get().absolute_url() for el in data or []: - for item in el.get("items") or []: - if item.get("text") and item.get("text").get("data"): - item["text"]["data"] = item["text"]["data"].replace( - 'href="/', f'href="{portal_url}/' - ) + if isinstance(el, dict): + for item in el.get("items") or []: + if ( + isinstance(item, dict) + and item.get("text") + and isinstance(item.get("text"), dict) + and item.get("text").get("data") + ): + item["text"]["data"] = item["text"]["data"].replace( + 'href="/', f'href="{portal_url}/' + ) return data diff --git a/src/redturtle/voltoplugin/editablefooter/tests/test_footer_columns_route.py b/src/redturtle/voltoplugin/editablefooter/tests/test_footer_columns_route.py index e296482..afa0598 100644 --- a/src/redturtle/voltoplugin/editablefooter/tests/test_footer_columns_route.py +++ b/src/redturtle/voltoplugin/editablefooter/tests/test_footer_columns_route.py @@ -32,31 +32,35 @@ def setUp(self): self.api_session.headers.update({"Accept": "application/json"}) self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) - self.value = {"foo": "bar"} - self.set_record_value( - field="footer_columns", value=json.dumps(self.value) - ) + self.value = [ + { + "items": [ + {"text": {"data": 'Link 1'}}, + {"text": {"data": 'Link 1'}}, + ] + } + ] + self.set_record_value(field="footer_columns", value=json.dumps(self.value)) def tearDown(self): self.api_session.close() def set_record_value(self, field, value): - api.portal.set_registry_record( - field, value, interface=IEditableFooterSettings - ) + api.portal.set_registry_record(field, value, interface=IEditableFooterSettings) commit() def test_route_exists(self): response = self.api_session.get("/@footer-columns") - self.assertEqual(response.status_code, 200) - self.assertEqual( - response.headers.get("Content-Type"), "application/json" - ) + self.assertEqual(response.headers.get("Content-Type"), "application/json") def test_return_json_data(self): - response = self.api_session.get("/@footer-columns") + self.assertEqual(response.status_code, 200) result = response.json() - - self.assertEqual(result, self.value) + # self.value has relative links, but the result should have absolute links + self.assertNotEqual(result, self.value) + self.assertEqual( + json.dumps(result), + json.dumps(self.value).replace('href=\\"/', f'href=\\"{self.portal_url}/'), + ) From dd9ab079b25dc1240a38aa109c2d9a7cca2fbdc6 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Fri, 19 May 2023 13:59:25 +0200 Subject: [PATCH 03/13] tests --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index e920041..e3c5e00 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,4 +16,5 @@ not_skip = __init__.py [flake8] exclude = bootstrap.py,docs,*.egg.,omelette +ignore = W503 max-complexity = 15 From 16ddf91c8f7a91b8c0609e68d39d6cf438b74641 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Fri, 19 May 2023 14:00:48 +0200 Subject: [PATCH 04/13] tests --- src/redturtle/voltoplugin/editablefooter/restapi/get.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/redturtle/voltoplugin/editablefooter/restapi/get.py b/src/redturtle/voltoplugin/editablefooter/restapi/get.py index 8543e26..c1b00e8 100644 --- a/src/redturtle/voltoplugin/editablefooter/restapi/get.py +++ b/src/redturtle/voltoplugin/editablefooter/restapi/get.py @@ -28,9 +28,9 @@ def reply(self): for item in el.get("items") or []: if ( isinstance(item, dict) - and item.get("text") - and isinstance(item.get("text"), dict) - and item.get("text").get("data") + and item.get("text") # noqa: W503 + and isinstance(item.get("text"), dict) # noqa: W503 + and item.get("text").get("data") # noqa: W503 ): item["text"]["data"] = item["text"]["data"].replace( 'href="/', f'href="{portal_url}/' From be3e8dab41fbc2339ddd72ea5067edbce9915986 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Jan 2024 12:28:23 +0100 Subject: [PATCH 05/13] handle plone.volto frontend_domain field and fix tests --- .github/workflows/black.yml | 35 +++++++ .github/workflows/flake8.yml | 35 +++++++ .github/workflows/pyroma.yml | 35 +++++++ .github/workflows/tests.yml | 50 +++++++--- .github/workflows/zpretty.yml | 40 ++++++++ base.cfg | 98 +++++++++++-------- buildout.cfg | 6 +- constraints_plone60.txt | 1 + setup.py | 1 + .../voltoplugin/editablefooter/restapi/get.py | 27 ++++- .../voltoplugin/editablefooter/testing.py | 6 +- .../tests/test_footer_columns_route.py | 49 +++++++++- test_plone52.cfg | 17 ++++ test_plone60.cfg | 10 ++ 14 files changed, 347 insertions(+), 63 deletions(-) create mode 100644 .github/workflows/black.yml create mode 100644 .github/workflows/flake8.yml create mode 100644 .github/workflows/pyroma.yml create mode 100644 .github/workflows/zpretty.yml create mode 100644 constraints_plone60.txt create mode 100644 test_plone60.cfg diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml new file mode 100644 index 0000000..d2573b6 --- /dev/null +++ b/.github/workflows/black.yml @@ -0,0 +1,35 @@ +name: Black +on: [push] +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [3.8] + + steps: + # git checkout + - uses: actions/checkout@v2 + + # python setup + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + + # python cache + - uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + # install black + - name: install black + run: pip install black==21.12b0 click==8.0.4 + + # run black + - name: run black + run: black src/ --check --diff diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml new file mode 100644 index 0000000..97c7dfa --- /dev/null +++ b/.github/workflows/flake8.yml @@ -0,0 +1,35 @@ +name: Flake8 +on: [push] +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [3.8] + + steps: + # git checkout + - uses: actions/checkout@v2 + + # python setup + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + + # python cache + - uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + # install flake8 + - name: install flake8 + run: pip install flake8 + + # run black + - name: run flake8 + run: flake8 src/ setup.py diff --git a/.github/workflows/pyroma.yml b/.github/workflows/pyroma.yml new file mode 100644 index 0000000..bbad3c2 --- /dev/null +++ b/.github/workflows/pyroma.yml @@ -0,0 +1,35 @@ +name: Pyroma +on: [push] +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [3.8] + + steps: + # git checkout + - uses: actions/checkout@v2 + + # python setup + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + + # python cache + - uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + # install pyroma + - name: install pyroma + run: pip install pyroma + + # run pyroma + - name: run pyroma + run: pyroma -n 10 -d . diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e740303..4d9c4d1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,27 +1,33 @@ name: Tests -on: [push] - +on: + push: + paths-ignore: + - '**.md' + - '**.rst' jobs: build: runs-on: ubuntu-latest strategy: max-parallel: 4 matrix: - python: ["3.7"] - plone: ["52"] - # exclude: - # - python: "3.7" - # plone: "51" + python: ["3.8", "3.9", "3.10", "3.11"] + plone: ["52", "60"] + tz: ["UTC", "Europe/Rome"] + exclude: + - python: "3.10" + plone: "52" + - python: "3.11" + plone: "52" steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Cache eggs - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: eggs key: ${{ runner.OS }}-build-python${{ matrix.python }}-${{ matrix.plone }} - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python }} - name: Install dependencies @@ -30,10 +36,32 @@ jobs: cp test_plone${{ matrix.plone }}.cfg buildout.cfg - name: Install buildout run: | - buildout -N -t 3 code-analysis:return-status-codes=True + buildout -N code-analysis:return-status-codes=True - name: Code analysis run: | bin/code-analysis - name: Run tests run: | bin/test-coverage + env: + PROXY_BEARER_AUTH: on + TZ: ${{ matrix.tz }} + - name: Upload coverage data to coveralls.io + run: | + pip install coveralls + coveralls --service=github + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_FLAG_NAME: py${{ matrix.python }}-plone${{ matrix.plone }}-tz${{ matrix.tz }} + COVERALLS_PARALLEL: true + + coveralls_finish: + needs: build + runs-on: ubuntu-latest + steps: + - name: Finished + run: | + pip install --upgrade coveralls + coveralls --service=github --finish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/zpretty.yml b/.github/workflows/zpretty.yml new file mode 100644 index 0000000..180f0e9 --- /dev/null +++ b/.github/workflows/zpretty.yml @@ -0,0 +1,40 @@ +name: zpretty +on: [push] +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [3.8] + + steps: + # git checkout + - uses: actions/checkout@v2 + + # python setup + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + + # python cache + - uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + # install zpretty + - name: install zpretty + run: pip install zpretty + + # run zpretty + - name: run zpretty + run: find src -name '*.zcml' | xargs zpretty -i + + # XXX: this doesn't work on gh actions (https://github.com/plone/plone.restapi/pull/1119/checks?check_run_id=2686474411) + # run git diff + - name: run git diff + run: git diff --exit-code diff --git a/base.cfg b/base.cfg index 0cf3628..699d188 100644 --- a/base.cfg +++ b/base.cfg @@ -9,16 +9,17 @@ parts = instance test code-analysis - coverage - test-coverage - createcoverage releaser i18ndude omelette - robot plone-helper-scripts -develop = . + zpretty + zpretty-run + createcoverage + coverage + test-coverage +develop = . [instance] recipe = plone.recipe.zope2instance @@ -31,7 +32,7 @@ eggs = Pillow redturtle.voltoplugin.editablefooter [test] -zcml-additional += +zcml-additional = = 1.8.4", "plone.restapi", "plone.app.dexterity", + "plone.volto", ], extras_require={ "test": [ diff --git a/src/redturtle/voltoplugin/editablefooter/restapi/get.py b/src/redturtle/voltoplugin/editablefooter/restapi/get.py index c1b00e8..45914f9 100644 --- a/src/redturtle/voltoplugin/editablefooter/restapi/get.py +++ b/src/redturtle/voltoplugin/editablefooter/restapi/get.py @@ -3,10 +3,19 @@ IEditableFooterSettings, ) from plone import api +from plone.registry.interfaces import IRegistry from plone.restapi.services import Service +from zope.component import getUtility from zope.interface import implementer from zope.publisher.interfaces import IPublishTraverse +try: + from plone.volto.interfaces import IVoltoSettings + + HAS_PLONE_VOLTO = True +except ImportError: + HAS_PLONE_VOLTO = False + import json @@ -22,7 +31,7 @@ def reply(self): if not record: return [] data = json.loads(record) - portal_url = api.portal.get().absolute_url() + portal_url = self.get_portal_url() for el in data or []: if isinstance(el, dict): for item in el.get("items") or []: @@ -36,3 +45,19 @@ def reply(self): 'href="/', f'href="{portal_url}/' ) return data + + def get_portal_url(self): + portal_url = api.portal.get().absolute_url() + if not HAS_PLONE_VOLTO: + return portal_url + registry = getUtility(IRegistry) + settings = registry.forInterface(IVoltoSettings, prefix="volto", check=False) + settings_frontend_domain = getattr(settings, "frontend_domain", None) + if ( + settings_frontend_domain + and settings_frontend_domain != "http://localhost:3000" + ): + portal_url = settings_frontend_domain + if portal_url.endswith("/"): + portal_url = portal_url[:-1] + return portal_url diff --git a/src/redturtle/voltoplugin/editablefooter/testing.py b/src/redturtle/voltoplugin/editablefooter/testing.py index e761025..2e74cee 100644 --- a/src/redturtle/voltoplugin/editablefooter/testing.py +++ b/src/redturtle/voltoplugin/editablefooter/testing.py @@ -9,10 +9,10 @@ import redturtle.voltoplugin.editablefooter import plone.restapi +import plone.volto class VoltoEditableFooterLayer(PloneSandboxLayer): - defaultBases = (PLONE_APP_CONTENTTYPES_FIXTURE,) def setUpZope(self, app, configurationContext): @@ -20,6 +20,7 @@ def setUpZope(self, app, configurationContext): # The z3c.autoinclude feature is disabled in the Plone fixture base # layer. self.loadZCML(package=plone.restapi) + self.loadZCML(package=plone.volto) self.loadZCML(package=redturtle.voltoplugin.editablefooter) def setUpPloneSite(self, portal): @@ -42,7 +43,6 @@ def setUpPloneSite(self, portal): class VoltoEditableFooterRestApiLayer(PloneRestApiDXLayer): - defaultBases = (PLONE_APP_CONTENTTYPES_FIXTURE,) def setUpZope(self, app, configurationContext): @@ -50,7 +50,7 @@ def setUpZope(self, app, configurationContext): app, configurationContext ) - self.loadZCML(package=plone.restapi) + self.loadZCML(package=plone.volto) self.loadZCML(package=redturtle.voltoplugin.editablefooter) def setUpPloneSite(self, portal): diff --git a/src/redturtle/voltoplugin/editablefooter/tests/test_footer_columns_route.py b/src/redturtle/voltoplugin/editablefooter/tests/test_footer_columns_route.py index afa0598..d2e236d 100644 --- a/src/redturtle/voltoplugin/editablefooter/tests/test_footer_columns_route.py +++ b/src/redturtle/voltoplugin/editablefooter/tests/test_footer_columns_route.py @@ -1,17 +1,19 @@ # -*- coding: utf-8 -*- from plone import api +from plone.app.testing import applyProfile from plone.app.testing import setRoles from plone.app.testing import SITE_OWNER_NAME from plone.app.testing import SITE_OWNER_PASSWORD from plone.app.testing import TEST_USER_ID +from plone.registry.interfaces import IRegistry from plone.restapi.testing import RelativeSession +from redturtle.voltoplugin.editablefooter.interfaces import IEditableFooterSettings from redturtle.voltoplugin.editablefooter.testing import ( VOLTO_EDITABLEFOOTER_API_FUNCTIONAL_TESTING, ) -from redturtle.voltoplugin.editablefooter.interfaces import ( - IEditableFooterSettings, -) from transaction import commit +from zope.component import getUtility + import json import unittest @@ -64,3 +66,44 @@ def test_return_json_data(self): json.dumps(result), json.dumps(self.value).replace('href=\\"/', f'href=\\"{self.portal_url}/'), ) + + +class FooterColumnsEndpointTestWithPloneVolto(FooterColumnsEndpointTest): + layer = VOLTO_EDITABLEFOOTER_API_FUNCTIONAL_TESTING + + def setUp(self): + super().setUp() + applyProfile(self.portal, "plone.volto:default") + + def test_return_json_data_with_portal_url_if_plone_volto_installed_and_not_configured( + self, + ): + response = self.api_session.get("/@footer-columns") + self.assertEqual(response.status_code, 200) + result = response.json() + # self.value has relative links, but the result should have absolute links + self.assertNotEqual(result, self.value) + self.assertEqual( + json.dumps(result), + json.dumps(self.value).replace('href=\\"/', f'href=\\"{self.portal_url}/'), + ) + + def test_return_json_data_with_frontend_domain_if_set(self): + from plone.volto.interfaces import IVoltoSettings + + registry = getUtility(IRegistry) + settings = registry.forInterface(IVoltoSettings, prefix="volto", check=False) + settings.frontend_domain = "http://foo.org" + commit() + + response = self.api_session.get("/@footer-columns") + self.assertEqual(response.status_code, 200) + result = response.json() + # self.value has relative links, but the result should have absolute links + self.assertNotEqual(result, self.value) + self.assertEqual( + json.dumps(result), + json.dumps(self.value).replace( + 'href=\\"/', f'href=\\"{settings.frontend_domain}/' + ), + ) diff --git a/test_plone52.cfg b/test_plone52.cfg index 1f4da9a..fad22a0 100644 --- a/test_plone52.cfg +++ b/test_plone52.cfg @@ -17,3 +17,20 @@ mccabe = 0.6.1 plone.recipe.codeanalysis = 3.0.1 pycodestyle = 2.7.0 pyflakes = 2.3.1 + +# Added by buildout at 2024-01-17 10:30:15.067952 + +# Required by: +# Plone==5.2.14 +# redturtle.voltoplugin.editablefooter==1.1.3.dev0 +plone.restapi = 9.1.2 + +# Required by: +# redturtle.voltoplugin.editablefooter==1.1.3.dev0 +plone.volto = 4.1.0 + +# Added by buildout at 2024-01-17 10:32:56.251199 + +# Required by: +# plone.app.caching==3.1.3 +plone.base = 1.2.0 diff --git a/test_plone60.cfg b/test_plone60.cfg new file mode 100644 index 0000000..f9b9605 --- /dev/null +++ b/test_plone60.cfg @@ -0,0 +1,10 @@ +[buildout] + +extends = + https://raw.github.com/collective/buildout.plonetest/master/test-6.0.x.cfg + https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg + base.cfg + +update-versions-file = test_plone60.cfg + +[versions] From 6e15d6153c9b3f835b62c569204475f10bd97afd Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Jan 2024 12:29:01 +0100 Subject: [PATCH 06/13] handle plone.volto frontend_domain field and fix tests --- src/redturtle/voltoplugin/editablefooter/restapi/get.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/redturtle/voltoplugin/editablefooter/restapi/get.py b/src/redturtle/voltoplugin/editablefooter/restapi/get.py index 45914f9..c7f9486 100644 --- a/src/redturtle/voltoplugin/editablefooter/restapi/get.py +++ b/src/redturtle/voltoplugin/editablefooter/restapi/get.py @@ -53,10 +53,9 @@ def get_portal_url(self): registry = getUtility(IRegistry) settings = registry.forInterface(IVoltoSettings, prefix="volto", check=False) settings_frontend_domain = getattr(settings, "frontend_domain", None) - if ( - settings_frontend_domain - and settings_frontend_domain != "http://localhost:3000" - ): + if not settings_frontend_domain: + return portal_url + if settings_frontend_domain != "http://localhost:3000": portal_url = settings_frontend_domain if portal_url.endswith("/"): portal_url = portal_url[:-1] From bea8deb642273e954db352009a18d1d392783ebd Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Jan 2024 12:30:33 +0100 Subject: [PATCH 07/13] zpretty --- .../editablefooter/browser/configure.zcml | 11 ++--- .../voltoplugin/editablefooter/configure.zcml | 9 ++-- .../editablefooter/permissions.zcml | 9 ++-- .../editablefooter/restapi/configure.zcml | 35 ++++++++------- test_plone60.cfg | 44 +++++++++++++++++++ 5 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/redturtle/voltoplugin/editablefooter/browser/configure.zcml b/src/redturtle/voltoplugin/editablefooter/browser/configure.zcml index 394259b..af01780 100644 --- a/src/redturtle/voltoplugin/editablefooter/browser/configure.zcml +++ b/src/redturtle/voltoplugin/editablefooter/browser/configure.zcml @@ -2,14 +2,15 @@ xmlns="http://namespaces.zope.org/zope" xmlns:browser="http://namespaces.zope.org/browser" xmlns:plone="http://namespaces.plone.org/plone" - i18n_domain="redturtle.voltoplugin.editablefooter"> + i18n_domain="redturtle.voltoplugin.editablefooter" + > + layer="redturtle.voltoplugin.editablefooter.interfaces.IRedturtleVoltoEditablefooterLayer" + /> diff --git a/src/redturtle/voltoplugin/editablefooter/configure.zcml b/src/redturtle/voltoplugin/editablefooter/configure.zcml index 7b9e1fc..758fbc4 100644 --- a/src/redturtle/voltoplugin/editablefooter/configure.zcml +++ b/src/redturtle/voltoplugin/editablefooter/configure.zcml @@ -3,7 +3,8 @@ xmlns:genericsetup="http://namespaces.zope.org/genericsetup" xmlns:i18n="http://namespaces.zope.org/i18n" xmlns:plone="http://namespaces.plone.org/plone" - i18n_domain="redturtle.voltoplugin.editablefooter"> + i18n_domain="redturtle.voltoplugin.editablefooter" + > @@ -15,24 +16,24 @@ - + diff --git a/src/redturtle/voltoplugin/editablefooter/permissions.zcml b/src/redturtle/voltoplugin/editablefooter/permissions.zcml index 1f79c8a..74de0f4 100644 --- a/src/redturtle/voltoplugin/editablefooter/permissions.zcml +++ b/src/redturtle/voltoplugin/editablefooter/permissions.zcml @@ -1,10 +1,11 @@ + xmlns="http://namespaces.zope.org/zope" + xmlns:zcml="http://namespaces.zope.org/zcml" + i18n_domain="plone" + > - + diff --git a/src/redturtle/voltoplugin/editablefooter/restapi/configure.zcml b/src/redturtle/voltoplugin/editablefooter/restapi/configure.zcml index e04f9dc..07b360c 100644 --- a/src/redturtle/voltoplugin/editablefooter/restapi/configure.zcml +++ b/src/redturtle/voltoplugin/editablefooter/restapi/configure.zcml @@ -1,31 +1,36 @@ + xmlns:plone="http://namespaces.plone.org/plone" + xmlns:zcml="http://namespaces.zope.org/zcml" + > + + - - - + + factory=".controlpanel.EditableFooterControlpanel" + provides="redturtle.voltoplugin.editablefooter.interfaces.IEditableFooterSettings" + name="editable-footer-settings" + /> + method="GET" + factory=".get.FooterColumns" + for="Products.CMFCore.interfaces.ISiteRoot" + permission="zope2.View" + name="@footer-columns" + /> - + diff --git a/test_plone60.cfg b/test_plone60.cfg index f9b9605..5081fdc 100644 --- a/test_plone60.cfg +++ b/test_plone60.cfg @@ -8,3 +8,47 @@ extends = update-versions-file = test_plone60.cfg [versions] + +# Added by buildout at 2024-01-17 12:29:47.135659 +build = 1.0.3 +cmarkgfm = 2022.10.27 +coverage = 7.3.2 +createcoverage = 1.5 +flake8 = 6.1.0 +flake8-coding = 1.3.2 +flake8-debugger = 4.1.2 +flake8-print = 5.0.0 +i18ndude = 6.1.0 +keyring = 24.3.0 +markdown-it-py = 3.0.0 +mccabe = 0.7.0 +mdurl = 0.1.2 +nh3 = 0.2.15 +pkginfo = 1.9.6 +plone.recipe.codeanalysis = 3.0.1 +pyflakes = 3.1.0 +pyproject-hooks = 1.0.0 +readme-renderer = 42.0 +requests-toolbelt = 1.0.0 +rfc3986 = 2.0.0 +rich = 13.7.0 +twine = 4.0.2 +zest.releaser = 9.1.1 +zpretty = 3.1.0 + +# Required by: +# plone.recipe.codeanalysis==3.0.1 +check-manifest = 0.49 + +# Required by: +# keyring==24.3.0 +jaraco.classes = 3.3.0 + +# Required by: +# jaraco.classes==3.3.0 +more-itertools = 10.1.0 + +# Required by: +# flake8-debugger==4.1.2 +# flake8-print==5.0.0 +pycodestyle = 2.11.0 From a7a53c296da2e36f64eb2d98ca1bf976e1125b41 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Jan 2024 12:32:20 +0100 Subject: [PATCH 08/13] blacked --- .../editablefooter/browser/controlpanel.py | 5 +--- .../editablefooter/restapi/deserializer.py | 16 ++++--------- .../editablefooter/restapi/serializer.py | 4 +--- .../tests/test_controlpanel_api.py | 24 ++++--------------- .../editablefooter/tests/test_setup.py | 21 ++++------------ 5 files changed, 16 insertions(+), 54 deletions(-) diff --git a/src/redturtle/voltoplugin/editablefooter/browser/controlpanel.py b/src/redturtle/voltoplugin/editablefooter/browser/controlpanel.py index a33299f..7e886a3 100644 --- a/src/redturtle/voltoplugin/editablefooter/browser/controlpanel.py +++ b/src/redturtle/voltoplugin/editablefooter/browser/controlpanel.py @@ -7,11 +7,8 @@ class EditableFooterForm(controlpanel.RegistryEditForm): - schema = IEditableFooterSettings - label = _( - "editable_footer_settings_label", default="Editable Footer Settings" - ) + label = _("editable_footer_settings_label", default="Editable Footer Settings") description = _( "editable_footer_settings_help", default="Set infos for columns in footer.", diff --git a/src/redturtle/voltoplugin/editablefooter/restapi/deserializer.py b/src/redturtle/voltoplugin/editablefooter/restapi/deserializer.py index 7e8ee79..48ee160 100644 --- a/src/redturtle/voltoplugin/editablefooter/restapi/deserializer.py +++ b/src/redturtle/voltoplugin/editablefooter/restapi/deserializer.py @@ -16,28 +16,20 @@ @implementer(IDeserializeFromJson) @adapter(IEditableFooterSettings) -class EditableFooterControlpanelDeserializeFromJson( - ControlpanelDeserializeFromJson -): +class EditableFooterControlpanelDeserializeFromJson(ControlpanelDeserializeFromJson): def __call__(self): req = json_body(self.controlpanel.request) - proxy = self.registry.forInterface( - self.schema, prefix=self.schema_prefix - ) + proxy = self.registry.forInterface(self.schema, prefix=self.schema_prefix) errors = [] data = req.get("footer_columns", {}) if not data: - errors.append( - {"message": "Missing data", "field": "footer_columns"} - ) + errors.append({"message": "Missing data", "field": "footer_columns"}) raise BadRequest(errors) try: # later we need to do some validations setattr(proxy, "footer_columns", json.dumps(data)) except ValueError as e: - errors.append( - {"message": str(e), "field": "footer_columns", "error": e} - ) + errors.append({"message": str(e), "field": "footer_columns", "error": e}) if errors: raise BadRequest(errors) diff --git a/src/redturtle/voltoplugin/editablefooter/restapi/serializer.py b/src/redturtle/voltoplugin/editablefooter/restapi/serializer.py index a845ce0..0428c16 100644 --- a/src/redturtle/voltoplugin/editablefooter/restapi/serializer.py +++ b/src/redturtle/voltoplugin/editablefooter/restapi/serializer.py @@ -14,9 +14,7 @@ @adapter(IEditableFooterSettings) class EditableFooterControlpanelSerializeToJson(ControlpanelSerializeToJson): def __call__(self): - json_data = super( - EditableFooterControlpanelSerializeToJson, self - ).__call__() + json_data = super(EditableFooterControlpanelSerializeToJson, self).__call__() conf = json_data["data"].get("footer_columns", "") if conf: json_data["data"]["footer_columns"] = json.loads(conf) diff --git a/src/redturtle/voltoplugin/editablefooter/tests/test_controlpanel_api.py b/src/redturtle/voltoplugin/editablefooter/tests/test_controlpanel_api.py index 135d7a4..d3ca613 100644 --- a/src/redturtle/voltoplugin/editablefooter/tests/test_controlpanel_api.py +++ b/src/redturtle/voltoplugin/editablefooter/tests/test_controlpanel_api.py @@ -18,7 +18,6 @@ class EditableFooterServiceTest(unittest.TestCase): - layer = VOLTO_EDITABLEFOOTER_API_FUNCTIONAL_TESTING def setUp(self): @@ -43,18 +42,13 @@ def test_controlpanel_listed(self): self.assertIn("Editable footer settings", titles) def test_route_exists(self): - response = self.api_session.get( - "/@controlpanels/editable-footer-settings" - ) + response = self.api_session.get("/@controlpanels/editable-footer-settings") self.assertEqual(response.status_code, 200) - self.assertEqual( - response.headers.get("Content-Type"), "application/json" - ) + self.assertEqual(response.headers.get("Content-Type"), "application/json") class EditableFooterServiceDeserializerTest(unittest.TestCase): - layer = VOLTO_EDITABLEFOOTER_API_FUNCTIONAL_TESTING def setUp(self): @@ -79,31 +73,23 @@ def get_record_value(self, field): return record def set_record_value(self, field, value): - api.portal.set_registry_record( - field, value, interface=IEditableFooterSettings - ) + api.portal.set_registry_record(field, value, interface=IEditableFooterSettings) commit() def test_set_wrong_data(self): - response = self.api_session.patch( - self.controlpanel_url, json={"foo": "bar"} - ) + response = self.api_session.patch(self.controlpanel_url, json={"foo": "bar"}) self.assertEqual(response.status_code, 400) def test_deserializer_convert_dict_into_json_string(self): - data = {"foo": "", "bar": 2} - self.api_session.patch( - self.controlpanel_url, json={"footer_columns": data} - ) + self.api_session.patch(self.controlpanel_url, json={"footer_columns": data}) commit() self.assertEqual( self.get_record_value(field="footer_columns"), json.dumps(data) ) def test_serializer_convert_string_into_json_object(self): - self.assertEqual(self.get_record_value(field="footer_columns"), "") value = {"foo": "bar"} self.set_record_value(field="footer_columns", value=json.dumps(value)) diff --git a/src/redturtle/voltoplugin/editablefooter/tests/test_setup.py b/src/redturtle/voltoplugin/editablefooter/tests/test_setup.py index 76689ea..e250579 100644 --- a/src/redturtle/voltoplugin/editablefooter/tests/test_setup.py +++ b/src/redturtle/voltoplugin/editablefooter/tests/test_setup.py @@ -32,9 +32,7 @@ def setUp(self): def test_product_installed(self): """Test if redturtle.voltoplugin.editablefooter is installed.""" self.assertTrue( - self.installer.isProductInstalled( - "redturtle.voltoplugin.editablefooter" - ) + self.installer.isProductInstalled("redturtle.voltoplugin.editablefooter") ) def test_browserlayer(self): @@ -44,13 +42,10 @@ def test_browserlayer(self): ) from plone.browserlayer import utils - self.assertIn( - IRedturtleVoltoEditablefooterLayer, utils.registered_layers() - ) + self.assertIn(IRedturtleVoltoEditablefooterLayer, utils.registered_layers()) class TestUninstall(unittest.TestCase): - layer = VOLTO_EDITABLEFOOTER_INTEGRATION_TESTING def setUp(self): @@ -61,17 +56,13 @@ def setUp(self): self.installer = api.portal.get_tool("portal_quickinstaller") roles_before = api.user.get_roles(TEST_USER_ID) setRoles(self.portal, TEST_USER_ID, ["Manager"]) - self.installer.uninstallProducts( - ["redturtle.voltoplugin.editablefooter"] - ) + self.installer.uninstallProducts(["redturtle.voltoplugin.editablefooter"]) setRoles(self.portal, TEST_USER_ID, roles_before) def test_product_uninstalled(self): """Test if redturtle.voltoplugin.editablefooter is cleanly uninstalled.""" self.assertFalse( - self.installer.isProductInstalled( - "redturtle.voltoplugin.editablefooter" - ) + self.installer.isProductInstalled("redturtle.voltoplugin.editablefooter") ) def test_browserlayer_removed(self): @@ -81,6 +72,4 @@ def test_browserlayer_removed(self): ) from plone.browserlayer import utils - self.assertNotIn( - IRedturtleVoltoEditablefooterLayer, utils.registered_layers() - ) + self.assertNotIn(IRedturtleVoltoEditablefooterLayer, utils.registered_layers()) From b2c7cc9865635b3eeeb53d0df7a53694fc0d1528 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Jan 2024 12:33:42 +0100 Subject: [PATCH 09/13] flake8 and pyroma --- setup.cfg | 15 +++++++++++++-- setup.py | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index e3c5e00..bd9250c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,6 +15,17 @@ line_length = 200 not_skip = __init__.py [flake8] +# black compatible flake8 rules: +ignore = + W503, + C812, + E501 + T001 + C813 +# E203, E266 exclude = bootstrap.py,docs,*.egg.,omelette -ignore = W503 -max-complexity = 15 +max-line-length = 88 +max-complexity = 18 +select = B,C,E,F,W,T4,B9 +builtins = unicode,basestring + diff --git a/setup.py b/setup.py index 97b479e..1ff2183 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,7 @@ # Get more from https://pypi.org/classifiers/ classifiers=[ "Environment :: Web Environment", + "Development Status :: 5 - Production/Stable", "Framework :: Plone", "Framework :: Plone :: Addon", "Framework :: Plone :: 5.2", From 27a96065ae41f69f309fb603e91e20dc7705cc09 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Jan 2024 12:35:58 +0100 Subject: [PATCH 10/13] fix requirements --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fa2f614..af90416 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ --c constraints_plone52.txt +pip setuptools zc.buildout +wheel From 9370dad8991ca24e5caed8b447d7bb46370a0e17 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Jan 2024 12:37:15 +0100 Subject: [PATCH 11/13] remote tz from matrix --- .github/workflows/tests.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4d9c4d1..cc4f5c2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,8 +3,8 @@ name: Tests on: push: paths-ignore: - - '**.md' - - '**.rst' + - "**.md" + - "**.rst" jobs: build: runs-on: ubuntu-latest @@ -13,7 +13,6 @@ jobs: matrix: python: ["3.8", "3.9", "3.10", "3.11"] plone: ["52", "60"] - tz: ["UTC", "Europe/Rome"] exclude: - python: "3.10" plone: "52" @@ -59,9 +58,9 @@ jobs: needs: build runs-on: ubuntu-latest steps: - - name: Finished - run: | - pip install --upgrade coveralls - coveralls --service=github --finish - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Finished + run: | + pip install --upgrade coveralls + coveralls --service=github --finish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From f76fb3507e9b67e6928b569b8d81769854480138 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Jan 2024 12:46:05 +0100 Subject: [PATCH 12/13] removed useful test --- .../editablefooter/tests/test_setup.py | 75 ------------------- 1 file changed, 75 deletions(-) delete mode 100644 src/redturtle/voltoplugin/editablefooter/tests/test_setup.py diff --git a/src/redturtle/voltoplugin/editablefooter/tests/test_setup.py b/src/redturtle/voltoplugin/editablefooter/tests/test_setup.py deleted file mode 100644 index e250579..0000000 --- a/src/redturtle/voltoplugin/editablefooter/tests/test_setup.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- -"""Setup tests for this package.""" -from redturtle.voltoplugin.editablefooter.testing import ( - VOLTO_EDITABLEFOOTER_INTEGRATION_TESTING, -) # noqa: E501 -from plone import api -from plone.app.testing import setRoles -from plone.app.testing import TEST_USER_ID - -import unittest - - -try: - from Products.CMFPlone.utils import get_installer -except ImportError: - get_installer = None - - -class TestSetup(unittest.TestCase): - """Test that redturtle.voltoplugin.editablefooter is properly installed.""" - - layer = VOLTO_EDITABLEFOOTER_INTEGRATION_TESTING - - def setUp(self): - """Custom shared utility setup for tests.""" - self.portal = self.layer["portal"] - if get_installer: - self.installer = get_installer(self.portal, self.layer["request"]) - else: - self.installer = api.portal.get_tool("portal_quickinstaller") - - def test_product_installed(self): - """Test if redturtle.voltoplugin.editablefooter is installed.""" - self.assertTrue( - self.installer.isProductInstalled("redturtle.voltoplugin.editablefooter") - ) - - def test_browserlayer(self): - """Test that IRedturtleVoltoEditablefooterLayer is registered.""" - from redturtle.voltoplugin.editablefooter.interfaces import ( - IRedturtleVoltoEditablefooterLayer, - ) - from plone.browserlayer import utils - - self.assertIn(IRedturtleVoltoEditablefooterLayer, utils.registered_layers()) - - -class TestUninstall(unittest.TestCase): - layer = VOLTO_EDITABLEFOOTER_INTEGRATION_TESTING - - def setUp(self): - self.portal = self.layer["portal"] - if get_installer: - self.installer = get_installer(self.portal, self.layer["request"]) - else: - self.installer = api.portal.get_tool("portal_quickinstaller") - roles_before = api.user.get_roles(TEST_USER_ID) - setRoles(self.portal, TEST_USER_ID, ["Manager"]) - self.installer.uninstallProducts(["redturtle.voltoplugin.editablefooter"]) - setRoles(self.portal, TEST_USER_ID, roles_before) - - def test_product_uninstalled(self): - """Test if redturtle.voltoplugin.editablefooter is cleanly uninstalled.""" - self.assertFalse( - self.installer.isProductInstalled("redturtle.voltoplugin.editablefooter") - ) - - def test_browserlayer_removed(self): - """Test that IRedturtleVoltoEditablefooterLayer is removed.""" - from redturtle.voltoplugin.editablefooter.interfaces import ( - IRedturtleVoltoEditablefooterLayer, - ) - from plone.browserlayer import utils - - self.assertNotIn(IRedturtleVoltoEditablefooterLayer, utils.registered_layers()) From 8f1b0c1ada633ea3e8bc0ddb5a2c7eb4800f0b82 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Jan 2024 13:18:14 +0100 Subject: [PATCH 13/13] fix versions --- test_plone52.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/test_plone52.cfg b/test_plone52.cfg index fad22a0..1a74d52 100644 --- a/test_plone52.cfg +++ b/test_plone52.cfg @@ -9,6 +9,7 @@ update-versions-file = test_plone52.cfg [versions] plone.testing = 7.0.1 +plone.app.caching = 3.1.3 # Added by buildout at 2021-10-11 07:50:20.464790 createcoverage = 1.5