Package Gnumed :: Package business :: Module gmOrganization
[frames] | no frames]

Source Code for Module Gnumed.business.gmOrganization

   1  """Organization classes 
   2   
   3  author: Karsten Hilbert et al 
   4  """ 
   5  #============================================================ 
   6  __license__ = "GPL" 
   7   
   8   
   9  import sys, logging 
  10   
  11   
  12  if __name__ == '__main__': 
  13          sys.path.insert(0, '../../') 
  14  from Gnumed.pycommon import gmPG2 
  15  from Gnumed.pycommon import gmTools 
  16  from Gnumed.pycommon import gmBusinessDBObject 
  17   
  18  from Gnumed.business import gmDemographicRecord 
  19   
  20   
  21  _log = logging.getLogger('gm.org') 
  22   
  23  #============================================================ 
24 -def create_org_category(category=None):
25 args = {'cat': category} 26 cmd1 = u"""INSERT INTO dem.org_category (description) SELECT %(cat)s 27 WHERE NOT EXISTS ( 28 SELECT 1 FROM dem.org_category WHERE description = %(cat)s or _(description) = %(cat)s 29 )""" 30 cmd2 = u"""SELECT pk FROM dem.org_category WHERE description = %(cat)s or _(description) = %(cat)s LIMIT 1""" 31 queries = [ 32 {'cmd': cmd1, 'args': args}, 33 {'cmd': cmd2, 'args': args} 34 ] 35 rows, idx = gmPG2.run_rw_queries(queries = queries, get_col_idx = False, return_data = True) 36 return rows[0][0]
37 38 #============================================================ 39 # organization API 40 #------------------------------------------------------------ 41 _SQL_get_org = u'SELECT * FROM dem.v_orgs WHERE %s' 42
43 -class cOrg(gmBusinessDBObject.cBusinessDBObject):
44 45 _cmd_fetch_payload = _SQL_get_org % u'pk_org = %s' 46 _cmds_store_payload = [ 47 u"""UPDATE dem.org SET 48 description = %(organization)s, 49 fk_category = %(pk_category_org)s, 50 WHERE 51 pk = %(pk_org)s 52 AND 53 xmin = %(xmin_org)s 54 RETURNING 55 xmin AS xmin_org""" 56 ] 57 _updatable_fields = [ 58 u'organization', 59 u'pk_category_org' 60 ] 61 #--------------------------------------------------------
62 - def add_unit(self, unit=None):
63 return create_org_unit(pk_organization = self._payload[self._idx['pk_org']], unit = unit)
64 #------------------------------------------------------------
65 -def org_exists(organization=None, category=None):
66 args = {'desc': organization, 'cat': category} 67 68 if isinstance(category, basestring): 69 cat_part = u'fk_category = (SELECT pk FROM dem.org_category WHERE description = %(cat)s)' 70 elif category is None: 71 cat_part = u'True' 72 else: 73 cat_part = u'fk_category = %(cat)s' 74 75 cmd = u'SELECT pk FROM dem.org WHERE description = %%(desc)s AND %s' % cat_part 76 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 77 if len(rows) > 0: 78 return cOrg(aPK_obj = rows[0][0]) 79 80 return None
81 #------------------------------------------------------------
82 -def create_org(organization=None, category=None):
83 84 org = org_exists(organization, category) 85 if org is not None: 86 return org 87 88 args = {'desc': organization, 'cat': category} 89 90 if isinstance(category, basestring): 91 cat_part = u'(SELECT pk FROM dem.org_category WHERE description = %(cat)s)' 92 else: 93 cat_part = u'%(cat)s' 94 95 cmd = u'INSERT INTO dem.org (description, fk_category) VALUES (%%(desc)s, %s) RETURNING pk' % cat_part 96 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True) 97 98 return cOrg(aPK_obj = rows[0][0])
99 #------------------------------------------------------------
100 -def delete_org(organization=None):
101 args = {'pk': organization} 102 cmd = u""" 103 DELETE FROM dem.org 104 WHERE 105 pk = %(pk)s 106 AND NOT EXISTS ( 107 SELECT 1 FROM dem.org_unit WHERE fk_org = %(pk)s 108 ) 109 """ 110 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 111 return True
112 #------------------------------------------------------------
113 -def get_orgs(order_by=None):
114 115 if order_by is None: 116 order_by = u'' 117 else: 118 order_by = u'ORDER BY %s' % order_by 119 120 cmd = _SQL_get_org % (u'TRUE %s' % order_by) 121 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 122 123 return [ cOrg(row = {'data': r, 'idx': idx, 'pk_field': u'pk_org'}) for r in rows ]
124 125 #============================================================ 126 # organizational units API 127 #------------------------------------------------------------ 128 _SQL_get_org_unit = u'SELECT * FROM dem.v_org_units WHERE %s' 129
130 -class cOrgUnit(gmBusinessDBObject.cBusinessDBObject):
131 132 _cmd_fetch_payload = _SQL_get_org_unit % u'pk_org_unit = %s' 133 _cmds_store_payload = [ 134 u"""UPDATE dem.org_unit SET 135 description = %(unit)s, 136 fk_org = %(pk_org)s, 137 fk_category = %(pk_category_unit)s, 138 fk_address = %(pk_address)s 139 WHERE 140 pk = %(pk_org_unit)s 141 AND 142 xmin = %(xmin_org_unit)s 143 RETURNING 144 xmin AS xmin_org_unit""" 145 ] 146 _updatable_fields = [ 147 u'unit', 148 u'pk_org', 149 u'pk_category_unit', 150 u'pk_address' 151 ] 152 #-------------------------------------------------------- 153 # comms API 154 #--------------------------------------------------------
155 - def get_comm_channels(self, comm_medium=None):
156 157 args = {'pk': self.pk_obj, 'medium': comm_medium} 158 159 if comm_medium is None: 160 cmd = u""" 161 SELECT * 162 FROM dem.v_org_unit_comms 163 WHERE 164 pk_org_unit = %(pk)s 165 """ 166 else: 167 cmd = u""" 168 SELECT * 169 FROM dem.v_org_unit_comms 170 WHERE 171 pk_org_unit = %(pk)s 172 AND 173 comm_type = %(medium)s 174 """ 175 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 176 177 return [ gmDemographicRecord.cOrgCommChannel(row = { 178 'pk_field': 'pk_lnk_org_unit2comm', 179 'data': r, 180 'idx': idx 181 }) for r in rows 182 ]
183 #-------------------------------------------------------- 200 #-------------------------------------------------------- 206 #-------------------------------------------------------- 207 # address API 208 #-------------------------------------------------------- 212 #-------------------------------------------------------- 220 #--------------------------------------------------------
221 - def format(self, with_address=False, with_org=True, with_comms=False):
222 lines = [] 223 lines.append(_('Unit: %s%s') % ( 224 self._payload[self._idx['unit']], 225 gmTools.coalesce(self._payload[self._idx['l10n_unit_category']], u'', u' (%s)') 226 )) 227 if with_org: 228 lines.append(_('Organization: %s (%s)') % ( 229 self._payload[self._idx['organization']], 230 self._payload[self._idx['l10n_organization_category']] 231 )) 232 if with_address: 233 adr = self.address 234 if adr is not None: 235 lines.extend(adr.format()) 236 if with_comms: 237 for comm in self.comm_channels: 238 lines.append(u'%s: %s%s' % ( 239 comm['l10n_comm_type'], 240 comm['url'], 241 gmTools.bool2subst(comm['is_confidential'], _(' (confidential)'), u'', u'') 242 )) 243 return lines
244 #-------------------------------------------------------- 245 # properties 246 #--------------------------------------------------------
247 - def _get_address(self):
248 if self._payload[self._idx['pk_address']] is None: 249 return None 250 return gmDemographicRecord.cAddress(aPK_obj = self._payload[self._idx['pk_address']])
251
252 - def _set_address(self, address):
253 self['pk_address'] = address['pk_address'] 254 self.save()
255 256 address = property(_get_address, _set_address) 257 #--------------------------------------------------------
258 - def _get_org(self):
259 return cOrg(aPK_obj = self._payload[self._idx['pk_org']])
260 261 organization = property(_get_org, lambda x:x) 262 263 comm_channels = property(get_comm_channels, lambda x:x)
264 #------------------------------------------------------------
265 -def create_org_unit(pk_organization=None, unit=None):
266 267 args = {'desc': unit, 'pk_org': pk_organization} 268 269 # exists ? 270 cmd = u'SELECT pk FROM dem.org_unit WHERE description = %(desc)s AND fk_org = %(pk_org)s' 271 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 272 if len(rows) > 0: 273 return cOrgUnit(aPK_obj = rows[0][0]) 274 275 # no, create 276 cmd = u'INSERT INTO dem.org_unit (description, fk_org) VALUES (%(desc)s, %(pk_org)s) RETURNING pk' 277 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True) 278 279 return cOrgUnit(aPK_obj = rows[0][0])
280 #------------------------------------------------------------
281 -def delete_org_unit(unit=None):
282 args = {'pk': unit} 283 cmd = u"DELETE FROM dem.org_unit WHERE pk = %(pk)s" 284 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 285 return True
286 #------------------------------------------------------------
287 -def get_org_units(order_by=None, org=None):
288 289 if order_by is None: 290 order_by = u'' 291 else: 292 order_by = u' ORDER BY %s' % order_by 293 294 if org is None: 295 where_part = u'TRUE' 296 else: 297 where_part = u'pk_org = %(org)s' 298 299 args = {'org': org} 300 cmd = (_SQL_get_org_unit % where_part) + order_by 301 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 302 303 return [ cOrgUnit(row = {'data': r, 'idx': idx, 'pk_field': u'pk_org_unit'}) for r in rows ]
304 305 #====================================================================== 306 # main 307 #---------------------------------------------------------------------- 308 if __name__ == "__main__": 309 310 if len(sys.argv) < 2: 311 sys.exit() 312 313 if sys.argv[1] != u'test': 314 sys.exit() 315 316 317 for unit in get_org_units(): 318 print unit 319 320 sys.exit(0) 321 #============================================================ 322 #============================================================ 323 # outdated code below ======================================= 324 #============================================================ 325 #============================================================ 326 #============================================================ 327 #============================================================ 328 #============================================================ 329 #============================================================ 330 #============================================================ 331 #============================================================ 332 #============================================================
333 -def get_comm_channels_data_for_org_ids( idList):
334 """gets comm_channels for a list of org_id. 335 returns a map keyed by org_id with lists of comm_channel data (url, type). 336 this allows a single fetch of comm_channel data for multiple orgs""" 337 338 ids = ", ".join( [ str(x) for x in idList]) 339 cmd = """select l.id_org, id_type, url 340 from dem.comm_channel c, dem.lnk_org2comm_channel l 341 where 342 c.id = l.id_comm and 343 l.id_org in ( select id from dem.org where id in (%s) ) 344 """ % ids 345 result = gmPG.run_ro_query("personalia", cmd) 346 if result == None: 347 _log.error("Unable to load comm channels for org" ) 348 return None 349 m = {} 350 for (id_org, id_type, url) in result: 351 if not m.has_key(id_org): 352 m[id_org] = [] 353 m[id_org].append( (id_type, url) ) 354 355 return m # is a Map[id_org] = list of comm_channel data 356
357 -def get_address_data_for_org_ids( idList):
358 """gets addresses for a list of valid id values for orgs. 359 returns a map keyed by org_id with the address data 360 """ 361 362 ids = ", ".join( [ str(x) for x in idList]) 363 cmd = """select l.id_org, number, street, city, postcode, state, country 364 from dem.v_basic_address v , dem.lnk_org2address l 365 where v.addr_id = l.id_address and 366 l.id_org in ( select id from dem.org where id in (%s) ) """ % ids 367 result = gmPG.run_ro_query( "personalia", cmd) 368 369 if result == None: 370 _log.error("failure in org address load" ) 371 return None 372 m = {} 373 for (id_org, n,s,ci,p,st,co) in result: 374 m[id_org] = (n,s,ci,p,st,co) 375 return m
376
377 -def get_org_data_for_org_ids(idList):
378 """ for a given list of org id values , 379 returns a map of id_org vs. org attributes: description, id_category""" 380 381 ids = ", ".join( [ str(x) for x in idList]) 382 cmd = """select id, description, id_category from dem.org 383 where id in ( select id from dem.org where id in( %s) )""" % ids 384 #<DEBUG> 385 print cmd 386 #</DEBUG> 387 result = gmPG.run_ro_query("personalia", cmd, ) 388 if result is None: 389 _log.error("Unable to load orgs with ids (%s)" %ids) 390 return None 391 m = {} 392 for (id_org, d, id_cat) in result: 393 m[id_org] = (d, id_cat) 394 return m
395 #============================================================ 396 # 397 # IGNORE THE FOLLOWING, IF NOT INTERESTED IN TEST CODE 398 # 399 # 400 401 if __name__ == '__main__': 402 print "Please enter a write-enabled user e.g. _test-doc " 403
404 - def testListOrgs():
405 print "running test listOrg" 406 for (f,a) in get_test_data(): 407 h = cOrgImpl1() 408 h.set(*f) 409 h.setAddress(*a) 410 if not h.save(): 411 print "did not save ", f 412 413 orgs = cOrgHelperImpl1().findAllOrganizations() 414 415 for org in orgs: 416 print "Found org ", org.get(), org.getAddress() 417 if not org.shallow_del(): 418 print "Unable to delete above org"
419 420 421 422 423 424
425 - def get_test_data():
426 """test org data for unit testing in testOrg()""" 427 return [ 428 ( ["Box Hill Hospital", "", "", "Eastern", "hospital", "0398953333", "111-1111","bhh@oz", ""], ["33", "Nelson Rd", "Box Hill", "3128", None , None] ), 429 ( ["Frankston Hospital", "", "", "Peninsula", "hospital", "0397847777", "03784-3111","fh@oz", ""], ["21", "Hastings Rd", "Frankston", "3199", None , None] ) 430 ]
431
432 - def get_test_persons():
433 return { "Box Hill Hospital": 434 [ 435 ['Dr.', 'Bill' , 'Smith', '123-4567', '0417 111 222'], 436 ['Ms.', 'Anita', 'Jones', '124-5544', '0413 222 444'], 437 ['Dr.', 'Will', 'Stryker', '999-4444', '0402 333 111'] ], 438 "Frankston Hospital": 439 [ [ "Dr.", "Jason", "Boathead", "444-5555", "0403 444 2222" ], 440 [ "Mr.", "Barnie", "Commuter", "222-1111", "0444 999 3333"], 441 [ "Ms.", "Morita", "Traveller", "999-1111", "0222 333 1111"]] }
442
443 - def testOrgPersons():
444 m = get_test_persons() 445 d = dict( [ (f[0] , (f, a)) for (f, a) in get_test_data() ] ) 446 for orgName , personList in m.items(): 447 f1 , a1 = d[orgName][0], d[orgName][1] 448 _testOrgClassPersonRun( f1, a1, personList, cOrgImpl1) 449 _testOrgClassPersonRun( f1, a1, personList, cCompositeOrgImpl1) 450 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl1().create) 451 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl2().create) 452 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl3().create) 453 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl3().create, getTestIdentityUsing_cOrgDemographicAdapter)
454 455
456 - def _outputPersons( org):
457 m = org.getPersonMap() 458 459 if m== []: 460 print "NO persons were found unfortunately" 461 462 print """ TestOrgPersonRun got back for """ 463 a = org.getAddress() 464 print org["name"], a["number"], a["street"], a["urb"], a["postcode"] , " phone=", org['phone'] 465 466 for id, r in m.items(): 467 print "\t",", ".join( [ " ".join(r.get_names().values()), 468 "work no=", r.getCommChannel(gmDemographicRecord.WORK_PHONE), 469 "mobile no=", r.getCommChannel(gmDemographicRecord.MOBILE) 470 ] )
471 472
473 - def _testOrgPersonRun(f1, a1, personList):
474 print "Using test data :f1 = ", f1, "and a1 = ", a1 , " and lp = ", personList 475 print "-" * 50 476 _testOrgClassPersonRun( f1, a1, personList, cOrgImpl1) 477 _testOrgClassPersonRun( f1, a1, personList, cCompositeOrgImpl1) 478 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl1().create) 479 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl2().create)
480 481
482 - def _setIdentityTestData(identity, data):
483 identity.addName(data[1], data[2], True) 484 identity.setTitle(data[0]) 485 identity.linkCommChannel( gmDemographicRecord.WORK_PHONE, data[3]) 486 identity.linkCommChannel( gmDemographicRecord.MOBILE, data[4])
487
488 - def getTestIdentityUsingDirectDemographicRecord( data, org):
489 id = gmPerson.create_dummy_identity() 490 identity = gmDemographicRecord.cDemographicRecord_SQL(id) 491 _setIdentityTestData(identity, data) 492 return identity
493
494 - def getTestIdentityUsing_cOrgDemographicAdapter( data, org):
495 helper = cOrgHelperImpl3() 496 orgPerson= helper.createOrgPerson() 497 orgPerson.setParent(org) 498 orgPerson['name'] = ' '.join( [data[0], data[1], data[2]]) 499 orgPerson['phone'] = data[3] 500 orgPerson['mobile'] = data[4] 501 orgPerson.save() 502 return orgPerson.getDemographicRecord()
503 504
505 - def _testOrgClassPersonRun(f1, a1, personList, orgCreate, identityCreator = getTestIdentityUsingDirectDemographicRecord):
506 print "-" * 50 507 print "Testing org creator ", orgCreate 508 print " and identity creator ", identityCreator 509 print "-" * 50 510 h = orgCreate() 511 h.set(*f1) 512 h.setAddress(*a1) 513 if not h.save(): 514 print "Unable to save org for person test" 515 h.shallow_del() 516 return False 517 # use gmDemographicRecord to convert person list 518 for lp in personList: 519 identity = identityCreator(lp, h) 520 result , msg = h.linkPerson(identity) 521 print msg 522 523 _outputPersons(h) 524 deletePersons(h) 525 526 if h.shallow_del(): 527 print "Managed to dispose of org" 528 else: 529 print "unable to dispose of org" 530 531 return True
532 533 # def testOrgPerson(f1, a1, personList): 534
535 - def deletePerson(id):
536 cmds = [ ( "delete from dem.lnk_identity2comm_chan where fk_identity=%d"%id,[]), 537 ("delete from dem.names where id_identity=%d"%id,[]), 538 ("delete from dem.identity where id = %d"%id,[]) ] 539 result = gmPG.run_commit("personalia", cmds) 540 return result
541
542 - def deletePersons( org):
543 map = org.getPersonMap() 544 for id, r in map.items(): 545 org.unlinkPerson(r) 546 547 result = deletePerson(r.getID()) 548 if result == None: 549 _log.error("FAILED TO CLEANUP PERSON %d" %r.getID() )
550 551 552
553 - def testOrg():
554 """runs a test of load, save , shallow_del on items in from get_test_data""" 555 l = get_test_data() 556 results = [] 557 for (f, a) in l: 558 result, obj = _testOrgRun(f, a) 559 results.append( (result, obj) ) 560 return results
561 562 563
564 - def _testOrgRun( f1, a1):
565 566 print """testing single level orgs""" 567 f = [ "name", "office", "subtype", "memo", "category", "phone", "fax", "email","mobile"] 568 a = ["number", "street", "urb", "postcode", "state", "country"] 569 h = cOrgImpl1() 570 571 h.set(*f1) 572 h.setAddress(*a1) 573 574 print "testing get, getAddress" 575 print h.get() 576 print h.getAddressDict() 577 578 import sys 579 if not h.save(): 580 print "failed to save first time. Is an old test org needing manual removal?" 581 return False, h 582 print "saved pk =", h.getId() 583 584 585 pk = h.getId() 586 if h.shallow_del(): 587 print "shallow deleted ", h['name'] 588 else: 589 print "failed shallow delete of ", h['name'] 590 591 592 593 h2 = cOrgImpl1() 594 595 print "testing load" 596 597 print "should fail" 598 if not h2.load(pk): 599 print "Failed as expected" 600 601 if h.save(): 602 print "saved ", h['name'] , "again" 603 else: 604 print "failed re-save" 605 return False, h 606 607 h['fax'] = '222-1111' 608 print "using update save" 609 610 if h.save(): 611 print "saved updated passed" 612 print "Test reload next" 613 else: 614 print "failed save of updated data" 615 print "continuing to reload" 616 617 618 if not h2.load(h.getId()): 619 print "failed load" 620 return False, h 621 print "reloaded values" 622 print h2.get() 623 print h2.getAddressDict() 624 625 print "** End of Test org" 626 627 if h2.shallow_del(): 628 print "cleaned up" 629 else: 630 print "Test org needs to be manually removed" 631 632 return True, h2
633
634 - def clean_test_org():
635 l = get_test_data() 636 637 names = [ "".join( ["'" ,str(org[0]), "'"] ) for ( org, address) in l] 638 names += [ "'John Hunter Hospital'", "'Belmont District Hospital'"] 639 nameList = ",".join(names) 640 categoryList = "'hospital'" 641 642 cmds = [ ( """create temp table del_org as 643 select id from dem.org 644 where description in(%s) or 645 id_category in ( select id from dem.org_category c 646 where c.description in (%s)) 647 """ % (nameList, categoryList), [] ), 648 ("""create temp table del_identity as 649 select id from dem.identity 650 where id in 651 ( 652 select id_identity from dem.lnk_person_org_address 653 where id_org in ( select id from del_org) 654 )""",[] ), 655 ("""create temp table del_comm as 656 (select id_comm from dem.lnk_org2comm_channel where 657 id_org in ( select id from del_org) 658 ) UNION 659 (select id_comm from dem.lnk_identity2comm_chan where 660 id_identity in ( select id from del_identity) 661 )""", [] ), 662 ("""delete from dem.names where id_identity in 663 (select id from del_identity)""",[]), 664 ("""delete from dem.lnk_person_org_address where 665 id_org in (select id from del_org )""",[]), 666 ("""delete from dem.lnk_person_org_address where 667 id_identity in (select id from del_identity)""", []), 668 ("""delete from dem.lnk_org2comm_channel 669 where id_org in (select id from del_org) """,[]), 670 ("""delete from dem.lnk_identity2comm_chan 671 where id_identity in (select id from del_identity)""",[] ), 672 ("""delete from dem.comm_channel where id in ( select id_comm from del_comm)""",[]), 673 ("""delete from dem.lnk_job2person where id_identity in (select id from del_identity)""", []), 674 ("""delete from dem.identity where id in (select id from del_identity)""",[] ), 675 ("""delete from dem.org where id in ( select id from del_org) """ , [] ), 676 ("""drop table del_comm""",[]), 677 ("""drop table del_identity""",[]), 678 ("""drop table del_org""", []) 679 680 ] 681 result = gmPG.run_commit("personalia", cmds) <> None 682 683 return result
684 685
686 - def login_user_and_test(logintest, service = 'personalia', msg = "failed test" , use_prefix_rw= False):
687 """ tries to get and verify a read-write connection 688 which has permission to write to org tables, so the test case 689 can run. 690 """ 691 login2 = gmPG.request_login_params() 692 693 #login as the RW user 694 p = gmPG.ConnectionPool( login2) 695 if use_prefix_rw: 696 conn = p.GetConnection( service, readonly = 0) 697 else: 698 conn = p.GetConnection(service) 699 result = logintest(conn) 700 701 if result is False: 702 print msg 703 704 p.ReleaseConnection(service) 705 return result, login2
706
707 - def test_rw_user(conn):
708 # test it is a RW user, by making a entry and deleting it 709 try: 710 c.reload("org_category") 711 cursor = conn.cursor() 712 713 cursor.execute("select last_value from dem.org_id_seq") 714 [org_id_seq] = cursor.fetchone() 715 716 cursor.execute(""" 717 insert into dem.org ( description, id_category, id) 718 values ( 'xxxDEFAULTxxx', %d, 719 %d) 720 """ % ( c.getId('org_category', 'hospital') , org_id_seq + 1 ) ) 721 cursor.execute(""" 722 delete from dem.org where id = %d""" % ( org_id_seq + 1) ) 723 # make sure this exercise is committed, else a deadlock will occur 724 conn.commit() 725 except: 726 _log.exception("Test of Update Permission failed") 727 return False 728 return True
729
730 - def test_admin_user(conn):
731 try: 732 cursor = conn.cursor() 733 734 cursor.execute("select last_value from dem.org_category_id_seq") 735 [org_cat_id_seq] = cursor.fetchone() 736 737 cursor.execute(""" 738 insert into dem.org_category ( description, id) 739 values ( 'xxxDEFAULTxxx',%d) 740 """ % (org_cat_id_seq + 1 ) ) 741 cursor.execute(""" 742 delete from dem.org_category where description like 'xxxDEFAULTxxx' """ ) 743 # make sure this exercise is committed, else a deadlock will occur 744 conn.commit() 745 except: 746 _log.exception("Test of Update Permission failed") 747 return False 748 return True
749
750 - def login_rw_user():
751 return login_user_and_test( test_rw_user, "login cannot update org", use_prefix_rw = True)
752 753
754 - def login_admin_user():
755 return login_user_and_test( test_admin_user, "login cannot update org_category" )
756 757
758 - def create_temp_categories( categories = ['hospital']):
759 print "NEED TO CREATE TEMPORARY ORG_CATEGORY.\n\n ** PLEASE ENTER administrator login : e.g user 'gm-dbo' and his password" 760 #get a admin login 761 for i in xrange(0, 4): 762 result ,tmplogin = login_admin_user() 763 if result: 764 break 765 if i == 4: 766 print "Failed to login" 767 return categories 768 769 # and save it , for later removal of test categories. 770 from Gnumed.pycommon import gmLoginInfo 771 adminlogin = gmLoginInfo.LoginInfo(*tmplogin.GetInfo()) 772 773 #login as admin 774 p = gmPG.ConnectionPool( tmplogin) 775 conn = p.GetConnection("personalia") 776 777 # use the last value + 1 of the relevant sequence, but don't increment it 778 cursor = conn.cursor() 779 780 failed_categories = [] 781 n =1 782 for cat in categories: 783 cursor.execute("select last_value from dem.org_category_id_seq") 784 [org_cat_id_seq] = cursor.fetchone() 785 786 cursor.execute( "insert into dem.org_category(description, id) values('%s', %d)" % (cat, org_cat_id_seq + n) ) 787 cursor.execute("select id from dem.org_category where description in ('%s')" % cat) 788 789 result = cursor.fetchone() 790 if result == None or len(result) == 0: 791 failed_categories.append(cat) 792 print "Failed insert of category", cat 793 conn.rollback() 794 else: 795 conn.commit() 796 n += 1 797 798 conn.commit() 799 p.ReleaseConnection('personalia') 800 return failed_categories, adminlogin
801
802 - def clean_org_categories(adminlogin = None, categories = ['hospital'], service='personalia'):
803 804 print""" 805 806 The temporary category(s) will now 807 need to be removed under an administrator login 808 e.g. gm-dbo 809 Please enter login for administrator: 810 """ 811 if adminlogin is None: 812 for i in xrange(0, 4): 813 result, adminlogin = login_admin_user() 814 if result: 815 break 816 if i == 4: 817 print "FAILED TO LOGIN" 818 return categories 819 820 p = gmPG.ConnectionPool(adminlogin) 821 conn = p.GetConnection(service) 822 failed_remove = [] 823 for cat in categories: 824 try: 825 cursor = conn.cursor() 826 cursor.execute( "delete from dem.org_category where description in ('%s')"%cat) 827 conn.commit() 828 cursor.execute("select id from dem.org_category where description in ('%s')"%cat) 829 if cursor.fetchone() == None: 830 print "Succeeded in removing temporary org_category" 831 else: 832 print "*** Unable to remove temporary org_category" 833 failed_remove .append(cat) 834 except: 835 import sys 836 print sys.exc_info()[0], sys.exc_info()[1] 837 import traceback 838 traceback.print_tb(sys.exc_info()[2]) 839 840 failed_remove.append(cat) 841 842 conn = None 843 p.ReleaseConnection(service) 844 if failed_remove <> []: 845 print "FAILED TO REMOVE ", failed_remove 846 return failed_remove
847
848 - def test_CatFinder():
849 print "TESTING cCatFinder" 850 851 print """c = cCatFinder("org_category")""" 852 c = cCatFinder("org_category") 853 854 print c.getCategories("org_category") 855 856 print """c = cCatFinder("enum_comm_types")""" 857 c = cCatFinder("enum_comm_types") 858 859 l = c.getCategories("enum_comm_types") 860 print "testing getId()" 861 l2 = [] 862 for x in l: 863 l2.append((x, c.getId("enum_comm_types", x))) 864 print l2 865 866 print """testing borg behaviour of cCatFinder""" 867 868 print c.getCategories("org_category")
869 870
871 - def help():
872 print """\nNB If imports not found , try: 873 874 change to gnumed/client directory , then 875 876 export PYTHONPATH=$PYTHONPATH:../;python business/gmOrganization.py 877 878 --clean , cleans the test data and categories 879 880 --gui sets up as for no arguments, then runs the client. 881 on normal exit of client, normal tests run, and 882 then cleanup of entered data. 883 884 using the gui, 885 886 the 'list organisations' toolbar button , loads all organisations 887 in the database, and display suborgs and persons associated 888 with each organisation. 889 890 the 'add organisation' button will add a top-level organisation. 891 the 'add branch/division' button will work when the last selected 892 org was a top level org. 893 894 the 'add person M|F' button works if an org is selected. 895 896 the save button works when entry is finished. 897 898 selecting on an item, will bring it into the editing area. 899 900 No test yet for dirtied edit data, to query whether to 901 save or discard. (30/5/2004) 902 """ 903 print 904 print "In the connection query, please enter" 905 print "a WRITE-ENABLED user e.g. _test-doc (not test-doc), and the right password" 906 print 907 print "Run the unit test with cmdline argument '--clean' if trying to clean out test data" 908 print 909 910 print """You can get a sermon by running 911 export PYTHONPATH=$PYTHONPATH:../;python business/gmOrganization.py --sermon 912 """ 913 print """ 914 Pre-requisite data in database is : 915 gnumed=# select * from org_category ; 916 id | description 917 ----+------------- 918 1 | hospital 919 (1 row) 920 921 gnumed=# select * from enum_comm_types ; 922 id | description 923 ----+------------- 924 1 | email 925 2 | fax 926 3 | homephone 927 4 | workphone 928 5 | mobile 929 6 | web 930 7 | jabber 931 (7 rows) 932 """
933
934 - def sermon():
935 print""" 936 This test case shows how many things can go wrong , even with just a test case. 937 Problem areas include: 938 - postgres administration : pg_ctl state, pg_hba.conf, postgres.conf config files . 939 - schema integrity constraints : deletion of table entries which are subject to foreign keys, no input for no default value and no null value columns, input with duplicated values where unique key constraint applies to non-primary key columns, dealing with access control by connection identity management. 940 941 942 - efficiency trade-offs -e.g. using db objects for localising code with data and easier function call interface ( then hopefully, easier to program with) , vs. need to access many objects at once 943 without calling the backend for each object. 944 945 - error and exception handling - at what point in the call stack to handle an error. 946 Better to use error return values and log exceptions near where they occur, vs. wrapping inside try: except: blocks and catching typed exceptions. 947 948 949 - test-case construction: test data is needed often, and the issue 950 is whether it is better to keep the test data volatile in the test-case, 951 which handles both its creation and deletion, or to add it to test data 952 server configuration files, which may involve running backend scripts 953 for loading and removing test data. 954 955 956 957 - Database connection problems: 958 -Is the problem in : 959 - pg_ctl start -D /...mydata-directory is wrong, and gnumed isn't existing there. 960 961 - ..mydata-directory/pg_hba.conf 962 - can psql connect locally and remotely with the username and password. 963 - Am I using md5 authenentication and I've forgotten the password. 964 - I need to su postgres, alter pg_hba.conf to use trust for 965 the gnumed database, pg_ctl restart -D .., su normal_user, psql gnumed, alter user my_username password 'doh' 966 - might be helpful: the default password for _test-doc is test-doc 967 968 - ../mydata-directory/postgres.conf 969 - tcp connect flag isn't set to true 970 971 - remote/local mixup : 972 a different set of user passwords on different hosts. e.g the password 973 for _test-doc is 'pass' on localhost and 'test-doc' for the serverhost. 974 - In the prompts for admin and user login, local host was used for one, and 975 remote host for the other 976 977 978 979 - test data won't go away : 980 - 'hospital' category in org_category : the test case failed in a previous run 981 and the test data was left there; now the test case won't try to delete it 982 because it exists as a pre-existing category; 983 soln : run with --clean option 984 985 - test-case failed unexpectedly, or break key was hit in the middle of a test-case run. 986 Soln: run with --clean option, 987 988 989 """
990 991 992 #============================================================ 993 994 import sys 995 testgui = False 996 if len(sys.argv) > 1: 997 if sys.argv[1] == '--clean': 998 result = clean_test_org() 999 p = gmPG.ConnectionPool() 1000 p.ReleaseConnection('personalia') 1001 if result: 1002 print "probably succeeded in cleaning orgs" 1003 else: print "failed to clean orgs" 1004 1005 clean_org_categories() 1006 sys.exit(1) 1007 1008 if sys.argv[1] == "--sermon": 1009 sermon() 1010 1011 if sys.argv[1] == "--help": 1012 help() 1013 1014 if sys.argv[1] =="--gui": 1015 testgui = True 1016 1017 print "*" * 50 1018 print "RUNNING UNIT TEST of gmOrganization " 1019 1020 1021 test_CatFinder() 1022 tmp_category = False # tmp_category means test data will need to be added and removed 1023 # for org_category . 1024 1025 c = cCatFinder() 1026 if not "hospital" in c.getCategories("org_category") : 1027 print "FAILED in prerequisite for org_category : test categories are not present." 1028 1029 tmp_category = True 1030 1031 if tmp_category: 1032 # test data in a categorical table (restricted access) is needed 1033 1034 print """You will need to switch login identity to database administrator in order 1035 to have permission to write to the org_category table, 1036 and then switch back to the ordinary write-enabled user in order 1037 to run the test cases. 1038 Finally you will need to switch back to administrator login to 1039 remove the temporary org_categories. 1040 """ 1041 categories = ['hospital'] 1042 result, adminlogin = create_temp_categories(categories) 1043 if result == categories: 1044 print "Unable to create temporary org_category. Test aborted" 1045 sys.exit(-1) 1046 if result <> []: 1047 print "UNABLE TO CREATE THESE CATEGORIES" 1048 if not raw_input("Continue ?") in ['y', 'Y'] : 1049 sys.exit(-1) 1050 1051 try: 1052 results = [] 1053 if tmp_category: 1054 print "succeeded in creating temporary org_category" 1055 print 1056 print "** Now ** RESUME LOGIN ** of write-enabled user (e.g. _test-doc) " 1057 while (1): 1058 # get the RW user for org tables (again) 1059 if login_rw_user(): 1060 break 1061 1062 if testgui: 1063 if cCatFinder().getId('org_category','hospital') == None: 1064 print "Needed to set up temporary org_category 'hospital" 1065 sys.exit(-1) 1066 import os 1067 print os.environ['PWD'] 1068 os.spawnl(os.P_WAIT, "/usr/bin/python", "/usr/bin/python","wxpython/gnumed.py", "--debug") 1069 1070 #os.popen2('python client/wxpython/gnumed.py --debug') 1071 1072 # run the test case 1073 results = testOrg() 1074 1075 # cleanup after the test case 1076 for (result , org) in results: 1077 if not result and org.getId() <> None: 1078 print "trying cleanup" 1079 if org.shallow_del(): print " may have succeeded" 1080 else: 1081 print "May need manual removal of org id =", org.getId() 1082 1083 testOrgPersons() 1084 1085 testListOrgs() 1086 1087 except: 1088 import sys 1089 print sys.exc_info()[0], sys.exc_info()[1] 1090 _log.exception( "Fatal exception") 1091 1092 # clean-up any temporary categories. 1093 if tmp_category: 1094 try: 1095 clean_org_categories(adminlogin) 1096 except: 1097 while(not login_rw_user()[0]): 1098 pass 1099 clean_test_org() 1100 clean_org_categories(adminlogin) 1101 1102 1103
1104 -def setPostcodeWidgetFromUrbId(postcodeWidget, id_urb):
1105 """convenience method for urb and postcode phrasewheel interaction. 1106 never called without both arguments, but need to check that id_urb 1107 is not invalid""" 1108 #TODO type checking that the postcodeWidget is a phrasewheel configured 1109 # with a postcode matcher 1110 if postcodeWidget is None or id_urb is None: 1111 return False 1112 postcode = getPostcodeForUrbId(id_urb) 1113 if postcode is None: 1114 return False 1115 if len(postcode) == 0: 1116 return True 1117 postcodeWidget.SetValue(postcode) 1118 postcodeWidget.input_was_selected= 1 1119 return True
1120 1121 #------------------------------------------------------------ 1122
1123 -def setUrbPhraseWheelFromPostcode(pwheel, postcode):
1124 """convenience method for common postcode to urb phrasewheel collaboration. 1125 there is no default args for these utility functions, 1126 This function is never called without both arguments, otherwise 1127 there is no intention (= modify the urb phrasewheel with postcode value). 1128 """ 1129 # TODO type checking that the pwheel is a urb phrasewheel with a urb matcher 1130 # clearing post code unsets target 1131 # phrasewheel's postcode context 1132 if pwheel is None: 1133 return False 1134 if postcode == '': 1135 pwheel.set_context("postcode", "%") 1136 return True 1137 urbs = getUrbsForPostcode(postcode) 1138 if urbs is None: 1139 return False 1140 if len(urbs) == 0: 1141 return True 1142 pwheel.SetValue(urbs[0]) 1143 pwheel.input_was_selected = 1 1144 1145 # FIXME: once the postcode context is set, 1146 # the urb phrasewheel will only return urbs with 1147 # the same postcode. These can be viewed by clearing 1148 # the urb widget. ?How to unset the postcode context, 1149 # some gui gesture ? clearing the postcode 1150 # (To view all the urbs for a set context, 1151 # put a "*" in the urb box and activate the picklist. 1152 # THE PROBLEM WITH THIS IS IF THE USER CLEARS THE BOX AND SET CONTEXT IS RESET, 1153 # then the "*" will try to pull all thousands of urb names, freezing the app. 1154 # so needs a fixup (? have SQL select ... LIMIT n in Phrasewheel ) 1155 1156 pwheel.set_context("postcode", postcode) 1157 return True
1158 1159 #====================================================================== 1160