Migration des mots de passe vers les utilisateurs Django
authorEric Mc Sween <eric.mcsween@gmail.com>
Fri, 10 Dec 2010 21:44:41 +0000 (16:44 -0500)
committerEric Mc Sween <eric.mcsween@gmail.com>
Fri, 10 Dec 2010 21:44:41 +0000 (16:44 -0500)
18 files changed:
auf_savoirs_en_partage/authentification.py
auf_savoirs_en_partage/chercheurs/decorators.py [new file with mode: 0644]
auf_savoirs_en_partage/chercheurs/forms.py
auf_savoirs_en_partage/chercheurs/middleware.py [new file with mode: 0644]
auf_savoirs_en_partage/chercheurs/models.py
auf_savoirs_en_partage/chercheurs/utils.py [new file with mode: 0644]
auf_savoirs_en_partage/chercheurs/views.py
auf_savoirs_en_partage/context_processors.py
auf_savoirs_en_partage/media/css/global.css
auf_savoirs_en_partage/settings.py
auf_savoirs_en_partage/sql/2010-12-08.sql [new file with mode: 0644]
auf_savoirs_en_partage/sql/README
auf_savoirs_en_partage/templates/accounts/login.html [deleted file]
auf_savoirs_en_partage/templates/accounts/new_password.html
auf_savoirs_en_partage/templates/chercheurs/actions.html
auf_savoirs_en_partage/templates/container_base.html
auf_savoirs_en_partage/templates/registration/login.html [new file with mode: 0644]
auf_savoirs_en_partage/urls.py

index 3dd916e..ff21d84 100644 (file)
@@ -1,64 +1,15 @@
 # -*- encoding: utf-8 -*-
-import hashlib, sys
-
-import settings
+from chercheurs.models import Personne
 from django.contrib.auth.backends import ModelBackend
-from django.contrib.auth.models import User as DjangoUser, check_password
+from django.contrib.auth.models import check_password
 
-from chercheurs.models import Personne as RemoteUser
+class PersonneBackend(ModelBackend):
+    """Authentifie un chercheur qui a le courriel donné."""
 
-class CascadeBackend(ModelBackend):
     def authenticate(self, username=None, password=None):
-        user = None
-        email = username
-
-        # Cherche les comptes roa+locaux
-        remoteUser = localUser = None
-        try:
-            remoteUser = RemoteUser.objects.get(courriel=email)
-            if settings.AUTH_PASSWORD_REQUIRED and not remoteUser.check_password(password):
-                remoteUser = None
-        except:
-            pass
         try:
-            localUser = DjangoUser.objects.get (username=username)
-        except: pass
-
-        # Si on a pas besoin du mdp, on doit copier qd meme,
-        # il ne faut jamais retourner un "RemoteUser" ici
-        if not settings.AUTH_PASSWORD_REQUIRED:
-            if remoteUser and not localUser:
-                localUser = DjangoUser (username = username,
-                                        email = username,
-                                        first_name = remoteUser.prenom,
-                                        last_name = remoteUser.nom,
-                                        is_staff = settings.USERS_AS_STAFF,
-                                        is_active = True,
-                                        is_superuser = False)
-                localUser.set_password (password)
-                localUser.save ()
-            user = localUser
-        # Gestion des comptes roa vs. local
-        else:
-            # Local existe pas, on doit de tte facon le creer
-            if not localUser:
-                localUser = DjangoUser (username = username,
-                        email = email, 
-                        is_staff = settings.USERS_AS_STAFF,
-                        is_active = True,
-                        is_superuser = False)
-            # Cas du compte local seul, on verifie le mot de passe
-            elif not remoteUser:
-                if localUser.check_password (password):
-                    user = localUser
-            # Compte roa, on valide le mot de passe distant et on
-            # met a jour la copie locale
-            if remoteUser:
-                localUser.first_name = remoteUser.prenom
-                localUser.last_name = remoteUser.nom
-                # pass distant en md5
-                localUser.set_password (password)
-                localUser.save ()
-                user = localUser
-
-        return user
+            personne = Personne.objects.get(courriel=username)
+        except Personne.DoesNotExist:
+            return None
+        if personne.user.check_password(password):
+            return personne.user
diff --git a/auf_savoirs_en_partage/chercheurs/decorators.py b/auf_savoirs_en_partage/chercheurs/decorators.py
new file mode 100644 (file)
index 0000000..64da9a9
--- /dev/null
@@ -0,0 +1,18 @@
+# coding: utf-8
+
+from chercheurs.models import Personne, Chercheur
+from django.conf import settings
+from django.contrib.auth.decorators import login_required
+from django.http import HttpResponseRedirect
+
+def chercheur_required(func):
+    """Décorateur qui vérifie si un chercheur est connecté."""
+
+    def wrapper(request, *args, **kwargs):
+        chercheur = request.chercheur
+        if chercheur: 
+            return func(request, *args, **kwargs)
+        else:
+            return HttpResponseRedirect(settings.LOGIN_URL)
+
+    return wrapper
index 6165007..69ab78b 100644 (file)
@@ -187,8 +187,9 @@ class ChercheurInscriptionForm(ChercheurForm):
         return confirmation
 
     def save(self):
