Package Gnumed :: Package wxpython :: Module gmAuthWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmAuthWidgets

  1  """GNUmed authentication widgets. 
  2   
  3  This module contains widgets and GUI 
  4  functions for authenticating users. 
  5  """ 
  6  #================================================================ 
  7  __version__ = "$Revision: 1.45 $" 
  8  __author__ = "karsten.hilbert@gmx.net, H.Herb, H.Berger, R.Terry" 
  9  __license__ = "GPL v2 or later (details at http://www.gnu.org)" 
 10   
 11   
 12  # stdlib 
 13  import sys, os.path, logging, re as regex 
 14   
 15   
 16  # 3rd party 
 17  import wx 
 18   
 19   
 20  # GNUmed 
 21  if __name__ == '__main__': 
 22          sys.path.insert(0, '../../') 
 23  from Gnumed.pycommon import gmLoginInfo, gmPG2, gmBackendListener, gmTools, gmCfg2, gmI18N 
 24  from Gnumed.business import gmSurgery 
 25  from Gnumed.wxpython import gmGuiHelpers, gmExceptionHandlingWidgets 
 26   
 27   
 28  _log = logging.getLogger('gm.ui') 
 29  _log.info(__version__) 
 30  _cfg = gmCfg2.gmCfgData() 
 31   
 32  try: 
 33          _('dummy-no-need-to-translate-but-make-epydoc-happy') 
 34  except NameError: 
 35          _ = lambda x:x 
 36   
 37   
 38  msg_generic = _(""" 
 39  GNUmed database version mismatch. 
 40   
 41  This database version cannot be used with this client: 
 42   
 43   client version: %s 
 44   database version detected: %s 
 45   database version needed: %s 
 46   
 47  Currently connected to database: 
 48   
 49   host: %s 
 50   database: %s 
 51   user: %s 
 52  """) 
 53   
 54  msg_time_skew_fail = _("""\ 
 55  The server and client clocks are off 
 56  by more than %s minutes ! 
 57   
 58  You must fix the time settings before 
 59  you can use this database with this 
 60  client. 
 61   
 62  You may have to contact your 
 63  administrator for help.""") 
 64   
 65  msg_time_skew_warn = _("""\ 
 66  The server and client clocks are off 
 67  by more than %s minutes ! 
 68   
 69  You should fix the time settings. 
 70  Otherwise clinical data may appear to 
 71  have been entered at the wrong time. 
 72   
 73  You may have to contact your 
 74  administrator for help.""") 
 75   
 76  msg_insanity = _(""" 
 77  There is a serious problem with the database settings: 
 78   
 79  %s 
 80   
 81  You may have to contact your administrator for help.""") 
 82   
 83  msg_fail = _(""" 
 84  You must connect to a different database in order 
 85  to use the GNUmed client. You may have to contact 
 86  your administrator for help.""") 
 87   
 88  msg_override = _(""" 
 89  The client will, however, continue to start up because 
 90  you are running a development/test version of GNUmed. 
 91   
 92  There may be schema related errors. Please report and/or 
 93  fix them. Do not rely on this database to work properly 
 94  in all cases !""") 
 95   
 96  #================================================================ 
 97  # convenience functions 
 98  #---------------------------------------------------------------- 
99 -def connect_to_database(max_attempts=3, expected_version=None, require_version=True):
100 """Display the login dialog and try to log into the backend. 101 102 - up to max_attempts times 103 - returns True/False 104 """ 105 # force programmer to set a valid expected_version 106 expected_hash = gmPG2.known_schema_hashes[expected_version] 107 client_version = _cfg.get(option = u'client_version') 108 global current_db_name 109 current_db_name = u'gnumed_v%s' % expected_version 110 111 attempt = 0 112 113 dlg = cLoginDialog(None, -1, client_version = client_version) 114 dlg.Centre(wx.BOTH) 115 116 while attempt < max_attempts: 117 118 _log.debug('login attempt %s of %s', (attempt+1), max_attempts) 119 120 connected = False 121 122 dlg.ShowModal() 123 login = dlg.panel.GetLoginInfo() 124 if login is None: 125 _log.info("user cancelled login dialog") 126 break 127 128 # try getting a connection to verify the DSN works 129 dsn = gmPG2.make_psycopg2_dsn ( 130 database = login.database, 131 host = login.host, 132 port = login.port, 133 user = login.user, 134 password = login.password 135 ) 136 try: 137 conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True) 138 connected = True 139 140 except gmPG2.cAuthenticationError, e: 141 attempt += 1 142 _log.error(u"login attempt failed: %s", e) 143 if attempt < max_attempts: 144 if (u'host=127.0.0.1' in (u'%s' % e)) or (u'host=' not in (u'%s' % e)): 145 msg = _( 146 'Unable to connect to database:\n\n' 147 '%s\n\n' 148 "Are you sure you have got a local database installed ?\n" 149 '\n' 150 "Please retry with proper credentials or cancel.\n" 151 '\n' 152 'You may also need to check the PostgreSQL client\n' 153 'authentication configuration in pg_hba.conf. For\n' 154 'details see:\n' 155 '\n' 156 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL' 157 ) 158 else: 159 msg = _( 160 "Unable to connect to database:\n\n" 161 "%s\n\n" 162 "Please retry with proper credentials or cancel.\n" 163 "\n" 164 'You may also need to check the PostgreSQL client\n' 165 'authentication configuration in pg_hba.conf. For\n' 166 'details see:\n' 167 '\n' 168 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL' 169 ) 170 msg = msg % e 171 msg = regex.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg) 172 gmGuiHelpers.gm_show_error ( 173 msg, 174 _('Connecting to backend') 175 ) 176 del e 177 continue 178 179 except gmPG2.dbapi.OperationalError, e: 180 _log.error(u"login attempt failed: %s", e) 181 msg = _( 182 "Unable to connect to database:\n\n" 183 "%s\n\n" 184 "Please retry another backend / user / password combination !\n" 185 ) % gmPG2.extract_msg_from_pg_exception(e) 186 msg = regex.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg) 187 gmGuiHelpers.gm_show_error ( 188 msg, 189 _('Connecting to backend') 190 ) 191 del e 192 continue 193 194 # connect was successful 195 gmPG2.set_default_login(login = login) 196 gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding) 197 198 seems_bootstrapped = gmPG2.schema_exists(schema = 'gm') 199 if not seems_bootstrapped: 200 _log.error('schema [gm] does not exist - database not bootstrapped ?') 201 msg = _( 202 'The database you connected to does not seem\n' 203 'to have been boostrapped properly.\n' 204 '\n' 205 'Make sure you have run the GNUmed database\n' 206 'bootstrapper tool to create a new database.\n' 207 '\n' 208 'Further help can be found on the website at\n' 209 '\n' 210 ' http://wiki.gnumed.de\n' 211 '\n' 212 'or on the GNUmed mailing list.' 213 ) 214 gmGuiHelpers.gm_show_error(msg, _('Verifying database')) 215 connected = False 216 break 217 218 compatible = gmPG2.database_schema_compatible(version = expected_version) 219 if compatible or not require_version: 220 dlg.panel.save_state() 221 222 if not compatible: 223 connected_db_version = gmPG2.get_schema_version() 224 msg = msg_generic % ( 225 client_version, 226 connected_db_version, 227 expected_version, 228 gmTools.coalesce(login.host, '<localhost>'), 229 login.database, 230 login.user 231 ) 232 if require_version: 233 gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version')) 234 connected = False 235 continue 236 gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version')) 237 238 # FIXME: make configurable 239 max_skew = 1 # minutes 240 if _cfg.get(option = 'debug'): 241 max_skew = 10 242 if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)): 243 if _cfg.get(option = 'debug'): 244 gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings')) 245 else: 246 gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings')) 247 connected = False 248 continue 249 250 sanity_level, message = gmPG2.sanity_check_database_settings() 251 if sanity_level != 0: 252 gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings')) 253 if sanity_level == 2: 254 connected = False 255 continue 256 257 gmExceptionHandlingWidgets.set_is_public_database(login.public_db) 258 gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk) 259 260 listener = gmBackendListener.gmBackendListener(conn = conn) 261 break 262 263 dlg.Destroy() 264 265 return connected
266 #================================================================
267 -def get_dbowner_connection(procedure=None, dbo_password=None, dbo_account=u'gm-dbo'):
268 if procedure is None: 269 procedure = _('<restricted procedure>') 270 271 # 1) get password for gm-dbo 272 if dbo_password is None: 273 dbo_password = wx.GetPasswordFromUser ( 274 message = _(""" 275 [%s] 276 277 This is a restricted procedure. We need the 278 current password for the GNUmed database owner. 279 280 Please enter the current password for <%s>:""") % ( 281 procedure, 282 dbo_account 283 ), 284 caption = procedure 285 ) 286 if dbo_password == '': 287 return None 288 289 # 2) connect as gm-dbo 290 login = gmPG2.get_default_login() 291 dsn = gmPG2.make_psycopg2_dsn ( 292 database = login.database, 293 host = login.host, 294 port = login.port, 295 user = dbo_account, 296 password = dbo_password 297 ) 298 try: 299 conn = gmPG2.get_connection ( 300 dsn = dsn, 301 readonly = False, 302 verbose = True, 303 pooled = False 304 ) 305 except: 306 _log.exception('cannot connect') 307 gmGuiHelpers.gm_show_error ( 308 aMessage = _('Cannot connect as the GNUmed database owner <%s>.') % dbo_account, 309 aTitle = procedure 310 ) 311 gmPG2.log_database_access(action = u'failed to connect as database owner for [%s]' % procedure) 312 return None 313 314 return conn
315 #================================================================
316 -def change_gmdbowner_password():
317 318 title = _(u'Changing GNUmed database owner password') 319 320 dbo_account = wx.GetTextFromUser ( 321 message = _(u"Enter the account name of the GNUmed database owner:"), 322 caption = title, 323 default_value = u'' 324 ) 325 326 if dbo_account.strip() == u'': 327 return False 328 329 dbo_conn = get_dbowner_connection ( 330 procedure = title, 331 dbo_account = dbo_account 332 ) 333 if dbo_conn is None: 334 return False 335 336 dbo_pwd_new_1 = wx.GetPasswordFromUser ( 337 message = _(u"Enter the NEW password for the GNUmed database owner:"), 338 caption = title 339 ) 340 if dbo_pwd_new_1.strip() == u'': 341 return False 342 343 dbo_pwd_new_2 = wx.GetPasswordFromUser ( 344 message = _(u"""Enter the NEW password for the GNUmed database owner, again. 345 346 (This will protect you from typos.) 347 """), 348 caption = title 349 ) 350 if dbo_pwd_new_2.strip() == u'': 351 return False 352 353 if dbo_pwd_new_1 != dbo_pwd_new_2: 354 return False 355 356 cmd = u"""ALTER ROLE "%s" ENCRYPTED PASSWORD '%s';""" % ( 357 dbo_account, 358 dbo_pwd_new_2 359 ) 360 gmPG2.run_rw_queries(link_obj = dbo_conn, queries = [{'cmd': cmd}], end_tx = True) 361 362 return True
363 #================================================================
364 -class cBackendProfile:
365 pass
366 #================================================================
367 -class cLoginDialog(wx.Dialog):
368 """cLoginDialog - window holding cLoginPanel""" 369
370 - def __init__(self, parent, id, title=_("Welcome to the"), client_version=u'*** unknown ***'):
371 wx.Dialog.__init__(self, parent, id, title) 372 self.panel = cLoginPanel(self, -1, isDialog=1, client_version = client_version) 373 self.Fit() # needed for Windoze. 374 self.Centre() 375 376 self.SetIcon(gmTools.get_icon(wx = wx))
377 #================================================================
378 -class cLoginPanel(wx.Panel):
379 """GUI panel class that interactively gets Postgres login parameters. 380 381 It features combo boxes which "remember" any number of 382 previously entered settings. 383 """
384 - def __init__(self, parent, id, 385 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.TAB_TRAVERSAL, 386 isDialog = 0, client_version = u'*** unknown ***'):
387 """Create login panel. 388 389 isDialog: if this panel is the main panel of a dialog, the panel will 390 resize the dialog automatically to display everything neatly 391 if isDialog is set to True 392 """ 393 wx.Panel.__init__(self, parent, id, pos, size, style) 394 self.parent = parent 395 396 #True if dialog was cancelled by user 397 #if the dialog is closed manually, login should be cancelled 398 self.cancelled = True 399 400 # True if this panel is displayed within a dialog (will resize the dialog automatically then) 401 self.isDialog = isDialog 402 403 self.topsizer = wx.BoxSizer(wx.VERTICAL) 404 405 # find bitmap 406 paths = gmTools.gmPaths(app_name = u'gnumed', wx = wx) 407 bitmap = os.path.join(paths.system_app_data_dir, 'bitmaps', 'gnumedlogo.png') 408 try: 409 png = wx.Image(bitmap, wx.BITMAP_TYPE_PNG).ConvertToBitmap() 410 bmp = wx.StaticBitmap(self, -1, png, wx.Point(10, 10), wx.Size(png.GetWidth(), png.GetHeight())) 411 self.topsizer.Add ( 412 bmp, 413 proportion = 0, 414 flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 415 border = 10 416 ) 417 except: 418 self.topsizer.Add ( 419 wx.StaticText ( 420 self, 421 -1, 422 label = _("Cannot find image") + bitmap, 423 style = wx.ALIGN_CENTRE 424 ), 425 proportion = 0, 426 flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 427 border = 10 428 ) 429 430 paramsbox_caption = _('"%s" (version %s)') % (gmSurgery.gmCurrentPractice().active_workplace, client_version) 431 432 # FIXME: why doesn't this align in the centre ? 433 self.paramsbox = wx.StaticBox( self, -1, paramsbox_caption, style = wx.ALIGN_CENTRE_HORIZONTAL) 434 self.paramsboxsizer = wx.StaticBoxSizer( self.paramsbox, wx.VERTICAL ) 435 self.paramsbox.SetForegroundColour(wx.Colour(35, 35, 142)) 436 self.paramsbox.SetFont(wx.Font( 437 pointSize = 12, 438 family = wx.SWISS, 439 style = wx.NORMAL, 440 weight = wx.BOLD, 441 underline = False 442 )) 443 self.pboxgrid = wx.FlexGridSizer(5, 2, 5, 5) 444 self.pboxgrid.AddGrowableCol(1) 445 446 # PROFILE COMBO 447 label = wx.StaticText( self, -1, _('Log into'), wx.DefaultPosition, wx.DefaultSize, 0) 448 label.SetForegroundColour(wx.Colour(35, 35, 142)) 449 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) 450 self.__backend_profiles = self.__get_backend_profiles() 451 self._CBOX_profile = wx.ComboBox ( 452 self, 453 -1, 454 self.__backend_profiles.keys()[0], 455 wx.DefaultPosition, 456 size = wx.Size(150,-1), 457 choices = self.__backend_profiles.keys(), 458 style = wx.CB_READONLY 459 ) 460 self.pboxgrid.Add (self._CBOX_profile, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 461 462 # USER NAME COMBO 463 label = wx.StaticText( self, -1, _("Username"), wx.DefaultPosition, wx.DefaultSize, 0 ) 464 label.SetForegroundColour(wx.Colour(35, 35, 142)) 465 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 466 self.__previously_used_accounts = self.__get_previously_used_accounts() 467 self._CBOX_user = wx.ComboBox ( 468 self, 469 -1, 470 self.__previously_used_accounts[0], 471 wx.DefaultPosition, 472 wx.Size(150,-1), 473 self.__previously_used_accounts, 474 wx.CB_DROPDOWN 475 ) 476 self.pboxgrid.Add( self._CBOX_user, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 477 478 #PASSWORD TEXT ENTRY 479 label = wx.StaticText( self, -1, _("Password"), wx.DefaultPosition, wx.DefaultSize, 0 ) 480 label.SetForegroundColour(wx.Colour(35, 35, 142)) 481 self.pboxgrid.Add( label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 482 self.pwdentry = wx.TextCtrl( self, 1, '', wx.DefaultPosition, wx.Size(80,-1), wx.TE_PASSWORD ) 483 # set focus on password entry 484 self.pwdentry.SetFocus() 485 self.pboxgrid.Add( self.pwdentry, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 486 487 # --debug checkbox 488 label = wx.StaticText(self, -1, _('Options'), wx.DefaultPosition, wx.DefaultSize, 0) 489 label.SetForegroundColour(wx.Colour(35, 35, 142)) 490 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 491 self._CHBOX_debug = wx.CheckBox(self, -1, _('&Debug mode')) 492 self._CHBOX_debug.SetToolTipString(_('Check this to run GNUmed client in debugging mode.')) 493 self.pboxgrid.Add(self._CHBOX_debug, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) 494 495 # --slave checkbox 496 label = wx.StaticText(self, -1, '', wx.DefaultPosition, wx.DefaultSize, 0) 497 label.SetForegroundColour(wx.Colour(35, 35, 142)) 498 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 499 self._CHBOX_slave = wx.CheckBox(self, -1, _('Enable &remote control')) 500 self._CHBOX_slave.SetToolTipString(_('Check this to run GNUmed client in slave mode for remote control.')) 501 self.pboxgrid.Add(self._CHBOX_slave, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) 502 503 #---------------------------------------------------------------------- 504 #new button code inserted rterry 06Sept02 505 #button order re-arraged to make it consistant with usual dialog format 506 #in most operating systems ie btns ok and cancel are standard and 507 #in that order 508 #ie Order is now help, ok and cancel 509 #The order of creation is the tab order 510 #login-ok button automatically is the default when tabbing (or <enter>) 511 #from password 512 #this eliminates the heavy border when you use the default 513 #?is the default word needed for any other reason? 514 #---------------------------------------------------------------------- 515 self.button_gridsizer = wx.GridSizer(1,3,0,0) 516 #--------------------- 517 #3:create login ok button 518 #--------------------- 519 ID_BUTTON_LOGIN = wx.NewId() 520 button_login_ok = wx.Button(self, ID_BUTTON_LOGIN, _("&Ok"), wx.DefaultPosition, wx.DefaultSize, 0 ) 521 button_login_ok.SetToolTip(wx.ToolTip(_("Proceed with login.")) ) 522 button_login_ok.SetDefault() 523 524 #--------------------- 525 #3:create cancel button 526 #--------------------- 527 ID_BUTTON_CANCEL = wx.NewId() 528 button_cancel = wx.Button(self, ID_BUTTON_CANCEL, _("&Cancel"), wx.DefaultPosition, wx.DefaultSize, 0 ) 529 button_cancel.SetToolTip(wx.ToolTip(_("Cancel Login.")) ) 530 #--------------------- 531 #2:create Help button 532 #--------------------- 533 ID_BUTTON_HELP = wx.NewId() 534 button_help = wx.Button(self, ID_BUTTON_HELP, _("&Help"), wx.DefaultPosition, wx.DefaultSize, 0 ) 535 button_help.SetToolTip(wx.ToolTip(_("Help for login screen"))) 536 #---------------------------- 537 #Add buttons to the gridsizer 538 #---------------------------- 539 self.button_gridsizer.Add (button_help,0,wx.EXPAND|wx.ALL,5) 540 self.button_gridsizer.Add (button_login_ok,0,wx.EXPAND|wx.ALL,5) 541 self.button_gridsizer.Add (button_cancel,0,wx.EXPAND|wx.ALL,5) 542 543 self.paramsboxsizer.Add(self.pboxgrid, 1, wx.GROW|wx.ALL, 10) 544 self.topsizer.Add(self.paramsboxsizer, 1, wx.GROW|wx.ALL, 10) 545 self.topsizer.Add( self.button_gridsizer, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 546 547 self.__load_state() 548 549 self.SetAutoLayout(True) 550 self.SetSizer( self.topsizer) 551 self.topsizer.Fit( self ) 552 if self.isDialog: 553 self.topsizer.SetSizeHints(parent) 554 555 wx.EVT_BUTTON(self, ID_BUTTON_HELP, self.OnHelp) 556 wx.EVT_BUTTON(self, ID_BUTTON_LOGIN, self.__on_login_button_pressed) 557 wx.EVT_BUTTON(self, ID_BUTTON_CANCEL, self.OnCancel)
558 559 #---------------------------------------------------------- 560 # internal helper methods 561 #----------------------------------------------------------
563 564 accounts = gmTools.coalesce ( 565 _cfg.get ( 566 group = u'backend', 567 option = u'logins', 568 source_order = [ 569 (u'explicit', u'extend'), 570 (u'user', u'extend'), 571 (u'workbase', u'extend') 572 ] 573 ), 574 ['any-doc'] 575 ) 576 # FIXME: make unique 577 578 return accounts
579 #----------------------------------------------------
580 - def __get_backend_profiles(self):
581 """Get server profiles from the configuration files. 582 583 1) from system-wide file 584 2) from user file 585 586 Profiles in the user file which have the same name 587 as a profile in the system file will override the 588 system file. 589 """ 590 # find active profiles 591 src_order = [ 592 (u'explicit', u'extend'), 593 (u'system', u'extend'), 594 (u'user', u'extend'), 595 (u'workbase', u'extend') 596 ] 597 598 profile_names = gmTools.coalesce ( 599 _cfg.get(group = u'backend', option = u'profiles', source_order = src_order), 600 [] 601 ) 602 603 # find data for active profiles 604 src_order = [ 605 (u'explicit', u'return'), 606 (u'workbase', u'return'), 607 (u'user', u'return'), 608 (u'system', u'return') 609 ] 610 611 profiles = {} 612 613 for profile_name in profile_names: 614 # FIXME: once the profile has been found always use the corresponding source ! 615 # FIXME: maybe not or else we cannot override parts of the profile 616 profile = cBackendProfile() 617 profile_section = 'profile %s' % profile_name 618 619 profile.name = profile_name 620 profile.host = gmTools.coalesce(_cfg.get(profile_section, u'host', src_order), u'').strip() 621 port = gmTools.coalesce(_cfg.get(profile_section, u'port', src_order), 5432) 622 try: 623 profile.port = int(port) 624 if profile.port < 1024: 625 raise ValueError('refusing to use priviledged port (< 1024)') 626 except ValueError: 627 _log.warning('invalid port definition: [%s], skipping profile [%s]', port, profile_name) 628 continue 629 profile.database = gmTools.coalesce(_cfg.get(profile_section, u'database', src_order), u'').strip() 630 if profile.database == u'': 631 _log.warning('database name not specified, skipping profile [%s]', profile_name) 632 continue 633 profile.encoding = gmTools.coalesce(_cfg.get(profile_section, u'encoding', src_order), u'UTF8') 634 profile.public_db = bool(_cfg.get(profile_section, u'public/open access', src_order)) 635 profile.helpdesk = _cfg.get(profile_section, u'help desk', src_order) 636 637 label = u'%s (%s@%s)' % (profile_name, profile.database, profile.host) 638 profiles[label] = profile 639 640 # sort out profiles with incompatible database versions if not --debug 641 # NOTE: this essentially hardcodes the database name in production ... 642 if not (_cfg.get(option = 'debug') or current_db_name.endswith('_devel')): 643 profiles2remove = [] 644 for label in profiles: 645 if profiles[label].database != current_db_name: 646 profiles2remove.append(label) 647 for label in profiles2remove: 648 del profiles[label] 649 650 if len(profiles) == 0: 651 host = u'publicdb.gnumed.de' 652 label = u'public GNUmed database (%s@%s)' % (current_db_name, host) 653 profiles[label] = cBackendProfile() 654 profiles[label].name = label 655 profiles[label].host = host 656 profiles[label].port = 5432 657 profiles[label].database = current_db_name 658 profiles[label].encoding = u'UTF8' 659 profiles[label].public_db = True 660 profiles[label].helpdesk = u'http://wiki.gnumed.de' 661 662 return profiles
663 #----------------------------------------------------------
664 - def __load_state(self):
665 666 src_order = [ 667 (u'explicit', u'return'), 668 (u'user', u'return'), 669 ] 670 671 self._CBOX_user.SetValue ( 672 gmTools.coalesce ( 673 _cfg.get(u'preferences', u'login', src_order), 674 self.__previously_used_accounts[0] 675 ) 676 ) 677 678 last_used_profile_label = _cfg.get(u'preferences', u'profile', src_order) 679 if last_used_profile_label in self.__backend_profiles.keys(): 680 self._CBOX_profile.SetValue(last_used_profile_label) 681 else: 682 self._CBOX_profile.SetValue(self.__backend_profiles.keys()[0]) 683 684 self._CHBOX_debug.SetValue(_cfg.get(option = 'debug')) 685 self._CHBOX_slave.SetValue(_cfg.get(option = 'slave'))
686 #----------------------------------------------------
687 - def save_state(self):
688 """Save parameter settings to standard configuration file""" 689 prefs_name = _cfg.get(option = 'user_preferences_file') 690 _log.debug(u'saving login preferences in [%s]', prefs_name) 691 692 gmCfg2.set_option_in_INI_file ( 693 filename = prefs_name, 694 group = 'preferences', 695 option = 'login', 696 value = self._CBOX_user.GetValue() 697 ) 698 699 gmCfg2.set_option_in_INI_file ( 700 filename = prefs_name, 701 group = 'preferences', 702 option = 'profile', 703 value = self._CBOX_profile.GetValue() 704 )
705 ############################################################################# 706 # Retrieve current settings from user interface widgets 707 #############################################################################
708 - def GetLoginInfo(self):
709 """convenience function for compatibility with gmLoginInfo.LoginInfo""" 710 if not self.cancelled: 711 # FIXME: do not assume conf file is latin1 ! 712 #profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()] 713 profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('utf8').strip()] 714 _log.debug(u'backend profile "%s" selected', profile.name) 715 _log.debug(u' details: <%s> on %s@%s:%s (%s, %s)', 716 self._CBOX_user.GetValue(), 717 profile.database, 718 profile.host, 719 profile.port, 720 profile.encoding, 721 gmTools.bool2subst(profile.public_db, u'public', u'private') 722 ) 723 _log.debug(u' helpdesk: "%s"', profile.helpdesk) 724 login = gmLoginInfo.LoginInfo ( 725 user = self._CBOX_user.GetValue(), 726 password = self.pwdentry.GetValue(), 727 host = profile.host, 728 database = profile.database, 729 port = profile.port 730 ) 731 login.public_db = profile.public_db 732 login.helpdesk = profile.helpdesk 733 return login 734 735 return None
736 #---------------------------- 737 # event handlers 738 #----------------------------
739 - def OnHelp(self, event):
740 praxis = gmSurgery.gmCurrentPractice() 741 wx.MessageBox(_( 742 """GNUmed main login screen 743 744 Welcome to the GNUmed client. Shown are the current 745 "Workplace" and (version). 746 747 You may select to log into a public database with username 748 and password {any-doc, any-doc}. Any other database 749 (including a local one) must first be separately installed 750 before you can log in. 751 752 For assistance on using GNUmed please consult the wiki: 753 754 http://wiki.gnumed.de/bin/view/Gnumed/GnumedManual 755 756 and to install a local database see: 757 758 http://wiki.gnumed.de/bin/view/Gnumed/GmManualServerInstall 759 760 For more help than the above, please contact: 761 762 GNUmed Development List <gnumed-bugs@gnu.org> 763 764 For local assistance please contact: 765 766 %s""") % praxis.helpdesk)
767 768 #----------------------------
769 - def __on_login_button_pressed(self, event):
770 771 root_logger = logging.getLogger() 772 if self._CHBOX_debug.GetValue(): 773 _log.info('debug mode enabled') 774 _cfg.set_option(option = 'debug', value = True) 775 root_logger.setLevel(logging.DEBUG) 776 else: 777 _log.info('debug mode disabled') 778 _cfg.set_option(option = 'debug', value = False) 779 if _cfg.get(option = '--quiet', source_order = [('cli', 'return')]): 780 root_logger.setLevel(logging.ERROR) 781 else: 782 root_logger.setLevel(logging.WARNING) 783 784 if self._CHBOX_slave.GetValue(): 785 _log.info('slave mode enabled') 786 _cfg.set_option(option = 'slave', value = True) 787 else: 788 _log.info('slave mode disabled') 789 _cfg.set_option(option = 'slave', value = False) 790 791 self.backend_profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()] 792 # self.user = self._CBOX_user.GetValue().strip() 793 # self.password = self.GetPassword() 794 self.cancelled = False 795 self.parent.Close()
796 #----------------------------
797 - def OnCancel(self, event):
798 self.cancelled = True 799 self.parent.Close()
800 801 #================================================================ 802 # main 803 #---------------------------------------------------------------- 804 if __name__ == "__main__": 805 806 if len(sys.argv) < 2: 807 sys.exit() 808 809 if sys.argv[1] != 'test': 810 sys.exit() 811 812 # we don't have tests yet 813 sys.exit() 814 815 from Gnumed.pycommon import gmI18N 816 817 logging.basicConfig(level = logging.DEBUG) 818 819 gmI18N.activate_locale() 820 gmI18N.install_domain(domain='gnumed') 821 #----------------------------------------------- 822 #-----------------------------------------------
823 - def test():
824 app = wx.PyWidgetTester(size = (300,400)) 825 #show the login panel in a main window 826 # app.SetWidget(cLoginPanel, -1) 827 #and pop the login dialog up modally 828 dlg = cLoginDialog(None, -1) #, png_bitmap = 'bitmaps/gnumedlogo.png') 829 dlg.ShowModal() 830 #demonstration how to access the login dialog values 831 lp = dlg.panel.GetLoginInfo() 832 if lp is None: 833 wx.MessageBox(_("Dialog was cancelled by user")) 834 else: 835 wx.MessageBox(_("You tried to log in as [%s] with password [%s].\nHost:%s, DB: %s, Port: %s") % (lp.GetUser(),lp.GetPassword(),lp.GetHost(),lp.GetDatabase(),lp.GetPort())) 836 dlg.Destroy()
837 # app.MainLoop() 838 839 #================================================================ 840