1
2
3 __doc__ = """GNUmed web client launcher.
4 """
5
6
7
8 __version__ = "$Revision: 1 $"
9 __author__ = "S. Hilbert <Sebastian.Hilbert@gmx.net>"
10 __license__ = "GPL (details at http://www.gnu.org)"
11
12
13 from jsonserver import SimpleForkingJSONRPCServer
14
15
16
17 import re, sys, time, os, cPickle, zlib, locale, os.path, datetime as pyDT, webbrowser, shutil, logging, urllib2
18
19
20 from Gnumed.pycommon import gmI18N, gmTools, gmDateTime, gmHooks
21 from Gnumed.pycommon import gmLoginInfo, gmBackendListener, gmTools, gmCfg2, gmI18N, gmDispatcher, gmBusinessDBObject
22 from Gnumed.pycommon.gmBusinessDBObject import jsonclasshintify
23 from Gnumed.pycommon import gmPG2
24 from Gnumed.business import gmDocuments
25
26
27
28
29
30
31 _cfg = gmCfg2.gmCfgData()
32 _provider = None
33 _scripting_listener = None
34
35 _log = logging.getLogger('gm.main')
36 _log.info(__version__)
37 _log.info('web GUI framework')
38
39
40
41
42 -def connect_to_database(login_info=None, max_attempts=3, expected_version=None, require_version=True):
43 """Display the login dialog and try to log into the backend.
44
45 - up to max_attempts times
46 - returns True/False
47 """
48 from Gnumed.pycommon import gmPG2
49
50 expected_hash = gmPG2.known_schema_hashes[expected_version]
51 client_version = _cfg.get(option = u'client_version')
52 global current_db_name
53 current_db_name = u'gnumed_%s' % expected_version
54
55 attempt = 0
56
57 while attempt < max_attempts:
58
59 _log.debug('login attempt %s of %s', (attempt+1), max_attempts)
60
61 connected = False
62
63 login = login_info
64 if login is None:
65 _log.info("did not provide a login information")
66
67
68 dsn = gmPG2.make_psycopg2_dsn (
69 database = login.database,
70 host = login.host,
71 port = login.port,
72 user = login.user,
73 password = login.password
74 )
75 try:
76
77 conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True)
78 connected = True
79
80 except gmPG2.cAuthenticationError, e:
81 attempt += 1
82 _log.error(u"login attempt failed: %s", e)
83 if attempt < max_attempts:
84 if (u'host=127.0.0.1' in (u'%s' % e)) or (u'host=' not in (u'%s' % e)):
85 msg = _(
86 'Unable to connect to database:\n\n'
87 '%s\n\n'
88 "Are you sure you have got a local database installed ?\n"
89 '\n'
90 "Please retry with proper credentials or cancel.\n"
91 '\n'
92 'You may also need to check the PostgreSQL client\n'
93 'authentication configuration in pg_hba.conf. For\n'
94 'details see:\n'
95 '\n'
96 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
97 )
98 else:
99 msg = _(
100 "Unable to connect to database:\n\n"
101 "%s\n\n"
102 "Please retry with proper credentials or cancel.\n"
103 "\n"
104 'You may also need to check the PostgreSQL client\n'
105 'authentication configuration in pg_hba.conf. For\n'
106 'details see:\n'
107 '\n'
108 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL'
109 )
110 msg = msg % e
111 msg = re.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
112 gmGuiHelpers.gm_show_error (
113 msg,
114 _('Connecting to backend')
115 )
116 del e
117 continue
118
119 except gmPG2.dbapi.OperationalError, e:
120 _log.error(u"login attempt failed: %s", e)
121 msg = _(
122 "Unable to connect to database:\n\n"
123 "%s\n\n"
124 "Please retry another backend / user / password combination !\n"
125 ) % gmPG2.extract_msg_from_pg_exception(e)
126 msg = re.sub(r'password=[^\s]+', u'password=%s' % gmTools.u_replacement_character, msg)
127 gmGuiHelpers.gm_show_error (
128 msg,
129 _('Connecting to backend')
130 )
131 del e
132 continue
133
134
135 gmPG2.set_default_login(login = login)
136
137
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 listener = gmBackendListener.gmBackendListener(conn = conn)
180 break
181
182
183
184 return connected
185
186
187
188
190 """Get server profiles from the configuration files.
191
192 1) from system-wide file
193 2) from user file
194
195 Profiles in the user file which have the same name
196 as a profile in the system file will override the
197 system file.
198 """
199
200 src_order = [
201 (u'explicit', u'extend'),
202 (u'system', u'extend'),
203 (u'user', u'extend'),
204 (u'workbase', u'extend')
205 ]
206
207 profile_names = gmTools.coalesce (
208 _cfg.get(group = u'backend', option = u'profiles', source_order = src_order),
209 []
210 )
211
212
213 src_order = [
214 (u'explicit', u'return'),
215 (u'workbase', u'return'),
216 (u'user', u'return'),
217 (u'system', u'return')
218 ]
219
220 profiles = {}
221
222 for profile_name in profile_names:
223
224
225 profile = cBackendProfile()
226 profile_section = 'profile %s' % profile_name
227
228 profile.name = profile_name
229 profile.host = gmTools.coalesce(_cfg.get(profile_section, u'host', src_order), u'').strip()
230 port = gmTools.coalesce(_cfg.get(profile_section, u'port', src_order), 5432)
231 try:
232 profile.port = int(port)
233 if profile.port < 1024:
234 raise ValueError('refusing to use priviledged port (< 1024)')
235 except ValueError:
236 _log.warning('invalid port definition: [%s], skipping profile [%s]', port, profile_name)
237 continue
238 profile.database = gmTools.coalesce(_cfg.get(profile_section, u'database', src_order), u'').strip()
239 if profile.database == u'':
240 _log.warning('database name not specified, skipping profile [%s]', profile_name)
241 continue
242 profile.encoding = gmTools.coalesce(_cfg.get(profile_section, u'encoding', src_order), u'UTF8')
243 profile.public_db = bool(_cfg.get(profile_section, u'public/open access', src_order))
244 profile.helpdesk = _cfg.get(profile_section, u'help desk', src_order)
245
246 label = u'%s (%s@%s)' % (profile_name, profile.database, profile.host)
247 profiles[label] = profile
248
249
250
251 if not (_cfg.get(option = 'debug') or current_db_name.endswith('_devel')):
252 profiles2remove = []
253 for label in profiles:
254 if profiles[label].database != current_db_name:
255 profiles2remove.append(label)
256 for label in profiles2remove:
257 del profiles[label]
258
259 if len(profiles) == 0:
260 host = u'salaam.homeunix.com'
261 label = u'public GNUmed database (%s@%s)' % (current_db_name, host)
262 profiles[label] = cBackendProfile()
263 profiles[label].name = label
264 profiles[label].host = host
265 profiles[label].port = 5432
266 profiles[label].database = current_db_name
267 profiles[label].encoding = u'UTF8'
268 profiles[label].public_db = True
269 profiles[label].helpdesk = u'http://wiki.gnumed.de'
270
271 return profiles
272
273
274 -def GetLoginInfo(username=None, password=None, backend=None ):
275
276
277
278
279
280 """convenience function for compatibility with gmLoginInfo.LoginInfo"""
281 from Gnumed.pycommon import gmLoginInfo
282
283
284
285
286 __backend_profiles = __get_backend_profiles()
287 profile = __backend_profiles[backend.encode('utf8').strip()]
288
289 _log.debug(u'backend profile "%s" selected', profile.name)
290 _log.debug(u' details: <%s> on %s@%s:%s (%s, %s)',
291 username,
292 profile.database,
293 profile.host,
294 profile.port,
295 profile.encoding,
296 gmTools.bool2subst(profile.public_db, u'public', u'private')
297 )
298
299 login = gmLoginInfo.LoginInfo (
300 user = username,
301 password = password,
302 host = profile.host,
303 database = profile.database,
304 port = profile.port
305 )
306
307
308 return login
309
310
312 try:
313 kwargs['originated_in_database']
314 print '==> got notification from database "%s":' % kwargs['signal']
315 except KeyError:
316 print '==> received signal from client: "%s"' % kwargs['signal']
317
318 del kwargs['signal']
319 for key in kwargs.keys():
320 print ' [%s]: %s' % (key, kwargs[key])
321
322
325
326
327
328
329 PYJSDIR = sys._getframe().f_code.co_filename
330 PYJSDIR = os.path.split(os.path.dirname(PYJSDIR))[0]
331 PYJSDIR = os.path.join(PYJSDIR, 'pyjamas')
332
333 DEFAULT_BACKEND = "GNUmed database on this machine (Linux/Mac) (gnumed_v14@)"
334
336 '''An application instance containing any number of streams. Except for constructor all methods are generators.'''
337 count = 0
347
348 - def echo(self, text):
356
357 - def login(self, username=None, password=None, backend=None):
372
375
379
382
390
391
392
393
394
395
397
398 if _cfg.get(option = 'debug'):
399 gmDispatcher.connect(receiver = _signal_debugging_monitor)
400 _log.debug('gmDispatcher signal monitor activated')
401
402 server = HTTPServer()
403 server.serve_forever()
404