
J'ai rajouté il y a quelques temps un continue dans certains cas, avec print à la clé. On ne faisait donc plus de màj du dernier job traité. On préfère donc le faire au début, pour éviter la redondance. De toute façon, si le body de la boucle plante, ça enverra un mail.
182 lines
6.8 KiB
Python
Executable file
182 lines
6.8 KiB
Python
Executable file
#! /usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
print_status.py
|
|
|
|
Récupère le statut des dernières impressions auprès de l'imprimante et envoie un
|
|
mail à l'intérressé quand son impression est sortie, ou envoie un message aux
|
|
imprimeurs si l'impression semble avoir échoué.
|
|
|
|
Auteur : Sylvain Boilard <boilard@crans.org>
|
|
License : BSD 2 clauses.
|
|
|
|
"""
|
|
|
|
import sys, os
|
|
sys.path.append("/usr/scripts/gestion")
|
|
|
|
import time
|
|
import httplib2
|
|
import re
|
|
import smtplib
|
|
from ldap_crans import crans_ldap
|
|
|
|
last_print_filename = "/var/run/print_status/last_print.txt"
|
|
# Cette chaîne est utilisée pour construire une regexp, il faut que ce soit une chaîne brute.
|
|
files_directory = r"/var/impression/fichiers/"
|
|
printer_host = "imprimante.adm.crans.org"
|
|
smtp_server = "smtp.crans.org"
|
|
error_send_to = u"impression@crans.org"
|
|
ok_mail = u"""Content-Type: text/plain; charset=utf-8
|
|
Content-Disposition: inline
|
|
Content-Transfer-Encoding: quoted-printable
|
|
From: %s
|
|
To: %s
|
|
Subject: [Impression] Impression de "%s" terminée.
|
|
|
|
Bonjour %s,
|
|
|
|
Le fichier "%s" que tu as envoyé %s
|
|
a été imprimé. Tu peux venir le récupérer au local impression, au 4ème étage du
|
|
bâtiment J, muni du code secret qui t'a été donné lorsque tu as envoyé ton
|
|
document. Si tu as oublié ce code, ou pour tout autre problème lié au service
|
|
d'impression, tu peux contacter les imprimeurs à l'adresse %s .
|
|
|
|
Bonne journée,
|
|
|
|
--
|
|
Les imprimeurs du Cr@ns
|
|
"""
|
|
error_mail = u"""Content-Transfer-Encoding: quoted-printable
|
|
Content-Type: text/plain; charset=utf-8
|
|
Content-Disposition: inline
|
|
From: %s
|
|
To: %s
|
|
Subject: [Impression][print_status.py] Impression potentiellement échouée.
|
|
|
|
Bonjour,
|
|
|
|
Il semble y avoir eu un problème avec l'impression du fichier
|
|
"%s" (tâche n°%s) de %s (uid=%s),
|
|
lancée %s.
|
|
Le statut de la tâche est "%s".
|
|
|
|
Aucun autre mail ne sera envoyé à ce sujet. Si nécéssaire, veuillez tenir
|
|
l'intéressé au courant aux adresses suivantes :
|
|
|
|
%s
|
|
|
|
Bonne journée,
|
|
|
|
--
|
|
print_status.py
|
|
"""
|
|
|
|
litMonths = [u"Janvier", u"Février", u"Mars", u"Avril", u"Mai", u"Juin", u"Juillet", u"Août", u"Septembre", u"Octobre", u"Novembre", u"Décembre"]
|
|
|
|
def getMSE():
|
|
"""Retourne le nombre de millisecondes depuis le 1 Janvier 1970 sous forme d'une chaîne de caractères."""
|
|
return str(int(time.time()*1000.))
|
|
|
|
def buildDate(date):
|
|
"""Retourne la date et l'heure passée en argument après l'avoir mise en forme."""
|
|
dm, year, hms = date.split(' ')
|
|
day, month = dm.split('/')
|
|
hour, minute, _ = hms.split(':')
|
|
return u"le " + day + u" " + litMonths[int(month) - 1] + u" " + year + u" à " + hour + u":" + minute
|
|
|
|
def sendMail(from_addr, to_addrs, mail_content):
|
|
"""Wrapper pour smtplib.sendmail(). Permet d'attendre un peu en cas d'erreur temporaire (typiquement, si on essaie d'envoyer trop de mails à la minute)."""
|
|
conn = smtplib.SMTP(smtp_server)
|
|
try:
|
|
conn.sendmail(from_addr, to_addrs, mail_content)
|
|
except smtplib.SMTPSenderRefused as (code, _, _):
|
|
if code == 450:
|
|
time.sleep(65)
|
|
conn.sendmail(from_addr, to_addrs, mail_content)
|
|
else:
|
|
raise
|
|
conn.quit()
|
|
|
|
http = httplib2.Http()
|
|
|
|
# On récupère la liste des tâches. Pour faire la requête, on doit récupérer un cookie de session.
|
|
headers, _ = http.request("http://" + printer_host + "/twelcome.cgi?CorePGTAG=0&Dummy=" + getMSE())
|
|
_, content = http.request("http://" + printer_host + "/pprint.csv?Flag=Csv_Data&LogType=0&Dummy=" + getMSE(), 'GET', headers={'Cookie': headers['set-cookie']})
|
|
task_list = content.split('\n')
|
|
# On enlève les entêtes et les deux lignes vides à la fin de la liste.
|
|
task_list.pop(0)
|
|
task_list.pop()
|
|
task_list.pop()
|
|
|
|
# On récupère la dernière tâche à avoir été traitée la dernière fois quel le script a été lancé.
|
|
# Si le fichier n'existe pas, on le crée en y mettant la première tâche parmi celles que l'on vient de récupérer, et on s'arrête là.
|
|
try:
|
|
last_file = open(last_print_filename, "r")
|
|
last = last_file.read()
|
|
last_file.close()
|
|
except:
|
|
last_file = open(last_print_filename, "w")
|
|
last_file.write(task_list[0].split(',')[0])
|
|
last_file.close()
|
|
exit(0)
|
|
|
|
db = crans_ldap()
|
|
|
|
# On parcoure les tâches récupérées et on ne garde que celles qui n'ont pas déja été traitées.
|
|
# Au passage, on inverse leur ordre pour traiter la plus ancienne en premier.
|
|
# Ainsi, si le script plante, on n'envoie pas un mail aux adhérents à chaque fois que le cron le relance.
|
|
tasks_to_treat = []
|
|
for item in task_list:
|
|
if item.split(',', 1)[0] == last:
|
|
break
|
|
tasks_to_treat.append(item)
|
|
tasks_to_treat.reverse()
|
|
|
|
for item in tasks_to_treat:
|
|
fields = item.split(',', 6)
|
|
# On met à jour le numéro de la dernière tâche traitée.
|
|
last_file = open(last_print_filename, "w")
|
|
last_file.write(fields[0])
|
|
last_file.close()
|
|
if fields[3].strip('"') in ["root",'DIRECT PRINT']:
|
|
result = fields[1].strip('"')
|
|
jobinfos = fields[2].strip('"').split(':', 2)
|
|
if len(jobinfos) <= 2:
|
|
print "Skipping: %s" % fields[2]
|
|
continue
|
|
taskID, user, _ = jobinfos
|
|
user = user.split('@').pop() # On récupère le nom du club si besoin.
|
|
date = buildDate(fields[5])
|
|
match_taskID = re.compile(r"impression\(%s\)" % taskID)
|
|
db_query = db.search("uid=" + user)
|
|
if db_query['adherent']:
|
|
target = db_query['adherent'][0]
|
|
full_name = target.prenom() + u" " + target.nom()
|
|
if not '@' in target.mail():
|
|
mail = target.mail() + '@crans.org'
|
|
else:
|
|
mail = target.mail()
|
|
send_to = [ mail ]
|
|
else:
|
|
target = db_query['club'][0]
|
|
full_name = u"Club " + target.nom()
|
|
send_to = map(lambda aid : db.search("aid=" + aid)['adherent'][0].mail(), target.imprimeurs())
|
|
if send_to == []:
|
|
print "Skipping sending to %s, empty recipient" % full_name
|
|
continue
|
|
historique = target.historique()
|
|
historique.reverse() # Ce qu'on cherche a des chances d'être récent et donc d'être à la fin de l'historique.
|
|
file_dirname = files_directory + user + r"/"
|
|
match_doc_name = re.compile(file_dirname + r"[^ ]* ")
|
|
for hist_line in historique:
|
|
if match_taskID.search(hist_line):
|
|
filename = match_doc_name.search(hist_line).group()[len(file_dirname):-1]
|
|
break
|
|
if result == "OK":
|
|
mail_content = ok_mail % (error_send_to, u", ".join(send_to), filename, full_name, filename, date, error_send_to)
|
|
sendMail(error_send_to, send_to, mail_content.encode("utf-8"))
|
|
else:
|
|
mail_content = error_mail % (error_send_to, error_send_to, filename, taskID, full_name, user, date, result, u"\n".join(send_to))
|
|
sendMail(error_send_to, error_send_to, mail_content.encode("utf-8"))
|