django-cms-qe 3.3.0__py3-none-any.whl → 3.4.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.
- cms_qe/settings/base/auth.py +3 -0
- cms_qe_auth/admin.py +28 -1
- cms_qe_auth/locale/cs/LC_MESSAGES/django.mo +0 -0
- cms_qe_auth/locale/cs/LC_MESSAGES/django.po +3 -0
- cms_qe_auth/utils.py +65 -0
- {django_cms_qe-3.3.0.dist-info → django_cms_qe-3.4.1.dist-info}/METADATA +1 -1
- {django_cms_qe-3.3.0.dist-info → django_cms_qe-3.4.1.dist-info}/RECORD +10 -10
- {django_cms_qe-3.3.0.dist-info → django_cms_qe-3.4.1.dist-info}/WHEEL +1 -1
- {django_cms_qe-3.3.0.dist-info → django_cms_qe-3.4.1.dist-info}/LICENSE +0 -0
- {django_cms_qe-3.3.0.dist-info → django_cms_qe-3.4.1.dist-info}/top_level.txt +0 -0
cms_qe/settings/base/auth.py
CHANGED
|
@@ -9,3 +9,6 @@ LOGIN_REDIRECT_URL = '/'
|
|
|
9
9
|
LOGIN_URL = '/auth/login'
|
|
10
10
|
|
|
11
11
|
CMS_QE_AUTH_ENABLED = False # Enable cms_qe_auth registration.
|
|
12
|
+
|
|
13
|
+
ALDRYN_FORMS_EMAIL_AVAILABILITY_CHECKER_FNC = 'cms_qe_auth.utils.smtp_server_accepts_email_address'
|
|
14
|
+
ALDRYN_FORMS_EMAIL_AVAILABILITY_CHECKER_CLASS = 'cms_qe_auth.utils.SMTPCheckRecipient'
|
cms_qe_auth/admin.py
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
|
+
from django import forms
|
|
1
2
|
from django.contrib import admin
|
|
2
3
|
from django.contrib.auth.admin import UserAdmin
|
|
4
|
+
from django.core.exceptions import ValidationError
|
|
5
|
+
from django.utils.translation import gettext_lazy as _
|
|
3
6
|
|
|
4
7
|
from .models import User
|
|
8
|
+
from .utils import smtp_server_accepts_email_address
|
|
5
9
|
|
|
6
|
-
|
|
10
|
+
|
|
11
|
+
class CmsQeAuthUserForm(forms.ModelForm):
|
|
12
|
+
|
|
13
|
+
def clean(self):
|
|
14
|
+
field_name = "email"
|
|
15
|
+
if self.cleaned_data.get(field_name) and self.cleaned_data.get("is_active") and \
|
|
16
|
+
self.cleaned_data.get("is_staff"):
|
|
17
|
+
try:
|
|
18
|
+
smtp_server_accepts_email_address(self.cleaned_data[field_name])
|
|
19
|
+
except ValidationError as err:
|
|
20
|
+
msg = _("Enter a valid email or don't enter any.")
|
|
21
|
+
if "email" in self._errors:
|
|
22
|
+
self._errors[field_name].append(err)
|
|
23
|
+
self._errors[field_name].append(msg)
|
|
24
|
+
else:
|
|
25
|
+
self._errors[field_name] = self.error_class([err, msg])
|
|
26
|
+
return self.cleaned_data
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class CmsQeAuthUserAdmin(UserAdmin):
|
|
30
|
+
form = CmsQeAuthUserForm
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
admin.register(User)(CmsQeAuthUserAdmin)
|
|
Binary file
|
|
@@ -329,3 +329,6 @@ msgstr ""
|
|
|
329
329
|
"Jste přihlášen jako <strong>%(username)s</strong>.\n"
|
|
330
330
|
"Chcete se <a href=\"%(logout_url)s?next=%(register_url)s>i tak registrovat</"
|
|
331
331
|
"a>?"
|
|
332
|
+
|
|
333
|
+
msgid "Enter a valid email or don't enter any."
|
|
334
|
+
msgstr "Zadejte platný e-mail nebo nedávejte žádný."
|
cms_qe_auth/utils.py
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import smtplib
|
|
3
|
+
import socket
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from django.conf import settings
|
|
1
7
|
from django.contrib.auth import get_user_model
|
|
8
|
+
from django.core.exceptions import ValidationError
|
|
2
9
|
from django.utils.encoding import force_bytes, force_str
|
|
3
10
|
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
|
|
4
11
|
|
|
12
|
+
ACTION_OK = 250 # Requested mail action okay, completed.
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
5
16
|
# pylint:disable=invalid-name
|
|
6
17
|
|
|
7
18
|
|
|
@@ -21,3 +32,57 @@ def get_user_by_uidb64(uidb64):
|
|
|
21
32
|
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
|
|
22
33
|
user = None
|
|
23
34
|
return user
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ActionIsNoOkResponse(Exception):
|
|
38
|
+
"""Action si not OK response."""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def check_smtp_response(response: tuple[int, bytes]) -> None:
|
|
42
|
+
"""Check if response is valid."""
|
|
43
|
+
if response[0] != ACTION_OK:
|
|
44
|
+
raise ActionIsNoOkResponse(force_str(response[1]))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SMTPCheckRecipient:
|
|
48
|
+
"""SMTP server checks recipient email if the server accepts it."""
|
|
49
|
+
|
|
50
|
+
def __init__(self, hostname: str):
|
|
51
|
+
self.smtp: Optional[smtplib.SMTP] = None
|
|
52
|
+
self.hostname = hostname
|
|
53
|
+
|
|
54
|
+
def connect(self) -> None:
|
|
55
|
+
if self.hostname and self.smtp is None:
|
|
56
|
+
try:
|
|
57
|
+
self.smtp = smtplib.SMTP(self.hostname, timeout=5)
|
|
58
|
+
check_smtp_response(self.smtp.helo())
|
|
59
|
+
check_smtp_response(self.smtp.docmd('MAIL FROM:""'))
|
|
60
|
+
except (ActionIsNoOkResponse, OSError, socket.gaierror, smtplib.SMTPException) as error:
|
|
61
|
+
logger.error(error)
|
|
62
|
+
|
|
63
|
+
def close(self) -> None:
|
|
64
|
+
if self.smtp is not None and self.smtp.sock is not None:
|
|
65
|
+
self.smtp.close()
|
|
66
|
+
|
|
67
|
+
def __enter__(self):
|
|
68
|
+
return self
|
|
69
|
+
|
|
70
|
+
def __exit__(self, exc_type, exc_value, exc_tb):
|
|
71
|
+
self.close()
|
|
72
|
+
|
|
73
|
+
def check(self, address: str) -> None:
|
|
74
|
+
"""Check if SMTP server accepts email address. Raise ValidationError if not."""
|
|
75
|
+
self.connect()
|
|
76
|
+
if self.smtp is not None and self.smtp.sock is not None:
|
|
77
|
+
try:
|
|
78
|
+
code, message = self.smtp.docmd(f'RCPT TO:{address}')
|
|
79
|
+
if code != ACTION_OK:
|
|
80
|
+
raise ValidationError(force_str(message), code="invalid")
|
|
81
|
+
except (socket.gaierror, smtplib.SMTPException) as error:
|
|
82
|
+
logger.error(error)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def smtp_server_accepts_email_address(address: str) -> None:
|
|
86
|
+
"""SMTP server accepts email address. Raise ValidationError if not."""
|
|
87
|
+
with SMTPCheckRecipient(settings.EMAIL_HOST) as checker:
|
|
88
|
+
checker.check(address)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-cms-qe
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.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.
|
|
@@ -48,7 +48,7 @@ cms_qe/settings/dev.py,sha256=51CBwiclE8LLoNB2uioIK_L3JhM1yzukQ0gZimkcFqw,1487
|
|
|
48
48
|
cms_qe/settings/unittest.py,sha256=folLIMJb1Arh60_Sn0eNQrvIlx0OsAs6v1tDfyRZVuQ,514
|
|
49
49
|
cms_qe/settings/base/__init__.py,sha256=5yHfne9gPD_xuTaG3voZP23yzuCwROmif2mmKs-hG_A,446
|
|
50
50
|
cms_qe/settings/base/app.py,sha256=pmy_0ThkSDNXmEVrWwFpRQ-mjHCvYFoo8YxmFRLG5bM,3988
|
|
51
|
-
cms_qe/settings/base/auth.py,sha256=
|
|
51
|
+
cms_qe/settings/base/auth.py,sha256=OTr1LJ4RSMZm8STs4Q3pwPXmQoURax8OKLJ8eAj7PW4,395
|
|
52
52
|
cms_qe/settings/base/cache.py,sha256=9p6C5lOz1pG-6k15PyvxlShUjBYIbU0ewpA8AX_YFus,297
|
|
53
53
|
cms_qe/settings/base/cms.py,sha256=8icCNxcEp_KRDyP8-LXB21UurJL4wNysY39whAyt3I4,1855
|
|
54
54
|
cms_qe/settings/base/constants.py,sha256=Rdq6ESg_J2B1Xm-ImEYM8pmsid-LqkSR7LXQdb3wlZU,7899
|
|
@@ -94,7 +94,7 @@ cms_qe_analytical/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
|
|
|
94
94
|
cms_qe_analytical/templatetags/google_analytics.py,sha256=cN87jJzwVcjhqSS2JKTmPt9WntuBLnzxEcwgjrQMJSg,7370
|
|
95
95
|
cms_qe_analytical/templatetags/piwik.py,sha256=EHOaojmewFpMqHzm_QCtCXGc_HGoiCJ_G-LPc8IfjM4,4131
|
|
96
96
|
cms_qe_auth/__init__.py,sha256=SZS-CdmFLgIN4WGaUX_780L-vH0lqC7CdxKWjm_EuxE,867
|
|
97
|
-
cms_qe_auth/admin.py,sha256=
|
|
97
|
+
cms_qe_auth/admin.py,sha256=PVxb9G_r6R4cyKvZUehENIN-aBSNDpqzA6O2gRbdQeQ,1135
|
|
98
98
|
cms_qe_auth/apps.py,sha256=YiIgOI3Bxj4-7IZdxUEvHmTK1xS9fR2qMS-fe5AZ-W0,191
|
|
99
99
|
cms_qe_auth/cms_menus.py,sha256=UxzzuMfOJCC_EiCkV2__6R5JKV9q1WGbTEgO7yLy8rE,1675
|
|
100
100
|
cms_qe_auth/cms_plugins.py,sha256=USiNHaWdIJqPFUMLOjhuVam4nwOckujg1uguXNIs798,1575
|
|
@@ -103,15 +103,15 @@ cms_qe_auth/forms.py,sha256=x7sdFoOrKBLTJXqESedpIh6Kc1k5zZhL4vwnmhj1gH8,1137
|
|
|
103
103
|
cms_qe_auth/models.py,sha256=Aro43D9y1zrS-3eKHVZEuSkchusDZAcj15B2vYcdt0Q,2713
|
|
104
104
|
cms_qe_auth/token.py,sha256=DG4Bu8AVV-d1ayL4Oc9DXNnERt1sstrll80RBGrplx0,224
|
|
105
105
|
cms_qe_auth/urls.py,sha256=RCgr9t1YonE0yR_8gXiXZIGESvQfrwVwlKhBOWmgxkw,2040
|
|
106
|
-
cms_qe_auth/utils.py,sha256=
|
|
106
|
+
cms_qe_auth/utils.py,sha256=94aELOVicanApvKkZ3xw5sFjd2C8AEzyCrHdgpFW8Pc,2790
|
|
107
107
|
cms_qe_auth/views.py,sha256=TG7kwG2xtRUt9S8nG3rUlNOU_BsfvRVybNexGpF_9uI,2233
|
|
108
108
|
cms_qe_auth/boilerplates/bootstrap3/templates/cms_qe/auth/login_form.html,sha256=nG9X-nvfXA4_9h4lVJGIHdcYFhf7sNEg_rVPa6ze9a4,884
|
|
109
109
|
cms_qe_auth/boilerplates/bootstrap3/templates/cms_qe/auth/password_change_form.html,sha256=1khb3qibf_YpVV2GyT6W9sgTMtFetNmjs2mbCdCFtIo,599
|
|
110
110
|
cms_qe_auth/boilerplates/bootstrap3/templates/cms_qe/auth/password_reset_confirm.html,sha256=5x4jB2vKZIRG5CSUxsKKHnSF0laVsUALR4Vqo7ZgQTU,920
|
|
111
111
|
cms_qe_auth/boilerplates/bootstrap3/templates/cms_qe/auth/password_reset_form.html,sha256=RforEA_H8W7EOIIFqeJtJ3H1FE8dsWgUW5vDVjzTIw4,571
|
|
112
112
|
cms_qe_auth/boilerplates/bootstrap3/templates/cms_qe/auth/register_form.html,sha256=oyq6uHRx2DHzSO1j-AlV99xgaoRgF9zXdetfOUz0JQs,653
|
|
113
|
-
cms_qe_auth/locale/cs/LC_MESSAGES/django.mo,sha256=
|
|
114
|
-
cms_qe_auth/locale/cs/LC_MESSAGES/django.po,sha256=
|
|
113
|
+
cms_qe_auth/locale/cs/LC_MESSAGES/django.mo,sha256=YhgQa3TxE9VvULZaMt4YJfC3HC8wU8pp_s4m2RMiXWU,6722
|
|
114
|
+
cms_qe_auth/locale/cs/LC_MESSAGES/django.po,sha256=pBsbpADrzEImaS-Ib4hCUGsW6sWC9MlbdXrpZsF5ZiM,11998
|
|
115
115
|
cms_qe_auth/locale/en/LC_MESSAGES/django.mo,sha256=1Oza0kFTJYv1uLpu51-XbZShcMmsgRMPdKVmSFB0mZk,378
|
|
116
116
|
cms_qe_auth/locale/en/LC_MESSAGES/django.po,sha256=oKfD16eQBOFiMYTJ_nMrhWiHUmTOqMkOEExuFfbZlb4,9205
|
|
117
117
|
cms_qe_auth/migrations/0001_initial.py,sha256=6cJuHqIgIqa2G5jhCJfGFh6tWdAShujT5PHK9S38MDI,3403
|
|
@@ -3971,8 +3971,8 @@ test_selenium/pages/cms/__init__.py,sha256=_qe4YZYaQbrXp7Szmmeo4TUSkXlE5Rozu8E3t
|
|
|
3971
3971
|
test_selenium/pages/cms/login.py,sha256=UPzJQcYff8NUAT4nvmfQoJQxzOJyPrJ_cKtH35NVfNg,521
|
|
3972
3972
|
test_selenium/pages/cms/page.py,sha256=YQnpZkopfVnhoyQKpRDGqjNeV6xUl-pEHjEcZ9HRiPk,489
|
|
3973
3973
|
test_selenium/pages/cms/wizard.py,sha256=yatbXH-rf1ap4O1hY0I13WikM3zkm_NrAiSK6bqENIU,545
|
|
3974
|
-
django_cms_qe-3.
|
|
3975
|
-
django_cms_qe-3.
|
|
3976
|
-
django_cms_qe-3.
|
|
3977
|
-
django_cms_qe-3.
|
|
3978
|
-
django_cms_qe-3.
|
|
3974
|
+
django_cms_qe-3.4.1.dist-info/LICENSE,sha256=5wLaeUil0gfU9p8C4zn2Yu_PvZBNieUoYl0z9FcFWdA,1521
|
|
3975
|
+
django_cms_qe-3.4.1.dist-info/METADATA,sha256=4GwpR4Vo-XJx0k4xZRWxwjzjr4i4DF3IIYEImvYNW_8,4677
|
|
3976
|
+
django_cms_qe-3.4.1.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
|
|
3977
|
+
django_cms_qe-3.4.1.dist-info/top_level.txt,sha256=T4dauFwJy7FmxCy7WoQI3pPwiDessNB2LkfOAP76ssE,172
|
|
3978
|
+
django_cms_qe-3.4.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|