| Home | Trees | Indices | Help |
|
|---|
|
|
1 #!/usr/bin/env python
2
3 __doc__ = """GNUmed web client launcher.
4 """
5 #==========================================================
6 # $Source: /home/ncq/Projekte/cvs2git/vcs-mirror/gnumed/gnumed/client/wxpython/gnumed.py,v $
7 # $Id: gnumed.py,v 1.169 2010-01-31 18:20:41 ncq Exp $
8 __version__ = "$Revision: 1 $"
9 __author__ = "S. Hilbert <Sebastian.Hilbert@gmx.net>"
10 __license__ = "GPL (details at http://www.gnu.org)"
11
12 import cherrypy
13
14 # stdlib
15 import sys, time, os, cPickle, zlib, locale, os.path, datetime as pyDT, webbrowser, shutil, logging, urllib2
16
17 # GNUmed libs
18 from Gnumed.pycommon import gmI18N, gmTools, gmDateTime, gmHooks
19 from Gnumed.pycommon import gmLoginInfo, gmPG2, gmBackendListener, gmTools, gmCfg2, gmI18N, gmDispatcher
20
21 from Gnumed.business import gmDocuments
22
23 #try:
24 # _('dummy-no-need-to-translate-but-make-epydoc-happy')
25 #except NameError:
26 # _ = lambda x:x
27
28 _cfg = gmCfg2.gmCfgData()
29 _provider = None
30 _scripting_listener = None
31
32 _log = logging.getLogger('gm.main')
33 _log.info(__version__)
34 _log.info('web GUI framework')
35
36 #================================================================
37 # convenience functions
38 #----------------------------------------------------------------
39 -def connect_to_database(login_info=None, max_attempts=3, expected_version=None, require_version=True):
40 """Display the login dialog and try to log into the backend.
41
42 - up to max_attempts times
43 - returns True/False
44 """
45 # force programmer to set a valid expected_version
46 expected_hash = gmPG2.known_schema_hashes[expected_version]
47 client_version = _cfg.get(option = u'client_version')
48 global current_db_name
49 current_db_name = u'gnumed_%s' % expected_version
50
51 attempt = 0
52
53 while attempt < max_attempts:
54
55 _log.debug('login attempt %s of %s', (attempt+1), max_attempts)
56
57 connected = False
58
59 login = login_info
60 if login is None:
61 _log.info("did not provide a login information")
62
63 # try getting a connection to verify the DSN works
64 dsn = gmPG2.make_psycopg2_dsn (
65 database = login.database,
66 host = login.host,
67 port = login.port,
68 user = login.user,
69 password = login.password
70 )
71 try:
72 conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
73 connected = True
74
75 except gmPG2.cAuthenticationError, e:
76 attempt += 1
77 _log.error(u"login attempt failed: %s", e)
78 if attempt < max_attempts:
79 if (u'host=127.0.0.1' in (u'%s' % e)) or (u'host=' not in (u'%s' % e)):
80 msg = _(
81 'Unable to connect to database:\n\n'
82 '%s\n\n'
83 "Are you sure you have got a local database installed ?\n"
84 '\n'
85 "Please retry with proper credentials or cancel.\n"
86 '\n'
87 'You may also need to check the PostgreSQL client\n'
88 'authentication configuration in pg_hba.conf. For\n'
89 'details see:\n'
90 '\n'
91 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
92 )
93 else:
94 msg = _(
95 "Unable to connect to database:\n\n"
96 "%s\n\n"
97 "Please retry with proper credentials or cancel.\n"
98 "\n"
99 'You may also need to check the PostgreSQL client\n'
100 'authentication configuration in pg_hba.conf. For\n'
101 'details see:\n'
102 '\n'
103 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
104 )
105 msg = msg % e
106 msg = regex.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
107 gmGuiHelpers.gm_show_error (
108 msg,
109 _('Connecting to backend')
110 )
111 del e
112 continue
113
114 except gmPG2.dbapi.OperationalError, e:
115 _log.error(u"login attempt failed: %s", e)
116 msg = _(
117 "Unable to connect to database:\n\n"
118 "%s\n\n"
119 "Please retry another backend / user / password combination !\n"
120 ) % gmPG2.extract_msg_from_pg_exception(e)
121 msg = regex.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
122 gmGuiHelpers.gm_show_error (
123 msg,
124 _('Connecting to backend')
125 )
126 del e
127 continue
128
129 # connect was successful
130 gmPG2.set_default_login(login = login)
131 #gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding)
132
133 # compatible = gmPG2.database_schema_compatible(version = expected_version)
134 # if compatible or not require_version:
135 #dlg.panel.save_state()
136 # continue
137
138 # if not compatible:
139 # connected_db_version = gmPG2.get_schema_version()
140 # msg = msg_generic % (
141 # client_version,
142 # connected_db_version,
143 # expected_version,
144 # gmTools.coalesce(login.host, '<localhost>'),
145 # login.database,
146 # login.user
147 # )
148
149 # if require_version:
150 # gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version'))
151 # pass
152 #gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version'))
153
154 # # FIXME: make configurable
155 # max_skew = 1 # minutes
156 # if _cfg.get(option = 'debug'):
157 # max_skew = 10
158 # if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)):
159 # if _cfg.get(option = 'debug'):
160 # gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings'))
161 # else:
162 # gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings'))
163 # continue
164
165 # sanity_level, message = gmPG2.sanity_check_database_settings()
166 # if sanity_level != 0:
167 # gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings'))
168 # if sanity_level == 2:
169 # continue
170
171 # gmExceptionHandlingWidgets.set_is_public_database(login.public_db)
172 # gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk)
173
174 listener = gmBackendListener.gmBackendListener(conn = conn)
175 break
176
177 #dlg.Destroy()
178
179 return connected
180
181 #----------------------------------------------------------------------------
182 #internal helper functions
183 #----------------------------------------------------
185 """Get server profiles from the configuration files.
186
187 1) from system-wide file
188 2) from user file
189
190 Profiles in the user file which have the same name
191 as a profile in the system file will override the
192 system file.
193 """
194 # find active profiles
195 src_order = [
196 (u'explicit', u'extend'),
197 (u'system', u'extend'),
198 (u'user', u'extend'),
199 (u'workbase', u'extend')
200 ]
201
202 profile_names = gmTools.coalesce (
203 _cfg.get(group = u'backend', option = u'profiles', source_order = src_order),
204 []
205 )
206
207 # find data for active profiles
208 src_order = [
209 (u'explicit', u'return'),
210 (u'workbase', u'return'),
211 (u'user', u'return'),
212 (u'system', u'return')
213 ]
214
215 profiles = {}
216
217 for profile_name in profile_names:
218 # FIXME: once the profile has been found always use the corresponding source !
219 # FIXME: maybe not or else we cannot override parts of the profile
220 profile = cBackendProfile()
221 profile_section = 'profile %s' % profile_name
222
223 profile.name = profile_name
224 profile.host = gmTools.coalesce(_cfg.get(profile_section, u'host', src_order), u'').strip()
225 port = gmTools.coalesce(_cfg.get(profile_section, u'port', src_order), 5432)
226 try:
227 profile.port = int(port)
228 if profile.port < 1024:
229 raise ValueError('refusing to use priviledged port (< 1024)')
230 except ValueError:
231 _log.warning('invalid port definition: [%s], skipping profile [%s]', port, profile_name)
232 continue
233 profile.database = gmTools.coalesce(_cfg.get(profile_section, u'database', src_order), u'').strip()
234 if profile.database == u'':
235 _log.warning('database name not specified, skipping profile [%s]', profile_name)
236 continue
237 profile.encoding = gmTools.coalesce(_cfg.get(profile_section, u'encoding', src_order), u'UTF8')
238 profile.public_db = bool(_cfg.get(profile_section, u'public/open access', src_order))
239 profile.helpdesk = _cfg.get(profile_section, u'help desk', src_order)
240
241 label = u'%s (%s@%s)' % (profile_name, profile.database, profile.host)
242 profiles[label] = profile
243
244 # sort out profiles with incompatible database versions if not --debug
245 # NOTE: this essentially hardcodes the database name in production ...
246 if not (_cfg.get(option = 'debug') or current_db_name.endswith('_devel')):
247 profiles2remove = []
248 for label in profiles:
249 if profiles[label].database != current_db_name:
250 profiles2remove.append(label)
251 for label in profiles2remove:
252 del profiles[label]
253
254 if len(profiles) == 0:
255 host = u'salaam.homeunix.com'
256 label = u'public GNUmed database (%s@%s)' % (current_db_name, host)
257 profiles[label] = cBackendProfile()
258 profiles[label].name = label
259 profiles[label].host = host
260 profiles[label].port = 5432
261 profiles[label].database = current_db_name
262 profiles[label].encoding = u'UTF8'
263 profiles[label].public_db = True
264 profiles[label].helpdesk = u'http://wiki.gnumed.de'
265
266 return profiles
267
268 # ------------------------------------------------------------
270
271 # username is provided through the web interface
272 # password is provided
273 # we need the profile
274
275 """convenience function for compatibility with gmLoginInfo.LoginInfo"""
276 #if not self.cancelled:
277 # FIXME: do not assume conf file is latin1 !
278 #profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()]
279 #self.__backend_profiles = self.__get_backend_profiles()
280 __backend_profiles = __get_backend_profiles()
281 profile = __backend_profiles[backend.encode('utf8').strip()]
282
283 _log.debug(u'backend profile "%s" selected', profile.name)
284 _log.debug(u' details: <%s> on %s@%s:%s (%s, %s)',
285 username,
286 profile.database,
287 profile.host,
288 profile.port,
289 profile.encoding,
290 gmTools.bool2subst(profile.public_db, u'public', u'private')
291 )
292 #_log.debug(u' helpdesk: "%s"', profile.helpdesk)
293 login = gmLoginInfo.LoginInfo (
294 user = username,
295 password = password,
296 host = profile.host,
297 database = profile.database,
298 port = profile.port
299 )
300 #login.public_db = profile.public_db
301 #login.helpdesk = profile.helpdesk
302 return login
303
304 #----------------------------------------------
306 try:
307 kwargs['originated_in_database']
308 print '==> got notification from database "%s":' % kwargs['signal']
309 except KeyError:
310 print '==> received signal from client: "%s"' % kwargs['signal']
311
312 del kwargs['signal']
313 for key in kwargs.keys():
314 print ' [%s]: %s' % (key, kwargs[key])
315
316 #================================================================
319
320 #================================================================
322
324 msg = 'schema version is:' + gmPG2.get_schema_version() +'\n\n'
325 msg2 =''
326 for item in gmDocuments.get_document_types():
327 msg2 = msg2 +'\n' + str(item)
328 msg = msg + msg2
329 return msg
330
332 login_info = GetLoginInfo(username, password, backend)
333 override = _cfg.get(option = '--override-schema-check', source_order = [('cli', 'return')])
334 connected = connect_to_database (
335 login_info,
336 expected_version = gmPG2.map_client_branch2required_db_version[_cfg.get(option = 'client_branch')],
337 require_version = not override
338 )
339 msg = self.doSomething()
340 return msg
341
342 doLogin.exposed = True
343
344 # ------------------------------------------------------------
346 # backend is hardcoded for now, make it use drop down list later
347 return """
348 <form action="doLogin" method="post">
349 <p>Backend</p>
350 <input type="text" name="backend" value="GNUmed database on this machine (Linux/Mac) (gnumed_v14@)"
351 size="15" maxlength="40"/>
352 <p>Username</p>
353 <input type="text" name="username" value=""
354 size="15" maxlength="40"/>
355 <p>Password</p>
356 <input type="password" name="password" value=""
357 size="10" maxlength="40"/>
358 <p><input type="submit" value="Login"/></p>
359 <p><input type="reset" value="Clear"/></p>
360 </form>
361 """
362 index.exposed = True
363
364 #==========================================================
365 # main - launch the GNUmed web client
366 #----------------------------------------------------------
367
375
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Jun 28 04:11:52 2010 | http://epydoc.sourceforge.net |