whos.py 50 KB
Newer Older
1
#!/bin/bash /usr/scripts/python.sh
2
# -*- coding: utf-8 -*-
bernat's avatar
bernat committed
3

4
# Copyright (C) Frédéric Pauget
bernat's avatar
bernat committed
5
6
# Licence : GPLv2

7
8
u"""Ce script permet de recherche et d'afficher le détail d'une machine ou
d'un adhérent.
bernat's avatar
bernat committed
9
10
11

Usage: %(prog)s [options] <chaine de recherche>

12
13
La chaine de recherche peut être :
    * soit un terme unique, dans ce cas la recherche sera effectuée sur les
bernat's avatar
bernat committed
14
champs en bleu ci-dessous.
15
16
    * soit du type "champ1=valeur1&champ2!=valeur2 ...", les résultats seront
alors limités aux entrées correspondantes à tous les critères.
bernat's avatar
bernat committed
17

18
Les champs de recherche possibles sont :
bernat's avatar
bernat committed
19
%(champs_rech)s
20
21

Recherche sur prise possible (utiliser uniquement ce champ dans ce cas).
bernat's avatar
bernat committed
22

23
24
Les options de recherches sont :
   * limitations sur l'affichage :
25
        -a ou --adherent : limitation de l'affichage aux adhérents
26
27
28
29
        -m ou --machine : limitation de l'affichage aux machines
        -c ou --club : limitation de l'affichage aux clubs
        -b ou --bornes : limitation de l'affichage aux bornes wifi
        --crans : recherche uniquement les machines du crans
bernat's avatar
bernat committed
30
   * options d'affichage :
31
        -t ou --tech : affichages des infos techniques des machines
32
à la place des infos administratives dans les résumés.
33
        -i ou --ipsec : montre la clef wifi (anciennement ipsec) des machines wifi
34
        -l <num> ou --limit=<num> : limite du nombre de résultats pour utiliser
35
le mode d'affichage condensé au lieu du mode détaillé (défaut %(limit_aff_details)i)
bernat's avatar
bernat committed
36
        -L <num> ou --limit-historique=<num> : limitation du nombre de lignes
37
d'historique affichées (défaut %(limit_aff_historique)i)
38
39
        -d <num> ou --limit-blacklist=<num> : limitation du nombre de lignes
d'historique des déconnexions affichées (défaut %(limit_aff_blacklist)i)
40
        -s ou --ssh : affiche les fingerprint ssh des machines
41
42
        --servers : limite les résultats aux servers
        --adm : limite les résultats aux machines adm
43
        -6 ou --ipv6 : affiche les ipv6 dans l'affichage synthétique
bernat's avatar
bernat committed
44
45
"""

46
47
48
49
import commands
import getopt
import subprocess
import sys
50
from time import strftime, localtime, time
51
52

from affich_tools import *
53
from ldap_crans import is_actif, crans_ldap, AssociationCrans, hostname
54
from ldap_crans import MachineCrans, MachineWifi, BorneWifi
55
from ldap_crans import Adherent
56
from ldap_crans import datetimeFromGTF
57
58
from hptools import sw_chbre, ConversationError
import gestion.annuaires_pg as annuaires_pg
59
import gestion.config as config
60
import ridtools
61
62
63
import user_tests

base = None
bernat's avatar
bernat committed
64
65

limit_aff_details = 1
66
limit_aff_machines = 15
bernat's avatar
bernat committed
67
limit_aff_historique = 4
68
limit_aff_blacklist = 4
bernat's avatar
bernat committed
69
aff_ipsec = 0
70
aff_ssh = 0
71
aff_ipv6 = 0
bernat's avatar
bernat committed
72

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
################################################################################
### Fonctions utiles

def indicatif (num):
    """
    Sépare l'indicatif de nationalité du reste d'un numéro de téléphone
    """
    if num[0:2] != '00':
        return ('', num)
    if num[2] == '1':
        return ('1 '+num[3:6], num[6:])
    if num[2] in ['0','7']:
        return (num[2], num[3:])
    # indicatifs nationaux à 2 chiffres
    ids = [20, 27, 36, 86, 98]
88
89
90
91
92
93
94
    ids.extend(range(30, 35))
    ids.extend(range(39, 42))
    ids.extend(range(43, 50))
    ids.extend(range(51, 59))
    ids.extend(range(60, 67))
    ids.extend(range(81, 85))
    ids.extend(range(90, 96))
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    if int(num[2:4]) in ids:
        return (num[2:4], num[4:])
    return (num[2:5], num[5:])

