forms.py 15.3 KB
Newer Older
1 2 3 4 5
# -*- coding: utf-8 -*-


from django import forms
from django.forms import widgets
6
from django.core.validators import validate_email
7
from gestion import config
8
from gestion.config import factures
9
from gestion.chgpass import check_password
Gabriel Detraz's avatar
Gabriel Detraz committed
10
from django.forms.utils import ErrorList
11
from lc_ldap.attributs import UniquenessError
Charlie Jacomme's avatar
Charlie Jacomme committed
12
from lc_ldap.crans_utils import hash_password
13
import subprocess
14
import unicodedata
15 16
from datetime import date
from dateutil import relativedelta as rdelta
Mathilde Espinasse's avatar
Mathilde Espinasse committed
17 18
from django.utils.translation import ugettext_lazy as _

19

20
class BaseCompteForm(forms.Form):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
21
    nom = forms.CharField(label=_(u'Nom'), max_length=40, required=True)
22

23
    def __init__(self, ldap_user=None, *args, **kwargs):
24
        super(BaseCompteForm, self).__init__(*args, **kwargs)
25 26
        if ldap_user:
            self.fields['nom'].initial = ldap_user['nom'][0]
27
        #self.fields['tel'].initial = ldap_user.get('tel',[''])[0]
Charlie Jacomme's avatar
Charlie Jacomme committed
28 29 30 31 32 33 34 35 36 37 38 39
    def apply(self, luser):
        """
            Fonction d'application des modifications à l'objet ldap. Doit être appellé après un form.valid
        """
        for field in self.changed_data:
            try:
                luser[field] = unicode(self.cleaned_data[field])
            except ValueError as e:
                elist = self._errors.setdefault(field, ErrorList())
                elist.append(e)
                return False
        return True
40 41 42 43



class CompteForm(BaseCompteForm):
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
    prenom = forms.CharField(
        label=_(u'Prénom'),
        max_length=40,
        required=True,
    )
    tel = forms.CharField(
        label=_(u'Téléphone'),
        max_length=15,
        required=True,
    )
    etudes = forms.CharField(
        label=_(u'Etablissement'),
        max_length=100,
        required=True,
    )
    contourneGreylist = forms.BooleanField(
        label=_(u'Contournement du greylisting'),
        required=False,
    )

    def __init__(self, ldap_user=None, *args, **kwargs):
65 66 67
        """
            On initialise le formulaire par rapport aux données du ldap_user
        """
68
        super(CompteForm, self).__init__(ldap_user, *args, **kwargs)
69
        if ldap_user:
70

71
            self.fields['etudes'].initial = ldap_user.get('etudes', ['Inconnu'])[0]
72

73 74 75
            self.fields['prenom'].initial = ldap_user['prenom'][0]
            self.fields['tel'].initial = ldap_user['tel'][0]
            self.fields['contourneGreylist'].initial = ldap_user.get('contourneGreylist', [u''])[0]
Charlie Jacomme's avatar
Charlie Jacomme committed
76 77

    def clean_contourneGreylist(self):
78 79 80
        """
            ContourneGreyList est stocké côté LDAP comme "" ou "OK", on convertit donc le bool du formulaire
        """
Charlie Jacomme's avatar
Charlie Jacomme committed
81 82 83
        if self.cleaned_data['contourneGreylist']:
            return u"OK"
        else:
84
            return False
85

86
    def apply(self, luser):
87 88 89
        """
            Fonction d'application des modifications à l'objet ldap. Doit être appellé après un form.valid
        """
90
        # On boucle sur les champs "simples"
91 92
        # La date de naissance n'est pas un champ ldap
        if 'naissance' in self.changed_data: self.changed_data.remove('naissance')
93 94
        for field in self.changed_data:
            try:
95 96 97 98
                if field == 'contourneGreylist' and not self.cleaned_data[field]:
                    luser[field] = []
                else:
                    luser[field] = unicode(self.cleaned_data[field])
99 100 101 102 103
            except ValueError as e:
                elist = self._errors.setdefault(field, ErrorList())
                elist.append(e)
                return False
        return True
104

105
class MailForm(forms.Form):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
106
    mailredirect = forms.CharField(label=_(u'Redirection des mails'), max_length=40, required=False)
