scripts/impression/class_impression.py
bernat c28734caab Plus robuste.
Ceci dit, je ne vois pas pourquoi on ne se dbarasse pas du nom
original dans sa totalit. Car avec cette mthode, on ne neutralise
pas entirement le nom. Pourquoi ne pas simplement garder le rsultat
de mkstemp comme nom de fichier ?

darcs-hash:20060127085813-d1718-46c8257721915b7e0df16a13513f5351ac0e2272.gz
2006-01-27 09:58:13 +01:00

426 lines
19 KiB
Python
Executable file

#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
#
# Class pour l'impression depuis le web par cups
# Codé par Francois
# Inspiré par le backend écrit par Benoit, Fred et Brice, inspirés par CUPSPykota
# Licence : GNU General Public Licence, version 2
import sys, time, tempfile, os, commands, string
sys.path.append('/usr/scripts/impression')
sys.path.append('/usr/scripts/gestion')
from config import impression
#sys.path.append('/localhome/bobot/scripts/gestion')
from ldap_crans import crans_ldap
#import vraicouts
duree_vie_pdf=3600
#fonction principal: impression (fichier_impression)
class test:
def mail(self):
return u"francois.bobot@crans.org"
def Nom(self):
return u"francois"
def solde(self,modif=0.):
return (40.+modif)
def save(self):
pass
class fichier_impression :
nom_job=''
nbr_pages=1
nb_copie=1
taille="A4"
recto_verso=False
transparent=False
couleur=True
cout=0.0
portrait=True
user=""
user_ldap=None #seras une instance de l'utilisateur dans la base ldap.
imprime=-1 #-2 impression en suspend, -1 mise dans la file d'attente, 0 devis, time pour l'heure, -3 déja imprimé ou devis fait depuis trops longtemps : le pdf n'est plus disponible
nom_fichier_pdf="" #chemin et nom du pdf
nom_fichier_desc="" #chemin et nom du fichier contenant les options de l'utilisateur
list_messages=[] #liste d'erreur et de remarque
list_messages_importants=[]
list_messages_admin=[] #liste d'erreur réservé au administrateur
erreur_critique=False #True si une erreur empêchant l'impression est apparue
code=None #code pour le digicode
modif_epoch=0.0 #moment de création du job ou devis. exprimé en epoch (float) : nombre de seconde depuis la référence du temps unix (+-=1970)
job_id=None #champs pour de futur amélioration
def actualise_cout(self):
# Calcul du cout de l'impression :
retour = cout(self)
# Met le prix dans cout s'il n'y a pas d'erreur
if type(retour) is float :
self.cout=retour
self.list_messages_importants.append('cout')
else:
self.erreur_critique=True
self.list_messages_importants.append('erreur_critique')
self.list_messages_admin.append('erreur_cout')
sys.stderr.write(retour)
#repond vrai si le solde est assez élevé.
def test_cout(self):
if self.user_ldap==None:
self.user_ldap = utilisateur(self.user,False)
#self.user_ldap = test()
return not (self.cout > (self.user_ldap.solde() - impression.decouvert)) #!impression.decouvert est négatif.
def fait_payer(self):
self.user_ldap = utilisateur(self.user,True)
#self.user_ldap = test()
self.user_ldap.solde(-self.cout)
self.user_ldap.save()
return not (self.cout > (self.user_ldap.solde() - impression.decouvert))
def gen_code(self):
#Génération du code et écriture du code
i=0
code=0
import random
#instance de base
rand=random.Random()
#graine automatique avec le temps
rand.seed()
while(i<1000) :
#on génère le numéro de session
code=rand.randint(100000,999999) #pour avoir six chiffres
#on verifie que le code n'est déja pas utilisé
try:
open("/var/impression/codes/%d" %code, 'r')
#open("/home/bobot/tmp/codes/%d" %code, 'r')
except :
break
i=i+1
if code:
#on enregistre le fichier avec le code pour numéro
codefichier=open("/var/impression/codes/%d" %code, 'w')
#codefichier=open("/localhome/bobot/codes/%d" %code, 'w')
codefichier.write("Utilisateur %s\n"%(self.user_ldap.Nom()))
codefichier.close()
self.code=code
self.list_messages_importants.append('code')
else :
# Grosse erreur : on logue, on previent et on stoppe.
print ("ERROR: Il n'y a pas de code disponible" )
sys.stderr.write ("ERROR: Il n'y a pas de code disponible" )
try:
#crans_backend.send_email(prix.From, "Impression <%s>" % impression.From_imprimante , u"ERREUR " + sujet, mail_err % {'erreur' : "Il n'y a plus de code disponible.\n"})
self.list_messages_importants.append('erreur gen_code')
sys.stderr.write("DEBUG: Un rapport de bug a ete automatiquement envoye.\n")
except :
sys.stderr.write("ERROR: Impossible d'envoyer le rapport de bug.\n")
sys.stderr.write("ERROR: Plus de codes disponibles.\n")
sys.stderr.write("ERROR: Penser a ouvrir a l'adherent debite...\n")
#sys.exit(1)
def impression(self):
# Envoi du fichier à CUPS
#Création de la liste d'options
#pour le nombre de copies
options ='-# '+str(self.nb_copie)
#options ='-n '+str(self.nb_copie)
#pour spécifier l'imprimante
options +=' -P laserjet'
#pour spécifier la version du language postscript utilisé par pdftops
options +=' -o pdf-level3'
#pour donner le titre de l'impression
options +=' -T '+self.nom_job
#options +=' -t '+self.nom_job
#pour donner le login de l'adherent
options +=' -U '+self.user
#pour demander une page de garde
options +=' -o job-sheets=crans' #page de garde de type standard
if self.transparent :
options+=' -o InputSlot=Tray1 -o Media=Transparency'
if self.taille=='A4':
options+=(' -o pdf-paper=571x817 -o PageSize=A4')
else:
options+=(' -o pdf-paper=825x1166 -o InputSlot=Tray3 -o HPPaperPolicy=A3 -o PageSize=A3')
if self.portrait:
if self.recto_verso:
options+=(' -o sides=two-sided-long-edge')
else:
options+=(' -o sides=one-sided')
else:
options+=(' -o landscape')
if self.recto_verso:
options+=' -o sides=two-sided-short-edge'
else:
options+=' -o sides=one-sided'
options+=' -o HPColorasGray='+str(not self.couleur)
(status,rep) = commands.getstatusoutput("lpr %s %s" %(options,self.nom_fichier_pdf))
if status<>0:
print "<p>status:"+str(status)+" rep:"+rep+"</p>"
#else:
#self.job_id=rep.split(' ')[3]
def corrige (self):
#
# fic_impr=fichier_impression()
# fic_impr.user=utilisateur(arguments[2],rw)
#trouve le nombre de pages
self.nbr_pages = int(os.popen("pdfinfo %s | grep Pages " % (self.nom_fichier_pdf)).readline().split()[1])
##Corrige les aberrations
##Correction des aberations (transparent et recto_verso :) )
##Priorité des informations par ordre décroissant
##Transparent, paper, nbr_page, recto_verso
if (self.taille<>'A4') & (self.taille<>'A3'):
self.list_messages_importants.append("paper")
self.erreur_critique=True
if self.transparent:
if self.paper<>'A4':
self.list_messages.append("A3 transparent")
self.paper='A4'
if self.recto_verso:
self.list_messages.append("Recto_verso transparent")
self.recto_verso=False
if self.nbr_pages==1 & self.recto_verso:
self.list_messages.append("Recto_verso 1 page")
self.recto_verso=False
def affiche_messages_html(self):
body=""
"""if self.imprime:
body=string.join(map ((dico_message_laserjet.get),self.list_messages_importants))
if len(self.list_messages)<>0:
body=body+'\nRemarques:\n'+string.join(map ((dico_message_laserjet.get),self.list_messages))
else:
body=string.join(map ((dico_message_devis.get),self.list_messages_importants))
body=body+'\nRemarque:\n'+string.join(map ((dico_message_devis.get),self.list_messages))
body=body % {'taille' : self.taille, 'code' : self.code, 'solde' : self.user_ldap.solde(), 'cout' : self.cout , 'adresse_imprimante' : impression.From_imprimante}
"""
body=string.join(self.list_messages_importants)
return "<p>"+body+"</p>"
def enregistre_pdf(self,f_value,f_nom,dossier):
f_nom = f_nom.translate(string.maketrans(string.punctuation+string.whitespace,'_' * len(string.punctuation+string.whitespace)))
(fd_fichier_desc,self.nom_fichier_desc) = tempfile.mkstemp(suffix='.desc',prefix=f_nom,dir=dossier)
os.close(fd_fichier_desc)
os.chmod(self.nom_fichier_desc,33184)
self.nom_fichier_pdf=self.nom_fichier_desc[0:-5]+".pdf"
#(,self.nom_fichier_pdf) = tempfile.mkstemp(suffix='.pdf',prefix=identifiant+f_nom,dir=data_dir+identifiant)
file_obj_pdf=open(self.nom_fichier_pdf,'w')
file_obj_pdf.write(f_value)
file_obj_pdf.close()
self.nbr_pages = int(os.popen("pdfinfo '%s' | grep Pages " % (self.nom_fichier_pdf)).readline().split()[1])
self.modif_epoch=time.time()
def sauve_desc(self):
file_obj_desc=open(self.nom_fichier_desc,'w')
for key in ("erreur_critique","nom_job","nbr_pages","nb_copie","taille","recto_verso","transparent","couleur","cout","portrait","user","imprime","nom_fichier_pdf","nom_fichier_desc","code","modif_epoch","job_id"):
file_obj_desc.write(key+"="+str(getattr(self,key))+"\n")
file_obj_desc.close()
def read_desc(self):
file_obj_desc=open(self.nom_fichier_desc,'r')
ligne=file_obj_desc.readline()[0:-1]
while ligne<>"":
parse=ligne.split("=")
if parse[1]=='None':
setattr(self,parse[0],None)
else:
if parse[0] in ("nom_job","taille","user","nom_fichier_pdf","nom_fichier_desc","job_id"):
setattr(self,parse[0],parse[1])
else:
if parse[0] in ("nbr_pages","nb_copie","imprime","code"):
setattr(self,parse[0],int(parse[1]))
else:
if parse[0] in ("recto_verso","transparent","couleur","portrait","erreur_critique"):
setattr(self,parse[0],(parse[1]=='True'))
else:
if parse[0] in ("cout","modif_epoch"):
setattr(self,parse[0],float(parse[1]))
else:
self.erreur_critique=True
print '<p>ligne non parser:'+ligne+'</p>'
ligne=file_obj_desc.readline()[0:-1]
file_obj_desc.close()
#Vérifie que le fichier existe bien si il doit exister.
if not os.access(self.nom_fichier_pdf,os.F_OK):
if self.imprime<>-3:
self.imprime=-4
#else:
# if (time.time()-self.modif_epoch)>duree_vie_pdf:
# os.remove(self.nom_fichier_pdf)
# self.imprime=-4
#fonction utilisé par print et str : renvoie le string canonique de l'objet
def __repr__(self):
dict_contraire={'couleur' : 'Noir et Blanc' , 'transparent' : 'Normal' , 'portrait': 'Paysage' , 'recto_verso' : 'Recto' , 'erreur_critique' : "Pas d'erreur"}
dict_normale={'couleur' : 'Couleur' , 'transparent' : 'Transparent' , 'portrait': 'Portrait' , 'recto_verso' : 'Recto-Verso' , 'erreur_critique' : "Problême survenue"}
#dict_imprime={-4: 'PDF indisponible', -3: 'Envoyé', -2 : 'En suspend', -1 : "En cours d'envoi", 0 : "Devis"}
#corps="<TABLE BORDER=0 CELLPADDDING=2>\n<TR><th ALIGN=CENTER COLSPAN=2><U>"+self.nom_job+"</U></th><td ALIGN=RIGHT>"+time.ctime(self.modif_epoch)+"</TR>\n"
corps="<TABLE BORDER=0 CELLPADDDING=2>\n<TR><th ALIGN=CENTER COLSPAN=2><U>"+self.nom_job+"</U></th><td ALIGN=RIGHT>"+time.ctime(0.0)+"</TR>\n"
corps+="<TR><td>\n<TABLE BORDER=2 RULES=ROWS CELLPADDDING=0>\n"
#if self.imprime>0:
# t=time.localtime(self.imprime)
# date="le %i à %i:%i" % t[2:4]
#else:
# date=dict_imprime[self.imprime]
#corps+="<TR><td>Impression</td><td>"+date+"</td></TR>\n"
for key in ("nbr_pages","nb_copie","taille","code"):
corps+='<TR><td>'+key+"</td><td>"+str(getattr(self,key))+"</td></TR>\n"
corps+="</TABLE>\n</td>\n<td>\n<TABLE BORDER=2 RULES=ROWS CELLPADDDING=0>\n"
for key in ("couleur","transparent","portrait","recto_verso"):
if getattr(self,key):
corps+='<TR><td>'+dict_normale[key]+"</td></TR>\n"
else:
corps+='<TR><td>'+dict_contraire[key]+"</td></TR>\n"
corps+="</TABLE>\n</td><td><U>"
if self.erreur_critique:
corps+="erreur de comptage"
else:
corps+=str(self.cout)+"euros"
corps+="</U></td></TR>\n</TABLE>"
#if self.job_id<>None:
# corps+="Le travaille à été imprimé sous le nom : "+self.job_id+"<BR/>
return corps
def utilisateur(user, rw):
""" Renvoie l'adherent qui imprime le job
* user est l'utilisateur (argument n°2 des paramètres passés au backend)
* rw vaut True si on veut modifier le compte LDAP de l'adhérent,
False dans le cas contraire
"""
# Impression en local avec les certificats (possible pour le groupe adm)
if user=="root":
sys.stderr.write("ERROR: Utilisateur root passé en paramètre.\n")
sys.exit(0) # On conclue l'impression
# Récupération de l'adhérent
try:
base = crans_ldap()
if rw:
res=base.search("login=%s"%user,'w')['adherent']
else:
res=base.search("login=%s"%user)['adherent']
except:
print ("ERROR: Erreur : Base LDAP non joignable\n")
sys.exit(0) # On arrete l'avant-impression ?on arrete l'imprimante?
# Si on ne trouve rien :
if len(res) != 1 :
print ("ERROR: Erreur : adhérent %s non trouvé\n" % user)
sys.exit(0) # On conclue l'avant-impression sans stopper l'imprimante
adherent = res[0]
sys.stderr.write("DEBUG: Adherent %s recupere.\n" % adherent.Nom())
return adherent
#fonction cout calcule le pourcentage de couleur sur les pages
# renvoit un string avec le nom de l'erreur si erreur il y a
#renvoit un float dans les cas de fonctionnement...
def cout( fic_impr):
#taille peut valoir A3 ou A4
#nb_copie est le nombre de copies désirées
#nom_rep seras le dossier dans tmp ou tous les fichier créé par convert seront entreposé
nom_rep=tempfile.mkdtemp(prefix='tmpimpr')
nom_png=nom_rep + "/convert.png" #nom prefixe et chemin des png créé par convert
if (fic_impr.taille == "A3"):
# Une feuille A3 couvre 2 fois plus de surface que A4
c_taille = impression.c_a3
cout_coul = 2*impression.c_coul
cout_noir = 2*impression.c_noir
else:
cout_coul = impression.c_coul
cout_noir = impression.c_noir
if fic_impr.transparent:
c_taille = impression.c_trans
else:
c_taille = impression.c_a4
if (fic_impr.couleur):
#convertit les pdf en png couleur
#(status,rep) = commands.getstatusoutput("nice -n 5 convert %s %s" % (fic_impr.nom_fichier_pdf,nom_png))
(status,rep) = commands.getstatusoutput("nice -n 5 gs -sDEVICE=png16m -r30 -dBATCH -dNOPAUSE -dSAFER -dPARANOIDSAFER -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dMaxBitmap=50000000 -sOutputFile=%s -q %s" % (nom_png,fic_impr.nom_fichier_pdf))
if status:
return "ERREUR : Fichier invalide. Aucun png n'a été créé.\n"
#récupère la liste des fichiers
list_filepng=os.listdir(nom_rep)
#calcule le nombre de pixel de couleur
remplissage = [0, 0, 0, 0, 0] # C, M, J, N, nombre de pages
for fichier in list_filepng:
resultats = commands.getoutput("nice -n 5 /usr/scripts/impression/percentcolour %s" % (nom_rep+'/'+fichier))
#resultats = '2.103:3.363:4.131:29.300:1'
l_resultats = resultats.split(":")
for i in [0, 1, 2, 3]:
remplissage[i] += float(l_resultats[i])*float(l_resultats[4])
remplissage[4] += float(l_resultats[4])
total_noir = remplissage[3]
total_couleur = sum(remplissage[0:3])
faces = int(remplissage[4])
if (fic_impr.recto_verso == False):
pages = faces # nb de pages par copies
else:
pages = int(faces/2.+0.5)
if total_couleur > 0:
c_total = c_taille*pages+(impression.c_tambour_coul+impression.c_tambour_noir)*faces+cout_noir*total_noir+cout_coul*total_couleur
else: # Pas de couleur, malgre l'indication
c_total = c_taille*pages+impression.c_tambour_noir*faces+cout_noir*total_noir
else:
#convertit les pdf en png
#(status,rep) = commands.getstatusoutput("nice -n 5 convert -colorspace GRAY %s %s" % (fic_impr.nom_fichier_pdf,nom_png))
(status,rep) = commands.getstatusoutput("nice -n 5 gs -sDEVICE=pnggray -r30 -dBATCH -dNOPAUSE -dSAFER -dPARANOIDSAFER -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dMaxBitmap=50000000 -sOutputFile=%s -q %s" % (nom_png,fic_impr.nom_fichier_pdf))
if status:
return "ERREUR : Fichier invalide. Aucun png n'a été créé.\n"
#récupère la liste des fichiers
list_filepng=os.listdir(nom_rep)
remplissage = [0, 0] # Noir, nombre de pages
for fichier in list_filepng:
#resultats = commands.getoutput("/home/bobot/crans/impression/percentblack '%s'" % (nomrep+'/'+fichier))
resultats = commands.getoutput("nice -n 5 /usr/scripts/impression/percentblack '%s'" % (nom_rep+'/'+fichier) )
#resultats = '2.103:3.363:4.131:29.300:1'
l_resultats = resultats.split(":")
remplissage[0] += float(l_resultats[0])*float(l_resultats[1])
remplissage[1] += float(l_resultats[1])
total_noir = remplissage[0]
faces = int(remplissage[1])
if (fic_impr.recto_verso == False):
pages = faces # nb de pages par copies
else:
pages = int(faces/2.+0.5)
c_total = c_taille*pages+impression.c_tambour_noir*faces+cout_noir*total_noir
c_total = int(fic_impr.nb_copie*c_total+impression.fact+0.5) # arrondi et facture
if commands.getoutput("rm -r -f " + nom_rep):
self.list_messages_admin.append('erreur_cout')
sys.stderr.write("ERREUR : Impossible d'enlever le dossier.\n")
return float(c_total)/100