#! /usr/bin/env python # -*- coding: iso-8859-15 -*- # Copyright (C) Stéphane Glondu # Licence : GPLv2 u"""Ce script permet au trésorier de contrôler plus facilement le travail des câbleurs. Usage: %(prog)s {paiement|carte|mail} Les options sont : * paiement : contrôle interactif des nouvelles (ré-)adhésions * carte : contrôle interactif des nouvelles cartes d'étudiant * mails : envoyer les mails de rappel""" import sys, os, re sys.path.append('/usr/scripts/gestion') # Fonctions d'affichage from affich_tools import coul, tableau, prompt # Importation de la base de données from ldap_crans import crans_ldap, ann_scol db = crans_ldap() # Détermination de l'uid du câbleur from user_tests import getuser uid = getuser() if not uid : print u"Impossible de déterminer l'utilisateur !" sys.exit(1) cableur = db.search('uid=%s' % uid)['adherent'][0] # Vérification des droits if u'Contrôleur' not in cableur.droits(): print u"Il faut être contrôleur pour exécuter ce script !" sys.exit(1) # Lors des tests sur egon, on m'envoie tous les mails ! from socket import gethostname testing = gethostname().split(".")[0] == 'egon' if testing: print coul(u'Mode testing !', 'violet') ann_scol = 2004 def _controle_interactif_adherents(liste, quoi): u""" Contrôle interactif des adhérents de la liste (quoi = p ou c). Retourne (nb_OK, nb_pas_OK). """ if quoi not in 'pc': raise ValueError explicite = {'p': u'du paiement', 'c': u"de la carte d'étudiant"}[quoi] restant = len(liste) print coul(u'\nContrôle %s des adhérents' % explicite, 'cyan') print u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n)." print u"Une autre réponse entraîne l'interruption du processus." print u"Le format est [nb_restant] Nom, Prénom (aid)." print nb = 0 for a in liste: ok = prompt(u'[%3d] %s, %s (%s) ?' % (restant, a.nom(), a.prenom(), a.id()), 'n', '').lower() restant -= 1 if ok == 'o': modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0] if modifiable._modifiable: modifiable.controle('+%s' % quoi) print modifiable.save() nb += 1 else: print coul(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge') elif ok != 'n': print coul(u'Arrêt du contrôle %s des adhérents' % explicite, 'rouge') break return nb, len(liste)-nb def _controle_interactif_clubs(liste): u""" Contrôle interactif des clubs de la liste (uniquement la charte). Retourne (nb_OK, nb_pas_OK). """ restant = len(liste) print coul(u'\nContrôle de la charte des clubs', 'cyan') print u"Pour chaque entrée, il faut taper 'o' ou 'n'." print u"Une autre réponse entraîne l'interruption du processus." print u"Le format est [nb_restant] Nom (cid)." print nb = 0 for c in liste: ok = prompt(u'[%2d] %s (%s) ?' % (restant, c.Nom(), c.id()), 'n', '').lower() restant -= 1 if ok == 'o': modifiable = db.search('cid=%s' % c.id(), 'w')['club'][0] if modifiable._modifiable: modifiable.controle('+p') print modifiable.save() nb += 1 else: print coul(u'Club %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge') elif ok != 'n': print coul(u'Arrêt du contrôle de la charte des clubs', 'rouge') break return nb, len(liste)-nb def controle_interactif(quoi): u""" Procédure interactive de contrôle des paiements/chartes (quoi=p) et cartes (quoi=c). """ if quoi not in 'pc': raise ValueError todo_list = db.search('%s=%d&controle!=*%s*' % ({'p': 'paiement', 'c': 'carteEtudiant'}[quoi], ann_scol, quoi)) # Tri de la liste des adhérents selon nom, prénom # Ça peut se faire plus facilement en Python 2.4 avec l'argument key todo_list['adherent'].sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom()))) # Traitement des adhérents oka, noka = _controle_interactif_adherents(todo_list['adherent'], quoi) if quoi == 'p': # Tri de la liste des clubs todo_list['club'].sort(lambda x, y: cmp(x.nom(), y.nom())) # Traitement des clubs (uniquement la charte) okc, nokc =_controle_interactif_clubs(todo_list['club']) print coul(u'\nRécapitulatif des nouveaux contrôles +%s :' % quoi, 'violet') liste = [(u'Catégorie', u'OK', u'pas OK'), (u'adhérents', str(oka), str(noka))] if quoi == 'p': liste.append((u'clubs', str(okc), str(nokc))) print tableau([15, 10, 10], liste) def formater_pour_cableur(liste): u""" Formate la liste d'adhérents ou de clubs avec les dates correspondantes. liste est une liste de couples (date, objet). """ lignes = [(u'id', u'Nom', u'Date Heure')] for date, a in liste: lignes.append((a.id(), a.Nom(), date)) return tableau([6, 40, 18], lignes) def formater_pour_bureau(dico): u""" Formate la liste d'adhérents ou de clubs avec les câbleurs correspondantes pour le mail récapitulatif envoyé à bureau. """ lignes = [(u'id', u'Nom', u'Câbleur')] total = 0 for cableur in dico.keys(): for date, a in dico[cableur]: lignes.append((a.id(), a.Nom(), cableur)) total += 1 return tableau([6, 40, 17], lignes) + '\nTotal : %d' % total def qui(historique, quoi): u""" Recherche le câbleur qui a effectué la dernière modification quoi dans l'historique, ou qui a inscrit l'adhérent. Retourne le couple (date_heure, nom_cableur). """ regexp = re.compile(r'^([^,]*), ([^ :]*)') cableur = ('_inconnu_', '_inconnu_') for ligne in historique: if quoi in ligne or 'inscription' in ligne: matched = regexp.match(ligne) if matched: cableur = matched.group(1), matched.group(2) return cableur def chercher_cableurs(liste, quoi): u""" Renvoie un dictionnaire cableur->adherents à partir de liste, quoi désigne le champ qui sera recherché dans l'historique. """ resultat = {} for a in liste: date, cableur = qui(a.historique(), quoi) if not resultat.has_key(cableur): resultat[cableur] = [] resultat[cableur].append((date, a)) return resultat from smtplib import SMTP from email.MIMEText import MIMEText def envoyer_mails_rappel(): u""" Envoyer les mails de rappel aux câbleurs avec bureau en cc, ainsi que le récapitulatif à bureau. """ # On recherche tous les câbleurs concernés todo_list = db.search('paiement=%d&controle!=*p*' % ann_scol) paiements = chercher_cableurs(todo_list['adherent'], 'paiement') chartes = chercher_cableurs(todo_list['club'], 'paiement') cartes = chercher_cableurs(db.search('carteEtudiant=%d&controle!=*c*' % ann_scol)['adherent'], 'carteEtudiant') # Méthode de Vince cableurs = {} for a in paiements.keys(): if a != '_inconnu_': cableurs[a] = None for a in chartes.keys(): if a != '_inconnu_': cableurs[a] = None for a in cartes.keys(): if a != '_inconnu_': cableurs[a] = None # Squelette à modifier après msg_skeleton = u"""\ Salut, Tu me dois des papiers. J'ai mis l'aid ou le cid afin que tu puisses vérifier facilement dans la base. %s Peux-tu confirmer et donner ces papiers le plus rapidement possible à Florian, Augustin, les laisser au 2B ou directement me les donner ? -- Stéphane """ # Vérification de l'alias pour l'envoi des mails if u'tresorier' in cableur.alias(): moi = (u'%s ' % cableur.Nom()).encode('utf8') else: moi = (u'%s <%s@crans.org>' % (cableur.Nom(), cableur.canonical_alias())).encode('utf8') # On se connecte au serveur s = SMTP() s.connect() # On envoie les mails nb = 0 for c in cableurs.keys(): msg = u'' if c in paiements.keys(): msg += u"\nFiches d'adhésion et cotisations des adhérents :\n" msg += formater_pour_cableur(paiements[c]) + '\n' if c in chartes.keys(): msg += u"\nChartes signées des clubs :\n" msg += formater_pour_cableur(chartes[c]) + '\n' if c in cartes.keys(): msg += u"\nCarte d'étudiant des adhérents :\n" msg += formater_pour_cableur(cartes[c]) + '\n' mail = MIMEText((msg_skeleton % msg).encode('utf8'), _charset='UTF-8') mail['Subject'] = u'Papiers manquants'.encode('utf8') mail['From'] = moi adresse_cableur = '%s@crans.org' % c mail['To'] = adresse_cableur mail['Cc'] = 'Bureau ' if testing: recipients = ['glondu@crans.org'] else: recipients = [adresse_cableur, 'bureau@crans.org'] s.sendmail(moi, recipients, mail.as_string()) nb += 1 # On envoie le mail récapitulatif sur bureau if paiements or chartes or cartes: msg = u'' msg += u"\nFiches d'adhésion et cotisations des adhérents :\n" msg += formater_pour_bureau(paiements) + '\n' msg += u"\nChartes signées des clubs :\n" msg += formater_pour_bureau(chartes) + '\n' msg += u"\nCarte d'étudiant des adhérents :\n" msg += formater_pour_bureau(cartes) + '\n' msg += u"\n-- \nScript exécuté par %s\n" % cableur.Nom() mail = MIMEText(msg.encode('utf8'), _charset='utf8') mail['Subject'] = u'Récapitulatif des papiers manquants'.encode('utf8') mail['From'] = moi mail['To'] = 'Bureau ' if testing: recipients = ['glondu@crans.org'] else: recipients = ['bureau@crans.org'] s.sendmail(moi, recipients, mail.as_string()) nb += 1 s.close() print coul(u"%d mail(s) envoyé(s) avec succès !" % nb, "vert") def __usage(): u""" Comment ça marche ? """ print __doc__ % {'prog': sys.argv[0]} sys.exit(1) if __name__ == '__main__' : if len(sys.argv) == 2: if sys.argv[1] == 'paiement': controle_interactif('p') elif sys.argv[1] == 'carte': controle_interactif('c') elif sys.argv[1] == 'mail': envoyer_mails_rappel() else: __usage() else: __usage() sys.exit(0)