fin_connexion: regarde les finAdhesion + calendar
This commit is contained in:
parent
68ce0eac00
commit
67369a8b3c
1 changed files with 114 additions and 26 deletions
|
@ -1,19 +1,29 @@
|
|||
#!/bin/bash /usr/scripts/python.sh
|
||||
# -*- coding: utf-8 -*-
|
||||
# Draf de code pour alerter les adhérents de leur fin de connexion imminente
|
||||
# Draft de code pour alerter les adhérents de leur fin de connexion imminente
|
||||
# Ce script devra aussi permettre d'alerter les cableurs sur les prochaines
|
||||
# affluences en perm
|
||||
|
||||
import sys
|
||||
import pytz
|
||||
import datetime
|
||||
from dateutil.parser import parse as parse_gtf
|
||||
import calendar
|
||||
|
||||
from lc_ldap.shortcuts import lc_ldap_readonly
|
||||
from lc_ldap.variables import base_dn
|
||||
import ldap
|
||||
from affich_tools import coul
|
||||
|
||||
#: Une journée (c'est plus pratique)
|
||||
DAY = datetime.timedelta(days=1)
|
||||
|
||||
#: Format des dates dans la base LDAP
|
||||
FORMAT_LDAP = '%Y%m%d%H%M%S%z'
|
||||
|
||||
#: Infos à oublier dans un datetime pour ne garder que le jour
|
||||
ERASE_DAY = { 'second': 0, 'minute': 0, 'microsecond': 0, 'hour': 0, }
|
||||
|
||||
#: filtre ldap max(finConnexion) \in intervalle
|
||||
# NB: finConnexion est un attribut ldap multivalué, et on s'intéresse ici
|
||||
# à sa valeur max pour un adhérent.
|
||||
|
@ -23,44 +33,122 @@ FORMAT_LDAP = '%Y%m%d%H%M%S%z'
|
|||
# L'autre inégalité ( < ) est plus délicate :
|
||||
# max(F) < v <=> \forall x\in F x < v <=> \not( \exists x\in F x >= v )
|
||||
# <=> \not( finConnexion>= v )
|
||||
filtre_tpl = u'(&(finConnexion>=%s)(!(finConnexion>=%s)))'
|
||||
FILTRE_TPL_SIMPLE = u'(&(finConnexion>=%(debut)s)(!(finConnexion>=%(fin)s)))'
|
||||
|
||||
try:
|
||||
with open('/etc/timezone', 'r') as f:
|
||||
tz = pytz.timezone(f.read().strip())
|
||||
except:
|
||||
tz = pytz.UTC
|
||||
# Le cas précédent était simplifié, en réalité, la connexion s'achève dès que
|
||||
# l'adhésion se termine. On regarde donc min(max(finConnexion), max(finAdhesion))
|
||||
# min(a,b) >= v <=> a >= v /\ b >= v
|
||||
# min(a,b) < v <=> a < v \/ b < v
|
||||
FILTRE_TPL = u"""(&
|
||||
(&(finConnexion>=%(debut)s)(finAdhesion>=%(debut)s))
|
||||
(|(!(finConnexion>=%(fin)s))(!(finAdhesion>=%(fin)s)))
|
||||
)"""
|
||||
|
||||
#: Périodicité du script (pour n'envoyer le mail qu'une fois)
|
||||
periodicite = datetime.timedelta(days=7)
|
||||
|
||||
#: Dans combien de temps la connexion aura-t-elle expiré ?
|
||||
expire_delay = datetime.timedelta(days=21)
|
||||
# Calcul de la timezone locale
|
||||
#try:
|
||||
# with open('/etc/timezone', 'r') as f:
|
||||
# tz = pytz.timezone(f.read().strip())
|
||||
#except:
|
||||
# tz = pytz.UTC
|
||||
# usage :
|
||||
# datetime.datetime.now(tz)
|
||||
|
||||
c = lc_ldap_readonly()
|
||||
|
||||
# Instant courant: on ne garde que le jour
|
||||
to_erase = { 'second': 0, 'minute': 0, 'microsecond': 0, 'hour': 0, }
|
||||
now = datetime.datetime.now(tz).replace(**to_erase)
|
||||
now = datetime.datetime.now()
|
||||
|
||||
# Applique un delta, si spécifié
|
||||
for arg in sys.argv[1:]:
|
||||
if arg.startswith('+'):
|
||||
now += datetime.timedelta(days=int(arg[1:]))
|
||||
print "Nous serons le %s" % now
|
||||
now += int(arg[1:])*DAY
|
||||
today = now.replace(**ERASE_DAY)
|
||||
print "Nous serons le %s" % today
|
||||
|
||||
fin = now + expire_delay
|
||||
warn_debut = fin - periodicite
|
||||
def compute_fin_connexion(adh):
|
||||
return min( max(parse_gtf(v.value) for v in adh['fin' + l])
|
||||
for l in ['Adhesion', 'Connexion'])
|
||||
|
||||
filtre = filtre_tpl % tuple(d.strftime(FORMAT_LDAP) for d in [warn_debut, fin] )
|
||||
def select(conn, begin, to, mode='r'):
|
||||
"""Récupère les adhérents dont la connexion expire entre les datetimes
|
||||
``begin`` (inclu) et ``to`` (exclu)"""
|
||||
# Nous avons besoin de dates avec timezone.
|
||||
if not begin.tzinfo:
|
||||
begin = begin.replace(tzinfo=pytz.UTC)
|
||||
if not to.tzinfo:
|
||||
to = to.replace(tzinfo=pytz.UTC)
|
||||
data = { 'debut': begin.strftime(FORMAT_LDAP),
|
||||
'fin': to.strftime(FORMAT_LDAP),
|
||||
}
|
||||
filtre = FILTRE_TPL % data
|
||||
|
||||
# NB: on ne prend que les adhérents, d'où SCOPE_ONELEVEL
|
||||
to_warn = c.search(filtre, scope=ldap.SCOPE_ONELEVEL, dn=base_dn)
|
||||
res = conn.search(filtre, scope=ldap.SCOPE_ONELEVEL, dn=base_dn, mode=mode)
|
||||
|
||||
return res
|
||||
|
||||
print ("%d adhérents seront prévenu que leur connexion expire entre le %s " + \
|
||||
"et le %s") % (len(to_warn), warn_debut, fin)
|
||||
def brief(c, debut, fin):
|
||||
if not debut.tzinfo:
|
||||
debut = debut.replace(tzinfo=pytz.UTC)
|
||||
if not fin.tzinfo:
|
||||
fin = fin.replace(tzinfo=pytz.UTC)
|
||||
to_warn = select(c, debut, fin)
|
||||
print ("%d adhérents seront prévenus que leur connexion expire entre le %s " + \
|
||||
"et le %s") % (len(to_warn), debut, fin)
|
||||
|
||||
if "--list" in sys.argv:
|
||||
for adh in to_warn:
|
||||
print repr(adh) + ' ' + adh.dn.split(',', 1)[0]
|
||||
valeurs = [max(parse_gtf(v.value) for v in adh[l]) \
|
||||
for l in ['finConnexion', 'finAdhesion'] ]
|
||||
[f_con, f_adh] = [ coul(str(v), 'rouge' if v >= debut and v < fin else 'vert') \
|
||||
for v in valeurs]
|
||||
print "%r %s %s;%s" % (adh, adh.dn.split(',', 1)[0], f_con, f_adh)
|
||||
return to_warn
|
||||
|
||||
def prev(c, date):
|
||||
"""Prévisualise l'expiration des connexions sur le mois courant"""
|
||||
month = date.month
|
||||
year = date.year
|
||||
|
||||
cal = calendar.Calendar()
|
||||
first = datetime.datetime(day=1, month=month, year=year, tzinfo=pytz.UTC)
|
||||
last = first + 31*DAY # un peu plus probablement
|
||||
disconnect = brief(c, first, last)
|
||||
by_day = {x: 0 for x in xrange(1,32)}
|
||||
for adh in disconnect:
|
||||
date = compute_fin_connexion(adh)
|
||||
by_day[date.day] += 1
|
||||
|
||||
spaces = 3
|
||||
days = ['L', 'M', 'Me', 'J', 'V', 'S', 'D']
|
||||
print " ".join(d + ' '*(spaces-len(d)) for d in days)
|
||||
l = []
|
||||
for d in cal.itermonthdays(year, month):
|
||||
if not d:
|
||||
item = ""
|
||||
elif not by_day[d]:
|
||||
item = "."
|
||||
else:
|
||||
item = str(by_day[d])
|
||||
l.append(item + ' '*(spaces-len(item)))
|
||||
if len(l) == 7:
|
||||
print " ".join(l)
|
||||
l = []
|
||||
if l:
|
||||
print " ".join(l)
|
||||
|
||||
|
||||
# Plusieurs type d'execution:
|
||||
# * Manuel (préventif): avertit d'une déco dans moins d'un mois
|
||||
# select(c, today, today+30*DAY)
|
||||
# * Quotidien (préventif) : avertit d'une déco dans moins d'un mois
|
||||
# select(c, today+(30-1)*DAY, today+30*DAY)
|
||||
# * Quotidien (last chance): avertit d'une déco dans moins de 4 jours
|
||||
# (l'idée, c'est qu'il y a toujours une perm entre les deux)
|
||||
# select(c, today+(4-1)*DAY, today+4*DAY)
|
||||
# * Mensuel: avertit les cableurs des connexions à expiration dans le mois
|
||||
# prochain
|
||||
# select(c, first_day, last_day+DAY)
|
||||
# prev(c, today+28*DAY)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue