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
26 import os, sys, stat, logging
27
28 _log = logging.getLogger('gm.hook')
29 _log.info(__version__)
30
31
32
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
76
77 global hook_module
78 if not reimport:
79 if hook_module is not None:
80 return True
81
82
83
84
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:
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
138
139
140 _log.info('hook script: %s', full_script)
141 return True
142
144
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