def add_file(self, filename=None, hint=None): try: open(filename).close() except Exception: _log.exception('cannot open file <%s>', filename) return None file_md5 = gmTools.file2md5(filename=filename, return_hex=True) existing_item = self.md5_exists(md5=file_md5, include_document_parts=False) if existing_item is not None: _log.debug('md5 match (%s): %s already in export area', file_md5, filename) return existing_item path, basename = os.path.split(filename) item = create_export_item( description=u'%s: %s (%s/)' % (gmTools.coalesce(hint, _(u'file'), u'%s'), basename, path), pk_identity=self.__pk_identity, filename=filename) if item.update_data_from_file(filename=filename): return item delete_export_item(pk_export_item=item['pk_export_item']) return None
def add_file(self, filename=None, hint=None): try: open(filename).close() except Exception: _log.exception('cannot open file <%s>', filename) return None file_md5 = gmTools.file2md5(filename = filename, return_hex = True) existing_item = self.md5_exists(md5 = file_md5, include_document_parts = False) if existing_item is not None: _log.debug('md5 match (%s): %s already in export area', file_md5, filename) return existing_item path, basename = os.path.split(filename) item = create_export_item ( description = u'%s: %s (%s/)' % ( gmTools.coalesce(hint, _(u'file'), u'%s'), basename, path ), pk_identity = self.__pk_identity, filename = filename ) if item.update_data_from_file(filename = filename): return item delete_export_item(pk_export_item = item['pk_export_item']) return None
def update_data_from_file(self, fname=None, link_obj=None): # sanity check if not (os.access(fname, os.R_OK) and os.path.isfile(fname)): _log.error('[%s] is not a readable file' % fname) return False cmd = "UPDATE blobs.doc_obj SET data = %(data)s::BYTEA WHERE pk = %(pk)s RETURNING md5(data) AS md5" args = {'pk': self.pk_obj} md5 = gmTools.file2md5(filename = fname, return_hex = True) if not gmPG2.file2bytea(conn = link_obj, query = cmd, filename = fname, args = args, file_md5 = md5): return False # must update XMIN now ... self.refetch_payload(link_obj = link_obj) return True
def update_data_from_file(self, fname=None, link_obj=None): # sanity check if not (os.access(fname, os.R_OK) and os.path.isfile(fname)): _log.error('[%s] is not a readable file' % fname) return False if not gmPG2.file2bytea ( conn = link_obj, query = "UPDATE blobs.doc_obj SET data = %(data)s::bytea WHERE pk = %(pk)s RETURNING md5(data) AS md5", filename = fname, args = {'pk': self.pk_obj}, file_md5 = gmTools.file2md5(filename = fname, return_hex = True) ): return False # must update XMIN now ... self.refetch_payload(link_obj = link_obj) return True
def download_data_pack(pack_url, filename=None, md5_url=None): _log.debug('downloading data pack from: %s', pack_url) dp_fname = download_file(pack_url, filename = filename, suffix = 'zip') _log.debug('downloading MD5 from: %s', md5_url) md5_fname = download_file(md5_url, filename = dp_fname + u'.md5') md5_file = io.open(md5_fname, mode = 'rt', encoding = 'utf8') md5_expected = md5_file.readline().strip('\n') md5_file.close() _log.debug('expected MD5: %s', md5_expected) md5_calculated = gmTools.file2md5(dp_fname, return_hex = True) _log.debug('calculated MD5: %s', md5_calculated) if md5_calculated != md5_expected: _log.error('mismatch of expected vs calculated MD5: [%s] vs [%s]', md5_expected, md5_calculated) return (False, (md5_expected, md5_calculated)) return True, dp_fname
def download_data_pack(pack_url, filename=None, md5_url=None): _log.debug('downloading data pack from: %s', pack_url) dp_fname = download_file(pack_url, filename = filename, suffix = 'zip') _log.debug('downloading MD5 from: %s', md5_url) md5_fname = download_file(md5_url, filename = dp_fname + '.md5') md5_file = io.open(md5_fname, mode = 'rt', encoding = 'utf8') md5_expected = md5_file.readline().strip('\n') md5_file.close() _log.debug('expected MD5: %s', md5_expected) md5_calculated = gmTools.file2md5(dp_fname, return_hex = True) _log.debug('calculated MD5: %s', md5_calculated) if md5_calculated != md5_expected: _log.error('mismatch of expected vs calculated MD5: [%s] vs [%s]', md5_expected, md5_calculated) return (False, (md5_expected, md5_calculated)) return True, dp_fname
def print_generic_document(parent=None, jobtype:str=None, episode=None): """Call LibreOffice Writer with a generated (fake) ODT file. Once Writer is closed, the ODT is imported if different from its initial content. Note: The file passed to LO _must_ reside in a directory the parents of which are all R-X by the user or else LO will throw up its arms in despair and fall back to the user's home dir upon saving. So, /tmp/user/$UID/some-file.odt will *not* work (because .../user/... is "drwx--x--x root.root") while /home/$USER/some/dir/some-file.odt does. """ sandbox = os.path.join(gmTools.gmPaths().user_tmp_dir, 'libreoffice') gmTools.mkdir(sandbox) fpath = gmTools.get_unique_filename(suffix = '.txt', tmp_dir = sandbox) doc_file = open(fpath, mode = 'wt') doc_file.write(__ODT_FILE_PREAMBLE) doc_file.write(_('Today: %s') % gmDateTime.pydt_now_here().strftime('%c')) doc_file.write('\n\n') prax = gmPraxis.gmCurrentPraxisBranch() doc_file.write('Praxis:\n') doc_file.write(prax.format()) doc_file.write('\n') doc_file.write('Praxis branch:\n') doc_file.write('\n'.join(prax.org_unit.format ( with_address = True, with_org = True, with_comms = True ))) doc_file.write('\n\n') pat = gmPerson.gmCurrentPatient(gmPerson.cPatient(12)) if pat.connected: doc_file.write('Patient:\n') doc_file.write(pat.get_description_gender()) doc_file.write('\n\n') for adr in pat.get_addresses(): doc_file.write(adr.format(single_line = False, verbose = True, show_type = True)) doc_file.write('\n\n') for chan in pat.get_comm_channels(): doc_file.werite(chan.format()) doc_file.write('\n\n') doc_file.write('Provider:\n') doc_file.write('\n'.join(gmStaff.gmCurrentProvider().get_staff().format())) doc_file.write('\n\n-----------------------------------------------------------------------------\n\n') doc_file.close() # convert txt -> odt success, ret_code, stdout = gmShellAPI.run_process ( cmd_line = [ 'lowriter', '--convert-to', 'odt', '--outdir', os.path.split(fpath)[0], fpath ], verbose = True ) if success: fpath = gmTools.fname_stem_with_path(fpath) + '.odt' else: _log.warning('cannot convert .txt to .odt') md5_before = gmTools.file2md5(fpath) gmShellAPI.run_process(cmd_line = ['lowriter', fpath], verbose = True) md5_after = gmTools.file2md5(fpath) if md5_before == md5_after: gmDispatcher.send(signal = 'statustext', msg = _('Document not modified. Discarding.'), beep = False) return if not pat.connected: shutil.move(fpath, gmTools.gmPaths().user_work_dir) gmDispatcher.send(signal = 'statustext', msg = _('No patient. Moved file into %s') % gmTools.gmPaths().user_work_dir, beep = False) return pat.export_area.add_file ( filename = fpath, hint = _('Generic letter, written at %s') % gmDateTime.pydt_now_here().strftime('%Y %b %d %H:%M') ) gmDispatcher.send(signal = 'display_widget', name = 'gmExportAreaPlugin')
def edit_visual_progress_note(filename=None, episode=None, discard_unmodified=False, doc_part=None, health_issue=None): """This assumes <filename> contains an image which can be handled by the configured image editor.""" if doc_part is not None: filename = doc_part.export_to_file() if filename is None: gmDispatcher.send( signal=u'statustext', msg=_('Cannot export visual progress note to file.')) return None dbcfg = gmCfg.cCfgSQL() cmd = dbcfg.get2( option=u'external.tools.visual_soap_editor_cmd', workplace=gmPraxis.gmCurrentPraxisBranch().active_workplace, bias='user') if cmd is None: gmDispatcher.send( signal=u'statustext', msg=_('Editor for visual progress note not configured.'), beep=False) cmd = configure_visual_progress_note_editor() if cmd is None: gmDispatcher.send( signal=u'statustext', msg=_('Editor for visual progress note not configured.'), beep=True) return None if u'%(img)s' in cmd: cmd = cmd % {u'img': filename} else: cmd = u'%s %s' % (cmd, filename) if discard_unmodified: original_stat = os.stat(filename) original_md5 = gmTools.file2md5(filename) success = gmShellAPI.run_command_in_shell(cmd, blocking=True) if not success: gmGuiHelpers.gm_show_error( _('There was a problem with running the editor\n' 'for visual progress notes.\n' '\n' ' [%s]\n' '\n') % cmd, _('Editing visual progress note')) return None try: open(filename, 'r').close() except Exception: _log.exception('problem accessing visual progress note file [%s]', filename) gmGuiHelpers.gm_show_error( _('There was a problem reading the visual\n' 'progress note from the file:\n' '\n' ' [%s]\n' '\n') % filename, _('Saving visual progress note')) return None if discard_unmodified: modified_stat = os.stat(filename) # same size ? if original_stat.st_size == modified_stat.st_size: modified_md5 = gmTools.file2md5(filename) # same hash ? if original_md5 == modified_md5: _log.debug('visual progress note (template) not modified') # ask user to decide msg = _( u'You either created a visual progress note from a template\n' u'in the database (rather than from a file on disk) or you\n' u'edited an existing visual progress note.\n' u'\n' u'The template/original was not modified at all, however.\n' u'\n' u'Do you still want to save the unmodified image as a\n' u'visual progress note into the EMR of the patient ?\n') save_unmodified = gmGuiHelpers.gm_show_question( msg, _('Saving visual progress note')) if not save_unmodified: _log.debug('user discarded unmodified note') return if doc_part is not None: _log.debug('updating visual progress note') doc_part.update_data_from_file(fname=filename) doc_part.set_reviewed(technically_abnormal=False, clinically_relevant=True) return None if not isinstance(episode, gmEMRStructItems.cEpisode): if episode is None: episode = _('visual progress notes') pat = gmPerson.gmCurrentPatient() emr = pat.emr episode = emr.add_episode(episode_name=episode.strip(), pk_health_issue=health_issue, is_open=False) doc = gmDocumentWidgets.save_file_as_new_document( filename=filename, document_type=gmDocuments.DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE, episode=episode, unlock_patient=False, pk_org_unit=gmPraxis.gmCurrentPraxisBranch()['pk_org_unit']) doc.set_reviewed(technically_abnormal=False, clinically_relevant=True) return doc
def edit_visual_progress_note(filename=None, episode=None, discard_unmodified=False, doc_part=None, health_issue=None): """This assumes <filename> contains an image which can be handled by the configured image editor.""" if doc_part is not None: filename = doc_part.save_to_file() if filename is None: gmDispatcher.send( signal='statustext', msg=_('Cannot export visual progress note to file.')) return None editor = gmCfgDB.get4user( option='external.tools.visual_soap_editor_cmd', workplace=gmPraxis.gmCurrentPraxisBranch().active_workplace) if editor is None: _log.error( 'no editor for visual progress notes configured, trying mimetype editor' ) gmDispatcher.send( signal='statustext', msg=_('Editor for visual progress note not configured.'), beep=False) mimetype = gmMimeLib.guess_mimetype(filename=filename) editor = gmMimeLib.get_editor_cmd(mimetype=mimetype, filename=filename) if editor is None: _log.error( 'no editor for mimetype <%s> configured, trying mimetype viewer', mimetype) success, msg = gmMimeLib.call_viewer_on_file(aFile=filename, block=True) if not success: _log.debug('problem running mimetype <%s> viewer', mimetype) gmGuiHelpers.gm_show_error( _('There is no editor for visual progress notes defined.\n' 'Also, there is no editor command defined for the file type\n' '\n' ' [%s].\n' '\n' 'Therefor GNUmed attempted to at least *show* this\n' 'visual progress note. That failed as well, however:\n' '\n' '%s') % (mimetype, msg), _('Editing visual progress note')) editor = configure_visual_progress_note_editor() if editor is None: gmDispatcher.send( signal='statustext', msg=_( 'Editor for visual progress note not configured.'), beep=True) return None if '%(img)s' in editor: editor = editor % {'img': filename} else: editor = '%s %s' % (editor, filename) if discard_unmodified: original_stat = os.stat(filename) original_md5 = gmTools.file2md5(filename) success = gmShellAPI.run_command_in_shell(editor, blocking=True) if not success: success, msg = gmMimeLib.call_viewer_on_file(aFile=filename, block=True) if not success: _log.debug('problem running mimetype <%s> viewer', mimetype) gmGuiHelpers.gm_show_error( _('There was a problem running the editor\n' '\n' ' [%s] (%s)\n' '\n' 'on the visual progress note.\n' '\n' 'Therefor GNUmed attempted to at least *show* it.\n' 'That failed as well, however:\n' '\n' '%s') % (editor, mimetype, msg), _('Editing visual progress note')) editor = configure_visual_progress_note_editor() if editor is None: gmDispatcher.send( signal='statustext', msg=_('Editor for visual progress note not configured.'), beep=True) return None try: open(filename, 'r').close() except Exception: _log.exception('problem accessing visual progress note file [%s]', filename) gmGuiHelpers.gm_show_error( _('There was a problem reading the visual\n' 'progress note from the file:\n' '\n' ' [%s]\n' '\n') % filename, _('Saving visual progress note')) return None if discard_unmodified: modified_stat = os.stat(filename) # same size ? if original_stat.st_size == modified_stat.st_size: modified_md5 = gmTools.file2md5(filename) # same hash ? if original_md5 == modified_md5: _log.debug('visual progress note (template) not modified') # ask user to decide msg = _( 'You either created a visual progress note from a template\n' 'in the database (rather than from a file on disk) or you\n' 'edited an existing visual progress note.\n' '\n' 'The template/original was not modified at all, however.\n' '\n' 'Do you still want to save the unmodified image as a\n' 'visual progress note into the EMR of the patient ?\n') save_unmodified = gmGuiHelpers.gm_show_question( msg, _('Saving visual progress note')) if not save_unmodified: _log.debug('user discarded unmodified note') return if doc_part is not None: _log.debug('updating visual progress note') doc_part.update_data_from_file(fname=filename) doc_part.set_reviewed(technically_abnormal=False, clinically_relevant=True) return None if not isinstance(episode, gmEMRStructItems.cEpisode): if episode is None: episode = _('visual progress notes') pat = gmPerson.gmCurrentPatient() emr = pat.emr episode = emr.add_episode(episode_name=episode.strip(), pk_health_issue=health_issue, is_open=False) doc = gmDocumentWidgets.save_file_as_new_document( filename=filename, document_type=gmDocuments.DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE, episode=episode, unlock_patient=False, pk_org_unit=gmPraxis.gmCurrentPraxisBranch()['pk_org_unit'], date_generated=gmDateTime.pydt_now_here()) doc.set_reviewed(technically_abnormal=False, clinically_relevant=True) return doc