From fe3a1740d6b0490b8db9d5dc3364d353c7e22fa8 Mon Sep 17 00:00:00 2001
From: Kazuhiko Shiozaki <kazuhiko@nexedi.com>
Date: Wed, 16 Dec 2015 10:11:32 +0100
Subject: [PATCH] monkey patch ExternalMethod so that we have Guard like
 DCWorkflow.Transition.

---
 product/ERP5Type/patches/ExternalMethod.py | 28 ++++++++++++++++++++++
 product/ERP5Type/patches/PythonScript.py   | 10 ++++++--
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/product/ERP5Type/patches/ExternalMethod.py b/product/ERP5Type/patches/ExternalMethod.py
index 7044bdf993..bf18a97736 100644
--- a/product/ERP5Type/patches/ExternalMethod.py
+++ b/product/ERP5Type/patches/ExternalMethod.py
@@ -13,6 +13,13 @@
 
 from inspect import getargs
 from Products.ExternalMethod.ExternalMethod import *
+from AccessControl import ModuleSecurityInfo
+from AccessControl.class_init import InitializeClass
+from Acquisition import aq_parent
+from Products.ERP5Type.patches.PythonScript import _guard_form, \
+     _guard_manage_options, checkGuard, getGuard, manage_guardForm, \
+     manage_setGuard
+from zExceptions import Forbidden
 
 if 1:
     def getFunction(self, reload=False, f=None):
@@ -74,6 +81,7 @@ if 1:
         first argument.
 
         Monkey patches:
+        - check guard against context, if guard exists.
         - call ZODB Component Extension, by trying first to import ZODB
           Component Extension if available, otherwise fallback on filesystem
           Extension
@@ -81,6 +89,11 @@ if 1:
         - fix magic "self" argument when positional arguments get their values
           from kw.
         """
+        guard = getattr(self, 'guard', None)
+        if guard is not None:
+            if not checkGuard(guard, aq_parent(self)):
+                raise Forbidden, 'Calling %s %s is denied by Guard.' % (self.meta_type, self.id)
+
         import erp5.component.extension
         component_module = erp5.component.extension.find_load_module(self._module)
         if component_module is not None:
@@ -133,3 +146,18 @@ if 1:
             finally: tb=None
 
     ExternalMethod.__call__ = __call__
+
+security = ModuleSecurityInfo('Products.ExternalMethod.ExternalMethod.ExternalMethod')
+
+ExternalMethod.manage_options += _guard_manage_options
+ExternalMethod._guard_form = _guard_form
+
+ExternalMethod.manage_guardForm = manage_guardForm
+security.declareProtected(view_management_screens, 'manage_guardForm')
+
+ExternalMethod.getGuard = getGuard
+
+ExternalMethod.manage_setGuard = manage_setGuard
+security.declareProtected(change_external_methods, 'manage_setGuard')
+
+InitializeClass(ExternalMethod)
diff --git a/product/ERP5Type/patches/PythonScript.py b/product/ERP5Type/patches/PythonScript.py
index a190fe5316..a93ea8e506 100644
--- a/product/ERP5Type/patches/PythonScript.py
+++ b/product/ERP5Type/patches/PythonScript.py
@@ -16,6 +16,7 @@ from Products.PythonScripts.PythonScript import PythonScript
 from App.special_dtml import DTMLFile
 from Products.ERP5Type import _dtmldir
 from AccessControl import ModuleSecurityInfo, getSecurityManager
+from AccessControl.class_init import InitializeClass
 from OFS.misc_ import p_
 from App.ImageFile import ImageFile
 from Acquisition import aq_base, aq_parent
@@ -58,14 +59,17 @@ PythonScript.manage_editForm = manage_editForm
 
 security = ModuleSecurityInfo('Products.PythonScripts.PythonScript.PythonScript')
 
-PythonScript.manage_options += (
+_guard_manage_options = (
   {
     'label':'Guard',
     'action':'manage_guardForm',
   },
 )
-PythonScript._guard_form = DTMLFile(
+PythonScript.manage_options += _guard_manage_options
+
+_guard_form = DTMLFile(
   'editGuardForm', _dtmldir)
+PythonScript._guard_form = _guard_form
 
 def manage_guardForm(self, REQUEST, manage_tabs_message=None):
   '''
@@ -157,3 +161,5 @@ def _exec(self, *args):
   # PATCH END
   return PythonScript_exec(self, *args)
 PythonScript._exec = _exec
+
+InitializeClass(PythonScript)
-- 
2.30.9