From d3fa9b79b4fe7568fdfdf7997859b92032392b45 Mon Sep 17 00:00:00 2001 From: Paarhati Ozkasgarli Date: Sun, 4 Dec 2016 20:54:21 +0000 Subject: [PATCH] User Registration & Email Authantication Basic user registration system and email authantication. Change-Id: Iaa4266edaf78b5c42c4aafc0de2d1f11f9f6c4f5 --- authcp/forms.py | 36 ++++++++ authcp/urls.py | 5 +- authcp/views.py | 78 +++++++++++++++++- dash_stack_dashboard/settings.py | 25 +++++- requirement.txt | 1 + .../avatar/2016-12-10/aws_logo_web_300px.png | Bin 0 -> 6165 bytes .../openstack-logo-1-300x150_soH1jUf.png | Bin 0 -> 4629 bytes templates/authcp/activation.html | 22 +++++ templates/authcp/login.html | 14 ++-- templates/authcp/register.html | 62 ++++++++++++++ templates/authcp/success.html | 25 ++++++ templates/base_headless.html | 7 +- templates/mail/user_register_welcome.html | 20 +++++ templates/mail/user_register_welcome.txt | 6 ++ .../migrations/0003_auto_20161209_2125.py | 27 ++++++ .../migrations/0004_auto_20161210_1857.py | 22 +++++ .../migrations/0005_auto_20161210_1914.py | 48 +++++++++++ .../migrations/0006_auto_20161210_1915.py | 22 +++++ .../migrations/0007_auto_20161210_1916.py | 20 +++++ .../migrations/0008_auto_20161210_1917.py | 22 +++++ user_profile/models.py | 31 +++++-- 21 files changed, 475 insertions(+), 18 deletions(-) create mode 100644 static/avatar/2016-12-10/aws_logo_web_300px.png create mode 100644 static/provider-logo/openstack-logo-1-300x150_soH1jUf.png create mode 100644 templates/authcp/activation.html create mode 100644 templates/authcp/register.html create mode 100644 templates/authcp/success.html create mode 100644 templates/mail/user_register_welcome.html create mode 100644 templates/mail/user_register_welcome.txt create mode 100644 user_profile/migrations/0003_auto_20161209_2125.py create mode 100644 user_profile/migrations/0004_auto_20161210_1857.py create mode 100644 user_profile/migrations/0005_auto_20161210_1914.py create mode 100644 user_profile/migrations/0006_auto_20161210_1915.py create mode 100644 user_profile/migrations/0007_auto_20161210_1916.py create mode 100644 user_profile/migrations/0008_auto_20161210_1917.py diff --git a/authcp/forms.py b/authcp/forms.py index e69de29..5b1a9f8 100644 --- a/authcp/forms.py +++ b/authcp/forms.py @@ -0,0 +1,36 @@ +import re +from django.contrib.auth.models import User +from django.core.exceptions import ObjectDoesNotExist + +from django import forms + +class UserRegisterForm(forms.Form): + email = forms.EmailField(label='Email') + password1 = forms.CharField( + label='Password', + widget=forms.PasswordInput(), + ) + password2 = forms.CharField( + label='Password (Again)', + widget=forms.PasswordInput(), + ) + tos = forms.BooleanField( + required=True, + error_messages={'required': 'You must accept TOS.'} + ) + + def clean_email(self): + email = self.cleaned_data['email'] + try: + User.objects.get(email=email) + except ObjectDoesNotExist: + return email + raise forms.ValidationError('Email address is not available.') + + def clean_password2(self): + if 'password1' in self.cleaned_data: + password1 = self.cleaned_data['password1'] + password2 = self.cleaned_data['password2'] + if password1 == password2: + return password2 + raise forms.ValidationError('Password do not match.') diff --git a/authcp/urls.py b/authcp/urls.py index 9b9e052..b182ddf 100644 --- a/authcp/urls.py +++ b/authcp/urls.py @@ -1,5 +1,4 @@ -from django.conf.urls import url -from django.contrib import admin +from django.conf.urls import include, url from django.contrib.auth import views as auth_views from . import views @@ -8,4 +7,6 @@ urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^login/$', auth_views.login, {'template_name': 'authcp/login.html'}, name='login'), url(r'^logout/$', auth_views.logout, name='logout'), + url(r'^register/$', views.register_user, name='register'), + url(r'^register-success/$', views.register_success, name='register-success'), ] diff --git a/authcp/views.py b/authcp/views.py index 3e6d569..3e6794b 100644 --- a/authcp/views.py +++ b/authcp/views.py @@ -1,6 +1,82 @@ -from django.shortcuts import render +import random, hashlib, datetime +from django.shortcuts import render, get_object_or_404 +from django.http import HttpResponseRedirect +from django.core.mail import EmailMultiAlternatives +from django.template import Context +from django.template.loader import render_to_string +from django.conf import settings +from django.utils import timezone + +from django.contrib.auth.models import User + +from .forms import UserRegisterForm +from user_profile.models import Profile + +# email sending function +def send_email(con,subject,email_to,email_from): + c = Context(con) + text_content = render_to_string('mail/user_register_welcome.txt', c) + html_content = render_to_string('mail/user_register_welcome.html', c) + + email = EmailMultiAlternatives(subject,text_content,email_from) + email.attach_alternative(html_content, "text/html") + email.to = [email_to] + email.send() def index(request): return render(request, "authcp/index.html", {}) +def register_user(request): + if request.method == 'POST': + form = UserRegisterForm(request.POST) + if form.is_valid(): + u=User.objects.create_user( + form.cleaned_data['email'], + form.cleaned_data['email'], + form.cleaned_data['password2'], + ) + u.is_active=False + u.save() + salt = hashlib.sha1(str(random.random())).hexdigest()[:5] + usernamesalt=form.cleaned_data['email'] + profile=Profile.objects.get(user_id=u.id) + profile.activation_key=hashlib.sha1(salt+usernamesalt).hexdigest() + profile.key_expires=datetime.datetime.strftime(datetime.datetime.now() + datetime.timedelta(days=2), + "%Y-%m-%d %H:%M:%S") + profile.save() + send_email({'u': u, 'profil': profile}, + 'Welcome to our cloud', + u.email, + settings.DEFAULT_EMAIL_FROM, + ) + return render(request, + 'authcp/success.html', + {'u': u, 'profil': profile}) + else: + print(form.errors) + else: + form = UserRegisterForm() + return render(request, 'authcp/register.html', {'form': form}) + +def register_success(request): + return render(request, 'authcp/success.html', {}) + +def activation(request, key): + activation_expired=False + already_active=False + profile=get_object_or_404(Profile, activation_key=key) + if profile.user.is_active == False: + if timezone.now() > profile.key_expires: + # Display: offer the user to send a new activation link + activation_expired=True + id_user=profile.user.id + # Activation successful + else: + profile.user.is_active=True + profile.user.save() + # If user is already active, simply display error message + else: + # Display : error message + already_active=True + return render(request, 'authcp/activation.html', locals()) \ No newline at end of file diff --git a/dash_stack_dashboard/settings.py b/dash_stack_dashboard/settings.py index a451bfe..52889c6 100644 --- a/dash_stack_dashboard/settings.py +++ b/dash_stack_dashboard/settings.py @@ -27,7 +27,7 @@ DEBUG = True ALLOWED_HOSTS = [ 'dash-stack', - '198.211.127.189', + '127.0.0.1', ] # login url @@ -39,6 +39,9 @@ LOGIN_REDIRECT_URL = '/' LOGOUT_REDIRECT_URL = '/auth/login/' +# user profile +AUTH_PROFILE_MODULE = 'user_profile.Profile' + # Application definition INSTALLED_APPS = [ @@ -82,6 +85,7 @@ TEMPLATES = [ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', + 'django_settings_export.settings_export', ], }, }, @@ -152,4 +156,21 @@ STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ] -STATIC_URL = '/static/' \ No newline at end of file +STATIC_URL = '/static/' + +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' + +# Host for sending e-mail. +EMAIL_HOST = 'localhost' + +# Port for sending e-mail. +EMAIL_PORT = 25 + +# Optional SMTP authentication information for EMAIL_HOST. +EMAIL_HOST_USER = '' +EMAIL_HOST_PASSWORD = '' +EMAIL_USE_TLS = False +DEFAULT_EMAIL_FROM = 'admin@dash-stack.org' + +# fullt qualified hostname or domain. Ex +SITE_ROOT_URL = 'http://198.211.127.189/' \ No newline at end of file diff --git a/requirement.txt b/requirement.txt index 24a8447..0641f6e 100644 --- a/requirement.txt +++ b/requirement.txt @@ -3,3 +3,4 @@ Django==1.10.3 mysqlclient==1.3.9 oslo.i18n==3.10.0 requests==2.12.1 +django-settings-export==1.2.1 \ No newline at end of file diff --git a/static/avatar/2016-12-10/aws_logo_web_300px.png b/static/avatar/2016-12-10/aws_logo_web_300px.png new file mode 100644 index 0000000000000000000000000000000000000000..ca57e1ced9313c485c2a155e3ce78d20e786d3b1 GIT binary patch literal 6165 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 literal 0 HcmV?d00001 diff --git a/static/provider-logo/openstack-logo-1-300x150_soH1jUf.png b/static/provider-logo/openstack-logo-1-300x150_soH1jUf.png new file mode 100644 index 0000000000000000000000000000000000000000..b6e1fb02de716d188f7938dbbaa3f752ece374f6 GIT binary patch literal 4629 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 | You have been activated {% endblock title %} + +{% block content %} +
+ + + + +
+ +{% endblock content %} \ No newline at end of file diff --git a/templates/authcp/login.html b/templates/authcp/login.html index 97e7e65..8a4984a 100644 --- a/templates/authcp/login.html +++ b/templates/authcp/login.html @@ -1,8 +1,9 @@ {% extends "base_headless.html" %} -{% block auth %} +{% block title %}dash-stack | Log in{% endblock title %} + +{% block content %} - -{% endblock auth %} \ No newline at end of file +{% endblock content %} \ No newline at end of file diff --git a/templates/authcp/register.html b/templates/authcp/register.html new file mode 100644 index 0000000..6ebd114 --- /dev/null +++ b/templates/authcp/register.html @@ -0,0 +1,62 @@ +{% extends "base_headless.html" %} + +{% block title %}dash-stack | Register {% endblock title %} + +{% block content %} + +
+ + +
+ + + {{ form.errors.email.as_text }} + {{ form.errors.username.as_text }} +
+ + +
+ {{ form.errors.password1.as_text }} +
+ + +
+ {{ form.errors.password2.as_text }} +
+ + +
+
+ {{ form.errors.tos.as_text }} +
+
+ +
+
+ +
+ +
+ +
+ {% csrf_token %} + + + + + I already have a membership +
+ +
+ +{% endblock content %} \ No newline at end of file diff --git a/templates/authcp/success.html b/templates/authcp/success.html new file mode 100644 index 0000000..5af90c1 --- /dev/null +++ b/templates/authcp/success.html @@ -0,0 +1,25 @@ +{% extends "base_headless.html" %} + +{% block title %}dash-stack | Register {% endblock title %} + +{% block content %} +
+ + + {{ u.get_profile.activation_key }}
+ {{ profile }} + + + +
+ +{% endblock content %} \ No newline at end of file diff --git a/templates/base_headless.html b/templates/base_headless.html index 00580ad..2645ebd 100644 --- a/templates/base_headless.html +++ b/templates/base_headless.html @@ -3,7 +3,7 @@ - AdminLTE 2 | Log in + {% block title %}AdminLTE 2 | Log in{% endblock title %} @@ -24,9 +24,10 @@ -{% block auth %} + +{% block content %} -{% endblock auth %} +{% endblock content %} diff --git a/templates/mail/user_register_welcome.html b/templates/mail/user_register_welcome.html new file mode 100644 index 0000000..470144e --- /dev/null +++ b/templates/mail/user_register_welcome.html @@ -0,0 +1,20 @@ + + + + +

