This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
dauphine-logement/appli_project/appli_recherche/views.py

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))