[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Publisher/Browser - FileResource.py:1.1 Resource.py:1.1 Resources.py:1.1 config.zcml:1.1 metaConfigure.py:1.3 browser.zcml:NONE

Jim Fulton jim@zope.com
Thu, 13 Jun 2002 19:16:14 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/App/Publisher/Browser
In directory cvs.zope.org:/tmp/cvs-serv10697/lib/python/Zope/App/Publisher/Browser

Modified Files:
	metaConfigure.py 
Added Files:
	FileResource.py Resource.py Resources.py config.zcml 
Removed Files:
	browser.zcml 
Log Message:
Got icons working, and, along the way:

- Implemented the icon directive

- Implemented
  http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/ResourcesProposal

- Added a special view, named '', for service manager containers that
  allows resources to have URLs like:

  http://foo.com/@@/resourcename

- Fixed some server code that caused HTTP response data to get
  promoted to unicode

- Updated the folder contents page to display icons.

- Ported icons for folder, file, image, and zptpage. Many more icons
  need to be ported or created.



=== Added File Zope3/lib/python/Zope/App/Publisher/Browser/FileResource.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""

$Id: FileResource.py,v 1.1 2002/06/13 23:15:43 jim Exp $
"""
__metaclass__ = type # All classes are new style when run with Python 2.2+

from Zope.Exceptions import NotFoundError

from Zope.Publisher.Browser.BrowserView import BrowserView
from Zope.Publisher.Browser.IBrowserResource import IBrowserResource
from Zope.Publisher.Browser.IBrowserPublisher import IBrowserPublisher

from Zope.App.Publisher.FileResource import File, Image

from Zope.App.Publisher.Browser.Resource import Resource

class FileResource(BrowserView, Resource):

    __implements__ = IBrowserResource, IBrowserPublisher

    ############################################################
    # Implementation methods for interface
    # Zope.Publisher.Browser.IBrowserPublisher.

    def publishTraverse(self, request, name):
        '''See interface IBrowserPublisher'''
        raise NotFoundError(name)

    def browserDefault(self, request):
        '''See interface IBrowserPublisher'''
        method = request.get('REQUET_METHOD', 'GET').upper()
        return getattr(self, method), ()
        
    #
    ############################################################

    # for unit tests
    def _testData(self):
        f=open(self.context.path,'rb')
        data=f.read()
        f.close()
        return data
        

    def GET(self):
        """Default document"""

        file = self.context
        request = self.request
        response = request.getResponse()

        # HTTP If-Modified-Since header handling. This is duplicated
        # from OFS.Image.Image - it really should be consolidated
        # somewhere...
        header = request.getHeader('If-Modified-Since', None)
        if header is not None:
            header = header.split(';')[0]
            # Some proxies seem to send invalid date strings for this
            # header. If the date string is not valid, we ignore it
            # rather than raise an error to be generally consistent
            # with common servers such as Apache (which can usually
            # understand the screwy date string as a lucky side effect
            # of the way they parse it).
            try:    mod_since=long(timeFromDateTimeString(header))
            except: mod_since=None
            if mod_since is not None:
                if getattr(file, 'lmt', None):
                    last_mod = long(file.lmt)
                else:
                    last_mod = long(0)
                if last_mod > 0 and last_mod <= mod_since:
                    response.setStatus(304)
                    return ''

        response.setHeader('Content-Type', file.content_type)
        response.setHeader('Last-Modified', file.lmh)
        f=open(file.path,'rb')
        data=f.read()
        f.close()
        
        return data

    def HEAD(self):
        file = self.context
        response = self.request.getResponse()
        response.setHeader('Content-Type', file.content_type)
        response.setHeader('Last-Modified', file.lmh)
        return ''
    

class FileResourceFactory:

    def __init__(self, path):
        self.__file = File(path)

    def __call__(self, request):
        return FileResource(self.__file, request)

class ImageResourceFactory:

    def __init__(self, path):
        self.__file = Image(path)

    def __call__(self, request):
        return FileResource(self.__file, request)


=== Added File Zope3/lib/python/Zope/App/Publisher/Browser/Resource.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""

$Id: Resource.py,v 1.1 2002/06/13 23:15:43 jim Exp $
"""
__metaclass__ = type # All classes are new style when run with Python 2.2+

from Zope.ComponentArchitecture import queryView
from Zope.Proxy.ContextWrapper import getWrapperContainer, getWrapperData
from Zope.ContextWrapper import ContextMethod

class Resource:

    def __init__(self, request):
        self.request = request

    def __call__(self):
        name = getWrapperData(self)['name']
        if name.startswith('++resource++'):
            name = name[12:]

        service = getWrapperContainer(self)
        site = getWrapperContainer(service)
        if site is None:
            return "/@@/%s" % (name)

        absolute_url = queryView(service, 'absolute_url', self.request)

        if absolute_url is None:
            return "/@@/%s" % (name)

        site_url = absolute_url()
        
        return "%s/@@/%s" % (site_url, name)

    __call__ = ContextMethod(__call__)


=== Added File Zope3/lib/python/Zope/App/Publisher/Browser/Resources.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""Resource URL acess

$Id: Resources.py,v 1.1 2002/06/13 23:15:43 jim Exp $
"""
__metaclass__ = type # All classes are new style when run with Python 2.2+

from Zope.Publisher.Browser.BrowserView import BrowserView
from Zope.Publisher.Browser.IBrowserPublisher import IBrowserPublisher
from Zope.ComponentArchitecture import getService
from Zope.Proxy.ContextWrapper import ContextWrapper
from Zope.ContextWrapper import ContextMethod

class Resources(BrowserView):
    """Provide a URL-accessible resource namespace
    """

    __implements__ = BrowserView.__implements__, IBrowserPublisher

    ############################################################
    # Implementation methods for interface
    # Zope.Publisher.Browser.IBrowserPublisher.

    def publishTraverse(self, request, name):
        '''See interface IBrowserPublisher'''
        
        resource_service = getService(self, 'Resources')
        resource = resource_service.queryResource(self, name, request)
        if resource is None:
            raise NotFoundError(self, name)
        return ContextWrapper(resource, resource_service)

    publishTraverse = ContextMethod(publishTraverse)

    def browserDefault(self, request):
        '''See interface IBrowserPublisher'''
        return empty, ()
        
    #
    ############################################################

def empty():
    return ''


=== Added File Zope3/lib/python/Zope/App/Publisher/Browser/config.zcml ===
<zopeConfigure
   xmlns='http://namespaces.zope.org/zope'
   xmlns:security='http://namespaces.zope.org/security'
   xmlns:browser='http://namespaces.zope.org/browser'
>

<content class="Zope.Publisher.Browser.BrowserRequest.">
  <security:allow
      interface="Zope.Publisher.Browser.IBrowserApplicationRequest." />
  <security:allow
      interface="Zope.ComponentArchitecture.IPresentationRequest." />
</content>

<content class=".FileResource.">
  <security:allow interface="Zope.Publisher.Browser.IBrowserPublisher." />
  <security:allow attributes="GET HEAD __call__" />
</content>


<browser:view name=""
              factory=".Resources."
              for="Zope.ComponentArchitecture.IServiceManagerContainer."
              permission="Zope.Public"
              allowed_interface="Zope.Publisher.Browser.IBrowserPublisher."
              />

</zopeConfigure>


=== Zope3/lib/python/Zope/App/Publisher/Browser/metaConfigure.py 1.2 => 1.3 ===
 from Zope.App.PageTemplate.SimpleViewClass import SimpleViewClass
 
+from Zope.App.Publisher.Browser.FileResource \
+     import FileResourceFactory, ImageResourceFactory
 
 def skin(_context, **__kw):
     return _skin(_context,
@@ -41,12 +43,13 @@
     type = IBrowserPresentation
     default_allowed_attributes = '__call__'
 
-    def __init__(self, _context, factory, name=None, layer='default',
+    def __init__(self, _context, factory=None, name=None, layer='default',
                  permission=None,
-                 allowed_interface=None, allowed_attributes=None):
+                 allowed_interface=None, allowed_attributes=None,
+                 file=None, image=None):
 
         if ((allowed_attributes or allowed_interface)
-            and (not name or not permission)):
+            and ((name is None) or not permission)):
             raise ConfigurationError(
                 "Must use name attribute with allowed_interface or "
                 "allowed_attributes"
@@ -55,6 +58,9 @@
         if allowed_interface is not None:
             allowed_interface = _context.resolve(allowed_interface)
 
+        self.__file = file
+        self.__image = image
+
         self.factory = self._factory(_context, factory)
         self.layer = layer
         self.name = name
@@ -64,7 +70,29 @@
         self.pages = 0
 
     def _factory(self, _context, factory):
-        return _context.resolve(factory)
+        if ((factory is not None)
+            + (self.__file is not None)
+            + (self.__image is not None)
+            ) > 1:
+            raise ConfigurationError(
+                "Can't use more than one of factory, file, and image "
+                "attributes for resource directives"
+                )
+            
+        if factory is not None:
+            return _context.resolve(factory)
+
+        if self.__file is not None:
+            return FileResourceFactory(_context.path(self.__file))
+
+        if self.__image is not None:
+            return FileResourceFactory(_context.path(self.__image))
+
+        raise ConfigurationError(
+            "At least one of the factory, file, and image "
+            "attributes for resource directives must be specified"
+            )
+        
 
     def page(self, _context, name, attribute, permission=None, layer=None):
 
@@ -112,7 +140,7 @@
         return pageView
 
     def __call__(self):
-        if not self.name:
+        if self.name is None:
             return ()
 
         permission = self.permission
@@ -169,7 +197,7 @@
                  template=None):
 
         if template:
-            if not name:
+            if name is None:
                 raise ConfigurationError(
                     "Must specify name for template view")
 
@@ -252,10 +280,11 @@
 
             view = factory(context, request)
 
-            # We need this in case the resource gets unwrapped and needs to be rewrapped
+            # We need this in case the resource gets unwrapped and
+            # needs to be rewrapped
             view.__Security_checker__ = checker
 
-            return Proxy(view, checker)
+            return view
 
         factory[-1] =  proxyView
 

=== Removed File Zope3/lib/python/Zope/App/Publisher/Browser/browser.zcml ===