# HG changeset patch # User rougeronj # Date 1433440984 -7200 # Node ID 4a152f5f4a092b77be7407cb11f0ac057d7e389d # Parent 1e18c880021ef4f52f9505ce1e53857c3b6083d1 update user model to authenticate with the email as username diff -r 1e18c880021e -r 4a152f5f4a09 server/ammico/admin.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 diff -r 1e18c880021e -r 4a152f5f4a09 server/ammico/models.py --- 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 diff -r 1e18c880021e -r 4a152f5f4a09 server/authentication/models.py --- 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) diff -r 1e18c880021e -r 4a152f5f4a09 server/authentication/urls.py --- 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()), ) diff -r 1e18c880021e -r 4a152f5f4a09 server/authentication/views.py --- 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