Skip to content
This repository has been archived by the owner on Jul 29, 2020. It is now read-only.

Commit

Permalink
Merge pull request #91 from kbhff/56-first-version-of-sign-up
Browse files Browse the repository at this point in the history
implements #56 As a user I can sign-up to the system
  • Loading branch information
pawciobiel committed Nov 12, 2015
2 parents 28a3647 + 38f2b52 commit d384d6e
Show file tree
Hide file tree
Showing 13 changed files with 181 additions and 23 deletions.
2 changes: 2 additions & 0 deletions eggplant/core/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@

from django.conf import settings
from django.core.urlresolvers import reverse


def coop_vars(request):
return {
'COOP_NAME': settings.COOP_NAME,
'COOP_DESCRIPTION': settings.COOP_DESCRIPTION,
'SIGNUP_URL': reverse(settings.SIGNUP_URL_NAME),
}
3 changes: 2 additions & 1 deletion eggplant/invitations/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from uuid import uuid4

from django.contrib.auth.models import User
from django.contrib.auth import get_user_model

from allauth.account.models import EmailAddress, EmailConfirmation


def create_verified_user(invitation):
password = uuid4().hex
User = get_user_model()
user = User.objects.create_user(invitation.email, invitation.email,
password)
req = None
Expand Down
23 changes: 22 additions & 1 deletion eggplant/profiles/forms.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django import forms
from django.contrib.auth import get_user_model

from allauth.account.forms import SetPasswordForm
from allauth.account.forms import SetPasswordForm, SetPasswordField,\
PasswordField

from eggplant.profiles.models import UserProfile

Expand All @@ -20,6 +22,25 @@ class ProfileForm(forms.Form):
sex = forms.ChoiceField(choices=UserProfile.SEX_CHOICES, required=False)


class SignupForm(ProfileForm):
email = forms.EmailField(required=True)
password1 = SetPasswordField(label="Password", required=True)
password2 = PasswordField(label="Password (again)", required=True)

def clean_email(self):
"""
Check if user is already registered and if so raise validation error.
It may be considered a security hole to inform if a user
is registered or not but it improves usability.
"""
email = self.cleaned_data['email']
User = get_user_model()
if User.objects.filter(email=email).exists():
raise forms.ValidationError('This email is already registered.')
return email


class NewUserSetPasswordForm(SetPasswordForm):
def save(self, *args, **kwargs):
self.user.set_password(self.cleaned_data["password1"])
Expand Down
9 changes: 3 additions & 6 deletions eggplant/profiles/middleware.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.conf import settings
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
Expand All @@ -10,12 +11,8 @@ class NewUserForceProfileMiddleware(object):

def process_request(self, request):
if request.user.is_authenticated() and not request.user.is_superuser:
allowed_paths = (
reverse('eggplant:profiles:profile'),
reverse('account_login'),
reverse('account_logout'),
reverse('account_set_password'),
)
allowed_paths = [reverse(urlname) for urlname in
settings.NEW_USER_FORCE_PROFILE_ALLOWED_URL_NAMES]
if request.path not in allowed_paths:
try:
profile = request.user.profile
Expand Down
38 changes: 38 additions & 0 deletions eggplant/profiles/templates/eggplant/profiles/signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{% extends "eggplant/core/base.html" %}
{% load staticfiles %}
{% load bootstrap3 %}

{% block app_css %}
{% endblock%}

{% block app_js %}
{% endblock%}

{% block content %}


<div class="container">
<div class="row">
<div class="col-md-5 col-md-offset-3">

{% if user.profile.is_complete %}
<h3>Signup</h3>
{% else %}
<h3>Please add Your details</h3>
{% endif %}
<form action="{% url 'eggplant:profiles:signup' %}" method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "star" %} Submit
</button>
{% endbuttons %}
</form>

<hr/>

</div>
</div>
</div>
{% endblock%}
48 changes: 47 additions & 1 deletion eggplant/profiles/tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from allauth.account.models import EmailAddress

from django.core import mail
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.test import TestCase
from allauth.account.models import EmailAddress

# Create your tests here.
from eggplant.factories import UserFactory, DepartmentFactory, \
Expand Down Expand Up @@ -83,3 +85,47 @@ def test_user_member_department_models(self):
self.assertEqual(1, department.accounts.count())
department.accounts.all().delete()
self.assertEqual(0, department.accounts.count())


class TestSignup(TestCase):

def test_signup_get(self):
url = reverse('eggplant:profiles:signup')
response = self.client.get(url)
self.assertEqual(200, response.status_code)
self.assertTemplateUsed(response, 'eggplant/profiles/signup.html')

def test_signup_post(self):
url = reverse('eggplant:profiles:signup')
profile_data = {
'address': 'Vestergade 20c',
'city': 'København',
'postcode': '1456',
'tel': '+45 71 99 91 93',
'sex': 'other',
}
user_data = {
'first_name': 'test first name',
'last_name': 'test last name',
'email': 'test@localhost',
'password1': '!super secure123',
'password2': '!super secure123',
}
user_data.update(profile_data)
response = self.client.post(url, user_data, follow=True)
expected_url = reverse('account_email_verification_sent')
self.assertRedirects(response, expected_url, status_code=302,
target_status_code=200, msg_prefix='')
user_query = User.objects.filter(email=user_data['email'])
self.assertEqual(1, user_query.count())

actual = user_query[0]
profile_query = UserProfile.objects.filter(user=actual, **profile_data)
self.assertEqual(1, profile_query.count())

address_query = EmailAddress.objects.filter(email=user_data['email'])
self.assertEqual(1, address_query.count())

self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject,
'[localhost] Bekræft e-mailadresse')
3 changes: 2 additions & 1 deletion eggplant/profiles/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@


urlpatterns = [
url(r'', views.Profile.as_view(), name='profile')
url(r'signup/$', views.signup, name='signup'),
url(r'$', views.Profile.as_view(), name='profile'),
]
49 changes: 44 additions & 5 deletions eggplant/profiles/views.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import logging
from allauth.account.views import PasswordSetView, sensitive_post_parameters_m, \
PasswordChangeView

from django.contrib import messages
from django.contrib.auth import logout
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse_lazy
from django.http import Http404
from django.shortcuts import redirect

from django.shortcuts import redirect, render
from django.views.generic import FormView
from django.db import transaction

from allauth.account.views import PasswordSetView, PasswordChangeView, \
sensitive_post_parameters_m
from allauth.account.models import EmailAddress

from eggplant.core.views import LoginRequiredMixin
from eggplant.profiles.forms import NewUserSetPasswordForm, ProfileForm
from eggplant.profiles.forms import NewUserSetPasswordForm, ProfileForm, \
SignupForm
from eggplant.profiles.models import UserProfile

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -113,3 +117,38 @@ def get_context_data(self, **kwargs):
context = super(Profile, self).get_context_data(**kwargs)
context['form'] = kwargs['form']
return context


def signup(request):
if request.user.is_authenticated():
messages.info(request, 'You are already logged-in')
return redirect('eggplant:profiles:profile')
form = SignupForm()
if request.method == "POST":
form = SignupForm(request.POST)
if form.is_valid():
with transaction.atomic():
user = User.objects.create_user(
form.cleaned_data['email'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password1'],
first_name=form.cleaned_data['first_name'],
last_name=form.cleaned_data['last_name'],
)
email = EmailAddress.objects.create(
user=user,
email=form.cleaned_data['email'],
primary=True
)
email.send_confirmation(request, signup=True)
non_profile = ('first_name', 'last_name', 'email', 'password1',
'password2')
for field in non_profile:
del form.cleaned_data[field]
UserProfile.objects.filter(user=user).update(**form.cleaned_data)
return redirect('account_email_verification_sent')

ctx = {
'form': form,
}
return render(request, 'eggplant/profiles/signup.html', ctx)
3 changes: 2 additions & 1 deletion eggplant/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
r'^invitations/',
include('eggplant.invitations.urls', namespace='invitations')
),
url(r'^profiles/', include('eggplant.profiles.urls', namespace='profiles')),
url(r'^profiles/',
include('eggplant.profiles.urls', namespace='profiles')),
url(
r'^departments/',
include('eggplant.departments.urls', namespace='departments',)
Expand Down
4 changes: 2 additions & 2 deletions eggplant_project/authnadapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ def is_email_verified(self, request, email):
ret = DepartmentInvitation.objects.filter(
email__iexact=email,
accepted=True
).count()
return bool(ret)
).exists()
return ret
9 changes: 9 additions & 0 deletions eggplant_project/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ def ACCOUNT_USER_DISPLAY(u):
ACCOUNT_SESSION_REMEMBER = None

