class TxDisplayWidget(QtGui.QWidget): text_edited = QtCore.pyqtSignal() def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.pl_lineedit = UpperCaseLineEdit() self.cmp_lineedit = UpperCaseLineEdit() icon = QtGui.QIcon(":forward.png") but = QtGui.QPushButton() but.setIcon(icon) but.setMaximumWidth(30) but.clicked.connect(self._complete_treatments) layout = QtGui.QHBoxLayout(self) layout.setMargin(0) layout.addWidget(self.pl_lineedit) layout.addWidget(but) layout.addWidget(self.cmp_lineedit) def set_plan_text(self, text): self._initial_pl_text = text self.pl_lineedit.setText(text) self.pl_lineedit.textChanged.connect(self.text_edited.emit) def set_completed_text(self, text): self._initial_cmp_text = text self.cmp_lineedit.setText(text) self.cmp_lineedit.textChanged.connect(self.text_edited.emit) def _complete_treatments(self): self.cmp_lineedit.setText(u"%s %s" % (self.cmp_text, self.plan_text)) self.pl_lineedit.setText("") @property def plan_text(self): txt = unicode(self.pl_lineedit.text().toUtf8()) # denture codes are dumb! return re.sub("SR\ ", "SR_", txt) @property def cmp_text(self): txt = unicode(self.cmp_lineedit.text().toUtf8()) # denture codes are dumb! return re.sub("SR\ ", "SR_", txt) @property def plan_edited(self): return self.plan_text != self._initial_pl_text @property def cmp_edited(self): return self.cmp_text != self._initial_cmp_text @property def has_been_edited(self): return not (self.plan_edited or self.cmp_edited)
class TxDisplayWidget(QtGui.QWidget): text_edited = QtCore.pyqtSignal() def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.pl_lineedit = UpperCaseLineEdit() self.cmp_lineedit = UpperCaseLineEdit() icon = QtGui.QIcon(":forward.png") but = QtGui.QPushButton() but.setIcon(icon) but.setMaximumWidth(30) but.clicked.connect(self._complete_treatments) layout = QtGui.QHBoxLayout(self) layout.setMargin(0) layout.addWidget(self.pl_lineedit) layout.addWidget(but) layout.addWidget(self.cmp_lineedit) def set_plan_text(self, text): self._initial_pl_text = text self.pl_lineedit.setText(text) self.pl_lineedit.textChanged.connect(self.text_edited.emit) def set_completed_text(self, text): self._initial_cmp_text = text self.cmp_lineedit.setText(text) self.cmp_lineedit.textChanged.connect(self.text_edited.emit) def _complete_treatments(self): self.cmp_lineedit.setText("%s %s" % (self.cmp_text, self.plan_text)) self.pl_lineedit.setText("") @property def plan_text(self): txt = str(self.pl_lineedit.text()) # denture codes are dumb! return re.sub("SR\ ", "SR_", txt) @property def cmp_text(self): txt = str(self.cmp_lineedit.text()) # denture codes are dumb! return re.sub("SR\ ", "SR_", txt) @property def plan_edited(self): return self.plan_text != self._initial_pl_text @property def cmp_edited(self): return self.cmp_text != self._initial_cmp_text @property def has_been_edited(self): return not (self.plan_edited or self.cmp_edited)
class AddUserDialog(ExtendableDialog): def __init__(self, parent=None): ExtendableDialog.__init__(self, parent) self.setWindowTitle(_("Add User Dialog")) self.top_label = WarningLabel("%s<br />%s<hr />%s" % ( _('Add a new user to the system?'), _("This is done using initials or a short nickname."), _("Must be unique and Maximum allowed in 5 characters"))) self.line_edit = UpperCaseLineEdit() frame = QtWidgets.QFrame(self) layout = QtWidgets.QFormLayout(frame) layout.addRow(_("User Initials or nickname"), self.line_edit) self.insertWidget(self.top_label) self.insertWidget(frame) self.line_edit.textChanged.connect(self._check_enable) self.line_edit.setFocus() settings_fetcher = db_settings.SettingsFetcher() self.existing_logins = settings_fetcher.existing_logins() list_widget = QtWidgets.QListWidget() list_widget.addItems(sorted(self.existing_logins)) self.add_advanced_widget(list_widget) self.set_advanced_but_text(_("view existing users")) def _check_enable(self, *args): input_ = self.username if input_ in self.existing_logins: QtWidgets.QMessageBox.warning( self, _("error"), _("Initials/nickname must be unique")) self.enableApply(False) else: self.enableApply(input_ != "") @property def username(self): return str(self.line_edit.text()) def apply(self): if db_settings.insert_login(self.username): localsettings.initiateUsers() return True def exec_(self): if ExtendableDialog.exec_(self): return self.apply() return False
class AddUserDialog(ExtendableDialog): def __init__(self, parent=None): ExtendableDialog.__init__(self, parent) self.setWindowTitle(_("Add User Dialog")) self.top_label = WarningLabel( "%s<br />%s<hr />%s" % (_('Add a new user to the system?'), _("This is done using initials or a short nickname."), _("Must be unique and Maximum allowed in 5 characters"))) self.line_edit = UpperCaseLineEdit() frame = QtGui.QFrame(self) layout = QtGui.QFormLayout(frame) layout.addRow(_("User Initials or nickname"), self.line_edit) self.insertWidget(self.top_label) self.insertWidget(frame) self.line_edit.textChanged.connect(self._check_enable) self.line_edit.setFocus() list_widget = QtGui.QListWidget() list_widget.addItems(sorted(localsettings.allowed_logins)) self.add_advanced_widget(list_widget) self.set_advanced_but_text(_("view existing users")) def _check_enable(self, *args): input_ = self.username if input_ in localsettings.allowed_logins: QtGui.QMessageBox.warning( self, _("error"), _("Initials/nickname mut be unique"), ) self.enableApply(False) else: self.enableApply(input_ != "") @property def username(self): return unicode(self.line_edit.text().toUtf8()) def apply(self): if db_settings.insert_login(self.username): localsettings.initiateUsers() return True def exec_(self): if ExtendableDialog.exec_(self): return self.apply() return False
class ChildSmileDialog(BaseDialog): result = "" is_checking_website = False def __init__(self, parent): BaseDialog.__init__(self, parent) self.main_ui = parent self.header_label = QtGui.QLabel() self.header_label.setAlignment(QtCore.Qt.AlignCenter) self.pcde_le = UpperCaseLineEdit() self.pcde_le.setText(self.main_ui.pt.pcde) self.simd_label = QtGui.QLabel() self.simd_label.setAlignment(QtCore.Qt.AlignCenter) self.tbi_checkbox = QtGui.QCheckBox( _("ToothBrushing Instruction Given")) self.tbi_checkbox.setChecked(True) self.di_checkbox = QtGui.QCheckBox(_("Dietary Advice Given")) self.di_checkbox.setChecked(True) self.fl_checkbox = QtGui.QCheckBox(_("Fluoride Varnish Applied")) self.fl_checkbox.setToolTip( _("Fee claimable for patients betwen 2 and 5")) self.fl_checkbox.setChecked(2 <= self.main_ui.pt.ageYears <= 5) self.insertWidget(self.header_label) self.insertWidget(self.pcde_le) self.insertWidget(self.simd_label) self.insertWidget(self.tbi_checkbox) self.insertWidget(self.di_checkbox) self.insertWidget(self.fl_checkbox) self.pcde_le.textEdited.connect(self.check_pcde) self._simd = None @property def pcde(self): try: return str(self.pcde_le.text()) except: return "" @property def valid_postcode(self): return bool(re.match("[A-Z][A-Z](\d+) (\d+)[A-Z][A-Z]", self.pcde)) def postcode_warning(self): if not self.valid_postcode: QtGui.QMessageBox.warning(self, "error", "Postcode is not valid") def check_pcde(self): if self.valid_postcode: QtCore.QTimer.singleShot(50, self.simd_lookup) else: self.header_label.setText(_("Please enter a valid postcode")) self.simd_label.setText("") self.enableApply(False) def simd_lookup(self): ''' poll the server for a simd for a postcode ''' QtGui.QApplication.instance().processEvents() global TODAYS_LOOKUPS try: self.result = TODAYS_LOOKUPS[self.pcde] self.simd_label.setText("%s %s" % (_("KNOWN SIMD"), self.result)) self.enableApply(True) LOGGER.debug("simd_lookup unnecessary, value known") return except KeyError: pass self.header_label.setText(_("Polling website with Postcode")) pcde = self.pcde.replace(" ", "%20") url = "%s?pCode=%s" % (LOOKUP_URL, pcde) try: QtGui.QApplication.instance().setOverrideCursor( QtCore.Qt.WaitCursor) req = urllib.request.Request(url, headers=HEADERS) response = urllib.request.urlopen(req, timeout=20) result = response.read() self.result = self._parse_result(result) except urllib.error.URLError: LOGGER.error("url error polling NHS website?") self.result = _("Error polling website") except socket.timeout: LOGGER.error("timeout error polling NHS website?") self.result = _("Timeout polling website") finally: QtGui.QApplication.instance().restoreOverrideCursor() self.simd_label.setText("%s = %s" % (_("RESULT"), self.result)) QtGui.QApplication.instance().processEvents() TODAYS_LOOKUPS[self.pcde] = "SIMD: %s" % self.simd_number self.enableApply(self.simd_number is not None) self.header_label.setText("SIMD %d" % self.simd_number) def _parse_result(self, result): try: dom = minidom.parseString(result) e = dom.getElementsByTagName("span")[0] return e.firstChild.data except ExpatError: return "UNDECIPHERABLE REPLY" def manual_entry(self): simd, result = QtGui.QInputDialog.getInteger( self, _("Manual Input Required"), _("Online lookup has failed, please enter the SIMD manually"), 4, 1, 5) if not result: self.reject() self.result += " - Manually entered SIMD of %d" % simd return simd @property def simd_number(self): if self._simd is None: m = re.search("(\d+)", self.result) if m: self._simd = int(m.groups()[0]) else: self._simd = 4 self._simd = self.manual_entry() return self._simd @property def tbi_performed(self): return self.tbi_checkbox.isChecked() @property def di_performed(self): return self.di_checkbox.isChecked() @property def fl_applied(self): return self.fl_checkbox.isChecked() @property def tx_items(self): age = self.main_ui.pt.ageYears is_dentist = \ localsettings.clinicianNo in list(localsettings.dentDict.keys()) LOGGER.debug("Performed by dentist = %s" % is_dentist) if age < 3: if self.simd_number < 4: yield ("other", "CS1") else: yield ("other", "CS2") if self.tbi_performed: code = "TB1" if is_dentist else "TB2" yield ("other", code) if self.di_performed: code = "DI1" if is_dentist else "DI2" yield ("other", code) else: if self.simd_number < 4: yield ("other", "CS3") if self.tbi_performed: code = "TB3" if is_dentist else "TB4" yield ("other", code) if self.di_performed: code = "DI3" if is_dentist else "DI4" yield ("other", code) if 2 <= age <= 5: if self.fl_applied: yield ("other", "CSFL") def exec_(self): QtCore.QTimer.singleShot(100, self.check_pcde) QtCore.QTimer.singleShot(500, self.postcode_warning) if BaseDialog.exec_(self): if self.valid_postcode: self.main_ui.pt.pcde = self.pcde self.main_ui.addNewNote( "CHILDSMILE (postcode '%s'): %s" % (self.pcde, self.result)) return True return False
class LoginDialog(ExtendableDialog): sys_password = None uninitiated = True __is_developer_environment = None def __init__(self, parent=None): ExtendableDialog.__init__(self, parent) self.setWindowTitle(_("Login Dialog")) header_label = WarningLabel(_('Login Required')) self.password_lineEdit = QtGui.QLineEdit() self.password_lineEdit.setEchoMode(QtGui.QLineEdit.Password) self.user1_lineEdit = UpperCaseLineEdit() self.user1_lineEdit.setMaximumWidth(50) self.user2_lineEdit = UpperCaseLineEdit() self.user2_lineEdit.setMaximumWidth(50) self.reception_radioButton = QtGui.QRadioButton(_("Reception Machine")) self.surgery_radioButton = QtGui.QRadioButton(_("Surgery Machine")) self.surgery_radioButton.setChecked(True) frame = QtGui.QFrame() form_layout = QtGui.QFormLayout(frame) form_layout.addRow(_("System Password"), self.password_lineEdit) form_layout.addRow(_("User 1 (Required)"), self.user1_lineEdit) form_layout.addRow(_("User 2 (Optional)"), self.user2_lineEdit) but_group = QtGui.QButtonGroup(self) but_group.addButton(self.surgery_radioButton) but_group.addButton(self.reception_radioButton) self.insertWidget(header_label) self.insertWidget(frame) self.insertWidget(self.surgery_radioButton) self.insertWidget(self.reception_radioButton) self.enableApply() # grab any stored information PASSWORD, USER1, USER2 = localsettings.autologin() self.password_lineEdit.setText(PASSWORD) self.user1_lineEdit.setText(USER1) self.user2_lineEdit.setText(USER2) self.autoreception(QtCore.QString(USER1)) self.autoreception(QtCore.QString(USER2)) self.parse_conf_file() self.alternate_servers_widget = AlternateServersWidget(self) if self.alternate_servers_widget.has_options: self.more_but.setText(_("Database choice")) self.add_advanced_widget(self.alternate_servers_widget) else: self.more_but.hide() self.user1_lineEdit.textEdited.connect(self.autoreception) self.user2_lineEdit.textEdited.connect(self.autoreception) self.dirty = True self.set_check_on_cancel(True) QtCore.QTimer.singleShot(0, self._developer_login) def sizeHint(self): return QtCore.QSize(350, 300) def showEvent(self, event): self.password_lineEdit.setFocus(True) @property def abandon_message(self): return _("Are you sure you wish to cancel the login process?") def parse_conf_file(self): try: dom = minidom.parse(localsettings.cflocation) self.sys_password = dom.getElementsByTagName( "system_password")[0].firstChild.data servernames = dom.getElementsByTagName("connection") for i, server in enumerate(servernames): nameDict = server.attributes try: localsettings.server_names.append(nameDict["name"].value) except KeyError: localsettings.server_names.append("%d" % i + 1) except IOError as e: LOGGER.warning("still no settings file. quitting politely") QtGui.QMessageBox.information(None, _("Unable to Run OpenMolar"), _("Good Bye!")) QtGui.QApplication.instance().closeAllWindows() sys.exit("unable to run - openMolar couldn't find a settings file") def autoreception(self, user): ''' check to see if the user is special user "rec" which implies a reception machine ''' if user.toLower() == "rec": self.reception_radioButton.setChecked(True) @property def _is_developer_environment(self): if self.__is_developer_environment is None: self.__is_developer_environment = False try: dev_path = os.path.join( localsettings.localFileDirectory, "dev_login.txt") f = open(dev_path, "r") data = f.read().strip("\n") f.close() if localsettings.hash_func(data) == \ '1fd0c27f4d65caaa10ef5ef6a714faf96ed44fdd': LOGGER.warning("allowing developer login") self.__is_developer_environment = True else: LOGGER.warning( "dev_login - file present, but with bad checksum") except: # fail quietly pass return self.__is_developer_environment def _developer_login(self): ''' convenience function for developer to login without password ''' if self._is_developer_environment and not "--no-dev-login" in sys.argv: self.accept() @property def password_ok(self): LOGGER.info("checking password") pword = "diqug_ADD_SALT_3i2some%s" % ( self.password_lineEdit.text().toAscii()) #-- hash the salted password (twice!) and compare to the value #-- stored in /etc/openmolar/openmolar.conf (linux) stored_password = hashlib.md5( hashlib.sha1(pword).hexdigest()).hexdigest() match = stored_password == self.sys_password return match @property def user1(self): return str(self.user1_lineEdit.text().toAscii()) @property def user1_ok(self): return self.user1 in localsettings.allowed_logins @property def user2(self): return str(self.user2_lineEdit.text().toAscii()) @property def user2_ok(self): return self.user2 == "" or self.user2 in localsettings.allowed_logins @property def login_ok(self): return self.user1_ok and self.user2_ok and ( self._is_developer_environment or self.password_ok) @property def chosen_server(self): return self.alternate_servers_widget.chosen def db_check(self): LOGGER.debug("performing db_check") changedServer = localsettings.chosenserver != self.chosen_server localsettings.setChosenServer(self.chosen_server) if self.uninitiated or changedServer: #- user has entered the correct password #- so now we connect to the mysql database #- for the 1st time #- I do it this way so that anyone sniffing the network #- won't see the mysql password until this point #- this could and should possibly still be improved upon #- maybe by using an ssl connection to the server. localsettings.initiateUsers(changedServer) self.uninitiated = False def exec_(self): while ExtendableDialog.exec_(self): self.db_check() if self.login_ok: if self.reception_radioButton.isChecked(): localsettings.station = "reception" localsettings.setOperator(self.user1, self.user2) self.accept() return True else: # LOGGER.debug("passwords ok %s", self.password_ok) # LOGGER.debug("user1 ok %s", self.user1_ok) # LOGGER.debug("user2 ok %s", self.user2_ok) QtGui.QMessageBox.warning( self.parent(), _("Login Error"), u'<h2>%s %s</h2><em>%s</em>' % ( _('Incorrect'), _("User/password combination!"), _('Please Try Again.') ) ) return False
class FeescaleTestingDialog(Ui_codeChecker.Ui_Dialog, QtGui.QDialog): def __init__(self, parent=None): QtGui.QDialog.__init__(self, parent) self.setupUi(self) self.table_list = [] tablenames = [] self.load_feescales() self.model2 = DeciduousAttributeModel(self.current_table) self.model3 = AdultAttributeModel(self.current_table) self.dec_tableView.setModel(self.model2) self.adult_tableView.setModel(self.model3) self.dec_tableView.horizontalHeader().setStretchLastSection(True) self.adult_tableView.horizontalHeader().setStretchLastSection(True) self.setWindowTitle(_("Shortcut tester")) self.connect(self.comboBox, QtCore.SIGNAL("currentIndexChanged (int)"), self.change_table) self.pushButton.clicked.connect(self.check_codes) self.quit_pushButton.clicked.connect(self.accept) self.line_edits = {} form_layout = QtGui.QFormLayout(self.frame) for att in CURRTRT_NON_TOOTH_ATTS: widg = QtGui.QLineEdit() self.line_edits[att] = widg form_layout.addRow(att, widg) self.lineEdit = UpperCaseLineEdit() self.bottom_layout.insertWidget(1, self.lineEdit) self.lineEdit.setText("P") self.check_codes() def load_feescales(self): self.table_list = [] self.tablenames = [] for table in localsettings.FEETABLES.tables.values(): self.table_list.append(table) self.tablenames.append(table.briefName) self.comboBox.clear() self.comboBox.addItems(self.tablenames) def check_codes(self): tx = str(self.lineEdit.text().toAscii()).upper() complex_matches = [] for att in CURRTRT_NON_TOOTH_ATTS: for complex_shortcut in self.current_table.complex_shortcuts: if complex_shortcut.matches(att, tx): complex_matches.append(att) usercode = "%s %s"% (att, tx) code = self.current_table.getItemCodeFromUserCode(usercode) if code == "-----": self.line_edits[att].setText("") else: description = self.current_table.getItemDescription( code, usercode) self.line_edits[att].setText("%s %s"%(code, description)) for model in (self.model2, self.model3): model.code = tx model.reset() for att in DECIDMOUTH + ADULTMOUTH: for complex_shortcut in self.current_table.complex_shortcuts: if complex_shortcut.matches(att, tx): complex_matches.append(att) if complex_matches != []: QtGui.QMessageBox.information(self, _("Information"), "%s '%s' %s<hr />%s"% ( _("This feescale handles"), tx, _("as a complex code for the following attributes."), complex_matches)) @property def current_table(self): return self.table_list[self.comboBox.currentIndex()] def change_table(self, i): self.model2.table = self.current_table self.model3.table = self.current_table self.check_codes()
class ChildSmileDialog(BaseDialog): result = "" is_checking_website = False def __init__(self, parent): BaseDialog.__init__(self, parent) self.main_ui = parent self.header_label = QtWidgets.QLabel() self.header_label.setAlignment(QtCore.Qt.AlignCenter) self.pcde_le = UpperCaseLineEdit() self.pcde_le.setText(self.main_ui.pt.pcde) self.simd_label = QtWidgets.QLabel() self.simd_label.setAlignment(QtCore.Qt.AlignCenter) self.tbi_checkbox = QtWidgets.QCheckBox( _("ToothBrushing Instruction Given")) self.tbi_checkbox.setChecked(True) self.di_checkbox = QtWidgets.QCheckBox(_("Dietary Advice Given")) self.di_checkbox.setChecked(True) self.fl_checkbox = QtWidgets.QCheckBox(_("Fluoride Varnish Applied")) self.fl_checkbox.setToolTip( _("Fee claimable for patients betwen 2 and 5")) self.fl_checkbox.setChecked(2 <= self.main_ui.pt.ageYears <= 5) self.insertWidget(self.header_label) self.insertWidget(self.pcde_le) self.insertWidget(self.simd_label) self.insertWidget(self.tbi_checkbox) self.insertWidget(self.di_checkbox) self.insertWidget(self.fl_checkbox) self.pcde_le.textEdited.connect(self.check_pcde) self._simd = None @property def pcde(self): try: return str(self.pcde_le.text()) except: return "" @property def valid_postcode(self): return bool(re.match("[A-Z][A-Z](\d+) (\d+)[A-Z][A-Z]", self.pcde)) def postcode_warning(self): if not self.valid_postcode: QtWidgets.QMessageBox.warning(self, "error", "Postcode is not valid") def check_pcde(self): if self.valid_postcode: QtCore.QTimer.singleShot(50, self.simd_lookup) else: self.header_label.setText(_("Please enter a valid postcode")) self.simd_label.setText("") self.enableApply(False) def simd_lookup(self): ''' poll the server for a simd for a postcode ''' QtWidgets.QApplication.instance().processEvents() global TODAYS_LOOKUPS try: self.result = TODAYS_LOOKUPS[self.pcde] self.simd_label.setText("%s %s" % (_("KNOWN SIMD"), self.result)) self.enableApply(True) LOGGER.debug("simd_lookup unnecessary, value known") return except KeyError: pass self.header_label.setText(_("Polling website with Postcode")) pcde = self.pcde.replace(" ", "%20") url = "%s?pCode=%s" % (LOOKUP_URL, pcde) try: QtWidgets.QApplication.instance().setOverrideCursor( QtCore.Qt.WaitCursor) req = urllib.request.Request(url, headers=HEADERS) response = urllib.request.urlopen(req, timeout=20) result = response.read() self.result = self._parse_result(result) TODAYS_LOOKUPS[self.pcde] = "SIMD: %s" % self.simd_number except urllib.error.URLError: LOGGER.error("url error polling NHS website?") self.result = _("Error polling website") except socket.timeout: LOGGER.error("timeout error polling NHS website?") self.result = _("Timeout polling website") finally: QtWidgets.QApplication.instance().restoreOverrideCursor() self.simd_label.setText("%s = %s" % (_("RESULT"), self.result)) QtWidgets.QApplication.instance().processEvents() self.enableApply(self.simd_number is not None) self.header_label.setText("SIMD %d" % self.simd_number) def _parse_result(self, result): try: dom = minidom.parseString(result) e = dom.getElementsByTagName("span")[0] return e.firstChild.data except ExpatError: return "UNDECIPHERABLE REPLY" def manual_entry(self): dl = QtWidgets.QInputDialog(self) dl.setWindowTitle(_("Manual Input Required")) dl.setInputMode(dl.IntInput) dl.setIntRange(1, 5) dl.setIntValue(4) dl.setLabelText( _("Online lookup has failed, please enter the SIMD manually")) self.rejected.connect(dl.reject) # for Unittests if dl.exec_(): self.reject() return simd = dl.intValue() self.result += " - Manually entered SIMD of %d" % simd return simd @property def simd_number(self): if self._simd is None: m = re.search("(\d+)", self.result) if m: self._simd = int(m.groups()[0]) else: self._simd = 4 self._simd = self.manual_entry() return self._simd @property def tbi_performed(self): return self.tbi_checkbox.isChecked() @property def di_performed(self): return self.di_checkbox.isChecked() @property def fl_applied(self): return self.fl_checkbox.isChecked() @property def tx_items(self): age = self.main_ui.pt.ageYears is_dentist = \ localsettings.clinicianNo in list(localsettings.dentDict.keys()) LOGGER.debug("Performed by dentist = %s" % is_dentist) if age < 3: if self.simd_number < 4: yield ("other", "CS1") else: yield ("other", "CS2") if self.tbi_performed: code = "TB1" if is_dentist else "TB2" yield ("other", code) if self.di_performed: code = "DI1" if is_dentist else "DI2" yield ("other", code) else: if self.simd_number < 4: yield ("other", "CS3") if self.tbi_performed: code = "TB3" if is_dentist else "TB4" yield ("other", code) if self.di_performed: code = "DI3" if is_dentist else "DI4" yield ("other", code) if 2 <= age <= 5: if self.fl_applied: yield ("other", "CSFL") def exec_(self): QtCore.QTimer.singleShot(100, self.check_pcde) QtCore.QTimer.singleShot(500, self.postcode_warning) if BaseDialog.exec_(self): if self.valid_postcode: self.main_ui.pt.pcde = self.pcde self.main_ui.addNewNote( "CHILDSMILE (postcode '%s'): %s" % (self.pcde, self.result)) return True return False
class LoginDialog(ExtendableDialog): sys_password = None uninitiated = True __is_developer_environment = None def __init__(self, parent=None): ExtendableDialog.__init__(self, parent) self.setWindowTitle(_("Login Dialog")) header_label = WarningLabel(_('Login Required')) self.password_lineEdit = QtWidgets.QLineEdit() self.password_lineEdit.setEchoMode(QtWidgets.QLineEdit.Password) self.user1_lineEdit = UpperCaseLineEdit() self.user1_lineEdit.setMaximumWidth(50) self.user2_lineEdit = UpperCaseLineEdit() self.user2_lineEdit.setMaximumWidth(50) self.reception_radioButton = QtWidgets.QRadioButton( _("Reception Machine")) self.surgery_radioButton = QtWidgets.QRadioButton(_("Surgery Machine")) self.surgery_radioButton.setChecked(True) frame = QtWidgets.QFrame() form_layout = QtWidgets.QFormLayout(frame) form_layout.addRow(_("System Password"), self.password_lineEdit) form_layout.addRow(_("User 1 (Required)"), self.user1_lineEdit) form_layout.addRow(_("User 2 (Optional)"), self.user2_lineEdit) but_group = QtWidgets.QButtonGroup(self) but_group.addButton(self.surgery_radioButton) but_group.addButton(self.reception_radioButton) self.insertWidget(header_label) self.insertWidget(frame) self.insertWidget(self.surgery_radioButton) self.insertWidget(self.reception_radioButton) self.enableApply() # grab any stored information PASSWORD, USER1, USER2 = localsettings.autologin() self.password_lineEdit.setText(PASSWORD) self.user1_lineEdit.setText(USER1) self.user2_lineEdit.setText(USER2) self.autoreception(USER1) self.autoreception(USER2) self.parse_conf_file() self.alternate_servers_widget = AlternateServersWidget(self) if self.alternate_servers_widget.has_options: self.more_but.setText(_("Database choice")) self.add_advanced_widget(self.alternate_servers_widget) else: self.more_but.hide() self.user1_lineEdit.textEdited.connect(self.autoreception) self.user2_lineEdit.textEdited.connect(self.autoreception) self.dirty = True self.set_check_on_cancel(True) QtCore.QTimer.singleShot(1000, self._developer_login) def sizeHint(self): return QtCore.QSize(350, 300) def showEvent(self, event): self.password_lineEdit.setFocus(True) @property def abandon_message(self): return _("Are you sure you wish to cancel the login process?") def parse_conf_file(self): try: dom = minidom.parse(localsettings.cflocation) self.sys_password = dom.getElementsByTagName( "system_password")[0].firstChild.data servernames = dom.getElementsByTagName("connection") for i, server in enumerate(servernames): nameDict = server.attributes try: localsettings.server_names.append(nameDict["name"].value) except KeyError: localsettings.server_names.append("%d" % i + 1) except IOError: LOGGER.warning("still no settings file. quitting politely") QtWidgets.QMessageBox.information( None, _("Unable to Run OpenMolar"), _("Good Bye!")) QtWidgets.QApplication.instance().closeAllWindows() sys.exit("unable to run - openMolar couldn't find a settings file") def autoreception(self, user): ''' check to see if the user is special user "rec" which implies a reception machine ''' if user.lower() == "rec": self.reception_radioButton.setChecked(True) @property def _is_developer_environment(self): if self.__is_developer_environment is None: self.__is_developer_environment = False try: dev_path = os.path.join( localsettings.LOCALFILEDIRECTORY, "dev_login.txt") f = open(dev_path, "r") data = f.read().strip("\n") f.close() if localsettings.hash_func(data) == \ '1fd0c27f4d65caaa10ef5ef6a714faf96ed44fdd': LOGGER.warning("allowing developer login") self.__is_developer_environment = True else: LOGGER.warning( "dev_login - file present, but with bad checksum") except: # fail quietly pass return self.__is_developer_environment def _developer_login(self): ''' convenience function for developer to login without password ''' LOGGER.debug("Checking for developer environment") if "--no-dev-login" in sys.argv: return if self._is_developer_environment: LOGGER.info("developer environment found!") self.accept() else: LOGGER.debug("not a developer environment") @property def password_ok(self): if self._is_developer_environment: return True LOGGER.info("checking password") pword = "diqug_ADD_SALT_3i2some%s" % self.password_lineEdit.text() # hash the salted password (twice!) and compare to the value # stored in /etc/openmolar/openmolar.conf (linux) sha1_pass = hashlib.sha1(pword.encode("utf8")).hexdigest() stored_password = hashlib.md5(sha1_pass.encode("utf8")).hexdigest() match = stored_password == self.sys_password return match @property def user1(self): return self.user1_lineEdit.text() @property def user1_ok(self): return self.user1 in localsettings.allowed_logins @property def user2(self): return self.user2_lineEdit.text() @property def user2_ok(self): return self.user2 == "" or self.user2 in localsettings.allowed_logins @property def login_ok(self): try: return self.user1_ok and self.user2_ok and ( self._is_developer_environment or self.password_ok) except: LOGGER.exception("error checking login") @property def chosen_server(self): return self.alternate_servers_widget.chosen def db_check(self): LOGGER.debug("performing db_check") changedServer = localsettings.chosenserver != self.chosen_server localsettings.setChosenServer(self.chosen_server) if self.uninitiated or changedServer: # user has entered the correct password # so now we connect to the mysql database # for the 1st time # I do it this way so that anyone sniffing the network # won't see the mysql password until this point # this could and should possibly still be improved upon # maybe by using an ssl connection to the server. localsettings.initiateUsers(changedServer) self.uninitiated = False def exec_(self): if ExtendableDialog.exec_(self): if self.password_ok: return True else: QtWidgets.QMessageBox.warning( self.parent(), _("Login Error"), '<h2>%s %s</h2><em>%s</em>' % ( _('Incorrect'), _("User/password combination!"), _('Please Try Again.') ) ) return self.exec_() return False
class NewDentureDialog(ExtendableDialog): def __init__(self, om_gui=None): ExtendableDialog.__init__(self, om_gui) self.om_gui = om_gui message = _("Add A New Denture To The Treatment Plan") self.setWindowTitle(message) self.header_label = WarningLabel(message) self.ndu_le = UpperCaseLineEdit() self.ndl_le = UpperCaseLineEdit() self.set_default_lineedit(self.ndl_le) self.wizard_widget = QtWidgets.QStackedWidget() page0 = PageZero(self) page0.finished_signal.connect(self.next_widget) page1 = PageOne(self) page2 = PageTwo(self) page3 = PageThree(self) page4 = PageFour(self) accept_page = AcceptPage(self) self.wizard_widget.addWidget(page0) self.wizard_widget.addWidget(page1) self.wizard_widget.addWidget(page2) self.wizard_widget.addWidget(page3) self.wizard_widget.addWidget(page4) self.wizard_widget.addWidget(accept_page) self.insertWidget(self.header_label) self.insertWidget(self.wizard_widget) frame = QtWidgets.QFrame() layout = QtWidgets.QFormLayout(frame) layout.addRow(_("Upper Denture"), self.ndu_le) layout.addRow(_("Lower Denture"), self.ndl_le) self.add_advanced_widget(frame) self.next_but = self.button_box.addButton(_("Next"), self.button_box.ActionRole) self.apply_but.hide() self.ndu_le.textChanged.connect(self.enable_apply) self.ndl_le.textChanged.connect(self.enable_apply) self.ndu_le.editingFinished.connect(self.advanced_apply) self.ndl_le.editingFinished.connect(self.advanced_apply) @property def current_index(self): return self.wizard_widget.currentIndex() @property def current_page(self): return self.wizard_widget.widget(self.current_index) def next_widget(self): if not self.current_page.is_completed: QtWidgets.QMessageBox.information(self, _("Whoops"), self.current_page.error_message) return if self.current_index == 0: self.set_default_lineedit(self.current_page.chosen_arch) le = self.default_lineedit le.setText(le.text() + self.current_page.return_text) self.current_page.cleanup() if self.current_index == 4: if "F/F" in self.upper_input: le = self.ndl_le le.setText(le.text() + self.current_page.return_text) index_ = self.current_index + self.current_page.next_index if index_ >= self.wizard_widget.count() - 1: self.apply_but.show() self.next_but.hide() self.wizard_widget.setCurrentIndex(index_) @property def is_upper_input(self): return self.default_lineedit == self.ndu_le @property def default_lineedit(self): return self._default_lineedit def set_default_lineedit(self, value="upper"): if value == "upper": self._default_lineedit = self.ndu_le else: self._default_lineedit = self.ndl_le def _clicked(self, but): """ "private" function called when button box is clicked """ role = self.button_box.buttonRole(but) if role == self.button_box.ActionRole: self.next_widget() else: ExtendableDialog._clicked(self, but) @property def check_valid_input(self): ndus, ndls = self.upper_input, self.lower_input for ndu in ndus.split(" "): matched = False for input_ in VALID_INPUTS: if re.match(input_, ndu): matched = True if not matched: QtWidgets.QMessageBox.warning(self, _("Warning"), _("Your upper denture input is invalid")) return False for ndl in ndls.split(" "): LOGGER.debug("checking '%s'" % ndl) matched = False for input_ in VALID_INPUTS: if re.match(input_, ndl): matched = True if not matched: QtWidgets.QMessageBox.warning(self, ("Warning"), _("Your lower denture input is invalid")) return False return True def enable_apply(self, *args): self.enableApply(self.upper_input != "" or self.lower_input != "") def advanced_apply(self, *args): self.apply_but.show() self.enableApply(self.upper_input != "" or self.lower_input != "") @property def upper_input(self): return str(self.ndu_le.text()).strip(" ") @property def lower_input(self): return str(self.ndl_le.text()).strip(" ") @property def chosen_treatments(self): for input_ in self.upper_input.split(" "): if input_ != "": yield ("ndu", input_) for input_ in self.lower_input.split(" "): if input_ != "": yield ("ndl", input_) def exec_(self): result = ExtendableDialog.exec_(self) if result: result = self.check_valid_input or self.exec_() return result
class AlterDentureDialog(ExtendableDialog): def __init__(self, om_gui=None): ExtendableDialog.__init__(self, om_gui) self.om_gui = om_gui message = (_("Alterations to an existing Denture")) self.setWindowTitle(message) self.header_label = QtGui.QLabel(message) self.header_label.setAlignment(QtCore.Qt.AlignCenter) self.odu_le = UpperCaseLineEdit() self.odl_le = UpperCaseLineEdit() self.set_default_lineedit(self.odl_le) self.wizard_widget = QtGui.QStackedWidget() page0 = PageZero(self) page1 = PageOne(self) page2 = PageTwo(self) page3 = PageThree(self) page4 = PageFour(self) page5 = PageFive(self) accept_page = AcceptPage(self) self.wizard_widget.addWidget(page0) self.wizard_widget.addWidget(page1) self.wizard_widget.addWidget(page2) self.wizard_widget.addWidget(page3) self.wizard_widget.addWidget(page4) self.wizard_widget.addWidget(page5) self.wizard_widget.addWidget(accept_page) self.insertWidget(self.header_label) self.insertWidget(self.wizard_widget) frame = QtGui.QFrame() layout = QtGui.QFormLayout(frame) layout.addRow(_("Upper Denture"), self.odu_le) layout.addRow(_("Lower Denture"), self.odl_le) self.add_advanced_widget(frame) self.next_but = self.button_box.addButton(_("Next"), self.button_box.ActionRole) self.apply_but.hide() self.odu_le.textChanged.connect(self.enable_apply) self.odl_le.textChanged.connect(self.enable_apply) self.odu_le.editingFinished.connect(self.advanced_apply) self.odl_le.editingFinished.connect(self.advanced_apply) @property def current_index(self): return self.wizard_widget.currentIndex() @property def current_page(self): return self.wizard_widget.widget(self.current_index) def next_widget(self): if not self.current_page.is_completed: QtGui.QMessageBox.information(self, _("Whoops"), self.current_page.error_message) return if self.current_index == 0: self.set_default_lineedit(self.current_page.chosen_arch) le = self.default_lineedit le.setText(le.text() + self.current_page.return_text) self.current_page.cleanup() index_ = self.current_index + self.current_page.next_index if index_ >= self.wizard_widget.count() - 1: index = self.wizard_widget.count() self.apply_but.show() self.next_but.hide() self.wizard_widget.setCurrentIndex(index_) @property def is_upper_input(self): return self.default_lineedit == self.odu_le @property def default_lineedit(self): return self._default_lineedit def set_default_lineedit(self, value="upper"): if value == "upper": self._default_lineedit = self.odu_le else: self._default_lineedit = self.odl_le def _clicked(self, but): ''' "private" function called when button box is clicked ''' role = self.button_box.buttonRole(but) if role == self.button_box.ActionRole: self.next_widget() else: ExtendableDialog._clicked(self, but) @property def check_valid_input(self): odus, odls = self.upper_input, self.lower_input for odu in odus.split(" "): matched = False for input_ in VALID_INPUTS: if re.match(input_, odu): matched = True break if not matched: LOGGER.debug("failed to match %s %s" % (input_, odu)) QtGui.QMessageBox.warning( self, _("Warning"), _("Your upper denture input is invalid")) return False for odl in odls.split(" "): matched = False for input_ in VALID_INPUTS: if re.match(input_, odl): matched = True break if not matched: LOGGER.debug("failed to match %s %s" % (input_, odu)) QtGui.QMessageBox.warning( self, _("Warning"), _("Your lower denture input is invalid")) return False return True def enable_apply(self, *args): self.enableApply(self.upper_input != "" or self.lower_input != "") def advanced_apply(self, *args): self.apply_but.show() self.enableApply(self.upper_input != "" or self.lower_input != "") @property def upper_input(self): return str(self.odu_le.text().toAscii()).strip(" ") @property def lower_input(self): return str(self.odl_le.text().toAscii()).strip(" ") @property def chosen_treatments(self): for input_ in self.upper_input.split(" "): if input_ != "": yield ("odu", input_) for input_ in self.lower_input.split(" "): if input_ != "": yield ("odl", input_) def exec_(self): result = ExtendableDialog.exec_(self) if result: result = self.check_valid_input or self.exec_() return result
class FeescaleTestingDialog(Ui_codeChecker.Ui_Dialog, QtGui.QDialog): def __init__(self, parent=None): QtGui.QDialog.__init__(self, parent) self.setupUi(self) self.table_list = [] tablenames = [] self.load_feescales() self.model2 = DeciduousAttributeModel(self.current_table) self.model3 = AdultAttributeModel(self.current_table) self.dec_tableView.setModel(self.model2) self.adult_tableView.setModel(self.model3) self.dec_tableView.horizontalHeader().setStretchLastSection(True) self.adult_tableView.horizontalHeader().setStretchLastSection(True) self.setWindowTitle(_("Shortcut tester")) self.connect(self.comboBox, QtCore.SIGNAL("currentIndexChanged (int)"), self.change_table) self.pushButton.clicked.connect(self.check_codes) self.quit_pushButton.clicked.connect(self.accept) self.line_edits = {} form_layout = QtGui.QFormLayout(self.frame) for att in CURRTRT_NON_TOOTH_ATTS: widg = QtGui.QLineEdit() self.line_edits[att] = widg form_layout.addRow(att, widg) self.lineEdit = UpperCaseLineEdit() self.bottom_layout.insertWidget(1, self.lineEdit) self.lineEdit.setText("P") self.check_codes() def load_feescales(self): self.table_list = [] self.tablenames = [] for table in localsettings.FEETABLES.tables.values(): self.table_list.append(table) self.tablenames.append(table.briefName) self.comboBox.clear() self.comboBox.addItems(self.tablenames) def check_codes(self): tx = str(self.lineEdit.text().toAscii()).upper() complex_matches = [] for att in CURRTRT_NON_TOOTH_ATTS: for complex_shortcut in self.current_table.complex_shortcuts: if complex_shortcut.matches(att, tx): complex_matches.append(att) usercode = "%s %s" % (att, tx) code = self.current_table.getItemCodeFromUserCode(usercode) if code == "-----": self.line_edits[att].setText("") else: description = self.current_table.getItemDescription( code, usercode) self.line_edits[att].setText("%s %s" % (code, description)) for model in (self.model2, self.model3): model.code = tx model.reset() for att in DECIDMOUTH + ADULTMOUTH: for complex_shortcut in self.current_table.complex_shortcuts: if complex_shortcut.matches(att, tx): complex_matches.append(att) if complex_matches != []: QtGui.QMessageBox.information( self, _("Information"), "%s '%s' %s<hr />%s" % (_("This feescale handles"), tx, _("as a complex code for the following attributes."), complex_matches)) @property def current_table(self): return self.table_list[self.comboBox.currentIndex()] def change_table(self, i): self.model2.table = self.current_table self.model3.table = self.current_table self.check_codes()
class ChildSmileDialog(BaseDialog): result = "" is_checking_website = False def __init__(self, parent): BaseDialog.__init__(self, parent) self.main_ui = parent self.header_label = QtGui.QLabel() self.header_label.setAlignment(QtCore.Qt.AlignCenter) self.pcde_le = UpperCaseLineEdit() self.pcde_le.setText(self.main_ui.pt.pcde) self.simd_label = QtGui.QLabel() self.header_label.setAlignment(QtCore.Qt.AlignCenter) self.tbi_checkbox = QtGui.QCheckBox( _("ToothBrushing Instruction Given")) self.tbi_checkbox.setChecked(True) self.di_checkbox = QtGui.QCheckBox(_("Dietary Advice Given")) self.di_checkbox.setChecked(True) self.fl_checkbox = QtGui.QCheckBox(_("Fluoride Varnish Applied")) self.fl_checkbox.setToolTip( _("Fee claimable for patients betwen 2 and 5")) self.fl_checkbox.setChecked(2 <= self.main_ui.pt.ageYears <=5) self.insertWidget(self.header_label) self.insertWidget(self.pcde_le) self.insertWidget(self.simd_label) self.insertWidget(self.tbi_checkbox) self.insertWidget(self.di_checkbox) self.insertWidget(self.fl_checkbox) self.pcde_le.textEdited.connect(self.check_pcde) @property def pcde(self): try: return str(self.pcde_le.text()) except: return "" @property def valid_postcode(self): return bool(re.match("[A-Z][A-Z](\d+) (\d+)[A-Z][A-Z]", self.pcde)) def postcode_warning(self): if not self.valid_postcode: QtGui.QMessageBox.warning(self, "error", "Postcode is not valid") def check_pcde(self): if self.valid_postcode: QtCore.QTimer.singleShot(50, self.simd_lookup) else: self.header_label.setText(_("Please enter a valid postcode")) self.simd_label.setText("") self.enableApply(False) def check_hung(self): ''' this is called by a timout of the web polling ''' if self.is_checking_website: QtGui.QApplication.instance().restoreOverrideCursor() QtGui.QMessageBox.warning(self, "error", "unable to poll NHS website") self.reject() return def simd_lookup(self): ''' poll the server for a simd for a postcode ''' global TODAYS_LOOKUPS try: self.result = TODAYS_LOOKUPS[self.pcde] self.simd_label.setText(self.result) self.enableApply(True) LOGGER.debug("simd_lookup unnecessary, value known") return except KeyError: pass try: self.is_checking_website = True QtCore.QTimer.singleShot(15000, self.check_hung) self.header_label.setText(_("Polling website with Postcode")) QtGui.QApplication.instance().setOverrideCursor( QtCore.Qt.WaitCursor) pcde = self.pcde.replace(" ", "%20") url = "%s?pCode=%s" %(LOOKUP_URL, pcde) req = urllib2.Request(url) response = urllib2.urlopen(req) result = response.read() self.result = self._parse_result(result) TODAYS_LOOKUPS[self.pcde] = self.result self.simd_label.setText(self.result) self.enableApply(True) self.is_checking_website = False QtGui.QApplication.instance().restoreOverrideCursor() except Exception as exc: LOGGER.exception("error polling NHS website?") QtGui.QApplication.instance().restoreOverrideCursor() QtGui.QMessageBox.warning(self, "error", "unable to poll NHS website") self.reject() def _parse_result(self, result): dom = minidom.parseString(result) e=dom.getElementsByTagName("span")[0] return e.firstChild.data @property def simd_number(self): return int(re.search("(\d+)", self.result).groups()[0]) @property def tbi_performed(self): return self.tbi_checkbox.isChecked() @property def di_performed(self): return self.di_checkbox.isChecked() @property def fl_applied(self): return self.fl_checkbox.isChecked() @property def tx_items(self): age = self.main_ui.pt.ageYears dentist = localsettings.clinicianNo in localsettings.dentDict.keys() LOGGER.debug("Performed by dentist = %s"% dentist) if age < 3: if self.simd_number < 4: yield ("other", "CS1") else: yield ("other", "CS2") if self.tbi_performed: code = "TB1" if dentist else "TB2" yield ("other", code) if self.di_performed: code = "DI1" if dentist else "DI2" yield ("other", code) else: if self.simd_number < 4: yield ("other", "CS3") if self.tbi_performed: code = "TB3" if dentist else "TB4" yield ("other", code) if self.di_performed: code = "DI3" if dentist else "DI4" yield ("other", code) if 2 <= age <= 5: if self.fl_applied: yield ("other", "CSFL") def exec_(self): self.check_pcde() QtCore.QTimer.singleShot(100, self.postcode_warning) if BaseDialog.exec_(self): if self.valid_postcode: self.main_ui.pt.pcde = self.pcde self.main_ui.addNewNote("CHILDSMILE (postcode '%s'): %s"% (self.pcde, self.result)) return True