-        self.instance.set_password(self.cleaned_data['password'])
-        return super(ChercheurInscriptionForm, self).save()
+        super(ChercheurInscriptionForm, self).save()
+        self.instance.user.set_password(self.cleaned_data['password'])
+        self.instance.user.save()
 
 class GroupesForm(forms.Form):
     """Formulaire qui associe des groupes à un chercheur."""
diff --git a/auf_savoirs_en_partage/chercheurs/middleware.py b/auf_savoirs_en_partage/chercheurs/middleware.py
new file mode 100644 (file)
index 0000000..160cd8f
--- /dev/null
@@ -0,0 +1,18 @@
+from chercheurs.models import Personne, Chercheur
+
+class LazyChercheur(object):
+
+    def __get__(self, request, obj_type=None):
+        if not hasattr(request, '_cached_chercheur'):
+            request._cached_chercheur = None
+            if request.user.is_authenticated():
+                try:
+                    request._cached_chercheur = request.user.personne.chercheur
+                except (Personne.DoesNotExist, ChercheurDoesNotExist):
+                    pass
+        return request._cached_chercheur
+
+class ChercheurMiddleware(object):
+    
+    def process_request(self, request):
+        request.__class__.chercheur = LazyChercheur()
index a52868e..7887ecb 100644 (file)
@@ -1,6 +1,8 @@
 # -*- encoding: utf-8 -*-
 import hashlib
+from chercheurs.utils import get_django_user_for_email
 from datamaster_modeles.models import *
+from django.contrib.auth.models import User
 from django.db import models
 from django.db.models import Q
 from django.utils.encoding import smart_str
@@ -9,6 +11,7 @@ from savoirs.models import Discipline, SEPManager, SEPSphinxQuerySet, SEPQuerySe
 
 GENRE_CHOICES = (('m', 'Homme'), ('f', 'Femme'))
 class Personne(models.Model):
+    user = models.OneToOneField(User, null=True, editable=False)
     salutation = models.CharField(max_length=128, null=True, blank=True)
     nom = models.CharField(max_length=255)
     prenom = models.CharField(max_length=128, verbose_name='prénom')
@@ -20,7 +23,6 @@ class Personne(models.Model):
     genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
     commentaire = models.TextField(verbose_name='commentaires', null=True, blank=True)
     actif = models.BooleanField(editable=False, default=True)
-    encrypted_password = models.CharField(db_column='password', max_length=35, verbose_name='Mot de passe')
 
     def __unicode__(self):
         return u"%s %s, %s" % (self.prenom, self.nom, self.courriel)
@@ -28,17 +30,20 @@ class Personne(models.Model):
     class Meta:
         ordering = ["nom", "prenom"]
 
-    def set_password(self, clear_password):
-        self.encrypted_password = self.encrypt_password(clear_password)
-
-    def check_password(self, clear_password):
-        return self.encrypted_password == self.encrypt_password(clear_password)
-    
-    def encrypt_password(self, clear_password):
-        return hashlib.md5(smart_str(clear_password)).hexdigest()
-
-    def get_new_password_code(self):
-        return hashlib.md5(smart_str(self.courriel + self.encrypted_password)).hexdigest()[0:6]
+    def save(self):
+        if self.actif:
+            if self.user:
+                self.user.username = self.courriel
+                self.user.email = self.courriel
+            else:
+                self.user = get_django_user_for_email(self.courriel)
+            self.user.last_name = self.nom
+            self.user.first_name = self.prenom
+        else:
+            if self.user:
+                self.user.is_active = False
+        self.user.save()
+        super(Personne, self).save()
 
 class ChercheurQuerySet(SEPQuerySet):
 
