Merge branch 'test' into nilovna nilovna
authorOlivier Larchevêque <olivier.larcheveque@auf.org>
Mon, 16 Apr 2012 18:24:13 +0000 (14:24 -0400)
committerOlivier Larchevêque <olivier.larcheveque@auf.org>
Mon, 16 Apr 2012 18:24:13 +0000 (14:24 -0400)
14 files changed:
auf_savoirs_en_partage/chercheurs/admin.py
auf_savoirs_en_partage/chercheurs/api.py
auf_savoirs_en_partage/chercheurs/forms.py
auf_savoirs_en_partage/chercheurs/migrations/0027_personne_user.py
auf_savoirs_en_partage/chercheurs/models.py
auf_savoirs_en_partage/chercheurs/views.py
auf_savoirs_en_partage/rappels/admin.py
auf_savoirs_en_partage/rappels/management/__init__.py [new file with mode: 0644]
auf_savoirs_en_partage/rappels/management/commands/__init__.py [new file with mode: 0644]
auf_savoirs_en_partage/rappels/management/commands/envoyer_rappels.py [new file with mode: 0644]
auf_savoirs_en_partage/rappels/migrations/0004_auto__add_field_rappeluser_date_demande_envoi__chg_field_rappeluser_da.py [new file with mode: 0644]
auf_savoirs_en_partage/rappels/models.py
auf_savoirs_en_partage/savoirs/models.py
auf_savoirs_en_partage/urls.py

index fb74efb..20e727e 100644 (file)
@@ -25,6 +25,8 @@ class ChercheurAdmin(admin.ModelAdmin):
     actions = ('remove_from_group', 'export_as_ods', 'export_as_csv')
     search_fields = ('nom', 'prenom')
 
