update user model to authenticate with the email as username
authorrougeronj
Thu, 04 Jun 2015 20:03:04 +0200
changeset 108 4a152f5f4a09
parent 107 1e18c880021e
child 109 fda9006b0ec1
update user model to authenticate with the email as username
server/ammico/admin.py
server/ammico/models.py
server/authentication/models.py
server/authentication/urls.py
server/authentication/views.py
--- a/server/ammico/admin.py	Tue Jun 02 09:46:55 2015 +0200
+++ b/server/ammico/admin.py	Thu Jun 04 20:03:04 2015 +0200
@@ -1,9 +1,87 @@
+from django import forms
 from django.contrib import admin
+from django.contrib.auth import get_user_model
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.models import Group
 
 from ammico.models import Slide, Book
-from django.contrib.auth import get_user_model
+
+
+class UserCreationForm(forms.ModelForm):
+    """A form for creating new users. Includes all the required
+    fields, plus a repeated password."""
+    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
+    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
+
+    class Meta:
+        model = get_user_model()
+        fields = ('email', 'idUser')
+
+    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(UserCreationForm, self).save(commit=False)
+        user.set_password(self.cleaned_data["password1"])
+        if commit:
+            user.save()
+        return user
 
 
-admin.site.register(Slide)
+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.
+    """
+    password = ReadOnlyPasswordHashField()
+
+    class Meta:
+        model = get_user_model()
+        fields = ('email', 'password', 'idUser', 'is_active', 'is_admin')
+
+    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 MyUserAdmin(UserAdmin):
+    # The forms to add and change user instances
+    form = UserChangeForm
+    add_form = UserCreationForm
+
+    # 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', 'idUser', 'is_admin')
+    list_filter = ('is_admin',)
+    fieldsets = (
+        (None, {'fields': ('email', 'password')}),
+        ('external id', {'fields': ('idUser',)}),
+        ('Permissions', {'fields': ('is_admin',)}),
+    )
+    # 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': ('email', 'idUser', 'password1', 'password2')}
+        ),
+    )
+    search_fields = ('email',)
+    ordering = ('email',)
+    filter_horizontal = ()
+    
+    
 admin.site.register(get_user_model())
+admin.site.unregister(Group)
+admin.site.register(Slide)
 admin.site.register(Book)
\ No newline at end of file
--- a/server/ammico/models.py	Tue Jun 02 09:46:55 2015 +0200
+++ b/server/ammico/models.py	Thu Jun 04 20:03:04 2015 +0200
@@ -8,13 +8,13 @@
 
 class Book(models.Model):
     user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name = "books")
-    idArticle = models.CharField(max_length=512, null=True)
+    idArticle = models.CharField(max_length=512, blank=True, null=True)
     title = models.CharField(max_length=512, blank=True)
     description = models.CharField(max_length=512, blank=True, null=True)
     image = models.URLField(max_length=2048, blank=True)
     date = models.DateTimeField(default=datetime.datetime.now)
     public = models.BooleanField(default=False, db_index=True)
-    parent_visit = models.ForeignKey('Book', related_name = "books_copy", null=True)
+    parent_visit = models.ForeignKey('Book', related_name = "books_copy", blank=True, null=True)
     
     def __str__(self):
         return self.title
@@ -28,7 +28,7 @@
     image = models.URLField(max_length=2048, blank=True)
     date = models.DateTimeField(default=datetime.datetime.now)
     favorite = models.BooleanField(default=False, db_index=True)
-    tags = TaggableManager()
+    tags = TaggableManager(blank=True)
     
     def __str__(self):
         return self.idStop
--- a/server/authentication/models.py	Tue Jun 02 09:46:55 2015 +0200
+++ b/server/authentication/models.py	Thu Jun 04 20:03:04 2015 +0200
@@ -1,12 +1,80 @@
 
-from django.contrib.auth.models import AbstractUser
+from django.contrib.auth.models import (
+    BaseUserManager, AbstractBaseUser
+)
 from django.db import models
+from django.utils.translation import ugettext_lazy as _
 
 import settings
 
 
-class AmmicoUser(AbstractUser):
-    idUser = models.CharField(max_length=50, blank=True)
+class AmmicoUserManager(BaseUserManager):
+    def create_user(self, email, idUser=None, password=None):
+        """
+        Creates and saves a User with the given email and password.
+        """
+        if not email:
+            raise ValueError('Users must have an email address')
+        
+        user = self.model(
+            email=self.normalize_email(email),
+            idUser=idUser,
+        )
+
+        user.set_password(password)
+        user.save(using=self._db)
+        return user
+
+    def create_superuser(self, email, password, idUser=None):
+        """
+        Creates and saves a superuser with the given email and password.
+        """
+        user = self.create_user(email,
+            password=password,
+            idUser=idUser
+        )
+        user.is_admin = True
+        user.save(using=self._db)
+        return user
+
+
+class AmmicoUser(AbstractBaseUser):
+    email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
+    idUser = models.IntegerField(_('identifiant utilisateur'), blank=True, null=True)
+    is_active = models.BooleanField(default=True)
+    is_admin = models.BooleanField(default=False)
+
+    objects = AmmicoUserManager()
+
+    USERNAME_FIELD = 'email'
+    REQUIRED_FIELDS = []
+
+    def get_full_name(self):
+        # The user is identified by their email address
+        return self.email
+
+    def get_short_name(self):
+        # The user is identified by their email address
+        return self.email
+
+    def __str__(self):              # __unicode__ on Python 2
+        return self.email
+
+    def has_perm(self, perm, obj=None):
+        "Does the user have a specific permission?"
+        # Simplest possible answer: Yes, always
+        return True
+
+    def has_module_perms(self, app_label):
+        "Does the user have permissions to view the app `app_label`?"
+        # Simplest possible answer: Yes, always
+        return True
+
+    @property
+    def is_staff(self):
+        "Is the user a member of staff?"
+        # Simplest possible answer: All admins are staff
+        return self.is_admin
     
 class Profile(models.Model):
     user = models.OneToOneField(settings.AUTH_USER_MODEL)
--- a/server/authentication/urls.py	Tue Jun 02 09:46:55 2015 +0200
+++ b/server/authentication/urls.py	Thu Jun 04 20:03:04 2015 +0200
@@ -6,5 +6,5 @@
 
 urlpatterns = patterns('',
     url(r'^user', User.as_view()),
-    url(r'^api-token-auth', ObtainAuthToken.as_view())
+    url(r'^api-token-auth', ObtainAuthToken.as_view()),
 )
--- a/server/authentication/views.py	Tue Jun 02 09:46:55 2015 +0200
+++ b/server/authentication/views.py	Thu Jun 04 20:03:04 2015 +0200
@@ -5,12 +5,11 @@
 import requests
 from rest_framework import serializers, status, permissions, parsers, renderers
 from rest_framework.authtoken.models import Token
-from rest_framework.authtoken.serializers import AuthTokenSerializer
 from rest_framework.response import Response
 from rest_framework.views import APIView
 
+from ammico.views import populateVisit
 from config import URL_JAMESPOT
-from ammico.views import populateVisit
 
 
 class UserSerializer(serializers.ModelSerializer):
@@ -31,11 +30,6 @@
         
     def post(self, request):
         VALID_USER_FIELDS = [f.name for f in get_user_model()._meta.fields]
-        DEFAULTS = {
-            "groups":"",
-            "user_permissions":""
-        }
-        request.data.update(DEFAULTS)
         serialized = UserSerializer(data=request.data)
         
         if serialized.is_valid():
@@ -60,10 +54,8 @@
     renderer_classes = (renderers.JSONRenderer,)
 
     def post(self, request):
-        serializer = AuthTokenSerializer(data=request.data)
-        serializer.is_valid(raise_exception=True)
-        user = serializer.validated_data['user']
+        user = get_user_model().objects.get(email = request.data['email'], password = request.data['password'])
         if (user.idUser):
             populateVisit(user)
-        token, created = Token.objects.get_or_create(user=user)
+        token, _ = Token.objects.get_or_create(user=user)
         return Response({'token': token.key})
\ No newline at end of file