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

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