@@ -155,9 +160,9 @@ class Chercheur(Personne):
 
     #Domaine
     thematique = models.ForeignKey(Thematique, db_column='thematique', null=True, verbose_name='thematique')
-    mots_cles = models.CharField(max_length=255, null=True, verbose_name='mots-clés')                    
+    mots_cles = models.CharField(max_length=255, null=True, verbose_name='mots-clés') 
     discipline = models.ForeignKey(Discipline, db_column='discipline', null=True, verbose_name='Discipline')
-    theme_recherche = models.TextField(null=True, blank=True, verbose_name='thèmes de recherche')                                    
+    theme_recherche = models.TextField(null=True, blank=True, verbose_name='thèmes de recherche') 
     groupe_recherche = models.CharField(max_length=255, blank=True, verbose_name='groupe de recherche')
     url_site_web = models.URLField(max_length=255, null=True, blank=True, 
                                    verbose_name='adresse site Internet', verify_exists=False)
diff --git a/auf_savoirs_en_partage/chercheurs/utils.py b/auf_savoirs_en_partage/chercheurs/utils.py
new file mode 100644 (file)
index 0000000..df5eed9
--- /dev/null
@@ -0,0 +1,28 @@
+# coding: utf-8
+import re
+from django.contrib.auth.models import User
+
+def get_django_user_for_email(email):
+    """Retourne un utilisateur Django avec le courriel donné.
+
+       S'il y a déjà un utilisateur avec ce courriel, on s'assure qu'il est activé.
+
+       Sinon, on crée un nouvel utilisateur."""
+    try:
+        user = User.objects.get(email=email)
+        if not user.is_active:
+            user.is_active = True
+        user.save()
+    except User.DoesNotExist:
+        username = email.split('@')[0]
+        username = re.sub('\W', '_', username)[:30]
+        i = 1
+        while User.objects.filter(username=username).count() > 0:
+            suffix = '_' + str(i)
+            username = username[:30-len(suffix)] + suffix
+            i += 1
+        # XXX: possible race condition here...
+        user = User.objects.create_user(username, email)
+        user.save()
+    return user
+
index 415ef8c..5bf3e02 100644 (file)
@@ -1,5 +1,6 @@
 # -*- encoding: utf-8 -*-
 import hashlib
+from chercheurs.decorators import chercheur_required
 from django.shortcuts import render_to_response
 from django.http import HttpResponseRedirect, HttpResponse
 from django.template import Context, RequestContext
@@ -42,22 +43,19 @@ def send_password(request):
             variables = { 'user': u,
                           'link': link,
                           'SITE_ROOT_URL': settings.SITE_ROOT_URL,
-                          'CONTACT_EMAIL': settings.CONTACT_EMAIL,
-                }     
+                          'CONTACT_EMAIL': settings.CONTACT_EMAIL }
             t = get_template('accounts/email_password.html')
-            content = t.render(Context(variables)) 
+            content = t.render(variables)
             
             send_mail('Savoirs en partage: changement de mot de passe',
-                    content, settings.CONTACT_EMAIL,
-                [u.courriel], fail_silently=False)
+                      content, settings.CONTACT_EMAIL,
+                      [u.courriel], fail_silently=False)
     else:
         form = SendPasswordForm()
-    
-    variables = { 'form': form,
-                }
-    return render_to_response ("accounts/send_password.html", \
-            Context (variables), 
-            context_instance = RequestContext(request))
+
+    return render_to_response("accounts/send_password.html",
+                              dict(form=form), 
+                              context_instance=RequestContext(request))
             
 def new_password(request, email, code):
     u = Personne.objects.get(courriel=email)
@@ -74,23 +72,18 @@ def new_password(request, email, code):
             form = NewPasswordForm()
     else:
         return HttpResponseRedirect('/')
-    variables = { 'form': form,
-                  'message': message,
-                }
-    return render_to_response ("accounts/new_password.html", \
-            Context (variables), 
-            context_instance = RequestContext(request))
+    return render_to_response("accounts/new_password.html",
+                              dict(form=form, message=message),
+                              context_instance=RequestContext(request))
 
-@login_required()            
+@login_required          
 def change_password(request):
-    context_instance = RequestContext(request)
-    u = context_instance['user_chercheur']
     message = ""
     if request.method == "POST":
         form = NewPasswordForm(data=request.POST)
         if form.is_valid():
