views.py 34.5 KB
Newer Older
1 2 3 4
# -*- coding: utf-8 -*-
# Récriture de l'app compte
# Enrichissement de celle-ci.
# Gabriel Détraz detraz@crans.org
5
# Charlie Jacomme jacomme@crans.org
6

7
from django.shortcuts import render, redirect
8
from django.contrib.auth.decorators import login_required
9
from django.views.decorators.debug import sensitive_post_parameters
10
from django.utils.decorators import method_decorator
11
import subprocess
Mathilde Espinasse's avatar
Mathilde Espinasse committed
12
from django.utils.translation import ugettext_lazy as _
13 14 15

from django.http import HttpResponseRedirect
from django.template import RequestContext
16
from intranet import conn_pool
17
from django.utils import timezone
18
from django.core.urlresolvers import reverse
19

20
from django.contrib import messages
21
from django.views.generic import View
22

23
import datetime
24
from dateutil.relativedelta import relativedelta
25

26
from passlib.apps import ldap_context
27
import lc_ldap.crans_utils
28
from lc_ldap import shortcuts
29
from intranet import settings
30

31
from gestion.config import factures, cotisation
32

33
from forms import BaseCompteForm, CompteForm, BasePassForm, PassForm, MailForm, AliasForm, SoldeForm, VenteForm, AdhesionForm, CguForm, ComptecransForm, DemenagementForm, NewCompteForm, EmenagementForm, NewClubForm
Gabriel Detraz's avatar
Gabriel Detraz committed
34
from django.forms.utils import ErrorList
35

36 37
from intranet.mixins import CableurOrSelfMixin, CableurMixin

38 39 40 41
class RedirectHomeMixin(object):
    """
      Mixin permettant de rediriger vers le compte de l'utilisateur modifié et non du request.user
    """
42
    def dispatch(self, request, uid, ptype=u'adh', next=None, *args, **kwargs):
43 44 45 46 47 48 49
        if not next:
            if not uid:
                next = reverse('compte:afficher')
            if ptype == 'club':
                next = reverse('compte:afficher_club', args=(uid,))
            else:
                next = reverse('compte:afficher', args=(uid,))
50
        return super(RedirectHomeMixin, self).dispatch(request, uid=uid, next=next, ptype=ptype, *args, **kwargs)
51

Charlie Jacomme's avatar
Charlie Jacomme committed
52
def get_luser(request, uid, ptype, mode='ro'):
53 54 55 56 57 58 59 60 61 62 63
    if ptype == 'adh':
        return conn_pool.get_conn(request.user).search(u'aid=%s' % uid, mode=mode)[0]
    elif ptype == 'club':
        return conn_pool.get_conn(request.user).search(u'cid=%s' % uid, mode=mode)[0]

def get_admin_luser(request, uid, ptype, mode='ro'):
    ldap = shortcuts.lc_ldap_admin()
    if ptype == 'adh':
        return ldap.search(u'aid=%s' % uid, mode=mode)[0]
    elif ptype == 'club':
        return ldap.search(u'cid=%s' % uid, mode=mode)[0]
Pierre-Elliott Bécue's avatar
Pierre-Elliott Bécue committed
64

65
class ClubView(CableurOrSelfMixin, View):
66
    """
67
      Classe de base pour l'affichage d'un club. Doit être appellé avec un cid.
68 69
    """
    template_name = 'compte/affichage_club.html'
70

Charlie Jacomme's avatar
Charlie Jacomme committed
71
    def get(self, request, cid, *args, **kwargs):
72 73
        # On a juste a peupler le form avec les informations de l'utilisateur
        luser = conn_pool.get_conn(request.user).search(u'cid=%s' % cid)[0]
74
        # Si il n'y a pas de compte crans derrière, uid vaut false et l'app de cablage n'affiche pas tout
75
        uid = luser.get('uid', False)
76 77 78 79 80
        form = BaseCompteForm(luser)
        context = {
            'form': form,
            'now': timezone.now(),
            'luser': luser,
81
            'comptecrans': uid,
82 83
            }
        return render(request, self.template_name, context)
84

Charlie Jacomme's avatar
Charlie Jacomme committed
85
    def post(self, request, cid, *args, **kwargs):
86
        luser = conn_pool.get_conn(request.user).search(u'cid=%s' % cid)[0]
87
        # Si il n'y a pas de compte crans derrière, uid vaut false et l'app de cablage n'affiche pas tout
88
        uid = luser.get('uid', False)
89
        form = BaseCompteForm(luser, request.POST)
90 91 92 93 94 95 96 97 98 99 100 101 102 103
        if form.is_valid():
            luser = conn_pool.get_conn(request.user).search(u'cid=%s' % cid, mode="w")[0]

            # On boucle sur les champs modifiés pour mettre à jour ldap
            for field in form.changed_data:
                try:
                    luser[field] = form.cleaned_data[field]
                except ValueError as e:
                    elist = form._errors.setdefault(field, ErrorList())
                    elist.append(e)

            # Il faut créer l'historique avant de sauvegarder.
            luser.history_gen()
            luser.save()
