]> Softwares of Agnibho - medscript.git/blob - installer.py
Bugfix: Windows uninstall package permission error
[medscript.git] / installer.py
1 # MedScript
2 # Copyright (C) 2023 Dr. Agnibho Mondal
3 # This file is part of MedScript.
4 # MedScript is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5 # 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.
6 # You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
7
8 from PyQt6.QtWidgets import QWidget, QMainWindow, QVBoxLayout, QHBoxLayout, QPushButton, QListWidget, QMessageBox, QFileDialog
9 from PyQt6.QtGui import QIcon, QStandardItemModel, QStandardItem
10 from glob import glob
11 from zipfile import ZipFile
12 from config import config
13 import logging, os, tempfile, shutil
14
15 class Installer(QMainWindow):
16
17 preset={"name":[], "path":[]}
18 template={"name":[], "path":[]}
19 form={"name":[], "path":[]}
20 plugin={"name":[], "path":[]}
21
22 protected=["note", "report", "advice", "investigation", "medication", "additional", "certificate", "default", "medcert", "<unchanged>"]
23 directory=None
24
25 def cmd_install(self):
26 try:
27 file=QFileDialog.getOpenFileName(self, "Open Package", config["data_directory"], "Zip (*.zip);; All Files (*)")[0]
28 self.directory=tempfile.TemporaryDirectory()
29 with ZipFile(file, "r", strict_timestamps=False) as package:
30 package.extractall(self.directory.name)
31 for i in glob(os.path.join(self.directory.name, "preset", "*.csv")):
32 name=os.path.splitext(os.path.basename(i))[0]
33 if name not in self.protected:
34 if name not in self.preset["name"]:
35 if(QMessageBox.StandardButton.Yes==QMessageBox.question(self, "Confirm install", "Installing PRESET <strong>"+name+"</strong>. Continue?")):
36 self.copy(i, config["preset_directory"])
37 else:
38 QMessageBox.information(self, "File exists", "PRESET <strong>"+name+"</strong> is already installed.")
39 for i in glob(os.path.join(self.directory.name, "template", "*")):
40 if os.path.exists(os.path.join(i, "index.html")):
41 name=os.path.basename(i)
42 if name not in self.protected:
43 if name not in self.template["name"]:
44 if(QMessageBox.StandardButton.Yes==QMessageBox.question(self, "Confirm install", "Installing TEMPLATE <strong>"+name+"</strong>. Continue?")):
45 self.copy(i, os.path.join(config["template_directory"], name))
46 else:
47 QMessageBox.information(self, "File exists", "TEMPLATE <strong>"+name+"</strong> is already installed.")
48 for i in glob(os.path.join(self.directory.name, "form", "*.json")):
49 name=os.path.splitext(os.path.basename(i))[0]
50 if name not in self.protected:
51 if name not in self.form["name"]:
52 if(QMessageBox.StandardButton.Yes==QMessageBox.question(self, "Confirm install", "Installing FORM <strong>"+name+"</strong>. Continue?")):
53 self.copy(i, config["form_directory"])
54 else:
55 QMessageBox.information(self, "File exists", "FORM <strong>"+name+"</strong> is already installed.")
56 for i in glob(os.path.join(self.directory.name, "plugin", "*")):
57 if os.path.exists(os.path.join(i, "main.py")):
58 name=os.path.basename(i)
59 if name not in self.protected:
60 if name not in self.plugin["name"]:
61 if(QMessageBox.StandardButton.Yes==QMessageBox.question(self, "Confirm install", "Installing PLUGIN <strong>"+name+"</strong>. Continue?")):
62 self.copy(i, os.path.join(config["plugin_directory"], name))
63 else:
64 QMessageBox.information(self, "File exists", "PLUGIN <strong>"+name+"</strong> is already installed.")
65 QMessageBox.information(self, "Restart", "Please restart MedScript for the changes to take effect.")
66 except Exception as e:
67 logging.exception(e)
68
69 def cmd_uninstall(self):
70 txt=self.installed.currentItem().text().split("\t")
71 name=txt[1]
72 group=txt[0].replace("[", "").replace("]", "")
73 if name not in self.protected:
74 if(group=="preset"):
75 if(QMessageBox.StandardButton.Yes==QMessageBox.question(self, "Confirm uninstall", "Uninstalling PRESET <strong>"+name+"</strong>. Continue?")):
76 idx=self.preset["name"].index(name)
77 path=self.preset["path"][idx]
78 self.delete(path)
79 elif(group=="template"):
80 if(QMessageBox.StandardButton.Yes==QMessageBox.question(self, "Confirm uninstall", "Uninstalling TEMPLATE <strong>"+name+"</strong>. Continue?")):
81 idx=self.template["name"].index(name)
82 path=self.template["path"][idx]
83 self.delete(path)
84 elif(group=="form"):
85 if(QMessageBox.StandardButton.Yes==QMessageBox.question(self, "Confirm uninstall", "Uninstalling FORM <strong>"+name+"</strong>. Continue?")):
86 idx=self.form["name"].index(name)
87 path=self.form["path"][idx]
88 self.delete(path)
89 elif(group=="plugin"):
90 if(QMessageBox.StandardButton.Yes==QMessageBox.question(self, "Confirm uninstall", "Uninstalling PLUGIN <strong>"+name+"</strong>. Continue?")):
91 idx=self.plugin["name"].index(name)
92 path=self.plugin["path"][idx]
93 self.delete(path)
94 QMessageBox.information(self, "Restart", "Please restart MedScript for the changes to take effect.")
95 else:
96 QMessageBox.information(self, "Item protected", "Protected items cannot be deleted.")
97
98 def delete(self, path):
99 try:
100 os.unlink(path)
101 except (IsADirectoryError, PermissionError):
102 shutil.rmtree(path)
103 except Exception as e:
104 QMessageBox.critical(self, "Failed", "Uninstallation failed. Please manually delete package.")
105 logging.critical(e)
106 self.load()
107
108 def copy(self, path, destination):
109 try:
110 shutil.copytree(path, destination)
111 except NotADirectoryError:
112 shutil.copy(path, destination)
113 except Exception as e:
114 logging.critical(e)
115 self.load()
116
117 def __init__(self, *args, **kwargs):
118 super().__init__(*args, **kwargs)
119
120 self.setWindowTitle("MedScript Package Installer")
121 self.setGeometry(200, 200, 600, 400)
122
123 widget=QWidget(self)
124 layout=QVBoxLayout(widget)
125 self.installed=QListWidget()
126 layout.addWidget(self.installed)
127 layout2=QHBoxLayout()
128 button_install=QPushButton("Install")
129 button_install.clicked.connect(self.cmd_install)
130 button_uninstall=QPushButton("Uninstall")
131 button_uninstall.clicked.connect(self.cmd_uninstall)
132 layout2.addWidget(button_install)
133 layout2.addWidget(button_uninstall)
134 layout.addLayout(layout2)
135
136 self.setCentralWidget(widget)
137 self.setWindowIcon(QIcon(os.path.join("resource", "icon_medscript.ico")))
138
139 self.load()
140
141 def load(self, file=None):
142 self.preset={"name":[], "path":[]}
143 self.template={"name":[], "path":[]}
144 self.form={"name":[], "path":[]}
145 self.plugin={"name":[], "path":[]}
146 self.installed.clear()
147 try:
148 for i in glob(os.path.join(config["preset_directory"], "*.csv")):
149 self.preset["name"].append(os.path.splitext(os.path.basename(i))[0])
150 self.preset["path"].append(i)
151 for i in glob(os.path.join(config["template_directory"], "*")):
152 if(os.path.exists(os.path.join(i, "index.html"))):
153 self.template["name"].append(os.path.basename(i))
154 self.template["path"].append(i)
155 for i in glob(os.path.join(config["form_directory"], "*.json")):
156 self.form["name"].append(os.path.splitext(os.path.basename(i))[0])
157 self.form["path"].append(i)
158 for i in glob(os.path.join(config["plugin_directory"], "*")):
159 if(os.path.exists(os.path.join(i, "main.py"))):
160 self.plugin["name"].append(os.path.basename(i))
161 self.plugin["path"].append(i)
162
163 for i in self.preset["name"]:
164 if i not in self.protected:
165 self.installed.addItem("[preset]\t"+i)
166 for i in self.template["name"]:
167 if i not in self.protected:
168 self.installed.addItem("[template]\t"+i)
169 for i in self.form["name"]:
170 if i not in self.protected:
171 self.installed.addItem("[form]\t"+i)
172 for i in self.plugin["name"]:
173 if i not in self.protected:
174 self.installed.addItem("[plugin]\t"+i)
175 except Exception as e:
176 logging.exception(e)