+    exclude = ('user',)
+
     def lookup_allowed(self, lookup, value):
         return lookup in ['genre', 'statut', 'membre_reseau_institutionnel', 
                           'membre_instance_auf', 'discipline', 'region', 'pays', 
@@ -53,7 +55,7 @@ class ChercheurAdmin(admin.ModelAdmin):
         return actions
 
     def queryset(self, request):
-        return ChercheurAdminQuerySet(Chercheur)
+        return ChercheurAdminQuerySet(Chercheur).filter(actif=True)
 
     def get_object(self, request, object_id):
         """On doit réimplémenter cette méthode à cause de ce qu'on fait avec "initial" dans la méthode queryset()."""
@@ -62,6 +64,8 @@ class ChercheurAdmin(admin.ModelAdmin):
         except Chercheur.DoesNotExist:
             return None
 
+    def has_add_permission(self, request, obj=None):
+        return False
 
     def export_as_csv(self, request, queryset):
         return export(queryset, 'csv')
@@ -101,6 +105,9 @@ admin.site.register(ChercheurVoir, ChercheurVoirAdmin)
 
 class ChercheurAdminQuerySet(ChercheurQuerySet):
 
+    def delete(self):
+        self.update(actif=False)
+
     def filter(self, *args, **kwargs):
         """Gère des filtres supplémentaires pour l'admin.
            
index 27035e7..0c8435e 100644 (file)
@@ -1,13 +1,14 @@
 # -*- encoding: utf-8 -*
+
 from django.http import HttpResponse
-from django.core import serializers
 from django.shortcuts import get_object_or_404
 
 from django.utils import simplejson
 
-from savoirs.models import Region
 from savoirs.rss import FilChercheurs
-from chercheurs.models import Chercheur, Personne
+from auf.django.references import models as ref
+from chercheurs.models import Chercheur
+from chercheurs.forms import ChercheurSearchForm
 
 STATUS_OK = 200
 STATUS_ERROR = 400
@@ -15,12 +16,70 @@ STATUS_ERROR_PERMISSIONS = 403
 STATUS_ERROR_NOT_FOUND = 404
 STATUS_ERROR_BADMETHOD = 405
 
-class APIFilChercheurs(FilChercheurs):
-    description = "Pour services tiers"
+def recherche(request):
+    """
+    API spéciale de recherche pour retourner une structure de données complète
+    par rapport au RSS.
+    """
+    search_form = ChercheurSearchForm(request.GET)
+    search = search_form.save(commit=False)
+    data = []
+
+    # S'assure qu'un filtre existe au moins
+    no_criterion = True
+    for criterion, val in request.GET.items():
+        if val not in (None, u'', ''):
+            no_criterion = False
+            break
+    if no_criterion:
+        return api_return(STATUS_ERROR, 'no criterion', True)
+
+    # run() de ChercheurSearchForm()
+    results = Chercheur.objects
+    if search.q:
+        results = results.search(search.q)
+    if search.nom_chercheur:
+        results = results.add_to_query('@(nom,prenom) ' + search.nom_chercheur)
+    if search.equipe_recherche:
+        results = results.add_to_query('@equipe_recherche ' + search.equipe_recherche)
+    if search.discipline:
+        results = results.filter_discipline(search.discipline)
+    if search.region:
+        results = results.filter_region(search.region)
+    if search.statut:
+        if search.statut == "expert":
+            results = results.filter_expert()
+        else:
+            results = results.filter_statut(search.statut)
+    if search.domaine:
+        results = results.filter_groupe(search.domaine)
+    if search.pays:
+        results = results.filter_pays(search.pays)
+    if search.nord_sud:
+        results = results.filter_nord_sud(search.nord_sud)
+    if search.genre:
+        results = results.filter_genre(search.genre)
+    if search.activites_francophonie == 'instance_auf':
+        results = results.filter(membre_instance_auf=True)
+    elif search.activites_francophonie == 'expert_oif':
+        results = results.filter(expert_oif=True)
+    elif search.activites_francophonie == 'association_francophone':
+        results = results.filter(membre_association_francophone=True)
+    elif search.activites_francophonie == 'reseau_institutionnel':
+        results = results.filter(membre_reseau_institutionnel=True)
+
+    # sous-ensemble de pays
+    limitation_pays = request.GET.get('limitation_pays', None)
+    
+    if limitation_pays is not None:
+        pays = [ref.Pays.objects.get(code=pays_code) for pays_code in limitation_pays.split(',')]
+        results = results.filter_pays(pays)
+
+    for chercheur in results.all():
+        data.append(chercheur_2_dict(chercheur))
+    
+    return api_return(STATUS_OK, dict_2_json(data), True)
 
-    def items(self, search):
-        """Pas de limite temporelle"""
-        return search.run().order_by('-date_modification')
 
 def api(request, pays=None, region=None, chercheur_id=None):
     api = API(request)
@@ -60,104 +119,104 @@ def dict_2_json(data):
     return simplejson.dumps(data, indent=4)
 
 
+def chercheur_2_dict(chercheur):
+    """
+    Structure flat d'un chercheur pour JSON
+    """
+    # Domaines de recherche du chercheur
+    domaines_recherche = []
+    for dr in chercheur.domaines_recherche:
+        domaines_recherche.append(dr.nom)
+
+    # Groupes chercheur
+    groupes_chercheur = []
+    for gc in chercheur.groupes_chercheur:
+        groupes_chercheur.append(gc.nom)
+
+    # Expertises
+    expertises = []
+    for exp in chercheur.expertises.all():
+        expertises.append(
+        {'nom': '%s' % exp.nom,
+            'date': '%s' % exp.date,
+            'organisme_demandeur': '%s' % exp.organisme_demandeur,
+            'organisme_demandeur_visible': exp.organisme_demandeur_visible})
+
+    # Publications
+    publications = []
+    for pub in chercheur.publications.all():
+        publications.append(
+        {'auteurs': '%s' % pub.auteurs,
+            'titre': '%s' % pub.titre,
+            'revue': '%s' % pub.revue,
+            'annee': '%s' % pub.annee,
+            'editeur': '%s' % pub.editeur,
+            'lieu_edition': '%s' % pub.lieu_edition,
+            'nb_pages': '%s' % pub.nb_pages,
+            'url': '%s' % pub.url,
+            'publication_affichage': '%s' %  pub.publication_affichage})
+
+    chercheur_details = {'id': '%s' % chercheur.id, 
+            'civilite': '%s' % chercheur.civilite, 
+            'prenom': '%s' % chercheur.prenom, 
+            'nom': '%s' % chercheur.nom,
+            'pays': '%s' % chercheur.pays,
+            'pays_code': '%s' % chercheur.pays.code,
+            'etablissement': '%s' % chercheur.etablissement_display,
+            'afficher_courriel': '%s' % chercheur.afficher_courriel,
+            'courriel': '%s' % chercheur.courriel_display(), 
+            'region': '%s' % chercheur.region.nom, 
+            'statut': '%s' % chercheur.get_statut_display(), 
+            'diplome': '%s' % chercheur.diplome, 
+            'domaines_recherche': domaines_recherche,
+            'discipline': '%s' % chercheur.discipline,
+            'theme_recherche': '%s' % chercheur.theme_recherche, 
+            'equipe_recherche': '%s' % chercheur.equipe_recherche, 
+            'mots_cles': '%s' % chercheur.mots_cles, 
+            'url_site_web': '%s' % chercheur.url_site_web, 
+            'url_blog': '%s' % chercheur.url_blog, 
+            'url_reseau_social': '%s' % chercheur.url_reseau_social, 
+            'membre_instance_auf': chercheur.membre_instance_auf, 
+            'expert_oif': chercheur.expert_oif, 
+            'membre_association_francophone': chercheur.membre_association_francophone, 
+            'membre_reseau_institutionnel': chercheur.membre_reseau_institutionnel, 
+            'membre_instance_auf_nom': '%s' % chercheur.get_membre_instance_auf_nom_display(), 
+            'membre_instance_auf_fonction': '%s' % chercheur.membre_instance_auf_fonction, 
+            'membre_instance_auf_dates': '%s' % chercheur.membre_instance_auf_dates, 
+            'expert_oif_details': '%s' % chercheur.expert_oif_details, 
+            'expert_oif_dates': '%s' % chercheur.expert_oif_dates, 
+            'membre_association_francophone_details': '%s' % chercheur.membre_association_francophone_details, 
+            'membre_reseau_institutionnel_nom': '%s' %
+            chercheur.get_membre_reseau_institutionnel_nom_display(), 
+            "membre_reseau_institutionnel_fonction": "%s" % chercheur.membre_reseau_institutionnel_fonction, 
+            "membre_reseau_institionnel_dates": "%s" % chercheur.membre_reseau_institutionnel_dates, 
+            "expertises": expertises, 
+            "expertises_auf": chercheur.expertises_auf,
+            "publications": publications}
+
+    # devrait faire le lookup 
+    try:
+        if chercheur.these:
+            chercheur_details['these'] = {"these" : "%s" % chercheur.these,
+                "these_url": "%s" % chercheur.these.url, 
+                "these_titre": "%s" % chercheur.these.titre, 
+                "these_etablissement": "%s" % chercheur.these.etablissement, 
+                "these_annee": "%s" % chercheur.these.annee, 
+                "these_nb_pages": "%s" % chercheur.these.nb_pages, 
+                "these_directeur": "%s" % chercheur.these.directeur, 
+                }
+    except:
+        pass
+    return chercheur_details
+
+
 class API:
     def __init__(self, request):
         self.request = request
 
     def api_chercheur(self, chercheur_id):
         chercheur = get_object_or_404(Chercheur, id=chercheur_id)
-        # Domaines de recherche du chercheur
-        data = serializers.serialize('json', [chercheur,])
-        #return api_return(STATUS_OK, data, True)     
-
-
-        domaines_recherche = []
-        for dr in chercheur.domaines_recherche:
-            domaines_recherche.append(dr.nom)
-
-        # Groupes chercheur
-        groupes_chercheur = []
-        for gc in chercheur.groupes_chercheur:
-            groupes_chercheur.append(gc.nom)
-
-        # Expertises
-        expertises = []
-        for exp in chercheur.expertises.all():
-            expertises.append(
-            {'nom': '%s' % exp.nom,
-                'date': '%s' % exp.date,
-                'organisme_demandeur': '%s' % exp.organisme_demandeur,
-                'organisme_demandeur_visible': exp.organisme_demandeur_visible})
-
-        # Publications
-        publications = []
-        for pub in chercheur.publications.all():
-            publications.append(
-            {'auteurs': '%s' % pub.auteurs,
-                'titre': '%s' % pub.titre,
-                'revue': '%s' % pub.revue,
-                'annee': '%s' % pub.annee,
-                'editeur': '%s' % pub.editeur,
-                'lieu_edition': '%s' % pub.lieu_edition,
-                'nb_pages': '%s' % pub.nb_pages,
-                'url': '%s' % pub.url,
-                'publication_affichage': '%s' %  pub.publication_affichage})
-
-        chercheur_details = [{'id': '%s' % chercheur.id, 
-                'civilite': '%s' % chercheur.civilite, 
-                'prenom': '%s' % chercheur.prenom, 
-                'nom': '%s' % chercheur.nom,
-                'pays': '%s' % chercheur.pays,
-                'pays_code': '%s' % chercheur.pays.code,
-                'etablissement': '%s' % chercheur.etablissement_display,
-                'afficher_courriel': '%s' % chercheur.afficher_courriel,
-                'courriel': '%s' % chercheur.courriel, 
-                'region': '%s' % chercheur.region.nom, 
-                'statut': '%s' % chercheur.get_statut_display(), 
-                'diplome': '%s' % chercheur.diplome, 
-                'domaines_recherche': domaines_recherche,
-                'discipline': '%s' % chercheur.discipline,
-                'theme_recherche': '%s' % chercheur.theme_recherche, 
-                'equipe_recherche': '%s' % chercheur.equipe_recherche, 
-                'mots_cles': '%s' % chercheur.mots_cles, 
-                'url_site_web': '%s' % chercheur.url_site_web, 
-                'url_blog': '%s' % chercheur.url_blog, 
-                'url_reseau_social': '%s' % chercheur.url_reseau_social, 
-                'membre_instance_auf': chercheur.membre_instance_auf, 
-                'expert_oif': chercheur.expert_oif, 
-                'membre_association_francophone': chercheur.membre_association_francophone, 
-                'membre_reseau_institutionnel': chercheur.membre_reseau_institutionnel, 
-                'membre_instance_auf_nom': '%s' % chercheur.get_membre_instance_auf_nom_display(), 
-                'membre_instance_auf_fonction': '%s' % chercheur.membre_instance_auf_fonction, 
-                'membre_instance_auf_dates': '%s' % chercheur.membre_instance_auf_dates, 
-                'expert_oif_details': '%s' % chercheur.expert_oif_details, 
-                'expert_oif_dates': '%s' % chercheur.expert_oif_dates, 
-                'membre_association_francophone_details': '%s' % chercheur.membre_association_francophone_details, 
-                'membre_reseau_institutionnel_nom': '%s' %
-                chercheur.get_membre_reseau_institutionnel_nom_display(), 
-                "membre_reseau_institutionnel_fonction": "%s" % chercheur.membre_reseau_institutionnel_fonction, 
-                "membre_reseau_institionnel_dates": "%s" % chercheur.membre_reseau_institutionnel_dates, 
-                "expertises": expertises, 
-                "expertises_auf": chercheur.expertises_auf,
-                "publications": publications}]
-
-        # devrait faire le lookup 
-        try:
-            if chercheur.these:
-                details_pop = chercheur_details.pop(0)
-                details_pop.update(
-                    {"these" : "%s" % chercheur.these,
-                    "these_url": "%s" % chercheur.these.url, 
-                    "these_titre": "%s" % chercheur.these.titre, 
-                    "these_etablissement": "%s" % chercheur.these.etablissement, 
-                    "these_annee": "%s" % chercheur.these.annee, 
-                    "these_nb_pages": "%s" % chercheur.these.nb_pages, 
-                    "these_directeur": "%s" % chercheur.these.directeur, 
-                    })
-            chercheur_details.append(details_pop)
-        except:
-            pass
-
+        chercheur_details = chercheur_2_dict(chercheur)
         return api_return(STATUS_OK, dict_2_json(chercheur_details), True)     
         
 
@@ -170,16 +229,21 @@ class API:
             return api_return(STATUS_ERROR, "Erreur dans la requete de recherche de chercheurs")
 
         results = []
-        for c in chercheurs:
+        for c in chercheurs:            
             if c.etablissement_autre_pays is not None:
                 etablissement_autre_pays_nom = c.etablissement_autre_pays.nom
             else:
                 etablissement_autre_pays_nom = None
+            
+            if c.etablissement is not None:
+                    etablissement = c.etablissement.nom
+            else:
+                etablissement = c.etablissement_autre_nom
 
             data = {"id": "%s" % c.id,
                 "nom": "%s" % c.nom,
                 "prenom": "%s" % c.prenom,
-                "etablissement": "%s" % c.etablissement_display,
+                "etablissement": "%s" % etablissement,
                 "etablissement_autre_nom": "%s" % c.etablissement_autre_nom,
                 "pays": "%s" % c.pays.nom,
                 "etablissement_pays_autre_nom": "%s" % etablissement_autre_pays_nom}
index 81f24e4..204d7f3 100644 (file)
@@ -135,6 +135,13 @@ class ChercheurForm(forms.ModelForm):
         existing = Chercheur.objects.filter(courriel=courriel, actif=True)
         if self.instance and self.instance.id:
             existing = existing.exclude(id=self.instance.id)
+
+        else:
+            # Nouveau chercheur
+            user = User.objects.filter(is_active=True, email=courriel)
+            if user.count():
+                raise forms.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
+
         if existing.count():
             raise forms.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
         return courriel
index 331f747..202930f 100644 (file)
@@ -11,10 +11,12 @@ class Migration(DataMigration):
 
     def forwards(self, orm):
         for personne in orm.Personne.objects.filter(actif=1):
-            user = orm['auth.User'].objects.get(email=personne.courriel)
-            personne.user = user
-            personne.save()
-
+            try:
+                user = orm['auth.User'].objects.get(email=personne.courriel)
+                personne.user = user
+                personne.save()
+            except:
+                pass
 
     def backwards(self, orm):
         for personne in orm.Personne.objects.filter(actif=1):
index 5b107c4..6fd1649 100644 (file)
@@ -9,6 +9,7 @@ from django.db import models
 from django.db.models import Q
 from django.utils.encoding import smart_str
 from django.utils.hashcompat import sha_constructor
+from django.db.models.signals import post_save
 from djangosphinx.models import SphinxSearch
 
 from savoirs.models import Discipline, SEPManager, SEPSphinxQuerySet, SEPQuerySet, Search
@@ -52,6 +53,10 @@ class Personne(models.Model):
 
         super(Personne, self).save(*args, **kwargs)
 
+    def delete(self):
+        self.actif = False
+        self.save()
+
     @property
     def civilite(self):
         if self.genre == 'm':
@@ -68,13 +73,36 @@ class Personne(models.Model):
     def courriel_display(self):
         return self.courriel.replace(u'@', u' (à) ')
 
+
+def change_personne_courriel(sender, **kwargs):
+    user = kwargs['instance']
+    try:
+        if user.chercheur:
+            if user.email != user.chercheur.courriel:
+                chercheur = user.chercheur
+                chercheur.courriel = user.email
+                chercheur.save()
+    except:
+        pass
+
+post_save.connect(change_personne_courriel, sender=User)
+
+
 class ChercheurQuerySet(SEPQuerySet):
 
     def filter_groupe(self, groupe):
         return self.filter(groupes=groupe)
 
     def filter_pays(self, pays):
-        return self.filter(Q(etablissement__pays=pays) | Q(etablissement_autre_pays=pays))
+        """
+        Filtre sur un ou plusieurs pays.
+        """
+        if hasattr(pays, "__getitem__") or hasattr(pays, "__iter__"):
+            pays_ids = [p.id for p in pays]
+            return self.filter(Q(etablissement__pays__id__in=pays_ids) |
+                    Q(etablissement_autre_pays__id__in=pays_ids))
+        else:
+            return self.filter(Q(etablissement__pays=pays) | Q(etablissement_autre_pays=pays))
 
     def filter_region(self, region):
         return self.filter(Q(etablissement__pays__region=region) | Q(etablissement_autre_pays__region=region))
@@ -123,7 +151,13 @@ class ChercheurSphinxQuerySet(SEPSphinxQuerySet):
         return self.filter(groupe_ids=groupe.id)
 
     def filter_pays(self, pays):
-        return self.filter(pays_id=pays.id)
+        """
+        Filtre sur un ou plusieurs pays.
+        """
+        if hasattr(pays, "__getitem__") or hasattr(pays, "__iter__"):
+            return self.filter(pays_id__in=[p.id for p in pays])
+        else:
+            return self.filter(pays_id=pays.id)
 
     NORD_SUD_CODES = {'Nord': 1, 'Sud': 2}
     def filter_nord_sud(self, nord_sud):
index 1e2d32a..f70662a 100644 (file)
@@ -91,10 +91,11 @@ def activation(request, id_base36, token):
                 password = form.cleaned_data['password']
                 email = chercheur.courriel
                 chercheur.actif = True
-                chercheur.save()
                 user = get_django_user_for_email(email)
                 user.set_password(password)
                 user.save()
+                chercheur.user = user
+                chercheur.save()
 
                 # Auto-login
                 auth_login(request, authenticate(username=email, password=password))
index 702018b..ddb7a3d 100644 (file)
@@ -8,7 +8,7 @@ from rappels import actions
 
 
 class ChercheurRappelAdmin(ChercheurAdmin):
-    list_display = ['__unicode__', 'last_login']
+    list_display = ['__unicode__', 'last_login', 'dernier_rappel']
     list_editable = []
 
     actions = [actions.rappel]
@@ -59,7 +59,11 @@ admin.site.register(RappelModele, RappelModeleAdmin)
 
 
 class RappelUserAdmin(admin.ModelAdmin):
-    readonly_fields = ['date_envoi', 'rappel', 'user']
-    list_display = ['date_envoi', 'rappel', 'user']
+    readonly_fields = ['date_envoi', 'date_demande_envoi', 'rappel', 'user']
+    list_display = ['date_envoi_clean', 'date_demande_envoi_clean', 'rappel', 'user']
     list_filter = ['rappel']
+
+    def has_add_permission(self, obj):
+        return False
+
 admin.site.register(RappelUser, RappelUserAdmin)
diff --git a/auf_savoirs_en_partage/rappels/management/__init__.py b/auf_savoirs_en_partage/rappels/management/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auf_savoirs_en_partage/rappels/management/commands/__init__.py b/auf_savoirs_en_partage/rappels/management/commands/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auf_savoirs_en_partage/rappels/management/commands/envoyer_rappels.py b/auf_savoirs_en_partage/rappels/management/commands/envoyer_rappels.py
new file mode 100644 (file)
index 0000000..424f4a9
--- /dev/null
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+
+import datetime
+
+from django.core.management.base import BaseCommand
+from django.template import Context, Template
+from django.core.mail import EmailMessage
+from django.conf import settings
+
+from rappels.models import RappelUser
+
+
+class Command(BaseCommand):
+    help = "Envoi des courriels de rappels par tranche de 300"
+
+    def handle(self, *args, **kwargs):
+
+        logs = RappelUser.objects.filter(date_envoi=None).order_by('date_demande_envoi')[0:300]
+
+        for log in logs:
+
+            template = Template(log.rappel.contenu)
+            domaine = settings.SITE_DOMAIN
+            message = template.render(Context({
+                'chercheur': log.user.chercheur.prenom_nom,
+                'domaine': domaine,
+                'date_limite': log.rappel.date_limite
+            }))
+            email = EmailMessage(log.rappel.sujet,
+                                 message,
+                                 settings.CONTACT_EMAIL,
+                                 [log.user.email])
+            email.send()
+
+            log.date_envoi = datetime.datetime.today()
+            log.save()
diff --git a/auf_savoirs_en_partage/rappels/migrations/0004_auto__add_field_rappeluser_date_demande_envoi__chg_field_rappeluser_da.py b/auf_savoirs_en_partage/rappels/migrations/0004_auto__add_field_rappeluser_date_demande_envoi__chg_field_rappeluser_da.py
new file mode 100644 (file)
index 0000000..537ff17
--- /dev/null
@@ -0,0 +1,91 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Adding field 'RappelUser.date_demande_envoi'
+        db.add_column('rappels_rappeluser', 'date_demande_envoi', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, null=True, blank=True), keep_default=False)
+
+        # Changing field 'RappelUser.date_envoi'
+        db.alter_column('rappels_rappeluser', 'date_envoi', self.gf('django.db.models.fields.DateTimeField')(null=True))
+
+
+    def backwards(self, orm):
+        
+        # Deleting field 'RappelUser.date_demande_envoi'
+        db.delete_column('rappels_rappeluser', 'date_demande_envoi')
+
+        # User chose to not deal with backwards NULL issues for 'RappelUser.date_envoi'
+        raise RuntimeError("Cannot reverse this migration. 'RappelUser.date_envoi' and its values cannot be restored.")
+
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'max_length': '30', 'unique': 'True'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'rappels.rappel': {
+            'Meta': {'object_name': 'Rappel'},
+            'contenu': ('django.db.models.fields.TextField', [], {}),
+            'date_cible': ('django.db.models.fields.DateField', [], {}),
+            'date_creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'date_limite': ('django.db.models.fields.DateField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'sujet': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'user_creation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'rappels.rappelmodele': {
+            'Meta': {'object_name': 'RappelModele'},
+            'contenu': ('django.db.models.fields.TextField', [], {}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'nom': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'sujet': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        'rappels.rappeluser': {
+            'Meta': {'ordering': "['-date_envoi']", 'object_name': 'RappelUser'},
+            'date_demande_envoi': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
+            'date_envoi': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'rappel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rappels.Rappel']"}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        }
+    }
+
+    complete_apps = ['rappels']
index b4979fc..5b6b48f 100644 (file)
@@ -23,7 +23,8 @@ class Rappel(models.Model):
 class RappelUser(models.Model):
     rappel = models.ForeignKey(Rappel, verbose_name="rappel")
     user = models.ForeignKey(User, verbose_name="utilisateur")
-    date_envoi = models.DateTimeField("date de l'envoi", auto_now_add=True)
+    date_demande_envoi = models.DateTimeField("date de la demande de l'envoi", null=True, auto_now_add=True)
+    date_envoi = models.DateTimeField("date de l'envoi", null=True)
 
     class Meta:
         verbose_name = "Trace d'un rappel"
@@ -33,27 +34,11 @@ class RappelUser(models.Model):
     def __unicode__(self):
         return "%s - %s" % (self.rappel.sujet, self.user)
 
-    def save(self, *args, **kwargs):
-        super(RappelUser, self).save(*args, **kwargs)
-
-        # Envoi du courriel...
-        from django.template import Context, Template
-        from django.core.mail import EmailMessage
-        from django.conf import settings
-
-        template = Template(self.rappel.contenu)
-        domaine = settings.SITE_DOMAIN
-        message = template.render(Context({
-            'chercheur': self.user.chercheur.prenom_nom,
-            'domaine': domaine,
-            'date_limite': self.rappel.date_limite
-        }))
-        email = EmailMessage(self.rappel.sujet,
-                             message,
-                             settings.CONTACT_EMAIL,
-                             [self.user.email],
-                             settings.ADMINS_SEP)
-        email.send()
+    def date_demande_envoi_clean(self):
+        return self.date_demande_envoi or ''
+
+    def date_envoi_clean(self):
+        return self.date_envoi or 'Pas envoyé'
 
 
 class RappelModele(models.Model):
@@ -87,3 +72,10 @@ class ChercheurRappel(Chercheur):
     def last_login(self):
         return self.user.last_login
     last_login.short_description = "Dernière connexion"
+
+    def dernier_rappel(self):
+        try:
+            return self.user.rappeluser_set.all()[0].date_envoi
+        except:
+            return "Aucun rappel envoyé"
+    dernier_rappel.short_description = 'Dernier rappel'
index b7503a7..ec22245 100644 (file)
@@ -948,7 +948,7 @@ class Search(models.Model):
             actualites=actualites.order_by('-date').filter_type('actu'),
             appels=actualites.order_by('-date').filter_type('appels'),
             evenements=evenements.order_by('-debut'),
-            ressources=ressources.order_by('-id'),
+            ressources=ressources.order_by('-modified'),
             chercheurs=chercheurs.order_by('-date_modification'),
             groupes=groupes.order_by('nom'),
             sites=sites.order_by('-date_maj'),
index ec14293..37b784a 100644 (file)
@@ -4,7 +4,6 @@ from django.conf.urls.defaults import patterns, include, handler500, handler404,
 from django.conf import settings
 from django.contrib import admin
 from savoirs.rss import FilChercheurs, FilRessources, FilActualites, FilAppels, FilEvenements, FilSites, FilMessages
-from chercheurs.api import APIFilChercheurs
 admin.autodiscover()
 
 handler500 = "views.page_500"
@@ -107,7 +106,7 @@ urlpatterns = sep_patterns + patterns(
     (r'^api/chercheurs/(?P<chercheur_id>\d+)/$', 'chercheurs.api.api'),
     (r'^api/chercheurs/pays/(?P<pays>.*)/$', 'chercheurs.api.api'),
     (r'^api/chercheurs/region/(?P<region>.*)/$', 'chercheurs.api.api'),
-    (r'^api/chercheurs/rss$', APIFilChercheurs(), {}, ),
+    (r'^api/chercheurs/recherche', 'chercheurs.api.recherche' ),
 
 
     # groupes