diff options
| -rw-r--r-- | blog/static/css/main.css | 1 | ||||
| -rw-r--r-- | blog/templates/partials/sidebar.html | 30 | ||||
| -rw-r--r-- | requirements.txt | 1 | ||||
| -rw-r--r-- | thatcomputerscientist/settings.py | 6 | ||||
| -rw-r--r-- | users/templates/verification_email.html | 10 | ||||
| -rw-r--r-- | users/tokens.py | 11 | ||||
| -rw-r--r-- | users/urls.py | 2 | ||||
| -rw-r--r-- | users/views.py | 61 |
8 files changed, 105 insertions, 17 deletions
diff --git a/blog/static/css/main.css b/blog/static/css/main.css index a6a3e42b..cf534be3 100644 --- a/blog/static/css/main.css +++ b/blog/static/css/main.css @@ -20,6 +20,7 @@ body { overflow-y: auto; border: 1px solid #191919; min-width: 15rem; + max-width: 15rem; } .main { diff --git a/blog/templates/partials/sidebar.html b/blog/templates/partials/sidebar.html index 36984977..259d70b6 100644 --- a/blog/templates/partials/sidebar.html +++ b/blog/templates/partials/sidebar.html @@ -10,21 +10,29 @@ <button type="submit" onclick="location.href='{% url 'users:logout' %}'">Logout</button> </div> {% else %} - <form method="post" action="{% url 'users:login' %} "> - {% csrf_token %} - <fieldset> - <legend>Login Area</legend> + <fieldset> + <legend>Login Area</legend> + <form method="post" action="{% url 'users:login' %} "> + {% csrf_token %} <label for="username">Username</label> <input type="text" id="username" name="username" placeholder="Username" autocomplete="off"> <label for="password">Password</label> <input type="password" id="password" name="password" placeholder="Password"> - {% for message in messages %} - <p class="{{message.tags}}">{{ message }}</p> - {% endfor %} <input type="hidden" name="next" value="{{ request.path }}"> <input type="submit" value="Login"> - </fieldset> - </form> + </form> + {% for message in messages %} + {% if message.message == "EVERR" %} + <form method="post" action="{% url 'users:sendverificationemail' %}" > + <p class="{{message.tags}}"> + Your email is unverified. Please check your inbox for a verification email or to request a new verification email by clicking{% csrf_token %}<input type="hidden" name="username"><input style="display: inline; background: none; border: none; color: blue; text-decoration: underline; cursor: pointer; margin: 0;" type="submit" value="here."> + </p> + </form> + {% else %} + <p class="{{message.tags}}">{{message.message}}</p> + {% endif %} + {% endfor %} + </fieldset> {% endif %} <br> <fieldset> @@ -53,6 +61,8 @@ var username = new URLSearchParams(window.location.search).get('username'); // if the username parameter is not empty, set the username input to the value of the username parameter if (username) { - document.getElementById('username').value = username; + document.getElementsByName("username").forEach(function(input) { + input.value = username; + }); } </script> diff --git a/requirements.txt b/requirements.txt index 8838a9c4..001170f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ python-dotenv==0.20.0 mysqlclient==2.1.1 gunicorn==20.1.0 whitenoise==6.2.0 +six==1.16.0 diff --git a/thatcomputerscientist/settings.py b/thatcomputerscientist/settings.py index 8aeff78f..9629797f 100644 --- a/thatcomputerscientist/settings.py +++ b/thatcomputerscientist/settings.py @@ -132,3 +132,9 @@ STATIC_URL = 'static/' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' STATIC_ROOT = BASE_DIR / "staticfiles" + +EMAIL_USE_TLS = True +EMAIL_HOST = os.getenv('MAIL_HOST') +EMAIL_PORT = 587 +EMAIL_HOST_USER = os.getenv('EMAIL_USER') +EMAIL_HOST_PASSWORD = os.getenv('EMAIL_PASSWORD') diff --git a/users/templates/verification_email.html b/users/templates/verification_email.html new file mode 100644 index 00000000..9a96e31b --- /dev/null +++ b/users/templates/verification_email.html @@ -0,0 +1,10 @@ +{% autoescape off %} +Hi {{ user }}, + +Thanks for registering an account on {{ site_name }}. To verify your email address, please click the link below.</p> +{{ protocol }}{{ domain }}{% url 'users:verifyemail' uidb64=uid token=token %} + +Thanks, +{{ site_name }} Team +{% endautoescape %} + diff --git a/users/tokens.py b/users/tokens.py new file mode 100644 index 00000000..7bc5bc90 --- /dev/null +++ b/users/tokens.py @@ -0,0 +1,11 @@ +from django.contrib.auth.tokens import PasswordResetTokenGenerator +from six import text_type + +class AccountActivationTokenGenerator(PasswordResetTokenGenerator): + def _make_hash_value(self, user, timestamp): + return ( + text_type(user.pk) + text_type(timestamp) + + text_type(user.is_active) + ) + +account_activation_token = AccountActivationTokenGenerator() diff --git a/users/urls.py b/users/urls.py index 24230426..b7cd5f82 100644 --- a/users/urls.py +++ b/users/urls.py @@ -9,6 +9,8 @@ urlpatterns = [ path('logout', views.logout_user, name='logout'), path('update', views.update_user, name='update'), path('changepassword', views.change_password, name='changepassword'), + path('sendverificationemail', views.send_verification_email, name='sendverificationemail'), + path('verifyemail/<uidb64>/<token>', views.verify_email, name='verifyemail'), ] # Configure Admin Site diff --git a/users/views.py b/users/views.py index 175d68e6..f4405a38 100644 --- a/users/views.py +++ b/users/views.py @@ -4,7 +4,15 @@ from django.contrib.auth import authenticate, login, logout, update_session_auth from django.contrib import messages from .models import UserProfile from django.contrib.auth.models import User - +from django.core.mail import send_mail +from django.conf import settings +from django.template.loader import render_to_string +from django.utils.html import strip_tags +from django.utils.encoding import force_bytes +from django.utils.http import urlsafe_base64_encode +from django.contrib.sites.shortcuts import get_current_site +from .tokens import account_activation_token +from django.utils.http import urlsafe_base64_decode # Create your views here. def login_user(request): @@ -14,17 +22,21 @@ def login_user(request): password = request.POST['password'] print (username, password) if username == '' or password == '': - messages.error(request, 'Please fill in all fields') + messages.error(request, 'Please fill in all fields.') return HttpResponseRedirect(next + '?username=' + username) else: + # check if email is verified user = authenticate(request, username=username, password=password) if user is not None: - print('here3') - login(request, user) - return HttpResponseRedirect(next) + email_verified = UserProfile.objects.get(user=user.pk).email_verified + if email_verified: + login(request, user) + return HttpResponseRedirect(next) + else: + messages.error(request, 'EVERR') + return HttpResponseRedirect(next + '?username=' + username) else: - messages.error(request, 'Invalid username or password') - print('here4') + messages.error(request, 'Invalid username or password.') return HttpResponseRedirect(next + '?username=' + username) def logout_user(request): @@ -90,3 +102,38 @@ def change_password(request): messages.error(request, 'Unable to change password! Please try again later.') return redirect('/') + +def send_verification_email(request): + username = request.POST['username'] + user = User.objects.get(username=username) + + + subject = 'Verify your email address' + message = render_to_string('verification_email.html', { + 'user': user.username if user.first_name is None else user.first_name, + 'site_name': 'That Computer Scientist', + 'uid': urlsafe_base64_encode(force_bytes(user.pk)), + 'token': account_activation_token.make_token(user), + 'protocol': 'https://' if request.is_secure() else 'http://', + 'domain': get_current_site(request).domain, + }) + message = strip_tags(message) + send_mail(subject, message, 'That Computer Scientist <' + settings.EMAIL_HOST_USER + '>', [user.email]) + messages.success(request, 'Verification email was sent! Please check your email.') + return HttpResponseRedirect(request.META.get('HTTP_REFERER')) + +def verify_email(request, uidb64, token): + try: + uid = urlsafe_base64_decode(uidb64).decode() + user = User.objects.get(pk=uid) + user_profile = UserProfile.objects.get(user=user.pk) + except (TypeError, ValueError, OverflowError, User.DoesNotExist): + user = None + if user is not None and account_activation_token.check_token(user, token): + user_profile.email_verified = True + user_profile.save() + messages.success(request, 'Your email has been verified! You can now login.') + return redirect('/') + else: + messages.error(request, 'The verification link is invalid!') + return redirect('/')
\ No newline at end of file |
