From 27730d59496c52f6f3c0cf5a065124312f4d42fe Mon Sep 17 00:00:00 2001 From: Adelson Date: Sun, 5 Jun 2022 23:58:54 -0300 Subject: [PATCH 1/2] =?UTF-8?q?Adi=C3=A7=C3=A3o=20da=20possibilidade=20de?= =?UTF-8?q?=20enviar=20e-mail=20de=20ativa=C3=A7=C3=A3o=20de=20conta=20e?= =?UTF-8?q?=20defini=C3=A7=C3=A3o=20de=20senha=20quando=20se=20cadastra=20?= =?UTF-8?q?um=20usu=C3=A1rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sloth/actions/__init__.py | 16 +++++++++++----- sloth/api/models.py | 2 +- sloth/api/tokes.py | 20 ++++++++++++++++++++ sloth/app/urls.py | 1 + sloth/app/views.py | 23 ++++++++++++++++++++++- sloth/conf/settings.py | 2 ++ sloth/core/base.py | 34 ++++++++++++++++++++++++++++++++-- 7 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 sloth/api/tokes.py diff --git a/sloth/actions/__init__.py b/sloth/actions/__init__.py index ebf1079a..ca553eae 100644 --- a/sloth/actions/__init__.py +++ b/sloth/actions/__init__.py @@ -591,6 +591,12 @@ class PasswordForm(Action): class Meta: verbose_name = 'Alterar Senha' + def __init__(self, *args, **kwargs): + self.user = kwargs.pop('user', None) + super().__init__(*args, **kwargs) + if not self.user: + self.user = self.request.user + def clean(self): password = self.cleaned_data.get('password') password2 = self.cleaned_data.get('password2') @@ -598,14 +604,14 @@ def clean(self): raise forms.ValidationError('Senhas não conferem.') if settings.SLOTH.get('FORCE_PASSWORD_DEFINITION') == True and settings.SLOTH.get('DEFAULT_PASSWORD'): - default_password = settings.SLOTH['DEFAULT_PASSWORD'](self.request.user) - if self.request.user.check_password(default_password) and self.request.user.check_password(password): + default_password = settings.SLOTH['DEFAULT_PASSWORD'](self.user) + if self.user.check_password(default_password) and self.user.check_password(password): raise forms.ValidationError('Senha não pode ser a senha padrão.') return self.cleaned_data def submit(self): - self.request.user.set_password(self.cleaned_data.get('password')) - self.request.user.save() - auth.login(self.request, self.request.user, backend='django.contrib.auth.backends.ModelBackend') + self.user.set_password(self.cleaned_data.get('password')) + self.user.save() + auth.login(self.request, self.user, backend='django.contrib.auth.backends.ModelBackend') self.redirect(message='Senha alterada com sucesso.') diff --git a/sloth/api/models.py b/sloth/api/models.py index 16094054..c9a69996 100644 --- a/sloth/api/models.py +++ b/sloth/api/models.py @@ -42,7 +42,7 @@ def get_general_info(self): return self.values(('first_name', 'last_name'), 'username', 'email').verbose_name('Dados Gerais') def get_access_info(self): - return self.values('is_superuser',).verbose_name('Dados de Acesso') + return self.values(('is_superuser', 'is_active')).verbose_name('Dados de Acesso') @meta('Papéis') def get_roles(self): diff --git a/sloth/api/tokes.py b/sloth/api/tokes.py new file mode 100644 index 00000000..3a847f1f --- /dev/null +++ b/sloth/api/tokes.py @@ -0,0 +1,20 @@ +import six +from django.contrib.auth.tokens import PasswordResetTokenGenerator + + +class AccountActivationTokenGenerator(PasswordResetTokenGenerator): + def _make_hash_value(self, user, timestamp): + return ( + six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active) + ) + + +class PasswordResetToken(PasswordResetTokenGenerator): + def _make_hash_value(self, user, timestamp): + return ( + six.text_type(user.pk) + six.text_type(timestamp) + ) + + +account_activation_token = AccountActivationTokenGenerator() +password_reset_token = PasswordResetToken() diff --git a/sloth/app/urls.py b/sloth/app/urls.py index d753d0ca..4c0dcb3c 100644 --- a/sloth/app/urls.py +++ b/sloth/app/urls.py @@ -14,6 +14,7 @@ path('app/roles//', views.roles), path('app/logout/', views.logout), path('app/password/', views.password), + path('app/account_activate///', views.account_activate), path('app///', views.dispatcher), path('app////', views.dispatcher), path('app////////', views.dispatcher), diff --git a/sloth/app/views.py b/sloth/app/views.py index 0eb6ea52..6bba2587 100644 --- a/sloth/app/views.py +++ b/sloth/app/views.py @@ -5,9 +5,13 @@ from django.conf import settings from django.contrib import auth, messages from django.core.exceptions import PermissionDenied +from django.core.mail import send_mail from django.http import JsonResponse, HttpResponseForbidden, HttpResponse, HttpResponseRedirect -from django.shortcuts import render +from django.shortcuts import render, get_object_or_404 from django.template.loader import render_to_string +from django.utils.encoding import force_str +from django.utils.http import urlsafe_base64_decode +from sloth.api.tokes import account_activation_token from .templatetags.tags import is_ajax from ..core import views @@ -167,6 +171,23 @@ def logout(request): return HttpResponseRedirect('/') +def account_activate(request, uid64, token): + uid = force_str(urlsafe_base64_decode(uid64)) + user = get_object_or_404(User, pk=uid) + if user is not None and account_activation_token.check_token(user, token): + form = PasswordForm(request=request, user=user) + if form.is_valid(): + form.submit() + user.is_active = True + user.save() + auth.login(request, user) + return HttpResponseRedirect('/app/') + return render(request, ['app/default.html'], context(request, form=form)) + + messages.warning(request, "Link de ativação inválido") + return HttpResponseRedirect('/') + + def index(request): return HttpResponseRedirect('/app/') diff --git a/sloth/conf/settings.py b/sloth/conf/settings.py index 28eeda06..a01b9de8 100644 --- a/sloth/conf/settings.py +++ b/sloth/conf/settings.py @@ -59,6 +59,8 @@ }, 'DEFAULT_PASSWORD': lambda user: '123', 'FORCE_PASSWORD_DEFINITION': False, + 'ADD_USER_CONFIRMATION': False, + 'LIST_PER_PAGE': 20, } # #SESSION_ENGINE = 'django.contrib.sessions.backends.cache' diff --git a/sloth/core/base.py b/sloth/core/base.py index 302d83a0..d8ec8c7a 100644 --- a/sloth/core/base.py +++ b/sloth/core/base.py @@ -1,13 +1,19 @@ -from functools import lru_cache import types +from functools import lru_cache + from django.apps import apps from django.conf import settings from django.core.exceptions import FieldDoesNotExist +from django.core.mail import send_mail +from django.db import transaction from django.template.loader import render_to_string +from django.utils.encoding import force_bytes +from django.utils.http import urlsafe_base64_encode from sloth.actions import Action -from sloth.core.valueset import ValueSet +from sloth.api.tokes import account_activation_token from sloth.core.queryset import QuerySet +from sloth.core.valueset import ValueSet from sloth.utils import to_snake_case, to_camel_case, getattrr FILTER_FIELD_TYPES = 'BooleanField', 'NullBooleanField', 'ForeignKey', 'ForeignKeyPlus', 'DateField', 'DateFieldPlus' @@ -144,6 +150,7 @@ def get_role_tuples(self, ignore_active_condition=False): # print('\n\n') return tuples + @transaction.atomic() def sync_roles(self, role_tuples): from django.contrib.auth.models import User user_id = None @@ -159,10 +166,33 @@ def sync_roles(self, role_tuples): user.email = email if 'DEFAULT_PASSWORD' in settings.SLOTH: default_password = settings.SLOTH['DEFAULT_PASSWORD'](user) + if settings.SLOTH.get('ADD_USER_CONFIRMATION') == True: + user.is_active = False else: default_password = '123' if settings.DEBUG else str(abs(hash(username))) user.set_password(default_password) user.save() + + site = settings.CSRF_TRUSTED_ORIGINS[0] + uid = urlsafe_base64_encode(force_bytes(user.pk)) + token = account_activation_token.make_token(user) + send_mail( + subject="Cadastro no RAIZ", + message=None, + html_message=f""" +

