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