# -*- coding: utf-8 -*- import os import ConfigParser from PyQt4 import QtGui, QtCore from global_functions import app_dir, titleFont from models import conn, cursor, \ generate_certificate, \ Mailer class CertificatesWidget(QtGui.QWidget): """ Creates the frame with options for certificate preview, generation and mailing. """ def __init__(self): """ Setup widgets and select data from database. """ super(CertificatesWidget, self).__init__() # Window settings self.save_folder = "" # Connects with configuration file to get info self.Config = ConfigParser.ConfigParser() self.Config.read(os.path.join(app_dir, "institution.ini")) cursor.execute("SELECT * FROM events ORDER BY id DESC") self.events = cursor.fetchall() cursor.execute("SELECT * FROM signatures ORDER BY name ASC") self.signatures = cursor.fetchall() # Defines all layouts self.mainLayout = QtGui.QVBoxLayout() self.listLayout = QtGui.QHBoxLayout() self.btnsLayout = QtGui.QVBoxLayout() self.respLayout = QtGui.QVBoxLayout() self.instLayout = QtGui.QVBoxLayout() self.combosLayoutH = QtGui.QHBoxLayout() self.generateBtnsLayout = QtGui.QHBoxLayout() # Window config self.titleLabel = QtGui.QLabel(u"Certificados", self) self.titleLabel.setFont(titleFont) # Make buttons layout self.addBtn = QtGui.QPushButton(u"Adicionar") self.addBtn.clicked.connect(self.add_client) self.removeBtn = QtGui.QPushButton(u"Remover") self.removeBtn.clicked.connect(self.remove_client) self.btnsLayout.addWidget(self.addBtn) self.btnsLayout.addWidget(self.removeBtn) self.btnsLayout.addStretch() # Fill combobox with event info self.eventsListName = QtGui.QLabel(u"Selecione um evento:", self) self.eventsList = QtGui.QComboBox() for event in self.events: self.eventsList.addItem(unicode(event[1])) self.eventsList.currentIndexChanged.connect(self.load_list) # Fill listwidget with subscriptions info self.subscriptionListName = QtGui.QLabel(u"Inscritos", self) self.subscriptionList = QtGui.QListWidget() self.load_list() # Fill both responsible and institution combos # with signatures info self.responsibleListName = QtGui.QLabel( u"Selecione um responsável/ministrante:", self ) self.responsibleList = QtGui.QComboBox() self.institutionListName = QtGui.QLabel( u"Assinatura da instituição:", self ) self.institutionList = QtGui.QComboBox() for sig in self.signatures: self.responsibleList.addItem(unicode(sig[1])) self.institutionList.addItem(unicode(sig[1])) # A label for showing errors self.errorMsg = QtGui.QLabel(u"", self) self.errorMsg.setStyleSheet("color: red; font-weight: bold;") # Defines buttons for preview, generate and mail certificates self.previewBtn = QtGui.QPushButton(u"Preview") self.previewBtn.clicked.connect(self.preview_certificate) self.generateBtn = QtGui.QPushButton(u"Gerar!") self.generateBtn.clicked.connect(self.generate) self.generateSendBtn = QtGui.QPushButton(u"Gerar e enviar por email!") self.generateSendBtn.clicked.connect(self.generate_send) # Add them to generateBtnsLayout self.generateBtnsLayout.addWidget(self.previewBtn) self.generateBtnsLayout.addWidget(self.generateBtn) self.generateBtnsLayout.addWidget(self.generateSendBtn) # Add subscriptions list to listLayout self.listLayout.addWidget(self.subscriptionList) self.listLayout.addLayout(self.btnsLayout) # Add signatures info to their specific layouts self.respLayout.addWidget(self.responsibleListName) self.respLayout.addWidget(self.responsibleList) self.instLayout.addWidget(self.institutionListName) self.instLayout.addWidget(self.institutionList) self.combosLayoutH.addLayout(self.respLayout) self.combosLayoutH.addLayout(self.instLayout) # Add everything to the mainLayout self.mainLayout.addWidget(self.titleLabel) self.mainLayout.addWidget(self.eventsListName) self.mainLayout.addWidget(self.eventsList) self.mainLayout.addWidget(self.subscriptionListName) self.mainLayout.addLayout(self.listLayout) self.mainLayout.addLayout(self.combosLayoutH) self.mainLayout.addWidget(self.errorMsg) self.mainLayout.addLayout(self.generateBtnsLayout) # Set the mainLayout as the visible layout self.setLayout(self.mainLayout) def load_list(self): """ Loads all subscriptions of the selected event and insert them in the subscriptionList widget. """ # Get the subscripted clients if self.events: cursor.execute( "SELECT id,client_id FROM subscriptions WHERE event_id=?", (str(self.events[self.eventsList.currentIndex()][0]),) ) self.clients = cursor.fetchall() else: self.clients = [] # Clears the widget to insert updated info self.subscriptionList.clear() # Select all subscripted clients and add them # to the subscriptionList widget for client in self.clients: cursor.execute( "SELECT name FROM clients WHERE id=?", (str(client[1]),) ) client_name = cursor.fetchone() if client: self.subscriptionList.addItem(unicode(client_name[0])) def add_client(self): """ Subscribes a new client to the event. """ # If there is an event selected, get it's ID and passes # it to the AddClientDialog. # If there is not, shows up an error message. try: event_id = self.events[self.eventsList.currentIndex()][0] self.add_client_widget = AddClientDialog(self, event_id) self.add_client_widget.show() except IndexError: self.errorMsg.setText(u"Selecione um evento existente!") def remove_client(self): """ Remove a client from the event's subscriptions. """ # If there is a client selected, removes it. # If there is not, shows up an error message. try: current_subscription = self.subscriptionList.currentRow() subscription_id = self.clients[current_subscription][0] # Asks if the user really wants to remove the client choice = QtGui.QMessageBox.question( self, u"Apagar inscrição", u"Tem certeza que deseja apagar esta inscrição?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No ) if choice == QtGui.QMessageBox.Yes: cursor.execute( "DELETE FROM subscriptions WHERE id=?", (str(subscription_id),) ) conn.commit() else: pass self.load_list() except IndexError: self.errorMsg.setText(u"Selecione um cliente existente!") def generate_general(self, preview=False): """ Prepare all general info that needs to be passed whenever the user wants to preview, generate or mail a certificate. """ # Asks for subscripted clients to generate certificates if len(self.clients) == 0 and not preview: self.errorMsg.setText(u"Primeiro inscreva clientes!") else: # Get the folder where to save the certificates self.save_folder = QtGui.QFileDialog.getExistingDirectory( None, u"Salvar em" ) self.cert_data = {} # Collect all data that needs to be passed # Selected items current_event = self.eventsList.currentIndex() current_responsible = self.responsibleList.currentIndex() current_institution = self.institutionList.currentIndex() if current_event == -1: self.errorMsg.setText(u"Primeiro cadastre um evento!") return 0 elif current_responsible == -1 or current_institution == -1: self.errorMsg.setText(u"Primeiro cadastre assinaturas!") return 0 # Current event event_title = unicode(self.events[current_event][1]).upper() event_start_date = unicode(self.events[current_event][2]) event_end_date = unicode(self.events[current_event][3]) event_hours = unicode(self.events[current_event][4]) event_content = unicode(self.events[current_event][5]).upper() # Current responsible responsible_id = unicode(self.signatures[current_responsible][0]) responsible_sig = os.path.join( app_dir, "signatures", "{0}.png".format(responsible_id) ) # Current institution institution_id = unicode(self.signatures[current_institution][0]) institution_sig = os.path.join( app_dir, "signatures", "{0}.png".format(institution_id) ) institution_role = unicode(self.signatures[current_institution][2]) try: institution_name = unicode(self.Config.get("Main", "Name")).upper() institution_register = unicode(self.Config.get("Main", "ID")) except: self.errorMsg.setText(u"Cadastre os dados da aba " u"Instituição primeiro!") return 0 # Fills with the data self.cert_data = { "event": event_title, "start_date": event_start_date, "end_date": event_end_date, "hours": event_hours, "content": event_content, "responsible_sig": responsible_sig, "institution_sig": institution_sig, "role": institution_role, "institution": institution_name, "inst_register": institution_register } # Get data about the event's responsible # to generate it's certificate cursor.execute( "SELECT * FROM signatures WHERE id=?", (str(self.signatures[current_responsible][0]),) ) self.responsible = cursor.fetchone() return 1 def preview_certificate(self): """ Open a dialog for showing the progress of the preview certificate generation. """ r = self.generate_general(preview=True) # Verifies if user selected a folder or cancelled if self.save_folder != u"" and r == 1: self.preview_progress = GenerateCertificateProgress( self.save_folder, self.cert_data, (), (), True ) self.preview_progress.show() def generate(self): """ Open a dialog for showing the progress of the subscriptions and responsible certificate generation. """ r = self.generate_general() # Verifies if user selected a folder or cancelled if self.save_folder != u"" and r == 1: self.generate_progress = GenerateCertificateProgress( self.save_folder, self.cert_data, self.clients, self.responsible ) self.generate_progress.show() def generate_send(self): """ Open a dialog for showing the progress of the subscriptions and responsible certificate generation and mailing. """ r = self.generate_general() # Verifies if user selected a folder or cancelled if self.save_folder != u"" and r == 1: self.generate_send_progress = GenerateSendProgress( self.save_folder, self.cert_data, self.clients, self.responsible ) self.generate_send_progress.show() class AddClientDialog(QtGui.QDialog): """ A dialog to subscribe new clients to an event. """ def __init__(self, certificates_instance, event_id): """ Setup widgets and select data from database. """ super(AddClientDialog, self).__init__() # Window config self.setWindowTitle(u"Adicionar cliente") self.certificates_instance = certificates_instance self.event_id = event_id # Select clients in alphabetical order cursor.execute("SELECT * FROM clients ORDER BY name ASC") self.clients = cursor.fetchall() # Define layouts self.mainLayout = QtGui.QVBoxLayout() # Frame config self.titleLabel = QtGui.QLabel(u"Selecione um cliente") self.titleLabel.setFont(titleFont) # Fill combo with clients info self.clientsList = QtGui.QComboBox() for client in self.clients: self.clientsList.addItem(unicode(client[1])) # Create the main button self.saveBtn = QtGui.QPushButton(u"Selecionar") self.saveBtn.clicked.connect(self.add_client) # Add all widgets to the mainLayout self.mainLayout.addWidget(self.titleLabel) self.mainLayout.addWidget(self.clientsList) self.mainLayout.addWidget(self.saveBtn) # Set mainLayout as the visible layout self.setLayout(self.mainLayout) def add_client(self): """ Inserts the selected user into the database as a subscription to the selected event. """ # Inserts data into the database cursor.execute( "INSERT INTO subscriptions VALUES (NULL,?,?)", ( str(self.event_id), str(self.clients[self.clientsList.currentIndex()][0]) ) ) conn.commit() # Update the listwidget that contains # the subscripted clients self.certificates_instance.load_list() # Hide the dialog self.hide() class GenerateCertificateProgress(QtGui.QDialog): """ A dialog to show the progress of the certificate generation and manage the generation thread. """ def __init__(self, save_folder, cert_data, clients, responsible, preview=False): """ Setup all widgets. """ super(GenerateCertificateProgress, self).__init__() # Window config self.setWindowTitle(u"Gerando certificados") self.setGeometry(450, 300, 400, 200) self.preview = preview self.n = 0 self.total = len(clients)+1 # Creates the new thread self.generate_thread = GenerateThread(self.preview) self.generate_thread._get_info(save_folder, cert_data, clients, responsible) # Connect the signals with slots self.connect( self.generate_thread, QtCore.SIGNAL("finished()"), self.done ) self.connect( self.generate_thread, QtCore.SIGNAL("update"), self.update ) # Defines the layouts self.mainLayout = QtGui.QVBoxLayout() # Widget config self.titleLabel = QtGui.QLabel(u"Gerando certificados", self) self.titleLabel.setFont(titleFont) # Make the progress bar from 0 to 100 self.progress_bar = QtGui.QProgressBar() self.progress_bar.setRange(0, 100) self.status = QtGui.QLabel(u"Carregando...", self) # Make the cancel button self.cancelBtn = QtGui.QPushButton(u"Cancelar") self.cancelBtn.clicked.connect(self.generate_thread.terminate) # Add all widgets to the mainLayout self.mainLayout.addWidget(self.titleLabel) self.mainLayout.addWidget(self.progress_bar) self.mainLayout.addWidget(self.status) self.mainLayout.addWidget(self.cancelBtn) # Runs the thread self.generate_thread.start() # Set the mainLayout as the visible layout self.setLayout(self.mainLayout) def update(self, step, n): """ Updates the progress bar value and text according to the signal received. """ # Percentage calcs self.n += 100/self.total # Update progress bar value self.progress_bar.setValue(int(self.n)) # Update status according to the signal if step == 1: if self.preview: certs = 1 else: certs = self.total-1 self.status.setText( u"Gerando certificado {0}/{1}".format(n, certs) ) elif step == 2: self.status.setText(u"Gerando certificado do responsável") elif step == 3: self.progress_bar.setValue(100) self.status.setText("Finalizando...") def done(self): """ Shows up a message box informing that the task is completed. """ # Setup the message box self.message = QtGui.QMessageBox() self.message.setGeometry(450, 300, 300, 200) self.message.setIcon(QtGui.QMessageBox.Information) self.message.setWindowTitle(u"Pronto!") self.message.setStandardButtons(QtGui.QMessageBox.Ok) if not self.preview: self.message.setText(u"Todos os certificados foram gerados!") else: self.message.setText(u"O certificado foi gerado com " u"o nome PREVIEWDECLIENTE.pdf") # Shows up the message box self.message.exec_() # Hide the dialog self.hide() class GenerateThread(QtCore.QThread): """ The thread that deals with the certificate generation. """ def __init__(self, preview=False): """ Setup the thread. """ super(GenerateThread, self).__init__() self.preview = preview def __del__(self): self.wait() def _get_info(self, save_folder, cert_data, clients, responsible): """ Gets all the needed info for generating certificates. """ self.save_folder = save_folder self.cert_data = cert_data self.clients = clients self.responsible = responsible def run(self): """ Generate all certificates. """ n = 1 if not self.preview: for client in self.clients: # Select client info cursor.execute( "SELECT name,register FROM clients \ WHERE id=?", (str(client[1]),) ) client_data = cursor.fetchone() self.cert_data["name"] = unicode(client_data[0]).upper() self.cert_data["register"] = unicode(client_data[1]) # Updates the progress bar status self.emit(QtCore.SIGNAL("update"), 1, n) # Generate the certificate generate_certificate(self.save_folder, self.cert_data) n += 1 # Updates the progress bar status self.emit(QtCore.SIGNAL("update"), 2, 0) # Get the responsible info self.cert_data["name"] = unicode(self.responsible[1]).upper() self.cert_data["register"] = unicode(self.responsible[4]).upper() # Generate the responsible certificate generate_certificate(self.save_folder, self.cert_data, True) # Updates the progress bar status self.emit(QtCore.SIGNAL("update"), 3, 0) else: # Setup preview info self.cert_data["name"] = u"Preview de Cliente".upper() self.cert_data["register"] = u"000.000.000-00" # Generate preview certificate self.emit(QtCore.SIGNAL("update"), 1, n) generate_certificate(self.save_folder, self.cert_data) self.emit(QtCore.SIGNAL("update"), 3, 0) class GenerateSendProgress(QtGui.QDialog): """ A dialog to generate and sent certificates. """ def __init__(self, save_folder, cert_data, clients, responsible): """ Setup all widgets. """ super(GenerateSendProgress, self).__init__() # Window config self.setWindowTitle(u"Gerando & enviando certificados") self.setGeometry(450, 300, 400, 200) self.n = 0 self.total = len(clients)+3 self.error = False # Create thread for dealing with # the generation and mailing self.generate_send_thread = GenerateSendThread() self.generate_send_thread._get_info(save_folder, cert_data, clients, responsible) # Connects signals with slots self.connect( self.generate_send_thread, QtCore.SIGNAL("finished()"), self.done ) self.connect( self.generate_send_thread, QtCore.SIGNAL("update"), self.update ) self.connect( self.generate_send_thread, QtCore.SIGNAL("error_raised()"), self.error_raised ) # Defines all layouts self.mainLayout = QtGui.QVBoxLayout() # Widget config self.titleLabel = QtGui.QLabel(u"Gerando & enviando certificados", self) self.titleLabel.setFont(titleFont) # Creates progress bar from 0 to 100 self.progress_bar = QtGui.QProgressBar() self.progress_bar.setRange(0, 100) self.status = QtGui.QLabel(u"Carregando...", self) # Cancel button self.cancelBtn = QtGui.QPushButton(u"Cancelar") self.cancelBtn.clicked.connect(self.generate_send_thread.terminate) # Adds all widgets to the mainLayout self.mainLayout.addWidget(self.titleLabel) self.mainLayout.addWidget(self.progress_bar) self.mainLayout.addWidget(self.status) self.mainLayout.addWidget(self.cancelBtn) # Starts the thread self.generate_send_thread.start() # Set the mainLayout as the visible layout self.setLayout(self.mainLayout) def update(self, step, n): """ Updates the progress bar value and information text. """ # Updates value self.n += 100/self.total self.progress_bar.setValue(int(self.n)) # Updates status if step == 1: self.status.setText(u"Conectando...") if step == 2: self.status.setText( u"Gerando & enviando " "certificado {0}/{1}".format(n, (self.total-3)) ) if step == 3: self.status.setText(u"Gerando & enviando " u"certificado do responsável") if step == 4: self.progress_bar.setValue(100) self.status.setText(u"Finalizando") def error_raised(self): """ Updates error status to True. """ self.error = True def done(self): """ Shows up message box with information about the completed thread. """ # Verifies if the connection was OK if self.error is False: # Creates the message box self.message = QtGui.QMessageBox() self.message.setGeometry(450, 300, 300, 200) self.message.setIcon(QtGui.QMessageBox.Information) self.message.setText(u"Todos os certificados " u"foram gerados e enviados!") self.message.setWindowTitle(u"Pronto!") self.message.setStandardButtons(QtGui.QMessageBox.Ok) # Shows up message box self.message.exec_() else: # Display a message box for more error info self.error = QtGui.QMessageBox() self.error.setGeometry(450, 300, 300, 200) self.error.setIcon(QtGui.QMessageBox.Critical) self.error.setWindowTitle(u"Erro de autenticação!") self.error.setText(u"Erro de autenticação!") self.error.setInformativeText(u"Houve uma falha na autenticação! " u"Verifique as informações de " u"conexão na aba Instituição.") self.error.setStandardButtons(QtGui.QMessageBox.Ok) self.error.exec_() # Hide the dialog self.hide() class GenerateSendThread(QtCore.QThread): """ A thread for dealing with certificates generation and mailing. """ def __init__(self): """ Setup widgets. """ super(GenerateSendThread, self).__init__() def __del__(self): self.wait() def _get_info(self, save_folder, cert_data, clients, responsible): """ Gets info to generate and send certificates. """ self.save_folder = save_folder self.cert_data = cert_data self.clients = clients self.responsible = responsible def run(self): """ Connects with the mailer, generates and send the certificates. """ # connects to the mailer and updates progress bar self.emit(QtCore.SIGNAL("update"), 1, 0) self.mailer = Mailer() r = self.mailer.connect() # Verifies authentication if r == 1: n = 1 for client in self.clients: # Get client info cursor.execute( "SELECT name,email FROM clients WHERE id=?", (str(client[1]),) ) client_data = cursor.fetchone() filepath = os.path.join( unicode(self.save_folder), u''.join(i for i in unicode(client_data[0]) if ord(i) < 128) .upper() .replace(" ", "") ) filepath += ".pdf" self.cert_data["name"] = unicode(client_data[0]).upper() self.cert_data["register"] = unicode(client_data[1]) # Updates progress bar and generate and send certificate self.emit(QtCore.SIGNAL("update"), 2, n) generate_certificate(self.save_folder, self.cert_data) self.mailer.send_certificate(filepath, unicode(client_data[1])) n += 1 # Gets responsible info filepath = os.path.join( unicode(self.save_folder), u"responsible.pdf" ) self.cert_data["name"] = unicode(self.responsible[1]).upper() self.cert_data["register"] = unicode(self.responsible[4]).upper() # Updates progress bar and generate and send certificate self.emit(QtCore.SIGNAL("update"), 3, 0) generate_certificate(self.save_folder, self.cert_data, True) self.mailer.send_certificate( unicode(filepath), unicode(self.responsible[3]) ) self.emit(QtCore.SIGNAL("update"), 4, 0) # Quits mailer self.mailer.quit() else: self.emit(QtCore.SIGNAL("error_raised()"))