django-cms-qe 3.7.0__py3-none-any.whl → 3.7.1__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.
Files changed (39) hide show
  1. cms_qe/boilerplates/bootstrap3/templates/cms_qe/home.html +3 -3
  2. cms_qe/export.py +7 -8
  3. cms_qe/settings/base/app.py +4 -12
  4. cms_qe/settings/base/cache.py +4 -6
  5. cms_qe/settings/base/cms.py +1 -4
  6. cms_qe/settings/base/constants.py +11 -0
  7. cms_qe/settings/base/database.py +10 -7
  8. cms_qe/settings/base/email.py +11 -9
  9. cms_qe/settings/base/logging.py +1 -2
  10. cms_qe/settings/base/search.py +1 -5
  11. cms_qe/settings/base/security.py +1 -2
  12. cms_qe/settings/dev.py +19 -25
  13. cms_qe/templates/base.html +4 -7
  14. cms_qe/templates/cms_qe/home.html +2 -0
  15. cms_qe/utils.py +17 -11
  16. cms_qe/views/redirect_to_page.py +3 -18
  17. cms_qe_auth/models.py +1 -1
  18. cms_qe_test/cms.py +5 -22
  19. {django_cms_qe-3.7.0.dist-info → django_cms_qe-3.7.1.dist-info}/METADATA +22 -61
  20. {django_cms_qe-3.7.0.dist-info → django_cms_qe-3.7.1.dist-info}/RECORD +30 -32
  21. {django_cms_qe-3.7.0.dist-info → django_cms_qe-3.7.1.dist-info}/top_level.txt +1 -0
  22. example/__init__.py +0 -0
  23. example/settings/__init__.py +0 -0
  24. example/settings/aldryn_newsblog.py +14 -0
  25. example/settings/dev.py +29 -0
  26. example/settings/selenium.py +10 -0
  27. example/urls.py +16 -0
  28. example/wsgi.py +16 -0
  29. cms_qe/hooks.py +0 -90
  30. cms_qe/ldap.py +0 -4
  31. cms_qe/settings/base/env.py +0 -3
  32. cms_qe/static/cms_qe/css/fix-djangocms-admin-style.css +0 -33
  33. cms_qe/templates/admin/inc/extrastyle.html +0 -2
  34. cms_qe/templates/cms_qe/alias_content_preview.html +0 -28
  35. cms_qe/templates/pg_is_in_recovery_login.html +0 -4
  36. cms_qe/views/test_messages.py +0 -32
  37. cms_qe_test/mail_filebased_backend.py +0 -20
  38. {django_cms_qe-3.7.0.dist-info → django_cms_qe-3.7.1.dist-info}/WHEEL +0 -0
  39. {django_cms_qe-3.7.0.dist-info → django_cms_qe-3.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
1
- {% load static i18n cms_tags sekizai_tags djangocms_alias_tags %}
1
+ {% load static i18n cms_tags sekizai_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
- {% static_alias "header" %}
29
+ {% static_placeholder "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
- {% static_alias "footer" %}
39
+ {% static_placeholder "footer" %}
40
40
  </footer>
41
41
  {% endblock %}
42
42
 
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, selected_fields=None) -> list:
140
+ def get_export_headers(self) -> 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, instance, **kwargs):
157
- value = super().export_field(field, instance, **kwargs)
156
+ def export_field(self, field, obj):
157
+ value = super().export_field(field, obj)
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, instance):
179
+ def get_value(self, obj):
180
180
  admin_property = getattr(self.get_modeladmin(), self.attribute, None)
181
181
  if admin_property:
182
- return admin_property(instance)
183
- return super().get_value(instance)
182
+ return admin_property(obj)
183
+ return super().get_value(obj)
184
184
 
185
185
 
186
186
  # Taken from https://github.com/django-import-export/django-import-export/issues/525#issuecomment-303046691
@@ -197,13 +197,12 @@ 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__()
201
200
 
202
201
  # pylint: disable=keyword-arg-before-vararg
203
202
  def clean(self, value, row=None, *args, **kwargs):
204
203
  """Returns the db value given the display value"""
205
204
  return self.revert_choices.get(value, value) if value else None
206
205
 
207
- def render(self, value, obj=None, **kwargs):
206
+ def render(self, value, obj=None):
208
207
  """Returns the display value given the db value"""
209
208
  return self.choices.get(value, '')
@@ -1,7 +1,6 @@
1
1
  """
2
2
  Base settings for Django app.
3
3
  """
4
- from .env import ENV
5
4
 
6
5
  # Default primary key field type
7
6
  # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
@@ -9,10 +8,8 @@ from .env import ENV
9
8
  DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
10
9
 
11
10
  SITE_ID = 1
12
- CMS_CONFIRM_VERSION4 = True
13
- DJANGOCMS_VERSIONING_ALLOW_DELETING_VERSIONS = True
14
11
 
15
- INTERNAL_IPS = ENV.list("INTERNAL_IPS", default=[])
12
+ INTERNAL_IPS = ['127.0.0.1']
16
13
 
17
14
  META_USE_SITES = True
18
15
  META_SITE_PROTOCOL = 'https'