def format_tel (num):
    """
    Formate un numéro de téléphone
        * Remplace un éventuel "00" au début par un "+"
        * Insère des espaces pour que ce soit lisible
    """
    res = ''
    (indic, reste) = indicatif(num)
    if indic != '':
        res += '+' + indic + ' '
    l = len(reste)
    if l%2 == 1:
        res += reste[0] + ' '
    for i in range(l%2,l,2):
        res += reste[i:i+2] + ' '
    return res

################################################################################

bernat's avatar
bernat committed
118
119
def aff(qqch,mtech=0) :
    """ Affichage de qqch.
120
    qqch peut être une liste d'instances des classes adhérent ou machine
121
    (un seul type dans la liste) dans ce cas :
122
        * si la longueur de la liste est inférieure à limit_aff_details
123
    affiche les propriétés détaillées de chaque élément.
124
125
        * sinon résume dans un tabeau des principales propriétés
    si qqch est une instance seul la traité comme une liste à une élément
126
    Si mtech = 1 affiches les infomations techniques des machines plutot
127
    qu'administratives dans le tableau des propriétés
128
    """
bernat's avatar
bernat committed
129
    if type(qqch) != list :
130
        qqch = [ qqch ]
131

bernat's avatar
bernat committed
132
    if len(qqch) > limit_aff_details :
133
        t = qqch[0].idn
134
135
        if t == 'aid':
            cprint(adhers_brief(qqch))
136
        elif t == 'mid':
137
138
139
140
141
142
            if mtech:
                cprint(list_machines(qqch))
            else:
                cprint(machines_brief(qqch))
        elif t == 'cid':
            cprint(clubs_brief(qqch))
143
144
        elif t == 'fid':
            cprint(factures_brief(qqch))
bernat's avatar
bernat committed
145
    else :
146
147
148
        i = 0
        for c in qqch :
            t = c.idn
149
            if i: cprint(u'='*80, 'cyan')
150
            i = 1
151
152
153
154
155
156
            if t == 'aid':
                cprint(adher_details(c).strip())
            elif t == 'mid':
                cprint(machine_details(c).strip())
            elif t == 'cid':
                cprint(club_details(c).strip())
157
158
            elif t == 'fid':
                cprint(facture_details(c).strip())
159

160
    # affiche le nombre de résultats
bernat's avatar
Totaux    
bernat committed
161
    if len(qqch) > 1:
162
        cprint(u"Total: %d" % len(qqch))
163

bernat's avatar
bernat committed
164
165
def adhers_brief(adhers) :
    """
166
    Formatage sous forme de tableau des infos sur la liste d'adhérent fournie :
167
        * aid
168
        * prénom nom
169
170
        * chambre
        * machines
bernat's avatar
bernat committed
171
    """
172
    data = []
glondu's avatar
glondu committed
173

174
    # Copie locale triée par (nom, prenom)
glondu's avatar
glondu committed
175
176
    adhers = adhers[:]
    adhers.sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom())))
177

glondu's avatar
glondu committed
178
    for a in adhers:
179
        ## État administratif
180
        ok = u'\x1b[1;32mo\x1b[1;0m'
181
        ook = u'\x1b[1;32mO\x1b[1;0m'
182
183
        nok = u'\x1b[1;31mn\x1b[1;0m'
        # Paiement
184
        if a.adhesion() > time():
185
186
            if 'p' in a.controle(): paid = ook
            else: paid = ok
187
        else: paid = nok
188

189
        machines = ''
190
        # Récupération des machines
191
192
193
194
        if len(adhers) <= limit_aff_machines:
            for machine in a.machines() :
                nom = machine.nom().split('.')[0]
                if machine.blacklist_actif() : k = 'rouge'
195
                elif isinstance(machine, MachineWifi): k = 'cyan'
196
197
198
199
200
                else : k= ''
                if machines : machines += ', ' + coul(nom,k)
                else : machines = coul(nom,k)
        else:
            machines = None
201
        # Données
202
        if len(adhers) <= limit_aff_machines:
203
            data.append([a.id(), a.Nom(), a.chbre(), paid, machines])
204
        else:
205
            data.append([a.id(), a.Nom(), a.chbre(), paid])
206

207
208
    if len(adhers) <= limit_aff_machines:
        return u"Machines en rouge = machines avec limitation de services\n" + \
209
210
               u"P : paiement année en cours, le fond vert indique le précâblage (G bleu = inscription gratuite)\n" + \
               u"C : carte d'étudiant année en cours\n" + \
211
               tableau(data,
212
213
214
                       titre = [u'aid', u'Prénom Nom', u'Chbre', u'P', u'Machines'],
                       largeur = [5, 30, 5, 1, '*'],
                       alignement = ['d', 'c', 'g', 'c', 'c'])
