diff --git a/later42/settings.py b/later42/settings.py index aa31f05..1dd70af 100644 --- a/later42/settings.py +++ b/later42/settings.py @@ -160,3 +160,4 @@ REST_FRAMEWORK = { URLS_PER_PAGE = 20 READABILITY_HOST = os.getenv('READABILITY_HOST', None) +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' diff --git a/later42/templates/email_activation.html b/later42/templates/email_activation.html new file mode 100644 index 0000000..179e6d0 --- /dev/null +++ b/later42/templates/email_activation.html @@ -0,0 +1,5 @@ +{% autoescape off %} +Привет, {{ user.username }}. +Ссылка для активации аккаунта: +http://{{ domain }}{% url 'activate' uidb64=uid token=token %} +{% endautoescape %} \ No newline at end of file diff --git a/later42/templates/email_sent.html b/later42/templates/email_sent.html new file mode 100644 index 0000000..884af1b --- /dev/null +++ b/later42/templates/email_sent.html @@ -0,0 +1,6 @@ +{% extends 'base.html' %} + +{% block content %} +

Активация аккаунта

+

Письмо со ссылкой отправлено по указанному адресу.

+{% endblock %} diff --git a/later42/tokens.py b/later42/tokens.py new file mode 100644 index 0000000..a2fa72e --- /dev/null +++ b/later42/tokens.py @@ -0,0 +1,13 @@ +from django.contrib.auth.tokens import PasswordResetTokenGenerator +import six + + +class TokenGenerator(PasswordResetTokenGenerator): + def _make_hash_value(self, user, timestamp): + return ( + six.text_type(user.pk) + six.text_type(timestamp) + + six.text_type(user.is_active) + ) + + +account_activation_token = TokenGenerator() diff --git a/later42/urls.py b/later42/urls.py index eb9de87..39d2929 100644 --- a/later42/urls.py +++ b/later42/urls.py @@ -22,7 +22,7 @@ from django.contrib.auth.views import LoginView from rest_framework import routers, serializers, viewsets from later42.forms import CustomLoginForm -from later42.views import index, profile, api, api_token, reader, signup, about +from later42.views import account_activation, index, profile, api, api_token, reader, signup, about class UserSerializer(serializers.HyperlinkedModelSerializer): @@ -42,6 +42,8 @@ router.register(r'users', UserViewSet) urlpatterns = [ path('admin/', admin.site.urls), path('signup/', signup.register, name='signup'), + path(r'^activate/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', + account_activation.activate, name='activate'), path("accounts/login/", LoginView.as_view(authentication_form=CustomLoginForm), name="login"), path("accounts/", include("django.contrib.auth.urls")), diff --git a/later42/views/account_activation.py b/later42/views/account_activation.py new file mode 100644 index 0000000..4eb7ccf --- /dev/null +++ b/later42/views/account_activation.py @@ -0,0 +1,29 @@ +import django +from django.core.mail import EmailMessage +from django.contrib.auth.models import User +from later42.tokens import account_activation_token +from django.template.loader import render_to_string +from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode +from django.http import HttpResponse +from django.shortcuts import render, redirect +from django.contrib.auth import login, authenticate +from later42.forms import SignUpForm +from django.contrib.sites.shortcuts import get_current_site +from django.utils.encoding import force_bytes +from django.utils.encoding import force_str +django.utils.encoding.force_text = force_str + + +def activate(request, uidb64, token): + try: + uid = django.utils.encoding.force_text(urlsafe_base64_decode(uidb64)) + user = User.objects.get(pk=uid) + except (TypeError, ValueError, OverflowError, User.DoesNotExist): + user = None + if user is not None and account_activation_token.check_token(user, token): + user.is_active = True + user.save() + login(request, user) + return redirect('index') + else: + return HttpResponse('Activation link is invalid!') diff --git a/later42/views/signup.py b/later42/views/signup.py index 4ac27d7..a6a5bf5 100644 --- a/later42/views/signup.py +++ b/later42/views/signup.py @@ -1,21 +1,43 @@ from django.contrib.auth import authenticate, login from django.shortcuts import redirect, render +from django.contrib.sites.shortcuts import get_current_site +from django.template.loader import render_to_string +from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode +from django.utils.encoding import force_bytes, force_text +from django.core.mail import EmailMessage from later42.forms import SignUpForm +from later42.tokens import account_activation_token def register(request): if request.method == 'POST': form = SignUpForm(request.POST) if form.is_valid(): - user = form.save() - user.refresh_from_db() + user = form.save(commit=False) + # user.refresh_from_db() + user.is_active = False user.save() raw_password = form.cleaned_data.get('password1') - user = authenticate(username=user.username, password=raw_password) - login(request, user) + current_site = get_current_site(request) - return redirect('index') + # user = authenticate(username=user.username, password=raw_password) + # login(request, user) + + mail_subject = 'Later42: Активация аккаунта' + message = render_to_string('email_activation.html', { + 'user': user, + 'domain': current_site.domain, + 'uid': urlsafe_base64_encode(force_bytes(user.pk)), + 'token': account_activation_token.make_token(user), + }) + to_email = form.cleaned_data.get('email') + email = EmailMessage( + mail_subject, message, to=[to_email] + ) + email.send() + + return render(request, 'email_sent.html') else: form = SignUpForm() return render(request, 'signup.html', {'form': form}) diff --git a/requirements.txt b/requirements.txt index a392712..be382a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ requests==2.28.1 djangorestframework==3.14.0 whitenoise==6.2.0 psycopg2-binary==2.9.4 +six==1.16.0