@@ -50,12 +47,8 @@ INSTALLED_APPS = [
50
47
  'treebeard', # Tree structure of pages and plugins.
51
48
  'sekizai', # Static file management.
52
49
 
53
- 'djangocms_text',
54
- 'djangocms_link',
55
- 'djangocms_alias',
56
- 'djangocms_versioning',
57
-
58
50
  # Other Django CMS's useful modules.
51
+ 'djangocms_text_ckeditor',
59
52
  'djangocms_googlemap',
60
53
 
61
54
  # Django Filer's modules.
@@ -77,13 +70,11 @@ INSTALLED_APPS = [
77
70
  'djangocms_frontend.contrib.collapse',
78
71
  'djangocms_frontend.contrib.content',
79
72
  'djangocms_frontend.contrib.grid',
80
- 'djangocms_frontend.contrib.icon',
81
- 'djangocms_frontend.contrib.image',
82
73
  'djangocms_frontend.contrib.jumbotron',
83
74
  'djangocms_frontend.contrib.link',
84
75
  'djangocms_frontend.contrib.listgroup',
85
76
  'djangocms_frontend.contrib.media',
86
- 'djangocms_frontend.contrib.navigation',
77
+ 'djangocms_frontend.contrib.image',
87
78
  'djangocms_frontend.contrib.tabs',
88
79
  'djangocms_frontend.contrib.utilities',
89
80
 
@@ -92,6 +83,7 @@ INSTALLED_APPS = [
92
83
  'constance',
93
84
  'constance.backends.database',
94
85
  'import_export',
86
+ 'mailqueue',
95
87
 
96
88
  # Aldryn forms
97
89
  'aldryn_forms',
@@ -5,11 +5,9 @@ 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
-
13
8
  CACHES = {
14
- "default": ENV.cache("CACHE_URL", default="pymemcache://127.0.0.1:11211"),
9
+ 'default': {
10
+ 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
11
+ 'LOCATION': '127.0.0.1:11211',
12
+ }
15
13
  }
@@ -41,7 +41,7 @@ THUMBNAIL_PROCESSORS = (
41
41
  'easy_thumbnails.processors.filters'
42
42
  )
43
43
 
44
- TEXT_ADDITIONAL_ATTRIBUTES: dict[str, set] = {"iframe": set()}
44
+ TEXT_ADDITIONAL_TAGS = ('iframe',)
45
45
 
46
46
  # cmsplugin_filer_folder
47
47
  CMSPLUGIN_FILER_FOLDER_STYLE_CHOICES = (
@@ -65,6 +65,3 @@ 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] = []
@@ -139,6 +139,14 @@ MAILCHIMP_CONSTANCE_CONFIG = (
139
139
  )),
140
140
  )
141
141
 
142
+ REDIRECT_TO_PAGE = (
143
+ ('REDIRECT_TO_PAGE', (
144
+ '',
145
+ mark_safe('<div>Redirect to page from path <code>/redirect-to-page/</code>.</div>'
146
+ '<div>Example: <pre>/path/one/\n/path/two/ localhost:8000</pre></div>'),
147
+ )),
148
+ )
149
+
142
150
  # The content ready for .well-known/security.txt
143
151
  SECURITY_TXT_CONTENT = None # "Contact: mailto:abuse@nic.cz"
144
152
 
@@ -156,12 +164,14 @@ SECURITY_TXT_CONFIG = (
156
164
  ]),
157
165
  )
158
166
 
167
+
159
168
  CONSTANCE_CONFIG = OrderedDict(
160
169
  GOOGLE_ANALYTICS_CONSTANCE_CONFIG + # type: ignore
161
170
  GOOGLE_TAG_MANAGER_CONSTANCE_CONFIG + # type: ignore
162
171
  PIWIK_CONSTANCE_CONFIG + # type: ignore
163
172
  DJANGOCMS_GOOGLEMAP_CONSTANCE_CONFIG + # type: ignore
164
173
  MAILCHIMP_CONSTANCE_CONFIG + # type: ignore
174
+ REDIRECT_TO_PAGE + # type: ignore
165
175
  SECURITY_TXT_CONFIG # type: ignore
166
176
  )
167
177
 
@@ -171,6 +181,7 @@ CONSTANCE_CONFIG_FIELDSETS = {
171
181
  'Google tag manager options': dict(GOOGLE_TAG_MANAGER_CONSTANCE_CONFIG).keys(),
172
182
  'Piwik options': dict(PIWIK_CONSTANCE_CONFIG).keys(),
173
183
  'Mailchimp options': dict(MAILCHIMP_CONSTANCE_CONFIG).keys(),
184
+ 'Redirect to page': dict(REDIRECT_TO_PAGE).keys(),
174
185
  'Security.txt': dict(SECURITY_TXT_CONFIG).keys(),
175
186
  }
176
187
 
@@ -5,12 +5,15 @@ 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
14
8
  DATABASES = {
15
- "default": ENV.db("DATABASE_URL", default='postgres://qe_user:password@/cms_qe'),
9
+ 'default': {
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
+ }
16
19
  }
@@ -1,12 +1,14 @@
1
1
  """
2
2
  Mailing settings, by default app looks for smtp server.
3
3
  """
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")
4
+
5
+ EMAIL_HOST = 'localhost'
6
+ EMAIL_PORT = 587 # TLS uses usually 587, not 22
7
+
8
+ EMAIL_HOST_USER = ''
9
+ EMAIL_HOST_PASSWORD = ''
10
+
11
+ EMAIL_USE_TLS = True # Prefer to use secure mailing by default
12
+ EMAIL_SUBJECT_PREFIX = '' # Remove Django default prefix
13
+
14
+ DEFAULT_FROM_EMAIL = 'django_cms_qe@localhost'
@@ -1,7 +1,6 @@
1
1
  """
2
2
  Logging settings with base formatters and handlers.
3
3
  """
4
- from .env import ENV
5
4
 
6
5
  # Logging
7
6
  # https://docs.djangoproject.com/en/1.11/topics/logging/
@@ -50,7 +49,7 @@ LOGGING = {
50
49
  'propagate': True,
51
50
  },
52
51
  '': {
53
- 'level': ENV.str("LOGGER", default="ERROR"),
52
+ 'level': 'INFO',
54
53
  'handlers': ['console'],
55
54
  },
56
55
  }
@@ -1,19 +1,15 @@
1
1
  import os
2
2
  from pathlib import Path
3
3
 
4
- from .env import ENV
5
-
6
4
  site_resolver = Path(__file__).resolve()
7
5
 
8
6
  PROJECT_DIR = site_resolver.parent.parent.parent.parent
9
7
 
10
8
  HAYSTACK_ROUTERS = ['aldryn_search.router.LanguageRouter']
11
9
  HAYSTACK_ENGINE = 'cms_qe.whoosh.backend.AnalyzerWhooshEngine'
12
- _HAYSTACK_PATH = ENV.str('HAYSTACK_PATH', default=os.path.normpath(os.path.join(PROJECT_DIR, 'whoosh_index')))
10
+ _HAYSTACK_PATH = os.path.normpath(os.path.join(PROJECT_DIR, 'whoosh_index'))
13
11
  HAYSTACK_CONNECTIONS = {
14
12
  'default': {'ENGINE': HAYSTACK_ENGINE, 'PATH': os.path.join(_HAYSTACK_PATH, 'default')},
15
13
  'en': {'ENGINE': HAYSTACK_ENGINE, 'PATH': os.path.join(_HAYSTACK_PATH, 'en')},
16
14
  }
