| 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, datetime as pyDT, webbrowser, shutil, logging, urllib2
12
13 # json-rpc
14 from jsonserver import SimpleForkingJSONRPCServer
15
16 # GNUmed libs
17 from Gnumed.pycommon import gmI18N, gmTools, gmDateTime, gmHooks
18 from Gnumed.pycommon import gmLoginInfo, gmBackendListener, gmTools, gmCfg2, gmI18N, gmDispatcher, gmBusinessDBObject
19 from Gnumed.pycommon.gmBusinessDBObject import jsonclasshintify
20 from Gnumed.pycommon import gmPG2
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 from Gnumed.pycommon import gmPG2
46 # force programmer to set a valid expected_version
47 expected_hash = gmPG2.known_schema_hashes[expected_version]
48 client_version = _cfg.get(option = u'client_version')
49 global current_db_name
50 current_db_name = u'gnumed_%s' % expected_version
51
52 attempt = 0
53
54 while attempt < max_attempts:
55
56 _log.debug('login attempt %s of %s', (attempt+1), max_attempts)
57
58 connected = False
59
60 login = login_info
61 if login is None:
62 _log.info("did not provide a login information")
63
64 # try getting a connection to verify the DSN works
65 dsn = gmPG2.make_psycopg2_dsn (
66 database = login.database,
67 host = login.host,
68 port = login.port,
69 user = login.user,
70 password = login.password
71 )
72 try:
73 #conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
74 conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
75 connected = True
76
77 except gmPG2.cAuthenticationError, e:
78 attempt += 1
79 _log.error(u"login attempt failed: %s", e)
80 if attempt < max_attempts:
81 if (u'host=127.0.0.1' in (u'%s' % e)) or (u'host=' not in (u'%s' % e)):
82 msg = _(
83 'Unable to connect to database:\n\n'
84 '%s\n\n'
85 "Are you sure you have got a local database installed ?\n"
86 '\n'
87 "Please retry with proper credentials or cancel.\n"
88 '\n'
89 'You may also need to check the PostgreSQL client\n'
90 'authentication configuration in pg_hba.conf. For\n'
91 'details see:\n'
92 '\n'
93 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
94 )
95 else:
96 msg = _(
97 "Unable to connect to database:\n\n"
98 "%s\n\n"
99 "Please retry with proper credentials or cancel.\n"
100 "\n"
101 'You may also need to check the PostgreSQL client\n'
102 'authentication configuration in pg_hba.conf. For\n'
103 'details see:\n'
104 '\n'
105 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
106 )
107 msg = msg % e
108 msg = re.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
109 gmGuiHelpers.gm_show_error (
110 msg,
111 _('Connecting to backend')
112 )
113 del e
114 continue
115
116 except gmPG2.dbapi.OperationalError, e:
117 _log.error(u"login attempt failed: %s", e)
118 msg = _(
119 "Unable to connect to database:\n\n"
120 "%s\n\n"
121 "Please retry another backend / user / password combination !\n"
122 ) % gmPG2.extract_msg_from_pg_exception(e)
123 msg = re.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
124 gmGuiHelpers.gm_show_error (
125 msg,
126 _('Connecting to backend')
127 )
128 del e
129 continue
130
131 # connect was successful
132 gmPG2.set_default_login(login = login)
133 #gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding)
134
135 # compatible = gmPG2.database_schema_compatible(version = expected_version)
136 # if compatible or not require_version:
137 #dlg.panel.save_state()
138 # continue
139
140 # if not compatible:
141 # connected_db_version = gmPG2.get_schema_version()
142 # msg = msg_generic % (
143 # client_version,
144 # connected_db_version,
145 # expected_version,
146 # gmTools.coalesce(login.host, '<localhost>'),
147 # login.database,
148 # login.user
149 # )
150
151 # if require_version:
152 # gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version'))
153 # pass
154 #gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version'))
155
156 # # FIXME: make configurable
157 # max_skew = 1 # minutes
158 # if _cfg.get(option = 'debug'):
159 # max_skew = 10
160 # if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)):
161 # if _cfg.get(option = 'debug'):
162 # gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings'))
163 # else:
164 # gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings'))
165 # continue
166
167 # sanity_level, message = gmPG2.sanity_check_database_settings()
168 # if sanity_level != 0:
169 # gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings'))
170 # if sanity_level == 2:
171 # continue
172
173 # gmExceptionHandlingWidgets.set_is_public_database(login.public_db)
174 # gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk)
175
176 listener = gmBackendListener.gmBackendListener(conn = conn)
177 break
178
179 #dlg.Destroy()
180
181 return connected
182
183 #----------------------------------------------------------------------------
184 #internal helper functions
185 #----------------------------------------------------
187 """Get server profiles from the configuration files.
188
189 1) from system-wide file
190 2) from user file
191
192 Profiles in the user file which have the same name
193 as a profile in the system file will override the
194 system file.
195 """
196 # find active profiles
197 src_order = [
198 (u'explicit', u'extend'),
199 (u'system', u'extend'),
200 (u'user', u'extend'),
201 (u'workbase', u'extend')
202 ]
203
204 profile_names = gmTools.coalesce (
205 _cfg.get(group = u'backend', option = u'profiles', source_order = src_order),
206 []
207 )
208
209 # find data for active profiles
210 src_order = [
211 (u'explicit', u'return'),
212 (u'workbase', u'return'),
213 (u'user', u'return'),
214 (u'system', u'return')
215 ]
216
217 profiles = {}
218
219 for profile_name in profile_names:
220 # FIXME: once the profile has been found always use the corresponding source !
221 # FIXME: maybe not or else we cannot override parts of the profile
222 profile = cBackendProfile()
223 profile_section = 'profile %s' % profile_name
224
225 profile.name = profile_name
226 profile.host = gmTools.coalesce(_cfg.get(profile_section, u'host', src_order), u'').strip()
227 port = gmTools.coalesce(_cfg.get(profile_section, u'port', src_order), 5432)
228 try:
229 profile.port = int(port)
230 if profile.port < 1024:
231 raise ValueError('refusing to use priviledged port (< 1024)')
232 except ValueError:
233 _log.warning('invalid port definition: [%s], skipping profile [%s]', port, profile_name)
234 continue
235 profile.database = gmTools.coalesce(_cfg.get(profile_section, u'database', src_order), u'').strip()
236 if profile.database == u'':
237 _log.warning('database name not specified, skipping profile [%s]', profile_name)
238 continue
239 profile.encoding = gmTools.coalesce(_cfg.get(profile_section, u'encoding', src_order), u'UTF8')
240 profile.public_db = bool(_cfg.get(profile_section, u'public/open access', src_order))
241 profile.helpdesk = _cfg.get(profile_section, u'help desk', src_order)
242
243 label = u'%s (%s@%s)' % (profile_name, profile.database, profile.host)
244 profiles[label] = profile
245
246 # sort out profiles with incompatible database versions if not --debug
247 # NOTE: this essentially hardcodes the database name in production ...
248 if not (_cfg.get(option = 'debug') or current_db_name.endswith('_devel')):
249 profiles2remove = []
250 for label in profiles:
251 if profiles[label].database != current_db_name:
252 profiles2remove.append(label)
253 for label in profiles2remove:
254 del profiles[label]
255
256 if len(profiles) == 0:
257 host = u'salaam.homeunix.com'
258 label = u'public GNUmed database (%s@%s)' % (current_db_name, host)
259 profiles[label] = cBackendProfile()
260 profiles[label].name = label
261 profiles[label].host = host
262 profiles[label].port = 5432
263 profiles[label].database = current_db_name
264 profiles[label].encoding = u'UTF8'
265 profiles[label].public_db = True
266 profiles[label].helpdesk = u'http://wiki.gnumed.de'
267
268 return profiles
269
270 # ------------------------------------------------------------
272
273 # username is provided through the web interface
274 # password is provided
275 # we need the profile
276
277 """convenience function for compatibility with gmLoginInfo.LoginInfo"""
278 from Gnumed.pycommon import gmLoginInfo
279 #if not self.cancelled:
280 # FIXME: do not assume conf file is latin1 !
281 #profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()]
282 #self.__backend_profiles = self.__get_backend_profiles()
283 __backend_profiles = __get_backend_profiles()
284 profile = __backend_profiles[backend.encode('utf8').strip()]
285
286 _log.debug(u'backend profile "%s" selected', profile.name)
287 _log.debug(u' details: <%s> on %s@%s:%s (%s, %s)',
288 username,
289 profile.database,
290 profile.host,
291 profile.port,
292 profile.encoding,
293 gmTools.bool2subst(profile.public_db, u'public', u'private')
294 )
295 #_log.debug(u' helpdesk: "%s"', profile.helpdesk)
296 login = gmLoginInfo.LoginInfo (
297 user = username,
298 password = password,
299 host = profile.host,
300 database = profile.database,
301 port = profile.port
302 )
303 #login.public_db = profile.public_db
304 #login.helpdesk = profile.helpdesk
305 return login
306
307 #----------------------------------------------
309 try:
310 kwargs['originated_in_database']
311 print '==> got notification from database "%s":' % kwargs['signal']
312 except KeyError:
313 print '==> received signal from client: "%s"' % kwargs['signal']
314
315 del kwargs['signal']
316 for key in kwargs.keys():
317 print ' [%s]: %s' % (key, kwargs[key])
318
319 #================================================================
322
323 #================================================================
324
325
326 PYJSDIR = sys._getframe().f_code.co_filename
327 PYJSDIR = os.path.split(os.path.dirname(PYJSDIR))[0]
328 PYJSDIR = os.path.join(PYJSDIR, 'pyjamas')
329
330 DEFAULT_BACKEND = "GNUmed database on this machine (Linux/Mac) (gnumed_v15@)"
331
333 '''An application instance containing any number of streams. Except for constructor all methods are generators.'''
334 count = 0
336 SimpleForkingJSONRPCServer.__init__(self, ("localhost", 60001))
337
338 self.register_function(self.echo)
339 self.register_function(self.login)
340 self.register_function(self.get_doc_types)
341 self.register_function(self.get_documents)
342 self.register_function(self.get_schema_version)
343 self.register_function(self.doSomething)
344
353
355 from Gnumed.pycommon import gmPG2
356 if backend is None:
357 backend = DEFAULT_BACKEND
358 login_info = GetLoginInfo(username, password, backend)
359 override = _cfg.get(option = '--override-schema-check',
360 source_order = [('cli', 'return')])
361 cb = _cfg.get(option = 'client_branch')
362 expected_version = gmPG2.map_client_branch2required_db_version[cb]
363 connected = connect_to_database (
364 login_info,
365 expected_version = expected_version,
366 require_version = not override
367 )
368 return connected
369
372
374 doc_folder = gmDocuments.cDocumentFolder(aPKey=key)
375 return jsonclasshintify(doc_folder.get_documents())
376
379
381 msg = 'schema version is:' + gmPG2.get_schema_version() +'\n\n'
382 msg2 =''
383 for item in gmDocuments.get_document_types():
384 msg2 = msg2 +'\n' + str(item)
385 msg = msg + msg2
386 return "<pre>%s</pre>" % msg
387
388
389 #==========================================================
390 # main - launch the GNUmed web client
391 #----------------------------------------------------------
392
394
395 if _cfg.get(option = 'debug'):
396 gmDispatcher.connect(receiver = _signal_debugging_monitor)
397 _log.debug('gmDispatcher signal monitor activated')
398
399 server = HTTPServer()
400 server.serve_forever()
401
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu Sep 9 04:07:39 2010 | http://epydoc.sourceforge.net |