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
13 import sys, os.path, logging, re as regex
14
15
16
17 import wx
18
19
20
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
98
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
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
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
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
219 max_skew = 1
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
248 if procedure is None:
249 procedure = _('<restricted procedure>')
250
251
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
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
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
346
348 """cLoginDialog - window holding cLoginPanel"""
349
350 - def __init__(self, parent, id, title=_("Welcome to the"), client_version=u'*** unknown ***'):
357
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
377
378 self.cancelled = True
379
380
381 self.isDialog = isDialog
382
383 self.topsizer = wx.BoxSizer(wx.VERTICAL)
384
385
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
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
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
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
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
464 self.pwdentry.SetFocus()
465 self.pboxgrid.Add( self.pwdentry, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
466
467
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
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
485
486
487
488
489
490
491
492
493
494
495 self.button_gridsizer = wx.GridSizer(1,3,0,0)
496
497
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
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
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
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
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
557
558 return accounts
559
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
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
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
595
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
621
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
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
685
686
687
689 """convenience function for compatibility with gmLoginInfo.LoginInfo"""
690 if not self.cancelled:
691
692
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
718
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
769
771 self.cancelled = True
772 self.parent.Close()
773
774
775
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
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
797 app = wx.PyWidgetTester(size = (300,400))
798
799
800
801 dlg = cLoginDialog(None, -1)
802 dlg.ShowModal()
803
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
811
812
813