17
15
  HAYSTACK_CUSTOM_HIGHLIGHTER = "cms_qe.haystack.highlighting.HaystackHighlighter"
18
-
19
- ALDRYN_NEWSBLOG_UPDATE_SEARCH_DATA_ON_SAVE = True
@@ -41,11 +41,10 @@ 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
45
44
 
46
45
  # Cookies.
47
46
 
48
- SESSION_COOKIE_NAME = ENV.str("SESSION_COOKIE_NAME", default="sessionid")
47
+ SESSION_COOKIE_NAME = 'sessionid'
49
48
  SESSION_COOKIE_SECURE = True
50
49
 
51
50
  # Secure headers.
cms_qe/settings/dev.py CHANGED
@@ -8,7 +8,6 @@ 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
12
11
 
13
12
  # Quick-start development settings - unsuitable for production
14
13
  # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
@@ -17,7 +16,7 @@ DEBUG = True
17
16
 
18
17
  META_SITE_PROTOCOL = 'http'
19
18
 
20
- SECRET_KEY = ENV.str("SECRET_KEY", default='secret')
19
+ SECRET_KEY = '^xzhq0*q1+t0*ihq^^1wuyj3i%y#(38b7d-vlpkm-d(=!^uk6x'
21
20
 
22
21
  SESSION_COOKIE_SECURE = False
23
22
 
