Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port django CMS 4 features #83

Draft
wants to merge 39 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9151e10
Feature/cms version 4 compatible (#51)
vipulnarang95 May 12, 2020
81c5e9e
Relese 0.9.0a1
yakky May 15, 2020
2e7100d
Fix django CMS requirements in setup.py
yakky May 19, 2020
a85999e
Release 0.9.0dev3
yakky May 19, 2020
a208e1e
Updated lastmod() to return latest publish version modified date in c…
NarenderRajuB Aug 8, 2020
42d5a52
Release 0.9.0dev4
yakky Aug 8, 2020
07d00b8
Release 0.9.0dev5
yakky Sep 1, 2020
4702697
Use the correct toolbar for versioning and django-cms v4 (#59)
Aiky30 Sep 25, 2020
230558c
Release 0.9.0dev6
yakky Sep 25, 2020
98e1417
Feature/list published pagecontent if versioning enabled (#61)
NarenderRajuB Nov 20, 2020
d13e299
Release 0.9.0dev7
yakky Nov 20, 2020
9846374
Release 0.9.0.dev8
yakky Nov 23, 2020
e1efa53
Initial port of tools changes
Aiky30 Dec 21, 2021
bda90b6
Updated the history
Aiky30 Dec 21, 2021
0ff3e57
Update the test suite to cms4
Aiky30 Dec 21, 2021
5b9a7d1
Bring the github workflows in line with the tox configuration
Aiky30 Dec 21, 2021
5634acd
Fix mismatch of python / django versions in tox and GH actions
Aiky30 Dec 21, 2021
15302a1
Fix various mismatch issues
Aiky30 Dec 21, 2021
0258afd
Removed all py2 # -*- coding: utf-8 -*-
Aiky30 Dec 21, 2021
8bdbe17
Use a dj 3.2 compatible version
Aiky30 Dec 21, 2021
d625403
Removed all __future__ imports
Aiky30 Dec 21, 2021
9b1cd1a
Removed @python_2_unicode_compatible
Aiky30 Dec 21, 2021
4ce98ca
Update django limitation from 3.3 to 4.0
Aiky30 Dec 22, 2021
dd1bb82
Fix isort failures
Aiky30 Dec 22, 2021
812a0f0
Fix installation dependancies
Aiky30 Dec 22, 2021
591df62
fixed lint failures
Aiky30 Dec 22, 2021
a54ae9a
Fix missing secret key for the test suite
Aiky30 Dec 22, 2021
f0a17c5
Fixed failing tests
Aiky30 Dec 22, 2021
2d4c09e
Fix deprecation notices
Aiky30 Dec 22, 2021
774ff10
Replace changelog entry with towncrier configuraton
Aiky30 Dec 22, 2021
2dfb2fc
Fixed versioning tests
Aiky30 Dec 22, 2021
acc9942
Requirements added
Aiky30 Dec 22, 2021
e8a0b70
Fix merge
yakky May 12, 2023
ce882df
Merge
yakky May 12, 2023
f561031
Merge
yakky May 12, 2023
ad03a0e
Ensure tests runs on django CMS 3 and 4
yakky May 12, 2023
1b3fbc1
Fix test
yakky May 12, 2023
fa035bb
Merge branch 'develop' into feature/issue-82-djangocms-4
yakky May 12, 2023
55dbdac
Fix coverage
yakky May 12, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ jobs:
matrix:
python-version: ["3.11", "3.10", "3.9"]
django: [42, 41, 32]
cms: [311, 39]
cms: [4, 311, 39]
continue-on-error: [true]
exclude:
- django: 41
cms: 39
- django: 42
cms: 39
- django: 41
cms: 4
- django: 42
cms: 4
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
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
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
Loading