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_offre/forms.py

404 lines
17 KiB
Python

# vim:spell:spelllang=fr
# -*- encoding: utf-8 -*-
import random
from django.utils.translation import ugettext_lazy as _
import django.forms as forms
from django.core.exceptions import ValidationError
from django.utils.safestring import mark_safe
from django.core.urlresolvers import reverse
from django.core.cache import cache
from django.template import Template, Context
from django.core.mail import send_mail
from django.conf import settings
from django.contrib import messages
from django.contrib.localflavor.fr.forms import FRZipCodeField
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Fieldset, ButtonHolder, HTML, Field
from appli_project.appli_socle import models
from appli_project.appli_socle.settings import Parametres
from appli_project.appli_socle.forms import FormulaireAvecRelaie
from appli_project.appli_socle.utils import next_url, envoyer_jeton
from appli_project.appli_socle import views as socle_views
class InscriptionForm(FormulaireAvecRelaie):
email = forms.EmailField(label=_(u'Votre email'))
first_name = forms.CharField(label=_(u'Prénom'))
last_name = forms.CharField(label=_(u'Nom'))
address = forms.CharField(label=_(u'Adresse personnelle'),
widget=forms.Textarea)
phone = forms.CharField(max_length=20,
label=_(u'Téléphone fixe'))
mobile = forms.CharField(max_length=20,
label=_(u'Mobile'))
job = forms.CharField(max_length=128,
label=_(u'Profession'))
comment = forms.ChoiceField(label=_(u'Comment avez-vous connu le site ?'),
choices=models.ProfilOffre.COMMENT)
def __init__(self, *args, **kwargs):
self.static_next_url = reverse('mes-alertes-offre')
super(InscriptionForm, self).__init__(*args, **kwargs)
def clean_email(self):
'''Vérifie que l'email n'est pas déjà utilisé par un profil offre'''
email = self.cleaned_data['email']
if models.ProfilOffre.objects.filter(email=email).exists():
url = reverse('mot-de-passe-perdu', kwargs=dict(email=email))
raise ValidationError(mark_safe(_(u'''Cette adresse email est déjà '''
u'''utilisée. <a href="%s">Peut-être avez vous oublié'''
u''' votre mot de passe ?</a>''') % url))
return email
def save(self):
email = self.cleaned_data['email']
url = self.next_url()
self.jeton = jeton = ''.join([random.SystemRandom().choice('123456789ABCDEFGHJKMNPQRSTUVWXYZ')
for i in range(8)])
d = { 'next': url, 'creation': 1 }
d.update(self.cleaned_data)
cache.set('inscription_%s' % jeton, d, settings.INSCRIPTION_TIMEOUT)
jeton_url = self.request.build_absolute_uri(
reverse('confirmation-email', kwargs=dict(jeton=jeton)))
confirmation_url = self.request.build_absolute_uri(
reverse('confirmation-email', kwargs=dict(jeton='')))
modele, created = models.EmailModele.objects.get_or_create(
nom='Inscription')
host = self.request.get_host()
if created:
modele.sujet = u'''Confirmation de votre email pour inscription à {{host}}'''
modele.texte = u'''Vous venez d'inscrire votre email {{email}} sur {{host}}.
Il est nécessaire de confirmer cet email pour que votre compte soit créé.
Pour cela veuillez entrez le code {{ jeton }} sur la page Web suivante:
{{ confirmation_url }}
ou bien recopier le lien suivant dans la barre d'adresse de votre navigateur:
{{ jeton_url }}'''
modele.save()
variables = Context({ 'email' : email, 'jeton': jeton,
'jeton_url': jeton_url, 'host': host,
'confirmation_url': confirmation_url})
subject = Template(modele.sujet).render(variables)
body = Template(modele.texte).render(variables)
send_mail(subject, body, settings.INSCRIPTION_FROM_EMAIL, [email])
helper = FormHelper()
helper.form_class = 'form-horizontal'
helper.layout = Layout(
'email',
'first_name',
'last_name',
'address',
'phone',
'mobile',
'job',
'comment',
'next',
ButtonHolder(
Submit('submit', _(u"M'inscrire"), css_class="btn-primary btn"),
css_class="bouton-group"))
from django.contrib.gis.admin.widgets import OpenLayersWidget
from django.contrib.gis.admin import options
class MapWidget(OpenLayersWidget):
template = 'appli_offre/openlayers.html'
geom_type = 'POINT'
params = {
'default_lon': 261223.54412843,
'default_lat': 6251249.4833769,
'default_zoom': 11,
'display_wkt': False,
'geom_type': 'POINT',
'field_name': 'position_geographique',
'is_collection': False,
'scrollable': True,
'layerswitcher': False,
'collectiontype': 'None',
'is_linestring': False,
'is_polygon': False,
'is_point': True,
'num_zoom': 20,
'max_zoom': False,
'min_zoom': False,
'units': 'm',
'max_resolution': '156543.0339',
'max_extent': '-20037508,-20037508,20037508,20037508',
'modifiable': True,
'mouse_position': True,
'scale_text': True,
'map_width': '400',
'map_height': 400,
'point_zoom': 11,
'srid': options.spherical_mercator_srid,
'display_srid': False,
'wms_url': 'http://vmap0.tiles.osgeo.org/wms/vmap0',
'wms_layer': 'basic',
'wms_name': 'OpenLayers WMS'
}
class AnnonceForm(forms.ModelForm):
class Meta:
model = models.Annonce
widgets = {
'position_geographique': MapWidget,
}
fields = ('prix_par_mois', 'duree_location', 'surface_en_m2', 'type_de_logement',
'pays', 'ville', 'type_d_offre', 'position_geographique',
'photo', 'description')
class Media:
js = ('/static/openlayers/OpenLayers.js',)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.prestations = fields = []
type_de_prestations = models.TypeDePrestation.objects.order_by('ordre')
for type_de_prestation in type_de_prestations:
name = 'prestation-%s' % type_de_prestation.id
if type_de_prestation.type_de_valeur == 'B':
field = forms.BooleanField(label=type_de_prestation.nom,
required=False)
elif type_de_prestation.type_de_valeur == 'N':
field = forms.IntegerField(label=type_de_prestation.nom,
required=False)
fields.append((name, field))
field_names = [x[0] for x in fields]
super(AnnonceForm, self).__init__(*args, **kwargs)
self.fields.update(dict(fields))
self.fields['duree_location'].required = True
if self.instance.id:
# modification
for prestation in self.instance.prestations.all():
type_de_prestation = prestation.type_de_prestation
name = 'prestation-%s' % type_de_prestation.id
if type_de_prestation.type_de_valeur == 'B':
self.fields[name].initial = True
elif type_de_prestation.type_de_valeur == 'N':
self.fields[name].initial = prestation.valeur_numerique
submits = [Submit('modifier-et-publier', _(u'Modifier et publier'), css_class='btn btn-primary'),
Submit('modifier', _(u'Modifier')),
Submit('supprimer', _(u'Supprimer'))]
else:
# création
submits = [Submit('creer', _(u'Créer'))]
self.helper.layout = Layout(
'type_de_logement',
'prix_par_mois',
'duree_location',
'surface_en_m2',
'pays',
Field('ville', placeholder=_(u'en région parisienne'), help_text='coin'),
'type_d_offre',
Field('position_geographique', css_class='osm-input'),
'photo',
'description',
Fieldset(_(u'Prestations diverses'),
HTML(_("""<p class="alert alert-info">Tous ces champs sont facultatifs</p>""")),
*field_names),
ButtonHolder(*submits,
css_class='bouton-group'))
def clean_surface_en_m2(self):
'''Vérifie que la surface dépasse la surface minimum autorisée'''
surface_en_m2 = self.cleaned_data['surface_en_m2']
surface_minimum = Parametres().surface_minimum
if surface_en_m2 < surface_minimum:
raise ValidationError(
mark_safe(_(u'Pour respecter la <a href="/charte-qualite">charte'
u' qualité</a> la surface doit être supérieur à %s '
u'') % surface_minimum))
return surface_en_m2
def clean_photo(self):
photo = self.cleaned_data['photo']
if photo and photo.size > 1024*1024:
raise ValidationError(_(u'La taille des images est limitée à 1Mo'))
return photo
def clean(self):
'''Vérifie que l'annonce respecte le prix maximum au m²'''
cleaned_data = super(AnnonceForm, self).clean()
try:
surface_en_m2 = cleaned_data['surface_en_m2']
prix_par_mois = cleaned_data['prix_par_mois']
except KeyError:
return cleaned_data
parametres = Parametres()
prix_au_m2_maximum = parametres.prix_au_m2_maximum
prix_au_m2 = float(prix_par_mois) / float(surface_en_m2)
prix_maximum = surface_en_m2 * parametres.prix_au_m2_maximum
if prix_au_m2 > prix_au_m2_maximum:
raise ValidationError(
mark_safe(_(u'Pour respecter la <a href="/charte-qualite">charte'
u' qualité</a> le prix au m² ne doit pas dépasser {0}'
u' €/m². Ici il est de {1:.2f} €/m². Le prix par mois'
u' maximum au vu de la surface est de {2}').format(prix_au_m2_maximum,
prix_au_m2,
prix_maximum)))
return cleaned_data
def save(self):
self.instance.monnaie = 'EUR'
self.instance.proprietaire = self.request.user
# Les profils offre sans validation ont leurs offres validés
# automatiquement
if self.request.user.sans_validation:
if self.instance.etat_validation != 'publiee':
self.instance.etat_validation = 'valide'
else:
if self.instance.etat_validation == 'valide':
pass
elif self.instance.etat_validation == 'invalide':
self.instance.etat_validation = 'attend_validation'
elif self.instance.etat_validation == 'publiee':
self.instance.etat_validation = 'attend_validation'
elif self.instance.etat_validation == 'attend_validation':
pass
instance = super(AnnonceForm, self).save()
new_prestations = []
for type_de_prestation in models.TypeDePrestation.objects.order_by('ordre'):
name = 'prestation-%s' % type_de_prestation.id
if type_de_prestation.type_de_valeur == 'B' \
and self.cleaned_data.get(name, False):
prestation, created = models.Prestation.objects.get_or_create(
type_de_prestation=type_de_prestation)
new_prestations.append(prestation)
elif type_de_prestation.type_de_valeur == 'N' \
and self.cleaned_data.get(name) is not None:
prestation, created = models.Prestation.objects.get_or_create(
type_de_prestation=type_de_prestation,
valeur_numerique=self.cleaned_data[name])
new_prestations.append(prestation)
instance.prestations = new_prestations
return instance
class MonEmailForm(FormulaireAvecRelaie):
email = forms.EmailField(label=_(u'Mon email'))
url_de_contact = forms.URLField(label=_(u'URL de contact'), required=False,
help_text=_(u'en option, remplace le mail pour le contact du propriétaire'))
success_url = '/offre'
def __init__(self, **kwargs):
request = kwargs.get('request')
user = self.user = request.user
initial = kwargs.setdefault('initial', {})
initial['email'] = user.email
if hasattr(user, 'url_de_contact'):
initial['url_de_contact'] = user.url_de_contact
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.layout = Layout('email', 'url_de_contact', 'next',
ButtonHolder(Submit('submit', _(u"Confirmer"))))
super(MonEmailForm, self).__init__(**kwargs)
def clean_email(self):
email = self.cleaned_data.get('email')
if email and models.ProfilOffre.objects \
.filter(email=email) \
.exclude(id=self.request.user.id).exists():
raise ValidationError(_(u'Cet email est déjà utilisé par un autre compte'))
return email
def save(self):
cleaned_data = self.cleaned_data
if hasattr(self.user, 'url_de_contact'):
if self.user.url_de_contact != cleaned_data['url_de_contact']:
self.user.url_de_contact = cleaned_data['url_de_contact']
self.user.save()
email = cleaned_data['email']
if email != self.user.email:
jeton = envoyer_jeton(self.request, "Changement d'email",
_(u'''Code de confirmation pour le changement d'email sur {{host}}'''),
_(u'''\
Vous avez demandé à changer d'email sur {{ host }}. Pour confirmer
ce changement veuillez entrer le code {{jeton}} sur la page:
{{ confirmation_url }}
ou bien recopier le lien suivant dans la barre de navigation de votre navigateur
{{ jeton_url }}'''),
{ },
settings.CHANGE_EMAIL_FROM,
cleaned_data['email'],
{ 'email': email, 'user_id': self.user.id,
'change_email': 1, 'next': next_url(self.request, '/')
})
messages.info(self.request, _(u"Vous avez demandé à changer d'email."
u" Un email a été envoyé a l'email"
u" %s pour validation. Après validation votre email sera"
u" changé.") % cleaned_data['email'])
self.request.logger.info(u"demande un changement d'email "
u"de %s à %s", self.request.user.email, cleaned_data['email'])
self.request.logger.info(u"le jeton %s lui a été envoyé", jeton)
class MesAlertesForm(FormulaireAvecRelaie):
refuse_notif_depublication = forms.BooleanField(
label=_(u'Je ne souhaite pas recevoir les messages de'
u' désactivation automatique des annonces'),
required=False)
refuse_notif_alertes = forms.BooleanField(
label=_(u'Je ne souhaite pas recevoir de notification'
u" des périodes d'affluence"),
required=False)
refuse_invitations = forms.BooleanField(
label=_(u"Je ne souhaite pas recevoir d'invitations"),
required=False)
success_url = '/offre'
def __init__(self, **kwargs):
request = kwargs.get('request')
user = self.user = request.user
initial = kwargs.setdefault('initial', {})
if not socle_views.is_webmaster(user):
initial['refuse_notif_depublication'] = not user.accepte_notif_depublication
initial['refuse_notif_alertes'] = not user.accepte_notif_alertes
initial['refuse_invitations'] = not user.accepte_invitations
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
button_holder = ButtonHolder(Submit('submit', _(u"Confirmer")))
fields = [ 'refuse_notif_depublication',
'refuse_notif_alertes', 'refuse_invitations', 'next',
button_holder]
if socle_views.is_webmaster(user):
invitations = True
else:
invitations = models.Annonce.objects \
.filter(proprietaire=user) \
.exclude(type_d_offre=1) \
.filter(etat_validation__in=['valide', 'publiee']) \
.exists() or user.accepte_invitations
if not invitations:
fields.remove('refuse_invitations')
self.helper.layout = Layout(*fields)
super(MesAlertesForm, self).__init__(**kwargs)
if not invitations:
del self.fields['refuse_invitations']
def save(self):
cleaned_data = self.cleaned_data
for other in cleaned_data:
if other.startswith('refuse_'):
key = 'accepte_' + other[len('refuse_'):]
if getattr(self.user, key) == cleaned_data[other]:
setattr(self.user, key, not cleaned_data[other])
self.request.logger.info(
u"met son paramètre %s"
u" à la valeur %s",
key, getattr(self.user, key))
self.user.save()