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

Source Code for Module Gnumed.business.gmExportArea

  1  """GNUmed export area 
  2   
  3  Think shopping cart in a web shop. 
  4   
  5  This is where you want to put documents for further 
  6  processing by you or someone else, like your secretary. 
  7  """ 
  8  #============================================================ 
  9  __license__ = "GPL v2 or later" 
 10  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>" 
 11   
 12   
 13  import sys 
 14  import logging 
 15  import shutil 
 16  import os 
 17  import io 
 18   
 19   
 20  if __name__ == '__main__': 
 21          sys.path.insert(0, '../../') 
 22          from Gnumed.pycommon import gmI18N 
 23          gmI18N.activate_locale() 
 24          gmI18N.install_domain() 
 25  from Gnumed.pycommon import gmTools 
 26  from Gnumed.pycommon import gmBusinessDBObject 
 27  from Gnumed.pycommon import gmPG2 
 28  from Gnumed.pycommon import gmMimeLib 
 29  from Gnumed.pycommon import gmDateTime 
 30  from Gnumed.pycommon import gmCfg2 
 31  from Gnumed.pycommon import gmCrypto 
 32   
 33  from Gnumed.business import gmDocuments 
 34  from Gnumed.business import gmKeywordExpansion 
 35   
 36   
 37  _log = logging.getLogger('gm.exp_area') 
 38   
 39  PRINT_JOB_DESIGNATION = 'print' 
 40   
 41  #============================================================ 
 42  # export area item handling 
 43  #------------------------------------------------------------ 
 44  _SQL_get_export_items = "SELECT * FROM clin.v_export_items WHERE %s" 
 45   
