Compare commits
296 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1637a4aae4 | ||
![]() |
93d505745c | ||
![]() |
7b26e38606 | ||
![]() |
fe6f71acbc | ||
![]() |
cf76003c1f | ||
![]() |
16777e3914 | ||
![]() |
a1256091b3 | ||
![]() |
346861139c | ||
![]() |
8f715ff771 | ||
![]() |
525c77c2ce | ||
![]() |
0918366bb8 | ||
![]() |
fdca02be27 | ||
![]() |
229cd97fce | ||
![]() |
e7ba95b36d | ||
![]() |
3418dbb1b1 | ||
![]() |
450f6c49aa | ||
![]() |
daedb2b657 | ||
![]() |
8c00727456 | ||
![]() |
e67b3be24b | ||
![]() |
5e5a819b47 | ||
![]() |
4dd908e746 | ||
![]() |
69bff1c2da | ||
![]() |
baf79bdda7 | ||
![]() |
af0e971764 | ||
![]() |
14167847db | ||
![]() |
8b86e04dba | ||
![]() |
cc0b6bf013 | ||
![]() |
9ea84a34bc | ||
![]() |
cb0fda8c6c | ||
![]() |
023b354848 | ||
![]() |
bb0bedf1fd | ||
![]() |
b9bd5ab1fc | ||
![]() |
46b5aca99f | ||
![]() |
bbcd49c88c | ||
![]() |
4279b3db23 | ||
![]() |
565a2ae8ed | ||
![]() |
f52422622a | ||
![]() |
e16ff77675 | ||
![]() |
77ca50c48c | ||
![]() |
ad8846920e | ||
![]() |
09497c7c7a | ||
![]() |
20ddcb12bc | ||
![]() |
730db0107e | ||
![]() |
d989c9966c | ||
![]() |
8647650078 | ||
![]() |
dba410ceaf | ||
![]() |
b36b5ba2ce | ||
![]() |
73617312b8 | ||
![]() |
1eed679e40 | ||
![]() |
28cfce0916 | ||
![]() |
f943cf52a6 | ||
![]() |
9bfe935522 | ||
![]() |
43cdcc9c6f | ||
![]() |
e2141e1043 | ||
![]() |
19b13c39d7 | ||
![]() |
9194364ad0 | ||
![]() |
b88ba2a34f | ||
![]() |
ef95c2b159 | ||
![]() |
fc1b2c0edf | ||
![]() |
310356eba9 | ||
![]() |
06d97c9aa3 | ||
![]() |
51c0140dfb | ||
![]() |
e4a36fb702 | ||
![]() |
182597ca35 | ||
![]() |
f6609980fc | ||
![]() |
df4d564ffb | ||
![]() |
6f52c57431 | ||
![]() |
f4e5ce3104 | ||
![]() |
d58b92b957 | ||
![]() |
22bf89eef0 | ||
![]() |
b552af7739 | ||
![]() |
246cba6107 | ||
![]() |
b14847c625 | ||
![]() |
079831f5f3 | ||
![]() |
f975e60636 | ||
![]() |
b2f1f9c038 | ||
![]() |
712b256943 | ||
![]() |
7a9dd65698 | ||
![]() |
fbe99ab65c | ||
![]() |
d49c87b6c3 | ||
![]() |
32e4416687 | ||
![]() |
2860fe931c | ||
![]() |
6d4f6b0864 | ||
![]() |
44361f86ce | ||
![]() |
196bc1db68 | ||
![]() |
7d8f7c79ca | ||
![]() |
f3186853ec | ||
![]() |
1969b7909b | ||
![]() |
99003ebaf3 | ||
![]() |
e4c2a6e3bd | ||
![]() |
26a82dbb92 | ||
![]() |
abaea5ee8d | ||
![]() |
53bddc87b2 | ||
![]() |
d7c15ab14b | ||
![]() |
a527a6f394 | ||
![]() |
9f7c8ceaf3 | ||
![]() |
af9d15bcc6 | ||
![]() |
955dd379c7 | ||
![]() |
6ae6e54101 | ||
![]() |
ba6baa40dc | ||
![]() |
50415d4a90 | ||
![]() |
d4f67daea0 | ||
![]() |
a732024852 | ||
![]() |
ade4a9d82e | ||
![]() |
e7ba8c346d | ||
![]() |
22a05d3e1d | ||
![]() |
e2b8fd08f8 | ||
![]() |
588eba0515 | ||
![]() |
ef0e8bb22e | ||
![]() |
3dd845d333 | ||
![]() |
ea4d25f597 | ||
![]() |
5c6386abae | ||
![]() |
5b8ad633b3 | ||
![]() |
7aa2b6b688 | ||
![]() |
6a51e0c520 | ||
![]() |
ed91745fec | ||
![]() |
a363b6927d | ||
![]() |
947047dea0 | ||
![]() |
e46f6ba4d8 | ||
![]() |
c700ec4c03 | ||
![]() |
c5c903b114 | ||
![]() |
6da84bbfd1 | ||
![]() |
ca77b3defa | ||
![]() |
87382fbf6f | ||
![]() |
4d7585574f | ||
![]() |
1df6eb37f5 | ||
![]() |
2c1674038e | ||
![]() |
13555c735d | ||
![]() |
31f21003e7 | ||
![]() |
bd4403d8ee | ||
![]() |
cb2a389077 | ||
![]() |
1a06bcf4f9 | ||
![]() |
86991c6f5f | ||
![]() |
553b5f39ce | ||
![]() |
d8d31462f7 | ||
![]() |
5271e51f30 | ||
![]() |
de8832a3f9 | ||
![]() |
87d971ac7e | ||
![]() |
3abcb7b144 | ||
![]() |
c2a21b8756 | ||
![]() |
52a4cefdb5 | ||
![]() |
98b591978c | ||
![]() |
c653f97c03 | ||
![]() |
4624363443 | ||
![]() |
467565b90f | ||
![]() |
5bb370bffb | ||
![]() |
1e769cc9a9 | ||
![]() |
0492338bf8 | ||
![]() |
9e934c2e8c | ||
![]() |
9507536d3e | ||
![]() |
fbf76bec6b | ||
![]() |
59186fe37e | ||
![]() |
43d6795b53 | ||
![]() |
1d7b04a264 | ||
![]() |
4b165cef91 | ||
![]() |
16bc0eab01 | ||
![]() |
b53a92b2a7 | ||
![]() |
4e10e930cd | ||
![]() |
e7aa590314 | ||
![]() |
c9b3198e26 | ||
![]() |
587b76d930 | ||
![]() |
4915d64e90 | ||
![]() |
80fff2f826 | ||
![]() |
de52de5059 | ||
![]() |
94185a8f81 | ||
![]() |
062114d4ea | ||
![]() |
1262b47fb3 | ||
![]() |
96a8ceca8d | ||
![]() |
18d6e674f1 | ||
![]() |
11b2586819 | ||
![]() |
be8247667f | ||
![]() |
9c89e7af0a | ||
![]() |
ecbe29d3fb | ||
![]() |
fe9f69d19a | ||
![]() |
4ee1ea55d1 | ||
![]() |
1c675f251c | ||
![]() |
fe37e87532 | ||
![]() |
f1bcfde617 | ||
![]() |
29cb2a38f1 | ||
![]() |
f527a12064 | ||
![]() |
4874b2eebc | ||
![]() |
e2eb01f2aa | ||
![]() |
d57588e313 | ||
![]() |
dd1178d7d3 | ||
![]() |
13b7bfd936 | ||
![]() |
55aac0e164 | ||
![]() |
85f9ea46bb | ||
![]() |
7c2543d90e | ||
![]() |
7ed5d5e829 | ||
![]() |
394597c186 | ||
![]() |
c035723e54 | ||
![]() |
6f21fde1ea | ||
![]() |
628036e8da | ||
![]() |
6913629672 | ||
![]() |
f77a73218d | ||
![]() |
72bde6ca25 | ||
![]() |
b10d2d1e95 | ||
![]() |
b949b42364 | ||
![]() |
00d67f1fc3 | ||
![]() |
5a7e367e9c | ||
![]() |
037ecab023 | ||
![]() |
82b8fea9da | ||
![]() |
2a5c273b2c | ||
![]() |
a3c3290a26 | ||
![]() |
241b760921 | ||
![]() |
8c41ce5a5b | ||
![]() |
3944441033 | ||
![]() |
395db97395 | ||
![]() |
6161a4bc32 | ||
![]() |
3f70d1b825 | ||
![]() |
89c8f33f68 | ||
![]() |
aac1b74dbf | ||
![]() |
20cb9cdad0 | ||
![]() |
9b255bbb30 | ||
![]() |
118fa4700e | ||
![]() |
4b7a8be09b | ||
![]() |
914390a891 | ||
![]() |
79182f2b42 | ||
![]() |
0adfe858cc | ||
![]() |
4c20f02f73 | ||
![]() |
13d8829e0d | ||
![]() |
8c503584f9 | ||
![]() |
c3ba567ec8 | ||
![]() |
fcfdfbced9 | ||
![]() |
8db871f115 | ||
![]() |
12c09f10b6 | ||
![]() |
cc4c7c68c8 | ||
![]() |
36a299caa8 | ||
![]() |
2bc93d071b | ||
![]() |
a2a8538b61 | ||
![]() |
8d250bdc27 | ||
![]() |
6c7c4ecf74 | ||
![]() |
0b12a81e93 | ||
![]() |
ae803ba2c3 | ||
![]() |
93d6b2d175 | ||
![]() |
8d8164b80d | ||
![]() |
adeead08fc | ||
![]() |
0774fb688f | ||
![]() |
6258828e31 | ||
![]() |
c0a2697aea | ||
![]() |
9cb259ea71 | ||
![]() |
2d76cea2f9 | ||
![]() |
c34ebc5177 | ||
![]() |
94ee83b86a | ||
![]() |
a5ddd73ce5 | ||
![]() |
21176bfcf9 | ||
![]() |
f66fa61993 | ||
![]() |
9485236f2f | ||
![]() |
7e072aca3c | ||
![]() |
dd32a30814 | ||
![]() |
8f3f9c13da | ||
![]() |
a9593fe783 | ||
![]() |
39409ec894 | ||
![]() |
686bc45ed5 | ||
![]() |
96676dee69 | ||
![]() |
fb5f0888de | ||
![]() |
62d9379f03 | ||
![]() |
09a720b827 | ||
![]() |
5f0247ffb3 | ||
![]() |
f8e7ffb3ed | ||
![]() |
6d44f7e538 | ||
![]() |
b9cecfbc9e | ||
![]() |
c6e3bf4f44 | ||
![]() |
5568fc8bc7 | ||
![]() |
cce8a7ff37 | ||
![]() |
c36a513747 | ||
![]() |
0602ee1c5c | ||
![]() |
22511a52a7 | ||
![]() |
5f1a1b1397 | ||
![]() |
eac34dfc55 | ||
![]() |
0907ab98d3 | ||
![]() |
1ae148671d | ||
![]() |
6648b2e009 | ||
![]() |
8a08dc2cc1 | ||
![]() |
e087de4f57 | ||
![]() |
818ff14d56 | ||
![]() |
4504a3925d | ||
![]() |
29fdd087c3 | ||
![]() |
f53e64a14d | ||
![]() |
b72cc11447 | ||
![]() |
9d53c8e882 | ||
![]() |
6b2f41214f | ||
![]() |
d457162767 | ||
![]() |
0a3c9a0324 | ||
![]() |
4c8980a377 | ||
![]() |
418aa7b79b | ||
![]() |
52c3795255 | ||
![]() |
ebeab8a0a0 | ||
![]() |
650f55e7e8 | ||
![]() |
beb09f265b | ||
![]() |
7efb8a4db6 | ||
![]() |
8539e8c38d | ||
![]() |
dfa75aee76 | ||
![]() |
fbc9a4ef5c | ||
![]() |
8a015e0d16 | ||
![]() |
8d410af8a3 |
217 changed files with 25578 additions and 22913 deletions
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -17,17 +17,8 @@
|
|||
# Cr@ns specific ignore files #
|
||||
###############################
|
||||
|
||||
# On ne versionne pas les fiches de déconnexion
|
||||
surveillance/fiche_deconnexion/*
|
||||
# Mais on garde de quoi les générer
|
||||
!/surveillance/fiche_deconnexion/deconnexion_p2p.tex
|
||||
!/surveillance/fiche_deconnexion/deconnexion_upload.tex
|
||||
!/surveillance/fiche_deconnexion/generate.py
|
||||
!/surveillance/fiche_deconnexion/logo.eps
|
||||
!/surveillance/fiche_deconnexion/logo.eps.old
|
||||
|
||||
# Les clés wifi privées
|
||||
gestion/clef-wifi*
|
||||
archive/gestion/clef-wifi*
|
||||
|
||||
# Autres dépôts git
|
||||
gestion/logreader/
|
||||
|
|
31
README.md
Normal file
31
README.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
## Sous-dépôts
|
||||
À cloner pour faire marcher certains scripts
|
||||
|
||||
* `./lc_ldap`
|
||||
* `./wifi_new`
|
||||
|
||||
## Paquets Debian
|
||||
|
||||
Rajoutez-en si vous vous rendez compte qu'il en manque, à l'occasion.
|
||||
|
||||
* python-ldap
|
||||
* python-netifaces
|
||||
* python-psycopg2
|
||||
* python-netsnmp
|
||||
* python-pyparsing
|
||||
* python-markdown
|
||||
* python-jinja2
|
||||
* python-beautifulsoup
|
||||
* python-ipaddr
|
||||
* python-passlib
|
||||
* python-dateutil
|
||||
* python-tz
|
||||
* python-netaddr
|
||||
|
||||
## À faire
|
||||
|
||||
* Expliquer l'environnement de test
|
||||
* tunnel pour apprentis
|
||||
* http://stackoverflow.com/questions/8021/allow-user-to-set-up-an-ssh-tunnel-but-nothing-else
|
||||
* snmp et les mibs ! !!
|
|
@ -1,7 +1,8 @@
|
|||
#! /usr/bin/env python
|
||||
#!/bin/bash /usr/scripts/python.sh
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) Stéphane Glondu, Alexandre Bos, Michel Blockelet
|
||||
# Remanié en 2015 par Gabriel Détraz
|
||||
# Licence : GPLv2
|
||||
|
||||
u"""Ce script permet au secrétaire de repérer plus facilement les membres
|
||||
|
@ -21,22 +22,23 @@ Les commandes sont :
|
|||
|
||||
|
||||
import sys, os, re
|
||||
sys.path.append('/usr/scripts/gestion')
|
||||
import config
|
||||
import config.mails
|
||||
from email_tools import send_email, parse_mail_template
|
||||
|
||||
# Fonctions d'affichage
|
||||
from affich_tools import coul, tableau, prompt, cprint
|
||||
from gestion.affich_tools import coul, tableau, prompt, cprint
|
||||
|
||||
from utils.sendmail import actually_sendmail
|
||||
from gestion import mail
|
||||
|
||||
# Importation de la base de données
|
||||
from ldap_crans import crans_ldap, ann_scol
|
||||
db = crans_ldap()
|
||||
from lc_ldap import shortcuts
|
||||
|
||||
# Lors des tests, on m'envoie tous les mails !
|
||||
from socket import gethostname
|
||||
debug = False
|
||||
|
||||
# Conn à la db
|
||||
ldap = shortcuts.lc_ldap_admin()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 3 and sys.argv[-2] == '--debug':
|
||||
debug = sys.argv[-1]
|
||||
|
@ -56,42 +58,37 @@ def _controle_interactif_adherents(liste):
|
|||
restant = len(liste)
|
||||
if restant == 0:
|
||||
return 0, 0
|
||||
|
||||
|
||||
cprint(u'\nContrôle des membre actifs' , 'cyan')
|
||||
cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n).")
|
||||
cprint(u"Une autre réponse entraîne l'interruption du processus.")
|
||||
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
|
||||
cprint(u"")
|
||||
|
||||
|
||||
nb = 0
|
||||
for a in liste:
|
||||
valeur = a.charteMA()
|
||||
valeur = a['charteMA']
|
||||
if valeur:
|
||||
suggestion = 'o'
|
||||
else:
|
||||
suggestion = 'n'
|
||||
ok = prompt(u'[%3d] %s, %s (%s) ?'
|
||||
% (restant, a.nom(), a.prenom(), a.id()), suggestion, '').lower()
|
||||
% (restant, a['nom'][0], a['prenom'][0], a['aid'][0]), suggestion, '').lower()
|
||||
restant -= 1
|
||||
if ok == 'o':
|
||||
nb += 1
|
||||
if a.charteMA() == False :
|
||||
modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0]
|
||||
if modifiable._modifiable:
|
||||
modifiable.charteMA(True)
|
||||
cprint(modifiable.save())
|
||||
else:
|
||||
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
|
||||
elif ok == 'n':
|
||||
if a.charteMA() == True:
|
||||
modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0]
|
||||
if modifiable._modifiable:
|
||||
modifiable.charteMA(False)
|
||||
cprint(modifiable.save())
|
||||
else:
|
||||
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
|
||||
else:
|
||||
cprint(u'Arrêt du contrôle %s des membres actifs' % explicite, 'rouge')
|
||||
if a['charteMA'] != True :
|
||||
modifiable = ldap.search(u'aid=%s' % a['aid'][0], mode='rw')
|
||||
try:
|
||||
with modifiable[0] as adh:
|
||||
adh['charteMA']=True
|
||||
adh.history_gen()
|
||||
adh.save()
|
||||
cprint(u'Controle OK')
|
||||
except:
|
||||
cprint(u'Adhérent %s locké, réessayer plus tard' % a['nom'][0], 'rouge')
|
||||
elif ok != 'n':
|
||||
cprint(u'Arrêt du contrôle des membres actifs', 'rouge')
|
||||
break
|
||||
|
||||
return nb, len(liste)-nb
|
||||
|
@ -99,12 +96,12 @@ def _controle_interactif_adherents(liste):
|
|||
|
||||
def liste_charte_nok():
|
||||
"""Retourne la liste des membres actifs qui n'ont pas signé la charte."""
|
||||
liste_actifs = db.search('droits=*')['adherent']
|
||||
liste_actifs = ldap.search(u'droits=*')
|
||||
liste_nok = []
|
||||
for adh in liste_actifs:
|
||||
if (len([droit for droit in adh.droits()
|
||||
if (len([droit for droit in adh['droits']
|
||||
if droit not in ['Multimachines', 'Webradio']]) > 0
|
||||
and not adh.charteMA()):
|
||||
and not adh['charteMA']):
|
||||
liste_nok.append(adh)
|
||||
return liste_nok
|
||||
|
||||
|
@ -113,14 +110,14 @@ def controle_interactif():
|
|||
Procédure interactive de contrôle des chartes de membres actifs.
|
||||
"""
|
||||
todo_list = liste_charte_nok()
|
||||
|
||||
|
||||
# Tri de la liste des adhérents selon nom, prénom
|
||||
# Ça peut se faire plus facilement en Python 2.4 avec l'argument key
|
||||
todo_list.sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom())))
|
||||
todo_list.sort(lambda x, y: cmp((x['nom'][0], x['prenom'][0]), (y['nom'][0], y['prenom'][0])))
|
||||
|
||||
# Zou !
|
||||
ok, nok = _controle_interactif_adherents(todo_list)
|
||||
|
||||
|
||||
cprint(u'\nRécapitulatif des nouveaux contrôles :', 'violet')
|
||||
liste = [[u'membres actifs', str(ok), str(nok)]]
|
||||
cprint(tableau(liste,
|
||||
|
@ -132,20 +129,19 @@ def spammer():
|
|||
todo_list = liste_charte_nok()
|
||||
|
||||
if todo_list:
|
||||
from smtplib import SMTP
|
||||
connexion = SMTP()
|
||||
if gethostname().split(".")[0] == 'redisdead':
|
||||
connexion.connect("localhost")
|
||||
else: connexion.connect("redisdead.crans.org")
|
||||
print "Envoi des mails de rappel pour les chartes des membres actifs"
|
||||
|
||||
|
||||
for adh in todo_list:
|
||||
to = adh.email()
|
||||
to = adh['mail'][0]
|
||||
print to
|
||||
if not debug:
|
||||
data = config.mails.txt_charte_MA % {'From' : u"ca@crans.org", 'To' : to}
|
||||
connexion.sendmail("ca@crans.org",to,data.encode('utf-8'))
|
||||
|
||||
From = u"ca@crans.org"
|
||||
data=mail.generate('missing_charte_MA', {
|
||||
'To': unicode(to),
|
||||
'From': From,
|
||||
})
|
||||
actually_sendmail(u'ca@crans.org', (unicode(to),), data)
|
||||
|
||||
def __usage(message=None):
|
||||
""" Comment ça marche ? """
|
||||
cprint(__doc__ % { 'prog': sys.argv[0] })
|
||||
|
@ -163,7 +159,7 @@ if __name__ == '__main__' :
|
|||
__usage(u'Mauvaise utilisation de liste')
|
||||
print "Liste des membres actifs n'ayant pas signé la charte :"
|
||||
for adh in liste_charte_nok():
|
||||
print adh.Nom()
|
||||
print unicode(adh['prenom'][0]) + u" " + unicode(adh['nom'][0])
|
||||
elif sys.argv[1] == 'modif':
|
||||
if len(sys.argv) != 2:
|
||||
__usage(u'Mauvaise utilisation de modif')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#! /usr/bin/env python
|
||||
#!/bin/bash /usr/scripts/python.sh
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
|
@ -12,9 +12,8 @@ Licence : GPL v2
|
|||
|
||||
import os, sys, time
|
||||
import subprocess
|
||||
sys.path.append('/usr/scripts/gestion')
|
||||
from ldap_crans import crans_ldap
|
||||
from config import upload
|
||||
from lc_ldap import shortcuts
|
||||
from gestion.config import upload
|
||||
# logging tools
|
||||
import syslog
|
||||
def log(x):
|
||||
|
@ -30,6 +29,8 @@ import utils.exceptions
|
|||
import locale
|
||||
locale.setlocale(locale.LC_TIME, 'fr_FR.UTF-8')
|
||||
|
||||
# On blackliste 14 jours après que le script ait été éxécuté
|
||||
DELAY = 14
|
||||
|
||||
help = """Script de déconnexion pour mail invalide.
|
||||
Une fiche sera générée pour chaque adhérent.
|
||||
|
@ -49,22 +50,23 @@ l'adhérent ayant l'aid 42."""
|
|||
def generate_ps(proprio, mail):
|
||||
"""On génère la feuille d'avertissement et on retourne son emplacement."""
|
||||
barcode = "/usr/scripts/admin/mail_invalide/barcode.eps"
|
||||
name = unicode(proprio['prenom'][0]) + u" " + unicode(proprio['nom'][0])
|
||||
try:
|
||||
log('Generate invalid mail notice for %s' % proprio.Nom())
|
||||
log(u'Generate invalid mail notice for %s' % name)
|
||||
# Dossier de génération du ps
|
||||
dossier = '/usr/scripts/var/mails_invalides'
|
||||
|
||||
# Base pour le nom du fichier
|
||||
fichier = time.strftime('%Y-%m-%d-%H-%M') + '-mail-%s' % (proprio.Nom().
|
||||
fichier = time.strftime('%Y-%m-%d-%H-%M') + '-mail-%s' % (name.
|
||||
lower().replace(' ', '-'))
|
||||
|
||||
# Création du fichier tex
|
||||
format_date = '%A %d %B %Y'
|
||||
with open('%s/mail_invalide.tex' % os.path.dirname(__file__), 'r') as tempfile:
|
||||
template = tempfile.read()
|
||||
template = template.replace('~prenom~', proprio.prenom().encode('utf-8'))
|
||||
template = template.replace('~nom~', proprio.nom().encode('utf-8'))
|
||||
template = template.replace('~chambre~', proprio.chbre().encode('utf-8'))
|
||||
template = template.replace('~prenom~', proprio['prenom'][0].encode('utf-8'))
|
||||
template = template.replace('~nom~', proprio['nom'][0].encode('utf-8'))
|
||||
template = template.replace('~chambre~', proprio['chbre'][0].encode('utf-8'))
|
||||
template = template.replace('~mail~', mail.encode('utf-8').replace('_', '\\_'))
|
||||
template = template.replace('~fin~',
|
||||
time.strftime(format_date, time.localtime(time.time()+14*86400)))
|
||||
|
@ -83,35 +85,37 @@ def generate_ps(proprio, mail):
|
|||
except Exception, e:
|
||||
log('Erreur lors de la génération du ps : ')
|
||||
log(str(e))
|
||||
log("Values : adherent:%s" % proprio.Nom())
|
||||
log("Values : adherent:%s" % name)
|
||||
log(utils.exceptions.formatExc())
|
||||
raise
|
||||
|
||||
def set_mail_invalide(adherent, mail, a_verifier, a_imprimer):
|
||||
if adherent.chbre() in ['????', 'EXT']:
|
||||
print u"Chambre de %s : %s, générer la fiche ? [Yn]" % (adherent.Nom().encode('utf-8'), adherent.chbre())
|
||||
name = unicode(adherent['prenom'][0]) + u" " + unicode(adherent['nom'][0])
|
||||
if adherent['chbre'][0] in ['????', 'EXT']:
|
||||
print u"Chambre de %s : %s, générer la fiche ? [Yn]" % (name, adherent['chbre'][0])
|
||||
read = ''
|
||||
while read not in ['y', 'n']:
|
||||
read = raw_input().lower()
|
||||
if read == 'n':
|
||||
print u"Chambre de %s : %s, impossible de générer la fiche." % (adherent.Nom().encode('utf-8'), adherent.chbre())
|
||||
print u"Chambre de %s : %s, impossible de générer la fiche." % (name, adherent['chbre'][0])
|
||||
a_verifier.append(mail)
|
||||
return
|
||||
|
||||
print "Génération de la fiche pour %s :" % adherent.Nom().encode('utf-8')
|
||||
|
||||
print u"Génération de la fiche pour %s :" % name
|
||||
fiche = generate_ps(adherent, mail)
|
||||
print fiche
|
||||
a_imprimer.append(fiche)
|
||||
adherent.blacklist([time.time() + 14 * 24 * 3600,
|
||||
'-', 'mail_invalide', "Mail invalide"])
|
||||
adherent.save()
|
||||
with adherent as adh:
|
||||
adh.blacklist('mail_invalide','Mail Invalide - Script',debut=int(time.time()) + DELAY * 24 * 3600)
|
||||
adh.history_gen()
|
||||
adh.save()
|
||||
|
||||
if __name__ == "__main__":
|
||||
if '--help' in sys.argv or '-h' in sys.argv or len(sys.argv) < 2:
|
||||
print help
|
||||
sys.exit(0)
|
||||
|
||||
db = crans_ldap()
|
||||
ldap = shortcuts.lc_ldap_admin()
|
||||
|
||||
# On fait la liste des .forwards dans les homes
|
||||
print " * Lecture des .forward ..."
|
||||
|
@ -141,24 +145,24 @@ if __name__ == "__main__":
|
|||
# Est-ce un aid ?
|
||||
if adresse[0] == '-':
|
||||
print " * Recherche de aid=%s ..." % adresse[1:]
|
||||
res = db.search("aid=%s" % adresse[1:], 'w')['adherent']
|
||||
res = ldap.search(u"aid=%s" % adresse[1:], mode='rw')
|
||||
if len(res) == 0:
|
||||
print "*** Erreur : aucun résultat pour aid=%s" % adresse[1:]
|
||||
a_verifier.append(adresse)
|
||||
elif len(res) > 1:
|
||||
print "*** Erreur : plusieurs résultats pour aid=%s :" % adresse[1:]
|
||||
for adh in res:
|
||||
print adh.Nom()
|
||||
print unicode(adh['prenom'][0]) + u" " + unicode(adh['nom'][0])
|
||||
a_verifier.append(adresse)
|
||||
else:
|
||||
adherent = res[0]
|
||||
set_mail_invalide(adherent, adherent.email(), a_verifier, a_imprimer)
|
||||
set_mail_invalide(adherent, adherent['mail'][0], a_verifier, a_imprimer)
|
||||
continue
|
||||
|
||||
print " * Recherche de %s ..." % adresse
|
||||
# Est-ce un .forward ?
|
||||
if forwards.has_key(adresse):
|
||||
res = db.search("uid=%s" % forwards[adresse], 'w')['adherent']
|
||||
res = ldap.search(u"uid=%s" % forwards[adresse], mode='rw')
|
||||
if len(res) == 0:
|
||||
print "*** Erreur : aucun résultat pour uid=%s" % forwards[adresse]
|
||||
a_verifier.append(adresse)
|
||||
|
@ -168,18 +172,18 @@ if __name__ == "__main__":
|
|||
continue
|
||||
|
||||
# Est-ce une adresse mail sans compte Cr@ns ?
|
||||
res = db.search("mail=%s" % adresse, 'w')['adherent']
|
||||
res = ldap.search(u"(|(mail=%s)(mailExt=%s))" % (adresse,adresse), mode='rw')
|
||||
if len(res) == 0:
|
||||
print "*** Erreur : aucun résultat pour %s" % adresse
|
||||
a_verifier.append(adresse)
|
||||
elif len(res) > 1:
|
||||
print "*** Erreur : plusieurs résultats pour %s :" % adresse
|
||||
for adh in res:
|
||||
print adh.Nom()
|
||||
print unicode(adh['prenom'][0]) + u" " + unicode(adh['nom'][0])
|
||||
a_verifier.append(adresse)
|
||||
else:
|
||||
adherent = res[0]
|
||||
set_mail_invalide(adherent, adherent.email(), a_verifier, a_imprimer)
|
||||
set_mail_invalide(adherent, adresse, a_verifier, a_imprimer)
|
||||
|
||||
if len(a_verifier) + len(a_imprimer) > 0:
|
||||
print ''
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#! /usr/bin/env python
|
||||
#!/bin/bash /usr/scripts/python.sh
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
|
||||
# Copyright (C) Stéphane Glondu, Alexandre Bos
|
||||
# Copyright (C) Stéphane Glondu, Alexandre Bos, et autres
|
||||
# Licence : GPLv2
|
||||
|
||||
__doc__ = u"""Ce script permet de faire le menages parmis les câbleurs qui ne
|
||||
__doc__ = u"""Ce script permet de faire le menages parmis les câbleurs qui ne
|
||||
sont plus sur le campus, ie ceux qui ne sont plus à jour de cotisation.
|
||||
|
||||
Utilisation :
|
||||
|
@ -15,22 +14,20 @@ Utilisation :
|
|||
Les commandes sont :
|
||||
* lister afficher la liste des câbleurs succeptibles d'être
|
||||
radiés
|
||||
* radier selectionner, parmis eux, les cableurs que l'on
|
||||
* radier selectionner, parmis eux, les cableurs que l'on
|
||||
souhaite radier
|
||||
"""
|
||||
|
||||
|
||||
import sys, os, re
|
||||
sys.path.append('/usr/scripts/gestion')
|
||||
import config
|
||||
from email_tools import send_email, parse_mail_template
|
||||
import gestion.config
|
||||
|
||||
# Fonctions d'affichage
|
||||
from affich_tools import coul, tableau, prompt, cprint
|
||||
from gestion.affich_tools import coul, tableau, prompt, cprint
|
||||
|
||||
# Importation de la base de données
|
||||
from ldap_crans import crans_ldap, ann_scol
|
||||
db = crans_ldap()
|
||||
from lc_ldap import shortcuts
|
||||
ldap = shortcuts.lc_ldap_admin()
|
||||
|
||||
def _controle_interactif_adherents(liste):
|
||||
"""
|
||||
|
@ -40,38 +37,40 @@ def _controle_interactif_adherents(liste):
|
|||
restant = len(liste)
|
||||
if restant == 0:
|
||||
return 0, 0
|
||||
|
||||
|
||||
cprint(u'\nRadiation des câbleurs fantômes' , 'cyan')
|
||||
cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n).")
|
||||
cprint(u"Une autre réponse entraîne l'interruption du processus.")
|
||||
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
|
||||
cprint(u"")
|
||||
|
||||
|
||||
nb = 0
|
||||
for a in liste:
|
||||
ok = prompt(u'[%3d] %s, %s (%s) ?'
|
||||
% (restant, a.nom(), a.prenom(), a.id()), 'n', '').lower()
|
||||
% (restant, a['nom'][0], a['prenom'][0], a['aid'][0]), 'n', '').lower()
|
||||
restant -= 1
|
||||
if ok == 'o':
|
||||
modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0]
|
||||
if modifiable._modifiable:
|
||||
modifiable.droits([])
|
||||
cprint(modifiable.save())
|
||||
else:
|
||||
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
|
||||
modifiable = ldap.search(u'aid=%s' % a['aid'][0], mode='rw')[0]
|
||||
try:
|
||||
with modifiable as adh:
|
||||
adh['droits'].remove(u'Cableur')
|
||||
adh.history_gen()
|
||||
adh.save()
|
||||
cprint(u'Droits cableurs retirés', 'rouge')
|
||||
except:
|
||||
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable['nom'][0], 'rouge')
|
||||
elif ok != 'n':
|
||||
cprint(u'Arrêt du contrôle %s des membres actifs' % explicite, 'rouge')
|
||||
break
|
||||
|
||||
def candidats():
|
||||
todo_list1 = db.search('droits=*')['adherent']
|
||||
todo_list1 = ldap.search(u'droits=cableur')
|
||||
todo_list = []
|
||||
for adh in todo_list1:
|
||||
if adh.droitsGeles():
|
||||
if not adh.paiement_ok():
|
||||
todo_list.append(adh)
|
||||
todo_list.sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom())))
|
||||
return todo_list
|
||||
|
||||
|
||||
def lister():
|
||||
"""
|
||||
Afficher les câbleurs fantômes potentiels.
|
||||
|
@ -80,19 +79,19 @@ def lister():
|
|||
print "Liste des câbleur dont la cotisation n'est pas à jour."
|
||||
print
|
||||
for adh in todo_list:
|
||||
print adh.prenom() + " " + adh.nom()
|
||||
print unicode(adh['prenom'][0]) + u" " + unicode(adh['nom'][0])
|
||||
print
|
||||
print "total : " + str(len(todo_list))
|
||||
|
||||
|
||||
def controle_interactif():
|
||||
"""
|
||||
Procédure interactive de radiations des câbleurs fantômes.
|
||||
"""
|
||||
todo_list = candidats()
|
||||
|
||||
|
||||
# Zou !
|
||||
_controle_interactif_adherents(todo_list)
|
||||
|
||||
|
||||
def __usage(message=None):
|
||||
""" Comment ça marche ? """
|
||||
|
||||
|
@ -103,22 +102,22 @@ def __usage(message=None):
|
|||
|
||||
|
||||
if __name__ == '__main__' :
|
||||
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
__usage()
|
||||
|
||||
|
||||
elif sys.argv[1] == 'lister':
|
||||
if len(sys.argv) != 2:
|
||||
__usage(u'Mauvaise utilisation de lister')
|
||||
lister()
|
||||
|
||||
|
||||
elif sys.argv[1] == 'radier':
|
||||
if len(sys.argv) != 2:
|
||||
__usage(u'Mauvaise utilisation de radier')
|
||||
controle_interactif()
|
||||
else:
|
||||
__usage(u'Commande inconnue : %s' % sys.argv[1])
|
||||
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/bin/bash /usr/scripts/python.sh
|
||||
# -*- mode: python; coding: utf-8 -*-
|
||||
#
|
||||
# total_impression.py
|
||||
|
@ -6,6 +6,7 @@
|
|||
#
|
||||
# Copyright (C) 2007 Michel Blockelet <blockelet@crans.org>
|
||||
#
|
||||
# Revu et corrigé en 2015 par Gabriel Détraz
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
|
@ -32,14 +33,11 @@ Options :
|
|||
Les dates doivent etre de la forme jj/mm/aaaa."""
|
||||
|
||||
import sys
|
||||
sys.path.append("/usr/scripts/gestion/")
|
||||
from ldap_crans import crans_ldap
|
||||
from config import ann_scol
|
||||
from affich_tools import cprint
|
||||
from lc_ldap import shortcuts
|
||||
from gestion.affich_tools import cprint
|
||||
import time
|
||||
|
||||
db = crans_ldap()
|
||||
date_debut_ann_scol = time.mktime((ann_scol, 8, 1, 0, 0, 0, 0, 0, 0))
|
||||
ldap = shortcuts.lc_ldap_admin()
|
||||
|
||||
def datestrtoint(strdate):
|
||||
u""" Convertit une date en entier. """
|
||||
|
@ -52,7 +50,7 @@ def soldes_adherent(dlinf, dlsup, adherent, verbose):
|
|||
totaldebit = 0
|
||||
totalcredit = 0
|
||||
|
||||
for hist in adherent.historique():
|
||||
for hist in adherent['historique']:
|
||||
sep = ' '
|
||||
champ = hist.replace(',', '').replace(': ', '').split(sep)
|
||||
if datestrtoint(champ[0]) >= dlinf and (dlsup == 0 or datestrtoint(champ[0]) <= dlsup):
|
||||
|
@ -112,19 +110,23 @@ def calcul_soldes():
|
|||
totaldebit = 0
|
||||
totalcredit = 0
|
||||
|
||||
liste = db.search("login=*")['adherent']
|
||||
liste = ldap.search(u"uid=*",sizelimit=10000)
|
||||
|
||||
for adherent in liste:
|
||||
adhdebit, adhcredit = soldes_adherent(dlinf, dlsup, adherent, verbose)
|
||||
if adhdebit + adhcredit > 0 and adhdebit + adhcredit < 1000000: # On evite Toto Passoir
|
||||
if verbose >= 2:
|
||||
cprint('-' * 40, 'cyan')
|
||||
if verbose >= 1:
|
||||
cprint('Debit total pour ' + adherent.Nom() + ' : ' + str(adhdebit) + ' euros', 'rouge')
|
||||
cprint('Credit total pour ' + adherent.Nom() + ' : ' + str(adhcredit) + ' euros', 'vert')
|
||||
cprint('=' * 40, 'bleu')
|
||||
totaldebit += adhdebit
|
||||
totalcredit += adhcredit
|
||||
try:
|
||||
adhdebit, adhcredit = soldes_adherent(dlinf, dlsup, adherent, verbose)
|
||||
if adhdebit + adhcredit > 0 and adhdebit + adhcredit < 1000000: # On evite Toto Passoir
|
||||
if verbose >= 2:
|
||||
cprint('-' * 40, 'cyan')
|
||||
if verbose >= 1:
|
||||
name = unicode(adherent['prenom'][0]) + u" " + unicode(adherent['nom'][0])
|
||||
cprint(u'Debit total pour ' + name + u' : ' + unicode(adhdebit) + u' euros', 'rouge')
|
||||
cprint(u'Credit total pour ' + name + u' : ' + unicode(adhcredit) + u' euros', 'vert')
|
||||
cprint('=' * 40, 'bleu')
|
||||
totaldebit += adhdebit
|
||||
totalcredit += adhcredit
|
||||
except KeyError:
|
||||
pass
|
||||
if verbose >= 1:
|
||||
cprint('=' * 80, 'bleu')
|
||||
if dlinf == 0:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#! /usr/bin/env python
|
||||
#!/bin/bash /usr/scripts/python.sh
|
||||
# -*- coding: utf-8 -*-
|
||||
# #############################################################
|
||||
# ..
|
||||
|
@ -38,7 +38,8 @@ import commands
|
|||
import shutil
|
||||
import syslog
|
||||
import stat
|
||||
sys.path.append('/usr/scripts/')
|
||||
if '/usr/scripts' not in sys.path:
|
||||
sys.path.append('/usr/scripts')
|
||||
from cranslib.deprecated import module as deprecated_module
|
||||
deprecated_module()
|
||||
from cranslib.utils import QuoteForPOSIX as escapeForShell
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# #############################################################
|
||||
# ..
|
||||
|
@ -31,10 +30,11 @@ Calcule le coût des options d'impression.
|
|||
__version__ = '9.11'
|
||||
|
||||
import sys, os.path
|
||||
sys.path.append('/usr/scripts/gestion')
|
||||
from config import impression as config_impression
|
||||
from gestion.config import impression as config_impression
|
||||
from commands import getstatusoutput
|
||||
sys.path.append('/usr/scripts/')
|
||||
|
||||
if '/usr/scripts' not in sys.path:
|
||||
sys.path.append('/usr/scripts')
|
||||
from cranslib.utils import logs
|
||||
from subprocess import Popen, PIPE
|
||||
from base import FichierInvalide, SoldeInsuffisant, PrintError, SettingsError
|
||||
|
@ -415,9 +415,7 @@ class impression:
|
|||
|
||||
def _get_adh(self, adh):
|
||||
if type(adh) == str:
|
||||
sys.path.append("/usr/scripts/gestion/")
|
||||
#from ldap_crans_test import crans_ldap
|
||||
from ldap_crans import CransLdap
|
||||
from gestion.ldap_crans import CransLdap
|
||||
adh = CransLdap().getProprio(adh, 'w')
|
||||
return adh
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/bin/bash /usr/scripts/python.sh
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
""" Envoie un mail avec la liste des serveurs qui ne sont pas synchro avec bcfg2.
|
||||
|
@ -43,7 +43,6 @@ if __name__ == "__main__":
|
|||
debug = "--debug" in sys.argv
|
||||
if "--mail" in sys.argv:
|
||||
if hosts != "":
|
||||
sys.path.append("/usr/scripts/")
|
||||
import utils.sendmail
|
||||
utils.sendmail.sendmail("root@crans.org", "roots@crans.org", u"Serveurs non synchronisés avec bcfg2", hosts, more_headers={"X-Mailer" : "bcfg2-reports"}, debug=debug)
|
||||
elif debug:
|
||||
|
|
|
@ -4,19 +4,13 @@ if [[ $1 = "" ]] || [[ $1 = $USER ]] ; then
|
|||
/usr/bin/quota
|
||||
else
|
||||
/usr/bin/quota $*
|
||||
fi | awk -F'(:| *)' '
|
||||
fi | sed 's/home-adh/home/' | awk -F'(:| *)' '
|
||||
BEGIN { fs = "" }
|
||||
/Disk/ { print; print "utilisé\tquota\tlimite\t%\t(en Mo)" }
|
||||
{
|
||||
if (NF == 2) { fs = $2 }
|
||||
else if (fs != "") {
|
||||
#unit = 512/1024
|
||||
#system(/usr/bin/stat -c %B " fs) | getline unit
|
||||
#if (fs == "/home") { total = 400 }
|
||||
#else if (fs == "/var/mail") { total = 75 }
|
||||
#else { total = 100 }
|
||||
printf "%3.2f\t%3.2f\t%3.2f\t%3.1f\t%s\n", $2/1024, $3/1024, $4/1024, $2*100/$3, fs
|
||||
#printf "%3.2f\t%3.2f\t%3.2f\t%3.1f\t%s\n", $2/1024*unit, $3/1024*unit, $4/1024*unit, $2*100/$3, fs
|
||||
fs = ""
|
||||
}
|
||||
}'
|
||||
|
|
|
@ -70,10 +70,13 @@ BL_REJECT = [u'bloq']
|
|||
BL_ISOLEMENT = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra']
|
||||
|
||||
#: place sur accueil
|
||||
BL_ACCUEIL = []
|
||||
BL_ACCUEIL = [u'paiement']
|
||||
|
||||
# Ces blacklists ont des effets soft (portail captif port 80)
|
||||
#BL_ACCUEIL = [u'carte_etudiant', u'chambre_invalide', u'paiement']
|
||||
# À classer:
|
||||
# [u'carte_etudiant', u'chambre_invalide', ]
|
||||
# TODO: mettre ça dans config.py en explicitant un peu comment ça marche
|
||||
# et en trouvant moyen de refresh en fonction de la période de l'année
|
||||
# (bl soft/hard parefeu ou pas)
|
||||
|
||||
#: chambre qui n'en sont pas vraiment. Il s'agit de prises en libre accès,
|
||||
# pour lequelles il est donc idiot d'activer la protection antisquattage:
|
||||
|
@ -101,11 +104,14 @@ def radius_event(fun):
|
|||
tuples en entrée en un dictionnaire."""
|
||||
|
||||
def new_f(auth_data):
|
||||
data = dict()
|
||||
for (key, value) in auth_data or []:
|
||||
# Beware: les valeurs scalaires sont entre guillemets
|
||||
# Ex: Calling-Station-Id: "une_adresse_mac"
|
||||
data[key] = value.replace('"', '')
|
||||
if type(auth_data) == dict:
|
||||
data = auth_data
|
||||
else:
|
||||
data = dict()
|
||||
for (key, value) in auth_data or []:
|
||||
# Beware: les valeurs scalaires sont entre guillemets
|
||||
# Ex: Calling-Station-Id: "une_adresse_mac"
|
||||
data[key] = value.replace('"', '')
|
||||
try:
|
||||
return fun(data)
|
||||
except Exception as err:
|
||||
|
@ -213,7 +219,7 @@ def get_prise_chbre(data):
|
|||
def realm_of_machine(machine):
|
||||
"""Renvoie le `realm` d'une machine. Don't ask"""
|
||||
if isinstance(machine, lc_ldap.objets.machineFixe):
|
||||
return 'fil'
|
||||
return 'adherents'
|
||||
elif isinstance(machine, lc_ldap.objets.machineWifi):
|
||||
return 'wifi-adh'
|
||||
else:
|
||||
|
@ -271,6 +277,18 @@ def instantiate(*_):
|
|||
if TEST_SERVER:
|
||||
logger.info('DBG_FREERADIUS is enabled')
|
||||
|
||||
@radius_event
|
||||
def authorize(data):
|
||||
"""Fonction qui aiguille entre nas, wifi et filaire pour authorize
|
||||
On se contecte de faire une verification basique de ce que contien la requète
|
||||
pour déterminer la fonction à utiliser"""
|
||||
if data.get('NAS-Port-Type', '')==u'Ethernet':
|
||||
return authorize_fil(data)
|
||||
elif u"Wireless" in data.get('NAS-Port-Type', ''):
|
||||
return authorize_wifi(data)
|
||||
else:
|
||||
return authorize_nas(data)
|
||||
|
||||
@radius_event
|
||||
def authorize_wifi(data):
|
||||
"""Section authorize pour le wifi
|
||||
|
@ -355,7 +373,7 @@ def authorize_fil(data):
|
|||
return (radiusd.RLM_MODULE_UPDATED,
|
||||
(),
|
||||
(
|
||||
("Auth-Type", "crans_fil"),
|
||||
("Auth-Type", "Accept"),
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -428,6 +446,15 @@ def authorize_nas(data, ldap):
|
|||
("FreeRADIUS-Client-Virtual-Server", vserver),
|
||||
),
|
||||
)
|
||||
|
||||
@radius_event
|
||||
def post_auth(data):
|
||||
# On cherche quel est le type de machine, et quel sites lui appliquer
|
||||
if data.get('NAS-Port-Type', '')==u'Ethernet':
|
||||
return post_auth_fil(data)
|
||||
elif u"Wireless" in data.get('NAS-Port-Type', ''):
|
||||
return post_auth_wifi(data)
|
||||
|
||||
@radius_event
|
||||
def post_auth_wifi(data):
|
||||
"""Appelé une fois que l'authentification est ok.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../rlm_python_fil.conf
|
|
@ -1 +0,0 @@
|
|||
../rlm_python_nas.conf
|
1
freeradius/modules/rlm_python_unifie.conf
Symbolic link
1
freeradius/modules/rlm_python_unifie.conf
Symbolic link
|
@ -0,0 +1 @@
|
|||
../rlm_python_unifie.conf
|
|
@ -1 +0,0 @@
|
|||
../rlm_python_wifi.conf
|
|
@ -1,37 +0,0 @@
|
|||
# Configuration for the Python module.
|
||||
#
|
||||
#
|
||||
|
||||
python crans_fil {
|
||||
mod_instantiate = freeradius.auth
|
||||
func_instantiate = instantiate
|
||||
|
||||
# Spécifique au filaire: accepte direct
|
||||
mod_authorize = freeradius.auth
|
||||
func_authorize = authorize_fil
|
||||
|
||||
# Renseigne le vlan
|
||||
# remplacer par dummy_fun pour ignorer le tagging de vlan
|
||||
mod_post_auth = freeradius.auth
|
||||
func_post_auth = post_auth_fil
|
||||
|
||||
# Que faire avant de quitter
|
||||
mod_detach = freeradius.auth
|
||||
func_detach = detach
|
||||
|
||||
# Le reste est dumb et inutile
|
||||
mod_accounting = freeradius.auth
|
||||
func_accounting = dummy_fun
|
||||
|
||||
mod_pre_proxy = freeradius.auth
|
||||
func_pre_proxy = dummy_fun
|
||||
|
||||
mod_post_proxy = freeradius.auth
|
||||
func_post_proxy = dummy_fun
|
||||
|
||||
mod_recv_coa = freeradius.auth
|
||||
func_recv_coa = dummy_fun
|
||||
|
||||
mod_send_coa = freeradius.auth
|
||||
func_send_coa = dummy_fun
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
# Configuration for the Python module.
|
||||
#
|
||||
#
|
||||
|
||||
python crans_nas {
|
||||
mod_instantiate = freeradius.auth
|
||||
func_instantiate = instantiate
|
||||
|
||||
# Spécifique NAS : rempli le mdp
|
||||
mod_authorize = freeradius.auth
|
||||
func_authorize = authorize_nas
|
||||
|
||||
# Que faire avant de quitter
|
||||
mod_detach = freeradius.auth
|
||||
func_detach = detach
|
||||
|
||||
# Le reste est dumb et inutile
|
||||
mod_post_auth = freeradius.auth
|
||||
func_post_auth = dummy_fun
|
||||
|
||||
mod_accounting = freeradius.auth
|
||||
func_accounting = dummy_fun
|
||||
|
||||
mod_pre_proxy = freeradius.auth
|
||||
func_pre_proxy = dummy_fun
|
||||
|
||||
mod_post_proxy = freeradius.auth
|
||||
func_post_proxy = dummy_fun
|
||||
|
||||
mod_recv_coa = freeradius.auth
|
||||
func_recv_coa = dummy_fun
|
||||
|
||||
mod_send_coa = freeradius.auth
|
||||
func_send_coa = dummy_fun
|
||||
}
|
38
freeradius/rlm_python_unifie.conf
Normal file
38
freeradius/rlm_python_unifie.conf
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Configuration for the Python module.
|
||||
#
|
||||
#
|
||||
|
||||
python crans_unifie {
|
||||
mod_instantiate = freeradius.auth
|
||||
func_instantiate = instantiate
|
||||
|
||||
# Pour le authorize, c'est auth.py qui fait le tri maintenant
|
||||
mod_authorize = freeradius.auth
|
||||
func_authorize = authorize
|
||||
|
||||
# Renseigne le vlan si necessaire
|
||||
# remplacer par dummy_fun pour ignorer le tagging de vlan
|
||||
mod_post_auth = freeradius.auth
|
||||
func_post_auth = post_auth
|
||||
|
||||
# Que faire avant de quitter
|
||||
mod_detach = freeradius.auth
|
||||
func_detach = detach
|
||||
|
||||
# Le reste sert à rien
|
||||
mod_accounting = freeradius.auth
|
||||
func_accounting = dummy_fun
|
||||
|
||||
mod_pre_proxy = freeradius.auth
|
||||
func_pre_proxy = dummy_fun
|
||||
|
||||
mod_post_proxy = freeradius.auth
|
||||
func_post_proxy = dummy_fun
|
||||
|
||||
mod_recv_coa = freeradius.auth
|
||||
func_recv_coa = dummy_fun
|
||||
|
||||
mod_send_coa = freeradius.auth
|
||||
func_send_coa = dummy_fun
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# Configuration for the Python module.
|
||||
#
|
||||
#
|
||||
|
||||
python crans_wifi {
|
||||
mod_instantiate = freeradius.auth
|
||||
func_instantiate = instantiate
|
||||
|
||||
# Spécifique au WiFi : rempli le mdp
|
||||
mod_authorize = freeradius.auth
|
||||
func_authorize = authorize_wifi
|
||||
|
||||
# Renseigne le vlan
|
||||
# remplacer par dummy_fun pour ignorer le tagging de vlan
|
||||
mod_post_auth = freeradius.auth
|
||||
func_post_auth = post_auth_wifi
|
||||
|
||||
# Que faire avant de quitter
|
||||
mod_detach = freeradius.auth
|
||||
func_detach = detach
|
||||
|
||||
# Le reste est dumb et inutile
|
||||
mod_accounting = freeradius.auth
|
||||
func_accounting = dummy_fun
|
||||
|
||||
mod_pre_proxy = freeradius.auth
|
||||
func_pre_proxy = dummy_fun
|
||||
|
||||
mod_post_proxy = freeradius.auth
|
||||
func_post_proxy = dummy_fun
|
||||
|
||||
mod_recv_coa = freeradius.auth
|
||||
func_recv_coa = dummy_fun
|
||||
|
||||
mod_send_coa = freeradius.auth
|
||||
func_send_coa = dummy_fun
|
||||
}
|
|
@ -11,7 +11,7 @@ server dynamic_clients {
|
|||
update request {
|
||||
NAS-Identifier = "%{Packet-Src-IP-Address:-%{Packet-Src-IPv6-Address}}"
|
||||
}
|
||||
crans_nas
|
||||
crans_unifie
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
server filaire {
|
||||
authorize{
|
||||
preprocess
|
||||
crans_fil
|
||||
crans_unifie
|
||||
}
|
||||
|
||||
authenticate{
|
||||
crans_fil
|
||||
crans_unifie
|
||||
}
|
||||
|
||||
post-auth{
|
||||
crans_fil
|
||||
crans_unifie
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ server inner-tunnel {
|
|||
authorize {
|
||||
#preprocess
|
||||
|
||||
crans_wifi
|
||||
crans_unifie
|
||||
#
|
||||
# The chap module will set 'Auth-Type := CHAP' if we are
|
||||
# handling a CHAP request and Auth-Type has not already been set
|
||||
|
@ -237,7 +237,7 @@ session {
|
|||
# Once we KNOW that the user has been authenticated, there are
|
||||
# additional steps we can take.
|
||||
post-auth {
|
||||
crans_wifi
|
||||
crans_unifie
|
||||
|
||||
# Note that we do NOT assign IP addresses here.
|
||||
# If you try to assign IP addresses for EAP authentication types,
|
||||
|
|
|
@ -558,7 +558,26 @@ if __name__ == "__main__":
|
|||
time.sleep(1)
|
||||
prettyDoin("Les carottes sont cuites." , "Ok")
|
||||
|
||||
data = [[style("Durand", "rouge"), "Toto", "40", "50 rue Döp"], ["Dupont", "Robert", "50", "42" + style(" avenue ", "vert") + style("dumotel", 'rouge')], [style("znvuzbvzruobouzb", ["gras", "vert"]), "pppoe", "1", "poiodur 50 pepe"]]
|
||||
data = [
|
||||
[
|
||||
style("Durand", "rouge"),
|
||||
"Toto",
|
||||
"40",
|
||||
"50 rue Döp"
|
||||
],
|
||||
[
|
||||
"Dupont",
|
||||
"Robert",
|
||||
"50",
|
||||
"42" + style(" avenue ", "vert") + style("dumotel", 'rouge')
|
||||
],
|
||||
[
|
||||
style("znvuzbvzruobouzb", ["gras", "vert"]),
|
||||
"pppoe",
|
||||
"1",
|
||||
"poiodur 50 pepe"
|
||||
]
|
||||
]
|
||||
titres = ("Nom", "Prénom", "Âge", "Adresse")
|
||||
longueurs = [25, 25, '*', '*']
|
||||
print tableau(data, titres, longueurs).encode(guess_preferred_encoding())
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
|
||||
import os
|
||||
import psycopg2
|
||||
|
||||
from functools import wraps
|
||||
|
||||
import time
|
||||
import socket
|
||||
|
||||
conn = None
|
||||
# : échec définitif, on raise une exception direct
|
||||
|
@ -134,7 +137,8 @@ uplink_prises={ 'a' :
|
|||
349 : 'uplink->batb-4', 350 : 'libre-service',
|
||||
401 : 'uplink->batb-0', 402 : 'uplink->batb-1',
|
||||
403 : 'uplink->batb-2', 404 : 'uplink->batb-3',
|
||||
405 : 'uplink->backbone' },
|
||||
405 : 'uplink->backbone', 523 : 'uplink->batb-4',
|
||||
},
|
||||
'c' :
|
||||
{ 49 : 'uplink->batc-3', 50 : 'libre-service',
|
||||
149 : 'uplink->batc-3', 150 : 'libre-service',
|
||||
|
@ -278,6 +282,26 @@ _HIDDEN_SWITCHES = [
|
|||
'batv-0.adm.crans.org',
|
||||
]
|
||||
|
||||
def guess_switch_fqdn(switch_name):
|
||||
"""Retourne le FQDN d'un switch à partir de son nom"""
|
||||
|
||||
try:
|
||||
return socket.gethostbyname_ex(switch_name)[0]
|
||||
except socket.gaierror:
|
||||
pass
|
||||
|
||||
try:
|
||||
return socket.gethostbyname_ex(switch_name + ".adm.crans.org")[0]
|
||||
except socket.gaierror:
|
||||
pass
|
||||
|
||||
try:
|
||||
return socket.gethostbyname_ex(switch_name + ".crans.org")[0]
|
||||
except socket.gaierror:
|
||||
pass
|
||||
|
||||
raise socket.gaierror
|
||||
|
||||
def all_switchs(bat=None, hide=_SPECIAL_SWITCHES + _HIDDEN_SWITCHES):
|
||||
"""Retourne la liste des switchs pour un batiment.
|
||||
|
||||
|
@ -294,7 +318,12 @@ def all_switchs(bat=None, hide=_SPECIAL_SWITCHES + _HIDDEN_SWITCHES):
|
|||
for b in bat:
|
||||
indexes = set(n/100 for n in uplink_prises[b])
|
||||
for i in indexes:
|
||||
hostname = "bat%s-%s.adm.crans.org" % (b, i)
|
||||
switch_name = "bat%s-%s" % (b, i)
|
||||
try:
|
||||
hostname = guess_switch_fqdn(switch_name)
|
||||
except socket.gaierror:
|
||||
print "Le switch %s ne semble pas exister." % (switch_name,)
|
||||
continue
|
||||
if hostname not in hide:
|
||||
switchs.append(hostname)
|
||||
# on ajoute quand-même le backbone et/ou multiprise-v6 si demandé
|
||||
|
|
|
@ -18,11 +18,10 @@ import re
|
|||
|
||||
import affichage
|
||||
import lc_ldap.shortcuts
|
||||
from lc_ldap.crans_utils import to_generalized_time_format as to_gtf
|
||||
|
||||
import mail as mail_module
|
||||
from config import demenagement_delai as delai, \
|
||||
debut_periode_transitoire, periode_transitoire
|
||||
gtf_debut_periode_transitoire, periode_transitoire
|
||||
|
||||
ERASE_DAY = { 'second': 0, 'minute': 0, 'microsecond': 0, 'hour': 0, }
|
||||
DAY = datetime.timedelta(days=1)
|
||||
|
@ -54,7 +53,7 @@ def get_kickout(adh):
|
|||
def warn_or_delete(smtp, clandestin, fail, done):
|
||||
"""Avertit l'adhérent ou supprime ses machines si nécessaire"""
|
||||
date, exchambre = get_kickout(clandestin)
|
||||
|
||||
|
||||
# Date de suppression prévue
|
||||
date_suppr = date + delai*DAY
|
||||
|
||||
|
@ -72,16 +71,28 @@ def warn_or_delete(smtp, clandestin, fail, done):
|
|||
mail_addr = clandestin.get_mail()
|
||||
if not clandestin.machines() or not mail_addr:
|
||||
return # Si pas de machine, on s'en fout. Si pas de mail, inutile
|
||||
try:
|
||||
data = {
|
||||
'dn': clandestin.dn.split(',')[0],
|
||||
'when': now.strftime('%Y/%M/%D %H:%m:%S:%s'),
|
||||
'chbre' : exchambre,
|
||||
}
|
||||
chbre_url = mail_module.validation_url('demenagement', data, True)
|
||||
chbre_url_error = u""
|
||||
except Exception as error:
|
||||
chbre_url_error = u"[[erreur de génération: %r]]" % error
|
||||
chbre_url = u""
|
||||
data = {
|
||||
"from" : RESP,
|
||||
"chambre" : exchambre,
|
||||
"jours" : (date_suppr - now).days+1,
|
||||
"to" : mail_addr,
|
||||
"adh": clandestin,
|
||||
"chbre_url" : chbre_url,
|
||||
"chbre_url_error" : chbre_url_error,
|
||||
"lang_info": "English version below",
|
||||
}
|
||||
mail = mail_module.generate('demenagement', data)
|
||||
smtp.sendmail(RESP, [mail_addr], mail.as_string())
|
||||
smtp.send_template('demenagement', data)
|
||||
|
||||
def format_entry(m):
|
||||
"""Renvoie une ligne de tableau, pour une machine"""
|
||||
|
@ -101,7 +112,7 @@ if __name__ == '__main__':
|
|||
conn = lc_ldap.shortcuts.lc_ldap_admin()
|
||||
|
||||
if periode_transitoire:
|
||||
date = to_gtf(debut_periode_transitoire)
|
||||
date = gtf_debut_periode_transitoire
|
||||
else:
|
||||
date = now.strftime(FORMAT_LDAP) + 'Z'
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ import lc_ldap.attributs
|
|||
import lc_ldap.objets
|
||||
import gestion.mail as mail_module
|
||||
|
||||
encoding = getattr(sys.stdout, 'encoding', "UTF-8")
|
||||
current_user = os.getenv("SUDO_USER") or os.getenv("USER") or os.getenv("LOGNAME") or getpass.getuser()
|
||||
|
||||
def check_password(password, no_cracklib=False, dialog=False):
|
||||
|
@ -41,10 +40,14 @@ def check_password(password, no_cracklib=False, dialog=False):
|
|||
problem = True
|
||||
msg += u"Le mot de passe ne doit contenir que des caractères ascii.\n"
|
||||
|
||||
if len(password) >= 64:
|
||||
problem = True
|
||||
msg += u"Le mot de passe doit faire strictement moins de 64 caractères\n"
|
||||
|
||||
# Nounou mode
|
||||
if no_cracklib:
|
||||
if len(password) >= config.password.root_min_len:
|
||||
return True
|
||||
return True, msg
|
||||
else:
|
||||
upp = 0
|
||||
low = 0
|
||||
|
@ -97,7 +100,7 @@ def check_password(password, no_cracklib=False, dialog=False):
|
|||
msg = affich_tools.coul(msg, 'rouge', dialog=dialog)
|
||||
return True, msg
|
||||
except ValueError as e:
|
||||
msg += str(e).decode()
|
||||
msg += str(e).decode(config.in_encoding)
|
||||
|
||||
if dialog:
|
||||
msg = affich_tools.coul(msg, 'rouge', dialog=dialog)
|
||||
|
@ -116,16 +119,23 @@ def check_password(password, no_cracklib=False, dialog=False):
|
|||
return False, msg
|
||||
|
||||
@lc_ldap.shortcuts.with_ldap_conn(retries=2, delay=5, constructor=lc_ldap.shortcuts.lc_ldap_admin)
|
||||
def change_password(ldap, login=None, verbose=False, no_cracklib=False, **args):
|
||||
def change_password(ldap, login=None, verbose=False, no_cracklib=False, **kwargs):
|
||||
"""
|
||||
Change le mot de passe en fonction des arguments
|
||||
"""
|
||||
if login is None:
|
||||
login = current_user
|
||||
|
||||
if type(login) == str:
|
||||
login = login.decode(encoding)
|
||||
login = login.decode(config.in_encoding)
|
||||
|
||||
if no_cracklib:
|
||||
if not lc_ldap.attributs.nounou in ldap.droits:
|
||||
no_cracklib = False
|
||||
|
||||
login = lc_ldap.crans_utils.escape(login)
|
||||
query = ldap.search(u"(uid=%s)" % login, mode="w")
|
||||
|
||||
if not query:
|
||||
affich_tools.cprint('Utilisateur introuvable dans la base de données, modification de l\'utilisateur local.', "rouge")
|
||||
sys.exit(2)
|
||||
|
@ -135,7 +145,7 @@ def change_password(ldap, login=None, verbose=False, no_cracklib=False, **args):
|
|||
user['userPassword'] = [lc_ldap.crans_utils.hash_password("test").decode('ascii')]
|
||||
user.cancel()
|
||||
except EnvironmentError as e:
|
||||
affich_tools.cprint(str(e).decode(encoding), "rouge")
|
||||
affich_tools.cprint(str(e).decode(config.in_encoding), "rouge")
|
||||
|
||||
# Génération d'un mail
|
||||
From = 'roots@crans.org'
|
||||
|
@ -145,11 +155,11 @@ To: %s
|
|||
Subject: Tentative de changement de mot de passe !
|
||||
|
||||
Tentative de changement du mot de passe de %s par %s.
|
||||
""" % (From, To , login.encode(encoding), current_user)
|
||||
""" % (From, To, login.encode(config.out_encoding), current_user)
|
||||
|
||||
# Envoi mail
|
||||
with mail_module.ServerConnection() as conn:
|
||||
conn.sendmail(From, To , mail )
|
||||
conn.sendmail(From, To, mail)
|
||||
sys.exit(1)
|
||||
|
||||
# On peut modifier le MDP
|
||||
|
@ -157,44 +167,50 @@ Tentative de changement du mot de passe de %s par %s.
|
|||
prenom = "Club"
|
||||
else:
|
||||
prenom = user['prenom'][0]
|
||||
affich_tools.cprint("Changement du mot de passe de %s %s." %
|
||||
(prenom, user['nom'][0]),
|
||||
"vert")
|
||||
affich_tools.cprint(
|
||||
"Changement du mot de passe de %s %s." % (
|
||||
prenom,
|
||||
user['nom'][0]
|
||||
),
|
||||
"vert",
|
||||
)
|
||||
|
||||
# Règles du jeu
|
||||
# (J'ai perdu)
|
||||
if verbose:
|
||||
affich_tools.cprint(u"""Règles :
|
||||
affich_tools.cprint(
|
||||
u"""Règles :
|
||||
Longueur standard : %s, root : %s,
|
||||
Minimums : chiffres : %s, minuscules : %s, majuscules : %s, autres : %s,
|
||||
Scores de longueur : chiffres : %s, minuscules : %s, majuscules : %s, autres : %s,
|
||||
Cracklib : %s.""" % (
|
||||
config.password.min_len,
|
||||
config.password.root_min_len,
|
||||
config.password.min_cif,
|
||||
config.password.min_low,
|
||||
config.password.min_upp,
|
||||
config.password.min_oth,
|
||||
config.password.cif_value,
|
||||
config.password.low_value,
|
||||
config.password.upp_value,
|
||||
config.password.oth_value,
|
||||
"Oui" * (not no_cracklib) + "Non" * (no_cracklib)
|
||||
),
|
||||
'jaune')
|
||||
Cracklib : %s.""" % (config.password.min_len,
|
||||
config.password.root_min_len,
|
||||
config.password.min_cif,
|
||||
config.password.min_low,
|
||||
config.password.min_upp,
|
||||
config.password.min_oth,
|
||||
config.password.cif_value,
|
||||
config.password.low_value,
|
||||
config.password.upp_value,
|
||||
config.password.oth_value,
|
||||
"Oui" * (not no_cracklib) + "Non" * (no_cracklib),
|
||||
),
|
||||
'jaune',
|
||||
)
|
||||
else:
|
||||
affich_tools.cprint(u"""Le nouveau mot de passe doit comporter au minimum %s caractères.
|
||||
affich_tools.cprint(
|
||||
u"""Le nouveau mot de passe doit comporter au minimum %s caractères.
|
||||
Il ne doit pas être basé sur un mot du dictionnaire.
|
||||
Il doit contenir au moins %s chiffre(s), %s minuscule(s),
|
||||
%s majuscule(s) et au moins %s autre(s) caractère(s).
|
||||
CTRL+D ou CTRL+C provoquent un abandon.""" %
|
||||
(
|
||||
config.password.min_len,
|
||||
config.password.min_cif,
|
||||
config.password.min_low,
|
||||
config.password.min_upp,
|
||||
config.password.min_oth
|
||||
), 'jaune')
|
||||
CTRL+D ou CTRL+C provoquent un abandon.""" % (config.password.min_len,
|
||||
config.password.min_cif,
|
||||
config.password.min_low,
|
||||
config.password.min_upp,
|
||||
config.password.min_oth
|
||||
),
|
||||
'jaune',
|
||||
)
|
||||
|
||||
try:
|
||||
while True:
|
||||
|
@ -224,29 +240,35 @@ CTRL+D ou CTRL+C provoquent un abandon.""" %
|
|||
affich_tools.cprint(u"Mot de passe de %s changé." % (user['uid'][0]), "vert")
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Recherche dans la base des adhérents",
|
||||
add_help=False)
|
||||
parser.add_argument('-h', '--help',
|
||||
help="Affiche ce message et quitte.",
|
||||
action="store_true")
|
||||
parser.add_argument('-n', '--no-cracklib',
|
||||
help="Permet de contourner les règles de choix du mot de passe" +
|
||||
"(réservé aux nounous).",
|
||||
action="store_true")
|
||||
parser.add_argument('-v', '--verbose',
|
||||
help="Permet de contourner les règles de choix du mot de passe" +
|
||||
"(réservé aux nounous).",
|
||||
action="store_true")
|
||||
parser.add_argument('login', type=str, nargs="?",
|
||||
help="L'utilisateur dont on veut changer le mot de passe.")
|
||||
parser = argparse.ArgumentParser(description="Recherche dans la base des adhérents",
|
||||
add_help=False,
|
||||
)
|
||||
parser.add_argument('-h',
|
||||
'--help',
|
||||
help="Affiche ce message et quitte.",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument('-n',
|
||||
'--no-cracklib',
|
||||
help="Permet de contourner les règles de choix du mot de passe" +
|
||||
"(réservé aux nounous).",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument('-v',
|
||||
'--verbose',
|
||||
help="Permet de contourner les règles de choix du mot de passe" +
|
||||
"(réservé aux nounous).",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument('login',
|
||||
type=str,
|
||||
nargs="?",
|
||||
help="L'utilisateur dont on veut changer le mot de passe.",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.help:
|
||||
parser.print_help()
|
||||
sys.exit(0)
|
||||
if args.no_cracklib:
|
||||
if not lc_ldap.attributs.nounou in ldap.droits:
|
||||
args.no_cracklib = False
|
||||
change_password(**vars(args))
|
||||
|
|
|
@ -10,29 +10,28 @@
|
|||
import os, sys
|
||||
|
||||
from gestion.affich_tools import prompt
|
||||
from gestion.ldap_crans import crans_ldap
|
||||
|
||||
db = crans_ldap()
|
||||
from lc_ldap import shortcuts
|
||||
|
||||
ldap = shortcuts.lc_ldap_admin()
|
||||
uid = os.getenv('SUDO_UID')
|
||||
if not uid :
|
||||
print "Impossible de déterminer l'utilisateur"
|
||||
sys.exit(1)
|
||||
|
||||
s = db.search('uidNumber=%s' % os.getenv('SUDO_UID'),'w')
|
||||
adh = ldap.search(u'uidNumber=%s' % uid,mode='w')
|
||||
|
||||
# On vérifie que c'est pas un club
|
||||
club = s['club']
|
||||
if len(club) == 1 :
|
||||
print 'Pas de changement de shell pour les clubs'
|
||||
sys.exit(2)
|
||||
|
||||
# On regarde si on a des résultats dans les adhérents
|
||||
adh = s['adherent']
|
||||
if len(adh) != 1 :
|
||||
try:
|
||||
adh = adh[0]
|
||||
except IndexError:
|
||||
print 'Erreur fatale lors de la consultation de la base LDAP'
|
||||
sys.exit(3)
|
||||
|
||||
adh = adh[0]
|
||||
# On vérifie que c'est pas un club
|
||||
if unicode(adh.ldap_name)!=u"adherent":
|
||||
print 'Pas de changement de shell pour les clubs'
|
||||
sys.exit(2)
|
||||
|
||||
shell = prompt(u'Nouveau shell :')
|
||||
fd=open('/etc/shells')
|
||||
lines=fd.readlines()
|
||||
|
@ -45,7 +44,9 @@ if not shell in shells:
|
|||
print '\n'.join(shells)
|
||||
sys.exit(4)
|
||||
|
||||
adh.chsh(shell)
|
||||
adh.save()
|
||||
with adh as ad:
|
||||
ad['loginShell']=shell
|
||||
ad.save()
|
||||
|
||||
# A cause de nscd
|
||||
print "La modification sera prise en compte dans l'heure suivante."
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
from config import *
|
||||
from encoding import *
|
||||
|
||||
import dns
|
||||
|
|
|
@ -9,34 +9,35 @@ import datetime
|
|||
# Fichier généré à partir de bcfg2
|
||||
from config_srv import adm_only, role
|
||||
|
||||
# Valeur par défaut pour les champs d'études
|
||||
etudes_defaults = [
|
||||
u"Établissement inconnu",
|
||||
u"Année inconnue",
|
||||
u"Domaine d'études inconnu"
|
||||
]
|
||||
|
||||
gtfepoch = "19700101000000Z"
|
||||
##### Gestion des câblages
|
||||
# Selon la date, on met :
|
||||
# -ann_scol : Année scolaire en cours
|
||||
# -periode_transitoire : on accepte ceux qui ont payé l'année dernière
|
||||
|
||||
# Ne modifier que les dates !
|
||||
dat = time.localtime()
|
||||
if dat[1] < 8 or dat[1] == 8 and dat[2] < 16:
|
||||
# Si pas encore début août, on est dans l'année précédente
|
||||
ann_scol = dat[0]-1
|
||||
periode_transitoire = False
|
||||
# sinon on change d'année
|
||||
elif dat[1] < 10:
|
||||
# Si pas encore octobre, les gens ayant payé l'année précédente sont
|
||||
# acceptés
|
||||
ann_scol = dat[0]
|
||||
periode_transitoire = True
|
||||
else:
|
||||
# Seulement ceux qui ont payé cette année sont acceptés
|
||||
ann_scol = dat[0]
|
||||
periode_transitoire = False
|
||||
# On récupère l'année scolaire à tout besoin
|
||||
__annee = time.localtime()[0]
|
||||
|
||||
debut_periode_transitoire = time.mktime(time.strptime("%s/08/16 00:00:00" % (ann_scol,), "%Y/%m/%d %H:%M:%S"))
|
||||
fin_periode_transitoire = time.mktime(time.strptime("%s/09/30 23:59:59" % (ann_scol,), "%Y/%m/%d %H:%M:%S"))
|
||||
# Prochaine période transitoire de l'année version generalizedTimeFormat
|
||||
gtf_debut_periode_transitoire = "%s0816000000+0200" % (__annee,)
|
||||
gtf_fin_periode_transitoire = "%s0930235959+0200" % (__annee,)
|
||||
|
||||
#Sursis pour les inscription après le 1/11 pour fournir la carte étudiant
|
||||
sursis_carte=8*24*3600
|
||||
# Version timestampées timezone-naïves
|
||||
debut_periode_transitoire = time.mktime(time.strptime("%s/08/16 00:00:00" % (__annee,), "%Y/%m/%d %H:%M:%S"))
|
||||
fin_periode_transitoire = time.mktime(time.strptime("%s/09/30 23:59:59" % (__annee,), "%Y/%m/%d %H:%M:%S"))
|
||||
|
||||
# On est en période transitoire si on est dans le bon intervale
|
||||
periode_transitoire = (debut_periode_transitoire <= time.time() <= fin_periode_transitoire)
|
||||
|
||||
ann_scol = __annee
|
||||
if time.time() <= debut_periode_transitoire:
|
||||
ann_scol -= 1
|
||||
|
||||
# Gel des cableurs pas a jour de cotisation
|
||||
# Les droits ne sont pas retires mais il n'y a plus de sudo
|
||||
|
@ -54,89 +55,201 @@ quota_hard = 10000000
|
|||
fquota_soft = 0
|
||||
fquota_hard = 0
|
||||
# Shell
|
||||
login_shell='/bin/zsh'
|
||||
club_login_shell='/usr/bin/rssh'
|
||||
login_shell = '/bin/zsh'
|
||||
club_login_shell = '/usr/bin/rssh'
|
||||
# Longueur maximale d'un login
|
||||
maxlen_login=25
|
||||
maxlen_login = 25
|
||||
|
||||
shells_possibles = [u'/bin/csh',
|
||||
u'/bin/sh', # tout caca
|
||||
u'/bin/dash', # un bash light
|
||||
u'/usr/bin/rc',
|
||||
u'/usr/bin/ksh', # symlink vers zsh
|
||||
u'/bin/ksh', # symlink vers zsh
|
||||
u'/usr/bin/tcsh', # TENEX C Shell (csh++)
|
||||
u'/bin/tcsh', # TENEX C Shell (csh++)
|
||||
u'/bin/bash', # the Bourne-Again SHell
|
||||
u'/bin/zsh', # the Z shell
|
||||
u'/usr/bin/zsh', # the Z shell
|
||||
u'/usr/bin/screen',
|
||||
u'/bin/rbash', # Bash restreint
|
||||
u'/usr/bin/rssh', # restricted secure shell allowing only scp and/or sftp
|
||||
u'/usr/local/bin/badPassSh', # demande de changer de mot de passe
|
||||
u'/usr/bin/passwd', # idem
|
||||
u'/usr/local/bin/disconnect_shell', # déconnexion crans
|
||||
u'/usr/scripts/surveillance/disconnect_shell', # idem
|
||||
u'/usr/sbin/nologin', # This account is currently not available.
|
||||
u'/bin/false', # vraiement méchant
|
||||
u'/usr/bin/es', # n'exsite plus
|
||||
u'/usr/bin/esh', # n'existe plus
|
||||
u'', # le shell vide pour pouvoir les punis
|
||||
shells_possibles = [
|
||||
u'/bin/csh',
|
||||
u'/bin/sh', # tout caca
|
||||
u'/bin/dash', # un bash light
|
||||
u'/usr/bin/rc',
|
||||
u'/usr/bin/ksh', # symlink vers zsh
|
||||
u'/bin/ksh', # symlink vers zsh
|
||||
u'/usr/bin/tcsh', # TENEX C Shell (csh++)
|
||||
u'/bin/tcsh', # TENEX C Shell (csh++)
|
||||
u'/bin/bash', # the Bourne-Again SHell
|
||||
u'/bin/zsh', # the Z shell
|
||||
u'/usr/bin/zsh', # the Z shell
|
||||
u'/usr/bin/screen',
|
||||
u'/bin/rbash', # Bash restreint
|
||||
u'/usr/bin/rssh', # restricted secure shell allowing only scp and/or sftp
|
||||
u'/usr/local/bin/badPassSh', # demande de changer de mot de passe
|
||||
u'/usr/bin/passwd', # idem
|
||||
u'/usr/local/bin/disconnect_shell', # déconnexion crans
|
||||
u'/usr/scripts/surveillance/disconnect_shell', # idem
|
||||
u'/usr/sbin/nologin', # This account is currently not available.
|
||||
u'/bin/false', # vraiement méchant
|
||||
u'/usr/bin/es', # n'exsite plus
|
||||
u'/usr/bin/esh', # n'existe plus
|
||||
u'', # le shell vide pour pouvoir les punis
|
||||
]
|
||||
|
||||
shells_gest_crans_order = [
|
||||
"zsh",
|
||||
"bash",
|
||||
"tcsh",
|
||||
"screen",
|
||||
"rbash",
|
||||
"rssh",
|
||||
"badPassSh",
|
||||
"disconnect_shell"
|
||||
]
|
||||
|
||||
shells_gest_crans_order = ["zsh", "bash", "tcsh", "screen", "rbash", "rssh",
|
||||
"badPassSh", "disconnect_shell"]
|
||||
shells_gest_crans = {
|
||||
"zsh": {"path":"/bin/zsh", "desc":"Le Z SHell, shell par defaut sur zamok"},
|
||||
"bash": {"path":"/bin/bash", "desc":"Le Boune-Again SHell, shell par defaut de la plupart des linux"},
|
||||
"tcsh": {"path":"/bin/tcsh", "desc":"C SHell ++"},
|
||||
"screen":{"path":'/usr/bin/screen', "desc":"Un gestionnaire de fenêtre dans un terminal"},
|
||||
"rbash": {"path":"/bin/rbash", "desc":"Un bash très restreint, voir man rbash"},
|
||||
"rssh": {"path":"/usr/bin/rssh", "desc":"Shell ne permetant que les transferts de fichiers via scp ou sftp"},
|
||||
"badPassSh":{"path":"/usr/local/bin/badPassSh", "desc":"Demande de changer de mot de passe à la connexion"},
|
||||
"disconnect_shell":{"path":"/usr/local/bin/disconnect_shell", "desc":"Shell pour les suspensions de compte avec message explicatif"},
|
||||
"zsh" : {
|
||||
"path" : "/bin/zsh",
|
||||
"desc" : "Le Z SHell, shell par defaut sur zamok"
|
||||
},
|
||||
"bash" : {
|
||||
"path" : "/bin/bash",
|
||||
"desc" : "Le Boune-Again SHell, shell par defaut de la plupart des linux"
|
||||
},
|
||||
"tcsh" : {
|
||||
"path" : "/bin/tcsh",
|
||||
"desc" : "C SHell ++"
|
||||
},
|
||||
"screen" : {
|
||||
"path" : '/usr/bin/screen',
|
||||
"desc" : "Un gestionnaire de fenêtre dans un terminal"
|
||||
},
|
||||
"rbash" : {
|
||||
"path" : "/bin/rbash",
|
||||
"desc" : "Un bash très restreint, voir man rbash"
|
||||
},
|
||||
"rssh" : {
|
||||
"path" : "/usr/bin/rssh",
|
||||
"desc" : "Shell ne permetant que les transferts de fichiers via scp ou sftp"
|
||||
},
|
||||
"badPassSh" : {
|
||||
"path" : "/usr/local/bin/badPassSh",
|
||||
"desc" : "Demande de changer de mot de passe à la connexion"
|
||||
},
|
||||
"disconnect_shell" : {
|
||||
"path" : "/usr/local/bin/disconnect_shell",
|
||||
"desc" : "Shell pour les suspensions de compte avec message explicatif"
|
||||
},
|
||||
}
|
||||
# Quels droits donnent l'appartenance à quel groupe Unix ?
|
||||
droits_groupes = {'adm' : [u'Nounou'],
|
||||
'respbats' : [u'Imprimeur', u'Cableur', u'Nounou'],
|
||||
'apprentis' : [u'Apprenti'],
|
||||
'moderateurs' : [u'Moderateur'],
|
||||
'disconnect' : [u'Bureau'],
|
||||
'imprimeurs' : [u'Imprimeur', u'Nounou', u'Tresorier'],
|
||||
'bureau' : [u'Bureau'],
|
||||
'webadm' : [u'Webmaster'],
|
||||
'webradio' : [u'Webradio'],
|
||||
}
|
||||
droits_groupes = {
|
||||
'adm' : [
|
||||
u'Nounou',
|
||||
],
|
||||
'respbats' : [
|
||||
u'Imprimeur',
|
||||
u'Cableur',
|
||||
u'Nounou',
|
||||
],
|
||||
'apprentis' : [
|
||||
u'Apprenti',
|
||||
],
|
||||
'moderateurs' : [
|
||||
u'Moderateur',
|
||||
],
|
||||
'disconnect' : [
|
||||
u'Bureau',
|
||||
],
|
||||
'imprimeurs' : [
|
||||
u'Imprimeur',
|
||||
u'Nounou',
|
||||
u'Tresorier',
|
||||
],
|
||||
'bureau' : [
|
||||
u'Bureau',
|
||||
],
|
||||
'webadm' : [
|
||||
u'Webmaster',
|
||||
],
|
||||
'webradio' : [
|
||||
u'Webradio',
|
||||
],
|
||||
}
|
||||
|
||||
####### Les modes de paiement accepté par le crans
|
||||
|
||||
modePaiement = ['liquide', 'paypal', 'solde', 'cheque', 'carte', 'comnpay', 'arbitraire',]
|
||||
modePaiement = [
|
||||
'liquide',
|
||||
'paypal',
|
||||
'solde',
|
||||
'cheque',
|
||||
'carte',
|
||||
'comnpay',
|
||||
'arbitraire',
|
||||
'note',
|
||||
]
|
||||
|
||||
####### Les ML
|
||||
# Le + devant un nom de ML indique une synchronisation
|
||||
# ML <-> fonction partielle : il n'y a pas d'effacement automatique
|
||||
# des abonnés si le droit est retiré
|
||||
droits_mailing_listes = {'roots' : [ u'Nounou', u'Apprenti'],
|
||||
'mailman' : [ u'Nounou'],
|
||||
'+nounou' : [ u'Nounou', u'Apprenti'],
|
||||
'respbats' : [ u'Cableur', u'Nounou', u'Bureau'],
|
||||
'moderateurs' : [ u'Moderateur', u'Bureau'],
|
||||
'disconnect' : [ u'Nounou', u'Bureau'],
|
||||
'impression' : [ u'Imprimeur'],
|
||||
'bureau' : [u'Bureau'],
|
||||
'tresorier' : [u'Tresorier'],
|
||||
'apprentis' : [u'Apprenti'],
|
||||
'+ca' : [u'Bureau', u'Apprenti', u'Nounou', u'Cableur'],
|
||||
droits_mailing_listes = {
|
||||
'roots' : [
|
||||
u'Nounou',
|
||||
u'Apprenti',
|
||||
],
|
||||
'mailman' : [
|
||||
u'Nounou',
|
||||
],
|
||||
'+nounou' : [
|
||||
u'Nounou',
|
||||
u'Apprenti',
|
||||
],
|
||||
'respbats' : [
|
||||
u'Cableur',
|
||||
u'Nounou',
|
||||
u'Bureau',
|
||||
],
|
||||
'moderateurs' : [
|
||||
u'Moderateur',
|
||||
u'Bureau',
|
||||
],
|
||||
'disconnect' : [
|
||||
u'Nounou',
|
||||
u'Bureau',
|
||||
],
|
||||
'impression' : [
|
||||
u'Imprimeur',
|
||||
],
|
||||
'bureau' : [
|
||||
u'Bureau',
|
||||
],
|
||||
'tresorier' : [
|
||||
u'Tresorier',
|
||||
],
|
||||
'apprentis' : [
|
||||
u'Apprenti',
|
||||
],
|
||||
'+ca' : [
|
||||
u'Bureau',
|
||||
u'Apprenti',
|
||||
u'Nounou',
|
||||
u'Cableur',
|
||||
],
|
||||
'+federez' : [
|
||||
u'Bureau',
|
||||
u'Apprenti',
|
||||
u'Nounou',
|
||||
],
|
||||
'+install-party' : [
|
||||
u'Bureau',
|
||||
u'Apprenti',
|
||||
u'Nounou',
|
||||
],
|
||||
|
||||
'+federez' : [u'Bureau', u'Apprenti', u'Nounou'],
|
||||
'+install-party' : [u'Bureau', u'Apprenti', u'Nounou'],
|
||||
|
||||
# Correspondance partielle nécessaire... Des adresses non-crans sont inscrites à ces ML.
|
||||
'+dsi-crans' : [u'Nounou', u'Bureau'],
|
||||
'+crous-crans' : [u'Nounou', u'Bureau'],
|
||||
|
||||
'+wrc' : [u'Webradio'],
|
||||
}
|
||||
# Correspondance partielle nécessaire... Des adresses non-crans sont inscrites à ces ML.
|
||||
'+dsi-crans' : [
|
||||
u'Nounou',
|
||||
u'Bureau',
|
||||
],
|
||||
'+crous-crans' : [
|
||||
u'Nounou',
|
||||
u'Bureau',
|
||||
],
|
||||
'+wrc' : [
|
||||
u'Webradio',
|
||||
],
|
||||
}
|
||||
|
||||
#: Répertoire de stockage des objets détruits
|
||||
cimetiere = '/home/cimetiere'
|
||||
|
@ -160,21 +273,21 @@ ISCSI_MAP_FILE = "/usr/scripts/var/iscsi_names_%s.py"
|
|||
# IANA_id correspond à l'entier attribué par l'IANA pour l'algorithm dans les champs DNS SSHFP
|
||||
# ssh_algo correspond a la première chaine de caractères donnant le nom de l'algorithme de chiffrement lorsque la clef ssh est dans le format openssh (algo key comment)
|
||||
sshfp_algo = {
|
||||
"rsa" : (1, "ssh-rsa"),
|
||||
"dsa" : (2, "ssh-dss"),
|
||||
"ecdsa-256" : (3, "ecdsa-sha2-nistp256"),
|
||||
"ecdsa-384" : (3, "ecdsa-sha2-nistp384"),
|
||||
"ecdsa-521" : (3, "ecdsa-sha2-nistp521"),
|
||||
"ecdsa" : (3, "ecdsa-sha2-nistp521"),
|
||||
}
|
||||
"rsa" : (1, "ssh-rsa"),
|
||||
"dsa" : (2, "ssh-dss"),
|
||||
"ecdsa-256" : (3, "ecdsa-sha2-nistp256"),
|
||||
"ecdsa-384" : (3, "ecdsa-sha2-nistp384"),
|
||||
"ecdsa-521" : (3, "ecdsa-sha2-nistp521"),
|
||||
"ecdsa" : (3, "ecdsa-sha2-nistp521"),
|
||||
}
|
||||
|
||||
sshfs_ralgo = {}
|
||||
for key, value in sshfp_algo.items():
|
||||
sshfs_ralgo[value[1]] = (value[0], key)
|
||||
|
||||
sshfp_hash = {
|
||||
"sha1" : 1,
|
||||
"sha256" : 2,
|
||||
"sha1" : 1,
|
||||
"sha256" : 2,
|
||||
}
|
||||
|
||||
sshkey_max_age = int(9.869604401089358 * (365.25 * 24 * 3600))
|
||||
|
@ -212,40 +325,74 @@ plage_ens = '138.231.0.0/16'
|
|||
# clefs qui cassent la bijectivité, mais qui peuvent servir.
|
||||
# NETs est l'union des deux
|
||||
NETs_primaires = {
|
||||
'serveurs' : ['138.231.136.0/24'],
|
||||
'adherents' : ['138.231.137.0/24', '138.231.138.0/23', '138.231.140.0/22'],
|
||||
'wifi-adh' : ['138.231.144.0/22',
|
||||
'138.231.148.32/27',
|
||||
'138.231.148.64/26',
|
||||
'138.231.148.128/25',
|
||||
'138.231.149.0/24',
|
||||
'138.231.150.0/23',
|
||||
],
|
||||
'bornes' : [
|
||||
'138.231.148.0/27',
|
||||
],
|
||||
'adm' : ['10.231.136.0/24'],
|
||||
'personnel-ens' : ['10.2.9.0/24'],
|
||||
'gratuit' : ['10.42.0.0/16'],
|
||||
'accueil' : ['10.51.0.0/16'],
|
||||
'federez' : ['10.53.0.0/16'],
|
||||
'isolement' : ['10.52.0.0/16'],
|
||||
'evenementiel' : ['10.231.137.0/24'],
|
||||
'multicast' : ['239.0.0.0/8'],
|
||||
'ens' : ['138.231.135.0/24'],
|
||||
}
|
||||
'serveurs' : [
|
||||
'138.231.136.0/24',
|
||||
],
|
||||
'adherents' : [
|
||||
'138.231.137.0/24',
|
||||
'138.231.138.0/23',
|
||||
'138.231.140.0/22',
|
||||
],
|
||||
'wifi-adh' : [
|
||||
'138.231.144.0/22',
|
||||
'138.231.148.32/27',
|
||||
'138.231.148.64/26',
|
||||
'138.231.148.128/25',
|
||||
'138.231.149.0/24',
|
||||
'138.231.150.0/23',
|
||||
],
|
||||
'bornes' : [
|
||||
'138.231.148.0/27',
|
||||
],
|
||||
'adm' : [
|
||||
'10.231.136.0/24'
|
||||
],
|
||||
'personnel-ens' : [
|
||||
'10.2.9.0/24'
|
||||
],
|
||||
'gratuit' : [
|
||||
'10.42.0.0/16'
|
||||
],
|
||||
'accueil' : [
|
||||
'10.51.0.0/16'
|
||||
],
|
||||
'federez' : [
|
||||
'10.53.0.0/16'
|
||||
],
|
||||
'isolement' : [
|
||||
'10.52.0.0/16'
|
||||
],
|
||||
'evenementiel' : [
|
||||
'10.231.137.0/24'
|
||||
],
|
||||
'multicast' : [
|
||||
'239.0.0.0/8'
|
||||
],
|
||||
'ens' : [
|
||||
'138.231.135.0/24'
|
||||
],
|
||||
}
|
||||
|
||||
NETs_secondaires = {
|
||||
'all' : ['138.231.136.0/21', '138.231.144.0/21'],
|
||||
'wifi': ['138.231.144.0/21'],
|
||||
'fil' : ['138.231.136.0/21'],
|
||||
}
|
||||
'all' : [
|
||||
'138.231.136.0/21',
|
||||
'138.231.144.0/21',
|
||||
],
|
||||
'wifi': [
|
||||
'138.231.144.0/21',
|
||||
],
|
||||
'fil' : [
|
||||
'138.231.136.0/21',
|
||||
],
|
||||
}
|
||||
|
||||
NETs = {}
|
||||
NETs.update(NETs_primaires)
|
||||
NETs.update(NETs_secondaires)
|
||||
|
||||
NETs_regexp = { 'all' : '^138\.231\.1(3[6789]|4[0123456789]|5[01])\.\d+$' }
|
||||
NETs_regexp = {
|
||||
'all' : r'^138\.231\.1(3[6789]|4[0123456789]|5[01])\.\d+$'
|
||||
}
|
||||
|
||||
# Classes de rid
|
||||
# Merci d'essayer de les faire correspondre avec les réseaux
|
||||
|
@ -282,13 +429,13 @@ rid_primaires = {
|
|||
'personnel-ens' : [(55296, 55551),],
|
||||
# Un unique rid pour les machines multicast
|
||||
'multicast' : [(65535, 65535),],
|
||||
}
|
||||
}
|
||||
|
||||
rid_secondaires = {
|
||||
# Rid pour les machines filaire ipv4
|
||||
'fil' : [(0, 2047),],
|
||||
'wifi' : [(2048, 4095), (34816, 35071),],
|
||||
}
|
||||
}
|
||||
|
||||
rid = {}
|
||||
rid.update(rid_primaires)
|
||||
|
@ -314,24 +461,59 @@ ipv6_machines_speciales = {
|
|||
}
|
||||
|
||||
# Les préfixes ipv6 publics
|
||||
prefix = { 'subnet' : [ '2a01:240:fe3d::/48' ],
|
||||
'serveurs' : [ '2a01:240:fe3d:4::/64' ],
|
||||
'adherents' : [ '2a01:240:fe3d:4::/64' ],
|
||||
'fil' : [ '2a01:240:fe3d:4::/64' ],
|
||||
'adm' : [ '2a01:240:fe3d:c804::/64' ],
|
||||
'adm-v6' : [ '2a01:240:fe3d:c804::/64' ],
|
||||
'wifi' : [ '2a01:240:fe3d:c04::/64' ],
|
||||
'serveurs-v6' : [ '2a01:240:fe3d:c04::/64' ],
|
||||
'adherents-v6' : [ '2a01:240:fe3d:4::/64' ],
|
||||
'wifi-adh-v6' : [ '2a01:240:fe3d:c04::/64' ],
|
||||
'personnel-ens' : [ '2a01:240:fe3d:4::/64' ],
|
||||
'sixxs2' : [ '2a01:240:fe00:68::/64' ],
|
||||
'evenementiel' : [ '2a01:240:fe3d:d2::/64' ],
|
||||
'bornes' : [ '2a01:240:fe3d:c04::/64' ],
|
||||
'bornes-v6' : [ '2a01:240:fe3d:c04::/64' ],
|
||||
'wifi-adh' : [ '2a01:240:fe3d:c04::/64' ],
|
||||
'v6only' : [ '2001:470:c8b9:a4::/64' ],
|
||||
}
|
||||
prefix = {
|
||||
'subnet' : [
|
||||
'2a01:240:fe3d::/48',
|
||||
],
|
||||
'serveurs' : [
|
||||
'2a01:240:fe3d:4::/64',
|
||||
],
|
||||
'adherents' : [
|
||||
'2a01:240:fe3d:4::/64',
|
||||
],
|
||||
'fil' : [
|
||||
'2a01:240:fe3d:4::/64',
|
||||
],
|
||||
'adm' : [
|
||||
'2a01:240:fe3d:c804::/64',
|
||||
],
|
||||
'adm-v6' : [
|
||||
'2a01:240:fe3d:c804::/64',
|
||||
],
|
||||
'wifi' : [
|
||||
'2a01:240:fe3d:c04::/64',
|
||||
],
|
||||
'serveurs-v6' : [
|
||||
'2a01:240:fe3d:c04::/64',
|
||||
],
|
||||
'adherents-v6' : [
|
||||
'2a01:240:fe3d:4::/64',
|
||||
],
|
||||
'wifi-adh-v6' : [
|
||||
'2a01:240:fe3d:c04::/64',
|
||||
],
|
||||
'personnel-ens' : [
|
||||
'2a01:240:fe3d:4::/64',
|
||||
],
|
||||
'sixxs2' : [
|
||||
'2a01:240:fe00:68::/64',
|
||||
],
|
||||
'evenementiel' : [
|
||||
'2a01:240:fe3d:d2::/64',
|
||||
],
|
||||
'bornes' : [
|
||||
'2a01:240:fe3d:c04::/64',
|
||||
],
|
||||
'bornes-v6' : [
|
||||
'2a01:240:fe3d:c04::/64',
|
||||
],
|
||||
'wifi-adh' : [
|
||||
'2a01:240:fe3d:c04::/64',
|
||||
],
|
||||
'v6only' : [
|
||||
'2001:470:c8b9:a4::/64',
|
||||
],
|
||||
}
|
||||
|
||||
# Préfixes ipv6 internes (ula)
|
||||
int_prefix = {
|
||||
|
@ -340,10 +522,12 @@ int_prefix = {
|
|||
}
|
||||
|
||||
# Domaines dans lesquels les machines sont placées suivant leur type
|
||||
domains = { 'machineFixe': 'crans.org',
|
||||
'machineCrans': 'crans.org',
|
||||
'machineWifi': 'wifi.crans.org',
|
||||
'borneWifi': 'wifi.crans.org' }
|
||||
domains = {
|
||||
'machineFixe': 'crans.org',
|
||||
'machineCrans': 'crans.org',
|
||||
'machineWifi': 'wifi.crans.org',
|
||||
'borneWifi': 'wifi.crans.org',
|
||||
}
|
||||
|
||||
# VLans
|
||||
vlans = {
|
||||
|
@ -363,8 +547,6 @@ vlans = {
|
|||
'v6only': 6,
|
||||
# Vlan isolement
|
||||
'isolement' : 9,
|
||||
# Vlan de tests de chiffrement DSI
|
||||
'chiffrement': 11,
|
||||
# VLan des appartements de l'ENS
|
||||
'appts': 21,
|
||||
# Vlan federez-wifi
|
||||
|
@ -377,33 +559,45 @@ vlans = {
|
|||
'iscsi': 42,
|
||||
# freebox (pour faire descendre la connexion au 0B)
|
||||
'freebox': 8,
|
||||
}
|
||||
}
|
||||
|
||||
filter_policy = { 'komaz' : { 'policy_input' : 'ACCEPT',
|
||||
'policy_forward' : 'ACCEPT',
|
||||
'policy_output' : 'ACCEPT'
|
||||
},
|
||||
'zamok' : { 'policy_input' : 'ACCEPT',
|
||||
'policy_forward' : 'DROP',
|
||||
'policy_output' : 'ACCEPT'
|
||||
},
|
||||
'default' : { 'policy_input' : 'ACCEPT',
|
||||
'policy_forward' : 'ACCEPT',
|
||||
'policy_output' : 'ACCEPT'
|
||||
}
|
||||
}
|
||||
filter_policy = {
|
||||
'komaz' : {
|
||||
'policy_input' : 'ACCEPT',
|
||||
'policy_forward' : 'ACCEPT',
|
||||
'policy_output' : 'ACCEPT',
|
||||
},
|
||||
'zamok' : {
|
||||
'policy_input' : 'ACCEPT',
|
||||
'policy_forward' : 'DROP',
|
||||
'policy_output' : 'ACCEPT',
|
||||
},
|
||||
'default' : {
|
||||
'policy_input' : 'ACCEPT',
|
||||
'policy_forward' : 'ACCEPT',
|
||||
'policy_output' : 'ACCEPT',
|
||||
}
|
||||
}
|
||||
|
||||
# Cf RFC 4890
|
||||
authorized_icmpv6 = ['echo-request', 'echo-reply', 'destination-unreachable',
|
||||
'packet-too-big', 'ttl-zero-during-transit', 'parameter-problem']
|
||||
authorized_icmpv6 = [
|
||||
'echo-request',
|
||||
'echo-reply',
|
||||
'destination-unreachable',
|
||||
'packet-too-big',
|
||||
'ttl-zero-during-transit',
|
||||
'parameter-problem',
|
||||
]
|
||||
|
||||
output_file = { 4 : '/tmp/ipt_rules',
|
||||
6 : '/tmp/ip6t_rules'
|
||||
}
|
||||
output_file = {
|
||||
4 : '/tmp/ipt_rules',
|
||||
6 : '/tmp/ip6t_rules',
|
||||
}
|
||||
|
||||
file_pickle = { 4 : '/tmp/ipt_pickle',
|
||||
6 : '/tmp/ip6t_pickle'
|
||||
}
|
||||
file_pickle = {
|
||||
4 : '/tmp/ipt_pickle',
|
||||
6 : '/tmp/ip6t_pickle',
|
||||
}
|
||||
|
||||
##################################################################################
|
||||
#: Items de la blackliste
|
||||
|
@ -427,7 +621,7 @@ blacklist_sanctions = [
|
|||
]
|
||||
|
||||
#: Blacklistes redirigeant le port 80 en http vers le portail captif (avec des explications)
|
||||
blacklist_sanctions_soft = [
|
||||
blacklist_sanctions_soft = [
|
||||
'ipv6_ra',
|
||||
'mail_invalide',
|
||||
'virus',
|
||||
|
@ -441,10 +635,24 @@ blacklist_bridage_upload = ['autodisc_upload', 'upload']
|
|||
|
||||
##################################################################################
|
||||
|
||||
adm_users = [ 'root', 'identd', 'daemon', 'postfix', 'freerad', 'amavis',
|
||||
'nut', 'respbats', 'list', 'sqlgrey', 'ntpd', 'lp' ]
|
||||
adm_users = [
|
||||
'root',
|
||||
'identd',
|
||||
'daemon',
|
||||
'postfix',
|
||||
'freerad',
|
||||
'amavis',
|
||||
'nut',
|
||||
'respbats',
|
||||
'list',
|
||||
'sqlgrey',
|
||||
'ntpd',
|
||||
'lp',
|
||||
]
|
||||
|
||||
open_ports = { 'tcp' : '22' }
|
||||
open_ports = {
|
||||
'tcp' : '22',
|
||||
}
|
||||
|
||||
# Debit max sur le vlan de la connexion gratuite
|
||||
debit_max_radin = 1000000
|
||||
|
@ -454,13 +662,83 @@ debit_max_gratuit = 1000000
|
|||
## Vlan accueil et isolement ##
|
||||
###############################
|
||||
accueil_route = {
|
||||
'138.231.136.1':{'tcp':['80','443', '22'],'hosts':['intranet.crans.org', 'ssh.crans.org', 'zamok.crans.org']},
|
||||
'138.231.136.67':{'tcp':['80','443'],'hosts':['www.crans.org', 'wiki.crans.org', 'wifi.crans.org']},
|
||||
'138.231.136.98':{'tcp':['20','21','80','111','1024:65535'],'udp':['69','1024:65535'], 'hosts':['ftp.crans.org']},
|
||||
'138.231.136.130':{'tcp':['80','443'],'hosts':['intranet2.crans.org']},
|
||||
'138.231.136.18':{'tcp':['80','443'],'hosts':['cas.crans.org', 'login.crans.org', 'auth.crans.org']},
|
||||
'213.154.225.236':{'tcp':['80','443'], 'hosts':['crl.cacert.org']},
|
||||
'213.154.225.237':{'tcp':['80','443'], 'hosts':['ocsp.cacert.org']},
|
||||
'138.231.136.1' : {
|
||||
'tcp' : [
|
||||
'80',
|
||||
'443',
|
||||
'22'
|
||||
],
|
||||
'hosts' : [
|
||||
'ssh.crans.org',
|
||||
'zamok.crans.org',
|
||||
],
|
||||
},
|
||||
'138.231.136.67' : {
|
||||
'tcp' : [
|
||||
'80',
|
||||
'443',
|
||||
],
|
||||
'hosts' : [
|
||||
'www.crans.org',
|
||||
'wiki.crans.org',
|
||||
'wifi.crans.org',
|
||||
],
|
||||
},
|
||||
'138.231.136.98' : {
|
||||
'tcp' : [
|
||||
'20',
|
||||
'21',
|
||||
'80',
|
||||
'111',
|
||||
'1024:65535',
|
||||
],
|
||||
'udp' : [
|
||||
'69',
|
||||
'1024:65535',
|
||||
],
|
||||
'hosts' : [
|
||||
'ftp.crans.org',
|
||||
],
|
||||
},
|
||||
'138.231.136.130' : {
|
||||
'tcp' : [
|
||||
'80',
|
||||
'443',
|
||||
],
|
||||
'hosts' : [
|
||||
'intranet2.crans.org',
|
||||
'intranet.crans.org',
|
||||
],
|
||||
},
|
||||
'138.231.136.18' : {
|
||||
'tcp' : [
|
||||
'80',
|
||||
'443',
|
||||
],
|
||||
'hosts' : [
|
||||
'cas.crans.org',
|
||||
'login.crans.org',
|
||||
'auth.crans.org',
|
||||
],
|
||||
},
|
||||
'213.154.225.236' : {
|
||||
'tcp' : [
|
||||
'80',
|
||||
'443',
|
||||
],
|
||||
'hosts' : [
|
||||
'crl.cacert.org',
|
||||
],
|
||||
},
|
||||
'213.154.225.237' : {
|
||||
'tcp' : [
|
||||
'80',
|
||||
'443',
|
||||
],
|
||||
'hosts' : [
|
||||
'ocsp.cacert.org',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
dhcp_servers = ['dhcp.adm.crans.org', 'isc.adm.crans.org']
|
||||
|
|
|
@ -10,11 +10,17 @@
|
|||
# Délai minimal avant de pouvoir réadhérer.
|
||||
# Ne tient pas compte de la période transitoire, qui est un confort
|
||||
# pour l'administration.
|
||||
delai_readh_jour = 28
|
||||
delai_readh_jour = 32
|
||||
delai_readh = delai_readh_jour * 86400
|
||||
|
||||
duree_adh_an = 1
|
||||
|
||||
# Un compte avec une adhésion valide ne peut être détruit que lorsque celle-ci
|
||||
# est expirée depuis plus que le délai indiqué ici. (secondes)
|
||||
# Ici, on choisit 90 jours.
|
||||
del_post_adh_jours = 90
|
||||
del_post_adh = del_post_adh_jours * 86400
|
||||
|
||||
# Cotisation pour adhérer à l'association. Les services autres que l'accès à
|
||||
# Internet sont offerts une et une fois pour toute aux personnes qui adhèrent,
|
||||
# et ce dès leur première fois. (comprendre : le compte Crans et cie ne sont pas
|
||||
|
|
|
@ -130,6 +130,14 @@ recursiv = {
|
|||
],
|
||||
}
|
||||
|
||||
#: Domaines correspondant à des mails crans
|
||||
mail_crans = [
|
||||
'crans.org',
|
||||
'crans.fr',
|
||||
'crans.eu',
|
||||
'crans.ens-cachan.fr',
|
||||
]
|
||||
|
||||
#: Les ip/net des vlans limité vue par les récursifs
|
||||
menteur_clients = [
|
||||
"138.231.136.210",
|
||||
|
|
|
@ -4,3 +4,4 @@ import sys
|
|||
|
||||
in_encoding = getattr(sys.stdin, 'encoding', None) or "UTF-8"
|
||||
out_encoding = getattr(sys.stdout, 'encoding', None) or "UTF-8"
|
||||
ldap_encoding = "UTF-8"
|
||||
|
|
|
@ -12,10 +12,14 @@ ITEMS = {
|
|||
'designation': u'Cable Ethernet 5m',
|
||||
'pu': 3.,
|
||||
},
|
||||
'ADAPTATEUR': {
|
||||
'designation': u'Adaptateur Ethernet/USB',
|
||||
'ADAPTATEUR_TrendNet': {
|
||||
'designation': u'Adaptateur 10/100 Ethernet/USB-2',
|
||||
'pu': 17.,
|
||||
},
|
||||
'ADAPTATEUR_UGreen': {
|
||||
'designation': u'Adaptateur 10/100/1000 Ethernet/USB-3',
|
||||
'pu': 14.,
|
||||
},
|
||||
'RELIURE': {
|
||||
'designation': u'Reliure plastique',
|
||||
'pu': 0.12,
|
||||
|
@ -37,3 +41,27 @@ ITEMS = {
|
|||
'pu': 28.92,
|
||||
},
|
||||
}
|
||||
|
||||
# Utilisé par gest_crans_lc, contient également le rachargement de solde
|
||||
|
||||
ITEM_SOLDE = {'SOLDE': {'designation': u'Rechargement de solde', 'pu': u'*'}}
|
||||
|
||||
# Dico avec les modes de paiement pour modification du solde
|
||||
|
||||
SOLDE = {
|
||||
'liquide' : u'Espèces',
|
||||
'cheque' : u'Chèque',
|
||||
'carte': u'Carte bancaire',
|
||||
'note': u'Note Kfet',
|
||||
'arbitraire': u'Modification arbitraire du solde',
|
||||
}
|
||||
|
||||
# Dico avec les modes de paiement pour la vente
|
||||
|
||||
VENTE = {
|
||||
'liquide' : u'Espèces',
|
||||
'cheque' : u'Chèque',
|
||||
'carte': u'Carte bancaire',
|
||||
'note': u'Note Kfet',
|
||||
'solde': u'Vente à partir du Solde',
|
||||
}
|
||||
|
|
|
@ -53,12 +53,20 @@ mask = [24]
|
|||
now=datetime.datetime.now()
|
||||
if now.hour >= 6 and now.hour < 19 and now.weekday() < 5 and not is_ferie():
|
||||
#: Débit maximal autorisé
|
||||
debit_max = 150 # mbits per second en connexion de jour
|
||||
debit_max = { 'total' : 250,
|
||||
'out' : 250,
|
||||
'wifi' : 100,
|
||||
'fil' : 150 }
|
||||
# mbits per second en connexion de jour
|
||||
#: Est-ce qu'on est en connexion de jour ou de nuit/week-end ?
|
||||
debit_jour = True
|
||||
else:
|
||||
#: Débit maximal autorisé
|
||||
debit_max = 500 # mbits per second en conn de nuit et du week-end
|
||||
debit_max = { 'total' : 600,
|
||||
'out' : 600,
|
||||
'wifi' : 150,
|
||||
'fil' : 450 }
|
||||
# mbits per second en conn de nuit et du week-end
|
||||
#: Est-ce qu'on est en connexion de jour ou de nuit/week-end ?
|
||||
debit_jour = False
|
||||
|
||||
|
@ -73,7 +81,7 @@ federez_upload_max = 10 #mbytes per second
|
|||
|
||||
# Debit appartement down max
|
||||
# TODO : mettre en place dans komaz.py
|
||||
appt_download_max = debit_max/10
|
||||
appt_download_max = debit_max['total']/10
|
||||
|
||||
#: Liste des réseaux non routables
|
||||
reseaux_non_routables = [ '10.0.0.0/8', '172.16.0.0/12','198.18.0.0/15',
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import itertools
|
||||
import os
|
||||
|
||||
debug = (int(os.environ['DBG_TRIGGER']) == 1) or True
|
||||
debug = (int(os.environ.get('DBG_TRIGGER', 0)) == 1) or True
|
||||
log_level = "info"
|
||||
|
||||
# Serveur maître
|
||||
|
@ -16,6 +16,12 @@ user = "trigger"
|
|||
port = 5671
|
||||
ssl = True
|
||||
|
||||
# TTL en secondes pour les messages en attente.
|
||||
# Une suite d'opérations a faire a un ob_id, qui est un hash.
|
||||
# Quand cette suite traîne depuis trop longtemps en attente sans que rien
|
||||
# ne se passe, on la jette.
|
||||
MSG_TTL = 3600
|
||||
|
||||
# Liste des services associés aux hôtes
|
||||
# useradd : Envoie le mail de bienvenue, et crée le home
|
||||
# userdel : Détruit le home, déconnecte l'utilisateur sur zamok, détruit les indexes dovecot, désinscrit l'adresse crans des mailing listes associées
|
||||
|
|
|
@ -19,7 +19,7 @@ if '/usr/scripts' not in sys.path:
|
|||
from pythondialog import Dialog as PythonDialog
|
||||
from pythondialog import DialogTerminatedBySignal, PythonDialogErrorBeforeExecInChildProcess
|
||||
from pythondialog import error as DialogError
|
||||
from gestion.affich_tools import get_screen_size, coul
|
||||
from gestion import affichage
|
||||
|
||||
debug_enable = False
|
||||
debugf = None
|
||||
|
@ -203,7 +203,7 @@ class Dialog(object):
|
|||
setattr(self, attr, ret)
|
||||
return ret
|
||||
|
||||
def __init__(self, debug_enable=False):
|
||||
def __init__(self, debug_enable=False, dialogrc=False):
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
|
||||
self.debug_enable = debug_enable
|
||||
|
@ -211,6 +211,7 @@ class Dialog(object):
|
|||
# On met un timeout à 10min d'innactivité sur dialog
|
||||
self.timeout = 600
|
||||
self.error_to_raise = (Continue, DialogError, ldap.SERVER_DOWN)
|
||||
self.dialogrc = dialogrc
|
||||
|
||||
_dialog = None
|
||||
@property
|
||||
|
@ -218,7 +219,9 @@ class Dialog(object):
|
|||
"""
|
||||
Renvois l'objet dialog.
|
||||
"""
|
||||
if self._dialog is None:
|
||||
if self.dialogrc:
|
||||
self._dialog = PythonDialog(DIALOGRC=self.dialogrc)
|
||||
else:
|
||||
self._dialog = PythonDialog()
|
||||
self.dialog_last_access = time.time()
|
||||
return self._dialog
|
||||
|
@ -227,7 +230,7 @@ class Dialog(object):
|
|||
"""
|
||||
Nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan
|
||||
"""
|
||||
(lines, cols) = get_screen_size()
|
||||
(cols, lines) = affichage.getTerminalSize()
|
||||
print "\033[48;5;17m"
|
||||
print " "*(lines * cols)
|
||||
cols = int(min(cols/2, 65))
|
||||
|
|
|
@ -9,6 +9,8 @@ Licence : GPLv3
|
|||
import sys
|
||||
import time
|
||||
import datetime
|
||||
import subprocess
|
||||
import pytz
|
||||
import dateutil.relativedelta
|
||||
if '/usr/scripts' not in sys.path:
|
||||
sys.path.append('/usr/scripts')
|
||||
|
@ -18,6 +20,7 @@ import config.cotisation
|
|||
import lc_ldap.objets as objets
|
||||
import lc_ldap.attributs as attributs
|
||||
from lc_ldap.attributs import UniquenessError
|
||||
from lc_ldap import crans_utils
|
||||
|
||||
import proprio
|
||||
from CPS import TailCall, tailcaller, Continue
|
||||
|
@ -45,20 +48,20 @@ class Dialog(proprio.Dialog):
|
|||
'GPGFingerprint' : [a.nounou, a.soi],
|
||||
'Remarques' : [a.cableur, a.nounou],
|
||||
'Droits':[a.nounou, a.bureau],
|
||||
'Blackliste':[a.cableur, a.nounou],
|
||||
'Blackliste':[a.bureau, a.nounou],
|
||||
'Vente':[a.cableur, a.nounou],
|
||||
'Supprimer':[a.nounou, a.bureau],
|
||||
}
|
||||
menu = {
|
||||
'Administratif' : {'text' : "Adhésion, carte étudiant, chartes", "callback":self.adherent_administratif},
|
||||
'Personnel' : {'text' : "Nom, prénom, téléphone... (ajouter l'age ?)", 'callback':self.adherent_personnel},
|
||||
'Administratif' : {'text' : "Adhésion, chartes", "callback":self.adherent_administratif},
|
||||
'Personnel' : {'text' : "Nom, prénom, téléphone, et mail de contact", 'callback':self.adherent_personnel},
|
||||
'Études' : {'text' : "Étude en cours", "callback":self.adherent_etudes},
|
||||
'Chambre' : {'text' : 'Déménagement', "callback":self.adherent_chambre},
|
||||
'Compte' : {'text' : "Gestion du compte crans", "adherent":"proprio", "callback":TailCall(self.proprio_compte, update_obj='adherent'), 'help':"Création/Suppression/Activation/Désactivation du compte, gestion des alias mails crans du compte"},
|
||||
'GPGFingerprint' : {'text':'Ajouter ou supprimer une empeinte GPG', 'attribut':attributs.gpgFingerprint},
|
||||
'Remarques' : {'text':'Ajouter ou supprimer une remarque de la machine', 'attribut':attributs.info},
|
||||
'Remarques' : {'text':'Ajouter ou supprimer une remarque à cet adhérent', 'attribut':attributs.info},
|
||||
'Droits' : {'text':"Modifier les droits alloués à cet adhérent", "callback":self.adherent_droits},
|
||||
'Blackliste' : {'text': 'Modifier les blacklist de la machine', 'callback':self.modif_adherent_blacklist},
|
||||
'Blackliste' : {'text': 'Modifier les blacklist de cet adhérent', 'callback':self.modif_adherent_blacklist},
|
||||
'Vente' : {'text':"Chargement solde crans, vente de cable ou adaptateur ethernet ou autre", "adherent":"proprio", "callback":self.proprio_vente},
|
||||
'Supprimer' : {'text':"Supprimer l'adhérent de la base de donnée", 'callback':TailCall(self.delete_adherent, del_cont=cont(proprio=None))},
|
||||
}
|
||||
|
@ -123,17 +126,13 @@ class Dialog(proprio.Dialog):
|
|||
"Adhésion": [a.cableur, a.nounou],
|
||||
'Connexion': [a.cableur, a.nounou],
|
||||
"Charte MA" : [a.nounou, a.bureau],
|
||||
"Carte Étudiant" : [a.nounou, a.cableur, a.tresorier],
|
||||
}
|
||||
menu = {
|
||||
"Adhésion" : {"text":"Pour toute réadhésion *sans* connexion.", "help":"", "callback":self.adherent_adhesion},
|
||||
'Connexion' : {'text': "Mise à jour de l'accès Internet (effectue la réadhésion si besoin)", "help":"", 'callback':self.adherent_connexion},
|
||||
"Carte Étudiant" : {"text" : "Validation de la carte étudiant", "help":"", "callback":self.adherent_carte_etudiant},
|
||||
"Charte MA" : {"text" : "Signature de la charte des membres actifs", "help":'', "callback":self.adherent_charte},
|
||||
}
|
||||
menu_order = ["Adhésion", 'Connexion']
|
||||
if self.has_right(a.tresorier, adherent) or not adherent.carte_controle():
|
||||
menu_order.append("Carte Étudiant")
|
||||
menu_order.append("Charte MA")
|
||||
def box(default_item=None):
|
||||
return self.dialog.menu(
|
||||
|
@ -221,8 +220,7 @@ class Dialog(proprio.Dialog):
|
|||
|
||||
# Boite si on ne peux pas réahdérer
|
||||
def box_already(end):
|
||||
t_end = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(end))
|
||||
self.dialog.msgbox("Actuellement adhérent jusqu'au %s.\nMerci de revenir lorsqu'il restera moins de %s jours avant la fin." % (t_end, config.cotisation.delai_readh_jour),
|
||||
self.dialog.msgbox("Actuellement adhérent jusqu'au %s.\nMerci de revenir lorsqu'il restera moins de %s jours avant la fin." % (end, config.cotisation.delai_readh_jour),
|
||||
width=0,
|
||||
height=0,
|
||||
timeout=self.timeout,
|
||||
|
@ -230,9 +228,8 @@ class Dialog(proprio.Dialog):
|
|||
|
||||
# Boite de confirmation à l'ahésion
|
||||
def box_adherer(end=None):
|
||||
if end:
|
||||
t_end = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(end))
|
||||
adherer = self.confirm(text="Adhésion jusqu'au %s. Réadhérer ?" % t_end, title="Adhésion de %s %s" % (adherent.get("prenom", [''])[0], adherent["nom"][0]))
|
||||
if end != crans_utils.localized_datetime():
|
||||
adherer = self.confirm(text="Adhésion jusqu'au %s. Réadhérer ?" % end, title="Adhésion de %s %s" % (adherent.get("prenom", [''])[0], adherent["nom"][0]))
|
||||
else:
|
||||
adherer = self.confirm(text="Adhésion pour un an, continuer ?", title="Adhésion de %s %s" % (adherent.get("prenom", [''])[0], adherent["nom"][0]))
|
||||
return adherer
|
||||
|
@ -246,9 +243,8 @@ class Dialog(proprio.Dialog):
|
|||
|
||||
# Génération de la facture pour adhésion
|
||||
def paiement(tag_paiement, adherent, finadhesion, comment, facture, cancel_cont, cont):
|
||||
now = time.time()
|
||||
new_finadhesion = datetime.datetime.fromtimestamp(max(finadhesion, now))
|
||||
new_finadhesion = time.mktime(new_finadhesion.replace(year=new_finadhesion.year + config.cotisation.duree_adh_an).timetuple()) + 86400
|
||||
now = crans_utils.localized_datetime()
|
||||
new_finadhesion = max(finadhesion, now).replace(year=max(finadhesion, now).year + 1)
|
||||
new_debutadhesion = now
|
||||
if facture:
|
||||
facture = self.conn.search(dn=facture.dn, scope=0, mode='rw')[0]
|
||||
|
@ -260,8 +256,8 @@ class Dialog(proprio.Dialog):
|
|||
facture['modePaiement'] = unicode(tag_paiement, 'utf-8')
|
||||
facture['info'] = unicode(comment, 'utf-8')
|
||||
facture['article'].append(config.cotisation.dico_adh)
|
||||
facture["finAdhesion"] = unicode(new_finadhesion)
|
||||
facture["debutAdhesion"] = unicode(new_debutadhesion)
|
||||
facture["finAdhesion"] = new_finadhesion
|
||||
facture["debutAdhesion"] = new_debutadhesion
|
||||
# On peut retarder le credit pour ajouter des contribution pour la connexion internet à la facture
|
||||
if crediter:
|
||||
if self.confirm_item(item=facture,
|
||||
|
@ -284,9 +280,13 @@ class Dialog(proprio.Dialog):
|
|||
raise Continue(cont(adherent=adherent))
|
||||
|
||||
|
||||
finadhesion = adherent.fin_adhesion()
|
||||
now = crans_utils.localized_datetime()
|
||||
try:
|
||||
finadhesion = adherent.fin_adhesion().value
|
||||
except AttributeError:
|
||||
finadhesion = now
|
||||
# Si fin de l'adhésion trop loin dans le futur, rien a faire
|
||||
if finadhesion and finadhesion - config.cotisation.delai_readh > time.time():
|
||||
if finadhesion and (finadhesion - now).days > config.cotisation.delai_readh_jour:
|
||||
self.handle_dialog(cancel_cont if cancel_cont else cont, box_already, finadhesion)
|
||||
raise Continue(cancel_cont if cancel_cont else cont)
|
||||
|
||||
|
@ -340,9 +340,9 @@ class Dialog(proprio.Dialog):
|
|||
|
||||
# Une boite pour choisir un nombre de mois pour prolonger la connexion
|
||||
def box(finconnexion, default_item=None):
|
||||
t_end = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(finconnexion))
|
||||
t_end = finconnexion
|
||||
return self.dialog.menu(
|
||||
"Connexion jusqu'au %s" % t_end if finconnexion else "N'a jamais été connecté",
|
||||
"Connexion jusqu'au %s" % t_end if finconnexion != datetime.datetime.fromtimestamp(0, tz=pytz.utc) else "N'a jamais été connecté",
|
||||
width=0,
|
||||
height=0,
|
||||
menu_height=0,
|
||||
|
@ -357,17 +357,16 @@ class Dialog(proprio.Dialog):
|
|||
|
||||
# Génération et crédit de la facture
|
||||
def todo(adherent, mois, finadhesion, finconnexion, cancel_cont, cont, facture=None, tag_paiment=None, comment=None):
|
||||
now = time.time()
|
||||
new_finconnexion = datetime.datetime.fromtimestamp(max(finconnexion, now))
|
||||
# On ajoute 3600 secondes sur suggestion de Raphaël Bonaque (<bonaque@crans.org>), pour tenir compte des malheureux qui
|
||||
# pourraient subir le changement d'heure.
|
||||
new_finconnexion = time.mktime((new_finconnexion + dateutil.relativedelta.relativedelta(months=mois)).timetuple()) + 3600
|
||||
now = crans_utils.localized_datetime()
|
||||
new_debutconnexion = max(now, finconnexion)
|
||||
con_month = new_debutconnexion.month
|
||||
con_year = new_debutconnexion.year
|
||||
new_finconnexion = max(finconnexion, now).replace(year=con_year + ((con_month + mois) // 13), month= (con_month + mois - 1) % 12 + 1)
|
||||
|
||||
if new_finconnexion > finadhesion:
|
||||
t_end_adh = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(finadhesion))
|
||||
t_end_conn = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(new_finconnexion))
|
||||
if new_finconnexion - finadhesion > 30 * 3600 * 24:
|
||||
if (new_finconnexion - finadhesion.value).days > 0:
|
||||
t_end_adh = finadhesion.value
|
||||
t_end_conn = finconnexion
|
||||
if (new_finconnexion - finadhesion.value).days > 30:
|
||||
raise ValueError("Impossible de prolonger la connexion jusqu'au %s plus d'un mois après la fin de l'adhésion au %s" % (t_end_conn, t_end_adh))
|
||||
else:
|
||||
if not self.confirm("La fin de la connexion de l'adhérent (%s) tombera après la fin de son adhésion (%s).\n" \
|
||||
|
@ -377,8 +376,8 @@ class Dialog(proprio.Dialog):
|
|||
if facture:
|
||||
with self.conn.search(dn=facture.dn, scope=0, mode='rw')[0] as facture:
|
||||
if mois:
|
||||
facture["finConnexion"] = unicode(new_finconnexion)
|
||||
facture["debutConnexion"] = unicode(new_debutconnexion)
|
||||
facture["finConnexion"] = new_finconnexion
|
||||
facture["debutConnexion"] = new_debutconnexion
|
||||
facture["article"].append(config.cotisation.dico_cotis(mois))
|
||||
if self.confirm_item(item=facture,
|
||||
text=u"Le paiement de %sEUR a-t-il bien été reçu (mode : %s) ?\n" % (facture.total(), facture['modePaiement'][0]),
|
||||
|
@ -401,8 +400,8 @@ class Dialog(proprio.Dialog):
|
|||
facture['modePaiement'] = unicode(tag_paiment, 'utf-8')
|
||||
facture['article'].append(config.cotisation.dico_cotis(mois))
|
||||
facture['info'] = unicode(comment, 'utf-8')
|
||||
facture["finConnexion"] = unicode(new_finconnexion)
|
||||
facture["debutConnexion"] = unicode(new_debutconnexion)
|
||||
facture["finConnexion"] = new_finconnexion
|
||||
facture["debutConnexion"] = new_debutconnexion
|
||||
if self.confirm_item(item=facture,
|
||||
text=u"Le paiement de %sEUR a-t-il bien été reçu (mode : %s) ?\n" % (facture.total(), tag_paiment),
|
||||
title=u"Validation du paiement",
|
||||
|
@ -412,7 +411,7 @@ class Dialog(proprio.Dialog):
|
|||
else:
|
||||
if not self.confirm(text=u"Le paiement n'a pas été reçue.\n Annuler ?", title="Annulation de l'adhésion", defaultno=True):
|
||||
raise Continue(cancel_cont)
|
||||
raise Continue(cont(adherent=adherent))
|
||||
raise Continue(cont)
|
||||
|
||||
def todo_mois(tag, self_cont):
|
||||
if tag == 'An':
|
||||
|
@ -434,16 +433,18 @@ class Dialog(proprio.Dialog):
|
|||
finconnexion = adherent.fin_connexion()
|
||||
|
||||
# Si l'adhésion fini avant la connexion
|
||||
if finadhesion <= time.time() or finadhesion <= finconnexion:
|
||||
if finadhesion <= crans_utils.localized_datetime() or finadhesion <= finconnexion:
|
||||
if finadhesion:
|
||||
t_end_adh = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(finadhesion))
|
||||
# Si l'adhésion est déjà fini
|
||||
if finadhesion <= time.time():
|
||||
self.dialog.msgbox(text=u"L'adhésion a expiré le %s, il va falloir réadhérer d'abord" % t_end_adh, title="Réadhésion nécessaire", width=0, height=0, timeout=self.timeout)
|
||||
if finadhesion <= crans_utils.localized_datetime():
|
||||
if finadhesion == datetime.datetime.fromtimestamp(0, tz=pytz.utc):
|
||||
self.dialog.msgbox(text=u"L'adhérent n'a jamais adhéré à l'association, on va d'abord le faire adhérer (10€)", title="Adhésion nécessaire", width=0, height=0, timeout=self.timeout)
|
||||
else:
|
||||
self.dialog.msgbox(text=u"L'adhésion a expiré le %s, il va falloir réadhérer d'abord (10€)" % finadhesion, title="Réadhésion nécessaire", width=0, height=0, timeout=self.timeout)
|
||||
# Sinon si elle fini avant la fin de la connexion courante
|
||||
elif finadhesion < finconnexion:
|
||||
t_end_conn = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(finconnexion))
|
||||
self.dialog.msgbox(text=u"L'adhésion de termine le %s, avant la fin de la connexion le %s, il va falloir réadhérer d'abord" % (t_end_adh, t_end_conn), title="Réadhésion nécessaire", width=0, height=0, timeout=self.timeout)
|
||||
t_end_conn = finconnexion
|
||||
self.dialog.msgbox(text=u"L'adhésion de termine le %s, avant la fin de la connexion le %s, il va falloir réadhérer d'abord (10€)" % (finadhesion, t_end_conn), title="Réadhésion nécessaire", width=0, height=0, timeout=self.timeout)
|
||||
# Échouera si on essaie de prolonger la connexion au dela de l'adhésion et que l'adhésion est encore valable plus de quinze jours
|
||||
return self.adherent_adhesion(cont=self_cont, cancel_cont=cont, adherent=adherent, crediter=False)
|
||||
|
||||
|
@ -483,76 +484,6 @@ class Dialog(proprio.Dialog):
|
|||
return self.proprio_choose_paiement(proprio=adherent, cont=self_cont, cancel_cont=lcont)
|
||||
return cont
|
||||
|
||||
def adherent_carte_etudiant(self, cont, adherent, values={}, cancel_cont=None):
|
||||
# Dictionnaire décrivant quelle est la valeur booléenne à donner à l'absence de l'attribut
|
||||
a = attributs
|
||||
choices = []
|
||||
if self.has_right(a.tresorier, adherent) or not adherent.carte_controle():
|
||||
choices.append((a.carteEtudiant.ldap_name, "Carte étudiant présentée", 1 if adherent[a.carteEtudiant.ldap_name] or values.get(a.carteEtudiant.ldap_name, False) else 0))
|
||||
if self.has_right(a.tresorier, adherent):
|
||||
choices.append(("controleCarte", "La carte a-t-elle été controlée", 1 if adherent.carte_controle() or values.get("controleCarte", False) else 0))
|
||||
|
||||
if not choices:
|
||||
self.dialog.msgbox("Carte d'étudiant déjà validée et non modifiable", title="Gestion de la carte étudiant", width=0, height=0)
|
||||
if cancel_cont:
|
||||
cancel_cont(cont=cont)
|
||||
try:
|
||||
cont(cancel_cont=cancel_cont)
|
||||
except TypeError:
|
||||
pass
|
||||
raise Continue(cont)
|
||||
|
||||
def box():
|
||||
return self.dialog.checklist("Gestion de la carte étudiant",
|
||||
height=0,
|
||||
width=0,
|
||||
timeout=self.timeout,
|
||||
list_height=7,
|
||||
choices=choices,
|
||||
title="Gestion de la carte étudiant")
|
||||
|
||||
def todo(values, adherent, cont):
|
||||
# On met à jour chaque attribut si sa valeur à changé
|
||||
with self.conn.search(dn=adherent.dn, scope=0, mode='rw')[0] as adherent:
|
||||
# Si on est trésorier et que controleCarte a changer on enregistre le changement
|
||||
if self.has_right(a.tresorier, adherent) and values["controleCarte"] and not adherent.carte_controle():
|
||||
if adherent["controle"]:
|
||||
adherent["controle"] = u"c%s" % adherent["controle"][0]
|
||||
else:
|
||||
adherent["controle"] = u"c"
|
||||
elif self.has_right(a.tresorier, adherent) and not values["controleCarte"] and adherent.carte_controle():
|
||||
adherent["controle"] = unicode(adherent["controle"][0]).replace('c','')
|
||||
if not adherent["controle"][0]:
|
||||
adherent["controle"] = []
|
||||
# Si la carte n'est pas validé ou qu'on est trésorier, on sauvegarde les changements
|
||||
if values[a.carteEtudiant.ldap_name] and not adherent[a.carteEtudiant.ldap_name] and (not adherent.carte_controle() or self.has_right(a.tresorier, adherent)):
|
||||
adherent[a.carteEtudiant.ldap_name] = u"TRUE"
|
||||
elif not values[a.carteEtudiant.ldap_name] and adherent[a.carteEtudiant.ldap_name] and (not adherent.carte_controle() or self.has_right(a.tresorier, adherent)):
|
||||
adherent[a.carteEtudiant.ldap_name] = []
|
||||
if adherent["controle"]:
|
||||
adherent["controle"] = unicode(adherent["controle"][0]).replace('c','')
|
||||
if not adherent["controle"][0]:
|
||||
adherent["controle"] = []
|
||||
adherent.validate_changes()
|
||||
adherent.history_gen()
|
||||
adherent.save()
|
||||
# On s'en va en mettant à jour dans la continuation la valeur de obj
|
||||
raise Continue(cont(adherent=adherent))
|
||||
|
||||
(code, output) = self.handle_dialog(cont, box)
|
||||
# On transforme la liste des cases dialog cochée en dictionnnaire
|
||||
values = dict((a[0], a[0] in output) for a in choices)
|
||||
|
||||
# Une continuation que l'on suivra si quelque chose se passe mal
|
||||
retry_cont = TailCall(self.adherent_carte_etudiant, adherent=adherent, cont=cont, values=values)
|
||||
|
||||
return self.handle_dialog_result(
|
||||
code=code,
|
||||
output=output,
|
||||
cancel_cont=cancel_cont if cancel_cont else cont,
|
||||
error_cont=retry_cont,
|
||||
codes_todo=[([self.dialog.DIALOG_OK], todo, [values, adherent, cont])]
|
||||
)
|
||||
def adherent_charte(self, cont, adherent):
|
||||
a = attributs
|
||||
attribs = [a.charteMA]
|
||||
|
@ -616,6 +547,15 @@ class Dialog(proprio.Dialog):
|
|||
with self.conn.search(dn=adherent.dn, scope=0, mode='rw')[0] as adherent:
|
||||
for (key, values) in attrs.items():
|
||||
adherent[key] = values
|
||||
# On retire les éventuelle bl mail invalide
|
||||
if key == u'mailExt' or key == u'mail':
|
||||
for bl in adherent['blacklist']:
|
||||
now = int(time.time())
|
||||
if bl['type'] == u'mail_invalide' and bl['fin'] > now:
|
||||
bl['fin'] = now
|
||||
if bl['debut'] > now:
|
||||
bl['debut'] = now
|
||||
bl['comm'] += u'- mail rectifié'
|
||||
adherent.validate_changes()
|
||||
adherent.history_gen()
|
||||
adherent.save()
|
||||
|
@ -653,6 +593,13 @@ class Dialog(proprio.Dialog):
|
|||
if self.confirm_item(adherent, title="Créer l'adhérent suivant ?"):
|
||||
adherent.validate_changes()
|
||||
adherent.create()
|
||||
if make_compte_crans:
|
||||
if self.dialog.yesno("Imprimer un ticket avec un mot de passe attribué automatiquement ?",
|
||||
title="Impression de ticket pour %s %s" % (adherent.get('prenom', [''])[0], adherent["nom"][0]),
|
||||
timeout=self.timeout
|
||||
) == self.dialog.DIALOG_OK:
|
||||
subprocess.call(['/usr/scripts/cransticket/dump_creds.py', '--forced', '--pass', 'aid=%s' % adherent['aid'][0]])
|
||||
self.display_item(adherent, "Impression du ticket en cours ...")
|
||||
else:
|
||||
adherent = None
|
||||
return adherent
|
||||
|
@ -916,13 +863,11 @@ class Dialog(proprio.Dialog):
|
|||
"""Crée un adhérent et potentiellement son compte crans avec lui"""
|
||||
def mycont(adherent=None, **kwargs):
|
||||
if adherent:
|
||||
# Une fois l'adhérent créé, on vois s'il donne sa carte étudiant et s'il adhére/prend la connexion internet
|
||||
# Une fois l'adhérent créé, on vois s'il adhére/prend la connexion internet
|
||||
#adh_cont = TailCall(self.modif_adherent, cont=cont, adherent=adherent)
|
||||
conn_cont = TailCall(self.adherent_connexion, cont=cont(proprio=adherent), adherent=adherent)
|
||||
carte_cont = TailCall(self.adherent_carte_etudiant, cont=conn_cont, adherent=adherent)
|
||||
etude_cont = TailCall(self.adherent_etudes, cont=carte_cont, adherent=adherent)
|
||||
etude_cont = TailCall(self.adherent_etudes, cont=conn_cont, adherent=adherent)
|
||||
etude_cont(cancel_cont=etude_cont)
|
||||
carte_cont(cancel_cont=etude_cont)
|
||||
# Comme on crée une facture, pas de retour possible
|
||||
conn_cont(cancel_cont=conn_cont)
|
||||
raise Continue(etude_cont)
|
||||
|
|
|
@ -13,7 +13,7 @@ import traceback
|
|||
if '/usr/scripts' not in sys.path:
|
||||
sys.path.append('/usr/scripts')
|
||||
|
||||
from gestion.affich_tools import coul
|
||||
from gestion import affichage
|
||||
import gestion.config as config
|
||||
|
||||
import lc_ldap.objets as objets
|
||||
|
@ -37,10 +37,14 @@ class Dialog(lc.Dialog):
|
|||
index = 0
|
||||
for bl in obj['blacklist']:
|
||||
choices.append(
|
||||
(str(index),
|
||||
coul("%s [%s]" % (bl['type'], bl['comm']), 'rouge' if bl['actif'] else None,
|
||||
dialog=True)
|
||||
)
|
||||
(
|
||||
str(index),
|
||||
affichage.style(
|
||||
"%s [%s]" % (bl['type'], bl['comm']),
|
||||
'rouge' if bl['actif'] else None,
|
||||
dialog=True
|
||||
)
|
||||
)
|
||||
)
|
||||
index+=1
|
||||
return self.dialog.menu(
|
||||
|
@ -145,7 +149,7 @@ class Dialog(lc.Dialog):
|
|||
fin_tuple = self.get_timestamp(title=title, text="Choisir la date de fin :",
|
||||
cont=self_cont(bl=bl, tag=tag, bl_type=bl_type,
|
||||
debut=None, fin=None, comm=None))
|
||||
fin = int(time.mktime(time.struct_time(debut_tuple + (0, 0, -1))))
|
||||
fin = int(time.mktime(time.struct_time(fin_tuple + (0, 0, -1))))
|
||||
else:
|
||||
fin = '-'
|
||||
bl['debut']=debut
|
||||
|
|
|
@ -6,16 +6,18 @@ Copyright (C) Valentin Samir
|
|||
Licence : GPLv3
|
||||
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import ldap
|
||||
import traceback
|
||||
import locale
|
||||
if '/usr/scripts' not in sys.path:
|
||||
sys.path.append('/usr/scripts')
|
||||
from pythondialog import Dialog
|
||||
from pythondialog import error as DialogError
|
||||
|
||||
from gestion.affich_tools import get_screen_size, coul
|
||||
from gestion import affichage
|
||||
|
||||
import lc_ldap.shortcuts
|
||||
import lc_ldap.objets as objets
|
||||
|
@ -27,12 +29,17 @@ from CPS import TailCall, tailcaller, Continue, TailCaller
|
|||
|
||||
class Dialog(CPS.Dialog):
|
||||
def __init__(self, debug_enable=False, ldap_test=False, custom_user=None):
|
||||
super(Dialog, self).__init__(debug_enable=debug_enable)
|
||||
super(Dialog, self).__init__()
|
||||
# On initialise le moteur de rendu en spécifiant qu'on va faire du dialog
|
||||
printing.template(dialog=True)
|
||||
self.ldap_test = ldap_test
|
||||
if custom_user:
|
||||
custom_user = custom_user.decode(locale.getdefaultlocale()[1] or "ascii")
|
||||
self.custom_user = custom_user
|
||||
self.check_ldap()
|
||||
login = self.conn.current_login
|
||||
dialogrc='/home/%s/.dialogrc' % login
|
||||
super(Dialog, self).__init__(debug_enable=debug_enable, dialogrc=dialogrc)
|
||||
|
||||
def has_right(self, liste, obj=None):
|
||||
"""Vérifie que l'un des droits de l'utilisateur courant est inclus dans list"""
|
||||
|
@ -340,7 +347,7 @@ class Dialog(CPS.Dialog):
|
|||
# pour prendre en compte la largeur du widget dialog
|
||||
del items[:] # On vide la liste pour la modifier en place
|
||||
items_id = {}
|
||||
(line, col) = get_screen_size()
|
||||
(col, line) = affichage.getTerminalSize()
|
||||
for c in classes:
|
||||
items.extend(olist[c])
|
||||
items_s = printing.sprint_list(olist[c], col-20).encode('utf-8').split('\n')
|
||||
|
|
|
@ -12,6 +12,7 @@ if '/usr/scripts' not in sys.path:
|
|||
|
||||
import lc_ldap.objets as objets
|
||||
import lc_ldap.attributs as attributs
|
||||
import subprocess
|
||||
|
||||
import certificat
|
||||
import blacklist
|
||||
|
@ -34,10 +35,12 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
|||
"""
|
||||
a = attributs
|
||||
# Quel sont les attributs ldap dont on veut afficher et la taille du champs d'édition correspondant
|
||||
to_display = [(a.host, 30), (a.macAddress, 17), (a.ipHostNumber, 15),
|
||||
(a.portTCPout, 50), (a.portTCPin, 50), (a.portUDPout, 50),
|
||||
(a.portUDPin, 50)
|
||||
]
|
||||
to_display = [(a.host, 30), (a.macAddress, 17), (a.ipHostNumber, 15)]
|
||||
|
||||
to_display_port = [(a.portTCPout, 50), (a.portTCPin, 50), (a.portUDPout, 50),
|
||||
(a.portUDPin, 50)]
|
||||
|
||||
to_display_borne = [(a.canal, 10), (a.hotspot, 10), (a.puissance, 10), (a.positionBorne, 50), (a.nvram, 10)]
|
||||
|
||||
# Quel séparateur on utilise pour les champs multivalué
|
||||
separateur = ' '
|
||||
|
@ -58,15 +61,19 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
|||
title="Paramètres machine",
|
||||
backtitle="Gestion des machines du Crans")
|
||||
|
||||
def check_host(host, objectClass):
|
||||
def check_host(host, objectClass, realm):
|
||||
# Si c'est une machine wifi, host doit finir par wifi.crans.org
|
||||
if "machineWifi" == objectClass or 'borneWifi' == objectClass:
|
||||
if "machineWifi" == objectClass or 'borneWifi' == objectClass or realm == 'bornes':
|
||||
hostend = ".wifi.crans.org"
|
||||
# Si c'est une machine wifi, host doit finir par crans.org
|
||||
elif "machineFixe" == objectClass:
|
||||
elif "machineFixe" == objectClass or realm == 'serveurs':
|
||||
hostend = ".crans.org"
|
||||
# Si l'object class est machineCrans, pas de vérification
|
||||
elif "machineCrans" == objectClass:
|
||||
if realm == 'adm':
|
||||
hostend = ".adm.crans.org"
|
||||
if not '.' in host:
|
||||
host = host + hostend
|
||||
return host
|
||||
# Sinon, libre à chachun d'ajouter d'autres objectClass ou de filtrer
|
||||
# plus finement fonction des droits de self.conn.droits
|
||||
|
@ -74,7 +81,7 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
|||
raise ValueError("La machine n'est ni une machine fixe, ni une machine wifi mais %s ?!?" % objectClass)
|
||||
|
||||
if not host.endswith(hostend) and not '.' in host:
|
||||
host = "%s.wifi.crans.org" % host
|
||||
host = host + hostend
|
||||
elif host.endswith(hostend) and '.' in host[:-len(hostend)]:
|
||||
raise ValueError("Nom d'hôte invalide, devrait finir par %s et être sans point dans la première partie" % hostend)
|
||||
elif not host.endswith(hostend) and '.' in host:
|
||||
|
@ -85,7 +92,8 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
|||
def modif_machine(machine, attrs):
|
||||
with self.conn.search(dn=machine.dn, scope=0, mode='rw')[0] as machine:
|
||||
for (key, values) in attrs.items():
|
||||
machine[key]=values
|
||||
if values!=u'<automatique>' or key != 'ipHostNumber':
|
||||
machine[key]=values
|
||||
machine.validate_changes()
|
||||
machine.history_gen()
|
||||
machine.save()
|
||||
|
@ -101,13 +109,18 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
|||
}
|
||||
with self.conn.newMachine(proprio.dn, realm, ldif) as machine:
|
||||
for (key, values) in attrs.items():
|
||||
machine[key]=values
|
||||
if values!=u'<automatique>' or key != u'ipHostNumber':
|
||||
machine[key]=values
|
||||
if attributs.ipsec in machine.attribs:
|
||||
machine[attributs.ipsec.ldap_name]=attributs.ipsec.default
|
||||
machine.validate_changes()
|
||||
if self.confirm_item(machine, "Voulez vous vraiement créer cette machine ?"):
|
||||
machine.create()
|
||||
self.display_item(machine, "La machine à bien été créée", ipsec=True)
|
||||
self.display_item(machine, "La machine a bien été créée", ipsec=True)
|
||||
if realm == 'wifi-adh':
|
||||
if self.dialog.yesno("Imprimer un ticket pour la machine ?", timeout=self.timeout, title="Impression de ticket", width=50) == self.dialog.DIALOG_OK:
|
||||
subprocess.call(['/usr/scripts/cransticket/dump_creds.py', '--forced', 'mid=%s' % machine['mid'][0]])
|
||||
self.display_item(machine, "Impression du ticket ...", ipsec=True)
|
||||
return machine
|
||||
else:
|
||||
raise Continue(cont)
|
||||
|
@ -123,7 +136,7 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
|||
values = [v for v in values.split(separateur) if v]
|
||||
# Pour host, on fait quelques vérification de syntaxe
|
||||
if a.ldap_name == 'host':
|
||||
attrs[a.ldap_name]=check_host(values, objectClass)
|
||||
attrs[a.ldap_name]=check_host(values, objectClass, realm)
|
||||
else:
|
||||
attrs[a.ldap_name]=values
|
||||
# Soit on édite une machine existante
|
||||
|
@ -134,10 +147,16 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
|||
machine = create_machine(proprio, realm, attrs)
|
||||
raise Continue(cont(machine=machine))
|
||||
|
||||
|
||||
if machine:
|
||||
objectClass = machine["objectClass"][0]
|
||||
|
||||
if self.has_right(a.nounou, proprio):
|
||||
to_display += to_display_port
|
||||
|
||||
# Les bornes wifi ont un to_display différent
|
||||
if objectClass == 'borneWifi':
|
||||
to_display += to_display_borne
|
||||
|
||||
(code, tags) = self.handle_dialog(cont, box)
|
||||
|
||||
# On prépare les fiels à afficher à l'utilisateur si une erreure à lieu
|
||||
|
@ -188,8 +207,8 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
|||
menu_droits = {
|
||||
'Information' : [a.parent, a.cableur, a.nounou],
|
||||
'Autre': [a.parent, a.cableur, a.nounou],
|
||||
'Blackliste':[a.cableur, a.nounou],
|
||||
'Certificat': [a.parent, a.cableur, a.nounou],
|
||||
'Blackliste':[a.nounou],
|
||||
'Certificat': [a.parent, a.nounou],
|
||||
'Exemption' : [a.nounou],
|
||||
'Alias' : [a.parent, a.cableur, a.nounou],
|
||||
'Remarques' : [a.cableur, a.nounou],
|
||||
|
@ -251,24 +270,41 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
|||
menu_droits = {
|
||||
'Fixe' : [a.soi, a.cableur, a.nounou],
|
||||
'Wifi' : [a.soi, a.cableur, a.nounou],
|
||||
'Appartements': [a.soi, a.cableur, a.nounou],
|
||||
}
|
||||
menu = {
|
||||
'Fixe' : {'text' : "Machine filaire", 'objectClass':'machineFixe', 'realm':'adherents'},
|
||||
'Appartements' : {'text' : "Machine filaire de personnel ENS", 'objectClass':'machineFixe', 'realm':'personnel-ens'},
|
||||
'Wifi' : {'text': 'Machine sans fil', 'objectClass':'machineWifi', 'realm':'wifi-adh'},
|
||||
}
|
||||
menu_order = ['Fixe', 'Wifi']
|
||||
menu_order = ['Wifi']
|
||||
|
||||
# Machine appartement pour les personnels, fixe pour les autres
|
||||
if proprio.get('etudes', [False])[0] == u'Personnel ENS':
|
||||
menu_order.append('Appartements')
|
||||
else:
|
||||
# On vérifie que un non MA a qu'une machine fixe
|
||||
menu_order.append('Fixe')
|
||||
if not bool(proprio.get('droits', False)) and isinstance(proprio, objets.adherent):
|
||||
for machine in proprio.machines():
|
||||
if isinstance(machine, objets.machineFixe):
|
||||
menu_order.remove('Fixe')
|
||||
break
|
||||
|
||||
if isinstance(proprio, objets.AssociationCrans):
|
||||
menu_droits.update({
|
||||
'Fixe' : [a.nounou],
|
||||
'Wifi' : [a.nounou],
|
||||
'Wifi-v6' : [a.nounou],
|
||||
'Adm' : [a.nounou],
|
||||
})
|
||||
menu.update({
|
||||
'Fixe' : {'text' : "Ajouter un serveur sur le vlan adherent", 'objectClass':'machineCrans', 'realm':'serveurs'},
|
||||
'Wifi' : {'text': 'Ajouter une borne WiFi sur le vlan wifi', 'objectClass':'borneWifi', 'realm':'bornes'},
|
||||
'Wifi-v6' : {'text': 'Ajouter une borne WiFi sur le vlan wifi en ipv6 only', 'objectClass':'borneWifi', 'realm':'bornes-v6'},
|
||||
'Adm' : {'text' : "Ajouter un serveur sur le vlan adm", "objectClass":"machineCrans", 'realm':'adm'},
|
||||
})
|
||||
menu_order.append('Adm')
|
||||
menu_order += ['Adm', 'Wifi-v6']
|
||||
def box(default_item=None):
|
||||
return self.dialog.menu(
|
||||
"Type de Machine ?",
|
||||
|
|
|
@ -85,11 +85,10 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
|||
|
||||
@tailcaller
|
||||
def set_password(proprio, update_obj, cont):
|
||||
if self.dialog.yesno("Attribuer un mot de passe maintenant ?",
|
||||
if self.dialog.yesno("Attribuer un mot de passe maintenant ? (Vous aurez la possibilité d'imprimer un ticket plus tard également ...)",
|
||||
title="Création du compte de %s %s" % (proprio.get('prenom', [''])[0], proprio["nom"][0]),
|
||||
timeout=self.timeout
|
||||
) == self.dialog.DIALOG_OK:
|
||||
#return self.proprio_compte_password(proprio=proprio, return_obj=return_obj, cont=cont(**{update_obj:proprio}))
|
||||
proprio = self.proprio_compte_password(proprio=proprio, return_obj=True, cont=TailCall(set_password, proprio, update_obj, cont))
|
||||
if return_obj:
|
||||
return proprio
|
||||
|
@ -168,7 +167,7 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
|||
raise Continue(cont(proprio=proprio))
|
||||
#(code, passwords) = self.handle_dialog(cont, box)
|
||||
(code, passwords) = (self.dialog.DIALOG_OK, "")
|
||||
self_cont = TailCall(self.proprio_compte_password, proprio=proprio, cont=cont)
|
||||
self_cont = TailCall(self.proprio_compte_password, proprio=proprio, cont=cont, return_obj=return_obj)
|
||||
return self.handle_dialog_result(
|
||||
code=code,
|
||||
output=passwords,
|
||||
|
@ -411,14 +410,19 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
|||
"cheque" : "Chèque",
|
||||
"carte" : "Par carte bancaire",
|
||||
"solde" : "Solde Crans (actuel : %s€)",
|
||||
"note" : "Note kfet (attention, moins tracable...)",
|
||||
"arbitraire" : "Création ou destruction magique d'argent.",
|
||||
}
|
||||
|
||||
def box_choose_paiment(tag, articles):
|
||||
box_paiement_order = ["liquide", "cheque", "carte"]
|
||||
box_paiement_order = ["liquide", "cheque", "carte","note"]
|
||||
if "cransAccount" in proprio['objectClass']:
|
||||
if not "SOLDE" in [art['code'] for art in articles] and proprio["solde"]:
|
||||
box_paiement_order.append("solde")
|
||||
box_paiement["solde"] = box_paiement["solde"] % proprio["solde"][0]
|
||||
if len(articles) == 1 and "SOLDE" in [art['code'] for art in articles]:
|
||||
box_paiement_order.append("arbitraire")
|
||||
|
||||
choices = []
|
||||
for key in box_paiement_order:
|
||||
choices.append((key, box_paiement[key], 1 if key == tag else 0))
|
||||
|
@ -457,6 +461,7 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
|||
|
||||
def box_choose_item(tags):
|
||||
choices = []
|
||||
gestion.config.factures.ITEMS.update(gestion.config.factures.ITEM_SOLDE)
|
||||
for code, article in gestion.config.factures.ITEMS.items():
|
||||
choices.append((code, u"%s%s" % (article['designation'], (u' (%s€)' % article['pu']) if article['pu'] != '*' else ""), 1 if code in tags else 0))
|
||||
return self.dialog.checklist(
|
||||
|
@ -499,11 +504,19 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
|||
|
||||
def paiement(have_set, tag, proprio, comment, cancel_cont, cont):
|
||||
articles = copy.deepcopy(have_set)
|
||||
|
||||
# On formate les articles
|
||||
for article in articles:
|
||||
if article['pu'] == '*':
|
||||
article['pu'] = article['nombre']
|
||||
article['nombre'] = 1
|
||||
|
||||
# En arbitraire, on accepte que le solde
|
||||
if tag == u"arbitraire":
|
||||
if len(articles) > 1 or "SOLDE" not in [art['code'] for art in articles]:
|
||||
raise ValueError("Il n'est possible que de faire une opération de solde en mode arbitraire")
|
||||
|
||||
# Les articles classiques on facture
|
||||
with self.conn.newFacture(proprio.dn, {}) as facture:
|
||||
facture['modePaiement']=unicode(tag, 'utf-8')
|
||||
facture['article']=articles
|
||||
|
@ -517,13 +530,13 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
|||
arts = ["%s %s" % (art['nombre'], art['designation']) for art in facture['article'] if art['code'] != 'SOLDE']
|
||||
if arts:
|
||||
self.dialog.msgbox(
|
||||
text=u"Vous pouvez remettre à l'adherent les articles (si se sont des articles) suivant :\n * %s" % '\n * '.join(arts),
|
||||
title=u"Vente terminée",
|
||||
width=0, height=0, timeout=self.timeout)
|
||||
text=u"Vous pouvez remettre à l'adherent les articles (si ce sont des articles) suivant :\n * %s" % '\n * '.join(arts),
|
||||
title=u"Vente terminée",
|
||||
width=0, height=0, timeout=self.timeout)
|
||||
if tag == "solde":
|
||||
self.dialog.msgbox(text=u"Le solde de l'adhérent à bien été débité", title="Solde débité", width=0, height=0, timeout=self.timeout)
|
||||
self.dialog.msgbox(text=u"Le solde de l'adhérent a bien été débité", title="Solde débité", width=0, height=0, timeout=self.timeout)
|
||||
if [a for a in facture['article'] if art['code'] == 'SOLDE']:
|
||||
self.dialog.msgbox(text=u"Le solde de l'adhérent à bien été crédité", title="Solde crédité", width=0, height=0, timeout=self.timeout)
|
||||
self.dialog.msgbox(text=u"Le solde de l'adhérent a bien été crédité", title="Solde crédité", width=0, height=0, timeout=self.timeout)
|
||||
else:
|
||||
if not self.confirm(text=u"Le paiement n'a pas été reçue.\n Annuler la vente ?", title="Annulation de la vente", defaultno=True):
|
||||
raise Continue(cancel_cont)
|
||||
|
@ -553,12 +566,13 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
|||
cancel_cont=cancel_cont,
|
||||
error_cont=cancel_cont,
|
||||
codes_todo=[([self.dialog.DIALOG_OK], paiement, [have_set, tag_paiment, proprio, comment_paiement, cancel_cont, cont])]
|
||||
)
|
||||
)
|
||||
|
||||
# Sinon, on propose des articles à chosir
|
||||
else:
|
||||
(code, tags) = self.handle_dialog(cont, box_choose_item, tags)
|
||||
self_cont=self_cont(tags=tags, have_set=[], to_set=[], tag_paiment=None)
|
||||
gestion.config.factures.ITEMS.update(gestion.config.factures.ITEM_SOLDE)
|
||||
return self.handle_dialog_result(
|
||||
code=code,
|
||||
output=tags,
|
||||
|
|
42208
gestion/ethercodes.dat
42208
gestion/ethercodes.dat
File diff suppressed because it is too large
Load diff
|
@ -176,14 +176,22 @@ class home:
|
|||
|
||||
### Redirection
|
||||
if mail_redirect:
|
||||
file(home + '/.forward', 'w').write(mail_redirect + '\n')
|
||||
write_in_forward = True
|
||||
|
||||
# On vérifie s'il y a déjà un .forward
|
||||
if os.path.exists(os.path.join(home, ".forward")):
|
||||
write_in_forward = False
|
||||
if write_in_forward:
|
||||
with open(os.path.join(home, '.forward'), 'w') as forward_file:
|
||||
forward_file.write(mail_redirect + '\n')
|
||||
|
||||
os.chown(home + '/.forward', int(uid), gid)
|
||||
os.chmod(home + '/.forward', 0604)
|
||||
os.chmod(home + '/.forward', 0600)
|
||||
### Owncloud dans le home
|
||||
if not os.path.exists(home + '/OwnCloud'):
|
||||
os.mkdir(home + '/OwnCloud')
|
||||
os.chown(home + '/OwnCloud', int(uid), grp.getgrnam('www-data').gr_gid)
|
||||
os.chmod(home + '/OwnCloud',0770)
|
||||
os.chmod(home + '/OwnCloud', 0770)
|
||||
except:
|
||||
print ERREUR
|
||||
if self.debug:
|
||||
|
|
|
@ -43,6 +43,7 @@ class autostatus(gen_config) :
|
|||
"obm.crans.org",
|
||||
"obm.adm.crans.org",
|
||||
"batv-3.adm.crans.org",
|
||||
"batv-1.adm.crans.org",
|
||||
|
||||
# Config par défaut
|
||||
"non-configure.wifi.crans.org",
|
||||
|
@ -70,6 +71,7 @@ class autostatus(gen_config) :
|
|||
"ragnarok.crans.org", # RIP contrôleur disque...
|
||||
"zamok.crans.org", # c'est en fait fx
|
||||
"bati-2.adm.crans.org", # N'est plus en place
|
||||
"batv-1.crans.org",
|
||||
|
||||
# Bornes wifi de test
|
||||
"bullet5.wifi.crans.org",
|
||||
|
@ -142,8 +144,10 @@ class autostatus(gen_config) :
|
|||
|
||||
infos_routeurs = {}
|
||||
infos_routeurs [ '138.231.136.4' ] = ['Odlyd', u'Routeur principal du CRANS']
|
||||
infos_routeurs [ '138.231.136.3' ] = ['Komaz', u'Routeur secondaire du CRANS']
|
||||
infos_routeurs [ '138.231.132.1' ] = ['Pioneer.zrt', u'Routeur principal de l\'ENS (interne)']
|
||||
infos_routeurs [ '138.231.132.102' ] = ['Pioneer', u'Routeur principal de l\'ENS (interne)']
|
||||
infos_routeurs [ '138.231.132.101' ] = ['Pioneer1.zrt.ens-cachan', u'Routeur principal de l\'ENS (interne)']
|
||||
infos_routeurs [ '138.231.132.102' ] = ['Pioneer2.zrt.ens-cachan', u'Routeur principal de l\'ENS (interne)']
|
||||
infos_routeurs [ '138.231.176.1' ] = ['Pioneer', u'Routeur principal de l\'ENS']
|
||||
infos_routeurs [ '193.49.65.1' ] = ['RenaterCachan1' , u'Routeur Renater' ]
|
||||
infos_routeurs [ '193.51.181.186' ] = ['RenaterCachan2', u'Routeur Renater']
|
||||
|
|
|
@ -73,6 +73,9 @@ class TLSA(ResourceRecord):
|
|||
if not r_format in ['pem', 'der']:
|
||||
raise ValueError("format should be pem or der")
|
||||
|
||||
if selector != 0:
|
||||
raise NotImplementedError("selector different form 0 not implemented")
|
||||
|
||||
if cert is None and proto == 'tcp' and name[-1] == '.':
|
||||
try:
|
||||
cert = ssl.get_server_certificate((name[:-1], port), ca_certs='/etc/ssl/certs/ca-certificates.crt')
|
||||
|
@ -90,6 +93,7 @@ class TLSA(ResourceRecord):
|
|||
raise ValueError("Impossible de convertir le certificat au format DER %s %s %s\n%s" % (name, port, proto, cert))
|
||||
|
||||
certhex = TLSA.hashCert(reftype, str(dercert))
|
||||
self.certhex = certhex
|
||||
if compat:
|
||||
super(TLSA, self).__init__(
|
||||
'TYPE52',
|
||||
|
@ -151,13 +155,17 @@ class TXT(ResourceRecord):
|
|||
"""Entrée DNS pour un champ TXT"""
|
||||
def __init__(self, name, value, ttl=None):
|
||||
super(TXT, self).__init__('TXT', name, value, ttl)
|
||||
if len(self.value) > 200:
|
||||
self.value = '( "' + '"\n\t\t\t\t"'.join([self.value[x:x+200] for x in xrange(0, len(self.value), 200)]) + '" )'
|
||||
else:
|
||||
self.value = '"%s"' % (self.value,)
|
||||
|
||||
def __str__(self):
|
||||
"""Retourne une chaîne printable dans un fichier bind"""
|
||||
if self._ttl:
|
||||
return '%s\t%s\tIN\t%s\t"%s"' % (self.name, self._ttl, self.r_type, self.value)
|
||||
return '%s\t%s\tIN\t%s\t%s' % (self.name, self._ttl, self.r_type, self.value)
|
||||
else:
|
||||
return '%s\tIN\t%s\t"%s"' % (self.name, self.r_type, self.value)
|
||||
return '%s\tIN\t%s\t%s' % (self.name, self.r_type, self.value)
|
||||
|
||||
class CNAME(ResourceRecord):
|
||||
"""Entrée DNS pour un alias (toto -> redisdead)"""
|
||||
|
@ -390,13 +398,14 @@ class Zone(ZoneBase):
|
|||
def add_tlsa_record(self, cert):
|
||||
"""Ajout d'un certif dans le DNS"""
|
||||
if 'TLSACert' in cert['objectClass']:
|
||||
for host in cert['hostCert']:
|
||||
nom = self.get_name(host)
|
||||
if nom is None: continue
|
||||
for port in cert['portTCPin']:
|
||||
self.add(TLSA(nom, port, 'tcp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], r_format='der'))
|
||||
for port in cert['portUDPin']:
|
||||
self.add(TLSA(nom, port, 'udp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], r_format='der'))
|
||||
if not cert.get('revocked', [False])[0]:
|
||||
for host in cert['hostCert']:
|
||||
nom = self.get_name(host)
|
||||
if nom is None: continue
|
||||
for port in cert['portTCPin']:
|
||||
self.add(TLSA(nom, port, 'tcp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], r_format='der'))
|
||||
for port in cert['portUDPin']:
|
||||
self.add(TLSA(nom, port, 'udp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], r_format='der'))
|
||||
|
||||
def add_machine(self, machine):
|
||||
"""Ajout d'une machine, à savoir chaînage d'ajout
|
||||
|
@ -620,6 +629,12 @@ class dns(gen_config):
|
|||
],
|
||||
}
|
||||
|
||||
DKIM = {
|
||||
'crans.org': [
|
||||
TXT('mail._domainkey', 'v=DKIM1; k=rsa; p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtwkNVd9Mmz8S4WcfuPk0X2drG39gS8+uxAv8igRILgzWeN8j2hjeZesl8pm/1UTVU87bYcdfUgXiGfQy9nR5p/Vmt2kS7sXk9nsJ/VYENgb3IJQ6paWupSTFMyeKycJ4ZHCEZB/bVvifoG6vLKqW5jpsfCiOcfdcgXATn0UPuVx9t93yRrhoEMntMv9TSodjqd3FKCtJUoh5cNQHo0T6dWKtxoIgNi/mvZ92D/IACwu/XOU+Rq9fnoEI8GukBQUR5AkP0B/JrvwWXWX/3EjY8X37ljEX0XUdq/ShzTl5iK+CM83stgkFUQh/rpww5mnxYEW3X4uirJ7VJHmY4KPoIU+2DPjLQj9Hz63CMWY3Ks2pXWzxD3V+GI1aJTMFOv2LeHnI3ScqFaKj9FR4ZKMb0OW2BEFBIY3J3aeo/paRwdbVCMM7twDtZY9uInR/NhVa1v9hlOxwp4/2pGSKQYoN2CkAZ1Alzwf8M3EONLKeiC43JLYwKH1uBB1oikSVhMnLjG0219XvfG/tphyoOqJR/bCc2rdv5pLwKUl4wVuygfpvOw12bcvnTfYuk/BXzVHg9t4H8k/DJR6GAoeNAapXIS8AfAScF8QdKfplhKLJyQGJ6lQ75YD9IwRAN0oV+8NTjl46lI/C+b7mpfXCew+p6YPwfNvV2shiR0Ez8ZGUQIcCAwEAAQ==')
|
||||
],
|
||||
}
|
||||
|
||||
NON_CLONABLE_SPFs = {
|
||||
'crans.org': [
|
||||
TXT(short_name(_mx), 'v=spf1 mx:crans.org ~all') for _mx in config.dns.MXs
|
||||
|
@ -673,7 +688,7 @@ class dns(gen_config):
|
|||
# On met les mêmes MX pour toutes les zones.
|
||||
zone.extend(self.MXs)
|
||||
# Les RR définis ici sont ajoutés aux zones idoines, de façon à se simplifier la vie.
|
||||
for rr_type in [self.SRVs, self.NAPTRs, self.DSs, self.EXTRAS, self.SPFs, self.NON_CLONABLE_SPFs]:
|
||||
for rr_type in [self.SRVs, self.NAPTRs, self.DSs, self.EXTRAS, self.SPFs, self.NON_CLONABLE_SPFs, self.DKIM]:
|
||||
if zone.zone_name in rr_type.keys():
|
||||
zone.extend(rr_type[zone.zone_name])
|
||||
for m in machines:
|
||||
|
|
|
@ -45,9 +45,13 @@ class exemptions(gen_config):
|
|||
for machine in machines:
|
||||
for destination in machine["exempt"]:
|
||||
if destination.value.version == 4:
|
||||
if not machine['ipHostNumber']:
|
||||
continue
|
||||
source = str(machine["ipHostNumber"][0])
|
||||
requete = "INSERT INTO exemptes (ip_crans, ip_dest) VALUES ('%s','%s')" % (source, destination)
|
||||
else:
|
||||
if not machine['macAddress']:
|
||||
continue
|
||||
source = str(machine["macAddress"][0])
|
||||
requete = "INSERT INTO exemptes6 (mac_crans, ip_dest) VALUES ('%s','%s')" % (source, destination)
|
||||
# Si ip vide, passons au suivant
|
||||
|
@ -86,7 +90,8 @@ class machines(gen_config):
|
|||
if not m['macAddress'][0].value == '<automatique>':
|
||||
curseur.execute("INSERT INTO machines (mac_addr, type, id) VALUES ('%s','adherent',%s);" % (m['macAddress'][0], m.proprio()['aid'][0].value))
|
||||
elif m.proprio().__class__ == lc_ldap.objets.AssociationCrans:
|
||||
curseur.execute("INSERT INTO machines (mac_addr, type, id) VALUES ('%s','crans',%s);" % (m['macAddress'][0], m['mid'][0].value))
|
||||
if not m['macAddress'][0].value == '<automatique>':
|
||||
curseur.execute("INSERT INTO machines (mac_addr, type, id) VALUES ('%s','crans',%s);" % (m['macAddress'][0], m['mid'][0].value))
|
||||
# on commit
|
||||
pgsql.commit()
|
||||
|
||||
|
|
|
@ -34,13 +34,13 @@ class firewall(utils.firewall_tools) :
|
|||
self.use_ipset = [self.blacklist_hard, self.test_mac_ip, self.blacklists]
|
||||
|
||||
self.ipset['mac_ip']={
|
||||
'adh' : Ipset("MAC-IP-ADH","macipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
||||
'adm' : Ipset("MAC-IP-ADM","macipmap","--from 10.231.136.0 --to 10.231.136.255"),
|
||||
'app' : Ipset("MAC-IP-APP","macipmap","--from 10.2.9.0 --to 10.2.9.255"),
|
||||
'adh' : Ipset("MAC-IP-ADH", "bitmap:ip,mac", "range 138.231.136.0-138.231.151.255"),
|
||||
'adm' : Ipset("MAC-IP-ADM", "bitmap:ip,mac", "range 10.231.136.0-10.231.136.255"),
|
||||
'app' : Ipset("MAC-IP-APP", "bitmap:ip,mac", "range 10.2.9.0-10.2.9.255"),
|
||||
}
|
||||
|
||||
self.ipset['blacklist']={
|
||||
'hard' : Ipset("BLACKLIST-HARD","ipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
||||
'hard' : Ipset("BLACKLIST-HARD", "hash:ip"),
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,7 +110,7 @@ class firewall(utils.firewall_tools) :
|
|||
|
||||
if fill_ipset:
|
||||
# On récupère la liste de toutes les ips blacklistés hard
|
||||
bl_hard_ips = self.blacklisted_ips(config.blacklist_sanctions, config.NETs['all'])
|
||||
bl_hard_ips = self.blacklisted_ips(config.blacklist_sanctions)
|
||||
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['hard'])
|
||||
self.ipset['blacklist']['hard'].restore(bl_hard_ips)
|
||||
print OK
|
||||
|
@ -131,7 +131,7 @@ class firewall(utils.firewall_tools) :
|
|||
|
||||
def mac_ip_remove(self, mac, ip):
|
||||
machine = {'macAddress':[mac], 'ipHostNumber': [ip]}
|
||||
self.test_mac_ip_dispatch(lambda set, data: set.ipset['mac_ip'][set].delete(data), machine)
|
||||
self.test_mac_ip_dispatch(lambda set, data: self.ipset['mac_ip'][set].delete(data), machine)
|
||||
|
||||
def test_mac_ip_dispatch(self, func, machine):
|
||||
"""Détermine à quel set de mac-ip appliquer la fonction ``func`` (add, delete, append, ...)"""
|
||||
|
|
|
@ -21,8 +21,9 @@ firewall = {
|
|||
'odlyd' : komaz.firewall,
|
||||
'zamok' : zamok.firewall,
|
||||
'routeur' : routeur.firewall,
|
||||
'gordon' : base.firewall_routeur,
|
||||
'eap' : base.firewall_wifionly,
|
||||
'pea' : base.firewall_wifionly,
|
||||
'radius' : base.firewall_wifionly
|
||||
}
|
||||
|
||||
if hostname in firewall.keys():
|
||||
|
|
|
@ -33,18 +33,21 @@ class firewall(base.firewall_routeur):
|
|||
self.use_tc.extend([self.limitation_debit])
|
||||
|
||||
self.ipset['reseaux_non_routable'] = {
|
||||
'deny' : base.Ipset("RESEAUX-NON-ROUTABLE-DENY","nethash"),
|
||||
'allow' : base.Ipset("RESEAUX-NON-ROUTABLE-ALLOW","nethash"),
|
||||
'deny' : base.Ipset("RESEAUX-NON-ROUTABLE-DENY", "hash:net"),
|
||||
'allow' : base.Ipset("RESEAUX-NON-ROUTABLE-ALLOW", "hash:net"),
|
||||
}
|
||||
|
||||
self.ipset['blacklist'].update({
|
||||
'soft' : base.Ipset("BLACKLIST-SOFT","ipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
||||
'upload' : base.Ipset("BLACKLIST-UPLOAD","ipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
||||
'soft' : base.Ipset("BLACKLIST-SOFT", "hash:ip"),
|
||||
'upload' : base.Ipset("BLACKLIST-UPLOAD", "hash:ip"),
|
||||
})
|
||||
|
||||
# Portail captif/blacklist soft: ipset des gens ayant cliqué pour continuer à naviguer
|
||||
self.ipset['confirmation'] = base.Ipset("CONFIRMATION", "hash:ip", "")
|
||||
|
||||
# Ouvertures de ports temporaires
|
||||
self.ipset['ip_port_tmp'] = base.Ipset("IP-PORT-TMP", "hash:ip,port", "timeout 3600")
|
||||
|
||||
def blacklist_maj(self, ips):
|
||||
"""Mise à jour des blacklistes"""
|
||||
self.blacklist_hard_maj(ips)
|
||||
|
@ -129,6 +132,7 @@ class firewall(base.firewall_routeur):
|
|||
self.add(table, chain, '-j %s' % self.ssh_on_https(table))
|
||||
self.add(table, chain, '-j %s' % self.connexion_secours(table))
|
||||
self.add(table, chain, '-j %s' % self.blacklist_soft(table))
|
||||
self.add(table, chain, '-j %s' % self.blacklist_hard(table))
|
||||
|
||||
chain = 'POSTROUTING'
|
||||
self.add(table, chain, '-j %s' % self.connexion_wififederez(table))
|
||||
|
@ -247,6 +251,7 @@ class firewall(base.firewall_routeur):
|
|||
if table == 'nat':
|
||||
pretty_print(table, chain)
|
||||
self.add(table, chain, '-p tcp -d 138.231.136.2 --dport 22 -j DNAT --to-destination 138.231.136.1:22') # redirection du ssh vers zamok
|
||||
self.add(table, chain, '-p tcp -d 138.231.136.2 --dport 80 -j DNAT --to-destination 138.231.136.1:81') # redirection du ssh vers zamok a travers httptunnel
|
||||
self.add(table, chain, '-p tcp -d 138.231.136.2 --dport 443 -j DNAT --to-destination 138.231.136.1:22') # redirection du ssh vers zamok (pour passer dans un proxy, avec corkscrew)
|
||||
print OK
|
||||
|
||||
|
@ -342,7 +347,7 @@ class firewall(base.firewall_routeur):
|
|||
|
||||
if fill_ipset:
|
||||
# On récupère la liste de toutes les ips blacklistés soft
|
||||
bl_soft_ips = self.blacklisted_ips(base.config.blacklist_sanctions_soft, base.config.NETs['all'])
|
||||
bl_soft_ips = self.blacklisted_ips(base.config.blacklist_sanctions_soft)
|
||||
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['soft'])
|
||||
self.ipset['blacklist']['soft'].restore(bl_soft_ips)
|
||||
print OK
|
||||
|
@ -367,6 +372,41 @@ class firewall(base.firewall_routeur):
|
|||
self.apply(table, chain)
|
||||
return chain
|
||||
|
||||
def blacklist_hard(self, table=None, fill_ipset=False, apply=False):
|
||||
"""Bloque tout, sauf le 80 pour afficher le portail captif"""
|
||||
chain = 'BLACKLIST_HARD'
|
||||
|
||||
if fill_ipset:
|
||||
# On récupère la liste de toutes les ips blacklistés hard
|
||||
bl_hard_ips = self.blacklisted_ips(base.config.blacklist_sanctions)
|
||||
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['hard'])
|
||||
self.ipset['blacklist']['hard'].restore(bl_hard_ips)
|
||||
print OK
|
||||
|
||||
if table == 'filter':
|
||||
pretty_print(table, chain)
|
||||
# Same as blacklist_soft: autorise le port 80 et 3128 vers soi-même
|
||||
self.add(table, chain, '-p tcp --dport 80 -m set --match-set %s src -j ACCEPT' % self.ipset['blacklist']['hard'] )
|
||||
self.add(table, chain, '-p tcp --sport 80 -m set --match-set %s dst -j ACCEPT' % self.ipset['blacklist']['hard'] )
|
||||
self.add(table, chain, '-p tcp -d 10.231.136.4 --dport 3128 -m set --match-set %s src -j ACCEPT' % self.ipset['blacklist']['hard'] )
|
||||
self.add(table, chain, '-p tcp -s 10.231.136.4 --sport 3128 -m set --match-set %s dst -j ACCEPT' % self.ipset['blacklist']['hard'] )
|
||||
# Mais on continue en refusant le reste
|
||||
self.add(table, chain, '-m set --match-set %s src -j REJECT' % self.ipset['blacklist']['hard'] )
|
||||
self.add(table, chain, '-m set --match-set %s dst -j REJECT' % self.ipset['blacklist']['hard'] )
|
||||
print OK
|
||||
|
||||
if table == 'nat':
|
||||
pretty_print(table, chain)
|
||||
for net in base.config.NETs['all']:
|
||||
self.add(table, chain, '-d %s -j RETURN' % net)
|
||||
self.add(table, chain, '-p tcp --dport 80 -m set --match-set %s src -j RETURN' % self.ipset['confirmation'] ) # Les gens qui ont cliqué -> fine !
|
||||
self.add(table, chain, '-p tcp --dport 80 -m set --match-set %s src -j DNAT --to-destination 10.231.136.4:3128' % self.ipset['blacklist']['hard'] )
|
||||
print OK
|
||||
|
||||
if apply:
|
||||
self.apply(table, chain)
|
||||
return chain
|
||||
|
||||
def blacklist_upload_maj(self, ip_list):
|
||||
self.blacklist_upload(fill_ipset=True)
|
||||
# for ip in ip_list:
|
||||
|
@ -385,7 +425,7 @@ class firewall(base.firewall_routeur):
|
|||
|
||||
if fill_ipset:
|
||||
# On récupère la liste de toutes les ips blacklistés pour upload
|
||||
bl_upload_ips = self.blacklisted_ips(base.config.blacklist_bridage_upload, base.config.NETs['all'])
|
||||
bl_upload_ips = self.blacklisted_ips(base.config.blacklist_bridage_upload)
|
||||
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['upload'])
|
||||
self.ipset['blacklist']['upload'].restore(bl_upload_ips)
|
||||
print OK
|
||||
|
@ -453,6 +493,7 @@ class firewall(base.firewall_routeur):
|
|||
|
||||
if table == 'filter':
|
||||
pretty_print(table, chain)
|
||||
self.add(table, chain, '-m set --match-set %s dst,dst -j ACCEPT' % self.ipset['ip_port_tmp'] )
|
||||
for net in base.config.NETs['serveurs']:
|
||||
for proto in base.config.firewall.srv_ports_default.keys():
|
||||
if base.config.firewall.srv_ports_default[proto]['output']:
|
||||
|
@ -543,17 +584,17 @@ class firewall(base.firewall_routeur):
|
|||
utils.tc("class add dev %s parent 1: classid 1:1 "
|
||||
"htb rate %s ceil %s" % (dev[int_key], uplink_speed, uplink_speed))
|
||||
utils.tc("class add dev %s parent 1:1 classid 1:2 "
|
||||
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max, debit_max))
|
||||
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max[int_key], debit_max[int_key]))
|
||||
|
||||
# Classe par defaut
|
||||
utils.tc('class add dev %s parent 1:2 classid 1:10 '
|
||||
'htb rate %smbit ceil %smbit prio 1' % (dev[int_key], debit_max, debit_max))
|
||||
'htb rate %smbit ceil %smbit prio 1' % (dev[int_key], debit_max[int_key], debit_max[int_key]))
|
||||
utils.tc('qdisc add dev %s parent 1:10 '
|
||||
'handle 10: sfq perturb 10' % dev[int_key])
|
||||
|
||||
# Classe par pour la voip
|
||||
utils.tc('class add dev %s parent 1:2 classid 1:12 '
|
||||
'htb rate %smbit ceil %smbit prio 0' % (dev[int_key], debit_max, debit_max))
|
||||
'htb rate %smbit ceil %smbit prio 0' % (dev[int_key], debit_max[int_key], debit_max[int_key]))
|
||||
utils.tc('qdisc add dev %s parent 1:12 '
|
||||
'handle 12: sfq perturb 10' % dev[int_key])
|
||||
|
||||
|
@ -581,7 +622,7 @@ class firewall(base.firewall_routeur):
|
|||
|
||||
# Classe pour le download des apparetments
|
||||
utils.tc("class add dev %s parent 1: classid 1:3 "
|
||||
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max/10, debit_max/2))
|
||||
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max['total']/10, debit_max['total']/2))
|
||||
utils.tc('qdisc add dev %s parent 1:3 '
|
||||
'handle 3: sfq perturb 10' % dev[int_key])
|
||||
|
||||
|
@ -605,7 +646,7 @@ class firewall(base.firewall_routeur):
|
|||
|
||||
# Classe pour le download wifi federez
|
||||
utils.tc("class add dev %s parent 1: classid 1:5 "
|
||||
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max/10, debit_max/2))
|
||||
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max['total']/10, debit_max['total']/2))
|
||||
utils.tc('qdisc add dev %s parent 1:5 '
|
||||
'handle 3: sfq perturb 10' % dev[int_key])
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import netaddr
|
||||
|
||||
if '/usr/scripts/' not in sys.path:
|
||||
sys.path.append('/usr/scripts/')
|
||||
if '/usr/scripts' not in sys.path:
|
||||
sys.path.append('/usr/scripts')
|
||||
|
||||
import syslog
|
||||
import subprocess
|
||||
|
@ -56,7 +55,7 @@ class firewall_tools(object) :
|
|||
"""Classe de base du pare-feu implémentant l'association mac-ip (pour les machines filaires) et les blacklists hard"""
|
||||
|
||||
def machines(self):
|
||||
"""Renvois la liste de toutes les machines"""
|
||||
"""Renvoit la liste de toutes les machines"""
|
||||
if self._machines:
|
||||
return self._machines
|
||||
# On utilise allMachinesAdherents car on a besoin que
|
||||
|
@ -64,48 +63,37 @@ class firewall_tools(object) :
|
|||
# les blacklistes d'un proprio lorsque l'on regarde les blacklistes
|
||||
# d'une machine
|
||||
anim('\tChargement des machines')
|
||||
self._machines, self._adherents = self.conn.allMachinesAdherents()
|
||||
self._adherents = [ adh for adh in self._adherents if adh.paiement_ok() ]
|
||||
# On prend toutes les machines y compris celles de ceux qui n'ont pas payé
|
||||
# elles seront ajoutées dans mac_ip mais blacklistées du fait du non paiement ensuite
|
||||
self._machines = self.conn.allMachines()
|
||||
|
||||
print OK
|
||||
return self._machines
|
||||
|
||||
def adherents(self):
|
||||
"""
|
||||
Renvois la liste de tous les adhérents à jour de paiement
|
||||
(car on suppose que la blackliste paiement est hard)
|
||||
"""
|
||||
if self._adherents:
|
||||
return self._adherents
|
||||
self._machines, self._adherents = self.conn.allMachinesAdherents()
|
||||
self._adherents = [ adh for adh in self._adherents if adh.paiement_ok() ]
|
||||
return self._adherents
|
||||
|
||||
def blacklisted_machines(self):
|
||||
"""Renvois la liste de toutes les machines ayant une blackliste actives"""
|
||||
"""Renvoit la liste de toutes les machines ayant une blackliste actives"""
|
||||
if self._blacklisted_machines:
|
||||
return self._blacklisted_machines
|
||||
self._blacklisted_machines = [ machine for machine in self.machines() if machine.blacklist_actif() ]
|
||||
return self._blacklisted_machines
|
||||
|
||||
def blacklisted_ips(self, blacklist_sanctions=None, nets=None):
|
||||
"""Renvois l'ensemble des ips des machines ayant une blacklist dans blacklist_sanctions et étant dans nets si spécifié"""
|
||||
def blacklisted_ips(self, blacklist_sanctions=None):
|
||||
"""Renvoit l'ensemble des ips des machines ayant une blacklist dans blacklist_sanctions et étant dans nets si spécifié"""
|
||||
bl_ips = set()
|
||||
for machine in self.blacklisted_machines():
|
||||
if blacklist_sanctions is None or set(bl['type'] for bl in machine.blacklist_actif()).intersection(blacklist_sanctions):
|
||||
for ip in machine['ipHostNumber']:
|
||||
if nets is None:
|
||||
bl_ips.add(str(ip))
|
||||
else:
|
||||
for net in nets:
|
||||
if ip.value in netaddr.IPNetwork(net):
|
||||
bl_ips.add(str(ip))
|
||||
bl_ips.add(str(ip))
|
||||
return bl_ips
|
||||
|
||||
def blacklisted_adherents(self, excepts=[]):
|
||||
"""Renvois la liste de tous les adhérents ayant une blackliste active en ignorant les blacklist de excepts"""
|
||||
"""Renvoit la liste de tous les adhérents ayant une blackliste active en ignorant les blacklist de excepts"""
|
||||
if not self._adherents:
|
||||
self._adherents = self.conn.allAdherents()
|
||||
|
||||
if self._blacklisted_adherents and self._blacklisted_adherents_type == set(excepts):
|
||||
return self._blacklisted_adherents
|
||||
self._blacklisted_adherents = filter(lambda adh: adh.blacklist_actif(excepts), self.adherents())
|
||||
self._blacklisted_adherents = filter(lambda adh: adh.blacklist_actif(excepts), self._adherents)
|
||||
self._blacklisted_adherents_type = set(excepts)
|
||||
return self._blacklisted_adherents
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ class firewall(base.firewall):
|
|||
self.add(table, chain, '-d 127.0.0.1/8 -j RETURN')
|
||||
for net in base.config.NETs['all']:
|
||||
self.add(table, chain, '-d %s -j RETURN' % net)
|
||||
for adh in self.blacklisted_adherents():
|
||||
for adh in self.blacklisted_adherents(excepts=['paiement']):
|
||||
if 'uidNumber' in adh:
|
||||
self.add(table, chain, '-m owner --uid-owner %s -j REJECT' % adh['uidNumber'][0])
|
||||
print OK
|
||||
|
|
|
@ -136,7 +136,7 @@ def main_router():
|
|||
ip6tables.mangle.prerouting('-i %s -m state --state NEW -j LOG --log-prefix "LOG_ALL "' % dev_ip6 )
|
||||
|
||||
# On force le /32 de google à passer en ipv4 pour tester si ça soulage le tunnel ipv6
|
||||
ip6tables.filter.forward('-o %s -p tcp -d 2a00:1450:4006::/32 -j REJECT' % dev_ip6)
|
||||
ip6tables.filter.forward('-o %s -p tcp -d 2a00:1450:4006::/32 -j REJECT --reject-with icmp6-addr-unreachable' % dev_ip6)
|
||||
|
||||
# Ipv6 sur évènementiel, on ne laisse sortir que si ça vient de la mac d'ytrap-llatsni
|
||||
ip6tables.filter.forward('-o %s -d 2a01:240:fe3d:d2::/64 -j ACCEPT' % dev_crans)
|
||||
|
|
|
@ -64,10 +64,7 @@ class base_reconfigure:
|
|||
'warez':__service_develop['blacklist_warez'],
|
||||
'ipv6_ra':__service_develop['blacklist_ipv6_ra'],
|
||||
'upload': __service_develop['blacklist_upload'],
|
||||
'p2p': __service_develop['blacklist_p2p'],
|
||||
'autodisc_virus':__service_develop['blacklist_autodisc_virus'],
|
||||
'autodisc_upload': __service_develop['blacklist_autodisc_upload'],
|
||||
'autodisc_p2p': __service_develop['blacklist_autodisc_p2p'],
|
||||
'bloq': __service_develop['blacklist_bloq'],
|
||||
})
|
||||
except ImportError:
|
||||
|
|
|
@ -16,31 +16,37 @@
|
|||
|
||||
|
||||
import sys
|
||||
sys.path.append('/usr/scripts/gestion')
|
||||
if '/usr/scripts' not in sys.path:
|
||||
sys.path.append('/usr/scripts')
|
||||
|
||||
import commands
|
||||
import os
|
||||
|
||||
IPSET_PATH = '/sbin/ipset'
|
||||
|
||||
# Avant jessie: ipset était dans /usr/sbin
|
||||
if not os.path.exists(IPSET_PATH):
|
||||
IPSET_PATH = '/usr' + IPSET_PATH
|
||||
|
||||
class IpsetError(Exception):
|
||||
# Gestion des erreurs d'ipset
|
||||
def __init__(self,cmd,err_code,output):
|
||||
self.cmd=cmd
|
||||
self.err_code=err_code
|
||||
self.output=output
|
||||
def __init__(self, cmd, err_code, output):
|
||||
self.cmd = cmd
|
||||
self.err_code = err_code
|
||||
self.output = output
|
||||
def __str__(self):
|
||||
return "%s\n status : %s\n %s" % (self.cmd,self.err_code,self.output)
|
||||
return "%s\n status : %s\n %s" % (self.cmd, self.err_code, self.output)
|
||||
|
||||
class Ipset(object):
|
||||
ipset="/usr/sbin/ipset"
|
||||
ipset = IPSET_PATH
|
||||
|
||||
def __str__(self):
|
||||
return self.set
|
||||
|
||||
def __init__(self,set,type,typeopt=''):
|
||||
self.set=set
|
||||
self.type=type
|
||||
self.typeopt=typeopt
|
||||
self.squeeze = os.uname()[2] < '3'
|
||||
def __init__(self, set, type, typeopt=''):
|
||||
self.set = set
|
||||
self.type = type
|
||||
self.typeopt = typeopt
|
||||
try:
|
||||
self.create()
|
||||
except IpsetError as error:
|
||||
|
@ -50,62 +56,58 @@ class Ipset(object):
|
|||
raise
|
||||
pass
|
||||
|
||||
def call(self,cmd,arg=''):
|
||||
def call(self, cmd, arg=''):
|
||||
"""Appel système à ipset"""
|
||||
cmd_line="%s %s %s %s" % (self.ipset,cmd,self.set,arg)
|
||||
status,output=commands.getstatusoutput(cmd_line)
|
||||
cmd_line = "%s %s %s %s" % (self.ipset, cmd, self.set, arg)
|
||||
status, output = commands.getstatusoutput(cmd_line)
|
||||
if status:
|
||||
raise IpsetError(cmd_line,status,output)
|
||||
raise IpsetError(cmd_line, status, output)
|
||||
return output
|
||||
|
||||
def create(self,opt=''):
|
||||
self.call("-N","%s %s" % (self.type, self.typeopt))
|
||||
def create(self, opt=''):
|
||||
self.call("create", "%s %s" % (self.type, self.typeopt))
|
||||
|
||||
def add(self,arg):
|
||||
self.call("-A",arg)
|
||||
def add(self, arg):
|
||||
self.call("add", arg)
|
||||
|
||||
def list(self):
|
||||
output=self.call("-L").splitlines()
|
||||
list=[]
|
||||
output = self.call("list").splitlines()
|
||||
list = []
|
||||
for line in output[6:]:
|
||||
if line=='Bindings:':
|
||||
if line == 'Bindings:':
|
||||
break
|
||||
list.append(line)
|
||||
return list
|
||||
|
||||
def delete(self,ip):
|
||||
def delete(self, ip):
|
||||
"""Delete an IP"""
|
||||
self.call("-D",ip)
|
||||
|
||||
def restore(self,rules):
|
||||
self.call("del", ip)
|
||||
|
||||
def restore(self, rules):
|
||||
""" restore le set courrant"""
|
||||
rules_str=self.restore_format(rules)
|
||||
if self.squeeze:
|
||||
create_str="-N %s %s %s" % (self.set,self.type,self.typeopt)
|
||||
str="%s\n%s\nCOMMIT\n" % (create_str,rules_str)
|
||||
else:
|
||||
str="%s\nCOMMIT\n" % rules_str
|
||||
path='/tmp/ipset_%s' % self.set
|
||||
f=open(path, 'w+')
|
||||
rules_str = self.restore_format(rules)
|
||||
str = "%s\nCOMMIT\n" % rules_str
|
||||
path = '/tmp/ipset_%s' % self.set
|
||||
f = open(path, 'w+')
|
||||
f.write(str)
|
||||
f.close()
|
||||
try:
|
||||
self.flush()
|
||||
if self.squeeze:
|
||||
self.destroy()
|
||||
except IpsetError as error: sys.stderr.write("%s\n" % error)
|
||||
cmd="cat %s | %s -R" % (path,self.ipset)
|
||||
status,output=commands.getstatusoutput(cmd)
|
||||
except IpsetError as error:
|
||||
sys.stderr.write("%s\n" % error)
|
||||
|
||||
cmd = "cat %s | %s -R" % (path, self.ipset)
|
||||
status, output = commands.getstatusoutput(cmd)
|
||||
if status:
|
||||
raise IpsetError(cmd,status,output)
|
||||
raise IpsetError(cmd, status, output)
|
||||
return output
|
||||
|
||||
def flush(self):
|
||||
self.call("-F")
|
||||
self.call("flush")
|
||||
|
||||
def destroy(self):
|
||||
self.call("-X")
|
||||
self.call("destroy")
|
||||
|
||||
def restore_format(self,rules):
|
||||
return '\n'.join(["-A %s %s" % (self.set,data) for data in rules])
|
||||
def restore_format(self, rules):
|
||||
return '\n'.join(["add %s %s" % (self.set, data) for data in rules])
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ console inactivity-timer 30
|
|||
logging {{ s }}
|
||||
{%- endfor %}
|
||||
;--- IP du switch ---
|
||||
ip default-gateway 10.231.136.4
|
||||
ip default-gateway {{ gateway }}
|
||||
{%- for vlan in vlans %}
|
||||
vlan {{ vlan.id }}
|
||||
name "{{ vlan.name|capitalize }}"
|
||||
|
@ -54,12 +54,13 @@ no web-management
|
|||
aaa authentication ssh login public-key none
|
||||
aaa authentication ssh enable public-key none
|
||||
ip ssh
|
||||
ip authorized-managers 10.231.136.0 255.255.255.0
|
||||
ip authorized-managers {{ network_id }} {{ subnet }}
|
||||
ip ssh filetransfer
|
||||
;--- Protection contre les boucles ---
|
||||
loop-protect disable-timer 30
|
||||
loop-protect transmit-interval 3
|
||||
loop-protect {{ non_trusted }}
|
||||
{%- if not public %}
|
||||
;--- Serveurs radius ---
|
||||
radius-server dead-time 2
|
||||
radius-server key {{ radius_key }}
|
||||
|
@ -68,6 +69,7 @@ radius-server host {{ s }}
|
|||
{%- endfor %}
|
||||
;--- Filtrage mac ---
|
||||
aaa port-access mac-based addr-format multi-colon
|
||||
{%- endif %}
|
||||
;--- Bricoles ---
|
||||
no cdp run
|
||||
no stack
|
||||
|
@ -86,7 +88,7 @@ no ipv6 ra-guard ports {{ trusted }}
|
|||
{% endif %}
|
||||
;--- Config des prises ---
|
||||
{%- for port in ports %}
|
||||
{%- if port.radius_auth() %}
|
||||
{%- if port.radius_auth() and not public %}
|
||||
aaa port-access mac-based {{ port|int }}
|
||||
aaa port-access mac-based {{ port|int }} addr-limit {{ port.num_mac() }}
|
||||
aaa port-access mac-based {{ port|int }} logoff-period 3600
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Génération de la configuration d'un switch.
|
||||
|
||||
Attention, cette version n'a pas encore été totalement testée.
|
||||
|
||||
procédure de configuration initiale :
|
||||
* mot de passe admin (password manager user-name <username>)
|
||||
* activation du ssh (crypto key generate ssh)
|
||||
* copie fichier de conf
|
||||
pour les reconfiguration copier le fichier de conf
|
||||
pour les reconfiguration copier le fichier de conf
|
||||
dans /cfg/startup-config
|
||||
|
||||
Dans tous les cas FAIRE LE SNMP A LA MAIN (script hptools)
|
||||
|
@ -73,13 +71,13 @@ def net_of_vlan_name(name):
|
|||
class Port(object):
|
||||
"""Un port de switch"""
|
||||
num = None
|
||||
|
||||
|
||||
# : uplink: None ou str
|
||||
uplink = None
|
||||
|
||||
|
||||
# : Liste de serveurs
|
||||
servers = None
|
||||
|
||||
|
||||
# : Liste de bornes
|
||||
bornes = None
|
||||
|
||||
|
@ -100,7 +98,7 @@ class Port(object):
|
|||
self.chambres = list()
|
||||
self.seen_macs = list()
|
||||
self.seen_vlans = list()
|
||||
|
||||
|
||||
def __str__(self):
|
||||
if self.uplink:
|
||||
return self.uplink
|
||||
|
@ -139,7 +137,7 @@ class Port(object):
|
|||
if any( adh.get('droits', None) for adh in self.adherents()):
|
||||
return ''
|
||||
return 'speed-duplex auto-10-100'
|
||||
|
||||
|
||||
def flowcontrol(self):
|
||||
"""Est-ce que le flowcontrol est activé sur ce port ?"""
|
||||
if self.uplink or self.servers:
|
||||
|
@ -190,11 +188,11 @@ class Port(object):
|
|||
# l'auth radius
|
||||
else:
|
||||
return V_NO
|
||||
|
||||
|
||||
def radius_auth(self):
|
||||
"""Doit-on faire de l'auth radius ?"""
|
||||
return not self.uplink and not self.servers and not self.bornes
|
||||
|
||||
|
||||
def adherents(self):
|
||||
"""Adhérents sur la prise"""
|
||||
filtre = u'(|%s)' % (''.join('(chbre=%s)' % c for c in self.chambres))
|
||||
|
@ -227,7 +225,7 @@ class PortList(list):
|
|||
"""
|
||||
liste = list(int(x) for x in self)
|
||||
liste.sort()
|
||||
|
||||
|
||||
sortie = []
|
||||
groupe = [-99999, -99999]
|
||||
for x in itertools.chain(liste, [99999]):
|
||||
|
@ -270,7 +268,7 @@ def get_port_dict(switch):
|
|||
port.servers.append(machine)
|
||||
elif classe == 'borneWifi':
|
||||
port.bornes.append(machine)
|
||||
|
||||
|
||||
# On remplit les chambres
|
||||
for prise, chbres in annuaire.reverse(bat).iteritems():
|
||||
# TODO rajouter un arg à reverse
|
||||
|
@ -349,7 +347,7 @@ def check_conf_ldap(hostname):
|
|||
# La chambre est inconnue -> drop
|
||||
continue
|
||||
th_prises_set.add(th_prise)
|
||||
|
||||
|
||||
pr_prise = bat.lower() + '%d%02d' % (sw_num, port.num)
|
||||
if th_prises_set and pr_prise not in th_prises_set:
|
||||
print(" Aucune machine de chbre. Candidats: %r" % th_prises_set)
|
||||
|
@ -402,7 +400,7 @@ def format_prises_group(data, first, last):
|
|||
prises. Entre first et last"""
|
||||
first = (first-1)/2*2+1
|
||||
last = (-last/2)*-2
|
||||
|
||||
|
||||
def align5(txt, right=False):
|
||||
"""Aligne le texte en limitant à 5 char"""
|
||||
if len(txt) > 5:
|
||||
|
@ -443,7 +441,11 @@ def format_prises_group(data, first, last):
|
|||
def pretty_print(hostname):
|
||||
"""Affiche joliement le plan de connexion d'un switch"""
|
||||
bat, sw_num = get_bat_num(hostname)
|
||||
switch = ldap.search(u'host=bat%s-%d.adm.crans.org' % (bat, sw_num))[0]
|
||||
|
||||
try:
|
||||
switch = ldap.search(u'host=bat%s-%d.adm.crans.org' % (bat, sw_num))[0]
|
||||
except IndexError:
|
||||
switch = ldap.search(u'host=bat%s-%d.crans.org' % (bat, sw_num))[0]
|
||||
|
||||
port_dict = get_port_dict(switch)
|
||||
total = max(port_dict.keys())
|
||||
|
@ -463,8 +465,12 @@ def conf_switch(hostname):
|
|||
"""Affiche la configuration d'un switch"""
|
||||
bat, sw_num = get_bat_num(hostname)
|
||||
|
||||
switch = ldap.search(u'host=bat%s-%d.adm.crans.org' % (bat, sw_num))[0]
|
||||
|
||||
try:
|
||||
switch = ldap.search(u'host=bat%s-%d.adm.crans.org' % (bat, sw_num))[0]
|
||||
except IndexError:
|
||||
switch = ldap.search(u'host=bat%s-%d.crans.org' % (bat, sw_num))[0]
|
||||
|
||||
|
||||
tpl_env = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
|
||||
##for info:
|
||||
tpl_env.filters['vlan_id'] = vlan_id
|
||||
|
@ -482,9 +488,6 @@ def conf_switch(hostname):
|
|||
],
|
||||
'radius_key': secrets.get('radius_key'),
|
||||
|
||||
'ntp_servers': ['10.231.136.98'],
|
||||
'log_servers': ['10.231.136.38'],
|
||||
|
||||
# dhcp et isc (secondaire) sont les deux seuls serveurs
|
||||
'dhcp_rid_servers': [34, 160],
|
||||
|
||||
|
@ -519,7 +522,25 @@ def conf_switch(hostname):
|
|||
for rid in data['dhcp_rid_servers']:
|
||||
first = netaddr.IPNetwork(net_of_vlan_name(vname)[0]).first
|
||||
data['dhcp_servers'].append(str(netaddr.IPAddress(first + rid)))
|
||||
|
||||
|
||||
# Si le switch n'est pas en .adm, il n'est pas publique (ex : batk-0)
|
||||
# (désactivation de radius etc)
|
||||
# On règle les logs, ntp, suivant si le switch est public ou privé (adm)
|
||||
if u"adm" in unicode(switch['host']):
|
||||
data['public'] = False
|
||||
data['ntp_servers'] = ['10.231.136.98']
|
||||
data['log_servers'] = ['10.231.136.38']
|
||||
data['gateway'] = '10.231.136.4'
|
||||
data['network_id'] = '10.231.136.0'
|
||||
data['subnet'] = '255.255.255.0'
|
||||
else:
|
||||
data['public'] = True
|
||||
data['ntp_servers'] = ['138.231.136.98']
|
||||
data['log_servers'] = ['138.231.136.38']
|
||||
data['gateway'] = '138.231.136.4'
|
||||
data['network_id'] = '138.231.136.0'
|
||||
data['subnet'] = '255.255.248.0'
|
||||
|
||||
# Ra gards ne concerne que les 2620
|
||||
if "2620" in switch['info'][0].value:
|
||||
data['ra_filter'] = True
|
||||
|
@ -529,7 +550,7 @@ def conf_switch(hostname):
|
|||
# Switch avec des ports gigabit uniquement
|
||||
if imodel in GIGABIT_MODELS:
|
||||
data['gigabit'] = True
|
||||
|
||||
|
||||
# Build ports !
|
||||
ports_list = PortList(get_port_dict(switch).itervalues())
|
||||
data['ports'] = ports_list
|
||||
|
@ -548,9 +569,14 @@ def conf_switch(hostname):
|
|||
V_NO: 'no'}[assign]
|
||||
vlan.setdefault(attr, PortList())
|
||||
vlan[attr].extend(p)
|
||||
if name == 'adm':
|
||||
if name == 'adm' and not data['public']:
|
||||
vlan['ip_cfg'] = (gethostbyname(hostname), '255.255.255.0')
|
||||
if name == 'adherent':
|
||||
# TODO : proprifier cela
|
||||
# Si le switch est publique, adh en non tagué partout
|
||||
if data['public']:
|
||||
vlan['untagged'] = u'1-' + unicode(switch['nombrePrises'][0])
|
||||
vlan['ip_cfg'] = (gethostbyname(hostname), '255.255.248.0')
|
||||
# igmp snooping (multicast) mais nous ne sommes pas querier
|
||||
vlan['extra'] = 'ip igmp\nno ip igmp querier'
|
||||
vlans[name] = vlan
|
||||
|
@ -581,7 +607,7 @@ if __name__ == "__main__":
|
|||
help="Affiche un tableau ascii du plan de connexion du switch")
|
||||
|
||||
options = parser.parse_args(sys.argv[1:])
|
||||
|
||||
|
||||
if options.check:
|
||||
check_conf_ldap(options.hostname)
|
||||
elif options.pretty:
|
||||
|
|
|
@ -29,8 +29,10 @@ from whos import aff
|
|||
import signal
|
||||
import getopt
|
||||
from time import strftime, strptime, localtime, mktime, time
|
||||
import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import re
|
||||
|
||||
import subprocess
|
||||
import affich_tools
|
||||
import config
|
||||
import config.cotisation as cotisation
|
||||
|
@ -39,7 +41,7 @@ from lock import make_lock, remove_lock
|
|||
from ldap_crans import crans_ldap, blacklist_items, droits_possibles, droits_critiques, smtpserv, script_utilisateur
|
||||
from ldap_crans import Adherent, AssociationCrans, Club, Facture
|
||||
from ldap_crans import Machine, MachineFixe, MachineWifi, MachineCrans, BorneWifi
|
||||
from ldap_crans import tz, generalizedTimeFormat, fromGeneralizedTimeFormat
|
||||
from ldap_crans import tz, generalizedTimeFormat, fromGeneralizedTimeFormat, datetimeFromGTF, datetimeToGTF, localizedDatetime
|
||||
import user_tests
|
||||
|
||||
isadm = user_tests.isadm()
|
||||
|
@ -52,6 +54,8 @@ iscontroleur = u'Tresorier' in droits
|
|||
isbureau = u'Bureau' in droits
|
||||
encoding = sys.stdin.encoding or 'UTF-8'
|
||||
|
||||
NAISSANCE_RE = re.compile(r"(?P<jour>[^ ]*)/(?P<mois>[^ ]*)/(?P<annee>[^ ]*)")
|
||||
|
||||
if u'Nounou' in droits:
|
||||
# Si on est nounou
|
||||
if os.path.exists(os.path.expanduser('~/.dialogrc')):
|
||||
|
@ -101,22 +105,30 @@ def set_bases(adher):
|
|||
arg += u'"Chambre :" 4 1 "%s" 4 11 05 00 ' % adher.chbre()
|
||||
arg += u'"(bat+numéro)" 4 17 "" 0 0 0 0 '
|
||||
arg += u'"EXT pour chambre extérieure au campus" 5 1 "" 0 0 0 0 '
|
||||
arg += u'"Date de naissance : " 6 1 "" 6 21 11 11 '
|
||||
arg += u'"Format : dd/mm/yyyy" 7 1 "" 0 0 0 0 '
|
||||
|
||||
# Affichage
|
||||
annul, result = dialog(arg)
|
||||
if annul:
|
||||
if annul or any([result[i] == '' for i in xrange(len(result))]):
|
||||
return 1
|
||||
|
||||
# Traitement
|
||||
err = ''
|
||||
try: adher.nom(result[0])
|
||||
except ValueError, c: err += c.args[0] + '\n'
|
||||
try:
|
||||
adher.nom(result[0])
|
||||
except ValueError, c:
|
||||
err += c.args[0] + '\n'
|
||||
|
||||
try: adher.prenom(result[1])
|
||||
except ValueError, c: err += c.args[0] + '\n'
|
||||
try:
|
||||
adher.prenom(result[1])
|
||||
except ValueError, c:
|
||||
err += c.args[0] + '\n'
|
||||
|
||||
try: adher.tel(result[2])
|
||||
except ValueError, c: err += c.args[0] + '\n'
|
||||
try:
|
||||
adher.tel(result[2])
|
||||
except ValueError, c:
|
||||
err += c.args[0] + '\n'
|
||||
|
||||
# Un adhérent du même nom existe-t-il déjà ?
|
||||
req = 'nom=' + result[0] + '&prenom=' + result[1]
|
||||
|
@ -128,6 +140,25 @@ def set_bases(adher):
|
|||
if no:
|
||||
return 1
|
||||
|
||||
# On controle que l'adh est majeur
|
||||
naissance = NAISSANCE_RE.match(result[4].decode(config.in_encoding))
|
||||
if naissance is None:
|
||||
err += "La date est invalide"
|
||||
else:
|
||||
naissance = naissance.groupdict()
|
||||
try:
|
||||
naissance_date = datetime.date(int(naissance['annee']), int(naissance['mois']), int(naissance['jour']))
|
||||
age = relativedelta(datetime.date.today(), naissance_date).years
|
||||
if age < 18:
|
||||
arg = u'--title "Inscription adhérent" '
|
||||
arg += u'--yesno "Cet adhérent est mineur, merci de demander un accord écrit des parents'
|
||||
arg += u'\nContinuer ?" 0 0'
|
||||
no, res = dialog(arg)
|
||||
if no:
|
||||
return 1
|
||||
except ValueError, c:
|
||||
err += c.args[0] + '\n'
|
||||
|
||||
err += _set_chbre(adher, result[3])
|
||||
|
||||
# Des erreurs ?
|
||||
|
@ -213,6 +244,7 @@ def set_etudes(adher):
|
|||
arg += u'"Maximilien Sorre" "" '
|
||||
arg += u'"Gustave Eiffel" "" '
|
||||
arg += u'"EFREI" "" '
|
||||
arg += u'"ESIGETEL" "" '
|
||||
arg += u'"ESTP" "" '
|
||||
arg += u'"P1" "Université Panthéon Sorbonne" '
|
||||
arg += u'"P2" "Université Panthéon Assas" '
|
||||
|
@ -424,9 +456,12 @@ def set_contact(adher):
|
|||
if result[0].split()[0] == 'Laisser':
|
||||
break
|
||||
elif result[0].split()[1] == u'un':
|
||||
if not set_compte(adher): break
|
||||
if not set_compte(adher):
|
||||
set_mail_ext(adher)
|
||||
break
|
||||
else:
|
||||
if not set_mail(adher): break
|
||||
if not set_mail(adher):
|
||||
break
|
||||
|
||||
def set_mail(adher):
|
||||
"""Demande l'adresse mail extérieure d'un adhérent
|
||||
|
@ -794,7 +829,13 @@ def del_adher(adher):
|
|||
arg += u'--msgbox "Le commentaire est obligatoire\n\n\n" 0 0'
|
||||
dialog(arg)
|
||||
|
||||
adher.delete(res[0])
|
||||
try:
|
||||
adher.delete(res[0])
|
||||
except EnvironmentError, c:
|
||||
arg = u'--title "Destruction du compte" '
|
||||
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(c.args[0])
|
||||
dialog(arg)
|
||||
return
|
||||
|
||||
arg = u'--title "Destruction adhérent" '
|
||||
arg += u'--msgbox "Adhérent détruit\n\n\n" 0 0'
|
||||
|
@ -1049,18 +1090,18 @@ def set_solde(clas):
|
|||
annul, comment = dialog(arg)
|
||||
|
||||
if not annul:
|
||||
if comment[0]:
|
||||
if comment:
|
||||
comment = comment[0]
|
||||
else:
|
||||
comment = None
|
||||
comment = ''
|
||||
|
||||
f = Facture(clas)
|
||||
f.ajoute({'nombre': 1, 'code':'SOLDE', 'designation': "Modification du solde par un imprimeur. Moyen de paiement: %s, remarque: %s" % (_mode, comment), 'pu': _montant})
|
||||
f.ajoute({'nombre': 1, 'code':'SOLDE', 'designation': "Modification du solde par un imprimeur. Moyen de paiement: %s, remarque: %s" % (_mode, comment.decode(config.in_encoding)), 'pu': _montant})
|
||||
f.modePaiement(_mode.lower())
|
||||
|
||||
try:
|
||||
# Met aussi à jour le solde.
|
||||
f.recuPaiement(strftime("%Y-%m-%d %H:%M:%S"))
|
||||
f.recuPaiement(datetimeToGTF(localizedDatetime()))
|
||||
f.save()
|
||||
db.services_to_restart('mail_solde', [
|
||||
'%s a fait %s euros pour %s [mode: %s, remarque: %s]' %
|
||||
|
@ -1074,6 +1115,7 @@ def set_solde(clas):
|
|||
arg = u'--title "%s du solde de %s" ' % (_kword, clas.Nom())
|
||||
arg += u'--msgbox "Modification effectuée, merci de noter le numéro de facture %s." 0 0' % (f.numero(),)
|
||||
dialog(arg)
|
||||
break
|
||||
|
||||
def set_vente(proprio):
|
||||
u"""
|
||||
|
@ -1161,6 +1203,7 @@ def set_vente(proprio):
|
|||
menu.append(u'"Spc" "Espèces" ')
|
||||
menu.append(u'"Chq" "Chèque" ')
|
||||
menu.append(u'"Cb" "Carte bancaire" ')
|
||||
menu.append(u'"Note" "Note Kfet (attention, moins traçable)" ')
|
||||
if isimprimeur and proprio.solde() - f.total() > 0:
|
||||
menu.append(u'"Sol" "Solde Crans (actuel : %s€)" ' % (proprio.solde()))
|
||||
|
||||
|
@ -1187,6 +1230,10 @@ def set_vente(proprio):
|
|||
f.modePaiement('cheque')
|
||||
paiement = u"Chèque"
|
||||
annul, comment = dialog(arg)
|
||||
elif result[0] == "Note":
|
||||
f.modePaiement('note')
|
||||
paiement = u"Note"
|
||||
annul, comment = dialog(arg)
|
||||
elif result[0] == "Sol" and isimprimeur:
|
||||
f.modePaiement('solde')
|
||||
paiement = u"Solde Crans"
|
||||
|
@ -1210,8 +1257,15 @@ def set_vente(proprio):
|
|||
return 1
|
||||
else:
|
||||
try:
|
||||
f.recuPaiement(strftime("%Y-%m-%d %H:%M:%S"))
|
||||
f.recuPaiement(datetimeToGTF(localizedDatetime()))
|
||||
f.save()
|
||||
# arg = u'--title "Impression facture" '
|
||||
# arg += u'--yesno "Voulez vous imprimer cette facture ?\n" 0 0'
|
||||
# no, res_1 = dialog(arg)
|
||||
# if no:
|
||||
# return 1
|
||||
# else:
|
||||
# subprocess.call(['/usr/scripts/cransticket/dump_creds.py','fid=%s' % f.numero()])
|
||||
arg = u'--title "Vente terminée" '
|
||||
arg += u'--msgbox "Vous pouvez remettre à l\'adherent les articles suivant :\n%s\n\nMerci de noter la facture: fid=%s" 0 0' % ('\n'.join([
|
||||
"%s %s" % (art['nombre'], art['designation'])
|
||||
|
@ -1250,9 +1304,26 @@ def confirm(clas):
|
|||
return 1
|
||||
try:
|
||||
res = clas.save()
|
||||
cprint(res)
|
||||
affich_tools.prompt(u"Appuyez sur ENTREE pour continuer")
|
||||
if isinstance(clas, MachineWifi):
|
||||
arg = u'--title "Imprimer code wifi ?" '
|
||||
arg += u'--yesno "Voulez vous imprimer ce code wifi ?\n" 0 0'
|
||||
no, res_0 = dialog(arg)
|
||||
if no:
|
||||
pass
|
||||
else:
|
||||
subprocess.call(['/usr/scripts/cransticket/dump_creds.py', 'mid=%s' % clas.id()])
|
||||
if in_facture is not None:
|
||||
in_facture.recuPaiement(strftime("%Y-%m-%d %H:%M:%S"))
|
||||
in_facture.recuPaiement(datetimeToGTF(localizedDatetime()))
|
||||
in_facture.save()
|
||||
# arg = u'--title "Impression facture" '
|
||||
# arg += u'--yesno "Voulez vous imprimer cette facture ?\n" 0 0'
|
||||
# no, res_2 = dialog(arg)
|
||||
# if no:
|
||||
# pass
|
||||
# else:
|
||||
# subprocess.call(['/usr/scripts/cransticket/dump_creds.py','fid=%s' % in_facture.numero()])
|
||||
except Exception as c:
|
||||
arg = u'--title "Enregistrement" '
|
||||
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(unicode(c.args[0]))
|
||||
|
@ -1260,9 +1331,6 @@ def confirm(clas):
|
|||
return 1
|
||||
in_facture = None
|
||||
|
||||
cprint(res)
|
||||
affich_tools.prompt(u"Appuyez sur ENTREE pour continuer")
|
||||
|
||||
def set_blackliste(clas):
|
||||
u""" Édite ou ajoute un item de la blackliste """
|
||||
bl = clas.blacklist()
|
||||
|
@ -1494,6 +1562,9 @@ def set_adhesion(proprio):
|
|||
facture.modePaiement(_mode.lower())
|
||||
break
|
||||
in_facture = facture
|
||||
if not in_facture._data.get('finConnexion', []) and not in_facture._data.get('finAdhesion', []):
|
||||
in_facture = None
|
||||
proprio.restore()
|
||||
|
||||
def set_connexion(proprio):
|
||||
"""Maj de la période d'accès de l'adhérent"""
|
||||
|
@ -1501,12 +1572,16 @@ def set_connexion(proprio):
|
|||
|
||||
# Si l'adhérent ne l'est plus, on commence par le faire adhérer, sauf s'il a une facture adhésion.
|
||||
adhEnd = proprio.adhesion()
|
||||
|
||||
if in_facture is not None:
|
||||
adhEnd = max(adhEnd, fromGeneralizedTimeFormat(in_facture._data.get('finAdhesion', ["19700101000000Z"])[0]))
|
||||
if adhEnd < time():
|
||||
|
||||
if adhEnd - cotisation.delai_readh < time():
|
||||
stat = set_adhesion(proprio)
|
||||
if stat == 1:
|
||||
|
||||
if stat == 1 and adhEnd < time():
|
||||
return 1
|
||||
|
||||
if in_facture is not None:
|
||||
adhEnd = max(adhEnd, fromGeneralizedTimeFormat(in_facture._data.get('finAdhesion', ["19700101000000Z"])[0]))
|
||||
|
||||
|
@ -1521,7 +1596,7 @@ def set_connexion(proprio):
|
|||
while True:
|
||||
args = u'--title "Connexion de %s" ' % proprio.Nom()
|
||||
if proprio.connexion() > time():
|
||||
args += u'--menu "Connexion jusqu\'au %s, choisir une durée de prolongation. : " 0 0 0 ' % (strftime("%d/%m/%Y %H:%M:%S"),)
|
||||
args += u'--menu "Connexion jusqu\'au %s, choisir une durée de prolongation. : " 0 0 0 ' % (strftime("%d/%m/%Y %H:%M:%S", localtime(proprio.connexion())),)
|
||||
else:
|
||||
args += u'--menu "Connexion actuellement inactive, choisir une durée. : " 0 0 0 '
|
||||
args += u'"An" "Prolonger d\'un an." '
|
||||
|
@ -1531,7 +1606,8 @@ def set_connexion(proprio):
|
|||
annul, res = dialog(args)
|
||||
|
||||
if annul:
|
||||
in_facture.supprime(pop=True)
|
||||
if in_facture is not None:
|
||||
in_facture.supprime(pop=True)
|
||||
return 1
|
||||
res = res[0]
|
||||
if res == "An":
|
||||
|
@ -1581,17 +1657,17 @@ def set_connexion(proprio):
|
|||
newEnd = fromGeneralizedTimeFormat(facture._data.get('finConnexion', ["19700101000000Z"])[0])
|
||||
if newEnd > adhEnd:
|
||||
arg = u'--title "Avertissement" '
|
||||
arg += u'--yesno "La fin de la connexion de l\'adhérent (%s) tombera après la fin de son adhésion (%s).\nS\'il veut en profiter, il lui faudra éventuellement réadhérer. Continuer ?" 0 0' %(strftime('%d/%m/%Y %H:%M:%S', localtime(newEnd)), strftime('%d/%m/%Y %H:%M:%S', localtime(adhEnd)), )
|
||||
no, res = dialog(arg)
|
||||
if no:
|
||||
arg += u'--yesno "La nouvelle fin de connexion (%s) arriverait après la fin de l\'adhésion actuelle (%s).\nIl sera nécessaire que l\'adhérent réadhère, (possible %s jours avant la fin de l\'adhésion actuelle).\n\nLe paiement ne vaut *PAS* réadhésion. Merci de lui préciser explicitement !" 0 0 ' % (strftime("%d/%m/%Y %H:%M:%S", localtime(newEnd)), strftime("%d/%m/%Y %H:%M:%S", localtime(adhEnd)), cotisation.delai_readh_jour)
|
||||
annul, res = dialog(arg)
|
||||
if annul:
|
||||
facture._set('finConnexion', [])
|
||||
facture._set('debutConnexion', [])
|
||||
facture.supprime(pop=True)
|
||||
continue
|
||||
break
|
||||
|
||||
if not facture.modePaiement():
|
||||
arg = u'--title "Mode de paiement pour la connexion de %s" ' % (proprio.Nom(),)
|
||||
arg += u'--menu "Comment %s souhaite-t-il payer ?" 0 0 0 ' % (proprio.Nom(), )
|
||||
arg += u'--menu "Comment %s souhaite-t-il payer ?" 0 0 0 ' % (proprio.Nom(),)
|
||||
arg += u'"Liquide" "En espèces : penser à mettre l\'argent dans une enveloppe." '
|
||||
arg += u'"Cheque" "Par chèque : ne pas oublier de vérifier signature, date, ordre et montant." '
|
||||
arg += u'"Carte" "Par CB : tromboner le ticket." '
|
||||
|
@ -1618,6 +1694,10 @@ def set_connexion(proprio):
|
|||
break
|
||||
in_facture = facture
|
||||
|
||||
if not in_facture._data.get('finConnexion', []) and not in_facture._data.get('finAdhesion', []):
|
||||
in_facture = None
|
||||
proprio.restore()
|
||||
|
||||
###############################################################
|
||||
## Fonctions de remplissage ou modification des paramètres club
|
||||
|
||||
|
@ -1778,7 +1858,7 @@ def set_facture_recu(facture):
|
|||
if annul:
|
||||
return 1
|
||||
if u"Pmt" in res:
|
||||
facture.recuPaiement(strftime("%Y-%m-%d %H:%M:%S"))
|
||||
facture.recuPaiement(datetimeToGTF(localizedDatetime()))
|
||||
else:
|
||||
facture.recuPaiement(False)
|
||||
|
||||
|
@ -2104,8 +2184,10 @@ def new_adher(adher):
|
|||
4 etapes :
|
||||
* set_bases
|
||||
* set_etudes
|
||||
* set_admin
|
||||
* set_adhesion
|
||||
* set_connexion
|
||||
* set_contact
|
||||
(qui appelle set_mail_ext si on met un compte crans)
|
||||
* set_rque
|
||||
Retourne 1 si annulation.
|
||||
"""
|
||||
|
@ -2117,15 +2199,16 @@ def new_adher(adher):
|
|||
set_etudes,
|
||||
set_adhesion,
|
||||
set_connexion,
|
||||
set_admin,
|
||||
set_contact,
|
||||
set_mail_ext,
|
||||
set_rque,
|
||||
]
|
||||
|
||||
step = 0
|
||||
while step < len(steps):
|
||||
if steps[step](adher): step -= 1
|
||||
if steps[step](adher):
|
||||
if step == 0:
|
||||
return 1
|
||||
step -= 1
|
||||
else: step += 1
|
||||
|
||||
if not confirm(adher): break
|
||||
|
@ -2155,7 +2238,8 @@ def modif_adher(adher):
|
|||
arg += u'--menu "Que souhaitez vous modifier ?" 0 0 0 '
|
||||
arg += u'"Connexion" "Mise à jour de l\'accès Internet (effectue la réadhésion si besoin)" '
|
||||
arg += u'"Adhesion" "Pour toute réadhésion *sans* connexion." '
|
||||
arg += u'"Administratif" "Pour renseigner la fournitire de la charte des MA." '
|
||||
if isadm or isbureau:
|
||||
arg += u'"Administratif" "Pour renseigner la fourniture de la charte des MA." '
|
||||
arg += u'"Etat-civil" "Nom, prénom" '
|
||||
if adher.chbre() == 'EXT':
|
||||
arg += u'"Adresse" "Déménagement" '
|
||||
|
@ -2167,7 +2251,7 @@ def modif_adher(adher):
|
|||
arg += u'"Mail" "Créer un compte ou changer l\'adresse mail de contact" '
|
||||
if 'cransAccount' in adher._data['objectClass']:
|
||||
arg += u'"MailExt" "Ajouter une adresse mail de contact extérieur." '
|
||||
arg += u'"Alias" "Créer ou supprimer un alias mail" '
|
||||
arg += u'"Alias" "Créer ou supprimer un alias mail" '
|
||||
arg += u'"GPGFingerprint" "Ajouter ou supprimer une empreinte GPG" '
|
||||
arg += u'"Remarque" "Ajouter ou modifer un commentaire" '
|
||||
if isadm or isbureau:
|
||||
|
@ -2179,7 +2263,7 @@ def modif_adher(adher):
|
|||
arg += u'"Shell" "Changer le shell de cet utilisateur" '
|
||||
if isdeconnecteur:
|
||||
arg += u'"Blackliste" "Modifier la blackliste de cet adhérent" '
|
||||
if isimprimeur:
|
||||
if isimprimeur and adher.compte():
|
||||
arg += u'"Solde" "Effectuer un débit/crédit pour cet adhérent" '
|
||||
arg += u'"Vente" "Vendre un cable ou adaptateur ethernet ou autre" '
|
||||
|
||||
|
@ -2236,13 +2320,15 @@ def modif_adher(adher):
|
|||
arg += u'--msgbox "Vous n\'avez pas les droits necessaires pour effectuer cette opération.\n\n\n" 0 0'
|
||||
dialog(arg)
|
||||
return modif_adher(adher)
|
||||
|
||||
arg = u'--title "Départ de %s" ' % adher.Nom()
|
||||
arg += u'--yesno "Le départ du campus de %s va provoquer la destruction de son compte.\n' % adher.Nom()
|
||||
arg += u'\nDoit-on continuer ?" 0 0'
|
||||
no, res = dialog(arg)
|
||||
if no: return modif_adher(adher)
|
||||
for m in adher.machines():
|
||||
m.delete("Depart du campus")
|
||||
|
||||
if no:
|
||||
return modif_adher(adher)
|
||||
|
||||
try:
|
||||
adher.delete("Depart du campus")
|
||||
except EnvironmentError, c:
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
#!/usr/bin/env python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This file is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
|
||||
|
||||
import os
|
||||
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
#!/bin/bash /usr/scripts/python.sh
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This file is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
|
||||
"""Ce sont les variables utiles pour les autres scripts du
|
||||
module"""
|
||||
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
#!/bin/bash /usr/scripts/python.sh
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This file is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
|
||||
"""Contient les outils pour manipuler des adresses MAC
|
||||
dans le module hptools"""
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue