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 compatible = gmPG2.database_schema_compatible(version = expected_version) 199 if compatible or not require_version: 200 dlg.panel.save_state() 201 202 if not compatible: 203 connected_db_version = gmPG2.get_schema_version() 204 msg = msg_generic % ( 205 client_version, 206 connected_db_version, 207 expected_version, 208 gmTools.coalesce(login.host, '<localhost>'), 209 login.database, 210 login.user 211 ) 212 if require_version: 213 gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version')) 214 connected = False 215 continue 216 gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version')) 217 218 # FIXME: make configurable 219 max_skew = 1 # minutes 220 if _cfg.get(option = 'debug'): 221 max_skew = 10 222 if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)): 223 if _cfg.get(option = 'debug'): 224 gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings')) 225 else: 226 gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings')) 227 connected = False 228 continue 229 230 sanity_level, message = gmPG2.sanity_check_database_settings() 231 if sanity_level != 0: 232 gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings')) 233 if sanity_level == 2: 234 connected = False 235 continue 236 237 gmExceptionHandlingWidgets.set_is_public_database(login.public_db) 238 gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk) 239 240 listener = gmBackendListener.gmBackendListener(conn = conn) 241 break 242 243 dlg.Destroy() 244 245 return connected
246 #================================================================
247 -def get_dbowner_connection(procedure=None, dbo_password=None, dbo_account=u'gm-dbo'):
248 if procedure is None: 249 procedure = _('<restricted procedure>') 250 251 # 1) get password for gm-dbo 252 if dbo_password is None: 253 dbo_password = wx.GetPasswordFromUser ( 254 message = _(""" 255 [%s] 256 257 This is a restricted procedure. We need the 258 current password for the GNUmed database owner. 259 260 Please enter the current password for <%s>:""") % ( 261 procedure, 262 dbo_account 263 ), 264 caption = procedure 265 ) 266 if dbo_password == '': 267 return None 268 269 # 2) connect as gm-dbo 270 login = gmPG2.get_default_login() 271 dsn = gmPG2.make_psycopg2_dsn ( 272 database = login.database, 273 host = login.host, 274 port = login.port, 275 user = dbo_account, 276 password = dbo_password 277 ) 278 try: 279 conn = gmPG2.get_connection ( 280 dsn = dsn, 281 readonly = False, 282 verbose = True, 283 pooled = False 284 ) 285 except: 286 _log.exception('cannot connect') 287 gmGuiHelpers.gm_show_error ( 288 aMessage = _('Cannot connect as the GNUmed database owner <%s>.') % dbo_account, 289 aTitle = procedure 290 ) 291 gmPG2.log_database_access(action = u'failed to connect as database owner for [%s]' % procedure) 292 return None 293 294 return conn
295 #================================================================
296 -def change_gmdbowner_password():
297 298 title = _(u'Changing GNUmed database owner password') 299 300 dbo_account = wx.GetTextFromUser ( 301 message = _(u"Enter the account name of the GNUmed database owner:"), 302 caption = title, 303 default_value = u'' 304 ) 305 306 if dbo_account.strip() == u'': 307 return False 308 309 dbo_conn = get_dbowner_connection ( 310 procedure = title, 311 dbo_account = dbo_account 312 ) 313 if dbo_conn is None: 314 return False 315 316 dbo_pwd_new_1 = wx.GetPasswordFromUser ( 317 message = _(u"Enter the NEW password for the GNUmed database owner:"), 318 caption = title 319 ) 320 if dbo_pwd_new_1.strip() == u'': 321 return False 322 323 dbo_pwd_new_2 = wx.GetPasswordFromUser ( 324 message = _(u"""Enter the NEW password for the GNUmed database owner, again. 325 326 (This will protect you from typos.) 327 """), 328 caption = title 329 ) 330 if dbo_pwd_new_2.strip() == u'': 331 return False 332 333 if dbo_pwd_new_1 != dbo_pwd_new_2: 334 return False 335 336 cmd = u"""ALTER ROLE "%s" ENCRYPTED PASSWORD '%s';""" % ( 337 dbo_account, 338 dbo_pwd_new_2 339 ) 340 gmPG2.run_rw_queries(link_obj = dbo_conn, queries = [{'cmd': cmd}], end_tx = True) 341 342 return True
343 #================================================================
344 -class cBackendProfile:
345 pass
346 #================================================================
347 -class cLoginDialog(wx.Dialog):
348 """cLoginDialog - window holding cLoginPanel""" 349
350 - def __init__(self, parent, id, title=_("Welcome to the"), client_version=u'*** unknown ***'):
351 wx.Dialog.__init__(self, parent, id, title) 352 self.panel = cLoginPanel(self, -1, isDialog=1, client_version = client_version) 353 self.Fit() # needed for Windoze. 354 self.Centre() 355 356 self.SetIcon(gmTools.get_icon(wx = wx))
357 #================================================================
358 -class cLoginPanel(wx.Panel):
359 """GUI panel class that interactively gets Postgres login parameters. 360 361 It features combo boxes which "remember" any number of 362 previously entered settings. 363 """
364 - def __init__(self, parent, id, 365 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.TAB_TRAVERSAL, 366 isDialog = 0, client_version = u'*** unknown ***'):
367 """Create login panel. 368 369 isDialog: if this panel is the main panel of a dialog, the panel will 370 resize the dialog automatically to display everything neatly 371 if isDialog is set to True 372 """ 373 wx.Panel.__init__(self, parent, id, pos, size, style) 374 self.parent = parent 375 376 #True if dialog was cancelled by user 377 #if the dialog is closed manually, login should be cancelled 378 self.cancelled = True 379 380 # True if this panel is displayed within a dialog (will resize the dialog automatically then) 381 self.isDialog = isDialog 382 383 self.topsizer = wx.BoxSizer(wx.VERTICAL) 384 385 # find bitmap 386 paths = gmTools.gmPaths(app_name = u'gnumed', wx = wx) 387 bitmap = os.path.join(paths.system_app_data_dir, 'bitmaps', 'gnumedlogo.png') 388 try: 389 png = wx.Image(bitmap, wx.BITMAP_TYPE_PNG).ConvertToBitmap() 390 bmp = wx.StaticBitmap(self, -1, png, wx.Point(10, 10), wx.Size(png.GetWidth(), png.GetHeight())) 391 self.topsizer.Add ( 392 bmp, 393 proportion = 0, 394 flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 395 border = 10 396 ) 397 except: 398 self.topsizer.Add ( 399 wx.StaticText ( 400 self, 401 -1, 402 label = _("Cannot find image") + bitmap, 403 style = wx.ALIGN_CENTRE 404 ), 405 proportion = 0, 406 flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 407 border = 10 408 ) 409 410 paramsbox_caption = _('"%s" (version %s)') % (gmSurgery.gmCurrentPractice().active_workplace, client_version) 411 412 # FIXME: why doesn't this align in the centre ? 413 self.paramsbox = wx.StaticBox( self, -1, paramsbox_caption, style = wx.ALIGN_CENTRE_HORIZONTAL) 414 self.paramsboxsizer = wx.StaticBoxSizer( self.paramsbox, wx.VERTICAL ) 415 self.paramsbox.SetForegroundColour(wx.Colour(35, 35, 142)) 416 self.paramsbox.SetFont(wx.Font( 417 pointSize = 12, 418 family = wx.SWISS, 419 style = wx.NORMAL, 420 weight = wx.BOLD, 421 underline = False 422 )) 423 self.pboxgrid = wx.FlexGridSizer(5, 2, 5, 5) 424 self.pboxgrid.AddGrowableCol(1) 425 426 # PROFILE COMBO 427 label = wx.StaticText( self, -1, _('Log into'), wx.DefaultPosition, wx.DefaultSize, 0) 428 label.SetForegroundColour(wx.Colour(35, 35, 142)) 429 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) 430 self.__backend_profiles = self.__get_backend_profiles() 431 self._CBOX_profile = wx.ComboBox ( 432 self, 433 -1, 434 self.__backend_profiles.keys()[0], 435 wx.DefaultPosition, 436 size = wx.Size(150,-1), 437 choices = self.__backend_profiles.keys(), 438 style = wx.CB_READONLY 439 ) 440 self.pboxgrid.Add (self._CBOX_profile, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 441 442 # USER NAME COMBO 443 label = wx.StaticText( self, -1, _("Username"), wx.DefaultPosition, wx.DefaultSize, 0 ) 444 label.SetForegroundColour(wx.Colour(35, 35, 142)) 445 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 446 self.__previously_used_accounts = self.__get_previously_used_accounts() 447 self._CBOX_user = wx.ComboBox ( 448 self, 449 -1, 450 self.__previously_used_accounts[0], 451 wx.DefaultPosition, 452 wx.Size(150,-1), 453 self.__previously_used_accounts, 454 wx.CB_DROPDOWN 455 ) 456 self.pboxgrid.Add( self._CBOX_user, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 457 458 #PASSWORD TEXT ENTRY 459 label = wx.StaticText( self, -1, _("Password"), wx.DefaultPosition, wx.DefaultSize, 0 ) 460 label.SetForegroundColour(wx.Colour(35, 35, 142)) 461 self.pboxgrid.Add( label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 462 self.pwdentry = wx.TextCtrl( self, 1, '', wx.DefaultPosition, wx.Size(80,-1), wx.TE_PASSWORD ) 463 # set focus on password entry 464 self.pwdentry.SetFocus() 465 self.pboxgrid.Add( self.pwdentry, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 466 467 # --debug checkbox 468 label = wx.StaticText(self, -1, _('Options'), wx.DefaultPosition, wx.DefaultSize, 0) 469 label.SetForegroundColour(wx.Colour(35, 35, 142)) 470 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 471 self._CHBOX_debug = wx.CheckBox(self, -1, _('&Debug mode')) 472 self._CHBOX_debug.SetToolTipString(_('Check this to run GNUmed client in debugging mode.')) 473 self.pboxgrid.Add(self._CHBOX_debug, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) 474 475 # --slave checkbox 476 label = wx.StaticText(self, -1, '', wx.DefaultPosition, wx.DefaultSize, 0) 477 label.SetForegroundColour(wx.Colour(35, 35, 142)) 478 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 479 self._CHBOX_slave = wx.CheckBox(self, -1, _('Enable &remote control')) 480 self._CHBOX_slave.SetToolTipString(_('Check this to run GNUmed client in slave mode for remote control.')) 481 self.pboxgrid.Add(self._CHBOX_slave, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) 482 483 #---------------------------------------------------------------------- 484 #new button code inserted rterry 06Sept02 485 #button order re-arraged to make it consistant with usual dialog format 486 #in most operating systems ie btns ok and cancel are standard and 487 #in that order 488 #ie Order is now help, ok and cancel 489 #The order of creation is the tab order 490 #login-ok button automatically is the default when tabbing (or <enter>) 491 #from password 492 #this eliminates the heavy border when you use the default 493 #?is the default word needed for any other reason? 494 #---------------------------------------------------------------------- 495 self.button_gridsizer = wx.GridSizer(1,3,0,0) 496 #--------------------- 497 #3:create login ok button 498 #--------------------- 499 ID_BUTTON_LOGIN = wx.NewId() 500 button_login_ok = wx.Button(self, ID_BUTTON_LOGIN, _("&Ok"), wx.DefaultPosition, wx.DefaultSize, 0 ) 501 button_login_ok.SetToolTip(wx.ToolTip(_("Proceed with login.")) ) 502 button_login_ok.SetDefault() 503 504 #--------------------- 505 #3:create cancel button 506 #--------------------- 507 ID_BUTTON_CANCEL = wx.NewId() 508 button_cancel = wx.Button(self, ID_BUTTON_CANCEL, _("&Cancel"), wx.DefaultPosition, wx.DefaultSize, 0 ) 509 button_cancel.SetToolTip(wx.ToolTip(_("Cancel Login.")) ) 510 #--------------------- 511 #2:create Help button 512 #--------------------- 513 ID_BUTTON_HELP = wx.NewId() 514 button_help = wx.Button(self, ID_BUTTON_HELP, _("&Help"), wx.DefaultPosition, wx.DefaultSize, 0 ) 515 button_help.SetToolTip(wx.ToolTip(_("Help for login screen"))) 516 #---------------------------- 517 #Add buttons to the gridsizer 518 #---------------------------- 519 self.button_gridsizer.Add (button_help,0,wx.EXPAND|wx.ALL,5) 520 self.button_gridsizer.Add (button_login_ok,0,wx.EXPAND|wx.ALL,5) 521 self.button_gridsizer.Add (button_cancel,0,wx.EXPAND|wx.ALL,5) 522 523 self.paramsboxsizer.Add(self.pboxgrid, 1, wx.GROW|wx.ALL, 10) 524 self.topsizer.Add(self.paramsboxsizer, 1, wx.GROW|wx.ALL, 10) 525 self.topsizer.Add( self.button_gridsizer, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 526 527 self.__load_state() 528 529 self.SetAutoLayout(True) 530 self.SetSizer( self.topsizer) 531 self.topsizer.Fit( self ) 532 if self.isDialog: 533 self.topsizer.SetSizeHints(parent) 534 535 wx.EVT_BUTTON(self, ID_BUTTON_HELP, self.OnHelp) 536 wx.EVT_BUTTON(self, ID_BUTTON_LOGIN, self.__on_login_button_pressed) 537 wx.EVT_BUTTON(self, ID_BUTTON_CANCEL, self.OnCancel)
538 539 #---------------------------------------------------------- 540 # internal helper methods 541 #----------------------------------------------------------
543 544 accounts = gmTools.coalesce ( 545 _cfg.get ( 546 group = u'backend', 547 option = u'logins', 548 source_order = [ 549 (u'explicit', u'extend'), 550 (u'user', u'extend'), 551 (u'workbase', u'extend') 552 ] 553 ), 554 ['any-doc'] 555 ) 556 # FIXME: make unique 557 558 return accounts
559 #----------------------------------------------------
560 - def __get_backend_profiles(self):
561 """Get server profiles from the configuration files. 562 563 1) from system-wide file 564 2) from user file 565 566 Profiles in the user file which have the same name 567 as a profile in the system file will override the 568 system file. 569 """ 570 # find active profiles 571 src_order = [ 572 (u'explicit', u'extend'), 573 (u'system', u'extend'), 574 (u'user', u'extend'), 575 (u'workbase', u'extend') 576 ] 577 578 profile_names = gmTools.coalesce ( 579 _cfg.get(group = u'backend', option = u'profiles', source_order = src_order), 580 [] 581 ) 582 583 # find data for active profiles 584 src_order = [ 585 (u'explicit', u'return'), 586 (u'workbase', u'return'), 587 (u'user', u'return'), 588 (u'system', u'return') 589 ] 590 591 profiles = {} 592 593 for profile_name in profile_names: 594 # FIXME: once the profile has been found always use the corresponding source ! 595 # FIXME: maybe not or else we cannot override parts of the profile 596 profile = cBackendProfile() 597 profile_section = 'profile %s' % profile_name 598 599 profile.name = profile_name 600 profile.host = gmTools.coalesce(_cfg.get(profile_section, u'host', src_order), u'').strip() 601 port = gmTools.coalesce(_cfg.get(profile_section, u'port', src_order), 5432) 602 try: 603 profile.port = int(port) 604 if profile.port < 1024: 605 raise ValueError('refusing to use priviledged port (< 1024)') 606 except ValueError: 607 _log.warning('invalid port definition: [%s], skipping profile [%s]', port, profile_name) 608 continue 609 profile.database = gmTools.coalesce(_cfg.get(profile_section, u'database', src_order), u'').strip() 610 if profile.database == u'': 611 _log.warning('database name not specified, skipping profile [%s]', profile_name) 612 continue 613 profile.encoding = gmTools.coalesce(_cfg.get(profile_section, u'encoding', src_order), u'UTF8') 614 profile.public_db = bool(_cfg.get(profile_section, u'public/open access', src_order)) 615 profile.helpdesk = _cfg.get(profile_section, u'help desk', src_order) 616 617 label = u'%s (%s@%s)' % (profile_name, profile.database, profile.host) 618 profiles[label] = profile 619 620 # sort out profiles with incompatible database versions if not --debug 621 # NOTE: this essentially hardcodes the database name in production ... 622 if not (_cfg.get(option = 'debug') or current_db_name.endswith('_devel')): 623 profiles2remove = [] 624 for label in profiles: 625 if profiles[label].database != current_db_name: 626 profiles2remove.append(label) 627 for label in profiles2remove: 628 del profiles[label] 629 630 if len(profiles) == 0: 631 host = u'publicdb.gnumed.de' 632 label = u'public GNUmed database (%s@%s)' % (current_db_name, host) 633 profiles[label] = cBackendProfile() 634 profiles[label].name = label 635 profiles[label].host = host 636 profiles[label].port = 5432 637 profiles[label].database = current_db_name 638 profiles[label].encoding = u'UTF8' 639 profiles[label].public_db = True 640 profiles[label].helpdesk = u'http://wiki.gnumed.de' 641 642 return profiles
643 #----------------------------------------------------------
644 - def __load_state(self):
645 646 src_order = [ 647 (u'explicit', u'return'), 648 (u'user', u'return'), 649 ] 650 651 self._CBOX_user.SetValue ( 652 gmTools.coalesce ( 653 _cfg.get(u'preferences', u'login', src_order), 654 self.__previously_used_accounts[0] 655 ) 656 ) 657 658 last_used_profile_label = _cfg.get(u'preferences', u'profile', src_order) 659 if last_used_profile_label in self.__backend_profiles.keys(): 660 self._CBOX_profile.SetValue(last_used_profile_label) 661 else: 662 self._CBOX_profile.SetValue(self.__backend_profiles.keys()[0]) 663 664 self._CHBOX_debug.SetValue(_cfg.get(option = 'debug')) 665 self._CHBOX_slave.SetValue(_cfg.get(option = 'slave'))
666 #----------------------------------------------------
667 - def save_state(self):
668 """Save parameter settings to standard configuration file""" 669 prefs_name = _cfg.get(option = 'user_preferences_file') 670 _log.debug(u'saving login preferences in [%s]', prefs_name) 671 672 gmCfg2.set_option_in_INI_file ( 673 filename = prefs_name, 674 group = 'preferences', 675 option = 'login', 676 value = self._CBOX_user.GetValue() 677 ) 678 679 gmCfg2.set_option_in_INI_file ( 680 filename = prefs_name, 681 group = 'preferences', 682 option = 'profile', 683 value = self._CBOX_profile.GetValue() 684 )
685 ############################################################################# 686 # Retrieve current settings from user interface widgets 687 #############################################################################
688 - def GetLoginInfo(self):
689 """convenience function for compatibility with gmLoginInfo.LoginInfo""" 690 if not self.cancelled: 691 # FIXME: do not assume conf file is latin1 ! 692 #profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()] 693 profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('utf8').strip()] 694 _log.debug(u'backend profile "%s" selected', profile.name) 695 _log.debug(u' details: <%s> on %s@%s:%s (%s, %s)', 696 self._CBOX_user.GetValue(), 697 profile.database, 698 profile.host, 699 profile.port, 700 profile.encoding, 701 gmTools.bool2subst(profile.public_db, u'public', u'private') 702 ) 703 _log.debug(u' helpdesk: "%s"', profile.helpdesk) 704 login = gmLoginInfo.LoginInfo ( 705 user = self._CBOX_user.GetValue(), 706 password = self.pwdentry.GetValue(), 707 host = profile.host, 708 database = profile.database, 709 port = profile.port 710 ) 711 login.public_db = profile.public_db 712 login.helpdesk = profile.helpdesk 713 return login 714 715 return None
716 #---------------------------- 717 # event handlers 718 #----------------------------
719 - def OnHelp(self, event):
720 praxis = gmSurgery.gmCurrentPractice() 721 wx.MessageBox(_( 722 """GNUmed main login screen 723 724 USER: 725 name of the GNUmed user 726 PASSWORD 727 password for this user 728 729 button OK: 730 proceed with login 731 button OPTIONS: 732 set advanced options 733 button CANCEL: 734 abort login and quit GNUmed client 735 button HELP: 736 this help screen 737 738 For assistance on using GNUmed please contact: 739 %s""") % praxis.helpdesk)
740 741 #----------------------------
742 - def __on_login_button_pressed(self, event):
743 744 root_logger = logging.getLogger() 745 if self._CHBOX_debug.GetValue(): 746 _log.info('debug mode enabled') 747 _cfg.set_option(option = 'debug', value = True) 748 root_logger.setLevel(logging.DEBUG) 749 else: 750 _log.info('debug mode disabled') 751 _cfg.set_option(option = 'debug', value = False) 752 if _cfg.get(option = '--quiet', source_order = [('cli', 'return')]): 753 root_logger.setLevel(logging.ERROR) 754 else: 755 root_logger.setLevel(logging.WARNING) 756 757 if self._CHBOX_slave.GetValue(): 758 _log.info('slave mode enabled') 759 _cfg.set_option(option = 'slave', value = True) 760 else: 761 _log.info('slave mode disabled') 762 _cfg.set_option(option = 'slave', value = False) 763 764 self.backend_profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()] 765 # self.user = self._CBOX_user.GetValue().strip() 766 # self.password = self.GetPassword() 767 self.cancelled = False 768 self.parent.Close()
769 #----------------------------
770 - def OnCancel(self, event):
771 self.cancelled = True 772 self.parent.Close()
773 774 #================================================================ 775 # main 776 #---------------------------------------------------------------- 777 if __name__ == "__main__": 778 779 if len(sys.argv) < 2: 780 sys.exit() 781 782 if sys.argv[1] != 'test': 783 sys.exit() 784 785 # we don't have tests yet 786 sys.exit() 787 788 from Gnumed.pycommon import gmI18N 789 790 logging.basicConfig(level = logging.DEBUG) 791 792 gmI18N.activate_locale() 793 gmI18N.install_domain(domain='gnumed') 794 #----------------------------------------------- 795 #-----------------------------------------------
796 - def test():
797 app = wx.PyWidgetTester(size = (300,400)) 798 #show the login panel in a main window 799 # app.SetWidget(cLoginPanel, -1) 800 #and pop the login dialog up modally 801 dlg = cLoginDialog(None, -1) #, png_bitmap = 'bitmaps/gnumedlogo.png') 802 dlg.ShowModal() 803 #demonstration how to access the login dialog values 804 lp = dlg.panel.GetLoginInfo() 805 if lp is None: 806 wx.MessageBox(_("Dialog was cancelled by user")) 807 else: 808 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())) 809 dlg.Destroy()
810 # app.MainLoop() 811 812 #================================================================ 813