Added new registration system

This commit is contained in:
Zakary Timson 2018-01-25 00:18:13 -05:00
parent ae663a1ef9
commit f3dca67ec4
11 changed files with 214 additions and 72 deletions

View File

@ -53,7 +53,8 @@ INSTALLED_APPS = [
'forum.apps.ForumConfig',
'main.apps.MainConfig',
'newsletters.apps.NewslettersConfig',
'tinymce'
'tinymce',
'widget_tweaks'
]
MIDDLEWARE = [

View File

@ -1,16 +1,16 @@
from django.contrib import admin
from .models import Chapter, Position, Attorney
from .models import Region, Position, Attorney
admin.site.register(Chapter)
admin.site.register(Region)
admin.site.register(Position)
@admin.register(Attorney)
class MemberAdmin(admin.ModelAdmin):
list_display = ['name', 'position', 'chapter', 'phone_formatted', 'email', 'front_page', 'order', 'joined', 'thumbnail']
list_filter = ['chapter', 'position', 'front_page', 'joined']
search_fields = ['email', 'joined', 'name', 'chapter', 'position', 'website', 'phone', 'phone_formatted']
fields = ['image_preview', 'image', 'name', 'position', 'chapter', 'biography', 'phone', 'email', 'website', 'front_page', 'order', 'joined']
list_display = ['last_name', 'first_name', 'position', 'region', 'phone_formatted', 'email', 'front_page', 'order', 'joined', 'thumbnail']
list_filter = ['region', 'position', 'front_page', 'joined']
search_fields = ['email', 'joined', 'last_name', 'first_name', 'region', 'position', 'website', 'phone', 'phone_formatted']
fields = ['image_preview', 'image', 'last_name', 'first_name', 'position', 'region', 'biography', 'phone', 'email', 'website', 'front_page', 'order', 'joined']
readonly_fields = ['image_preview']

78
charter_members/forms.py Normal file
View File

@ -0,0 +1,78 @@
from django.core import mail
from django import forms
from django.contrib.auth.models import Group, User
from tinymce import TinyMCE
from newsletters.models import Subscriber
from .models import Attorney, Position
from OACPL import settings
from OACPL.utils import render_to_string
class RegisterForm(forms.ModelForm):
def email_validator(self):
if User.objects.filter(email=self).exists():
raise forms.ValidationError('This email is already registered')
def password_length(self):
if len(self) < 8:
raise forms.ValidationError('Password must be at least 8 characters long')
biography = forms.CharField(widget=forms.Textarea, required=False, label='Biography')
call_to_bar = forms.CharField(max_length=4, required=False, label='Year of Call to Bar')
case_law = forms.BooleanField(initial=True, required=False)
email = forms.EmailField(max_length=255, validators=[email_validator])
lso = forms.CharField(max_length=20, required=False, label='LSO #')
newsletter = forms.BooleanField(initial=True, required=False)
request_training = forms.CharField(max_length=255, required=False, label='Request Training For...')
password1 = forms.CharField(widget=forms.PasswordInput(), validators=[password_length])
password2 = forms.CharField(widget=forms.PasswordInput())
provide_training = forms.CharField(max_length=255, required=False, label='Offer Training For...')
class Meta:
model = Attorney
fields = ['first_name', 'last_name', 'region', 'password1', 'password2', 'image', 'email', 'address', 'phone', 'website', 'call_to_bar', 'lso', 'biography', 'provide_training', 'request_training', 'case_law', 'newsletter']
def clean(self):
cleaned_data = super().clean()
password = cleaned_data.get('password1')
password_confirm = cleaned_data.get('password2')
if password != password_confirm:
raise forms.ValidationError("The two password fields must match.")
return cleaned_data
def save(self, commit=True):
# Create attorney profile
user = super().save(commit=False)
member = Position.objects.filter(name='Member').first()
if member:
user.position = member
user.save()
# Add user to default Group
default_group = Group.objects.filter(name='default').first()
if default_group:
default_group[0].user_set.add(user)
# Send confirmation email
mail.send_mail('OACPL Registration', 'You have successfully registered to the Ontario Association of Child Protection Lawyers!', settings.EMAIL_HOST_USER, [user.email], html_message=render_to_string('email.html', {'content': 'You have successfully registered to the Ontario Association of Child Protection Lawyers!', 'name': user.first_name + ' ' + user.last_name, 'base_url': settings.BASE_URL}))
# Subscribe to newsletters
if self.cleaned_data['newsletter'] == 'on' and not Subscriber.objects.filter(email=user.email).exists():
Subscriber.objects.create(email=user.email)
# Send email to register@oacpl.org
body = '{} {} ({}) has registered with OACPL. <br><br>'.format(user.first_name, user.last_name, user.email)
if self.cleaned_data['case_law'] == 'on':
body += 'They have request access to case law. <br><br>'
if self.cleaned_data['provide_training']:
body += 'They have offered to provide training for: {}. <br><br>'.format(self.cleaned_data['provide_training'])
if self.cleaned_data['request_training']:
body += 'They have request training for: {}. <br><br>'.format(self.cleaned_data['request_training'])
mail.send_mail(user.first_name + ' ' + user.last_name, body.replace('<br>', ' '), settings.EMAIL_HOST_USER, ['register@oacpl.org'], html_message=render_to_string('email.html', {'content': body, 'base_url': settings.BASE_URL}))
# Create Auth
auth = User.objects.create_user(user.email, first_name=user.first_name, last_name=user.last_name, email=user.email, password=self.cleaned_data['password1'])
auth.save()
return auth

View File

@ -1,10 +1,11 @@
from django.conf import settings
from django.db import models
from django.utils import timezone
from tinymce import HTMLField
class Chapter(models.Model):
class Region(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
@ -12,23 +13,27 @@ class Chapter(models.Model):
class Position(models.Model):
position_name = models.CharField(max_length=50)
name = models.CharField(max_length=50)
def __str__(self):
return self.position_name
return self.name
class Attorney(models.Model):
address = models.CharField(max_length=255)
biography = HTMLField(blank=True, null=True)
chapter = models.ForeignKey(Chapter, blank=True, null=True)
email = models.CharField(max_length=255, blank=True, null=True)
call_to_bar = models.CharField(max_length=4, blank=True, null=True)
region = models.ForeignKey(Region, blank=True, null=True)
email = models.CharField(max_length=255)
first_name = models.CharField(max_length=100)
front_page = models.BooleanField(default=False)
image = models.ImageField(upload_to='portraits', default='portraits/silhouette.png')
joined = models.DateField(blank=True, null=True)
name = models.CharField(max_length=100)
joined = models.DateField(default=timezone.now)
last_name = models.CharField(max_length=100)
lso = models.CharField(max_length=20, blank= True, null=True)
order = models.IntegerField(blank=True, null=True, verbose_name='Order On Front Page')
phone = models.CharField(max_length=10, blank=True, null=True)
position = models.ForeignKey(Position)
phone = models.CharField(max_length=10)
position = models.ForeignKey(Position, blank=True, null=True)
website = models.CharField(max_length=255, blank=True, null=True)
def phone_formatted(self):
@ -47,4 +52,4 @@ class Attorney(models.Model):
image_preview.allow_tags = True
def __str__(self):
return self.name
return self.first_name + ' ' + self.last_name

View File

@ -3,19 +3,19 @@
{% block body %}
<div class="container-fluid bg-dark-primary py-3">
<div class="container">
{% for chapter in chapters %}
{% for region in region %}
<div class="row bg-white mb-5">
<div class="col-12 pt-3">
<h2 class="text-dark-primary">{{ chapter }}</h2>
<h2 class="text-dark-primary">{{ region }}</h2>
<hr style="border-top: 1px solid rgba(0,0,0,0.2) !important">
<div class="row">
{% for attorney in attorneys %}
{% if attorney.chapter == chapter %}
{% if attorney.region == region %}
<a class="col-3 text-center pt-5" href="{% url 'attorney' attorney.id %}">
<div>
<img class="pb-3" src="/media/{{ attorney.image }}"
style="width: auto; max-width: 100%; height: 200px"/>
<h5 class="text-dark-primary">{{ attorney.name }}</h5>
<h5 class="text-dark-primary">{{ attorney.first_name }} {{ attorney.last_name }}</h5>
<span class="text-light-primary">{{ attorney.position }}</span>
<hr>
</div>

View File

@ -4,7 +4,7 @@
<div class="container-fluid">
<div class="row bg-dark-primary">
<div class="col-lg-3 ml-auto">
<h2 class="d-lg-none text-white mt-3">{{ attorney.name }}</h2>
<h2 class="d-lg-none text-white mt-3">{{ attorney.first_name }} {{ attorney.last_name }}</h2>
<div class="p-2 my-3 shadow bg-white">
<img class="d-block mx-auto" src="/media/{{ attorney.image }}" style="max-width: 100%"/>
</div>
@ -14,7 +14,7 @@
</div>
<div class="col-lg-6 pt-3 bg-light-blue">
<div class="col-lg-6">
<h2 class="d-none d-lg-inline text-dark-primary">{{ attorney.name }}</h2>
<h2 class="d-none d-lg-inline text-dark-primary">{{ attorney.first_name }} {{ attorney.last_name }}</h2>
<p>{{ attorney.biography | safe }}</p>
</div>
</div>

View File

@ -1,7 +1,7 @@
from django.db.models import Count
from django.shortcuts import render
from .models import Chapter, Attorney
from .models import Region, Attorney
def index(request, id):
@ -10,6 +10,6 @@ def index(request, id):
def all(request):
chapters = Chapter.objects.all().order_by('name')
attorneys = Attorney.objects.all().annotate(Count('chapter'))
return render(request, 'all.html', {'chapters': chapters, 'attorneys': attorneys})
region = Region.objects.all().order_by('name')
attorneys = Attorney.objects.all().annotate(Count('region'))
return render(request, 'all.html', {'region': region, 'attorneys': attorneys})

View File

@ -141,7 +141,7 @@
<a class="col-4 text-center pt-5" href="{% url 'attorney' attorney.id %}">
<div>
<img class="pb-3" src="/media/{{ attorney.image }}" style="width: auto; max-width: 100%; height: 200px"/>
<h5 class="text-dark-primary">{{ attorney.name }}</h5>
<h5 class="text-dark-primary">{{ attorney.first_name }} {{ attorney.last_name }}</h5>
<span class="text-light-primary">{{ attorney.position }}</span>
<hr>
</div>

View File

@ -1,5 +1,6 @@
{% extends 'base.html' %}
{% load static %}
{% load widget_tweaks %}
{% block head %}
<style>
@ -19,20 +20,20 @@
</style>
<script>
$(function() {
$('#register-mode').click(function() {
$(function () {
$('#register-mode').click(function () {
$('#login-form').collapse('hide');
$('#register-form').collapse('show');
$('#reset-form').collapse('hide');
});
$('#login-mode').click(function() {
$('#login-mode').click(function () {
$('#login-form').collapse('show');
$('#register-form').collapse('hide');
$('#reset-form').collapse('hide');
});
$('#forgot-password').click(function() {
$('#forgot-password').click(function () {
$('#login-form').collapse('hide');
$('#register-form').collapse('hide');
$('#reset-form').collapse('show');
@ -42,12 +43,18 @@
$('#login-form input[name="username"]').css('border-color', '#ff0000').effect('shake');
$('#login-form input[name="password"]').css('border-color', '#ff0000').effect('shake');
{% endif %}
{% if register.errors %}
$('#login-form').collapse('hide');
$('#register-form').collapse('show');
$('#reset-form').collapse('hide');
{% endif %}
});
</script>
{% endblock %}
{% block body %}
<div class="col-sm-11 col-md-6 col-lg-4 col-xl-2 mx-auto mt-5 p-5 login">
<div class="col-11 col-md-8 col-lg-6 col-xl-4 mx-auto mt-5 p-5 login">
<div class="form">
<div class="my-4">
<img src="{% static 'main/img/logo.png' %}" height="30px" width="auto">
@ -62,32 +69,96 @@
<form id="login-form" class="collapse show" method="post">
{% csrf_token %}
<input type="hidden" name="request" value="login">
<input type="text" class="form-control mb-2 p-2" name="username" placeholder="Username"/>
<input type="text" class="form-control mb-2 p-2" name="username" placeholder="Email"/>
<input type="password" class="form-control mb-2 p-2" name="password" placeholder="Password"/>
<button class="btn btn-primary col-12 mb-2 p-2">login</button>
<p class="d-inline-block text-muted curs-pointer"><a id="register-mode">Register</a></p>
{% if failed %}
<p class="d-inline-block text-muted curs-pointer float-right"><a id="forgot-password">Forgot Password</a></p>
<p class="d-inline-block text-muted curs-pointer float-right"><a id="forgot-password">Forgot
Password</a></p>
{% endif %}
</form>
<form id="register-form" class="collapse" method="post">
<form id="register-form" class="collapse" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="request" value="register">
<input type="text" class="form-control mb-2 p-2" name="username" placeholder="Username"/>
<input type="text" class="form-control mb-2 p-2" name="email" placeholder="Email"/>
<input type="password" class="form-control mb-2 p-2" name="password" placeholder="Password"/>
<input type="password" class="form-control mb-2 p-2" placeholder="Confirm Password"/>
<div class="col-12 px-0">
<input id="newsletter" type="checkbox" class="mb-2 curs-pointer" name="newsletter">
<label for="newsletter" class="curs-pointer">Newsletter</label>
{% if register.errors %}
<div class="alert alert-danger" role="alert">
{% for key, value in register.errors.items %}
{{ value }}
{% endfor %}
</div>
{% endif %}
<h3>General Information</h3>
<div class="form-row">
<div class="form-group col-6">
{{ register.first_name|add_class:"form-control"|attr:"placeholder:First Name" }}
</div>
<div class="form-group col-6">
{{ register.last_name|add_class:"form-control"|attr:"placeholder:Last Name" }}
</div>
<div class="form-group col-6">
{{ register.password1|add_class:"form-control"|attr:"placeholder:Password" }}
</div>
<div class="form-group col-6">
{{ register.password2|add_class:"form-control"|attr:"placeholder:Confirm Password" }}
</div>
<div class="form-group col-6">
{{ register.phone|add_class:"form-control"|attr:"placeholder:Phone Number" }}
</div>
<div class="form-group col-6">
{{ register.email|add_class:"form-control"|attr:"placeholder:Email" }}
</div>
<div class="form-group col-8">
{{ register.address|add_class:"form-control"|attr:"placeholder:Address" }}
</div>
<div class="form-group col-4">
{{ register.region|add_class:"form-control"}}
</div>
<div class="form-group col-12">
{{ register.website|add_class:"form-control"|attr:"placeholder:Website" }}
</div>
</div>
<div class="col-12 px-0">
<input id="caselaw" type="checkbox" class="mb-2 curs-pointer" name="caselaw">
<label for="caselaw" class="curs-pointer">Case Law Access</label>
<h3>Attorney Information</h3>
<div class="form-row">
<div class="form-group col-6">
{{ register.call_to_bar|add_class:"form-control"|attr:"placeholder:Year of Call to Bar" }}
</div>
<div class="form-group col-6">
{{ register.lso|add_class:"form-control"|attr:"placeholder:LSO #" }}
</div>
<div class="form-group col-12">
Portrait
{{ register.image|add_class:"form-control" }}
</div>
<div class="form-group col-12">
{{ register.biography|add_class:"form-control"|attr:"placeholder:Biography" }}
</div>
</div>
<h3>Other</h3>
<div class="form-row">
<div class="form-group col-12">
<div class="form-check">
{{ register.newsletter|add_class:"form-check-input" }} <label class="form-check-label">Receive
newsletters</label>
</div>
</div>
<div class="form-group col-12">
<div class="form-check">
{{ register.case_law|add_class:"form-check-input" }} <label class="form-check-label">Request
access to case law database</label>
</div>
</div>
<div class="form-group col-12">
{{ register.provide_training|add_class:"form-control"|attr:"placeholder:Training I am willing to provide..." }}
</div>
<div class="form-group col-12">
{{ register.request_training|add_class:"form-control"|attr:"placeholder:Training I would like to recieve..." }}
</div>
</div>
<button class="btn btn-primary col-12 mb-2 p-2">Register</button>
<p class="text-muted curs-pointer"><a id="login-mode">Login</a></p>
<p class="d-inline-block text-muted curs-pointer"><a id="login-mode">Login</a></p>
</form>
<form id="reset-form" class="collapse" method="post">

View File

@ -1,14 +1,11 @@
from django.http import JsonResponse
from django.contrib import auth
from django.contrib.auth.models import Group, User, Permission
from django.core import mail
from django.db.models import Q
from django.shortcuts import render, redirect
from django.template.loader import render_to_string
from charter_members.forms import RegisterForm
from OACPL.utils import url_fix_render_to_string
from charter_members.models import Attorney
from newsletters.models import Subscriber
from OACPL import settings
@ -33,33 +30,23 @@ def contact(request):
def login(request):
if request.method == 'POST':
if request.POST.get('request') == 'login':
if request.POST.get('request') == 'register':
register_form = RegisterForm(request.POST, request.FILES)
if register_form.is_valid():
user = register_form.save()
auth.login(request, user)
return redirect('/')
elif request.POST.get('request') == 'login':
user = auth.authenticate(request, username=request.POST.get('username'), password=request.POST.get('password'))
if user:
auth.login(request, user)
return redirect('/')
else:
return render(request, 'login.html', {'navbar': False, 'footer': False, 'failed': True})
elif request.POST.get('request') == 'register':
user = User.objects.create_user(request.POST.get('username'), email=request.POST.get('email'), password=request.POST.get('password'))
user.save()
default_group = Group.objects.filter(name='default')
if default_group:
default_group[0].user_set.add(user)
if settings.EMAIL_HOST:
mail.send_mail('OACPL Registration', 'You have successfully registered to the Ontario Association of Child Protection Lawyers!', settings.EMAIL_HOST_USER, [request.POST.get('email')], html_message=render_to_string('email.html', {'content': 'You have successfully registered to the Ontario Association of Child Protection Lawyers!', 'name': user.username, 'base_url': settings.BASE_URL}))
if request.POST.get('newsletter'):
Subscriber.objects.create(email=request.POST.get('email'))
if request.POST.get('caselaw'):
perm = Permission.objects.get(codename='change_user')
admins = User.objects.filter(Q(groups__permissions=perm) | Q(user_permissions=perm) | Q(is_superuser=True)).distinct().values_list('email', flat=True)
mail.send_mail('OACPL Case Law Request', '{} {} ({}) has requested access to case law'.format(user.first_name, user.last_name, user.email), settings.EMAIL_HOST_USER, admins, html_message=render_to_string('email.html', {'content': '{} {} ({}) has requested access to case law'.format(user.first_name, user.last_name, user.email), 'base_url': settings.BASE_URL}))
auth.login(request, user)
return redirect('/')
else:
return render(request, 'login.html', {'navbar': False, 'footer': False})
if 'register_form' not in vars():
register_form = RegisterForm()
return render(request, 'login.html', {'navbar': False, 'footer': False, 'register': register_form})
def logout(request):

View File

@ -1,7 +1,7 @@
bootstrap-admin==0.3.7.1
Django==1.11.5
django-forms-bootstrap==3.1.0
django-tinymce4-lite==1.7.0
django-widget-tweaks==1.4.1
mysqlclient==1.3.12
Pillow==4.2.1
requests==2.11.1