From 7b94efbabaac887f2fc05a56f62a32843a8214c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Justen=20=28=40turicas=29?= Date: Mon, 29 Mar 2021 17:56:15 -0300 Subject: [PATCH 01/18] =?UTF-8?q?Adiciona=20fun=C3=A7=C3=A3o=20que=20migra?= =?UTF-8?q?=20usernames=20(parcialmente)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brasilio_auth/auth_backend.py | 4 +- .../scripts/migrate_wrong_usernames.py | 60 +++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 brasilio_auth/scripts/migrate_wrong_usernames.py diff --git a/brasilio_auth/auth_backend.py b/brasilio_auth/auth_backend.py index 54929547..a80d737f 100644 --- a/brasilio_auth/auth_backend.py +++ b/brasilio_auth/auth_backend.py @@ -11,9 +11,9 @@ def authenticate(self, request, username=None, password=None, *args, **kwargs): return None elif "@" in username: # Won't allow anybody having "@" in username to log in - query = Q(email=username) + query = Q(email=username) # TODO: use lower of both else: - query = Q(username=username) + query = Q(username=username) # TODO: use lower of both try: user = User.objects.get(query) diff --git a/brasilio_auth/scripts/migrate_wrong_usernames.py b/brasilio_auth/scripts/migrate_wrong_usernames.py new file mode 100644 index 00000000..4f436f36 --- /dev/null +++ b/brasilio_auth/scripts/migrate_wrong_usernames.py @@ -0,0 +1,60 @@ +""" +TODO: relatar problema da issue de login +""" + +def possible_usernames(username, email): + """ + >>> possible_usernames('test@example.com', 'test@example.com') + ('test', 'test', 'test_example') + >>> possible_usernames('@test', 'test@example.com') + ('test', 'test', 'test_example') + >>> possible_usernames('test@', 'test@example.com') + ('test', 'test', 'test_example') + >>> possible_usernames('@test@', 'test@example.com') + ('test', 'test', 'test_example') + >>> possible_usernames('test@123', 'test@example.com') + ('test_123', 'test', 'test_example') + >>> possible_usernames('test@exampl.com', 'test@example.com') + ('test', 'test', 'test_example') + """ + username = username.strip() + email = email.strip() + + if username.lower() == email.lower(): + username = username.split("@")[0] + else: + if username.startswith("@"): + username = username[1:] + if username.endswith("@"): + username = username[:-1] + if "@" in username: + stop = username.find("@") + before, after = username[:stop], username[stop + 1:] + if "." in after: + username = before + else: + username = "_".join(username.split("@")) + + email_parts = email.split("@") + possible_2 = email_parts[0] + possible_3 = email_parts[0] + "_" + email_parts[1].split(".")[0] + return (username, possible_2, possible_3) + + +def migrate_usernames(): + # with open("/data/fixed-usernames.csv", mode="w") as fobj: + # writer = csv.DictWriter(fobj, fieldnames=["old_username", "new_username", "email"]) + for user in User.objects.filter(username__contains="@"): + possible = possible_usernames(user.username, user.email) + changed = False + for username in possible: + if not User.objects.filter(username=username).exists(): + # writer.writerow(...) + changed = True + # TODO: save user.email in CSV + # TODO: create script to send email + #user.username = new + #user.save() + pass + if not changed: + print(f"Conflict in: {user.username} / {user.email} (would be: {new} but already exists)") From 085e86e4918101c4d5ee7f9a409e880ed6c80455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Justen=20=28=40turicas=29?= Date: Mon, 29 Mar 2021 19:52:10 -0300 Subject: [PATCH 02/18] =?UTF-8?q?Altera=20maneira=20de=20buscar=20usu?= =?UTF-8?q?=C3=A1rios/emails?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brasilio_auth/auth_backend.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/brasilio_auth/auth_backend.py b/brasilio_auth/auth_backend.py index a80d737f..12bcd3d0 100644 --- a/brasilio_auth/auth_backend.py +++ b/brasilio_auth/auth_backend.py @@ -10,10 +10,9 @@ def authenticate(self, request, username=None, password=None, *args, **kwargs): if username is None: return None elif "@" in username: - # Won't allow anybody having "@" in username to log in - query = Q(email=username) # TODO: use lower of both + query = Q(email__iexact=username.strip()) else: - query = Q(username=username) # TODO: use lower of both + query = Q(username__iexact=username.strip()) try: user = User.objects.get(query) From 8e1c9c38112c40bd5fdc3d0ca2c7c9f50d1bb39f Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Mon, 29 Mar 2021 21:35:58 -0300 Subject: [PATCH 03/18] Valida caracteres especiais em username durante SignUp --- brasilio_auth/forms.py | 10 +++++++++- brasilio_auth/tests/test_forms.py | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/brasilio_auth/forms.py b/brasilio_auth/forms.py index af6b20ea..bdfb2f49 100644 --- a/brasilio_auth/forms.py +++ b/brasilio_auth/forms.py @@ -1,3 +1,5 @@ +import re + from django import forms from django.contrib.auth import get_user_model from django.utils.translation import gettext_lazy as _ @@ -24,7 +26,13 @@ class Meta: def clean_username(self): username = self.cleaned_data.get("username", "") - return username.lower() + username = username.lower() + non_valid_chars = re.search(r"[^a-z0-9_]", username) + if non_valid_chars: + raise forms.ValidationError( + "Nome de usário somente pode conter letras, números e '_'" + ) + return username def clean_email(self): email = self.cleaned_data.get("email") diff --git a/brasilio_auth/tests/test_forms.py b/brasilio_auth/tests/test_forms.py index 7a4225b6..659db13e 100644 --- a/brasilio_auth/tests/test_forms.py +++ b/brasilio_auth/tests/test_forms.py @@ -142,6 +142,21 @@ def test_do_not_validate_if_bad_captcha(self): assert not form.is_valid() assert "captcha" in form.errors + @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) + def test_invalid_username_characters(self): + passwd = "verygoodpassword" + data = { + "username": "foo@", + "email": "foo@bar.com", + "password1": passwd, + "password2": passwd, + "captcha": "captcha-validation", + } + + form = UserCreationForm(data) + assert not form.is_valid() + assert "username" in form.errors + class TestTokenApiManagementForm(TestCase): def test_required_fields(self): From 780121cc904746c3627d45bbe036eb2a6fdbf8e2 Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Mon, 29 Mar 2021 21:50:10 -0300 Subject: [PATCH 04/18] Mostra mensagens de erro do Form --- brasilio_auth/templates/brasilio_auth/login.html | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/brasilio_auth/templates/brasilio_auth/login.html b/brasilio_auth/templates/brasilio_auth/login.html index d180a719..8fa21332 100644 --- a/brasilio_auth/templates/brasilio_auth/login.html +++ b/brasilio_auth/templates/brasilio_auth/login.html @@ -7,9 +7,18 @@

