Skip to content

Commit 5147aaf

Browse files
renzonrenzon
authored andcommitted
Sanitized email on register forms
Missing existing email sanitizing part of #1694
1 parent 0691bbb commit 5147aaf

File tree

7 files changed

+109
-7
lines changed

7 files changed

+109
-7
lines changed

pythonpro/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ def client_with_user(client, django_user_model, logged_user):
2020
@pytest.fixture
2121
def logged_user(django_user_model):
2222
logged_user = mommy.make(django_user_model)
23+
logged_user.email = logged_user.email.lower()
24+
logged_user.save()
2325
return logged_user
2426

2527

pythonpro/core/forms.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@
99
from pythonpro.core.models import User
1010

1111

12-
class UserEmailForm(ModelForm):
12+
class NormalizeEmailMixin:
13+
def _normalize_email(self):
14+
self.data = dict(self.data.items())
15+
email = self.data.get('email')
16+
if email is not None:
17+
self.data['email'] = email.lower()
18+
19+
20+
class UserEmailForm(ModelForm, NormalizeEmailMixin):
1321
current_password = CharField(label=_("Password"), strip=False, required=True)
1422

1523
class Meta:
@@ -19,6 +27,7 @@ class Meta:
1927
def __init__(self, *args, **kwargs):
2028
self.user = kwargs.pop('user')
2129
super().__init__(*args, **kwargs)
30+
self._normalize_email()
2231

2332
def clean(self):
2433
cleaned_data = super().clean()
@@ -27,7 +36,7 @@ def clean(self):
2736
return cleaned_data
2837

2938

30-
class UserSignupForm(UserCreationForm):
39+
class UserSignupForm(UserCreationForm, NormalizeEmailMixin):
3140
class Meta:
3241
model = User
3342
fields = ('first_name', 'email', 'source')
@@ -44,6 +53,7 @@ def __init__(self, *args, **kwargs):
4453
self._set_passwords(dct)
4554
args = (ChainMap(query_dict, dct), *args[1:])
4655
super().__init__(*args, **kwargs)
56+
self._normalize_email()
4757

4858
def _set_passwords(self, data):
4959
if 'password1' not in data and 'password2' not in data:

pythonpro/core/tests/test_lead_landing_page.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,56 @@ def create_lead_mock(mocker):
3232
return mocker.patch('pythonpro.domain.user_facade._email_marketing_facade.create_or_update_lead')
3333

3434

35+
@pytest.fixture()
36+
def email(fake):
37+
return fake.email()
38+
39+
3540
@pytest.fixture
36-
def resp_lead_creation(client, db, fake: Faker, create_lead_mock):
41+
def resp_lead_creation(client, db, fake: Faker, create_lead_mock, email):
3742
return client.post(
3843
reverse('core:lead_form') + '?utm_source=facebook',
3944
data={
4045
'first_name': fake.name(),
41-
'email': fake.email(),
46+
'email': email,
4247
},
4348
secure=True
4449
)
4550

4651