Hello,

+ +

Welcome to our cloud platform.

+ +

Activate your email:

+ +Please click on following link to activate your account: + +

+ + {{ profile.activation_key }} + +

+ + + \ No newline at end of file diff --git a/templates/mail/user_register_welcome.txt b/templates/mail/user_register_welcome.txt new file mode 100644 index 0000000..ecd7924 --- /dev/null +++ b/templates/mail/user_register_welcome.txt @@ -0,0 +1,6 @@ +Hello, + +Welcome to our cloud platform. + +Activare your email: + diff --git a/user_profile/migrations/0003_auto_20161209_2125.py b/user_profile/migrations/0003_auto_20161209_2125.py new file mode 100644 index 0000000..793626d --- /dev/null +++ b/user_profile/migrations/0003_auto_20161209_2125.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-12-09 21:25 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0002_auto_20161201_2120'), + ] + + operations = [ + migrations.AddField( + model_name='profile', + name='activation_key', + field=models.CharField(default='', max_length=64), + ), + migrations.AddField( + model_name='profile', + name='key_expires', + field=models.DateTimeField(default=django.utils.timezone.now), + preserve_default=False, + ), + ] diff --git a/user_profile/migrations/0004_auto_20161210_1857.py b/user_profile/migrations/0004_auto_20161210_1857.py new file mode 100644 index 0000000..0eab060 --- /dev/null +++ b/user_profile/migrations/0004_auto_20161210_1857.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-12-10 18:57 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0003_auto_20161209_2125'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='user', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/user_profile/migrations/0005_auto_20161210_1914.py b/user_profile/migrations/0005_auto_20161210_1914.py new file mode 100644 index 0000000..191dfda --- /dev/null +++ b/user_profile/migrations/0005_auto_20161210_1914.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-12-10 19:14 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0004_auto_20161210_1857'), + ] + + operations = [ + migrations.AlterModelOptions( + name='profile', + options={'ordering': ('user',), 'verbose_name': 'Profile', 'verbose_name_plural': 'Profiles'}, + ), + migrations.AlterField( + model_name='profile', + name='activation_key', + field=models.CharField(max_length=64, null=True), + ), + migrations.AlterField( + model_name='profile', + name='key_expires', + field=models.DateTimeField(null=True), + ), + migrations.AlterField( + model_name='profile', + name='provider_password', + field=models.CharField(max_length=50, null=True), + ), + migrations.AlterField( + model_name='profile', + name='selected_provider', + field=models.IntegerField(null=True), + ), + migrations.AlterField( + model_name='profile', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL, verbose_name='user'), + preserve_default=False, + ), + ] diff --git a/user_profile/migrations/0006_auto_20161210_1915.py b/user_profile/migrations/0006_auto_20161210_1915.py new file mode 100644 index 0000000..9b857b5 --- /dev/null +++ b/user_profile/migrations/0006_auto_20161210_1915.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-12-10 19:15 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0005_auto_20161210_1914'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='key_expires', + field=models.DateTimeField(default=django.utils.timezone.now), + preserve_default=False, + ), + ] diff --git a/user_profile/migrations/0007_auto_20161210_1916.py b/user_profile/migrations/0007_auto_20161210_1916.py new file mode 100644 index 0000000..74b5919 --- /dev/null +++ b/user_profile/migrations/0007_auto_20161210_1916.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-12-10 19:16 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0006_auto_20161210_1915'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='key_expires', + field=models.DateTimeField(null=True), + ), + ] diff --git a/user_profile/migrations/0008_auto_20161210_1917.py b/user_profile/migrations/0008_auto_20161210_1917.py new file mode 100644 index 0000000..d5bddc1 --- /dev/null +++ b/user_profile/migrations/0008_auto_20161210_1917.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-12-10 19:17 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_profile', '0007_auto_20161210_1916'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='user', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL, verbose_name='user'), + ), + ] diff --git a/user_profile/models.py b/user_profile/models.py index 1506fdd..ddbfbb0 100644 --- a/user_profile/models.py +++ b/user_profile/models.py @@ -1,14 +1,35 @@ from __future__ import unicode_literals from django.db import models -from django.contrib.auth.models import User +from django.conf import settings +from django.dispatch import receiver +from django.db.models.signals import post_save class Profile(models.Model): user = models.OneToOneField( - User, - on_delete=models.CASCADE + settings.AUTH_USER_MODEL, + related_name='profile', + verbose_name=('user'), + null=True, + blank=True, ) avatar = models.FileField(upload_to='static/avatar/%Y-%m-%d') - provider_password = models.CharField(max_length=50) - selected_provider = models.IntegerField() \ No newline at end of file + provider_password = models.CharField(max_length=50,null=True) + selected_provider = models.IntegerField(null=True) + activation_key = models.CharField(max_length=64,null=True) + key_expires = models.DateTimeField(null=True) + + class Meta: + verbose_name=('Profile') + verbose_name_plural=('Profiles') + ordering=('user',) + + def __str__(self): + return self.user.username + +@receiver(post_save, sender=settings.AUTH_USER_MODEL) +def create_profile_for_new_user(sender, created, instance, **kwargs): + if created: + profile = Profile(user=instance) + profile.save() \ No newline at end of file