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