215
216
    else:
        return u"Machines en rouge = machines avec limitation de services\n" + \
217
218
               u"P : paiement année en cours, le fond vert indique le précâblage (G bleu = inscription gratuite)\n" + \
               u"C : carte d'étudiant année en cours\n" + \
219
               tableau(data,
220
221
222
                       titre = [u'aid', u'Prénom Nom', u'Chbre', u'P'],
                       largeur = [5, '*', 5, 1],
                       alignement = ['d', 'c', 'g', 'c'])
223

bernat's avatar
bernat committed
224
225
def machines_brief(machines) :
    """
226
    Formatage sous forme d'un tableau des propriétés de la liste de machine :
227
        * mid
228
229
        * rid
        * type (serveur, adm, fil, wifi, adm, borne)
230
231
232
        * nom
        * adresse IP
        * adresse MAC
233
        * si blacklistée
bernat's avatar
bernat committed
234
    """
235
    data = []
glondu's avatar
glondu committed
236

237
    # Copie locale triée par nom
glondu's avatar
glondu committed
238
239
    machines = machines[:]
    machines.sort(lambda x, y: cmp(x.nom(), y.nom()))
240

bernat's avatar
bernat committed
241
    for m in machines :
242
        t, bl = __bases_machines(m)
243

244
        # Propriétaire
245
246
        a = m.proprietaire()
        p = a.Nom()
247

248
        # A jour administrativement
249
        if not a.paiement_ok():
250
            p = coul(p,'rouge')
251

252
        # Données
253
        data.append([m.id(), m.rid() , t, m.nom().split('.')[0], p, a.chbre(), bl])
254

255
    return u"Le propriétaire en rouge signale un problème administratif, en bleu une inscription gratuite\n" + \
256
            tableau(data,
257
258
259
                    titre = [u'mid', u'rid', u'Type', u'Nom de machine', u'Propriétaire', u'Chbre', u'Limitation'],
                    largeur = [5, 5, 13, 18, '*', 5, 10],
                    alignement = ['d', 'd', 'c', 'c', 'c', 'g', 'c'])
bernat's avatar
bernat committed
260

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
def factures_brief(factures) :
    """
    Formatage sous forme d'un tableau des propriétés de la liste de machine :
        * fid
        * priorio
        * articles
        * modePaiement
        * recuPaiement
        * controle
        * total
    """
    data = []

    # Copie locale triée par nom
    factures = [] + factures
    factures.sort(lambda x, y: cmp(int(x.id()), int(y.id())))

    for facture in factures:
        # Propriétaire
        a = facture.proprietaire()
        p = a.Nom()

        # Contrôle
        controle = facture.controle()
        if controle == "TRUE":
286
            controle = coul(u"Validée", "vert")
287
        elif controle == "FALSE":
288
            controle = coul(u"Invalide", "rouge")
289
        else:
290
            controle = u"N/A"
291
292
293
294
295
296

        # Données
        data.append([
            facture.id(),
            p,
            facture.modePaiement(),
297
            coul(datetimeFromGTF(facture.recuPaiement()).strftime("%d/%m/%Y %H:%M:%S"), "vert") if facture.recuPaiement() else coul("NON", "rouge"),
298
            controle,
299
            ', '.join(article['code'] for article in facture.articles()),
300
301
302
303
304
            unicode(facture.total()) + u" €",
            ])

    return u"Le propriétaire en rouge signale un problème administratif.\n" + \
        tableau(data,
305
306
            titre = [u'fid', u'Propriétaire', u'Mode de paiement', u'Reçu', u"Contrôle", u'Articles', u"Total"],
            largeur = [5, 18, 8, 19, 10, '*', 8],
307
308
309
            alignement = ['d', 'g', 'g', 'c', 'c', 'g', 'd']
        )

bernat's avatar
bernat committed
310
311
312
def clubs_brief(clubs) :
    """
    Formatage sous forme de tableau des infos sur la liste de clubs fournie :
313
314
315
316
        * cid
        * nom
        * local
        * machines
bernat's avatar
bernat committed
317
    """
318
    data = []
glondu's avatar
glondu committed
319

320
    # Copie locale triée par Nom
glondu's avatar
glondu committed
321
322
    clubs = clubs[:]
    clubs.sort(lambda x, y: cmp(x.Nom(), y.Nom()))
323

bernat's avatar
bernat committed
324
    for c in clubs :
325
        ## État administratif
326
        ok = u'\x1b[1;32mo\x1b[1;0m'
327
        ook = u'\x1b[1;32mO\x1b[1;0m'
328
329
        nok = u'\x1b[1;31mn\x1b[1;0m'
        # Paiement
