From a9efa181078b2000c131bfba646ba795050c8f20 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Wed, 20 Nov 2024 14:17:32 +0100 Subject: [PATCH] chore: Update testing, iconography, and formatting (#41) Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 20 +++-- CHANGELOG.rst | 8 ++ README.rst | 30 ++++--- djangocms_transfer/__init__.py | 2 +- djangocms_transfer/cms_plugins.py | 16 ++-- djangocms_transfer/cms_toolbars.py | 7 +- djangocms_transfer/compat.py | 8 +- djangocms_transfer/exporter.py | 8 +- djangocms_transfer/forms.py | 38 +++++---- djangocms_transfer/helpers.py | 8 +- djangocms_transfer/importer.py | 2 +- .../djangocms_transfer/css/transfer.css | 10 +-- .../static/djangocms_transfer/img/icons.png | Bin 850 -> 0 bytes pyproject.toml | 77 ++++++++++++++++++ setup.cfg | 27 ------ setup.py | 56 +------------ tests/requirements/base.txt | 3 +- tests/requirements/dj30_cms38.txt | 4 - tests/requirements/dj31_cms38.txt | 4 - tests/requirements/dj32_cms310.txt | 4 - tests/requirements/dj32_cms38.txt | 4 - tests/requirements/dj41_cms311.txt | 4 - tests/requirements/dj42_cms41.txt | 4 + tests/requirements/dj50_cms41.txt | 4 + tests/requirements/dj51_cms41.txt | 4 + tests/settings.py | 3 +- tests/transfer/abstract.py | 15 ++-- tests/transfer/test_export.py | 8 +- tests/transfer/test_forms.py | 29 ++++--- tests/transfer/test_import.py | 2 +- tox.ini | 34 ++------ 31 files changed, 216 insertions(+), 227 deletions(-) delete mode 100644 djangocms_transfer/static/djangocms_transfer/img/icons.png create mode 100644 pyproject.toml delete mode 100644 setup.cfg delete mode 100644 tests/requirements/dj30_cms38.txt delete mode 100644 tests/requirements/dj31_cms38.txt delete mode 100644 tests/requirements/dj32_cms310.txt delete mode 100644 tests/requirements/dj32_cms38.txt delete mode 100644 tests/requirements/dj41_cms311.txt create mode 100644 tests/requirements/dj42_cms41.txt create mode 100644 tests/requirements/dj50_cms41.txt create mode 100644 tests/requirements/dj51_cms41.txt diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0fc0da5..6a5a2f3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,18 +8,20 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ 3.8, 3.9, ] # latest release minus two + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13"] requirements-file: [ - dj30_cms38.txt, - dj31_cms38.txt, - dj32_cms310.txt, - dj32_cms38.txt, - dj41_cms311.txt, + dj50_cms41.txt, + dj51_cms41.txt, + dj42_cms41.txt, ] os: [ - ubuntu-20.04, + ubuntu-latest, ] - + exclude: + - requirements-file: dj50_cms41.txt + python-version: 3.9 + - requirements-file: dj51_cms41.txt + python-version: 3.9 steps: - uses: actions/checkout@v1 - name: Set up Python ${{ matrix.python-version }} @@ -33,7 +35,7 @@ jobs: python setup.py install - name: Run coverage - run: coverage run setup.py test + run: coverage run tests/settings.py - name: Upload Coverage to Codecov uses: codecov/codecov-action@v1 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1675f8f..6f57765 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,14 @@ Changelog ========= +2.0.0 (2024-11-20) +================== + +* Add support for django CMS 4 +* Drop support for django CMS 3.7 - 3.11 +* Add support for Django 4.2, 5.0 and 5.1 + + 1.0.2 (2024-02-29) ================== diff --git a/README.rst b/README.rst index 9610ed7..0956d86 100644 --- a/README.rst +++ b/README.rst @@ -2,16 +2,17 @@ django CMS Transfer =================== -|pypi| |build| |coverage| +|pypi| |build| |coverage| |python| |django| |djangocms| + **django CMS Transfer** is an **experimental** package that allows you to export and import plugin data from a page or a placeholder. It does not support foreign key relations and won't import/export related data, such as `media `_. -.. note:: - +.. note:: + This project is endorsed by the `django CMS Association `_. - That means that it is officially accepted by the dCA as being in line with our roadmap vision and development/plugin policy. + That means that it is officially accepted by the dCA as being in line with our roadmap vision and development/plugin policy. Join us on `Slack `_. .. image:: preview.gif @@ -21,10 +22,10 @@ key relations and won't import/export related data, such as `media `_ and -`receive a reward `_ for their contribution. -Become part of a fantastic community and help us make django CMS the best CMS in the world. +`receive a reward `_ for their contribution. +Become part of a fantastic community and help us make django CMS the best CMS in the world. We'll be delighted to receive your feedback in the form of issues and pull requests. Before submitting your @@ -39,12 +40,11 @@ section. Documentation ============= -The setting ``DJANGO_CMS_TRANSFER_SERIALIZER`` allows to register a custom json serializer. An example for an use case could be to subclass Django's build-in python serializer and let it base64-encode inline image data base64. +The setting ``DJANGO_CMS_TRANSFER_SERIALIZER`` allows registration of a custom JSON serializer. An example use case would be subclassing Django's built-in Python serializer to base64-encode inline image data. See ``REQUIREMENTS`` in the `setup.py `_ file for additional dependencies: -|python| |django| |djangocms| Installation @@ -131,14 +131,12 @@ After this you just need to run `tools/black`. .. |pypi| image:: https://badge.fury.io/py/djangocms-transfer.svg :target: http://badge.fury.io/py/djangocms-transfer -.. |build| image:: https://travis-ci.org/divio/djangocms-transfer.svg?branch=master - :target: https://travis-ci.org/divio/djangocms-transfer -.. |coverage| image:: https://codecov.io/gh/divio/djangocms-transfer/branch/master/graph/badge.svg - :target: https://codecov.io/gh/divio/djangocms-transfer +.. |coverage| image:: https://codecov.io/gh/django-cms/djangocms-transfer/branch/master/graph/badge.svg + :target: https://codecov.io/gh/django-cms/djangocms-transfer -.. |python| image:: https://img.shields.io/badge/python-3.5+-blue.svg +.. |python| image:: https://img.shields.io/badge/python-3.9+-blue.svg :target: https://pypi.org/project/djangocms-transfer/ -.. |django| image:: https://img.shields.io/badge/django-3.0,%203.1,%203.2,%204.0,%204.1-blue.svg +.. |django| image:: https://img.shields.io/badge/django-4.2,%205.0,%205.1-blue.svg :target: https://www.djangoproject.com/ -.. |djangocms| image:: https://img.shields.io/badge/django%20CMS-3.7--3.11-blue.svg +.. |djangocms| image:: https://img.shields.io/badge/django%20CMS-4-blue.svg :target: https://www.django-cms.org/ diff --git a/djangocms_transfer/__init__.py b/djangocms_transfer/__init__.py index 8ea4d0e..ed7ba05 100644 --- a/djangocms_transfer/__init__.py +++ b/djangocms_transfer/__init__.py @@ -1,4 +1,4 @@ -__version__ = '1.0.2' +__version__ = "2.0.0a" default_app_config = "djangocms_transfer.apps.TranferConfig" diff --git a/djangocms_transfer/cms_plugins.py b/djangocms_transfer/cms_plugins.py index 4cef200..5a94d24 100644 --- a/djangocms_transfer/cms_plugins.py +++ b/djangocms_transfer/cms_plugins.py @@ -12,7 +12,6 @@ from cms.utils import get_language_from_request from cms.utils.urlutils import admin_reverse -from .compat import LTE_CMS_3_4 from .forms import ExportImportForm, PluginExportForm, PluginImportForm @@ -152,18 +151,19 @@ def import_plugins_view(cls, request): # Page placeholders/plugins import # TODO: Check permissions import_form.run_import() - return HttpResponse('
') + return HttpResponse( + '
' + ) tree_order = placeholder.get_plugin_tree_order(language, parent_id=root_id) # TODO: Check permissions import_form.run_import() - if LTE_CMS_3_4: - return HttpResponse('
') - if plugin: new_plugins = plugin.reload().get_descendants().exclude(pk__in=tree_order) - return plugin.get_plugin_class_instance().render_close_frame(request, obj=new_plugins[0]) + return plugin.get_plugin_class_instance().render_close_frame( + request, obj=new_plugins[0] + ) from cms.toolbar.utils import get_plugin_tree_as_json @@ -173,7 +173,9 @@ def import_plugins_view(cls, request): data["plugin_order"] = tree_order + ["__COPY__"] data["target_placeholder_id"] = placeholder.pk context = {"structure_data": json.dumps(data)} - return render(request, "djangocms_transfer/placeholder_close_frame.html", context) + return render( + request, "djangocms_transfer/placeholder_close_frame.html", context + ) @classmethod def export_plugins_view(cls, request): diff --git a/djangocms_transfer/cms_toolbars.py b/djangocms_transfer/cms_toolbars.py index 59e756e..bbe4d15 100644 --- a/djangocms_transfer/cms_toolbars.py +++ b/djangocms_transfer/cms_toolbars.py @@ -1,10 +1,11 @@ +from django.utils.http import urlencode +from django.utils.translation import gettext + from cms.models import PageContent from cms.toolbar_base import CMSToolbar from cms.toolbar_pool import toolbar_pool from cms.utils.page_permissions import user_can_change_page from cms.utils.urlutils import admin_reverse -from django.utils.http import urlencode -from django.utils.translation import gettext @toolbar_pool.register @@ -36,7 +37,7 @@ def populate(self): data = urlencode( { "language": self.current_lang, - "cms_page": obj.pk, + "cms_pagecontent": obj.pk, } ) diff --git a/djangocms_transfer/compat.py b/djangocms_transfer/compat.py index 643f01a..235a689 100644 --- a/djangocms_transfer/compat.py +++ b/djangocms_transfer/compat.py @@ -1,10 +1,6 @@ -from distutils.version import LooseVersion - import cms +from packaging.version import Version -cms_version = LooseVersion(cms.__version__) -LTE_CMS_3_4 = cms_version < LooseVersion("3.5") -LTE_CMS_3_5 = cms_version < LooseVersion("3.6") -GTE_CMS_3_6 = cms_version >= LooseVersion("3.6") +cms_version = Version(cms.__version__) diff --git a/djangocms_transfer/exporter.py b/djangocms_transfer/exporter.py index 9e6fd89..bcc476a 100644 --- a/djangocms_transfer/exporter.py +++ b/djangocms_transfer/exporter.py @@ -19,8 +19,8 @@ def export_placeholder(placeholder, language): return dump_json(data) -def export_page(cms_page, language): - data = get_page_export_data(cms_page, language) +def export_page(cms_pagecontent, language): + data = get_page_export_data(cms_pagecontent, language) return dump_json(data) @@ -45,9 +45,9 @@ def get_placeholder_export_data(placeholder, language): return [get_data(plugin) for plugin in helpers.get_bound_plugins(list(plugins))] -def get_page_export_data(cms_page, language): +def get_page_export_data(cms_pagecontent, language): data = [] - placeholders = cms_page.rescan_placeholders().values() + placeholders = cms_pagecontent.rescan_placeholders().values() for placeholder in list(placeholders): plugins = get_placeholder_export_data(placeholder, language) diff --git a/djangocms_transfer/forms.py b/djangocms_transfer/forms.py index c994047..4e81abe 100644 --- a/djangocms_transfer/forms.py +++ b/djangocms_transfer/forms.py @@ -44,8 +44,8 @@ class ExportImportForm(forms.Form): required=False, widget=forms.HiddenInput(), ) - cms_page = forms.ModelChoiceField( - queryset=PageContent.objects.all(), + cms_pagecontent = forms.ModelChoiceField( + queryset=PageContent.admin_manager.latest_content(), required=False, widget=forms.HiddenInput(), ) @@ -61,22 +61,28 @@ def clean(self): plugin = self.cleaned_data.get("plugin") placeholder = self.cleaned_data.get("placeholder") - cms_page = self.cleaned_data.get("cms_page") + cms_pagecontent = self.cleaned_data.get("cms_pagecontent") - if not any([plugin, placeholder, cms_page]): + if not any([plugin, placeholder, cms_pagecontent]): message = _("A plugin, placeholder or page is required.") raise forms.ValidationError(message) - if cms_page and (plugin or placeholder): - message = _("Plugins can be imported to pages, plugins or placeholders. Not all three.") + if cms_pagecontent and (plugin or placeholder): + message = _( + "Plugins can be imported to pages, plugins or placeholders. Not all three." + ) raise forms.ValidationError(message) - if placeholder and (cms_page or plugin): - message = _("Plugins can be imported to pages, plugins or placeholders. Not all three.") + if placeholder and (cms_pagecontent or plugin): + message = _( + "Plugins can be imported to pages, plugins or placeholders. Not all three." + ) raise forms.ValidationError(message) - if plugin and (cms_page or placeholder): - message = _("Plugins can be imported to pages, plugins or placeholders. Not all three.") + if plugin and (cms_pagecontent or placeholder): + message = _( + "Plugins can be imported to pages, plugins or placeholders. Not all three." + ) raise forms.ValidationError(message) if plugin: @@ -94,12 +100,12 @@ class PluginExportForm(ExportImportForm): def get_filename(self): data = self.cleaned_data language = data["language"] - page = data["cms_page"] + cms_pagecontent = data["cms_pagecontent"] plugin = data["plugin"] placeholder = data["placeholder"] - if page: - return "{}.json".format(page.page.get_slug(language=language)) + if cms_pagecontent: + return "{}.json".format(cms_pagecontent.page.get_slug(language=language)) elif placeholder and placeholder.page is not None: return "{}_{}.json".format( placeholder.page.get_slug(language=language), @@ -124,7 +130,7 @@ def run_export(self): if placeholder: return export_placeholder(placeholder, language) - return export_page(data["cms_page"], language) + return export_page(data["cms_pagecontent"], language) class PluginImportForm(ExportImportForm): @@ -143,7 +149,7 @@ def clean(self): first_item = data[0] is_placeholder = isinstance(first_item, ArchivedPlaceholder) - page_import = bool(self.cleaned_data["cms_page"]) + page_import = bool(self.cleaned_data["cms_pagecontent"]) plugins_import = not page_import if (is_placeholder and plugins_import) or (page_import and not is_placeholder): @@ -155,7 +161,7 @@ def clean(self): def run_import(self): data = self.cleaned_data language = data["language"] - target_page = data["cms_page"] + target_page = data["cms_pagecontent"] target_plugin = data["plugin"] target_placeholder = data["placeholder"] diff --git a/djangocms_transfer/helpers.py b/djangocms_transfer/helpers.py index 3c2b690..237c3c0 100644 --- a/djangocms_transfer/helpers.py +++ b/djangocms_transfer/helpers.py @@ -30,7 +30,9 @@ def get_bound_plugins(plugins): plugin_lookup[instance.pk] = instance for plugin in plugins: - parent_not_available = not plugin.parent_id or plugin.parent_id not in plugin_ids + parent_not_available = ( + not plugin.parent_id or plugin.parent_id not in plugin_ids + ) # The plugin either has no parent or needs to have a non-ghost parent valid_parent = parent_not_available or plugin.parent_id in plugin_lookup @@ -43,7 +45,9 @@ def get_plugin_data(plugin, only_meta=False): custom_data = None else: plugin_fields = get_plugin_fields(plugin.plugin_type) - _plugin_data = serializers.serialize(get_serializer_name(), (plugin,), fields=plugin_fields)[0] + _plugin_data = serializers.serialize( + get_serializer_name(), (plugin,), fields=plugin_fields + )[0] custom_data = _plugin_data["fields"] plugin_data = { diff --git a/djangocms_transfer/importer.py b/djangocms_transfer/importer.py index b39929b..55e3007 100644 --- a/djangocms_transfer/importer.py +++ b/djangocms_transfer/importer.py @@ -51,7 +51,7 @@ def import_plugins(plugins, placeholder, language, root_plugin_id=None): @transaction.atomic def import_plugins_to_page(placeholders, page, language): - page_placeholders = page.rescan_placeholders() + page_placeholders = page.rescan_placeholders(language) for archived_placeholder in placeholders: plugins = archived_placeholder.plugins diff --git a/djangocms_transfer/static/djangocms_transfer/css/transfer.css b/djangocms_transfer/static/djangocms_transfer/css/transfer.css index 117041d..30fd0d9 100644 --- a/djangocms_transfer/static/djangocms_transfer/css/transfer.css +++ b/djangocms_transfer/static/djangocms_transfer/css/transfer.css @@ -5,23 +5,23 @@ div.cms .cms-structure .cms-submenu-item a[data-icon=export]:before { display: block !important; width: 16px !important; height: 16px !important; - background-image: url('../img/icons.png') !important; - background-size: 16px 64px !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-arrow-bar-down' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1 3.5a.5.5 0 0 1 .5-.5h13a.5.5 0 0 1 0 1h-13a.5.5 0 0 1-.5-.5M8 6a.5.5 0 0 1 .5.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 .708-.708L7.5 12.293V6.5A.5.5 0 0 1 8 6'/%3E%3C/svg%3E"); top: 15px !important; + background-size: 16px 16px; overflow: hidden !important; line-height: 16px !important; min-height: 16px !important; } div.cms .cms-structure .cms-submenu-item a[data-icon=import]:before { - background-position: 0 -32px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-arrow-bar-up' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8 10a.5.5 0 0 0 .5-.5V3.707l2.146 2.147a.5.5 0 0 0 .708-.708l-3-3a.5.5 0 0 0-.708 0l-3 3a.5.5 0 1 0 .708.708L7.5 3.707V9.5a.5.5 0 0 0 .5.5m-7 2.5a.5.5 0 0 1 .5-.5h13a.5.5 0 0 1 0 1h-13a.5.5 0 0 1-.5-.5'/%3E%3C/svg%3E"); } div.cms .cms-structure .cms-submenu-item a[data-icon=export]:hover:before, div.cms .cms-structure .cms-submenu-item a[data-icon=export]:focus:before { - background-position: 0 -16px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-arrow-bar-down' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1 3.5a.5.5 0 0 1 .5-.5h13a.5.5 0 0 1 0 1h-13a.5.5 0 0 1-.5-.5M8 6a.5.5 0 0 1 .5.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 .708-.708L7.5 12.293V6.5A.5.5 0 0 1 8 6'/%3E%3C/svg%3E"); } div.cms .cms-structure .cms-submenu-item a[data-icon=import]:hover:before, div.cms .cms-structure .cms-submenu-item a[data-icon=import]:focus:before { - background-position: 0 -48px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-arrow-bar-up' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8 10a.5.5 0 0 0 .5-.5V3.707l2.146 2.147a.5.5 0 0 0 .708-.708l-3-3a.5.5 0 0 0-.708 0l-3 3a.5.5 0 1 0 .708.708L7.5 3.707V9.5a.5.5 0 0 0 .5.5m-7 2.5a.5.5 0 0 1 .5-.5h13a.5.5 0 0 1 0 1h-13a.5.5 0 0 1-.5-.5'/%3E%3C/svg%3E"); } div.cms .cms-structure.cms-structure-condensed .cms-submenu-item a[data-icon=export]:before, div.cms .cms-structure.cms-structure-condensed .cms-submenu-item a[data-icon=import]:before { diff --git a/djangocms_transfer/static/djangocms_transfer/img/icons.png b/djangocms_transfer/static/djangocms_transfer/img/icons.png deleted file mode 100644 index f3ed60b38e204a88b9178c60c3f3da83354651fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 850 zcmV-Y1FigtP)n2XYP$_;+qUhXR#e-zjj%Cm+lZ6e zwr$K#|7qqWlgWDS&c65doaC3g-A?bEVRyfs=gQ{R6%lSTeohFc&=zK!}Q1tb9q2H(|`xR zU@7Ms(1Cb0U{pdk@D>`Blq&}r1L2($RT<`>3$9=)jjHoy6R%jJ@MK=J|g4M;w~C1)!i;L=PZ`GDjDoC^`>0~~*K z`2dqeln=1H`h0*%!^#I(E&=iZ&I!Ny09*gt$&XWwumFjh4@gPL^8@nyfIL4S&kx95 ztTz^*k)vPDSYdi};N=ud$9Vo+)sY5RQ6`4wSc*!<+Z`~Azbgq(toJ}e%tJZLmz$PY zgd#C(fURr8Fd0?-{JU&uhuJJwR(S(V+JIp+njszhRaW%GD3&j+>|;5THDs89HVCJ_ zV>8y^F+b(~wYvwVpcQoZ0KerkWJVthLpBx95tYMh)Azs3e)0hg@9@_Y*;PV%73aVR z^fwH`B3SD+MqvQ@8RH^+iq%iI)|l=#DssI4#49E9Ag|=42", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "djangocms-transfer" +description = "Adds import and export of plugin data." +dependencies = [ + "django-cms>=4.1", +] +dynamic = [ "version" ] +readme = "README.rst" +requires-python = ">=3.9" +license = {text = "BSD-3-Clause"} +authors = [ + {name = "Divio AG", email = "info@divio.ch"}, +] +maintainers = [ + {name = "Django CMS Association and contributors", email = "info@django-cms.org"}, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Framework :: Django", + "Framework :: Django :: 4.2", + "Framework :: Django :: 5.0", + "Framework :: Django :: 5.1", + "Framework :: Django CMS", + "Framework :: Django CMS :: 4.1", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries", +] + +[project.urls] +Homepage = "https://github.com/django-cms/djangocms-transfer" + +[tool.setuptools] +packages = [ "djangocms_transfer" ] + +[tool.setuptools.dynamic] +version = { attr = "djangocms_transfer.__version__" } + +[tool.flake8] +max-line-length = 119 +exclude = [ + "*.egg-info", + ".eggs", + ".git", + ".settings", + ".tox", + ".venv", + "build", + "data", + "dist", + "docs", + "*migrations*", + "requirements", + "tmp" +] + +[tools.isort] +line_length = 119 +skip = ["manage.py", "*migrations*", ".tox", ".eggs", "data"] +include_trailing_comma = true +multi_line_output = 5 +lines_after_imports = 2 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 1bf3bb0..0000000 --- a/setup.cfg +++ /dev/null @@ -1,27 +0,0 @@ -[flake8] -max-line-length = 119 -exclude = - *.egg-info, - .eggs, - .git, - .settings, - .tox, - build, - data, - dist, - docs, - *migrations*, - requirements, - tmp - -[isort] -line_length = 79 -skip = manage.py, *migrations*, .tox, .eggs, data -include_trailing_comma = true -multi_line_output = 5 -lines_after_imports = 2 -default_section = THIRDPARTY -sections = FUTURE, STDLIB, DJANGO, CMS, THIRDPARTY, FIRSTPARTY, LOCALFOLDER -known_first_party = djangocms_transfer -known_cms = cms, menus -known_django = django diff --git a/setup.py b/setup.py index 3fe20f4..2598061 100644 --- a/setup.py +++ b/setup.py @@ -1,57 +1,5 @@ #!/usr/bin/env python -from setuptools import find_packages, setup +from setuptools import setup -from djangocms_transfer import __version__ - -REQUIREMENTS = [ - 'django-cms>=3.7', -] - - -CLASSIFIERS = [ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Web Environment', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Framework :: Django', - 'Framework :: Django :: 3.0', - 'Framework :: Django :: 3.1', - 'Framework :: Django :: 3.2', - 'Framework :: Django :: 4.0', - 'Framework :: Django :: 4.1', - 'Framework :: Django CMS', - 'Framework :: Django CMS :: 3.7', - 'Framework :: Django CMS :: 3.8', - 'Framework :: Django CMS :: 3.9', - 'Framework :: Django CMS :: 3.10', - 'Framework :: Django CMS :: 3.11', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - 'Topic :: Software Development', - 'Topic :: Software Development :: Libraries', -] - - -setup( - name='djangocms-transfer', - version=__version__, - author='Divio AG', - author_email='info@divio.ch', - maintainer='Django CMS Association and contributors', - maintainer_email='info@django-cms.org', - url='https://github.com/django-cms/djangocms-transfer', - license='BSD-3-Clause', - description='Adds import and export of plugin data.', - long_description=open('README.rst').read(), - packages=find_packages(), - include_package_data=True, - zip_safe=False, - install_requires=REQUIREMENTS, - classifiers=CLASSIFIERS, - test_suite='tests.settings.run', -) +setup() diff --git a/tests/requirements/base.txt b/tests/requirements/base.txt index c739b57..3939213 100644 --- a/tests/requirements/base.txt +++ b/tests/requirements/base.txt @@ -4,4 +4,5 @@ tox coverage black freezegun -djangocms-text-ckeditor +djangocms-text +pytest diff --git a/tests/requirements/dj30_cms38.txt b/tests/requirements/dj30_cms38.txt deleted file mode 100644 index 266ab69..0000000 --- a/tests/requirements/dj30_cms38.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django~=3.0.0 -django-cms~=3.8.0 diff --git a/tests/requirements/dj31_cms38.txt b/tests/requirements/dj31_cms38.txt deleted file mode 100644 index a381d13..0000000 --- a/tests/requirements/dj31_cms38.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django~=3.1.0 -django-cms~=3.8.0 diff --git a/tests/requirements/dj32_cms310.txt b/tests/requirements/dj32_cms310.txt deleted file mode 100644 index 61c3ca1..0000000 --- a/tests/requirements/dj32_cms310.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django~=3.2.0 -django-cms~=3.10.0 diff --git a/tests/requirements/dj32_cms38.txt b/tests/requirements/dj32_cms38.txt deleted file mode 100644 index 6d259e2..0000000 --- a/tests/requirements/dj32_cms38.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django~=3.2.0 -django-cms~=3.8.0 diff --git a/tests/requirements/dj41_cms311.txt b/tests/requirements/dj41_cms311.txt deleted file mode 100644 index 3a11d3e..0000000 --- a/tests/requirements/dj41_cms311.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django~=4.1.0 -django-cms~=3.11.0 diff --git a/tests/requirements/dj42_cms41.txt b/tests/requirements/dj42_cms41.txt new file mode 100644 index 0000000..4f0b9d9 --- /dev/null +++ b/tests/requirements/dj42_cms41.txt @@ -0,0 +1,4 @@ +-r base.txt + +Django>=4.2,<5.0 +django-cms>=4.1,<4.2 diff --git a/tests/requirements/dj50_cms41.txt b/tests/requirements/dj50_cms41.txt new file mode 100644 index 0000000..1c578f2 --- /dev/null +++ b/tests/requirements/dj50_cms41.txt @@ -0,0 +1,4 @@ +-r base.txt + +Django>=5.0,<5.1 +django-cms>=4.1,<4.2 diff --git a/tests/requirements/dj51_cms41.txt b/tests/requirements/dj51_cms41.txt new file mode 100644 index 0000000..3e2807c --- /dev/null +++ b/tests/requirements/dj51_cms41.txt @@ -0,0 +1,4 @@ +-r base.txt + +Django>=5.1,<5.2 +django-cms>=4.1,<4.2 diff --git a/tests/settings.py b/tests/settings.py index a601747..6b89124 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -2,7 +2,7 @@ HELPER_SETTINGS = { "INSTALLED_APPS": [ "djangocms_transfer", - "djangocms_text_ckeditor", + "djangocms_text", ], "CMS_LANGUAGES": { 1: [ @@ -15,6 +15,7 @@ "LANGUAGE_CODE": "en", "ALLOWED_HOSTS": ["localhost"], "DEFAULT_AUTO_FIELD": "django.db.models.AutoField", + "CMS_CONFIRM_VERSION4": True, } diff --git a/tests/transfer/abstract.py b/tests/transfer/abstract.py index 54e0654..cac3105 100644 --- a/tests/transfer/abstract.py +++ b/tests/transfer/abstract.py @@ -1,13 +1,14 @@ +from cms.test_utils.testcases import CMSTestCase from freezegun import freeze_time -from app_helper.base_test import BaseTestCase from cms.api import add_plugin, create_page @freeze_time("2024-02-28 00:00:00") -class FunctionalityBaseTestCase(BaseTestCase): +class FunctionalityBaseTestCase(CMSTestCase): def setUp(self): self.page = self._create_page() + self.page_content = self.page.pagecontent_set(manager="admin_manager").first() self.page.set_as_homepage() def _create_plugin(self, parent=None): @@ -31,7 +32,11 @@ def _add_plugin_to_page(self, plugin_publisher, *args, page=None, **kwargs): if page is None: page = self.page return add_plugin( - page.placeholders.get(slot="content"), + page.pagecontent_set(manager="admin_manager") + .filter(language="en") + .first() + .get_placeholders() + .get(slot="content"), plugin_publisher, "en", *args, @@ -50,10 +55,10 @@ def _get_expected_plugin_export_data(self): { "pk": 1, "creation_date": "2024-02-28T00:00:00Z", - "position": 0, + "position": 1, "plugin_type": "TextPlugin", "parent_id": None, - "data": {"body": "Hello World!"}, + "data": {'body': 'Hello World!', 'json': None, 'rte': ''}, }, ] diff --git a/tests/transfer/test_export.py b/tests/transfer/test_export.py index 8ba49ce..7ce532d 100644 --- a/tests/transfer/test_export.py +++ b/tests/transfer/test_export.py @@ -18,7 +18,7 @@ def test_export_plugin(self): self.assertEqual(self._get_expected_plugin_export_data(), actual) def test_export_placeholder(self): - placeholder = self.page.placeholders.get(slot="content") + placeholder = self.page_content.get_placeholders().get(slot="content") with self.subTest("empty placeholder"): actual = json.loads(export_placeholder(placeholder, "en")) @@ -30,13 +30,11 @@ def test_export_placeholder(self): self.assertEqual(self._get_expected_placeholder_export_data(), actual) def test_export_page(self): - page = self.page - with self.subTest("empty page"): - actual = json.loads(export_page(page, "en")) + actual = json.loads(export_page(self.page_content, "en")) self.assertEqual([{"placeholder": "content", "plugins": []}], actual) with self.subTest("page with plugin"): self._create_plugin() - actual = json.loads(export_page(page, "en")) + actual = json.loads(export_page(self.page_content, "en")) self.assertEqual(self._get_expected_page_export_data(), actual) diff --git a/tests/transfer/test_forms.py b/tests/transfer/test_forms.py index b6c0998..6171107 100644 --- a/tests/transfer/test_forms.py +++ b/tests/transfer/test_forms.py @@ -13,14 +13,13 @@ class PluginExportFormTest(FunctionalityBaseTestCase): def test_get_filename(self): - page = self.page - placeholder = page.placeholders.get(slot="content") + placeholder = self.page_content.get_placeholders().get(slot="content") plugin = self._create_plugin() data = { "plugin": plugin, "placeholder": placeholder, - "cms_page": page, + "cms_pagecontent": self.page_content, "language": "en", } @@ -30,7 +29,7 @@ def test_get_filename(self): self.assertEqual("home.json", form.get_filename()) with self.subTest("filename from placeholder"): - data["cms_page"] = None + data["cms_pagecontent"] = None form = PluginExportForm(data=data) form.clean() self.assertEqual("home_content.json", form.get_filename()) @@ -48,8 +47,7 @@ def test_get_filename(self): self.assertEqual("plugins.json", form.get_filename()) def test_validation(self): - page = self.page - placeholder = page.placeholders.get(slot="content") + placeholder = self.page_content.get_placeholders().get(slot="content") plugin = self._create_plugin() with self.subTest("language missing"): @@ -60,15 +58,17 @@ def test_validation(self): form = PluginExportForm(data={"language": "en"}) self.assertEqual(["A plugin, placeholder or page is required."], form.errors["__all__"]) - with self.subTest("cms_page + plugin given"): - form = PluginExportForm(data={"language": "en", "cms_page": page, "plugin": plugin}) + with self.subTest("cms_pagecontent + plugin given"): + form = PluginExportForm(data={"language": "en", "cms_pagecontent": self.page_content, "plugin": plugin}) self.assertEqual( ["Plugins can be imported to pages, plugins or placeholders. Not all three."], form.errors["__all__"], ) - with self.subTest("cms_page + placeholder given"): - form = PluginExportForm(data={"language": "en", "cms_page": page, "placeholder": placeholder}) + with self.subTest("cms_pagecontent + placeholder given"): + form = PluginExportForm( + data={"language": "en", "cms_pagecontent": self.page_content, "placeholder": placeholder} + ) self.assertEqual( ["Plugins can be imported to pages, plugins or placeholders. Not all three."], form.errors["__all__"], @@ -82,8 +82,7 @@ def test_validation(self): ) def test_run_export(self): - page = self.page - placeholder = page.placeholders.get(slot="content") + placeholder = self.page_content.get_placeholders().get(slot="content") plugin = self._create_plugin() data = { @@ -108,7 +107,7 @@ def test_run_export(self): self.assertEqual(self._get_expected_placeholder_export_data(), actual) with self.subTest("export page"): - data["cms_page"] = page + data["cms_pagecontent"] = self.page_content data["placeholder"] = None form = PluginExportForm(data=data) form.clean() @@ -119,7 +118,7 @@ def test_run_export(self): class PluginImportFormTest(FunctionalityBaseTestCase): def test_validation(self): page = self.page - placeholder = page.placeholders.get(slot="content") + placeholder = self.page_content.get_placeholders().get(slot="content") plugin = self._create_plugin() file_ = self._get_file() @@ -169,7 +168,7 @@ def test_run_import(self): # TODO: when setting the form, the `form.errors` is filled for "missing # import_file" although it is given/set in `data` page = self.page - placeholder = page.placeholders.get(slot="content") + placeholder = self.page_content.get_placeholders().get(slot="content") plugin = self._create_plugin() file_ = self._get_file() diff --git a/tests/transfer/test_import.py b/tests/transfer/test_import.py index d6730f4..9f90407 100644 --- a/tests/transfer/test_import.py +++ b/tests/transfer/test_import.py @@ -13,7 +13,7 @@ class ImportTest(FunctionalityBaseTestCase): def test_import(self): page = self.page - placeholder = page.placeholders.get(slot="content") + placeholder = self.page_content.get_placeholders().get(slot="content") plugin = self._create_plugin() plugin_data = ArchivedPlugin(**json.loads(export_plugin(plugin))[0]) diff --git a/tox.ini b/tox.ini index 6a5bbae..380485d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,7 @@ [tox] envlist = - flake8 - isort - black - py{38,39,310}-dj{30,31,32}-cms{38,39,310,311} - py{38,39,310}-dj{40,41}-cms{311} + py{39}-dj{42}-cms{41}, + py{310,311,312}-dj{42,50,51}-cms{41} skip_missing_interpreters=True @@ -40,16 +37,10 @@ known_django = django [testenv] deps = -r{toxinidir}/tests/requirements/base.txt - dj30: Django>=3.0,<3.1 - dj31: Django>=3.1,<3.2 - dj32: Django>=3.2,<4.0 - dj40: Django>=4.0,<4.1 - dj41: Django>=4.1,<4.2 - cms37: django-cms>=3.7,<3.8 - cms38: django-cms>=3.8,<3.9 - cms39: django-cms>=3.9,<3.10 - cms310: django-cms>=3.10,<3.11 - cms311: django-cms>=3.11,<3.12 + dj42: Django>=4.2,<5.0 + dj50: Django>=5.0,<5.1 + dj51: Django>=5.1,<5.2 + cms41: django-cms>=4.1,<4.2 commands = {envpython} --version @@ -57,16 +48,3 @@ commands = {env:COMMAND:coverage} run setup.py test {env:COMMAND:coverage} report -[testenv:flake8] -deps = flake8 -commands = flake8 djangocms_transfer - -[testenv:isort] -deps = isort -commands = isort -c --df djangocms_transfer -skip_install = true - -[testenv:black] -allowlist_externals = tools/black -deps = black -commands = tools/black --check