| Home | Trees | Indices | Help |
|
|---|
|
|
1 #!/usr/bin/env python
2
3 __doc__ = """GNUmed web user interface server launcher.
4 """
5 #==========================================================
6 __version__ = "$Revision: 0.1 $"
7 __author__ = "S. Hilbert <Sebastian.Hilbert@gmx.net>"
8 __license__ = "GPL (details at http://www.gnu.org)"
9
10 # stdlib
11 import re, sys, time, os, cPickle, zlib, locale, os.path
12 import datetime as pyDT, webbrowser, shutil, logging, urllib2
13
14 # json-rpc
15 from jsonserver import SimpleForkingJSONRPCServer, CloseConnection
16
17 # GNUmed libs
18 from Gnumed.pycommon import gmI18N, gmTools, gmDateTime, gmHooks
19 from Gnumed.pycommon import gmLoginInfo, gmBackendListener, gmTools, gmCfg2
20 from Gnumed.pycommon import gmCfg2, gmI18N, gmDispatcher, gmBusinessDBObject
21 from Gnumed.pycommon.gmBusinessDBObject import jsonclasshintify
22 from Gnumed.pycommon import gmPG2
23 from Gnumed.business import gmDocuments
24 from Gnumed.business import gmPerson
25 from Gnumed.business import gmProviderInbox
26 from Gnumed.business import gmPersonSearch
27
28 #try:
29 # _('dummy-no-need-to-translate-but-make-epydoc-happy')
30 #except NameError:
31 # _ = lambda x:x
32
33 _cfg = gmCfg2.gmCfgData()
34 _provider = None
35 _scripting_listener = None
36
37 _log = logging.getLogger('gm.main')
38 _log.info(__version__)
39 _log.info('web GUI framework')
40
41 #================================================================
42 # convenience functions
43 #----------------------------------------------------------------
44 -def connect_to_database(login_info=None, max_attempts=3, expected_version=None, require_version=True):
45 """Display the login dialog and try to log into the backend.
46
47 - up to max_attempts times
48 - returns True/False
49 """
50 from Gnumed.pycommon import gmPG2
51 # force programmer to set a valid expected_version
52 expected_hash = gmPG2.known_schema_hashes[expected_version]
53 client_version = _cfg.get(option = u'client_version')
54 global current_db_name
55 current_db_name = u'gnumed_%s' % expected_version
56
57 attempt = 0
58
59 while attempt < max_attempts:
60
61 _log.debug('login attempt %s of %s', (attempt+1), max_attempts)
62
63 connected = False
64
65 login = login_info
66 if login is None:
67 _log.info("did not provide a login information")
68
69 # try getting a connection to verify the DSN works
70 dsn = gmPG2.make_psycopg2_dsn (
71 database = login.database,
72 host = login.host,
73 port = login.port,
74 user = login.user,
75 password = login.password
76 )
77 try:
78 #conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
79 conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
80 connected = True
81
82 except gmPG2.cAuthenticationError, e:
83 attempt += 1
84 _log.error(u"login attempt failed: %s", e)
85 if attempt < max_attempts:
86 if (u'host=127.0.0.1' in (u'%s' % e)) or (u'host=' not in (u'%s' % e)):
87 msg = _(
88 'Unable to connect to database:\n\n'
89 '%s\n\n'
90 "Are you sure you have got a local database installed ?\n"
91 '\n'
92 "Please retry with proper credentials or cancel.\n"
93 '\n'
94 'You may also need to check the PostgreSQL client\n'
95 'authentication configuration in pg_hba.conf. For\n'
96 'details see:\n'
97 '\n'
98 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
99 )
100 else:
101 msg = _(
102 "Unable to connect to database:\n\n"
103 "%s\n\n"
104 "Please retry with proper credentials or cancel.\n"
105 "\n"
106 'You may also need to check the PostgreSQL client\n'
107 'authentication configuration in pg_hba.conf. For\n'
108 'details see:\n'
109 '\n'
110 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
111 )
112 msg = msg % e
113 msg = re.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
114 gmGuiHelpers.gm_show_error (
115 msg,
116 _('Connecting to backend')
117 )
118 del e
119 continue
120
121 except gmPG2.dbapi.OperationalError, e:
122 _log.error(u"login attempt failed: %s", e)
123 msg = _(
124 "Unable to connect to database:\n\n"
125 "%s\n\n"
126 "Please retry another backend / user / password combination !\n"
127 ) % gmPG2.extract_msg_from_pg_exception(e)
128 msg = re.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
129 gmGuiHelpers.gm_show_error (
130 msg,
131 _('Connecting to backend')
132 )
133 del e
134 continue
135
136 # connect was successful
137 gmPG2.set_default_login(login = login)
138 #gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding)
139
140 # compatible = gmPG2.database_schema_compatible(version = expected_version)
141 # if compatible or not require_version:
142 #dlg.panel.save_state()
143 # continue
144
145 # if not compatible:
146 # connected_db_version = gmPG2.get_schema_version()
147 # msg = msg_generic % (
148 # client_version,
149 # connected_db_version,
150 # expected_version,
151 # gmTools.coalesce(login.host, '<localhost>'),
152 # login.database,
153 # login.user
154 # )
155
156 # if require_version:
157 # gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version'))
158 # pass
159 #gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version'))
160
161 # # FIXME: make configurable
162 # max_skew = 1 # minutes
163 # if _cfg.get(option = 'debug'):
164 # max_skew = 10
165 # if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)):
166 # if _cfg.get(option = 'debug'):
167 # gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings'))
168 # else:
169 # gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings'))
170 # continue
171
172 # sanity_level, message = gmPG2.sanity_check_database_settings()
173 # if sanity_level != 0:
174 # gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings'))
175 # if sanity_level == 2:
176 # continue
177
178 # gmExceptionHandlingWidgets.set_is_public_database(login.public_db)
179 # gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk)
180
181 listener = gmBackendListener.gmBackendListener(conn = conn)
182 break
183
184 #dlg.Destroy()
185
186 return connected
187
188 #----------------------------------------------------------------------------
189 #internal helper functions
190 #----------------------------------------------------
192 """Get server profiles from the configuration files.
193
194 1) from system-wide file
195 2) from user file
196
197 Profiles in the user file which have the same name
198 as a profile in the system file will override the
199 system file.
200 """
201 # find active profiles
202 src_order = [
203 (u'explicit', u'extend'),
204 (u'system', u'extend'),
205 (u'user', u'extend'),
206 (u'workbase', u'extend')
207 ]
208
209 profile_names = gmTools.coalesce (
210 _cfg.get(group = u'backend', option = u'profiles', source_order = src_order),
211 []
212 )
213
214 # find data for active profiles
215 src_order = [
216 (u'explicit', u'return'),
217 (u'workbase', u'return'),
218 (u'user', u'return'),
219 (u'system', u'return')
220 ]
221
222 profiles = {}
223
224 for profile_name in profile_names:
225 # FIXME: once the profile has been found always use the corresponding source !
226 # FIXME: maybe not or else we cannot override parts of the profile
227 profile = cBackendProfile()
228 profile_section = 'profile %s' % profile_name
229
230 profile.name = profile_name
231 profile.host = gmTools.coalesce(_cfg.get(profile_section, u'host', src_order), u'').strip()
232 port = gmTools.coalesce(_cfg.get(profile_section, u'port', src_order), 5432)
233 try:
234 profile.port = int(port)
235 if profile.port < 1024:
236 raise ValueError('refusing to use priviledged port (< 1024)')
237 except ValueError:
238 _log.warning('invalid port definition: [%s], skipping profile [%s]', port, profile_name)
239 continue
240 profile.database = gmTools.coalesce(_cfg.get(profile_section, u'database', src_order), u'').strip()
241 if profile.database == u'':
242 _log.warning('database name not specified, skipping profile [%s]', profile_name)
243 continue
244 profile.encoding = gmTools.coalesce(_cfg.get(profile_section, u'encoding', src_order), u'UTF8')
245 profile.public_db = bool(_cfg.get(profile_section, u'public/open access', src_order))
246 profile.helpdesk = _cfg.get(profile_section, u'help desk', src_order)
247
248 label = u'%s (%s@%s)' % (profile_name, profile.database, profile.host)
249 profiles[label] = profile
250
251 # sort out profiles with incompatible database versions if not --debug
252 # NOTE: this essentially hardcodes the database name in production ...
253 if not (_cfg.get(option = 'debug') or current_db_name.endswith('_devel')):
254 profiles2remove = []
255 for label in profiles:
256 if profiles[label].database != current_db_name:
257 profiles2remove.append(label)
258 for label in profiles2remove:
259 del profiles[label]
260
261 if len(profiles) == 0:
262 host = u'salaam.homeunix.com'
263 label = u'public GNUmed database (%s@%s)' % (current_db_name, host)
264 profiles[label] = cBackendProfile()
265 profiles[label].name = label
266 profiles[label].host = host
267 profiles[label].port = 5432
268 profiles[label].database = current_db_name
269 profiles[label].encoding = u'UTF8'
270 profiles[label].public_db = True
271 profiles[label].helpdesk = u'http://wiki.gnumed.de'
272
273 return profiles
274
275 # ------------------------------------------------------------
277
278 # username is provided through the web interface
279 # password is provided
280 # we need the profile
281
282 """convenience function for compatibility with gmLoginInfo.LoginInfo"""
283 from Gnumed.pycommon import gmLoginInfo
284 #if not self.cancelled:
285 # FIXME: do not assume conf file is latin1 !
286 #profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()]
287 #self.__backend_profiles = self.__get_backend_profiles()
288 __backend_profiles = __get_backend_profiles()
289 profile = __backend_profiles[backend.encode('utf8').strip()]
290
291 _log.debug(u'backend profile "%s" selected', profile.name)
292 _log.debug(u' details: <%s> on %s@%s:%s (%s, %s)',
293 username,
294 profile.database,
295 profile.host,
296 profile.port,
297 profile.encoding,
298 gmTools.bool2subst(profile.public_db, u'public', u'private')
299 )
300 #_log.debug(u' helpdesk: "%s"', profile.helpdesk)
301 login = gmLoginInfo.LoginInfo (
302 user = username,
303 password = password,
304 host = profile.host,
305 database = profile.database,
306 port = profile.port
307 )
308 #login.public_db = profile.public_db
309 #login.helpdesk = profile.helpdesk
310 return login
311
312 #----------------------------------------------
314 try:
315 kwargs['originated_in_database']
316 print '==> got notification from database "%s":' % kwargs['signal']
317 except KeyError:
318 print '==> received signal from client: "%s"' % kwargs['signal']
319
320 del kwargs['signal']
321 for key in kwargs.keys():
322 print ' [%s]: %s' % (key, kwargs[key])
323
324 #================================================================
327
328 #================================================================
329
330
331 PYJSDIR = sys._getframe().f_code.co_filename
332 PYJSDIR = os.path.split(os.path.dirname(PYJSDIR))[0]
333 PYJSDIR = os.path.join(PYJSDIR, 'pyjamas')
334
335 DEFAULT_BACKEND = "GNUmed database on this machine (Linux/Mac) (gnumed_v15@)"
336
338 '''An application instance containing any number of streams. Except for constructor all methods are generators.'''
339 count = 0
341 SimpleForkingJSONRPCServer.__init__(self, ("localhost", 60001))
342
343 self.register_function(self.echo)
344 self.register_function(self.login)
345 self.register_function(self.logout)
346 self.register_function(self.search_patient)
347 self.register_function(self.get_provider_inbox_data)
348 self.register_function(self.get_patient_messages)
349 self.register_function(self.get_doc_types)
350 self.register_function(self.get_documents)
351 self.register_function(self.get_schema_version)
352 self.register_function(self.doSomething)
353
362
364 from Gnumed.pycommon import gmPG2
365 if backend is None:
366 backend = DEFAULT_BACKEND
367 login_info = GetLoginInfo(username, password, backend)
368 override = _cfg.get(option = '--override-schema-check',
369 source_order = [('cli', 'return')])
370 cb = _cfg.get(option = 'client_branch')
371 expected_version = gmPG2.map_client_branch2required_db_version[cb]
372 connected = connect_to_database (
373 login_info,
374 expected_version = expected_version,
375 require_version = not override
376 )
377 return connected
378
383
385
386 self.__person_searcher = gmPersonSearch.cPatientSearcher_SQL()
387 # get list of matching ids
388 idents = self.__person_searcher.get_identities(search_term)
389
390 if idents is None:
391 idents = []
392
393 _log.info("%s matching person(s) found", len(idents))
394
395 # only one matching identity
396 if len(idents) == 1:
397 self.person = idents[0]
398 return jsonclasshintify(self.person)
399
400 # ambiguous - return available choices, to be able to choose from them.
401 self.person = None
402 return jsonclasshintify(idents)
403
405 messages = gmProviderInbox.get_inbox_messages(pk_patient=pk_patient)
406 return jsonclasshintify(messages)
407
409 self.provider = gmPerson.gmCurrentProvider(provider=gmPerson.cStaff())
410 inbox = gmProviderInbox.cProviderInbox()
411 self.__msgs = inbox.messages
412 return jsonclasshintify(inbox.messages)
413
416
418 doc_folder = gmDocuments.cDocumentFolder(aPKey=key)
419 return jsonclasshintify(doc_folder.get_documents())
420
423
425 msg = 'schema version is:' + gmPG2.get_schema_version() +'\n\n'
426 msg2 =''
427 for item in gmDocuments.get_document_types():
428 msg2 = msg2 +'\n' + str(item)
429 msg = msg + msg2
430 return "<pre>%s</pre>" % msg
431
432
433 #==========================================================
434 # main - launch the GNUmed web client
435 #----------------------------------------------------------
436
438
439 if _cfg.get(option = 'debug'):
440 gmDispatcher.connect(receiver = _signal_debugging_monitor)
441 _log.debug('gmDispatcher signal monitor activated')
442
443 server = HTTPServer()
444 server.serve_forever()
445
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Nov 29 04:04:50 2010 | http://epydoc.sourceforge.net |