330
331
332
333
334
        if c.paiement_ok():
            # TODO
            #if 'p' in c.controle(): paid = ook
            #else: paid = ok
            paid = ok
335
        else : paid = nok
336

337
        # Précablage
338
        # TODO
339

340
        machines = ''
341
        # Récupération des machines
342
343
344
345
346
347
        for machine in c.machines() :
            nom = machine.nom().split('.')[0]
            if machine.blacklist_actif() : k = 'rouge'
            else : k= ''
            if machines : machines += ', ' + coul(nom,k)
            else : machines = coul(nom,k)
348

349
        # Responsable
350
351
352
353
        try:
            resp = c.responsable().Nom()
        except ValueError, e:
            resp = e
354

355
        # Données
356
        data.append([c.id() , c.Nom(), c.local(), paid, resp, machines])
357

bernat's avatar
bernat committed
358
    return u"Machines en rouge = machines avec limitation de services\n" + \
359
           u"P : signature charte année en cours, le fond vert indique le précâblage\n" + \
360
361
362
363
           tableau(data,
                   titre = [u'cid', u'Nom ', u'Local', u'P', u'Responsable', u'Machines'],
                   largeur = [5, '*', 6, 1, 21, 15],
                   alignement = ['d', 'c', 'g', 'c', 'c', 'c'])
bernat's avatar
bernat committed
364

365

bernat's avatar
bernat committed
366
367
def list_machines(machines) :
    """
368
    Formatage sous forme d'un tableau des propriétés de la liste de machine :
369
370
371
372
373
        * mid
        * type (fixe ou wifi)
        * nom
        * adresse IP
        * adresse MAC
374
        * si blacklistée
bernat's avatar
bernat committed
375
    """
376
    data = []
bernat's avatar
bernat committed
377

378
    # Copie locale triée par nom
glondu's avatar
glondu committed
379
380
381
    machines = machines[:]
    machines.sort(lambda x, y: cmp(x.nom(), y.nom()))

bernat's avatar
bernat committed
382
    for m in machines :
383
        t, bl = __bases_machines(m)
384

385
        # Données
386
387
388
389
390
391
        if not aff_ipv6:
            data.append([m.id(), m.rid(), t, m.nom().split('.')[0], m.ip(), m.mac(), bl])
            larg = 15
        else:
            larg = 22
            data.append([m.id(), m.rid(), t, m.nom().split('.')[0], m.ipv6(), m.mac(), bl])
392

393
    return tableau(data,
394
                titre = [u'mid', u'rid', u'Type', u'Nom de machine', u'Adresse IP', u'Adresse MAC', u'Limitation'],
395
                largeur = [5, 5, 9, '*', larg, 17, 10],
396
                alignement = ['d', 'd', 'c', 'c', 'c', 'c', 'c'])
bernat's avatar
bernat committed
397

398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
def list_factures(factures) :
    """
    Formatage sous forme d'un tableau des propriétés de la liste de facture :
        * fid
        * mode de paiement
        * payé
        * codes article
        * total
    """
    data = []

    # Copie locale triée par fid
    factures = factures[:]
    factures.sort(lambda x, y: cmp(x.id(), y.id()))

    for f in factures :
414
415
        controle = f.controle()
        if controle == "TRUE":
416
            controle = coul(u"Validée", "vert")
417
        elif controle == "FALSE":
418
            controle = coul(u"Invalide", "rouge")
419
        else:
420
            controle = u"N/A"
421
422
423
        data.append([
           f.id(),
           f.modePaiement(),
Pierre-Elliott Bécue's avatar
Typo    
Pierre-Elliott Bécue committed
424
           coul(datetimeFromGTF(f.recuPaiement()).strftime("%d/%m/%Y %H:%M:%S"), "vert") if f.recuPaiement() else coul("NON", "rouge"),
425
           controle,
426
427
428
429
430
           ', '.join(a['code'] for a in f.articles()),
           u"%s€" % sum([float(a['pu'])*int(a['nombre']) for a in f.articles()])
        ])

    return tableau(data,
431
432
                titre = [u'fid', u'Mode de paiement', u'Reçu', u"Contrôle", u'Articles', u"Total"],
                largeur = [5, 16, 19, 10, '*', 8],
433
                alignement = ['d', 'g', 'c', 'c', 'g', 'd'])
434

435
def list_spec(machines) :
bernat's avatar
bernat committed
436
    """
437
    Formatage sous forme d'un tableau des propriétés de la liste de machines spéciales :
438
        * mid
439
        * rid
440
        * nom
441
        * adresse IPv4/IPv6
442
        * adresse MAC
443

444
445
446
447
448
449
450
        Pour les bornes :
            * État
            * puissance
            * canal
            * lieu (la première remarque en fait)
        Pour le reste :
            * ??
bernat's avatar
bernat committed
451
    """