+ Olá {user}, +

+ Para ativar o seu cadastro e definir sua senha clique no link abaixo: +

+ Definir senha +

+ Se o link acima não funcionar, por favor, copie e cole a URL no seu navegador. + """, + from_email=settings.DEFAULT_FROM_EMAIL, + recipient_list=(email,), + ) + user_id = user.id role.objects.get_or_create( user_id=user_id, name=scope_name, From 5965c0ca04053cd69532d37f885a02b0f13c4756 Mon Sep 17 00:00:00 2001 From: Adelson Date: Sun, 12 Jun 2022 21:17:56 -0300 Subject: [PATCH 2/2] =?UTF-8?q?Corre=C3=A7=C3=A3o=20de=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sloth/core/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sloth/core/base.py b/sloth/core/base.py index 996a0435..775aeff2 100644 --- a/sloth/core/base.py +++ b/sloth/core/base.py @@ -167,10 +167,10 @@ def sync_roles(self, role_tuples): user.email = email if 'DEFAULT_PASSWORD' in settings.SLOTH: default_password = settings.SLOTH['DEFAULT_PASSWORD'](user) - if settings.SLOTH.get('ADD_USER_CONFIRMATION') == True: - user.is_active = False else: default_password = '123' if settings.DEBUG else str(abs(hash(username))) + if settings.SLOTH.get('ADD_USER_CONFIRMATION') == True: + user.is_active = False user.set_password(default_password) user.save()