Initial commit of DEMOS2 with the upgraded 'Create Event' UI. However, there is no input validation currently
This commit is contained in:
commit
7084bd1b16
155 changed files with 8102 additions and 0 deletions
2
allauthdemo/auth/__init__.py
Executable file
2
allauthdemo/auth/__init__.py
Executable file
|
@ -0,0 +1,2 @@
|
|||
# See https://docs.djangoproject.com/en/1.7/ref/applications/#for-application-authors
|
||||
default_app_config = 'allauthdemo.auth.apps.AllAuthDemoAuthAppConfig'
|
87
allauthdemo/auth/admin.py
Executable file
87
allauthdemo/auth/admin.py
Executable file
|
@ -0,0 +1,87 @@
|
|||
from django.contrib import admin
|
||||
#from django.utils.html import format_html_join
|
||||
#from django.utils.safestring import mark_safe
|
||||
#from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
try:
|
||||
from django.utils.encoding import force_text
|
||||
except ImportError:
|
||||
from django.utils.encoding import force_unicode as force_text
|
||||
|
||||
from .models import DemoUser, UserProfile
|
||||
from .forms import DemoUserAdminForm
|
||||
|
||||
|
||||
class UserProfileAdmin(admin.ModelAdmin):
|
||||
search_fields = ('user', 'dob')
|
||||
ordering = ('user',)
|
||||
list_select_related = ('user',)
|
||||
|
||||
|
||||
admin.site.register(UserProfile, UserProfileAdmin)
|
||||
|
||||
|
||||
class UserProfileAdminInline(admin.TabularInline):
|
||||
model = UserProfile
|
||||
|
||||
|
||||
class DemoUserAdmin(UserAdmin):
|
||||
"""The project uses a custom User model, so it uses a custom User admin model.
|
||||
|
||||
Some related notes at:
|
||||
https://github.com/dabapps/django-email-as-username/blob/master/emailusernames/admin.py
|
||||
|
||||
And:
|
||||
.../lib/python2.7/site-packages/django/contrib/auth/admin.py
|
||||
"""
|
||||
|
||||
inlines = [
|
||||
UserProfileAdminInline,
|
||||
]
|
||||
|
||||
#readonly_fields = ('private_uuid', 'public_id')
|
||||
|
||||
fieldsets = (
|
||||
(None, {'fields': ('email', 'password')}),
|
||||
(_('Personal info'), {'fields': ('first_name', 'last_name', 'display_name')}),
|
||||
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
|
||||
'groups', 'user_permissions')}),
|
||||
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
||||
#(_('Ids'), {'fields': ('private_uuid', 'public_id')}),
|
||||
)
|
||||
|
||||
add_fieldsets = (
|
||||
(None, {
|
||||
'classes': ('wide',),
|
||||
'fields': ('email', 'password1', 'password2')}
|
||||
),
|
||||
)
|
||||
list_display = ('email', 'first_name', 'last_name', 'display_name', 'is_staff')
|
||||
search_fields = ('first_name', 'last_name', 'display_name', 'email')
|
||||
ordering = ('email',)
|
||||
|
||||
form = DemoUserAdminForm
|
||||
|
||||
|
||||
|
||||
|
||||
# *** NOTE ***
|
||||
# As the site uses email instead of username, I'm changing how a User object
|
||||
# displays or identifies itself in admin. The default in Django (file is
|
||||
# lib/python2.7/site-packages/django/contrib/auth/models.py) is
|
||||
#
|
||||
# def __str__(self):
|
||||
# return self.get_username()
|
||||
#
|
||||
# def natural_key(self):
|
||||
# return (self.get_username(),)
|
||||
#
|
||||
# I'm overriding that a cheap way. I'm not sure if I should replace the entire
|
||||
# User object ... might be better.
|
||||
#
|
||||
#User.__unicode__ = lambda(u): u.email
|
||||
#User.natural_key = lambda(u): (u.email,)
|
||||
|
||||
#admin.site.unregister(DjangoDefaultUser)
|
||||
admin.site.register(DemoUser, DemoUserAdmin)
|
8
allauthdemo/auth/apps.py
Executable file
8
allauthdemo/auth/apps.py
Executable file
|
@ -0,0 +1,8 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AllAuthDemoAuthAppConfig(AppConfig):
|
||||
label = "allauthdemo_auth"
|
||||
name = "allauthdemo.auth" # "all_auth_demo_auth"
|
||||
verbose_name = "AllAuthDemo Auth"
|
||||
|
46
allauthdemo/auth/forms.py
Executable file
46
allauthdemo/auth/forms.py
Executable file
|
@ -0,0 +1,46 @@
|
|||
from django import forms
|
||||
from django.core.validators import MinLengthValidator
|
||||
|
||||
from .models import DemoUser
|
||||
|
||||
from captcha.fields import ReCaptchaField
|
||||
|
||||
|
||||
class DemoUserEditForm(forms.ModelForm):
|
||||
"""Form for viewing and editing name fields in a DemoUser object.
|
||||
|
||||
A good reference for Django forms is:
|
||||
http://pydanny.com/core-concepts-django-modelforms.html
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# TODO: this doesn't seem to work. Need to get to the bottom of it.
|
||||
#self.base_fields["display_name"].min_length = 2
|
||||
#self.base_fields["display_name"].validators.append(MinLengthValidator)
|
||||
#print self.base_fields['display_name'].validators
|
||||
super(forms.ModelForm, self).__init__(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
model = DemoUser
|
||||
fields = ('first_name', 'last_name', 'display_name')
|
||||
|
||||
|
||||
class DemoUserAdminForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = DemoUser
|
||||
fields = ('email', 'first_name', 'last_name', 'display_name', 'is_staff', 'is_active', 'date_joined')
|
||||
|
||||
def is_valid(self):
|
||||
#log.info(force_text(self.errors))
|
||||
return super(DemoUserAdminForm, self).is_valid()
|
||||
|
||||
class NameForm(forms.Form):
|
||||
your_name = forms.CharField(label='Your name', max_length=100)
|
||||
|
||||
|
||||
class RegistrationForm(forms.Form):
|
||||
captcha = ReCaptchaField()
|
||||
|
||||
def signup(self, request, user):
|
||||
user.save()
|
199
allauthdemo/auth/models.py
Executable file
199
allauthdemo/auth/models.py
Executable file
|
@ -0,0 +1,199 @@
|
|||
import hashlib
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, UserManager
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.http import urlquote
|
||||
from django.core.mail import send_mail
|
||||
from django.dispatch import receiver
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
try:
|
||||
from django.utils.encoding import force_text
|
||||
except ImportError:
|
||||
from django.utils.encoding import force_unicode as force_text
|
||||
from allauth.account.signals import user_signed_up
|
||||
|
||||
|
||||
class MyUserManager(UserManager):
|
||||
"""
|
||||
Custom User Model manager.
|
||||
|
||||
It overrides default User Model manager's create_user() and create_superuser,
|
||||
which requires username field.
|
||||
"""
|
||||
|
||||
def create_user(self, email, password=None, **kwargs):
|
||||
user = self.model(email=email, **kwargs)
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
return user
|
||||
|
||||
def create_superuser(self, email, password, **kwargs):
|
||||
user = self.model(email=email, is_staff=True, is_superuser=True, **kwargs)
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
return user
|
||||
|
||||
|
||||
class DemoUser(AbstractBaseUser, PermissionsMixin):
|
||||
"""A site-specific user model.
|
||||
|
||||
Important: You don't have to use a custom user model. I did it here because
|
||||
I didn't want a username to be part of the system and I wanted other data
|
||||
to be part of the user and not in a separate table.
|
||||
|
||||
You can avoid the username issue without writing a custom model but it
|
||||
becomes increasingly obtuse as time goes on. Write a custom user model, then
|
||||
add a custom admin form and model.
|
||||
|
||||
Remember to change ``AUTH_USER_MODEL`` in ``settings.py``.
|
||||
"""
|
||||
|
||||
email = models.EmailField(_('email address'), blank=False, unique=True)
|
||||
first_name = models.CharField(_('first name'), max_length=40, blank=True, null=True, unique=False)
|
||||
last_name = models.CharField(_('last name'), max_length=40, blank=True, null=True, unique=False)
|
||||
display_name = models.CharField(_('display name'), max_length=14, blank=True, null=True, unique=False)
|
||||
is_staff = models.BooleanField(_('staff status'), default=False,
|
||||
help_text=_('Designates whether the user can log into this admin '
|
||||
'site.'))
|
||||
is_active = models.BooleanField(_('active'), default=True,
|
||||
help_text=_('Designates whether this user should be treated as '
|
||||
'active. Unselect this instead of deleting accounts.'))
|
||||
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
|
||||
|
||||
objects = MyUserManager()
|
||||
|
||||
USERNAME_FIELD = 'email'
|
||||
REQUIRED_FIELDS = []
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('user')
|
||||
verbose_name_plural = _('users')
|
||||
db_table = 'auth_user'
|
||||
abstract = False
|
||||
|
||||
def get_absolute_url(self):
|
||||
# TODO: what is this for?
|
||||
return "/users/%s/" % urlquote(self.email) # TODO: email ok for this? better to have uuid?
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
if self.first_name:
|
||||
return self.first_name
|
||||
elif self.display_name:
|
||||
return self.display_name
|
||||
return 'You'
|
||||
|
||||
def get_full_name(self):
|
||||
"""
|
||||
Returns the first_name plus the last_name, with a space in between.
|
||||
"""
|
||||
full_name = '%s %s' % (self.first_name, self.last_name)
|
||||
return full_name.strip()
|
||||
|
||||
def get_short_name(self):
|
||||
"Returns the short name for the user."
|
||||
return self.first_name
|
||||
|
||||
def guess_display_name(self):
|
||||
"""Set a display name, if one isn't already set."""
|
||||
if self.display_name:
|
||||
return
|
||||
|
||||
if self.first_name and self.last_name:
|
||||
dn = "%s %s" % (self.first_name, self.last_name[0]) # like "Andrew E"
|
||||
elif self.first_name:
|
||||
dn = self.first_name
|
||||
else:
|
||||
dn = 'You'
|
||||
self.display_name = dn.strip()
|
||||
|
||||
def email_user(self, subject, message, from_email=None):
|
||||
"""
|
||||
Sends an email to this User.
|
||||
"""
|
||||
send_mail(subject, message, from_email, [self.email])
|
||||
|
||||
def __str__(self):
|
||||
return self.email
|
||||
|
||||
def natural_key(self):
|
||||
return (self.email,)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class UserProfile(models.Model):
|
||||
"""Profile data about a user.
|
||||
Certain data makes sense to be in the User model itself, but some
|
||||
is more "profile" data than "user" data. I think this is things like
|
||||
date-of-birth, favourite colour, etc. If you have domain-specific
|
||||
profile information you might create additional profile classes, like
|
||||
say UserGeologistProfile.
|
||||
"""
|
||||
user = models.OneToOneField(DemoUser, on_delete=models.CASCADE, primary_key=True, verbose_name='user', related_name='profile')
|
||||
|
||||
# I oscillate between whether the ``avatar_url`` should be
|
||||
# a) in the User model
|
||||
# b) in this UserProfile model
|
||||
# c) in a table of it's own to track multiple pictures, with the
|
||||
# "current" avatar as a foreign key in User or UserProfile.
|
||||
avatar_url = models.CharField(max_length=256, blank=True, null=True)
|
||||
|
||||
dob=models.DateField(verbose_name="dob", blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return force_text(self.user.email)
|
||||
|
||||
class Meta():
|
||||
db_table = 'user_profile'
|
||||
|
||||
|
||||
@receiver(user_signed_up)
|
||||
def set_initial_user_names(request, user, sociallogin=None, **kwargs):
|
||||
"""
|
||||
When a social account is created successfully and this signal is received,
|
||||
django-allauth passes in the sociallogin param, giving access to metadata on the remote account, e.g.:
|
||||
|
||||
sociallogin.account.provider # e.g. 'twitter'
|
||||
sociallogin.account.get_avatar_url()
|
||||
sociallogin.account.get_profile_url()
|
||||
sociallogin.account.extra_data['screen_name']
|
||||
|
||||
See the socialaccount_socialaccount table for more in the 'extra_data' field.
|
||||
|
||||
From http://birdhouse.org/blog/2013/12/03/django-allauth-retrieve-firstlast-names-from-fb-twitter-google/comment-page-1/
|
||||
"""
|
||||
|
||||
preferred_avatar_size_pixels=256
|
||||
|
||||
picture_url = "http://www.gravatar.com/avatar/{0}?s={1}".format(
|
||||
hashlib.md5(user.email.encode('UTF-8')).hexdigest(),
|
||||
preferred_avatar_size_pixels
|
||||
)
|
||||
|
||||
if sociallogin:
|
||||
# Extract first / last names from social nets and store on User record
|
||||
if sociallogin.account.provider == 'twitter':
|
||||
name = sociallogin.account.extra_data['name']
|
||||
user.first_name = name.split()[0]
|
||||
user.last_name = name.split()[1]
|
||||
|
||||
if sociallogin.account.provider == 'facebook':
|
||||
user.first_name = sociallogin.account.extra_data['first_name']
|
||||
user.last_name = sociallogin.account.extra_data['last_name']
|
||||
#verified = sociallogin.account.extra_data['verified']
|
||||
picture_url = "http://graph.facebook.com/{0}/picture?width={1}&height={1}".format(
|
||||
sociallogin.account.uid, preferred_avatar_size_pixels)
|
||||
|
||||
if sociallogin.account.provider == 'google':
|
||||
user.first_name = sociallogin.account.extra_data['given_name']
|
||||
user.last_name = sociallogin.account.extra_data['family_name']
|
||||
#verified = sociallogin.account.extra_data['verified_email']
|
||||
picture_url = sociallogin.account.extra_data['picture']
|
||||
|
||||
profile = UserProfile(user=user, avatar_url=picture_url)
|
||||
profile.save()
|
||||
|
||||
user.guess_display_name()
|
||||
user.save()
|
3
allauthdemo/auth/tests.py
Executable file
3
allauthdemo/auth/tests.py
Executable file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
53
allauthdemo/auth/views.py
Executable file
53
allauthdemo/auth/views.py
Executable file
|
@ -0,0 +1,53 @@
|
|||
|
||||
|
||||
from django.contrib import messages
|
||||
from django.views.generic.base import TemplateResponseMixin, View
|
||||
from django.views.generic.edit import FormView, ContextMixin, FormMixin, UpdateView
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
|
||||
from .forms import DemoUserEditForm
|
||||
|
||||
class MyModelInstanceMixin(FormMixin):
|
||||
def get_model_instance(self):
|
||||
return None
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(MyModelInstanceMixin, self).get_form_kwargs()
|
||||
instance = self.get_model_instance()
|
||||
if instance:
|
||||
kwargs.update({'instance': instance})
|
||||
return instance
|
||||
|
||||
|
||||
class DemoUserEditView(UpdateView):
|
||||
"""Allow view and update of basic user data.
|
||||
|
||||
In practice this view edits a model, and that model is
|
||||
the DemoUser object itself, specifically the names that
|
||||
a user has.
|
||||
|
||||
The key to updating an existing model, as compared to creating
|
||||
a model (i.e. adding a new row to a database) by using the
|
||||
Django generic view ``UpdateView``, specifically the
|
||||
``get_object`` method.
|
||||
"""
|
||||
form_class = DemoUserEditForm
|
||||
template_name = "auth/profile.html"
|
||||
#success_url = '/email-sent/'
|
||||
view_name = 'account_profile'
|
||||
success_url = reverse_lazy(view_name)
|
||||
|
||||
def get_object(self):
|
||||
return self.request.user
|
||||
|
||||
def form_valid(self, form):
|
||||
# TODO: not sure how to enforce *minimum* length of a field.
|
||||
#print "form valid..."
|
||||
#print "save to user:", self.request.user, form.cleaned_data
|
||||
form.save()
|
||||
messages.add_message(self.request, messages.INFO, 'User profile updated')
|
||||
return super(DemoUserEditView, self).form_valid(form)
|
||||
|
||||
|
||||
account_profile = login_required(DemoUserEditView.as_view())
|
Reference in a new issue