/[opental]/opental/OpenPT/ZOPT.py
ViewVC logotype

Diff of /opental/OpenPT/ZOPT.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.40 by lalo, Mon Jan 27 02:04:16 2003 UTC revision 1.41 by lalo, Mon Jan 27 05:11:10 2003 UTC
# Line 15  Line 15 
15  #    You should have received a copy of the GNU General Public License  #    You should have received a copy of the GNU General Public License
16  #    along with this program; if not, write to the Free Software  #    along with this program; if not, write to the Free Software
17  #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA  #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA
18  import OpenTAL, pax, PTmetal_handler, pax.paxtransform  __version__='$Revision$'[11:-2]
 from pax.backwards_compatibility import *  
 from ZPythonExpr import PythonExpr, SecureModuleImporter  
 import cPickle as pickle  
 #import pickle  
   
 import os, AccessControl, Acquisition, sys, fnmatch  
 from App.FactoryDispatcher import FactoryDispatcher  
 from Acquisition import aq_base  
 from Globals import DTMLFile, ImageFile, MessageDialog, package_home  
 from zLOG import LOG, ERROR, INFO  
 from OFS.SimpleItem import SimpleItem  
 from DateTime.DateTime import DateTime  
 from string import join, strip, rstrip, split, replace, lower  
 from Shared.DC.Scripts.Script import Script, BindingsUI  
 from Shared.DC.Scripts.Signature import FuncCode  
 from Shared.DC.Scripts.Bindings import NameAssignments, Bindings  
 from AccessControl import getSecurityManager  
 try:  
     from AccessControl import Unauthorized  
 except ImportError:  
     Unauthorized = "Unauthorized"  
 from OFS.History import Historical, html_diff  
 from OFS.Cache import Cacheable  
 from OFS.Traversable import Traversable  
 from OFS.PropertyManager import PropertyManager  
 from Products.PageTemplates.PageTemplateFile import PageTemplateFile  
 from webdav.Lockable import ResourceLockedError  
 from webdav.WriteLockInterface import WriteLockInterface  
 from ZODB.PersistentMapping import PersistentMapping  
 from OFS.SimpleItem import SimpleItem  
 import Globals  
 from DocumentTemplate.DT_Util import TemplateDict, InstanceDict  
 from AccessControl.DTML import RestrictedDTML  
 class Rtd(RestrictedDTML, TemplateDict):  
     this = None  
   
 def call_with_ns(f, ns, arg=1):  
     td = Rtd()  
     td.this = ns['here']  
     td._push(ns['request'])  
     td._push(InstanceDict(td.this, td))  
     td._push(ns)  
     try:  
         if arg==2:  
             return f(None, td)  
         else:  
             return f(td)  
     finally:  
         td._pop(3)  
   
 class PTNameAssignments(NameAssignments):  
     # this should emulate the following ugly zpt code:  
 ##         c = {'template': self,  
 ##              'here': self._getContext(),  
 ##              'container': self._getContainer(),  
 ##              'nothing': None,  
 ##              'options': {},  
 ##              'root': root,  
 ##              'request': getattr(root, 'REQUEST', None),  
 ##              'modules': SecureModuleImporter,  
 ##              }  
     _exprs = NameAssignments._exprs + (  
               ('name_none',   'None'),  
               ('name_options',   '{}'),  
               ('name_root',   'self._getRoot()'),  
               ('name_request',   'getattr(self, "REQUEST", None)'),  
               ('name_modules',   'self._getModuleImporter()'),  
               )  
   
 class PTRuntimeError(RuntimeError):  
     '''The Page Template has template errors that prevent it from rendering.'''  
     pass  
   
 def make_macro_collection():  
     col = PersistentMapping()  
     col.__roles__ = None  
     col.__allow_access_to_unprotected_subobjects__ = 1  
     #col.__altpt_0_2__ = 1  
     return col  
   
 def fetchmacros(template, tree, context):  
     macros = getattr(context, 'metal_macros', {})  
     col = template.macros  
     col.clear()  
     for name, macro in macros.items():  
         col[name] = pickle.dumps(macro)  
     return tree  
   
   
 ZopeExprEngine = OpenTAL.Expressions.Engine()  
 ZopeExprEngine.registerType('python', PythonExpr)  
 ZopeExprEngine.Undefs += (Unauthorized,)  
   
 class ZopeContext(OpenTAL.Context.Context):  
     def __init__(self, bindings=None):  
         OpenTAL.Context.Context.__init__(self, ZopeExprEngine, bindings)  
         self._securityManager = getSecurityManager()  
   
     def validate(self, accessed=None, container=None, name=None, value=None, *a):  
         if not self._securityManager.validate(accessed, container, name, value, *a):  
             raise Unauthorized, name  
   
     def render(self, ob):  
         """  
         Calls the object, possibly a document template, or just returns it if  
         not callable.  (From DT_Util.py)  
         """  
         ns = self.vars  
         if hasattr(ob, '__render_with_namespace__'):  
             ob = call_with_ns(ob.__render_with_namespace__, ns)  
         else:  
             base = aq_base(ob)  
             if callable(base):  
                 try:  
                     if getattr(base, 'isDocTemp', 0):  
                         ob = call_with_ns(ob, ns, 2)  
                     else:  
                         ob = ob()  
                 except AttributeError, n:  
                     if str(n) != '__call__':  
                         raise  
         return ob  
