Example #1
0
    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
Example #2
0
	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
Example #3
0
	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
Example #4
0
	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
Example #5
0
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
Example #6
0
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
Example #7
0
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')
Example #8
0
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
Example #9
0
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