452
    data = []
bernat's avatar
bernat committed
453

454
    # Copie locale triée par nom
455
456
    machines = machines[:]
    machines.sort(lambda x, y: cmp(x.nom(), y.nom()))
glondu's avatar
glondu committed
457

458
    for b in machines:
459
        t, bl = __bases_machines(b)
460

461
        # Données
462
463
464
465
466
467
468
        if t == 'borne':
            try :
                l = [x for x in b.info() if not x[0]=='<'][0]
                if len(l) > 11 :
                    l = l[0:11]
            except :
                l = u'????'
469

470
471
472
473
474
475
476
477
478
479
480
481
482
            if '-' in b.puissance() :
                puiss = coul(b.puissance(),'rouge')
            else :
                puiss = b.puissance()

            if aff_ipv6:
                data.append([b.id(), b.rid(), b.nom().split('.')[0], b.ipv6(), b.mac(), b.canal(), puiss, b.prise(), l])
            else:
                data.append([b.id(), b.rid(), b.nom().split('.')[0], b.ip(), b.mac(), b.canal(), puiss, b.prise(), l])

            titre = [u'mid', u'rid', u'Nom', u'Adresse IP', u'Adresse MAC', u'Can', u'P', u'Pris', u'Lieu']
            largeur = [5, 5, 16, 22, 17, 1, 5, 3, 4, '*']
            alignement = ['d', 'd', 'c', 'c', 'c', 'c', 'c', 'c', 'g', 'c']
483

484
        else:
485
486
487
488
            if aff_ipv6:
                data.append([b.id(), b.rid(), t, b.nom().split('.')[0], b.ipv6(), b.mac()])
            else:
                data.append([b.id(), b.rid(), t, b.nom().split('.')[0], b.ip(), b.mac()])
489

490
491
492
493
494
495
496
            titre = [u'mid', u'rid', u'Type', u'Nom', u'Adresse IP', u'Adresse MAC']
            largeur = [5, 5, 10, 20, '*', 17]
            alignement = ['d', 'd', 'd', 'c', 'c', 'c']

    output = tableau(data, titre=titre, largeur=largeur, alignement=alignement)

    return output
bernat's avatar
bernat committed
497
498
499

def adher_details(adher) :
    """
500
    Affichage du détail des propriétés d'un adhérent
bernat's avatar
bernat committed
501
    """
502
    f=u''
bernat's avatar
bernat committed
503
504
505
506
    # Aid
    f+= coul(u'aid=%s   ' % adher.id() ,'bleu')
    # Nom, prenom
    f += coul(u'Nom : ','gras') + "%s\n" % adher.Nom()
507

bernat's avatar
bernat committed
508
    # Mail
chove's avatar
chove committed
509
    GL = RMH = u''
510
    if adher.mail() == '' or adher.compte() == '':
511
        f += coul(u'Adresse mail : ','gras')
512
513
514
        if adher.mail() == '':
            f += coul('INCONNUE','rouge')
        elif adher.mail_invalide():
salles's avatar
Typos    
salles committed
515
            f += coul(adher.mail(),'rouge')
516
517
518
        else:
            f += adher.mail()
        f += "\n"
bernat's avatar
bernat committed
519
    else :
520
521
        f += coul(u'Login : ','gras')
        if adher.mail_invalide():
522
            f += coul(adher.compte(),'rouge')
523
        else:
524
            f += adher.compte()
525
526
        if not adher.active():
            f += " " + coul(u"(Compte désactivé)", "rouge")
527
        f += "\t"
528
529
530
        # controurneGreylisting
        if not adher.contourneGreylist():
            GL = u' (%s)'%coul(u'GreyList','gris')
chove's avatar
chove committed
531
        if adher.rewriteMailHeaders():
532
            RMH = u' (%s)'%coul(u'réécriture en-têtes mail','gris')
533

534
        alias = u', '.join([adher.canonical_alias()] + adher.alias())
535
        if alias:
536
            if alias[0] == u',':
537
                # Canonical étéait vide
538
539
540
541
542
                alias = alias[2:]
            f += coul(u'Alias : ','gras') + alias
        f += GL
        f += RMH
        f += u'\n'
543
544
545
546
547
        if adher.email_exterieur():
            f += coul(u'Mail extérieur : ', 'gras')
            f += adher.email_exterieur()
            f += u'\n'
        # Réservé aux comptes Crans.
548
549
        if len(adher.gpgFingerprint()) > 0:
            f += u"\n".join([coul(u'Fingerprint GPG : ', 'gras') + u"%s" % (i) for i in adher.gpgFingerprint()])+"\n"