19    
20    # FIXME: determine what exactly has to be imported.
21    # some imports probably aren't needed by Base anymore.
22    from OpenPTBase import *
23    from OpenPTFile import OpenPTFile
24    import os
25    
26  # paxtransform handlers  my_home = package_home(globals())
27  handler_registry = [OpenTAL.metal_handler, OpenTAL.tal_handler]  default_text_dir = os.path.join(my_home, 'default_text')
 # paxtransform handlers  
 compiler_registry = [OpenTAL.metal_compiler, OpenTAL.tal_compiler]  
 # functions!  
 postcompiler_registry = [fetchmacros]  
   
 def _registry_replace(registry, new_item, position):  
     name = new_item.name  
     for index, item in enumerate(registry):  
         if item.name == name:  
             del registry[index]  
     registry.insert(position, new_item)  
   
 def register_handlers(handler=None, compiler=None, position=None):  
     if position is None:  
         position = max(len(handler_registry), len(compiler_registry))  
     if handler:  
         _registry_replace(handler_registry, handler, position)  
     if compiler:  
         _registry_replace(compiler_registry, compiler, position)  
   
 # these are calculated automatically, don't touch them  
 handler_namespaces = {}  
 handler_namespaces_rev = {}  
   
 def PT_initial_namespaces():  
     if len(handler_namespaces) != len(handler_registry):  
         handler_namespaces.clear()  
         for handler in handler_registry:  
             handler_namespaces[handler.name] = handler.ns  
     return handler_namespaces  
   
 source_types = {'HTML':pax.html2pax, 'Text':pax.text2pax}  
 if hasattr(pax, 'xml2pax'):  
     source_types['XML'] = pax.xml2pax  
   
 default_text_dir = os.path.join(package_home(globals()), 'default_text')  
   
 # FIXME: lots of stuff below can probably be refactored out -  
 # there is still a lot of cruft pasted from ZPT  
   
 # FIXME2: it would be interesting to check if a non-zope OpenPT class  
 # is doable. If not, all claims to its existence should be removed.  
   
 class ZopePageTemplate(Script, Historical, Cacheable,  
                        Traversable, PropertyManager):  
     "Zope Open Page Template using TAL, TALES, and METAL"  
       
     __implements__ = (WriteLockInterface,)  
   
     content_type = 'text/html'  
     source_type = 'HTML'  
     handlers = ('tal', 'metal')  
     encoding = 'utf-8'  
     _errors = ()  
     _warnings = ()  
     _text = ''  
     _error_start = '<!-- Page Template Diagnostics'  
     _paxtree = ''  
     meta_type = 'Page Template (OpenPT)'  
     _icon = 'misc_/OpenPT/opt.png'  
   
     func_defaults = None  
     func_code = FuncCode((), 0)  
   
     _default_bindings = {'name_context': 'here',  
                          'name_container': 'container',  
                          'name_m_self': 'template',  
                          'name_subpath': 'traverse_subpath',  
                          'name_none': 'nothing',  
                          'name_options': 'options',  
                          'name_root': 'root',  
                          'name_request': 'request',  
                          'name_modules': 'modules',  
                          }  
28    
29    class ZopePageTemplate(OpenPageTemplate, PropertyManager):
30        "Normal (ZMI-managed) Open Page Template"
31      manage_options = (      manage_options = (
32          {'label':'Edit', 'action':'pt_editForm',          {'label':'Edit', 'action':'pt_editForm',
33           'help': ('PageTemplates', 'PageTemplate_Edit.stx')},           'help': ('PageTemplates', 'PageTemplate_Edit.stx')},
# Line 236  class ZopePageTemplate(Script, Historica Line 47  class ZopePageTemplate(Script, Historica
47                   )                   )
48    
49      def __init__(self, id, text_fn):      def __init__(self, id, text_fn):
50          self.id = str(id)          OpenPageTemplate.__init__(self, id)
51          self.ZBindings_edit(self._default_bindings)          if text_fn is not None:
         if text_fn is None:  
             text = '<openpt />'  
         else:  