Mathilde Espinasse's avatar
Mathilde Espinasse committed
104
            messages.success(request, _(u"""Les modifications ont été prises en compte"""))
105 106 107 108 109

        context = {
            'form': form,
            'now': timezone.now(),
            'luser': luser,
110
            'comptecrans': uid,
111 112
            }
        return render(request, self.template_name, context)
113

114
    @method_decorator(login_required)
115 116 117 118
    def dispatch(self, request, cid=None, *args, **kwargs):
        if not cid:
            luser = conn_pool.get_user(request.user)
            cid = luser['cid'][0]
Charlie Jacomme's avatar
Charlie Jacomme committed
119
        return super(ClubView, self).dispatch(request, cid, *args, **kwargs)
120 121 122 123

afficher_club = ClubView.as_view()


124
class CompteView(CableurOrSelfMixin, View):
125 126 127 128 129
    """
      Affichage d'un adhérent. Necessite un aid.
    """
    template_name = 'compte/affichage.html'

Charlie Jacomme's avatar
Charlie Jacomme committed
130
    def get(self, request, aid, *args, **kwargs):
131
        luser = conn_pool.get_conn(request.user).search(u'aid=%s' % aid)[0]
132
        # Si il n'y a pas de compte crans derrière, uid vaut false et l'app de cablage n'affiche pas tout
133
        uid = luser.get('uid', False)
134 135 136 137 138 139 140
        if uid:
            redirection_mail = subprocess.Popen(["sudo", "-n", "/usr/scripts/utils/forward.py", "--read", "--name=%s" % luser['uid'][0]], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            mailredirect = redirection_mail.stdout.readlines()
            if mailredirect:
                mailredirect = mailredirect[0]
            else:
                mailredirect = "N/A"
141 142 143
        else:
            mailredirect = "N/A"

144 145 146 147 148 149
        form = CompteForm(luser)
        context = {
            'form': form,
            'now': timezone.now(),
            'luser': luser,
            'mailredirect': mailredirect,
150
            'comptecrans': uid,
151 152
            }
        return render(request, self.template_name, context)
153

Charlie Jacomme's avatar
Charlie Jacomme committed
154
    def post(self, request, aid, *args, **kwargs):
155
        luser = conn_pool.get_conn(request.user).search(u'aid=%s' % aid)[0]
156
        uid = luser.get('uid', False)
157
        form = CompteForm(luser, request.POST)
158 159
        if form.is_valid():
            luser = conn_pool.get_conn(request.user).search(u'aid=%s' % aid, mode="w")[0]
160 161 162 163
            if form.apply(luser):
                # Il faut créer l'historique avant de sauvegarder.
                luser.history_gen()
                luser.save()
Mathilde Espinasse's avatar
Mathilde Espinasse committed
164
                messages.success(request, _(u"""Les modifications ont été prises en compte"""))
165 166 167 168 169

        context = {
            'form': form,
            'now': timezone.now(),
            'luser': luser,
170
            'comptecrans': uid,
171 172 173 174 175
            }
        return render(request, self.template_name, context)

    @method_decorator(login_required)
    def dispatch(self, request, aid=None, *args, **kwargs):
176
        if not aid:     # Si aid=None, on renvoit celui de l'user
177 178
            luser = conn_pool.get_user(request.user)
            aid = luser['aid'][0]
Charlie Jacomme's avatar
Charlie Jacomme committed
179
        return super(CompteView, self).dispatch(request, aid, *args, **kwargs)
180 181

afficher = CompteView.as_view()
182

183
class ChgPassView(CableurOrSelfMixin, RedirectHomeMixin, View):
184 185 186 187 188 189 190 191 192 193 194
    """
      Classe de base pour le changement d'un password
    """
    template_name = "compte/chgpass.html"

    def get(self, request, uid, ptype, cablage, *args, **kwargs):
        # Selon si on est cableur on a besoin ou pas de rentrer l'ancien mdp
        if cablage:
            form = BasePassForm()
        else:
            form = PassForm()
195 196 197 198 199 200 201 202 203 204
        return render(
            request,
            self.template_name,
            {
                'form': form,
                'ptype': ptype,
                'ide': uid,
                'cablage': cablage,
            },
        )
205 206

    @method_decorator(sensitive_post_parameters())
207
    def post(self, request, uid, ptype, cablage, next='/compte/', *args, **kwargs):
208
        # Selon si on est cableur on a besoin ou pas de rentrer l'ancien mdp
209 210 211 212
        if cablage:
            form = BasePassForm(request.POST)
        else:
            form = PassForm(request.POST)
Charlie Jacomme's avatar
Charlie Jacomme committed
213
        luser = get_luser(request, uid, ptype, 'w')
214
        if form.is_valid():
215
            # Soit on est en train de cabler soit l'ancien mot de passe est bon
216 217 218 219
            if cablage or ldap_context.verify(
                    unicode(form.cleaned_data['passwdexists']),
                    unicode(luser['userPassword'][0])
            ):
220
                if form.apply(luser):
221 222
                    luser.history_gen()
                    luser.save()
Mathilde Espinasse's avatar
Mathilde Espinasse committed
223
                    messages.success(request, _(u"""Le mot de passe a bien été changé"""))
224
                    return redirect(next)
225
            else: # l'ancien mot de passe est éroné
226
                errors = form._errors.setdefault("passwdexists", ErrorList())
Mathilde Espinasse's avatar
Mathilde Espinasse committed
227
                errors.append(_(u"Ancien mot de passe erroné."))
228 229 230 231 232 233 234 235

        return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid, 'cablage': cablage})

    @method_decorator(login_required)
    def dispatch(self, request, uid, ptype, *args, **kwargs):
        luser = conn_pool.get_user(request.user)
        cablage = False
        # Si je ne me modifie pas moi même et que je suis cableur => Cablage
