def __database_is_acceptable_for_use(require_version: bool = True, expected_version: int = None, login=None) -> bool: if not gmPG2.schema_exists(schema='gm'): _log.error('schema [gm] does not exist - database not bootstrapped ?') gmGuiHelpers.gm_show_error(msg_not_bootstrapped, _('Verifying database')) return False if not gmPG2.database_schema_compatible(version=expected_version): client_version = _cfg.get(option='client_version') connected_db_version = gmPG2.get_schema_version() msg = msg_generic % (client_version, connected_db_version, expected_version, gmTools.coalesce(login.host, '<localhost>'), login.database, login.user) if require_version: gmGuiHelpers.gm_show_error(msg + '\n\n' + msg_fail, _('Verifying database version')) return False gmGuiHelpers.gm_show_info(msg + '\n\n' + msg_override, _('Verifying database version')) max_skew = 10 if _cfg.get(option='debug') else 1 # in minutes if not gmPG2.sanity_check_time_skew(tolerance=(max_skew * 60)): if not _cfg.get(option='debug'): gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings')) return False gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings')) sanity_level, message = gmPG2.sanity_check_database_settings() if sanity_level != 0: gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings')) if sanity_level == 2: return False gmLog2.log_multiline(logging.DEBUG, message='DB seems suitable to use, fingerprint:', text=gmPG2.get_db_fingerprint(eol='\n')) return True
def install_data_pack(data_pack=None): if data_pack is None: return False _log.info('attempting installation of data pack: %s', data_pack['name']) msg = _( 'Note that GNUmed data packs are provided\n' '\n' 'WITHOUT ANY GUARANTEE WHATSOEVER\n' '\n' 'regarding their content.\n' '\n' 'Despite data packs having been prepared with the\n' 'utmost care you must still vigilantly apply caution,\n' 'common sense, and due diligence to make sure you\n' 'render appropriate care to your patients.\n' '\n' 'Press [Yes] to declare agreement with this precaution.\n' '\n' 'Press [No] to abort installation of the data pack.\n' ) go_ahead = gmGuiHelpers.gm_show_question(msg, _('Terms of Data Pack Use')) if not go_ahead: _log.info('user did not agree to terms of data pack use') return True gm_dbo_conn = gmAuthWidgets.get_dbowner_connection(procedure = _('installing data pack')) if gm_dbo_conn is None: msg = _('Lacking permissions to install data pack.') gmGuiHelpers.gm_show_error(msg, _('Installing data pack')) return False wx.BeginBusyCursor() verified, data = gmNetworkTools.download_data_pack ( data_pack['pack_url'], md5_url = data_pack['md5_url'] ) wx.EndBusyCursor() if not verified: _log.error('cannot download and verify data pack: %s', data_pack['name']) md5_expected, md5_calculated = data msg = _( 'Cannot validate data pack.\n' '\n' ' name: %s\n' ' URL: %s\n' '\n' ' MD5\n' ' calculated: %s\n' ' expected: %s\n' ' source: %s\n' '\n' 'You may want to try downloading again or you\n' 'may need to contact your administrator.' ) % ( data_pack['name'], data_pack['pack_url'], md5_calculated, md5_expected, data_pack['md5_url'] ) gmGuiHelpers.gm_show_error(msg, _('Verifying data pack')) return False data_pack['local_archive'] = data wx.BeginBusyCursor() unzip_dir = gmNetworkTools.unzip_data_pack(filename = data) wx.EndBusyCursor() if unzip_dir is None: msg = _( 'Cannot unpack data pack.\n' '\n' ' name: %s\n' ' URL: %s\n' ' local: %s\n' '\n' 'You may want to try downloading again or you\n' 'may need to contact your administrator.' ) % ( data_pack['name'], data_pack['pack_url'], data_pack['local_archive'] ) gmGuiHelpers.gm_show_error(msg, _('Unpacking data pack')) return False data_pack['unzip_dir'] = unzip_dir wx.BeginBusyCursor() try: installed = gmNetworkTools.install_data_pack(data_pack, gm_dbo_conn) finally: wx.EndBusyCursor() # check schema hash db_version = gmPG2.map_client_branch2required_db_version[_cfg.get(option = 'client_branch')] if not gmPG2.database_schema_compatible(version = db_version): if db_version != 0: msg = _( 'Installation of data pack failed because\n' 'it attempted to modify the database layout.\n' '\n' ' name: %s\n' ' URL: %s\n' ' local: %s\n' '\n' 'You will need to contact your administrator.' ) % ( data_pack['name'], data_pack['pack_url'], data_pack['local_archive'] ) gmGuiHelpers.gm_show_error(msg, _('Installing data pack')) return False if not installed: msg = _( 'Installation of data pack failed.\n' '\n' ' name: %s\n' ' URL: %s\n' ' local: %s\n' '\n' 'You may want to try downloading again or you\n' 'may need to contact your administrator.' ) % ( data_pack['name'], data_pack['pack_url'], data_pack['local_archive'] ) gmGuiHelpers.gm_show_error(msg, _('Installing data pack')) return False msg = _( 'Successfully installed data pack.\n' '\n' ' name: %s\n' ' URL: %s\n' ) % ( data_pack['name'], data_pack['pack_url'] ) gmGuiHelpers.gm_show_info(msg, _('Installing data pack')) return True
def connect_to_database(max_attempts=3, expected_version=None, require_version=True): """Display the login dialog and try to log into the backend. - up to max_attempts times - returns True/False """ # force programmer to set a valid expected_version expected_hash = gmPG2.known_schema_hashes[expected_version] client_version = _cfg.get(option='client_version') global current_db_name current_db_name = 'gnumed_v%s' % expected_version attempt = 0 dlg = cLoginDialog(None, -1, client_version=client_version) dlg.Centre(wx.BOTH) while attempt < max_attempts: _log.debug('login attempt %s of %s', (attempt + 1), max_attempts) connected = False dlg.ShowModal() login = dlg.panel.GetLoginInfo() if login is None: _log.info("user cancelled login dialog") break gmLog2.add_word2hide(login.password) # try getting a connection to verify the DSN works dsn = gmPG2.make_psycopg2_dsn(database=login.database, host=login.host, port=login.port, user=login.user, password=login.password) try: conn = gmPG2.get_raw_connection(dsn=dsn, verbose=True, readonly=True) connected = True except gmPG2.cAuthenticationError as e: attempt += 1 _log.error("login attempt failed: %s", e) if attempt < max_attempts: if ('host=127.0.0.1' in ('%s' % e)) or ('host=' not in ('%s' % e)): msg = _( 'Unable to connect to database:\n\n' '%s\n\n' "Are you sure you have got a local database installed ?\n" '\n' "Please retry with proper credentials or cancel.\n" '\n' ' (for the public and any new GNUmed data-\n' ' bases the default user name and password\n' ' are {any-doc, any-doc})\n' '\n' 'You may also need to check the PostgreSQL client\n' 'authentication configuration in pg_hba.conf. For\n' 'details see:\n' '\n' 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL') else: msg = _( "Unable to connect to database:\n\n" "%s\n\n" "Please retry with proper credentials or cancel.\n" "\n" "For the public and any new GNUmed databases the\n" "default user name and password are {any-doc, any-doc}.\n" "\n" 'You may also need to check the PostgreSQL client\n' 'authentication configuration in pg_hba.conf. For\n' 'details see:\n' '\n' 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL') msg = msg % e msg = regex.sub( r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error(msg, _('Connecting to backend')) del e continue except gmPG2.dbapi.OperationalError as exc: _log.exception('login attempt failed') gmPG2.log_pg_exception_details(exc) msg = _( "Unable to connect to database:\n\n" "%s\n\n" "Please retry another backend / user / password combination !\n" "\n" " (for the public and any new GNUmed databases\n" " the default user name and password are\n" " {any-doc, any-doc})\n" "\n") % exc msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error(msg, _('Connecting to backend')) del exc continue conn.close() # connect was successful gmPG2.set_default_login(login=login) gmPG2.set_default_client_encoding( encoding=dlg.panel.backend_profile.encoding) seems_bootstrapped = gmPG2.schema_exists(schema='gm') if not seems_bootstrapped: _log.error( 'schema [gm] does not exist - database not bootstrapped ?') msg = _('The database you connected to does not seem\n' 'to have been boostrapped properly.\n' '\n' 'Make sure you have run the GNUmed database\n' 'bootstrapper tool to create a new database.\n' '\n' 'Further help can be found on the website at\n' '\n' ' http://wiki.gnumed.de\n' '\n' 'or on the GNUmed mailing list.') gmGuiHelpers.gm_show_error(msg, _('Verifying database')) connected = False break compatible = gmPG2.database_schema_compatible(version=expected_version) if compatible or not require_version: dlg.panel.save_state() if not compatible: connected_db_version = gmPG2.get_schema_version() msg = msg_generic % (client_version, connected_db_version, expected_version, gmTools.coalesce(login.host, '<localhost>'), login.database, login.user) if require_version: gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version')) connected = False continue gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version')) # FIXME: make configurable max_skew = 1 # minutes if _cfg.get(option='debug'): max_skew = 10 if not gmPG2.sanity_check_time_skew(tolerance=(max_skew * 60)): if _cfg.get(option='debug'): gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings')) else: gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings')) connected = False continue sanity_level, message = gmPG2.sanity_check_database_settings() if sanity_level != 0: gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings')) if sanity_level == 2: connected = False continue gmExceptionHandlingWidgets.set_is_public_database(login.public_db) gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk) conn = gmPG2.get_connection( verbose=True, connection_name='GNUmed-[DbListenerThread]', pooled=False) listener = gmBackendListener.gmBackendListener(conn=conn) break dlg.DestroyLater() return connected
"to have been boostrapped properly.\n" "\n" "Make sure you have run the GNUmed database\n" "bootstrapper tool to create a new database.\n" "\n" "Further help can be found on the website at\n" "\n" " http://wiki.gnumed.de\n" "\n" "or on the GNUmed mailing list." ) gmGuiHelpers.gm_show_error(msg, _("Verifying database")) connected = False break compatible = gmPG2.database_schema_compatible(version=expected_version) if compatible or not require_version: dlg.panel.save_state() if not compatible: connected_db_version = gmPG2.get_schema_version() msg = msg_generic % ( client_version, connected_db_version, expected_version, gmTools.coalesce(login.host, "<localhost>"), login.database, login.user, ) if require_version: gmGuiHelpers.gm_show_error(msg + msg_fail, _("Verifying database version"))
def install_data_pack(data_pack=None): if data_pack is None: return False _log.info('attempting installation of data pack: %s', data_pack['name']) msg = _('Note that GNUmed data packs are provided\n' '\n' 'WITHOUT ANY GUARANTEE WHATSOEVER\n' '\n' 'regarding their content.\n' '\n' 'Despite data packs having been prepared with the\n' 'utmost care you must still vigilantly apply caution,\n' 'common sense, and due diligence to make sure you\n' 'render appropriate care to your patients.\n' '\n' 'Press [Yes] to declare agreement with this precaution.\n' '\n' 'Press [No] to abort installation of the data pack.\n') go_ahead = gmGuiHelpers.gm_show_question(msg, _('Terms of Data Pack Use')) if not go_ahead: _log.info('user did not agree to terms of data pack use') return True gm_dbo_conn = gmAuthWidgets.get_dbowner_connection( procedure=_('installing data pack')) if gm_dbo_conn is None: msg = _('Lacking permissions to install data pack.') gmGuiHelpers.gm_show_error(msg, _('Installing data pack')) return False wx.BeginBusyCursor() verified, data = gmNetworkTools.download_data_pack( data_pack['pack_url'], md5_url=data_pack['md5_url']) wx.EndBusyCursor() if not verified: _log.error('cannot download and verify data pack: %s', data_pack['name']) md5_expected, md5_calculated = data msg = _('Cannot validate data pack.\n' '\n' ' name: %s\n' ' URL: %s\n' '\n' ' MD5\n' ' calculated: %s\n' ' expected: %s\n' ' source: %s\n' '\n' 'You may want to try downloading again or you\n' 'may need to contact your administrator.') % ( data_pack['name'], data_pack['pack_url'], md5_calculated, md5_expected, data_pack['md5_url']) gmGuiHelpers.gm_show_error(msg, _('Verifying data pack')) return False data_pack['local_archive'] = data wx.BeginBusyCursor() unzip_dir = gmNetworkTools.unzip_data_pack(filename=data) wx.EndBusyCursor() if unzip_dir is None: msg = _('Cannot unpack data pack.\n' '\n' ' name: %s\n' ' URL: %s\n' ' local: %s\n' '\n' 'You may want to try downloading again or you\n' 'may need to contact your administrator.') % ( data_pack['name'], data_pack['pack_url'], data_pack['local_archive']) gmGuiHelpers.gm_show_error(msg, _('Unpacking data pack')) return False data_pack['unzip_dir'] = unzip_dir wx.BeginBusyCursor() try: installed = gmNetworkTools.install_data_pack(data_pack, gm_dbo_conn) finally: wx.EndBusyCursor() # check schema hash db_version = gmPG2.map_client_branch2required_db_version[_cfg.get( option='client_branch')] if not gmPG2.database_schema_compatible(version=db_version): if db_version != 0: msg = _('Installation of data pack failed because\n' 'it attempted to modify the database layout.\n' '\n' ' name: %s\n' ' URL: %s\n' ' local: %s\n' '\n' 'You will need to contact your administrator.') % ( data_pack['name'], data_pack['pack_url'], data_pack['local_archive']) gmGuiHelpers.gm_show_error(msg, _('Installing data pack')) return False if not installed: msg = _('Installation of data pack failed.\n' '\n' ' name: %s\n' ' URL: %s\n' ' local: %s\n' '\n' 'You may want to try downloading again or you\n' 'may need to contact your administrator.') % ( data_pack['name'], data_pack['pack_url'], data_pack['local_archive']) gmGuiHelpers.gm_show_error(msg, _('Installing data pack')) return False msg = _('Successfully installed data pack.\n' '\n' ' name: %s\n' ' URL: %s\n') % (data_pack['name'], data_pack['pack_url']) gmGuiHelpers.gm_show_info(msg, _('Installing data pack')) return True
def connect_to_database(max_attempts=3, expected_version=None, require_version=True): """Display the login dialog and try to log into the backend. - up to max_attempts times - returns True/False """ # force programmer to set a valid expected_version expected_hash = gmPG2.known_schema_hashes[expected_version] client_version = _cfg.get(option = 'client_version') global current_db_name current_db_name = 'gnumed_v%s' % expected_version attempt = 0 dlg = cLoginDialog(None, -1, client_version = client_version) dlg.Centre(wx.BOTH) while attempt < max_attempts: _log.debug('login attempt %s of %s', (attempt+1), max_attempts) connected = False dlg.ShowModal() login = dlg.panel.GetLoginInfo() if login is None: _log.info("user cancelled login dialog") break gmLog2.add_word2hide(login.password) # try getting a connection to verify the DSN works dsn = gmPG2.make_psycopg2_dsn ( database = login.database, host = login.host, port = login.port, user = login.user, password = login.password ) try: conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True) connected = True except gmPG2.cAuthenticationError as e: attempt += 1 _log.error("login attempt failed: %s", e) if attempt < max_attempts: if ('host=127.0.0.1' in ('%s' % e)) or ('host=' not in ('%s' % e)): msg = _( 'Unable to connect to database:\n\n' '%s\n\n' "Are you sure you have got a local database installed ?\n" '\n' "Please retry with proper credentials or cancel.\n" '\n' ' (for the public and any new GNUmed data-\n' ' bases the default user name and password\n' ' are {any-doc, any-doc})\n' '\n' 'You may also need to check the PostgreSQL client\n' 'authentication configuration in pg_hba.conf. For\n' 'details see:\n' '\n' 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL' ) else: msg = _( "Unable to connect to database:\n\n" "%s\n\n" "Please retry with proper credentials or cancel.\n" "\n" "For the public and any new GNUmed databases the\n" "default user name and password are {any-doc, any-doc}.\n" "\n" 'You may also need to check the PostgreSQL client\n' 'authentication configuration in pg_hba.conf. For\n' 'details see:\n' '\n' 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL' ) msg = msg % e msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error ( msg, _('Connecting to backend') ) del e continue except gmPG2.dbapi.OperationalError as exc: _log.exception('login attempt failed') gmPG2.log_pg_exception_details(exc) msg = _( "Unable to connect to database:\n\n" "%s\n\n" "Please retry another backend / user / password combination !\n" "\n" " (for the public and any new GNUmed databases\n" " the default user name and password are\n" " {any-doc, any-doc})\n" "\n" ) % exc msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg) gmGuiHelpers.gm_show_error(msg, _('Connecting to backend')) del exc continue conn.close() # connect was successful gmPG2.set_default_login(login = login) gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding) seems_bootstrapped = gmPG2.schema_exists(schema = 'gm') if not seems_bootstrapped: _log.error('schema [gm] does not exist - database not bootstrapped ?') msg = _( 'The database you connected to does not seem\n' 'to have been boostrapped properly.\n' '\n' 'Make sure you have run the GNUmed database\n' 'bootstrapper tool to create a new database.\n' '\n' 'Further help can be found on the website at\n' '\n' ' http://wiki.gnumed.de\n' '\n' 'or on the GNUmed mailing list.' ) gmGuiHelpers.gm_show_error(msg, _('Verifying database')) connected = False break compatible = gmPG2.database_schema_compatible(version = expected_version) if compatible or not require_version: dlg.panel.save_state() if not compatible: connected_db_version = gmPG2.get_schema_version() msg = msg_generic % ( client_version, connected_db_version, expected_version, gmTools.coalesce(login.host, '<localhost>'), login.database, login.user ) if require_version: gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version')) connected = False continue gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version')) # FIXME: make configurable max_skew = 1 # minutes if _cfg.get(option = 'debug'): max_skew = 10 if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)): if _cfg.get(option = 'debug'): gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings')) else: gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings')) connected = False continue sanity_level, message = gmPG2.sanity_check_database_settings() if sanity_level != 0: gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings')) if sanity_level == 2: connected = False continue gmExceptionHandlingWidgets.set_is_public_database(login.public_db) gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk) conn = gmPG2.get_connection(verbose = True, connection_name = 'GNUmed-[DbListenerThread]', pooled = False) listener = gmBackendListener.gmBackendListener(conn = conn) break dlg.DestroyLater() return connected