-
Notifications
You must be signed in to change notification settings - Fork 96
/
resource.py
186 lines (136 loc) · 5.34 KB
/
resource.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
##############################################################################
#
# Copyright (c) 2004, 2005 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (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.
#
##############################################################################
"""Provide basic resource functionality
"""
import os
import urllib
import zope.browserresource.directory
import zope.browserresource.file
from zope.browserresource.file import File
from zope.interface import implements
from zope.traversing.browser import absoluteURL
from zope.publisher.interfaces import NotFound
from zope.publisher.interfaces.browser import IBrowserPublisher
from zope.ptresource.ptresource import PageTemplate
from Products.Five.browser import BrowserView
_marker = object()
class Resource(object):
"""A mixin that changes the URL-rendering of resources (__call__).
In zope.browserresource, resource URLs are of the form
nearest_site/@@/resource_name. Since Zope 2 didn't have support
for sites from the beginning of the Five integration, resource
URLs in Zope 2 are of the form context/++resource++resource_name.
TODO It would be good if that could be changed in the long term,
thus making this mixin (and probably the other classes in this
module) obsolete.
"""
def __call__(self):
name = self.__name__
container = self.__parent__
url = urllib.unquote(absoluteURL(container, self.request))
if not isinstance(container, DirectoryResource):
name = '++resource++%s' % name
return "%s/%s" % (url, name)
class PageTemplateResource(Resource, BrowserView):
implements(IBrowserPublisher)
def browserDefault(self, request):
return self.render, ()
def publishTraverse(self, request, name):
raise NotFound(self, name, request)
def render(self):
"""Rendered content"""
# ZPublisher might have called setBody with an incorrect URL
# we definitely don't want that if we are plain html
self.request.response.setBase(None)
pt = self.context
return pt(self.request)
class FileResource(Resource, zope.browserresource.file.FileResource):
pass
class ResourceFactory(object):
factory = None
resource = None
def __init__(self, name, path, resource_factory=None):
self.__name = name
self.__rsrc = self.factory(path, name)
if resource_factory is not None:
self.resource = resource_factory
def __call__(self, request):
resource = self.resource(self.__rsrc, request)
return resource
def _PageTemplate(self, path, name):
# PageTemplate doesn't take a name parameter,
# which makes it different from FileResource.
# This is probably an error.
template = PageTemplate(path)
template.__name__ = name
return template
class PageTemplateResourceFactory(ResourceFactory):
"""A factory for Page Template resources"""
factory = _PageTemplate
resource = PageTemplateResource
class FileResourceFactory(ResourceFactory):
"""A factory for File resources"""
factory = File
resource = FileResource
class ImageResourceFactory(ResourceFactory):
"""A factory for Image resources"""
factory = File
resource = FileResource
# we only need this class a context for DirectoryResource
class Directory(object):
def __init__(self, path, name):
self.path = path
self.__name__ = name
class DirectoryResource(Resource,
zope.browserresource.directory.DirectoryResource):
resource_factories = {
'gif': ImageResourceFactory,
'png': ImageResourceFactory,
'jpg': ImageResourceFactory,
'pt': PageTemplateResourceFactory,
'zpt': PageTemplateResourceFactory,
'html': PageTemplateResourceFactory,
'htm': PageTemplateResourceFactory,
}
default_factory = FileResourceFactory
def getId(self):
name = self.__name__
if not name.startswith('++resource++'):
name = '++resource++%s' % self.__name__
return name
def get(self, name, default=_marker):
path = self.context.path
filename = os.path.join(path, name)
isfile = os.path.isfile(filename)
isdir = os.path.isdir(filename)
if not (isfile or isdir):
if default is _marker:
raise KeyError(name)
return default
if isfile:
ext = name.split('.')[-1]
factory = self.resource_factories.get(ext, self.default_factory)
else:
factory = DirectoryResourceFactory
resource = factory(name, filename)(self.request)
resource.__name__ = name
resource.__parent__ = self
# We need to propagate security so that restrictedTraverse() will
# work
if hasattr(self, '__roles__'):
resource.__roles__ = self.__roles__
return resource
class DirectoryResourceFactory(ResourceFactory):
factory = Directory
resource = DirectoryResource