550
        try:
551
            forward = file(os.path.join(adher.home(), ".forward")).readlines()
552
            if len(forward) > 1:
553
                forward = forward[0].strip() + u" ...\n"
554
            elif len(forward) == 1:
555
                forward = forward[0].strip() + u"\n"
556
557
558
            if forward:
                f += coul(u'Redirection : ', 'gras') + forward
        except IOError, e:
559
            # Pas de .forward, ou .forward privé... on laisse tomber
560
            pass
561
        f += coul(u'Dernière connexion : ', 'gras')
562
563
564
565
566
567
        timestamp = adher.derniereConnexion()
        if timestamp == 0:
            f += coul(u'Jamais', 'rouge')
        else:
            f += coul(strftime('%d/%m/%Y %H:%M', localtime(timestamp)),
                      time()-timestamp > 32*24*3600 and 'rouge' or '')
glondu's avatar
glondu committed
568
        f += u"\n"
bernat's avatar
bernat committed
569

570
    # État administratif
571
    f += coul(u"Date d'inscription : ", "gras")
572
    f += strftime('%d/%m/%Y %H:%M:%S', localtime(adher.dateInscription()))
573
    f += coul(u'\nÉtat administratif : ','gras')
574
    jour = True
575
    if adher.adhesion() <= time():
576
        if not jour: f += ' et '
577
578
579
580
        f += coul(u"non adhérent actuellement",'violet')
        jour = False
    if not adher.paiement_ok():
        if not jour: f += ' et '
Pierre-Elliott Bécue's avatar
Pierre-Elliott Bécue committed
581
        f += coul(u"pas d'accès Internet ", "violet")
582

583
    if jour:
584
        f += coul(u"à jour",'vert')
585
    f += "\n"
586

bernat's avatar
bernat committed
587
588
    # Telephone
    tel = adher.tel()
pauget's avatar
pauget committed
589
    if tel != 'inconnu' :
590
        f += coul(u'Numéro de téléphone : ','gras') + "%s\n" % format_tel(tel).ljust(12)
591

bernat's avatar
bernat committed
592
593
594
    # Adresse
    chbre = adher.chbre()
    if chbre == 'EXT' :
595
        # Adhérent extérieur
596
        addr = adher.adresse()
597
        if addr[0] :
598
599
600
601
            f += coul(u'Adresse : ','gras')
            f += addr[0] + u'\n'
            if addr[1] != ' ' : f += u'          ' + addr[1] + u'\n'
            f+= u'          ' + addr[2] + u' ' + addr[3] + '\n'
602
603
    elif chbre == '????' :
        f += coul(u'Chambre invalide\n','violet')
bernat's avatar
bernat committed
604
    else :
605
        # Chambre + prise (d'après annuaire)
606
        etat, vlans, cablage = prise_etat(adher.chbre())
607
        f += coul(u'Chambre : ','gras') + u"%s " % chbre
608
        f += u'(%s)' % etat
609
        f += u'\n'
Xavier Lagorce's avatar
Xavier Lagorce committed
610
611
612
613
        # VLAN
        if vlans :
            f += coul(u'VLAN : ','gras') + u'%s' % vlans
            f += u'\n'
614

615
    # Études
bernat's avatar
bernat committed
616
    if adher.etudes(1).isdigit() :
617
        f += coul(u'Études : ','gras')+ "%s %s%s\n" % \
618
        ( adher.etudes(0), adher.etudes(1), adher.etudes(2) )
pauget's avatar
pauget committed
619
    elif adher.etudes(0) :
620
        f += coul(u'Études : ','gras')+ "%s %s %s\n" % \
621
        ( adher.etudes(0), adher.etudes(1), adher.etudes(2) )
622

623
624
625
    # Solde
    solde = adher.solde()
    if solde :
626
627
628
629
630
631
        f += coul(u'Solde : ','gras')
        if solde < 0 :
            f+= coul(str(solde).replace('.',','),'rouge')
        else :
            f += str(solde).replace('.',',')
        f += u" Euros\n"
632

bernat's avatar
bernat committed
633
    # Role dans l'assoce
634
635
    d = adher.droits()
    if d :
636
        f += coul(u"Droits sur les serveurs : ",'gras') + ', '.join(d)
bos's avatar
bos committed
637
        if adher.droitsGeles():
638
            f +=  coul(u" (droits gelés car pas cotisé cette année)",'bleu')
639
        f += u'\n'
640

641
642
643
644
    # Adhésion
    if adher.adhesion() > time():
        f += coul(u"Adhésion jusqu'au %s" % strftime("%d/%m/%Y %H:%M:%S", localtime(adher.adhesion())), "vert")
        f += u"\n"
