Skip to content

Commit

Permalink
Feat: Django 4.2 support (#2)
Browse files Browse the repository at this point in the history
* Feature/cms version 4 compatible (nephila#51)

* Update compatible with Django CMS version4

sitemap.py and cms_toolbars.py updated to support page menu and sitemap compatible with Django CMS version 4


Co-authored-by: Vipul, Narang <[email protected]>

* Relese 0.9.0a1

* Fix django CMS requirements in setup.py

* Release 0.9.0dev3

* Updated lastmod() to return latest publish version modified date in cms4 (nephila#58)

* Updated lastmod() to return latest publish version modified date if versioning is enabled.



Co-authored-by: narender81 <[email protected]>

* Release 0.9.0dev4

* Release 0.9.0dev5

* Use the correct toolbar for versioning and django-cms v4 (nephila#59)

* Use the page toolbar from the CMS as this doesn't add more buttons. It's also designed fro use just on the page too

* Functioning toolbar with versioning enabled

* Added versioning test to ensure that the toolbar duplicated button issue never occurs again

* Remove limit on versioning being installed. The test suite should run the same regardless of versioning

* Release 0.9.0dev6

* Feature/list published pagecontent if versioning enabled (nephila#61)

* Add filter to list only published pages in versioning is enabled/installed
* Add test to check query performance

Co-authored-by: narender81 <[email protected]>

* Release 0.9.0dev7

* Release 0.9.0.dev8

* Initial port of tools changes

* Updated the history

* Update the test suite to cms4

* Bring the github workflows in line with the tox configuration

* Fix mismatch of python / django versions in tox and GH actions

* Fix various mismatch issues

* Removed all py2 # -*- coding: utf-8 -*-

* Use a dj 3.2 compatible version

* Removed all __future__ imports

* Removed @python_2_unicode_compatible

* Update django limitation from 3.3 to 4.0

* Fix isort failures

* Fix installation dependancies

* fixed lint failures

* Fix missing secret key for the test suite

* Fixed failing tests

* Fix deprecation notices

* Replace changelog entry with towncrier configuraton

* Fixed versioning tests

* Requirements added

* Fix merge

* Merge

* Ensure tests runs on django CMS 3 and 4

* Fix test

* Fix coverage

* fix: update workflow files

* fix: update test.yml

* fix: remove comments

* update setup.cfg

---------

Co-authored-by: vipulnarang95 <[email protected]>
Co-authored-by: Vipul, Narang <[email protected]>
Co-authored-by: Iacopo Spalletti <[email protected]>
Co-authored-by: NarenderRajuB <[email protected]>
Co-authored-by: narender81 <[email protected]>
Co-authored-by: Aiky30 <[email protected]>
Co-authored-by: Andrew Aikman <[email protected]>
Co-authored-by: Josh Yu <[email protected]>
  • Loading branch information
9 people authored Mar 27, 2024
1 parent 5c1a44f commit 3dd4ffb
Show file tree
Hide file tree
Showing 18 changed files with 319 additions and 91 deletions.
17 changes: 9 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ jobs:
continue-on-error: ${{ matrix.continue-on-error }}
strategy:
matrix:
python-version: ["3.11", "3.10", "3.9"]
django: [42, 41, 32]
cms: [311, 39]
python-version: ["3.8", "3.9", "3.10"]
django: [32, 42]
cms: [40]
requirements-file: [
dj32_cms40.txt,
dj42_cms40.txt,
]
continue-on-error: [true]
exclude:
- django: 41
cms: 39
- django: 42
cms: 39
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -40,6 +39,8 @@ jobs:
${{ runner.os }}-tox-${{ format('{{py{0}-django{1}-cms{2}}}', matrix.python-version, matrix.django, matrix.cms) }}-
- name: Install dependencies
run: |
python setup.py install
pip install -r tests/requirements/dj${{matrix.django}}_cms${{matrix.cms}}.txt
sudo apt-get install gettext
python -m pip install --upgrade pip setuptools tox>4
- name: Test with tox
Expand Down
1 change: 1 addition & 0 deletions changes/82.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for django CMS 4+
3 changes: 3 additions & 0 deletions changes/910.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* Update tooling and ci test suite to Github Actions
* Add compatibility with Django 3.2
* Drop compatibility with Django < 2.2
10 changes: 7 additions & 3 deletions cms_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ def gettext(s):


HELPER_SETTINGS = {
"NOSE_ARGS": [
"-s",
],
"CACHES": {
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
Expand All @@ -19,6 +16,7 @@ def gettext(s):
"content": 10,
"permissions": 10,
},
"CMS_CONFIRM_VERSION4": True,
"ROOT_URLCONF": "tests.test_utils.urls",
"INSTALLED_APPS": [
"django.contrib.sitemaps",
Expand Down Expand Up @@ -53,6 +51,12 @@ def gettext(s):
},
},
}
try:
import djangocms_versioning # noqa: F401

HELPER_SETTINGS["INSTALLED_APPS"].append("djangocms_versioning")
except ImportError:
pass


def run():
Expand Down
30 changes: 12 additions & 18 deletions djangocms_page_sitemap/cms_toolbars.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
from cms.api import get_page_draft
from cms.cms_toolbars import PAGE_MENU_THIRD_BREAK
from cms.toolbar.items import Break
from cms.toolbar_base import CMSToolbar
from cms.toolbar_pool import toolbar_pool
from cms.utils.conf import get_cms_setting
from cms.utils.permissions import has_page_permission
Expand All @@ -10,14 +6,20 @@

from .models import PageSitemapProperties

# Handle versioned toolbar if it exists, otherwise just use the normal CMS toolbar
try:
from djangocms_versioning.cms_toolbars import VersioningPageToolbar as PageToolbar
except ImportError:
from cms.cms_toolbars import PageToolbar


PAGE_SITEMAP_MENU_TITLE = _("Sitemap properties")


@toolbar_pool.register
class PageSitemapPropertiesMeta(CMSToolbar):
class PageSitemapPropertiesMeta(PageToolbar):
def populate(self):
# always use draft if we have a page
self.page = get_page_draft(self.request.current_page)
self.page = self.request.current_page
if not self.page:
return
if self.page.is_page_type:
Expand All @@ -36,7 +38,6 @@ def populate(self):
if has_global_current_page_change_permission or can_change:
not_edit_mode = not self.toolbar.edit_mode_active
current_page_menu = self.toolbar.get_or_create_menu("page")
position = current_page_menu.find_first(Break, identifier=PAGE_MENU_THIRD_BREAK) - 1
# Page tags
try:
page_extension = PageSitemapProperties.objects.get(extended_object_id=self.page.pk)
Expand All @@ -45,21 +46,14 @@ def populate(self):
try:
if page_extension:
url = reverse(
"admin:djangocms_page_sitemap_pagesitemapproperties_change",
args=(page_extension.pk,),
"admin:djangocms_page_sitemap_pagesitemapproperties_change", args=(page_extension.pk,)
)
else:
url = "{}?extended_object={}".format(
reverse("admin:djangocms_page_sitemap_pagesitemapproperties_add"),
self.page.pk,
reverse("admin:djangocms_page_sitemap_pagesitemapproperties_add"), self.page.pk
)
except NoReverseMatch: # pragma: no cover
# not in urls
pass
else:
current_page_menu.add_modal_item(
PAGE_SITEMAP_MENU_TITLE,
url=url,
disabled=not_edit_mode,
position=position,
)
current_page_menu.add_modal_item(PAGE_SITEMAP_MENU_TITLE, url=url, disabled=not_edit_mode)
13 changes: 3 additions & 10 deletions djangocms_page_sitemap/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@
@extension_pool.register
class PageSitemapProperties(PageExtension):
changefreq = models.CharField(
_("Change frequency"),
max_length=20,
default="monthly",
choices=PAGE_SITEMAP_CHANGEFREQ_LIST.items(),
_("Change frequency"), max_length=20, default="monthly", choices=PAGE_SITEMAP_CHANGEFREQ_LIST.items()
)
priority = models.DecimalField(
_("Priority"),
Expand All @@ -28,14 +25,10 @@ class PageSitemapProperties(PageExtension):
)
include_in_sitemap = models.BooleanField(_("Include in sitemap"), default=True)
noindex = models.BooleanField(
_("Mark as no index"),
default=False,
help_text=_("Add meta tag robots with value noindex"),
_("Mark as no index"), default=False, help_text=_("Add meta tag robots with value noindex")
)
noarchive = models.BooleanField(
_("Mark as no archive"),
default=False,
help_text=_("Add meta tag robots with value noarchive"),
_("Mark as no archive"), default=False, help_text=_("Add meta tag robots with value noarchive")
)
robots_extra = models.CharField(
_("Extra robots value"),
Expand Down
60 changes: 58 additions & 2 deletions djangocms_page_sitemap/sitemap.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,54 @@
from cms.sitemaps import CMSSitemap
from cms.utils import get_current_site
from cms.utils.i18n import get_public_languages
from django.core.cache import cache
from django.db.models import Prefetch

from .models import PageSitemapProperties
from .settings import PAGE_SITEMAP_CACHE_DURATION, PAGE_SITEMAP_DEFAULT_CHANGEFREQ
from .utils import get_cache_key
from .utils import get_cache_key, is_versioning_enabled


class ExtendedSitemap(CMSSitemap):
default_changefreq = PAGE_SITEMAP_DEFAULT_CHANGEFREQ
default_priority = CMSSitemap.priority

def items(self):
return super().items().exclude(page__pagesitemapproperties__include_in_sitemap=False)
try:
from cms.models import PageContent, PageUrl

# FIXME:This method was created from this commit:
# https://github.com/divio/django-cms/blob/2894ae8bcf92092d947a097499c01ab2bbb0e6df/cms/sitemaps/cms_sitemap.py
site = get_current_site()
languages = get_public_languages(site_id=site.pk)
page_content_prefetch = Prefetch(
"page__pagecontent_set",
queryset=PageContent.objects.filter(
language__in=languages,
),
)
all_urls = (
PageUrl.objects.get_for_site(site)
.prefetch_related(page_content_prefetch)
.filter(
language__in=languages,
path__isnull=False,
page__login_required=False,
page__node__site=site,
)
.exclude(page__pagesitemapproperties__include_in_sitemap=False)
.order_by("page__node__path")
)
valid_urls = []
for page_url in all_urls:
for page_content in page_url.page.pagecontent_set.all():
if page_url.language == page_content.language:
valid_urls.append(page_url)
break

return valid_urls
except ImportError:
return super().items().exclude(page__pagesitemapproperties__include_in_sitemap=False)

def priority(self, title):
ext_key = get_cache_key(title.page)
Expand Down Expand Up @@ -44,3 +81,22 @@ def changefreq(self, title):
return title.page.pagesitemapproperties.changefreq
except PageSitemapProperties.DoesNotExist:
return self.default_changefreq

def lastmod(self, page_url):
# if versioning is enabled we return the latest version modified using the versioning
# modified date. if versioning is disabled we return the page changed_date
if is_versioning_enabled():
from cms.models import PageContent

site = get_current_site()
page_contents = PageContent.objects.filter(
page=page_url.page,
language=page_url.language,
page__node__site=site,
).first()

if page_contents:
published_version = page_contents.versions.first()
return published_version.modified

return page_url.page.changed_date
15 changes: 15 additions & 0 deletions djangocms_page_sitemap/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from cms.cache import _get_cache_key
from django.apps import apps


def get_cache_key(page):
Expand All @@ -7,3 +8,17 @@ def get_cache_key(page):
"""
site_id = page.node.site_id
return _get_cache_key("page_sitemap", page, "default", site_id)


def is_versioning_enabled():
"""Check if djangocms-versioning plugin is installed."""
try:
from cms.models import PageContent

try:
app_config = apps.get_app_config("djangocms_versioning")
return app_config.cms_extension.is_content_model_versioned(PageContent)
except LookupError: # pragma: no cover
return False
except ImportError:
return False
4 changes: 1 addition & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ classifiers =
Framework :: Django :: 4.1
Framework :: Django :: 4.2
Programming Language :: Python :: 3
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11

[options]
include_package_data = True
Expand All @@ -36,7 +34,7 @@ install_requires =
setup_requires =
setuptools
packages = djangocms_page_sitemap
python_requires = >=3.7
python_requires = >=3.8
zip_safe = False
test_suite = cms_helper.run

Expand Down
36 changes: 34 additions & 2 deletions tests/base.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from io import StringIO

from cms.api import create_page, create_title
from cms.utils.i18n import get_language_list
from django.contrib.auth.models import User
from django.http import HttpResponse, SimpleCookie
from django.test import RequestFactory, TestCase

from djangocms_page_sitemap.utils import is_versioning_enabled


class BaseTest(TestCase):
"""
Expand All @@ -27,8 +30,14 @@ def setUpClass(cls):
cls.user_normal = User.objects.create(username="normal")

def get_pages(self):
from cms.api import create_page, create_title
try:
from cms.models import PageContent # noqa: F401

return self._cms_4_pages()
except ImportError:
return self._cms_3_pages()

def _cms_3_pages(self):
page_1 = create_page("page one", "page.html", language="en")
page_2 = create_page("page two", "page.html", language="en")
page_3 = create_page("page three", "page.html", language="en")
Expand All @@ -49,6 +58,29 @@ def get_pages(self):
page_3.get_draft_object(),
)

def _cms_4_pages(self):
from cms.models import PageContent # noqa: F401

page_1 = create_page("page one", "page.html", language="en", created_by=self.user)
page_2 = create_page("page two", "page.html", language="en", created_by=self.user)
page_3 = create_page("page three", "page.html", language="en", created_by=self.user)
page_content1 = PageContent._base_manager.get(page=page_1, language="en")
page_content2 = PageContent._base_manager.get(page=page_2, language="en")
page_content3 = PageContent._base_manager.get(page=page_3, language="en")
page_1_content_fr = create_title(language="fr", title="page un", page=page_1, created_by=self.user)
page_1_content_it = create_title(language="it", title="pagina uno", page=page_1, created_by=self.user)
page_3_content_fr = create_title(language="fr", title="page trois", page=page_3, created_by=self.user)
if is_versioning_enabled():
page_content1.versions.first().publish(self.user)
page_content2.versions.first().publish(self.user)
page_content3.versions.first().publish(self.user)
page_1_content_fr.versions.first().publish(self.user)
page_1_content_it.versions.first().publish(self.user)
page_3_content_fr.versions.first().publish(self.user)
if hasattr(page_1, "set_as_homepage"):
page_1.set_as_homepage()
return page_1, page_2, page_3

def get_request(self, page, lang):
request = self.request_factory.get(page.get_path(lang))
request.current_page = page
Expand All @@ -75,7 +107,7 @@ def get_page_request(self, page, user, path=None, edit=False, lang_code="en"):
request.GET = {"edit_off": None}
request.current_page = page
if hasattr(ToolbarMiddleware, "process_request"):
mid = ToolbarMiddleware()
mid = ToolbarMiddleware(lambda req: HttpResponse())
mid.process_request(request)
else:
mid = ToolbarMiddleware(lambda req: HttpResponse())
Expand Down
4 changes: 4 additions & 0 deletions tests/requirements/dj32_cms40.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-r requirements_base.txt

Django>=3.2,<4

4 changes: 4 additions & 0 deletions tests/requirements/dj42_cms40.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-r requirements_base.txt

Django>=4.2,<5

7 changes: 7 additions & 0 deletions tests/requirements/requirements_base.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-e .[docs]
coverage>5
coveralls>2
mock>=1.0.1
django-app-helper>=2.0.0

https://github.com/django-cms/django-cms/tarball/release/4.0.1.x#egg=django-cms
Loading

0 comments on commit 3dd4ffb

Please sign in to comment.