-            u.set_password(form.cleaned_data['password'])
-            u.save()
+            request.user.set_password(form.cleaned_data['password'])
+            request.user.save()
             message = "Votre mot de passe a été modifié."
     else:
         form = NewPasswordForm()
@@ -101,22 +94,6 @@ def change_password(request):
             Context (variables), 
             context_instance = RequestContext(request))            
              
-def chercheur_login(request):
-    "Displays the login form and handles the login action."
-    if request.method == "POST":
-        form = AuthenticationForm(data=request.POST)
-        if form.is_valid():
-            from django.contrib.auth import login
-            login(request, form.get_user())
-            if request.session.test_cookie_worked():
-                request.session.delete_test_cookie()
-            return HttpResponseRedirect(url('chercheurs.views.perso'))
-    else:
-        form = AuthenticationForm(request)
-    request.session.set_test_cookie()
-    return render_to_response('accounts/login.html', dict(form=form),
-                              context_instance=RequestContext(request))
-    
 def index(request):
     """Répertoire des chercheurs"""
     search_form = RepertoireSearchForm(request.GET)
@@ -157,13 +134,10 @@ def inscription(request):
                               dict(forms=forms),
                               context_instance=RequestContext(request))
 
-@login_required()
+@chercheur_required
 def desinscription(request):
     """Désinscription du chercheur"""
-    try:
-        chercheur = Chercheur.objects.get(courriel=request.user.email, actif=True)
-    except Chercheur.DoesNotExist:
-        return HttpResponseRedirect(url('chercheurs.views.chercheur_login'))
+    chercheur = request.chercheur
     if request.method == 'POST':
         if request.POST.get('confirmer'):
             chercheur.actif = False
@@ -177,12 +151,11 @@ def desinscription(request):
     return render_to_response("chercheurs/desinscription.html", {},
                               context_instance=RequestContext(request))
 
-@login_required()
+@chercheur_required
 @never_cache
 def edit(request):
     """Edition d'un chercheur"""
-    context_instance = RequestContext(request)
-    chercheur = context_instance['user_chercheur']    
+    chercheur = request.chercheur
     if request.method == 'POST':
         forms = ChercheurFormGroup(request.POST, chercheur=chercheur)
         if forms.is_valid():
@@ -195,17 +168,14 @@ def edit(request):
                               dict(forms=forms, chercheur=chercheur),
                               context_instance=RequestContext(request))
             
-@login_required()
+@chercheur_required
 def perso(request):
     """Espace chercheur (espace personnel du chercheur)"""
-    context_instance = RequestContext(request)
-    chercheur = context_instance['user_chercheur']
+    chercheur = request.chercheur
     modification = request.GET.get('modification')
-    if not chercheur:
-        return HttpResponseRedirect(url('chercheurs.views.chercheur_login'))
     return render_to_response("chercheurs/perso.html",
                               dict(chercheur=chercheur, modification=modification),
-                              context_instance=context_instance)
+                              context_instance=RequestContext(request))
             
 def retrieve(request, id):
     """Fiche du chercheur"""
index 8e043be..5150e2e 100644 (file)
@@ -1,17 +1,7 @@
 # -*- encoding: utf-8 -*-
 
 import re
-from chercheurs.models import Chercheur
     
-def user_chercheur(request):
-    user_chercheur = Chercheur.objects.none()
-    if request.user.is_authenticated():
-        try:
-            user_chercheur = Chercheur.objects.get(courriel=request.user.email)
-        except:
-            pass
-    return {'user_chercheur': user_chercheur}
-
 DISCIPLINE_REGION_RE = re.compile(r'/(discipline/(?P<discipline>\d+)/)?(region/(?P<region>\d+)/)?')
 def discipline_region(request):
     match = DISCIPLINE_REGION_RE.match(request.path)
index 68290b8..617f3a3 100644 (file)
@@ -114,6 +114,8 @@ form ul.errorlist li { list-style:none; }
 .add-row { font-size: 90%; float:right; margin-right:16px }
 .edit-publication { font-size: 90%; position: absolute; bottom: 5px; right: 5px; cursor: pointer; }
 
