diff --git a/quest/views.py b/quest/views.py index e54bc16..c09c41a 100644 --- a/quest/views.py +++ b/quest/views.py @@ -12,7 +12,6 @@ from django.shortcuts import render, redirect from django.db.models import F from django.conf import settings from django.urls import reverse -from django.http import HttpResponse from .models import Quest, DiceRoll, PollOption, PollVote, Page, Post from .forms import EditQuestForm, QuestForm, PostForm diff --git a/signup/jinja2/signup/confirmation_sent.html b/signup/jinja2/signup/confirmation_sent.html new file mode 100644 index 0000000..0e79c64 --- /dev/null +++ b/signup/jinja2/signup/confirmation_sent.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} +{% block title %}Email confirmation sent{% endblock %} +{% block content %} +A confirmation email has been sent to {{ user.email }}. Please follow the enclosed instructions to finish creating your account. Be sure to check your spam folder if you do not see the email. +{% endblock %} diff --git a/signup/jinja2/signup/confirmed.html b/signup/jinja2/signup/confirmed.html new file mode 100644 index 0000000..4404acf --- /dev/null +++ b/signup/jinja2/signup/confirmed.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} +{% block title %}Success!{% endblock %} +{% block content %} +Your account has been activated. You may now login. +{% endblock %} + diff --git a/signup/models.py b/signup/models.py new file mode 100644 index 0000000..5107e7c --- /dev/null +++ b/signup/models.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +""" +A table to lookup confirmation codes. +""" +from django.db import models +from django.conf import settings + +class Confirmation(models.Model): + """ + Contains a reference to the user's newly created account + and a random string to be emailed to them for them to confirm. + """ + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE + ) + code = models.CharField(max_length=32) diff --git a/signup/urls.py b/signup/urls.py index 0ed313b..c6006f8 100644 --- a/signup/urls.py +++ b/signup/urls.py @@ -9,4 +9,5 @@ from . import views app_name = 'signup' urlpatterns = [ path('', views.index, name='index'), + path('verify', views.verify, name='verify'), ] diff --git a/signup/views.py b/signup/views.py index 7094cd3..6d8d12f 100644 --- a/signup/views.py +++ b/signup/views.py @@ -3,9 +3,16 @@ /signup app views. """ # TODO: make unique username validation be case insensitive +import random +import string + from django.shortcuts import redirect, render +from django.core.mail import send_mail +from django.urls import reverse +from django.conf import settings from .forms import SignupForm +from .models import Confirmation def index(request): """ @@ -16,8 +23,58 @@ def index(request): if request.method == 'POST': form = SignupForm(request.POST) if form.is_valid(): - form.save() - return redirect('login:index') + user = form.save() + confirm = Confirmation( + user=user, + code=get_code(32) + ) + confirm.save() + verify_url = request.build_absolute_uri(reverse('signup:verify')) + verify_url = verify_url.replace("http", "https") + email_confirmation(confirm, verify_url) + return render(request, 'signup/confirmation_sent.html', locals()) else: form = SignupForm() return render(request, 'signup/index.html', {'form': form}) + + +def get_code(n): + """ + Helper function to generate n number of psudeo-random ASCII characters. + """ + chars = [] + for _ in range(n): + chars.append(random.choice(string.ascii_letters + string.digits)) + return "".join(chars) + + +def email_confirmation(confirm, verify_url): + """ + Sends out a confirmation to the user. + """ + message = "Please use the following link to verify your account: " + message += verify_url + "?code=" + confirm.code + send_mail( + "Email verification", + message, + settings.DEFAULT_FROM_EMAIL, + [confirm.user.email], + ) + + +def verify(request): + """ + Verifies and activates the user's account. + """ + code = request.GET.get("code") + if not code: + return redirect('homepage:index') + try: + confirm = Confirmation.objects.get(code=code) + except Confirmation.DoesNotExist: + return redirect('homepage:index') + user = confirm.user + user.is_active = True + user.save() + confirm.delete() + return render(request, 'signup/confirmed.html', locals()) diff --git a/titivillus/settings.py b/titivillus/settings.py index 20b7cd3..6623103 100644 --- a/titivillus/settings.py +++ b/titivillus/settings.py @@ -168,3 +168,11 @@ TAGGIT_CASE_INSENSITIVE = True # Server user id SERVER_USER_ID = 3 + +DEFAULT_FROM_EMAIL = "scribe@steelbea.me" +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = "mail.steelbea.me" +EMAIL_HOST_PASSWORD = titivillus.settings_secret.EMAIL_KEY +EMAIL_HOST_USER = "scribe@steelbea.me" +EMAIL_PORT = 587 +EMAIL_USE_TLS = True diff --git a/todo b/todo index 195aa8e..3015208 100644 --- a/todo +++ b/todo @@ -1,5 +1,4 @@ New Features: -Notifications Front page to show new quests Webm posting (you) counter @@ -15,3 +14,5 @@ Total voters per poll Chat archives Adjust quote preview postioning Better API +Reserve/prevent certain usernames eg. Admin, Administrator, etc. +Search from front page doesn't work diff --git a/user/migrations/0004_auto_20190118_1251.py b/user/migrations/0004_auto_20190118_1251.py new file mode 100644 index 0000000..d91c9ec --- /dev/null +++ b/user/migrations/0004_auto_20190118_1251.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.1 on 2019-01-18 17:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0003_user_subscriptions'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='is_active', + field=models.BooleanField(default=False), + ), + ] diff --git a/user/models.py b/user/models.py index 84fc26c..992975e 100644 --- a/user/models.py +++ b/user/models.py @@ -47,6 +47,7 @@ class User(AbstractUser): + "the conversation." ) subscriptions = models.ManyToManyField(Quest) + is_active = models.BooleanField(default=False) def get_full_name(self): return None