Login

{% if form.errors %} -

- Senha inválida. Por favor tente novamente. -

+ {% for field in form %} + {% for error in field.errors %} +

+ {{ error|escape }} +

+ {% endfor %} + {% endfor %} + {% for error in form.non_field_errors %} +

+ {{ error|escape }} +

+ {% endfor %} {% endif %} {% if next %} From ec726211169bdb098b72d223c0b8d25e8342d7ba Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Tue, 30 Mar 2021 10:55:46 -0300 Subject: [PATCH 05/18] =?UTF-8?q?Refatora=20e=20implementa=20testes=20para?= =?UTF-8?q?=20script=20de=20corre=C3=A7=C3=A3o=20de=20usernames?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scripts/migrate_wrong_usernames.py | 79 ++++++----- brasilio_auth/tests/test_scripts.py | 124 ++++++++++++++++++ 2 files changed, 167 insertions(+), 36 deletions(-) create mode 100644 brasilio_auth/tests/test_scripts.py diff --git a/brasilio_auth/scripts/migrate_wrong_usernames.py b/brasilio_auth/scripts/migrate_wrong_usernames.py index 4f436f36..eb44279b 100644 --- a/brasilio_auth/scripts/migrate_wrong_usernames.py +++ b/brasilio_auth/scripts/migrate_wrong_usernames.py @@ -1,22 +1,23 @@ """ -TODO: relatar problema da issue de login +Anteriormente, os usuários podiam cadastrar seu username utilizando o caractere +inválido '@'. +Este script corrige esse problema alterando os usernames que contem '@' por +variações únicas baseadas no nome de usuário e/ou no e-mail de cada registro. + +Exemplo: + old_username = 'name@' + new_username = 'name' """ +import csv +from typing import Tuple + +from django.contrib.auth import get_user_model + + +User = get_user_model() -def possible_usernames(username, email): - """ - >>> possible_usernames('test@example.com', 'test@example.com') - ('test', 'test', 'test_example') - >>> possible_usernames('@test', 'test@example.com') - ('test', 'test', 'test_example') - >>> possible_usernames('test@', 'test@example.com') - ('test', 'test', 'test_example') - >>> possible_usernames('@test@', 'test@example.com') - ('test', 'test', 'test_example') - >>> possible_usernames('test@123', 'test@example.com') - ('test_123', 'test', 'test_example') - >>> possible_usernames('test@exampl.com', 'test@example.com') - ('test', 'test', 'test_example') - """ + +def possible_usernames(username:str, email:str, n_suffix:int = 10) -> Tuple[str, ...]: username = username.strip() email = email.strip() @@ -38,23 +39,29 @@ def possible_usernames(username, email): email_parts = email.split("@") possible_2 = email_parts[0] possible_3 = email_parts[0] + "_" + email_parts[1].split(".")[0] - return (username, possible_2, possible_3) - - -def migrate_usernames(): - # with open("/data/fixed-usernames.csv", mode="w") as fobj: - # writer = csv.DictWriter(fobj, fieldnames=["old_username", "new_username", "email"]) - for user in User.objects.filter(username__contains="@"): - possible = possible_usernames(user.username, user.email) - changed = False - for username in possible: - if not User.objects.filter(username=username).exists(): - # writer.writerow(...) - changed = True - # TODO: save user.email in CSV - # TODO: create script to send email - #user.username = new - #user.save() - pass - if not changed: - print(f"Conflict in: {user.username} / {user.email} (would be: {new} but already exists)") + possible_with_suffix = [f"{username}_{i}" for i in range(1, n_suffix)] + return (username, possible_2, possible_3, *possible_with_suffix) + + +def migrate_usernames(filepath=None): + filepath = filepath or "/data/fixed-usernames.csv" + with open(filepath, mode="w") as fobj: + writer = csv.DictWriter( + fobj, fieldnames=["old_username", "new_username", "email"] + ) + writer.writeheader() + for user in User.objects.filter(username__contains="@"): + possible = possible_usernames(user.username, user.email) + changed = False + for username in possible: + if not User.objects.filter(username=username).exists() and not changed: + writer.writerow( + { + "old_username": user.username, + "new_username": username, + "email": user.email + } + ) + changed = True + user.username = username + user.save() diff --git a/brasilio_auth/tests/test_scripts.py b/brasilio_auth/tests/test_scripts.py new file mode 100644 index 00000000..8de86960 --- /dev/null +++ b/brasilio_auth/tests/test_scripts.py @@ -0,0 +1,124 @@ +from tempfile import NamedTemporaryFile + +from django.contrib.auth import get_user_model +from django.test import TestCase +from model_bakery import baker +from brasilio_auth.scripts.migrate_wrong_usernames import ( + possible_usernames, + migrate_usernames, +) + + +User = get_user_model() + + +class TestPossibleUsernames(TestCase): + def test_username_equal_to_email(self): + username = "test@example.com" + email = "test@example.com" + + possible_values = possible_usernames(username, email, n_suffix=2) + expected = ("test", "test", "test_example", "test_1") + + assert possible_values == expected + + def test_username_with_invalid_char_at_the_beginning(self): + username = "@test" + email = "test@example.com" + + possible_values = possible_usernames(username, email, n_suffix=2) + expected = ("test", "test", "test_example", "test_1") + + assert possible_values == expected + + def test_username_with_invalid_char_at_the_end(self): + username = "test@" + email = "test@example.com" + + possible_values = possible_usernames(username, email, n_suffix=2) + expected = ("test", "test", "test_example", "test_1") + + assert possible_values == expected + + def test_username_with_invalid_char_at_the_both_ends(self): + username = "@test@" + email = "test@example.com" + + possible_values = possible_usernames(username, email, n_suffix=2) + expected = ("test", "test", "test_example", "test_1") + + assert possible_values == expected + + def test_replace_invalid_char_with_undescore(self): + username = "test@123" + email = "test@example.com" + + possible_values = possible_usernames(username, email, n_suffix=2) + expected = ("test_123", "test", "test_example", "test_123_1") + + assert possible_values == expected + + def test_combine_email_with_domain_name(self): + username = "test@exampl.com" + email = "test@example.com" + + possible_values = possible_usernames(username, email, n_suffix=2) + expected = ("test", "test", "test_example", "test_1") + + assert possible_values == expected + + def test_create_more_possibilities_with_suffixes(self): + username = "test@exampl.com" + email = "test@example.com" + + possible_values = possible_usernames(username, email, n_suffix=3) + expected = ("test", "test", "test_example", "test_1", "test_2") + + assert possible_values == expected + + +class TestReplaceUsernameWithSuggestions(TestCase): + def setUp(self): + self.user_1 = baker.make( + User, + username="test@", + email="test@example.com", + ) + self.expected_username_1 = "test" + + self.user_2 = baker.make( + User, + username="@test@", + email="name@example.com" + ) + # teste would already exists because of self.username_1 + self.expected_username_2 = "name" + + self.temp_file = NamedTemporaryFile(mode="r") + self.expected_csv = ( + "old_username,new_username,email\n" + "test@,test,test@example.com\n" + "@test@,name,name@example.com\n" + ) + + def test_happy_path_wrong_usernames_replacement(self): + migrate_usernames(filepath=self.temp_file.name) + + self.user_1.refresh_from_db() + self.user_2.refresh_from_db() + self.temp_file.seek(0) + + assert self.user_1.username == self.expected_username_1 + assert self.user_2.username == self.expected_username_2 + assert self.temp_file.read() == self.expected_csv + + def test_all_combinations_of_user_1_already_exists(self): + baker.make(User, username="test") + baker.make(User, username="test_example") + + migrate_usernames(self.temp_file.name) + self.expected_username_1 = "test_1" + + self.user_1.refresh_from_db() + + assert self.user_1.username == self.expected_username_1 From d15b647fb28afdad25dc7fa33bd5bc866b5695a6 Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Tue, 30 Mar 2021 11:03:29 -0300 Subject: [PATCH 06/18] Transforma script em RunsScript --- brasilio_auth/scripts/migrate_wrong_usernames.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/brasilio_auth/scripts/migrate_wrong_usernames.py b/brasilio_auth/scripts/migrate_wrong_usernames.py index eb44279b..b0fbaec0 100644 --- a/brasilio_auth/scripts/migrate_wrong_usernames.py +++ b/brasilio_auth/scripts/migrate_wrong_usernames.py @@ -43,8 +43,7 @@ def possible_usernames(username:str, email:str, n_suffix:int = 10) -> Tuple[str, return (username, possible_2, possible_3, *possible_with_suffix) -def migrate_usernames(filepath=None): - filepath = filepath or "/data/fixed-usernames.csv" +def migrate_usernames(filepath): with open(filepath, mode="w") as fobj: writer = csv.DictWriter( fobj, fieldnames=["old_username", "new_username", "email"] @@ -65,3 +64,8 @@ def migrate_usernames(filepath=None): changed = True user.username = username user.save() + + +def run(): + filepath = "/data/fixed-usernames.csv" + migrate_usernames(filepath) From 3cf41887fcda149011c3e64dc9b0c727f64bfc1d Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Tue, 30 Mar 2021 21:31:22 -0300 Subject: [PATCH 07/18] =?UTF-8?q?Ajusta=20identa=C3=A7=C3=A3o=20em=20html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brasilio_auth/templates/brasilio_auth/login.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/brasilio_auth/templates/brasilio_auth/login.html b/brasilio_auth/templates/brasilio_auth/login.html index 8fa21332..c61cffea 100644 --- a/brasilio_auth/templates/brasilio_auth/login.html +++ b/brasilio_auth/templates/brasilio_auth/login.html @@ -9,14 +9,14 @@