645
    elif config.periode_transitoire and (config.debut_periode_transitoire <= min(adher.adhesion(), adher.connexion()) <= config.fin_periode_transitoire):
646
        f += coul(u"Fin d'adhésion, mais en sursis jusqu'au %s" % (strftime("%d/%m/%Y %H:%M:%S", localtime(config.fin_periode_transitoire)),), "rouge")
647
        f += u"\n"
648

bernat's avatar
bernat committed
649
    # Paiement
650
    if adher.connexion() > time():
651
        f += coul(u"Connexion jusqu'au %s" % strftime("%d/%m/%Y %H:%M:%S", localtime(min(adher.connexion(), adher.adhesion()))), "vert")
652
653
        if adher.adhesion() < adher.connexion():
            f += coul(u"(Théoriquement %s, sous réserve de réadhésion)" % (strftime("%d/%m/%Y %H:%M:%S", localtime(adher.connexion())),), "rouge")
654
        f += u'\n'
bernat's avatar
bernat committed
655
656
657
658

    f += _blacklist(adher)
    f += _info(adher)
    f += _hist(adher)
659

bernat's avatar
bernat committed
660
661
662
663
    # Formatage des machines aussi
    f += coul(u'Machine(s) : ','gras')
    m = adher.machines()
    if m :
664
        f += u'\n' + list_machines(m)
bernat's avatar
bernat committed
665
    else :
666
        f += u'aucune'
bernat's avatar
bernat committed
667

668
669
670
671
672
673
674
675
    f += u"\n"
    f += coul(u'Facture(s) : ','gras')
    m = adher.factures()
    if m :
        f += u'\n' + list_factures(m)
    else :
        f += u'aucune'

bernat's avatar
bernat committed
676
    return f
bernat's avatar
bernat committed
677

678
679
680
681
682
683
684
def facture_details(facture) :
    """
    Affichage du détail des propriétés d'une facture
    """

    controle = facture.controle()
    if controle == "TRUE":
685
        controle = coul(u"Validée", "vert")
686
    elif controle == "FALSE":
687
        controle = coul(u"Invalide", "rouge")
688
    else:
689
        controle = u"N/A"
690
691
692
693
694

    f=u''
    # Fid
    f+= coul(u'fid=%s   ' % facture.id() ,'bleu')
    # Proprio
695
    f += coul(u'Proprio : ','gras') + "%s (%s %s)\n" % (facture.proprietaire().Nom(), facture.proprietaire().idn, facture.proprietaire().id())
696
697
698
699
700

    # Articles
    f += coul(u"Articles :", "gras") + u"\n"
    f += list_articles(facture)
    f += u"\n"
701
702
    f += coul(u"Total : ", "gras") + u"%s €" % facture.total()
    f += "\n"
703
704
705
706
707
708

    # Mode de paiement
    f += coul(u"Mode de paiement : ", "gras")
    f += facture.modePaiement()
    f += u"        "
    f += coul(u"Paiement reçu : ", "gras")
709
    f += coul(datetimeFromGTF(facture.recuPaiement()).strftime("%d/%m/%Y %H:%M:%S"), "vert") if facture.recuPaiement() else coul(u"Non", "rouge")
710
711
712
    f += u"\n"
    f += coul(u"Contrôle : ", "gras")
    f += controle
713
714
    f += u"\n"
    f += _hist(facture)
715
716
717
718
719
720
721
722
723
724
725
726

    return f

def list_articles(facture):
    """Liste en détail des articles d'une facture

    """

    data = [[article['code'], article['designation'], article['nombre'], article['pu']] for article in facture.articles()]

    return tableau(data,
                titre = [u'Code', u'Désignation', u'Nombre', u"Prix unitaire"],
727
                largeur = [10, '*', 10, 13],
728
729
730
                alignement = ['c', 'g', 'c', 'c'])


bernat's avatar
bernat committed
731
732
clients_ipsec = None
def ipsec_ok(machine) :
733
    """Indique si une machine est correctement authentifiée"""
734
    return False
735

bernat's avatar
bernat committed
736
def machine_details(machine) :
737
    """
738
    Formatage du détail des propriétés d'une machine
bernat's avatar
bernat committed
739
740
741
    """
    f = ''
    f+= coul(u'mid=%s   ' % machine.id(),'bleu')
742

bernat's avatar
bernat committed
743
    # Type de machine
glondu's avatar
glondu committed
744
    if isinstance(machine, MachineWifi): a = 'Machine wifi'
glondu's avatar
glondu committed
745
746
747
    elif isinstance(machine, BorneWifi): a = 'Borne wifi'
    else: a = 'Machine fixe'
    f += coul(a + ' : ', 'gras')