107 108 109 110 111 112 113 114
    def __init__(self, ldap_user, *args, **kwargs):
        super(MailForm, self).__init__(*args, **kwargs)
        redirection_mail = subprocess.Popen(["sudo", "-n", "/usr/scripts/utils/forward.py", "--read", "--name=%s" % ldap_user['uid'][0]], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        mailredirect = redirection_mail.stdout.readlines()
        if mailredirect:
            self.fields['mailredirect'].initial = mailredirect[0]
        else:
            self.fields['mailredirect'].initial = "N/A"
115

116
    def clean_mailredirect(self):
117 118
        """Nettoie le champ de redirection et vérifie qu'il correspond
        aux critères imposés"""
119
        mailredirect = self.cleaned_data['mailredirect']
120 121 122 123

        if not mailredirect.strip():
            return ""

124
        if "@crans.org" in mailredirect:
Mathilde Espinasse's avatar
Mathilde Espinasse committed
125
            raise forms.ValidationError(_(u"Impossible de rediriger vers une adresse mail crans"))
126 127 128
        try:
            validate_email(mailredirect)
        except forms.ValidationError:
129
            if not mailredirect.strip('"').strip().startswith('|'):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
130
                raise forms.ValidationError(_(u"Ce champ doit être une adresse mail ou l'execution d'un programme type procmail"))
131
        return mailredirect
132

133
class AliasForm(forms.Form):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
134
    mailAlias = forms.EmailField(label=_(u'Nouvel alias Mail'), max_length=40, required=False)
135

136
class BasePassForm(forms.Form):
137 138 139 140 141 142 143 144 145 146 147 148 149
    newpasswd1 = forms.CharField(
        label=_(u'Nouveau mot de passe'),
        max_length=255,
        widget=widgets.PasswordInput,
        required=False,
    )
    newpasswd2 = forms.CharField(
        label=_(u'Retaper le mot de passe'),
        max_length=255,
        widget=widgets.PasswordInput,
        required=False,
    )

150 151 152 153 154 155
    def clean(self):
        newpasswd1 = self.cleaned_data.get('newpasswd1')
        newpasswd2 = self.cleaned_data.get('newpasswd2')
        check, msg = check_password(newpasswd1)
        if not check:
            raise forms.ValidationError(msg)
156

157
        if newpasswd1 != newpasswd2:
Mathilde Espinasse's avatar
Mathilde Espinasse committed
158
            raise forms.ValidationError(_(u"Les mots de passe ne sont pas identiques."))
159 160 161

        return self.cleaned_data

162 163 164 165 166
    def apply(self, luser):
        """
            Applique les modifications dans le user ldap
        """
        if self.cleaned_data['newpasswd1']:
Charlie Jacomme's avatar
Charlie Jacomme committed
167
            hashedPassword = hash_password(self.cleaned_data['newpasswd1'].encode('utf-8'))
168 169 170 171 172 173 174 175 176
            try:
                luser['userPassword'] = [hashedPassword.decode('ascii')]
                return True

            except EnvironmentError as e:
                errors = self._errors.setdefault("newpasswd2", ErrorList())
                errors.append(e)
                return False

177
class PassForm(BasePassForm):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
178
    passwdexists = forms.CharField(label=_(u'Ancien mot de passe'), max_length=255, widget=widgets.PasswordInput, required=True)
179

180
class SoldeForm(forms.Form):
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
    montant = forms.DecimalField(
        label=_(u'Montant à ajouter ou supprimer'),
        required=True,
    )
    mode = forms.ChoiceField(
        label=_(u'Mode de réglement'),
        choices=tuple(
            [("", "<choisis un mode de réglement>")] + factures.SOLDE.items()
        ),
        required=True,
    )
    commentaire = forms.CharField(
        label=_(u'Commentaire'),
        max_length=255,
        required=False,
    )
197 198

class VenteForm(forms.Form):
199 200 201 202 203 204 205
    articles = forms.MultipleChoiceField(
        label=_(u'Articles disponibles'),
        choices=tuple(
            (a, b['designation'] + " : " + str(b['pu']) + u"€")\
            for a, b in factures.ITEMS.items()),
        required=True,
    )
Mathilde Espinasse's avatar
Mathilde Espinasse committed
206 207
    mode = forms.ChoiceField(label=_(u'Mode de réglement'), choices=tuple([("", "<choisis un mode de réglement>")] + factures.VENTE.items()), required=True)
    commentaire = forms.CharField(label=_(u'Commentaire'), max_length=255, required=False)
208 209

class AdhesionForm(forms.Form):
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    def __init__(self, *args, **kwargs):
        is_cableur = kwargs.pop('is_cableur')
        super(AdhesionForm, self).__init__(*args, **kwargs)
        nbr_mois_label = u"Nombre de mois de connexion, entre 0 et 12"
        if is_cableur:
            nbr_mois_label += u", 0 pour une adhésion seule"
            mode_choix = tuple(factures.VENTE.items())
        else:
            mode_choix = (('solde', u'Vente \xe0 partir du Solde'),)
        self.fields['mode'].empty_label = u"choisir un mode de réglement"
        self.fields['nbrmois'].label = nbr_mois_label
        self.fields['mode'].choices = mode_choix

    nbrmois = forms.IntegerField(min_value=0, max_value=12, required=True)
    mode = forms.ChoiceField(label=_(u'Mode de réglement'), required=True)
225

226 227 228
class CguForm(forms.Form):
    check = forms.BooleanField(required=True)

229
class ComptecransForm(forms.Form):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
230
    login = forms.CharField(label=_(u'Login Crans'), required=False)
231
    def __init__(self, ldap_user=None, ldap_conn=None, ptype=None, *args, **kwargs):
232
        super(ComptecransForm, self).__init__(*args, **kwargs)
233 234 235 236 237 238
        if ldap_user and ldap_conn and ptype:
            nom = unicode(unicodedata.normalize('NFKD', unicode(ldap_user['nom'][0])).encode('ascii', 'ignore')).lower().replace(' ', '-')
            if ptype != 'club':
                prenom = unicode(unicodedata.normalize('NFKD', unicode(ldap_user['prenom'][0])).encode('ascii', 'ignore')).lower().replace(' ', '-')
                login_crans = nom
                baselogin = nom
239
                for rang, let in enumerate(prenom):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
240
                    if ldap_conn.search(_(u'uid=%s') % login_crans) == []:
241 242 243 244 245 246 247 248
                        break
                    else:
                        login_crans = prenom[:rang] + baselogin
            else:
                login_crans = u'club-' + nom
            self.fields['login'].initial = login_crans

    def apply(self, luser):
249 250 251
        """
            Fonction d'application des modifications à l'objet ldap. Doit être appellé après un form.valid
        """
252 253 254 255 256 257 258 259 260
        if self.cleaned_data['login']:
            try:
                luser.compte(login=unicode(self.cleaned_data['login']))
                return True
            except ValueError as e:
            # Le message d'une ValueError est directement dans e
                elist = self._errors.setdefault('login', ErrorList())
                elist.append(e)
                return False
261 262 263 264 265 266
            except UniquenessError as e:
            # Le message d'une ValueError est directement dans e
                elist = self._errors.setdefault('login', ErrorList())
                elist.append(e)
                return False

267 268
        return True
class EmenagementForm(forms.Form):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
269
    chbre = forms.CharField(label=_(u'Chambre de l\'adhérent'), max_length=255, required=True)
270
    def apply(self, luser, confirm, conn):
271 272 273
        """
            Fonction d'application des modifications à l'objet ldap. Doit être appellé après un form.valid
        """
274 275
        chbre = self.cleaned_data['chbre']
        try:
276
            luser['chbre'] = chbre
Charlie Jacomme's avatar
Charlie Jacomme committed
277
            if 'adherent' in luser.get("objectClass", []):
278
                luser['postalAddress'] = []
279 280
            return True
        except ValueError as e:
281 282
            self._errors.setdefault('chbre', ErrorList()).append(e)
            return False
283 284 285 286
        except UniquenessError:
            # La chambre est occupée
            if not confirm:
                # on demande confirmation
Mathilde Espinasse's avatar
Mathilde Espinasse committed
287
                squatteur = conn.search('chbre=%s' % chbre, mode='w')[0]
288
                if 'adherent' in luser.get("objectClass", []):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
289
                    denomination = _(u"Cette chambre")
290
                    uid = "aid = %s" % squatteur.get('aid', [''])[0]
291
                else:
Mathilde Espinasse's avatar
Mathilde Espinasse committed
292
                    denomination = _(u("Ce local"))
293 294 295 296 297 298 299 300 301 302 303 304 305
                    uid = "cid = %s" % squatteur.get('cid', [''])[0]
                self._errors.setdefault('chbre', ErrorList()).append(
                    _(u"%(denomination)s est déjà occupé(e) par %(squatteur_prenom)s\
                            %(squatteur_nom)s, %(uid)s, corrigez la saisie\
                            ou revalidez pour confirmer.") %
                    {
                        'denomination': denomination,
                        'squatteur_prenom' : squatteur.get('prenom', [''])[0],
                        'squatteur_nom' : squatteur.get('nom', [''])[0],
                        'uid' : uid,
                    }
                )
                return 'confirm' # Ce confirm doit être rattrapé par la view
306
            else:
307 308 309 310
                squatteur = conn.search(u'chbre=%s' % chbre, mode='w')[0]
                squatteur['chbre'] = '????' # on vire le squatteur si on a eu une confirmation
                squatteur.history_gen()
                squatteur.save()
311
                luser['chbre'] = chbre
312
                return True
313 314

class DemenagementForm(EmenagementForm):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
315 316 317 318 319 320
    postalAddress = forms.CharField(label=_(u'Adresse :'), max_length=255, required=False)
    postalAddress2 = forms.CharField(label=_(u'Adresse :'), max_length=255, required=False)
    postalAddress3 = forms.CharField(label=_(u'Code Postal :'), max_length=255, required=False)
    postalAddress4 = forms.CharField(label=_(u'Ville :'), max_length=255, required=False)
    chbre = forms.CharField(label=_(u'Chambre de l\'adhérent'), max_length=255, required=False)
    del_machines = forms.BooleanField(label=_(u'Supprimer les machines enregistrées'), required=False)
321 322 323
    def __init__(self, ldap_user=None, *args, **kwargs):
        super(DemenagementForm, self).__init__(*args, **kwargs)
        if ldap_user:
324
            _postalAddress = ['', '', '', '']
325 326 327 328 329 330 331

            for i in xrange(len(ldap_user['postalAddress'])):
                _postalAddress[i] = ldap_user['postalAddress'][i]
            self.fields['postalAddress'].initial = _postalAddress[0]
            self.fields['postalAddress2'].initial = _postalAddress[1]
            self.fields['postalAddress3'].initial = _postalAddress[2]
            self.fields['postalAddress4'].initial = _postalAddress[3]
332

333 334
    def clean(self):
        datas = [field for field in self.cleaned_data if self.cleaned_data[field]]
335
        if "chbre" in datas and len(datas) > 1:
336
            print self.cleaned_data
Mathilde Espinasse's avatar
Mathilde Espinasse committed
337
            raise forms.ValidationError(_(u"Impossible d'avoir une chambre et une adresse extérieure"))
338

339
    def apply(self, luser, confirm, conn):
340 341 342
        """
            Fonction d'application des modifications à l'objet ldap. Doit être appellé après un form.valid
        """
343
        chbre = self.cleaned_data['chbre']
Mathilde Espinasse's avatar
Mathilde Espinasse committed
344
        # Soit on met un chambre, soit une adresse extérieure
345
        if chbre:
346
            # Si on met une chambre, c'est comme pour EmenagementForm
347
            return super(DemenagementForm, self).apply(luser, confirm, conn)
348
        else:
349
            # Sinon, on ajoute l'adresse extérieur
350
            luser['chbre'] = 'EXT'
351 352 353 354 355 356
            luser['postalAddress'] = [
                self.cleaned_data['postalAddress'],
                self.cleaned_data['postalAddress2'],
                self.cleaned_data['postalAddress3'],
                self.cleaned_data['postalAddress4'],
            ]
357 358
            if self.cleaned_data['del_machines']:
                for m in luser.machines():
359
                    m.delete()
360 361 362 363
            return True


class NewCompteForm(CompteForm):
364 365 366 367 368 369 370 371 372 373
    mail = forms.CharField(
        label=_(u'Email'),
        max_length=40,
        validators=[validate_email],
        required=False,
    )
    naissance = forms.DateField(
        label=_(u'Date de naissance'),
        required=True,
    )
374 375 376 377 378 379 380 381 382

    def check_date(self):
        """ Verifie la date de naissance """
        naissance = self.cleaned_data['naissance']
        Now = date.today()
        age = rdelta.relativedelta(Now, naissance).years
        if age < 18:
            return False
        return True
Charlie Jacomme's avatar
Charlie Jacomme committed
383 384 385


class NewClubForm(BaseCompteForm):
Mathilde Espinasse's avatar
Mathilde Espinasse committed
386
    responsable = forms.IntegerField(label=_(u'Aid du responsable'), required=True)
Charlie Jacomme's avatar
Charlie Jacomme committed
387 388 389

    def check_date(self):
        return True