52              text = open(os.path.join(default_text_dir, text_fn)+'.pt').read()              text = open(os.path.join(default_text_dir, text_fn)+'.pt').read()
53          self.macros = make_macro_collection()              self.write(text)
         self.pt_edit(text)  
   
     def manage_afterAdd(self, item, container):  
         try:  
             self.encoding = container.default_zope_data_encoding  
         except:  
             pass  
   
     def __setstate__(self, state):  
         ZopePageTemplate.inheritedAttribute('__setstate__')(self, state)  
         ###backward compatibility  
         #col = getattr(self, 'macros', None)  
         #if not hasattr(col, '__altpt_0_2__'):  
         #    self.macros = make_macro_collection()  
         #if not self._bind_names.isNameAssigned('here'):  
         #x    self.ZBindings_edit(self._default_bindings)  
         ###/backward compatibility  
   
     def _setupBindings(self, names={}):  
         self._bind_names = names = PTNameAssignments(names)  
         return names  
   
     def _getModuleImporter(self):  
         return SecureModuleImporter  
   
     def _getRoot(self):  
         root = getattr(self, 'getPhysicalRoot', None)  
         # don't know how this happens, but it does: sometimes root is a string  
         if callable(root):  
             root = root()  
         return root  
   
     def _getContext(self):  
         if hasattr(self, 'aq_parent'):  
             return ZopePageTemplate.inheritedAttribute('_getContext')(self)  
         return self  
   
     def _setPropValue(self, id, value):  
         PropertyManager._setPropValue(self, id, value)  
         self.ZCacheable_invalidate()  
54    
55      security = AccessControl.ClassSecurityInfo()      security = AccessControl.ClassSecurityInfo()
56    
     security.declareObjectProtected('View')  
     security.declareProtected('View', '__call__')  
   