236
        if ptype == 'adh' and luser.get("aid", [""])[0] != uid and request.user.has_perm('auth.crans_cableur'):
237
            cablage = True
238
        if ptype == 'club' and request.user.has_perm('auth.crans_cableur'):
239
            cablage = True
240
        return super(ChgPassView, self).dispatch(request, uid=uid, ptype=ptype, cablage=cablage, *args, **kwargs)
241 242

chgpass = ChgPassView.as_view()
243

244

245
class RedirectionView(CableurOrSelfMixin, RedirectHomeMixin, View):
246
    """
247
        Vue pour la gestion de la redirection mail
248 249 250
    """
    template_name = 'compte/redirection.html'

251
    def get(self, request, uid, *args, **kwargs):
252
        # On a juste a peupler le form avec les informations de l'utilisateur
253
        luser = conn_pool.get_conn(request.user).search(u'aid=%s' % uid)[0]
254 255 256
        form = MailForm(luser)
        return render(request, self.template_name, {'form': form, 'luser': luser})

257 258
    def post(self, request, uid, generate=False, next='/compte/', *args, **kwargs):
        luser = conn_pool.get_conn(request.user).search(u'aid=%s' % uid)[0]
259
        form = MailForm(luser, request.POST)
260 261 262 263
        if form.is_valid():
        # La redirection n'est pas un champ ldap
            if 'mailredirect' in form.changed_data:
                mailredirect = unicode(form.cleaned_data['mailredirect'])
264 265 266 267
                if mailredirect != "":
                    if not generate:
                        redirection_mail = subprocess.Popen(["sudo", "-n", "/usr/scripts/utils/forward.py", "--write", "--mail=%s" % mailredirect, "--name=%s" % luser['uid'][0]])
                    else:
268
                        luser = conn_pool.get_conn(request.user).search(u'aid=%s' % uid, mode='w')[0]
269
                        with luser as adh:
270
                            adh['mailExt'] = mailredirect
271 272
                            adh.history_gen()
                            adh.save()
Mathilde Espinasse's avatar
Mathilde Espinasse committed
273
                    messages.success(request, _(u"""Votre redirection a bien été prise en compte"""))
274
                return redirect(next)
275 276 277 278

        return render(request, self.template_name, {'form': form, 'luser': luser})

redirection = RedirectionView.as_view()
279

280 281
class DeleteForwardView(CableurOrSelfMixin, RedirectHomeMixin, View):
    """
282
        Classe pour la suppresion d'une redirection mail.
283
    """
284
    def get(self, request, uid, next="/compte/", *args, **kwargs):
285 286
        luser = conn_pool.get_conn(request.user).search(u'aid=%s' % uid, mode='w')[0]
        try:
287 288 289 290 291 292 293 294 295 296 297 298 299
            redirection_mail = subprocess.Popen(
                [
                    "sudo",
                    "-n",
                    "/usr/scripts/utils/forward.py",
                    "--delete",
                    "--name=%s" % luser['uid'][0]
                ]
            )
            messages.success(
                request,
                _(u"Votre redirection a été supprimée, pensez à consulter régulièrement votre adresse Cr@ns !")
            )
300
        except ValueError as e:
301
            messages.error(request, e)
302
        return redirect(next)
303

304
deleteforward = DeleteForwardView.as_view()
305 306 307

class DeleteAliasView(CableurMixin, RedirectHomeMixin, View):
    """
308
        Classe pour la réinitialisation du mot de passe et l'impression d'un ticket
309 310 311
    """
    def get(self, request, uid, ptype, alias_id, next='/compte/', *args, **kwargs):
        # Vue de suppresion d'un alias. N'a pas de visuel, redirige juste vers le home
