django-cms-qe 3.1.0__py3-none-any.whl → 3.2.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/apps.py +12 -0
- cms_qe/settings/base/app.py +3 -0
- cms_qe/signals.py +42 -0
- cms_qe/urls.py +3 -0
- cms_qe/views/maintenance.py +39 -0
- cms_qe_analytical/templates/cms_qe_analytical/google_tag_manager.html +11 -0
- {django_cms_qe-3.1.0.dist-info → django_cms_qe-3.2.0.dist-info}/METADATA +2 -1
- {django_cms_qe-3.1.0.dist-info → django_cms_qe-3.2.0.dist-info}/RECORD +13 -7
- {django_cms_qe-3.1.0.dist-info → django_cms_qe-3.2.0.dist-info}/WHEEL +1 -1
- {django_cms_qe-3.1.0.dist-info → django_cms_qe-3.2.0.dist-info}/top_level.txt +1 -0
- django_mail_backends/__init__.py +0 -0
- django_mail_backends/filebased.py +17 -0
- {django_cms_qe-3.1.0.dist-info → django_cms_qe-3.2.0.dist-info}/LICENSE +0 -0
cms_qe/apps.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from django.apps import AppConfig
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CmsQEConfig(AppConfig):
|
|
5
|
+
name = 'cms_qe'
|
|
6
|
+
|
|
7
|
+
def ready(self):
|
|
8
|
+
from cms.signals import urls_need_reloading # pylint: disable=import-outside-toplevel
|
|
9
|
+
|
|
10
|
+
from .signals import reload_site # pylint: disable=import-outside-toplevel
|
|
11
|
+
|
|
12
|
+
urls_need_reloading.connect(reload_site)
|
cms_qe/settings/base/app.py
CHANGED
cms_qe/signals.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import subprocess
|
|
3
|
+
import time
|
|
4
|
+
from multiprocessing import Lock, Process
|
|
5
|
+
from typing import Any, Optional, Union
|
|
6
|
+
|
|
7
|
+
from django.conf import settings
|
|
8
|
+
from django.db.models import Model
|
|
9
|
+
|
|
10
|
+
DelayType = Union[int, float]
|
|
11
|
+
ArgsType = Union[tuple[str, ...], list[str]]
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
lock = Lock()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def run_subprocess(args: ArgsType, delay: Optional[DelayType] = None) -> Optional[subprocess.CompletedProcess]:
|
|
18
|
+
"""Run the system command in subprocess."""
|
|
19
|
+
if delay is not None:
|
|
20
|
+
time.sleep(delay)
|
|
21
|
+
logger.info('subprocess.run(%s)', args)
|
|
22
|
+
lock.acquire()
|
|
23
|
+
try:
|
|
24
|
+
return subprocess.run(args, check=False)
|
|
25
|
+
except Exception as err: # pylint: disable=broad-exception-caught
|
|
26
|
+
logger.error(str(err))
|
|
27
|
+
finally:
|
|
28
|
+
lock.release()
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def run_process(args: ArgsType, delay: Optional[DelayType] = None) -> Process:
|
|
33
|
+
"""Run the process and no wait for the result."""
|
|
34
|
+
proc = Process(target=run_subprocess, args=(args, delay))
|
|
35
|
+
proc.start()
|
|
36
|
+
return proc
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def reload_site(sender: Optional[Model], **kwargs: dict[str, Any]) -> None: # pylint: disable=unused-argument
|
|
40
|
+
"Reload the site."
|
|
41
|
+
if settings.RELOAD_SITE:
|
|
42
|
+
run_process(settings.RELOAD_SITE, 3)
|
cms_qe/urls.py
CHANGED
|
@@ -13,6 +13,7 @@ from django.contrib.sitemaps.views import sitemap
|
|
|
13
13
|
from django.urls import include, path
|
|
14
14
|
from django.views.i18n import JavaScriptCatalog
|
|
15
15
|
|
|
16
|
+
from cms_qe.views.maintenance import HealthCheckView, ReloadSiteView
|
|
16
17
|
from cms_qe.views.search_result import SiteSearchView
|
|
17
18
|
from cms_qe.views.security import SecurityTxtView
|
|
18
19
|
|
|
@@ -41,6 +42,8 @@ urlpatterns = [
|
|
|
41
42
|
path('api/monitoring', views.get_monitoring),
|
|
42
43
|
path('.well-known/security.txt', SecurityTxtView.as_view(), name='security-txt'),
|
|
43
44
|
path('site-search-result/', SiteSearchView.as_view(), name='site-search-result'),
|
|
45
|
+
path("healthcheck/", HealthCheckView.as_view(), name='healthcheck'), # Used by uwsgi in docker.
|
|
46
|
+
path("superuser/reload-site/", ReloadSiteView.as_view(), name='reload-site'),
|
|
44
47
|
]
|
|
45
48
|
|
|
46
49
|
# django-simple-captcha
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from django.conf import settings
|
|
2
|
+
from django.contrib.sites.models import Site
|
|
3
|
+
from django.core.cache import cache
|
|
4
|
+
from django.http import HttpRequest, HttpResponse
|
|
5
|
+
from django.views import View
|
|
6
|
+
|
|
7
|
+
from cms_qe.signals import run_subprocess
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HealthCheckView(View):
|
|
11
|
+
"""Health check View."""
|
|
12
|
+
|
|
13
|
+
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
|
14
|
+
"""Apply HTTP GET. Used by uwsgi in docker."""
|
|
15
|
+
# Check database connection.
|
|
16
|
+
site = Site.objects.first()
|
|
17
|
+
if not site.domain:
|
|
18
|
+
raise RuntimeError('db')
|
|
19
|
+
# Check cache.
|
|
20
|
+
key = 'health-check-test'
|
|
21
|
+
cache.set(key, 'OK', 2)
|
|
22
|
+
if cache.get(key) != 'OK':
|
|
23
|
+
raise RuntimeError('cache')
|
|
24
|
+
return HttpResponse("OK", content_type="text/plain")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ReloadSiteView(View):
|
|
28
|
+
"""Reload site View."""
|
|
29
|
+
|
|
30
|
+
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
|
31
|
+
"""Run subprocess defined in settings."""
|
|
32
|
+
if request.user.is_superuser:
|
|
33
|
+
if settings.RELOAD_SITE:
|
|
34
|
+
msg = str(run_subprocess(settings.RELOAD_SITE))
|
|
35
|
+
else:
|
|
36
|
+
msg = "SKIP: No settings.RELOAD_SITE."
|
|
37
|
+
else:
|
|
38
|
+
msg = "ERROR: User is not is_superuser."
|
|
39
|
+
return HttpResponse(msg, content_type="text/plain")
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{% if config.GOOGLE_TAG_MANAGER_ID %}
|
|
2
|
+
<!-- Google tag (gtag.js) -->
|
|
3
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id={{ config.GOOGLE_TAG_MANAGER_ID }}"></script>
|
|
4
|
+
<script>
|
|
5
|
+
window.dataLayer = window.dataLayer || [];
|
|
6
|
+
function gtag() {dataLayer.push(arguments)}
|
|
7
|
+
gtag('js', new Date());
|
|
8
|
+
gtag('config', '{{ config.GOOGLE_TAG_MANAGER_ID }}');
|
|
9
|
+
{{ config.GOOGLE_TAG_MANAGER_SCRIPT|safe }}
|
|
10
|
+
</script>
|
|
11
|
+
{% endif %}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-cms-qe
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.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.
|
|
@@ -73,6 +73,7 @@ Requires-Dist: pytest-watch ==4.2.0 ; extra == 'test'
|
|
|
73
73
|
Requires-Dist: PyVirtualDisplay ==1.3.2 ; extra == 'test'
|
|
74
74
|
Requires-Dist: webdriverwrapper ==2.8.0 ; extra == 'test'
|
|
75
75
|
Requires-Dist: django-simple-captcha ==0.5.14 ; extra == 'test'
|
|
76
|
+
Requires-Dist: testfixtures ; extra == 'test'
|
|
76
77
|
Requires-Dist: tzdata ; extra == 'test'
|
|
77
78
|
|
|
78
79
|
# Django CMS QE
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
cms_qe/__init__.py,sha256=do1c4s8BgjukMZMMMhBHs_lG9j8ncnAjR3oTICWEq5w,684
|
|
2
2
|
cms_qe/admin.py,sha256=eLqAF3UIDWWyA0xE0Ft5WP5_3HImSWk3EYL2cRfL_8A,171
|
|
3
|
+
cms_qe/apps.py,sha256=AeRcBWwGs7rKLlzHhnV8M_2BEnkoO9959VwesxfHaio,338
|
|
3
4
|
cms_qe/constants.py,sha256=YWUWCIabSwcamGZynvkJ9i8OWGtfHf-wFirm8GtqQpI,90
|
|
4
5
|
cms_qe/export.py,sha256=PyKzMoFGzMdwCTKIYP1zri0Pn8zR_2e0-IkbHYfAv3g,8138
|
|
5
6
|
cms_qe/fixtures.py,sha256=cq_wnZnqBwPBOHpp_0bHk424iCXKvwmN6ZaKwDvguXk,755
|
|
6
7
|
cms_qe/monitoring.py,sha256=5t_o7o0htmAAxVjkN2oz0O0v9XdzfePhSfPGcLNPmE8,769
|
|
8
|
+
cms_qe/signals.py,sha256=MbuLSxPlJA147LEg-lDWDoUNTV1y0OKjwoI3HzgR97g,1253
|
|
7
9
|
cms_qe/staticfiles.py,sha256=OHkfDfpIxN0B-eCRagZzHDHyBgaulcyYgKhp_3mPZuk,1363
|
|
8
|
-
cms_qe/urls.py,sha256=
|
|
10
|
+
cms_qe/urls.py,sha256=vNiiN7NwFFT48SBNIg6lzjTRMN6BicwH_zz6p-EApsw,3042
|
|
9
11
|
cms_qe/utils.py,sha256=gxsWZmS34ZC0Tv1VW8A7VeGlrPyDshodF1ZWXj7xyWE,3057
|
|
10
12
|
cms_qe/boilerplates/bootstrap3/static/cms_qe/css/bootstrap-theme.css,sha256=xOpS-e_dER8z72w-qryCieOGysQI8cELAVt3MHG0phY,26132
|
|
11
13
|
cms_qe/boilerplates/bootstrap3/static/cms_qe/css/bootstrap-theme.css.map,sha256=cZQbJTuJQjdM1XuKhdRzSJ8hMRQ4up491P76Iq2_D1M,47706
|
|
@@ -45,7 +47,7 @@ cms_qe/settings/__init__.py,sha256=GJwHXMHwMuGYE-3ZzePJ-26I2WwE8bAIMUDoiTFr0L8,9
|
|
|
45
47
|
cms_qe/settings/dev.py,sha256=51CBwiclE8LLoNB2uioIK_L3JhM1yzukQ0gZimkcFqw,1487
|
|
46
48
|
cms_qe/settings/unittest.py,sha256=folLIMJb1Arh60_Sn0eNQrvIlx0OsAs6v1tDfyRZVuQ,514
|
|
47
49
|
cms_qe/settings/base/__init__.py,sha256=5yHfne9gPD_xuTaG3voZP23yzuCwROmif2mmKs-hG_A,446
|
|
48
|
-
cms_qe/settings/base/app.py,sha256=
|
|
50
|
+
cms_qe/settings/base/app.py,sha256=vAq5Eo2LK6yU19cvbLrpLpWLV_REhdVRs9NfCZGEeu8,3966
|
|
49
51
|
cms_qe/settings/base/auth.py,sha256=axEmEG5UYxyY3EE0keQjGZzkTv2iwxwfULr4LcvZPns,207
|
|
50
52
|
cms_qe/settings/base/cache.py,sha256=9p6C5lOz1pG-6k15PyvxlShUjBYIbU0ewpA8AX_YFus,297
|
|
51
53
|
cms_qe/settings/base/cms.py,sha256=8icCNxcEp_KRDyP8-LXB21UurJL4wNysY39whAyt3I4,1855
|
|
@@ -78,6 +80,7 @@ cms_qe/templatetags/cms_qe_filters.py,sha256=ciYCXLuMVde-f_-B_7a5mHfAJPWPMxYEUMg
|
|
|
78
80
|
cms_qe/templatetags/kwacros.py,sha256=r2oHLltu8BgKKlrpgzXgvLjbIqwcrH13Lww3zTF-nr8,6275
|
|
79
81
|
cms_qe/views/__init__.py,sha256=3b5FCZ5MaqgiWglC7c5mfvP3WYLWTtNp3YpVb9BgYi8,106
|
|
80
82
|
cms_qe/views/errors.py,sha256=zUbCoyXy_MPsQv3UV1mgq-q2bwqPw9G4KgKU2-oue4w,3169
|
|
83
|
+
cms_qe/views/maintenance.py,sha256=rBfovOGETlfGNF7jlv-vuTEfjZIb5x9dYCSIyFTgHgQ,1312
|
|
81
84
|
cms_qe/views/monitoring.py,sha256=1r2s_jm6B6P0gEmiqjH9m3loUW3BmJivvpg6qcUOxVM,1909
|
|
82
85
|
cms_qe/views/search_result.py,sha256=H1eMOmtONnWqBDsBvz3MartyHhh42vyi0jPoxWb0X8c,296
|
|
83
86
|
cms_qe/views/security.py,sha256=SNdJe4NSm1vuOGchVF3VqlmFDopt9xYoO-b4Y0UxkFU,1108
|
|
@@ -86,6 +89,7 @@ cms_qe/whoosh/backend.py,sha256=YOVJGz3htWdcSUbYtX2a9VqywAU3EJP_EvxXHCY0QVA,5418
|
|
|
86
89
|
cms_qe_analytical/LICENSE.txt,sha256=ptQIrnsiWFFf2LZ60DTAO6XA7CQYFuwhX1m4kzhv5_8,1072
|
|
87
90
|
cms_qe_analytical/__init__.py,sha256=G2QJmxgo4HbUvG4GObM7PcCodfo8SM2auAVQoa36mBY,4189
|
|
88
91
|
cms_qe_analytical/utils.py,sha256=oQRPUyGIWW4lfaVNBPuwBwvnLg-D2JWaRHgNQrwvjcU,5149
|
|
92
|
+
cms_qe_analytical/templates/cms_qe_analytical/google_tag_manager.html,sha256=MJJJWSWfKAx4Z_7NFvhILlZWs0sO4zWaV5wZmEDXmd4,473
|
|
89
93
|
cms_qe_analytical/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
90
94
|
cms_qe_analytical/templatetags/google_analytics.py,sha256=cN87jJzwVcjhqSS2JKTmPt9WntuBLnzxEcwgjrQMJSg,7370
|
|
91
95
|
cms_qe_analytical/templatetags/piwik.py,sha256=EHOaojmewFpMqHzm_QCtCXGc_HGoiCJ_G-LPc8IfjM4,4131
|
|
@@ -3936,6 +3940,8 @@ cms_qe_video/templates/cms_qe/video/video_source_file.html,sha256=QJF5fs88s9Fznp
|
|
|
3936
3940
|
cms_qe_video/templates/cms_qe/video/video_widget.html,sha256=Yumciq6bGlAYI1lYx5j9V6IF8QYrncNYygPTkXEz6Wk,925
|
|
3937
3941
|
cms_qe_video/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3938
3942
|
cms_qe_video/templatetags/cms_qe_video.py,sha256=NR_mGv91J0rEreZrQjCzaaXSrZsKvrSas12wMJ-Dg24,1168
|
|
3943
|
+
django_mail_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3944
|
+
django_mail_backends/filebased.py,sha256=tsvMFFlm7-U5krIly53DArYZmrDrNZwQowKHScE8qQ4,612
|
|
3939
3945
|
example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3940
3946
|
example/urls.py,sha256=H-IJsRGFVZGw6FD9gvK-0B0dLeSOsduziHvDvcHCQZ0,399
|
|
3941
3947
|
example/wsgi.py,sha256=lCKhvtFZlorSIA8qYEqc3pZ1Oflrz_Tc696MWJ62ue4,396
|
|
@@ -3956,8 +3962,8 @@ test_selenium/pages/cms/__init__.py,sha256=_qe4YZYaQbrXp7Szmmeo4TUSkXlE5Rozu8E3t
|
|
|
3956
3962
|
test_selenium/pages/cms/login.py,sha256=UPzJQcYff8NUAT4nvmfQoJQxzOJyPrJ_cKtH35NVfNg,521
|
|
3957
3963
|
test_selenium/pages/cms/page.py,sha256=YQnpZkopfVnhoyQKpRDGqjNeV6xUl-pEHjEcZ9HRiPk,489
|
|
3958
3964
|
test_selenium/pages/cms/wizard.py,sha256=yatbXH-rf1ap4O1hY0I13WikM3zkm_NrAiSK6bqENIU,545
|
|
3959
|
-
django_cms_qe-3.
|
|
3960
|
-
django_cms_qe-3.
|
|
3961
|
-
django_cms_qe-3.
|
|
3962
|
-
django_cms_qe-3.
|
|
3963
|
-
django_cms_qe-3.
|
|
3965
|
+
django_cms_qe-3.2.0.dist-info/LICENSE,sha256=5wLaeUil0gfU9p8C4zn2Yu_PvZBNieUoYl0z9FcFWdA,1521
|
|
3966
|
+
django_cms_qe-3.2.0.dist-info/METADATA,sha256=6MBxVvDvwZR8z0sS-gYogsECKcYxogAu9YMsCNReG1o,4677
|
|
3967
|
+
django_cms_qe-3.2.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
3968
|
+
django_cms_qe-3.2.0.dist-info/top_level.txt,sha256=sns93tUvzAUoyPpolDHe0Orka1l44A4BJnYFko7EIKU,178
|
|
3969
|
+
django_cms_qe-3.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
|
|
2
|
+
# EMAIL_BACKEND = 'django_mail_backends.filebased.EmailBackend'
|
|
3
|
+
import datetime
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from django.core.mail.backends.filebased import EmailBackend as DjangoEmailBackend
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EmailBackend(DjangoEmailBackend):
|
|
10
|
+
|
|
11
|
+
def _get_filename(self):
|
|
12
|
+
"""Return a unique file name."""
|
|
13
|
+
if self._fname is None:
|
|
14
|
+
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
|
15
|
+
fname = "%s-%s.eml" % (timestamp, abs(id(self)))
|
|
16
|
+
self._fname = os.path.join(self.file_path, fname)
|
|
17
|
+
return self._fname
|
|
File without changes
|