Envoi de mail.

Plus de flexibilit.
Par Stphane.

darcs-hash:20051112202343-d1718-8362a0de7a93945ae9250cbabb102e33e02e2271.gz
This commit is contained in:
bernat 2005-11-12 21:23:43 +01:00
parent 2c8793825d
commit d30c547306

View file

@ -4,15 +4,36 @@
# Copyright (C) Stéphane Glondu
# Licence : GPLv2
u"""Ce script permet au trésorier de contrôler plus facilement le travail
des câbleurs.
u"""Ce script permet au trésorier de repérer plus facilement les papiers que
les câbleurs n'ont pas encore rendus.
Usage: %(prog)s {paiement|carte|mail}
Utilisations possibles :
* %(prog)s {paiement|carte|list} [--debug <adresse>]
* %(prog)s mail <liste> [--debug <adresse>]
L'unique option est :
--debug <adresse> envoyer tous les mails à l'<adresse> indiquée, plutôt
qu'aux vrais destinataires
Les commandes sont :
* paiement contrôle interactif des nouvelles (-)adhésions
* carte contrôle interactif des nouvelles cartes d'étudiant
* list affiche le récapitulatif des papiers manquants
* mail <liste> envoyer les mails de rappel aux câbleurs dont le
login est dans la <liste>, 'bureau' désignant le mail
récapitulatif envoyé à bureau ; si la liste est vide
tous les mails nécessaires seront envoyés
Le modèle du mail envoyé aux câbleurs est lu sur l'entrée standard (typiquement
via une redirection). Les trois premières lignes doivent être :
Encoding: <encodage du fichier>
Subject: <sujet du mail>
<ligne vide>
Le reste est le corps du message. Il doit contenir une occurrence de '%%s' qui
sera remplacée par la liste des papiers manquants.
Le mail récapitulatif envoyé à bureau est immuable."""
Les options sont :
* paiement : contrôle interactif des nouvelles (-)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')
@ -37,16 +58,26 @@ if u'Contr
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 !
# Lors des tests, on m'envoie tous les mails !
from socket import gethostname
testing = gethostname().split(".")[0] == 'egon'
if testing:
print coul(u'Mode testing !', 'violet')
debug = False
if gethostname().split(".")[0] == 'egon':
debug = 'glondu@crans.org'
ann_scol = 2004
if __name__ == '__main__':
if len(sys.argv) > 3 and sys.argv[-2] == '--debug':
debug = sys.argv[-1]
sys.argv.pop()
sys.argv.pop()
if debug:
print u'Mode debug, tous les mails seront envoyés à %s.' % debug
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).
"""
@ -81,7 +112,7 @@ def _controle_interactif_adherents(liste, quoi):
def _controle_interactif_clubs(liste):
u"""
"""
Contrôle interactif des clubs de la liste (uniquement la charte).
Retourne (nb_OK, nb_pas_OK).
"""
@ -114,7 +145,7 @@ def _controle_interactif_clubs(liste):
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
@ -144,53 +175,58 @@ def controle_interactif(quoi):
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')]
total = 0
liste.sort(lambda x, y: cmp(x[1].nom(), y[1].nom()))
for date, a in liste:
lignes.append((a.id(), a.Nom(), date))
total += 1
return tableau([6, 40, 18], lignes)
return tableau([6, 40, 18], lignes) + u'\nTotal : %d' % total
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():
liste = dico.keys()
liste.sort()
for cableur in liste:
for date, a in dico[cableur]:
lignes.append((a.id(), a.Nom(), cableur))
total += 1
return tableau([6, 40, 17], lignes) + '\nTotal : %d' % total
return tableau([6, 40, 18], lignes) + u'\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).
Retourne le couple (date, cableur) ou ('_inconnu_', '_inconnu_').
"""
regexp = re.compile(r'^([^,]*), ([^ :]*)')
cableur = ('_inconnu_', '_inconnu_')
for ligne in historique:
if quoi in ligne or 'inscription' in ligne:
matched = regexp.match(ligne)
matched = regexp.search(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.
"""
@ -204,128 +240,180 @@ def chercher_cableurs(liste, quoi):
return resultat
from smtplib import SMTP
from email.MIMEText import MIMEText
from email_tools import send_email, parse_mail_template
# Mise en application du mémorable cours de Fred sur les objets :-)
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
class ControleMailer:
def __init__(self):
# Recherche des câbleurs possédant des cotisations/chartes
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')
self._paiements = chercher_cableurs(todo_list['adherent'], 'paiement')
self._chartes = chercher_cableurs(todo_list['club'], 'paiement')
# Méthode de Vince
# Recherche des câbleurs possédant des cartes d'étudiant
todo_list = db.search('carteEtudiant=%d&controle!=*c*' % ann_scol)
self._cartes = chercher_cableurs(todo_list['adherent'], 'carteEtudiant')
# Récupère tous les câbleurs qui doivent quelque chose
cableurs = {}
for a in paiements.keys():
for a in self._paiements.keys():
if a != '_inconnu_': cableurs[a] = None
for a in chartes.keys():
for a in self._chartes.keys():
if a != '_inconnu_': cableurs[a] = None
for a in cartes.keys():
for a in self._cartes.keys():
if a != '_inconnu_': cableurs[a] = None
self._cableurs = cableurs.keys()
# 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
# Vérification de l'alias pour l'expéditeur
if u'tresorier' in cableur.alias():
moi = (u'%s <tresorier@crans.org>' % cableur.Nom()).encode('utf8')
self._sender = u'%s <tresorier@crans.org>' % cableur.Nom()
else:
moi = (u'%s <%s@crans.org>' % (cableur.Nom(), cableur.canonical_alias())).encode('utf8')
self._sender = u'%s <%s@crans.org>' % (cableur.Nom(),
cableur.cannonical_alias() or cableur.mail())
# On se connecte au serveur
s = SMTP()
s.connect()
# Se connecte au serveur SMTP par défaut
from smtplib import SMTP
self._server = SMTP()
self._server.connect()
# On envoie les mails
def __del__(self):
# Termine la connexion au serveur SMTP
self._server.quit()
def recapitulatif(self):
"""
Renvoie le récapitulatif pour le bureau.
"""
msg = u''
if self._paiements:
msg += u"Fiches d'adhésion et cotisations des adhérents :\n"
msg += formater_pour_bureau(self._paiements) + '\n\n'
if self._chartes:
msg += u"Chartes signées des clubs :\n"
msg += formater_pour_bureau(self._chartes) + '\n\n'
if self._cartes:
msg += u"Carte d'étudiant des adhérents :\n"
msg += formater_pour_bureau(self._cartes) + '\n\n'
return msg
def mail_bureau(self):
"""
Envoie le mail récapitulatif à bureau (s'il y a qqch à envoyer).
"""
msg = self.recapitulatif()
if msg:
msg += u"-- \nScript exécuté par %s\n" % cableur.Nom()
send_email(self._sender,
u"Bureau <bureau@crans.org>",
u"Récapitulatif des papiers manquants",
msg,
server = self._server,
debug = debug)
return coul(u'Mail envoyé à bureau avec succès !', 'vert')
else:
return coul(u'Tout est à jour, aucun mail envoyé.', 'vert')
def mail_cableurs(self, subject, body, liste=None):
"""
Envoie un mail aux câbleurs concernés qui figurent dans la liste.
Si liste vaut None, envoie un mail à tous les câbleurs concernés.
Les arguments subject, body permettent de personnaliser (un peu)
le mail qui sera envoyé.
"""
nb = 0
for c in cableurs.keys():
if liste == None:
liste = self._cableurs
for c in liste:
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 self._paiements.has_key(c):
msg += u"Fiches d'adhésion et cotisations des adhérents :\n"
msg += formater_pour_cableur(self._paiements[c]) + '\n\n'
if c in chartes.keys():
msg += u"\nChartes signées des clubs :\n"
msg += formater_pour_cableur(chartes[c]) + '\n'
if self._chartes.has_key(c):
msg += u"Chartes signées des clubs :\n"
msg += formater_pour_cableur(self._chartes[c]) + '\n\n'
if c in cartes.keys():
msg += u"\nCarte d'étudiant des adhérents :\n"
msg += formater_pour_cableur(cartes[c]) + '\n'
if self._cartes.has_key(c):
msg += u"Carte d'étudiant des adhérents :\n"
msg += formater_pour_cableur(self._cartes[c]) + '\n\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 <bureau@crans.org>'
if testing:
recipients = ['glondu@crans.org']
else:
recipients = [adresse_cableur, 'bureau@crans.org']
s.sendmail(moi, recipients, mail.as_string())
if msg:
send_email(self._sender,
"%s@crans.org" % c,
subject,
body % msg,
server = self._server,
cc = u'Bureau <bureau@crans.org>',
debug = debug)
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 <bureau@crans.org>'
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")
return coul(u'%d mail(s) envoyé(s) aux câbleurs avec succès !' % nb, 'vert')
def __usage():
u""" Comment ça marche ? """
print __doc__ % {'prog': sys.argv[0]}
def __usage(message=None):
""" Comment ça marche ? """
print __doc__ % { 'prog': sys.argv[0] }
if message:
print message
sys.exit(1)
if __name__ == '__main__' :
if len(sys.argv) == 2:
if sys.argv[1] == 'paiement':
if len(sys.argv) <= 1:
__usage()
elif sys.argv[1] == 'paiement':
if len(sys.argv) != 2:
__usage(u'Mauvaise utilisation de paiement')
controle_interactif('p')
elif sys.argv[1] == 'carte':
if len(sys.argv) != 2:
__usage(u'Mauvaise utilisation de carte')
controle_interactif('c')
elif sys.argv[1] == 'list':
if len(sys.argv) != 2:
__usage(u'Mauvaise utilisation de list')
print ControleMailer().recapitulatif(),
elif sys.argv[1] == 'mail':
envoyer_mails_rappel()
mailer = ControleMailer()
cableurs = sys.argv[2:]
if cableurs:
bureau = False
if 'bureau' in cableurs:
cableurs.remove('bureau')
bureau = True
else:
__usage()
bureau = True
cableurs = mailer._cableurs
if cableurs:
print u'Des mails vont être envoyés aux câbleurs, lecture du modèle...'
subject, body = parse_mail_template(sys.stdin)
try:
body % u''
except TypeError:
print u"Le format du modèle n'est pas correct, arrêt."
sys.exit(1)
print u'Modèle OK, on envoie les mails...'
print mailer.mail_cableurs(subject, body, cableurs)
if bureau:
print mailer.mail_bureau()
else:
__usage()
__usage(u'Commande inconnue : %s' % sys.argv[1])
sys.exit(0)
# pydoc n'aime pas l'unicode :-(