Charlie Jacomme's avatar
Charlie Jacomme committed
312
        luser = get_luser(request, uid, ptype, 'w')
313 314 315 316
        try:
            luser['mailAlias'].remove(luser['mailAlias'][int(alias_id)])
            luser.history_gen()
            luser.save()
Mathilde Espinasse's avatar
Mathilde Espinasse committed
317
            messages.success(request, _(u"""L'alias a été retiré avec succès"""))
318 319 320 321 322 323
        except ValueError as e:
            # Le message d'une ValueError est directement dans e
            messages.error(request, e)
        return redirect(next)

delete_alias = DeleteAliasView.as_view()
Charlie Jacomme's avatar
Charlie Jacomme committed
324

325
class AliasView(CableurOrSelfMixin, RedirectHomeMixin, View):
Charlie Jacomme's avatar
Charlie Jacomme committed
326 327 328 329
    """
      Classe de base pour les alias
    """
    template_name = "compte/alias.html"
330

Charlie Jacomme's avatar
Charlie Jacomme committed
331
    def get(self, request, uid, ptype, *args, **kwargs):
Charlie Jacomme's avatar
Charlie Jacomme committed
332
        luser = get_luser(request, uid, ptype)
Charlie Jacomme's avatar
Charlie Jacomme committed
333
        form = AliasForm()
Charlie Jacomme's avatar
Charlie Jacomme committed
334
        return render(request, self.template_name, {'form': form, 'luser': luser, 'ptype': ptype, 'ide': uid})
335

336
    def post(self, request, uid, ptype, next='/compte/', *args, **kwargs):
337
        form = AliasForm(request.POST)
Charlie Jacomme's avatar
Charlie Jacomme committed
338
        luser = get_luser(request, uid, ptype, 'w')
339 340 341 342 343 344 345
        if form.is_valid():
            # Pour les Alias mail, on ne permet que l'ajout, pas la suppression
            if 'mailAlias' in form.changed_data:
                try:
                    luser['mailAlias'].append(form.cleaned_data['mailAlias'])
                    luser.history_gen()
                    luser.save()
Mathilde Espinasse's avatar
Mathilde Espinasse committed
346
                    messages.success(request, _(u"""L'alias a été ajouté avec succès"""))
347
                    return redirect(next)
348 349
                except ValueError as e:
                     # Le message d'une ValueError est directement dans e
350 351
                    elist = form._errors.setdefault('mailAlias', ErrorList())
                    elist.append(e)
Charlie Jacomme's avatar
Charlie Jacomme committed
352
        return render(request, self.template_name, {'form': form, 'luser': luser, 'ptype': ptype, 'ide': uid})
Charlie Jacomme's avatar
Charlie Jacomme committed
353 354 355 356

alias = AliasView.as_view()


357

358
class SoldeView(CableurMixin, RedirectHomeMixin, View):
359 360 361
    """
      Classe de base pour les modifications de solde
    """
362
    template_name = "compte/solde.html"
363
    def get(self, request, uid, ptype, *args, **kwargs):
364
        form = SoldeForm()
365 366 367 368 369 370 371 372
        return render(request,
            self.template_name,
            {
                'form': form,
                'ptype': ptype,
                'ide': uid,
            }
        )
373

374
    def post(self, request, uid, ptype, next='/compte/', *args, **kwargs):
375
        form = SoldeForm(request.POST)
Charlie Jacomme's avatar
Charlie Jacomme committed
376
        luser = get_luser(request, uid, ptype, 'w')
377
        if form.is_valid():
378
            fact = {
379 380
                'modePaiement': [form.cleaned_data['mode']],
                'article': [u'%s~~%s~~1~~%s' % ('SOLDE', 'Rechargement de solde ' + form.cleaned_data['commentaire'],float(form.cleaned_data['montant']))],
381 382 383 384 385 386 387
            }
            with conn_pool.get_conn(request.user).newFacture(luser.dn, fact) as facture:
                try:
                    facture.crediter()
                except ValueError as e:
                # Cas où le solde n'est pas suffisant
                    messages.error(request, e)
Gabriel Detraz's avatar
Gabriel Detraz committed
388
                    return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid})
389
                fid = facture['fid'][0]
Mathilde Espinasse's avatar
Mathilde Espinasse committed
390
            messages.success(request, _(u"""Vente effectuée, fid=%s (à conserver)""") % fid )
391
            return redirect(next)
392

393
        return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid})
394

395 396
solde = SoldeView.as_view()

397
class VenteView(CableurMixin, RedirectHomeMixin, View):
398 399 400 401 402 403
    """
      Classe de base pour la vente d'objets
    """
    template_name = "compte/vente.html"
    def get(self, request, uid, ptype, *args, **kwargs):
        form = VenteForm()
404 405
        articles = factures.ITEMS
        return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid, 'articles': articles})
406

