Compare commits
No commits in common. "master" and "peb_dev" have entirely different histories.
217 changed files with 22913 additions and 25578 deletions
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -17,8 +17,17 @@
|
||||||
# Cr@ns specific ignore files #
|
# 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
|
# Les clés wifi privées
|
||||||
archive/gestion/clef-wifi*
|
gestion/clef-wifi*
|
||||||
|
|
||||||
# Autres dépôts git
|
# Autres dépôts git
|
||||||
gestion/logreader/
|
gestion/logreader/
|
||||||
|
|
31
README.md
31
README.md
|
@ -1,31 +0,0 @@
|
||||||
|
|
||||||
## 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,8 +1,7 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#! /usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (C) Stéphane Glondu, Alexandre Bos, Michel Blockelet
|
# Copyright (C) Stéphane Glondu, Alexandre Bos, Michel Blockelet
|
||||||
# Remanié en 2015 par Gabriel Détraz
|
|
||||||
# Licence : GPLv2
|
# Licence : GPLv2
|
||||||
|
|
||||||
u"""Ce script permet au secrétaire de repérer plus facilement les membres
|
u"""Ce script permet au secrétaire de repérer plus facilement les membres
|
||||||
|
@ -22,23 +21,22 @@ Les commandes sont :
|
||||||
|
|
||||||
|
|
||||||
import sys, os, re
|
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
|
# Fonctions d'affichage
|
||||||
from gestion.affich_tools import coul, tableau, prompt, cprint
|
from affich_tools import coul, tableau, prompt, cprint
|
||||||
|
|
||||||
from utils.sendmail import actually_sendmail
|
|
||||||
from gestion import mail
|
|
||||||
|
|
||||||
# Importation de la base de données
|
# Importation de la base de données
|
||||||
from lc_ldap import shortcuts
|
from ldap_crans import crans_ldap, ann_scol
|
||||||
|
db = crans_ldap()
|
||||||
|
|
||||||
# Lors des tests, on m'envoie tous les mails !
|
# Lors des tests, on m'envoie tous les mails !
|
||||||
from socket import gethostname
|
from socket import gethostname
|
||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
# Conn à la db
|
|
||||||
ldap = shortcuts.lc_ldap_admin()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) > 3 and sys.argv[-2] == '--debug':
|
if len(sys.argv) > 3 and sys.argv[-2] == '--debug':
|
||||||
debug = sys.argv[-1]
|
debug = sys.argv[-1]
|
||||||
|
@ -67,28 +65,33 @@ def _controle_interactif_adherents(liste):
|
||||||
|
|
||||||
nb = 0
|
nb = 0
|
||||||
for a in liste:
|
for a in liste:
|
||||||
valeur = a['charteMA']
|
valeur = a.charteMA()
|
||||||
if valeur:
|
if valeur:
|
||||||
suggestion = 'o'
|
suggestion = 'o'
|
||||||
else:
|
else:
|
||||||
suggestion = 'n'
|
suggestion = 'n'
|
||||||
ok = prompt(u'[%3d] %s, %s (%s) ?'
|
ok = prompt(u'[%3d] %s, %s (%s) ?'
|
||||||
% (restant, a['nom'][0], a['prenom'][0], a['aid'][0]), suggestion, '').lower()
|
% (restant, a.nom(), a.prenom(), a.id()), suggestion, '').lower()
|
||||||
restant -= 1
|
restant -= 1
|
||||||
if ok == 'o':
|
if ok == 'o':
|
||||||
nb += 1
|
nb += 1
|
||||||
if a['charteMA'] != True :
|
if a.charteMA() == False :
|
||||||
modifiable = ldap.search(u'aid=%s' % a['aid'][0], mode='rw')
|
modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0]
|
||||||
try:
|
if modifiable._modifiable:
|
||||||
with modifiable[0] as adh:
|
modifiable.charteMA(True)
|
||||||
adh['charteMA']=True
|
cprint(modifiable.save())
|
||||||
adh.history_gen()
|
else:
|
||||||
adh.save()
|
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
|
||||||
cprint(u'Controle OK')
|
elif ok == 'n':
|
||||||
except:
|
if a.charteMA() == True:
|
||||||
cprint(u'Adhérent %s locké, réessayer plus tard' % a['nom'][0], 'rouge')
|
modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0]
|
||||||
elif ok != 'n':
|
if modifiable._modifiable:
|
||||||
cprint(u'Arrêt du contrôle des membres actifs', 'rouge')
|
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')
|
||||||
break
|
break
|
||||||
|
|
||||||
return nb, len(liste)-nb
|
return nb, len(liste)-nb
|
||||||
|
@ -96,12 +99,12 @@ def _controle_interactif_adherents(liste):
|
||||||
|
|
||||||
def liste_charte_nok():
|
def liste_charte_nok():
|
||||||
"""Retourne la liste des membres actifs qui n'ont pas signé la charte."""
|
"""Retourne la liste des membres actifs qui n'ont pas signé la charte."""
|
||||||
liste_actifs = ldap.search(u'droits=*')
|
liste_actifs = db.search('droits=*')['adherent']
|
||||||
liste_nok = []
|
liste_nok = []
|
||||||
for adh in liste_actifs:
|
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
|
if droit not in ['Multimachines', 'Webradio']]) > 0
|
||||||
and not adh['charteMA']):
|
and not adh.charteMA()):
|
||||||
liste_nok.append(adh)
|
liste_nok.append(adh)
|
||||||
return liste_nok
|
return liste_nok
|
||||||
|
|
||||||
|
@ -113,7 +116,7 @@ def controle_interactif():
|
||||||
|
|
||||||
# Tri de la liste des adhérents selon nom, prénom
|
# 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
|
# Ça peut se faire plus facilement en Python 2.4 avec l'argument key
|
||||||
todo_list.sort(lambda x, y: cmp((x['nom'][0], x['prenom'][0]), (y['nom'][0], y['prenom'][0])))
|
todo_list.sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom())))
|
||||||
|
|
||||||
# Zou !
|
# Zou !
|
||||||
ok, nok = _controle_interactif_adherents(todo_list)
|
ok, nok = _controle_interactif_adherents(todo_list)
|
||||||
|
@ -129,18 +132,19 @@ def spammer():
|
||||||
todo_list = liste_charte_nok()
|
todo_list = liste_charte_nok()
|
||||||
|
|
||||||
if todo_list:
|
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"
|
print "Envoi des mails de rappel pour les chartes des membres actifs"
|
||||||
|
|
||||||
for adh in todo_list:
|
for adh in todo_list:
|
||||||
to = adh['mail'][0]
|
to = adh.email()
|
||||||
print to
|
print to
|
||||||
if not debug:
|
if not debug:
|
||||||
From = u"ca@crans.org"
|
data = config.mails.txt_charte_MA % {'From' : u"ca@crans.org", 'To' : to}
|
||||||
data=mail.generate('missing_charte_MA', {
|
connexion.sendmail("ca@crans.org",to,data.encode('utf-8'))
|
||||||
'To': unicode(to),
|
|
||||||
'From': From,
|
|
||||||
})
|
|
||||||
actually_sendmail(u'ca@crans.org', (unicode(to),), data)
|
|
||||||
|
|
||||||
def __usage(message=None):
|
def __usage(message=None):
|
||||||
""" Comment ça marche ? """
|
""" Comment ça marche ? """
|
||||||
|
@ -159,7 +163,7 @@ if __name__ == '__main__' :
|
||||||
__usage(u'Mauvaise utilisation de liste')
|
__usage(u'Mauvaise utilisation de liste')
|
||||||
print "Liste des membres actifs n'ayant pas signé la charte :"
|
print "Liste des membres actifs n'ayant pas signé la charte :"
|
||||||
for adh in liste_charte_nok():
|
for adh in liste_charte_nok():
|
||||||
print unicode(adh['prenom'][0]) + u" " + unicode(adh['nom'][0])
|
print adh.Nom()
|
||||||
elif sys.argv[1] == 'modif':
|
elif sys.argv[1] == 'modif':
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
__usage(u'Mauvaise utilisation de modif')
|
__usage(u'Mauvaise utilisation de modif')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#! /usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -12,8 +12,9 @@ Licence : GPL v2
|
||||||
|
|
||||||
import os, sys, time
|
import os, sys, time
|
||||||
import subprocess
|
import subprocess
|
||||||
from lc_ldap import shortcuts
|
sys.path.append('/usr/scripts/gestion')
|
||||||
from gestion.config import upload
|
from ldap_crans import crans_ldap
|
||||||
|
from config import upload
|
||||||
# logging tools
|
# logging tools
|
||||||
import syslog
|
import syslog
|
||||||
def log(x):
|
def log(x):
|
||||||
|
@ -29,8 +30,6 @@ import utils.exceptions
|
||||||
import locale
|
import locale
|
||||||
locale.setlocale(locale.LC_TIME, 'fr_FR.UTF-8')
|
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.
|
help = """Script de déconnexion pour mail invalide.
|
||||||
Une fiche sera générée pour chaque adhérent.
|
Une fiche sera générée pour chaque adhérent.
|
||||||
|
@ -50,23 +49,22 @@ l'adhérent ayant l'aid 42."""
|
||||||
def generate_ps(proprio, mail):
|
def generate_ps(proprio, mail):
|
||||||
"""On génère la feuille d'avertissement et on retourne son emplacement."""
|
"""On génère la feuille d'avertissement et on retourne son emplacement."""
|
||||||
barcode = "/usr/scripts/admin/mail_invalide/barcode.eps"
|
barcode = "/usr/scripts/admin/mail_invalide/barcode.eps"
|
||||||
name = unicode(proprio['prenom'][0]) + u" " + unicode(proprio['nom'][0])
|
|
||||||
try:
|
try:
|
||||||
log(u'Generate invalid mail notice for %s' % name)
|
log('Generate invalid mail notice for %s' % proprio.Nom())
|
||||||
# Dossier de génération du ps
|
# Dossier de génération du ps
|
||||||
dossier = '/usr/scripts/var/mails_invalides'
|
dossier = '/usr/scripts/var/mails_invalides'
|
||||||
|
|
||||||
# Base pour le nom du fichier
|
# Base pour le nom du fichier
|
||||||
fichier = time.strftime('%Y-%m-%d-%H-%M') + '-mail-%s' % (name.
|
fichier = time.strftime('%Y-%m-%d-%H-%M') + '-mail-%s' % (proprio.Nom().
|
||||||
lower().replace(' ', '-'))
|
lower().replace(' ', '-'))
|
||||||
|
|
||||||
# Création du fichier tex
|
# Création du fichier tex
|
||||||
format_date = '%A %d %B %Y'
|
format_date = '%A %d %B %Y'
|
||||||
with open('%s/mail_invalide.tex' % os.path.dirname(__file__), 'r') as tempfile:
|
with open('%s/mail_invalide.tex' % os.path.dirname(__file__), 'r') as tempfile:
|
||||||
template = tempfile.read()
|
template = tempfile.read()
|
||||||
template = template.replace('~prenom~', proprio['prenom'][0].encode('utf-8'))
|
template = template.replace('~prenom~', proprio.prenom().encode('utf-8'))
|
||||||
template = template.replace('~nom~', proprio['nom'][0].encode('utf-8'))
|
template = template.replace('~nom~', proprio.nom().encode('utf-8'))
|
||||||
template = template.replace('~chambre~', proprio['chbre'][0].encode('utf-8'))
|
template = template.replace('~chambre~', proprio.chbre().encode('utf-8'))
|
||||||
template = template.replace('~mail~', mail.encode('utf-8').replace('_', '\\_'))
|
template = template.replace('~mail~', mail.encode('utf-8').replace('_', '\\_'))
|
||||||
template = template.replace('~fin~',
|
template = template.replace('~fin~',
|
||||||
time.strftime(format_date, time.localtime(time.time()+14*86400)))
|
time.strftime(format_date, time.localtime(time.time()+14*86400)))
|
||||||
|
@ -85,37 +83,35 @@ def generate_ps(proprio, mail):
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log('Erreur lors de la génération du ps : ')
|
log('Erreur lors de la génération du ps : ')
|
||||||
log(str(e))
|
log(str(e))
|
||||||
log("Values : adherent:%s" % name)
|
log("Values : adherent:%s" % proprio.Nom())
|
||||||
log(utils.exceptions.formatExc())
|
log(utils.exceptions.formatExc())
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def set_mail_invalide(adherent, mail, a_verifier, a_imprimer):
|
def set_mail_invalide(adherent, mail, a_verifier, a_imprimer):
|
||||||
name = unicode(adherent['prenom'][0]) + u" " + unicode(adherent['nom'][0])
|
if adherent.chbre() in ['????', 'EXT']:
|
||||||
if adherent['chbre'][0] in ['????', 'EXT']:
|
print u"Chambre de %s : %s, générer la fiche ? [Yn]" % (adherent.Nom().encode('utf-8'), adherent.chbre())
|
||||||
print u"Chambre de %s : %s, générer la fiche ? [Yn]" % (name, adherent['chbre'][0])
|
|
||||||
read = ''
|
read = ''
|
||||||
while read not in ['y', 'n']:
|
while read not in ['y', 'n']:
|
||||||
read = raw_input().lower()
|
read = raw_input().lower()
|
||||||
if read == 'n':
|
if read == 'n':
|
||||||
print u"Chambre de %s : %s, impossible de générer la fiche." % (name, adherent['chbre'][0])
|
print u"Chambre de %s : %s, impossible de générer la fiche." % (adherent.Nom().encode('utf-8'), adherent.chbre())
|
||||||
a_verifier.append(mail)
|
a_verifier.append(mail)
|
||||||
return
|
return
|
||||||
|
|
||||||
print u"Génération de la fiche pour %s :" % name
|
print "Génération de la fiche pour %s :" % adherent.Nom().encode('utf-8')
|
||||||
fiche = generate_ps(adherent, mail)
|
fiche = generate_ps(adherent, mail)
|
||||||
print fiche
|
print fiche
|
||||||
a_imprimer.append(fiche)
|
a_imprimer.append(fiche)
|
||||||
with adherent as adh:
|
adherent.blacklist([time.time() + 14 * 24 * 3600,
|
||||||
adh.blacklist('mail_invalide','Mail Invalide - Script',debut=int(time.time()) + DELAY * 24 * 3600)
|
'-', 'mail_invalide', "Mail invalide"])
|
||||||
adh.history_gen()
|
adherent.save()
|
||||||
adh.save()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if '--help' in sys.argv or '-h' in sys.argv or len(sys.argv) < 2:
|
if '--help' in sys.argv or '-h' in sys.argv or len(sys.argv) < 2:
|
||||||
print help
|
print help
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
ldap = shortcuts.lc_ldap_admin()
|
db = crans_ldap()
|
||||||
|
|
||||||
# On fait la liste des .forwards dans les homes
|
# On fait la liste des .forwards dans les homes
|
||||||
print " * Lecture des .forward ..."
|
print " * Lecture des .forward ..."
|
||||||
|
@ -145,24 +141,24 @@ if __name__ == "__main__":
|
||||||
# Est-ce un aid ?
|
# Est-ce un aid ?
|
||||||
if adresse[0] == '-':
|
if adresse[0] == '-':
|
||||||
print " * Recherche de aid=%s ..." % adresse[1:]
|
print " * Recherche de aid=%s ..." % adresse[1:]
|
||||||
res = ldap.search(u"aid=%s" % adresse[1:], mode='rw')
|
res = db.search("aid=%s" % adresse[1:], 'w')['adherent']
|
||||||
if len(res) == 0:
|
if len(res) == 0:
|
||||||
print "*** Erreur : aucun résultat pour aid=%s" % adresse[1:]
|
print "*** Erreur : aucun résultat pour aid=%s" % adresse[1:]
|
||||||
a_verifier.append(adresse)
|
a_verifier.append(adresse)
|
||||||
elif len(res) > 1:
|
elif len(res) > 1:
|
||||||
print "*** Erreur : plusieurs résultats pour aid=%s :" % adresse[1:]
|
print "*** Erreur : plusieurs résultats pour aid=%s :" % adresse[1:]
|
||||||
for adh in res:
|
for adh in res:
|
||||||
print unicode(adh['prenom'][0]) + u" " + unicode(adh['nom'][0])
|
print adh.Nom()
|
||||||
a_verifier.append(adresse)
|
a_verifier.append(adresse)
|
||||||
else:
|
else:
|
||||||
adherent = res[0]
|
adherent = res[0]
|
||||||
set_mail_invalide(adherent, adherent['mail'][0], a_verifier, a_imprimer)
|
set_mail_invalide(adherent, adherent.email(), a_verifier, a_imprimer)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print " * Recherche de %s ..." % adresse
|
print " * Recherche de %s ..." % adresse
|
||||||
# Est-ce un .forward ?
|
# Est-ce un .forward ?
|
||||||
if forwards.has_key(adresse):
|
if forwards.has_key(adresse):
|
||||||
res = ldap.search(u"uid=%s" % forwards[adresse], mode='rw')
|
res = db.search("uid=%s" % forwards[adresse], 'w')['adherent']
|
||||||
if len(res) == 0:
|
if len(res) == 0:
|
||||||
print "*** Erreur : aucun résultat pour uid=%s" % forwards[adresse]
|
print "*** Erreur : aucun résultat pour uid=%s" % forwards[adresse]
|
||||||
a_verifier.append(adresse)
|
a_verifier.append(adresse)
|
||||||
|
@ -172,18 +168,18 @@ if __name__ == "__main__":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Est-ce une adresse mail sans compte Cr@ns ?
|
# Est-ce une adresse mail sans compte Cr@ns ?
|
||||||
res = ldap.search(u"(|(mail=%s)(mailExt=%s))" % (adresse,adresse), mode='rw')
|
res = db.search("mail=%s" % adresse, 'w')['adherent']
|
||||||
if len(res) == 0:
|
if len(res) == 0:
|
||||||
print "*** Erreur : aucun résultat pour %s" % adresse
|
print "*** Erreur : aucun résultat pour %s" % adresse
|
||||||
a_verifier.append(adresse)
|
a_verifier.append(adresse)
|
||||||
elif len(res) > 1:
|
elif len(res) > 1:
|
||||||
print "*** Erreur : plusieurs résultats pour %s :" % adresse
|
print "*** Erreur : plusieurs résultats pour %s :" % adresse
|
||||||
for adh in res:
|
for adh in res:
|
||||||
print unicode(adh['prenom'][0]) + u" " + unicode(adh['nom'][0])
|
print adh.Nom()
|
||||||
a_verifier.append(adresse)
|
a_verifier.append(adresse)
|
||||||
else:
|
else:
|
||||||
adherent = res[0]
|
adherent = res[0]
|
||||||
set_mail_invalide(adherent, adresse, a_verifier, a_imprimer)
|
set_mail_invalide(adherent, adherent.email(), a_verifier, a_imprimer)
|
||||||
|
|
||||||
if len(a_verifier) + len(a_imprimer) > 0:
|
if len(a_verifier) + len(a_imprimer) > 0:
|
||||||
print ''
|
print ''
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#! /usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
# Copyright (C) Stéphane Glondu, Alexandre Bos, et autres
|
# Copyright (C) Stéphane Glondu, Alexandre Bos
|
||||||
# Licence : GPLv2
|
# 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
|
||||||
|
@ -20,14 +21,16 @@ Les commandes sont :
|
||||||
|
|
||||||
|
|
||||||
import sys, os, re
|
import sys, os, re
|
||||||
import gestion.config
|
sys.path.append('/usr/scripts/gestion')
|
||||||
|
import config
|
||||||
|
from email_tools import send_email, parse_mail_template
|
||||||
|
|
||||||
# Fonctions d'affichage
|
# Fonctions d'affichage
|
||||||
from gestion.affich_tools import coul, tableau, prompt, cprint
|
from affich_tools import coul, tableau, prompt, cprint
|
||||||
|
|
||||||
# Importation de la base de données
|
# Importation de la base de données
|
||||||
from lc_ldap import shortcuts
|
from ldap_crans import crans_ldap, ann_scol
|
||||||
ldap = shortcuts.lc_ldap_admin()
|
db = crans_ldap()
|
||||||
|
|
||||||
def _controle_interactif_adherents(liste):
|
def _controle_interactif_adherents(liste):
|
||||||
"""
|
"""
|
||||||
|
@ -47,28 +50,26 @@ def _controle_interactif_adherents(liste):
|
||||||
nb = 0
|
nb = 0
|
||||||
for a in liste:
|
for a in liste:
|
||||||
ok = prompt(u'[%3d] %s, %s (%s) ?'
|
ok = prompt(u'[%3d] %s, %s (%s) ?'
|
||||||
% (restant, a['nom'][0], a['prenom'][0], a['aid'][0]), 'n', '').lower()
|
% (restant, a.nom(), a.prenom(), a.id()), 'n', '').lower()
|
||||||
restant -= 1
|
restant -= 1
|
||||||
if ok == 'o':
|
if ok == 'o':
|
||||||
modifiable = ldap.search(u'aid=%s' % a['aid'][0], mode='rw')[0]
|
modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0]
|
||||||
try:
|
if modifiable._modifiable:
|
||||||
with modifiable as adh:
|
modifiable.droits([])
|
||||||
adh['droits'].remove(u'Cableur')
|
cprint(modifiable.save())
|
||||||
adh.history_gen()
|
else:
|
||||||
adh.save()
|
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
|
||||||
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':
|
elif ok != 'n':
|
||||||
cprint(u'Arrêt du contrôle %s des membres actifs' % explicite, 'rouge')
|
cprint(u'Arrêt du contrôle %s des membres actifs' % explicite, 'rouge')
|
||||||
break
|
break
|
||||||
|
|
||||||
def candidats():
|
def candidats():
|
||||||
todo_list1 = ldap.search(u'droits=cableur')
|
todo_list1 = db.search('droits=*')['adherent']
|
||||||
todo_list = []
|
todo_list = []
|
||||||
for adh in todo_list1:
|
for adh in todo_list1:
|
||||||
if not adh.paiement_ok():
|
if adh.droitsGeles():
|
||||||
todo_list.append(adh)
|
todo_list.append(adh)
|
||||||
|
todo_list.sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom())))
|
||||||
return todo_list
|
return todo_list
|
||||||
|
|
||||||
def lister():
|
def lister():
|
||||||
|
@ -79,7 +80,7 @@ def lister():
|
||||||
print "Liste des câbleur dont la cotisation n'est pas à jour."
|
print "Liste des câbleur dont la cotisation n'est pas à jour."
|
||||||
print
|
print
|
||||||
for adh in todo_list:
|
for adh in todo_list:
|
||||||
print unicode(adh['prenom'][0]) + u" " + unicode(adh['nom'][0])
|
print adh.prenom() + " " + adh.nom()
|
||||||
print
|
print
|
||||||
print "total : " + str(len(todo_list))
|
print "total : " + str(len(todo_list))
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#!/usr/bin/python
|
||||||
# -*- mode: python; coding: utf-8 -*-
|
# -*- mode: python; coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# total_impression.py
|
# total_impression.py
|
||||||
|
@ -6,7 +6,6 @@
|
||||||
#
|
#
|
||||||
# Copyright (C) 2007 Michel Blockelet <blockelet@crans.org>
|
# 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
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
@ -33,11 +32,14 @@ Options :
|
||||||
Les dates doivent etre de la forme jj/mm/aaaa."""
|
Les dates doivent etre de la forme jj/mm/aaaa."""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from lc_ldap import shortcuts
|
sys.path.append("/usr/scripts/gestion/")
|
||||||
from gestion.affich_tools import cprint
|
from ldap_crans import crans_ldap
|
||||||
|
from config import ann_scol
|
||||||
|
from affich_tools import cprint
|
||||||
import time
|
import time
|
||||||
|
|
||||||
ldap = shortcuts.lc_ldap_admin()
|
db = crans_ldap()
|
||||||
|
date_debut_ann_scol = time.mktime((ann_scol, 8, 1, 0, 0, 0, 0, 0, 0))
|
||||||
|
|
||||||
def datestrtoint(strdate):
|
def datestrtoint(strdate):
|
||||||
u""" Convertit une date en entier. """
|
u""" Convertit une date en entier. """
|
||||||
|
@ -50,7 +52,7 @@ def soldes_adherent(dlinf, dlsup, adherent, verbose):
|
||||||
totaldebit = 0
|
totaldebit = 0
|
||||||
totalcredit = 0
|
totalcredit = 0
|
||||||
|
|
||||||
for hist in adherent['historique']:
|
for hist in adherent.historique():
|
||||||
sep = ' '
|
sep = ' '
|
||||||
champ = hist.replace(',', '').replace(': ', '').split(sep)
|
champ = hist.replace(',', '').replace(': ', '').split(sep)
|
||||||
if datestrtoint(champ[0]) >= dlinf and (dlsup == 0 or datestrtoint(champ[0]) <= dlsup):
|
if datestrtoint(champ[0]) >= dlinf and (dlsup == 0 or datestrtoint(champ[0]) <= dlsup):
|
||||||
|
@ -110,23 +112,19 @@ def calcul_soldes():
|
||||||
totaldebit = 0
|
totaldebit = 0
|
||||||
totalcredit = 0
|
totalcredit = 0
|
||||||
|
|
||||||
liste = ldap.search(u"uid=*",sizelimit=10000)
|
liste = db.search("login=*")['adherent']
|
||||||
|
|
||||||
for adherent in liste:
|
for adherent in liste:
|
||||||
try:
|
adhdebit, adhcredit = soldes_adherent(dlinf, dlsup, adherent, verbose)
|
||||||
adhdebit, adhcredit = soldes_adherent(dlinf, dlsup, adherent, verbose)
|
if adhdebit + adhcredit > 0 and adhdebit + adhcredit < 1000000: # On evite Toto Passoir
|
||||||
if adhdebit + adhcredit > 0 and adhdebit + adhcredit < 1000000: # On evite Toto Passoir
|
if verbose >= 2:
|
||||||
if verbose >= 2:
|
cprint('-' * 40, 'cyan')
|
||||||
cprint('-' * 40, 'cyan')
|
if verbose >= 1:
|
||||||
if verbose >= 1:
|
cprint('Debit total pour ' + adherent.Nom() + ' : ' + str(adhdebit) + ' euros', 'rouge')
|
||||||
name = unicode(adherent['prenom'][0]) + u" " + unicode(adherent['nom'][0])
|
cprint('Credit total pour ' + adherent.Nom() + ' : ' + str(adhcredit) + ' euros', 'vert')
|
||||||
cprint(u'Debit total pour ' + name + u' : ' + unicode(adhdebit) + u' euros', 'rouge')
|
cprint('=' * 40, 'bleu')
|
||||||
cprint(u'Credit total pour ' + name + u' : ' + unicode(adhcredit) + u' euros', 'vert')
|
totaldebit += adhdebit
|
||||||
cprint('=' * 40, 'bleu')
|
totalcredit += adhcredit
|
||||||
totaldebit += adhdebit
|
|
||||||
totalcredit += adhcredit
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
if verbose >= 1:
|
if verbose >= 1:
|
||||||
cprint('=' * 80, 'bleu')
|
cprint('=' * 80, 'bleu')
|
||||||
if dlinf == 0:
|
if dlinf == 0:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
""" Envoie un mail avec la liste des serveurs qui ne sont pas synchro avec bcfg2.
|
""" Envoie un mail avec la liste des serveurs qui ne sont pas synchro avec bcfg2.
|
||||||
|
@ -43,6 +43,7 @@ if __name__ == "__main__":
|
||||||
debug = "--debug" in sys.argv
|
debug = "--debug" in sys.argv
|
||||||
if "--mail" in sys.argv:
|
if "--mail" in sys.argv:
|
||||||
if hosts != "":
|
if hosts != "":
|
||||||
|
sys.path.append("/usr/scripts/")
|
||||||
import utils.sendmail
|
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)
|
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:
|
elif debug:
|
||||||
|
|
|
@ -4,13 +4,19 @@ if [[ $1 = "" ]] || [[ $1 = $USER ]] ; then
|
||||||
/usr/bin/quota
|
/usr/bin/quota
|
||||||
else
|
else
|
||||||
/usr/bin/quota $*
|
/usr/bin/quota $*
|
||||||
fi | sed 's/home-adh/home/' | awk -F'(:| *)' '
|
fi | awk -F'(:| *)' '
|
||||||
BEGIN { fs = "" }
|
BEGIN { fs = "" }
|
||||||
/Disk/ { print; print "utilisé\tquota\tlimite\t%\t(en Mo)" }
|
/Disk/ { print; print "utilisé\tquota\tlimite\t%\t(en Mo)" }
|
||||||
{
|
{
|
||||||
if (NF == 2) { fs = $2 }
|
if (NF == 2) { fs = $2 }
|
||||||
else if (fs != "") {
|
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, $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 = ""
|
fs = ""
|
||||||
}
|
}
|
||||||
}'
|
}'
|
||||||
|
|
|
@ -70,13 +70,10 @@ BL_REJECT = [u'bloq']
|
||||||
BL_ISOLEMENT = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra']
|
BL_ISOLEMENT = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra']
|
||||||
|
|
||||||
#: place sur accueil
|
#: place sur accueil
|
||||||
BL_ACCUEIL = [u'paiement']
|
BL_ACCUEIL = []
|
||||||
|
|
||||||
# À classer:
|
# Ces blacklists ont des effets soft (portail captif port 80)
|
||||||
# [u'carte_etudiant', u'chambre_invalide', ]
|
#BL_ACCUEIL = [u'carte_etudiant', u'chambre_invalide', u'paiement']
|
||||||
# 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,
|
#: 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:
|
# pour lequelles il est donc idiot d'activer la protection antisquattage:
|
||||||
|
@ -104,14 +101,11 @@ def radius_event(fun):
|
||||||
tuples en entrée en un dictionnaire."""
|
tuples en entrée en un dictionnaire."""
|
||||||
|
|
||||||
def new_f(auth_data):
|
def new_f(auth_data):
|
||||||
if type(auth_data) == dict:
|
data = dict()
|
||||||
data = auth_data
|
for (key, value) in auth_data or []:
|
||||||
else:
|
# Beware: les valeurs scalaires sont entre guillemets
|
||||||
data = dict()
|
# Ex: Calling-Station-Id: "une_adresse_mac"
|
||||||
for (key, value) in auth_data or []:
|
data[key] = value.replace('"', '')
|
||||||
# Beware: les valeurs scalaires sont entre guillemets
|
|
||||||
# Ex: Calling-Station-Id: "une_adresse_mac"
|
|
||||||
data[key] = value.replace('"', '')
|
|
||||||
try:
|
try:
|
||||||
return fun(data)
|
return fun(data)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -219,7 +213,7 @@ def get_prise_chbre(data):
|
||||||
def realm_of_machine(machine):
|
def realm_of_machine(machine):
|
||||||
"""Renvoie le `realm` d'une machine. Don't ask"""
|
"""Renvoie le `realm` d'une machine. Don't ask"""
|
||||||
if isinstance(machine, lc_ldap.objets.machineFixe):
|
if isinstance(machine, lc_ldap.objets.machineFixe):
|
||||||
return 'adherents'
|
return 'fil'
|
||||||
elif isinstance(machine, lc_ldap.objets.machineWifi):
|
elif isinstance(machine, lc_ldap.objets.machineWifi):
|
||||||
return 'wifi-adh'
|
return 'wifi-adh'
|
||||||
else:
|
else:
|
||||||
|
@ -277,18 +271,6 @@ def instantiate(*_):
|
||||||
if TEST_SERVER:
|
if TEST_SERVER:
|
||||||
logger.info('DBG_FREERADIUS is enabled')
|
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
|
@radius_event
|
||||||
def authorize_wifi(data):
|
def authorize_wifi(data):
|
||||||
"""Section authorize pour le wifi
|
"""Section authorize pour le wifi
|
||||||
|
@ -373,7 +355,7 @@ def authorize_fil(data):
|
||||||
return (radiusd.RLM_MODULE_UPDATED,
|
return (radiusd.RLM_MODULE_UPDATED,
|
||||||
(),
|
(),
|
||||||
(
|
(
|
||||||
("Auth-Type", "Accept"),
|
("Auth-Type", "crans_fil"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -446,15 +428,6 @@ def authorize_nas(data, ldap):
|
||||||
("FreeRADIUS-Client-Virtual-Server", vserver),
|
("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
|
@radius_event
|
||||||
def post_auth_wifi(data):
|
def post_auth_wifi(data):
|
||||||
"""Appelé une fois que l'authentification est ok.
|
"""Appelé une fois que l'authentification est ok.
|
||||||
|
|
1
freeradius/modules/rlm_python_fil.conf
Symbolic link
1
freeradius/modules/rlm_python_fil.conf
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../rlm_python_fil.conf
|
1
freeradius/modules/rlm_python_nas.conf
Symbolic link
1
freeradius/modules/rlm_python_nas.conf
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../rlm_python_nas.conf
|
|
@ -1 +0,0 @@
|
||||||
../rlm_python_unifie.conf
|
|
1
freeradius/modules/rlm_python_wifi.conf
Symbolic link
1
freeradius/modules/rlm_python_wifi.conf
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../rlm_python_wifi.conf
|
37
freeradius/rlm_python_fil.conf
Normal file
37
freeradius/rlm_python_fil.conf
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# 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
|
||||||
|
}
|
35
freeradius/rlm_python_nas.conf
Normal file
35
freeradius/rlm_python_nas.conf
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# 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
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
# 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
|
|
||||||
}
|
|
||||||
|
|
37
freeradius/rlm_python_wifi.conf
Normal file
37
freeradius/rlm_python_wifi.conf
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# 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 {
|
update request {
|
||||||
NAS-Identifier = "%{Packet-Src-IP-Address:-%{Packet-Src-IPv6-Address}}"
|
NAS-Identifier = "%{Packet-Src-IP-Address:-%{Packet-Src-IPv6-Address}}"
|
||||||
}
|
}
|
||||||
crans_unifie
|
crans_nas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,14 @@
|
||||||
server filaire {
|
server filaire {
|
||||||
authorize{
|
authorize{
|
||||||
preprocess
|
preprocess
|
||||||
crans_unifie
|
crans_fil
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticate{
|
authenticate{
|
||||||
crans_unifie
|
crans_fil
|
||||||
}
|
}
|
||||||
|
|
||||||
post-auth{
|
post-auth{
|
||||||
crans_unifie
|
crans_fil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ server inner-tunnel {
|
||||||
authorize {
|
authorize {
|
||||||
#preprocess
|
#preprocess
|
||||||
|
|
||||||
crans_unifie
|
crans_wifi
|
||||||
#
|
#
|
||||||
# The chap module will set 'Auth-Type := CHAP' if we are
|
# The chap module will set 'Auth-Type := CHAP' if we are
|
||||||
# handling a CHAP request and Auth-Type has not already been set
|
# 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
|
# Once we KNOW that the user has been authenticated, there are
|
||||||
# additional steps we can take.
|
# additional steps we can take.
|
||||||
post-auth {
|
post-auth {
|
||||||
crans_unifie
|
crans_wifi
|
||||||
|
|
||||||
# Note that we do NOT assign IP addresses here.
|
# Note that we do NOT assign IP addresses here.
|
||||||
# If you try to assign IP addresses for EAP authentication types,
|
# If you try to assign IP addresses for EAP authentication types,
|
||||||
|
|
|
@ -558,26 +558,7 @@ if __name__ == "__main__":
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
prettyDoin("Les carottes sont cuites." , "Ok")
|
prettyDoin("Les carottes sont cuites." , "Ok")
|
||||||
|
|
||||||
data = [
|
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"]]
|
||||||
[
|
|
||||||
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")
|
titres = ("Nom", "Prénom", "Âge", "Adresse")
|
||||||
longueurs = [25, 25, '*', '*']
|
longueurs = [25, 25, '*', '*']
|
||||||
print tableau(data, titres, longueurs).encode(guess_preferred_encoding())
|
print tableau(data, titres, longueurs).encode(guess_preferred_encoding())
|
||||||
|
|
|
@ -2,11 +2,8 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import socket
|
|
||||||
|
|
||||||
conn = None
|
conn = None
|
||||||
# : échec définitif, on raise une exception direct
|
# : échec définitif, on raise une exception direct
|
||||||
|
@ -137,8 +134,7 @@ uplink_prises={ 'a' :
|
||||||
349 : 'uplink->batb-4', 350 : 'libre-service',
|
349 : 'uplink->batb-4', 350 : 'libre-service',
|
||||||
401 : 'uplink->batb-0', 402 : 'uplink->batb-1',
|
401 : 'uplink->batb-0', 402 : 'uplink->batb-1',
|
||||||
403 : 'uplink->batb-2', 404 : 'uplink->batb-3',
|
403 : 'uplink->batb-2', 404 : 'uplink->batb-3',
|
||||||
405 : 'uplink->backbone', 523 : 'uplink->batb-4',
|
405 : 'uplink->backbone' },
|
||||||
},
|
|
||||||
'c' :
|
'c' :
|
||||||
{ 49 : 'uplink->batc-3', 50 : 'libre-service',
|
{ 49 : 'uplink->batc-3', 50 : 'libre-service',
|
||||||
149 : 'uplink->batc-3', 150 : 'libre-service',
|
149 : 'uplink->batc-3', 150 : 'libre-service',
|
||||||
|
@ -282,26 +278,6 @@ _HIDDEN_SWITCHES = [
|
||||||
'batv-0.adm.crans.org',
|
'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):
|
def all_switchs(bat=None, hide=_SPECIAL_SWITCHES + _HIDDEN_SWITCHES):
|
||||||
"""Retourne la liste des switchs pour un batiment.
|
"""Retourne la liste des switchs pour un batiment.
|
||||||
|
|
||||||
|
@ -318,12 +294,7 @@ def all_switchs(bat=None, hide=_SPECIAL_SWITCHES + _HIDDEN_SWITCHES):
|
||||||
for b in bat:
|
for b in bat:
|
||||||
indexes = set(n/100 for n in uplink_prises[b])
|
indexes = set(n/100 for n in uplink_prises[b])
|
||||||
for i in indexes:
|
for i in indexes:
|
||||||
switch_name = "bat%s-%s" % (b, i)
|
hostname = "bat%s-%s.adm.crans.org" % (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:
|
if hostname not in hide:
|
||||||
switchs.append(hostname)
|
switchs.append(hostname)
|
||||||
# on ajoute quand-même le backbone et/ou multiprise-v6 si demandé
|
# on ajoute quand-même le backbone et/ou multiprise-v6 si demandé
|
||||||
|
|
|
@ -18,10 +18,11 @@ import re
|
||||||
|
|
||||||
import affichage
|
import affichage
|
||||||
import lc_ldap.shortcuts
|
import lc_ldap.shortcuts
|
||||||
|
from lc_ldap.crans_utils import to_generalized_time_format as to_gtf
|
||||||
|
|
||||||
import mail as mail_module
|
import mail as mail_module
|
||||||
from config import demenagement_delai as delai, \
|
from config import demenagement_delai as delai, \
|
||||||
gtf_debut_periode_transitoire, periode_transitoire
|
debut_periode_transitoire, periode_transitoire
|
||||||
|
|
||||||
ERASE_DAY = { 'second': 0, 'minute': 0, 'microsecond': 0, 'hour': 0, }
|
ERASE_DAY = { 'second': 0, 'minute': 0, 'microsecond': 0, 'hour': 0, }
|
||||||
DAY = datetime.timedelta(days=1)
|
DAY = datetime.timedelta(days=1)
|
||||||
|
@ -71,28 +72,16 @@ def warn_or_delete(smtp, clandestin, fail, done):
|
||||||
mail_addr = clandestin.get_mail()
|
mail_addr = clandestin.get_mail()
|
||||||
if not clandestin.machines() or not mail_addr:
|
if not clandestin.machines() or not mail_addr:
|
||||||
return # Si pas de machine, on s'en fout. Si pas de mail, inutile
|
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 = {
|
data = {
|
||||||
"from" : RESP,
|
"from" : RESP,
|
||||||
"chambre" : exchambre,
|
"chambre" : exchambre,
|
||||||
"jours" : (date_suppr - now).days+1,
|
"jours" : (date_suppr - now).days+1,
|
||||||
"to" : mail_addr,
|
"to" : mail_addr,
|
||||||
"adh": clandestin,
|
"adh": clandestin,
|
||||||
"chbre_url" : chbre_url,
|
|
||||||
"chbre_url_error" : chbre_url_error,
|
|
||||||
"lang_info": "English version below",
|
"lang_info": "English version below",
|
||||||
}
|
}
|
||||||
smtp.send_template('demenagement', data)
|
mail = mail_module.generate('demenagement', data)
|
||||||
|
smtp.sendmail(RESP, [mail_addr], mail.as_string())
|
||||||
|
|
||||||
def format_entry(m):
|
def format_entry(m):
|
||||||
"""Renvoie une ligne de tableau, pour une machine"""
|
"""Renvoie une ligne de tableau, pour une machine"""
|
||||||
|
@ -112,7 +101,7 @@ if __name__ == '__main__':
|
||||||
conn = lc_ldap.shortcuts.lc_ldap_admin()
|
conn = lc_ldap.shortcuts.lc_ldap_admin()
|
||||||
|
|
||||||
if periode_transitoire:
|
if periode_transitoire:
|
||||||
date = gtf_debut_periode_transitoire
|
date = to_gtf(debut_periode_transitoire)
|
||||||
else:
|
else:
|
||||||
date = now.strftime(FORMAT_LDAP) + 'Z'
|
date = now.strftime(FORMAT_LDAP) + 'Z'
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import lc_ldap.attributs
|
||||||
import lc_ldap.objets
|
import lc_ldap.objets
|
||||||
import gestion.mail as mail_module
|
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()
|
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):
|
def check_password(password, no_cracklib=False, dialog=False):
|
||||||
|
@ -40,14 +41,10 @@ def check_password(password, no_cracklib=False, dialog=False):
|
||||||
problem = True
|
problem = True
|
||||||
msg += u"Le mot de passe ne doit contenir que des caractères ascii.\n"
|
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
|
# Nounou mode
|
||||||
if no_cracklib:
|
if no_cracklib:
|
||||||
if len(password) >= config.password.root_min_len:
|
if len(password) >= config.password.root_min_len:
|
||||||
return True, msg
|
return True
|
||||||
else:
|
else:
|
||||||
upp = 0
|
upp = 0
|
||||||
low = 0
|
low = 0
|
||||||
|
@ -100,7 +97,7 @@ def check_password(password, no_cracklib=False, dialog=False):
|
||||||
msg = affich_tools.coul(msg, 'rouge', dialog=dialog)
|
msg = affich_tools.coul(msg, 'rouge', dialog=dialog)
|
||||||
return True, msg
|
return True, msg
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
msg += str(e).decode(config.in_encoding)
|
msg += str(e).decode()
|
||||||
|
|
||||||
if dialog:
|
if dialog:
|
||||||
msg = affich_tools.coul(msg, 'rouge', dialog=dialog)
|
msg = affich_tools.coul(msg, 'rouge', dialog=dialog)
|
||||||
|
@ -119,23 +116,16 @@ def check_password(password, no_cracklib=False, dialog=False):
|
||||||
return False, msg
|
return False, msg
|
||||||
|
|
||||||
@lc_ldap.shortcuts.with_ldap_conn(retries=2, delay=5, constructor=lc_ldap.shortcuts.lc_ldap_admin)
|
@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, **kwargs):
|
def change_password(ldap, login=None, verbose=False, no_cracklib=False, **args):
|
||||||
"""
|
"""
|
||||||
Change le mot de passe en fonction des arguments
|
Change le mot de passe en fonction des arguments
|
||||||
"""
|
"""
|
||||||
if login is None:
|
if login is None:
|
||||||
login = current_user
|
login = current_user
|
||||||
|
|
||||||
if type(login) == str:
|
if type(login) == str:
|
||||||
login = login.decode(config.in_encoding)
|
login = login.decode(encoding)
|
||||||
|
|
||||||
if no_cracklib:
|
|
||||||
if not lc_ldap.attributs.nounou in ldap.droits:
|
|
||||||
no_cracklib = False
|
|
||||||
|
|
||||||
login = lc_ldap.crans_utils.escape(login)
|
login = lc_ldap.crans_utils.escape(login)
|
||||||
query = ldap.search(u"(uid=%s)" % login, mode="w")
|
query = ldap.search(u"(uid=%s)" % login, mode="w")
|
||||||
|
|
||||||
if not query:
|
if not query:
|
||||||
affich_tools.cprint('Utilisateur introuvable dans la base de données, modification de l\'utilisateur local.', "rouge")
|
affich_tools.cprint('Utilisateur introuvable dans la base de données, modification de l\'utilisateur local.', "rouge")
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
@ -145,7 +135,7 @@ def change_password(ldap, login=None, verbose=False, no_cracklib=False, **kwargs
|
||||||
user['userPassword'] = [lc_ldap.crans_utils.hash_password("test").decode('ascii')]
|
user['userPassword'] = [lc_ldap.crans_utils.hash_password("test").decode('ascii')]
|
||||||
user.cancel()
|
user.cancel()
|
||||||
except EnvironmentError as e:
|
except EnvironmentError as e:
|
||||||
affich_tools.cprint(str(e).decode(config.in_encoding), "rouge")
|
affich_tools.cprint(str(e).decode(encoding), "rouge")
|
||||||
|
|
||||||
# Génération d'un mail
|
# Génération d'un mail
|
||||||
From = 'roots@crans.org'
|
From = 'roots@crans.org'
|
||||||
|
@ -155,11 +145,11 @@ To: %s
|
||||||
Subject: Tentative de changement de mot de passe !
|
Subject: Tentative de changement de mot de passe !
|
||||||
|
|
||||||
Tentative de changement du mot de passe de %s par %s.
|
Tentative de changement du mot de passe de %s par %s.
|
||||||
""" % (From, To, login.encode(config.out_encoding), current_user)
|
""" % (From, To , login.encode(encoding), current_user)
|
||||||
|
|
||||||
# Envoi mail
|
# Envoi mail
|
||||||
with mail_module.ServerConnection() as conn:
|
with mail_module.ServerConnection() as conn:
|
||||||
conn.sendmail(From, To, mail)
|
conn.sendmail(From, To , mail )
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# On peut modifier le MDP
|
# On peut modifier le MDP
|
||||||
|
@ -167,50 +157,44 @@ Tentative de changement du mot de passe de %s par %s.
|
||||||
prenom = "Club"
|
prenom = "Club"
|
||||||
else:
|
else:
|
||||||
prenom = user['prenom'][0]
|
prenom = user['prenom'][0]
|
||||||
affich_tools.cprint(
|
affich_tools.cprint("Changement du mot de passe de %s %s." %
|
||||||
"Changement du mot de passe de %s %s." % (
|
(prenom, user['nom'][0]),
|
||||||
prenom,
|
"vert")
|
||||||
user['nom'][0]
|
|
||||||
),
|
|
||||||
"vert",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Règles du jeu
|
# Règles du jeu
|
||||||
# (J'ai perdu)
|
# (J'ai perdu)
|
||||||
if verbose:
|
if verbose:
|
||||||
affich_tools.cprint(
|
affich_tools.cprint(u"""Règles :
|
||||||
u"""Règles :
|
|
||||||
Longueur standard : %s, root : %s,
|
Longueur standard : %s, root : %s,
|
||||||
Minimums : chiffres : %s, minuscules : %s, majuscules : %s, autres : %s,
|
Minimums : chiffres : %s, minuscules : %s, majuscules : %s, autres : %s,
|
||||||
Scores de longueur : 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,
|
Cracklib : %s.""" % (
|
||||||
config.password.root_min_len,
|
config.password.min_len,
|
||||||
config.password.min_cif,
|
config.password.root_min_len,
|
||||||
config.password.min_low,
|
config.password.min_cif,
|
||||||
config.password.min_upp,
|
config.password.min_low,
|
||||||
config.password.min_oth,
|
config.password.min_upp,
|
||||||
config.password.cif_value,
|
config.password.min_oth,
|
||||||
config.password.low_value,
|
config.password.cif_value,
|
||||||
config.password.upp_value,
|
config.password.low_value,
|
||||||
config.password.oth_value,
|
config.password.upp_value,
|
||||||
"Oui" * (not no_cracklib) + "Non" * (no_cracklib),
|
config.password.oth_value,
|
||||||
),
|
"Oui" * (not no_cracklib) + "Non" * (no_cracklib)
|
||||||
'jaune',
|
),
|
||||||
)
|
'jaune')
|
||||||
else:
|
else:
|
||||||
affich_tools.cprint(
|
affich_tools.cprint(u"""Le nouveau mot de passe doit comporter au minimum %s caractères.
|
||||||
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 ne doit pas être basé sur un mot du dictionnaire.
|
||||||
Il doit contenir au moins %s chiffre(s), %s minuscule(s),
|
Il doit contenir au moins %s chiffre(s), %s minuscule(s),
|
||||||
%s majuscule(s) et au moins %s autre(s) caractère(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,
|
CTRL+D ou CTRL+C provoquent un abandon.""" %
|
||||||
config.password.min_cif,
|
(
|
||||||
config.password.min_low,
|
config.password.min_len,
|
||||||
config.password.min_upp,
|
config.password.min_cif,
|
||||||
config.password.min_oth
|
config.password.min_low,
|
||||||
),
|
config.password.min_upp,
|
||||||
'jaune',
|
config.password.min_oth
|
||||||
)
|
), 'jaune')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
|
@ -240,35 +224,29 @@ CTRL+D ou CTRL+C provoquent un abandon.""" % (config.password.min_len,
|
||||||
affich_tools.cprint(u"Mot de passe de %s changé." % (user['uid'][0]), "vert")
|
affich_tools.cprint(u"Mot de passe de %s changé." % (user['uid'][0]), "vert")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Recherche dans la base des adhérents",
|
parser = argparse.ArgumentParser(
|
||||||
add_help=False,
|
description="Recherche dans la base des adhérents",
|
||||||
)
|
add_help=False)
|
||||||
parser.add_argument('-h',
|
parser.add_argument('-h', '--help',
|
||||||
'--help',
|
help="Affiche ce message et quitte.",
|
||||||
help="Affiche ce message et quitte.",
|
action="store_true")
|
||||||
action="store_true",
|
parser.add_argument('-n', '--no-cracklib',
|
||||||
)
|
help="Permet de contourner les règles de choix du mot de passe" +
|
||||||
parser.add_argument('-n',
|
"(réservé aux nounous).",
|
||||||
'--no-cracklib',
|
action="store_true")
|
||||||
help="Permet de contourner les règles de choix du mot de passe" +
|
parser.add_argument('-v', '--verbose',
|
||||||
"(réservé aux nounous).",
|
help="Permet de contourner les règles de choix du mot de passe" +
|
||||||
action="store_true",
|
"(réservé aux nounous).",
|
||||||
)
|
action="store_true")
|
||||||
parser.add_argument('-v',
|
parser.add_argument('login', type=str, nargs="?",
|
||||||
'--verbose',
|
help="L'utilisateur dont on veut changer le mot de passe.")
|
||||||
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.help:
|
if args.help:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
if args.no_cracklib:
|
||||||
|
if not lc_ldap.attributs.nounou in ldap.droits:
|
||||||
|
args.no_cracklib = False
|
||||||
change_password(**vars(args))
|
change_password(**vars(args))
|
||||||
|
|
|
@ -10,28 +10,29 @@
|
||||||
import os, sys
|
import os, sys
|
||||||
|
|
||||||
from gestion.affich_tools import prompt
|
from gestion.affich_tools import prompt
|
||||||
|
from gestion.ldap_crans import crans_ldap
|
||||||
|
|
||||||
from lc_ldap import shortcuts
|
db = crans_ldap()
|
||||||
|
|
||||||
ldap = shortcuts.lc_ldap_admin()
|
|
||||||
uid = os.getenv('SUDO_UID')
|
uid = os.getenv('SUDO_UID')
|
||||||
if not uid :
|
if not uid :
|
||||||
print "Impossible de déterminer l'utilisateur"
|
print "Impossible de déterminer l'utilisateur"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
adh = ldap.search(u'uidNumber=%s' % uid,mode='w')
|
s = db.search('uidNumber=%s' % os.getenv('SUDO_UID'),'w')
|
||||||
|
|
||||||
try:
|
|
||||||
adh = adh[0]
|
|
||||||
except IndexError:
|
|
||||||
print 'Erreur fatale lors de la consultation de la base LDAP'
|
|
||||||
sys.exit(3)
|
|
||||||
|
|
||||||
# On vérifie que c'est pas un club
|
# On vérifie que c'est pas un club
|
||||||
if unicode(adh.ldap_name)!=u"adherent":
|
club = s['club']
|
||||||
|
if len(club) == 1 :
|
||||||
print 'Pas de changement de shell pour les clubs'
|
print 'Pas de changement de shell pour les clubs'
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
|
# On regarde si on a des résultats dans les adhérents
|
||||||
|
adh = s['adherent']
|
||||||
|
if len(adh) != 1 :
|
||||||
|
print 'Erreur fatale lors de la consultation de la base LDAP'
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
adh = adh[0]
|
||||||
shell = prompt(u'Nouveau shell :')
|
shell = prompt(u'Nouveau shell :')
|
||||||
fd=open('/etc/shells')
|
fd=open('/etc/shells')
|
||||||
lines=fd.readlines()
|
lines=fd.readlines()
|
||||||
|
@ -44,9 +45,7 @@ if not shell in shells:
|
||||||
print '\n'.join(shells)
|
print '\n'.join(shells)
|
||||||
sys.exit(4)
|
sys.exit(4)
|
||||||
|
|
||||||
with adh as ad:
|
adh.chsh(shell)
|
||||||
ad['loginShell']=shell
|
adh.save()
|
||||||
ad.save()
|
|
||||||
|
|
||||||
# A cause de nscd
|
# A cause de nscd
|
||||||
print "La modification sera prise en compte dans l'heure suivante."
|
print "La modification sera prise en compte dans l'heure suivante."
|
||||||
|
|
|
@ -4,4 +4,3 @@
|
||||||
from config import *
|
from config import *
|
||||||
from encoding import *
|
from encoding import *
|
||||||
|
|
||||||
import dns
|
|
||||||
|
|
|
@ -9,35 +9,34 @@ import datetime
|
||||||
# Fichier généré à partir de bcfg2
|
# Fichier généré à partir de bcfg2
|
||||||
from config_srv import adm_only, role
|
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"
|
gtfepoch = "19700101000000Z"
|
||||||
##### Gestion des câblages
|
##### Gestion des câblages
|
||||||
# Selon la date, on met :
|
# 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
|
# -periode_transitoire : on accepte ceux qui ont payé l'année dernière
|
||||||
|
|
||||||
# On récupère l'année scolaire à tout besoin
|
# Ne modifier que les dates !
|
||||||
__annee = time.localtime()[0]
|
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
|
||||||
|
|
||||||
# Prochaine période transitoire de l'année version generalizedTimeFormat
|
debut_periode_transitoire = time.mktime(time.strptime("%s/08/16 00:00:00" % (ann_scol,), "%Y/%m/%d %H:%M:%S"))
|
||||||
gtf_debut_periode_transitoire = "%s0816000000+0200" % (__annee,)
|
fin_periode_transitoire = time.mktime(time.strptime("%s/09/30 23:59:59" % (ann_scol,), "%Y/%m/%d %H:%M:%S"))
|
||||||
gtf_fin_periode_transitoire = "%s0930235959+0200" % (__annee,)
|
|
||||||
|
|
||||||
# Version timestampées timezone-naïves
|
#Sursis pour les inscription après le 1/11 pour fournir la carte étudiant
|
||||||
debut_periode_transitoire = time.mktime(time.strptime("%s/08/16 00:00:00" % (__annee,), "%Y/%m/%d %H:%M:%S"))
|
sursis_carte=8*24*3600
|
||||||
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
|
# Gel des cableurs pas a jour de cotisation
|
||||||
# Les droits ne sont pas retires mais il n'y a plus de sudo
|
# Les droits ne sont pas retires mais il n'y a plus de sudo
|
||||||
|
@ -55,201 +54,89 @@ quota_hard = 10000000
|
||||||
fquota_soft = 0
|
fquota_soft = 0
|
||||||
fquota_hard = 0
|
fquota_hard = 0
|
||||||
# Shell
|
# Shell
|
||||||
login_shell = '/bin/zsh'
|
login_shell='/bin/zsh'
|
||||||
club_login_shell = '/usr/bin/rssh'
|
club_login_shell='/usr/bin/rssh'
|
||||||
# Longueur maximale d'un login
|
# Longueur maximale d'un login
|
||||||
maxlen_login = 25
|
maxlen_login=25
|
||||||
|
|
||||||
shells_possibles = [
|
shells_possibles = [u'/bin/csh',
|
||||||
u'/bin/csh',
|
u'/bin/sh', # tout caca
|
||||||
u'/bin/sh', # tout caca
|
u'/bin/dash', # un bash light
|
||||||
u'/bin/dash', # un bash light
|
u'/usr/bin/rc',
|
||||||
u'/usr/bin/rc',
|
u'/usr/bin/ksh', # symlink vers zsh
|
||||||
u'/usr/bin/ksh', # symlink vers zsh
|
u'/bin/ksh', # symlink vers zsh
|
||||||
u'/bin/ksh', # symlink vers zsh
|
u'/usr/bin/tcsh', # TENEX C Shell (csh++)
|
||||||
u'/usr/bin/tcsh', # TENEX C Shell (csh++)
|
u'/bin/tcsh', # TENEX C Shell (csh++)
|
||||||
u'/bin/tcsh', # TENEX C Shell (csh++)
|
u'/bin/bash', # the Bourne-Again SHell
|
||||||
u'/bin/bash', # the Bourne-Again SHell
|
u'/bin/zsh', # the Z shell
|
||||||
u'/bin/zsh', # the Z shell
|
u'/usr/bin/zsh', # the Z shell
|
||||||
u'/usr/bin/zsh', # the Z shell
|
u'/usr/bin/screen',
|
||||||
u'/usr/bin/screen',
|
u'/bin/rbash', # Bash restreint
|
||||||
u'/bin/rbash', # Bash restreint
|
u'/usr/bin/rssh', # restricted secure shell allowing only scp and/or sftp
|
||||||
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/local/bin/badPassSh', # demande de changer de mot de passe
|
u'/usr/bin/passwd', # idem
|
||||||
u'/usr/bin/passwd', # idem
|
u'/usr/local/bin/disconnect_shell', # déconnexion crans
|
||||||
u'/usr/local/bin/disconnect_shell', # déconnexion crans
|
u'/usr/scripts/surveillance/disconnect_shell', # idem
|
||||||
u'/usr/scripts/surveillance/disconnect_shell', # idem
|
u'/usr/sbin/nologin', # This account is currently not available.
|
||||||
u'/usr/sbin/nologin', # This account is currently not available.
|
u'/bin/false', # vraiement méchant
|
||||||
u'/bin/false', # vraiement méchant
|
u'/usr/bin/es', # n'exsite plus
|
||||||
u'/usr/bin/es', # n'exsite plus
|
u'/usr/bin/esh', # n'existe plus
|
||||||
u'/usr/bin/esh', # n'existe plus
|
u'', # le shell vide pour pouvoir les punis
|
||||||
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 = {
|
shells_gest_crans = {
|
||||||
"zsh" : {
|
"zsh": {"path":"/bin/zsh", "desc":"Le Z SHell, shell par defaut sur zamok"},
|
||||||
"path" : "/bin/zsh",
|
"bash": {"path":"/bin/bash", "desc":"Le Boune-Again SHell, shell par defaut de la plupart des linux"},
|
||||||
"desc" : "Le Z SHell, shell par defaut sur zamok"
|
"tcsh": {"path":"/bin/tcsh", "desc":"C SHell ++"},
|
||||||
},
|
"screen":{"path":'/usr/bin/screen', "desc":"Un gestionnaire de fenêtre dans un terminal"},
|
||||||
"bash" : {
|
"rbash": {"path":"/bin/rbash", "desc":"Un bash très restreint, voir man rbash"},
|
||||||
"path" : "/bin/bash",
|
"rssh": {"path":"/usr/bin/rssh", "desc":"Shell ne permetant que les transferts de fichiers via scp ou sftp"},
|
||||||
"desc" : "Le Boune-Again SHell, shell par defaut de la plupart des linux"
|
"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"},
|
||||||
"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 ?
|
# Quels droits donnent l'appartenance à quel groupe Unix ?
|
||||||
droits_groupes = {
|
droits_groupes = {'adm' : [u'Nounou'],
|
||||||
'adm' : [
|
'respbats' : [u'Imprimeur', u'Cableur', u'Nounou'],
|
||||||
u'Nounou',
|
'apprentis' : [u'Apprenti'],
|
||||||
],
|
'moderateurs' : [u'Moderateur'],
|
||||||
'respbats' : [
|
'disconnect' : [u'Bureau'],
|
||||||
u'Imprimeur',
|
'imprimeurs' : [u'Imprimeur', u'Nounou', u'Tresorier'],
|
||||||
u'Cableur',
|
'bureau' : [u'Bureau'],
|
||||||
u'Nounou',
|
'webadm' : [u'Webmaster'],
|
||||||
],
|
'webradio' : [u'Webradio'],
|
||||||
'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
|
####### Les modes de paiement accepté par le crans
|
||||||
|
|
||||||
modePaiement = [
|
modePaiement = ['liquide', 'paypal', 'solde', 'cheque', 'carte', 'comnpay', 'arbitraire',]
|
||||||
'liquide',
|
|
||||||
'paypal',
|
|
||||||
'solde',
|
|
||||||
'cheque',
|
|
||||||
'carte',
|
|
||||||
'comnpay',
|
|
||||||
'arbitraire',
|
|
||||||
'note',
|
|
||||||
]
|
|
||||||
|
|
||||||
####### Les ML
|
####### Les ML
|
||||||
# Le + devant un nom de ML indique une synchronisation
|
# Le + devant un nom de ML indique une synchronisation
|
||||||
# ML <-> fonction partielle : il n'y a pas d'effacement automatique
|
# ML <-> fonction partielle : il n'y a pas d'effacement automatique
|
||||||
# des abonnés si le droit est retiré
|
# des abonnés si le droit est retiré
|
||||||
droits_mailing_listes = {
|
droits_mailing_listes = {'roots' : [ u'Nounou', u'Apprenti'],
|
||||||
'roots' : [
|
'mailman' : [ u'Nounou'],
|
||||||
u'Nounou',
|
'+nounou' : [ u'Nounou', u'Apprenti'],
|
||||||
u'Apprenti',
|
'respbats' : [ u'Cableur', u'Nounou', u'Bureau'],
|
||||||
],
|
'moderateurs' : [ u'Moderateur', u'Bureau'],
|
||||||
'mailman' : [
|
'disconnect' : [ u'Nounou', u'Bureau'],
|
||||||
u'Nounou',
|
'impression' : [ u'Imprimeur'],
|
||||||
],
|
'bureau' : [u'Bureau'],
|
||||||
'+nounou' : [
|
'tresorier' : [u'Tresorier'],
|
||||||
u'Nounou',
|
'apprentis' : [u'Apprenti'],
|
||||||
u'Apprenti',
|
'+ca' : [u'Bureau', u'Apprenti', u'Nounou', u'Cableur'],
|
||||||
],
|
|
||||||
'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',
|
|
||||||
],
|
|
||||||
|
|
||||||
# Correspondance partielle nécessaire... Des adresses non-crans sont inscrites à ces ML.
|
'+federez' : [u'Bureau', u'Apprenti', u'Nounou'],
|
||||||
'+dsi-crans' : [
|
'+install-party' : [u'Bureau', u'Apprenti', u'Nounou'],
|
||||||
u'Nounou',
|
|
||||||
u'Bureau',
|
# Correspondance partielle nécessaire... Des adresses non-crans sont inscrites à ces ML.
|
||||||
],
|
'+dsi-crans' : [u'Nounou', u'Bureau'],
|
||||||
'+crous-crans' : [
|
'+crous-crans' : [u'Nounou', u'Bureau'],
|
||||||
u'Nounou',
|
|
||||||
u'Bureau',
|
'+wrc' : [u'Webradio'],
|
||||||
],
|
}
|
||||||
'+wrc' : [
|
|
||||||
u'Webradio',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
#: Répertoire de stockage des objets détruits
|
#: Répertoire de stockage des objets détruits
|
||||||
cimetiere = '/home/cimetiere'
|
cimetiere = '/home/cimetiere'
|
||||||
|
@ -273,21 +160,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
|
# 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)
|
# 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 = {
|
sshfp_algo = {
|
||||||
"rsa" : (1, "ssh-rsa"),
|
"rsa" : (1, "ssh-rsa"),
|
||||||
"dsa" : (2, "ssh-dss"),
|
"dsa" : (2, "ssh-dss"),
|
||||||
"ecdsa-256" : (3, "ecdsa-sha2-nistp256"),
|
"ecdsa-256" : (3, "ecdsa-sha2-nistp256"),
|
||||||
"ecdsa-384" : (3, "ecdsa-sha2-nistp384"),
|
"ecdsa-384" : (3, "ecdsa-sha2-nistp384"),
|
||||||
"ecdsa-521" : (3, "ecdsa-sha2-nistp521"),
|
"ecdsa-521" : (3, "ecdsa-sha2-nistp521"),
|
||||||
"ecdsa" : (3, "ecdsa-sha2-nistp521"),
|
"ecdsa" : (3, "ecdsa-sha2-nistp521"),
|
||||||
}
|
}
|
||||||
|
|
||||||
sshfs_ralgo = {}
|
sshfs_ralgo = {}
|
||||||
for key, value in sshfp_algo.items():
|
for key, value in sshfp_algo.items():
|
||||||
sshfs_ralgo[value[1]] = (value[0], key)
|
sshfs_ralgo[value[1]] = (value[0], key)
|
||||||
|
|
||||||
sshfp_hash = {
|
sshfp_hash = {
|
||||||
"sha1" : 1,
|
"sha1" : 1,
|
||||||
"sha256" : 2,
|
"sha256" : 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
sshkey_max_age = int(9.869604401089358 * (365.25 * 24 * 3600))
|
sshkey_max_age = int(9.869604401089358 * (365.25 * 24 * 3600))
|
||||||
|
@ -325,74 +212,40 @@ plage_ens = '138.231.0.0/16'
|
||||||
# clefs qui cassent la bijectivité, mais qui peuvent servir.
|
# clefs qui cassent la bijectivité, mais qui peuvent servir.
|
||||||
# NETs est l'union des deux
|
# NETs est l'union des deux
|
||||||
NETs_primaires = {
|
NETs_primaires = {
|
||||||
'serveurs' : [
|
'serveurs' : ['138.231.136.0/24'],
|
||||||
'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',
|
||||||
'adherents' : [
|
'138.231.148.32/27',
|
||||||
'138.231.137.0/24',
|
'138.231.148.64/26',
|
||||||
'138.231.138.0/23',
|
'138.231.148.128/25',
|
||||||
'138.231.140.0/22',
|
'138.231.149.0/24',
|
||||||
],
|
'138.231.150.0/23',
|
||||||
'wifi-adh' : [
|
],
|
||||||
'138.231.144.0/22',
|
'bornes' : [
|
||||||
'138.231.148.32/27',
|
'138.231.148.0/27',
|
||||||
'138.231.148.64/26',
|
],
|
||||||
'138.231.148.128/25',
|
'adm' : ['10.231.136.0/24'],
|
||||||
'138.231.149.0/24',
|
'personnel-ens' : ['10.2.9.0/24'],
|
||||||
'138.231.150.0/23',
|
'gratuit' : ['10.42.0.0/16'],
|
||||||
],
|
'accueil' : ['10.51.0.0/16'],
|
||||||
'bornes' : [
|
'federez' : ['10.53.0.0/16'],
|
||||||
'138.231.148.0/27',
|
'isolement' : ['10.52.0.0/16'],
|
||||||
],
|
'evenementiel' : ['10.231.137.0/24'],
|
||||||
'adm' : [
|
'multicast' : ['239.0.0.0/8'],
|
||||||
'10.231.136.0/24'
|
'ens' : ['138.231.135.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 = {
|
NETs_secondaires = {
|
||||||
'all' : [
|
'all' : ['138.231.136.0/21', '138.231.144.0/21'],
|
||||||
'138.231.136.0/21',
|
'wifi': ['138.231.144.0/21'],
|
||||||
'138.231.144.0/21',
|
'fil' : ['138.231.136.0/21'],
|
||||||
],
|
}
|
||||||
'wifi': [
|
|
||||||
'138.231.144.0/21',
|
|
||||||
],
|
|
||||||
'fil' : [
|
|
||||||
'138.231.136.0/21',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
NETs = {}
|
NETs = {}
|
||||||
NETs.update(NETs_primaires)
|
NETs.update(NETs_primaires)
|
||||||
NETs.update(NETs_secondaires)
|
NETs.update(NETs_secondaires)
|
||||||
|
|
||||||
NETs_regexp = {
|
NETs_regexp = { 'all' : '^138\.231\.1(3[6789]|4[0123456789]|5[01])\.\d+$' }
|
||||||
'all' : r'^138\.231\.1(3[6789]|4[0123456789]|5[01])\.\d+$'
|
|
||||||
}
|
|
||||||
|
|
||||||
# Classes de rid
|
# Classes de rid
|
||||||
# Merci d'essayer de les faire correspondre avec les réseaux
|
# Merci d'essayer de les faire correspondre avec les réseaux
|
||||||
|
@ -429,13 +282,13 @@ rid_primaires = {
|
||||||
'personnel-ens' : [(55296, 55551),],
|
'personnel-ens' : [(55296, 55551),],
|
||||||
# Un unique rid pour les machines multicast
|
# Un unique rid pour les machines multicast
|
||||||
'multicast' : [(65535, 65535),],
|
'multicast' : [(65535, 65535),],
|
||||||
}
|
}
|
||||||
|
|
||||||
rid_secondaires = {
|
rid_secondaires = {
|
||||||
# Rid pour les machines filaire ipv4
|
# Rid pour les machines filaire ipv4
|
||||||
'fil' : [(0, 2047),],
|
'fil' : [(0, 2047),],
|
||||||
'wifi' : [(2048, 4095), (34816, 35071),],
|
'wifi' : [(2048, 4095), (34816, 35071),],
|
||||||
}
|
}
|
||||||
|
|
||||||
rid = {}
|
rid = {}
|
||||||
rid.update(rid_primaires)
|
rid.update(rid_primaires)
|
||||||
|
@ -461,59 +314,24 @@ ipv6_machines_speciales = {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Les préfixes ipv6 publics
|
# Les préfixes ipv6 publics
|
||||||
prefix = {
|
prefix = { 'subnet' : [ '2a01:240:fe3d::/48' ],
|
||||||
'subnet' : [
|
'serveurs' : [ '2a01:240:fe3d:4::/64' ],
|
||||||
'2a01:240:fe3d::/48',
|
'adherents' : [ '2a01:240:fe3d:4::/64' ],
|
||||||
],
|
'fil' : [ '2a01:240:fe3d:4::/64' ],
|
||||||
'serveurs' : [
|
'adm' : [ '2a01:240:fe3d:c804::/64' ],
|
||||||
'2a01:240:fe3d:4::/64',
|
'adm-v6' : [ '2a01:240:fe3d:c804::/64' ],
|
||||||
],
|
'wifi' : [ '2a01:240:fe3d:c04::/64' ],
|
||||||
'adherents' : [
|
'serveurs-v6' : [ '2a01:240:fe3d:c04::/64' ],
|
||||||
'2a01:240:fe3d:4::/64',
|
'adherents-v6' : [ '2a01:240:fe3d:4::/64' ],
|
||||||
],
|
'wifi-adh-v6' : [ '2a01:240:fe3d:c04::/64' ],
|
||||||
'fil' : [
|
'personnel-ens' : [ '2a01:240:fe3d:4::/64' ],
|
||||||
'2a01:240:fe3d:4::/64',
|
'sixxs2' : [ '2a01:240:fe00:68::/64' ],
|
||||||
],
|
'evenementiel' : [ '2a01:240:fe3d:d2::/64' ],
|
||||||
'adm' : [
|
'bornes' : [ '2a01:240:fe3d:c04::/64' ],
|
||||||
'2a01:240:fe3d:c804::/64',
|
'bornes-v6' : [ '2a01:240:fe3d:c04::/64' ],
|
||||||
],
|
'wifi-adh' : [ '2a01:240:fe3d:c04::/64' ],
|
||||||
'adm-v6' : [
|
'v6only' : [ '2001:470:c8b9:a4::/64' ],
|
||||||
'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)
|
# Préfixes ipv6 internes (ula)
|
||||||
int_prefix = {
|
int_prefix = {
|
||||||
|
@ -522,12 +340,10 @@ int_prefix = {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Domaines dans lesquels les machines sont placées suivant leur type
|
# Domaines dans lesquels les machines sont placées suivant leur type
|
||||||
domains = {
|
domains = { 'machineFixe': 'crans.org',
|
||||||
'machineFixe': 'crans.org',
|
'machineCrans': 'crans.org',
|
||||||
'machineCrans': 'crans.org',
|
'machineWifi': 'wifi.crans.org',
|
||||||
'machineWifi': 'wifi.crans.org',
|
'borneWifi': 'wifi.crans.org' }
|
||||||
'borneWifi': 'wifi.crans.org',
|
|
||||||
}
|
|
||||||
|
|
||||||
# VLans
|
# VLans
|
||||||
vlans = {
|
vlans = {
|
||||||
|
@ -547,6 +363,8 @@ vlans = {
|
||||||
'v6only': 6,
|
'v6only': 6,
|
||||||
# Vlan isolement
|
# Vlan isolement
|
||||||
'isolement' : 9,
|
'isolement' : 9,
|
||||||
|
# Vlan de tests de chiffrement DSI
|
||||||
|
'chiffrement': 11,
|
||||||
# VLan des appartements de l'ENS
|
# VLan des appartements de l'ENS
|
||||||
'appts': 21,
|
'appts': 21,
|
||||||
# Vlan federez-wifi
|
# Vlan federez-wifi
|
||||||
|
@ -559,45 +377,33 @@ vlans = {
|
||||||
'iscsi': 42,
|
'iscsi': 42,
|
||||||
# freebox (pour faire descendre la connexion au 0B)
|
# freebox (pour faire descendre la connexion au 0B)
|
||||||
'freebox': 8,
|
'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
|
# Cf RFC 4890
|
||||||
authorized_icmpv6 = [
|
authorized_icmpv6 = ['echo-request', 'echo-reply', 'destination-unreachable',
|
||||||
'echo-request',
|
'packet-too-big', 'ttl-zero-during-transit', 'parameter-problem']
|
||||||
'echo-reply',
|
|
||||||
'destination-unreachable',
|
|
||||||
'packet-too-big',
|
|
||||||
'ttl-zero-during-transit',
|
|
||||||
'parameter-problem',
|
|
||||||
]
|
|
||||||
|
|
||||||
output_file = {
|
output_file = { 4 : '/tmp/ipt_rules',
|
||||||
4 : '/tmp/ipt_rules',
|
6 : '/tmp/ip6t_rules'
|
||||||
6 : '/tmp/ip6t_rules',
|
}
|
||||||
}
|
|
||||||
|
|
||||||
file_pickle = {
|
file_pickle = { 4 : '/tmp/ipt_pickle',
|
||||||
4 : '/tmp/ipt_pickle',
|
6 : '/tmp/ip6t_pickle'
|
||||||
6 : '/tmp/ip6t_pickle',
|
}
|
||||||
}
|
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
#: Items de la blackliste
|
#: Items de la blackliste
|
||||||
|
@ -621,7 +427,7 @@ blacklist_sanctions = [
|
||||||
]
|
]
|
||||||
|
|
||||||
#: Blacklistes redirigeant le port 80 en http vers le portail captif (avec des explications)
|
#: Blacklistes redirigeant le port 80 en http vers le portail captif (avec des explications)
|
||||||
blacklist_sanctions_soft = [
|
blacklist_sanctions_soft = [
|
||||||
'ipv6_ra',
|
'ipv6_ra',
|
||||||
'mail_invalide',
|
'mail_invalide',
|
||||||
'virus',
|
'virus',
|
||||||
|
@ -635,24 +441,10 @@ blacklist_bridage_upload = ['autodisc_upload', 'upload']
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
|
|
||||||
adm_users = [
|
adm_users = [ 'root', 'identd', 'daemon', 'postfix', 'freerad', 'amavis',
|
||||||
'root',
|
'nut', 'respbats', 'list', 'sqlgrey', 'ntpd', 'lp' ]
|
||||||
'identd',
|
|
||||||
'daemon',
|
|
||||||
'postfix',
|
|
||||||
'freerad',
|
|
||||||
'amavis',
|
|
||||||
'nut',
|
|
||||||
'respbats',
|
|
||||||
'list',
|
|
||||||
'sqlgrey',
|
|
||||||
'ntpd',
|
|
||||||
'lp',
|
|
||||||
]
|
|
||||||
|
|
||||||
open_ports = {
|
open_ports = { 'tcp' : '22' }
|
||||||
'tcp' : '22',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Debit max sur le vlan de la connexion gratuite
|
# Debit max sur le vlan de la connexion gratuite
|
||||||
debit_max_radin = 1000000
|
debit_max_radin = 1000000
|
||||||
|
@ -662,83 +454,13 @@ debit_max_gratuit = 1000000
|
||||||
## Vlan accueil et isolement ##
|
## Vlan accueil et isolement ##
|
||||||
###############################
|
###############################
|
||||||
accueil_route = {
|
accueil_route = {
|
||||||
'138.231.136.1' : {
|
'138.231.136.1':{'tcp':['80','443', '22'],'hosts':['intranet.crans.org', 'ssh.crans.org', 'zamok.crans.org']},
|
||||||
'tcp' : [
|
'138.231.136.67':{'tcp':['80','443'],'hosts':['www.crans.org', 'wiki.crans.org', 'wifi.crans.org']},
|
||||||
'80',
|
'138.231.136.98':{'tcp':['20','21','80','111','1024:65535'],'udp':['69','1024:65535'], 'hosts':['ftp.crans.org']},
|
||||||
'443',
|
'138.231.136.130':{'tcp':['80','443'],'hosts':['intranet2.crans.org']},
|
||||||
'22'
|
'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']},
|
||||||
'hosts' : [
|
'213.154.225.237':{'tcp':['80','443'], 'hosts':['ocsp.cacert.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',
|
|
||||||
'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']
|
dhcp_servers = ['dhcp.adm.crans.org', 'isc.adm.crans.org']
|
||||||
|
|
|
@ -10,17 +10,11 @@
|
||||||
# Délai minimal avant de pouvoir réadhérer.
|
# Délai minimal avant de pouvoir réadhérer.
|
||||||
# Ne tient pas compte de la période transitoire, qui est un confort
|
# Ne tient pas compte de la période transitoire, qui est un confort
|
||||||
# pour l'administration.
|
# pour l'administration.
|
||||||
delai_readh_jour = 32
|
delai_readh_jour = 28
|
||||||
delai_readh = delai_readh_jour * 86400
|
delai_readh = delai_readh_jour * 86400
|
||||||
|
|
||||||
duree_adh_an = 1
|
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 à
|
# 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,
|
# 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
|
# et ce dès leur première fois. (comprendre : le compte Crans et cie ne sont pas
|
||||||
|
|
|
@ -130,14 +130,6 @@ 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
|
#: Les ip/net des vlans limité vue par les récursifs
|
||||||
menteur_clients = [
|
menteur_clients = [
|
||||||
"138.231.136.210",
|
"138.231.136.210",
|
||||||
|
|
|
@ -4,4 +4,3 @@ import sys
|
||||||
|
|
||||||
in_encoding = getattr(sys.stdin, 'encoding', None) or "UTF-8"
|
in_encoding = getattr(sys.stdin, 'encoding', None) or "UTF-8"
|
||||||
out_encoding = getattr(sys.stdout, 'encoding', None) or "UTF-8"
|
out_encoding = getattr(sys.stdout, 'encoding', None) or "UTF-8"
|
||||||
ldap_encoding = "UTF-8"
|
|
||||||
|
|
|
@ -12,14 +12,10 @@ ITEMS = {
|
||||||
'designation': u'Cable Ethernet 5m',
|
'designation': u'Cable Ethernet 5m',
|
||||||
'pu': 3.,
|
'pu': 3.,
|
||||||
},
|
},
|
||||||
'ADAPTATEUR_TrendNet': {
|
'ADAPTATEUR': {
|
||||||
'designation': u'Adaptateur 10/100 Ethernet/USB-2',
|
'designation': u'Adaptateur Ethernet/USB',
|
||||||
'pu': 17.,
|
'pu': 17.,
|
||||||
},
|
},
|
||||||
'ADAPTATEUR_UGreen': {
|
|
||||||
'designation': u'Adaptateur 10/100/1000 Ethernet/USB-3',
|
|
||||||
'pu': 14.,
|
|
||||||
},
|
|
||||||
'RELIURE': {
|
'RELIURE': {
|
||||||
'designation': u'Reliure plastique',
|
'designation': u'Reliure plastique',
|
||||||
'pu': 0.12,
|
'pu': 0.12,
|
||||||
|
@ -41,27 +37,3 @@ ITEMS = {
|
||||||
'pu': 28.92,
|
'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,20 +53,12 @@ mask = [24]
|
||||||
now=datetime.datetime.now()
|
now=datetime.datetime.now()
|
||||||
if now.hour >= 6 and now.hour < 19 and now.weekday() < 5 and not is_ferie():
|
if now.hour >= 6 and now.hour < 19 and now.weekday() < 5 and not is_ferie():
|
||||||
#: Débit maximal autorisé
|
#: Débit maximal autorisé
|
||||||
debit_max = { 'total' : 250,
|
debit_max = 150 # mbits per second en connexion de jour
|
||||||
'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 ?
|
#: Est-ce qu'on est en connexion de jour ou de nuit/week-end ?
|
||||||
debit_jour = True
|
debit_jour = True
|
||||||
else:
|
else:
|
||||||
#: Débit maximal autorisé
|
#: Débit maximal autorisé
|
||||||
debit_max = { 'total' : 600,
|
debit_max = 500 # mbits per second en conn de nuit et du week-end
|
||||||
'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 ?
|
#: Est-ce qu'on est en connexion de jour ou de nuit/week-end ?
|
||||||
debit_jour = False
|
debit_jour = False
|
||||||
|
|
||||||
|
@ -81,7 +73,7 @@ federez_upload_max = 10 #mbytes per second
|
||||||
|
|
||||||
# Debit appartement down max
|
# Debit appartement down max
|
||||||
# TODO : mettre en place dans komaz.py
|
# TODO : mettre en place dans komaz.py
|
||||||
appt_download_max = debit_max['total']/10
|
appt_download_max = debit_max/10
|
||||||
|
|
||||||
#: Liste des réseaux non routables
|
#: Liste des réseaux non routables
|
||||||
reseaux_non_routables = [ '10.0.0.0/8', '172.16.0.0/12','198.18.0.0/15',
|
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 itertools
|
||||||
import os
|
import os
|
||||||
|
|
||||||
debug = (int(os.environ.get('DBG_TRIGGER', 0)) == 1) or True
|
debug = (int(os.environ['DBG_TRIGGER']) == 1) or True
|
||||||
log_level = "info"
|
log_level = "info"
|
||||||
|
|
||||||
# Serveur maître
|
# Serveur maître
|
||||||
|
@ -16,12 +16,6 @@ user = "trigger"
|
||||||
port = 5671
|
port = 5671
|
||||||
ssl = True
|
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
|
# Liste des services associés aux hôtes
|
||||||
# useradd : Envoie le mail de bienvenue, et crée le home
|
# 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
|
# 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 Dialog as PythonDialog
|
||||||
from pythondialog import DialogTerminatedBySignal, PythonDialogErrorBeforeExecInChildProcess
|
from pythondialog import DialogTerminatedBySignal, PythonDialogErrorBeforeExecInChildProcess
|
||||||
from pythondialog import error as DialogError
|
from pythondialog import error as DialogError
|
||||||
from gestion import affichage
|
from gestion.affich_tools import get_screen_size, coul
|
||||||
|
|
||||||
debug_enable = False
|
debug_enable = False
|
||||||
debugf = None
|
debugf = None
|
||||||
|
@ -203,7 +203,7 @@ class Dialog(object):
|
||||||
setattr(self, attr, ret)
|
setattr(self, attr, ret)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def __init__(self, debug_enable=False, dialogrc=False):
|
def __init__(self, debug_enable=False):
|
||||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
|
|
||||||
self.debug_enable = debug_enable
|
self.debug_enable = debug_enable
|
||||||
|
@ -211,7 +211,6 @@ class Dialog(object):
|
||||||
# On met un timeout à 10min d'innactivité sur dialog
|
# On met un timeout à 10min d'innactivité sur dialog
|
||||||
self.timeout = 600
|
self.timeout = 600
|
||||||
self.error_to_raise = (Continue, DialogError, ldap.SERVER_DOWN)
|
self.error_to_raise = (Continue, DialogError, ldap.SERVER_DOWN)
|
||||||
self.dialogrc = dialogrc
|
|
||||||
|
|
||||||
_dialog = None
|
_dialog = None
|
||||||
@property
|
@property
|
||||||
|
@ -219,9 +218,7 @@ class Dialog(object):
|
||||||
"""
|
"""
|
||||||
Renvois l'objet dialog.
|
Renvois l'objet dialog.
|
||||||
"""
|
"""
|
||||||
if self.dialogrc:
|
if self._dialog is None:
|
||||||
self._dialog = PythonDialog(DIALOGRC=self.dialogrc)
|
|
||||||
else:
|
|
||||||
self._dialog = PythonDialog()
|
self._dialog = PythonDialog()
|
||||||
self.dialog_last_access = time.time()
|
self.dialog_last_access = time.time()
|
||||||
return self._dialog
|
return self._dialog
|
||||||
|
@ -230,7 +227,7 @@ class Dialog(object):
|
||||||
"""
|
"""
|
||||||
Nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan
|
Nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan nyan
|
||||||
"""
|
"""
|
||||||
(cols, lines) = affichage.getTerminalSize()
|
(lines, cols) = get_screen_size()
|
||||||
print "\033[48;5;17m"
|
print "\033[48;5;17m"
|
||||||
print " "*(lines * cols)
|
print " "*(lines * cols)
|
||||||
cols = int(min(cols/2, 65))
|
cols = int(min(cols/2, 65))
|
||||||
|
|
|
@ -9,8 +9,6 @@ Licence : GPLv3
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
import subprocess
|
|
||||||
import pytz
|
|
||||||
import dateutil.relativedelta
|
import dateutil.relativedelta
|
||||||
if '/usr/scripts' not in sys.path:
|
if '/usr/scripts' not in sys.path:
|
||||||
sys.path.append('/usr/scripts')
|
sys.path.append('/usr/scripts')
|
||||||
|
@ -20,7 +18,6 @@ import config.cotisation
|
||||||
import lc_ldap.objets as objets
|
import lc_ldap.objets as objets
|
||||||
import lc_ldap.attributs as attributs
|
import lc_ldap.attributs as attributs
|
||||||
from lc_ldap.attributs import UniquenessError
|
from lc_ldap.attributs import UniquenessError
|
||||||
from lc_ldap import crans_utils
|
|
||||||
|
|
||||||
import proprio
|
import proprio
|
||||||
from CPS import TailCall, tailcaller, Continue
|
from CPS import TailCall, tailcaller, Continue
|
||||||
|
@ -48,20 +45,20 @@ class Dialog(proprio.Dialog):
|
||||||
'GPGFingerprint' : [a.nounou, a.soi],
|
'GPGFingerprint' : [a.nounou, a.soi],
|
||||||
'Remarques' : [a.cableur, a.nounou],
|
'Remarques' : [a.cableur, a.nounou],
|
||||||
'Droits':[a.nounou, a.bureau],
|
'Droits':[a.nounou, a.bureau],
|
||||||
'Blackliste':[a.bureau, a.nounou],
|
'Blackliste':[a.cableur, a.nounou],
|
||||||
'Vente':[a.cableur, a.nounou],
|
'Vente':[a.cableur, a.nounou],
|
||||||
'Supprimer':[a.nounou, a.bureau],
|
'Supprimer':[a.nounou, a.bureau],
|
||||||
}
|
}
|
||||||
menu = {
|
menu = {
|
||||||
'Administratif' : {'text' : "Adhésion, chartes", "callback":self.adherent_administratif},
|
'Administratif' : {'text' : "Adhésion, carte étudiant, chartes", "callback":self.adherent_administratif},
|
||||||
'Personnel' : {'text' : "Nom, prénom, téléphone, et mail de contact", 'callback':self.adherent_personnel},
|
'Personnel' : {'text' : "Nom, prénom, téléphone... (ajouter l'age ?)", 'callback':self.adherent_personnel},
|
||||||
'Études' : {'text' : "Étude en cours", "callback":self.adherent_etudes},
|
'Études' : {'text' : "Étude en cours", "callback":self.adherent_etudes},
|
||||||
'Chambre' : {'text' : 'Déménagement', "callback":self.adherent_chambre},
|
'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"},
|
'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},
|
'GPGFingerprint' : {'text':'Ajouter ou supprimer une empeinte GPG', 'attribut':attributs.gpgFingerprint},
|
||||||
'Remarques' : {'text':'Ajouter ou supprimer une remarque à cet adhérent', 'attribut':attributs.info},
|
'Remarques' : {'text':'Ajouter ou supprimer une remarque de la machine', 'attribut':attributs.info},
|
||||||
'Droits' : {'text':"Modifier les droits alloués à cet adhérent", "callback":self.adherent_droits},
|
'Droits' : {'text':"Modifier les droits alloués à cet adhérent", "callback":self.adherent_droits},
|
||||||
'Blackliste' : {'text': 'Modifier les blacklist de cet adhérent', 'callback':self.modif_adherent_blacklist},
|
'Blackliste' : {'text': 'Modifier les blacklist de la machine', 'callback':self.modif_adherent_blacklist},
|
||||||
'Vente' : {'text':"Chargement solde crans, vente de cable ou adaptateur ethernet ou autre", "adherent":"proprio", "callback":self.proprio_vente},
|
'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))},
|
'Supprimer' : {'text':"Supprimer l'adhérent de la base de donnée", 'callback':TailCall(self.delete_adherent, del_cont=cont(proprio=None))},
|
||||||
}
|
}
|
||||||
|
@ -126,13 +123,17 @@ class Dialog(proprio.Dialog):
|
||||||
"Adhésion": [a.cableur, a.nounou],
|
"Adhésion": [a.cableur, a.nounou],
|
||||||
'Connexion': [a.cableur, a.nounou],
|
'Connexion': [a.cableur, a.nounou],
|
||||||
"Charte MA" : [a.nounou, a.bureau],
|
"Charte MA" : [a.nounou, a.bureau],
|
||||||
|
"Carte Étudiant" : [a.nounou, a.cableur, a.tresorier],
|
||||||
}
|
}
|
||||||
menu = {
|
menu = {
|
||||||
"Adhésion" : {"text":"Pour toute réadhésion *sans* connexion.", "help":"", "callback":self.adherent_adhesion},
|
"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},
|
'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},
|
"Charte MA" : {"text" : "Signature de la charte des membres actifs", "help":'', "callback":self.adherent_charte},
|
||||||
}
|
}
|
||||||
menu_order = ["Adhésion", 'Connexion']
|
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")
|
menu_order.append("Charte MA")
|
||||||
def box(default_item=None):
|
def box(default_item=None):
|
||||||
return self.dialog.menu(
|
return self.dialog.menu(
|
||||||
|
@ -220,7 +221,8 @@ class Dialog(proprio.Dialog):
|
||||||
|
|
||||||
# Boite si on ne peux pas réahdérer
|
# Boite si on ne peux pas réahdérer
|
||||||
def box_already(end):
|
def box_already(end):
|
||||||
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),
|
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),
|
||||||
width=0,
|
width=0,
|
||||||
height=0,
|
height=0,
|
||||||
timeout=self.timeout,
|
timeout=self.timeout,
|
||||||
|
@ -228,8 +230,9 @@ class Dialog(proprio.Dialog):
|
||||||
|
|
||||||
# Boite de confirmation à l'ahésion
|
# Boite de confirmation à l'ahésion
|
||||||
def box_adherer(end=None):
|
def box_adherer(end=None):
|
||||||
if end != crans_utils.localized_datetime():
|
if end:
|
||||||
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]))
|
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]))
|
||||||
else:
|
else:
|
||||||
adherer = self.confirm(text="Adhésion pour un an, continuer ?", title="Adhésion de %s %s" % (adherent.get("prenom", [''])[0], adherent["nom"][0]))
|
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
|
return adherer
|
||||||
|
@ -243,8 +246,9 @@ class Dialog(proprio.Dialog):
|
||||||
|
|
||||||
# Génération de la facture pour adhésion
|
# Génération de la facture pour adhésion
|
||||||
def paiement(tag_paiement, adherent, finadhesion, comment, facture, cancel_cont, cont):
|
def paiement(tag_paiement, adherent, finadhesion, comment, facture, cancel_cont, cont):
|
||||||
now = crans_utils.localized_datetime()
|
now = time.time()
|
||||||
new_finadhesion = max(finadhesion, now).replace(year=max(finadhesion, now).year + 1)
|
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
|
||||||
new_debutadhesion = now
|
new_debutadhesion = now
|
||||||
if facture:
|
if facture:
|
||||||
facture = self.conn.search(dn=facture.dn, scope=0, mode='rw')[0]
|
facture = self.conn.search(dn=facture.dn, scope=0, mode='rw')[0]
|
||||||
|
@ -256,8 +260,8 @@ class Dialog(proprio.Dialog):
|
||||||
facture['modePaiement'] = unicode(tag_paiement, 'utf-8')
|
facture['modePaiement'] = unicode(tag_paiement, 'utf-8')
|
||||||
facture['info'] = unicode(comment, 'utf-8')
|
facture['info'] = unicode(comment, 'utf-8')
|
||||||
facture['article'].append(config.cotisation.dico_adh)
|
facture['article'].append(config.cotisation.dico_adh)
|
||||||
facture["finAdhesion"] = new_finadhesion
|
facture["finAdhesion"] = unicode(new_finadhesion)
|
||||||
facture["debutAdhesion"] = new_debutadhesion
|
facture["debutAdhesion"] = unicode(new_debutadhesion)
|
||||||
# On peut retarder le credit pour ajouter des contribution pour la connexion internet à la facture
|
# On peut retarder le credit pour ajouter des contribution pour la connexion internet à la facture
|
||||||
if crediter:
|
if crediter:
|
||||||
if self.confirm_item(item=facture,
|
if self.confirm_item(item=facture,
|
||||||
|
@ -280,13 +284,9 @@ class Dialog(proprio.Dialog):
|
||||||
raise Continue(cont(adherent=adherent))
|
raise Continue(cont(adherent=adherent))
|
||||||
|
|
||||||
|
|
||||||
now = crans_utils.localized_datetime()
|
finadhesion = adherent.fin_adhesion()
|
||||||
try:
|
|
||||||
finadhesion = adherent.fin_adhesion().value
|
|
||||||
except AttributeError:
|
|
||||||
finadhesion = now
|
|
||||||
# Si fin de l'adhésion trop loin dans le futur, rien a faire
|
# Si fin de l'adhésion trop loin dans le futur, rien a faire
|
||||||
if finadhesion and (finadhesion - now).days > config.cotisation.delai_readh_jour:
|
if finadhesion and finadhesion - config.cotisation.delai_readh > time.time():
|
||||||
self.handle_dialog(cancel_cont if cancel_cont else cont, box_already, finadhesion)
|
self.handle_dialog(cancel_cont if cancel_cont else cont, box_already, finadhesion)
|
||||||
raise Continue(cancel_cont if cancel_cont else cont)
|
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
|
# Une boite pour choisir un nombre de mois pour prolonger la connexion
|
||||||
def box(finconnexion, default_item=None):
|
def box(finconnexion, default_item=None):
|
||||||
t_end = finconnexion
|
t_end = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(finconnexion))
|
||||||
return self.dialog.menu(
|
return self.dialog.menu(
|
||||||
"Connexion jusqu'au %s" % t_end if finconnexion != datetime.datetime.fromtimestamp(0, tz=pytz.utc) else "N'a jamais été connecté",
|
"Connexion jusqu'au %s" % t_end if finconnexion else "N'a jamais été connecté",
|
||||||
width=0,
|
width=0,
|
||||||
height=0,
|
height=0,
|
||||||
menu_height=0,
|
menu_height=0,
|
||||||
|
@ -357,16 +357,17 @@ class Dialog(proprio.Dialog):
|
||||||
|
|
||||||
# Génération et crédit de la facture
|
# 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):
|
def todo(adherent, mois, finadhesion, finconnexion, cancel_cont, cont, facture=None, tag_paiment=None, comment=None):
|
||||||
now = crans_utils.localized_datetime()
|
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
|
||||||
new_debutconnexion = max(now, finconnexion)
|
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.value).days > 0:
|
if new_finconnexion > finadhesion:
|
||||||
t_end_adh = finadhesion.value
|
t_end_adh = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(finadhesion))
|
||||||
t_end_conn = finconnexion
|
t_end_conn = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(new_finconnexion))
|
||||||
if (new_finconnexion - finadhesion.value).days > 30:
|
if new_finconnexion - finadhesion > 30 * 3600 * 24:
|
||||||
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))
|
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:
|
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" \
|
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" \
|
||||||
|
@ -376,8 +377,8 @@ class Dialog(proprio.Dialog):
|
||||||
if facture:
|
if facture:
|
||||||
with self.conn.search(dn=facture.dn, scope=0, mode='rw')[0] as facture:
|
with self.conn.search(dn=facture.dn, scope=0, mode='rw')[0] as facture:
|
||||||
if mois:
|
if mois:
|
||||||
facture["finConnexion"] = new_finconnexion
|
facture["finConnexion"] = unicode(new_finconnexion)
|
||||||
facture["debutConnexion"] = new_debutconnexion
|
facture["debutConnexion"] = unicode(new_debutconnexion)
|
||||||
facture["article"].append(config.cotisation.dico_cotis(mois))
|
facture["article"].append(config.cotisation.dico_cotis(mois))
|
||||||
if self.confirm_item(item=facture,
|
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]),
|
text=u"Le paiement de %sEUR a-t-il bien été reçu (mode : %s) ?\n" % (facture.total(), facture['modePaiement'][0]),
|
||||||
|
@ -400,8 +401,8 @@ class Dialog(proprio.Dialog):
|
||||||
facture['modePaiement'] = unicode(tag_paiment, 'utf-8')
|
facture['modePaiement'] = unicode(tag_paiment, 'utf-8')
|
||||||
facture['article'].append(config.cotisation.dico_cotis(mois))
|
facture['article'].append(config.cotisation.dico_cotis(mois))
|
||||||
facture['info'] = unicode(comment, 'utf-8')
|
facture['info'] = unicode(comment, 'utf-8')
|
||||||
facture["finConnexion"] = new_finconnexion
|
facture["finConnexion"] = unicode(new_finconnexion)
|
||||||
facture["debutConnexion"] = new_debutconnexion
|
facture["debutConnexion"] = unicode(new_debutconnexion)
|
||||||
if self.confirm_item(item=facture,
|
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),
|
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",
|
title=u"Validation du paiement",
|
||||||
|
@ -411,7 +412,7 @@ class Dialog(proprio.Dialog):
|
||||||
else:
|
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):
|
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(cancel_cont)
|
||||||
raise Continue(cont)
|
raise Continue(cont(adherent=adherent))
|
||||||
|
|
||||||
def todo_mois(tag, self_cont):
|
def todo_mois(tag, self_cont):
|
||||||
if tag == 'An':
|
if tag == 'An':
|
||||||
|
@ -433,18 +434,16 @@ class Dialog(proprio.Dialog):
|
||||||
finconnexion = adherent.fin_connexion()
|
finconnexion = adherent.fin_connexion()
|
||||||
|
|
||||||
# Si l'adhésion fini avant la connexion
|
# Si l'adhésion fini avant la connexion
|
||||||
if finadhesion <= crans_utils.localized_datetime() or finadhesion <= finconnexion:
|
if finadhesion <= time.time() or finadhesion <= finconnexion:
|
||||||
if finadhesion:
|
if finadhesion:
|
||||||
|
t_end_adh = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(finadhesion))
|
||||||
# Si l'adhésion est déjà fini
|
# Si l'adhésion est déjà fini
|
||||||
if finadhesion <= crans_utils.localized_datetime():
|
if finadhesion <= time.time():
|
||||||
if finadhesion == datetime.datetime.fromtimestamp(0, tz=pytz.utc):
|
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)
|
||||||
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
|
# Sinon si elle fini avant la fin de la connexion courante
|
||||||
elif finadhesion < finconnexion:
|
elif finadhesion < finconnexion:
|
||||||
t_end_conn = 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 (10€)" % (finadhesion, t_end_conn), title="Réadhésion nécessaire", width=0, height=0, timeout=self.timeout)
|
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)
|
||||||
# É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
|
# É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)
|
return self.adherent_adhesion(cont=self_cont, cancel_cont=cont, adherent=adherent, crediter=False)
|
||||||
|
|
||||||
|
@ -484,6 +483,76 @@ class Dialog(proprio.Dialog):
|
||||||
return self.proprio_choose_paiement(proprio=adherent, cont=self_cont, cancel_cont=lcont)
|
return self.proprio_choose_paiement(proprio=adherent, cont=self_cont, cancel_cont=lcont)
|
||||||
return cont
|
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):
|
def adherent_charte(self, cont, adherent):
|
||||||
a = attributs
|
a = attributs
|
||||||
attribs = [a.charteMA]
|
attribs = [a.charteMA]
|
||||||
|
@ -547,15 +616,6 @@ class Dialog(proprio.Dialog):
|
||||||
with self.conn.search(dn=adherent.dn, scope=0, mode='rw')[0] as adherent:
|
with self.conn.search(dn=adherent.dn, scope=0, mode='rw')[0] as adherent:
|
||||||
for (key, values) in attrs.items():
|
for (key, values) in attrs.items():
|
||||||
adherent[key] = values
|
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.validate_changes()
|
||||||
adherent.history_gen()
|
adherent.history_gen()
|
||||||
adherent.save()
|
adherent.save()
|
||||||
|
@ -593,13 +653,6 @@ class Dialog(proprio.Dialog):
|
||||||
if self.confirm_item(adherent, title="Créer l'adhérent suivant ?"):
|
if self.confirm_item(adherent, title="Créer l'adhérent suivant ?"):
|
||||||
adherent.validate_changes()
|
adherent.validate_changes()
|
||||||
adherent.create()
|
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:
|
else:
|
||||||
adherent = None
|
adherent = None
|
||||||
return adherent
|
return adherent
|
||||||
|
@ -863,11 +916,13 @@ class Dialog(proprio.Dialog):
|
||||||
"""Crée un adhérent et potentiellement son compte crans avec lui"""
|
"""Crée un adhérent et potentiellement son compte crans avec lui"""
|
||||||
def mycont(adherent=None, **kwargs):
|
def mycont(adherent=None, **kwargs):
|
||||||
if adherent:
|
if adherent:
|
||||||
# Une fois l'adhérent créé, on vois s'il adhére/prend la connexion internet
|
# Une fois l'adhérent créé, on vois s'il donne sa carte étudiant et s'il adhére/prend la connexion internet
|
||||||
#adh_cont = TailCall(self.modif_adherent, cont=cont, adherent=adherent)
|
#adh_cont = TailCall(self.modif_adherent, cont=cont, adherent=adherent)
|
||||||
conn_cont = TailCall(self.adherent_connexion, cont=cont(proprio=adherent), adherent=adherent)
|
conn_cont = TailCall(self.adherent_connexion, cont=cont(proprio=adherent), adherent=adherent)
|
||||||
etude_cont = TailCall(self.adherent_etudes, cont=conn_cont, 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(cancel_cont=etude_cont)
|
etude_cont(cancel_cont=etude_cont)
|
||||||
|
carte_cont(cancel_cont=etude_cont)
|
||||||
# Comme on crée une facture, pas de retour possible
|
# Comme on crée une facture, pas de retour possible
|
||||||
conn_cont(cancel_cont=conn_cont)
|
conn_cont(cancel_cont=conn_cont)
|
||||||
raise Continue(etude_cont)
|
raise Continue(etude_cont)
|
||||||
|
|
|
@ -13,7 +13,7 @@ import traceback
|
||||||
if '/usr/scripts' not in sys.path:
|
if '/usr/scripts' not in sys.path:
|
||||||
sys.path.append('/usr/scripts')
|
sys.path.append('/usr/scripts')
|
||||||
|
|
||||||
from gestion import affichage
|
from gestion.affich_tools import coul
|
||||||
import gestion.config as config
|
import gestion.config as config
|
||||||
|
|
||||||
import lc_ldap.objets as objets
|
import lc_ldap.objets as objets
|
||||||
|
@ -37,14 +37,10 @@ class Dialog(lc.Dialog):
|
||||||
index = 0
|
index = 0
|
||||||
for bl in obj['blacklist']:
|
for bl in obj['blacklist']:
|
||||||
choices.append(
|
choices.append(
|
||||||
(
|
(str(index),
|
||||||
str(index),
|
coul("%s [%s]" % (bl['type'], bl['comm']), 'rouge' if bl['actif'] else None,
|
||||||
affichage.style(
|
dialog=True)
|
||||||
"%s [%s]" % (bl['type'], bl['comm']),
|
)
|
||||||
'rouge' if bl['actif'] else None,
|
|
||||||
dialog=True
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
index+=1
|
index+=1
|
||||||
return self.dialog.menu(
|
return self.dialog.menu(
|
||||||
|
@ -149,7 +145,7 @@ class Dialog(lc.Dialog):
|
||||||
fin_tuple = self.get_timestamp(title=title, text="Choisir la date de fin :",
|
fin_tuple = self.get_timestamp(title=title, text="Choisir la date de fin :",
|
||||||
cont=self_cont(bl=bl, tag=tag, bl_type=bl_type,
|
cont=self_cont(bl=bl, tag=tag, bl_type=bl_type,
|
||||||
debut=None, fin=None, comm=None))
|
debut=None, fin=None, comm=None))
|
||||||
fin = int(time.mktime(time.struct_time(fin_tuple + (0, 0, -1))))
|
fin = int(time.mktime(time.struct_time(debut_tuple + (0, 0, -1))))
|
||||||
else:
|
else:
|
||||||
fin = '-'
|
fin = '-'
|
||||||
bl['debut']=debut
|
bl['debut']=debut
|
||||||
|
|
|
@ -6,18 +6,16 @@ Copyright (C) Valentin Samir
|
||||||
Licence : GPLv3
|
Licence : GPLv3
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import ldap
|
import ldap
|
||||||
import traceback
|
import traceback
|
||||||
import locale
|
|
||||||
if '/usr/scripts' not in sys.path:
|
if '/usr/scripts' not in sys.path:
|
||||||
sys.path.append('/usr/scripts')
|
sys.path.append('/usr/scripts')
|
||||||
from pythondialog import Dialog
|
from pythondialog import Dialog
|
||||||
from pythondialog import error as DialogError
|
from pythondialog import error as DialogError
|
||||||
|
|
||||||
from gestion import affichage
|
from gestion.affich_tools import get_screen_size, coul
|
||||||
|
|
||||||
import lc_ldap.shortcuts
|
import lc_ldap.shortcuts
|
||||||
import lc_ldap.objets as objets
|
import lc_ldap.objets as objets
|
||||||
|
@ -29,17 +27,12 @@ from CPS import TailCall, tailcaller, Continue, TailCaller
|
||||||
|
|
||||||
class Dialog(CPS.Dialog):
|
class Dialog(CPS.Dialog):
|
||||||
def __init__(self, debug_enable=False, ldap_test=False, custom_user=None):
|
def __init__(self, debug_enable=False, ldap_test=False, custom_user=None):
|
||||||
super(Dialog, self).__init__()
|
super(Dialog, self).__init__(debug_enable=debug_enable)
|
||||||
# On initialise le moteur de rendu en spécifiant qu'on va faire du dialog
|
# On initialise le moteur de rendu en spécifiant qu'on va faire du dialog
|
||||||
printing.template(dialog=True)
|
printing.template(dialog=True)
|
||||||
self.ldap_test = ldap_test
|
self.ldap_test = ldap_test
|
||||||
if custom_user:
|
|
||||||
custom_user = custom_user.decode(locale.getdefaultlocale()[1] or "ascii")
|
|
||||||
self.custom_user = custom_user
|
self.custom_user = custom_user
|
||||||
self.check_ldap()
|
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):
|
def has_right(self, liste, obj=None):
|
||||||
"""Vérifie que l'un des droits de l'utilisateur courant est inclus dans list"""
|
"""Vérifie que l'un des droits de l'utilisateur courant est inclus dans list"""
|
||||||
|
@ -347,7 +340,7 @@ class Dialog(CPS.Dialog):
|
||||||
# pour prendre en compte la largeur du widget dialog
|
# pour prendre en compte la largeur du widget dialog
|
||||||
del items[:] # On vide la liste pour la modifier en place
|
del items[:] # On vide la liste pour la modifier en place
|
||||||
items_id = {}
|
items_id = {}
|
||||||
(col, line) = affichage.getTerminalSize()
|
(line, col) = get_screen_size()
|
||||||
for c in classes:
|
for c in classes:
|
||||||
items.extend(olist[c])
|
items.extend(olist[c])
|
||||||
items_s = printing.sprint_list(olist[c], col-20).encode('utf-8').split('\n')
|
items_s = printing.sprint_list(olist[c], col-20).encode('utf-8').split('\n')
|
||||||
|
|
|
@ -12,7 +12,6 @@ if '/usr/scripts' not in sys.path:
|
||||||
|
|
||||||
import lc_ldap.objets as objets
|
import lc_ldap.objets as objets
|
||||||
import lc_ldap.attributs as attributs
|
import lc_ldap.attributs as attributs
|
||||||
import subprocess
|
|
||||||
|
|
||||||
import certificat
|
import certificat
|
||||||
import blacklist
|
import blacklist
|
||||||
|
@ -35,12 +34,10 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
||||||
"""
|
"""
|
||||||
a = attributs
|
a = attributs
|
||||||
# Quel sont les attributs ldap dont on veut afficher et la taille du champs d'édition correspondant
|
# 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)]
|
to_display = [(a.host, 30), (a.macAddress, 17), (a.ipHostNumber, 15),
|
||||||
|
(a.portTCPout, 50), (a.portTCPin, 50), (a.portUDPout, 50),
|
||||||
to_display_port = [(a.portTCPout, 50), (a.portTCPin, 50), (a.portUDPout, 50),
|
(a.portUDPin, 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é
|
# Quel séparateur on utilise pour les champs multivalué
|
||||||
separateur = ' '
|
separateur = ' '
|
||||||
|
@ -61,19 +58,15 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
||||||
title="Paramètres machine",
|
title="Paramètres machine",
|
||||||
backtitle="Gestion des machines du Crans")
|
backtitle="Gestion des machines du Crans")
|
||||||
|
|
||||||
def check_host(host, objectClass, realm):
|
def check_host(host, objectClass):
|
||||||
# Si c'est une machine wifi, host doit finir par wifi.crans.org
|
# Si c'est une machine wifi, host doit finir par wifi.crans.org
|
||||||
if "machineWifi" == objectClass or 'borneWifi' == objectClass or realm == 'bornes':
|
if "machineWifi" == objectClass or 'borneWifi' == objectClass:
|
||||||
hostend = ".wifi.crans.org"
|
hostend = ".wifi.crans.org"
|
||||||
# Si c'est une machine wifi, host doit finir par crans.org
|
# Si c'est une machine wifi, host doit finir par crans.org
|
||||||
elif "machineFixe" == objectClass or realm == 'serveurs':
|
elif "machineFixe" == objectClass:
|
||||||
hostend = ".crans.org"
|
hostend = ".crans.org"
|
||||||
# Si l'object class est machineCrans, pas de vérification
|
# Si l'object class est machineCrans, pas de vérification
|
||||||
elif "machineCrans" == objectClass:
|
elif "machineCrans" == objectClass:
|
||||||
if realm == 'adm':
|
|
||||||
hostend = ".adm.crans.org"
|
|
||||||
if not '.' in host:
|
|
||||||
host = host + hostend
|
|
||||||
return host
|
return host
|
||||||
# Sinon, libre à chachun d'ajouter d'autres objectClass ou de filtrer
|
# Sinon, libre à chachun d'ajouter d'autres objectClass ou de filtrer
|
||||||
# plus finement fonction des droits de self.conn.droits
|
# plus finement fonction des droits de self.conn.droits
|
||||||
|
@ -81,7 +74,7 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
||||||
raise ValueError("La machine n'est ni une machine fixe, ni une machine wifi mais %s ?!?" % objectClass)
|
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:
|
if not host.endswith(hostend) and not '.' in host:
|
||||||
host = host + hostend
|
host = "%s.wifi.crans.org" % host
|
||||||
elif host.endswith(hostend) and '.' in host[:-len(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)
|
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:
|
elif not host.endswith(hostend) and '.' in host:
|
||||||
|
@ -92,8 +85,7 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
||||||
def modif_machine(machine, attrs):
|
def modif_machine(machine, attrs):
|
||||||
with self.conn.search(dn=machine.dn, scope=0, mode='rw')[0] as machine:
|
with self.conn.search(dn=machine.dn, scope=0, mode='rw')[0] as machine:
|
||||||
for (key, values) in attrs.items():
|
for (key, values) in attrs.items():
|
||||||
if values!=u'<automatique>' or key != 'ipHostNumber':
|
machine[key]=values
|
||||||
machine[key]=values
|
|
||||||
machine.validate_changes()
|
machine.validate_changes()
|
||||||
machine.history_gen()
|
machine.history_gen()
|
||||||
machine.save()
|
machine.save()
|
||||||
|
@ -109,18 +101,13 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
||||||
}
|
}
|
||||||
with self.conn.newMachine(proprio.dn, realm, ldif) as machine:
|
with self.conn.newMachine(proprio.dn, realm, ldif) as machine:
|
||||||
for (key, values) in attrs.items():
|
for (key, values) in attrs.items():
|
||||||
if values!=u'<automatique>' or key != u'ipHostNumber':
|
machine[key]=values
|
||||||
machine[key]=values
|
|
||||||
if attributs.ipsec in machine.attribs:
|
if attributs.ipsec in machine.attribs:
|
||||||
machine[attributs.ipsec.ldap_name]=attributs.ipsec.default
|
machine[attributs.ipsec.ldap_name]=attributs.ipsec.default
|
||||||
machine.validate_changes()
|
machine.validate_changes()
|
||||||
if self.confirm_item(machine, "Voulez vous vraiement créer cette machine ?"):
|
if self.confirm_item(machine, "Voulez vous vraiement créer cette machine ?"):
|
||||||
machine.create()
|
machine.create()
|
||||||
self.display_item(machine, "La machine a bien été créée", ipsec=True)
|
self.display_item(machine, "La machine à 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
|
return machine
|
||||||
else:
|
else:
|
||||||
raise Continue(cont)
|
raise Continue(cont)
|
||||||
|
@ -136,7 +123,7 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
||||||
values = [v for v in values.split(separateur) if v]
|
values = [v for v in values.split(separateur) if v]
|
||||||
# Pour host, on fait quelques vérification de syntaxe
|
# Pour host, on fait quelques vérification de syntaxe
|
||||||
if a.ldap_name == 'host':
|
if a.ldap_name == 'host':
|
||||||
attrs[a.ldap_name]=check_host(values, objectClass, realm)
|
attrs[a.ldap_name]=check_host(values, objectClass)
|
||||||
else:
|
else:
|
||||||
attrs[a.ldap_name]=values
|
attrs[a.ldap_name]=values
|
||||||
# Soit on édite une machine existante
|
# Soit on édite une machine existante
|
||||||
|
@ -147,16 +134,10 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
||||||
machine = create_machine(proprio, realm, attrs)
|
machine = create_machine(proprio, realm, attrs)
|
||||||
raise Continue(cont(machine=machine))
|
raise Continue(cont(machine=machine))
|
||||||
|
|
||||||
|
|
||||||
if machine:
|
if machine:
|
||||||
objectClass = machine["objectClass"][0]
|
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)
|
(code, tags) = self.handle_dialog(cont, box)
|
||||||
|
|
||||||
# On prépare les fiels à afficher à l'utilisateur si une erreure à lieu
|
# On prépare les fiels à afficher à l'utilisateur si une erreure à lieu
|
||||||
|
@ -207,8 +188,8 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
||||||
menu_droits = {
|
menu_droits = {
|
||||||
'Information' : [a.parent, a.cableur, a.nounou],
|
'Information' : [a.parent, a.cableur, a.nounou],
|
||||||
'Autre': [a.parent, a.cableur, a.nounou],
|
'Autre': [a.parent, a.cableur, a.nounou],
|
||||||
'Blackliste':[a.nounou],
|
'Blackliste':[a.cableur, a.nounou],
|
||||||
'Certificat': [a.parent, a.nounou],
|
'Certificat': [a.parent, a.cableur, a.nounou],
|
||||||
'Exemption' : [a.nounou],
|
'Exemption' : [a.nounou],
|
||||||
'Alias' : [a.parent, a.cableur, a.nounou],
|
'Alias' : [a.parent, a.cableur, a.nounou],
|
||||||
'Remarques' : [a.cableur, a.nounou],
|
'Remarques' : [a.cableur, a.nounou],
|
||||||
|
@ -270,41 +251,24 @@ class Dialog(certificat.Dialog, blacklist.Dialog):
|
||||||
menu_droits = {
|
menu_droits = {
|
||||||
'Fixe' : [a.soi, a.cableur, a.nounou],
|
'Fixe' : [a.soi, a.cableur, a.nounou],
|
||||||
'Wifi' : [a.soi, a.cableur, a.nounou],
|
'Wifi' : [a.soi, a.cableur, a.nounou],
|
||||||
'Appartements': [a.soi, a.cableur, a.nounou],
|
|
||||||
}
|
}
|
||||||
menu = {
|
menu = {
|
||||||
'Fixe' : {'text' : "Machine filaire", 'objectClass':'machineFixe', 'realm':'adherents'},
|
'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'},
|
'Wifi' : {'text': 'Machine sans fil', 'objectClass':'machineWifi', 'realm':'wifi-adh'},
|
||||||
}
|
}
|
||||||
menu_order = ['Wifi']
|
menu_order = ['Fixe', '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):
|
if isinstance(proprio, objets.AssociationCrans):
|
||||||
menu_droits.update({
|
menu_droits.update({
|
||||||
'Fixe' : [a.nounou],
|
'Fixe' : [a.nounou],
|
||||||
'Wifi' : [a.nounou],
|
'Wifi' : [a.nounou],
|
||||||
'Wifi-v6' : [a.nounou],
|
|
||||||
'Adm' : [a.nounou],
|
'Adm' : [a.nounou],
|
||||||
})
|
})
|
||||||
menu.update({
|
menu.update({
|
||||||
'Fixe' : {'text' : "Ajouter un serveur sur le vlan adherent", 'objectClass':'machineCrans', 'realm':'serveurs'},
|
'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' : {'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'},
|
'Adm' : {'text' : "Ajouter un serveur sur le vlan adm", "objectClass":"machineCrans", 'realm':'adm'},
|
||||||
})
|
})
|
||||||
menu_order += ['Adm', 'Wifi-v6']
|
menu_order.append('Adm')
|
||||||
def box(default_item=None):
|
def box(default_item=None):
|
||||||
return self.dialog.menu(
|
return self.dialog.menu(
|
||||||
"Type de Machine ?",
|
"Type de Machine ?",
|
||||||
|
|
|
@ -85,10 +85,11 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
||||||
|
|
||||||
@tailcaller
|
@tailcaller
|
||||||
def set_password(proprio, update_obj, cont):
|
def set_password(proprio, update_obj, cont):
|
||||||
if self.dialog.yesno("Attribuer un mot de passe maintenant ? (Vous aurez la possibilité d'imprimer un ticket plus tard également ...)",
|
if self.dialog.yesno("Attribuer un mot de passe maintenant ?",
|
||||||
title="Création du compte de %s %s" % (proprio.get('prenom', [''])[0], proprio["nom"][0]),
|
title="Création du compte de %s %s" % (proprio.get('prenom', [''])[0], proprio["nom"][0]),
|
||||||
timeout=self.timeout
|
timeout=self.timeout
|
||||||
) == self.dialog.DIALOG_OK:
|
) == 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))
|
proprio = self.proprio_compte_password(proprio=proprio, return_obj=True, cont=TailCall(set_password, proprio, update_obj, cont))
|
||||||
if return_obj:
|
if return_obj:
|
||||||
return proprio
|
return proprio
|
||||||
|
@ -167,7 +168,7 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
||||||
raise Continue(cont(proprio=proprio))
|
raise Continue(cont(proprio=proprio))
|
||||||
#(code, passwords) = self.handle_dialog(cont, box)
|
#(code, passwords) = self.handle_dialog(cont, box)
|
||||||
(code, passwords) = (self.dialog.DIALOG_OK, "")
|
(code, passwords) = (self.dialog.DIALOG_OK, "")
|
||||||
self_cont = TailCall(self.proprio_compte_password, proprio=proprio, cont=cont, return_obj=return_obj)
|
self_cont = TailCall(self.proprio_compte_password, proprio=proprio, cont=cont)
|
||||||
return self.handle_dialog_result(
|
return self.handle_dialog_result(
|
||||||
code=code,
|
code=code,
|
||||||
output=passwords,
|
output=passwords,
|
||||||
|
@ -410,19 +411,14 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
||||||
"cheque" : "Chèque",
|
"cheque" : "Chèque",
|
||||||
"carte" : "Par carte bancaire",
|
"carte" : "Par carte bancaire",
|
||||||
"solde" : "Solde Crans (actuel : %s€)",
|
"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):
|
def box_choose_paiment(tag, articles):
|
||||||
box_paiement_order = ["liquide", "cheque", "carte","note"]
|
box_paiement_order = ["liquide", "cheque", "carte"]
|
||||||
if "cransAccount" in proprio['objectClass']:
|
if "cransAccount" in proprio['objectClass']:
|
||||||
if not "SOLDE" in [art['code'] for art in articles] and proprio["solde"]:
|
if not "SOLDE" in [art['code'] for art in articles] and proprio["solde"]:
|
||||||
box_paiement_order.append("solde")
|
box_paiement_order.append("solde")
|
||||||
box_paiement["solde"] = box_paiement["solde"] % proprio["solde"][0]
|
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 = []
|
choices = []
|
||||||
for key in box_paiement_order:
|
for key in box_paiement_order:
|
||||||
choices.append((key, box_paiement[key], 1 if key == tag else 0))
|
choices.append((key, box_paiement[key], 1 if key == tag else 0))
|
||||||
|
@ -461,7 +457,6 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
||||||
|
|
||||||
def box_choose_item(tags):
|
def box_choose_item(tags):
|
||||||
choices = []
|
choices = []
|
||||||
gestion.config.factures.ITEMS.update(gestion.config.factures.ITEM_SOLDE)
|
|
||||||
for code, article in gestion.config.factures.ITEMS.items():
|
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))
|
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(
|
return self.dialog.checklist(
|
||||||
|
@ -504,19 +499,11 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
||||||
|
|
||||||
def paiement(have_set, tag, proprio, comment, cancel_cont, cont):
|
def paiement(have_set, tag, proprio, comment, cancel_cont, cont):
|
||||||
articles = copy.deepcopy(have_set)
|
articles = copy.deepcopy(have_set)
|
||||||
|
|
||||||
# On formate les articles
|
|
||||||
for article in articles:
|
for article in articles:
|
||||||
if article['pu'] == '*':
|
if article['pu'] == '*':
|
||||||
article['pu'] = article['nombre']
|
article['pu'] = article['nombre']
|
||||||
article['nombre'] = 1
|
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:
|
with self.conn.newFacture(proprio.dn, {}) as facture:
|
||||||
facture['modePaiement']=unicode(tag, 'utf-8')
|
facture['modePaiement']=unicode(tag, 'utf-8')
|
||||||
facture['article']=articles
|
facture['article']=articles
|
||||||
|
@ -530,13 +517,13 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
||||||
arts = ["%s %s" % (art['nombre'], art['designation']) for art in facture['article'] if art['code'] != 'SOLDE']
|
arts = ["%s %s" % (art['nombre'], art['designation']) for art in facture['article'] if art['code'] != 'SOLDE']
|
||||||
if arts:
|
if arts:
|
||||||
self.dialog.msgbox(
|
self.dialog.msgbox(
|
||||||
text=u"Vous pouvez remettre à l'adherent les articles (si ce sont des articles) suivant :\n * %s" % '\n * '.join(arts),
|
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",
|
title=u"Vente terminée",
|
||||||
width=0, height=0, timeout=self.timeout)
|
width=0, height=0, timeout=self.timeout)
|
||||||
if tag == "solde":
|
if tag == "solde":
|
||||||
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)
|
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)
|
||||||
if [a for a in facture['article'] if art['code'] == 'SOLDE']:
|
if [a for a in facture['article'] if art['code'] == 'SOLDE']:
|
||||||
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)
|
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)
|
||||||
else:
|
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):
|
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)
|
raise Continue(cancel_cont)
|
||||||
|
@ -572,7 +559,6 @@ class Dialog(machine.Dialog, blacklist.Dialog):
|
||||||
else:
|
else:
|
||||||
(code, tags) = self.handle_dialog(cont, box_choose_item, tags)
|
(code, tags) = self.handle_dialog(cont, box_choose_item, tags)
|
||||||
self_cont=self_cont(tags=tags, have_set=[], to_set=[], tag_paiment=None)
|
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(
|
return self.handle_dialog_result(
|
||||||
code=code,
|
code=code,
|
||||||
output=tags,
|
output=tags,
|
||||||
|
|
42134
gestion/ethercodes.dat
42134
gestion/ethercodes.dat
File diff suppressed because it is too large
Load diff
|
@ -176,22 +176,14 @@ class home:
|
||||||
|
|
||||||
### Redirection
|
### Redirection
|
||||||
if mail_redirect:
|
if mail_redirect:
|
||||||
write_in_forward = True
|
file(home + '/.forward', 'w').write(mail_redirect + '\n')
|
||||||
|
|
||||||
# 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.chown(home + '/.forward', int(uid), gid)
|
||||||
os.chmod(home + '/.forward', 0600)
|
os.chmod(home + '/.forward', 0604)
|
||||||
### Owncloud dans le home
|
### Owncloud dans le home
|
||||||
if not os.path.exists(home + '/OwnCloud'):
|
if not os.path.exists(home + '/OwnCloud'):
|
||||||
os.mkdir(home + '/OwnCloud')
|
os.mkdir(home + '/OwnCloud')
|
||||||
os.chown(home + '/OwnCloud', int(uid), grp.getgrnam('www-data').gr_gid)
|
os.chown(home + '/OwnCloud', int(uid), grp.getgrnam('www-data').gr_gid)
|
||||||
os.chmod(home + '/OwnCloud', 0770)
|
os.chmod(home + '/OwnCloud',0770)
|
||||||
except:
|
except:
|
||||||
print ERREUR
|
print ERREUR
|
||||||
if self.debug:
|
if self.debug:
|
||||||
|
|
|
@ -43,7 +43,6 @@ class autostatus(gen_config) :
|
||||||
"obm.crans.org",
|
"obm.crans.org",
|
||||||
"obm.adm.crans.org",
|
"obm.adm.crans.org",
|
||||||
"batv-3.adm.crans.org",
|
"batv-3.adm.crans.org",
|
||||||
"batv-1.adm.crans.org",
|
|
||||||
|
|
||||||
# Config par défaut
|
# Config par défaut
|
||||||
"non-configure.wifi.crans.org",
|
"non-configure.wifi.crans.org",
|
||||||
|
@ -71,7 +70,6 @@ class autostatus(gen_config) :
|
||||||
"ragnarok.crans.org", # RIP contrôleur disque...
|
"ragnarok.crans.org", # RIP contrôleur disque...
|
||||||
"zamok.crans.org", # c'est en fait fx
|
"zamok.crans.org", # c'est en fait fx
|
||||||
"bati-2.adm.crans.org", # N'est plus en place
|
"bati-2.adm.crans.org", # N'est plus en place
|
||||||
"batv-1.crans.org",
|
|
||||||
|
|
||||||
# Bornes wifi de test
|
# Bornes wifi de test
|
||||||
"bullet5.wifi.crans.org",
|
"bullet5.wifi.crans.org",
|
||||||
|
@ -144,10 +142,8 @@ class autostatus(gen_config) :
|
||||||
|
|
||||||
infos_routeurs = {}
|
infos_routeurs = {}
|
||||||
infos_routeurs [ '138.231.136.4' ] = ['Odlyd', u'Routeur principal du CRANS']
|
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.1' ] = ['Pioneer.zrt', 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' ] = ['Pioneer', 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 [ '138.231.176.1' ] = ['Pioneer', u'Routeur principal de l\'ENS']
|
||||||
infos_routeurs [ '193.49.65.1' ] = ['RenaterCachan1' , u'Routeur Renater' ]
|
infos_routeurs [ '193.49.65.1' ] = ['RenaterCachan1' , u'Routeur Renater' ]
|
||||||
infos_routeurs [ '193.51.181.186' ] = ['RenaterCachan2', u'Routeur Renater']
|
infos_routeurs [ '193.51.181.186' ] = ['RenaterCachan2', u'Routeur Renater']
|
||||||
|
|
|
@ -73,9 +73,6 @@ class TLSA(ResourceRecord):
|
||||||
if not r_format in ['pem', 'der']:
|
if not r_format in ['pem', 'der']:
|
||||||
raise ValueError("format should be pem or 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] == '.':
|
if cert is None and proto == 'tcp' and name[-1] == '.':
|
||||||
try:
|
try:
|
||||||
cert = ssl.get_server_certificate((name[:-1], port), ca_certs='/etc/ssl/certs/ca-certificates.crt')
|
cert = ssl.get_server_certificate((name[:-1], port), ca_certs='/etc/ssl/certs/ca-certificates.crt')
|
||||||
|
@ -93,7 +90,6 @@ class TLSA(ResourceRecord):
|
||||||
raise ValueError("Impossible de convertir le certificat au format DER %s %s %s\n%s" % (name, port, proto, cert))
|
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))
|
certhex = TLSA.hashCert(reftype, str(dercert))
|
||||||
self.certhex = certhex
|
|
||||||
if compat:
|
if compat:
|
||||||
super(TLSA, self).__init__(
|
super(TLSA, self).__init__(
|
||||||
'TYPE52',
|
'TYPE52',
|
||||||
|
@ -155,17 +151,13 @@ class TXT(ResourceRecord):
|
||||||
"""Entrée DNS pour un champ TXT"""
|
"""Entrée DNS pour un champ TXT"""
|
||||||
def __init__(self, name, value, ttl=None):
|
def __init__(self, name, value, ttl=None):
|
||||||
super(TXT, self).__init__('TXT', name, value, ttl)
|
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):
|
def __str__(self):
|
||||||
"""Retourne une chaîne printable dans un fichier bind"""
|
"""Retourne une chaîne printable dans un fichier bind"""
|
||||||
if self._ttl:
|
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:
|
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):
|
class CNAME(ResourceRecord):
|
||||||
"""Entrée DNS pour un alias (toto -> redisdead)"""
|
"""Entrée DNS pour un alias (toto -> redisdead)"""
|
||||||
|
@ -398,14 +390,13 @@ class Zone(ZoneBase):
|
||||||
def add_tlsa_record(self, cert):
|
def add_tlsa_record(self, cert):
|
||||||
"""Ajout d'un certif dans le DNS"""
|
"""Ajout d'un certif dans le DNS"""
|
||||||
if 'TLSACert' in cert['objectClass']:
|
if 'TLSACert' in cert['objectClass']:
|
||||||
if not cert.get('revocked', [False])[0]:
|
for host in cert['hostCert']:
|
||||||
for host in cert['hostCert']:
|
nom = self.get_name(host)
|
||||||
nom = self.get_name(host)
|
if nom is None: continue
|
||||||
if nom is None: continue
|
for port in cert['portTCPin']:
|
||||||
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'))
|
||||||
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']:
|
||||||
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'))
|
||||||
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):
|
def add_machine(self, machine):
|
||||||
"""Ajout d'une machine, à savoir chaînage d'ajout
|
"""Ajout d'une machine, à savoir chaînage d'ajout
|
||||||
|
@ -629,12 +620,6 @@ 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 = {
|
NON_CLONABLE_SPFs = {
|
||||||
'crans.org': [
|
'crans.org': [
|
||||||
TXT(short_name(_mx), 'v=spf1 mx:crans.org ~all') for _mx in config.dns.MXs
|
TXT(short_name(_mx), 'v=spf1 mx:crans.org ~all') for _mx in config.dns.MXs
|
||||||
|
@ -688,7 +673,7 @@ class dns(gen_config):
|
||||||
# On met les mêmes MX pour toutes les zones.
|
# On met les mêmes MX pour toutes les zones.
|
||||||
zone.extend(self.MXs)
|
zone.extend(self.MXs)
|
||||||
# Les RR définis ici sont ajoutés aux zones idoines, de façon à se simplifier la vie.
|
# 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, self.DKIM]:
|
for rr_type in [self.SRVs, self.NAPTRs, self.DSs, self.EXTRAS, self.SPFs, self.NON_CLONABLE_SPFs]:
|
||||||
if zone.zone_name in rr_type.keys():
|
if zone.zone_name in rr_type.keys():
|
||||||
zone.extend(rr_type[zone.zone_name])
|
zone.extend(rr_type[zone.zone_name])
|
||||||
for m in machines:
|
for m in machines:
|
||||||
|
|
|
@ -45,13 +45,9 @@ class exemptions(gen_config):
|
||||||
for machine in machines:
|
for machine in machines:
|
||||||
for destination in machine["exempt"]:
|
for destination in machine["exempt"]:
|
||||||
if destination.value.version == 4:
|
if destination.value.version == 4:
|
||||||
if not machine['ipHostNumber']:
|
|
||||||
continue
|
|
||||||
source = str(machine["ipHostNumber"][0])
|
source = str(machine["ipHostNumber"][0])
|
||||||
requete = "INSERT INTO exemptes (ip_crans, ip_dest) VALUES ('%s','%s')" % (source, destination)
|
requete = "INSERT INTO exemptes (ip_crans, ip_dest) VALUES ('%s','%s')" % (source, destination)
|
||||||
else:
|
else:
|
||||||
if not machine['macAddress']:
|
|
||||||
continue
|
|
||||||
source = str(machine["macAddress"][0])
|
source = str(machine["macAddress"][0])
|
||||||
requete = "INSERT INTO exemptes6 (mac_crans, ip_dest) VALUES ('%s','%s')" % (source, destination)
|
requete = "INSERT INTO exemptes6 (mac_crans, ip_dest) VALUES ('%s','%s')" % (source, destination)
|
||||||
# Si ip vide, passons au suivant
|
# Si ip vide, passons au suivant
|
||||||
|
@ -90,8 +86,7 @@ class machines(gen_config):
|
||||||
if not m['macAddress'][0].value == '<automatique>':
|
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))
|
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:
|
elif m.proprio().__class__ == lc_ldap.objets.AssociationCrans:
|
||||||
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))
|
||||||
curseur.execute("INSERT INTO machines (mac_addr, type, id) VALUES ('%s','crans',%s);" % (m['macAddress'][0], m['mid'][0].value))
|
|
||||||
# on commit
|
# on commit
|
||||||
pgsql.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.use_ipset = [self.blacklist_hard, self.test_mac_ip, self.blacklists]
|
||||||
|
|
||||||
self.ipset['mac_ip']={
|
self.ipset['mac_ip']={
|
||||||
'adh' : Ipset("MAC-IP-ADH", "bitmap:ip,mac", "range 138.231.136.0-138.231.151.255"),
|
'adh' : Ipset("MAC-IP-ADH","macipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
||||||
'adm' : Ipset("MAC-IP-ADM", "bitmap:ip,mac", "range 10.231.136.0-10.231.136.255"),
|
'adm' : Ipset("MAC-IP-ADM","macipmap","--from 10.231.136.0 --to 10.231.136.255"),
|
||||||
'app' : Ipset("MAC-IP-APP", "bitmap:ip,mac", "range 10.2.9.0-10.2.9.255"),
|
'app' : Ipset("MAC-IP-APP","macipmap","--from 10.2.9.0 --to 10.2.9.255"),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ipset['blacklist']={
|
self.ipset['blacklist']={
|
||||||
'hard' : Ipset("BLACKLIST-HARD", "hash:ip"),
|
'hard' : Ipset("BLACKLIST-HARD","ipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ class firewall(utils.firewall_tools) :
|
||||||
|
|
||||||
if fill_ipset:
|
if fill_ipset:
|
||||||
# On récupère la liste de toutes les ips blacklistés hard
|
# On récupère la liste de toutes les ips blacklistés hard
|
||||||
bl_hard_ips = self.blacklisted_ips(config.blacklist_sanctions)
|
bl_hard_ips = self.blacklisted_ips(config.blacklist_sanctions, config.NETs['all'])
|
||||||
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['hard'])
|
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['hard'])
|
||||||
self.ipset['blacklist']['hard'].restore(bl_hard_ips)
|
self.ipset['blacklist']['hard'].restore(bl_hard_ips)
|
||||||
print OK
|
print OK
|
||||||
|
@ -131,7 +131,7 @@ class firewall(utils.firewall_tools) :
|
||||||
|
|
||||||
def mac_ip_remove(self, mac, ip):
|
def mac_ip_remove(self, mac, ip):
|
||||||
machine = {'macAddress':[mac], 'ipHostNumber': [ip]}
|
machine = {'macAddress':[mac], 'ipHostNumber': [ip]}
|
||||||
self.test_mac_ip_dispatch(lambda set, data: self.ipset['mac_ip'][set].delete(data), machine)
|
self.test_mac_ip_dispatch(lambda set, data: set.ipset['mac_ip'][set].delete(data), machine)
|
||||||
|
|
||||||
def test_mac_ip_dispatch(self, func, machine):
|
def test_mac_ip_dispatch(self, func, machine):
|
||||||
"""Détermine à quel set de mac-ip appliquer la fonction ``func`` (add, delete, append, ...)"""
|
"""Détermine à quel set de mac-ip appliquer la fonction ``func`` (add, delete, append, ...)"""
|
||||||
|
|
|
@ -21,9 +21,8 @@ firewall = {
|
||||||
'odlyd' : komaz.firewall,
|
'odlyd' : komaz.firewall,
|
||||||
'zamok' : zamok.firewall,
|
'zamok' : zamok.firewall,
|
||||||
'routeur' : routeur.firewall,
|
'routeur' : routeur.firewall,
|
||||||
|
'gordon' : base.firewall_routeur,
|
||||||
'eap' : base.firewall_wifionly,
|
'eap' : base.firewall_wifionly,
|
||||||
'pea' : base.firewall_wifionly,
|
|
||||||
'radius' : base.firewall_wifionly
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if hostname in firewall.keys():
|
if hostname in firewall.keys():
|
||||||
|
|
|
@ -33,21 +33,18 @@ class firewall(base.firewall_routeur):
|
||||||
self.use_tc.extend([self.limitation_debit])
|
self.use_tc.extend([self.limitation_debit])
|
||||||
|
|
||||||
self.ipset['reseaux_non_routable'] = {
|
self.ipset['reseaux_non_routable'] = {
|
||||||
'deny' : base.Ipset("RESEAUX-NON-ROUTABLE-DENY", "hash:net"),
|
'deny' : base.Ipset("RESEAUX-NON-ROUTABLE-DENY","nethash"),
|
||||||
'allow' : base.Ipset("RESEAUX-NON-ROUTABLE-ALLOW", "hash:net"),
|
'allow' : base.Ipset("RESEAUX-NON-ROUTABLE-ALLOW","nethash"),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ipset['blacklist'].update({
|
self.ipset['blacklist'].update({
|
||||||
'soft' : base.Ipset("BLACKLIST-SOFT", "hash:ip"),
|
'soft' : base.Ipset("BLACKLIST-SOFT","ipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
||||||
'upload' : base.Ipset("BLACKLIST-UPLOAD", "hash:ip"),
|
'upload' : base.Ipset("BLACKLIST-UPLOAD","ipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
||||||
})
|
})
|
||||||
|
|
||||||
# Portail captif/blacklist soft: ipset des gens ayant cliqué pour continuer à naviguer
|
# Portail captif/blacklist soft: ipset des gens ayant cliqué pour continuer à naviguer
|
||||||
self.ipset['confirmation'] = base.Ipset("CONFIRMATION", "hash:ip", "")
|
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):
|
def blacklist_maj(self, ips):
|
||||||
"""Mise à jour des blacklistes"""
|
"""Mise à jour des blacklistes"""
|
||||||
self.blacklist_hard_maj(ips)
|
self.blacklist_hard_maj(ips)
|
||||||
|
@ -132,7 +129,6 @@ class firewall(base.firewall_routeur):
|
||||||
self.add(table, chain, '-j %s' % self.ssh_on_https(table))
|
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.connexion_secours(table))
|
||||||
self.add(table, chain, '-j %s' % self.blacklist_soft(table))
|
self.add(table, chain, '-j %s' % self.blacklist_soft(table))
|
||||||
self.add(table, chain, '-j %s' % self.blacklist_hard(table))
|
|
||||||
|
|
||||||
chain = 'POSTROUTING'
|
chain = 'POSTROUTING'
|
||||||
self.add(table, chain, '-j %s' % self.connexion_wififederez(table))
|
self.add(table, chain, '-j %s' % self.connexion_wififederez(table))
|
||||||
|
@ -251,7 +247,6 @@ class firewall(base.firewall_routeur):
|
||||||
if table == 'nat':
|
if table == 'nat':
|
||||||
pretty_print(table, chain)
|
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 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)
|
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
|
print OK
|
||||||
|
|
||||||
|
@ -347,7 +342,7 @@ class firewall(base.firewall_routeur):
|
||||||
|
|
||||||
if fill_ipset:
|
if fill_ipset:
|
||||||
# On récupère la liste de toutes les ips blacklistés soft
|
# On récupère la liste de toutes les ips blacklistés soft
|
||||||
bl_soft_ips = self.blacklisted_ips(base.config.blacklist_sanctions_soft)
|
bl_soft_ips = self.blacklisted_ips(base.config.blacklist_sanctions_soft, base.config.NETs['all'])
|
||||||
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['soft'])
|
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['soft'])
|
||||||
self.ipset['blacklist']['soft'].restore(bl_soft_ips)
|
self.ipset['blacklist']['soft'].restore(bl_soft_ips)
|
||||||
print OK
|
print OK
|
||||||
|
@ -372,41 +367,6 @@ class firewall(base.firewall_routeur):
|
||||||
self.apply(table, chain)
|
self.apply(table, chain)
|
||||||
return 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):
|
def blacklist_upload_maj(self, ip_list):
|
||||||
self.blacklist_upload(fill_ipset=True)
|
self.blacklist_upload(fill_ipset=True)
|
||||||
# for ip in ip_list:
|
# for ip in ip_list:
|
||||||
|
@ -425,7 +385,7 @@ class firewall(base.firewall_routeur):
|
||||||
|
|
||||||
if fill_ipset:
|
if fill_ipset:
|
||||||
# On récupère la liste de toutes les ips blacklistés pour upload
|
# 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)
|
bl_upload_ips = self.blacklisted_ips(base.config.blacklist_bridage_upload, base.config.NETs['all'])
|
||||||
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['upload'])
|
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['upload'])
|
||||||
self.ipset['blacklist']['upload'].restore(bl_upload_ips)
|
self.ipset['blacklist']['upload'].restore(bl_upload_ips)
|
||||||
print OK
|
print OK
|
||||||
|
@ -493,7 +453,6 @@ class firewall(base.firewall_routeur):
|
||||||
|
|
||||||
if table == 'filter':
|
if table == 'filter':
|
||||||
pretty_print(table, chain)
|
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 net in base.config.NETs['serveurs']:
|
||||||
for proto in base.config.firewall.srv_ports_default.keys():
|
for proto in base.config.firewall.srv_ports_default.keys():
|
||||||
if base.config.firewall.srv_ports_default[proto]['output']:
|
if base.config.firewall.srv_ports_default[proto]['output']:
|
||||||
|
@ -584,17 +543,17 @@ class firewall(base.firewall_routeur):
|
||||||
utils.tc("class add dev %s parent 1: classid 1:1 "
|
utils.tc("class add dev %s parent 1: classid 1:1 "
|
||||||
"htb rate %s ceil %s" % (dev[int_key], uplink_speed, uplink_speed))
|
"htb rate %s ceil %s" % (dev[int_key], uplink_speed, uplink_speed))
|
||||||
utils.tc("class add dev %s parent 1:1 classid 1:2 "
|
utils.tc("class add dev %s parent 1:1 classid 1:2 "
|
||||||
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max[int_key], debit_max[int_key]))
|
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max, debit_max))
|
||||||
|
|
||||||
# Classe par defaut
|
# Classe par defaut
|
||||||
utils.tc('class add dev %s parent 1:2 classid 1:10 '
|
utils.tc('class add dev %s parent 1:2 classid 1:10 '
|
||||||
'htb rate %smbit ceil %smbit prio 1' % (dev[int_key], debit_max[int_key], debit_max[int_key]))
|
'htb rate %smbit ceil %smbit prio 1' % (dev[int_key], debit_max, debit_max))
|
||||||
utils.tc('qdisc add dev %s parent 1:10 '
|
utils.tc('qdisc add dev %s parent 1:10 '
|
||||||
'handle 10: sfq perturb 10' % dev[int_key])
|
'handle 10: sfq perturb 10' % dev[int_key])
|
||||||
|
|
||||||
# Classe par pour la voip
|
# Classe par pour la voip
|
||||||
utils.tc('class add dev %s parent 1:2 classid 1:12 '
|
utils.tc('class add dev %s parent 1:2 classid 1:12 '
|
||||||
'htb rate %smbit ceil %smbit prio 0' % (dev[int_key], debit_max[int_key], debit_max[int_key]))
|
'htb rate %smbit ceil %smbit prio 0' % (dev[int_key], debit_max, debit_max))
|
||||||
utils.tc('qdisc add dev %s parent 1:12 '
|
utils.tc('qdisc add dev %s parent 1:12 '
|
||||||
'handle 12: sfq perturb 10' % dev[int_key])
|
'handle 12: sfq perturb 10' % dev[int_key])
|
||||||
|
|
||||||
|
@ -622,7 +581,7 @@ class firewall(base.firewall_routeur):
|
||||||
|
|
||||||
# Classe pour le download des apparetments
|
# Classe pour le download des apparetments
|
||||||
utils.tc("class add dev %s parent 1: classid 1:3 "
|
utils.tc("class add dev %s parent 1: classid 1:3 "
|
||||||
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max['total']/10, debit_max['total']/2))
|
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max/10, debit_max/2))
|
||||||
utils.tc('qdisc add dev %s parent 1:3 '
|
utils.tc('qdisc add dev %s parent 1:3 '
|
||||||
'handle 3: sfq perturb 10' % dev[int_key])
|
'handle 3: sfq perturb 10' % dev[int_key])
|
||||||
|
|
||||||
|
@ -646,7 +605,7 @@ class firewall(base.firewall_routeur):
|
||||||
|
|
||||||
# Classe pour le download wifi federez
|
# Classe pour le download wifi federez
|
||||||
utils.tc("class add dev %s parent 1: classid 1:5 "
|
utils.tc("class add dev %s parent 1: classid 1:5 "
|
||||||
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max['total']/10, debit_max['total']/2))
|
"htb rate %smbit ceil %smbit" % (dev[int_key], debit_max/10, debit_max/2))
|
||||||
utils.tc('qdisc add dev %s parent 1:5 '
|
utils.tc('qdisc add dev %s parent 1:5 '
|
||||||
'handle 3: sfq perturb 10' % dev[int_key])
|
'handle 3: sfq perturb 10' % dev[int_key])
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
if '/usr/scripts' not in sys.path:
|
if '/usr/scripts/' not in sys.path:
|
||||||
sys.path.append('/usr/scripts')
|
sys.path.append('/usr/scripts/')
|
||||||
|
|
||||||
import syslog
|
import syslog
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -55,7 +56,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"""
|
"""Classe de base du pare-feu implémentant l'association mac-ip (pour les machines filaires) et les blacklists hard"""
|
||||||
|
|
||||||
def machines(self):
|
def machines(self):
|
||||||
"""Renvoit la liste de toutes les machines"""
|
"""Renvois la liste de toutes les machines"""
|
||||||
if self._machines:
|
if self._machines:
|
||||||
return self._machines
|
return self._machines
|
||||||
# On utilise allMachinesAdherents car on a besoin que
|
# On utilise allMachinesAdherents car on a besoin que
|
||||||
|
@ -63,37 +64,48 @@ class firewall_tools(object) :
|
||||||
# les blacklistes d'un proprio lorsque l'on regarde les blacklistes
|
# les blacklistes d'un proprio lorsque l'on regarde les blacklistes
|
||||||
# d'une machine
|
# d'une machine
|
||||||
anim('\tChargement des machines')
|
anim('\tChargement des machines')
|
||||||
# On prend toutes les machines y compris celles de ceux qui n'ont pas payé
|
self._machines, self._adherents = self.conn.allMachinesAdherents()
|
||||||
# elles seront ajoutées dans mac_ip mais blacklistées du fait du non paiement ensuite
|
self._adherents = [ adh for adh in self._adherents if adh.paiement_ok() ]
|
||||||
self._machines = self.conn.allMachines()
|
|
||||||
|
|
||||||
print OK
|
print OK
|
||||||
return self._machines
|
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):
|
def blacklisted_machines(self):
|
||||||
"""Renvoit la liste de toutes les machines ayant une blackliste actives"""
|
"""Renvois la liste de toutes les machines ayant une blackliste actives"""
|
||||||
if self._blacklisted_machines:
|
if self._blacklisted_machines:
|
||||||
return self._blacklisted_machines
|
return self._blacklisted_machines
|
||||||
self._blacklisted_machines = [ machine for machine in self.machines() if machine.blacklist_actif() ]
|
self._blacklisted_machines = [ machine for machine in self.machines() if machine.blacklist_actif() ]
|
||||||
return self._blacklisted_machines
|
return self._blacklisted_machines
|
||||||
|
|
||||||
def blacklisted_ips(self, blacklist_sanctions=None):
|
def blacklisted_ips(self, blacklist_sanctions=None, nets=None):
|
||||||
"""Renvoit l'ensemble des ips des machines ayant une blacklist dans blacklist_sanctions et étant dans nets si spécifié"""
|
"""Renvois l'ensemble des ips des machines ayant une blacklist dans blacklist_sanctions et étant dans nets si spécifié"""
|
||||||
bl_ips = set()
|
bl_ips = set()
|
||||||
for machine in self.blacklisted_machines():
|
for machine in self.blacklisted_machines():
|
||||||
if blacklist_sanctions is None or set(bl['type'] for bl in machine.blacklist_actif()).intersection(blacklist_sanctions):
|
if blacklist_sanctions is None or set(bl['type'] for bl in machine.blacklist_actif()).intersection(blacklist_sanctions):
|
||||||
for ip in machine['ipHostNumber']:
|
for ip in machine['ipHostNumber']:
|
||||||
bl_ips.add(str(ip))
|
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))
|
||||||
return bl_ips
|
return bl_ips
|
||||||
|
|
||||||
def blacklisted_adherents(self, excepts=[]):
|
def blacklisted_adherents(self, excepts=[]):
|
||||||
"""Renvoit la liste de tous les adhérents ayant une blackliste active en ignorant les blacklist de excepts"""
|
"""Renvois 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):
|
if self._blacklisted_adherents and self._blacklisted_adherents_type == set(excepts):
|
||||||
return self._blacklisted_adherents
|
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)
|
self._blacklisted_adherents_type = set(excepts)
|
||||||
return self._blacklisted_adherents
|
return self._blacklisted_adherents
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ class firewall(base.firewall):
|
||||||
self.add(table, chain, '-d 127.0.0.1/8 -j RETURN')
|
self.add(table, chain, '-d 127.0.0.1/8 -j RETURN')
|
||||||
for net in base.config.NETs['all']:
|
for net in base.config.NETs['all']:
|
||||||
self.add(table, chain, '-d %s -j RETURN' % net)
|
self.add(table, chain, '-d %s -j RETURN' % net)
|
||||||
for adh in self.blacklisted_adherents(excepts=['paiement']):
|
for adh in self.blacklisted_adherents():
|
||||||
if 'uidNumber' in adh:
|
if 'uidNumber' in adh:
|
||||||
self.add(table, chain, '-m owner --uid-owner %s -j REJECT' % adh['uidNumber'][0])
|
self.add(table, chain, '-m owner --uid-owner %s -j REJECT' % adh['uidNumber'][0])
|
||||||
print OK
|
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 )
|
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
|
# 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 --reject-with icmp6-addr-unreachable' % dev_ip6)
|
ip6tables.filter.forward('-o %s -p tcp -d 2a00:1450:4006::/32 -j REJECT' % dev_ip6)
|
||||||
|
|
||||||
# Ipv6 sur évènementiel, on ne laisse sortir que si ça vient de la mac d'ytrap-llatsni
|
# 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)
|
ip6tables.filter.forward('-o %s -d 2a01:240:fe3d:d2::/64 -j ACCEPT' % dev_crans)
|
||||||
|
|
|
@ -64,7 +64,10 @@ class base_reconfigure:
|
||||||
'warez':__service_develop['blacklist_warez'],
|
'warez':__service_develop['blacklist_warez'],
|
||||||
'ipv6_ra':__service_develop['blacklist_ipv6_ra'],
|
'ipv6_ra':__service_develop['blacklist_ipv6_ra'],
|
||||||
'upload': __service_develop['blacklist_upload'],
|
'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_upload': __service_develop['blacklist_autodisc_upload'],
|
||||||
|
'autodisc_p2p': __service_develop['blacklist_autodisc_p2p'],
|
||||||
'bloq': __service_develop['blacklist_bloq'],
|
'bloq': __service_develop['blacklist_bloq'],
|
||||||
})
|
})
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
|
@ -16,37 +16,31 @@
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if '/usr/scripts' not in sys.path:
|
sys.path.append('/usr/scripts/gestion')
|
||||||
sys.path.append('/usr/scripts')
|
|
||||||
|
|
||||||
import commands
|
import commands
|
||||||
import os
|
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):
|
class IpsetError(Exception):
|
||||||
# Gestion des erreurs d'ipset
|
# Gestion des erreurs d'ipset
|
||||||
def __init__(self, cmd, err_code, output):
|
def __init__(self,cmd,err_code,output):
|
||||||
self.cmd = cmd
|
self.cmd=cmd
|
||||||
self.err_code = err_code
|
self.err_code=err_code
|
||||||
self.output = output
|
self.output=output
|
||||||
def __str__(self):
|
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):
|
class Ipset(object):
|
||||||
ipset = IPSET_PATH
|
ipset="/usr/sbin/ipset"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.set
|
return self.set
|
||||||
|
|
||||||
def __init__(self, set, type, typeopt=''):
|
def __init__(self,set,type,typeopt=''):
|
||||||
self.set = set
|
self.set=set
|
||||||
self.type = type
|
self.type=type
|
||||||
self.typeopt = typeopt
|
self.typeopt=typeopt
|
||||||
|
self.squeeze = os.uname()[2] < '3'
|
||||||
try:
|
try:
|
||||||
self.create()
|
self.create()
|
||||||
except IpsetError as error:
|
except IpsetError as error:
|
||||||
|
@ -56,58 +50,62 @@ class Ipset(object):
|
||||||
raise
|
raise
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def call(self, cmd, arg=''):
|
def call(self,cmd,arg=''):
|
||||||
"""Appel système à ipset"""
|
"""Appel système à ipset"""
|
||||||
cmd_line = "%s %s %s %s" % (self.ipset, cmd, self.set, arg)
|
cmd_line="%s %s %s %s" % (self.ipset,cmd,self.set,arg)
|
||||||
status, output = commands.getstatusoutput(cmd_line)
|
status,output=commands.getstatusoutput(cmd_line)
|
||||||
if status:
|
if status:
|
||||||
raise IpsetError(cmd_line, status, output)
|
raise IpsetError(cmd_line,status,output)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def create(self, opt=''):
|
def create(self,opt=''):
|
||||||
self.call("create", "%s %s" % (self.type, self.typeopt))
|
self.call("-N","%s %s" % (self.type, self.typeopt))
|
||||||
|
|
||||||
def add(self, arg):
|
def add(self,arg):
|
||||||
self.call("add", arg)
|
self.call("-A",arg)
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
output = self.call("list").splitlines()
|
output=self.call("-L").splitlines()
|
||||||
list = []
|
list=[]
|
||||||
for line in output[6:]:
|
for line in output[6:]:
|
||||||
if line == 'Bindings:':
|
if line=='Bindings:':
|
||||||
break
|
break
|
||||||
list.append(line)
|
list.append(line)
|
||||||
return list
|
return list
|
||||||
|
|
||||||
def delete(self, ip):
|
def delete(self,ip):
|
||||||
"""Delete an IP"""
|
"""Delete an IP"""
|
||||||
self.call("del", ip)
|
self.call("-D",ip)
|
||||||
|
|
||||||
def restore(self, rules):
|
def restore(self,rules):
|
||||||
""" restore le set courrant"""
|
""" restore le set courrant"""
|
||||||
rules_str = self.restore_format(rules)
|
rules_str=self.restore_format(rules)
|
||||||
str = "%s\nCOMMIT\n" % rules_str
|
if self.squeeze:
|
||||||
path = '/tmp/ipset_%s' % self.set
|
create_str="-N %s %s %s" % (self.set,self.type,self.typeopt)
|
||||||
f = open(path, 'w+')
|
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+')
|
||||||
f.write(str)
|
f.write(str)
|
||||||
f.close()
|
f.close()
|
||||||
try:
|
try:
|
||||||
self.flush()
|
self.flush()
|
||||||
except IpsetError as error:
|
if self.squeeze:
|
||||||
sys.stderr.write("%s\n" % error)
|
self.destroy()
|
||||||
|
except IpsetError as error: sys.stderr.write("%s\n" % error)
|
||||||
cmd = "cat %s | %s -R" % (path, self.ipset)
|
cmd="cat %s | %s -R" % (path,self.ipset)
|
||||||
status, output = commands.getstatusoutput(cmd)
|
status,output=commands.getstatusoutput(cmd)
|
||||||
if status:
|
if status:
|
||||||
raise IpsetError(cmd, status, output)
|
raise IpsetError(cmd,status,output)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
self.call("flush")
|
self.call("-F")
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
self.call("destroy")
|
self.call("-X")
|
||||||
|
|
||||||
def restore_format(self, rules):
|
def restore_format(self,rules):
|
||||||
return '\n'.join(["add %s %s" % (self.set, data) for data in rules])
|
return '\n'.join(["-A %s %s" % (self.set,data) for data in rules])
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ console inactivity-timer 30
|
||||||
logging {{ s }}
|
logging {{ s }}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
;--- IP du switch ---
|
;--- IP du switch ---
|
||||||
ip default-gateway {{ gateway }}
|
ip default-gateway 10.231.136.4
|
||||||
{%- for vlan in vlans %}
|
{%- for vlan in vlans %}
|
||||||
vlan {{ vlan.id }}
|
vlan {{ vlan.id }}
|
||||||
name "{{ vlan.name|capitalize }}"
|
name "{{ vlan.name|capitalize }}"
|
||||||
|
@ -54,13 +54,12 @@ no web-management
|
||||||
aaa authentication ssh login public-key none
|
aaa authentication ssh login public-key none
|
||||||
aaa authentication ssh enable public-key none
|
aaa authentication ssh enable public-key none
|
||||||
ip ssh
|
ip ssh
|
||||||
ip authorized-managers {{ network_id }} {{ subnet }}
|
ip authorized-managers 10.231.136.0 255.255.255.0
|
||||||
ip ssh filetransfer
|
ip ssh filetransfer
|
||||||
;--- Protection contre les boucles ---
|
;--- Protection contre les boucles ---
|
||||||
loop-protect disable-timer 30
|
loop-protect disable-timer 30
|
||||||
loop-protect transmit-interval 3
|
loop-protect transmit-interval 3
|
||||||
loop-protect {{ non_trusted }}
|
loop-protect {{ non_trusted }}
|
||||||
{%- if not public %}
|
|
||||||
;--- Serveurs radius ---
|
;--- Serveurs radius ---
|
||||||
radius-server dead-time 2
|
radius-server dead-time 2
|
||||||
radius-server key {{ radius_key }}
|
radius-server key {{ radius_key }}
|
||||||
|
@ -69,7 +68,6 @@ radius-server host {{ s }}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
;--- Filtrage mac ---
|
;--- Filtrage mac ---
|
||||||
aaa port-access mac-based addr-format multi-colon
|
aaa port-access mac-based addr-format multi-colon
|
||||||
{%- endif %}
|
|
||||||
;--- Bricoles ---
|
;--- Bricoles ---
|
||||||
no cdp run
|
no cdp run
|
||||||
no stack
|
no stack
|
||||||
|
@ -88,7 +86,7 @@ no ipv6 ra-guard ports {{ trusted }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
;--- Config des prises ---
|
;--- Config des prises ---
|
||||||
{%- for port in ports %}
|
{%- for port in ports %}
|
||||||
{%- if port.radius_auth() and not public %}
|
{%- if port.radius_auth() %}
|
||||||
aaa port-access mac-based {{ port|int }}
|
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 }} addr-limit {{ port.num_mac() }}
|
||||||
aaa port-access mac-based {{ port|int }} logoff-period 3600
|
aaa port-access mac-based {{ port|int }} logoff-period 3600
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
"""
|
"""
|
||||||
Génération de la configuration d'un switch.
|
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 :
|
procédure de configuration initiale :
|
||||||
* mot de passe admin (password manager user-name <username>)
|
* mot de passe admin (password manager user-name <username>)
|
||||||
* activation du ssh (crypto key generate ssh)
|
* activation du ssh (crypto key generate ssh)
|
||||||
|
@ -441,11 +443,7 @@ def format_prises_group(data, first, last):
|
||||||
def pretty_print(hostname):
|
def pretty_print(hostname):
|
||||||
"""Affiche joliement le plan de connexion d'un switch"""
|
"""Affiche joliement le plan de connexion d'un switch"""
|
||||||
bat, sw_num = get_bat_num(hostname)
|
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)
|
port_dict = get_port_dict(switch)
|
||||||
total = max(port_dict.keys())
|
total = max(port_dict.keys())
|
||||||
|
@ -465,11 +463,7 @@ def conf_switch(hostname):
|
||||||
"""Affiche la configuration d'un switch"""
|
"""Affiche la configuration d'un switch"""
|
||||||
bat, sw_num = get_bat_num(hostname)
|
bat, sw_num = get_bat_num(hostname)
|
||||||
|
|
||||||
try:
|
switch = ldap.search(u'host=bat%s-%d.adm.crans.org' % (bat, sw_num))[0]
|
||||||
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__)))
|
tpl_env = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
|
||||||
##for info:
|
##for info:
|
||||||
|
@ -488,6 +482,9 @@ def conf_switch(hostname):
|
||||||
],
|
],
|
||||||
'radius_key': secrets.get('radius_key'),
|
'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 et isc (secondaire) sont les deux seuls serveurs
|
||||||
'dhcp_rid_servers': [34, 160],
|
'dhcp_rid_servers': [34, 160],
|
||||||
|
|
||||||
|
@ -523,24 +520,6 @@ def conf_switch(hostname):
|
||||||
first = netaddr.IPNetwork(net_of_vlan_name(vname)[0]).first
|
first = netaddr.IPNetwork(net_of_vlan_name(vname)[0]).first
|
||||||
data['dhcp_servers'].append(str(netaddr.IPAddress(first + rid)))
|
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
|
# Ra gards ne concerne que les 2620
|
||||||
if "2620" in switch['info'][0].value:
|
if "2620" in switch['info'][0].value:
|
||||||
data['ra_filter'] = True
|
data['ra_filter'] = True
|
||||||
|
@ -569,14 +548,9 @@ def conf_switch(hostname):
|
||||||
V_NO: 'no'}[assign]
|
V_NO: 'no'}[assign]
|
||||||
vlan.setdefault(attr, PortList())
|
vlan.setdefault(attr, PortList())
|
||||||
vlan[attr].extend(p)
|
vlan[attr].extend(p)
|
||||||
if name == 'adm' and not data['public']:
|
if name == 'adm':
|
||||||
vlan['ip_cfg'] = (gethostbyname(hostname), '255.255.255.0')
|
vlan['ip_cfg'] = (gethostbyname(hostname), '255.255.255.0')
|
||||||
if name == 'adherent':
|
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
|
# igmp snooping (multicast) mais nous ne sommes pas querier
|
||||||
vlan['extra'] = 'ip igmp\nno ip igmp querier'
|
vlan['extra'] = 'ip igmp\nno ip igmp querier'
|
||||||
vlans[name] = vlan
|
vlans[name] = vlan
|
||||||
|
|
|
@ -29,10 +29,8 @@ from whos import aff
|
||||||
import signal
|
import signal
|
||||||
import getopt
|
import getopt
|
||||||
from time import strftime, strptime, localtime, mktime, time
|
from time import strftime, strptime, localtime, mktime, time
|
||||||
import datetime
|
|
||||||
from dateutil.relativedelta import relativedelta
|
|
||||||
import re
|
import re
|
||||||
import subprocess
|
|
||||||
import affich_tools
|
import affich_tools
|
||||||
import config
|
import config
|
||||||
import config.cotisation as cotisation
|
import config.cotisation as cotisation
|
||||||
|
@ -41,7 +39,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 crans_ldap, blacklist_items, droits_possibles, droits_critiques, smtpserv, script_utilisateur
|
||||||
from ldap_crans import Adherent, AssociationCrans, Club, Facture
|
from ldap_crans import Adherent, AssociationCrans, Club, Facture
|
||||||
from ldap_crans import Machine, MachineFixe, MachineWifi, MachineCrans, BorneWifi
|
from ldap_crans import Machine, MachineFixe, MachineWifi, MachineCrans, BorneWifi
|
||||||
from ldap_crans import tz, generalizedTimeFormat, fromGeneralizedTimeFormat, datetimeFromGTF, datetimeToGTF, localizedDatetime
|
from ldap_crans import tz, generalizedTimeFormat, fromGeneralizedTimeFormat
|
||||||
import user_tests
|
import user_tests
|
||||||
|
|
||||||
isadm = user_tests.isadm()
|
isadm = user_tests.isadm()
|
||||||
|
@ -54,8 +52,6 @@ iscontroleur = u'Tresorier' in droits
|
||||||
isbureau = u'Bureau' in droits
|
isbureau = u'Bureau' in droits
|
||||||
encoding = sys.stdin.encoding or 'UTF-8'
|
encoding = sys.stdin.encoding or 'UTF-8'
|
||||||
|
|
||||||
NAISSANCE_RE = re.compile(r"(?P<jour>[^ ]*)/(?P<mois>[^ ]*)/(?P<annee>[^ ]*)")
|
|
||||||
|
|
||||||
if u'Nounou' in droits:
|
if u'Nounou' in droits:
|
||||||
# Si on est nounou
|
# Si on est nounou
|
||||||
if os.path.exists(os.path.expanduser('~/.dialogrc')):
|
if os.path.exists(os.path.expanduser('~/.dialogrc')):
|
||||||
|
@ -105,30 +101,22 @@ def set_bases(adher):
|
||||||
arg += u'"Chambre :" 4 1 "%s" 4 11 05 00 ' % adher.chbre()
|
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'"(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'"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
|
# Affichage
|
||||||
annul, result = dialog(arg)
|
annul, result = dialog(arg)
|
||||||
if annul or any([result[i] == '' for i in xrange(len(result))]):
|
if annul:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Traitement
|
# Traitement
|
||||||
err = ''
|
err = ''
|
||||||
try:
|
try: adher.nom(result[0])
|
||||||
adher.nom(result[0])
|
except ValueError, c: err += c.args[0] + '\n'
|
||||||
except ValueError, c:
|
|
||||||
err += c.args[0] + '\n'
|
|
||||||
|
|
||||||
try:
|
try: adher.prenom(result[1])
|
||||||
adher.prenom(result[1])
|
except ValueError, c: err += c.args[0] + '\n'
|
||||||
except ValueError, c:
|
|
||||||
err += c.args[0] + '\n'
|
|
||||||
|
|
||||||
try:
|
try: adher.tel(result[2])
|
||||||
adher.tel(result[2])
|
except ValueError, c: err += c.args[0] + '\n'
|
||||||
except ValueError, c:
|
|
||||||
err += c.args[0] + '\n'
|
|
||||||
|
|
||||||
# Un adhérent du même nom existe-t-il déjà ?
|
# Un adhérent du même nom existe-t-il déjà ?
|
||||||
req = 'nom=' + result[0] + '&prenom=' + result[1]
|
req = 'nom=' + result[0] + '&prenom=' + result[1]
|
||||||
|
@ -140,25 +128,6 @@ def set_bases(adher):
|
||||||
if no:
|
if no:
|
||||||
return 1
|
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])
|
err += _set_chbre(adher, result[3])
|
||||||
|
|
||||||
# Des erreurs ?
|
# Des erreurs ?
|
||||||
|
@ -244,7 +213,6 @@ def set_etudes(adher):
|
||||||
arg += u'"Maximilien Sorre" "" '
|
arg += u'"Maximilien Sorre" "" '
|
||||||
arg += u'"Gustave Eiffel" "" '
|
arg += u'"Gustave Eiffel" "" '
|
||||||
arg += u'"EFREI" "" '
|
arg += u'"EFREI" "" '
|
||||||
arg += u'"ESIGETEL" "" '
|
|
||||||
arg += u'"ESTP" "" '
|
arg += u'"ESTP" "" '
|
||||||
arg += u'"P1" "Université Panthéon Sorbonne" '
|
arg += u'"P1" "Université Panthéon Sorbonne" '
|
||||||
arg += u'"P2" "Université Panthéon Assas" '
|
arg += u'"P2" "Université Panthéon Assas" '
|
||||||
|
@ -456,12 +424,9 @@ def set_contact(adher):
|
||||||
if result[0].split()[0] == 'Laisser':
|
if result[0].split()[0] == 'Laisser':
|
||||||
break
|
break
|
||||||
elif result[0].split()[1] == u'un':
|
elif result[0].split()[1] == u'un':
|
||||||
if not set_compte(adher):
|
if not set_compte(adher): break
|
||||||
set_mail_ext(adher)
|
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
if not set_mail(adher):
|
if not set_mail(adher): break
|
||||||
break
|
|
||||||
|
|
||||||
def set_mail(adher):
|
def set_mail(adher):
|
||||||
"""Demande l'adresse mail extérieure d'un adhérent
|
"""Demande l'adresse mail extérieure d'un adhérent
|
||||||
|
@ -829,13 +794,7 @@ def del_adher(adher):
|
||||||
arg += u'--msgbox "Le commentaire est obligatoire\n\n\n" 0 0'
|
arg += u'--msgbox "Le commentaire est obligatoire\n\n\n" 0 0'
|
||||||
dialog(arg)
|
dialog(arg)
|
||||||
|
|
||||||
try:
|
adher.delete(res[0])
|
||||||
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'--title "Destruction adhérent" '
|
||||||
arg += u'--msgbox "Adhérent détruit\n\n\n" 0 0'
|
arg += u'--msgbox "Adhérent détruit\n\n\n" 0 0'
|
||||||
|
@ -1090,18 +1049,18 @@ def set_solde(clas):
|
||||||
annul, comment = dialog(arg)
|
annul, comment = dialog(arg)
|
||||||
|
|
||||||
if not annul:
|
if not annul:
|
||||||
if comment:
|
if comment[0]:
|
||||||
comment = comment[0]
|
comment = comment[0]
|
||||||
else:
|
else:
|
||||||
comment = ''
|
comment = None
|
||||||
|
|
||||||
f = Facture(clas)
|
f = Facture(clas)
|
||||||
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.ajoute({'nombre': 1, 'code':'SOLDE', 'designation': "Modification du solde par un imprimeur. Moyen de paiement: %s, remarque: %s" % (_mode, comment), 'pu': _montant})
|
||||||
f.modePaiement(_mode.lower())
|
f.modePaiement(_mode.lower())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Met aussi à jour le solde.
|
# Met aussi à jour le solde.
|
||||||
f.recuPaiement(datetimeToGTF(localizedDatetime()))
|
f.recuPaiement(strftime("%Y-%m-%d %H:%M:%S"))
|
||||||
f.save()
|
f.save()
|
||||||
db.services_to_restart('mail_solde', [
|
db.services_to_restart('mail_solde', [
|
||||||
'%s a fait %s euros pour %s [mode: %s, remarque: %s]' %
|
'%s a fait %s euros pour %s [mode: %s, remarque: %s]' %
|
||||||
|
@ -1115,7 +1074,6 @@ def set_solde(clas):
|
||||||
arg = u'--title "%s du solde de %s" ' % (_kword, clas.Nom())
|
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(),)
|
arg += u'--msgbox "Modification effectuée, merci de noter le numéro de facture %s." 0 0' % (f.numero(),)
|
||||||
dialog(arg)
|
dialog(arg)
|
||||||
break
|
|
||||||
|
|
||||||
def set_vente(proprio):
|
def set_vente(proprio):
|
||||||
u"""
|
u"""
|
||||||
|
@ -1203,7 +1161,6 @@ def set_vente(proprio):
|
||||||
menu.append(u'"Spc" "Espèces" ')
|
menu.append(u'"Spc" "Espèces" ')
|
||||||
menu.append(u'"Chq" "Chèque" ')
|
menu.append(u'"Chq" "Chèque" ')
|
||||||
menu.append(u'"Cb" "Carte bancaire" ')
|
menu.append(u'"Cb" "Carte bancaire" ')
|
||||||
menu.append(u'"Note" "Note Kfet (attention, moins traçable)" ')
|
|
||||||
if isimprimeur and proprio.solde() - f.total() > 0:
|
if isimprimeur and proprio.solde() - f.total() > 0:
|
||||||
menu.append(u'"Sol" "Solde Crans (actuel : %s€)" ' % (proprio.solde()))
|
menu.append(u'"Sol" "Solde Crans (actuel : %s€)" ' % (proprio.solde()))
|
||||||
|
|
||||||
|
@ -1230,10 +1187,6 @@ def set_vente(proprio):
|
||||||
f.modePaiement('cheque')
|
f.modePaiement('cheque')
|
||||||
paiement = u"Chèque"
|
paiement = u"Chèque"
|
||||||
annul, comment = dialog(arg)
|
annul, comment = dialog(arg)
|
||||||
elif result[0] == "Note":
|
|
||||||
f.modePaiement('note')
|
|
||||||
paiement = u"Note"
|
|
||||||
annul, comment = dialog(arg)
|
|
||||||
elif result[0] == "Sol" and isimprimeur:
|
elif result[0] == "Sol" and isimprimeur:
|
||||||
f.modePaiement('solde')
|
f.modePaiement('solde')
|
||||||
paiement = u"Solde Crans"
|
paiement = u"Solde Crans"
|
||||||
|
@ -1257,15 +1210,8 @@ def set_vente(proprio):
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
f.recuPaiement(datetimeToGTF(localizedDatetime()))
|
f.recuPaiement(strftime("%Y-%m-%d %H:%M:%S"))
|
||||||
f.save()
|
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'--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([
|
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'])
|
"%s %s" % (art['nombre'], art['designation'])
|
||||||
|
@ -1304,26 +1250,9 @@ def confirm(clas):
|
||||||
return 1
|
return 1
|
||||||
try:
|
try:
|
||||||
res = clas.save()
|
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:
|
if in_facture is not None:
|
||||||
in_facture.recuPaiement(datetimeToGTF(localizedDatetime()))
|
in_facture.recuPaiement(strftime("%Y-%m-%d %H:%M:%S"))
|
||||||
in_facture.save()
|
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:
|
except Exception as c:
|
||||||
arg = u'--title "Enregistrement" '
|
arg = u'--title "Enregistrement" '
|
||||||
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(unicode(c.args[0]))
|
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(unicode(c.args[0]))
|
||||||
|
@ -1331,6 +1260,9 @@ def confirm(clas):
|
||||||
return 1
|
return 1
|
||||||
in_facture = None
|
in_facture = None
|
||||||
|
|
||||||
|
cprint(res)
|
||||||
|
affich_tools.prompt(u"Appuyez sur ENTREE pour continuer")
|
||||||
|
|
||||||
def set_blackliste(clas):
|
def set_blackliste(clas):
|
||||||
u""" Édite ou ajoute un item de la blackliste """
|
u""" Édite ou ajoute un item de la blackliste """
|
||||||
bl = clas.blacklist()
|
bl = clas.blacklist()
|
||||||
|
@ -1562,9 +1494,6 @@ def set_adhesion(proprio):
|
||||||
facture.modePaiement(_mode.lower())
|
facture.modePaiement(_mode.lower())
|
||||||
break
|
break
|
||||||
in_facture = facture
|
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):
|
def set_connexion(proprio):
|
||||||
"""Maj de la période d'accès de l'adhérent"""
|
"""Maj de la période d'accès de l'adhérent"""
|
||||||
|
@ -1572,16 +1501,12 @@ 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.
|
# 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()
|
adhEnd = proprio.adhesion()
|
||||||
|
|
||||||
if in_facture is not None:
|
if in_facture is not None:
|
||||||
adhEnd = max(adhEnd, fromGeneralizedTimeFormat(in_facture._data.get('finAdhesion', ["19700101000000Z"])[0]))
|
adhEnd = max(adhEnd, fromGeneralizedTimeFormat(in_facture._data.get('finAdhesion', ["19700101000000Z"])[0]))
|
||||||
|
if adhEnd < time():
|
||||||
if adhEnd - cotisation.delai_readh < time():
|
|
||||||
stat = set_adhesion(proprio)
|
stat = set_adhesion(proprio)
|
||||||
|
if stat == 1:
|
||||||
if stat == 1 and adhEnd < time():
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if in_facture is not None:
|
if in_facture is not None:
|
||||||
adhEnd = max(adhEnd, fromGeneralizedTimeFormat(in_facture._data.get('finAdhesion', ["19700101000000Z"])[0]))
|
adhEnd = max(adhEnd, fromGeneralizedTimeFormat(in_facture._data.get('finAdhesion', ["19700101000000Z"])[0]))
|
||||||
|
|
||||||
|
@ -1596,7 +1521,7 @@ def set_connexion(proprio):
|
||||||
while True:
|
while True:
|
||||||
args = u'--title "Connexion de %s" ' % proprio.Nom()
|
args = u'--title "Connexion de %s" ' % proprio.Nom()
|
||||||
if proprio.connexion() > time():
|
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", localtime(proprio.connexion())),)
|
args += u'--menu "Connexion jusqu\'au %s, choisir une durée de prolongation. : " 0 0 0 ' % (strftime("%d/%m/%Y %H:%M:%S"),)
|
||||||
else:
|
else:
|
||||||
args += u'--menu "Connexion actuellement inactive, choisir une durée. : " 0 0 0 '
|
args += u'--menu "Connexion actuellement inactive, choisir une durée. : " 0 0 0 '
|
||||||
args += u'"An" "Prolonger d\'un an." '
|
args += u'"An" "Prolonger d\'un an." '
|
||||||
|
@ -1606,8 +1531,7 @@ def set_connexion(proprio):
|
||||||
annul, res = dialog(args)
|
annul, res = dialog(args)
|
||||||
|
|
||||||
if annul:
|
if annul:
|
||||||
if in_facture is not None:
|
in_facture.supprime(pop=True)
|
||||||
in_facture.supprime(pop=True)
|
|
||||||
return 1
|
return 1
|
||||||
res = res[0]
|
res = res[0]
|
||||||
if res == "An":
|
if res == "An":
|
||||||
|
@ -1657,17 +1581,17 @@ def set_connexion(proprio):
|
||||||
newEnd = fromGeneralizedTimeFormat(facture._data.get('finConnexion', ["19700101000000Z"])[0])
|
newEnd = fromGeneralizedTimeFormat(facture._data.get('finConnexion', ["19700101000000Z"])[0])
|
||||||
if newEnd > adhEnd:
|
if newEnd > adhEnd:
|
||||||
arg = u'--title "Avertissement" '
|
arg = u'--title "Avertissement" '
|
||||||
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)
|
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)), )
|
||||||
annul, res = dialog(arg)
|
no, res = dialog(arg)
|
||||||
if annul:
|
if no:
|
||||||
facture._set('finConnexion', [])
|
facture._set('finConnexion', [])
|
||||||
facture._set('debutConnexion', [])
|
facture._set('debutConnexion', [])
|
||||||
facture.supprime(pop=True)
|
facture.supprime(pop=True)
|
||||||
break
|
continue
|
||||||
|
|
||||||
if not facture.modePaiement():
|
if not facture.modePaiement():
|
||||||
arg = u'--title "Mode de paiement pour la connexion de %s" ' % (proprio.Nom(),)
|
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'"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'"Cheque" "Par chèque : ne pas oublier de vérifier signature, date, ordre et montant." '
|
||||||
arg += u'"Carte" "Par CB : tromboner le ticket." '
|
arg += u'"Carte" "Par CB : tromboner le ticket." '
|
||||||
|
@ -1694,10 +1618,6 @@ def set_connexion(proprio):
|
||||||
break
|
break
|
||||||
in_facture = facture
|
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
|
## Fonctions de remplissage ou modification des paramètres club
|
||||||
|
|
||||||
|
@ -1858,7 +1778,7 @@ def set_facture_recu(facture):
|
||||||
if annul:
|
if annul:
|
||||||
return 1
|
return 1
|
||||||
if u"Pmt" in res:
|
if u"Pmt" in res:
|
||||||
facture.recuPaiement(datetimeToGTF(localizedDatetime()))
|
facture.recuPaiement(strftime("%Y-%m-%d %H:%M:%S"))
|
||||||
else:
|
else:
|
||||||
facture.recuPaiement(False)
|
facture.recuPaiement(False)
|
||||||
|
|
||||||
|
@ -2184,10 +2104,8 @@ def new_adher(adher):
|
||||||
4 etapes :
|
4 etapes :
|
||||||
* set_bases
|
* set_bases
|
||||||
* set_etudes
|
* set_etudes
|
||||||
* set_adhesion
|
* set_admin
|
||||||
* set_connexion
|
|
||||||
* set_contact
|
* set_contact
|
||||||
(qui appelle set_mail_ext si on met un compte crans)
|
|
||||||
* set_rque
|
* set_rque
|
||||||
Retourne 1 si annulation.
|
Retourne 1 si annulation.
|
||||||
"""
|
"""
|
||||||
|
@ -2199,16 +2117,15 @@ def new_adher(adher):
|
||||||
set_etudes,
|
set_etudes,
|
||||||
set_adhesion,
|
set_adhesion,
|
||||||
set_connexion,
|
set_connexion,
|
||||||
|
set_admin,
|
||||||
set_contact,
|
set_contact,
|
||||||
|
set_mail_ext,
|
||||||
set_rque,
|
set_rque,
|
||||||
]
|
]
|
||||||
|
|
||||||
step = 0
|
step = 0
|
||||||
while step < len(steps):
|
while step < len(steps):
|
||||||
if steps[step](adher):
|
if steps[step](adher): step -= 1
|
||||||
if step == 0:
|
|
||||||
return 1
|
|
||||||
step -= 1
|
|
||||||
else: step += 1
|
else: step += 1
|
||||||
|
|
||||||
if not confirm(adher): break
|
if not confirm(adher): break
|
||||||
|
@ -2238,8 +2155,7 @@ def modif_adher(adher):
|
||||||
arg += u'--menu "Que souhaitez vous modifier ?" 0 0 0 '
|
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'"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'"Adhesion" "Pour toute réadhésion *sans* connexion." '
|
||||||
if isadm or isbureau:
|
arg += u'"Administratif" "Pour renseigner la fournitire de la charte des MA." '
|
||||||
arg += u'"Administratif" "Pour renseigner la fourniture de la charte des MA." '
|
|
||||||
arg += u'"Etat-civil" "Nom, prénom" '
|
arg += u'"Etat-civil" "Nom, prénom" '
|
||||||
if adher.chbre() == 'EXT':
|
if adher.chbre() == 'EXT':
|
||||||
arg += u'"Adresse" "Déménagement" '
|
arg += u'"Adresse" "Déménagement" '
|
||||||
|
@ -2251,7 +2167,7 @@ def modif_adher(adher):
|
||||||
arg += u'"Mail" "Créer un compte ou changer l\'adresse mail de contact" '
|
arg += u'"Mail" "Créer un compte ou changer l\'adresse mail de contact" '
|
||||||
if 'cransAccount' in adher._data['objectClass']:
|
if 'cransAccount' in adher._data['objectClass']:
|
||||||
arg += u'"MailExt" "Ajouter une adresse mail de contact extérieur." '
|
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'"GPGFingerprint" "Ajouter ou supprimer une empreinte GPG" '
|
||||||
arg += u'"Remarque" "Ajouter ou modifer un commentaire" '
|
arg += u'"Remarque" "Ajouter ou modifer un commentaire" '
|
||||||
if isadm or isbureau:
|
if isadm or isbureau:
|
||||||
|
@ -2263,7 +2179,7 @@ def modif_adher(adher):
|
||||||
arg += u'"Shell" "Changer le shell de cet utilisateur" '
|
arg += u'"Shell" "Changer le shell de cet utilisateur" '
|
||||||
if isdeconnecteur:
|
if isdeconnecteur:
|
||||||
arg += u'"Blackliste" "Modifier la blackliste de cet adhérent" '
|
arg += u'"Blackliste" "Modifier la blackliste de cet adhérent" '
|
||||||
if isimprimeur and adher.compte():
|
if isimprimeur:
|
||||||
arg += u'"Solde" "Effectuer un débit/crédit pour cet adhérent" '
|
arg += u'"Solde" "Effectuer un débit/crédit pour cet adhérent" '
|
||||||
arg += u'"Vente" "Vendre un cable ou adaptateur ethernet ou autre" '
|
arg += u'"Vente" "Vendre un cable ou adaptateur ethernet ou autre" '
|
||||||
|
|
||||||
|
@ -2320,15 +2236,13 @@ def modif_adher(adher):
|
||||||
arg += u'--msgbox "Vous n\'avez pas les droits necessaires pour effectuer cette opération.\n\n\n" 0 0'
|
arg += u'--msgbox "Vous n\'avez pas les droits necessaires pour effectuer cette opération.\n\n\n" 0 0'
|
||||||
dialog(arg)
|
dialog(arg)
|
||||||
return modif_adher(adher)
|
return modif_adher(adher)
|
||||||
|
|
||||||
arg = u'--title "Départ de %s" ' % adher.Nom()
|
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'--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'
|
arg += u'\nDoit-on continuer ?" 0 0'
|
||||||
no, res = dialog(arg)
|
no, res = dialog(arg)
|
||||||
|
if no: return modif_adher(adher)
|
||||||
if no:
|
for m in adher.machines():
|
||||||
return modif_adher(adher)
|
m.delete("Depart du campus")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
adher.delete("Depart du campus")
|
adher.delete("Depart du campus")
|
||||||
except EnvironmentError, c:
|
except EnvironmentError, c:
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
#!/usr/bin/env python2.7
|
#!/usr/bin/env python2.7
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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
|
import os
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#!/bin/bash /usr/scripts/python.sh
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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
|
"""Ce sont les variables utiles pour les autres scripts du
|
||||||
module"""
|
module"""
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#!/bin/bash /usr/scripts/python.sh
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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
|
"""Contient les outils pour manipuler des adresses MAC
|
||||||
dans le module hptools"""
|
dans le module hptools"""
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#!/bin/bash /usr/scripts/python.sh
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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 la définition et les outils pour bosser avec
|
"""Contient la définition et les outils pour bosser avec
|
||||||
les ports.
|
les ports.
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#!/bin/bash /usr/scripts/python.sh
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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 fichier propose un client snmp basique"""
|
"""Ce fichier propose un client snmp basique"""
|
||||||
|
|
||||||
import netsnmp
|
import netsnmp
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#!/bin/bash /usr/scripts/python.sh
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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.
|
|
||||||
"""Outils principaux pour la description d'un switch"""
|
"""Outils principaux pour la description d'un switch"""
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
|
@ -65,7 +51,7 @@ class HPSwitch(object):
|
||||||
try:
|
try:
|
||||||
netaddr.IPAddress(switch)
|
netaddr.IPAddress(switch)
|
||||||
except netaddr.AddrFormatError:
|
except netaddr.AddrFormatError:
|
||||||
raise SwitchNotFound("Switch %r non trouvé." % (switch,))
|
raise SwitchNotFound
|
||||||
|
|
||||||
switch_object = HPSwitchFactory.get_switch(__switch)
|
switch_object = HPSwitchFactory.get_switch(__switch)
|
||||||
if switch_object is None:
|
if switch_object is None:
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#!/bin/bash /usr/scripts/python.sh
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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.
|
|
||||||
"""Fournit des outils et fonctions appelables au besoin"""
|
"""Fournit des outils et fonctions appelables au besoin"""
|
||||||
|
|
||||||
from gestion import annuaires_pg
|
from gestion import annuaires_pg
|
||||||
|
@ -75,16 +61,10 @@ def fetch_all_ports(switch, output):
|
||||||
__stuff = filter_uplink(switch, __stuff)
|
__stuff = filter_uplink(switch, __stuff)
|
||||||
output[switch] = __stuff
|
output[switch] = __stuff
|
||||||
|
|
||||||
def populate_all_switches(switches=None):
|
def populate_all_switches():
|
||||||
"""Remplit l'ensemble des switches avec les MACS qui sont
|
"""Remplit l'ensemble des switches avec les MACS qui sont
|
||||||
présentes sur leurs ports.
|
présentes sur leurs ports"""
|
||||||
|
switches = annuaires_pg.all_switchs()
|
||||||
Peut également ne remplir qu'une liste spécifique si fournie
|
|
||||||
en argument."""
|
|
||||||
|
|
||||||
if switches == None:
|
|
||||||
switches = annuaires_pg.all_switchs()
|
|
||||||
|
|
||||||
hp_switches = {
|
hp_switches = {
|
||||||
switch : HPSwitch(switch)
|
switch : HPSwitch(switch)
|
||||||
for switch in switches
|
for switch in switches
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
import sys
|
import sys
|
||||||
import os, re, syslog, cPickle, socket
|
import os, re, syslog, cPickle, socket
|
||||||
|
|
||||||
from ldap_crans import crans_ldap, hostname, generalizedTimeFormat
|
from ldap_crans import crans_ldap, hostname
|
||||||
from commands import getstatusoutput
|
from commands import getstatusoutput
|
||||||
from config import NETs, role, prefix, rid, output_file, filter_policy, rid_primaires
|
from config import NETs, role, prefix, rid, output_file, filter_policy, rid_primaires
|
||||||
from config import blacklist_sanctions, blacklist_sanctions_soft, blacklist_bridage_upload, file_pickle, periode_transitoire, gtf_debut_periode_transitoire
|
from config import blacklist_sanctions, blacklist_sanctions_soft, blacklist_bridage_upload, file_pickle, ann_scol, periode_transitoire
|
||||||
from iptools import AddrInNet
|
from iptools import AddrInNet
|
||||||
from ridtools import Rid, find_rid_plage
|
from ridtools import Rid, find_rid_plage
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -768,13 +768,9 @@ def blacklist(ipt):
|
||||||
if [x for x in sanctions if x in blacklist_sanctions_ipv6]:
|
if [x for x in sanctions if x in blacklist_sanctions_ipv6]:
|
||||||
blcklst.extend(target.machines())
|
blcklst.extend(target.machines())
|
||||||
|
|
||||||
s = db.search('mblacklist=*&finConnexion>=%(fin)s&finAdhesion>=%(fin)s' % {
|
s = db.search('mblacklist=*&paiement=%s' % ann_scol)
|
||||||
'fin': generalizedTimeFormat(),
|
|
||||||
})
|
|
||||||
if periode_transitoire:
|
if periode_transitoire:
|
||||||
s['machine'].extend(db.search('mblacklist=*&finConnexion>=%(fin)s&finAdhsion>=%(fin)s' % {
|
s['machine'].extend(db.search('mblacklist=*&paiement=%s' % (ann_scol-1))['machine'])
|
||||||
'fin': gtf_debut_periode_transitoire,
|
|
||||||
})['machine'])
|
|
||||||
|
|
||||||
for target in s['machine']:
|
for target in s['machine']:
|
||||||
sanctions = target.blacklist_actif()
|
sanctions = target.blacklist_actif()
|
||||||
|
|
|
@ -26,7 +26,7 @@ import ldap.modlist
|
||||||
import ldap_passwd
|
import ldap_passwd
|
||||||
import netaddr
|
import netaddr
|
||||||
import traceback
|
import traceback
|
||||||
import subprocess
|
|
||||||
import annuaires_pg as annuaires
|
import annuaires_pg as annuaires
|
||||||
import config
|
import config
|
||||||
import config.impression
|
import config.impression
|
||||||
|
@ -47,16 +47,6 @@ import ridtools
|
||||||
from user_tests import isadm
|
from user_tests import isadm
|
||||||
import getpass
|
import getpass
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
import dateutil.tz
|
|
||||||
except:
|
|
||||||
dateutil = None
|
|
||||||
|
|
||||||
cur_user = os.getenv("SUDO_USER") or os.getenv("USER") or os.getenv("LOGNAME") or getpass.getuser()
|
cur_user = os.getenv("SUDO_USER") or os.getenv("USER") or os.getenv("LOGNAME") or getpass.getuser()
|
||||||
|
|
||||||
date_format = '%d/%m/%Y %H:%M'
|
date_format = '%d/%m/%Y %H:%M'
|
||||||
|
@ -119,7 +109,7 @@ blacklist_items = config.blacklist_items
|
||||||
### Droits possibles
|
### Droits possibles
|
||||||
droits_possibles = [u'Multimachines', u'Cableur', u'Imprimeur', u'Apprenti',
|
droits_possibles = [u'Multimachines', u'Cableur', u'Imprimeur', u'Apprenti',
|
||||||
u'Webmaster', u'Moderateur', u'Webradio',
|
u'Webmaster', u'Moderateur', u'Webradio',
|
||||||
u'Nounou', u'Tresorier', u'Bureau']
|
u'Nounou', u'Tresorier', u'Bureau', u'Troll']
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
### Droits critiques, ie que seules les nounous peuvent attribuer
|
### Droits critiques, ie que seules les nounous peuvent attribuer
|
||||||
|
@ -134,6 +124,7 @@ droits_vieux = [u'Nounou', u'Bureau']
|
||||||
### Variables internes diverses
|
### Variables internes diverses
|
||||||
#isadm = user_tests.isadm()
|
#isadm = user_tests.isadm()
|
||||||
#isdeconnecteur = user_tests.isdeconnecteur()
|
#isdeconnecteur = user_tests.isdeconnecteur()
|
||||||
|
ann_scol = config.ann_scol
|
||||||
#script_utilisateur = user_tests.getuser()
|
#script_utilisateur = user_tests.getuser()
|
||||||
script_utilisateur = cur_user
|
script_utilisateur = cur_user
|
||||||
|
|
||||||
|
@ -158,15 +149,12 @@ def tz(thetz):
|
||||||
else:
|
else:
|
||||||
return "%s%04d" % ("+"*(thetz < 0) + "-"*(thetz > 0), abstz)
|
return "%s%04d" % ("+"*(thetz < 0) + "-"*(thetz > 0), abstz)
|
||||||
|
|
||||||
def generalizedTimeFormat(stamp=None):
|
def generalizedTimeFormat(stamp):
|
||||||
"""Converts a timestamp (local) in a generalized time format
|
"""Converts a timestamp (local) in a generalized time format
|
||||||
for LDAP
|
for LDAP
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if stamp is None:
|
|
||||||
stamp = time.time()
|
|
||||||
|
|
||||||
return "%s%s" % (time.strftime("%Y%m%d%H%M%S", time.localtime(stamp)), tz(time.altzone/3600))
|
return "%s%s" % (time.strftime("%Y%m%d%H%M%S", time.localtime(stamp)), tz(time.altzone/3600))
|
||||||
|
|
||||||
def fromGeneralizedTimeFormat(gtf):
|
def fromGeneralizedTimeFormat(gtf):
|
||||||
|
@ -175,60 +163,6 @@ def fromGeneralizedTimeFormat(gtf):
|
||||||
"""
|
"""
|
||||||
return time.mktime(time.strptime(gtf.split("-", 1)[0].split("+", 1)[0].split('Z', 1)[0], "%Y%m%d%H%M%S"))
|
return time.mktime(time.strptime(gtf.split("-", 1)[0].split("+", 1)[0].split('Z', 1)[0], "%Y%m%d%H%M%S"))
|
||||||
|
|
||||||
def datetimeFromGTF(gtf):
|
|
||||||
"""Returns a datetime from generalized time format
|
|
||||||
|
|
||||||
"""
|
|
||||||
if '-' in gtf or '+' in gtf:
|
|
||||||
date, tz = gtf[0:14], gtf[14:]
|
|
||||||
else:
|
|
||||||
date = gtf.replace("Z", '')
|
|
||||||
tz = '+0000'
|
|
||||||
return localizedDatetime(date, tz)
|
|
||||||
|
|
||||||
def datetimeToGTF(datetime_obj):
|
|
||||||
"""Transforms a datetime to a GTF"""
|
|
||||||
to_append = ""
|
|
||||||
if datetime_obj.utcoffset() is None:
|
|
||||||
if pytz is not None:
|
|
||||||
datetime_obj = pytz.utc.localize(datetime_obj)
|
|
||||||
else:
|
|
||||||
to_append = "Z"
|
|
||||||
mostly_gtf = datetime.datetime.strftime(datetime_obj, "%Y%m%d%H%M%S%z")
|
|
||||||
return mostly_gtf.replace('+0000', "Z") + to_append
|
|
||||||
|
|
||||||
def localizedDatetime(date=None, tz=None):
|
|
||||||
"""Génère un datetime localisé à partir d'une chaîne de la forme
|
|
||||||
%Y%m%d%H%M%S, et d'une chaîne tz de la forme +0200"""
|
|
||||||
|
|
||||||
_notz = (tz is None)
|
|
||||||
|
|
||||||
if date is not None:
|
|
||||||
the_date = datetime.datetime.strptime(date, "%Y%m%d%H%M%S")
|
|
||||||
else:
|
|
||||||
the_date = datetime.datetime.now()
|
|
||||||
|
|
||||||
# No timezone means we try to get from the system
|
|
||||||
# if we have dateutil, else, UTC.
|
|
||||||
if tz is None:
|
|
||||||
if dateutil is not None:
|
|
||||||
tz = datetime.datetime.now(dateutil.tz.tzlocal()).strftime("%z")
|
|
||||||
else:
|
|
||||||
tz = "+0000"
|
|
||||||
|
|
||||||
# No pytz means no timezoned datetime
|
|
||||||
if pytz is not None:
|
|
||||||
the_timezone = pytz.FixedOffset(int(tz[0:-2])*60 + int(tz[-2:]))
|
|
||||||
the_date = the_timezone.localize(the_date)
|
|
||||||
the_date = the_timezone.normalize(the_date)
|
|
||||||
else:
|
|
||||||
# Maybe we can do something
|
|
||||||
if dateutil is not None:
|
|
||||||
if _notz:
|
|
||||||
the_date.replace(tzinfo=dateutil.tz.tzlocal())
|
|
||||||
|
|
||||||
return the_date
|
|
||||||
|
|
||||||
def strip_accents(a, sois_un_porc_avec_les_espaces = True):
|
def strip_accents(a, sois_un_porc_avec_les_espaces = True):
|
||||||
""" Supression des accents de la chaîne fournie """
|
""" Supression des accents de la chaîne fournie """
|
||||||
res = normalize('NFKD', decode(a)).encode('ASCII', 'ignore')
|
res = normalize('NFKD', decode(a)).encode('ASCII', 'ignore')
|
||||||
|
@ -409,7 +343,7 @@ class Service:
|
||||||
starting = self.start
|
starting = self.start
|
||||||
starting.sort()
|
starting.sort()
|
||||||
dates = u' et '.join(map(lambda t: t < time.time() and \
|
dates = u' et '.join(map(lambda t: t < time.time() and \
|
||||||
u"maintenant" or time.strftime(date_format_new,
|
u"maintenant" or time.strftime(date_format,
|
||||||
time.localtime(t)),
|
time.localtime(t)),
|
||||||
self.start))
|
self.start))
|
||||||
dates = u" à partir d%s %s" % (dates.startswith(u"maintenant") and u"e" or u"u",
|
dates = u" à partir d%s %s" % (dates.startswith(u"maintenant") and u"e" or u"u",
|
||||||
|
@ -804,7 +738,7 @@ class CransLdap:
|
||||||
result[i] = []
|
result[i] = []
|
||||||
|
|
||||||
# Fonction utile
|
# Fonction utile
|
||||||
def build_filtre(champ, expr, neg=False, comp=''):
|
def build_filtre(champ, expr, neg=False):
|
||||||
"""
|
"""
|
||||||
Retourne une chaine pour recherche dans la base LDAP
|
Retourne une chaine pour recherche dans la base LDAP
|
||||||
du style (champ=expr) en adaptant les valeurs de expr au champ.
|
du style (champ=expr) en adaptant les valeurs de expr au champ.
|
||||||
|
@ -835,20 +769,16 @@ class CransLdap:
|
||||||
# définifif (cf config.py).
|
# définifif (cf config.py).
|
||||||
if config.periode_transitoire:
|
if config.periode_transitoire:
|
||||||
# Pour la période transitoire année précédente ok
|
# Pour la période transitoire année précédente ok
|
||||||
el = "(&(finAdhesion>=%(fin)s)(finConnexion>=%(fin)s))" % {
|
el = "(|(paiement=%d)(paiement=%d)(finAdhesion>=%s))" % (config.ann_scol, config.ann_scol-1, generalizedTimeFormat(time.time()))
|
||||||
'fin': config.gtf_debut_periode_transitoire,
|
|
||||||
}
|
|
||||||
else:
|
else:
|
||||||
el = "(&(finAdhesion>=%(fin)s)(finConnexion>=%(fin)s))" % {
|
el = "(|(paiement=%s)(finAdhesion>=%s))" % (config.ann_scol, generalizedTimeFormat(time.time()))
|
||||||
'fin': generalizedTimeFormat(),
|
|
||||||
}
|
|
||||||
# Doit-on bloquer en cas de manque de la carte d'etudiant ?
|
# Doit-on bloquer en cas de manque de la carte d'etudiant ?
|
||||||
# (si période transitoire on ne bloque dans aucun cas)
|
# (si période transitoire on ne bloque dans aucun cas)
|
||||||
elif champ[1:] == 'blacklist':
|
elif champ[1:] == 'blacklist':
|
||||||
el = '(blacklist=%s)' % expr
|
el = '(blacklist=%s)' % expr
|
||||||
else:
|
else:
|
||||||
# Cas général
|
# Cas général
|
||||||
el = '(%s%s=%s)' % (champ, comp, expr)
|
el = '(%s=%s)' % (champ, expr)
|
||||||
if neg: el = '(!%s)' % el
|
if neg: el = '(!%s)' % el
|
||||||
return el
|
return el
|
||||||
|
|
||||||
|
@ -871,16 +801,12 @@ class CransLdap:
|
||||||
# Test de l'expression de recherche et classement par filtres
|
# Test de l'expression de recherche et classement par filtres
|
||||||
for cond in conds:
|
for cond in conds:
|
||||||
neg = False
|
neg = False
|
||||||
comp = ''
|
|
||||||
try:
|
try:
|
||||||
champ, expr = cond.strip().split('=')
|
champ, expr = cond.strip().split('=')
|
||||||
if champ[-1] == '!':
|
if champ[-1] == '!':
|
||||||
# Négation pour ce champ
|
# Négation pour ce champ
|
||||||
champ = champ[:-1]
|
champ = champ[:-1]
|
||||||
neg = True
|
neg = True
|
||||||
if champ[-1] in ['>', '<']:
|
|
||||||
comp = champ[-1]
|
|
||||||
champ = champ[0:-1]
|
|
||||||
except:
|
except:
|
||||||
raise ValueError(u'Syntaxe de recherche invalide (%s)' % cond)
|
raise ValueError(u'Syntaxe de recherche invalide (%s)' % cond)
|
||||||
|
|
||||||
|
@ -900,7 +826,7 @@ class CransLdap:
|
||||||
# Construction du filtre
|
# Construction du filtre
|
||||||
for i in filtres:
|
for i in filtres:
|
||||||
if champ in self.search_champs[i]:
|
if champ in self.search_champs[i]:
|
||||||
filtre[i] += build_filtre(champ, expr, neg, comp)
|
filtre[i] += build_filtre(champ, expr, neg)
|
||||||
ok = True
|
ok = True
|
||||||
if champ not in self.auto_search_machines_champs \
|
if champ not in self.auto_search_machines_champs \
|
||||||
and champ not in self.non_auto_search_machines_champs:
|
and champ not in self.non_auto_search_machines_champs:
|
||||||
|
@ -1072,6 +998,9 @@ class BaseClasseCrans(CransLdap):
|
||||||
def connexion(self, update=False, f=None):
|
def connexion(self, update=False, f=None):
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
def sursis_carte(self):
|
||||||
|
return False
|
||||||
|
|
||||||
def chbre(self, new=None):
|
def chbre(self, new=None):
|
||||||
return "????"
|
return "????"
|
||||||
|
|
||||||
|
@ -1298,7 +1227,7 @@ class BaseClasseCrans(CransLdap):
|
||||||
|
|
||||||
# Cas spécial
|
# Cas spécial
|
||||||
if "solde" in self.modifs:
|
if "solde" in self.modifs:
|
||||||
diff = round(float(self._init_data.get('solde', [0])[0]) - float(self._data.get('solde', [0])[0]), 2)
|
diff = float(self._init_data.get('solde', [0])[0]) - float(self._data.get('solde', [0])[0])
|
||||||
if diff > 0:
|
if diff > 0:
|
||||||
modif['solde'] = "debit %s Euros" % str(diff)
|
modif['solde'] = "debit %s Euros" % str(diff)
|
||||||
else:
|
else:
|
||||||
|
@ -1360,7 +1289,7 @@ class BaseClasseCrans(CransLdap):
|
||||||
modif = ', '.join(liste_historique)
|
modif = ', '.join(liste_historique)
|
||||||
|
|
||||||
timestamp = time.localtime()
|
timestamp = time.localtime()
|
||||||
hist = "%s, %s" % ( time.strftime(date_format_new, timestamp), script_utilisateur )
|
hist = "%s, %s" % ( time.strftime(date_format, timestamp), script_utilisateur )
|
||||||
|
|
||||||
if self.modifs.has_key('derniereConnexion'):
|
if self.modifs.has_key('derniereConnexion'):
|
||||||
# On nettoie l'historique pour ne garder que la dernière modification
|
# On nettoie l'historique pour ne garder que la dernière modification
|
||||||
|
@ -1372,7 +1301,7 @@ class BaseClasseCrans(CransLdap):
|
||||||
# On loggue
|
# On loggue
|
||||||
try:
|
try:
|
||||||
fd = file('%s/%s_%s_%s' % ("%s/logs" % config.cimetiere, str(self.__class__).split('.')[-1],
|
fd = file('%s/%s_%s_%s' % ("%s/logs" % config.cimetiere, str(self.__class__).split('.')[-1],
|
||||||
time.strftime('%Y-%m-%d-%H:%M:%S', timestamp), self.nom()), 'wb')
|
time.strftime('%Y-%m-%d-%H:%M', timestamp), self.nom()), 'wb')
|
||||||
fd.write("%s\n" % self._data)
|
fd.write("%s\n" % self._data)
|
||||||
fd.close()
|
fd.close()
|
||||||
except:
|
except:
|
||||||
|
@ -1463,12 +1392,12 @@ class BaseClasseCrans(CransLdap):
|
||||||
# Sauvegarde
|
# Sauvegarde
|
||||||
t = str(self.__class__).split('.')[-1]
|
t = str(self.__class__).split('.')[-1]
|
||||||
fd = open('%s/%s/%s_%s' % (config.cimetiere, t,
|
fd = open('%s/%s/%s_%s' % (config.cimetiere, t,
|
||||||
time.strftime('%Y-%m-%d-%H:%M:%S'),
|
time.strftime('%Y-%m-%d-%H:%M'),
|
||||||
self.nom()), 'wb')
|
self.nom()), 'wb')
|
||||||
self.conn = None # Fermeture des connexions à la base sinon cPickle ne marchera pas
|
self.conn = None # Fermeture des connexions à la base sinon cPickle ne marchera pas
|
||||||
cPickle.dump(self, fd, 2)
|
cPickle.dump(self, fd, 2)
|
||||||
fd.close()
|
fd.close()
|
||||||
index = u"%s, %s : %s %s # %s\n" % (time.strftime(date_format_new),
|
index = u"%s, %s : %s %s # %s\n" % (time.strftime(date_format),
|
||||||
script_utilisateur, t,
|
script_utilisateur, t,
|
||||||
self.Nom(), decode(comment))
|
self.Nom(), decode(comment))
|
||||||
|
|
||||||
|
@ -1615,6 +1544,7 @@ class BaseProprietaire(BaseClasseCrans):
|
||||||
finAdh.append(facture._data['finAdhesion'][0])
|
finAdh.append(facture._data['finAdhesion'][0])
|
||||||
self._set('debutAdhesion', debutAdh)
|
self._set('debutAdhesion', debutAdh)
|
||||||
self._set('finAdhesion', finAdh)
|
self._set('finAdhesion', finAdh)
|
||||||
|
self._save()
|
||||||
|
|
||||||
def droits(self, droits=None, light=False):
|
def droits(self, droits=None, light=False):
|
||||||
""" Renvoie les droits courants. Non modifiable (sauf si surchargée dans classe enfant)"""
|
""" Renvoie les droits courants. Non modifiable (sauf si surchargée dans classe enfant)"""
|
||||||
|
@ -2018,9 +1948,6 @@ class BaseProprietaire(BaseClasseCrans):
|
||||||
def delete(self, comment=''):
|
def delete(self, comment=''):
|
||||||
"""Destruction du propriétaire"""
|
"""Destruction du propriétaire"""
|
||||||
|
|
||||||
if max(self.connexion(), self.adhesion()) + cotisation.del_post_adh >= time.time():
|
|
||||||
raise EnvironmentError("Vous ne pouvez supprimer un adhérent que %s jours après l'expiration de son adhésion et de sa connexion" % (cotisation.del_post_adh_jours,))
|
|
||||||
|
|
||||||
for m in self.machines():
|
for m in self.machines():
|
||||||
# Destruction machines
|
# Destruction machines
|
||||||
m.delete(comment)
|
m.delete(comment)
|
||||||
|
@ -2115,11 +2042,9 @@ class BaseProprietaire(BaseClasseCrans):
|
||||||
compte = self._data.get('uid', [''])[0]
|
compte = self._data.get('uid', [''])[0]
|
||||||
if compte:
|
if compte:
|
||||||
ret += u'\nUn compte a été créé :\n login : %s\n' % self.compte()
|
ret += u'\nUn compte a été créé :\n login : %s\n' % self.compte()
|
||||||
r = prompt(u"Attribuer tout de suite un mot de passe, (A pour Automatique) ? [o/n/A]", "A")
|
r = prompt(u"Attribuer tout de suite un mot de passe ? [O/N]", "O")
|
||||||
if r == 'O' or r == 'o':
|
if r == 'O' or r == 'o':
|
||||||
change_password(login=self.compte())
|
change_password(login=self.compte())
|
||||||
if r == 'A' or r == 'a':
|
|
||||||
subprocess.call(['/usr/scripts/cransticket/dump_creds.py','--pass','uid=%s' % self.compte()])
|
|
||||||
else:
|
else:
|
||||||
ret += coul(u' Il faudra penser à attribuer un mot de passe\n', 'jaune')
|
ret += coul(u' Il faudra penser à attribuer un mot de passe\n', 'jaune')
|
||||||
# Le deuxième argument est le potentiel chemin de l'ancien compte
|
# Le deuxième argument est le potentiel chemin de l'ancien compte
|
||||||
|
@ -2464,6 +2389,7 @@ class Adherent(BaseProprietaire):
|
||||||
finConn.append(facture._data['finConnexion'][0])
|
finConn.append(facture._data['finConnexion'][0])
|
||||||
self._set('debutConnexion', debutConn)
|
self._set('debutConnexion', debutConn)
|
||||||
self._set('finConnexion', finConn)
|
self._set('finConnexion', finConn)
|
||||||
|
self._save()
|
||||||
|
|
||||||
def adherentPayant(self, valeur = None):
|
def adherentPayant(self, valeur = None):
|
||||||
"""
|
"""
|
||||||
|
@ -3191,7 +3117,7 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
|
||||||
self._set('prise', [])
|
self._set('prise', [])
|
||||||
return
|
return
|
||||||
|
|
||||||
if not re.match('^[a-cg-jkmopv][0-7][0-5][0-9]$', new.lower()):
|
if not re.match('^[a-cg-jmopv][0-7][0-5][0-9]$', new.lower()):
|
||||||
raise ValueError('Prise incorrecte')
|
raise ValueError('Prise incorrecte')
|
||||||
|
|
||||||
self._set('prise', [new.upper()])
|
self._set('prise', [new.upper()])
|
||||||
|
@ -3321,7 +3247,7 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
|
||||||
rid = int(self.rid())
|
rid = int(self.rid())
|
||||||
rid_obj = ridtools.Rid(rid)
|
rid_obj = ridtools.Rid(rid)
|
||||||
if rid_obj.ipv4_dispo:
|
if rid_obj.ipv4_dispo:
|
||||||
ip = unicode(rid_obj.ipv4())
|
ip = rid_obj.ipv4()
|
||||||
else:
|
else:
|
||||||
ip = ''
|
ip = ''
|
||||||
#On essaye d'attribuer un rid si ip auto et pas encore de rid
|
#On essaye d'attribuer un rid si ip auto et pas encore de rid
|
||||||
|
@ -3350,7 +3276,7 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
|
||||||
|
|
||||||
# Si après tout ca, on a encore auto, c'est qu'il n'y a plus d'ip
|
# Si après tout ca, on a encore auto, c'est qu'il n'y a plus d'ip
|
||||||
if ip == '<automatique>':
|
if ip == '<automatique>':
|
||||||
raise RuntimeError(u"Plus d'IP (rid) libres dans %s." % mach_type)
|
raise RuntimeError(u"Plus d'IP (rid) libres dans %s." % ' et '.join(net))
|
||||||
|
|
||||||
# Sinon, ip fournie, contrôle qu'elle est compatible avec le type machine
|
# Sinon, ip fournie, contrôle qu'elle est compatible avec le type machine
|
||||||
# et calcule le rid qui va bien avec
|
# et calcule le rid qui va bien avec
|
||||||
|
@ -4113,7 +4039,7 @@ class Facture(BaseClasseCrans):
|
||||||
proprio.solde(operation=art['nombre']*art["pu"],
|
proprio.solde(operation=art['nombre']*art["pu"],
|
||||||
comment="Facture n°%s : %s" %
|
comment="Facture n°%s : %s" %
|
||||||
(self.numero(),
|
(self.numero(),
|
||||||
art['designation'].encode(config.ldap_encoding, errors='ignore')))
|
art['designation'].encode('utf-8', errors='ignore')))
|
||||||
proprio.save()
|
proprio.save()
|
||||||
if self.modePaiement() == 'solde':
|
if self.modePaiement() == 'solde':
|
||||||
proprio = self.proprietaire()
|
proprio = self.proprietaire()
|
||||||
|
@ -4160,17 +4086,17 @@ class Facture(BaseClasseCrans):
|
||||||
self._set('article',
|
self._set('article',
|
||||||
['%s~~%s~~%s~~%s' % (
|
['%s~~%s~~%s~~%s' % (
|
||||||
art['code'],
|
art['code'],
|
||||||
art['designation'],
|
art['designation'].encode('utf-8', errors='replace'),
|
||||||
str(art['nombre']),
|
str(art['nombre']),
|
||||||
str(art['pu']))
|
str(art['pu']))
|
||||||
for art in arts])
|
for art in arts])
|
||||||
|
|
||||||
# charge la liste des articles
|
# charge la liste des articles
|
||||||
arts = []
|
arts = []
|
||||||
for art in self._data.get("article", []):
|
for art in self._data.get("article", []):
|
||||||
art = art.split('~~')
|
art = art.split('~~')
|
||||||
art = { 'code' : art[0],
|
art = { 'code' : art[0],
|
||||||
'designation' : art[1].decode(config.ldap_encoding, errors='replace'),
|
'designation' : art[1].decode('utf-8', errors='replace'),
|
||||||
'nombre' : int(art[2]),
|
'nombre' : int(art[2]),
|
||||||
'pu' : float(art[3]) }
|
'pu' : float(art[3]) }
|
||||||
arts.append(art)
|
arts.append(art)
|
||||||
|
@ -4204,7 +4130,6 @@ class Facture(BaseClasseCrans):
|
||||||
# ajoute les articles
|
# ajoute les articles
|
||||||
if type(ajoute)==dict:
|
if type(ajoute)==dict:
|
||||||
ajoute = [ajoute]
|
ajoute = [ajoute]
|
||||||
|
|
||||||
if type(ajoute)==list:
|
if type(ajoute)==list:
|
||||||
for art in ajoute:
|
for art in ajoute:
|
||||||
if int(art['nombre']) != float(art['nombre']):
|
if int(art['nombre']) != float(art['nombre']):
|
||||||
|
@ -4212,7 +4137,7 @@ class Facture(BaseClasseCrans):
|
||||||
if round(art['pu'], 2) != art['pu']:
|
if round(art['pu'], 2) != art['pu']:
|
||||||
raise ValueError, u'pu ne doit pas avoir plus de 2 chiffres apres la virgule'
|
raise ValueError, u'pu ne doit pas avoir plus de 2 chiffres apres la virgule'
|
||||||
art['nombre'] = int(art['nombre'])
|
art['nombre'] = int(art['nombre'])
|
||||||
if '~~' in art['designation']:
|
if '~~' in ' '.join([unicode(x) for x in art.values()]):
|
||||||
raise ValueError, u'Ne pas mettre de ~~ dans les champs'
|
raise ValueError, u'Ne pas mettre de ~~ dans les champs'
|
||||||
arts.append(art)
|
arts.append(art)
|
||||||
|
|
||||||
|
@ -4234,9 +4159,9 @@ class Facture(BaseClasseCrans):
|
||||||
_ = arts.pop()
|
_ = arts.pop()
|
||||||
|
|
||||||
# on supprime les anciens articles
|
# on supprime les anciens articles
|
||||||
if type(supprime) == dict:
|
if type(supprime)==dict:
|
||||||
supprime = [supprime]
|
supprime = [supprime]
|
||||||
if type(supprime) == list:
|
if type(supprime)==list:
|
||||||
for art in supprime:
|
for art in supprime:
|
||||||
arts.remove(art)
|
arts.remove(art)
|
||||||
|
|
||||||
|
@ -4306,11 +4231,8 @@ class Facture(BaseClasseCrans):
|
||||||
|
|
||||||
def delete(self, comment=''):
|
def delete(self, comment=''):
|
||||||
"""Suppression de la facture"""
|
"""Suppression de la facture"""
|
||||||
|
|
||||||
if self.controle():
|
if self.controle():
|
||||||
if max(self.proprietaire().connexion(), self.proprietaire().adhesion()) + cotisation.del_post_adh >= time.time():
|
raise EnvironmentError(u"La facture a déjà été controlée, contacter trésorerie")
|
||||||
raise EnvironmentError(u"La facture a déjà été controlée, contacter trésorerie")
|
|
||||||
|
|
||||||
self.__proprietaire = None
|
self.__proprietaire = None
|
||||||
self._delete(self.dn, comment)
|
self._delete(self.dn, comment)
|
||||||
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import sys
|
|
||||||
from gestion.affich_tools import cprint
|
|
||||||
from gestion import mail
|
|
||||||
import time
|
|
||||||
import lc_ldap.shortcuts
|
|
||||||
import lc_ldap.crans_utils as crans_utils
|
|
||||||
|
|
||||||
# Attention, si à True envoie effectivement les mails
|
|
||||||
SEND=('--do-it' in sys.argv)
|
|
||||||
|
|
||||||
#ldap_filter=u"(&(finConnexion>=%(date)s)(aid=*)(!(chbre=????)))" % {'date': crans_utils.to_generalized_time_format(time.time())}
|
|
||||||
#ldap_filter=u"(|(uid=detraz))"
|
|
||||||
|
|
||||||
conn = lc_ldap.shortcuts.lc_ldap_readonly()
|
|
||||||
dest = conn.search(ldap_filter, sizelimit=2000)
|
|
||||||
|
|
||||||
From = 'respbats@crans.org'
|
|
||||||
print "%d destinataires (Ctrl + C pour annuler l'envoi)" % len(dest)
|
|
||||||
raw_input()
|
|
||||||
with mail.ServerConnection() as smtp:
|
|
||||||
for adh in dest:
|
|
||||||
print "Envoi du mail à %s" % adh.dn
|
|
||||||
if SEND:
|
|
||||||
smtp.send_template('all_coupure', {'adh': adh, 'From': From})
|
|
||||||
cprint(" Envoyé !")
|
|
||||||
else:
|
|
||||||
cprint(" (simulé)")
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ N'hésite pas à nous contacter pour toute question, remarque ou problème à
|
||||||
l'adresse cableurs@crans.org.
|
l'adresse cableurs@crans.org.
|
||||||
|
|
||||||
Plus d'informations sont disponibles sur :
|
Plus d'informations sont disponibles sur :
|
||||||
* https://intranet.crans.org/wifimap/ pour une carte de la couverture
|
* https://intranet2.crans.org/wifimap/ pour une carte de la couverture
|
||||||
* https://wifi.crans.org/ pour configurer sa machine en WiFi
|
* https://wifi.crans.org/ pour configurer sa machine en WiFi
|
||||||
|
|
||||||
En te souhaitant une bonne journée,
|
En te souhaitant une bonne journée,
|
||||||
|
|
|
@ -23,7 +23,7 @@ SEND=('--do-it' in sys.argv)
|
||||||
PREV=('--prev' in sys.argv)
|
PREV=('--prev' in sys.argv)
|
||||||
|
|
||||||
ldap_filter=u"(&(finAdhesion>=%(date)s)(aid=*))" % {'date': crans_utils.to_generalized_time_format(time.time())}
|
ldap_filter=u"(&(finAdhesion>=%(date)s)(aid=*))" % {'date': crans_utils.to_generalized_time_format(time.time())}
|
||||||
#ldap_filter=u"(|(uid=detraz)(uid=mespinasse)(uid=oudin)(uid=begel))"
|
#ldap_filter=u"(|(uid=dstan)(uid=lasseri))"
|
||||||
|
|
||||||
conn=lc_ldap.shortcuts.lc_ldap_readonly()
|
conn=lc_ldap.shortcuts.lc_ldap_readonly()
|
||||||
mailaddrs=set()
|
mailaddrs=set()
|
||||||
|
@ -38,17 +38,17 @@ echecs=[]
|
||||||
From = 'ca@crans.org'
|
From = 'ca@crans.org'
|
||||||
for To in mailaddrs:
|
for To in mailaddrs:
|
||||||
cprint(u"Envoi du mail à %s" % To)
|
cprint(u"Envoi du mail à %s" % To)
|
||||||
mailtxt = mail.generate('age', {'To':To, 'From': From, 'lang_info': 'English version below',})
|
mailtxt = mail.generate('age', {'To':To, 'From': From})
|
||||||
mailtxt["Reply-To"] = Header("ca@crans.org")
|
mailtxt["Reply-To"] = Header("ca@crans.org")
|
||||||
|
|
||||||
# fichier = open(STATUTS_PATH, 'rb')
|
fichier = open(STATUTS_PATH, 'rb')
|
||||||
# part = MIMEApplication(fichier.read(), 'pdf')
|
part = MIMEApplication(fichier.read(), 'pdf')
|
||||||
# part.add_header('Content-Disposition', 'attachment', filename="statuts.pdf")
|
part.add_header('Content-Disposition', 'attachment', filename="statuts.pdf")
|
||||||
# mailtxt.attach(part)
|
mailtxt.attach(part)
|
||||||
# fichier = open(RI_PATH, 'rb')
|
fichier = open(RI_PATH, 'rb')
|
||||||
# part = MIMEApplication(fichier.read(), 'pdf')
|
part = MIMEApplication(fichier.read(), 'pdf')
|
||||||
# part.add_header('Content-Disposition', 'attachment', filename="reglement.pdf")
|
part.add_header('Content-Disposition', 'attachment', filename="reglement.pdf")
|
||||||
# mailtxt.attach(part)
|
mailtxt.attach(part)
|
||||||
|
|
||||||
if PREV:
|
if PREV:
|
||||||
print mailtxt.as_string()
|
print mailtxt.as_string()
|
||||||
|
|
|
@ -7,22 +7,14 @@ affluences en perm"""
|
||||||
import sys
|
import sys
|
||||||
import pytz
|
import pytz
|
||||||
import datetime
|
import datetime
|
||||||
|
from dateutil.parser import parse as parse_gtf
|
||||||
import calendar
|
import calendar
|
||||||
|
|
||||||
from lc_ldap.shortcuts import lc_ldap_readonly
|
from lc_ldap.shortcuts import lc_ldap_readonly
|
||||||
from lc_ldap.variables import base_dn
|
from lc_ldap.variables import base_dn
|
||||||
from lc_ldap import crans_utils
|
|
||||||
import ldap
|
import ldap
|
||||||
from affich_tools import coul
|
from affich_tools import coul
|
||||||
import gestion.mail as mail_module
|
import gestion.mail as mail_module
|
||||||
import gestion.config as config
|
|
||||||
|
|
||||||
PERIODE_TRANSITOIRE = [
|
|
||||||
crans_utils.datetime_from_generalized_time_format(date)
|
|
||||||
for date in
|
|
||||||
[config.gtf_debut_periode_transitoire, config.gtf_fin_periode_transitoire]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
#: Une journée (c'est plus pratique)
|
#: Une journée (c'est plus pratique)
|
||||||
DAY = datetime.timedelta(days=1)
|
DAY = datetime.timedelta(days=1)
|
||||||
|
@ -31,7 +23,7 @@ DAY = datetime.timedelta(days=1)
|
||||||
FORMAT_LDAP = '%Y%m%d%H%M%S%z'
|
FORMAT_LDAP = '%Y%m%d%H%M%S%z'
|
||||||
|
|
||||||
#: Infos à oublier dans un datetime pour ne garder que le jour
|
#: Infos à oublier dans un datetime pour ne garder que le jour
|
||||||
ERASE_DAY = {'second': 0, 'minute': 0, 'microsecond': 0, 'hour': 0, }
|
ERASE_DAY = { 'second': 0, 'minute': 0, 'microsecond': 0, 'hour': 0, }
|
||||||
|
|
||||||
#: filtre ldap max(finConnexion) \in intervalle
|
#: filtre ldap max(finConnexion) \in intervalle
|
||||||
# NB: finConnexion est un attribut ldap multivalué, et on s'intéresse ici
|
# NB: finConnexion est un attribut ldap multivalué, et on s'intéresse ici
|
||||||
|
@ -49,6 +41,7 @@ FILTRE_TPL_SIMPLE = u'(&(finConnexion>=%(debut)s)(!(finConnexion>=%(fin)s)))'
|
||||||
# min(a,b) >= v <=> a >= v /\ b >= v
|
# min(a,b) >= v <=> a >= v /\ b >= v
|
||||||
# min(a,b) < v <=> a < v \/ b < v
|
# min(a,b) < v <=> a < v \/ b < v
|
||||||
FILTRE_TPL = u"""(&
|
FILTRE_TPL = u"""(&
|
||||||
|
(aid=*)
|
||||||
(&(finConnexion>=%(debut)s)(finAdhesion>=%(debut)s))
|
(&(finConnexion>=%(debut)s)(finAdhesion>=%(debut)s))
|
||||||
(|(!(finConnexion>=%(fin)s))(!(finAdhesion>=%(fin)s)))
|
(|(!(finConnexion>=%(fin)s))(!(finAdhesion>=%(fin)s)))
|
||||||
)"""
|
)"""
|
||||||
|
@ -66,38 +59,31 @@ FILTRE_TPL = u"""(&
|
||||||
def warn(mail_conn, adh):
|
def warn(mail_conn, adh):
|
||||||
"""Envoie un mail d'avertissement à ``adh``, en utilisant la connexion mail
|
"""Envoie un mail d'avertissement à ``adh``, en utilisant la connexion mail
|
||||||
``mail_conn``"""
|
``mail_conn``"""
|
||||||
tpl_name = 'fin_connexion'
|
fin = min(max(parse_gtf(v.value) for v in adh[l]) \
|
||||||
fields = ['finAdhesion']
|
for l in ['finConnexion', 'finAdhesion'] )
|
||||||
if 'aid' in adh:
|
|
||||||
fields.append('finConnexion')
|
|
||||||
else:
|
|
||||||
tpl_name += '_club'
|
|
||||||
|
|
||||||
fin = compute_fin_connexion(adh)
|
|
||||||
delai = (fin - datetime.datetime.now(pytz.UTC)).days
|
delai = (fin - datetime.datetime.now(pytz.UTC)).days
|
||||||
data = {
|
data = {
|
||||||
'delai': delai,
|
'delai': delai,
|
||||||
'adh': adh,
|
'adh': adh,
|
||||||
}
|
}
|
||||||
for l in fields:
|
for l in ['adhesion', 'connexion']:
|
||||||
fin = max(v.value for v in adh[l])
|
fin = max(parse_gtf(v.value) for v in adh['fin' + l.capitalize()])
|
||||||
data[l] = fin
|
data['fin_%s' % l] = fin
|
||||||
deco = min(data[l] for l in fields)
|
|
||||||
if deco >= PERIODE_TRANSITOIRE[0] and deco < PERIODE_TRANSITOIRE[1]:
|
From = 'respbats@crans.org'
|
||||||
data['sursis'] = PERIODE_TRANSITOIRE[1]
|
To = adh.get_mail()
|
||||||
|
if not To:
|
||||||
|
print "No valid mail for %r" % adh
|
||||||
|
return
|
||||||
|
data.update({'To': To, 'From': From})
|
||||||
|
mailtxt = mail_module.generate('fin_connexion', data)
|
||||||
|
mail_conn.sendmail(From, [To], mailtxt.as_string())
|
||||||
|
|
||||||
data.update({'From': 'respbats@crans.org'})
|
|
||||||
mail_conn.send_template(tpl_name, data)
|
|
||||||
|
|
||||||
def compute_fin_connexion(adh):
|
def compute_fin_connexion(adh):
|
||||||
"""Renvoie le datetime de fin effective de connexion de l'``adh``"""
|
"""Renvoie le datetime de fin effective de connexion de l'``adh``"""
|
||||||
fields = ['finAdhesion']
|
return min( max(parse_gtf(v.value) for v in adh['fin' + l])
|
||||||
if 'aid' in adh:
|
for l in ['Adhesion', 'Connexion'])
|
||||||
fields.append('finConnexion')
|
|
||||||
value = min(max(v.value for v in adh[l]) for l in fields)
|
|
||||||
if value >= PERIODE_TRANSITOIRE[0] and value < PERIODE_TRANSITOIRE[1]:
|
|
||||||
return PERIODE_TRANSITOIRE[1]
|
|
||||||
return value
|
|
||||||
|
|
||||||
def select(conn, begin, to, mode='r'):
|
def select(conn, begin, to, mode='r'):
|
||||||
"""Récupère les adhérents dont la connexion expire entre les datetimes
|
"""Récupère les adhérents dont la connexion expire entre les datetimes
|
||||||
|
@ -107,19 +93,6 @@ def select(conn, begin, to, mode='r'):
|
||||||
begin = begin.replace(tzinfo=pytz.UTC)
|
begin = begin.replace(tzinfo=pytz.UTC)
|
||||||
if not to.tzinfo:
|
if not to.tzinfo:
|
||||||
to = to.replace(tzinfo=pytz.UTC)
|
to = to.replace(tzinfo=pytz.UTC)
|
||||||
|
|
||||||
# Si la période considérée contient la liste des gens qui seront déco à la
|
|
||||||
# fin de la période transitoire (c'est-à-dire qui seront déco à
|
|
||||||
# PERIODE_TRANSITOIRE[1] )
|
|
||||||
if begin <= PERIODE_TRANSITOIRE[1] and to > PERIODE_TRANSITOIRE[1]:
|
|
||||||
# Alors il est nécessaire de les considérer, donc de selectionner
|
|
||||||
# à partir du début de la période transitoire, au moins
|
|
||||||
begin = min(PERIODE_TRANSITOIRE[0], begin)
|
|
||||||
# Si la période considérée se termine pendant la période transitoire
|
|
||||||
if to < PERIODE_TRANSITOIRE[1] and to >= PERIODE_TRANSITOIRE[0]:
|
|
||||||
# Alors, il ne faut considérer que les adhérents qui se font déco avant
|
|
||||||
# le début de la période transitoire
|
|
||||||
to = PERIODE_TRANSITOIRE[0]
|
|
||||||
data = { 'debut': begin.strftime(FORMAT_LDAP),
|
data = { 'debut': begin.strftime(FORMAT_LDAP),
|
||||||
'fin': to.strftime(FORMAT_LDAP),
|
'fin': to.strftime(FORMAT_LDAP),
|
||||||
}
|
}
|
||||||
|
@ -128,11 +101,7 @@ def select(conn, begin, to, mode='r'):
|
||||||
# NB: on ne prend que les adhérents, d'où SCOPE_ONELEVEL
|
# NB: on ne prend que les adhérents, d'où SCOPE_ONELEVEL
|
||||||
res = conn.search(filtre, scope=ldap.SCOPE_ONELEVEL, dn=base_dn, mode=mode)
|
res = conn.search(filtre, scope=ldap.SCOPE_ONELEVEL, dn=base_dn, mode=mode)
|
||||||
|
|
||||||
def keep(adh):
|
return res
|
||||||
"""Ne conserve que les adhérents ayant encore des machines"""
|
|
||||||
return bool(adh.machines())
|
|
||||||
|
|
||||||
return filter(keep, res)
|
|
||||||
|
|
||||||
def brief(c, debut, fin):
|
def brief(c, debut, fin):
|
||||||
"""Renvoie la liste des adhérents dont la connexion expire entre
|
"""Renvoie la liste des adhérents dont la connexion expire entre
|
||||||
|
@ -147,9 +116,9 @@ def brief(c, debut, fin):
|
||||||
|
|
||||||
if "--list" in sys.argv:
|
if "--list" in sys.argv:
|
||||||
for adh in to_warn:
|
for adh in to_warn:
|
||||||
valeurs = [max(v.value for v in adh[l]) \
|
valeurs = [max(parse_gtf(v.value) for v in adh[l]) \
|
||||||
for l in ['finConnexion', 'finAdhesion'] ]
|
for l in ['finConnexion', 'finAdhesion'] ]
|
||||||
[f_con, f_adh] = [coul(str(v), 'rouge' if v >= debut and v < fin else 'vert') \
|
[f_con, f_adh] = [ coul(str(v), 'rouge' if v >= debut and v < fin else 'vert') \
|
||||||
for v in valeurs]
|
for v in valeurs]
|
||||||
print "%r %s %s;%s" % (adh, adh.dn.split(',', 1)[0], f_con, f_adh)
|
print "%r %s %s;%s" % (adh, adh.dn.split(',', 1)[0], f_con, f_adh)
|
||||||
return to_warn
|
return to_warn
|
||||||
|
@ -162,16 +131,12 @@ def prev_calendar(c, date):
|
||||||
cal = calendar.Calendar()
|
cal = calendar.Calendar()
|
||||||
|
|
||||||
first = datetime.datetime(day=1, month=month, year=year, tzinfo=pytz.UTC)
|
first = datetime.datetime(day=1, month=month, year=year, tzinfo=pytz.UTC)
|
||||||
last = first.replace(month=1+month%12, year=year+int(month == 12))
|
last = first.replace(month=1+month%12, year=year+int(month==12))
|
||||||
|
|
||||||
disconnect = select(c, first, last)
|
disconnect = select(c, first, last)
|
||||||
by_day = {x: 0 for x in xrange(1, 32)}
|
by_day = {x: 0 for x in xrange(1, 32)}
|
||||||
for adh in disconnect:
|
for adh in disconnect:
|
||||||
date = compute_fin_connexion(adh)
|
date = compute_fin_connexion(adh)
|
||||||
# On veut le .day, mais dans le fuseau UTC (utilisé pour le select juste
|
|
||||||
# avant). Avec UTC, c'est facile: il suffit de virer l'offset de la TZ
|
|
||||||
if date.tzinfo:
|
|
||||||
date -= date.tzinfo.utcoffset(date)
|
|
||||||
by_day[date.day] += 1
|
by_day[date.day] += 1
|
||||||
|
|
||||||
yield ['L', 'M', 'Me', 'J', 'V', 'S', 'D']
|
yield ['L', 'M', 'Me', 'J', 'V', 'S', 'D']
|
||||||
|
|
|
@ -168,8 +168,12 @@ def generate(mail, params, lang=default_language, lang_fallback=default_language
|
||||||
def validation_url(view_name, data='', debug=False):
|
def validation_url(view_name, data='', debug=False):
|
||||||
"""Enregistre une nouvelle url pour le module "validation" de l'intranet."""
|
"""Enregistre une nouvelle url pour le module "validation" de l'intranet."""
|
||||||
import requests
|
import requests
|
||||||
CA = '/etc/ssl/certs/cacert.org.pem'
|
if debug:
|
||||||
ROOT = os.getenv('DBG_INTRANET', 'https://intranet.crans.org')
|
CA = False
|
||||||
|
ROOT = 'https://intranet-dev.crans.org'
|
||||||
|
else:
|
||||||
|
CA = '/etc/ssl/certs/cacert.org.pem'
|
||||||
|
ROOT = 'https://intranet2.crans.org'
|
||||||
url = ROOT + '/validation/register/%s/' % view_name
|
url = ROOT + '/validation/register/%s/' % view_name
|
||||||
payload = {
|
payload = {
|
||||||
'data': json.dumps(data),
|
'data': json.dumps(data),
|
||||||
|
@ -250,7 +254,7 @@ class ServerConnection(object):
|
||||||
adh = data.get('adh', data.get('proprio', ''))
|
adh = data.get('adh', data.get('proprio', ''))
|
||||||
to = data.get('to', None) or (adh.get_mail() if adh else None)
|
to = data.get('to', None) or (adh.get_mail() if adh else None)
|
||||||
if to is None:
|
if to is None:
|
||||||
print "Pas de mail valide pour %r. Skipping..." % (adh, )
|
print "No valid recipient mail. Aborting."
|
||||||
return
|
return
|
||||||
# TODO: get lang toussa
|
# TODO: get lang toussa
|
||||||
body = generate(tpl_name, data).as_string()
|
body = generate(tpl_name, data).as_string()
|
||||||
|
@ -259,11 +263,3 @@ class ServerConnection(object):
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
self._conn.quit()
|
self._conn.quit()
|
||||||
|
|
||||||
# TODO: intégrer ceci dans le ServerConnection
|
|
||||||
def postconf(i):
|
|
||||||
"Fixe la fréquence d'envoi maximale par client (en msg/min)"
|
|
||||||
os.system("/usr/sbin/postconf -e smtpd_client_message_rate_limit=%s" % i)
|
|
||||||
os.system("/etc/init.d/postfix reload")
|
|
||||||
|
|
||||||
# opt = commands.getoutput("/usr/sbin/postconf smtpd_client_message_rate_limit")
|
|
||||||
|
|
|
@ -5,10 +5,7 @@ adhérent. Le script se connecte à l'interface d'impression pour récupérer
|
||||||
la liste des dernières tâches imprimées.
|
la liste des dernières tâches imprimées.
|
||||||
Ce script est lancé par un cron toutes les dix minutes sur zamok. Pour éviter
|
Ce script est lancé par un cron toutes les dix minutes sur zamok. Pour éviter
|
||||||
de notifier plusieurs fois de la même fin d'impression, on ne balaie dans
|
de notifier plusieurs fois de la même fin d'impression, on ne balaie dans
|
||||||
la liste que le dernier intervalle (bornes entières) de dix minutes
|
la liste que le dernier intervalle (bornes entières) de dix minutes"""
|
||||||
|
|
||||||
detraz@crans.org
|
|
||||||
"""
|
|
||||||
|
|
||||||
import BeautifulSoup
|
import BeautifulSoup
|
||||||
import sys
|
import sys
|
||||||
|
@ -16,7 +13,9 @@ import requests
|
||||||
import re
|
import re
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
|
import smtplib
|
||||||
|
|
||||||
|
from gestion.affich_tools import cprint
|
||||||
from gestion import mail
|
from gestion import mail
|
||||||
from utils.sendmail import actually_sendmail
|
from utils.sendmail import actually_sendmail
|
||||||
from lc_ldap import shortcuts
|
from lc_ldap import shortcuts
|
||||||
|
@ -61,6 +60,7 @@ fin = now.replace(second=0, minute=(now.minute/10)*10, microsecond=0)
|
||||||
debut = fin - datetime.timedelta(minutes=10)
|
debut = fin - datetime.timedelta(minutes=10)
|
||||||
|
|
||||||
success=dict()
|
success=dict()
|
||||||
|
clubs=dict()
|
||||||
echecs=dict()
|
echecs=dict()
|
||||||
for job in jobs:
|
for job in jobs:
|
||||||
# Fin de parsing
|
# Fin de parsing
|
||||||
|
@ -101,10 +101,19 @@ for job in jobs:
|
||||||
nb = split[0]
|
nb = split[0]
|
||||||
name = split[1]
|
name = split[1]
|
||||||
task = u':'.join(split[2:])
|
task = u':'.join(split[2:])
|
||||||
|
if u'@' in name:
|
||||||
|
#Seuls les clubs ont un @ dans leur alias, donc boucle
|
||||||
|
# dédiée au clubs
|
||||||
|
[name, club] = name.split(u'@', 1)
|
||||||
|
if club not in clubs:
|
||||||
|
clubs[club] = {'task': []}
|
||||||
|
clubs[club]['task'].append(task)
|
||||||
if name not in success:
|
if name not in success:
|
||||||
success[name] = {'task': []}
|
success[name] = {'task': []}
|
||||||
success[name]['task'].append(task)
|
success[name]['task'].append(task)
|
||||||
|
|
||||||
|
#Section consacrée à l'envoi : partie 1 pour les adh, partie 2 pour les clubs
|
||||||
|
#To = 'detraz@crans.org'
|
||||||
From = 'impression@crans.org'
|
From = 'impression@crans.org'
|
||||||
e = 0
|
e = 0
|
||||||
a = 0
|
a = 0
|
||||||
|
@ -115,11 +124,7 @@ for name in success:
|
||||||
a = a + 1
|
a = a + 1
|
||||||
adh = ad[0]
|
adh = ad[0]
|
||||||
To = name + u'@crans.org'
|
To = name + u'@crans.org'
|
||||||
try:
|
tname = unicode(adh['prenom'][0]) + " " + unicode(adh['nom'][0])
|
||||||
tname = unicode(adh['prenom'][0]) + " " + unicode(adh['nom'][0])
|
|
||||||
# Pour les clubs
|
|
||||||
except KeyError:
|
|
||||||
tname = unicode(name)
|
|
||||||
codes = [x[0] + u'#' for x in digicode.list_code(name)]
|
codes = [x[0] + u'#' for x in digicode.list_code(name)]
|
||||||
if not codes:
|
if not codes:
|
||||||
codes = [digicode.gen_code(name) + u'#']
|
codes = [digicode.gen_code(name) + u'#']
|
||||||
|
@ -132,21 +137,36 @@ for name in success:
|
||||||
'taches': u', '.join(success[name]['task']),
|
'taches': u', '.join(success[name]['task']),
|
||||||
'codes': u', '.join(codes)
|
'codes': u', '.join(codes)
|
||||||
})
|
})
|
||||||
if VERB:
|
#print mailtxt.as_string()
|
||||||
print mailtxt.as_string()
|
|
||||||
actually_sendmail(From, (To,), mailtxt)
|
actually_sendmail(From, (To,), mailtxt)
|
||||||
else:
|
else:
|
||||||
e = e+1
|
e = e+1
|
||||||
|
|
||||||
|
for club in clubs:
|
||||||
|
a = a + 1
|
||||||
|
tname = club
|
||||||
|
To = club + u'@crans.org'
|
||||||
|
codes = [x[0] + u'#' for x in digicode.list_code(club)]
|
||||||
|
if not codes:
|
||||||
|
codes = [digicode.gen_code(club) + u'#']
|
||||||
|
if VERB:
|
||||||
|
print (u"Envoi du mail à %s" % To)
|
||||||
|
mailtxt=mail.generate('mail_impression_ok', {
|
||||||
|
'To': To,
|
||||||
|
'From': From,
|
||||||
|
'tname': tname,
|
||||||
|
'taches': u', '.join(clubs[club]['task']),
|
||||||
|
'codes': u', '.join(codes),
|
||||||
|
})
|
||||||
|
#print mailtxt.as_string()
|
||||||
|
actually_sendmail(From, (To,), mailtxt)
|
||||||
|
|
||||||
for name in echecs:
|
for name in echecs:
|
||||||
ad = con.search(u'(uid=%s)' % name)
|
ad = con.search(u'(uid=%s)' % name)
|
||||||
To = 'impression@lists.crans.org'
|
To = 'impression@lists.crans.org'
|
||||||
if ad <> []:
|
if ad <> []:
|
||||||
adh = ad[0]
|
adh = ad[0]
|
||||||
try:
|
tname = unicode(adh['prenom'][0]) + " " + unicode(adh['nom'][0])
|
||||||
tname = unicode(adh['prenom'][0]) + " " + unicode(adh['nom'][0])
|
|
||||||
except KeyError:
|
|
||||||
tname = unicode(name)
|
|
||||||
else:
|
else:
|
||||||
tname = name
|
tname = name
|
||||||
mailtxt=mail.generate('mail_impression_ratee', {
|
mailtxt=mail.generate('mail_impression_ratee', {
|
||||||
|
@ -155,8 +175,7 @@ for name in echecs:
|
||||||
'tname': tname,
|
'tname': tname,
|
||||||
'taches': u', '.join(echecs[name]['task']),
|
'taches': u', '.join(echecs[name]['task']),
|
||||||
})
|
})
|
||||||
if VERB:
|
#print mailtxt.as_string()
|
||||||
print mailtxt.as_string()
|
|
||||||
actually_sendmail(From, (To,), mailtxt)
|
actually_sendmail(From, (To,), mailtxt)
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,3 +186,4 @@ if e>0:
|
||||||
print a
|
print a
|
||||||
print "Nombre de mails non envoyés faute de résultats LDAP :"
|
print "Nombre de mails non envoyés faute de résultats LDAP :"
|
||||||
print e
|
print e
|
||||||
|
#print len(success)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Crans : Rappel assemblée générale extraordinaire du 26 novembre 2015
|
[Crans] Modification des statuts et du règlement intérieur : convocation en assemblée générale extraordinaire.
|
||||||
|
|
|
@ -1,14 +1,32 @@
|
||||||
Dear members,
|
Dear members,
|
||||||
|
|
||||||
We remind you that an Extraordinary General Meeting of the Crans will occur on Thursday,
|
In order to be able to follow ENS Cachan when it'll move to Saclay, Crans need
|
||||||
November 26th, 2015 at 7.15 pm in Amphithéâtre Tocqueville.
|
to reform its statutes and rules of procedure.
|
||||||
|
|
||||||
Before the meeting, you have to validate the agreement with CROUS and ENS that allow us to provide Internet in your appartment. That's why we hope you'll be a lot to vote because we need that at least 5% of you vote to validate it. As there are elections of CA/CVE/CS for the ENS, we will be with them at the Pavillon des Jardins between 10h and 19h.
|
We therefore rewrote these texts, as it was an opportunity to clarify the way
|
||||||
|
the association is supposed to work, inside and towards external entities. These
|
||||||
|
new texts explicitly contains a lot of guarantees about how it works, espcially
|
||||||
|
regarding privacy (which tends to become a big deal nowadays).
|
||||||
|
|
||||||
We will find the agenda of the meeting and then the report on the wiki.
|
Yet, due to timing issues, we need to have an extraordinary assembly to vote
|
||||||
https://wiki.crans.org/ComptesRendusCrans/Jeudi26Novembre2015
|
these texts on Thursday, July 9th at 7.00 pm (local time). This would allow us
|
||||||
|
to begin some files regarding Saclay project.
|
||||||
|
|
||||||
We hope to see you at this general meeting.
|
However, we are aware that a lot of our members won't be able to come to vote.
|
||||||
|
Furthermore, these new texts haven't been translated into English for now.
|
||||||
|
Anyway, as it is a duty, these new versions are attached to the current email.
|
||||||
|
If you're interested in, you may contact us in order to ask some questions about
|
||||||
|
these new texts or the assembly. You just need to answer that email.
|
||||||
|
|
||||||
|
Previous versions of statutes and rules of procedure may be found there:
|
||||||
|
https://wiki.crans.org/CransAdministratif/StatutsDuCrans
|
||||||
|
https://wiki.crans.org/CransAdministratif/R%C3%A8glementInt%C3%A9rieur
|
||||||
|
|
||||||
|
The votes will occur all the day in Hall Villon, starting at 9.00 am (local
|
||||||
|
time). The assembly will be held in Amphithéâtre Tocqueville, and its goal will
|
||||||
|
be to account the votes of the day.
|
||||||
|
|
||||||
|
Sincerely,
|
||||||
|
|
||||||
--
|
--
|
||||||
Crans active members
|
Crans active members
|
||||||
|
|
|
@ -1,13 +1,37 @@
|
||||||
Chers adhérents,
|
Chers adhérents,
|
||||||
|
|
||||||
Pour rappel, ce Jeudi 26 novembre 2015, à partir de 19h15, aura lieu une Assemblée Générale Extraordinaire du Crans dans l'Amphithéâtre Tocqueville.
|
Dans le but de pouvoir nous investir dans le projet Paris-Saclay et ainsi
|
||||||
|
accompagner le déménagement de l'Ecole Normale Supérieure de Cachan,
|
||||||
|
l'association doit adapter ses statuts et son règlement intérieur.
|
||||||
|
|
||||||
Cette Assemblée sera précédée d'un vote très important : vous devrez valider la convention signée avec l'ENS et le CROUS qui nous permet de vous fournir Internet dans les résidences. Nous espérons donc que vous serez nombreux à venir, le vote devant mobiliser au moins 5% des adhérents pour être validé. Nous serons au Pavillon des Jardins avec les élections CA/CVE/CS de l'ENS de 10h à 19h.
|
Nous avons donc travaillé à leur réécriture, qui vise aussi à clarifier la façon
|
||||||
|
dont l'association fonctionne, aussi bien en interne que vers les personnes
|
||||||
|
extérieures à l'association. Ainsi un certain nombre de garanties sont désormais
|
||||||
|
exprimées explicitement dans les statuts ou le règlement intérieur, en
|
||||||
|
particulier sur la notion de vie privée (qui est en ce moment au cœur des débats
|
||||||
|
publics).
|
||||||
|
|
||||||
Vous trouverez l'ordre du jour puis le compte-rendu de la réunion sur le wiki.
|
Cependant, le temps manque, et nous aimerions pouvoir également mener les
|
||||||
https://wiki.crans.org/ComptesRendusCrans/Jeudi26Novembre2015
|
démarches nécessaires dans le cadre du projet Saclay, y compris auprès des
|
||||||
|
établissements publics concernés. Aussi, nous souhaiterions voter ces
|
||||||
|
modifications lors d'une Assemblée Générale Extraordinaire qui se tiendrait le
|
||||||
|
jeudi 9 juillet 2015 à 19h.
|
||||||
|
|
||||||
En espérant vous voir jeudi.
|
Nous avons conscience que ce choix signifie aussi qu'un certain nombre d'entre
|
||||||
|
vous ne pourront pas nécessairement être présents. Les textes que nous
|
||||||
|
souhaitons adopter sont en pièce jointe du présent email. Si vous voyez des
|
||||||
|
choses qui vous semblent problématiques dans l'un d'entre eux, n'hésitez pas à
|
||||||
|
nous contacter par email (en répondant à celui-ci) pour exprimer votre pensée.
|
||||||
|
|
||||||
|
Les précédents statuts et règlement intérieur peuvent être trouvés ici :
|
||||||
|
https://wiki.crans.org/CransAdministratif/StatutsDuCrans
|
||||||
|
https://wiki.crans.org/CransAdministratif/R%C3%A8glementInt%C3%A9rieur
|
||||||
|
|
||||||
|
Vous pourrez vous rendre au Hall Villon à partir de 9h (heure locale) pour voter
|
||||||
|
concernant l'adoption des nouveaux textes. L'assemblée se tiendra à
|
||||||
|
l'amphithéâtre Tocqueville dans le but de dépouiller les votes.
|
||||||
|
|
||||||
|
Bien cordialement,
|
||||||
|
|
||||||
--
|
--
|
||||||
Les membres actifs du Crans
|
Les membres actifs du Crans
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
[Crans] Coupure électrique le 27 Novembre 2015
|
Crans: coupure de courant le 31/01/2015
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
"{{ adh|name }}" <{{adh.get_mail()}}>
|
"{{ adh|name }}" <{{to}}>
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
Chers adhérents,
|
Chère adhérente, cher adhérent,
|
||||||
|
|
||||||
Une maintenance électrique est planifiée par le Crous demain vendredi 27
|
Le Crous nous a informé que l'alimentation électrique sera interrompue le
|
||||||
novembre, à partir de 15h, et provoquera une coupure générale sur l'ensemble du campus.
|
samedi 31 janvier entre 9h à 17h, en raison de travaux de maintenance sur le
|
||||||
|
réseau électrique. Par conséquent, l'ensemble des services du Crans sera
|
||||||
|
indisponible durant cette maintenance. Davantage d'informations seront
|
||||||
|
fournies sur la page crans-incidents, accessible à cette adresse :
|
||||||
|
https://wiki.crans.org/CransIncidents .
|
||||||
|
|
||||||
L'accès à internet et tous les services du Crans seront interrompus durant l'intervention.
|
Veuillez nous excuser pour la gêne occasionnée.
|
||||||
|
|
||||||
Cordialement,
|
Cordialement,
|
||||||
--
|
--
|
||||||
Les membres actifs de l'association Crans
|
les membres actifs du Crans
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Bonjour {{tname}},
|
Bonjour {{tname}},
|
||||||
|
|
||||||
La machine {{mach}} dont tu es propriétaire a été déconnectée du réseau.
|
La machine {{mach}} dont tu es le propriétaire a été déconnectée du réseau.
|
||||||
|
|
||||||
La raison de cette déconnexion est technique : le comportement de la machine est anormal.
|
La raison de cette déconnexion est technique : le comportement de la machine est anormal.
|
||||||
Celle-ci émet des annonces signalant aux autres machines qu'elle peut gérer leur connexion
|
Celle-ci émet des annonces signalant aux autres machines qu'elle peut gérer leur connexion
|
||||||
|
|
|
@ -3,18 +3,14 @@ Hi {{ adh|name }}!
|
||||||
A new member of Crans has declared to live in the room {{chambre}} you were
|
A new member of Crans has declared to live in the room {{chambre}} you were
|
||||||
previously registered in. This means we do not have your residency information
|
previously registered in. This means we do not have your residency information
|
||||||
anymore.
|
anymore.
|
||||||
{% if chbre_url %}
|
|
||||||
You can do update these data by following this link:
|
|
||||||
{{ chbre_url }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
If you wish to keep your Crans Internet access, you need to give us the number
|
If you wish to keep your Crans Internet access, you need to give us the number
|
||||||
of your new room or your new *complete* address in case you moved out of
|
of your new room or your new *complete* address in case you moved out of
|
||||||
the campus.
|
the campus.
|
||||||
|
|
||||||
If you do not wish to keep your Crans Internet access, all your computers will
|
If you do not wish to keep your Crans Internet access, a simple message from
|
||||||
be deleted from our database. This deletion will automatically take place in
|
you is enough to delete all your computers from our database. This deletion
|
||||||
{{jours}} day{% if jours > 1 %}s{%endif%} if you do not answer.
|
will automatically take place in {{jours}} day{% if jours > 1 %}s{%endif%} if you do not answer.
|
||||||
|
|
||||||
If you do have a Crans account, you will keep an unlimited acces to it as well
|
If you do have a Crans account, you will keep an unlimited acces to it as well
|
||||||
as all the associated services such as your email firstname.lastname@crans.org.
|
as all the associated services such as your email firstname.lastname@crans.org.
|
||||||
|
|
|
@ -3,20 +3,15 @@ Bonjour {{ adh|name }},
|
||||||
Un adhérent du Crans a déclaré résider dans la chambre {{chambre}},
|
Un adhérent du Crans a déclaré résider dans la chambre {{chambre}},
|
||||||
que tu occupais précédemment. Cela signifie que nous ne disposons
|
que tu occupais précédemment. Cela signifie que nous ne disposons
|
||||||
plus d'informations de résidence valides à ton sujet.
|
plus d'informations de résidence valides à ton sujet.
|
||||||
{%- if chbre_url %}
|
|
||||||
Afin de mettre à jour ces informations, nous t'invitons à utiliser le lien
|
|
||||||
ci-dessous :
|
|
||||||
{{ chbre_url }}
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
Si tu souhaites conserver ton accès Internet via le Crans, il est nécessaire
|
Si tu souhaites conserver ton accès Internet via le Crans, il est nécessaire
|
||||||
que tu nous indiques ta nouvelle chambre, ou ta nouvelle adresse *complète*,
|
que tu nous indiques ta nouvelle chambre, ou ta nouvelle adresse *complète*,
|
||||||
si tu as quitté le campus.
|
si tu as quitté le campus.
|
||||||
|
|
||||||
Si tu ne souhaites pas conserver ton accès Internet, les machines que tu
|
Si tu ne souhaites pas conserver ton accès Internet, un simple message de
|
||||||
possèdes seront supprimées de notre base de données. Cette suppression aura
|
ta part et nous supprimerons les machines que tu possèdes de notre base de
|
||||||
automatiquement lieu dans {{jours}} jour{% if jours > 1%}s{%endif%} en l'absence
|
données. Cette suppression aura automatiquement lieu dans {{jours}} jour{% if jours > 1%}s{%endif%} en
|
||||||
de réponse.
|
l'absence de réponse.
|
||||||
|
|
||||||
Si tu possèdes un compte Crans, tu conserves un accès à celui-ci sans limite de
|
Si tu possèdes un compte Crans, tu conserves un accès à celui-ci sans limite de
|
||||||
durée ainsi qu'à tous les services associés, notamment ton adresse mail
|
durée ainsi qu'à tous les services associés, notamment ton adresse mail
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
"{{adh|name}}" <{{adh.get_mail()}}>
|
"{{ adh|name }}" <{{To}}>
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
Cher adhérent du Crans,
|
Cher adhérent du Crans,
|
||||||
|
|
||||||
Nous t'envoyons ce message pour t'informer que ta connexion arrive à
|
Nous t'envoyons ce message pour t'informer que ta connexion arrive à
|
||||||
expiration dans moins de {{ delai }} jours.{% if finConnexion > finAdhesion %}
|
expiration dans moins de {{ delai }} jours.{% if fin_connexion > fin_adhesion %}
|
||||||
En effet, ton adhésion annuelle s'achève le {{ finAdhesion|date}} même
|
En effet, ton adhésion annuelle s'achève le {{ fin_adhesion|date}} même
|
||||||
si les frais de connexion restent acquis jusqu'au {{ finConnexion|date }}.
|
si les frais de connexion restent acquis jusqu'au {{ fin_connexion|date }}.
|
||||||
{% else %}
|
{% else %}
|
||||||
En effet, les frais de connexion sont valables jusqu'au {{ finConnexion|date }}
|
En effet, les frais de connexion sont valables jusqu'au {{ fin_connexion|date }}
|
||||||
et ton adhésion annuelle s'achève le {{ finAdhesion|date }}.
|
et ton adhésion annuelle s'achève le {{ fin_adhesion|date }}.
|
||||||
{%- endif %}{%- if sursis %}
|
{% endif %}
|
||||||
Cependant, en raison de l'affluence de rentrée, ta connexion est prolongée
|
|
||||||
jusqu'au {{ sursis|date }}.{%- endif %}
|
|
||||||
|
|
||||||
Pour réadhérer ou prolonger ta connexion, tu peux nous retrouver
|
Pour réadhérer ou prolonger ta connexion, tu peux nous retrouver
|
||||||
lors d'une de nos permanences. Les horaires actuels sont disponibles à
|
lors d'une de nos permanences. Les horaires actuels sont disponibles à
|
||||||
l'adresse www.crans.org/PermanencesCrans .
|
l'adresse www.crans.org/PermanencesCrans .
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Les câbleurs du Crans <cableurs@crans.org>
|
|
|
@ -1,2 +0,0 @@
|
||||||
Envoyé lorsque la connexion (effective, adh+connexion) d'un adhérent est sur le
|
|
||||||
point d'expirer.
|
|
|
@ -1 +0,0 @@
|
||||||
[Crans] Fin de connexion dans moins de {{ delai }} jours
|
|
|
@ -1 +0,0 @@
|
||||||
"{{adh|name}}" <{{ adh.get_mail() }}>
|
|
|
@ -1 +0,0 @@
|
||||||
{{ mailer }}
|
|
|
@ -1,20 +0,0 @@
|
||||||
Cher adhérent du Crans,
|
|
||||||
|
|
||||||
Nous t'envoyons ce message pour t'informer que la connexion du {{adh|name}},
|
|
||||||
dont tu es responsable, arrive à expiration dans moins de {{delai}} jours.
|
|
||||||
En effet, son adhésion annuelle s'achève le {{finAdhesion|date}}
|
|
||||||
{%- if sursis %}
|
|
||||||
Cependant, en raison de l'affluence de rentrée, la connexion est prolongée
|
|
||||||
jusqu'au {{ sursis|date }}.{%- endif %}
|
|
||||||
|
|
||||||
Pour réadhérer (gratuitement), tu peux nous retrouver lors d'une de nos
|
|
||||||
permanences. Les horaires actuels sont disponibles à
|
|
||||||
l'adresse www.crans.org/PermanencesCrans .
|
|
||||||
|
|
||||||
Le cas échéant, tu peux nous indiquer si tu souhaites modifier ou supprimer le
|
|
||||||
club, ses machines, ses imprimeurs ou le responsable.
|
|
||||||
|
|
||||||
À très bientôt !
|
|
||||||
|
|
||||||
--
|
|
||||||
Les membres actifs de l'association
|
|
|
@ -1,7 +1,4 @@
|
||||||
Chers câbleurs,<br>
|
Calendrier des déconnexions ce mois-ci:
|
||||||
Vous trouverez ci-dessus le résumé prévisionnel des fins de connexions
|
|
||||||
de nos adhérents pour ce mois-ci. Ce graphe peut ainsi vous donner une
|
|
||||||
idée des prochaines affluences en permanence.<br>
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
{%- for line in calendar %}
|
{%- for line in calendar %}
|
||||||
|
@ -23,6 +20,7 @@ idée des prochaines affluences en permanence.<br>
|
||||||
</tr>
|
</tr>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
</table>
|
</table>
|
||||||
<br>
|
|
||||||
-- <br>
|
--
|
||||||
|
|
||||||
Les membres actifs de l'association
|
Les membres actifs de l'association
|
||||||
|
|
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