# MedScript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
-import argparse, json, os, sys, shutil
+import logging, argparse, json, os, sys, shutil
default_config_file=os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), "data", "config.json"))
"enable_form": False,
"plugin_directory": "plugin",
"enable_plugin": False,
+ "log_directory": "log",
"preset_newline": True,
"preset_delimiter": ",",
"markdown": False,
read = json.loads(conf.read())
config = default | read
except Exception as e:
- print(e)
+ logging.warning(e)
config=default
config["filename"]=args.filename
config["plugin_directory"]=os.path.join(config["data_directory"], config["plugin_directory"])
config["template_directory"]=os.path.join(config["data_directory"], config["template_directory"])
config["template"]=os.path.join(config["template_directory"], config["template"])
+config["log_directory"]=os.path.join(config["data_directory"], config["log_directory"])
config["resource"]=os.path.abspath(os.path.join(real_dir, "resource"))
if(args.prescriber is None):
config["prescriber_directory"]=os.path.join(config["data_directory"], config["prescriber_directory"])
config["prescriber"]=args.prescriber
else:
config["prescriber"]=os.path.join(config["prescriber_directory"], config["prescriber"])
- print("File "+args.prescriber+" not found.")
+ logging.warning("File "+args.prescriber+" not found.")
os.makedirs(config["data_directory"], exist_ok=True)
os.makedirs(config["document_directory"], exist_ok=True)
os.makedirs(config["form_directory"], exist_ok=True)
os.makedirs(config["plugin_directory"], exist_ok=True)
os.makedirs(config["template_directory"], exist_ok=True)
+os.makedirs(config["log_directory"], exist_ok=True)
if not os.path.exists(os.path.join(config["data_directory"], "config.json")):
shutil.copyfile(os.path.abspath(os.path.join(real_dir, "data", "config.json")), os.path.join(config["data_directory"], "config.json"))
if not os.path.exists(os.path.join(config["prescriber_directory"], "prescriber.json")):
from PyQt6.QtWidgets import QWidget, QFormLayout, QLineEdit, QTextEdit, QCheckBox, QDateTimeEdit, QCalendarWidget
from PyQt6.QtCore import QDateTime
from glob import glob
-import os, json, sys, dateutil.parser
+import logging, os, json, sys, dateutil.parser
from config import config
class CustomForm(QWidget):
try:
self.forms.append(json.loads(f.read()))
except Exception as e:
- print(e)
+ logging.warning(e)
for i in self.forms:
try:
for j in i["form"]:
elif(isinstance(self.inputs[index][1], QDateTimeEdit)):
self.custom[index][list(item)[0]]=self.inputs[index][1].text()
except Exception as e:
- print(e)
+ logging.warning(e)
return(self.custom)
def setData(self, custom=False):
d=QDateTime.fromString(pdate.strftime("%Y-%m-%d %H:%M:%S"), "yyyy-MM-dd hh:mm:ss")
self.inputs[index][1].setDateTime(d)
except Exception as e:
- print(e)
+ logging.warning(e)
def __init__(self, *args, **kwargs):
from PyQt6.QtWidgets import QWidget, QMainWindow, QVBoxLayout, QHBoxLayout, QPushButton, QComboBox, QTextEdit, QTableView, QMessageBox
from PyQt6.QtGui import QIcon, QStandardItemModel, QStandardItem
from config import config
-import os, csv
+import logging, os, csv
class EditPreset(QMainWindow):
self.load(file)
QMessageBox.information(self,"File saved", "Changes saved. Please restart the program.")
except Exception as e:
- print(e)
+ logging.warning(e)
def cmd_row(self):
tablerow=[]
self.table.resizeRowsToContents()
textedit=QTextEdit()
except Exception as e:
- print(e)
+ logging.warning(e)
def confirm(self):
return QMessageBox.StandardButton.Yes==QMessageBox.question(self,"Confirm action", "Unsaved changes may be lost. Continue?")
# MedScript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
-import os, shutil, glob, tempfile, json
+import logging, os, shutil, glob, tempfile, json
from zipfile import ZipFile
from config import config
from signature import Signature
try:
shutil.copyfile(file, os.path.join(dirname, os.path.basename(file)))
except shutil.SameFileError as e:
- print(e)
+ logging.warning(e)
def list(self, category="attachment"):
items=[]
signature=file.read()
return Signature.verify(data, certificate=os.path.join(self.directory.name, "certificate.pem"), signature=signature)
except FileNotFoundError as e:
- print(e)
+ logging.warning(e)
def delete_attachment(self, item):
try:
os.unlink(os.path.join(self.directory.name, "attachment", os.path.basename(item)))
except Exception as e:
- print(e)
+ logging.warning(e)
def delete_sign(self):
try:
os.unlink(os.path.join(self.directory.name, "certificate.pem"))
os.unlink(os.path.join(self.directory.name, "signature"))
except Exception as e:
- print(e)
+ logging.warning(e)
def has_template(self):
return(os.path.exists(os.path.join(self.directory.name, "template", "index.html")))
from glob import glob
from zipfile import ZipFile
from config import config
-import os, json
+import logging, os, json
class Index(QMainWindow):
self.signal_open.emit(self.getSelectedFile())
self.hide()
except Exception as e:
- print(e)
+ logging.warning(e)
def cmd_copy(self):
try:
self.signal_copy.emit(pres)
self.hide()
except Exception as e:
- print(e)
+ logging.warning(e)
def getSelectedFile(self):
# MedScript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
-import sys, os
+import logging, sys, os
+from logging.handlers import RotatingFileHandler
from PyQt6.QtWidgets import QApplication
from window import MainWindow
from config import config
if __name__=="__main__":
+ logging.basicConfig(level=logging.INFO,
+ format="[%(asctime)s] (%(module)s / %(funcName)s) %(levelname)s : %(message)s",
+ handlers=[RotatingFileHandler(os.path.join(config["log_directory"], "log.txt"), maxBytes=100000, backupCount=9), logging.StreamHandler()],
+ force=True
+ )
app=QApplication(sys.argv)
with open(os.path.join(config["resource"], "style.qss")) as qss:
app.setStyleSheet(qss.read())
# MedScript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
-import os, importlib, copy
+import logging, os, importlib, copy
from PyQt6.QtWidgets import QMessageBox, QInputDialog, QFileDialog
from PyQt6.QtCore import QThread, pyqtSignal
from glob import glob
spec.loader.exec_module(mod)
self.plugins.append(mod)
except Exception as e:
- print(i, ":", e)
+ logging.warning(i, ":", e)
def get_name(self, mod):
try:
if(message):
self.showMessage(message)
except Exception as e:
- print(e)
+ logging.warning(e)
def open(self, prescription):
for i in self.plugins:
if(message):
self.showMessage(message)
except Exception as e:
- print(e)
+ logging.warning(e)
def save(self, prescription):
for i in self.plugins:
if(message):
self.showMessage(message)
except Exception as e:
- print(e)
+ logging.warning(e)
def refresh(self, prescription):
for i in self.plugins:
if(message):
self.showMessage(message)
except Exception as e:
- print(e)
+ logging.warning(e)
def run(self, module, prescription):
try:
if(message):
self.showMessage(message)
except Exception as e:
- print(e)
+ logging.warning(e)
def input(self):
try:
else:
return ""
except Exception as e:
- print(e)
+ logging.warning(e)
def showMessage(self, message, index=None):
QMessageBox.information(None, "Information", message)
# MedScript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
-import json
+import logging, json
from config import config
class Prescriber:
self.extra = data["extra"]
self.properties = data["properties"]
except Exception as e:
- print(e)
+ logging.warning(e)
def read_from(self, file):
try:
self.custom = data.get("custom")
self.properties = data.get("properties")
except Exception as e:
- print(e)
+ logging.warning(e)
def get_json(self):
return(json.dumps(self, default=lambda o: o.__dict__, indent=4))
except AttributeError as e:
pass
except Exception as e:
- print(e)
+ logging.warning(e)
f.write(self.get_json())
self.file=file
# MedScript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
-import os, csv
+import logging, os, csv
from glob import glob
from config import config
buf[row[1].strip()]=row[1]
self.data = buf | self.data
except FileNotFoundError as e:
- print(e)
+ logging.warning(e)
except IndexError as e:
- print(e)
+ logging.warning(e)
except StopIteration as e:
- print(e)
+ logging.warning(e)
except Exception as e:
- print(e)
+ logging.warning(e)
from PyQt6.QtGui import QIcon, QPageLayout, QPageSize
from PyQt6.QtCore import QUrl, QMarginsF
from PyQt6.QtPrintSupport import QPrinter, QPrintDialog
-import os
+import logging, os
from config import config
class RenderBox(QMainWindow):
except Exception as e:
QMessageBox.warning(self,"Display failed", "Failed to display file.")
self.hide()
- print(e)
+ logging.warning(e)
# MedScript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
-import os, shutil, tempfile, json, datetime, re
+import logging, os, shutil, tempfile, json, datetime, re
from markdown import markdown
from jinja2 import Template
from config import config
try:
data["date"]=datetime.datetime.strptime(data["date"], "%Y-%m-%d %H:%M:%S")
except Exception as e:
- print(e)
+ logging.warning(e)
output=template_data.render(data)
target_file.write(output)
return(target)
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import Qt, pyqtSignal
from glob import glob
-import os, json
+import logging, os, json
from prescription import Prescriber
from config import config, config_file
self.close()
except Exception as e:
QMessageBox.critical(self,"Failed to save", "Failed to save the data to the file.")
- print(e)
+ logging.warning(e)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
with open(config_file) as f:
self.config=json.loads(f.read()) | config
except Exception as e:
- print(e)
+ logging.warning(e)
self.config=config
self.setWindowTitle("Configuration")
self.input_extra.setText(self.prescriber["extra"])
except Exception as e:
QMessageBox.critical(self,"Failed to load", "Failed to load the data into the application.")
- print(e)
+ logging.error(e)
def save(self, file=False):
if(file is not False or QMessageBox.StandardButton.Yes==QMessageBox.question(self,"Confirm Save", "This action will overwrite the previous information. Continue?")):
self.close()
except Exception as e:
QMessageBox.critical(self,"Failed to save", "Failed to save the data to the file.")
- print(e)
+ logging.error(e)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# MedScript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
+import logging
from config import config
from datetime import datetime
from cryptography.hazmat.primitives.serialization import load_pem_private_key, Encoding
if(not Signature.verify_chain(certificate)):
return False
except Exception as e:
- print(e)
+ logging.warning(e)
return False
with open(certificate, "rb") as f:
subattr+=i.oid._name+":"+i.value+"\n"
return subattr
except Exception as e:
- print(e)
+ logging.warning(e)
return False
def verify_chain(cert_chain_path):
for i in range(len(cert_chain)):
cert=cert_chain[i]
if(datetime.utcnow().timestamp()>cert.not_valid_after.timestamp()):
- print("Certificate expired")
+ logging.warning("Certificate expired")
return False
if(i>0):
prev_cert=cert_chain[i-1]
try:
cert.public_key().verify(prev_cert.signature, prev_cert.tbs_certificate_bytes, padding.PKCS1v15(), prev_cert.signature_hash_algorithm)
except InvalidSignature:
- print("Certificate chain signature verification failed")
+ logging.warning("Certificate chain signature verification failed")
return False
try:
with open(config["root_bundle"]) as root:
root_bundle=root.read()
if(cert_chain[-1].public_bytes(encoding=Encoding.PEM).decode() not in root_bundle):
- print("Certificate not in root bundle")
+ logging.warning("Certificate not in root bundle")
return False
return True
except Exception as e:
- print(e)
- print("Root bundle could not be loaded")
+ logging.warning(e)
+ logging.warning("Root bundle could not be loaded")
return False
# MedScript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
-import os, sys, datetime, dateutil.parser, shutil, json, threading
+import logging, os, sys, datetime, dateutil.parser, shutil, json, threading
from PyQt6.QtCore import Qt, QDateTime, QDate, QSize, pyqtSignal
from PyQt6.QtWidgets import QWidget, QMainWindow, QMessageBox, QLabel, QPushButton, QLineEdit, QTextEdit, QDateTimeEdit, QDateEdit, QCalendarWidget, QListWidget, QComboBox, QCheckBox, QRadioButton, QButtonGroup, QVBoxLayout, QHBoxLayout, QFormLayout, QToolBar, QTabWidget, QStatusBar, QFileDialog, QInputDialog, QCompleter, QSizePolicy
from PyQt6.QtGui import QAction, QIcon
self.unchanged_state=True
except Exception as e:
QMessageBox.warning(self,"Open failed", "Failed to open file.")
- print(e)
+ logging.warning(e)
def cmd_copy(self, data):
self.cmd_new()
self.save_state=md5(self.prescription.get_json().encode()).hexdigest()
except Exception as e:
QMessageBox.warning(self,"Save failed", "Failed to save file.")
- print(e)
+ logging.warning(e)
def cmd_save_as(self):
suggest=self.prescription.id if(self.prescription.id) else self.prescription.name
self.signal_view.emit(target)
self.renderbox.showMaximized()
except FileNotFoundError as e:
- print(e)
+ logging.warning(e)
QMessageBox.information(self, "Save first", "Please save the file before rendering.")
else:
#self.current_file.sign(password)
self.cmd_save()
except FileNotFoundError as e:
- print(e)
+ logging.warning(e)
QMessageBox.information(self, "Save first", "Please save the file before signing.")
except TypeError as e:
- print(e)
+ logging.warning(e)
QMessageBox.information(self, "Configure", "Please add valid key and certificate to the config file.")
except EVPError as e:
- print(e)
+ logging.warning(e)
QMessageBox.information(self, "Check password", "Failed to load key. Please check if password is correct.")
except BIOError as e:
- print(e)
+ logging.warning(e)
QMessageBox.information(self, "Not found", "Certifcate and/or key not found.")
except SMIME_Error as e:
- print(e)
+ logging.warning(e)
QMessageBox.information(self, "Failed to load", "Failed to sign. Please check if certificate and key match.")
except Exception as e:
- print(e)
+ logging.warning(e)
QMessageBox.information(self, "Failed", "Failed to sign.")
except Exception as e:
- print(e)
+ logging.warning(e)
else:
QMessageBox.information(self, "Save first", "Please save the file before signing.")
elif result is None:
QMessageBox.warning(self, "No Siganture", "No signature was found.")
else:
- print(result)
+ logging.info(result)
QMessageBox.information(self, "Valid signature", "Valid signature found with the following information:\n"+result)
except FileNotFoundError as e:
- print(e)
+ logging.warning(e)
QMessageBox.warning(self, "No Siganture", "No signature was found.")
except Exception as e:
- print(e)
+ logging.warning(e)
QMessageBox.warning(self, "Failed", "Failed to verify.")
def cmd_tabular(self):
Tabular.export(filename)
QMessageBox.information(self, "Data Exported", "Data exported to."+filename)
except Exception as e:
- print(e)
+ logging.warning(e)
QMessageBox.critical(self, "Export failed", "Failed to export the data.")
def cmd_index(self):
self.select_prescriber.load()
self.select_prescriber.exec()
except FileNotFoundError as e:
- print(e)
+ logging.warning(e)
def cmd_preset(self):
self.edit_preset.show()
def cmd_update(self, silent=False):
try:
- print("Current version "+info["version"])
+ logging.info("Current version "+info["version"])
with request.urlopen(info["url"]+"/info.json") as response:
latest=json.loads(response.read().decode())
- print("Latest version "+latest["version"])
+ logging.info("Latest version "+latest["version"])
if(version.parse(info["version"]) < version.parse(latest["version"])):
self.signal_update.emit("New version <strong>"+latest["version"]+"</strong> available.<br>Visit <a href='"+latest["url"]+"'>"+latest["url"]+"</a> to get the latest version.")
elif(not silent):
self.signal_update.emit("No update available. You are using version "+info["version"]+".")
except Exception as e:
self.signal_update.emit("Failed to check available update.")
- print(e)
+ logging.warning(e)
def show_update(self, message):
QMessageBox.information(self, "Check update", message)
d=QDateTime.fromString(pdate.strftime("%Y-%m-%d %H:%M:%S"), "yyyy-MM-dd hh:mm:ss")
except Exception as e:
QMessageBox.warning(self,"Failed to load", str(e))
- print(e)
+ logging.warning(e)
self.input_date.setDateTime(d)
self.input_id.setText(id)
self.input_name.setText(name)
self.label_prescriber.setText(self.prescriber.name)
except Exception as e:
QMessageBox.warning(self,"Failed to load", "Failed to load the data into the application.")
- print(e)
+ logging.warning(e)
def load_interface_from_instance(self):
if(self.current_file.has_template()):
)
except Exception as e:
QMessageBox.critical(self,"Failed", "Critical failure happned. Please check console for more info.")
- print(e)
+ logging.error(e)
def new_doc(self):
self.current_file.reset()
self.input_attachment.addItem(new)
except Exception as e:
QMessageBox.warning(self,"Attach failed", "Failed to attach file.")
- print(e)
+ logging.warning(e)
def remove_attachment(self):
index=self.input_attachment.currentRow()
try:
shutil.copyfile(self.input_attachment.currentItem().text(), QFileDialog.getSaveFileName(self, "Save Attachment", os.path.join(config["document_directory"], os.path.basename(self.input_attachment.currentItem().text())))[0])
except Exception as e:
- print(e)
+ logging.warning(e)
def load_attachment(self, attachments):
for attach in attachments:
action_plugin[-1].triggered.connect(partial(self.plugin.run, i[0], self.prescription))
action_plugin[-1].triggered.connect(self.load_interface_from_instance)
except Exception as e:
- print(e)
+ logging.warning(e)
menu_plugin=menubar.addMenu("Plugin")
for i in action_plugin:
menu_plugin.addAction(i)
templates.remove(os.path.basename(config["template"]))
templates.insert(0, os.path.basename(config["template"]))
except Exception as e:
- print(e)
+ logging.warning(e)
self.input_template.addItems(templates)
toolbar.addWidget(self.input_template)
spacer=QWidget(self)