Login

{% if form.errors %} {% for field in form %} {% for error in field.errors %} -

+

{{ error|escape }}

{% endfor %} {% endfor %} {% for error in form.non_field_errors %} -

- {{ error|escape }} +

+ {{ error|escape }}

{% endfor %} {% endif %} From 527c4b10b22853831ba974e056db23f641976575 Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Tue, 30 Mar 2021 21:34:07 -0300 Subject: [PATCH 08/18] =?UTF-8?q?Utilza=20break=20ao=20inv=C3=A9s=20de=20c?= =?UTF-8?q?hanged?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brasilio_auth/scripts/migrate_wrong_usernames.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/brasilio_auth/scripts/migrate_wrong_usernames.py b/brasilio_auth/scripts/migrate_wrong_usernames.py index b0fbaec0..db072176 100644 --- a/brasilio_auth/scripts/migrate_wrong_usernames.py +++ b/brasilio_auth/scripts/migrate_wrong_usernames.py @@ -51,9 +51,8 @@ def migrate_usernames(filepath): writer.writeheader() for user in User.objects.filter(username__contains="@"): possible = possible_usernames(user.username, user.email) - changed = False for username in possible: - if not User.objects.filter(username=username).exists() and not changed: + if not User.objects.filter(username=username).exists(): writer.writerow( { "old_username": user.username, @@ -61,9 +60,9 @@ def migrate_usernames(filepath): "email": user.email } ) - changed = True user.username = username user.save() + break def run(): From c3a4541d3d4a278ae9467aa776cfd9acab28b168 Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Tue, 30 Mar 2021 21:37:21 -0300 Subject: [PATCH 09/18] =?UTF-8?q?Utiliza=20vers=C3=A3o=20compilada=20de=20?= =?UTF-8?q?regex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brasilio_auth/forms.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/brasilio_auth/forms.py b/brasilio_auth/forms.py index bdfb2f49..394d04f3 100644 --- a/brasilio_auth/forms.py +++ b/brasilio_auth/forms.py @@ -8,6 +8,9 @@ from utils.forms import FlagedReCaptchaField as ReCaptchaField +USERNAME_REGEXP = re.compile(r"[^a-z0-9_]") + + class UserCreationForm(RegistrationFormUniqueEmail): username = forms.CharField(widget=forms.TextInput(attrs={"style": "text-transform: lowercase"}),) email = forms.EmailField() @@ -27,7 +30,7 @@ class Meta: def clean_username(self): username = self.cleaned_data.get("username", "") username = username.lower() - non_valid_chars = re.search(r"[^a-z0-9_]", username) + non_valid_chars = USERNAME_REGEXP.search(username) if non_valid_chars: raise forms.ValidationError( "Nome de usário somente pode conter letras, números e '_'" From 2a4c0c3666041104acbe6f988aaa272e5831ac87 Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Tue, 30 Mar 2021 21:45:19 -0300 Subject: [PATCH 10/18] =?UTF-8?q?Remove=20trecho=20que=20for=C3=A7a=20user?= =?UTF-8?q?name=20para=20caixa=20baixa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brasilio_auth/forms.py | 3 +-- brasilio_auth/tests/test_forms.py | 34 +++++++++++++++---------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/brasilio_auth/forms.py b/brasilio_auth/forms.py index 394d04f3..961a5478 100644 --- a/brasilio_auth/forms.py +++ b/brasilio_auth/forms.py @@ -8,7 +8,7 @@ from utils.forms import FlagedReCaptchaField as ReCaptchaField -USERNAME_REGEXP = re.compile(r"[^a-z0-9_]") +USERNAME_REGEXP = re.compile(r"[^A-Za-z0-9_]") class UserCreationForm(RegistrationFormUniqueEmail): @@ -29,7 +29,6 @@ class Meta: def clean_username(self): username = self.cleaned_data.get("username", "") - username = username.lower() non_valid_chars = USERNAME_REGEXP.search(username) if non_valid_chars: raise forms.ValidationError( diff --git a/brasilio_auth/tests/test_forms.py b/brasilio_auth/tests/test_forms.py index 659db13e..3a59f11a 100644 --- a/brasilio_auth/tests/test_forms.py +++ b/brasilio_auth/tests/test_forms.py @@ -42,24 +42,6 @@ def test_create_user(self): assert user.check_password(passwd) is True assert not NewsletterSubscriber.objects.filter(user=user).exists() - @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) - def test_force_lower_for_username(self): - passwd = "verygoodpassword" - data = { - "username": "FOO", - "email": "foo@bar.com", - "password1": passwd, - "password2": passwd, - "captcha": "captcha-validation", - } - - form = UserCreationForm(data) - assert form.is_valid() is True - user = form.save() - user.refresh_from_db() - - assert "foo" == user.username - @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) def test_respect_abstract_user_max_length_for_username(self): passwd = "verygoodpassword" @@ -157,6 +139,22 @@ def test_invalid_username_characters(self): assert not form.is_valid() assert "username" in form.errors + @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) + def test_do_not_set_username_to_lowercase(self): + passwd = "verygoodpassword" + username = "Foo" + data = { + "username": username, + "email": "foo@bar.com", + "password1": passwd, + "password2": passwd, + "captcha": "captcha-validation", + } + + form = UserCreationForm(data) + assert form.is_valid() + assert form.cleaned_data["username"] == username + class TestTokenApiManagementForm(TestCase): def test_required_fields(self): From fecc89fa1753aa50205be28397d266e1c73fc074 Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Wed, 31 Mar 2021 13:04:24 -0300 Subject: [PATCH 11/18] Utiliza background para colocar @ em input de username --- static/css/base.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/static/css/base.css b/static/css/base.css index 8f6b56af..7c9fbf6e 100644 --- a/static/css/base.css +++ b/static/css/base.css @@ -202,3 +202,10 @@ a { color: #ee6e73; font-size: 1rem; } + +#id_username { + background: url('data:image/svg+xml;utf8,@') no-repeat; + padding-left: 1.4rem !important; + width: 100%; + box-sizing: border-box !important; +} From 1db945f744a500ae2674c11e1725a45f7b95315f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Justen=20=28=40turicas=29?= Date: Fri, 2 Apr 2021 19:51:48 -0300 Subject: [PATCH 12/18] =?UTF-8?q?Corrige=20todos=20os=20usernames=20inv?= =?UTF-8?q?=C3=A1lidos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scripts/migrate_wrong_usernames.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/brasilio_auth/scripts/migrate_wrong_usernames.py b/brasilio_auth/scripts/migrate_wrong_usernames.py index db072176..913c20c9 100644 --- a/brasilio_auth/scripts/migrate_wrong_usernames.py +++ b/brasilio_auth/scripts/migrate_wrong_usernames.py @@ -9,12 +9,16 @@ new_username = 'name' """ import csv +import string from typing import Tuple from django.contrib.auth import get_user_model +from rows.utils import slug +from brasilio_auth.forms import UserCreationForm User = get_user_model() +possible_chars = string.ascii_letters + string.digits + "_" def possible_usernames(username:str, email:str, n_suffix:int = 10) -> Tuple[str, ...]: @@ -49,8 +53,17 @@ def migrate_usernames(filepath): fobj, fieldnames=["old_username", "new_username", "email"] ) writer.writeheader() - for user in User.objects.filter(username__contains="@"): - possible = possible_usernames(user.username, user.email) + for user in User.objects.all(): + if user.username.lower() == slug(user.username, permitted_chars=possible_chars): + # Valid username + continue + + # Define possible usernames based on current and remove any + # non-allowed chars + possible = [ + slug(username, permitted_chars=possible_chars) + for username in possible_usernames(user.username, user.email) + ] for username in possible: if not User.objects.filter(username=username).exists(): writer.writerow( @@ -63,6 +76,7 @@ def migrate_usernames(filepath): user.username = username user.save() break + print(f"ERROR: could not migrate {user} (tried: {', '.join(possible)})") def run(): From bce011e9de0ff5376f4112b6751fcf6bfb222bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Justen=20=28=40turicas=29?= Date: Fri, 2 Apr 2021 21:54:35 -0300 Subject: [PATCH 13/18] =?UTF-8?q?N=C3=A3o=20permite=20usu=C3=A1rios=20some?= =?UTF-8?q?nte=20com=20d=C3=ADgitos=20e=20pontua=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Isso evita que usuários coloquem seus CPFs como usernames (não queremos armazenar dados sensíveis). --- api/admin.py | 2 -- brasilio_auth/forms.py | 16 +++++++++---- .../scripts/migrate_wrong_usernames.py | 5 ++-- brasilio_auth/tests/test_forms.py | 23 +++++++++++++++++++ 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/api/admin.py b/api/admin.py index a849b138..6f013c63 100644 --- a/api/admin.py +++ b/api/admin.py @@ -3,8 +3,6 @@ from api.models import Token -User = get_user_model() - class TokenAdmin(admin.ModelAdmin): list_display = ("key", "user", "created") diff --git a/brasilio_auth/forms.py b/brasilio_auth/forms.py index 961a5478..3231e19b 100644 --- a/brasilio_auth/forms.py +++ b/brasilio_auth/forms.py @@ -9,6 +9,15 @@ USERNAME_REGEXP = re.compile(r"[^A-Za-z0-9_]") +PUNCT_REGEXP = re.compile("[-/ .]") + + +def is_valid_username(username): + return not ( + PUNCT_REGEXP.sub("", username).isdigit() + or + USERNAME_REGEXP.search(username) + ) class UserCreationForm(RegistrationFormUniqueEmail): @@ -28,11 +37,10 @@ class Meta: fields = ("username", "email") def clean_username(self): - username = self.cleaned_data.get("username", "") - non_valid_chars = USERNAME_REGEXP.search(username) - if non_valid_chars: + username = self.cleaned_data.get("username", "").strip() + if not is_valid_username(username): raise forms.ValidationError( - "Nome de usário somente pode conter letras, números e '_'" + "Nome de usuário pode conter apenas letras, números e '_' e não deve ser um documento" ) return username diff --git a/brasilio_auth/scripts/migrate_wrong_usernames.py b/brasilio_auth/scripts/migrate_wrong_usernames.py index 913c20c9..e78ad622 100644 --- a/brasilio_auth/scripts/migrate_wrong_usernames.py +++ b/brasilio_auth/scripts/migrate_wrong_usernames.py @@ -15,7 +15,7 @@ from django.contrib.auth import get_user_model from rows.utils import slug -from brasilio_auth.forms import UserCreationForm +from brasilio_auth.forms import is_valid_username User = get_user_model() possible_chars = string.ascii_letters + string.digits + "_" @@ -54,8 +54,7 @@ def migrate_usernames(filepath): ) writer.writeheader() for user in User.objects.all(): - if user.username.lower() == slug(user.username, permitted_chars=possible_chars): - # Valid username + if is_valid_username(user.username): continue # Define possible usernames based on current and remove any diff --git a/brasilio_auth/tests/test_forms.py b/brasilio_auth/tests/test_forms.py index 3a59f11a..27e46541 100644 --- a/brasilio_auth/tests/test_forms.py +++ b/brasilio_auth/tests/test_forms.py @@ -11,6 +11,10 @@ class UserCreationFormTests(TestCase): + username_invalid_error = "Nome de usuário pode conter apenas letras, números e '_' e não deve ser um documento" + username_max_length_error = "Certifique-se de que o valor tenha no máximo 150 caracteres (ele possui 151)." + username_exists_error = "Um usuário com este nome de usuário já existe." + def test_required_fields(self): required_fields = ["username", "email", "password1", "password2", "captcha"] @@ -60,6 +64,7 @@ def test_respect_abstract_user_max_length_for_username(self): form = UserCreationForm(data) assert not form.is_valid() assert "username" in form.errors + assert form.errors["username"] == [self.username_max_length_error] @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) def test_invalid_username_if_already_exists(self): @@ -76,6 +81,7 @@ def test_invalid_username_if_already_exists(self): form = UserCreationForm(data) assert form.is_valid() is False assert "username" in form.errors + assert form.errors["username"] == [self.username_exists_error] @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) def test_invalid_email_if_user_already_exists(self): @@ -138,6 +144,23 @@ def test_invalid_username_characters(self): form = UserCreationForm(data) assert not form.is_valid() assert "username" in form.errors + assert form.errors["username"] == [self.username_invalid_error] + + @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) + def test_invalid_username_digits(self): + passwd = "verygoodpassword" + data = { + "username": "123.456.789-01", + "email": "foo@bar.com", + "password1": passwd, + "password2": passwd, + "captcha": "captcha-validation", + } + + form = UserCreationForm(data) + assert not form.is_valid() + assert "username" in form.errors + assert form.errors["username"] == [self.username_invalid_error] @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) def test_do_not_set_username_to_lowercase(self): From 5312728ccb86f7bae49fc083f43af2198e629ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Justen=20=28=40turicas=29?= Date: Sat, 3 Apr 2021 01:25:11 -0300 Subject: [PATCH 14/18] =?UTF-8?q?Garante=20username=20=C3=BAnico=20com=20n?= =?UTF-8?q?ovo=20teste?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brasilio_auth/forms.py | 8 +++++--- brasilio_auth/tests/test_forms.py | 18 +++++++++++------- brasilio_auth/tests/test_views.py | 19 +++++++++++++++++-- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/brasilio_auth/forms.py b/brasilio_auth/forms.py index 3231e19b..8c093c73 100644 --- a/brasilio_auth/forms.py +++ b/brasilio_auth/forms.py @@ -10,6 +10,7 @@ USERNAME_REGEXP = re.compile(r"[^A-Za-z0-9_]") PUNCT_REGEXP = re.compile("[-/ .]") +User = get_user_model() def is_valid_username(username): @@ -42,13 +43,14 @@ def clean_username(self): raise forms.ValidationError( "Nome de usuário pode conter apenas letras, números e '_' e não deve ser um documento" ) + elif username and User.objects.filter(username__iexact=username).exists(): + raise forms.ValidationError(f"Nome de usuário já existente (escolha um diferente).") return username def clean_email(self): email = self.cleaned_data.get("email") - if email: - if get_user_model().objects.filter(email__iexact=email).exists(): - raise forms.ValidationError(f"Usuário com o email {email} já cadastrado.") + if email and User.objects.filter(email__iexact=email).exists(): + raise forms.ValidationError(f"Usuário com o email {email} já cadastrado.") return email diff --git a/brasilio_auth/tests/test_forms.py b/brasilio_auth/tests/test_forms.py index 27e46541..717d59eb 100644 --- a/brasilio_auth/tests/test_forms.py +++ b/brasilio_auth/tests/test_forms.py @@ -13,7 +13,7 @@ class UserCreationFormTests(TestCase): username_invalid_error = "Nome de usuário pode conter apenas letras, números e '_' e não deve ser um documento" username_max_length_error = "Certifique-se de que o valor tenha no máximo 150 caracteres (ele possui 151)." - username_exists_error = "Um usuário com este nome de usuário já existe." + username_exists_error = "Nome de usuário já existente (escolha um diferente)." def test_required_fields(self): required_fields = ["username", "email", "password1", "password2", "captcha"] @@ -51,7 +51,7 @@ def test_respect_abstract_user_max_length_for_username(self): passwd = "verygoodpassword" data = { "username": "a" * 150, - "email": "foo@bar.com", + "email": "another_foo@bar.com", "password1": passwd, "password2": passwd, "captcha": "captcha-validation", @@ -64,6 +64,7 @@ def test_respect_abstract_user_max_length_for_username(self): form = UserCreationForm(data) assert not form.is_valid() assert "username" in form.errors + assert "email" not in form.errors assert form.errors["username"] == [self.username_max_length_error] @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) @@ -72,7 +73,7 @@ def test_invalid_username_if_already_exists(self): passwd = "verygoodpassword" data = { "username": "foo", - "email": "foo@bar.com", + "email": "another_foo@bar.com", "password1": passwd, "password2": passwd, "captcha": "captcha-validation", @@ -81,14 +82,15 @@ def test_invalid_username_if_already_exists(self): form = UserCreationForm(data) assert form.is_valid() is False assert "username" in form.errors + assert "email" not in form.errors assert form.errors["username"] == [self.username_exists_error] @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) def test_invalid_email_if_user_already_exists(self): - baker.make(settings.AUTH_USER_MODEL, email="foo@bar.com") + baker.make(settings.AUTH_USER_MODEL, email="foo@bar.com", username="foo") passwd = "verygoodpassword" data = { - "username": "foo", + "username": "another_foo", "email": "foo@bar.com", "password1": passwd, "password2": passwd, @@ -98,13 +100,14 @@ def test_invalid_email_if_user_already_exists(self): form = UserCreationForm(data) assert not form.is_valid() assert "email" in form.errors + assert "username" not in form.errors @patch.object(ReCaptchaField, "validate", Mock(return_value=True)) def test_email_validation_does_not_break_if_different_letter_case(self): - baker.make(settings.AUTH_USER_MODEL, email="foo@bar.com") + baker.make(settings.AUTH_USER_MODEL, email="foo@bar.com", username="foo") passwd = "verygoodpassword" data = { - "username": "foo", + "username": "another_foo", "email": "FOO@bar.com", "password1": passwd, "password2": passwd, @@ -114,6 +117,7 @@ def test_email_validation_does_not_break_if_different_letter_case(self): form = UserCreationForm(data) assert not form.is_valid() assert "email" in form.errors + assert "username" not in form.errors def test_do_not_validate_if_bad_captcha(self): passwd = "verygoodpassword" diff --git a/brasilio_auth/tests/test_views.py b/brasilio_auth/tests/test_views.py index 650f0fe3..13088c79 100644 --- a/brasilio_auth/tests/test_views.py +++ b/brasilio_auth/tests/test_views.py @@ -76,11 +76,26 @@ def test_form_error_if_trying_to_create_user_with_existing_username(self): response = self.client.post(self.url, data=self.data) assert User.objects.filter(username="foo").exists() - self.data["username"] = "FOO" + new_username = "foo" + assert new_username == self.data["username"] # same capitalization + self.data["username"] = new_username + self.data["email"] = "new@foo.com" + response = self.client.post(self.url, data=self.data) + self.assertTemplateUsed(response, "brasilio_auth/user_creation_form.html") + assert bool(response.context["form"].errors) is True + + def test_form_error_if_trying_to_create_user_with_existing_username_uppercase(self): + response = self.client.post(self.url, data=self.data) + assert User.objects.filter(username="foo").exists() + + new_username = "FOO" + # same username, different capitalization + assert new_username.lower() == self.data["username"].lower() + assert new_username != self.data["username"] + self.data["username"] = new_username self.data["email"] = "new@foo.com" response = self.client.post(self.url, data=self.data) self.assertTemplateUsed(response, "brasilio_auth/user_creation_form.html") - print(response.context["form"].errors) assert bool(response.context["form"].errors) is True From 4c74b9bb794b4c9ac1d13589775af049a2952cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Justen=20=28=40turicas=29?= Date: Sat, 3 Apr 2021 01:39:38 -0300 Subject: [PATCH 15/18] Corrige testes (faltava a API em ALLOWED_HOSTS) --- api/tests/test_views.py | 12 ++++++++++-- core/tests/test_views.py | 1 + env.example | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/api/tests/test_views.py b/api/tests/test_views.py index cb428d85..4d20463a 100644 --- a/api/tests/test_views.py +++ b/api/tests/test_views.py @@ -153,7 +153,11 @@ def test_redirects(self): assert "/api/v1/datasets/" == path_assertions[0][1] def test_redirects_from_api_host(self): - self.client.force_login(baker.make(User)) + settings.ALLOWED_HOSTS.append(settings.BRASILIO_API_HOST) + user = baker.make(User, is_active=True) + self.client.force_login(user) + token = baker.make("api.Token", user=user) + auth_header = {"HTTP_AUTHORIZATION": f"Token {token.key}"} urlconf = settings.API_ROOT_URLCONF path_assertions = [ @@ -170,7 +174,11 @@ def test_redirects_from_api_host(self): ] for url, redirect_url in path_assertions: - response = self.client.get(url, HTTP_HOST=settings.BRASILIO_API_HOST) + response = self.client.get( + url, + HTTP_HOST=settings.BRASILIO_API_HOST, + **auth_header, + ) self.assertRedirects(response, redirect_url, msg_prefix=url, fetch_redirect_response=False, status_code=301) assert "/datasets/" == path_assertions[0][0] diff --git a/core/tests/test_views.py b/core/tests/test_views.py index 0a9bf0c7..1c9375dc 100644 --- a/core/tests/test_views.py +++ b/core/tests/test_views.py @@ -100,6 +100,7 @@ def test_enforce_rate_limit_if_flagged(self, mocked_ratelimit): @override_settings(RATELIMIT_RATE="0/s") @patch("traffic_control.decorators.ratelimit") def test_enforce_rate_limit_if_flagged_for_api(self, mocked_ratelimit): + settings.ALLOWED_HOSTS.append(settings.BRASILIO_API_HOST) urlconf = settings.API_ROOT_URLCONF self.url = reverse("v1:dataset-table-data", args=["sample", "sample_table"], urlconf=urlconf) response = self.client.get(self.url, HTTP_HOST=settings.BRASILIO_API_HOST) diff --git a/env.example b/env.example index 7efdc033..8163e6e2 100644 --- a/env.example +++ b/env.example @@ -6,7 +6,7 @@ POSTGRES_PASSWORD=postgres POSTGRES_DB=brasilio # Django settings -ALLOWED_HOSTS=localhost +ALLOWED_HOSTS=localhost,api.brasil.io APP_HOST="localhost:8000" BLOCKED_AGENTS="Wget,curl,python-requests,Python-urllib" DATABASE_URL=postgres://postgres:postgres@db:5432/brasilio From fa5f21b3bf8974615ffe5c25da0d5a8b7ded253b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Justen=20=28=40turicas=29?= Date: Sat, 3 Apr 2021 01:50:55 -0300 Subject: [PATCH 16/18] =?UTF-8?q?Remove=20forms=20desnecess=C3=A1rios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- api/admin.py | 1 - api/tests/test_views.py | 6 +-- brasilio/settings.py | 2 - brasilio_auth/forms.py | 9 +--- .../scripts/migrate_wrong_usernames.py | 16 ++---- brasilio_auth/tests/test_scripts.py | 21 ++------ core/forms.py | 49 ------------------- core/views_special.py | 1 - utils/rocketchat.py | 3 +- 10 files changed, 14 insertions(+), 96 deletions(-) diff --git a/Makefile b/Makefile index 93588be9..3e0a01be 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ lint: autoflake --in-place --recursive --remove-unused-variables --remove-all-unused-imports . isort --skip migrations --skip brasilio/wsgi.py -rc . black . --exclude "docker" -l 120 - flake8 + flake8 --ignore=E203,E231 test: pytest diff --git a/api/admin.py b/api/admin.py index 6f013c63..44e92cbc 100644 --- a/api/admin.py +++ b/api/admin.py @@ -1,5 +1,4 @@ from django.contrib import admin -from django.contrib.auth import get_user_model from api.models import Token diff --git a/api/tests/test_views.py b/api/tests/test_views.py index 4d20463a..5a99e8b1 100644 --- a/api/tests/test_views.py +++ b/api/tests/test_views.py @@ -174,11 +174,7 @@ def test_redirects_from_api_host(self): ] for url, redirect_url in path_assertions: - response = self.client.get( - url, - HTTP_HOST=settings.BRASILIO_API_HOST, - **auth_header, - ) + response = self.client.get(url, HTTP_HOST=settings.BRASILIO_API_HOST, **auth_header,) self.assertRedirects(response, redirect_url, msg_prefix=url, fetch_redirect_response=False, status_code=301) assert "/datasets/" == path_assertions[0][0] diff --git a/brasilio/settings.py b/brasilio/settings.py index e2afa60f..c5983b6f 100644 --- a/brasilio/settings.py +++ b/brasilio/settings.py @@ -1,5 +1,3 @@ -from urllib.parse import urlparse - import environ import sentry_sdk from django.urls import reverse_lazy diff --git a/brasilio_auth/forms.py b/brasilio_auth/forms.py index 8c093c73..ebd02cc0 100644 --- a/brasilio_auth/forms.py +++ b/brasilio_auth/forms.py @@ -7,18 +7,13 @@ from utils.forms import FlagedReCaptchaField as ReCaptchaField - USERNAME_REGEXP = re.compile(r"[^A-Za-z0-9_]") PUNCT_REGEXP = re.compile("[-/ .]") User = get_user_model() def is_valid_username(username): - return not ( - PUNCT_REGEXP.sub("", username).isdigit() - or - USERNAME_REGEXP.search(username) - ) + return not (PUNCT_REGEXP.sub("", username).isdigit() or USERNAME_REGEXP.search(username)) class UserCreationForm(RegistrationFormUniqueEmail): @@ -44,7 +39,7 @@ def clean_username(self): "Nome de usuário pode conter apenas letras, números e '_' e não deve ser um documento" ) elif username and User.objects.filter(username__iexact=username).exists(): - raise forms.ValidationError(f"Nome de usuário já existente (escolha um diferente).") + raise forms.ValidationError("Nome de usuário já existente (escolha um diferente).") return username def clean_email(self): diff --git a/brasilio_auth/scripts/migrate_wrong_usernames.py b/brasilio_auth/scripts/migrate_wrong_usernames.py index e78ad622..234ca000 100644 --- a/brasilio_auth/scripts/migrate_wrong_usernames.py +++ b/brasilio_auth/scripts/migrate_wrong_usernames.py @@ -21,7 +21,7 @@ possible_chars = string.ascii_letters + string.digits + "_" -def possible_usernames(username:str, email:str, n_suffix:int = 10) -> Tuple[str, ...]: +def possible_usernames(username: str, email: str, n_suffix: int = 10) -> Tuple[str, ...]: username = username.strip() email = email.strip() @@ -34,7 +34,7 @@ def possible_usernames(username:str, email:str, n_suffix:int = 10) -> Tuple[str, username = username[:-1] if "@" in username: stop = username.find("@") - before, after = username[:stop], username[stop + 1:] + before, after = username[:stop], username[stop + 1 :] if "." in after: username = before else: @@ -49,9 +49,7 @@ def possible_usernames(username:str, email:str, n_suffix:int = 10) -> Tuple[str, def migrate_usernames(filepath): with open(filepath, mode="w") as fobj: - writer = csv.DictWriter( - fobj, fieldnames=["old_username", "new_username", "email"] - ) + writer = csv.DictWriter(fobj, fieldnames=["old_username", "new_username", "email"]) writer.writeheader() for user in User.objects.all(): if is_valid_username(user.username): @@ -65,13 +63,7 @@ def migrate_usernames(filepath): ] for username in possible: if not User.objects.filter(username=username).exists(): - writer.writerow( - { - "old_username": user.username, - "new_username": username, - "email": user.email - } - ) + writer.writerow({"old_username": user.username, "new_username": username, "email": user.email}) user.username = username user.save() break diff --git a/brasilio_auth/tests/test_scripts.py b/brasilio_auth/tests/test_scripts.py index 8de86960..42541cf4 100644 --- a/brasilio_auth/tests/test_scripts.py +++ b/brasilio_auth/tests/test_scripts.py @@ -3,11 +3,8 @@ from django.contrib.auth import get_user_model from django.test import TestCase from model_bakery import baker -from brasilio_auth.scripts.migrate_wrong_usernames import ( - possible_usernames, - migrate_usernames, -) +from brasilio_auth.scripts.migrate_wrong_usernames import migrate_usernames, possible_usernames User = get_user_model() @@ -79,26 +76,16 @@ def test_create_more_possibilities_with_suffixes(self): class TestReplaceUsernameWithSuggestions(TestCase): def setUp(self): - self.user_1 = baker.make( - User, - username="test@", - email="test@example.com", - ) + self.user_1 = baker.make(User, username="test@", email="test@example.com",) self.expected_username_1 = "test" - self.user_2 = baker.make( - User, - username="@test@", - email="name@example.com" - ) + self.user_2 = baker.make(User, username="@test@", email="name@example.com") # teste would already exists because of self.username_1 self.expected_username_2 = "name" self.temp_file = NamedTemporaryFile(mode="r") self.expected_csv = ( - "old_username,new_username,email\n" - "test@,test,test@example.com\n" - "@test@,name,name@example.com\n" + "old_username,new_username,email\n" "test@,test,test@example.com\n" "@test@,name,name@example.com\n" ) def test_happy_path_wrong_usernames_replacement(self): diff --git a/core/forms.py b/core/forms.py index bb485f51..b6fc79d4 100644 --- a/core/forms.py +++ b/core/forms.py @@ -44,55 +44,6 @@ def _get_name(obj, person_type): return obj.name -class TracePathForm(forms.Form): - TYPE_CHOICES = [("pessoa-fisica", "Pessoa Física (nome completo)"), ("pessoa-juridica", "Pessoa Jurídica (CNPJ)")] - - origin_type = forms.ChoiceField(choices=TYPE_CHOICES, required=True) - origin_identifier = forms.CharField(required=True) - - destination_type = forms.ChoiceField(choices=TYPE_CHOICES, required=True) - destination_identifier = forms.CharField(required=True) - - def clean(self): - cleaned_data = super().clean() - origin_type = cleaned_data.get("origin_type") - origin_identifier = cleaned_data.get("origin_identifier") - destination_type = cleaned_data.get("destination_type") - destination_identifier = cleaned_data.get("destination_identifier") - - origin_field = _resolve_field_by_type(origin_type) - destination_field = _resolve_field_by_type(destination_type) - origin = _get_obj(origin_field, origin_identifier, origin_type) - destination = _get_obj(destination_field, destination_identifier, destination_type) - - if origin is None: - self.add_error("origin_identifier", "Name/document not found") - else: - cleaned_data["origin_name"] = _get_name(origin, origin_type) - if destination is None: - self.add_error("destination_identifier", "Name/document not found") - else: - cleaned_data["destination_name"] = _get_name(destination, destination_type) - - return cleaned_data - - -class CompanyGroupsForm(forms.Form): - identifier = forms.CharField(required=True, label="CNPJ") - - def clean(self): - cleaned_data = super().clean() - identifier = cleaned_data["identifier"] - for char in "./-": - identifier = identifier.replace(char, "") - company = _get_obj("", identifier, "pessoa-juridica") - if not company: - self.add_error("identifier", "Document not found") - else: - cleaned_data["company"] = company - return cleaned_data - - class ContactForm(forms.Form): name = forms.CharField(required=True, label="Nome") email = forms.EmailField(required=True, label="E-mail") diff --git a/core/views_special.py b/core/views_special.py index 1aa35cba..63d73b56 100644 --- a/core/views_special.py +++ b/core/views_special.py @@ -8,7 +8,6 @@ from django.urls import reverse from core.data_models import EmpresaTableConfig -from core.forms import CompanyGroupsForm, TracePathForm from core.models import get_table, get_table_model cipher_suite = Fernet(settings.FERNET_KEY) diff --git a/utils/rocketchat.py b/utils/rocketchat.py index d8f999f7..c97c4e05 100644 --- a/utils/rocketchat.py +++ b/utils/rocketchat.py @@ -27,7 +27,8 @@ def make_request(self, method, *args, **kwargs): response = getattr(requests, method)(*args, **kwargs) if response.status_code >= 400: raise RuntimeError( - f"HTTP {response.status_code} error when processing request to {response.url} (body: {response.content})" + f"HTTP {response.status_code} error when processing request " + f"to {response.url} (body: {response.content})" ) return response From 7afdccdb263eba0808f8b4d3cb5a3a5b249b753d Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Wed, 7 Apr 2021 15:28:25 -0300 Subject: [PATCH 17/18] Roda todos os comandos pelo docker-compose --- .github/workflows/django.yml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index f1bd9f69..1c2bd783 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -28,22 +28,18 @@ jobs: ENV_FILE: .env PROJECT_NAME: brasil.io DOCKER_COMPOSE_FILE: docker-compose.yml - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - pip install -I -r requirements-development.txt - name: Migrate and Update Data run: | - python manage.py migrate --no-input + docker-compose run web python manage.py migrate --no-input - name: Collect static staticfiles run: | - python manage.py collectstatic --no-input + docker-compose run web python manage.py collectstatic --no-input - name: Run Tests run: | - pytest + docker-compose run web pytest - name: Run black run: | - black . --exclude "docker" -l 120 --check + docker-compose run web black . --exclude "docker" -l 120 --check - name: Run flake8 run: | - flake8 --config setup.cfg + docker-compose run web flake8 --config setup.cfg From 86f47f167781451f0a93602ac9a46b60531de4f8 Mon Sep 17 00:00:00 2001 From: Rhenan Bartels Date: Wed, 7 Apr 2021 20:10:45 -0300 Subject: [PATCH 18/18] Ignore erro do flake8 --- Makefile | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3e0a01be..9c28a5f3 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ lint: autoflake --in-place --recursive --remove-unused-variables --remove-all-unused-imports . isort --skip migrations --skip brasilio/wsgi.py -rc . black . --exclude "docker" -l 120 - flake8 --ignore=E203,E231 + flake8 --config setup.cfg test: pytest diff --git a/setup.cfg b/setup.cfg index f004f728..23876f59 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,4 @@ [flake8] max-line-length = 120 exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,docker/postgresql/data -ignore=I001,I003,I004,E231,E501 +ignore=I001,I003,I004,E231,E501,E203