1
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
11 import re, sys, time, os, cPickle, zlib, locale, os.path
12 import datetime as pyDT, webbrowser, shutil, logging, urllib2
13
14
15 from jsonserver import SimpleForkingJSONRPCServer, CloseConnection
16
17
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
29
30
31
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
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
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_v%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
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
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
137 gmPG2.set_default_login(login = login)
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 listener = gmBackendListener.gmBackendListener(conn = conn)
182 break
183
184
185
186 return connected
187
188
189
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
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
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
226
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
252
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'publicdb.gnumed.de'
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
276 -def GetLoginInfo(username=None, password=None, backend=None ):
277
278
279
280
281
282 """convenience function for compatibility with gmLoginInfo.LoginInfo"""
283 from Gnumed.pycommon import gmLoginInfo
284
285
286
287
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
301 login = gmLoginInfo.LoginInfo (
302 user = username,
303 password = password,
304 host = profile.host,
305 database = profile.database,
306 port = profile.port
307 )
308
309
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
353
354 - def echo(self, text):
362
363 - def login(self, username=None, password=None, backend=None):
378
380 """ return value is in the exception
381 """
382 raise CloseConnection(True)
383
403
407
413
416
420
423
431
432
433
434
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