+.form-errors { margin: 10px 0px; background: #f3e3e7; color: #b03d5e; padding: 1em; font-size: 120%;
+               border: 1px solid #b03d5e; }
 /* Tables */
 
 table { width: 100%; }
index 493d5a0..a99abf1 100644 (file)
@@ -39,6 +39,7 @@ MIDDLEWARE_CLASSES = (
     'django.middleware.common.CommonMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'chercheurs.middleware.ChercheurMiddleware',
     'djangoflash.middleware.FlashMiddleware',
     'pagination.middleware.PaginationMiddleware',
     'django.middleware.doc.XViewMiddleware',
@@ -66,7 +67,6 @@ INSTALLED_APPS = (
     'datamaster_modeles'
 )
 
-
 TEMPLATE_CONTEXT_PROCESSORS = (
     # default : http://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#template-context-processors
     "django.core.context_processors.auth",
@@ -74,7 +74,6 @@ TEMPLATE_CONTEXT_PROCESSORS = (
     "django.core.context_processors.i18n",
     "django.core.context_processors.media",
     "django.core.context_processors.request",
-    "context_processors.user_chercheur",
     "context_processors.discipline_region",
     "djangoflash.context_processors.flash"
 )
@@ -88,9 +87,8 @@ TEMPLATE_DIRS = (
     os.path.join(os.path.dirname(__file__), "templates"),
 )
 
-AUTHENTICATION_BACKENDS = (
-    'authentification.CascadeBackend',
-)
+AUTHENTICATION_BACKENDS = ('authentification.PersonneBackend',)
+LOGIN_REDIRECT_URL = '/chercheurs/perso/'
 
 CACHE_BACKEND = 'memcached://localhost:11211'
 
@@ -98,8 +96,6 @@ ROA_CUSTOM_ARGS = {'api-key': ROA_API_KEY}
 
 ADMIN_TOOLS_INDEX_DASHBOARD = 'auf_savoirs_en_partage.dashboard.CustomIndexDashboard'
 
-AUTH_PROFILE_MODULE = 'savoirs.Profile'
-
 CONTACT_EMAIL = 'contact-savoirsenpartage@auf.org'
 
 SPHINX_API_VERSION = 0x116
diff --git a/auf_savoirs_en_partage/sql/2010-12-08.sql b/auf_savoirs_en_partage/sql/2010-12-08.sql
new file mode 100644 (file)
index 0000000..ae1bb3e
--- /dev/null
@@ -0,0 +1,28 @@
+-- Certains chercheurs ont des espaces dans leur adresse courriel...
+
+UPDATE chercheurs_personne SET courriel = REPLACE(courriel, ' ', '');
+
+-- On crée des users Django pour chaque chercheur et on change l'objet
+-- "personne" en profil Django
+
+ALTER TABLE auth_user ADD INDEX email (email);
+
+INSERT INTO auth_user (username, first_name, last_name, email, password, is_staff, is_active, is_superuser)
+SELECT REPLACE(REPLACE(LEFT(courriel, LOCATE('@', courriel) - 1), '-', '_'), '.', '_'), prenom, nom, courriel, password, 0, 1, 0
+FROM chercheurs_personne
+WHERE actif AND courriel NOT IN (SELECT email FROM auth_user)
+GROUP BY LEFT(courriel, LOCATE('@', courriel) - 1)
+HAVING COUNT(*) = 1;
+
+INSERT INTO auth_user (username, first_name, last_name, email, password, is_staff, is_active, is_superuser)
+SELECT CONCAT(REPLACE(REPLACE(LEFT(courriel, LOCATE('@', courriel) - 1), '-', '_'), '.', '_'), '_', id), prenom, nom, courriel, password, 0, 1, 0
+FROM chercheurs_personne
+WHERE actif AND courriel NOT IN (SELECT email FROM auth_user);
+
+ALTER TABLE chercheurs_personne ADD COLUMN `user_id` integer;
+
+UPDATE chercheurs_personne p INNER JOIN auth_user u ON u.email = p.courriel
+SET p.user_id = u.id
+WHERE p.actif;
+
+ALTER TABLE chercheurs_personne DROP COLUMN password;
index 7080bec..3b4425e 100644 (file)
@@ -11,6 +11,6 @@ fichier.
 Dernières mises à jour
 ======================
 
-DEV:  2010-12-07
+DEV:  2010-12-06
 TEST: 2010-12-06
 PROD: 2010-12-06
diff --git a/auf_savoirs_en_partage/templates/accounts/login.html b/auf_savoirs_en_partage/templates/accounts/login.html
deleted file mode 100644 (file)
index 781f663..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-{% extends "container_base.html" %}
-{% load sep %}
-
-{% block contenu %}
-
-<h1>Connexion</h1>
-
-{% if form.errors %}
-<p id="flash-message">Login ou mot de passe invalide.</p>
-{% endif %}
-<form method="post" action="{% url chercheurs.views.chercheur_login %}">
-  <table>
-    <tr>
-      <td>{{ form.username.label_tag }}</td>
-      <td>{{ form.username }}</td>
-    </tr>
-    <tr>
-      <td>{{ form.password.label_tag }}</td>
-      <td>{{ form.password }}</td>
-    </tr>
-  </table>
-  <input type="submit" value="Connexion" />
-</form>
-<p><a href="{% url chercheurs.views.send_password %}">Mot de passe oublié ?</a></p>
-<p>Vous n'avez pas encore de compte? 
-<a href="{% url chercheurs.views.inscription %}">Inscrivez-vous</a>.</p>
-
-{% endblock %}
-
index 7918c68..20b9960 100644 (file)
@@ -4,7 +4,8 @@
 <h1>Demande de changement de mot de passe</h1>
 {% if message %}
 <div id="flash-message">{{message}}</div>
-<p>Cliquez <a href="{% url chercheurs.views.chercheur_login %}">ici</a> pour accéder à votre <a href="{% url chercheurs.views.chercheur_login %}">espace chercheur.</a> </p>
+<p>Cliquez <a href="{% url django.contrib.auth.views.login %}">ici</a> 
+pour accéder à votre <a href="{% url django.contrib.auth.views.login %}">espace chercheur.</a> </p>
 {% endif %}
 <form method="post">
     <fieldset>
index 4c93b28..76772fb 100644 (file)
@@ -1,6 +1,6 @@
-{% if user_chercheur %}
+{% if request.chercheur %}
 <li><a href="{% url chercheurs.views.perso %}">Espace chercheur</a></li>
 {% else %}
-<li><a href="{% url chercheurs.views.chercheur_login %}">Se connecter</a></li>
+<li><a href="{% url django.contrib.auth.views.login %}">Se connecter</a></li>
 <li><a href="{% url chercheurs.views.inscription %}">S'inscrire</a></li>
 {% endif %}
index bb8ea68..41bc8d1 100644 (file)
@@ -66,7 +66,7 @@
                         {% if user.is_authenticated %}
                         <a href="{% url django.contrib.auth.views.logout %}">Déconnexion</a>
                         {% else %}
-                        <a href="{% url chercheurs.views.chercheur_login %}">Connexion</a>
+                        <a href="{% url django.contrib.auth.views.login %}">Connexion</a>
                         {% endif %}
                     </div>
                 </div>
diff --git a/auf_savoirs_en_partage/templates/registration/login.html b/auf_savoirs_en_partage/templates/registration/login.html
new file mode 100644 (file)
index 0000000..bffda53
--- /dev/null
@@ -0,0 +1,29 @@
+{% extends "container_base.html" %}
+
+{% block contenu %}
+
+<h1>Connexion</h1>
+
+{% if form.errors %}
+<p class="form-errors">Login ou mot de passe invalide.</p>
+{% endif %}
+
+<form method="post" action="{% url django.contrib.auth.views.login %}">
+  <table>
+    <tr>
+      <td>Adresse électronique</td>
+      <td>{{ form.username }}</td>
+    </tr>
+    <tr>
+      <td>Mot de passe</td>
+      <td>{{ form.password }}</td>
+    </tr>
+  </table>
+  <input type="submit" value="Connexion" />
+</form>
+<p><a href="{% url chercheurs.views.send_password %}">Mot de passe oublié ?</a></p>
+<p>Vous n'avez pas encore de compte? 
+<a href="{% url chercheurs.views.inscription %}">Inscrivez-vous</a>.</p>
+
+{% endblock %}
+
index ef32438..5f96feb 100644 (file)
@@ -69,7 +69,7 @@ urlpatterns = sep_patterns + patterns(
     (r'^chercheurs/perso/$', 'chercheurs.views.perso'),
     (r'^chercheurs/edit/$', 'chercheurs.views.edit'),
     (r'^chercheurs/conversion$', 'chercheurs.views.conversion'),
-    (r'^accounts/login/$', 'chercheurs.views.chercheur_login'),
+    (r'^accounts/login/$', 'django.contrib.auth.views.login'),
     (r'^accounts/change_password/$', 'chercheurs.views.change_password'),
     (r'^accounts/send_password/$', 'chercheurs.views.send_password'),
     (r'^etablissements/autocomplete/$', 'chercheurs.views.etablissements_autocomplete'),