341 lines
15 KiB
Python
341 lines
15 KiB
Python
# vim:spell:spelllang=fr
|
|
# -*- encoding: utf-8 -*-
|
|
|
|
import logging
|
|
import textwrap
|
|
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from django.views.generic import TemplateView
|
|
from django.views.generic.detail import SingleObjectMixin, DetailView
|
|
from django.views.generic.edit import FormView
|
|
from django.contrib.auth import authenticate, login
|
|
from django.shortcuts import redirect
|
|
from django.utils.http import urlencode
|
|
from django.http import HttpResponseRedirect
|
|
from django.contrib import messages
|
|
from django.conf import settings
|
|
from django.http import Http404
|
|
from django.db.models import Q
|
|
from fiber.models import Page
|
|
|
|
import appli_project.appli_socle.views as socle_views
|
|
import appli_project.appli_socle.models as models
|
|
from appli_project.appli_socle.backends import ProfilRechercheAuthentification
|
|
import forms
|
|
import appli_project.appli_socle.forms
|
|
from appli_project.appli_socle.utils import extraire_action_and_model, \
|
|
extra_sauvegardee, mail_avec_modele
|
|
|
|
class ProfilRechercheView(socle_views.SeulementPourProfil,
|
|
socle_views.ValidationCharteQualite):
|
|
login_url = '/recherche/connexion/'
|
|
profil = (models.ProfilRecherche,)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
ctx = super(ProfilRechercheView, self).get_context_data(**kwargs)
|
|
if socle_views.is_webmaster(self.request.user):
|
|
ctx['loyer_modere'] = True
|
|
else:
|
|
ctx['loyer_modere'] = self.request.user.type_d_offre.filter(nom__contains=u'prix modéré').exists()
|
|
return ctx
|
|
|
|
def annonces_sauvegardees_actions(request):
|
|
action, annonce = extraire_action_and_model(request,
|
|
('supprimer', 'enregistrer'), models.Annonce)
|
|
if action == 'supprimer':
|
|
request.user.annonces_sauvegardees.remove(annonce)
|
|
request.record('supprime-annonce-sauvegardee',
|
|
_(u'supprime l\'annonce sauvegardée {annonce}'),
|
|
annonce=annonce)
|
|
elif action == 'enregistrer':
|
|
request.user.annonces_sauvegardees.add(annonce)
|
|
request.record('sauve-annonce',
|
|
_(u'sauve l\'annonce {annonce}'),
|
|
annonce=annonce)
|
|
|
|
class Accueil(ProfilRechercheView, socle_views.ValidationCGU,
|
|
TemplateView):
|
|
template_name = 'appli_recherche/accueil.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(Accueil, self).get_context_data(**kwargs)
|
|
types_logement = set([a for a, b in models.TYPE_LOGEMENT])
|
|
quadrants = set([a for a,b in models.QUADRANTS])
|
|
default = {
|
|
'type_de_logement': list(types_logement),
|
|
'paris_et_alentours': 'paris',
|
|
'quadrants': list(quadrants),
|
|
'montant_loyer': None,
|
|
'duree_location': None}
|
|
if 'reset' not in self.request.GET:
|
|
default['quadrants'] = self.request.GET.getlist('quadrants',
|
|
default['quadrants'])
|
|
default['type_de_logement'] = self.request.GET.getlist(
|
|
'type_de_logement', default['type_de_logement'])
|
|
default['paris_et_alentours'] = \
|
|
self.request.GET.get('paris_et_alentours',
|
|
default['paris_et_alentours'])
|
|
default['montant_loyer'] = self.request.GET.get('montant_loyer')
|
|
default['duree_location'] = self.request.GET.get('duree_location')
|
|
if 'submit' in self.request.GET:
|
|
form = context['form'] = forms.RechercheForm(initial=default,
|
|
data=self.request.GET, request=self.request)
|
|
else:
|
|
form = context['form'] = forms.RechercheForm(initial=default,
|
|
request=self.request)
|
|
if socle_views.is_webmaster(self.request.user):
|
|
context['annonces'] = []
|
|
return context
|
|
|
|
qs = models.Annonce.objects.filter(etat_validation='publiee')
|
|
# uniquement les annonces autorisées pour cet utilisateur
|
|
qs = qs.filter(type_d_offre__in=self.request.user.type_d_offre.all()|models.TypeOffre.objects.filter(id=1))
|
|
# filtre les annonces en fonction des critères sélectionnés
|
|
if form.is_valid():
|
|
if default['paris_et_alentours'] == 'paris':
|
|
qs = qs.filter(ville__icontains='Paris')
|
|
if default['quadrants'] and set(default['quadrants']) != quadrants:
|
|
qs = qs.filter(zones__nom__in=default['quadrants'])
|
|
if default['type_de_logement'] and set(default['type_de_logement']) != types_logement:
|
|
qs = qs.filter(type_de_logement__in=default['type_de_logement'])
|
|
if form.cleaned_data.get('montant_loyer') is not None:
|
|
montant_loyer = form.cleaned_data.get('montant_loyer')
|
|
if montant_loyer == 0:
|
|
qs = qs.filter(prix_par_mois__lte=500)
|
|
elif montant_loyer == 1:
|
|
qs = qs.filter(prix_par_mois__gte=500, prix_par_mois__lte=700)
|
|
elif montant_loyer == 2:
|
|
qs = qs.filter(prix_par_mois__gte=700)
|
|
if form.cleaned_data.get('duree_location') is not None:
|
|
duree_location = form.cleaned_data.get('duree_location')
|
|
qs = qs.filter(Q(duree_location=duree_location)|Q(duree_location__isnull=True))
|
|
qs = extra_sauvegardee(qs, self.request.user)
|
|
qs = qs.prefetch_related('prestations', 'prestations__type_de_prestation')
|
|
context['annonces'] = qs
|
|
return context
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
if 'sauvegarder' in request.GET:
|
|
return redirect('/recherche/mes-alertes/?%s' % request.GET.urlencode())
|
|
return super(Accueil, self).get(request, *args, **kwargs)
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
annonces_sauvegardees_actions(request)
|
|
return super(Accueil, self).get(request, *args, **kwargs)
|
|
|
|
class Connexion(socle_views.VueRelaieMixin, FormView):
|
|
connexion_ent_class = forms.ConnexionEntForm
|
|
form_class = appli_project.appli_socle.forms.BaseAuthentificationForm
|
|
template_name = 'appli_recherche/connexion.html'
|
|
static_next_url = '/recherche'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
d = super(Connexion, self).get_context_data(**kwargs)
|
|
d['connexion_ent_form'] = self.connexion_ent_class()
|
|
return d
|
|
|
|
def get_form_kwargs(self):
|
|
kwargs = super(Connexion, self).get_form_kwargs()
|
|
kwargs['profil'] = (models.ProfilRecherche,)
|
|
kwargs['submit_id'] = 'connexion-recherche'
|
|
return kwargs
|
|
|
|
def get_success_url(self):
|
|
return self.next_url()
|
|
|
|
def return_url(self):
|
|
params = {'next': self.next_url() or '/recherche', 'nopassive': 1}
|
|
local_url = '%s?%s'% (self.request.path, urlencode(params))
|
|
return self.request.build_absolute_uri(local_url)
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
if 'ticket' in request.GET:
|
|
service = self.return_url()
|
|
user = authenticate(cas_ticket=request.GET['ticket'],
|
|
service=service)
|
|
if user and user.is_active:
|
|
login(request, user)
|
|
request.record('connexion', 'connexion via CAS',
|
|
ticket=request.GET['ticket'])
|
|
response = redirect(self.next_url())
|
|
return response
|
|
elif user and not user.is_active:
|
|
request.record('echec-de-connexion',
|
|
_(u'tentative de connexion CAS échouée avec '
|
|
u'l\'identifiant {cas_user}: ce compte '
|
|
u'est bloqué'),
|
|
cas_user=user.utilisateur_cas.all()[0].identifiant,
|
|
user=user, ticket=request.GET['ticket'])
|
|
messages.error(request, _(u"Votre compte est bloqué sur ce "
|
|
u"service. Veuillez prendre contact avec le service du "
|
|
u"logement."))
|
|
else:
|
|
messages.error(request, _(u"L'authentification ENT a échoué, "
|
|
u"essayez encore. Si vous n'êtes pas étudiant, contactez le "
|
|
u"service logement pour activer votre compte sur cette application."))
|
|
else:
|
|
if 'nopassive' not in request.GET:
|
|
return ProfilRechercheAuthentification.redirect_to_cas(request, service=self.return_url(),
|
|
passif=True)
|
|
return super(Connexion, self).get(request, *args, **kwargs)
|
|
|
|
def form_valid(self, form):
|
|
login(self.request, form.user_cache)
|
|
return super(Connexion, self).form_valid(form)
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
if 'compte-ent' in request.POST:
|
|
return ProfilRechercheAuthentification.redirect_to_cas(request,
|
|
service=self.return_url())
|
|
return super(Connexion, self).post(request, *args, **kwargs)
|
|
|
|
class MesAlertes(ProfilRechercheView, FormView):
|
|
form_class = forms.AlerteForm
|
|
template_name = 'appli_recherche/mes-alertes.html'
|
|
max_alertes = 10
|
|
|
|
def get_form_kwargs(self, **kwargs):
|
|
kwargs = super(MesAlertes, self).get_form_kwargs(**kwargs)
|
|
if self.request.method == 'GET':
|
|
kwargs['initial'] = {
|
|
'paris_et_alentours': 'paris',
|
|
'quadrants': dict(models.QUADRANTS).keys() }
|
|
if self.request.GET:
|
|
kwargs['data'] = self.request.GET
|
|
return kwargs
|
|
|
|
def form_valid(self, form):
|
|
if self.request.user.recherches_sauvegardees.count() < self.max_alertes:
|
|
recherche_sauvegardee = models.RechercheSauvegardee.objects.create(
|
|
types_de_logement=','.join(form.cleaned_data['type_de_logement']),
|
|
intra_muros=form.cleaned_data['paris_et_alentours']=='paris',
|
|
duree_location=form.cleaned_data['duree_location'],
|
|
montant_loyer=form.cleaned_data['montant_loyer'])
|
|
recherche_sauvegardee.zones = models.Zone.objects.filter(nom__in=form.cleaned_data['quadrants'])
|
|
self.request.record('nouvelle-alerte',
|
|
_(u'sauve une recherche comme alerte email {alerte}'),
|
|
alerte=recherche_sauvegardee,
|
|
**form.cleaned_data)
|
|
self.request.user.recherches_sauvegardees.add(recherche_sauvegardee)
|
|
return super(MesAlertes, self).form_valid(form)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
ctx = super(MesAlertes, self).get_context_data(**kwargs)
|
|
ctx['max_alertes'] = self.max_alertes
|
|
if socle_views.is_webmaster(self.request.user):
|
|
import random
|
|
ctx['alertes'] = models.RechercheSauvegardee.objects.all()[:random.randint(0,3)]
|
|
else:
|
|
ctx['alertes'] = self.request.user.recherches_sauvegardees.all()
|
|
ctx['QUADRANTS'] = models.QUADRANTS
|
|
return ctx
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
action, alerte = extraire_action_and_model(request, ('supprimer',), models.RechercheSauvegardee)
|
|
if action:
|
|
request.record('supprime-alerte', (u'supprime l\'alerte {alerte}'), alerte=alerte)
|
|
alerte.delete()
|
|
return HttpResponseRedirect('')
|
|
return super(MesAlertes, self).post(request, *args, **kwargs)
|
|
|
|
def get_success_url(self):
|
|
return ''
|
|
|
|
class MesAnnonces(ProfilRechercheView, TemplateView):
|
|
'''Page de traitement des annonces'''
|
|
template_name = 'appli_recherche/mes-annonces.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
ctx = super(MesAnnonces, self).get_context_data(**kwargs)
|
|
if not socle_views.is_webmaster(self.request.user):
|
|
qs = self.request.user.annonces_sauvegardees.filter(etat_validation='publiee')
|
|
qs = qs.extra(select={'sauvegardee': '1'})
|
|
qs = qs.prefetch_related('prestations',
|
|
'prestations__type_de_prestation')
|
|
else:
|
|
qs = models.Annonce.objects.filter(etat_validation='publiee')[:5]
|
|
ctx['annonces'] = qs
|
|
return ctx
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
annonces_sauvegardees_actions(request)
|
|
return super(MesAnnonces, self).get(request, *args, **kwargs)
|
|
|
|
class ReservedAnnounceMixin(object):
|
|
def get_queryset(self):
|
|
qs = self.model.objects
|
|
if socle_views.is_webmaster(self.request.user):
|
|
return qs.all()
|
|
else:
|
|
# uniquement les annonces autorisées pour cet utilisateur
|
|
return qs.filter(
|
|
type_d_offre__in=self.request.user.type_d_offre.all()
|
|
| models.TypeOffre.objects.filter(id=1))
|
|
|
|
class Contact(ReservedAnnounceMixin, ProfilRechercheView, SingleObjectMixin, FormView):
|
|
'''Formulaire de contact des propriétaires'''
|
|
form_class = forms.ContactAnnonceForm
|
|
template_name = 'appli_recherche/contact.html'
|
|
model = models.Annonce
|
|
success_url = '../..'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
ctx = FormView.get_context_data(self, **kwargs)
|
|
ctx['annonce'] = self.get_object()
|
|
return ctx
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
if 'annuler' in request.POST:
|
|
return HttpResponseRedirect('../../')
|
|
return super(Contact, self).post(request, *args, **kwargs)
|
|
|
|
def form_valid(self, form):
|
|
variables = {}
|
|
annonce = variables['annonce'] = self.get_object()
|
|
message = variables['message'] = textwrap.fill(form.cleaned_data['message'], 70)
|
|
variables['base_url'] = self.request.build_absolute_uri('/')
|
|
variables['host'] = self.request.META['HTTP_HOST']
|
|
sujet_par_defaut = '''Demande de contact une annonce publiée sur {{host}}'''
|
|
texte_par_defaut = '''{% load url from future %}Vous recevez ce mail car votre annonce:
|
|
|
|
{{ base_url }}{% url 'editer-annonce' pk=annonce.id %}
|
|
|
|
a attiré l'attention d'un étudiant ou d'un chercheur de l'université Paris
|
|
Dauphine. Voici son messages de contact:
|
|
|
|
==========================================================================
|
|
{{ message }}
|
|
==========================================================================
|
|
|
|
Pour lui répondre il vous suffit de répondre à ce mail.'''
|
|
headers = { 'Reply-To': self.request.user.email }
|
|
mail_avec_modele('Contact', sujet_par_defaut, texte_par_defaut,
|
|
variables, settings.CONTACT_FROM, annonce.proprietaire.email,
|
|
headers=headers)
|
|
messages.info(self.request,
|
|
_(u"Un email de contact a été envoyé au propriétaire"
|
|
u" de l'annonce"))
|
|
self.request.record('contact-annonceur', _(u'contacte l\'annonceur '
|
|
u'{annonceur} à propos de l\'annonce {annonce}'),
|
|
annonceur=annonce.proprietaire, annonce=annonce,
|
|
email=annonce.proprietaire.email, message=message)
|
|
return super(Contact, self).form_valid(form)
|
|
|
|
class FiberAddendum(object):
|
|
def get_context_data(self, **kwargs):
|
|
ctx = super(FiberAddendum, self).get_context_data(**kwargs)
|
|
ctx['fiber_page'] = Page.objects.get(url__exact='recherche')
|
|
return ctx
|
|
|
|
class Annonce(ReservedAnnounceMixin, ProfilRechercheView, FiberAddendum, DetailView):
|
|
template_name = 'appli_recherche/annonce-detail.html'
|
|
model = models.Annonce
|
|
context_object_name = "annonce"
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
try:
|
|
return super(Annonce, self).get(request, *args, **kwargs)
|
|
except Http404:
|
|
self.object = None
|
|
return self.render_to_response(self.get_context_data(object=None))
|