57      security.declareProtected('View management screens',      security.declareProtected('View management screens',
58        'pt_editForm', 'manage_main', 'read',        'pt_editForm', 'manage_main', 'read',
59        'ZScriptHTML_tryForm', 'PrincipiaSearchSource',        'ZScriptHTML_tryForm', 'PrincipiaSearchSource',
# Line 297  class ZopePageTemplate(Script, Historica Line 62  class ZopePageTemplate(Script, Historica
62      security.declareProtected('FTP access',      security.declareProtected('FTP access',
63        'manage_FTPstat','manage_FTPget','manage_FTPlist')        'manage_FTPstat','manage_FTPget','manage_FTPlist')
64    
65      pt_editForm = PageTemplateFile('www/ptEdit.pt', globals(),      pt_editForm = OpenPTFile('pt_editForm', my_home, 'www', 'ptEdit')
                                    __name__='pt_editForm')  
     pt_editForm._owner = None  
66      manage = manage_main = pt_editForm      manage = manage_main = pt_editForm
67    
68        def _setPropValue(self, id, value):
69            PropertyManager._setPropValue(self, id, value)
70            self.ZCacheable_invalidate()
71    
72      security.declareProtected('Change Page Templates',      security.declareProtected('Change Page Templates',
73        'pt_editAction', 'pt_setTitle', 'pt_edit', 'pt_expand',        'pt_editAction', 'pt_setTitle', 'pt_edit', 'pt_expand',
74        'pt_upload', 'pt_changePrefs')        'pt_upload', 'pt_changePrefs')
# Line 355  class ZopePageTemplate(Script, Historica Line 122  class ZopePageTemplate(Script, Historica
122          REQUEST.form.update({'dtpref_cols': cols, 'dtpref_rows': rows})          REQUEST.form.update({'dtpref_cols': cols, 'dtpref_rows': rows})
123          return self.manage_main()          return self.manage_main()
124    
     def paxtree(self):  
         'fetch the pax tree from the zodb'  
         if not hasattr(self, '_v_paxtree'):  
             self._v_paxtree = pickle.loads(self._paxtree)  
         return self._v_paxtree  
   
     def read(self, *args, **kw):  
         if not self._errors:  
             return self._text  
                                     
         return ('%s\n %s\n-->\n%s' % (self._error_start,  
                                       join(self._errors, '\n '),  
                                       self._text))  
   
     def write(self, text):  
         self.ZCacheable_invalidate()  
         assert type(text) in (type(''), type(u''))  
         if text.startswith(self._error_start):  
             errend = text.find('-->')  
             if errend >= 0:  
                 text = text[errend + 4:]  
         if self._text != text:  
             self._text = text  
   
         # "cooking" only ever happens when the template changes  
         parser = source_types[self.source_type]  
   
         self._errors = ()  
         try:  
             tree = parser(text, PT_initial_namespaces(), self.encoding)  
             tr_engine = pax.paxtransform.Engine()  
             for handler in compiler_registry:  
                 tr_engine.add_handler(handler)  
             # empty context:  
             # compilers and postcompilers shouldn't access the context anyway  
             context = ZopeContext()  
             context.template = self  
             try:  
                 context.encoding = self.default_zope_data_encoding  
             except:  
                 context.encoding = self.encoding  
             tr_engine.initialize(context)  
             tree = tr_engine.transform(tree, context)  
             for handler in postcompiler_registry:  
                 tree = handler(self, tree, context)  
             self._paxtree = pickle.dumps(tree)  
             if hasattr(self, '_v_paxtree'):  
                 del self._v_paxtree  
         except:  
             import traceback, zLOG  
             #zLOG.LOG('OpenPT', 0, 'Compilation error',  
             try:  
                 exc = sys.exc_info()  
                 traceback.print_exception(*exc)  
                 self._errors = ["Compilation failed",  
                                 "%s: %s" % exc[:2]]  
             finally:  
                 del exc  
                 if not self._errors:  
                     self._errors = ['something very wicked happened.']  
   
     def pt_edit(self, text):  
         if hasattr(text, 'read'):  
             text = text.read()  
         self.write(text)  
   
     def pt_errors(self):  
         return self._errors  
           
     def pt_warnings(self):  
         return self._warnings  
   
     def pt_parser_list(self):  
         return source_types.keys()  
   
     def pt_handler_list(self):  
         return [handler.name for handler in handler_registry]  
   
     security.declareProtected('Change Page Templates',  
       'PUT', 'manage_FTPput', 'write',  
       'manage_historyCopy',  
       'manage_beforeHistoryCopy', 'manage_afterHistoryCopy')  
   
     def PUT(self, REQUEST, RESPONSE):  
         """ Handle HTTP PUT requests """  
         self.dav__init(REQUEST, RESPONSE)  
         self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1)  
         self.write(REQUEST.get('BODY', ''))  
         RESPONSE.setStatus(204)  
         return RESPONSE          
   
     manage_FTPput = PUT  
   
     def manage_FTPget(self):  
         "Get source for FTP download"  
         self.REQUEST.RESPONSE.setHeader('Content-Type', self.content_type)  
         return self.read()  
   
     def get_size(self):  
         return len(self.read())  
     getSize = get_size  
   
     def PrincipiaSearchSource(self):  
         "Support for searching - the document's contents are searched."  
         return self.read()  
   
     def document_src(self, REQUEST=None, RESPONSE=None):  
         """Return document source."""  
   
         if RESPONSE is not None:  
             RESPONSE.setHeader('Content-Type', 'text/plain')  
         if REQUEST is not None and REQUEST.get('raw'):  
             return self._text  
         return self.read()  
   
     def pt_src(self, REQUEST=None, RESPONSE=None):  
         """Return (rendered) document source."""  
   
         if RESPONSE is not None:  
             RESPONSE.setHeader('Content-Type', 'text/plain')  
   
         if hasattr(REQUEST, 'pax') and REQUEST.pax:  
             return str(self.paxtree())  
         return pax.XML(self.paxtree())  
   
     def om_icons(self):  
         """Return a list of icon URLs to be displayed by an ObjectManager"""  
         icons = ({'path': self._icon,  
                   'alt': self.meta_type, 'title': self.meta_type},)  
         if self._errors:  
             icons = icons + ({'path': 'misc_/OpenPT/exclamation.gif',  
                               'alt': 'Error',  
                               'title': 'This template has an error'},)  
         return icons  
   
     def _exec(self, bound_names, args, kw, handlers=None, root_ns_map={}):  
         """Call a Page Template"""  
         __traceback_info__ = 'bindings: %s;\n args: %s;\n kw: %s' % (  
             repr(bound_names), repr(args), repr(kw))  
         tr_engine = pax.paxtransform.Engine()  
         if handlers is None:  
             handlers = [h for h in handler_registry if h.name in self.handlers]  
         for handler in handlers:  
             tr_engine.add_handler(handler)  
   
         if self._errors:  
             raise PTRuntimeError, 'Page Template %s has errors.' % self.id  
   
         if not kw.has_key('args'):  
             kw['args'] = args  
         bound_names['options'] = kw  
   
         security=getSecurityManager()  
         bound_names['user'] = security.getUser()  
   
         # Retrieve the value from the cache.  
         keyset = {}  
         if self.ZCacheable_isCachingEnabled():  
             for n in ('traverse_subpath', 'options'):  
                 keyset[n] = bound_names[n]  
             keyset['here'] = bound_names['here'].absolute_url()  
             result = self.ZCacheable_get(keywords=bound_names)  
             if result is not None:  
                 # Got a cached value.  
                 return result  
   
         # Execute the template in a new security context.  
         security.addContext(self)  
         try:  
             context = ZopeContext(bound_names)  
             try:  
                 context.encoding = self.default_zope_data_encoding  
             except:  
                 context.encoding = self.encoding  
             context.root_xmlns_map = root_ns_map  
             tr_engine.initialize(context)  
             result = pax.XML(tr_engine.transform(self.paxtree(), context),  
                                  root_ns_map, self.encoding)  
             if keyset is not None:  
                 # Store the result in the cache.  
                 self.ZCacheable_set(result, keywords=keyset)  
             try:  
                 self.REQUEST.RESPONSE.setHeader('content-type',  
                                                 '%s; charset=%s' % (  
                                                  self.content_type,  
                                                  context.encoding))  
             except AttributeError:  
                 pass  
             return result  
         finally:  
             security.removeContext(self)  
   
     def pt_expand(self, REQUEST=None):  
         """Expand macros"""  
         if len(handler_namespaces_rev) != len(handler_registry):  
             handler_namespaces_rev.clear()  
             for handler in handler_registry:  
                 handler_namespaces_rev[handler.ns] = handler.name  
         # FIXME: should catch exceptions (?)  
         expanded = self._exec({},(),{},  
                               (PTmetal_handler.metal_expander,),  
                               handler_namespaces_rev)  
         self.write(expanded)  
         if REQUEST is not None:  
             REQUEST.set('text', self.read()) # May not equal 'text'!  
             return self.pt_editForm(manage_tabs_message='Macros expanded')  
125  Globals.InitializeClass(ZopePageTemplate)  Globals.InitializeClass(ZopePageTemplate)
126    
127    
128  manage_addPageTemplateForm = ZopePageTemplate('manage_addPageTemplateForm', None)  manage_addPageTemplateForm = OpenPTFile('manage_addPageTemplateForm',
129  manage_addPageTemplateForm.write(                                          my_home, 'www', 'ptAdd.pt')
     open(os.path.join(package_home(globals()), 'www', 'ptAdd.pt')).read())  
 manage_addPageTemplateForm.__name__ = manage_addPageTemplateForm.id  
130    
131  from urllib import quote  from urllib import quote
132    
# Line 599  def manage_addPageTemplate(self, id, tit Line 158  def manage_addPageTemplate(self, id, tit
158          if submit==" Add and Edit ": u="%s/%s" % (u,quote(id))          if submit==" Add and Edit ": u="%s/%s" % (u,quote(id))
159          REQUEST.RESPONSE.redirect(u+'/manage_main')          REQUEST.RESPONSE.redirect(u+'/manage_main')
160      return ''      return ''
   
   
 class __FactoryDispatcher__(FactoryDispatcher):  
     "customized FactoryDispatcher for OpenPT"  
     security = AccessControl.ClassSecurityInfo()  
     security.declareObjectProtected('Add Page Templates')  
     security.declareProtected('Add Page Templates', 'default_text_dir')  
     def default_text_dir(*a, **kw):  
         return [name[:-3] for name in os.listdir(default_text_dir) if  
                 fnmatch.fnmatch(name, '*.pt')]  
 Globals.InitializeClass(__FactoryDispatcher__)  
   
   
 def initialize(context):  
     context.registerClass(  
         ZopePageTemplate,  
         permission='Add Page Templates',  
         constructors=(manage_addPageTemplateForm,  
                       manage_addPageTemplate),  
         icon='www/opt.png',  
         )  
     try:  
         # hook OpenPT up CMF's brain  
         import FSOPT  
         FSOPT.initialize(context)  
     except ImportError:  
         pass  

Legend:
Removed from v.1.40  
changed lines
  Added in v.1.41

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26