Skip to content

Commit

Permalink
PDF Encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Berberich committed Jun 26, 2017
1 parent 2b9a486 commit f80fe74
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 3 deletions.
1 change: 1 addition & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Have every time a complete overview to Results of Students and complete School C
* CSV/PDF Export of Exam Results
* CSV/PDF Export of Student Results (in Timeperiod and complete Schoolyear)
* CSV/PDF Export of Schoolclass Results (in Timeperiod and complete Schoolyear)
* optional PDF Password Encryption
* calculates each Timeperiod seperate and show result
* select method how schoolyear final result will be calculated
* "Simulation" (what happens if Student has in next Test(s) this result(s)?)
Expand Down
60 changes: 59 additions & 1 deletion examsresult/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from glob import glob
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from reportlab.lib import pdfencrypt
import csv

language_extension = 'lng'
Expand Down Expand Up @@ -101,11 +102,43 @@ class ExportPdf(object):
head_text = "Head"
foot_text = "Foot"

def __init__(self, target_file, template, head_text="Head", foot_text="Foot", data=None):
def __init__(self, target_file, template, head_text="Head", foot_text="Foot", data=None, security={}):
if not target_file.endswith(".pdf"):
target_file += ".pdf"
try:
userpassword = security['userpassword']
except KeyError:
userpassword = None
try:
ownerpassword = security['ownerpassword']
except KeyError:
ownerpassword = None
try:
cancopy = security['cancopy']
except KeyError:
cancopy = True
try:
canmodify = security['canmodify']
except KeyError:
canmodify = True
try:
canprint = security['canprint']
except KeyError:
canprint = True
try:
canannotate = security['canannotate']
except KeyError:
canannotate = True

encryption = self.encryption(userpassword=userpassword,
ownerpassword=ownerpassword,
cancopy=cancopy,
canmodify=canmodify,
canprint=canprint,
canannotate=canannotate)