407
    def post(self, request, uid, ptype, next='/compte/', *args, **kwargs):
408
        form = VenteForm(request.POST)
Charlie Jacomme's avatar
Charlie Jacomme committed
409
        luser = get_luser(request, uid, ptype, 'w')
410
        articles = factures.ITEMS
411 412

        if form.is_valid():
413
            fid = []
414 415
            # Boucle sur les différents articles
            for art in form.cleaned_data['articles']:
416
		details = factures.ITEMS[art]
417 418
                fact = {
                'modePaiement': [form.cleaned_data['mode']],
419
                'article': [u'%s~~%s~~1~~%s' % (art, details['designation'] + " " + form.cleaned_data['commentaire'],details['pu'])],
420 421
                }
                with conn_pool.get_conn(request.user).newFacture(luser.dn, fact) as facture:
422 423 424 425 426 427
                    try:
                        facture.crediter()
                    except ValueError as e:
                    # Cas où le solde n'est pas suffisant
                        messages.error(request, e)
                        return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid, 'articles': articles})
428
                    fid.append(unicode(facture['fid'][0]))
Mathilde Espinasse's avatar
Mathilde Espinasse committed
429
            messages.success(request, _(u"""Vente effectuée, fid=%s (à conserver)""") % (', '.join(fid)) )
430
            return redirect(next)
431
        return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid, 'articles': articles})
432 433 434 435



vente = VenteView.as_view()
436 437 438



439
class AdhesionView(CableurOrSelfMixin, RedirectHomeMixin, View):
440
    """
441
        Classe de base pour l'adhésion
442 443
    """
    template_name = "compte/adhesion.html"
444 445
    def get(self, request, uid, ptype, cablage, *args, **kwargs):
        form = AdhesionForm(request.POST, is_cableur=cablage)
446
        cgu = CguForm(request.POST)
447 448 449 450 451
        return render(
            request,
            self.template_name,
            {
                'form': form,
452
                'cgu': cgu,
453 454 455 456 457
                'ptype': ptype,
                'ide': uid,
                'cablage': cablage,
            }
        )
458

459
    def post(self, request, uid, ptype, cablage, next='/compte/', *args, **kwargs):
460 461 462
        """
            Si on est dans une requête POST
        """
463 464 465 466 467 468 469
        def connexion_possible(nbrmois, luser):
            # Determine le nombre de mois possible avant la readhesion
            try:
                reste_adhesion = relativedelta(luser.fin_adhesion().value, luser.fin_connexion().value)
                if reste_adhesion.months < 0:
                    nbrmois = 0
                    return nbrmois
470
                if nbrmois > reste_adhesion.months and reste_adhesion.years == 0:
471 472 473 474 475 476 477 478
                    if reste_adhesion.days > 15:
                        nbrmois = reste_adhesion.months + 1
                    else:
                        nbrmois = reste_adhesion.months
            except AttributeError:
                # La fin d'adhésion ne peut être évaluée, pas de connexion possible
                nbrmois = 0
            return nbrmois
479

480
        def prix(nbrmois, luser, ptype, cablage):
481 482 483
            # Détermine en fonction du nombre de mois si l'adhésion va étre faite et calcul le prix
            readhesion = False
            now = lc_ldap.crans_utils.localized_datetime()
484
            prix = min(nbrmois * cotisation.contribution, cotisation.plafond_contribution)
485 486 487 488 489 490 491 492 493
            try:
                delta = luser.fin_adhesion().value - now
                delta = delta.days
            # Si il n'y a pas de fin adh, on renvoie 0
            except AttributeError:
                delta = 0
            if delta < cotisation.delai_readh_jour:
                prix += cotisation.cotisation
                readhesion = True
494 495 496
            # Pour les clubs, c'est gratuit
            if ptype == 'club':
                prix = 0
497 498

            return nbrmois, prix, readhesion
499 500

        # On traite le post
501
        form = AdhesionForm(request.POST, is_cableur=cablage)
502
        cgu = CguForm(request.POST)
503
        luser = get_admin_luser(request, uid, ptype, 'w')
504 505
        if form.is_valid():
            #EN 2 etapes, on renvoie
506
            if 'confirm' in request.POST.keys():
507
                ######## Facturation de la connexion ########
508
                mois = form.cleaned_data['nbrmois']
509
                mois, prix, readhesion = prix(mois, luser, ptype, cablage)
510
                fact_cotis = cotisation.dico_cotis(mois)
511 512 513 514 515 516 517 518 519 520 521 522
                # On evite de créer des factures de 0 mois de connexions, pour les clubs, on ne fait pas de connexion
                if mois > 0 and ptype != 'club':
                    fact = {
                    'modePaiement': [form.cleaned_data['mode']],
                    'article': [u'%s~~%s~~%s~~%s' % (fact_cotis['code'], fact_cotis['designation'], fact_cotis['nombre'], fact_cotis['pu'])],
                    }
                else:
                    fact = {
                    'modePaiement': [form.cleaned_data['mode']],
                    'article': [],
                    }
                ########## Réadhésion ###########