@@ -39,35 +38,30 @@ MIDDLEWARE += [ # noqa: F405
39
38
  site_resolver = Path(__file__).resolve()
40
39
 
41
40
  PROJECT_DIR = site_resolver.parent.parent.parent
42
- RUN_SITE_DIR = os.environ.get("VENV_PATH", PROJECT_DIR)
43
41
 
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'))
42
+ STATIC_ROOT = os.path.join(PROJECT_DIR, 'staticfiles')
46
43
 
47
44
  # Caching
45
+ # https://docs.djangoproject.com/en/1.11/topics/cache/
46
+
48
47
  CACHES = {
49
- "default": ENV.cache("CACHE_URL", default=f'filecache://{os.path.join(RUN_SITE_DIR, "django_cache")}')
48
+ 'default': {
49
+ 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
50
+ 'LOCATION': os.path.join(PROJECT_DIR, 'django_cache'),
51
+ }
50
52
  }
51
53
 
52
54
  # Database
53
- database_path = os.path.join(RUN_SITE_DIR, 'db.sqlite3')
54
- database_url_default = f"sqlite:///{database_path}"
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',
55
+ # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
56
+
57
+ DATABASES = {
58
+ 'default': {
59
+ 'ENGINE': 'django.db.backends.sqlite3',
60
+ 'NAME': os.path.join(PROJECT_DIR, 'db.sqlite3'),
61
+ 'TEST': {
62
+ 'NAME': ':memory:',
63
+ },
64
+ }
67
65
  }
68
66
 
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
- ]
67
+ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
@@ -1,4 +1,4 @@
1
- {% load i18n static cms_tags djangocms_alias_tags menu_tags sekizai_tags %}
1
+ {% load i18n static cms_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,20 +9,17 @@
9
9
  {% include 'cms_qe/include/head.html' %}
10
10
  </head>
11
11
  <body>
12
- {% cms_toolbar %}
13
- {% block menu %}
14
- <menu>{% show_menu 0 100 100 100 %}</menu>
15
- {% endblock %}
16
12
  {% include 'cms_qe/include/body_top.html' %}
13
+ {% cms_toolbar %}
17
14
  {% block header %}
18
15
  <header>
19
- {% static_alias "header" %}
16
+ {% static_placeholder "header" %}
20
17
  </header>
21
18
  {% endblock %}
22
19
  {% block content %}{% endblock %}
23
20
  {% block footers %}
24
21
  <footer>
25
- {% static_alias "footer" %}
22
+ {% static_placeholder "footer" %}
26
23
  </footer>
27
24
  {% endblock %}
28
25
  {% include "cms_qe/include/body_bottom.html" %}
@@ -2,5 +2,7 @@
2
2
  {% load cms_tags %}
3
3
 
4
4
  {% block content %}
5
+ {% placeholder "page header" %}
5
6
  {% placeholder "content" %}
7
+ {% placeholder "page footer" %}
6
8
  {% endblock %}
cms_qe/utils.py CHANGED
@@ -5,35 +5,41 @@ 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
9
8
  from django.template import TemplateDoesNotExist
10
9
  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 ``EmailMultiAlternatives`` instance from ``django.core.mail``.
16
+ Returns a ``MailerMessage`` instance from ``mailqueue``. Use ``save()`` method instead of ``send()`` to send
17
+ message or put it to a mailqueue.
17
18
 
18
19
  Template should be without extension and you should create both ``.txt`` and ``.html`` version.
19
20
  Second one is not mandatory but is good to provide it as well.
20
21
 
21
22
  """
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
+
22
32
  template_txt = get_template(template + '.txt')
33
+ content = template_txt.render(kwargs)
34
+ email.content = content
23
35
 
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
- )
30
36
  try:
31
37
  template_html = get_template(template + '.html')
32
- msg.attach_alternative(template_html.render(kwargs), "text/html")
33
38
  except TemplateDoesNotExist:
34
- pass
39
+ return email
40
+ email.html_content = template_html.render(kwargs)
35
41
 
36
- return msg
42
+ return email
37
43
 
38
44
 
39
45
  def get_base_url(request) -> str:
@@ -1,16 +1,6 @@
1
- """
2
- from django.utils.safestring import mark_safe
3
-
4
- REDIRECT_TO_PAGE = (
5
- ('REDIRECT_TO_PAGE', (
6
- '',
7
- mark_safe('Redirect to page. Example: <pre>/path/one/\n/path/two/ localhost:8000</pre>'),
8
- )),
9
- )
10
-
11
- EXTRA_CONSTANCE_CONFIG = ... + REDIRECT_TO_PAGE
12
- """
13
1
  import re
2
+
3
+ from constance import config
14
4
  from django.views.generic import RedirectView
15
5
 
16
6
 
@@ -20,12 +10,7 @@ class RedirectToPage(RedirectView):
20
10
  url = "/"
21
11
 
22
12
  def get_redirect_url(self, *args, **kwargs):
23
- try:
24
- from constance import config
25
- redirect_to_page = config.REDIRECT_TO_PAGE
26
- except (ModuleNotFoundError, AttributeError):
27
- return self.url
28
- for line in re.split("\n+", redirect_to_page):
13
+ for line in re.split("\n+", config.REDIRECT_TO_PAGE):
29
14
  line = line.strip()
30
15
  groups = re.match(r"(?P<path>\S+)(\s+(?P<host>\S+))?", line.strip())
31
16
  if groups is None:
cms_qe_auth/models.py CHANGED
@@ -64,7 +64,7 @@ class User(AbstractUser):
64
64
  username=self.username,
65
65
  activation_url=activation_url,
66
66
  )
67
- email.send()
67
+ email.save()
68
68
 
69
69
  def _generate_activation_token(self):
70
70
  return TokenGenerator().make_token(self)
cms_qe_test/cms.py CHANGED
@@ -1,13 +1,9 @@
1
1
  from cms import api
2
- from cms.models import PageContent, Placeholder
2
+ from cms.models import 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
6
4
  from django.contrib.auth.models import AnonymousUser
7
5
  from django.contrib.messages.storage.fallback import FallbackStorage
8
6
  from django.test import RequestFactory
9
- from djangocms_versioning.constants import DRAFT, PUBLISHED
10
- from djangocms_versioning.models import Version
11
7
  from sekizai.context import SekizaiContext
12
8
 
13
9
 
@@ -15,7 +11,6 @@ def render_plugin(plugin, path='/', **data):
15
11
  placeholder = Placeholder.objects.create(slot='test')
16
12
  model_instance = api.add_plugin(placeholder, plugin, 'en', **data)
17
13
  request = generate_get_request(path)
18
- request.toolbar = CMSToolbar(request)
19
14
  renderer = ContentRenderer(request=request)
20
15
  context = SekizaiContext()
21
16
  context.update({'request': request, })
@@ -40,28 +35,16 @@ def generate_post_request(path='', body=None):
40
35
 
41
36
 
42
37
  # pylint: disable=dangerous-default-value
43
- def create_page(title, language='en', page_params={}, state="publish"):
38
+ def create_page(title, language='en', page_params={}):
39
+ page_params.setdefault('published', True)
44
40
  page_params.setdefault('overwrite_url', page_params.get('slug'))
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
41
+ return api.create_page(title, 'cms_qe/home.html', language, **page_params)
55
42
 
56
43
 
57
44
  # pylint: disable=dangerous-default-value
58
45
  def create_text_page(title, language='en', page_params={}, plugin_params={}):
59
46
  plugin_params.setdefault('body', 'shello')
60
47
  page = create_page(title, language, page_params)
61
- placeholder = page.get_placeholders(language).filter(slot="content").get()
48
+ placeholder = page.placeholders.get(slot='content')
62
49
  api.add_plugin(placeholder, 'TextPlugin', language, **plugin_params)
63
50
  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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-cms-qe
3
- Version: 3.7.0
3
+ Version: 3.7.1
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,41 +23,36 @@ 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.10
26
+ Requires-Python: >=3.9
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
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
29
+ Requires-Dist: django~=4.2
30
+ Requires-Dist: django-cms~=3.11
36
31
  Requires-Dist: easy-thumbnails[svg]~=2.10
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
- Requires-Dist: django-tablib~=3.2
32
+ Requires-Dist: djangocms-frontend~=1.1
33
+ Requires-Dist: django-csp~=3.7
34
+ Requires-Dist: djangocms-picture~=4.0
35
+ Requires-Dist: django-axes~=6.0
36
+ Requires-Dist: django-constance[database]~=2.9
43
37
  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
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
42
+ Requires-Dist: django-tablib~=3.2
52
43
  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
53
49
  Requires-Dist: whoosh~=2.7
54
- Requires-Dist: Markdown~=3.8
50
+ Requires-Dist: djangorestframework~=3.16
51
+ Requires-Dist: markdown~=3.8
55
52
  Requires-Dist: django-filter~=25.1
56
53
  Requires-Dist: django-rest-knox~=5.0
57
- Requires-Dist: djangorestframework~=3.16
58
54
  Requires-Dist: drf-spectacular~=0.28
59
55
  Provides-Extra: dev
60
- Requires-Dist: django-simple-captcha~=0.5; extra == "dev"
61
56
  Requires-Dist: django-debug-toolbar~=4.1; extra == "dev"
62
57
  Requires-Dist: django-extensions~=3.2; extra == "dev"
63
58
  Provides-Extra: test
@@ -67,7 +62,6 @@ Requires-Dist: mypy; extra == "test"
67
62
  Requires-Dist: pylint; extra == "test"
68
63
  Requires-Dist: pylint-django; extra == "test"
69
64
  Requires-Dist: pytest~=6.2; extra == "test"
70
- Requires-Dist: pytest-cov~=6.2; extra == "test"
71
65
  Requires-Dist: pytest-data~=0.4; extra == "test"
72
66
  Requires-Dist: pytest-django~=3.9; extra == "test"
73
67
  Requires-Dist: pytest-env~=0.6; extra == "test"
@@ -87,7 +81,7 @@ Requires-Dist: psycopg2; extra == "psql"
87
81
  Provides-Extra: mysql
88
82
  Requires-Dist: mysqlclient~=2.2; extra == "mysql"
89
83
  Provides-Extra: newsblog
90
- Requires-Dist: djangocms-aldryn-newsblog~=4.0; extra == "newsblog"
84
+ Requires-Dist: djangocms-aldryn-newsblog~=3.3; extra == "newsblog"
91
85
  Dynamic: author
92
86
  Dynamic: author-email
93
87
  Dynamic: classifier
@@ -150,36 +144,3 @@ To find more useful commands, run just `make`.
150
144
  ## Upgrade
151
145
 
152
146
  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
@@ -2,15 +2,13 @@ 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
4
  cms_qe/constants.py,sha256=YWUWCIabSwcamGZynvkJ9i8OWGtfHf-wFirm8GtqQpI,90
5
- cms_qe/export.py,sha256=3MflO_EmaCrlqqa-cTMOiRirsp3r4mxdQNt-Zh5FtzY,8242
5
+ cms_qe/export.py,sha256=PyKzMoFGzMdwCTKIYP1zri0Pn8zR_2e0-IkbHYfAv3g,8138
6
6
  cms_qe/fixtures.py,sha256=cq_wnZnqBwPBOHpp_0bHk424iCXKvwmN6ZaKwDvguXk,755
7
- cms_qe/hooks.py,sha256=L9gLppl74Gj8euTJ1vWuSlc553ZAFAkj6mZaGw7iaW8,3330
8
- cms_qe/ldap.py,sha256=2mpFdLoIdT_pAiGJ6ADnE74YXjaC55aNANv0L8DVwqU,188
9
7
  cms_qe/monitoring.py,sha256=5t_o7o0htmAAxVjkN2oz0O0v9XdzfePhSfPGcLNPmE8,769
10
8
  cms_qe/signals.py,sha256=MbuLSxPlJA147LEg-lDWDoUNTV1y0OKjwoI3HzgR97g,1253
11
9
  cms_qe/staticfiles.py,sha256=OHkfDfpIxN0B-eCRagZzHDHyBgaulcyYgKhp_3mPZuk,1363
12
10
  cms_qe/urls.py,sha256=npDzzW9SgLVMZECTyOUL5Cpw7RxeuuNssTKOXuXuxtM,3247
13
- cms_qe/utils.py,sha256=52ETz4NKv8xyBrMJ4yDUTfUBaO6Owp-5_IHfxDftQEE,2913
11
+ cms_qe/utils.py,sha256=gxsWZmS34ZC0Tv1VW8A7VeGlrPyDshodF1ZWXj7xyWE,3057
14
12
  cms_qe/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
13
  cms_qe/api/constants.py,sha256=pdSziATRm6yUaaPBYoD07JXcULMvKD0h5RdNTPpG0rM,64
16
14
  cms_qe/api/permissions.py,sha256=QKSll8wVOWKNbvX_FsC9CRKbPVcT2s5FM81_fnqeEQg,409
@@ -35,7 +33,7 @@ cms_qe/boilerplates/bootstrap3/static/cms_qe/js/bootstrap.min.js,sha256=U5ZEeKfG
35
33
  cms_qe/boilerplates/bootstrap3/static/cms_qe/js/jquery_3.2.1.min.js,sha256=hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4,86659
36
34
  cms_qe/boilerplates/bootstrap3/static/cms_qe/js/npm.js,sha256=x6qCoap9RSJKONkm0q2v9_5K71vNr6Kke9rAV_RCLC0,484
37
35
  cms_qe/boilerplates/bootstrap3/templates/cms_qe/error.html,sha256=gHFQbT2KPAwnhos6uMk4gvijDjubwiOA-j_q9fASBZM,375
38
- cms_qe/boilerplates/bootstrap3/templates/cms_qe/home.html,sha256=itXnWbX_-Z9jIgdca25obWjwVCTT0Jy6FxWTD5aUvyU,1474
36
+ cms_qe/boilerplates/bootstrap3/templates/cms_qe/home.html,sha256=swbpKbL2KJhDdnuLRUelfQn7xPxolzYye4fLrLjFVOM,1465
39
37
  cms_qe/boilerplates/bootstrap3/templates/cmsplugin_filer_folder/plugins/folder/gallery.html,sha256=ZAbkXcsJ6mwAJt0vQNd55ZWB-BhJ_gtvtbnKx8PysV8,3107
40
38
  cms_qe/haystack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
39
  cms_qe/haystack/forms.py,sha256=4FyieMfxfE6h2dcUaWAZJ18rEOAcnMVb2zLZ60iCbVA,912
@@ -54,31 +52,26 @@ cms_qe/middleware/page_status_code.py,sha256=J-Ezet9ban9rnjWaSuRss9gOz5h7uCCyL46
54
52
  cms_qe/migrations/0001_api_permissions.py,sha256=KPJYBdX3dWYEbUswSiIhkhDV6FcjXG-MPfC2aYwt7Wc,672
55
53
  cms_qe/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
54
  cms_qe/settings/__init__.py,sha256=GJwHXMHwMuGYE-3ZzePJ-26I2WwE8bAIMUDoiTFr0L8,982
57
- cms_qe/settings/dev.py,sha256=A0LJ1cnoGqq7p7KInfqI-DNL8NqKaHbe5dByRIptknc,2143
55
+ cms_qe/settings/dev.py,sha256=51CBwiclE8LLoNB2uioIK_L3JhM1yzukQ0gZimkcFqw,1487
58
56
  cms_qe/settings/unittest.py,sha256=folLIMJb1Arh60_Sn0eNQrvIlx0OsAs6v1tDfyRZVuQ,514
59
57
  cms_qe/settings/base/__init__.py,sha256=5yHfne9gPD_xuTaG3voZP23yzuCwROmif2mmKs-hG_A,446
60
- cms_qe/settings/base/app.py,sha256=rWkemCai4k6PBxcx9ga6ggF32lUUVyh30Vp_7QU22Rg,4469
58
+ cms_qe/settings/base/app.py,sha256=RGxe4deN_qLGc_aRNKGjmBgsWYYpd-wdm6V47a0VR5I,4213
61
59
  cms_qe/settings/base/auth.py,sha256=OTr1LJ4RSMZm8STs4Q3pwPXmQoURax8OKLJ8eAj7PW4,395
62
- cms_qe/settings/base/cache.py,sha256=yBCvIIW25bSBD9nzVbPQvsPfw-pkOmcnLO7OPwzXPWo,337
63
- cms_qe/settings/base/cms.py,sha256=hzl10CwswfQJkIfn4WoFJUmoumwC2smhSl8IR4VxkLM,1990
64
- cms_qe/settings/base/constants.py,sha256=Rdq6ESg_J2B1Xm-ImEYM8pmsid-LqkSR7LXQdb3wlZU,7899
65
- cms_qe/settings/base/database.py,sha256=_i3OJMRcrcI17VJeqY66JNOpAOXkhq570lRi0RVpzGw,354
66
- cms_qe/settings/base/email.py,sha256=WkTj4V4lMZ3BG5AvHGPqulZ8T_cQMrvXiLj_NhLmpZs,576
67
- cms_qe/settings/base/env.py,sha256=Oe10oSrA7QlD9TBDnEup8mtNTd1pXyaO5OThtUW8UVQ,36
60
+ cms_qe/settings/base/cache.py,sha256=9p6C5lOz1pG-6k15PyvxlShUjBYIbU0ewpA8AX_YFus,297
61
+ cms_qe/settings/base/cms.py,sha256=8icCNxcEp_KRDyP8-LXB21UurJL4wNysY39whAyt3I4,1855
62
+ cms_qe/settings/base/constants.py,sha256=2lggnUhHesx5HKaz8kJ983JwHEPj4ZLoMfhgOqERPZY,8248
63
+ cms_qe/settings/base/database.py,sha256=qT7ePr2lg4CVJcHnG2nXFPPvzIjBOLB4auvRiWxaDPY,408
64
+ cms_qe/settings/base/email.py,sha256=agT6ZBAyT29TUEQIRYObAdgOSETLlZEi7KizNhr9dVc,357
68
65
  cms_qe/settings/base/i18n.py,sha256=n_7esPYSbf9Wj-T23uWds7tCvQ0ol9MfyMtKzy009sM,355
69
- cms_qe/settings/base/logging.py,sha256=NnhPZnPX6zqobi4Ekx5euOnCD3Rw_Sb7jOl0tl80Vv0,1368
66
+ cms_qe/settings/base/logging.py,sha256=GFVyQ_DcdKl9iu9C8fCshrAdrIKY0T-OD6lst5bb8qQ,1319
70
67
  cms_qe/settings/base/path.py,sha256=s0eOmSDOWfjjI5onp28y2S2UKwCYFRDGeoUsZla6-og,410
71
- cms_qe/settings/base/search.py,sha256=Vp6ROmo2x3ZaMrnHhNBjR3dX_r7BvIkcG9CPXmlZhiE,725
72
- cms_qe/settings/base/security.py,sha256=fLaVfmqdF6-IZ0oppnV3Xs6KGARx7u9fYvWMwRJA3LM,4557
68
+ cms_qe/settings/base/search.py,sha256=xbO9OFFGLi8PZut_Ngb-27BUI6HPG0ZM4lrO1HXHW-c,618
69
+ cms_qe/settings/base/security.py,sha256=i6mHb8gv6XPthShL1kFLTwa_vrfoaivzqC9MXLE_YBw,4496
73
70
  cms_qe/settings/base/template.py,sha256=bITmA7XkoqbDpefWWOBsEiPtCREzFfHkUuFvGxJVLK4,1082
74
- cms_qe/static/cms_qe/css/fix-djangocms-admin-style.css,sha256=sf_9yH_rKSts9L0OQ1vN5t32PTyjBuwfHZnDCN0GTX4,805
75
- cms_qe/templates/base.html,sha256=Hb6MWA_IpBWlCyJ2NiPPQv0nSKOJgXSXS7y62-cHGUA,1094
76
- cms_qe/templates/pg_is_in_recovery_login.html,sha256=ng0snZ-rriwFRKVvG0ZCY5QsQbod7jex2pVJ3hVonc0,116
71
+ cms_qe/templates/base.html,sha256=BMd8MbubDB8m1ZzBWfAfzTs4EBQn0oBQUw1GVRA4z6A,972
77
72
  cms_qe/templates/admin/index.html,sha256=6CjuqOPQnEYXa7zwyoLyDHt-zzfBwLAf45B0F80ryZ0,1812
78
- cms_qe/templates/admin/inc/extrastyle.html,sha256=vgsAzeKxV8Meu5j60vo9hMzlsKnRagkyI7icucfQpEg,105
79
- cms_qe/templates/cms_qe/alias_content_preview.html,sha256=2klC7206SDOCf-sWYgeEcBiG2fIA8H2OML2fwEcewXc,956
80
73
  cms_qe/templates/cms_qe/error.html,sha256=1wNCO-ToNoM-HBnfq0Id_W8m_epmOEYcoozRhhHth5U,322
81
- cms_qe/templates/cms_qe/home.html,sha256=zT4fnq9V6CsVkGXs_iFMGE4RvcMAeWvs4r0XTiHcLwA,114
74
+ cms_qe/templates/cms_qe/home.html,sha256=XSyChEdMnxcw-OWrm_d_3h2lmXfPyfpCpyYKH6QNG2E,186
82
75
  cms_qe/templates/cms_qe/internal_error.html,sha256=n4JJ80KNHyhiSxGLQadCn9KmctnFABcwLU4KuZly8A4,251
83
76
  cms_qe/templates/cms_qe/search_result.html,sha256=5XDX4nhRDkSJq_EdW95p8CuEN1Yy14OG9UC3WDz7TXI,310
84
77
  cms_qe/templates/cms_qe/include/body_bottom.html,sha256=t-B_SA2AFPmTC5hnDANyR9O9tmH3-hzGTLoRPi9lgIY,29
@@ -96,10 +89,9 @@ cms_qe/views/__init__.py,sha256=3b5FCZ5MaqgiWglC7c5mfvP3WYLWTtNp3YpVb9BgYi8,106
96
89
  cms_qe/views/errors.py,sha256=zUbCoyXy_MPsQv3UV1mgq-q2bwqPw9G4KgKU2-oue4w,3169
97
90
  cms_qe/views/maintenance.py,sha256=Q410LCeeihRWhIJ-zzRpFSjfvA6xhgr6NJlNAoTNO2U,1658
98
91
  cms_qe/views/monitoring.py,sha256=1r2s_jm6B6P0gEmiqjH9m3loUW3BmJivvpg6qcUOxVM,1909
99
- cms_qe/views/redirect_to_page.py,sha256=MEgwDfjRYbMhCduimvIz_Do6NnKFRzjuSnuTBZmLnYI,1176
92
+ cms_qe/views/redirect_to_page.py,sha256=JijgNrv5ZHBX-oaKeUt6I2Dn1p6x5OhHIqW8cwIkQ1I,750
100
93
  cms_qe/views/search_result.py,sha256=H1eMOmtONnWqBDsBvz3MartyHhh42vyi0jPoxWb0X8c,296
101
94
  cms_qe/views/security.py,sha256=SNdJe4NSm1vuOGchVF3VqlmFDopt9xYoO-b4Y0UxkFU,1108
102
- cms_qe/views/test_messages.py,sha256=ULHdXwjSmQxCxFF1hzBzpDa5MltGwyIF8DjQPb7N-7M,1281
103
95
  cms_qe/whoosh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
96
  cms_qe/whoosh/backend.py,sha256=YOVJGz3htWdcSUbYtX2a9VqywAU3EJP_EvxXHCY0QVA,5418
105
97
  cms_qe_analytical/LICENSE.txt,sha256=ptQIrnsiWFFf2LZ60DTAO6XA7CQYFuwhX1m4kzhv5_8,1072
@@ -116,7 +108,7 @@ cms_qe_auth/cms_menus.py,sha256=UxzzuMfOJCC_EiCkV2__6R5JKV9q1WGbTEgO7yLy8rE,1675
116
108
  cms_qe_auth/cms_plugins.py,sha256=USiNHaWdIJqPFUMLOjhuVam4nwOckujg1uguXNIs798,1575
117
109
  cms_qe_auth/fixtures.py,sha256=hQO75OnBmU4NiT_GF-oW4lU50FrLDgGF-gfouYeLfRI,784
118
110
  cms_qe_auth/forms.py,sha256=x7sdFoOrKBLTJXqESedpIh6Kc1k5zZhL4vwnmhj1gH8,1137
119
- cms_qe_auth/models.py,sha256=ytcbh-rT36IQmOXxk4yef1xRq2RVvTzneORAC7pvWds,2713
111
+ cms_qe_auth/models.py,sha256=Aro43D9y1zrS-3eKHVZEuSkchusDZAcj15B2vYcdt0Q,2713
120
112
  cms_qe_auth/token.py,sha256=DG4Bu8AVV-d1ayL4Oc9DXNnERt1sstrll80RBGrplx0,224
121
113
  cms_qe_auth/urls.py,sha256=RCgr9t1YonE0yR_8gXiXZIGESvQfrwVwlKhBOWmgxkw,2040
122
114
  cms_qe_auth/utils.py,sha256=JYZUzQhUE_kycVBRBNi-fmGy5WtjIwc3_qsGxOVrNR0,2972
@@ -3949,8 +3941,7 @@ cms_qe_table/templates/cms_qe/table/table_widget.html,sha256=tsjlS5Mc_6iALFk0QIe
3949
3941
  cms_qe_table/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3950
3942
  cms_qe_table/templatetags/cms_qe_table_filters.py,sha256=eFBB2FoCcpQRAknMIJLac0ts18w8XIODbouuJlP0ty4,782
3951
3943
  cms_qe_test/__init__.py,sha256=-Vc3K2g4JFSE2qw5AvuTGi4rwQGMOXAEycrjgFWk1BQ,121
3952
- cms_qe_test/cms.py,sha256=cJs5ZHbyPamTBuIMOhT1R2DR6teKYwhbZeuY-M-7i8I,2660
3953
- cms_qe_test/mail_filebased_backend.py,sha256=9q3YuR-WcfhNOJc6hWclJmwRs949gzGFm6Eb3W7CjeI,645
3944
+ cms_qe_test/cms.py,sha256=pspLQxbnwG71PuZKtwfWDu6uVk7RYO86Od1cDXBF108,1796
3954
3945
  cms_qe_video/__init__.py,sha256=2iOdITrw_UvFcQpFA0rhUWBCRe2qvTuDvltp5Q233cc,1070
3955
3946
  cms_qe_video/cms_plugins.py,sha256=kqJX5eb-pYutxO-_0UnO784QpTwOb5Eudo6bW2NXaZg,3020
3956
3947
  cms_qe_video/fixtures.py,sha256=0oGo7Ufh3XwaLaMjcGN7CFao_BetcQ6xtikNeAHdqvs,701
@@ -3969,7 +3960,14 @@ cms_qe_video/templates/cms_qe/video/video_source_file.html,sha256=QJF5fs88s9Fznp
3969
3960
  cms_qe_video/templates/cms_qe/video/video_widget.html,sha256=Yumciq6bGlAYI1lYx5j9V6IF8QYrncNYygPTkXEz6Wk,925
3970
3961
  cms_qe_video/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3971
3962
  cms_qe_video/templatetags/cms_qe_video.py,sha256=NR_mGv91J0rEreZrQjCzaaXSrZsKvrSas12wMJ-Dg24,1168
3972
- django_cms_qe-3.7.0.dist-info/licenses/LICENSE,sha256=5wLaeUil0gfU9p8C4zn2Yu_PvZBNieUoYl0z9FcFWdA,1521
3963
+ django_cms_qe-3.7.1.dist-info/licenses/LICENSE,sha256=5wLaeUil0gfU9p8C4zn2Yu_PvZBNieUoYl0z9FcFWdA,1521
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
3971
  test_selenium/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3974
3972
  test_selenium/browser.py,sha256=OcfqxDa9OtL7M5CSwfIxtzToMUEhqGLvditemPeEUNo,1437
3975
3973
  test_selenium/conftest.py,sha256=mAptaAyj7a1hbUPDRWBBs1qL0TJ8Fma7Mch6PZwgtNo,220
@@ -3983,7 +3981,7 @@ test_selenium/pages/cms/__init__.py,sha256=_qe4YZYaQbrXp7Szmmeo4TUSkXlE5Rozu8E3t
3983
3981
  test_selenium/pages/cms/login.py,sha256=UPzJQcYff8NUAT4nvmfQoJQxzOJyPrJ_cKtH35NVfNg,521
3984
3982
  test_selenium/pages/cms/page.py,sha256=YQnpZkopfVnhoyQKpRDGqjNeV6xUl-pEHjEcZ9HRiPk,489
3985
3983
  test_selenium/pages/cms/wizard.py,sha256=yatbXH-rf1ap4O1hY0I13WikM3zkm_NrAiSK6bqENIU,545
3986
- django_cms_qe-3.7.0.dist-info/METADATA,sha256=JPaPrE76CgXO2VeTxyt0VNbQQWn0arzmOgJwuaRdjv4,6234
3987
- django_cms_qe-3.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
3988
- django_cms_qe-3.7.0.dist-info/top_level.txt,sha256=fQYSfQoprw1NXhYY-I8AzsPk-Rgst1REh3iOUvwAbkM,164
3989
- django_cms_qe-3.7.0.dist-info/RECORD,,
3984
+ django_cms_qe-3.7.1.dist-info/METADATA,sha256=fp3JLm9GIV1Qid56udfGSru4t3hZKitQavkavutoUB8,5144
3985
+ django_cms_qe-3.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
3986
+ django_cms_qe-3.7.1.dist-info/top_level.txt,sha256=T4dauFwJy7FmxCy7WoQI3pPwiDessNB2LkfOAP76ssE,172
3987
+ django_cms_qe-3.7.1.dist-info/RECORD,,
@@ -9,4 +9,5 @@ cms_qe_plugins
9
9
  cms_qe_table
10
10
  cms_qe_test
11
11
  cms_qe_video
12
+ example
12
13
  test_selenium
example/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,14 @@
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
+ ]
@@ -0,0 +1,29 @@
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
+ }
@@ -0,0 +1,10 @@
1
+ import os
2
+
3
+ from .dev import * # noqa: F403
4
+
5
+ DATABASES = {
6
+ 'default': {
7
+ 'ENGINE': 'django.db.backends.sqlite3',
8
+ 'NAME': os.path.join(BASE_DIR, '..', 'db_selenium.sqlite3'), # noqa: F405
9
+ }
10
+ }
example/urls.py ADDED
@@ -0,0 +1,16 @@
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 ADDED
@@ -0,0 +1,16 @@
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()
cms_qe/hooks.py DELETED
@@ -1,90 +0,0 @@
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
-
16
- def pg_is_in_recovery():
17
- """Return True when database is slave or False when database is master."""
18
- with connection.cursor() as cursor:
19
- if cursor.db.vendor != 'postgresql':
20
- return False
21
- cursor.execute("SELECT pg_is_in_recovery()")
22
- return cursor.fetchone()[0]
23
-
24
-
25
- class PgIsInRecoveryLoginView(LoginView):
26
- template_name = 'admin/login.html'
27
- url_page_name = "login"
28
-
29
- def get(self, request, *args, **kwargs):
30
- if pg_is_in_recovery():
31
- messages.add_message(request, messages.WARNING,
32
- _('The database is in recovery mode. Unable to login. Try it later.'))
33
- return super().get(request, *args, **kwargs)
34
-
35
- def post(self, request, *args, **kwargs):
36
- if pg_is_in_recovery():
37
- messages.add_message(request, messages.ERROR, _('Login failed. The database is in recovery mode.'))
38
- return HttpResponseRedirect(reverse(self.url_page_name))
39
- return super().post(request, *args, **kwargs)
40
-
41
- def get_template_names(self):
42
- if pg_is_in_recovery():
43
- return ['pg_is_in_recovery_login.html']
44
- return self.template_name
45
-
46
-
47
- class PgIsInRecoveryMenuRenderer(MenuRenderer):
48
-
49
- def get_nodes(self, namespace=None, root_id=None, breadcrumb=False):
50
- try:
51
- return super().get_nodes(namespace, root_id, breadcrumb)
52
- except InternalError:
53
- if pg_is_in_recovery():
54
- return []
55
- raise
56
-
57
-
58
- def render_alias_content(request: HttpRequest, alias_content: AliasContent) -> TemplateResponse:
59
- """Render alias content with additionad css class alias-$name.
60
-
61
- This is the same function as on the url
62
- https://github.com/django-cms/djangocms-alias/blob/master/djangocms_alias/rendering.py#L4,
63
- it just uses a different template. In the template, a css class is added by the alias name.
64
- This is necessary so that the appropriate styles can be linked to it.
65
- """
66
- template = "cms_qe/alias_content_preview.html"
67
- context = {
68
- "alias_content": alias_content,
69
- "site_styles": settings.STYLES_FOR_ALIAS_ADMIN_PREVIEW,
70
- }
71
- return TemplateResponse(request, template, context)
72
-
73
-
74
- def get_renderer(self, request: HttpRequest) -> PgIsInRecoveryMenuRenderer:
75
- self.discover_menus()
76
- return PgIsInRecoveryMenuRenderer(pool=self, request=request)
77
-
78
-
79
- def patch_menu_pool_cachekey():
80
- """Skip exception when MenuRenderer attempts to write to read only database."""
81
- menu_pool.get_renderer = MethodType(get_renderer, menu_pool)
82
-
83
-
84
- def patch_alias():
85
- """Patch alias template preview."""
86
- try:
87
- extension = apps.get_app_config('cms').cms_extension
88
- extension.toolbar_enabled_models[AliasContent] = render_alias_content
89
- except KeyError:
90
- pass
cms_qe/ldap.py DELETED
@@ -1,4 +0,0 @@
1
- def clean_user_data(model_fields):
2
- """Transform the user data loaded from LDAP into a form suitable for creating a user."""
3
- model_fields['is_staff'] = True
4
- return model_fields
@@ -1,3 +0,0 @@
1
- import environ
2
-
3
- ENV = environ.Env()
@@ -1,33 +0,0 @@
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
- }
@@ -1,2 +0,0 @@
1
- {% load static %}
2
- <link rel="stylesheet" href="{% static "cms_qe/css/fix-djangocms-admin-style.css" %}">
@@ -1,28 +0,0 @@
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 %}
@@ -1,4 +0,0 @@
1
- {% extends "admin/login.html" %}
2
- {% load i18n %}
3
-
4
- {% block content %}{# Do not display login form. #}{% endblock %}
@@ -1,32 +0,0 @@
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", "/")
@@ -1,20 +0,0 @@
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