self.pdf_export = canvas.Canvas(target_file, pagesize=letter)
self.pdf_export.setEncrypt(encrypt=encryption)
self.pdf_export.setLineWidth(.3)
self.pdf_export.setFont(self.font_normal, self.font_size)
self.pdf_export.font_size = self.font_size
Expand All @@ -118,6 +151,31 @@ def __init__(self, target_file, template, head_text="Head", foot_text="Foot", da
self.foot_text = foot_text
self.data = data

def encryption(self, userpassword=None, ownerpassword=None, strength=128,
cancopy=True, canmodify=True, canprint=True, canannotate=True):
#
# https://www.reportlab.com/docs/reportlab-userguide.pdf
# from reportlab.pdfgen import canvas
# from reportlab.lib import pdfencrypt
# enc=pdfencrypt.StandardEncryption("rptlab",canPrint=0)
# def hello(c):
# c.drawString(100,100,"Hello World")
# c = canvas.Canvas("hello.pdf",encrypt=enc)
# hello(c)
# c.showPage()
# c.save()
#

if not userpassword and not ownerpassword:
return None
return pdfencrypt.StandardEncryption(userPassword=userpassword,
ownerPassword=ownerpassword,
canCopy=cancopy,
canModify=canmodify,
canPrint=canprint,
canAnnotate=canannotate,
strength=strength)

def template(self, data):
self.pdf_export.drawString(100, 750, "no content")

Expand Down
2 changes: 1 addition & 1 deletion examsresult/views/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def __init__(self, parent, lng, width=400, height=150):
app_icon_label.setPixmap(pixmap)
app_icon_label.move(7, 7)

version = "%s %s" % (local_lng['version'], "1.0.3.0")
version = "%s %s" % (local_lng['version'], "1.0.4.0")

title_label = QLabel(self.lng['main']['title'], window)
title_label.move(80, 10)
Expand Down
11 changes: 10 additions & 1 deletion examsresult/views/core.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from PyQt5.QtWidgets import QMessageBox, QInputDialog, QTableWidgetItem, QFileDialog

from examsresult.tools import export_csv, ExportPdf, cleanup_filename
from examsresult.views.export_pdf import PDFExportSettings


class CoreView(object):
Expand Down Expand Up @@ -341,12 +342,20 @@ def configure_export_csv(self, parent, default_filename):
def do_pdf_export(self, default_filename, root=None):
if not root:
root = self.tab_window

pdf_settings = PDFExportSettings(parent=root)
security = pdf_settings.settings
if security['failure']:
return

filename = self.file_save(root, self.lng['title'], default_filename=default_filename, filetype='pdf')
if not filename:
return

data = self._collect_export_data(start_column=0)
pdf = ExportPdf(target_file=filename, template=self.pdf_template, data=data, head_text=self.pdf_head_text, foot_text=self.pdf_foot_text)
pdf = ExportPdf(target_file=filename, template=self.pdf_template,
data=data, security=security,
head_text=self.pdf_head_text, foot_text=self.pdf_foot_text)
pdf.save()

def pdf_template(self, obj, data):
Expand Down
173 changes: 173 additions & 0 deletions examsresult/views/export_pdf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
from PyQt5.QtWidgets import QDialog, QPushButton, QLabel, QFileDialog, \
QGroupBox, QRadioButton, QLineEdit, QMessageBox, QCheckBox

from examsresult import current_config
from examsresult.tools import lng_load


class PDFExportSettings(object):

settings = {'failure': False}
encryption = False

def __init__(self, parent, width=480, height=300):

self.load_language()

self.window = QDialog(parent=parent)
self.window.setFixedHeight(height)
self.window.setFixedWidth(width)
self.window.setWindowTitle(self.lng['title'])

self.radio_no_encryption = QRadioButton(self.window)
self.radio_no_encryption.move(20, 20)
self.radio_no_encryption.setText(self.lng['no_encryption'])
self.radio_no_encryption.clicked.connect(self.encryption_type_changed)

self.radio_encryption = QRadioButton(self.window)
self.radio_encryption.move(20, 40)
self.radio_encryption.setText(self.lng['encryption'])
self.radio_encryption.clicked.connect(self.encryption_type_changed)

self.security_settings = QGroupBox(self.window)
self.security_settings.setGeometry(30, 45, self.window.width() - 20 - 20, 200)

self.button_export = QPushButton(self.lng['export'], self.window)
self.button_export.move(self.window.width() - self.button_export.width() - 20,
self.window.height() - self.button_export.height() - 10)
self.button_export.clicked.connect(self.window_close)

option_x = 300
self.cancopy = QCheckBox(self.security_settings)
self.cancopy.setText(self.lng['cancopy'])
self.cancopy.move(option_x, 24)
self.canmodify = QCheckBox(self.security_settings)
self.canmodify.setText(self.lng['canmodify'])
self.canmodify.move(option_x, 44)
self.canprint = QCheckBox(self.security_settings)
self.canprint.setText(self.lng['canprint'])
self.canprint.move(option_x, 64)
self.cananotate = QCheckBox(self.security_settings)
self.cananotate.setText(self.lng['cananotate'])
self.cananotate.move(option_x, 84)

self.chk_userpassword_title = QCheckBox(self.lng['userpassword'], self.security_settings)
self.chk_userpassword_title.clicked.connect(self.set_user_password_ability)
self.chk_userpassword_title.move(10, 30)
self.label_userpassword = QLabel(self.lng['password'], self.security_settings)
self.label_userpassword.move(40, 50)
self.text_userpassword = QLineEdit(self.security_settings)
self.text_userpassword.setGeometry(160, 47, 100, 20)
self.text_userpassword.setEchoMode(QLineEdit.Password)
self.label_userpassword_retype = QLabel(self.lng['password_retype'], self.security_settings)
self.label_userpassword_retype.move(40, 70)
self.text_userpassword_retype = QLineEdit(self.security_settings)
self.text_userpassword_retype.setEchoMode(QLineEdit.Password)
self.text_userpassword_retype.setGeometry(160, 67, 100, 20)

self.chk_ownerpassword_title = QCheckBox(self.lng['ownerpassword'], self.security_settings)
self.chk_ownerpassword_title.clicked.connect(self.set_owner_password_ability)
self.chk_ownerpassword_title.move(10, 130)
self.label_ownerpassword = QLabel(self.lng['password'], self.security_settings)
self.label_ownerpassword.move(40, 150)
self.text_ownerpassword = QLineEdit(self.security_settings)
self.text_ownerpassword.setEchoMode(QLineEdit.Password)
self.text_ownerpassword.setGeometry(160, 147, 100, 20)
self.label_ownerpassword_retype = QLabel(self.lng['password_retype'], self.security_settings)
self.label_ownerpassword_retype.move(40, 170)
self.text_ownerpassword_retype = QLineEdit(self.security_settings)
self.text_ownerpassword_retype.setEchoMode(QLineEdit.Password)
self.text_ownerpassword_retype.setGeometry(160, 167, 100, 20)

self.radio_no_encryption.setChecked(True)
self.chk_userpassword_title.setChecked(True)

self.cananotate.setChecked(True)
self.cancopy.setChecked(True)
self.canmodify.setChecked(True)
self.canprint.setChecked(True)

self.set_user_password_ability()
self.set_owner_password_ability()
self.encryption_type_changed()

self.window.exec_()

def set_user_password_ability(self):
enabled = self.chk_userpassword_title.isChecked()
self.label_userpassword.setEnabled(enabled)
self.text_userpassword.setEnabled(enabled)
self.label_userpassword_retype.setEnabled(enabled)
self.text_userpassword_retype.setEnabled(enabled)

self.cananotate.setEnabled(enabled)
self.cancopy.setEnabled(enabled)
self.canmodify.setEnabled(enabled)
self.canprint.setEnabled(enabled)
if not enabled:
self.chk_ownerpassword_title.setChecked(enabled)
self.set_owner_password_ability()

def set_owner_password_ability(self):
enabled = self.chk_ownerpassword_title.isChecked()
self.label_ownerpassword.setEnabled(enabled)
self.text_ownerpassword.setEnabled(enabled)
self.label_ownerpassword_retype.setEnabled(enabled)
self.text_ownerpassword_retype.setEnabled(enabled)

def encryption_type_changed(self):
if self.radio_no_encryption.isChecked():
self.encryption = False
elif self.radio_encryption.isChecked():
self.encryption = True

self.security_settings.setEnabled(self.encryption)

def collect_settings(self):
settings = {}

if self.chk_userpassword_title.isChecked():
settings['userpassword'] = self.text_userpassword.text()
settings['cancopy'] = self.cancopy.isChecked()
settings['canmodify'] = self.canmodify.isChecked()
settings['canprint'] = self.canprint.isChecked()
settings['cananotate'] = self.cananotate.isChecked()

if self.chk_ownerpassword_title.isChecked():
settings['ownerpassword'] = self.text_ownerpassword.text()

self.settings = settings

def window_close(self):
self.collect_settings()

self.settings['failure'] = True

if self.encryption:
# check if enabled Password Types are filled with an password
for key in ['userpassword', 'ownerpassword']:
if key in self.settings.keys() and self.settings[key] == "":
QMessageBox.warning(self.window, "",self.lng['msg_empty_password'])
return
# are passwords equal?
if 'userpassword' in self.settings.keys():
if self.text_userpassword.text() != self.text_userpassword_retype.text():
QMessageBox.warning(self.window, "",self.lng['msg_unequal_user_password'])
return
if 'ownerpassword' in self.settings.keys():
if self.text_ownerpassword.text() != self.text_ownerpassword_retype.text():
QMessageBox.warning(self.window, "",self.lng['msg_unequal_owner_password'])
return

if 'ownerpassword' in self.settings.keys():
if self.text_userpassword.text() == self.text_ownerpassword.text():
QMessageBox.warning(self.window, "", self.lng['msg_user_owner_password_equal'])
return

self.settings['failure'] = False
self.window.close()

def load_language(self):
config = current_config
lng = lng_load(config['language'])
self.lng = lng['pdfexport']
18 changes: 18 additions & 0 deletions lng/english.lng
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@ msg_close_unsaved=Really close unsaved?
msg_file_not_found=File to open not found
all=(all)

[pdfexport]
title=PDF Settings
no_encryption= no Encryption
encryption=Encryption
password=Password
password_retype=Retype Password
userpassword=Userpassword
ownerpassword=Ownerpassword
cancopy=allow copying
canmodify=allow modifying
canprint=allow printing
cananotate=allow anotation
export=Export
msg_empty_password=no empty passwords allowed
msg_unequal_user_password=User Password has to be equal
msg_unequal_owner_password=Owner Password has to be equal
msg_user_owner_password_equal=User Password and Owner Password have to be different

[menu]
mainmenufile=File
mainmenureport=Report
Expand Down
18 changes: 18 additions & 0 deletions lng/german.lng
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@ msg_close_unsaved=Wirklich schließen ohne zu speichern?
msg_file_not_found=Datei nicht gefunden
all=(alle)

[pdfexport]
title=PDF Einstellungen
no_encryption= kein Verschlüsselung
encryption=Verschlüsselung
password=Passwort
password_retype=wiederhole Passwort
userpassword=Benuzerpasswort
ownerpassword=Besitzerpasswort
cancopy=erlaube Kopien
canmodify=erlaube Veränderung
canprint=erlaube Drucken
cananotate=erlaube Markierungen
export=Export
msg_empty_password=keine leeren Passwörter zugelassen
msg_unequal_user_password=Benutzerpasswort stimmt nicht überein
msg_unequal_owner_password=Besitzerpassword stimmt nicht überein
msg_user_owner_password_equal=Benutzerpasswort und Besitzerpassword müssern verschieden sein

[menu]
mainmenufile=Datei
mainmenureport=Report
Expand Down

0 comments on commit f80fe74

Please sign in to comment.