523
                # Si la fonct d readhésion a repondu True, on réadhère aussi
524
                if readhesion and cgu.is_valid():
525 526 527 528 529
                    if ptype == 'club':
                        dico_adh = cotisation.dico_adh_club
                    else:
                        dico_adh = cotisation.dico_adh
                    fact['article'].append(u'%s~~%s~~%s~~%s' % (dico_adh['code'], dico_adh['designation'], dico_adh['nombre'], dico_adh['pu']))
530 531 532 533 534 535 536 537 538 539 540 541
                elif readhesion and not cgu.is_valid():
                    # Les CGU sont obligatoires
                    messages.error(request, _(u"La case d'acceptation des textes est obligatoire"))
                    return render(
                            request,
                            self.template_name,
                            {'form': form,
                             'cgu': cgu,
                             'ptype': ptype,
                             'ide': uid,
                             'cablage': cablage},
                            )
542 543
                elif mois == 0 or ptype == 'club':
                    # Dans ce cas il n'y a rien à faire
Mathilde Espinasse's avatar
Mathilde Espinasse committed
544
                    messages.error(request, _(u"La réadhésion n'est possible que moins d'un mois avant l'expiration, merci de repasser"))
545 546
                    return redirect(next)
                ####### Ecriture de la facture ############
547
                with shortcuts.lc_ldap_admin().newFacture(luser.dn, fact) as facture:
548 549 550 551 552 553
                    try:
                        facture.adhesion_connexion()
                    except ValueError as e:
                        # Cas où le solde n'est pas suffisant
                        messages.error(request, e)
                        return redirect(next)
554
                    fid = unicode(facture['fid'][0])
555 556 557 558 559
                    if readhesion:
                        fin_adh = unicode(facture['finAdhesion'][0])
                        debut_adh = unicode(facture['debutAdhesion'][0])
                    if mois > 0 and ptype != 'club':
                        fin_conn = unicode(facture['finConnexion'][0])
560 561
                        debut_conn = unicode(facture['debutConnexion'][0])
                #Hack : on recharge l'objet ldap
562
                luser = get_admin_luser(request, uid, ptype, 'w')
563 564 565 566 567 568 569 570 571 572 573
                ######## Mise à jour des attributs adhérent #########
                # On met à jour les valeurs fin_adh et fin_conn de l'adhérent
                with luser as adh:
                    if mois > 0 and ptype != 'club':
                        adh['finConnexion'].append(fin_conn)
                        adh['debutConnexion'].append(debut_conn)
                    if readhesion:
                        adh['finAdhesion'].append(fin_adh)
                        adh['debutAdhesion'].append(debut_adh)
                    adh.history_gen()
                    adh.save()
574 575 576 577
                messages.success(
                        request,
                        _(u"""Vente effectuée, fid=%s (à conserver)""") % (fid)
                    )
578
                return redirect(next)
579 580
            else:
                mois = form.cleaned_data['nbrmois']
581
                mois, prix, readhesion = prix(mois, luser, ptype, cablage)
582
                if not readhesion and mois == 0:
583 584 585 586 587 588 589 590
                    messages.error(
                            request,
                            _(u"La réadhésion est impossible plus d'un mois avant la fin de l'adhésion. Vous pouvez soit prolonger votre connexion jusqu'à la fin de votre adhésion, soit revenir un mois avant la fin votre adhésion.")
                        )
                    return render(
                            request,
                            self.template_name,
                            {'form': form,
591
                             'cgu': cgu,
592 593 594 595 596 597 598
                             'ptype': ptype,
                             'ide': uid},
                        )
                return render(
                        request,
                        self.template_name,
                        {'form': form,
599
                         'cgu': cgu,
600 601 602 603 604 605 606 607 608 609 610 611
                         'ptype': ptype,
                         'ide': uid,
                         'confirm': True,
                         'prix': prix,
                         'readhesion': readhesion,
                         'nbrmois': mois,
                         'cablage': cablage},
                        )
        return render(
                request,
                self.template_name,
                {'form': form,
612
                 'cgu': cgu,
613 614 615 616
                 'ptype': ptype,
                 'ide': uid,
                 'cablage': cablage},
                )
617 618


619 620 621 622 623 624 625 626
    @method_decorator(login_required)
    def dispatch(self, request, uid, ptype, *args, **kwargs):
        luser = conn_pool.get_user(request.user)
        cablage = False
        if request.user.has_perm('auth.crans_cableur'):
            cablage = True
        return super(AdhesionView, self).dispatch(request, uid=uid, ptype=ptype, cablage=cablage, *args, **kwargs)

627 628

adhesion = AdhesionView.as_view()
629 630