748

Pierre-Elliott Bécue's avatar
Pierre-Elliott Bécue committed
749
750
751
    f+= "%s   " % machine.nom()

    if machine.rid() != '':
752
        f+= coul(u'rid=%s    '% machine.rid(), 'bleu')
Pierre-Elliott Bécue's avatar
Pierre-Elliott Bécue committed
753
754

    f+= "\n"
755

bernat's avatar
bernat committed
756
757
    # Alias ?
    alias = machine.alias()
758
    if alias :
759
760
        f += coul(u'Alias : ' ,'gras') + ', '.join(alias)
        f+= '\n'
761

bernat's avatar
bernat committed
762
763
    f+= coul(u'IP : ','gras') + "%s\t\t" %machine.ip()
    f+= coul(u'MAC : ','gras') + "%s\n" %machine.mac()
764
765
    if machine.ipv6() != None:
        f+= coul(u'IPv6 : ','gras') + "%s\n" %machine.ipv6()
766

767
768
769
    if len(machine.sshFingerprint()) > 0 and aff_ssh:
        f += u"\n".join([coul(u'Fingerprint SSH : ', 'gras') + u"%s" % (i) for i in machine.sshFingerprint()])+"\n"

770
771
    # Propriétaire
    f+= coul(u'Propriétaire : ','gras')
772
    try :
773
        f += machine.proprio + coul(' (adhérent détruit)', 'jaune')
glondu's avatar
glondu committed
774
        a = AssociationCrans()
775
    except :
776
777
        a = machine.proprietaire()
        f += "%s" % a.Nom()
778
        if a.chbre() in ['EXT', '????']:
779
            f += ' (%s = %s)' % (a.idn, a.id())
780
        elif a.chbre() != 'CRA':
781
782
783
            f += " (%s)" % a.chbre()
        else :
            f += coul(u'\t\tPrise : ','gras') + machine.prise()
bernat's avatar
bernat committed
784
    f+= '\n'
785

786
787
788
789
790
    if isinstance(machine, MachineCrans):
        n = machine.nombrePrises()
        if n >= 0:
            f += coul(u'Nombre de prises : ', 'gras')
            f += "%d\n" % n
bernat's avatar
bernat committed
791

792
    # Adhérent blacklisté ?
793
    bl = a.blacklist_actif()
bernat's avatar
bernat committed
794
    if bl :
795
        f += coul(u'Restrictions sur adhérent : ','gras')
796
797
        f +=  coul(u', '.join(bl),'rouge')
        f += '\n'
798

bernat's avatar
bernat committed
799
    # Borne wifi
glondu's avatar
glondu committed
800
    if isinstance(machine, BorneWifi):
glondu's avatar
glondu committed
801
        f += coul(u'Hotspot : ', 'gras')
glondu's avatar
glondu committed
802
803
804
        f += machine.hotspot() and 'oui' or 'non'
        position = machine.position()
        if position:
805
806
            f += coul(u'\t\t\tCoordonnées : ', 'gras')
            f += u'%s°N, %s°E\n' % position
glondu's avatar
glondu committed
807
        else:
glondu's avatar
glondu committed
808
            f += '\n'
809
810

        if (machine.prise() != 'N/A'):
811
812
813
814
            try:
                f += coul(u'VLANs : ', 'gras')
                from hptools import sw_prise
                f += ', '.join(sw_prise(machine.prise()).vlans())
815
                f += '\n'
816
817
            except:
                pass
818

819
820
        f += coul(u'Puissance : ','gras') + u"%4.d" % int(machine.puissance())
        f += coul(u'\tCanaux : ', 'gras') + machine.canal()
821
        f += coul(u'\tÉtat : ', 'gras')
822
823
        if borne_etat(machine.nom()):
            f += coul(u'borne active', 'vert')
824
            f += '\n'
825
826
827
828
829
            canal_clients = borne_clients_canal(machine.nom())
            clients = canal_clients["mac-rssi"]
            canal = canal_clients["canal"]
            f += coul(u'\t         Canal courant : ', 'gras') + u"%d" % canal
            f += "\n"
glondu's avatar
glondu committed
830
            # S'il y a des clients, on les liste
831
832
833
            if clients and base:
                f += coul(u'Clients : \n','gras')
                for (client, rssi) in clients:
834
                    # On va chercher le nom correspondant à l'adresse MAC
835
                    res = base.search("mac=%s" % client)['machine']
bernat's avatar
bernat committed
836
                    authentification=""
837
838
                    if not res:
                        client_nom = '????'
dubost's avatar
Bug    
dubost committed
839
                        client_chbre = '????'