django-cms-qe 3.7.2__py3-none-any.whl → 4.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cms_qe/boilerplates/bootstrap3/templates/cms_qe/home.html +3 -3
- cms_qe/cms_menus.py +134 -0
- cms_qe/export.py +8 -7
- cms_qe/hooks.py +96 -0
- cms_qe/ldap.py +4 -0
- cms_qe/settings/base/app.py +12 -4
- cms_qe/settings/base/cache.py +6 -4
- cms_qe/settings/base/cms.py +4 -1
- cms_qe/settings/base/database.py +7 -10
- cms_qe/settings/base/email.py +9 -11
- cms_qe/settings/base/env.py +3 -0
- cms_qe/settings/base/logging.py +2 -1
- cms_qe/settings/base/search.py +5 -1
- cms_qe/settings/base/security.py +2 -1
- cms_qe/settings/dev.py +25 -19
- cms_qe/static/cms_qe/css/fix-djangocms-admin-style.css +33 -0
- cms_qe/templates/admin/inc/extrastyle.html +2 -0
- cms_qe/templates/base.html +7 -4
- cms_qe/templates/cms_qe/alias_content_preview.html +28 -0
- cms_qe/templates/cms_qe/home.html +0 -2
- cms_qe/templates/pg_is_in_recovery_login.html +4 -0
- cms_qe/utils.py +11 -17
- cms_qe/views/test_messages.py +32 -0
- cms_qe_auth/models.py +1 -1
- cms_qe_test/cms.py +22 -5
- cms_qe_test/mail_filebased_backend.py +20 -0
- {django_cms_qe-3.7.2.dist-info → django_cms_qe-4.1.0.dist-info}/METADATA +61 -22
- {django_cms_qe-3.7.2.dist-info → django_cms_qe-4.1.0.dist-info}/RECORD +31 -28
- {django_cms_qe-3.7.2.dist-info → django_cms_qe-4.1.0.dist-info}/top_level.txt +0 -1
- example/__init__.py +0 -0
- example/settings/__init__.py +0 -0
- example/settings/aldryn_newsblog.py +0 -14
- example/settings/dev.py +0 -29
- example/settings/selenium.py +0 -10
- example/urls.py +0 -16
- example/wsgi.py +0 -16
- {django_cms_qe-3.7.2.dist-info → django_cms_qe-4.1.0.dist-info}/WHEEL +0 -0
- {django_cms_qe-3.7.2.dist-info → django_cms_qe-4.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% load static i18n cms_tags sekizai_tags %}
|
|
1
|
+
{% load static i18n cms_tags sekizai_tags djangocms_alias_tags %}
|
|
2
2
|
|
|
3
3
|
{% addtoblock "css" %}
|
|
4
4
|
<link rel="stylesheet" href="{% static "cms_qe/css/bootstrap.min.css" %}" />
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
{% block header %}
|
|
28
28
|
<header>
|
|
29
|
-
{%
|
|
29
|
+
{% static_alias "header" %}
|
|
30
30
|
</header>
|
|
31
31
|
{% endblock %}
|
|
32
32
|
{% block content %}
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
{% endblock %}
|
|
37
37
|
{% block footers %}
|
|
38
38
|
<footer>
|
|
39
|
-
{%
|
|
39
|
+
{% static_alias "footer" %}
|
|
40
40
|
</footer>
|
|
41
41
|
{% endblock %}
|
|
42
42
|
|
cms_qe/cms_menus.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from cms.cms_menus import CMSNavigationNode, get_menu_node_for_page, get_visible_nodes
|
|
2
|
+
from cms.models import EmptyPageContent, Page, PageContent, PageUrl
|
|
3
|
+
from cms.toolbar.utils import get_toolbar_from_request
|
|
4
|
+
from cms.utils.i18n import get_fallback_languages, get_public_languages, hide_untranslated, is_valid_site_language
|
|
5
|
+
from cms.utils.page import get_page_queryset
|
|
6
|
+
from django.db.models.query import Prefetch, prefetch_related_objects
|
|
7
|
+
from django.http import HttpRequest
|
|
8
|
+
from menus.base import Menu
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# This class i a copy of https://github.com/django-cms/django-cms/blob/4.1.7/cms/cms_menus.py#L199
|
|
12
|
+
# with extra function custom_menu_node.
|
|
13
|
+
class CMSMenu(Menu):
|
|
14
|
+
"""Subclass of :class:`menus.base.Menu`. Its :meth:`~menus.base.Menu.get_nodes()` creates a list of NavigationNodes
|
|
15
|
+
based on a site's :class:`cms.models.pagemodel.Page` objects.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def get_nodes(self, request):
|
|
19
|
+
site = self.renderer.site
|
|
20
|
+
lang = self.renderer.request_language
|
|
21
|
+
toolbar = get_toolbar_from_request(request)
|
|
22
|
+
|
|
23
|
+
pages = get_page_queryset(site)
|
|
24
|
+
|
|
25
|
+
if is_valid_site_language(lang, site_id=site.pk):
|
|
26
|
+
_valid_language = True
|
|
27
|
+
_hide_untranslated = hide_untranslated(lang, site.pk)
|
|
28
|
+
else:
|
|
29
|
+
_valid_language = False
|
|
30
|
+
_hide_untranslated = False
|
|
31
|
+
|
|
32
|
+
if _valid_language:
|
|
33
|
+
# The request language has been explicitly configured
|
|
34
|
+
# for the current site.
|
|
35
|
+
if _hide_untranslated:
|
|
36
|
+
fallbacks = []
|
|
37
|
+
else:
|
|
38
|
+
fallbacks = get_fallback_languages(lang, site_id=site.pk)
|
|
39
|
+
languages = [lang] + [_lang for _lang in fallbacks if _lang != lang]
|
|
40
|
+
else:
|
|
41
|
+
# The request language is not configured for the current site.
|
|
42
|
+
# Fallback to all configured public languages for the current site.
|
|
43
|
+
languages = get_public_languages(site.pk)
|
|
44
|
+
fallbacks = languages
|
|
45
|
+
|
|
46
|
+
pages = (
|
|
47
|
+
pages.filter(pagecontent_set__language__in=languages)
|
|
48
|
+
.select_related("node")
|
|
49
|
+
.order_by("node__path")
|
|
50
|
+
.distinct()
|
|
51
|
+
)
|
|
52
|
+
pages = get_visible_nodes(request, pages, site)
|
|
53
|
+
|
|
54
|
+
if not pages:
|
|
55
|
+
return []
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
homepage = [page for page in pages if page.is_home][0]
|
|
59
|
+
except IndexError:
|
|
60
|
+
homepage = None
|
|
61
|
+
|
|
62
|
+
urls_lookup = Prefetch(
|
|
63
|
+
"urls",
|
|
64
|
+
to_attr="filtered_urls",
|
|
65
|
+
queryset=PageUrl.objects.filter(language__in=languages),
|
|
66
|
+
)
|
|
67
|
+
if toolbar.edit_mode_active or toolbar.preview_mode_active:
|
|
68
|
+
# Get all translations visible in the admin for the current page
|
|
69
|
+
translations_qs = PageContent.admin_manager.current_content(language__in=languages)
|
|
70
|
+
else:
|
|
71
|
+
# Only get public translations
|
|
72
|
+
translations_qs = PageContent.objects.filter(language__in=languages)
|
|
73
|
+
translations_lookup = Prefetch(
|
|
74
|
+
"pagecontent_set",
|
|
75
|
+
to_attr="filtered_translations",
|
|
76
|
+
queryset=translations_qs,
|
|
77
|
+
)
|
|
78
|
+
prefetch_related_objects(pages, urls_lookup, translations_lookup)
|
|
79
|
+
# Build the blank title instances only once
|
|
80
|
+
blank_page_content_cache = {language: EmptyPageContent(language=language) for language in languages}
|
|
81
|
+
|
|
82
|
+
# Maps a node id to its page id
|
|
83
|
+
node_id_to_page: dict[int, int] = {}
|
|
84
|
+
|
|
85
|
+
def _page_to_node(page):
|
|
86
|
+
# EmptyPageContent is used to prevent the cms from trying
|
|
87
|
+
# to find a translation in the database
|
|
88
|
+
page.page_content_cache = blank_page_content_cache.copy()
|
|
89
|
+
|
|
90
|
+
for page_url in page.filtered_urls:
|
|
91
|
+
page.urls_cache[page_url.language] = page_url
|
|
92
|
+
|
|
93
|
+
for trans in page.filtered_translations:
|
|
94
|
+
page.page_content_cache[trans.language] = trans
|
|
95
|
+
|
|
96
|
+
menu_node = get_menu_node_for_page(
|
|
97
|
+
self.renderer,
|
|
98
|
+
page,
|
|
99
|
+
language=lang,
|
|
100
|
+
fallbacks=fallbacks,
|
|
101
|
+
endpoint=toolbar.preview_mode_active or toolbar.edit_mode_active,
|
|
102
|
+
)
|
|
103
|
+
return menu_node
|
|
104
|
+
|
|
105
|
+
menu_nodes = []
|
|
106
|
+
|
|
107
|
+
for page in pages:
|
|
108
|
+
node = page.node
|
|
109
|
+
parent_id = node_id_to_page.get(node.parent_id)
|
|
110
|
+
|
|
111
|
+
if node.parent_id and not parent_id:
|
|
112
|
+
# If the parent page is not available (unpublished, etc..)
|
|
113
|
+
# don't bother creating menu nodes for its descendants.
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
menu_node = _page_to_node(page)
|
|
117
|
+
if menu_node:
|
|
118
|
+
# Only add pages with at least one page content
|
|
119
|
+
cut_homepage = homepage and not homepage.get_in_navigation(lang)
|
|
120
|
+
|
|
121
|
+
if cut_homepage and parent_id == homepage.pk:
|
|
122
|
+
# When the homepage is hidden from navigation,
|
|
123
|
+
# we need to cut all its direct children from it.
|
|
124
|
+
menu_node.parent_id = None
|
|
125
|
+
else:
|
|
126
|
+
menu_node.parent_id = parent_id
|
|
127
|
+
menu_node = self.custom_menu_node(request, page, menu_node)
|
|
128
|
+
node_id_to_page[node.pk] = page.pk
|
|
129
|
+
menu_nodes.append(menu_node)
|
|
130
|
+
return menu_nodes
|
|
131
|
+
|
|
132
|
+
def custom_menu_node(self, request: HttpRequest, page: Page, menu_node: CMSNavigationNode) -> CMSNavigationNode:
|
|
133
|
+
menu_node.attr["page_description"] = page.get_meta_description()
|
|
134
|
+
return menu_node
|
cms_qe/export.py
CHANGED
|
@@ -137,7 +137,7 @@ def export_data(export_type, modeladmin, queryset):
|
|
|
137
137
|
if not field.auto_created or field.name == 'id'
|
|
138
138
|
]
|
|
139
139
|
|
|
140
|
-
def get_export_headers(self) -> list:
|
|
140
|
+
def get_export_headers(self, selected_fields=None) -> list:
|
|
141
141
|
"""
|
|
142
142
|
As header use verbose name which is better than database name.
|
|
143
143
|
"""
|
|
@@ -153,8 +153,8 @@ def export_data(export_type, modeladmin, queryset):
|
|
|
153
153
|
name = force_str(field.verbose_name)
|
|
154
154
|
return name
|
|
155
155
|
|
|
156
|
-
def export_field(self, field,
|
|
157
|
-
value = super().export_field(field,
|
|
156
|
+
def export_field(self, field, instance, **kwargs):
|
|
157
|
+
value = super().export_field(field, instance, **kwargs)
|
|
158
158
|
if '__proxy__' in value.__class__.__name__:
|
|
159
159
|
value = force_str(value)
|
|
160
160
|
return value
|
|
@@ -176,11 +176,11 @@ class AdminField(fields.Field):
|
|
|
176
176
|
self.get_modeladmin = lambda: modeladmin
|
|
177
177
|
super().__init__(*args, **kwds)
|
|
178
178
|
|
|
179
|
-
def get_value(self,
|
|
179
|
+
def get_value(self, instance):
|
|
180
180
|
admin_property = getattr(self.get_modeladmin(), self.attribute, None)
|
|
181
181
|
if admin_property:
|
|
182
|
-
return admin_property(
|
|
183
|
-
return super().get_value(
|
|
182
|
+
return admin_property(instance)
|
|
183
|
+
return super().get_value(instance)
|
|
184
184
|
|
|
185
185
|
|
|
186
186
|
# Taken from https://github.com/django-import-export/django-import-export/issues/525#issuecomment-303046691
|
|
@@ -197,12 +197,13 @@ class ChoicesWidget(widgets.Widget):
|
|
|
197
197
|
"""
|
|
198
198
|
self.choices = dict(choices)
|
|
199
199
|
self.revert_choices = {v: k for k, v in self.choices.items()}
|
|
200
|
+
super().__init__()
|
|
200
201
|
|
|
201
202
|
# pylint: disable=keyword-arg-before-vararg
|
|
202
203
|
def clean(self, value, row=None, *args, **kwargs):
|
|
203
204
|
"""Returns the db value given the display value"""
|
|
204
205
|
return self.revert_choices.get(value, value) if value else None
|
|
205
206
|
|
|
206
|
-
def render(self, value, obj=None):
|
|
207
|
+
def render(self, value, obj=None, **kwargs):
|
|
207
208
|
"""Returns the display value given the db value"""
|
|
208
209
|
return self.choices.get(value, '')
|
cms_qe/hooks.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from types import MethodType
|
|
2
|
+
|
|
3
|
+
from django.apps import apps
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.contrib import messages
|
|
6
|
+
from django.contrib.auth.views import LoginView
|
|
7
|
+
from django.db import InternalError, connection
|
|
8
|
+
from django.http import HttpRequest, HttpResponseRedirect
|
|
9
|
+
from django.template.response import TemplateResponse
|
|
10
|
+
from django.urls import reverse
|
|
11
|
+
from django.utils.translation import gettext_lazy as _
|
|
12
|
+
from djangocms_alias.models import AliasContent
|
|
13
|
+
from menus.menu_pool import MenuRenderer, menu_pool
|
|
14
|
+
|
|
15
|
+
from .cms_menus import CMSMenu
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def pg_is_in_recovery():
|
|
19
|
+
"""Return True when database is slave or False when database is master."""
|
|
20
|
+
with connection.cursor() as cursor:
|
|
21
|
+
if cursor.db.vendor != 'postgresql':
|
|
22
|
+
return False
|
|
23
|
+
cursor.execute("SELECT pg_is_in_recovery()")
|
|
24
|
+
return cursor.fetchone()[0]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PgIsInRecoveryLoginView(LoginView):
|
|
28
|
+
template_name = 'admin/login.html'
|
|
29
|
+
url_page_name = "login"
|
|
30
|
+
|
|
31
|
+
def get(self, request, *args, **kwargs):
|
|
32
|
+
if pg_is_in_recovery():
|
|
33
|
+
messages.add_message(request, messages.WARNING,
|
|
34
|
+
_('The database is in recovery mode. Unable to login. Try it later.'))
|
|
35
|
+
return super().get(request, *args, **kwargs)
|
|
36
|
+
|
|
37
|
+
def post(self, request, *args, **kwargs):
|
|
38
|
+
if pg_is_in_recovery():
|
|
39
|
+
messages.add_message(request, messages.ERROR, _('Login failed. The database is in recovery mode.'))
|
|
40
|
+
return HttpResponseRedirect(reverse(self.url_page_name))
|
|
41
|
+
return super().post(request, *args, **kwargs)
|
|
42
|
+
|
|
43
|
+
def get_template_names(self):
|
|
44
|
+
if pg_is_in_recovery():
|
|
45
|
+
return ['pg_is_in_recovery_login.html']
|
|
46
|
+
return self.template_name
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class PgIsInRecoveryMenuRenderer(MenuRenderer):
|
|
50
|
+
|
|
51
|
+
def __init__(self, pool, request):
|
|
52
|
+
pool.menus['CMSMenu'] = CMSMenu
|
|
53
|
+
super().__init__(pool, request)
|
|
54
|
+
|
|
55
|
+
def get_nodes(self, namespace=None, root_id=None, breadcrumb=False):
|
|
56
|
+
try:
|
|
57
|
+
return super().get_nodes(namespace, root_id, breadcrumb)
|
|
58
|
+
except InternalError:
|
|
59
|
+
if pg_is_in_recovery():
|
|
60
|
+
return []
|
|
61
|
+
raise
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def render_alias_content(request: HttpRequest, alias_content: AliasContent) -> TemplateResponse:
|
|
65
|
+
"""Render alias content with additionad css class alias-$name.
|
|
66
|
+
|
|
67
|
+
This is the same function as on the url
|
|
68
|
+
https://github.com/django-cms/djangocms-alias/blob/master/djangocms_alias/rendering.py#L4,
|
|
69
|
+
it just uses a different template. In the template, a css class is added by the alias name.
|
|
70
|
+
This is necessary so that the appropriate styles can be linked to it.
|
|
71
|
+
"""
|
|
72
|
+
template = "cms_qe/alias_content_preview.html"
|
|
73
|
+
context = {
|
|
74
|
+
"alias_content": alias_content,
|
|
75
|
+
"site_styles": settings.STYLES_FOR_ALIAS_ADMIN_PREVIEW,
|
|
76
|
+
}
|
|
77
|
+
return TemplateResponse(request, template, context)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_renderer(self, request: HttpRequest) -> PgIsInRecoveryMenuRenderer:
|
|
81
|
+
self.discover_menus()
|
|
82
|
+
return PgIsInRecoveryMenuRenderer(pool=self, request=request)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def patch_menu_pool_cachekey():
|
|
86
|
+
"""Skip exception when MenuRenderer attempts to write to read only database."""
|
|
87
|
+
menu_pool.get_renderer = MethodType(get_renderer, menu_pool)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def patch_alias():
|
|
91
|
+
"""Patch alias template preview."""
|
|
92
|
+
try:
|
|
93
|
+
extension = apps.get_app_config('cms').cms_extension
|
|
94
|
+
extension.toolbar_enabled_models[AliasContent] = render_alias_content
|
|
95
|
+
except KeyError:
|
|
96
|
+
pass
|
cms_qe/ldap.py
ADDED
cms_qe/settings/base/app.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Base settings for Django app.
|
|
3
3
|
"""
|
|
4
|
+
from .env import ENV
|
|
4
5
|
|
|
5
6
|
# Default primary key field type
|
|
6
7
|
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
|
@@ -8,8 +9,10 @@ Base settings for Django app.
|
|
|
8
9
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
|
9
10
|
|
|
10
11
|
SITE_ID = 1
|
|
12
|
+
CMS_CONFIRM_VERSION4 = True
|
|
13
|
+
DJANGOCMS_VERSIONING_ALLOW_DELETING_VERSIONS = True
|
|
11
14
|
|
|
12
|
-
INTERNAL_IPS = [
|
|
15
|
+
INTERNAL_IPS = ENV.list("INTERNAL_IPS", default=[])
|
|
13
16
|
|
|
14
17
|
META_USE_SITES = True
|
|
15
18
|
META_SITE_PROTOCOL = 'https'
|
|
@@ -47,8 +50,12 @@ INSTALLED_APPS = [
|
|
|
47
50
|
'treebeard', # Tree structure of pages and plugins.
|
|
48
51
|
'sekizai', # Static file management.
|
|
49
52
|
|
|
53
|
+
'djangocms_text',
|
|
54
|
+
'djangocms_link',
|
|
55
|
+
'djangocms_alias',
|
|
56
|
+
'djangocms_versioning',
|
|
57
|
+
|
|
50
58
|
# Other Django CMS's useful modules.
|
|
51
|
-
'djangocms_text_ckeditor',
|
|
52
59
|
'djangocms_googlemap',
|
|
53
60
|
|
|
54
61
|
# Django Filer's modules.
|
|
@@ -70,11 +77,13 @@ INSTALLED_APPS = [
|
|
|
70
77
|
'djangocms_frontend.contrib.collapse',
|
|
71
78
|
'djangocms_frontend.contrib.content',
|
|
72
79
|
'djangocms_frontend.contrib.grid',
|
|
80
|
+
'djangocms_frontend.contrib.icon',
|
|
81
|
+
'djangocms_frontend.contrib.image',
|
|
73
82
|
'djangocms_frontend.contrib.jumbotron',
|
|
74
83
|
'djangocms_frontend.contrib.link',
|
|
75
84
|
'djangocms_frontend.contrib.listgroup',
|
|
76
85
|
'djangocms_frontend.contrib.media',
|
|
77
|
-
'djangocms_frontend.contrib.
|
|
86
|
+
'djangocms_frontend.contrib.navigation',
|
|
78
87
|
'djangocms_frontend.contrib.tabs',
|
|
79
88
|
'djangocms_frontend.contrib.utilities',
|
|
80
89
|
|
|
@@ -83,7 +92,6 @@ INSTALLED_APPS = [
|
|
|
83
92
|
'constance',
|
|
84
93
|
'constance.backends.database',
|
|
85
94
|
'import_export',
|
|
86
|
-
'mailqueue',
|
|
87
95
|
|
|
88
96
|
# Aldryn forms
|
|
89
97
|
'aldryn_forms',
|
cms_qe/settings/base/cache.py
CHANGED
|
@@ -5,9 +5,11 @@ Caching setting by default in-memory without need to configure anything.
|
|
|
5
5
|
# Caching
|
|
6
6
|
# https://docs.djangoproject.com/en/4.2/topics/cache/
|
|
7
7
|
|
|
8
|
+
# https://pypi.org/project/python-environ/
|
|
9
|
+
# Supported types / cache_url
|
|
10
|
+
|
|
11
|
+
from .env import ENV
|
|
12
|
+
|
|
8
13
|
CACHES = {
|
|
9
|
-
|
|
10
|
-
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
|
11
|
-
'LOCATION': '127.0.0.1:11211',
|
|
12
|
-
}
|
|
14
|
+
"default": ENV.cache("CACHE_URL", default="pymemcache://127.0.0.1:11211"),
|
|
13
15
|
}
|
cms_qe/settings/base/cms.py
CHANGED
|
@@ -41,7 +41,7 @@ THUMBNAIL_PROCESSORS = (
|
|
|
41
41
|
'easy_thumbnails.processors.filters'
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
TEXT_ADDITIONAL_ATTRIBUTES: dict[str, set] = {"iframe": set()}
|
|
45
45
|
|
|
46
46
|
# cmsplugin_filer_folder
|
|
47
47
|
CMSPLUGIN_FILER_FOLDER_STYLE_CHOICES = (
|
|
@@ -65,3 +65,6 @@ DJANGOCMS_FRONTEND_GRID_CONTAINERS = (
|
|
|
65
65
|
("container-full", _("Full container")),
|
|
66
66
|
(" ", "----"),
|
|
67
67
|
)
|
|
68
|
+
|
|
69
|
+
# For example: ["css/bootstrap.min.css", "css/screen.css"]
|
|
70
|
+
STYLES_FOR_ALIAS_ADMIN_PREVIEW: list[str] = []
|
cms_qe/settings/base/database.py
CHANGED
|
@@ -5,15 +5,12 @@ Database settings, used PostgreSQL without auth by default.
|
|
|
5
5
|
# Database
|
|
6
6
|
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
|
|
7
7
|
|
|
8
|
+
# https://pypi.org/project/python-environ/
|
|
9
|
+
# Supported types / db_url
|
|
10
|
+
|
|
11
|
+
from .env import ENV
|
|
12
|
+
|
|
13
|
+
# Database
|
|
8
14
|
DATABASES = {
|
|
9
|
-
|
|
10
|
-
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
|
11
|
-
'NAME': 'cms_qe',
|
|
12
|
-
'USER': '',
|
|
13
|
-
'PASSWORD': '',
|
|
14
|
-
'HOST': '',
|
|
15
|
-
'OPTIONS': {
|
|
16
|
-
'application_name': 'cms_qe',
|
|
17
|
-
}
|
|
18
|
-
}
|
|
15
|
+
"default": ENV.db("DATABASE_URL", default='postgres://qe_user:password@/cms_qe'),
|
|
19
16
|
}
|
cms_qe/settings/base/email.py
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Mailing settings, by default app looks for smtp server.
|
|
3
3
|
"""
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
DEFAULT_FROM_EMAIL = 'django_cms_qe@localhost'
|
|
4
|
+
from .env import ENV
|
|
5
|
+
|
|
6
|
+
EMAIL_HOST = ENV.str("EMAIL_HOST", default="localhost")
|
|
7
|
+
EMAIL_HOST_USER = ENV.str("EMAIL_USER", default="")
|
|
8
|
+
EMAIL_HOST_PASSWORD = ENV.str("EMAIL_PASSWORD", default="")
|
|
9
|
+
EMAIL_PORT = ENV.int("EMAIL_PORT", default=587) # TLS uses usually 587, not 22
|
|
10
|
+
EMAIL_USE_TLS = ENV.bool("EMAIL_USE_TLS", default=False)
|
|
11
|
+
EMAIL_SUBJECT_PREFIX = ENV.str("EMAIL_SUBJECT_PREFIX", default="") # Remove Django default prefix
|
|
12
|
+
DEFAULT_FROM_EMAIL = ENV.str("DEFAULT_FROM_EMAIL", default="django_cms_qe@localhost")
|
cms_qe/settings/base/logging.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Logging settings with base formatters and handlers.
|
|
3
3
|
"""
|
|
4
|
+
from .env import ENV
|
|
4
5
|
|
|
5
6
|
# Logging
|
|
6
7
|
# https://docs.djangoproject.com/en/1.11/topics/logging/
|
|
@@ -49,7 +50,7 @@ LOGGING = {
|
|
|
49
50
|
'propagate': True,
|
|
50
51
|
},
|
|
51
52
|
'': {
|
|
52
|
-
'level':
|
|
53
|
+
'level': ENV.str("LOGGER", default="ERROR"),
|
|
53
54
|
'handlers': ['console'],
|
|
54
55
|
},
|
|
55
56
|
}
|
cms_qe/settings/base/search.py
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
|
+
from .env import ENV
|
|
5
|
+
|
|
4
6
|
site_resolver = Path(__file__).resolve()
|
|
5
7
|
|
|
6
8
|
PROJECT_DIR = site_resolver.parent.parent.parent.parent
|
|
7
9
|
|
|
8
10
|
HAYSTACK_ROUTERS = ['aldryn_search.router.LanguageRouter']
|
|
9
11
|
HAYSTACK_ENGINE = 'cms_qe.whoosh.backend.AnalyzerWhooshEngine'
|
|
10
|
-
_HAYSTACK_PATH = os.path.normpath(os.path.join(PROJECT_DIR, 'whoosh_index'))
|
|
12
|
+
_HAYSTACK_PATH = ENV.str('HAYSTACK_PATH', default=os.path.normpath(os.path.join(PROJECT_DIR, 'whoosh_index')))
|
|
11
13
|
HAYSTACK_CONNECTIONS = {
|
|
12
14
|
'default': {'ENGINE': HAYSTACK_ENGINE, 'PATH': os.path.join(_HAYSTACK_PATH, 'default')},
|
|
13
15
|
'en': {'ENGINE': HAYSTACK_ENGINE, 'PATH': os.path.join(_HAYSTACK_PATH, 'en')},
|
|
14
16
|
}
|
|
15
17
|
HAYSTACK_CUSTOM_HIGHLIGHTER = "cms_qe.haystack.highlighting.HaystackHighlighter"
|
|
18
|
+
|
|
19
|
+
ALDRYN_NEWSBLOG_UPDATE_SEARCH_DATA_ON_SAVE = True
|
cms_qe/settings/base/security.py
CHANGED
|
@@ -41,10 +41,11 @@ authorization by one of those options (more about that in `documentation
|
|
|
41
41
|
AXES_NUM_PROXIES = 1
|
|
42
42
|
|
|
43
43
|
"""
|
|
44
|
+
from .env import ENV
|
|
44
45
|
|
|
45
46
|
# Cookies.
|
|
46
47
|
|
|
47
|
-
SESSION_COOKIE_NAME =
|
|
48
|
+
SESSION_COOKIE_NAME = ENV.str("SESSION_COOKIE_NAME", default="sessionid")
|
|
48
49
|
SESSION_COOKIE_SECURE = True
|
|
49
50
|
|
|
50
51
|
# Secure headers.
|
cms_qe/settings/dev.py
CHANGED
|
@@ -8,6 +8,7 @@ import os
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
10
|
from .base import * # noqa: F401,F403 pylint: disable=wildcard-import,unused-wildcard-import
|
|
11
|
+
from .base.env import ENV
|
|
11
12
|
|
|
12
13
|
# Quick-start development settings - unsuitable for production
|
|
13
14
|
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
|
@@ -16,7 +17,7 @@ DEBUG = True
|
|
|
16
17
|
|
|
17
18
|
META_SITE_PROTOCOL = 'http'
|
|
18
19
|
|
|
19
|
-
SECRET_KEY =
|
|
20
|
+
SECRET_KEY = ENV.str("SECRET_KEY", default='secret')
|
|
20
21
|
|
|
21
22
|
SESSION_COOKIE_SECURE = False
|
|
22
23
|
|
|
@@ -38,30 +39,35 @@ MIDDLEWARE += [ # noqa: F405
|
|
|
38
39
|
site_resolver = Path(__file__).resolve()
|
|
39
40
|
|
|
40
41
|
PROJECT_DIR = site_resolver.parent.parent.parent
|
|
42
|
+
RUN_SITE_DIR = os.environ.get("VENV_PATH", PROJECT_DIR)
|
|
41
43
|
|
|
42
|
-
STATIC_ROOT = os.path.join(PROJECT_DIR, 'staticfiles')
|
|
44
|
+
STATIC_ROOT = ENV.str("STATIC_ROOT", default=os.path.join(PROJECT_DIR, 'staticfiles'))
|
|
45
|
+
MEDIA_ROOT = ENV.str("MEDIA_ROOT", default=os.path.join(RUN_SITE_DIR, 'media'))
|
|
43
46
|
|
|
44
47
|
# Caching
|
|
45
|
-
# https://docs.djangoproject.com/en/1.11/topics/cache/
|
|
46
|
-
|
|
47
48
|
CACHES = {
|
|
48
|
-
|
|
49
|
-
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
|
|
50
|
-
'LOCATION': os.path.join(PROJECT_DIR, 'django_cache'),
|
|
51
|
-
}
|
|
49
|
+
"default": ENV.cache("CACHE_URL", default=f'filecache://{os.path.join(RUN_SITE_DIR, "django_cache")}')
|
|
52
50
|
}
|
|
53
51
|
|
|
54
52
|
# Database
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
DATABASES = {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
database_path = os.path.join(RUN_SITE_DIR, 'db.sqlite3')
|
|
54
|
+
database_url_default = f"sqlite:///{database_path}" # pylint: disable=C0103
|
|
55
|
+
DATABASES = {"default": ENV.db("DATABASE_URL", default=database_url_default)}
|
|
56
|
+
|
|
57
|
+
EMAIL_BACKEND = 'cms_qe_test.mail_filebased_backend.EmlEmailBackend'
|
|
58
|
+
EMAIL_FILE_PATH = ENV.str("EMAIL_FILE_PATH", default=os.path.join(RUN_SITE_DIR, 'django_mails'))
|
|
59
|
+
|
|
60
|
+
ALDRYN_FORMS_SUBMISSION_LIST_DISPLAY_FIELD = "aldryn_forms.admin.display_form_submission_data"
|
|
61
|
+
|
|
62
|
+
SITE_API_ROOT = "/api/v1/"
|
|
63
|
+
|
|
64
|
+
REST_FRAMEWORK = {
|
|
65
|
+
'EXCEPTION_HANDLER': 'cms_qe.api.utils.exception_handler',
|
|
66
|
+
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
# API views: [("path/", "module.api.views.RecordViewSet", "api-records"), ...]
|
|
70
|
+
API_VIEWS = [
|
|
71
|
+
('aldryn-forms/forms', 'aldryn_forms.api.views.FormViewSet', 'aldryn-forms-form'),
|
|
72
|
+
('aldryn-forms/submitssions', 'aldryn_forms.api.views.SubmissionsViewSet', 'aldryn-forms-submitssions'),
|
|
73
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
form .selector-chosen-title {
|
|
2
|
+
background-color: #00bbff;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
fieldset .fieldset-heading,
|
|
6
|
+
fieldset .inline-heading,
|
|
7
|
+
:not(.inline-related) .collapse summary {
|
|
8
|
+
background-color: #00bbff !important;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
fieldset h2.fieldset-heading {
|
|
12
|
+
color: white !important;
|
|
13
|
+
background-color: #00bbff !important;
|
|
14
|
+
font-weight: bold !important;
|
|
15
|
+
padding-left: 1em !important;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.selector .selector-chooser button.selector-add,
|
|
19
|
+
.selector .selector-chooser button.selector-remove {
|
|
20
|
+
width: 38px !important;
|
|
21
|
+
height: 32px !important;
|
|
22
|
+
padding: 0.4em 1em 1em 0.5em !important;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:enabled.selector-add,
|
|
26
|
+
:enabled.selector-remove {
|
|
27
|
+
opacity: 1 !important;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.selector .selector-available button.selector-chooseall,
|
|
31
|
+
.selector .selector-chosen button.selector-clearall {
|
|
32
|
+
height: 32px !important;
|
|
33
|
+
}
|
cms_qe/templates/base.html
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% load i18n static cms_tags sekizai_tags %}
|
|
1
|
+
{% load i18n static cms_tags djangocms_alias_tags menu_tags sekizai_tags %}
|
|
2
2
|
{# Doctype is important for Django CMS so it can correctly detect height of window. #}
|
|
3
3
|
<!DOCTYPE html>
|
|
4
4
|
<html lang="{{ LANGUAGE_CODE }}">
|
|
@@ -9,17 +9,20 @@
|
|
|
9
9
|
{% include 'cms_qe/include/head.html' %}
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
|
-
{% include 'cms_qe/include/body_top.html' %}
|
|
13
12
|
{% cms_toolbar %}
|
|
13
|
+
{% block menu %}
|
|
14
|
+
<menu>{% show_menu 0 100 100 100 %}</menu>
|
|
15
|
+
{% endblock %}
|
|
16
|
+
{% include 'cms_qe/include/body_top.html' %}
|
|
14
17
|
{% block header %}
|
|
15
18
|
<header>
|
|
16
|
-
{%
|
|
19
|
+
{% static_alias "header" %}
|
|
17
20
|
</header>
|
|
18
21
|
{% endblock %}
|
|
19
22
|
{% block content %}{% endblock %}
|
|
20
23
|
{% block footers %}
|
|
21
24
|
<footer>
|
|
22
|
-
{%
|
|
25
|
+
{% static_alias "footer" %}
|
|
23
26
|
</footer>
|
|
24
27
|
{% endblock %}
|
|
25
28
|
{% include "cms_qe/include/body_bottom.html" %}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{% extends "djangocms_alias/base.html" %}
|
|
2
|
+
{% load i18n cms_tags static %}
|
|
3
|
+
|
|
4
|
+
{% if site_styles %}
|
|
5
|
+
{% block extrastyle %}
|
|
6
|
+
{{ block.super }}
|
|
7
|
+
{% for path in site_styles %}
|
|
8
|
+
<link rel="stylesheet" href="{% static path %}">
|
|
9
|
+
{% endfor %}
|
|
10
|
+
{% endblock %}
|
|
11
|
+
{% block base_css %}
|
|
12
|
+
{{ block.super }}
|
|
13
|
+
{% for path in site_styles %}
|
|
14
|
+
<link rel="stylesheet" href="{% static path %}">
|
|
15
|
+
{% endfor %}
|
|
16
|
+
{% endblock %}
|
|
17
|
+
{% endif %}
|
|
18
|
+
|
|
19
|
+
{% block aliases_content %}
|
|
20
|
+
<div class="cms-aliases-page container alias-{{ alias_content.name|slugify }}">
|
|
21
|
+
<h2 class="cms-aliases-page-heading" id="{{ alias_content.name|slugify }}">
|
|
22
|
+
<span class="cms-aliases-page-heading-inner">Alias: {{ alias_content.name }}</span>
|
|
23
|
+
</h2>
|
|
24
|
+
<div class="cms-aliases-detail">
|
|
25
|
+
{% render_placeholder alias_content.placeholder %}
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
{% endblock aliases_content %}
|
cms_qe/utils.py
CHANGED
|
@@ -5,41 +5,35 @@ from typing import Optional, Union
|
|
|
5
5
|
from django.apps import apps
|
|
6
6
|
from django.conf import settings
|
|
7
7
|
from django.contrib.sites.shortcuts import get_current_site
|
|
8
|
+
from django.core.mail import EmailMultiAlternatives
|
|
8
9
|
from django.template import TemplateDoesNotExist
|
|
9
10
|
from django.template.loader import get_template
|
|
10
|
-
from mailqueue.models import MailerMessage
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
# pylint:disable=invalid-name
|
|
14
14
|
def get_email(template: str, subject: str, to: Union[str, Iterable[str]], from_email: Optional[str] = None, **kwargs):
|
|
15
15
|
"""
|
|
16
|
-
Returns a ``
|
|
17
|
-
message or put it to a mailqueue.
|
|
16
|
+
Returns a ``EmailMultiAlternatives`` instance from ``django.core.mail``.
|
|
18
17
|
|
|
19
18
|
Template should be without extension and you should create both ``.txt`` and ``.html`` version.
|
|
20
19
|
Second one is not mandatory but is good to provide it as well.
|
|
21
20
|
|
|
22
21
|
"""
|
|
23
|
-
|
|
24
|
-
email = MailerMessage()
|
|
25
|
-
email.subject = subject
|
|
26
|
-
email.from_address = from_email or settings.DEFAULT_FROM_EMAIL
|
|
27
|
-
|
|
28
|
-
if isinstance(to, str):
|
|
29
|
-
to = [to]
|
|
30
|
-
email.to_address = ', '.join(to)
|
|
31
|
-
|
|
32
22
|
template_txt = get_template(template + '.txt')
|
|
33
|
-
content = template_txt.render(kwargs)
|
|
34
|
-
email.content = content
|
|
35
23
|
|
|
24
|
+
msg = EmailMultiAlternatives(
|
|
25
|
+
subject,
|
|
26
|
+
template_txt.render(kwargs),
|
|
27
|
+
from_email or settings.DEFAULT_FROM_EMAIL,
|
|
28
|
+
[to] if isinstance(to, str) else to,
|
|
29
|
+
)
|
|
36
30
|
try:
|
|
37
31
|
template_html = get_template(template + '.html')
|
|
32
|
+
msg.attach_alternative(template_html.render(kwargs), "text/html")
|
|
38
33
|
except TemplateDoesNotExist:
|
|
39
|
-
|
|
40
|
-
email.html_content = template_html.render(kwargs)
|
|
34
|
+
pass
|
|
41
35
|
|
|
42
|
-
return
|
|
36
|
+
return msg
|
|
43
37
|
|
|
44
38
|
|
|
45
39
|
def get_base_url(request) -> str:
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
from cms_qe.views.test_messages import TestMessagesView
|
|
3
|
+
|
|
4
|
+
urlpatterns = [
|
|
5
|
+
path("test-messages/", TestMessagesView.as_view(), name='test-messages'),
|
|
6
|
+
]
|
|
7
|
+
"""
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from django.contrib import messages
|
|
11
|
+
from django.http import HttpResponseRedirect
|
|
12
|
+
from django.views.generic import RedirectView
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestMessagesView(RedirectView):
|
|
16
|
+
"""Test messages view."""
|
|
17
|
+
|
|
18
|
+
def get_redirect_url(self, *args: Any, **kwargs: Any) -> HttpResponseRedirect:
|
|
19
|
+
"""Prepare message and redirect to the next."""
|
|
20
|
+
msg = self.request.GET.get("msg", "Test message. ?type=all / debug / info / success / warning / error")
|
|
21
|
+
messages.set_level(self.request, messages.DEBUG)
|
|
22
|
+
if self.request.GET.get("type") in ("debug", "all"):
|
|
23
|
+
messages.debug(self.request, msg)
|
|
24
|
+
if self.request.GET.get("type") in ("info", "all"):
|
|
25
|
+
messages.info(self.request, msg)
|
|
26
|
+
if self.request.GET.get("type") in ("success", "all"):
|
|
27
|
+
messages.success(self.request, msg)
|
|
28
|
+
if self.request.GET.get("type") in ("warning", "all"):
|
|
29
|
+
messages.warning(self.request, msg)
|
|
30
|
+
if self.request.GET.get("type") in ("error", "all"):
|
|
31
|
+
messages.error(self.request, msg)
|
|
32
|
+
return self.request.GET.get("next", "/")
|
cms_qe_auth/models.py
CHANGED
cms_qe_test/cms.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
from cms import api
|
|
2
|
-
from cms.models import Placeholder
|
|
2
|
+
from cms.models import PageContent, Placeholder
|
|
3
3
|
from cms.plugin_rendering import ContentRenderer
|
|
4
|
+
from cms.toolbar.toolbar import CMSToolbar
|
|
5
|
+
from django.contrib.auth import get_user_model
|
|
4
6
|
from django.contrib.auth.models import AnonymousUser
|
|
5
7
|
from django.contrib.messages.storage.fallback import FallbackStorage
|
|
6
8
|
from django.test import RequestFactory
|
|
9
|
+
from djangocms_versioning.constants import DRAFT, PUBLISHED
|
|
10
|
+
from djangocms_versioning.models import Version
|
|
7
11
|
from sekizai.context import SekizaiContext
|
|
8
12
|
|
|
9
13
|
|
|
@@ -11,6 +15,7 @@ def render_plugin(plugin, path='/', **data):
|
|
|
11
15
|
placeholder = Placeholder.objects.create(slot='test')
|
|
12
16
|
model_instance = api.add_plugin(placeholder, plugin, 'en', **data)
|
|
13
17
|
request = generate_get_request(path)
|
|
18
|
+
request.toolbar = CMSToolbar(request)
|
|
14
19
|
renderer = ContentRenderer(request=request)
|
|
15
20
|
context = SekizaiContext()
|
|
16
21
|
context.update({'request': request, })
|
|
@@ -35,16 +40,28 @@ def generate_post_request(path='', body=None):
|
|
|
35
40
|
|
|
36
41
|
|
|
37
42
|
# pylint: disable=dangerous-default-value
|
|
38
|
-
def create_page(title, language='en', page_params={}):
|
|
39
|
-
page_params.setdefault('published', True)
|
|
43
|
+
def create_page(title, language='en', page_params={}, state="publish"):
|
|
40
44
|
page_params.setdefault('overwrite_url', page_params.get('slug'))
|
|
41
|
-
|
|
45
|
+
page = api.create_page(title, 'cms_qe/home.html', language, **page_params)
|
|
46
|
+
content = PageContent.admin_manager.get(page=page)
|
|
47
|
+
user, _ = get_user_model().objects.get_or_create(username="tester")
|
|
48
|
+
version = content.versions.last()
|
|
49
|
+
if version is None:
|
|
50
|
+
version_state = PUBLISHED if state == "publish" else DRAFT
|
|
51
|
+
Version.objects.create(content=content, created_by=user, state=version_state)
|
|
52
|
+
else:
|
|
53
|
+
getattr(version, state)(user) # version.publish(user) / version.unpublish(user)
|
|
54
|
+
return page
|
|
42
55
|
|
|
43
56
|
|
|
44
57
|
# pylint: disable=dangerous-default-value
|
|
45
58
|
def create_text_page(title, language='en', page_params={}, plugin_params={}):
|
|
46
59
|
plugin_params.setdefault('body', 'shello')
|
|
47
60
|
page = create_page(title, language, page_params)
|
|
48
|
-
placeholder = page.
|
|
61
|
+
placeholder = page.get_placeholders(language).filter(slot="content").get()
|
|
49
62
|
api.add_plugin(placeholder, 'TextPlugin', language, **plugin_params)
|
|
50
63
|
return page
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def create_draft_page(title, language='en', page_params={}, state="unpublish"):
|
|
67
|
+
return create_page(title, language, page_params=page_params, state=state)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Same as django.core.mail.backends.filebased.EmailBackend, but save logs with .eml extension.
|
|
2
|
+
import datetime
|
|
3
|
+
import os
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from django.core.mail.backends.filebased import EmailBackend
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EmlEmailBackend(EmailBackend):
|
|
10
|
+
"""Save logs with .eml extension."""
|
|
11
|
+
|
|
12
|
+
_fname: Optional[str]
|
|
13
|
+
|
|
14
|
+
def _get_filename(self):
|
|
15
|
+
"""Return a unique file name."""
|
|
16
|
+
if self._fname is None:
|
|
17
|
+
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
|
18
|
+
fname = "%s-%s.eml" % (timestamp, abs(id(self)))
|
|
19
|
+
self._fname = os.path.join(self.file_path, fname)
|
|
20
|
+
return self._fname
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-cms-qe
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.1.0
|
|
4
4
|
Summary: Django CMS Quick & Easy provides all important modules to run new page withouta lot of coding. Aims to do it very easily and securely.
|
|
5
5
|
Home-page: https://websites.pages.nic.cz/django-cms-qe
|
|
6
6
|
Author: CZ.NIC, z.s.p.o.
|
|
@@ -23,36 +23,41 @@ Classifier: Framework :: Django :: 4.0
|
|
|
23
23
|
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
24
24
|
Classifier: Topic :: Software Development
|
|
25
25
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
26
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
License-File: LICENSE
|
|
29
|
-
Requires-Dist: django~=4.
|
|
30
|
-
Requires-Dist: django-
|
|
29
|
+
Requires-Dist: django-cms~=4.1
|
|
30
|
+
Requires-Dist: django-filer~=3.3
|
|
31
|
+
Requires-Dist: djangocms-admin-style~=3.3
|
|
32
|
+
Requires-Dist: djangocms-alias~=2.0
|
|
33
|
+
Requires-Dist: djangocms-frontend~=2.1
|
|
34
|
+
Requires-Dist: djangocms-text~=0.8
|
|
35
|
+
Requires-Dist: djangocms-versioning~=2.3
|
|
31
36
|
Requires-Dist: easy-thumbnails[svg]~=2.10
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist: django-
|
|
34
|
-
Requires-Dist:
|
|
35
|
-
Requires-Dist: django-
|
|
36
|
-
Requires-Dist: django-
|
|
37
|
-
Requires-Dist: djangocms-file~=3.0
|
|
38
|
-
Requires-Dist: django-import-export~=3.2
|
|
39
|
-
Requires-Dist: django-mail-queue==3.2.5
|
|
40
|
-
Requires-Dist: djangocms-icon~=2.0
|
|
41
|
-
Requires-Dist: djangocms-googlemap~=2.0
|
|
37
|
+
Requires-Dist: argon2-cffi~=23.1
|
|
38
|
+
Requires-Dist: django-axes~=8.0
|
|
39
|
+
Requires-Dist: django-constance~=4.3
|
|
40
|
+
Requires-Dist: django-csp~=4.0
|
|
41
|
+
Requires-Dist: django-import-export~=4.3
|
|
42
42
|
Requires-Dist: django-tablib~=3.2
|
|
43
|
+
Requires-Dist: djangocms-file~=3.0
|
|
44
|
+
Requires-Dist: djangocms-googlemap~=2.2
|
|
45
|
+
Requires-Dist: djangocms-icon~=2.1
|
|
46
|
+
Requires-Dist: djangocms-link~=5.0
|
|
47
|
+
Requires-Dist: djangocms-picture~=4.1
|
|
48
|
+
Requires-Dist: python-environ~=0.4
|
|
49
|
+
Requires-Dist: django-haystack~=3.3
|
|
50
|
+
Requires-Dist: djangocms-aldryn-forms[captcha]~=8.0
|
|
51
|
+
Requires-Dist: djangocms-aldryn-search~=3.0
|
|
43
52
|
Requires-Dist: mailchimp3~=3.0
|
|
44
|
-
Requires-Dist: argon2-cffi~=21.3
|
|
45
|
-
Requires-Dist: djangocms-aldryn-forms[captcha]~=7.7
|
|
46
|
-
Requires-Dist: djangocms-aldryn-search~=2.0
|
|
47
|
-
Requires-Dist: django-haystack~=3.2
|
|
48
|
-
Requires-Dist: pymemcache~=4.0
|
|
49
53
|
Requires-Dist: whoosh~=2.7
|
|
50
|
-
Requires-Dist:
|
|
51
|
-
Requires-Dist: markdown~=3.8
|
|
54
|
+
Requires-Dist: Markdown~=3.8
|
|
52
55
|
Requires-Dist: django-filter~=25.1
|
|
53
56
|
Requires-Dist: django-rest-knox~=5.0
|
|
57
|
+
Requires-Dist: djangorestframework~=3.16
|
|
54
58
|
Requires-Dist: drf-spectacular~=0.28
|
|
55
59
|
Provides-Extra: dev
|
|
60
|
+
Requires-Dist: django-simple-captcha~=0.5; extra == "dev"
|
|
56
61
|
Requires-Dist: django-debug-toolbar~=4.1; extra == "dev"
|
|
57
62
|
Requires-Dist: django-extensions~=3.2; extra == "dev"
|
|
58
63
|
Provides-Extra: test
|
|
@@ -62,6 +67,7 @@ Requires-Dist: mypy; extra == "test"
|
|
|
62
67
|
Requires-Dist: pylint; extra == "test"
|
|
63
68
|
Requires-Dist: pylint-django; extra == "test"
|
|
64
69
|
Requires-Dist: pytest~=6.2; extra == "test"
|
|
70
|
+
Requires-Dist: pytest-cov~=6.2; extra == "test"
|
|
65
71
|
Requires-Dist: pytest-data~=0.4; extra == "test"
|
|
66
72
|
Requires-Dist: pytest-django~=3.9; extra == "test"
|
|
67
73
|
Requires-Dist: pytest-env~=0.6; extra == "test"
|
|
@@ -81,7 +87,7 @@ Requires-Dist: psycopg2; extra == "psql"
|
|
|
81
87
|
Provides-Extra: mysql
|
|
82
88
|
Requires-Dist: mysqlclient~=2.2; extra == "mysql"
|
|
83
89
|
Provides-Extra: newsblog
|
|
84
|
-
Requires-Dist: djangocms-aldryn-newsblog~=
|
|
90
|
+
Requires-Dist: djangocms-aldryn-newsblog~=4.0; extra == "newsblog"
|
|
85
91
|
Dynamic: author
|
|
86
92
|
Dynamic: author-email
|
|
87
93
|
Dynamic: classifier
|
|
@@ -144,3 +150,36 @@ To find more useful commands, run just `make`.
|
|
|
144
150
|
## Upgrade
|
|
145
151
|
|
|
146
152
|
To upgrade from version `2.2` to version >= `3.0.0`, you can use the [DjangoCMS upgrade plugins](https://gitlab.nic.cz/utils/djangocms-upgrade-plugins) tool.
|
|
153
|
+
|
|
154
|
+
## Example in Docker
|
|
155
|
+
|
|
156
|
+
Download example:
|
|
157
|
+
|
|
158
|
+
curl https://gitlab.nic.cz/websites/django-cms-qe/-/archive/master/django-cms-qe.zip?path=example --output example.zip
|
|
159
|
+
|
|
160
|
+
Unzip and go to the example folder:
|
|
161
|
+
|
|
162
|
+
unzip example.zip
|
|
163
|
+
cd django-cms-qe*/example/
|
|
164
|
+
|
|
165
|
+
Build the site image:
|
|
166
|
+
|
|
167
|
+
docker compose build
|
|
168
|
+
|
|
169
|
+
Run website in docker:
|
|
170
|
+
|
|
171
|
+
docker compose up -d
|
|
172
|
+
|
|
173
|
+
See the website at http://localhost:8000/. Login into http://localhost:8000/admin/ as username ``admin`` with password ``admin``.
|
|
174
|
+
To run on a different port, specify the PORT parameter:
|
|
175
|
+
|
|
176
|
+
PORT=8008 docker compose up -d
|
|
177
|
+
|
|
178
|
+
Please wait a moment before browsing the website. It takes a while for all migrations to be completed and data to be loaded.
|
|
179
|
+
You can monitor the status of this process in the log:
|
|
180
|
+
|
|
181
|
+
docker compose logs -f web
|
|
182
|
+
|
|
183
|
+
Stop the website:
|
|
184
|
+
|
|
185
|
+
docker compose down
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
cms_qe/__init__.py,sha256=do1c4s8BgjukMZMMMhBHs_lG9j8ncnAjR3oTICWEq5w,684
|
|
2
2
|
cms_qe/admin.py,sha256=eLqAF3UIDWWyA0xE0Ft5WP5_3HImSWk3EYL2cRfL_8A,171
|
|
3
3
|
cms_qe/apps.py,sha256=AeRcBWwGs7rKLlzHhnV8M_2BEnkoO9959VwesxfHaio,338
|
|
4
|
+
cms_qe/cms_menus.py,sha256=KdgZgvzRZwkpqviv3exizo_Vf5qtJziC7Q2yFRslJSQ,5470
|
|
4
5
|
cms_qe/constants.py,sha256=YWUWCIabSwcamGZynvkJ9i8OWGtfHf-wFirm8GtqQpI,90
|
|
5
|
-
cms_qe/export.py,sha256=
|
|
6
|
+
cms_qe/export.py,sha256=3MflO_EmaCrlqqa-cTMOiRirsp3r4mxdQNt-Zh5FtzY,8242
|
|
6
7
|
cms_qe/fixtures.py,sha256=cq_wnZnqBwPBOHpp_0bHk424iCXKvwmN6ZaKwDvguXk,755
|
|
8
|
+
cms_qe/hooks.py,sha256=Bu8eV2E8wTeOAPET8C_YocwMV6h5XLItPO3ItCkV-yI,3482
|
|
9
|
+
cms_qe/ldap.py,sha256=2mpFdLoIdT_pAiGJ6ADnE74YXjaC55aNANv0L8DVwqU,188
|
|
7
10
|
cms_qe/monitoring.py,sha256=5t_o7o0htmAAxVjkN2oz0O0v9XdzfePhSfPGcLNPmE8,769
|
|
8
11
|
cms_qe/signals.py,sha256=MbuLSxPlJA147LEg-lDWDoUNTV1y0OKjwoI3HzgR97g,1253
|
|
9
12
|
cms_qe/staticfiles.py,sha256=OHkfDfpIxN0B-eCRagZzHDHyBgaulcyYgKhp_3mPZuk,1363
|
|
10
13
|
cms_qe/urls.py,sha256=npDzzW9SgLVMZECTyOUL5Cpw7RxeuuNssTKOXuXuxtM,3247
|
|
11
|
-
cms_qe/utils.py,sha256=
|
|
14
|
+
cms_qe/utils.py,sha256=52ETz4NKv8xyBrMJ4yDUTfUBaO6Owp-5_IHfxDftQEE,2913
|
|
12
15
|
cms_qe/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
16
|
cms_qe/api/constants.py,sha256=pdSziATRm6yUaaPBYoD07JXcULMvKD0h5RdNTPpG0rM,64
|
|
14
17
|
cms_qe/api/permissions.py,sha256=QKSll8wVOWKNbvX_FsC9CRKbPVcT2s5FM81_fnqeEQg,409
|
|
@@ -33,7 +36,7 @@ cms_qe/boilerplates/bootstrap3/static/cms_qe/js/bootstrap.min.js,sha256=U5ZEeKfG
|
|
|
33
36
|
cms_qe/boilerplates/bootstrap3/static/cms_qe/js/jquery_3.2.1.min.js,sha256=hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4,86659
|
|
34
37
|
cms_qe/boilerplates/bootstrap3/static/cms_qe/js/npm.js,sha256=x6qCoap9RSJKONkm0q2v9_5K71vNr6Kke9rAV_RCLC0,484
|
|
35
38
|
cms_qe/boilerplates/bootstrap3/templates/cms_qe/error.html,sha256=gHFQbT2KPAwnhos6uMk4gvijDjubwiOA-j_q9fASBZM,375
|
|
36
|
-
cms_qe/boilerplates/bootstrap3/templates/cms_qe/home.html,sha256=
|
|
39
|
+
cms_qe/boilerplates/bootstrap3/templates/cms_qe/home.html,sha256=itXnWbX_-Z9jIgdca25obWjwVCTT0Jy6FxWTD5aUvyU,1474
|
|
37
40
|
cms_qe/boilerplates/bootstrap3/templates/cmsplugin_filer_folder/plugins/folder/gallery.html,sha256=ZAbkXcsJ6mwAJt0vQNd55ZWB-BhJ_gtvtbnKx8PysV8,3107
|
|
38
41
|
cms_qe/haystack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
42
|
cms_qe/haystack/forms.py,sha256=4FyieMfxfE6h2dcUaWAZJ18rEOAcnMVb2zLZ60iCbVA,912
|
|
@@ -52,26 +55,31 @@ cms_qe/middleware/page_status_code.py,sha256=J-Ezet9ban9rnjWaSuRss9gOz5h7uCCyL46
|
|
|
52
55
|
cms_qe/migrations/0001_api_permissions.py,sha256=KPJYBdX3dWYEbUswSiIhkhDV6FcjXG-MPfC2aYwt7Wc,672
|
|
53
56
|
cms_qe/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
57
|
cms_qe/settings/__init__.py,sha256=GJwHXMHwMuGYE-3ZzePJ-26I2WwE8bAIMUDoiTFr0L8,982
|
|
55
|
-
cms_qe/settings/dev.py,sha256=
|
|
58
|
+
cms_qe/settings/dev.py,sha256=dKLpdibotQELoMjU-_HJlcsY30U5xM9KSONdsDW_Dq0,2168
|
|
56
59
|
cms_qe/settings/unittest.py,sha256=folLIMJb1Arh60_Sn0eNQrvIlx0OsAs6v1tDfyRZVuQ,514
|
|
57
60
|
cms_qe/settings/base/__init__.py,sha256=5yHfne9gPD_xuTaG3voZP23yzuCwROmif2mmKs-hG_A,446
|
|
58
|
-
cms_qe/settings/base/app.py,sha256=
|
|
61
|
+
cms_qe/settings/base/app.py,sha256=rWkemCai4k6PBxcx9ga6ggF32lUUVyh30Vp_7QU22Rg,4469
|
|
59
62
|
cms_qe/settings/base/auth.py,sha256=OTr1LJ4RSMZm8STs4Q3pwPXmQoURax8OKLJ8eAj7PW4,395
|
|
60
|
-
cms_qe/settings/base/cache.py,sha256=
|
|
61
|
-
cms_qe/settings/base/cms.py,sha256=
|
|
63
|
+
cms_qe/settings/base/cache.py,sha256=yBCvIIW25bSBD9nzVbPQvsPfw-pkOmcnLO7OPwzXPWo,337
|
|
64
|
+
cms_qe/settings/base/cms.py,sha256=hzl10CwswfQJkIfn4WoFJUmoumwC2smhSl8IR4VxkLM,1990
|
|
62
65
|
cms_qe/settings/base/constants.py,sha256=2lggnUhHesx5HKaz8kJ983JwHEPj4ZLoMfhgOqERPZY,8248
|
|
63
|
-
cms_qe/settings/base/database.py,sha256=
|
|
64
|
-
cms_qe/settings/base/email.py,sha256=
|
|
66
|
+
cms_qe/settings/base/database.py,sha256=_i3OJMRcrcI17VJeqY66JNOpAOXkhq570lRi0RVpzGw,354
|
|
67
|
+
cms_qe/settings/base/email.py,sha256=WkTj4V4lMZ3BG5AvHGPqulZ8T_cQMrvXiLj_NhLmpZs,576
|
|
68
|
+
cms_qe/settings/base/env.py,sha256=Oe10oSrA7QlD9TBDnEup8mtNTd1pXyaO5OThtUW8UVQ,36
|
|
65
69
|
cms_qe/settings/base/i18n.py,sha256=n_7esPYSbf9Wj-T23uWds7tCvQ0ol9MfyMtKzy009sM,355
|
|
66
|
-
cms_qe/settings/base/logging.py,sha256=
|
|
70
|
+
cms_qe/settings/base/logging.py,sha256=NnhPZnPX6zqobi4Ekx5euOnCD3Rw_Sb7jOl0tl80Vv0,1368
|
|
67
71
|
cms_qe/settings/base/path.py,sha256=s0eOmSDOWfjjI5onp28y2S2UKwCYFRDGeoUsZla6-og,410
|
|
68
|
-
cms_qe/settings/base/search.py,sha256=
|
|
69
|
-
cms_qe/settings/base/security.py,sha256=
|
|
72
|
+
cms_qe/settings/base/search.py,sha256=Vp6ROmo2x3ZaMrnHhNBjR3dX_r7BvIkcG9CPXmlZhiE,725
|
|
73
|
+
cms_qe/settings/base/security.py,sha256=fLaVfmqdF6-IZ0oppnV3Xs6KGARx7u9fYvWMwRJA3LM,4557
|
|
70
74
|
cms_qe/settings/base/template.py,sha256=bITmA7XkoqbDpefWWOBsEiPtCREzFfHkUuFvGxJVLK4,1082
|
|
71
|
-
cms_qe/
|
|
75
|
+
cms_qe/static/cms_qe/css/fix-djangocms-admin-style.css,sha256=sf_9yH_rKSts9L0OQ1vN5t32PTyjBuwfHZnDCN0GTX4,805
|
|
76
|
+
cms_qe/templates/base.html,sha256=Hb6MWA_IpBWlCyJ2NiPPQv0nSKOJgXSXS7y62-cHGUA,1094
|
|
77
|
+
cms_qe/templates/pg_is_in_recovery_login.html,sha256=ng0snZ-rriwFRKVvG0ZCY5QsQbod7jex2pVJ3hVonc0,116
|
|
72
78
|
cms_qe/templates/admin/index.html,sha256=6CjuqOPQnEYXa7zwyoLyDHt-zzfBwLAf45B0F80ryZ0,1812
|
|
79
|
+
cms_qe/templates/admin/inc/extrastyle.html,sha256=vgsAzeKxV8Meu5j60vo9hMzlsKnRagkyI7icucfQpEg,105
|
|
80
|
+
cms_qe/templates/cms_qe/alias_content_preview.html,sha256=2klC7206SDOCf-sWYgeEcBiG2fIA8H2OML2fwEcewXc,956
|
|
73
81
|
cms_qe/templates/cms_qe/error.html,sha256=1wNCO-ToNoM-HBnfq0Id_W8m_epmOEYcoozRhhHth5U,322
|
|
74
|
-
cms_qe/templates/cms_qe/home.html,sha256=
|
|
82
|
+
cms_qe/templates/cms_qe/home.html,sha256=zT4fnq9V6CsVkGXs_iFMGE4RvcMAeWvs4r0XTiHcLwA,114
|
|
75
83
|
cms_qe/templates/cms_qe/internal_error.html,sha256=n4JJ80KNHyhiSxGLQadCn9KmctnFABcwLU4KuZly8A4,251
|
|
76
84
|
cms_qe/templates/cms_qe/search_result.html,sha256=5XDX4nhRDkSJq_EdW95p8CuEN1Yy14OG9UC3WDz7TXI,310
|
|
77
85
|
cms_qe/templates/cms_qe/include/body_bottom.html,sha256=t-B_SA2AFPmTC5hnDANyR9O9tmH3-hzGTLoRPi9lgIY,29
|
|
@@ -92,6 +100,7 @@ cms_qe/views/monitoring.py,sha256=1r2s_jm6B6P0gEmiqjH9m3loUW3BmJivvpg6qcUOxVM,19
|
|
|
92
100
|
cms_qe/views/redirect_to_page.py,sha256=2HeGxTIKQQcfXsafdDz9F1fDHKGAbpiq1qKBKMvDL70,806
|
|
93
101
|
cms_qe/views/search_result.py,sha256=H1eMOmtONnWqBDsBvz3MartyHhh42vyi0jPoxWb0X8c,296
|
|
94
102
|
cms_qe/views/security.py,sha256=SNdJe4NSm1vuOGchVF3VqlmFDopt9xYoO-b4Y0UxkFU,1108
|
|
103
|
+
cms_qe/views/test_messages.py,sha256=ULHdXwjSmQxCxFF1hzBzpDa5MltGwyIF8DjQPb7N-7M,1281
|
|
95
104
|
cms_qe/whoosh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
96
105
|
cms_qe/whoosh/backend.py,sha256=YOVJGz3htWdcSUbYtX2a9VqywAU3EJP_EvxXHCY0QVA,5418
|
|
97
106
|
cms_qe_analytical/LICENSE.txt,sha256=ptQIrnsiWFFf2LZ60DTAO6XA7CQYFuwhX1m4kzhv5_8,1072
|
|
@@ -108,7 +117,7 @@ cms_qe_auth/cms_menus.py,sha256=UxzzuMfOJCC_EiCkV2__6R5JKV9q1WGbTEgO7yLy8rE,1675
|
|
|
108
117
|
cms_qe_auth/cms_plugins.py,sha256=USiNHaWdIJqPFUMLOjhuVam4nwOckujg1uguXNIs798,1575
|
|
109
118
|
cms_qe_auth/fixtures.py,sha256=hQO75OnBmU4NiT_GF-oW4lU50FrLDgGF-gfouYeLfRI,784
|
|
110
119
|
cms_qe_auth/forms.py,sha256=x7sdFoOrKBLTJXqESedpIh6Kc1k5zZhL4vwnmhj1gH8,1137
|
|
111
|
-
cms_qe_auth/models.py,sha256=
|
|
120
|
+
cms_qe_auth/models.py,sha256=ytcbh-rT36IQmOXxk4yef1xRq2RVvTzneORAC7pvWds,2713
|
|
112
121
|
cms_qe_auth/token.py,sha256=DG4Bu8AVV-d1ayL4Oc9DXNnERt1sstrll80RBGrplx0,224
|
|
113
122
|
cms_qe_auth/urls.py,sha256=RCgr9t1YonE0yR_8gXiXZIGESvQfrwVwlKhBOWmgxkw,2040
|
|
114
123
|
cms_qe_auth/utils.py,sha256=JYZUzQhUE_kycVBRBNi-fmGy5WtjIwc3_qsGxOVrNR0,2972
|
|
@@ -3941,7 +3950,8 @@ cms_qe_table/templates/cms_qe/table/table_widget.html,sha256=tsjlS5Mc_6iALFk0QIe
|
|
|
3941
3950
|
cms_qe_table/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3942
3951
|
cms_qe_table/templatetags/cms_qe_table_filters.py,sha256=eFBB2FoCcpQRAknMIJLac0ts18w8XIODbouuJlP0ty4,782
|
|
3943
3952
|
cms_qe_test/__init__.py,sha256=-Vc3K2g4JFSE2qw5AvuTGi4rwQGMOXAEycrjgFWk1BQ,121
|
|
3944
|
-
cms_qe_test/cms.py,sha256=
|
|
3953
|
+
cms_qe_test/cms.py,sha256=cJs5ZHbyPamTBuIMOhT1R2DR6teKYwhbZeuY-M-7i8I,2660
|
|
3954
|
+
cms_qe_test/mail_filebased_backend.py,sha256=9q3YuR-WcfhNOJc6hWclJmwRs949gzGFm6Eb3W7CjeI,645
|
|
3945
3955
|
cms_qe_video/__init__.py,sha256=2iOdITrw_UvFcQpFA0rhUWBCRe2qvTuDvltp5Q233cc,1070
|
|
3946
3956
|
cms_qe_video/cms_plugins.py,sha256=kqJX5eb-pYutxO-_0UnO784QpTwOb5Eudo6bW2NXaZg,3020
|
|
3947
3957
|
cms_qe_video/fixtures.py,sha256=0oGo7Ufh3XwaLaMjcGN7CFao_BetcQ6xtikNeAHdqvs,701
|
|
@@ -3960,14 +3970,7 @@ cms_qe_video/templates/cms_qe/video/video_source_file.html,sha256=QJF5fs88s9Fznp
|
|
|
3960
3970
|
cms_qe_video/templates/cms_qe/video/video_widget.html,sha256=Yumciq6bGlAYI1lYx5j9V6IF8QYrncNYygPTkXEz6Wk,925
|
|
3961
3971
|
cms_qe_video/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3962
3972
|
cms_qe_video/templatetags/cms_qe_video.py,sha256=NR_mGv91J0rEreZrQjCzaaXSrZsKvrSas12wMJ-Dg24,1168
|
|
3963
|
-
django_cms_qe-
|
|
3964
|
-
example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3965
|
-
example/urls.py,sha256=H-IJsRGFVZGw6FD9gvK-0B0dLeSOsduziHvDvcHCQZ0,399
|
|
3966
|
-
example/wsgi.py,sha256=lCKhvtFZlorSIA8qYEqc3pZ1Oflrz_Tc696MWJ62ue4,396
|
|
3967
|
-
example/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3968
|
-
example/settings/aldryn_newsblog.py,sha256=iQ5idy9rZR_N5IJzogc7R3PK3RIN7OMw7ksSIIIxPDk,276
|
|
3969
|
-
example/settings/dev.py,sha256=TGGlSzh9ZDh54Z2X5i6mz7Ja3lT_qBqw9MHX3EnMs9o,676
|
|
3970
|
-
example/settings/selenium.py,sha256=pRi8pIQIiYA0Y_yZsg7M63npHMRcUsFF7gZTr602yPY,215
|
|
3973
|
+
django_cms_qe-4.1.0.dist-info/licenses/LICENSE,sha256=5wLaeUil0gfU9p8C4zn2Yu_PvZBNieUoYl0z9FcFWdA,1521
|
|
3971
3974
|
test_selenium/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3972
3975
|
test_selenium/browser.py,sha256=OcfqxDa9OtL7M5CSwfIxtzToMUEhqGLvditemPeEUNo,1437
|
|
3973
3976
|
test_selenium/conftest.py,sha256=mAptaAyj7a1hbUPDRWBBs1qL0TJ8Fma7Mch6PZwgtNo,220
|
|
@@ -3981,7 +3984,7 @@ test_selenium/pages/cms/__init__.py,sha256=_qe4YZYaQbrXp7Szmmeo4TUSkXlE5Rozu8E3t
|
|
|
3981
3984
|
test_selenium/pages/cms/login.py,sha256=UPzJQcYff8NUAT4nvmfQoJQxzOJyPrJ_cKtH35NVfNg,521
|
|
3982
3985
|
test_selenium/pages/cms/page.py,sha256=YQnpZkopfVnhoyQKpRDGqjNeV6xUl-pEHjEcZ9HRiPk,489
|
|
3983
3986
|
test_selenium/pages/cms/wizard.py,sha256=yatbXH-rf1ap4O1hY0I13WikM3zkm_NrAiSK6bqENIU,545
|
|
3984
|
-
django_cms_qe-
|
|
3985
|
-
django_cms_qe-
|
|
3986
|
-
django_cms_qe-
|
|
3987
|
-
django_cms_qe-
|
|
3987
|
+
django_cms_qe-4.1.0.dist-info/METADATA,sha256=Jh_kHri1S4t76H1AAFtTMjvzx56EFXELL2HgwBEtzNI,6234
|
|
3988
|
+
django_cms_qe-4.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
3989
|
+
django_cms_qe-4.1.0.dist-info/top_level.txt,sha256=fQYSfQoprw1NXhYY-I8AzsPk-Rgst1REh3iOUvwAbkM,164
|
|
3990
|
+
django_cms_qe-4.1.0.dist-info/RECORD,,
|
example/__init__.py
DELETED
|
File without changes
|
example/settings/__init__.py
DELETED
|
File without changes
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
from .dev import *
|
|
2
|
-
|
|
3
|
-
INSTALLED_APPS += [ # noqa: F405
|
|
4
|
-
# Aldryn News&Blog
|
|
5
|
-
'aldryn_apphooks_config',
|
|
6
|
-
'aldryn_common',
|
|
7
|
-
'aldryn_categories',
|
|
8
|
-
'aldryn_newsblog',
|
|
9
|
-
'aldryn_people',
|
|
10
|
-
'aldryn_translation_tools',
|
|
11
|
-
'parler',
|
|
12
|
-
'sortedm2m',
|
|
13
|
-
'taggit',
|
|
14
|
-
]
|
example/settings/dev.py
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
from cms_qe.settings.dev import * # noqa: F403
|
|
4
|
-
|
|
5
|
-
INSTALLED_APPS += [ # noqa: F405
|
|
6
|
-
'example',
|
|
7
|
-
]
|
|
8
|
-
|
|
9
|
-
AUTHENTICATION_BACKENDS = [
|
|
10
|
-
'axes.backends.AxesBackend',
|
|
11
|
-
'django.contrib.auth.backends.ModelBackend',
|
|
12
|
-
]
|
|
13
|
-
|
|
14
|
-
ROOT_URLCONF = 'example.urls'
|
|
15
|
-
WSGI_APPLICATION = 'example.wsgi.application'
|
|
16
|
-
|
|
17
|
-
BASE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
|
|
18
|
-
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
|
19
|
-
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
|
20
|
-
|
|
21
|
-
DATABASES = {
|
|
22
|
-
'default': {
|
|
23
|
-
'ENGINE': 'django.db.backends.sqlite3',
|
|
24
|
-
'NAME': os.path.join(BASE_DIR, '..', 'db.sqlite3'),
|
|
25
|
-
'TEST': {
|
|
26
|
-
'NAME': ':memory:',
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
example/settings/selenium.py
DELETED
example/urls.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from django.conf import settings
|
|
2
|
-
from django.urls import path
|
|
3
|
-
from django.views.static import serve
|
|
4
|
-
|
|
5
|
-
from cms_qe.urls import handler403, handler404, handler500, handler503, urlpatterns
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def serve_favicon(request):
|
|
9
|
-
"""Serve favicon.ico."""
|
|
10
|
-
return serve(request, 'favicon.ico', settings.STATIC_ROOT)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if settings.DEBUG:
|
|
14
|
-
urlpatterns += [
|
|
15
|
-
path('favicon.ico', serve_favicon),
|
|
16
|
-
]
|
example/wsgi.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
WSGI config for example project.
|
|
3
|
-
|
|
4
|
-
It exposes the WSGI callable as a module-level variable named ``application``.
|
|
5
|
-
|
|
6
|
-
For more information on this file, see
|
|
7
|
-
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import os
|
|
11
|
-
|
|
12
|
-
from django.core.wsgi import get_wsgi_application
|
|
13
|
-
|
|
14
|
-
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings.dev')
|
|
15
|
-
|
|
16
|
-
application = get_wsgi_application()
|
|
File without changes
|
|
File without changes
|