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