Factorisation. Preparation de l'envoi des mails.
darcs-hash:20060507164909-68412-59836281afda0c54b73d318d9318e071a0b52246.gz
This commit is contained in:
parent
89d16d3eb5
commit
018f2d59c4
1 changed files with 64 additions and 34 deletions
|
@ -2,7 +2,7 @@
|
||||||
# -*- coding: iso-8859-15 -*-
|
# -*- coding: iso-8859-15 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Repère les comptes inactifs en parsant les logs de derniere connexion
|
Repère les comptes inactifs en parsant les logs de dernière connexion
|
||||||
de sshd et dovecot.
|
de sshd et dovecot.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -13,19 +13,37 @@ de sshd et dovecot.
|
||||||
import sys, os, sre, time, cPickle
|
import sys, os, sre, time, cPickle
|
||||||
from time import mktime, time, localtime, strptime, strftime
|
from time import mktime, time, localtime, strptime, strftime
|
||||||
from socket import gethostname
|
from socket import gethostname
|
||||||
|
from smtplib import SMTP
|
||||||
|
|
||||||
host = gethostname()
|
host = gethostname()
|
||||||
mail_address = u'disconnect@crans.org'
|
mail_address = u'disconnect@crans.org'
|
||||||
mail_sender = u"Comptes inactifs <disconnect@crans.org>"
|
mail_sender = u"Comptes inactifs <disconnect@crans.org>"
|
||||||
|
template_path = '/usr/scripts/templates/comptes_inactifs.%d'
|
||||||
|
|
||||||
sys.path.append('/usr/scripts/gestion')
|
sys.path.append('/usr/scripts/gestion')
|
||||||
from affich_tools import tableau
|
from affich_tools import tableau
|
||||||
from email_tools import send_email
|
from email_tools import send_email, parse_mail_template
|
||||||
from ldap_crans import crans_ldap
|
from ldap_crans import crans_ldap
|
||||||
from config import ann_scol
|
from config import ann_scol
|
||||||
db = crans_ldap()
|
db = crans_ldap()
|
||||||
|
|
||||||
|
|
||||||
|
def nb_mails_non_lus(login):
|
||||||
|
"""
|
||||||
|
Renvoie le nombre de mails non lus de login, ou None si impossible à
|
||||||
|
déterminer.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
maildir = '/var/mail/%s/new' % login
|
||||||
|
if os.path.isdir(maildir):
|
||||||
|
return len(os.listdir(maildir))
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
except:
|
||||||
|
# Arrive quand le script n'a pas les bons droits pour lire /var/mail
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ComptesInactifs:
|
class ComptesInactifs:
|
||||||
re = sre.compile(r'^(\w+\s+\d+\s+\d+:\d+:\d+).*(?:'
|
re = sre.compile(r'^(\w+\s+\d+\s+\d+:\d+:\d+).*(?:'
|
||||||
r'dovecot.*Login: user=<|'
|
r'dovecot.*Login: user=<|'
|
||||||
|
@ -49,7 +67,7 @@ class ComptesInactifs:
|
||||||
f.write('%s %d\n' % (host, os.getpid()))
|
f.write('%s %d\n' % (host, os.getpid()))
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
# A partir de la, on a le lock
|
# À partir de là, on a le lock
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
self.dic = cPickle.load(file(filename))
|
self.dic = cPickle.load(file(filename))
|
||||||
else:
|
else:
|
||||||
|
@ -62,22 +80,22 @@ class ComptesInactifs:
|
||||||
|
|
||||||
def update(self, login, timestamp):
|
def update(self, login, timestamp):
|
||||||
"""
|
"""
|
||||||
Met a jour l'entree correspondant au login donnee, ainsi que
|
Met à jour l'entrée correspondant au login donné, ainsi que
|
||||||
l'entree '!', qui correspond a la plus vieille entree.
|
l'entrée '!', qui correspond à la plus vieille entrée.
|
||||||
"""
|
"""
|
||||||
dic = self.dic
|
dic = self.dic
|
||||||
timestamp = int(timestamp)
|
timestamp = int(timestamp)
|
||||||
|
|
||||||
# Mise a jour de l'entree la plus vieille
|
# Mise à jour de l'entrée la plus vieille
|
||||||
if not dic.has_key('!') or timestamp < dic['!']:
|
if not dic.has_key('!') or timestamp < dic['!']:
|
||||||
dic['!'] = timestamp
|
dic['!'] = timestamp
|
||||||
|
|
||||||
# Mise a jour de l'entree correspondant au login
|
# Mise à jour de l'entrée correspondant au login
|
||||||
if not dic.has_key(login) or timestamp > dic[login]:
|
if not dic.has_key(login) or timestamp > dic[login]:
|
||||||
dic[login] = timestamp
|
dic[login] = timestamp
|
||||||
|
|
||||||
def update_from_syslog(self, loglines):
|
def update_from_syslog(self, loglines):
|
||||||
""" Met a jour le dico avec les lignes de syslog donnees """
|
""" Met à jour le dico avec les lignes de syslog données """
|
||||||
annee = localtime(time())[0]
|
annee = localtime(time())[0]
|
||||||
now = time() + 600
|
now = time() + 600
|
||||||
nombre = 0
|
nombre = 0
|
||||||
|
@ -95,9 +113,9 @@ class ComptesInactifs:
|
||||||
print '%d ligne(s) pertinente(s)' % nombre
|
print '%d ligne(s) pertinente(s)' % nombre
|
||||||
|
|
||||||
def do_log(self):
|
def do_log(self):
|
||||||
""" Lit des lignes de log sur l'entree std et met a jour le dico """
|
""" Lit des lignes de log sur l'entrée std et met à jour le dico """
|
||||||
self.update_from_syslog(sys.stdin)
|
self.update_from_syslog(sys.stdin)
|
||||||
print 'Lecture des logs terminee'
|
print 'Lecture des logs terminée'
|
||||||
|
|
||||||
def do_dump(self):
|
def do_dump(self):
|
||||||
""" Affiche le contenu du dico """
|
""" Affiche le contenu du dico """
|
||||||
|
@ -110,18 +128,28 @@ class ComptesInactifs:
|
||||||
|
|
||||||
def get_idle_accounts(self, since=32*24*3600):
|
def get_idle_accounts(self, since=32*24*3600):
|
||||||
"""
|
"""
|
||||||
Renvoie la liste de ceux qui ne se sont pas connectes depuis
|
Renvoie la liste des couples (login, objet Adherent) de ceux qui
|
||||||
since secondes, par defaut un mois (32 jours, pour etre sur).
|
ne se sont pas connectés depuis since secondes, par défaut un mois
|
||||||
|
(32 jours, pour etre sûr).
|
||||||
"""
|
"""
|
||||||
oldest = self.dic.get('!', int(time()))
|
oldest = self.dic.get('!', int(time()))
|
||||||
limit = int(time()) - since
|
limit = int(time()) - since
|
||||||
liste = [a
|
liste = []
|
||||||
for a in os.listdir('/home')
|
for x in os.listdir('/home'):
|
||||||
if os.path.isdir('/var/mail/' + a)
|
if os.path.isdir('/var/mail/' + x) and self.dic.get(x, oldest) < limit:
|
||||||
and self.dic.get(a, oldest) < limit]
|
a = db.search('uid=%s' % x)['adherent']
|
||||||
|
if a:
|
||||||
|
liste.append((x, a[0]))
|
||||||
|
else:
|
||||||
|
print 'uid=%s introuvable' % x
|
||||||
|
liste.sort()
|
||||||
return liste
|
return liste
|
||||||
|
|
||||||
def do_summary(self):
|
def do_summary(self):
|
||||||
|
"""
|
||||||
|
Envoie à disconnect un résume des comptes inactifs depuis plus d'un
|
||||||
|
mois.
|
||||||
|
"""
|
||||||
modele = u"""*Membres inscrits ne s'étant pas connectés depuis plus d'un mois*
|
modele = u"""*Membres inscrits ne s'étant pas connectés depuis plus d'un mois*
|
||||||
|
|
||||||
%(inscrits)s
|
%(inscrits)s
|
||||||
|
@ -141,32 +169,18 @@ L'analyse des logs remonte au %(oldest)s.
|
||||||
--
|
--
|
||||||
comptes_inactifs.py
|
comptes_inactifs.py
|
||||||
"""
|
"""
|
||||||
liste = []
|
|
||||||
for x in self.get_idle_accounts():
|
|
||||||
a = db.search('uid=%s' % x)['adherent']
|
|
||||||
if a:
|
|
||||||
liste.append((x, a[0]))
|
|
||||||
else:
|
|
||||||
print 'uid=%s introuvable' % x
|
|
||||||
liste.sort()
|
|
||||||
|
|
||||||
inscrits = []
|
inscrits = []
|
||||||
anciens = []
|
anciens = []
|
||||||
|
|
||||||
for (x, a) in liste:
|
for (x, a) in self.get_idle_accounts():
|
||||||
date = self.dic.get(x)
|
date = self.dic.get(x)
|
||||||
if date:
|
if date:
|
||||||
date = strftime(u'%d/%m/%Y %H:%M', localtime(date))
|
date = strftime(u'%d/%m/%Y %H:%M', localtime(date))
|
||||||
else:
|
else:
|
||||||
date = u'Jamais'
|
date = u'Jamais'
|
||||||
forward = os.path.isfile('/home/%s/.forward' % x) and u'X' or u''
|
forward = os.path.isfile('/home/%s/.forward' % x) and u'X' or u''
|
||||||
try:
|
mail = nb_mails_non_lus(x)
|
||||||
maildir = '/var/mail/%s/new' % x
|
mail = mail == None and u'?' or mail > 0 and u'X' or u' '
|
||||||
mail = os.path.isdir(maildir) and os.listdir(maildir) and u'X' or u''
|
|
||||||
except:
|
|
||||||
# Arrive quand le script n'a pas les bons droits pour lire
|
|
||||||
# /var/mail
|
|
||||||
mail = u'?'
|
|
||||||
ligne = (a.id(), x, a.Nom(), date, forward, mail)
|
ligne = (a.id(), x, a.Nom(), date, forward, mail)
|
||||||
if ann_scol in a.paiement():
|
if ann_scol in a.paiement():
|
||||||
inscrits.append(ligne)
|
inscrits.append(ligne)
|
||||||
|
@ -189,6 +203,22 @@ comptes_inactifs.py
|
||||||
u'Comptes inactifs',
|
u'Comptes inactifs',
|
||||||
modele % locals())
|
modele % locals())
|
||||||
|
|
||||||
|
def do_spam(self):
|
||||||
|
""" Envoie un mail explicatif aux possesseurs de compte inactif """
|
||||||
|
# Nombre de personnes concernées, en expansant de droite à gauche :
|
||||||
|
# inscrit/ancien, avec/sans procmail, avec/sans mail non lu
|
||||||
|
# Voir aussi template_path
|
||||||
|
stats = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
|
||||||
|
# On factorise la connexion
|
||||||
|
smtp = SMTP()
|
||||||
|
smtp.connect()
|
||||||
|
|
||||||
|
for (x, a) in self.get_idle_accounts():
|
||||||
|
pass
|
||||||
|
|
||||||
|
smtp.quit()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
args = sys.argv[1:]
|
args = sys.argv[1:]
|
||||||
|
@ -199,7 +229,7 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
commande = args[0]
|
commande = args[0]
|
||||||
if commande not in ('log', 'dump', 'summary'):
|
if commande not in ('log', 'dump', 'summary'):
|
||||||
sys.stderr.write("Commande incorrecte : %s\n" % args[1])
|
sys.stderr.write("Commande incorrecte : %s\n" % commande)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
ci_db = ComptesInactifs('/usr/scripts/var/comptes_inactifs.dict')
|
ci_db = ComptesInactifs('/usr/scripts/var/comptes_inactifs.dict')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue