148 lines
5.3 KiB
Python
148 lines
5.3 KiB
Python
"""
|
|
Vues de l'application LOGIS.
|
|
"""
|
|
import logging
|
|
import datetime
|
|
|
|
from django.conf import settings
|
|
from django.core.mail import send_mail
|
|
from django.http import JsonResponse
|
|
from django.template.loader import render_to_string
|
|
from django.utils import timezone
|
|
from django.utils.translation import gettext as _
|
|
from django.views.generic import ListView, DetailView, View
|
|
|
|
from .forms import ContactForm
|
|
from .models import Property, ContactRequest
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class PropertyListView(ListView):
|
|
"""Page d'accueil — liste des biens immobiliers actifs."""
|
|
|
|
model = Property
|
|
template_name = 'index.html'
|
|
context_object_name = 'properties'
|
|
|
|
def get_queryset(self):
|
|
"""Retourne les biens actifs avec leurs relations préchargées."""
|
|
return (
|
|
Property.objects.filter(is_active=True)
|
|
.prefetch_related('photos', 'features')
|
|
.select_related('environment')
|
|
)
|
|
|
|
|
|
class PropertyDetailView(DetailView):
|
|
"""Page de détail d'un bien immobilier."""
|
|
|
|
model = Property
|
|
template_name = 'properties/detail.html'
|
|
context_object_name = 'property'
|
|
|
|
def get_queryset(self):
|
|
"""Retourne uniquement les biens actifs."""
|
|
return (
|
|
Property.objects.filter(is_active=True)
|
|
.prefetch_related('photos', 'rooms__photos', 'features')
|
|
.select_related('environment')
|
|
)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
prop = self.object
|
|
context['contact_form'] = ContactForm(
|
|
initial={'property_id': prop.pk}
|
|
)
|
|
context['rooms_with_photos'] = prop.rooms.prefetch_related('photos').all()
|
|
context['general_photos'] = prop.photos.filter(room__isnull=True)
|
|
return context
|
|
|
|
|
|
class ContactView(View):
|
|
"""Endpoint AJAX pour le formulaire de contact."""
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
# Accepte uniquement les requêtes AJAX
|
|
if not request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
|
return JsonResponse({'success': False}, status=400)
|
|
|
|
form = ContactForm(request.POST)
|
|
|
|
if not form.is_valid():
|
|
return JsonResponse({'success': False, 'errors': form.errors})
|
|
|
|
# Vérification honeypot : si rempli, c'est un robot
|
|
if form.cleaned_data.get('website'):
|
|
return JsonResponse({'success': True})
|
|
|
|
# Limitation de débit : 5 minutes entre deux envois par session
|
|
last_contact = request.session.get('last_contact')
|
|
if last_contact:
|
|
try:
|
|
last_time = datetime.datetime.fromisoformat(last_contact)
|
|
if timezone.is_naive(last_time):
|
|
last_time = timezone.make_aware(last_time)
|
|
elapsed = (timezone.now() - last_time).total_seconds()
|
|
if elapsed < 300:
|
|
remaining = int((300 - elapsed) / 60) + 1
|
|
return JsonResponse({
|
|
'success': False,
|
|
'error': str(_(
|
|
'Merci de patienter encore %(min)s minute(s) avant d\'envoyer un nouveau message.'
|
|
) % {'min': remaining}),
|
|
})
|
|
except (ValueError, TypeError):
|
|
pass
|
|
|
|
# Récupération du bien concerné
|
|
property_obj = None
|
|
pid = form.cleaned_data.get('property_id')
|
|
if pid:
|
|
try:
|
|
property_obj = Property.objects.get(pk=pid, is_active=True)
|
|
except Property.DoesNotExist:
|
|
pass
|
|
|
|
# Enregistrement en base
|
|
contact = ContactRequest.objects.create(
|
|
property=property_obj,
|
|
name=form.cleaned_data['name'],
|
|
email=form.cleaned_data['email'],
|
|
phone=form.cleaned_data.get('phone', ''),
|
|
message=form.cleaned_data['message'],
|
|
ip_address=self._get_client_ip(request),
|
|
)
|
|
|
|
# Envoi de l'email à l'administrateur
|
|
try:
|
|
ctx = {'contact': contact, 'property': property_obj}
|
|
subject = render_to_string('emails/contact_subject.txt', ctx).strip()
|
|
body_text = render_to_string('emails/contact_body.txt', ctx)
|
|
body_html = render_to_string('emails/contact_body.html', ctx)
|
|
send_mail(
|
|
subject=subject,
|
|
message=body_text,
|
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
|
recipient_list=[settings.ADMIN_EMAIL],
|
|
html_message=body_html,
|
|
fail_silently=False,
|
|
)
|
|
except Exception as exc:
|
|
# L'email échoue mais le contact est enregistré en base
|
|
logger.error('Échec envoi email contact #%s : %s', contact.pk, exc)
|
|
|
|
request.session['last_contact'] = timezone.now().isoformat()
|
|
return JsonResponse({
|
|
'success': True,
|
|
'message': str(_('Votre message a bien été envoyé. Nous vous répondrons dans les plus brefs délais.')),
|
|
})
|
|
|
|
def _get_client_ip(self, request):
|
|
"""Extrait l'adresse IP réelle du client derrière un proxy."""
|
|
forwarded = request.META.get('HTTP_X_FORWARDED_FOR')
|
|
if forwarded:
|
|
return forwarded.split(',')[0].strip()
|
|
return request.META.get('REMOTE_ADDR')
|