Package Gnumed :: Package ProxiedWeb :: Module gmGuiWeb
[frames] | no frames]

Source Code for Module Gnumed.ProxiedWeb.gmGuiWeb

  1  #!/usr/bin/env python 
  2   
  3  __doc__ = """GNUmed web client launcher. 
  4  """ 
  5  #========================================================== 
  6  # $Source: /home/ncq/Projekte/cvs2git/vcs-mirror/gnumed/gnumed/client/wxpython/gnumed.py,v $ 
  7  # $Id: gnumed.py,v 1.169 2010-01-31 18:20:41 ncq Exp $ 
  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  # stdlib 
 17  import re, sys, time, os, cPickle, zlib, locale, os.path, datetime as pyDT, webbrowser, shutil, logging, urllib2 
 18   
 19  # GNUmed libs 
 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  #try: 
 27  #       _('dummy-no-need-to-translate-but-make-epydoc-happy') 
 28  #except NameError: 
 29  #       _ = lambda x:x 
 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  # convenience functions 
 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 # force programmer to set a valid expected_version 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 # try getting a connection to verify the DSN works 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 #conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True) 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 # connect was successful 135 gmPG2.set_default_login(login = login) 136 #gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding) 137 138 # compatible = gmPG2.database_schema_compatible(version = expected_version) 139 # if compatible or not require_version: 140 #dlg.panel.save_state() 141 # continue 142 143 # if not compatible: 144 # connected_db_version = gmPG2.get_schema_version() 145 # msg = msg_generic % ( 146 # client_version, 147 # connected_db_version, 148 # expected_version, 149 # gmTools.coalesce(login.host, '<localhost>'), 150 # login.database, 151 # login.user 152 # ) 153 154 # if require_version: 155 # gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version')) 156 # pass 157 #gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version')) 158 159 # # FIXME: make configurable 160 # max_skew = 1 # minutes 161 # if _cfg.get(option = 'debug'): 162 # max_skew = 10 163 # if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)): 164 # if _cfg.get(option = 'debug'): 165 # gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings')) 166 # else: 167 # gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings')) 168 # continue 169 170 # sanity_level, message = gmPG2.sanity_check_database_settings() 171 # if sanity_level != 0: 172 # gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings')) 173 # if sanity_level == 2: 174 # continue 175 176 # gmExceptionHandlingWidgets.set_is_public_database(login.public_db) 177 # gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk) 178 179 listener = gmBackendListener.gmBackendListener(conn = conn) 180 break 181 182 #dlg.Destroy() 183 184 return connected
185 186 #---------------------------------------------------------------------------- 187 #internal helper functions 188 #----------------------------------------------------
189 -def __get_backend_profiles():
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 # find active profiles 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 # find data for active profiles 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 # FIXME: once the profile has been found always use the corresponding source ! 224 # FIXME: maybe not or else we cannot override parts of the profile 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 # sort out profiles with incompatible database versions if not --debug 250 # NOTE: this essentially hardcodes the database name in production ... 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 # username is provided through the web interface 277 # password is provided 278 # we need the profile 279 280 """convenience function for compatibility with gmLoginInfo.LoginInfo""" 281 from Gnumed.pycommon import gmLoginInfo 282 #if not self.cancelled: 283 # FIXME: do not assume conf file is latin1 ! 284 #profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()] 285 #self.__backend_profiles = self.__get_backend_profiles() 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 #_log.debug(u' helpdesk: "%s"', profile.helpdesk) 299 login = gmLoginInfo.LoginInfo ( 300 user = username, 301 password = password, 302 host = profile.host, 303 database = profile.database, 304 port = profile.port 305 ) 306 #login.public_db = profile.public_db 307 #login.helpdesk = profile.helpdesk 308 return login
309 310 #----------------------------------------------
311 -def _signal_debugging_monitor(*args, **kwargs):
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 #================================================================
323 -class cBackendProfile:
324 pass
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
335 -class HTTPServer(SimpleForkingJSONRPCServer):
336 '''An application instance containing any number of streams. Except for constructor all methods are generators.''' 337 count = 0
338 - def __init__(self):
339 SimpleForkingJSONRPCServer.__init__(self, ("localhost", 60001)) 340 341 self.register_function(self.echo) 342 self.register_function(self.login) 343 self.register_function(self.get_doc_types) 344 self.register_function(self.get_documents) 345 self.register_function(self.get_schema_version) 346 self.register_function(self.doSomething)
347
348 - def echo(self, text):
349 return text
350 - def reverse(self, text):
351 return text[::-1]
352 - def uppercase(self, text):
353 return text.upper()
354 - def lowercase(self,text):
355 return text.lower()
356
357 - def login(self, username=None, password=None, backend=None):
358 from Gnumed.pycommon import gmPG2 359 if backend is None: 360 backend = DEFAULT_BACKEND 361 login_info = GetLoginInfo(username, password, backend) 362 override = _cfg.get(option = '--override-schema-check', 363 source_order = [('cli', 'return')]) 364 cb = _cfg.get(option = 'client_branch') 365 expected_version = gmPG2.map_client_branch2required_db_version[cb] 366 connected = connect_to_database ( 367 login_info, 368 expected_version = expected_version, 369 require_version = not override 370 ) 371 return connected
372
373 - def get_schema_version(self):
375
376 - def get_documents(self, key):
377 doc_folder = gmDocuments.cDocumentFolder(aPKey=key) 378 return jsonclasshintify(doc_folder.get_documents())
379
380 - def get_doc_types(self):
382
383 - def doSomething(self):
384 msg = 'schema version is:' + gmPG2.get_schema_version() +'\n\n' 385 msg2 ='' 386 for item in gmDocuments.get_document_types(): 387 msg2 = msg2 +'\n' + str(item) 388 msg = msg + msg2 389 return "<pre>%s</pre>" % msg
390 391 392 #========================================================== 393 # main - launch the GNUmed web client 394 #---------------------------------------------------------- 395
396 -def main():
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