Charlie Jacomme's avatar
Charlie Jacomme committed
631
class ComptecransView(CableurMixin, View):
632 633 634 635 636
    """
      Classe de base pour la création de compte crans
    """
    template_name = "compte/comptecrans.html"
    def get(self, request, uid, ptype, *args, **kwargs):
637
        luser = get_luser(request, uid, ptype)
638 639 640 641
        form = ComptecransForm(luser, conn_pool.get_conn(request.user), ptype)
        return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid})

    def post(self, request, uid, ptype, *args, **kwargs):
Charlie Jacomme's avatar
Charlie Jacomme committed
642
        luser = get_luser(request, uid, ptype, 'w')
643 644
        form = ComptecransForm(luser, conn_pool.get_conn(request.user), ptype, request.POST)
        if form.is_valid():
645 646 647
            if form.apply(luser): #Si on arrive à appliquer les modifs à l'objet
                luser.history_gen()
                luser.save()
Mathilde Espinasse's avatar
Mathilde Espinasse committed
648
                messages.success(request, _(u"""Compte Crans crée, choisir un mot de passe"""))
649 650 651 652 653
                if ptype == 'adh':
                    redir_url = reverse('compte:redirection', args=(luser['aid'][0], True, '/compte/'))
                    return redirect(reverse('compte:chgpass', args=(u'adh', luser['aid'][0], redir_url)))
                else:
                    return redirect(reverse('compte:chgpass', args=(ptype,uid)))
654 655
        return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid})

656
comptecrans = ComptecransView.as_view()
Charlie Jacomme's avatar
Charlie Jacomme committed
657 658


659
class DemenagementView(CableurMixin, RedirectHomeMixin, View):
660 661 662 663 664
    """
      Classe de base pour le déménagement
    """
    template_name = "compte/demenagement.html"
    def get(self, request, uid, ptype, *args, **kwargs):
665 666
        luser = get_luser(request, uid, ptype)
        form = DemenagementForm(luser)
667 668
        return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid})

669
    def post(self, request, uid, ptype, confirm = "", next='/compte/', *args, **kwargs):
Charlie Jacomme's avatar
Charlie Jacomme committed
670
        luser = get_luser(request, uid, ptype, 'w')
671
        form = DemenagementForm(luser, request.POST)
672
        if form.is_valid():
673 674 675 676 677
            lconn =  conn_pool.get_conn(request.user)
            res = form.apply(luser, confirm, lconn)
            if res == 'confirm':
                confirm = 'confirm'
            elif res:
678
                luser.save()
Mathilde Espinasse's avatar
Mathilde Espinasse committed
679
                messages.success(request, _(u"""Déménagement effectué"""))
680
                return redirect(next)
681 682 683 684 685 686 687 688 689 690 691 692 693 694
        return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid, 'confirm' : confirm})

demenagement = DemenagementView.as_view()


class DeleteCompteView(CableurMixin, View):
    """
      Classe pour la suppression d'un compte
    """
    template_name = "compte/delete.html"
    def get(self, request, uid, ptype, *args, **kwargs):
        return render(request, self.template_name, {'ptype': ptype, 'ide': uid})

    def post(self, request, uid, ptype, confirm = "", *args, **kwargs):
Charlie Jacomme's avatar
Charlie Jacomme committed
695
        luser = get_luser(request, uid, ptype, 'w')
696 697 698
        for m in luser.machines():
            m.delete(login = request.user.username)
        luser.delete(login = request.user.username)
Mathilde Espinasse's avatar
Mathilde Espinasse committed
699
        messages.success(request, _(u"""Compte supprimé"""))
700
        return redirect(reverse('cablage:afficher'))
701 702 703


delete = DeleteCompteView.as_view()
704 705 706

class CreateCompteView(CableurMixin, View):
    """
707 708 709 710
        Classe pour la création d'un adherent au crans. Au premier affichage, on ne voit pas encore le formulaire de comptecrans.
        La hidden value step2 est ajouté dans ce cas au template. Lors du post, si on a step2
        on affiche le formulaire de comptecrans avec un login prégénéré grace
        au informations du premier forms.
711
    """
Charlie Jacomme's avatar
Charlie Jacomme committed
712 713
    form1 = NewCompteForm
    form2 = EmenagementForm
714
    template_name = "compte/create.html"
Charlie Jacomme's avatar
Charlie Jacomme committed
715
    def get(self, request, ptype, *args, **kwargs):
716
        return render(request, self.template_name, {'form1' : self.form1(), 'form2' : self.form2(), 'ptype' : ptype})
Charlie Jacomme's avatar
Charlie Jacomme committed
717 718 719 720

    def post(self, request, ptype, confirm = "",  *args, **kwargs):
        form1 = self.form1(data=request.POST)
        form2 = self.form2(data=request.POST)
721
        form3 = None
722
        comptecrans = False
723
        if form1.is_valid() and form2.is_valid():
