From 590e0d4e1726b9d1ac3b675e66f324e7db00b163 Mon Sep 17 00:00:00 2001 From: salles Date: Mon, 9 Jan 2006 13:54:15 +0100 Subject: [PATCH] import initial darcs-hash:20060109125415-72cb0-ae9f4a673384b8e7226459f32235d7cf1c490872.gz --- impression/class_impression.py | 409 +++++++++++++++++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100755 impression/class_impression.py diff --git a/impression/class_impression.py b/impression/class_impression.py new file mode 100755 index 00000000..563c56d8 --- /dev/null +++ b/impression/class_impression.py @@ -0,0 +1,409 @@ +#! /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=None #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 + options ='-# '+str(self.nb_copie) + #options ='-n '+str(self.nb_copie) + options +=' -P laserjet' + options +=' -T '+self.nom_job + #options +=' -t '+self.nom_job + options +=' -U '+self.user + options +=' -o job-sheets=crans' #page de garde de type standard + if self.transparent : + options+=' -o PageSize=A4 -o Media=Transparency' + else: + options+=(' -o PageSize='+self.taille) + 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 "

status:"+str(status)+" rep:"+rep+"

" + #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 "

"+body+"

" + + def enregistre_pdf(self,f_value,f_nom,dossier): + (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 '

ligne non parser:'+ligne+'

' + 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="\n\n" + corps+="\n\n
"+self.nom_job+""+time.ctime(self.modif_epoch)+"
\n\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+="\n" + for key in ("nbr_pages","nb_copie","taille","code"): + corps+='\n" + corps+="
Impression"+date+"
'+key+""+str(getattr(self,key))+"
\n
\n\n" + for key in ("couleur","transparent","portrait","recto_verso"): + if getattr(self,key): + corps+='\n" + else: + corps+='\n" + corps+="
'+dict_normale[key]+"
'+dict_contraire[key]+"
\n
" + if self.erreur_critique: + corps+="erreur de comptage" + else: + corps+=str(self.cout)+"euros" + corps+="
" + #if self.job_id<>None: + # corps+="Le travaille à été imprimé sous le nom : "+self.job_id+"
+ 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 + + + + +