Skip to content

Commit

Permalink
chore: Update testing, iconography, and formatting (#41)
Browse files Browse the repository at this point in the history
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
  • Loading branch information
fsbraun and sourcery-ai[bot] authored Nov 20, 2024
1 parent 88ed994 commit a9efa18
Show file tree
Hide file tree
Showing 31 changed files with 216 additions and 227 deletions.
20 changes: 11 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand All @@ -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
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
==================

Expand Down
30 changes: 14 additions & 16 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://github.com/django-cms/djangocms-transfer/issues/18>`_.

.. note::
.. note::

This project is endorsed by the `django CMS Association <https://www.django-cms.org/en/about-us/>`_.
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 <https://www.django-cms.org/slack/>`_.

.. image:: preview.gif
Expand All @@ -21,10 +22,10 @@ key relations and won't import/export related data, such as `media <https://gith
Contribute to this project and win rewards
*******************************************

Because this is a an open-source project, we welcome everyone to
Because this is an open-source project, we welcome everyone to
`get involved in the project <https://www.django-cms.org/en/contribute/>`_ and
`receive a reward <https://www.django-cms.org/en/bounty-program/>`_ for their contribution.
Become part of a fantastic community and help us make django CMS the best CMS in the world.
`receive a reward <https://www.django-cms.org/en/bounty-program/>`_ 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
Expand All @@ -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 <https://github.com/divio/djangocms-transfer/blob/master/setup.py>`_
file for additional dependencies:

|python| |django| |djangocms|


Installation
Expand Down Expand Up @@ -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/
2 changes: 1 addition & 1 deletion djangocms_transfer/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '1.0.2'
__version__ = "2.0.0a"

default_app_config = "djangocms_transfer.apps.TranferConfig"

Expand Down
16 changes: 9 additions & 7 deletions djangocms_transfer/cms_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -152,18 +151,19 @@ def import_plugins_view(cls, request):
# Page placeholders/plugins import
# TODO: Check permissions
import_form.run_import()
return HttpResponse('<div><div class="messagelist"><div class="success"></div></div></div>')
return HttpResponse(
'<div><div class="messagelist"><div class="success"></div></div></div>'
)

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('<div><div class="messagelist"><div class="success"></div></div></div>')

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

Expand All @@ -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):
Expand Down
7 changes: 4 additions & 3 deletions djangocms_transfer/cms_toolbars.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -36,7 +37,7 @@ def populate(self):
data = urlencode(
{
"language": self.current_lang,
"cms_page": obj.pk,
"cms_pagecontent": obj.pk,
}
)

Expand Down
8 changes: 2 additions & 6 deletions djangocms_transfer/compat.py
Original file line number Diff line number Diff line change
@@ -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__)
8 changes: 4 additions & 4 deletions djangocms_transfer/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)


Expand All @@ -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)
Expand Down
38 changes: 22 additions & 16 deletions djangocms_transfer/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
)
Expand All @@ -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:
Expand All @@ -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),
Expand All @@ -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):
Expand All @@ -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):
Expand All @@ -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"]

Expand Down
8 changes: 6 additions & 2 deletions djangocms_transfer/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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 = {
Expand Down
2 changes: 1 addition & 1 deletion djangocms_transfer/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions djangocms_transfer/static/djangocms_transfer/css/transfer.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Binary file not shown.
Loading

0 comments on commit a9efa18

Please sign in to comment.