From b5dd2810a95bd3f2dafea68f8c0fdc382ffbdc5b Mon Sep 17 00:00:00 2001 From: David THENON Date: Thu, 17 Nov 2022 01:07:51 +0000 Subject: [PATCH] Finished DemoMaker with test and JSON data --- cookiecutter.json | 2 +- {{ cookiecutter.project_name }}/Makefile | 2 +- .../ckeditor/settings.py | 6 +-- .../djangocms/settings.py | 18 ++++---- .../webpack/settings.py | 12 +++--- .../commands/management/emencia_initial.py | 2 +- .../django-apps/project_utils/factories.py | 12 +++--- .../django-apps/project_utils/helpers.py | 32 +++++++++++++-- .../django-apps/project_utils/initial.json | 41 +++++++++++++++++++ .../project/__init__.py | 3 +- .../project/settings/__init__.py | 6 ++- .../project/settings/base.py | 2 - .../project/urls.py | 3 -- .../project/wsgi.py | 4 +- .../0050_initial.py} | 26 +++++++++++- .../tests/0100_cms/0101_factories.py | 6 +-- .../tests/1000_views/1010_index.py | 2 - .../tests/conftest.py | 14 +++++++ 18 files changed, 149 insertions(+), 44 deletions(-) create mode 100644 {{ cookiecutter.project_name }}/django-apps/project_utils/initial.json rename {{ cookiecutter.project_name }}/tests/{0100_cms/0102_helpers.py => 0010_base/0050_initial.py} (89%) diff --git a/cookiecutter.json b/cookiecutter.json index c21c982..e2cd66d 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -5,7 +5,7 @@ "version": "0.1.0", - "_bireli_version": "0.2.0-pre.12", + "_bireli_version": "0.2.0-pre.13", "_python_version": ">=3.8", "_django_version": ">=4.0,<4.1", "_project_composer_version": ">=0.6.0,<0.7.0", diff --git a/{{ cookiecutter.project_name }}/Makefile b/{{ cookiecutter.project_name }}/Makefile index 4a23449..75a7290 100644 --- a/{{ cookiecutter.project_name }}/Makefile +++ b/{{ cookiecutter.project_name }}/Makefile @@ -233,7 +233,7 @@ flake: @echo "" @printf "$(FORMATBLUE)$(FORMATBOLD)---> Flake <---$(FORMATRESET)\n" @echo "" - $(FLAKE) --statistics --show-source $(DJANGOPROJECT_DIR) django-apps tests + $(FLAKE) --statistics --show-source $(DJANGOPROJECT_DIR) django-apps tests composition_repository .PHONY: flake test: diff --git a/{{ cookiecutter.project_name }}/composition_repository/ckeditor/settings.py b/{{ cookiecutter.project_name }}/composition_repository/ckeditor/settings.py index 53368fe..355504d 100644 --- a/{{ cookiecutter.project_name }}/composition_repository/ckeditor/settings.py +++ b/{{ cookiecutter.project_name }}/composition_repository/ckeditor/settings.py @@ -85,7 +85,7 @@ def setup(cls): ["RemoveFormat"], # Disable Maximize because currently cause issue with admin-styles # fixed header - #["Maximize"], + # ["Maximize"], "/", ["Bold", "Italic", "Underline", "-", "Subscript", "Superscript"], ["JustifyLeft", "JustifyCenter", "JustifyRight"], @@ -93,8 +93,8 @@ def setup(cls): ["Link", "Unlink"], ["Image", "Youtube", "Vimeo", "-", "NumberedList", "BulletedList", "-", "Table", "-", "CreateDiv", "HorizontalRule"], - #["Iframe"], - #["Templates"], + # ["Iframe"], + # ["Templates"], ["Source"], ], }) diff --git a/{{ cookiecutter.project_name }}/composition_repository/djangocms/settings.py b/{{ cookiecutter.project_name }}/composition_repository/djangocms/settings.py index fcf7882..fbb51ec 100644 --- a/{{ cookiecutter.project_name }}/composition_repository/djangocms/settings.py +++ b/{{ cookiecutter.project_name }}/composition_repository/djangocms/settings.py @@ -32,7 +32,7 @@ class CmsBaseSettings(EnabledApplicationMarker): # Uncomment this to enable per-object user permission # See http://docs.django-cms.org/en/latest/topics/permissions.html - #CMS_PERMISSION = True + # CMS_PERMISSION = True @classmethod def post_setup(cls): @@ -101,7 +101,7 @@ def post_setup(cls): "toolbar": "CMS", "toolbar_CMS": [ ["Undo", "Redo"], - #["cmsplugins", "-", "ShowBlocks"], + # ["cmsplugins", "-", "ShowBlocks"], ["ShowBlocks"], ["Format", "Styles"], ["RemoveFormat"], @@ -110,14 +110,18 @@ def post_setup(cls): ["Bold", "Italic", "Underline", "-", "Subscript", "Superscript"], ["JustifyLeft", "JustifyCenter", "JustifyRight"], ["Link", "Unlink"], - ["Image", "Youtube", "Vimeo", "-", "NumberedList", "BulletedList", - "-", "Table", "-", "CreateDiv", "HorizontalRule"], - #["Iframe"], - #["Templates"], + [ + "Image", "Youtube", "Vimeo", "-", "NumberedList", "BulletedList", + "-", "Table", "-", "CreateDiv", "HorizontalRule" + ], + # ["Iframe"], + # ["Templates"], ["Source"], ], }) # Share the same config for djangocms_text_ckeditor field and derived # CKEditor widgets/fields from plugins - cls.CKEDITOR_SETTINGS["toolbar_HTMLField"] = cls.CKEDITOR_SETTINGS["toolbar_CMS"] + cls.CKEDITOR_SETTINGS["toolbar_HTMLField"] = ( + cls.CKEDITOR_SETTINGS["toolbar_CMS"] + ) diff --git a/{{ cookiecutter.project_name }}/composition_repository/webpack/settings.py b/{{ cookiecutter.project_name }}/composition_repository/webpack/settings.py index 3061f63..be5834c 100644 --- a/{{ cookiecutter.project_name }}/composition_repository/webpack/settings.py +++ b/{{ cookiecutter.project_name }}/composition_repository/webpack/settings.py @@ -13,10 +13,10 @@ class WebpackSettings(EnabledApplicationMarker): """ Django Webpack plugin settings - Cache is enabled by default since deployed instances are always reloaded and we don't - build frontend again until next deployment. However local development will have to - disable it else django-webpack will use the first encountered bundle hash until next - instance reload. + Cache is enabled by default since deployed instances are always reloaded and we + don't build frontend again until next deployment. However local development will + have to disable it else django-webpack will use the first encountered bundle hash + until next instance reload. """ @classmethod def setup(cls): @@ -33,7 +33,9 @@ def setup(cls): environ_name="WEBPACK_CACHE", environ_prefix=None ), - "STATS_FILE": cls.PROJECT_PATH / "static-sources" / "webpack-stats.json", + "STATS_FILE": ( + cls.PROJECT_PATH / "static-sources" / "webpack-stats.json" + ), "POLL_INTERVAL": 0.1, "IGNORE": [r".+\.hot-update.js", r".+\.map"], } diff --git a/{{ cookiecutter.project_name }}/django-apps/project_utils/commands/management/emencia_initial.py b/{{ cookiecutter.project_name }}/django-apps/project_utils/commands/management/emencia_initial.py index 4be6d04..86bd5e7 100644 --- a/{{ cookiecutter.project_name }}/django-apps/project_utils/commands/management/emencia_initial.py +++ b/{{ cookiecutter.project_name }}/django-apps/project_utils/commands/management/emencia_initial.py @@ -4,7 +4,7 @@ from django.conf import settings from django.core.management.base import CommandError, BaseCommand -from cms.api import Page, create_page +from cms.api import Page class Command(BaseCommand): diff --git a/{{ cookiecutter.project_name }}/django-apps/project_utils/factories.py b/{{ cookiecutter.project_name }}/django-apps/project_utils/factories.py index 4a39915..64a7385 100644 --- a/{{ cookiecutter.project_name }}/django-apps/project_utils/factories.py +++ b/{{ cookiecutter.project_name }}/django-apps/project_utils/factories.py @@ -1,5 +1,4 @@ from django.conf import settings -from django.contrib.auth.hashers import make_password from django.utils.text import slugify import factory @@ -122,12 +121,13 @@ def node(self): @classmethod def _after_postgeneration(cls, instance, create, results=None): """ - This hook method is called last when generating an instance from a factory. The super - method saves the instance one last time after all the "post_generation" hooks have played. + This hook method is called last when generating an instance from a factory. The + super method saves the instance one last time after all the "post_generation" + hooks have played. - This is the moment to finally publish the pages. If we published the pages before this - final "save", they would be set back to a pending state and would not be in a clean - published state. + This is the moment to finally publish the pages. If we published the pages + before this final "save", they would be set back to a pending state and would + not be in a clean published state. """ super()._after_postgeneration(instance, create, results=results) instance.rescan_placeholders() diff --git a/{{ cookiecutter.project_name }}/django-apps/project_utils/helpers.py b/{{ cookiecutter.project_name }}/django-apps/project_utils/helpers.py index 32589b6..31baa71 100644 --- a/{{ cookiecutter.project_name }}/django-apps/project_utils/helpers.py +++ b/{{ cookiecutter.project_name }}/django-apps/project_utils/helpers.py @@ -90,6 +90,9 @@ project-composer. """ +import json +from pathlib import Path + from django.conf import settings from django.core.validators import slug_re @@ -265,7 +268,7 @@ def page_creation(self, data, parent=None, level=0, created=[]): page = PageFactory(**payload) created.append(page) - level =+ 1 + level += 1 for child in data.get("children", []): self.page_creation(child, parent=page, level=level) @@ -282,8 +285,12 @@ def create(self, structure): self.global_author = structure.get("global_author") self.default_template = structure.get("default_template") + site = None + users = None + pages = None + if structure.get("site"): - self.site_update(structure["site"]) + site = self.site_update(structure["site"]) if structure.get("users"): users = self.user_creation(structure["users"]) @@ -299,4 +306,23 @@ def create(self, structure): pages = self.page_creation(structure["pages"]) self.log.info("* Created {} page(s)".format(len(pages))) - return + return { + "site": site, + "users": users, + "pages": pages, + } + + def load(self, path): + """ + Load data structure from a JSON file as given in argument and create its + objects. + + Arguments: + path (string or pathlib.Path): Path to the JSON file to load. + + Returns: + dict: Dictionnary of created objets as returned by ``DemoMaker.create()``. + """ + return self.create( + json.loads(Path(path).read_text()) + ) diff --git a/{{ cookiecutter.project_name }}/django-apps/project_utils/initial.json b/{{ cookiecutter.project_name }}/django-apps/project_utils/initial.json new file mode 100644 index 0000000..c1b9b8a --- /dev/null +++ b/{{ cookiecutter.project_name }}/django-apps/project_utils/initial.json @@ -0,0 +1,41 @@ +{ + "global_author": "emencia", + "default_template": "pages/single_column.html", + "site": { + "name": "Demo", + "domain": "demo.emencia.net" + }, + "users": { + "emencia": { + "status": "superuser", + "first_name": "Admin", + "last_name": "Staff", + "email": "contact@emencia.com", + "password": "django324" + } + }, + "pages": { + "key": "homepage", + "name": "Demo homepage", + "children": [ + { + "key": "annexes", + "name": "Annexes", + "children": [ + { + "key": "contact", + "name": "Contact" + }, + { + "key": "legal-notice", + "name": "Legal notice" + }, + { + "key": "privacy_policy", + "name": "Privacy policy" + } + ] + } + ] + } +} diff --git a/{{ cookiecutter.project_name }}/project/__init__.py b/{{ cookiecutter.project_name }}/project/__init__.py index a6ef60d..3e04f9c 100644 --- a/{{ cookiecutter.project_name }}/project/__init__.py +++ b/{{ cookiecutter.project_name }}/project/__init__.py @@ -29,7 +29,8 @@ def _extract_version(package_name): # Initialize composer with the manifest and the message processor print("🚀 Initialize composer") -_composer = Composer(Path("./pyproject.toml").resolve(), +_composer = Composer( + Path("./pyproject.toml").resolve(), processors=[ DjangoSettingsProcessor, DjangoUrlsProcessor, diff --git a/{{ cookiecutter.project_name }}/project/settings/__init__.py b/{{ cookiecutter.project_name }}/project/settings/__init__.py index 0095c70..e2bb0bf 100644 --- a/{{ cookiecutter.project_name }}/project/settings/__init__.py +++ b/{{ cookiecutter.project_name }}/project/settings/__init__.py @@ -3,6 +3,8 @@ Environments settings ===================== +TODO: Move this to the cookie docs and adjust it since some things have changed. + We use ``django-configurations`` to structure settings with a class per component and environment. @@ -40,5 +42,5 @@ use the ``setup`` and only the environment classes use the ``post_setup``. """ -from .development import Development -from .test import Test +from .development import Development # noqa: F401 +from .test import Test # noqa: F401 diff --git a/{{ cookiecutter.project_name }}/project/settings/base.py b/{{ cookiecutter.project_name }}/project/settings/base.py index 2dccae2..9c201c1 100644 --- a/{{ cookiecutter.project_name }}/project/settings/base.py +++ b/{{ cookiecutter.project_name }}/project/settings/base.py @@ -4,8 +4,6 @@ ============= """ -from pathlib import Path - from configurations import Configuration from project import _composer diff --git a/{{ cookiecutter.project_name }}/project/urls.py b/{{ cookiecutter.project_name }}/project/urls.py index ea71973..898ce58 100644 --- a/{{ cookiecutter.project_name }}/project/urls.py +++ b/{{ cookiecutter.project_name }}/project/urls.py @@ -3,10 +3,7 @@ Base Project URL configuration ============================== - """ -from pathlib import Path - from django.conf import settings from django.conf.urls.static import static from django.contrib import admin diff --git a/{{ cookiecutter.project_name }}/project/wsgi.py b/{{ cookiecutter.project_name }}/project/wsgi.py index 007fb6a..f5a5ac2 100644 --- a/{{ cookiecutter.project_name }}/project/wsgi.py +++ b/{{ cookiecutter.project_name }}/project/wsgi.py @@ -5,9 +5,9 @@ """ import os +from configurations.wsgi import get_wsgi_application + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") os.environ.setdefault("DJANGO_CONFIGURATION", "Development") -from configurations.wsgi import get_wsgi_application - application = get_wsgi_application() diff --git a/{{ cookiecutter.project_name }}/tests/0100_cms/0102_helpers.py b/{{ cookiecutter.project_name }}/tests/0010_base/0050_initial.py similarity index 89% rename from {{ cookiecutter.project_name }}/tests/0100_cms/0102_helpers.py rename to {{ cookiecutter.project_name }}/tests/0010_base/0050_initial.py index 1df1fa3..cdf1254 100644 --- a/{{ cookiecutter.project_name }}/tests/0100_cms/0102_helpers.py +++ b/{{ cookiecutter.project_name }}/tests/0010_base/0050_initial.py @@ -1,9 +1,11 @@ +""" +NOTE: Since the initials datas may change from a project to another, those tests try +to make the less assumptions possible on initial datas. +""" import logging import pytest -from django.conf import settings - from cms.api import Page from cms.utils import get_current_site @@ -235,3 +237,23 @@ def test_cms_demomaker_success(caplog, db): assert Page.objects.count() == 8 assert Page.objects.public().count() == 4 assert Page.objects.get_home().get_title() == "Demo homepage" + + +def test_cms_demomaker_fixture(caplog, db, load_initials): + """ + The Pytest fixture should load the initial data. + + We just check some content have been created with success but without to check the + contents themselves. + + This assumes there is at least a created user and page, nothing more so the + initials data may be changed. + + NOTE: This won't be safe for project without CMS. + """ + caplog.set_level(logging.DEBUG, logger="project-utils") + + User = safe_get_user_model() + assert User.objects.count() > 0 + + assert Page.objects.count() > 0 diff --git a/{{ cookiecutter.project_name }}/tests/0100_cms/0101_factories.py b/{{ cookiecutter.project_name }}/tests/0100_cms/0101_factories.py index 264d91b..daa9581 100644 --- a/{{ cookiecutter.project_name }}/tests/0100_cms/0101_factories.py +++ b/{{ cookiecutter.project_name }}/tests/0100_cms/0101_factories.py @@ -26,7 +26,7 @@ def test_cms_factory_page_root(db, client): assert page.get_title() == "Foo" assert page.get_slug() == "foo" assert page.reverse_id == "foofoo" - assert page.is_published(settings.LANGUAGE_CODE) == True + assert page.is_published(settings.LANGUAGE_CODE) is True # New root page is reachable response = client.get(page.get_absolute_url(settings.LANGUAGE_CODE), follow=True) @@ -47,8 +47,8 @@ def test_cms_factory_page_basic(db, client): assert page.get_title() == "Foo" assert page.get_slug() == "foo" - assert page.reverse_id == None - assert page.is_published(settings.LANGUAGE_CODE) == False + assert page.reverse_id is None + assert page.is_published(settings.LANGUAGE_CODE) is False # New page is not reachable since it is not published by default from factory response = client.get(page.get_absolute_url(settings.LANGUAGE_CODE), follow=True) diff --git a/{{ cookiecutter.project_name }}/tests/1000_views/1010_index.py b/{{ cookiecutter.project_name }}/tests/1000_views/1010_index.py index f55f082..6a77c99 100644 --- a/{{ cookiecutter.project_name }}/tests/1000_views/1010_index.py +++ b/{{ cookiecutter.project_name }}/tests/1000_views/1010_index.py @@ -1,5 +1,3 @@ -import pytest - from django.urls import reverse diff --git a/{{ cookiecutter.project_name }}/tests/conftest.py b/{{ cookiecutter.project_name }}/tests/conftest.py index f4dbc63..a09467d 100644 --- a/{{ cookiecutter.project_name }}/tests/conftest.py +++ b/{{ cookiecutter.project_name }}/tests/conftest.py @@ -12,6 +12,8 @@ import pytest +from project_utils import helpers + class FixturesSettingsTestMixin(object): """ @@ -81,3 +83,15 @@ def test_foo(tests_settings): print(tests_settings.format("Root: {ROOT}")) """ return FixturesSettingsTestMixin() + + +@pytest.fixture(scope="function") +def load_initials(db): + """ + Create objects from project initial structure data. + """ + maker = helpers.DemoMaker() + + return maker.load( + Path(helpers.__file__).parent / "initial.json" + )