diff --git a/impression/class_impression.py b/impression/class_impression.py index f1b1ec36..5ab51caf 100755 --- a/impression/class_impression.py +++ b/impression/class_impression.py @@ -1,10 +1,12 @@ #! /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 + +""" +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, random sys.path.append('/usr/scripts/impression') @@ -16,6 +18,8 @@ duree_vie_pdf=3600 #fonction principal: impression (fichier_impression) +################################################################################ + class test: def mail(self): return u"francois.bobot@crans.org" @@ -26,316 +30,325 @@ class test: 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 # sera 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 futures améliorations + 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 # sera 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 futures améliorations - def actualise_cout(self): - # Calcul du cout de l'impression : - retour = cout(self) + 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) + # 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) - return not (self.cout > (self.user_ldap.solde() - + # Repond vrai si le solde est assez élevé. + def test_cout(self): + if self.user_ldap == None: + self.user_ldap = utilisateur(self.user, False) + return not (self.cout > (self.user_ldap.solde() - impression.decouvert)) # /!\ decouvert est négatif. - def fait_payer(self): - self.user_ldap = utilisateur(self.user,True) - self.user_ldap.solde(-self.cout) - self.user_ldap.save() - return not (self.cout > (self.user_ldap.solde() - impression.decouvert)) + def fait_payer(self): + self.user_ldap = utilisateur(self.user,True) + 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 - rand=random.Random() - # Graine automatique avec le temps - rand.seed() + def gen_code(self): + # Génération du code et écriture du code + rand=random.Random() + # Graine automatique avec le temps + rand.seed() - for i in range(1000): - # On génère un code - code = rand.randint(100000,999999) - # Si le code est libre, on sort de la boucle - if not os.path.exists("/var/impression/codes/%d" % code): - break + for i in range(1000): + # On génère un code + code = rand.randint(100000,999999) + # Si le code est libre, on sort de la boucle + if not os.path.exists("/var/impression/codes/%d" % code): + break - else: - # Pas de code disponible - print ("ERROR: Il n'y a pas de code disponible" ) - sys.stderr.write ("ERROR: Il n'y a pas de code disponible" ) - try: - 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") - return + else: + # Pas de code disponible + print ("ERROR: Il n'y a pas de code disponible" ) + sys.stderr.write ("ERROR: Il n'y a pas de code disponible" ) + try: + 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") + return - # On enregistre le fichier avec le code pour numéro - codefichier = open("/var/impression/codes/%d" % code, 'w') - codefichier.write("Utilisateur %s\n" % self.user_ldap.Nom()) - codefichier.close() - self.code=code - self.list_messages_importants.append('code') + # On enregistre le fichier avec le code pour numéro + codefichier = open("/var/impression/codes/%d" % code, 'w') + codefichier.write("Utilisateur %s\n" % self.user_ldap.Nom()) + codefichier.close() + self.code=code + self.list_messages_importants.append('code') - def impression(self): - # Envoi du fichier à CUPS + def impression(self): + # Envoi du fichier à CUPS - # Création de la liste d'options - # pour le nombre de copies - options ='-# %d' % self.nb_copie + # Création de la liste d'options + # pour le nombre de copies + options ='-# %d' % self.nb_copie - # Pour spécifier l'imprimante - options +=' -P laserjet' + # Pour spécifier l'imprimante + options +=' -P laserjet' - # Pour spécifier la version du language postscript utilisé par pdftops - options +=' -o pdf-level3' + # Pour spécifier la version du language postscript utilisé par pdftops + options +=' -o pdf-level3' - # Pour donner le titre de l'impression - options +=' -T %s' % self.nom_job + # Pour donner le titre de l'impression + options +=' -T %s' % self.nom_job - # Pour donner le login de l'adherent - options +=' -U %s' % self.user + # Pour donner le login de l'adherent + options +=' -U %s' % 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' + # 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' + if self.portrait: + if self.recto_verso: + options += ' -o sides=two-sided-long-edge' else: - options += ' -o landscape' - if self.recto_verso: - options += ' -o sides=two-sided-short-edge' - else: - options += ' -o sides=one-sided' - options += ' -o HPColorasGray=%s' % (not self.couleur) - (status,rep) = commands.getstatusoutput("lpr %s %s" % (options, - self.nom_fichier_pdf)) - if status != 0: - print "

status:%d rep: %s

" % (status, rep) + 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=%s' % (not self.couleur) + (status,rep) = commands.getstatusoutput("lpr %s %s" % (options, self.nom_fichier_pdf)) + if status != 0: + print "

status:%d rep: %s

" % (status, rep) - def corrige(self): - # 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 and self.recto_verso: - self.list_messages.append("Recto_verso 1 page") + def corrige(self): + # 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 and self.recto_verso: + self.list_messages.append("Recto_verso 1 page") + self.recto_verso = False - def affiche_messages_html(self): - body="" + 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)) + """ + 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 "

%s

" % body + 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 "

%s

" % body - 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 = "%s.pdf" % self.nom_fichier_desc[0:-5] - 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 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 = "%s.pdf" % self.nom_fichier_desc[0:-5] + 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 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 parsée: %s

' % 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.path.exists(self.nom_fichier_pdf): - if self.imprime != -3: - 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" } - corps = "\n\n" % (self.nom_job, time.ctime(0.0)) - corps += "\n\n
%s%s
\n\n" - - self.code = "%s#" % self.code - for key in ("nbr_pages", "nb_copie", "taille", "code"): - corps+='\n' % (key, - str(getattr(self,key))) - self.code = int(self.code[:-1]) - - corps+="
%s%s
\n
\n\n" - for key in ("couleur", "transparent", - "portrait", "recto_verso"): - if getattr(self, key): - corps += '\n' % dict_normale[key] - else: - corps += '\n' % dict_contraire[key] - corps+="
%s
%s
\n
" - if self.erreur_critique: - corps += "erreur de comptage" + 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: - corps += "%s euros" % self.cout - corps+="
" - return corps + 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 parsée: %s

' % 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.path.exists(self.nom_fichier_pdf): + if self.imprime != -3: + self.imprime = -4 + + + def __repr__(self): + """ renvoie le string canonique de l'objet + fonction utilisé par print et str """ + + 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" } + corps = "\n\n" % (self.nom_job, time.ctime(0.0)) + corps += "\n\n
%s%s
\n\n" + + self.code = "%s#" % self.code + for key in ("nbr_pages", "nb_copie", "taille", "code"): + corps+='\n' % (key, + str(getattr(self,key))) + self.code = int(self.code[:-1]) + + corps+="
%s%s
\n
\n\n" + for key in ("couleur", "transparent", + "portrait", "recto_verso"): + if getattr(self, key): + corps += '\n' % dict_normale[key] + else: + corps += '\n' % dict_contraire[key] + corps+="
%s
%s
\n
" + if self.erreur_critique: + corps += "erreur de comptage" + else: + corps += "%s euros" % self.cout + corps+="
" + 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 - """ + """ 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 + # 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? + # 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 + # 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 + 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): + +def cout(fic_impr): + """ Calcule le pourcentage de couleur sur les pages + fic_impr est une instance de fichier_impression + retourn : + un string avec le nom de l'erreur si erreur il y a + un float dans les cas de fonctionnement + """ + # taille peut valoir A3 ou A4 # nb_copie est le nombre de copies désirées @@ -418,5 +431,3 @@ def cout( fic_impr): sys.stderr.write("ERREUR : Impossible d'enlever le dossier.\n") return float(c_total)/100 - -