724 725
            if 'comptecrans' in request.POST.keys():
                comptecrans = True
Charlie Jacomme's avatar
Charlie Jacomme committed
726 727 728 729 730
            if ptype == u"club":
                new_adherent = conn_pool.get_conn(request.user).newClub
            else:
                new_adherent = conn_pool.get_conn(request.user).newAdherent
            with new_adherent({}) as adherent:
731 732
                lconn =  conn_pool.get_conn(request.user)
                if 'step2' in request.POST.keys() and form1.apply(adherent):
733
                    if not form1.check_date():
Mathilde Espinasse's avatar
Mathilde Espinasse committed
734
                        messages.error(request, _(u"L'adhérent est mineur, merci de faire signer une décharge  par le responsable légal"))
Charlie Jacomme's avatar
Charlie Jacomme committed
735
                    form3 = ComptecransForm(ldap_user = adherent, ldap_conn=lconn, ptype =  ptype)
736 737 738
                else:
                    form3 = ComptecransForm(data=request.POST)
                    if form3.is_valid():
739 740 741
                        # Si ce n'est pas un club, on vérifie la présence d'un mail de contact
                        if not ptype==u"club":
                            if not form3.cleaned_data['login'] and not form1.cleaned_data['mail']:
Mathilde Espinasse's avatar
Mathilde Espinasse committed
742
                                messages.error(request, _(u"Il faut soit un mail extérieur soit un compte crans"))
743 744
                                return render(request, self.template_name, {'form1' : form1, 'form2' : form2, 'form3' : form3, 'confirm' : confirm, 'ptype' : ptype, 'comptecrans': comptecrans})
                        if form1.apply(adherent) and form3.apply(adherent):
745 746 747 748 749
                            res = form2.apply(adherent, confirm, lconn)
                            if res == 'confirm':
                                confirm = 'confirm'
                            elif res:
                                adherent.create()
Mathilde Espinasse's avatar
Mathilde Espinasse committed
750
                                messages.success(request, _(u"""Compte créé"""))
Charlie Jacomme's avatar
Charlie Jacomme committed
751 752 753
                                if ptype == u"club":
                                    uid = adherent['cid'][0]
                                    redir_url = reverse('compte:adhesion', args=(ptype, uid))
754
                                elif comptecrans:
Charlie Jacomme's avatar
Charlie Jacomme committed
755 756 757
                                    uid = adherent['aid'][0]
                                    adh_url = reverse('compte:adhesion', args=(ptype, uid))
                                    redir_url = reverse('compte:redirection', args=(uid, True, adh_url))
758 759 760
                                else:
                                    uid = adherent['aid'][0]
                                    redir_url = reverse('compte:adhesion', args=(ptype, uid))
761
                                if comptecrans:
Charlie Jacomme's avatar
Charlie Jacomme committed
762
                                    return redirect(reverse('compte:chgpass', args=(ptype, uid, redir_url)))
763
                                else:
Charlie Jacomme's avatar
Charlie Jacomme committed
764 765 766 767 768 769 770 771 772
                                    return redirect(redir_url)

        return render(request, self.template_name, {'form1' : form1, 'form2' : form2, 'form3' : form3, 'confirm' : confirm, 'ptype' : ptype, 'comptecrans': comptecrans})

    @method_decorator(login_required)
    def dispatch(self, request, ptype=u"adh", *args, **kwargs):
        if ptype == u"club":
            self.form1 = NewClubForm
        return super(CreateCompteView, self).dispatch(request, ptype=ptype, *args, **kwargs)
773 774

create = CreateCompteView.as_view()
775

776 777 778 779 780 781

#TODO:
# * proposer d'envoyer un email de réinitialisation à l'adhérent
# * rattraper OSError sur l'intranet de test à la tentative d'impression
#   de ticket

782
class ResetPassView(CableurMixin, RedirectHomeMixin, View):
783
    """
784 785
        Classe pour la réinitialisation du mot de passe et
        l'impression d'un ticket
786
    """
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
    template_name = "compte/resetpass.html"
    def get(self, request, uid, ptype, *args, **kwargs):
        user = get_luser(request, uid, ptype)
        return render(
            request,
            self.template_name,
            { 'user' : user },
        )

    def post(self, request, uid, next='/compte/', *args, **kwargs):
        # Si la réponse reçu n'est pas 'y' aka 'Yes' ou 'Oui'
        if not 'y' in request.POST:
            return redirect(next)
        #Sinon on continue
        #et on imprime un ticket
        subprocess.call([
            '/usr/scripts/cransticket/dump_creds.py',
            '--pass',
            '--forced',
            'aid=%s' % uid,
        ])
        messages.success(
            request,
            _(u"""Mot de passe réinitialisé, ticket en cours d'impression.""")
        )
812 813 814
        return redirect(next)

resetpass = ResetPassView.as_view()