scripts/stats_cableurs.py
Antoine Durand-Gasselin f1cb76f449 [stats_cableurs] on affiche les stats sur les machines, par mois
Ignore-this: 3e3d76242fcd7250d97409abb5b53fdb

darcs-hash:20090328124206-bd074-d5a2a44d0daf538ece093e91ce6deb5407128e24.gz
2009-03-28 13:42:06 +01:00

328 lines
12 KiB
Python

#!/usr/bin/python
# -*- mode: python; coding: utf-8 -*-
#
# stats_cableurs.py
# -----------------
#
# Copyright (C) 2008, 2009 François Bobot <bobot@crans.org>,
# Jeremie Dimino <jeremie@dimino.org>,
# Michel Blockelet <blockelet@crans.org>,
# Antoine Durand-Gasselin <adg@crans.org>
#
# 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 sys, re, datetime, time
sys.path.append("/usr/scripts/gestion/")
from ldap_crans import CransLdap
from affich_tools import cprint
db = CransLdap()
__DAYS_IN_PREVIOUS_MONTH = [datetime.timedelta(days) for days in
[ 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 ] ]
def parse_ligne_histo(ligne):
u"""Parse une ligne d'historique et renvoie (['dd', 'mm', 'yyyy'],
['date', 'heure', 'who', 'what'])"""
champ = ligne.replace(',', '').replace(': ', '').split(' ')
sdate = champ[0].split('/')
date = datetime.date(int(sdate[2]), int(sdate[1]), int(sdate[0]))
return date, champ
def parse_historique(truc):
u"""Parse l'historique"""
return [ parse_ligne_histo(ligne) for ligne in truc.historique() ]
def dec_date(date):
u"""retranche un mois à la date."""
return (date - __DAYS_IN_PREVIOUS_MONTH[date.month -1])
class StatsCableursBase:
u"""Classe prototype pour afficher des stats de câbleurs."""
colonnes = [('score', u'Son score')]
nbmois = 4
stats = {}
def __init__(self, mois = -4):
if mois > 0:
# si on demande depuis 09 (septembre) , on remonte
# jusqu'à septembre
self.nbmois = (datetime.date.today().month + 12 - mois) % 12
else:
# si on demande les stats sur 4 mois, on remonte sur 4
# mois
self.nbmois = - mois
# On récupère les statistiques
self.get_stats()
# On les affiche
self.print_stats()
def get_stats(self):
u"""Génération dummy de statistiques"""
self.stats = {}
def print_stats(self):
u"""Affiche pour chaque cableur les valeurs de ses différentes colonnes
définies dans self.colonnes."""
stats = self.stats
cableurs = stats.keys()
### Si quelqu'un trouve une manière plus élégante de faire…
try:
cableurs.sort(lambda x, y : cmp(stats[x]['score'], stats[y]['score']), reverse=True)
except TypeError:
cableurs.sort(lambda x, y : cmp(stats[x][0], stats[y][0]), reverse=True)
long_max = reduce(lambda m, c : max(m, len(c)), cableurs, len('cableur'))
# Titres des colonnes
ligne = "%-*s" % (long_max, u'Câbleur')
for typ, nom in self.colonnes:
ligne += " | %s" % nom
cprint(ligne)
# Ligne pour délimiter
ligne = ''.center(long_max, '-')
for typ, nom in self.colonnes:
ligne += "-+-%s" % ''.center(len(nom), '-')
cprint(ligne)
# Statiqtiques par câbleur
for cableur in cableurs:
acts = stats[cableur]
ligne = "%-*s" % (long_max, cableur)
for typ, nom in self.colonnes:
ligne += " | %*d" % (len(nom), acts[typ])
cprint(ligne)
def sort_events(self, events):
u"""Split une liste d'évènements selon les mois"""
sorted_events = []
since = datetime.date.replace(datetime.date.today(), day = 1)
backwards = self.nbmois
while backwards > 0:
sorted_events.append([ ev for ev in events if ev[0] >= since ])
events = [ ev for ev in events if ev[0] < since ]
backwards -= 1
since = dec_date(since)
sorted_events.append(events)
return sorted_events
class StatsCableursMachines(StatsCableursBase):
u"""Cette classe s'occupe de recenser l'activité des différents
câbleurs sur les machines, ce qui représente le travail typique du
câbleur en milieu d'année"""
def ajoute_actions(self, machine, hist):
u"""Ajoute dans hist la liste des actions effectués par
chacuns des câbleurs sur la machine pendant les mois."""
for date, champ in parse_historique(machine):
# on ne va pas non plus compter les actions qu'on fait sur
# ses propres machines.
if machine.proprietaire().compte() != champ[2]:
# Il se peut qu'une personne sans les droits câbleur ait
# effectué une action.
try:
hist[champ[2]].append( (date, champ[3]) )
except KeyError:
hist[champ[2]] = [ (date, champ[3]) ]
def get_stats(self):
u"""Récupère les statistiques des différents câbleurs sur les
différentes machines"""
# La liste des câbleurs en tant qu'entité ldap, histoire de bien
# faire apparaître ceux qui n'ont rien fait
ldap_cableurs = db.search("droits=cableur")['adherent']
# On récupère la liste des machines
all_machines = db.search('mid=*')
machines = all_machines['machineFixe'] + all_machines['machineWifi']
# hists permet de répartir toutes les actions sur les différents
# câbleurs.
hists = {}
for i in ldap_cableurs:
hists[i.compte()] = []
# on récupère l'historique des machines que l'on met dans hists
for becane in machines:
self.ajoute_actions(becane, hists)
split_hist = {}
for cableur in hists.keys():
split_hist[cableur] = self.sort_events(hists[cableur])
self.stats[cableur] = [ len(i) for i in split_hist[cableur] ]
score = sum (self.stats[cableur][:-1])
self.stats[cableur].insert(0, score)
month = datetime.date.today()
for i in range(self.nbmois):
self.colonnes.append( (i + 1, "%d/%02d" % (month.month, month.year - 2000)))
month = dec_date(month)
self.colonnes[0] = (0, "%d last" % self.nbmois)
self.colonnes.append( (self.nbmois +1, "< " + self.colonnes[-1][1]) )
if __name__ == "__main__":
StatsCableursMachines()
## class StatsCableursAdherents:
## u"""Cette classe s'occupe de recenser les actions que les câbleurs
## font sur les adhérents (en fait les {,re}adhésions)."""
##
## colonnes = [('inscription', u'inscription'),
## ('reinscription', u'réinscription'),
## ('total', u'score total')]
##
## date_debut_ann_scol = time.mktime((ann_scol, 8, 1, 0, 0, 0, 0, 0, 0))
## paiement_ann_scol = "paiement+%d" % ann_scol
##
## def donne_cableur(mois, adherent):
## u""" Cherche le cableur qui a inscrit ou réinscrit un adhérent. """
## cableur = None
##
## # Est-ce qu'on recherche une inscription ou une reinscription?
## if adherent.dateInscription() < self.date_debut_ann_scol:
## action = 'reinscription'
## action_filtre = self.paiement_ann_scol
## else:
## action = 'inscription'
## action_filtre = 'inscription'
##
## for hist in adherent.historique():
## # On decoupe pour avoir un truc utilisable
## champ = hist.replace(',', '').replace(': ', '').split(' ')
## # On inspecte la date
## date = champ[0].split('/')
## if int(date[1]) in mois and int(date[2]) == ann_scol:
## # Maintenant on regarde si l'action recherchee est ici
## if action_filtre in champ[3:]:
## return action, champ[2]
##
## return action, None
##
## def calcul_score(mois):
## u""" Calcul le score de tous les cableurs ayant inscrit ou
## réinscrit quelqu'un pour l'année en cours. """
##
## liste = db.search("paiement=2008")['adherent']
##
## score = {}
## for adherent in liste:
## action, cableur = donne_cableur(mois, adherent)
## if cableur:
## if not score.has_key(cableur):
## score[cableur] = { 'inscription': 0,
## 'reinscription': 0 }
## score[cableur][action] += 1
##
## # On calcul le score total pour chaque cableur
## for s in score.values():
## s['total'] = 2 * s['inscription'] + s['reinscription']
##
## return score
##
## def classement(score={}):
## u""" Retourne la liste des câbleurs classé par score total décroisant. """
## cableurs = score.keys()
## cableurs.sort(lambda x, y : cmp(score[x]['total'], score[y]['total']), reverse=True)
## return cableurs
##
##
##
## if __name__ == "__main__":
## nb_affiche = 10
## mois = range(8, 11)
## if len(sys.argv) > 1:
## if sys.argv[1] == '-e':
## mois = range(8, 13)
## if len(sys.argv) > 2:
## try:
## nb_affiche = int(sys.argv[2])
## except ValueError:
## nb_affiche = 10
## else:
## try:
## nb_affiche = int(sys.argv[1])
## except ValueError:
## nb_affiche = 10
##
## if sys.argv[1] == '--efficiency':
## ActionsCableurs([(1, 2009), (2, 2009), (3, 2009)])
## sys.exit(0)
##
## score = calcul_score(mois)
## classement = classe(score)
##
## if nb_affiche > 0:
## classement = classement[0:nb_affiche]
##
## # On cherche les noms des câbleurs parceque c'est quand même mieux
## nom_reel = {}
## for cableur in classement:
## nom_reel[cableur] = db.search('uid=%s' % cableur)['adherent'][0].Nom()
##
## # Calcul des statistiques
## total_inscription = 0
## total_reinscription = 0
## total = 0
## for s in score.values():
## total_inscription += s['inscription']
## total_reinscription += s['reinscription']
## total += s['total']
## cprint(u"""Statistiques globales:
## - inscriptions: %(inscription)d
## - réinscription: %(reinscription)d
## - total: %(total)d
##
## """ % { 'inscription': total_inscription,
## 'reinscription': total_reinscription,
## 'total': total }, newline=False)
##
## # Calcul la longueur du nom le plus long
## long_max = reduce(lambda m, c : max(m, len(c)), nom_reel.values(), len('cableur'))
##
##
## # Titres des colonnes
## ligne = "%-*s" % (long_max, u'câbleur')
## for typ, nom in colonnes:
## ligne += " | %s" % nom
## cprint(ligne)
## # Ligne pour délimiter
## ligne = ''.center(long_max, '-')
## for typ, nom in colonnes:
## ligne += "-+-%s" % ''.center(len(nom), '-')
## cprint(ligne)
## # Statiqtiques par câbleur
## for cableur in classement:
## score_cableur = score[cableur]
## ligne = "%-*s" % (long_max, nom_reel[cableur])
## for typ, nom in colonnes:
## ligne += " | %*d" % (len(nom), score_cableur[typ])
## cprint(ligne)