46 -class cExportItem(gmBusinessDBObject.cBusinessDBObject):
47 """Represents an item in the export area table""" 48 49 _cmd_fetch_payload = _SQL_get_export_items % "pk_export_item = %s" 50 _cmds_store_payload = [ 51 """UPDATE clin.export_item SET 52 fk_identity = %(pk_identity)s, 53 created_by = gm.nullify_empty_string(%(created_by)s), 54 created_when = %(created_when)s, 55 designation = gm.nullify_empty_string(%(designation)s), 56 description = gm.nullify_empty_string(%(description)s), 57 fk_doc_obj = %(pk_doc_obj)s, 58 data = CASE 59 WHEN %(pk_doc_obj)s IS NULL THEN coalesce(data, 'to be replaced by real data') 60 ELSE NULL 61 END, 62 filename = CASE 63 WHEN %(pk_doc_obj)s IS NULL THEN gm.nullify_empty_string(%(filename)s) 64 ELSE NULL 65 END 66 WHERE 67 pk = %(pk_export_item)s 68 AND 69 xmin = %(xmin_export_item)s 70 """, 71 _SQL_get_export_items % 'pk_export_item = %(pk_export_item)s' 72 ] 73 _updatable_fields = [ 74 'pk_identity', 75 'created_when', 76 'designation', 77 'description', 78 'pk_doc_obj', 79 'filename' 80 ] 81 #--------------------------------------------------------
82 - def __init__(self, aPK_obj=None, row=None, link_obj=None):
83 super(cExportItem, self).__init__(aPK_obj = aPK_obj, row = row, link_obj = link_obj) 84 # force auto-healing if need be 85 if self._payload[self._idx['pk_identity_raw_needs_update']]: 86 _log.warning ( 87 'auto-healing export item [%s] from identity [%s] to [%s] because of document part [%s] seems necessary', 88 self._payload[self._idx['pk_export_item']], 89 self._payload[self._idx['pk_identity_raw']], 90 self._payload[self._idx['pk_identity']], 91 self._payload[self._idx['pk_doc_obj']] 92 ) 93 if self._payload[self._idx['pk_doc_obj']] is None: 94 _log.error('however, .fk_doc_obj is NULL, which should not happen, leaving things alone for manual inspection') 95 return 96 # only flag ourselves as modified, do not actually 97 # modify any values, better safe than sorry 98 self._is_modified = True 99 self.save() 100 self.refetch_payload(ignore_changes = False, link_obj = link_obj)
101 102 #-------------------------------------------------------- 103 # def format(self): 104 # return u'%s' % self 105 #--------------------------------------------------------
106 - def update_data_from_file(self, filename=None):
107 # sanity check 108 if not (os.access(filename, os.R_OK) and os.path.isfile(filename)): 109 _log.error('[%s] is not a readable file' % filename) 110 return False 111 112 cmd = """ 113 UPDATE clin.export_item SET 114 data = %(data)s::bytea, 115 fk_doc_obj = NULL, 116 filename = gm.nullify_empty_string(%(fname)s) 117 WHERE pk = %(pk)s""" 118 args = {'pk': self.pk_obj, 'fname': filename} 119 if not gmPG2.file2bytea(query = cmd, filename = filename, args = args): 120 return False 121 122 # must update XMIN now ... 123 self.refetch_payload() 124 return True
125 126 #--------------------------------------------------------
127 - def save_to_file(self, aChunkSize=0, filename=None, directory=None):
128 129 # data linked from archive 130 if self._payload[self._idx['pk_doc_obj']] is not None: 131 part = self.document_part 132 if filename is None: 133 filename = part.get_useful_filename ( 134 make_unique = False, 135 directory = directory, 136 include_gnumed_tag = False, 137 date_before_type = True, 138 name_first = False 139 ) 140 return part.save_to_file ( 141 aChunkSize = aChunkSize, 142 filename = filename, 143 ignore_conversion_problems = True, 144 adjust_extension = True 145 ) 146 147 # data in export area table 148 if filename is None: 149 filename = self.get_useful_filename(directory = directory) 150 151 success = gmPG2.bytea2file ( 152 data_query = { 153 'cmd': 'SELECT substring(data from %(start)s for %(size)s) FROM clin.export_item WHERE pk = %(pk)s', 154 'args': {'pk': self.pk_obj} 155 }, 156 filename = filename, 157 chunk_size = aChunkSize, 158 data_size = self._payload[self._idx['size']] 159 ) 160 if not success: 161 return None 162 163 if filename.endswith('.dat'): 164 return gmMimeLib.adjust_extension_by_mimetype(filename) 165 166 return filename
167 168 #--------------------------------------------------------
169 - def display_via_mime(self, chunksize=0, block=None):
170 171 if self._payload[self._idx['pk_doc_obj']] is not None: 172 return self.document_part.display_via_mime(chunksize = chunksize, block = block) 173 174 fname = self.save_to_file(aChunkSize = chunksize) 175 if fname is None: 176 return False, '' 177 178 success, msg = gmMimeLib.call_viewer_on_file(fname, block = block) 179 if not success: 180 return False, msg 181 182 return True, ''
183 184 #--------------------------------------------------------
185 - def get_useful_filename(self, patient=None, directory=None):
186 patient_part = '' 187 if patient is not None: 188 patient_part = '-%s' % patient.subdir_name 189 190 # preserve original filename extension if available 191 suffix = '.dat' 192 if self._payload[self._idx['filename']] is not None: 193 tmp, suffix = os.path.splitext ( 194 gmTools.fname_sanitize(self._payload[self._idx['filename']]).lower() 195 ) 196 if suffix == '': 197 suffix = '.dat' 198 199 fname = gmTools.get_unique_filename ( 200 prefix = 'gm-export_item%s-' % patient_part, 201 suffix = suffix, 202 tmp_dir = directory 203 ) 204 205 return fname
206 207 #-------------------------------------------------------- 208 # properties 209 #--------------------------------------------------------
210 - def _get_doc_part(self):
211 if self._payload[self._idx['pk_doc_obj']] is None: 212 return None 213 return gmDocuments.cDocumentPart(aPK_obj = self._payload[self._idx['pk_doc_obj']])
214 215 document_part = property(_get_doc_part, lambda x:x) 216 217 #--------------------------------------------------------
218 - def _get_is_print_job(self):
219 return self._payload[self._idx['designation']] == PRINT_JOB_DESIGNATION
220
221 - def _set_is_print_job(self, is_print_job):
222 desig = gmTools.bool2subst(is_print_job, PRINT_JOB_DESIGNATION, None, None) 223 if self._payload[self._idx['designation']] == desig: 224 return 225 self['designation'] = desig 226 self.save()
227 228 is_print_job = property(_get_is_print_job, _set_is_print_job)
229 230 #------------------------------------------------------------
231 -def get_export_items(order_by=None, pk_identity=None, designation=None):
232 233 args = { 234 'pat': pk_identity, 235 'desig': gmTools.coalesce(designation, PRINT_JOB_DESIGNATION) 236 } 237 where_parts = [] 238 if pk_identity is not None: 239 where_parts.append('pk_identity = %(pat)s') 240 # note that invalidly linked items will be 241 # auto-healed when instantiated 242 if designation is None: 243 where_parts.append("designation IS DISTINCT FROM %(desig)s") 244 else: 245 where_parts.append('designation = %(desig)s') 246 247 if order_by is None: 248 order_by = '' 249 else: 250 order_by = ' ORDER BY %s' % order_by 251 252 cmd = (_SQL_get_export_items % ' AND '.join(where_parts)) + order_by 253 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 254 255 return [ cExportItem(row = {'data': r, 'idx': idx, 'pk_field': 'pk_export_item'}) for r in rows ]
256 257 #------------------------------------------------------------
258 -def get_print_jobs(order_by=None, pk_identity=None):
259 return get_export_items(order_by = order_by, pk_identity = pk_identity, designation = PRINT_JOB_DESIGNATION)
260 261 #------------------------------------------------------------
262 -def create_export_item(description=None, pk_identity=None, pk_doc_obj=None, filename=None):
263 264 args = { 265 'desc': description, 266 'pk_obj': pk_doc_obj, 267 'pk_pat': pk_identity, 268 'fname': filename 269 } 270 cmd = """ 271 INSERT INTO clin.export_item ( 272 description, 273 fk_doc_obj, 274 fk_identity, 275 data, 276 filename 277 ) VALUES ( 278 gm.nullify_empty_string(%(desc)s), 279 %(pk_obj)s, 280 %(pk_pat)s, 281 (CASE 282 WHEN %(pk_obj)s IS NULL THEN %(fname)s::bytea 283 ELSE NULL::bytea 284 END), 285 (CASE 286 WHEN %(pk_obj)s IS NULL THEN gm.nullify_empty_string(%(fname)s) 287 ELSE NULL 288 END) 289 ) 290 RETURNING pk 291 """ 292 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 293 294 return cExportItem(aPK_obj = rows[0]['pk'])
295 296 #------------------------------------------------------------
297 -def delete_export_item(pk_export_item=None):
298 args = {'pk': pk_export_item} 299 cmd = "DELETE FROM clin.export_item WHERE pk = %(pk)s" 300 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 301 return True
302 303 #============================================================ 304 _html_start = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 305 "http://www.w3.org/TR/html4/loose.dtd"> 306 <html> 307 <head> 308 <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 309 <link rel="icon" type="image/x-icon" href="gnumed.ico"> 310 <title>%(html_title_header)s %(html_title_patient)s</title> 311 </head> 312 <body> 313 314 <h1>%(title)s</h1> 315 316 <h2>Patient</h2> 317 318 <p> 319 %(pat_name)s<br> 320 %(pat_dob)s 321 </p> 322 323 <p><img src="%(mugshot_url)s" alt="%(mugshot_alt)s" title="%(mugshot_title)s" width="200" border="2"></p> 324 325 <h2>%(docs_title)s</h2> 326 327 <ul> 328 <li><a href="./">%(browse_root)s</a></li> 329 <li><a href="documents/">%(browse_docs)s</a></li> 330 %(browse_dicomdir)s 331 %(run_dicom_viewer)s 332 </ul> 333 334 <ul> 335 """ 336 337 # <li><a href="documents/filename-1.ext">document 1 description</a></li> 338 339 _html_list_item = """ <li><a href="documents/%s">%s</a></li> 340 """ 341 342 _html_end = """ 343 </ul> 344 345 <p> 346 %(date)s<br> 347 </p> 348 349 <h2>Praxis</h2> 350 351 <p> 352 %(branch)s @ %(praxis)s 353 %(adr)s 354 </p> 355 356 <p>(<a href="http://www.gnumed.de">GNUmed</a> version %(gm_ver)s)</p> 357 358 </body> 359 </html> 360 """ 361 362 363 _autorun_inf = ( # needs \r\n for Windows 364 '[AutoRun.Amd64]\r\n' # 64 bit 365 'label=%(label)s\r\n' # patient name/DOB 366 'shellexecute=index.html\r\n' 367 'action=%(action)s\r\n' # % _('Browse patient data') 368 '%(icon)s\r\n' # "icon=gnumed.ico" or "" 369 'UseAutoPlay=1\r\n' 370 '\r\n' 371 '[AutoRun]\r\n' # 32 bit 372 'label=%(label)s\r\n' # patient name/DOB 373 'shellexecute=index.html\r\n' 374 'action=%(action)s\r\n' # % _('Browse patient data') 375 '%(icon)s\r\n' # "icon=gnumed.ico" or "" 376 'UseAutoPlay=1\r\n' 377 '\r\n' 378 '[Content]\r\n' 379 'PictureFiles=yes\r\n' 380 'VideoFiles=yes\r\n' 381 'MusicFiles=no\r\n' 382 '\r\n' 383 '[IgnoreContentPaths]\r\n' 384 '\documents\r\n' 385 '\r\n' 386 '[unused]\r\n' 387 'open=requires explicit executable\r\n' 388 ) 389 390 391 _cd_inf = ( 392 '[Patient Info]\r\n' # needs \r\n for Windows 393 'PatientName=%s, %s\r\n' 394 'Gender=%s\r\n' 395 'BirthDate=%s\r\n' 396 'CreationDate=%s\r\n' 397 'PID=%s\r\n' 398 'EMR=GNUmed\r\n' 399 'Version=%s\r\n' 400 '#StudyDate=\r\n' 401 '#VNRInfo=<body part>\r\n' 402 '\r\n' 403 '# name format: lastnames, firstnames\r\n' 404 '# date format: YYYY-MM-DD (ISO 8601)\r\n' 405 '# gender format: %s\r\n' 406 ) 407 408 _README = """This is a patient data bundle created by the GNUmed Electronic Medical Record. 409 410 Patient: %s 411 412 Please display <index.html> to browse patient data. 413 414 Individual documents are stored under 415 416 ./documents/ 417 """ 418 419 #------------------------------------------------------------
420 -class cExportArea(object):
421
422 - def __init__(self, pk_identity):
423 self.__pk_identity = pk_identity
424 425 #--------------------------------------------------------
426 - def add_form(self, form=None, designation=None):
427 428 if len(form.final_output_filenames) == 0: 429 return True 430 431 items = [] 432 for fname in form.final_output_filenames: 433 item = self.add_file(filename = fname) 434 if item is None: 435 for prev_item in items: 436 delete_export_item(pk_export_item = prev_item['pk_export_item']) 437 return False 438 items.append(item) 439 item['description'] = _('form: %s %s (%s)') % (form.template['name_long'], form.template['external_version'], fname) 440 item['designation'] = designation 441 item.save() 442 443 return True
444 #--------------------------------------------------------
445 - def add_forms(self, forms=None, designation=None):
446 all_ok = True 447 for form in forms: 448 all_ok = all_ok and self.add_form(form = form, designation = designation) 449 450 return all_ok
451 #--------------------------------------------------------
452 - def add_file(self, filename=None, hint=None):
453 try: 454 open(filename).close() 455 except Exception: 456 _log.exception('cannot open file <%s>', filename) 457 return None 458 459 file_md5 = gmTools.file2md5(filename = filename, return_hex = True) 460 existing_item = self.md5_exists(md5 = file_md5, include_document_parts = False) 461 if existing_item is not None: 462 _log.debug('md5 match (%s): %s already in export area', file_md5, filename) 463 return existing_item 464 465 path, basename = os.path.split(filename) 466 item = create_export_item ( 467 description = '%s: %s (%s/)' % ( 468 gmTools.coalesce(hint, _('file'), '%s'), 469 basename, 470 path 471 ), 472 pk_identity = self.__pk_identity, 473 filename = filename 474 ) 475 476 if item.update_data_from_file(filename = filename): 477 return item 478 479 delete_export_item(pk_export_item = item['pk_export_item']) 480 return None
481 482 #--------------------------------------------------------
483 - def add_files(self, filenames=None, hint=None):
484 all_ok = True 485 for fname in filenames: 486 all_ok = all_ok and (self.add_file(filename = fname, hint = hint) is not None) 487 488 return all_ok
489 490 #--------------------------------------------------------
491 - def add_documents(self, documents=None):
492 for doc in documents: 493 doc_tag = _('%s (%s)%s') % ( 494 doc['l10n_type'], 495 gmDateTime.pydt_strftime(doc['clin_when'], '%Y %b %d'), 496 gmTools.coalesce(doc['comment'], '', ' "%s"') 497 ) 498 for obj in doc.parts: 499 if self.document_part_item_exists(pk_part = obj['pk_obj']): 500 continue 501 f_ext = '' 502 if obj['filename'] is not None: 503 f_ext = os.path.splitext(obj['filename'])[1].strip('.').strip() 504 if f_ext != '': 505 f_ext = ' .' + f_ext.upper() 506 obj_tag = _('part %s (%s%s)%s') % ( 507 obj['seq_idx'], 508 gmTools.size2str(obj['size']), 509 f_ext, 510 gmTools.coalesce(obj['obj_comment'], '', ' "%s"') 511 ) 512 create_export_item ( 513 description = '%s - %s' % (doc_tag, obj_tag), 514 pk_doc_obj = obj['pk_obj'] 515 )
516 517 #--------------------------------------------------------
518 - def document_part_item_exists(self, pk_part=None):
519 cmd = "SELECT EXISTS (SELECT 1 FROM clin.export_item WHERE fk_doc_obj = %(pk_obj)s)" 520 args = {'pk_obj': pk_part} 521 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 522 return rows[0][0]
523 524 #--------------------------------------------------------
525 - def md5_exists(self, md5=None, include_document_parts=False):
526 where_parts = [ 527 'pk_identity = %(pat)s', 528 'md5_sum = %(md5)s' 529 ] 530 args = { 531 'pat': self.__pk_identity, 532 'md5': md5 533 } 534 535 if not include_document_parts: 536 where_parts.append('pk_doc_obj IS NULL') 537 538 cmd = _SQL_get_export_items % ' AND '.join(where_parts) 539 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 540 541 if len(rows) == 0: 542 return None 543 544 r = rows[0] 545 return cExportItem(row = {'data': r, 'idx': idx, 'pk_field': 'pk_export_item'})
546 547 #--------------------------------------------------------
548 - def dump_items_to_disk(self, base_dir=None, items=None):
549 if items is None: 550 items = self.items 551 if len(items) == 0: 552 return None 553 if base_dir is None: 554 from Gnumed.business.gmPerson import cPatient 555 pat = cPatient(aPK_obj = self.__pk_identity) 556 base_dir = os.path.join(gmTools.mk_sandbox_dir(), pat.subdir_name) 557 gmTools.mkdir(base_dir) 558 _log.debug('dumping export items to: %s', base_dir) 559 for item in items: 560 item.save_to_file(directory = base_dir) 561 return base_dir
562 563 #--------------------------------------------------------
564 - def dump_items_to_disk_as_zip(self, base_dir=None, items=None, passphrase=None):
565 dump_dir = self.dump_items_to_disk(base_dir = base_dir, items = items) 566 if dump_dir is None: 567 _log.debug('cannot dump export area items') 568 return None 569 _cfg = gmCfg2.gmCfgData() 570 zip_file = gmTools.create_zip_archive_from_dir ( 571 dump_dir, 572 comment = _('GNUmed Patient Media'), 573 overwrite = True, 574 passphrase = passphrase, 575 verbose = _cfg.get(option = 'debug') 576 ) 577 if zip_file is None: 578 gmGuiHelpers.gm_show_error ( 579 aMessage = _('Error creating zip file.'), 580 aTitle = _('Creating zip archive') 581 ) 582 return zip_file
583 584 #--------------------------------------------------------
585 - def export(self, base_dir=None, items=None):
586 587 if items is None: 588 items = self.items 589 590 if len(items) == 0: 591 return None 592 593 media_base_dir = base_dir 594 595 from Gnumed.business.gmPerson import cPatient 596 pat = cPatient(aPK_obj = self.__pk_identity) 597 if media_base_dir is None: 598 media_base_dir = os.path.join(gmTools.mk_sandbox_dir(), pat.subdir_name) 599 gmTools.mkdir(media_base_dir) 600 _log.debug('patient media base dir: %s', media_base_dir) 601 602 doc_dir = os.path.join(media_base_dir, r'documents') 603 if os.path.isdir(doc_dir): 604 index_existing_docs = True 605 else: 606 index_existing_docs = False 607 gmTools.mkdir(doc_dir) 608 609 _html_start_data = { 610 'html_title_header': _('Patient data for'), 611 'html_title_patient': gmTools.html_escape_string(pat.get_description_gender(with_nickname = False) + ', ' + _('born') + ' ' + pat.get_formatted_dob('%Y %B %d')), 612 'title': _('Patient data excerpt'), 613 'pat_name': gmTools.html_escape_string(pat.get_description_gender(with_nickname = False)), 614 'pat_dob': gmTools.html_escape_string(_('born') + ' ' + pat.get_formatted_dob('%Y %B %d')), 615 'mugshot_url': 'documents/no-such-file.png', 616 'mugshot_alt': _('no patient photograph available'), 617 'mugshot_title': '', 618 'docs_title': _('Documents'), 619 'browse_root': _('browse storage medium'), 620 'browse_docs': _('browse documents area'), 621 'browse_dicomdir': '', 622 'run_dicom_viewer': '' 623 } 624 625 mugshot = pat.document_folder.latest_mugshot 626 if mugshot is not None: 627 _html_start_data['mugshot_url'] = mugshot.save_to_file(directory = doc_dir, adjust_extension = True) 628 _html_start_data['mugshot_alt'] =_('patient photograph from %s') % gmDateTime.pydt_strftime(mugshot['date_generated'], '%B %Y') 629 _html_start_data['mugshot_title'] = gmDateTime.pydt_strftime(mugshot['date_generated'], '%B %Y') 630 631 if 'DICOMDIR' in os.listdir(media_base_dir): 632 _html_start_data['browse_dicomdir'] = '<li><a href="./DICOMDIR">%s</a></li>' % _('show DICOMDIR file') 633 # copy DWV into target dir 634 dwv_src_dir = os.path.join(gmTools.gmPaths().local_base_dir, 'resources', 'dwv4export') 635 if not os.path.isdir(dwv_src_dir): 636 dwv_src_dir = os.path.join(gmTools.gmPaths().system_app_data_dir, 'resources', 'dwv4export') 637 if os.path.isdir(dwv_src_dir): 638 dwv_target_dir = os.path.join(media_base_dir, 'dwv') 639 gmTools.rmdir(dwv_target_dir) 640 try: 641 shutil.copytree(dwv_src_dir, dwv_target_dir) 642 _html_start_data['run_dicom_viewer'] = '<li><a href="./dwv/viewers/mobile-local/index.html">%s</a></li>' % _('run Radiology Images (DICOM) Viewer') 643 except (shutil.Error, OSError): 644 _log.exception('cannot include DWV, skipping') 645 646 # index.html 647 # - header 648 idx_fname = os.path.join(media_base_dir, 'index.html') 649 idx_file = io.open(idx_fname, mode = 'wt', encoding = 'utf8') 650 idx_file.write(_html_start % _html_start_data) 651 # - middle (side effect ! -> exports items into files ...) 652 existing_docs = os.listdir(doc_dir) # get them now, or else we will include the to-be-exported items 653 # - export items 654 for item in items: 655 item_path = item.save_to_file(directory = doc_dir) 656 item_fname = os.path.split(item_path)[1] 657 idx_file.write(_html_list_item % ( 658 item_fname, 659 gmTools.html_escape_string(item['description']) 660 )) 661 # - preexisting documents 662 for doc_fname in existing_docs: 663 idx_file.write(_html_list_item % ( 664 doc_fname, 665 gmTools.html_escape_string(_('other: %s') % doc_fname) 666 )) 667 # - footer 668 _cfg = gmCfg2.gmCfgData() 669 from Gnumed.business.gmPraxis import gmCurrentPraxisBranch 670 prax = gmCurrentPraxisBranch() 671 lines = [] 672 adr = prax.branch.org_unit.address 673 if adr is not None: 674 lines.extend(adr.format()) 675 for comm in prax.branch.org_unit.comm_channels: 676 if comm['is_confidential'] is True: 677 continue 678 lines.append('%s: %s' % ( 679 comm['l10n_comm_type'], 680 comm['url'] 681 )) 682 adr = '' 683 if len(lines) > 0: 684 adr = gmTools.html_escape_string('\n'.join(lines), replace_eol = True, keep_visual_eol = True) 685 _html_end_data = { 686 'branch': gmTools.html_escape_string(prax['branch']), 687 'praxis': gmTools.html_escape_string(prax['praxis']), 688 'date' : gmTools.html_escape_string(gmDateTime.pydt_strftime(gmDateTime.pydt_now_here(), format = '%Y %B %d')), 689 'gm_ver': gmTools.html_escape_string(gmTools.coalesce(_cfg.get(option = 'client_version'), 'git HEAD')), 690 'adr': adr 691 } 692 idx_file.write(_html_end % _html_end_data) 693 idx_file.close() 694 695 # start.html (just a copy of index.html, really ;-) 696 start_fname = os.path.join(media_base_dir, 'start.html') 697 try: 698 shutil.copy2(idx_fname, start_fname) 699 except Exception: 700 _log.exception('cannot copy %s to %s', idx_fname, start_fname) 701 702 # autorun.inf 703 autorun_dict = {} 704 autorun_dict['label'] = self._compute_autorun_inf_label(pat) 705 autorun_dict['action'] = _('Browse patient data') 706 autorun_dict['icon'] = '' 707 media_icon_kwd = '$$gnumed_patient_media_export_icon' 708 media_icon_kwd_exp = gmKeywordExpansion.get_expansion ( 709 keyword = media_icon_kwd, 710 textual_only = False, 711 binary_only = True 712 ) 713 icon_tmp_file = media_icon_kwd_exp.save_to_file ( 714 target_mime = 'image/x-icon', 715 target_extension = '.ico', 716 ignore_conversion_problems = True 717 ) 718 if icon_tmp_file is None: 719 _log.debug('cannot retrieve <%s>', media_icon_kwd) 720 else: 721 media_icon_fname = os.path.join(media_base_dir, 'gnumed.ico') 722 try: 723 shutil.move(icon_tmp_file, media_icon_fname) 724 autorun_dict['icon'] = 'icon=gnumed.ico' 725 except Exception: 726 _log.exception('cannot move %s to %s', icon_tmp_file, media_icon_fname) 727 autorun_fname = os.path.join(media_base_dir, 'AUTORUN.INF') 728 autorun_file = io.open(autorun_fname, mode = 'wt', encoding = 'cp1252', errors = 'replace') 729 autorun_file.write(_autorun_inf % autorun_dict) 730 autorun_file.close() 731 732 # cd.inf 733 cd_inf_fname = os.path.join(media_base_dir, 'CD.INF') 734 cd_inf_file = io.open(cd_inf_fname, mode = 'wt', encoding = 'utf8') 735 cd_inf_file.write(_cd_inf % ( 736 pat['lastnames'], 737 pat['firstnames'], 738 gmTools.coalesce(pat['gender'], '?'), 739 pat.get_formatted_dob('%Y-%m-%d'), 740 gmDateTime.pydt_strftime(gmDateTime.pydt_now_here(), format = '%Y-%m-%d'), 741 pat.ID, 742 _cfg.get(option = 'client_version'), 743 ' / '.join([ '%s = %s (%s)' % (g['tag'], g['label'], g['l10n_label']) for g in pat.gender_list ]) 744 )) 745 cd_inf_file.close() 746 747 # README 748 readme_fname = os.path.join(media_base_dir, 'README') 749 readme_file = io.open(readme_fname, mode = 'wt', encoding = 'utf8') 750 readme_file.write(_README % ( 751 pat.get_description_gender(with_nickname = False) + ', ' + _('born') + ' ' + pat.get_formatted_dob('%Y %B %d') 752 )) 753 readme_file.close() 754 755 # patient demographics as GDT/XML/VCF/MCF 756 pat.export_as_gdt(filename = os.path.join(media_base_dir, 'patient.gdt')) 757 pat.export_as_xml_linuxmednews(filename = os.path.join(media_base_dir, 'patient.xml')) 758 pat.export_as_vcard(filename = os.path.join(media_base_dir, 'patient.vcf')) 759 pat.export_as_mecard(filename = os.path.join(media_base_dir, u'patient.mcf')) 760 761 # praxis VCF/MCF 762 shutil.move(prax.vcf, os.path.join(media_base_dir, 'praxis.vcf')) 763 prax.export_as_mecard(filename = os.path.join(media_base_dir, u'praxis.mcf')) 764 765 return media_base_dir
766 767 #--------------------------------------------------------
768 - def export_as_zip(self, base_dir=None, items=None, passphrase=None):
769 media_dir = self.export(base_dir = base_dir, items = items) 770 if media_dir is None: 771 _log.debug('cannot export items') 772 return None 773 _cfg = gmCfg2.gmCfgData() 774 if passphrase is None: 775 zip_file = gmCrypto.create_zip_archive_from_dir ( 776 media_dir, 777 comment = _('GNUmed Patient Media'), 778 overwrite = True, 779 verbose = _cfg.get(option = 'debug') 780 ) 781 else: 782 zip_file = gmCrypto.create_encrypted_zip_archive_from_dir ( 783 media_dir, 784 comment = _('GNUmed Patient Media'), 785 overwrite = True, 786 passphrase = passphrase, 787 verbose = _cfg.get(option = 'debug') 788 ) 789 if zip_file is None: 790 _log.debug('cannot create zip archive') 791 return None 792 return zip_file
793 794 #--------------------------------------------------------
795 - def _compute_autorun_inf_label(self, patient):
796 LABEL_MAX_LEN = 32 797 dob = patient.get_formatted_dob(format = ' %Y%m%d', none_string = '', honor_estimation = False) 798 if dob == '': 799 gender_template = ' (%s)' 800 else: 801 gender_template = ' %s' 802 gender = gmTools.coalesce(patient['gender'], '', gender_template) 803 name_max_len = LABEL_MAX_LEN - len(gender) - len(dob) # they already include appropriate padding 804 name = patient.active_name 805 last = name['lastnames'].strip() 806 first = name['firstnames'].strip() 807 len_last = len(last) 808 len_first = len(first) 809 while (len_last + len_first + 1) > name_max_len: 810 if len_first > 6: 811 len_first -= 1 812 if first[len_first - 1] == ' ': 813 len_first -= 1 814 continue 815 len_last -= 1 816 if last[len_last - 1] == ' ': 817 len_last -= 1 818 last = last[:len_last].strip().upper() 819 first = first[:len_first].strip() 820 # max 32 chars, supposedly ASCII, but CP1252 likely works pretty well 821 label = (('%s %s%s%s' % (last, first, dob, gender)).strip())[:32] 822 return label
823 824 #-------------------------------------------------------- 825 # properties 826 #--------------------------------------------------------
827 - def get_items(self, designation=None, order_by='designation, description'):
828 return get_export_items(order_by = order_by, pk_identity = self.__pk_identity, designation = designation)
829 830 items = property(get_items, lambda x:x) 831 #--------------------------------------------------------
832 - def get_printouts(self, order_by='designation, description'):
833 return get_print_jobs(order_by = order_by, pk_identity = self.__pk_identity)
834 835 printouts = property(get_printouts, lambda x:x)
836 837 #============================================================ 838 if __name__ == '__main__': 839 840 if len(sys.argv) < 2: 841 sys.exit() 842 843 if sys.argv[1] != 'test': 844 sys.exit() 845 846 from Gnumed.pycommon import gmI18N 847 gmI18N.activate_locale() 848 gmI18N.install_domain() 849 850 from Gnumed.business import gmPraxis 851 852 #---------------------------------------
853 - def test_export_items():
854 # items = get_export_items() 855 # for item in items: 856 # print item.format() 857 import random 858 create_export_item(description = 'description %s' % random.random(), pk_identity = 12, pk_doc_obj = None, filename = 'dummy.dat') 859 items = get_export_items() 860 for item in items: 861 print(item.format()) 862 item['pk_doc_obj'] = 1 863 item.save() 864 print(item)
865 866 #---------------------------------------
867 - def test_export_area():
868 exp = cExportArea(12) 869 #print exp.export_with_meta_data() 870 #print exp.items 871 exp.add_file(sys.argv[2]) 872 prax = gmPraxis.gmCurrentPraxisBranch(branch = gmPraxis.cPraxisBranch(1)) 873 print(prax) 874 print(prax.branch) 875 print(exp.export())
876 877 #---------------------------------------
878 - def test_label():
879 880 from Gnumed.business.gmPerson import cPatient 881 from Gnumed.business.gmPersonSearch import ask_for_patient 882 883 #while ask_for_patient() is not None: 884 pat_min = 1 885 pat_max = 100 886 try: 887 pat_min = int(sys.argv[2]) 888 pat_max = int(sys.argv[3]) 889 except: 890 pass 891 cPatient(aPK_obj = pat_min) 892 f = io.open('x-auto_inf_labels.txt', mode = 'w', encoding = 'utf8') 893 f.write('--------------------------------\n') 894 f.write('12345678901234567890123456789012\n') 895 f.write('--------------------------------\n') 896 for pat_id in range(pat_min, pat_max): 897 try: 898 exp_area = cExportArea(pat_id) 899 pat = cPatient(aPK_obj = pat_id) 900 except: 901 continue 902 f.write(exp_area._compute_autorun_inf_label(pat) + '\n') 903 f.close() 904 return
905 906 #--------------------------------------- 907 #test_export_items() 908 test_export_area() 909 #test_label() 910 911 sys.exit(0) 912 913 #============================================================ 914 # CDROM "run.bat": 915 # 916 #@echo off 917 # 918 #if defined ProgramFiles(x86) ( 919 # ::64-bit 920 # start /B x64\mdicom.exe /scan . 921 #) else ( 922 # ::32-bit 923 # start /B win32\mdicom.exe /scan . 924 #) 925 # 926 #-------------------------------------------------- 927