52+
def test_email_error_subscribing_with_email_variation(resp_lead_creation, email: str, fake, client):
53+
email_upercase = email.upper()
54+
resp = client.post(
55+
reverse('core:lead_form') + '?utm_source=facebook',
56+
data={
57+
'first_name': fake.name(),
58+
'email': email_upercase,
59+
},
60+
secure=True
61+
)
62+
63+
assert resp.status_code == 400
64+
65+
66+
@pytest.fixture
67+
def resp_email_upper_case(client, db, fake: Faker, create_lead_mock, email):
68+
email = email.upper()
69+
return client.post(
70+
reverse('core:lead_form') + '?utm_source=facebook',
71+
data={
72+
'first_name': fake.name(),
73+
'email': email,
74+
},
75+
secure=True
76+
)
77+
78+
79+
def test_email_normalization(resp_email_upper_case, email, django_user_model):
80+
email_lower = email.lower()
81+
user = django_user_model.objects.first()
82+
assert user.email == email_lower
83+
84+
4785
@pytest.fixture
4886
def resp_lead_change_pasword(resp_lead_creation, client):
4987
client.post(

pythonpro/core/tests/test_view_profile.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,25 @@ def test_edit_email_link(resp_with_user):
5454

5555
def test_edit_password_link(resp_with_user):
5656
dj_assert_contains(resp_with_user, reverse('core:profile_password'))
57+
58+
59+
@pytest.fixture
60+
def user_with_plain_password(django_user_model):
61+
plain_password = 'senha'
62+
u = mommy.make(django_user_model)
63+
u.set_password(plain_password)
64+
u.plain_password = plain_password
65+
u.save()
66+
return u
67+
68+
69+
def test_email_normalization(user_with_plain_password, client, django_user_model):
70+
client.force_login(user_with_plain_password)
71+
email = 'ALUNO@PYTHON.PRO.BR'
72+
client.post(
73+
reverse('core:profile_email'),
74+
{'email': email, 'current_password': user_with_plain_password.plain_password},
75+
secure=True
76+
)
77+
saved_user = django_user_model.objects.first()
78+
assert saved_user.email == email.lower()

pythonpro/core/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from django_sitemaps import Sitemap
1010
from rolepermissions.checkers import has_role
1111

12-
from pythonpro.core.forms import UserEmailForm, UserSignupForm, LeadForm
12+
from pythonpro.core.forms import LeadForm, UserEmailForm, UserSignupForm
1313
from pythonpro.core.models import User
1414
from pythonpro.domain import user_facade
1515

@@ -158,6 +158,6 @@ def lead_form(request):
158158
try:
159159
user = user_facade.register_lead(first_name, email, source)
160160
except user_facade.UserCreationException as e:
161-
return render(request, 'core/lead_form_errors.html', context={'form': e.form})
161+
return render(request, 'core/lead_form_errors.html', context={'form': e.form}, status=400)
162162
login(request, user)
163163
return redirect(reverse('payments:client_landing_page_oto'))

pythonpro/launch/forms.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
from django import forms
2+
from django.forms.utils import ErrorList
23

34

45
class LeadForm(forms.Form):
56
email = forms.EmailField(required=True)
7+
8+
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=ErrorList,
9+
label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None,
10+
renderer=None):
11+
super().__init__(data, files, auto_id, prefix, initial, error_class, label_suffix, empty_permitted, field_order,
12+
use_required_attribute, renderer)
13+
self._normalize_email()
14+
15+
def _normalize_email(self):
16+
self.data = dict(self.data.items())
17+
email = self.data.get('email')
18+
if email is not None:
19+
self.data['email'] = email.lower()
Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66

77
@pytest.fixture
88
def email(fake):
9-
return fake.email()
9+
return fake.email().lower()
10+
11+
12+
@pytest.fixture
13+
def email_upper(email):
14+
return email.upper()
1015

1116

1217
@pytest.fixture
@@ -19,6 +24,11 @@ def resp(client, email, create_or_update_with_no_role, cohort):
1924
return client.post(reverse('launch:lead_form'), {'email': email}, secure=True)
2025

2126

27+
@pytest.fixture
28+
def resp_email_upper(client, email_upper, create_or_update_with_no_role, cohort):
29+
return client.post(reverse('launch:lead_form'), {'email': email_upper}, secure=True)
30+
31+
2232
@pytest.fixture
2333
def invalid_email(email):
2434
return f'@{email}'
@@ -34,6 +44,12 @@ def test_email_marketing_sucess_integration(resp, email, create_or_update_with_n
3444
f'turma-{cohort.slug}-semana-do-programador')
3545

3646

47+
def test_email_normalization(resp_email_upper, email, create_or_update_with_no_role, cohort):
48+
first_name = email.split('@')[0]
49+
create_or_update_with_no_role.assert_called_once_with(first_name, email,
50+
f'turma-{cohort.slug}-semana-do-programador')
51+
52+
3753
@pytest.fixture
3854
def resp_with_error(client, invalid_email, create_or_update_with_no_role):
3955
return client.post(reverse('launch:lead_form'), {'email': invalid_email}, secure=True)

0 commit comments

Comments
 (0)