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 # Copyright (C) Stéphane Glondu
# Licence : GPLv2 # Licence : GPLv2
u"""Ce script permet au trésorier de contrôler plus facilement le travail u"""Ce script permet au trésorier de repérer plus facilement les papiers que
des câbleurs. 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 import sys, os, re
sys.path.append('/usr/scripts/gestion') 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 !" print u"Il faut être contrôleur pour exécuter ce script !"
sys.exit(1) 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 from socket import gethostname
testing = gethostname().split(".")[0] == 'egon' debug = False
if testing:
print coul(u'Mode testing !', 'violet') if gethostname().split(".")[0] == 'egon':
debug = 'glondu@crans.org'
ann_scol = 2004 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): def _controle_interactif_adherents(liste, quoi):
u""" """
Contrôle interactif des adhérents de la liste (quoi = p ou c). Contrôle interactif des adhérents de la liste (quoi = p ou c).
Retourne (nb_OK, nb_pas_OK). Retourne (nb_OK, nb_pas_OK).
""" """
@ -81,7 +112,7 @@ def _controle_interactif_adherents(liste, quoi):
def _controle_interactif_clubs(liste): def _controle_interactif_clubs(liste):
u""" """
Contrôle interactif des clubs de la liste (uniquement la charte). Contrôle interactif des clubs de la liste (uniquement la charte).
Retourne (nb_OK, nb_pas_OK). Retourne (nb_OK, nb_pas_OK).
""" """
@ -114,7 +145,7 @@ def _controle_interactif_clubs(liste):
def controle_interactif(quoi): def controle_interactif(quoi):
u""" """
Procédure interactive de contrôle des paiements/chartes (quoi=p) et cartes (quoi=c). Procédure interactive de contrôle des paiements/chartes (quoi=p) et cartes (quoi=c).
""" """
if quoi not in 'pc': raise ValueError if quoi not in 'pc': raise ValueError
@ -144,53 +175,58 @@ def controle_interactif(quoi):
def formater_pour_cableur(liste): def formater_pour_cableur(liste):
u""" """
Formate la liste d'adhérents ou de clubs avec les dates correspondantes. Formate la liste d'adhérents ou de clubs avec les dates correspondantes.
liste est une liste de couples (date, objet). liste est une liste de couples (date, objet).
""" """
lignes = [(u'id', u'Nom', u'Date Heure')] 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: for date, a in liste:
lignes.append((a.id(), a.Nom(), date)) 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): def formater_pour_bureau(dico):
u""" """
Formate la liste d'adhérents ou de clubs avec les câbleurs correspondantes Formate la liste d'adhérents ou de clubs avec les câbleurs correspondantes
pour le mail récapitulatif envoyé à bureau. pour le mail récapitulatif envoyé à bureau.
""" """
lignes = [(u'id', u'Nom', u'Câbleur')] lignes = [(u'id', u'Nom', u'Câbleur')]
total = 0 total = 0
for cableur in dico.keys():
liste = dico.keys()
liste.sort()
for cableur in liste:
for date, a in dico[cableur]: for date, a in dico[cableur]:
lignes.append((a.id(), a.Nom(), cableur)) lignes.append((a.id(), a.Nom(), cableur))
total += 1 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): def qui(historique, quoi):
u""" """
Recherche le câbleur qui a effectué la dernière modification quoi Recherche le câbleur qui a effectué la dernière modification quoi
dans l'historique, ou qui a inscrit l'adhérent. 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'^([^,]*), ([^ :]*)') regexp = re.compile(r'^([^,]*), ([^ :]*)')
cableur = ('_inconnu_', '_inconnu_') cableur = ('_inconnu_', '_inconnu_')
for ligne in historique: for ligne in historique:
if quoi in ligne or 'inscription' in ligne: 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) if matched: cableur = matched.group(1), matched.group(2)
return cableur return cableur
def chercher_cableurs(liste, quoi): def chercher_cableurs(liste, quoi):
u""" """
Renvoie un dictionnaire cableur->adherents à partir de liste, quoi Renvoie un dictionnaire cableur->adherents à partir de liste, quoi
désigne le champ qui sera recherché dans l'historique. désigne le champ qui sera recherché dans l'historique.
""" """
@ -204,128 +240,180 @@ def chercher_cableurs(liste, quoi):
return resultat return resultat
from smtplib import SMTP from email_tools import send_email, parse_mail_template
from email.MIMEText import MIMEText
# Mise en application du mémorable cours de Fred sur les objets :-)
def envoyer_mails_rappel(): class ControleMailer:
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 def __init__(self):
cableurs = {} # Recherche des câbleurs possédant des cotisations/chartes
for a in paiements.keys(): todo_list = db.search('paiement=%d&controle!=*p*' % ann_scol)
if a != '_inconnu_': cableurs[a] = None self._paiements = chercher_cableurs(todo_list['adherent'], 'paiement')
for a in chartes.keys(): self._chartes = chercher_cableurs(todo_list['club'], 'paiement')
if a != '_inconnu_': cableurs[a] = None
for a in cartes.keys():
if a != '_inconnu_': cableurs[a] = None
# Squelette à modifier après # Recherche des câbleurs possédant des cartes d'étudiant
msg_skeleton = u"""\ todo_list = db.search('carteEtudiant=%d&controle!=*c*' % ann_scol)
Salut, self._cartes = chercher_cableurs(todo_list['adherent'], 'carteEtudiant')
Tu me dois des papiers. J'ai mis l'aid ou le cid afin que tu puisses # Récupère tous les câbleurs qui doivent quelque chose
vérifier facilement dans la base. cableurs = {}
%s for a in self._paiements.keys():
Peux-tu confirmer et donner ces papiers le plus rapidement possible à if a != '_inconnu_': cableurs[a] = None
Florian, Augustin, les laisser au 2B ou directement me les donner ? for a in self._chartes.keys():
if a != '_inconnu_': cableurs[a] = None
for a in self._cartes.keys():
if a != '_inconnu_': cableurs[a] = None
self._cableurs = cableurs.keys()
-- # Vérification de l'alias pour l'expéditeur
Stéphane if u'tresorier' in cableur.alias():
""" self._sender = u'%s <tresorier@crans.org>' % cableur.Nom()
else:
self._sender = u'%s <%s@crans.org>' % (cableur.Nom(),
cableur.cannonical_alias() or cableur.mail())
# Vérification de l'alias pour l'envoi des mails # Se connecte au serveur SMTP par défaut
if u'tresorier' in cableur.alias(): from smtplib import SMTP
moi = (u'%s <tresorier@crans.org>' % cableur.Nom()).encode('utf8') self._server = SMTP()
else: self._server.connect()
moi = (u'%s <%s@crans.org>' % (cableur.Nom(), cableur.canonical_alias())).encode('utf8')
# On se connecte au serveur def __del__(self):
s = SMTP() # Termine la connexion au serveur SMTP
s.connect() self._server.quit()
# On envoie les mails def recapitulatif(self):
nb = 0 """
for c in cableurs.keys(): Renvoie le récapitulatif pour le bureau.
"""
msg = u'' msg = u''
if c in paiements.keys(): if self._paiements:
msg += u"\nFiches d'adhésion et cotisations des adhérents :\n" msg += u"Fiches d'adhésion et cotisations des adhérents :\n"
msg += formater_pour_cableur(paiements[c]) + '\n' msg += formater_pour_bureau(self._paiements) + '\n\n'
if c in chartes.keys(): if self._chartes:
msg += u"\nChartes signées des clubs :\n" msg += u"Chartes signées des clubs :\n"
msg += formater_pour_cableur(chartes[c]) + '\n' msg += formater_pour_bureau(self._chartes) + '\n\n'
if c in cartes.keys(): if self._cartes:
msg += u"\nCarte d'étudiant des adhérents :\n" msg += u"Carte d'étudiant des adhérents :\n"
msg += formater_pour_cableur(cartes[c]) + '\n' msg += formater_pour_bureau(self._cartes) + '\n\n'
mail = MIMEText((msg_skeleton % msg).encode('utf8'), _charset='UTF-8') return msg
mail['Subject'] = u'Papiers manquants'.encode('utf8')
mail['From'] = moi def mail_bureau(self):
adresse_cableur = '%s@crans.org' % c """
mail['To'] = adresse_cableur Envoie le mail récapitulatif à bureau (s'il y a qqch à envoyer).
mail['Cc'] = 'Bureau <bureau@crans.org>' """
if testing: msg = self.recapitulatif()
recipients = ['glondu@crans.org'] 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: else:
recipients = [adresse_cableur, 'bureau@crans.org'] return coul(u'Tout est à jour, aucun mail envoyé.', 'vert')
s.sendmail(moi, recipients, mail.as_string())
nb += 1
# On envoie le mail récapitulatif sur bureau def mail_cableurs(self, subject, body, liste=None):
if paiements or chartes or cartes: """
msg = u'' 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
if liste == None:
liste = self._cableurs
msg += u"\nFiches d'adhésion et cotisations des adhérents :\n" for c in liste:
msg += formater_pour_bureau(paiements) + '\n' msg = u''
msg += u"\nChartes signées des clubs :\n" if self._paiements.has_key(c):
msg += formater_pour_bureau(chartes) + '\n' msg += u"Fiches d'adhésion et cotisations des adhérents :\n"
msg += formater_pour_cableur(self._paiements[c]) + '\n\n'
msg += u"\nCarte d'étudiant des adhérents :\n" if self._chartes.has_key(c):
msg += formater_pour_bureau(cartes) + '\n' msg += u"Chartes signées des clubs :\n"
msg += formater_pour_cableur(self._chartes[c]) + '\n\n'
msg += u"\n-- \nScript exécuté par %s\n" % cableur.Nom() if self._cartes.has_key(c):
mail = MIMEText(msg.encode('utf8'), _charset='utf8') msg += u"Carte d'étudiant des adhérents :\n"
mail['Subject'] = u'Récapitulatif des papiers manquants'.encode('utf8') msg += formater_pour_cableur(self._cartes[c]) + '\n\n'
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() if msg:
print coul(u"%d mail(s) envoyé(s) avec succès !" % nb, "vert") send_email(self._sender,
"%s@crans.org" % c,
subject,
body % msg,
server = self._server,
cc = u'Bureau <bureau@crans.org>',
debug = debug)
nb += 1
return coul(u'%d mail(s) envoyé(s) aux câbleurs avec succès !' % nb, 'vert')
def __usage(): def __usage(message=None):
u""" Comment ça marche ? """ """ Comment ça marche ? """
print __doc__ % {'prog': sys.argv[0]} print __doc__ % { 'prog': sys.argv[0] }
if message:
print message
sys.exit(1) sys.exit(1)
if __name__ == '__main__' : if __name__ == '__main__' :
if len(sys.argv) == 2:
if sys.argv[1] == 'paiement': if len(sys.argv) <= 1:
controle_interactif('p')
elif sys.argv[1] == 'carte':
controle_interactif('c')
elif sys.argv[1] == 'mail':
envoyer_mails_rappel()
else:
__usage()
else:
__usage() __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':
mailer = ControleMailer()
cableurs = sys.argv[2:]
if cableurs:
bureau = False
if 'bureau' in cableurs:
cableurs.remove('bureau')
bureau = True
else:
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(u'Commande inconnue : %s' % sys.argv[1])
sys.exit(0) sys.exit(0)
# pydoc n'aime pas l'unicode :-(