# -*- 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
--- /dev/null
+# 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
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."""
--- /dev/null
+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()
# -*- 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
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')
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)
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):
#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)
--- /dev/null
+# 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
+
# -*- 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
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)
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()
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)
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
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():
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"""
# -*- 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)
.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%; }
'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',
'datamaster_modeles'
)
-
TEMPLATE_CONTEXT_PROCESSORS = (
# default : http://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#template-context-processors
"django.core.context_processors.auth",
"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"
)
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'
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
--- /dev/null
+-- 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;
Dernières mises à jour
======================
-DEV: 2010-12-07
+DEV: 2010-12-06
TEST: 2010-12-06
PROD: 2010-12-06
+++ /dev/null
-{% 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 %}
-
<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>
-{% 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 %}
{% 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>
--- /dev/null
+{% 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 %}
+
(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'),