1
2 """GNUmed authentication widgets.
3
4 This module contains widgets and GUI
5 functions for authenticating users.
6 """
7
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
14 import os.path
15 import logging
16 import re as regex
17
18
19
20 import wx
21
22
23
24 if __name__ == '__main__':
25 sys.path.insert(0, '../../')
26 from Gnumed.pycommon import gmLoginInfo
27 from Gnumed.pycommon import gmPG2
28 from Gnumed.pycommon import gmBackendListener
29 from Gnumed.pycommon import gmTools
30 from Gnumed.pycommon import gmCfg2
31 from Gnumed.pycommon import gmI18N
32 from Gnumed.pycommon import gmLog2
33
34 from Gnumed.business import gmPraxis
35
36 from Gnumed.wxpython import gmGuiHelpers
37 from Gnumed.wxpython import gmExceptionHandlingWidgets
38
39
40 _log = logging.getLogger('gm.ui')
41 _cfg = gmCfg2.gmCfgData()
42
43 try:
44 _('dummy-no-need-to-translate-but-make-epydoc-happy')
45 except NameError:
46 _ = lambda x:x
47
48
49 msg_generic = _("""
50 GNUmed database version mismatch.
51
52 This database version cannot be used with this client:
53
54 client version: %s
55 database version detected: %s
56 database version needed: %s
57
58 Currently connected to database:
59
60 host: %s
61 database: %s
62 user: %s
63 """)
64
65 msg_time_skew_fail = _("""\
66 The server and client clocks are off
67 by more than %s minutes !
68
69 You must fix the time settings before
70 you can use this database with this
71 client.
72
73 You may have to contact your
74 administrator for help.""")
75
76 msg_time_skew_warn = _("""\
77 The server and client clocks are off
78 by more than %s minutes !
79
80 You should fix the time settings.
81 Otherwise clinical data may appear to
82 have been entered at the wrong time.
83
84 You may have to contact your
85 administrator for help.""")
86
87 msg_insanity = _("""
88 There is a serious problem with the database settings:
89
90 %s
91
92 You may have to contact your administrator for help.""")
93
94 msg_fail = _("""
95 You must connect to a different database in order
96 to use the GNUmed client. You may have to contact
97 your administrator for help.""")
98
99 msg_override = _("""
100 The client will, however, continue to start up because
101 you are running a development/test version of GNUmed.
102
103 There may be schema related errors. Please report and/or
104 fix them. Do not rely on this database to work properly
105 in all cases !""")
106
107
108
109
111 """Display the login dialog and try to log into the backend.
112
113 - up to max_attempts times
114 - returns True/False
115 """
116
117 expected_hash = gmPG2.known_schema_hashes[expected_version]
118 client_version = _cfg.get(option = 'client_version')
119 global current_db_name
120 current_db_name = 'gnumed_v%s' % expected_version
121
122 attempt = 0
123
124 dlg = cLoginDialog(None, -1, client_version = client_version)
125 dlg.Centre(wx.BOTH)
126
127 while attempt < max_attempts:
128
129 _log.debug('login attempt %s of %s', (attempt+1), max_attempts)
130
131 connected = False
132
133 dlg.ShowModal()
134 login = dlg.panel.GetLoginInfo()
135 if login is None:
136 _log.info("user cancelled login dialog")
137 break
138
139 gmLog2.add_word2hide(login.password)
140
141
142 dsn = gmPG2.make_psycopg2_dsn (
143 database = login.database,
144 host = login.host,
145 port = login.port,
146 user = login.user,
147 password = login.password
148 )
149 try:
150 conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
151 connected = True
152
153 except gmPG2.cAuthenticationError as e:
154 attempt += 1
155 _log.error("login attempt failed: %s", e)
156 if attempt < max_attempts:
157 if ('host=127.0.0.1' in ('%s' % e)) or ('host=' not in ('%s' % e)):
158 msg = _(
159 'Unable to connect to database:\n\n'
160 '%s\n\n'
161 "Are you sure you have got a local database installed ?\n"
162 '\n'
163 "Please retry with proper credentials or cancel.\n"
164 '\n'
165 ' (for the public and any new GNUmed data-\n'
166 ' bases the default user name and password\n'
167 ' are {any-doc, any-doc})\n'
168 '\n'
169 'You may also need to check the PostgreSQL client\n'
170 'authentication configuration in pg_hba.conf. For\n'
171 'details see:\n'
172 '\n'
173 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
174 )
175 else:
176 msg = _(
177 "Unable to connect to database:\n\n"
178 "%s\n\n"
179 "Please retry with proper credentials or cancel.\n"
180 "\n"
181 "For the public and any new GNUmed databases the\n"
182 "default user name and password are {any-doc, any-doc}.\n"
183 "\n"
184 'You may also need to check the PostgreSQL client\n'
185 'authentication configuration in pg_hba.conf. For\n'
186 'details see:\n'
187 '\n'
188 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
189 )
190 msg = msg % e
191 msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg)
192 gmGuiHelpers.gm_show_error (
193 msg,
194 _('Connecting to backend')
195 )
196 del e
197 continue
198
199 except gmPG2.dbapi.OperationalError as exc:
200 exc = gmPG2.make_pg_exception_fields_unicode(exc)
201 _log.error("login attempt failed: %s", exc)
202 msg = _(
203 "Unable to connect to database:\n\n"
204 "%s\n\n"
205 "Please retry another backend / user / password combination !\n"
206 "\n"
207 " (for the public and any new GNUmed databases\n"
208 " the default user name and password are\n"
209 " {any-doc, any-doc})\n"
210 "\n"
211 ) % exc.u_pgerror
212
213 msg = regex.sub(r'password=[^\s]+', 'password=%s' % gmTools.u_replacement_character, msg)
214 gmGuiHelpers.gm_show_error (
215 msg,
216 _('Connecting to backend')
217 )
218 del exc
219 continue
220
221 conn.close()
222
223
224 gmPG2.set_default_login(login = login)
225 gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding)
226
227 seems_bootstrapped = gmPG2.schema_exists(schema = 'gm')
228 if not seems_bootstrapped:
229 _log.error('schema [gm] does not exist - database not bootstrapped ?')
230 msg = _(
231 'The database you connected to does not seem\n'
232 'to have been boostrapped properly.\n'
233 '\n'
234 'Make sure you have run the GNUmed database\n'
235 'bootstrapper tool to create a new database.\n'
236 '\n'
237 'Further help can be found on the website at\n'
238 '\n'
239 ' http://wiki.gnumed.de\n'
240 '\n'
241 'or on the GNUmed mailing list.'
242 )
243 gmGuiHelpers.gm_show_error(msg, _('Verifying database'))
244 connected = False
245 break
246
247 compatible = gmPG2.database_schema_compatible(version = expected_version)
248 if compatible or not require_version:
249 dlg.panel.save_state()
250
251 if not compatible:
252 connected_db_version = gmPG2.get_schema_version()
253 msg = msg_generic % (
254 client_version,
255 connected_db_version,
256 expected_version,
257 gmTools.coalesce(login.host, '<localhost>'),
258 login.database,
259 login.user
260 )
261 if require_version:
262 gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version'))
263 connected = False
264 continue
265 gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version'))
266
267
268 max_skew = 1
269 if _cfg.get(option = 'debug'):
270 max_skew = 10
271 if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)):
272 if _cfg.get(option = 'debug'):
273 gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings'))
274 else:
275 gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings'))
276 connected = False
277 continue
278
279 sanity_level, message = gmPG2.sanity_check_database_settings()
280 if sanity_level != 0:
281 gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings'))
282 if sanity_level == 2:
283 connected = False
284 continue
285
286 gmExceptionHandlingWidgets.set_is_public_database(login.public_db)
287 gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk)
288
289 conn = gmPG2.get_connection(verbose = True, connection_name = 'GNUmed-[DbListenerThread]', pooled = False)
290 listener = gmBackendListener.gmBackendListener(conn = conn)
291 break
292
293 dlg.Destroy()
294
295 return connected
296
297
299 if procedure is None:
300 procedure = _('<restricted procedure>')
301
302
303 if dbo_password is None:
304 dbo_password = wx.GetPasswordFromUser (
305 message = _("""
306 [%s]
307
308 This is a restricted procedure. We need the
309 current password for the GNUmed database owner.
310
311 Please enter the current password for <%s>:""") % (
312 procedure,
313 dbo_account
314 ),
315 caption = procedure
316 )
317 if dbo_password == '':
318 return None
319
320 gmLog2.add_word2hide(dbo_password)
321
322
323 login = gmPG2.get_default_login()
324 dsn = gmPG2.make_psycopg2_dsn (
325 database = login.database,
326 host = login.host,
327 port = login.port,
328 user = dbo_account,
329 password = dbo_password
330 )
331 try:
332 conn = gmPG2.get_connection (
333 dsn = dsn,
334 readonly = False,
335 verbose = True,
336 pooled = False
337 )
338 except:
339 _log.exception('cannot connect')
340 gmGuiHelpers.gm_show_error (
341 aMessage = _('Cannot connect as the GNUmed database owner <%s>.') % dbo_account,
342 aTitle = procedure
343 )
344 gmPG2.log_database_access(action = 'failed to connect as database owner for [%s]' % procedure)
345 return None
346
347 return conn
348
349
351
352 title = _('Changing GNUmed database owner password')
353
354 dbo_account = wx.GetTextFromUser (
355 message = _("Enter the account name of the GNUmed database owner:"),
356 caption = title,
357 default_value = ''
358 )
359
360 if dbo_account.strip() == '':
361 return False
362
363 dbo_conn = get_dbowner_connection (
364 procedure = title,
365 dbo_account = dbo_account
366 )
367 if dbo_conn is None:
368 return False
369
370 dbo_pwd_new_1 = wx.GetPasswordFromUser (
371 message = _("Enter the NEW password for the GNUmed database owner:"),
372 caption = title
373 )
374 if dbo_pwd_new_1.strip() == '':
375 return False
376
377 gmLog2.add_word2hide(dbo_pwd_new_1)
378
379 dbo_pwd_new_2 = wx.GetPasswordFromUser (
380 message = _("""Enter the NEW password for the GNUmed database owner, again.
381
382 (This will protect you from typos.)
383 """),
384 caption = title
385 )
386 if dbo_pwd_new_2.strip() == '':
387 return False
388
389 if dbo_pwd_new_1 != dbo_pwd_new_2:
390 return False
391
392
393
394 """ On Mon, Mar 13, 2017 at 12:19:22PM -0400, Tom Lane wrote:
395 > Date: Mon, 13 Mar 2017 12:19:22 -0400
396 > From: Tom Lane <tgl@sss.pgh.pa.us>
397 > To: Adrian Klaver <adrian.klaver@aklaver.com>
398 > cc: Schmid Andreas <Andreas.Schmid@bd.so.ch>,
399 > "'pgsql-general@postgresql.org'" <pgsql-general@postgresql.org>
400 > Subject: Re: [GENERAL] createuser: How to specify a database to connect to
401 >
402 > Adrian Klaver <adrian.klaver@aklaver.com> writes:
403 > > On 03/13/2017 08:52 AM, Tom Lane wrote:
404 > >> If by "history" you're worried about the server-side statement log, this
405 > >> is merest fantasy: the createuser program is not magic, it just constructs
406 > >> and sends a CREATE USER command for you. You'd actually be more secure
407 > >> using psql, where (if you're superuser) you could shut off log_statement
408 > >> for your session first.
409 >
410 > > There is a difference though:
411 >
412 > > psql> CREATE USER:
413 >
414 > > postgres-2017-03-13 09:03:27.147 PDT-0LOG: statement: create user
415 > > dummy_user with login password '1234';
416 >
417 > Well, what you're supposed to do is
418 >
419 > postgres=# create user dummy_user;
420 > postgres=# \password dummy_user
421 > Enter new password:
422 > Enter it again:
423 > postgres=#
424 >
425 > which will result in sending something like
426 >
427 > ALTER USER dummy_user PASSWORD 'md5c5e9567bc40082671d02c654260e0e09'
428 >
429 > You can additionally protect that by wrapping it into one transaction
430 > (if you have a setup where the momentary existence of the role without a
431 > password would be problematic) and/or shutting off logging beforehand.
432 """
433
434
435 cmd = """ALTER ROLE "%s" ENCRYPTED PASSWORD '%s';""" % (
436 dbo_account,
437 dbo_pwd_new_2
438 )
439 gmPG2.run_rw_queries(link_obj = dbo_conn, queries = [{'cmd': cmd}], end_tx = True)
440
441 return True
442
443
446
447
449 """cLoginDialog - window holding cLoginPanel"""
450
451 - def __init__(self, parent, id, title = _("Welcome to"), client_version = '*** unknown ***'):
458
459
461 """GUI panel class that interactively gets Postgres login parameters.
462
463 It features combo boxes which "remember" any number of
464 previously entered settings.
465 """
466 - def __init__(self, parent, id,
467 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.TAB_TRAVERSAL,
468 isDialog = 0, client_version = '*** unknown ***'):
469 """Create login panel.
470
471 isDialog: if this panel is the main panel of a dialog, the panel will
472 resize the dialog automatically to display everything neatly
473 if isDialog is set to True
474 """
475 wx.Panel.__init__(self, parent, id, pos, size, style)
476 self.parent = parent
477
478
479
480 self.cancelled = True
481
482
483 self.isDialog = isDialog
484
485 self.topsizer = wx.BoxSizer(wx.VERTICAL)
486
487
488 paths = gmTools.gmPaths(app_name = 'gnumed', wx = wx)
489 bitmap = os.path.join(paths.system_app_data_dir, 'bitmaps', 'gnumedlogo.png')
490 try:
491 png = wx.Image(bitmap, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
492 bmp = wx.StaticBitmap(self, -1, png, wx.Point(10, 10), wx.Size(png.GetWidth(), png.GetHeight()))
493 self.topsizer.Add (
494 bmp,
495 proportion = 0,
496 flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL,
497 border = 10
498 )
499 except:
500 self.topsizer.Add (
501 wx.StaticText (
502 self,
503 -1,
504 label = _("Cannot find image") + bitmap,
505 style = wx.ALIGN_CENTRE
506 ),
507 proportion = 0,
508 flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL,
509 border = 10
510 )
511
512 paramsbox_caption = _('Workplace "%s" (version %s)') % (gmPraxis.gmCurrentPraxisBranch().active_workplace, client_version)
513
514
515 self.paramsbox = wx.StaticBox( self, -1, paramsbox_caption, style = wx.ALIGN_CENTRE_HORIZONTAL)
516 self.paramsboxsizer = wx.StaticBoxSizer( self.paramsbox, wx.VERTICAL )
517 self.paramsbox.SetForegroundColour(wx.Colour(35, 35, 142))
518 self.paramsbox.SetFont(wx.Font(
519 pointSize = 12,
520 family = wx.SWISS,
521 style = wx.NORMAL,
522 weight = wx.BOLD,
523 underline = False
524 ))
525 self.pboxgrid = wx.FlexGridSizer(5, 2, 5, 5)
526 self.pboxgrid.AddGrowableCol(1)
527
528
529 label = wx.StaticText( self, -1, _('Log into'), wx.DefaultPosition, wx.DefaultSize, 0)
530 label.SetForegroundColour(wx.Colour(35, 35, 142))
531 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
532 self.__backend_profiles = self.__get_backend_profiles()
533 self._CBOX_profile = wx.ComboBox (
534 self,
535 -1,
536 list(self.__backend_profiles.keys())[0],
537 wx.DefaultPosition,
538 size = wx.Size(550,-1),
539 choices = list(self.__backend_profiles.keys()),
540 style = wx.CB_READONLY
541 )
542 self.pboxgrid.Add (self._CBOX_profile, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
543
544
545 label = wx.StaticText( self, -1, _("Username"), wx.DefaultPosition, wx.DefaultSize, 0 )
546 label.SetForegroundColour(wx.Colour(35, 35, 142))
547 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
548 self.__previously_used_accounts = self.__get_previously_used_accounts()
549 self._CBOX_user = wx.ComboBox (
550 self,
551 -1,
552 self.__previously_used_accounts[0],
553 wx.DefaultPosition,
554 wx.Size(150,-1),
555 self.__previously_used_accounts,
556 wx.CB_DROPDOWN
557 )
558 self.pboxgrid.Add( self._CBOX_user, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
559
560
561 label = wx.StaticText( self, -1, _("Password"), wx.DefaultPosition, wx.DefaultSize, 0 )
562 label.SetForegroundColour(wx.Colour(35, 35, 142))
563 self.pboxgrid.Add( label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
564 self.pwdentry = wx.TextCtrl( self, 1, '', wx.DefaultPosition, wx.Size(80,-1), wx.TE_PASSWORD )
565
566 self.pwdentry.SetFocus()
567 self.pboxgrid.Add( self.pwdentry, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
568
569
570 label = wx.StaticText(self, -1, _('Options'), wx.DefaultPosition, wx.DefaultSize, 0)
571 label.SetForegroundColour(wx.Colour(35, 35, 142))
572 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
573 self._CHBOX_debug = wx.CheckBox(self, -1, _('&Debug mode'))
574 self._CHBOX_debug.SetToolTip(_('Check this to run GNUmed client in debugging mode.'))
575 self.pboxgrid.Add(self._CHBOX_debug, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
576
577
578 label = wx.StaticText(self, -1, '', wx.DefaultPosition, wx.DefaultSize, 0)
579 label.SetForegroundColour(wx.Colour(35, 35, 142))
580 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
581 self._CHBOX_slave = wx.CheckBox(self, -1, _('Enable &remote control'))
582 self._CHBOX_slave.SetToolTip(_('Check this to run GNUmed client in slave mode for remote control.'))
583 self.pboxgrid.Add(self._CHBOX_slave, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
584
585
586
587
588
589
590
591
592
593
594
595
596
597 self.button_gridsizer = wx.GridSizer(1,3,0,0)
598
599
600
601 ID_BUTTON_LOGIN = wx.NewId()
602 button_login_ok = wx.Button(self, ID_BUTTON_LOGIN, _("&Ok"), wx.DefaultPosition, wx.DefaultSize, 0 )
603 button_login_ok.SetToolTip(wx.ToolTip(_("Proceed with login.")) )
604 button_login_ok.SetDefault()
605
606
607
608
609 ID_BUTTON_CANCEL = wx.NewId()
610 button_cancel = wx.Button(self, ID_BUTTON_CANCEL, _("&Cancel"), wx.DefaultPosition, wx.DefaultSize, 0 )
611 button_cancel.SetToolTip(wx.ToolTip(_("Cancel Login.")) )
612
613
614
615 ID_BUTTON_HELP = wx.NewId()
616 button_help = wx.Button(self, ID_BUTTON_HELP, _("&Help"), wx.DefaultPosition, wx.DefaultSize, 0 )
617 button_help.SetToolTip(wx.ToolTip(_("Help for login screen")))
618
619
620
621 self.button_gridsizer.Add (button_help,0,wx.EXPAND|wx.ALL,5)
622 self.button_gridsizer.Add (button_login_ok,0,wx.EXPAND|wx.ALL,5)
623 self.button_gridsizer.Add (button_cancel,0,wx.EXPAND|wx.ALL,5)
624
625 self.paramsboxsizer.Add(self.pboxgrid, 1, wx.GROW|wx.ALL, 10)
626 self.topsizer.Add(self.paramsboxsizer, 1, wx.GROW|wx.ALL, 10)
627 self.topsizer.Add( self.button_gridsizer, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
628
629 self.__load_state()
630
631 self.SetAutoLayout(True)
632 self.SetSizer( self.topsizer)
633 self.topsizer.Fit( self )
634 if self.isDialog:
635 self.topsizer.SetSizeHints(parent)
636
637 button_help.Bind(wx.EVT_BUTTON, self.OnHelp)
638 button_login_ok.Bind(wx.EVT_BUTTON, self.__on_login_button_pressed)
639 button_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
640
641
642
643
644
645
646
648
649 accounts = gmTools.coalesce (
650 _cfg.get (
651 group = 'backend',
652 option = 'logins',
653 source_order = [
654 ('explicit', 'extend'),
655 ('user', 'extend'),
656 ('workbase', 'extend')
657 ]
658 ),
659 ['any-doc']
660 )
661
662
663 return accounts
664
666 """Get server profiles from the configuration files.
667
668 1) from system-wide file
669 2) from user file
670
671 Profiles in the user file which have the same name
672 as a profile in the system file will override the
673 system file.
674 """
675
676 src_order = [
677 ('explicit', 'extend'),
678 ('system', 'extend'),
679 ('user', 'extend'),
680 ('workbase', 'extend')
681 ]
682
683 profile_names = gmTools.coalesce (
684 _cfg.get(group = 'backend', option = 'profiles', source_order = src_order),
685 []
686 )
687
688
689 src_order = [
690 ('explicit', 'return'),
691 ('workbase', 'return'),
692 ('user', 'return'),
693 ('system', 'return')
694 ]
695
696 profiles = {}
697
698 for profile_name in profile_names:
699
700
701 profile = cBackendProfile()
702 profile_section = 'profile %s' % profile_name
703
704 profile.name = profile_name
705 profile.host = gmTools.coalesce(_cfg.get(profile_section, 'host', src_order), '').strip()
706 port = gmTools.coalesce(_cfg.get(profile_section, 'port', src_order), 5432)
707 try:
708 profile.port = int(port)
709 if profile.port < 1024:
710 raise ValueError('refusing to use priviledged port (< 1024)')
711 except ValueError:
712 _log.warning('invalid port definition: [%s], skipping profile [%s]', port, profile_name)
713 continue
714 profile.database = gmTools.coalesce(_cfg.get(profile_section, 'database', src_order), '').strip()
715 if profile.database == '':
716 _log.warning('database name not specified, skipping profile [%s]', profile_name)
717 continue
718 profile.encoding = gmTools.coalesce(_cfg.get(profile_section, 'encoding', src_order), 'UTF8')
719 profile.public_db = bool(_cfg.get(profile_section, 'public/open access', src_order))
720 profile.helpdesk = _cfg.get(profile_section, 'help desk', src_order)
721
722 label = '%s (%s@%s)' % (profile_name, profile.database, profile.host)
723 profiles[label] = profile
724
725
726
727 if not (_cfg.get(option = 'debug') or current_db_name.endswith('_devel')):
728 profiles2remove = []
729 for label in profiles:
730 if profiles[label].database != current_db_name:
731 profiles2remove.append(label)
732 for label in profiles2remove:
733 del profiles[label]
734
735 if len(profiles) == 0:
736 host = 'publicdb.gnumed.de'
737 label = 'public GNUmed database (%s@%s)' % (current_db_name, host)
738 profiles[label] = cBackendProfile()
739 profiles[label].name = label
740 profiles[label].host = host
741 profiles[label].port = 5432
742 profiles[label].database = current_db_name
743 profiles[label].encoding = 'UTF8'
744 profiles[label].public_db = True
745 profiles[label].helpdesk = 'http://wiki.gnumed.de'
746
747 return profiles
748
750
751 src_order = [
752 ('explicit', 'return'),
753 ('user', 'return'),
754 ]
755
756 self._CBOX_user.SetValue (
757 gmTools.coalesce (
758 _cfg.get('preferences', 'login', src_order),
759 self.__previously_used_accounts[0]
760 )
761 )
762
763 last_used_profile_label = _cfg.get('preferences', 'profile', src_order)
764 if last_used_profile_label in self.__backend_profiles.keys():
765 self._CBOX_profile.SetValue(last_used_profile_label)
766 else:
767 self._CBOX_profile.SetValue(list(self.__backend_profiles.keys())[0])
768
769 self._CHBOX_debug.SetValue(_cfg.get(option = 'debug'))
770 self._CHBOX_slave.SetValue(_cfg.get(option = 'slave'))
771
790
791
792
794 """convenience function for compatibility with gmLoginInfo.LoginInfo"""
795 if self.cancelled:
796 return None
797
798
799 profile = self.__backend_profiles[self._CBOX_profile.GetValue().strip()]
800 _log.info('backend profile "%s" selected', profile.name)
801 _log.info(' details: <%s> on %s@%s:%s (%s, %s)',
802 self._CBOX_user.GetValue(),
803 profile.database,
804 profile.host,
805 profile.port,
806 profile.encoding,
807 gmTools.bool2subst(profile.public_db, 'public', 'private')
808 )
809 _log.info(' helpdesk: "%s"', profile.helpdesk)
810 login = gmLoginInfo.LoginInfo (
811 user = self._CBOX_user.GetValue(),
812 password = self.pwdentry.GetValue(),
813 host = profile.host,
814 database = profile.database,
815 port = profile.port
816 )
817 login.public_db = profile.public_db
818 login.helpdesk = profile.helpdesk
819 login.backend_profile = profile.name
820 return login
821
822
823
825 praxis = gmPraxis.gmCurrentPraxisBranch()
826 wx.MessageBox(_(
827 """Unable to connect to the database ?
828
829 "PostgreSQL: FATAL: password authentication failed ..."
830
831 The default user name and password are {any-doc, any-doc}
832 for the public and any new GNUmed databases.
833
834 "... could not connect to server ..."
835
836 Mostly this is a case of new users who did not yet install
837 or configure a PostgreSQL server and/or a GNUmed database
838 of their own, which you must do before you can connect to
839 anything other than the public demonstration database, see
840
841 http://wiki.gnumed.de/bin/view/Gnumed/GmManualServerInstall
842
843 For assistance on using GNUmed please consult the wiki:
844
845 http://wiki.gnumed.de/bin/view/Gnumed/GnumedManual
846
847 For more help than the above, please contact:
848
849 GNUmed Development List <gnumed-bugs@gnu.org>
850
851 For local assistance please contact:
852
853 %s""") % praxis.helpdesk,
854 caption = _('HELP for GNUmed main login screen'))
855
856
884
888
889
890
891
892 if __name__ == "__main__":
893
894 if len(sys.argv) < 2:
895 sys.exit()
896
897 if sys.argv[1] != 'test':
898 sys.exit()
899
900
901 sys.exit()
902
903 from Gnumed.pycommon import gmI18N
904
905 logging.basicConfig(level = logging.DEBUG)
906
907 gmI18N.activate_locale()
908 gmI18N.install_domain(domain='gnumed')
909
910
912 app = wx.PyWidgetTester(size = (300,400))
913
914
915
916 dlg = cLoginDialog(None, -1)
917 dlg.ShowModal()
918
919 lp = dlg.panel.GetLoginInfo()
920 if lp is None:
921 wx.MessageBox(_("Dialog was cancelled by user"))
922 else:
923 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()))
924 dlg.Destroy()
925
926
927
928