Package Gnumed :: Package pycommon :: Module gmHooks |
[frames] | no frames]

# Source Code for Module Gnumed.pycommon.gmHooks

      1  """GNUmed hooks framework.
      2
      3  This module provides convenience functions and definitions
      4  for accessing the GNUmed hooks framework.
      5
      6  This framework calls the script
      7
      8          ~/.gnumed/scripts/hook_script.py
      9
     10  at various times during client execution. The script must
     11  contain a function
     12
     13  def run_script(hook=None):
     14          pass
     15
     16  which accepts a single argument <hook>. That argument will
     17  contain the hook that is being activated.
     18  """
     19  # ========================================================================
     20  __version__ = "$Revision: 1.18 $"
     21  __author__  = "K. Hilbert <Karsten.Hilbert@gmx.net>"
     22  __license__ = "GPL v2 or later (details at http://www.gnu.org)"
     23
     24
     25  # stdlib
     26  import os, sys, stat, logging
     27
     28  _log = logging.getLogger('gm.hook')
     29  _log.info(__version__)
     30
     31
     32  # GNUmed libs
     33  if __name__ == '__main__':
     34          sys.path.insert(0, '../../')
     35  from Gnumed.pycommon import gmDispatcher, gmTools
     36
     37  # ========================================================================
     38  known_hooks = [
     39          u'post_patient_activation',
     40          u'post_person_creation',
     41
     42          u'shutdown-post-GUI',
     43          u'startup-after-GUI-init',
     44          u'startup-before-GUI',
     45
     46          u'request_user_attention',
     47          u'app_activated_startup',
     48          u'app_activated',
     49          u'app_deactivated',
     50
     51          u'after_substance_intake_modified',
     52          u'after_test_result_modified',
     53          u'after_soap_modified',
     54          u'after_code_link_modified',
     55
     56          u'after_new_doc_created',
     57          u'before_print_doc',
     58          u'before_fax_doc',
     59          u'before_mail_doc',
     60          u'before_print_doc_part',
     61          u'before_fax_doc_part',
     62          u'before_mail_doc_part',
     63          u'before_external_doc_access',
     64
     65          u'db_maintenance_warning'
     66  ]
     67
     68  _log.debug('known hooks:')
     69  for hook in known_hooks:
     70          _log.debug(hook)
     71
     72  # ========================================================================
     73  hook_module = None
     74
     75 -def import_hook_module(reimport=False):
     76
     77          global hook_module
     78          if not reimport:
     79                  if hook_module is not None:
     80                          return True
     81
     82          # hardcoding path and script name allows us to
     83          # not need configuration for it, the environment
     84          # can always be detected at runtime (workplace etc)
     85          script_name = 'hook_script.py'
     86          script_path = os.path.expanduser(os.path.join('~', '.gnumed', 'scripts'))
     87          full_script = os.path.join(script_path, script_name)
     88
     89          if not os.access(full_script, os.F_OK):
     90                  _log.warning('creating default hook script')
     91                  f = open(full_script, 'w')
     92                  f.write("""
     93  # known hooks:
     94  #  %s
     95
     96  def run_script(hook=None):
     97          pass
     98  """ % '#  '.join(known_hooks))
     99                  f.close()
    100                  os.chmod(full_script, 384)
    101
    102          if os.path.islink(full_script):
    103                  gmDispatcher.send (
    104                          signal = 'statustext',
    105                          msg = _('Script must not be a link: [%s].') % full_script
    106                  )
    107                  return False
    108
    109          if not os.access(full_script, os.R_OK):
    110                  gmDispatcher.send (
    111                          signal = 'statustext',
    112                          msg = _('Script must be readable by the calling user: [%s].') % full_script
    113                  )
    114                  return False
    115
    116          script_stat_val = os.stat(full_script)
    117          _log.debug('hook script stat(): %s', script_stat_val)
    118          script_perms = stat.S_IMODE(script_stat_val.st_mode)
    119          _log.debug('hook script mode: %s (oktal: %s)', script_perms, oct(script_perms))
    120          if script_perms != 384:                         # octal 0600
    121                  if os.name in ['nt']:
    122                          _log.warning('this platform does not support os.stat() file permission checking')
    123                  else:
    124                          gmDispatcher.send (
    125                                  signal = 'statustext',
    126                                  msg = _('Script must be readable by the calling user only (permissions "0600"): [%s].') % full_script
    127                          )
    128                          return False
    129
    130          try:
    131                  tmp = gmTools.import_module_from_directory(script_path, script_name)
    132          except StandardError:
    133                  _log.exception('cannot import hook script')
    134                  return False
    135
    136          hook_module = tmp
    137  #       if reimport:
    138  #               reload(tmp)                     # this has well-known shortcomings !
    139
    140          _log.info('hook script: %s', full_script)
    141          return True
    142  # ========================================================================
    143 -def run_hook_script(hook=None):
    144          # NOTE: this just *might* be a huge security hole
    145
    146          if hook not in known_hooks:
    147                  raise ValueError('run_hook_script(): unknown hook [%s]' % hook)
    148
    149          if not import_hook_module(reimport = False):
    150                  return False
    151
    152          try:
    153                  hook_module.run_script(hook = hook)
    154          except StandardError:
    155                  _log.exception('error running hook script for [%s]', hook)
    156                  gmDispatcher.send (
    157                          signal = u'statustext',
    158                          msg = _('Error running hook [%s] script.') % hook,
    159                          beep = True
    160                  )
    161                  return False
    162
    163          return True
    164  # ========================================================================
    165  if __name__ == '__main__':
    166
    167          run_hook_script(hook = 'shutdown-post-GUI')
    168          run_hook_script(hook = 'invalid hook')
    169
    170  # ========================================================================
    171