Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Authentications and Custom Admin Forms #2

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion DonationApp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
# Application definition

INSTALLED_APPS = [
'accounts.apps.AccountsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
Expand All @@ -50,11 +51,15 @@
]

ROOT_URLCONF = 'DonationApp.urls'
#
AUTH_USER_MODEL = 'accounts.User'
# # AUTHENTICATION_BACKENDS = ('accounts.backends.FinancerAuth',)
AUTHENTICATION_BACKENDS = ('accounts.backends.CustomAccountAuth',)

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'DIRS': ['DonationApp/templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
Expand Down Expand Up @@ -118,3 +123,6 @@
# https://docs.djangoproject.com/en/2.1/howto/static-files/

STATIC_URL = '/static/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
71 changes: 71 additions & 0 deletions DonationApp/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Jekyll v3.8.5">
<title>Donation App</title>

<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">

<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
}

@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="album.css" rel="stylesheet">
</head>
<body>
<header>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="">Donation App</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav ml-auto">
{% if user.is_authenticated %}
<a class="nav-item nav-link" href="javascript:{document.getElementById('logout').submit()}" onclick="">Logout</a>
<form id="logout" method="POST" action="{% url 'accounts:logout' %}">
{% csrf_token %}
<input type="hidden" />
</form>
{% else %}
<a class="nav-item nav-link" href="{% url 'accounts:signup' %}">Sign Up</a>
<a class="nav-item nav-link" href="{% url 'accounts:login' %}">Login</a>
{% endif %}
</div>
</div>
</div>
</nav>
</header>

<div class="container">
{% block content %}

{% endblock %}
</div>

<footer class="text-muted">
<div class="container text-center">
<p>CopyRight Omer Habib {% now "Y" %}</p>
</div>
</footer>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
</body>
</html>
7 changes: 5 additions & 2 deletions DonationApp/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
path('admin/', admin.site.urls),
]
path('', include('accounts.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
89 changes: 89 additions & 0 deletions accounts/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.contrib.auth.models import Group

from accounts.forms import CustomUserCreationForm
from .models import User

GENDER_TYPES = (
('M', 'Male'),
('F', 'Female'),
)

USER_ROLES = (
('financer', 'Financer'),
('consumer', 'Consumer'),
)


class UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
username = forms.CharField(max_length=50)
email = forms.EmailField(max_length=255)
first_name = forms.CharField(max_length=100)
last_name = forms.CharField(max_length=100)
gender = forms.ChoiceField(choices=GENDER_TYPES, widget=forms.Select())
user_roles = forms.ChoiceField(choices=USER_ROLES, widget=forms.Select())
date_of_birth = forms.DateField(initial='2000-01-01')
is_active = forms.BooleanField(initial=True)
is_staff = forms.BooleanField(initial=True)
is_admin = forms.BooleanField(initial=False)
country = forms.CharField(max_length=50)
state = forms.CharField(max_length=50)
district = forms.CharField(max_length=50)
city = forms.CharField(max_length=50)
area = forms.CharField(max_length=150)
mobile = forms.CharField(max_length=10, initial='0')
password = ReadOnlyPasswordHashField()

class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name', 'gender', 'user_roles', 'date_of_birth',
'is_active', 'is_staff', 'is_admin', 'country', 'state', 'district', 'city', 'area', 'mobile')

def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]


class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
change_form = UserChangeForm
creation_form = CustomUserCreationForm

# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('email', 'date_of_birth', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('first_name', 'last_name', 'gender', 'user_roles', 'date_of_birth', 'mobile',)}),
('Address', {'fields': ('country', 'state', 'district', 'city', 'area',)}),
('Permissions', {'fields': ('financer', 'consumer', 'is_admin', 'is_active', 'is_staff',)}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'email', 'first_name', 'last_name', 'gender', 'user_roles', 'date_of_birth',
'financer', 'consumer', 'is_active', 'is_staff', 'is_admin', 'country', 'state', 'district',
'city', 'area',
'mobile', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()


admin.site.register(User, UserAdmin)
admin.site.unregister(Group)
5 changes: 5 additions & 0 deletions accounts/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class AccountsConfig(AppConfig):
name = 'accounts'
21 changes: 21 additions & 0 deletions accounts/backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from .models import User


class CustomAccountAuth(object):

def authenticate(self, request, username=None, password=None):
try:
user = User.objects.get(username=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None

def get_user(self, username):
try:
user = User.objects.get(username=username)
if user.is_active:
return user
return None
except User.DoesNotExist:
return None
83 changes: 83 additions & 0 deletions accounts/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from django import forms
from django.contrib.auth.forms import UserCreationForm

from .models import User

GENDER_TYPES = (
('M', 'Male'),
('F', 'Female'),
)

USER_ROLES = (
('financer', 'Financer'),
('consumer', 'Consumer'),
)


class CustomUserCreationForm(UserCreationForm):
username = forms.CharField(max_length=50)
email = forms.EmailField(max_length=255)
first_name = forms.CharField(max_length=100)
last_name = forms.CharField(max_length=100)
gender = forms.ChoiceField(choices=GENDER_TYPES, widget=forms.Select())
user_roles = forms.ChoiceField(choices=USER_ROLES, widget=forms.Select())
date_of_birth = forms.DateField(initial='2000-01-01')
country = forms.CharField(max_length=50)
state = forms.CharField(max_length=50)
district = forms.CharField(max_length=50)
city = forms.CharField(max_length=50)
area = forms.CharField(max_length=150)
mobile = forms.CharField(max_length=10, initial='0')
financer = forms.ModelChoiceField(queryset=User.objects.filter(user_roles='financer'), widget=forms.HiddenInput(),
required=False)
consumer = forms.ModelChoiceField(queryset=User.objects.filter(user_roles='financer'),
widget=forms.HiddenInput(),
initial=None,
required=False)
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name', 'gender', 'user_roles', 'date_of_birth',
'country', 'state', 'district', 'city', 'area', 'mobile')

def __init__(self, *args, **kwargs):
super(CustomUserCreationForm, self).__init__(*args, **kwargs)
self.fields['financer'].required = False

def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2

def save(self, commit=True):
# Save the provided password in hashed format
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user


class SignUp(forms.Form):
username = forms.CharField(label="Username", max_length=100)
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput())
first_name = forms.CharField(max_length=100)
last_name = forms.CharField(max_length=100)
gender = forms.ChoiceField()
date_of_birth = forms.DateField()
mobile = forms.CharField(max_length=11)
address = forms.CharField(max_length=255)
city = forms.CharField(max_length=100)
state = forms.CharField(max_length=100)
country = forms.CharField(max_length=100)


class LoginForm(forms.Form):
username = forms.CharField(label="Username", max_length=100)
password = forms.CharField(label="Password", widget=forms.PasswordInput())
53 changes: 53 additions & 0 deletions accounts/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 2.1.3 on 2019-02-08 13:09

import accounts.models
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
('auth', '0009_alter_user_last_name_max_length'),
]

operations = [
migrations.CreateModel(
name='User',
fields=[
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False,
help_text='Designates that this user has all permissions without explicitly assigning them.',
verbose_name='superuser status')),
('username', models.CharField(max_length=50, primary_key=True, serialize=False, unique=True)),
('email', models.EmailField(max_length=255, unique=True)),
('first_name', models.CharField(max_length=100)),
('last_name', models.CharField(max_length=100, null=True)),
('gender', models.CharField(choices=[('M', 'Male'), ('F', 'Female')], max_length=10)),
('user_roles',
models.CharField(choices=[('financer', 'Financer'), ('consumer', 'Consumer')], max_length=20)),
('date_of_birth', models.DateField(default='2000-01-01', null=True)),
('is_active', models.BooleanField(default=True)),
('is_staff', models.BooleanField(default=True)),
('is_admin', models.BooleanField(default=False)),
('country', models.CharField(max_length=50, null=True)),
('state', models.CharField(max_length=50, null=True)),
('district', models.CharField(max_length=50, null=True)),
('city', models.CharField(max_length=50, null=True)),
('area', models.CharField(max_length=150, null=True)),
('mobile', models.CharField(blank=True, default='0', max_length=10, null=True)),
('consumer', accounts.models.ListField(blank=True, default=None, null=True, token=',')),
('financer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'abstract': False,
},
),
]
File renamed without changes.
Loading