SITE_OPEN_FOR_SIGNUP = True
SIGNUP_URL_NAME = 'eggplant:profiles:signup'

LOGOUT_URL = 'account_logout'
LOGIN_URL = 'account_login'
Expand Down Expand Up @@ -266,3 +267,11 @@ def ACCOUNT_USER_DISPLAY(u):

GETPAID_SUCCESS_URL_NAME = 'eggplant:market:payment_accepted'
GETPAID_FAILURE_URL_NAME = 'eggplant:market:payment_rejected'

# If a new user has not completed his/her profile we force him to complete it.
NEW_USER_FORCE_PROFILE_ALLOWED_URL_NAMES = (
'eggplant:profiles:profile',
'account_login',
'account_logout',
'account_set_password',
)
6 changes: 3 additions & 3 deletions eggplant_project/templates/account/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

<p><strong>{% trans 'Want to become a member?' %}</strong></p>

{% with signup_url='SIGN_UP_URL_HERE' %}
{% with signup_url=SIGNUP_URL %}
<p>{% blocktrans with coop_name=COOP_NAME %}
You can read more about {{coop_name}} and sign-up <a href="{{signup_url}}">here</a>.
{% endblocktrans %}
Expand All @@ -41,7 +41,7 @@
<h3 class="text-center">{% trans "Member login" %}</h3>

{% if socialaccount.providers %}
<p>{% blocktrans with site.name as site_name %}Please sign in with one
<p>{% blocktrans with site_name=site.name signup_url=SIGNUP_URL %}Please sign in with one
of your existing third party accounts. Or, <a href="{{ signup_url }}">sign up</a>
for a {{ site_name }} account and sign in below:{% endblocktrans %}</p>

Expand Down Expand Up @@ -75,7 +75,7 @@ <h3 class="text-center">{% trans "Member login" %}</h3>
<br />
<br />
<div class="text-center">
<p>{% trans 'Not a member?' %} <a href="SIGN_UP_URL_HERE_2">{% trans 'Sign-up here' %}</a></p>
<p>{% trans 'Not a member?' %} <a href="{{SIGNUP_URL}}">{% trans 'Sign-up here' %}</a></p>
<p><a class="button secondaryAction" href="{% url 'account_reset_password' %}">
{% trans "Forgot your password?" %}</a></p>
</div>
Expand Down
7 changes: 5 additions & 2 deletions eggplant_project/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.contrib import admin
from django.views.generic.base import RedirectView

import eggplant.profiles.views
from eggplant.dashboard import views as dashboard_views

urlpatterns = [
url(r'^admin/', include(admin.site.urls)),

# signup is disabled - we only allow invited users
url(r'^account/signup/$', dashboard_views.home, name='account_signup'),
# allauth signup is disabled - we have our own signup flow
url(r'^account/signup/$',
RedirectView.as_view(url=settings.SIGNUP_URL_NAME, permanent=True),
name='account_signup'),

# override django-allauth password set and change views
url(r'^account/password/change/$',
Expand Down

0 comments on commit d384d6e

Please sign in to comment.