0001-general-serve-all-static-files-from-static-11582.patch
INSTALL | ||
---|---|---|
33 | 33 |
ServerAdmin webmaster@example.com |
34 | 34 |
ServerName www.example.com |
35 | 35 |
DocumentRoot /usr/share/wcs/web/ |
36 |
Alias /qo/ /usr/share/wcs/qommon/ |
|
37 | 36 | |
38 | 37 |
SCGIMount / 127.0.0.1:3001 |
39 |
<LocationMatch "^/(css|images|js|qo)/.*"> |
|
38 | ||
39 |
# this part allows serving static files directly from Apache, but it |
|
40 |
# requires to run wcsctl.py collectstatic first. |
|
41 |
Alias /static/ /var/lib/wcs/collectstatic/ |
|
42 |
<LocationMatch "^/static"> |
|
40 | 43 |
SCGIHandler off |
41 | 44 |
</LocationMatch> |
42 | 45 |
data/themes/alto/wcs.css | ||
---|---|---|
1 | 1 |
/* adapted from alto dotclear theme */ |
2 | 2 | |
3 |
@import url(/qo/css/qommon.css);
|
|
3 |
@import url(/static/css/qommon.css);
|
|
4 | 4 |
|
5 | 5 |
html, body { |
6 | 6 |
background: #CCCCCC; |
data/themes/default/template.mobile.ezt | ||
---|---|---|
3 | 3 |
<head> |
4 | 4 |
<title>[page_title]</title> |
5 | 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, user-scalable=0"> |
6 |
<script type="text/javascript" src="[root_url]qo/js/jquery.js"></script>
|
|
6 |
<script type="text/javascript" src="[root_url]static/xstatic/jquery.js"></script>
|
|
7 | 7 |
[script] |
8 |
<script type="text/javascript" src="[root_url]qo/js/wcs.mobile.js"></script>
|
|
9 |
<link rel="stylesheet" type="text/css" href="[root_url]qo/css/mobile.css"/>
|
|
8 |
<script type="text/javascript" src="[root_url]static/js/wcs.mobile.js"></script>
|
|
9 |
<link rel="stylesheet" type="text/css" href="[root_url]static/css/mobile.css"/>
|
|
10 | 10 |
<link rel="stylesheet" type="text/css" href="[theme_url]/mobile.css"/> |
11 | 11 |
</head> |
12 | 12 |
<body[if-any onload] onload="[onload]"[end]> |
data/web/css/wcs.css | ||
---|---|---|
1 |
@import url(../qo/css/sofresh.css);
|
|
1 |
@import url(sofresh.css); |
|
2 | 2 |
data/web/index.html | ||
---|---|---|
1 |
<html xmlns="http://www.w3.org/1999/xhtml"> |
|
2 |
<head> |
|
3 |
<title>w.c.s.</title> |
|
4 |
<link rel="stylesheet" type="text/css" href="/css/wcs.css"/> |
|
5 |
<style type="text/css"> |
|
6 |
p#wcs { |
|
7 |
margin-top: 30%; |
|
8 |
text-align: center; |
|
9 |
font-weight: bold; |
|
10 |
} |
|
11 |
</style> |
|
12 |
</head> |
|
13 |
<body> |
|
14 |
<p id="wcs"> |
|
15 |
w.c.s |
|
16 |
</p> |
|
17 |
</body> |
|
18 |
</html> |
debian/vhost-apache-wcs | ||
---|---|---|
2 | 2 |
ServerAdmin webmaster@locahost |
3 | 3 |
ServerName www.example.com |
4 | 4 |
DocumentRoot /usr/share/wcs/web/ |
5 |
Alias /qo/ /usr/share/wcs/qommon/ |
|
6 | 5 | |
7 | 6 |
SCGIMount / 127.0.0.1:3001 |
8 |
<LocationMatch "^/(css|images|js|qo)/.*"> |
|
7 | ||
8 |
Alias /static/ /var/lib/wcs/collectstatic/ |
|
9 |
<LocationMatch "^/static"> |
|
9 | 10 |
SCGIHandler off |
10 | 11 |
</LocationMatch> |
11 | 12 | |
13 |
Alias /themes/ /usr/share/wcs/themes/ |
|
14 |
RewriteEngine On |
|
15 |
RewriteCond /usr/share/wcs/%{REQUEST_URI} !-f |
|
16 |
RewriteCond /usr/share/wcs/%{REQUEST_URI} !-d |
|
17 |
RewriteRule ^/themes/(.*)$ /var/lib/wcs/%{HTTP_HOST}/themes/$1 |
|
18 | ||
12 | 19 |
CustomLog /var/log/apache2/wcs-access.log combined |
13 | 20 |
ErrorLog /var/log/apache2/wcs-error.log |
14 | ||
15 | 21 |
</VirtualHost> |
tests/test_ctl.py | ||
---|---|---|
21 | 21 |
def test_collectstatic(pub): |
22 | 22 |
CmdCollectStatic.collectstatic(pub) |
23 | 23 |
assert os.path.exists(os.path.join(pub.app_dir, 'collectstatic', 'css', 'wcs.css')) |
24 |
assert os.path.exists(os.path.join(pub.app_dir, 'collectstatic', 'css', 'qommon.css')) |
|
25 |
assert os.path.exists(os.path.join(pub.app_dir, 'collectstatic', 'css', 'gadjo.css')) |
|
26 |
assert os.path.exists(os.path.join(pub.app_dir, 'collectstatic', 'xstatic', 'jquery.js')) |
|
24 | 27 |
CmdCollectStatic.collectstatic(pub, clear=True, link=True) |
25 | 28 |
assert os.path.islink(os.path.join(pub.app_dir, 'collectstatic', 'css', 'wcs.css')) |
tests/test_rootdirectory.py | ||
---|---|---|
150 | 150 |
assert 'authentication required' in output # locales ? |
151 | 151 | |
152 | 152 |
def test_static_directories(): |
153 |
assert get_app(pub).get('/css/wcs.css') |
|
154 |
assert get_app(pub).get('/images/feed-icon-10x10.png') |
|
155 |
assert get_app(pub).get('/qo/css/qommon.css')
|
|
153 |
assert get_app(pub).get('/static/css/wcs.css')
|
|
154 |
assert get_app(pub).get('/static/images/feed-icon-10x10.png')
|
|
155 |
assert get_app(pub).get('/static/css/qommon.css')
|
|
156 | 156 |
if os.path.exists('/usr/share/javascript/leaflet/'): |
157 |
assert get_app(pub).get('/leaflet/leaflet.js') |
|
157 |
assert get_app(pub).get('/static/leaflet/leaflet.js')
|
|
158 | 158 |
assert get_app(pub).get('/static/css/gadjo.css') |
159 | 159 |
assert get_app(pub).get('/static/xstatic/jquery.js') |
160 | 160 |
assert get_app(pub).get('/static/xstatic/jquery-ui.js') |
161 | 161 | |
162 |
assert 'Directory listing denied' in get_app(pub).get('/css/').body |
|
162 |
assert 'Directory listing denied' in get_app(pub).get('/static/css/').body
|
|
163 | 163 |
assert get_app(pub).get('/static/xxx', status=404) |
wcs/ctl/collectstatic.py | ||
---|---|---|
41 | 41 | |
42 | 42 |
@classmethod |
43 | 43 |
def collectstatic(cls, pub, clear=False, link=False): |
44 |
root_directory_class = pub.root_directory_class |
|
44 |
from wcs.root import StaticsDirectory |
|
45 |
root_directory_class = StaticsDirectory |
|
45 | 46 |
static_dir = os.path.join(pub.app_dir, 'collectstatic') |
46 | 47 |
if clear and os.path.exists(static_dir): |
47 | 48 |
shutil.rmtree(static_dir) |
wcs/qommon/http_response.py | ||
---|---|---|
60 | 60 |
if not self.javascript_scripts: |
61 | 61 |
self.javascript_scripts = [] |
62 | 62 |
mappings = { |
63 |
'jquery.js': '../../static/xstatic/jquery.js',
|
|
64 |
'jquery-ui.js': '../../static/xstatic/jquery-ui.js',
|
|
63 |
'jquery.js': '../xstatic/jquery.js', |
|
64 |
'jquery-ui.js': '../xstatic/jquery-ui.js', |
|
65 | 65 |
} |
66 | 66 |
for script_name in script_names: |
67 | 67 |
mapped_script_name = mappings.get(script_name) or script_name |
68 | 68 |
if not mapped_script_name in self.javascript_scripts: |
69 | 69 |
if script_name == 'qommon.map.js': |
70 | 70 |
self.add_javascript(['jquery.js']) |
71 |
self.add_javascript(['../../leaflet/leaflet.js'])
|
|
72 |
self.add_css_include('../../leaflet/leaflet.css')
|
|
71 |
self.add_javascript(['../leaflet/leaflet.js']) |
|
72 |
self.add_css_include('../leaflet/leaflet.css') |
|
73 | 73 |
if script_name == 'jquery-ui.js': |
74 |
self.add_css_include('../../static/xstatic/themes/smoothness/jquery-ui.min.css')
|
|
74 |
self.add_css_include('../xstatic/themes/smoothness/jquery-ui.min.css') |
|
75 | 75 |
self.javascript_scripts.append(str(mapped_script_name)) |
76 | 76 |
if script_name == 'afterjob.js': |
77 | 77 |
self.add_javascript_code('var QOMMON_ROOT_URL = "%s";\n' % \ |
... | ... | |
92 | 92 |
if self.javascript_scripts: |
93 | 93 |
root_url = get_publisher().get_root_url() + get_publisher().qommon_static_dir |
94 | 94 |
s += '\n'.join(['<script type="text/javascript" src="%sjs/%s"></script>' % ( |
95 |
root_url, str(x)) for x in self.javascript_scripts |
|
96 |
if not x[0] == '/']) |
|
97 |
s += '\n' |
|
98 |
s += '\n'.join(['<script type="text/javascript" src="%sjs/%s"></script>' % ( |
|
99 |
get_publisher().get_root_url(), x[1:]) for x in self.javascript_scripts |
|
100 |
if x[0] == '/']) |
|
95 |
root_url, str(x)) for x in self.javascript_scripts]) |
|
101 | 96 |
s += '\n' |
102 | 97 |
if self.javascript_code_parts: |
103 | 98 |
s += '<script type="text/javascript">' |
wcs/qommon/publisher.py | ||
---|---|---|
81 | 81 |
unpickler_class = None |
82 | 82 | |
83 | 83 |
after_login_url = '' |
84 |
qommon_static_dir = 'qo/'
|
|
84 |
qommon_static_dir = 'static/'
|
|
85 | 85 |
qommon_admin_css = 'css/dc2/admin.css' |
86 | 86 |
default_theme = 'default' |
87 | 87 |
wcs/qommon/template.py | ||
---|---|---|
363 | 363 |
app_label = get_publisher().get_site_option('app_label') or 'w.c.s.' |
364 | 364 |
else: |
365 | 365 |
if current_theme == 'default': |
366 |
css = root_url + 'css/%s.css' % get_publisher().APP_NAME |
|
366 |
css = root_url + 'static/css/%s.css' % get_publisher().APP_NAME
|
|
367 | 367 |
else: |
368 | 368 |
css = root_url + 'themes/%s/%s.css' % (current_theme, get_publisher().APP_NAME) |
369 | 369 |
wcs/root.py | ||
---|---|---|
196 | 196 |
return errors.TraversalError() |
197 | 197 | |
198 | 198 | |
199 |
class StaticsDirectory(Directory): |
|
200 |
static_directories = { |
|
201 |
# maps /leaflet/ to the directory provided by the libjs-openlayers package |
|
202 |
'leaflet': ['/usr/share/javascript/leaflet'], |
|
203 |
'': ['web', 'qommon', 'django:gadjo'], |
|
204 |
'xstatic': ['xstatic:jquery', 'xstatic:jquery_ui', 'xstatic:font_awesome'], |
|
205 |
} |
|
206 | ||
207 |
@classmethod |
|
208 |
def resolve_static_directories(cls, prefix): |
|
209 |
directories = cls.static_directories[prefix] |
|
210 |
for directory in directories: |
|
211 |
if directory[0] == '/': |
|
212 |
yield directory |
|
213 |
elif not ':' in directory: |
|
214 |
yield os.path.join(get_publisher().data_dir, directory) |
|
215 |
else: |
|
216 |
directory_type, value = directory.split(':') |
|
217 |
try: |
|
218 |
if directory_type == 'xstatic': |
|
219 |
module = import_module('xstatic.pkg.%s' % value) |
|
220 |
yield module.BASE_DIR |
|
221 |
elif directory_type == 'django': |
|
222 |
module = import_module(value) |
|
223 |
yield os.path.join(os.path.dirname(module.__file__), 'static') |
|
224 |
except ImportError: |
|
225 |
pass |
|
226 | ||
227 |
def _q_traverse(self, path): |
|
228 |
if path[0] in self.static_directories.keys(): |
|
229 |
prefix, rest = path[0], path[1:] |
|
230 |
else: |
|
231 |
prefix, rest = '', path |
|
232 | ||
233 |
if not rest: |
|
234 |
raise errors.AccessForbiddenError() |
|
235 | ||
236 |
for directory in self.resolve_static_directories(prefix): |
|
237 |
try: |
|
238 |
return StaticDirectory(directory, follow_symlinks=True)._q_traverse(rest) |
|
239 |
except errors.TraversalError: |
|
240 |
continue |
|
241 |
raise errors.TraversalError() |
|
242 | ||
243 | ||
199 | 244 |
class RootDirectory(Directory): |
200 | 245 |
_q_exports = ['admin', 'backoffice', 'forms', 'login', 'logout', 'saml', |
201 | 246 |
'ident', 'register', 'afterjobs', 'themes', 'myspace', 'user', 'roles', |
202 | 247 |
'pages', ('tmp-upload', 'tmp_upload'), 'api', '__version__', |
203 | 248 |
'tryauth', 'auth', 'preview', ('reload-top', 'reload_top'), |
204 |
'fargo', ('i18n.js', 'i18n_js')] |
|
249 |
'fargo', ('i18n.js', 'i18n_js'), 'static']
|
|
205 | 250 | |
206 | 251 |
api = ApiDirectory() |
207 | 252 |
themes = template.ThemesDirectory() |
208 | 253 |
myspace = MyspaceDirectory() |
209 | 254 |
pages = qommon.pages.PagesDirectory() |
210 | 255 |
fargo = file_validation.FargoDirectory() |
211 | ||
212 |
static_directories = { |
|
213 |
'css': ['web/css'], |
|
214 |
'images': ['web/images'], |
|
215 |
'qo': ['qommon'], |
|
216 |
# maps /leaflet/ to the directory provided by the libjs-openlayers package |
|
217 |
'leaflet': ['/usr/share/javascript/leaflet'], |
|
218 |
'static': ['django:gadjo'], |
|
219 |
'static_xstatic': ['xstatic:jquery', 'xstatic:jquery_ui', 'xstatic:font_awesome'], |
|
220 |
} |
|
256 |
static = StaticsDirectory() |
|
221 | 257 | |
222 | 258 |
def tryauth(self): |
223 | 259 |
return forms.root.tryauth(get_publisher().get_root_url()) |
... | ... | |
303 | 339 |
if not self.backoffice: |
304 | 340 |
self.backoffice = get_publisher().backoffice_directory_class() |
305 | 341 | |
306 |
if path and path[0] in self.static_directories: |
|
307 |
return self.serve_statics(path) |
|
308 | ||
309 | 342 |
try: |
310 | 343 |
return Directory._q_traverse(self, path) |
311 | 344 |
except errors.TraversalError: |
... | ... | |
313 | 346 | |
314 | 347 |
return forms.root.RootDirectory()._q_traverse(path) |
315 | 348 | |
316 |
@classmethod |
|
317 |
def resolve_static_directories(cls, prefix): |
|
318 |
directories = cls.static_directories[prefix] |
|
319 |
for directory in directories: |
|
320 |
if directory[0] == '/': |
|
321 |
yield directory |
|
322 |
elif not ':' in directory: |
|
323 |
yield os.path.join(get_publisher().data_dir, directory) |
|
324 |
else: |
|
325 |
directory_type, value = directory.split(':') |
|
326 |
try: |
|
327 |
if directory_type == 'xstatic': |
|
328 |
module = import_module('xstatic.pkg.%s' % value) |
|
329 |
yield module.BASE_DIR |
|
330 |
elif directory_type == 'django': |
|
331 |
module = import_module(value) |
|
332 |
yield os.path.join(os.path.dirname(module.__file__), 'static') |
|
333 |
except ImportError: |
|
334 |
pass |
|
335 | ||
336 |
def serve_statics(self, path): |
|
337 |
if path[:2] == ['static', 'xstatic']: |
|
338 |
# hack path so it's easier to lookup files from xstatic modules |
|
339 |
# (the gadjo xstatic storage adds a "xstatic" prefix that is not on |
|
340 |
# the filesystem, while StaticDirectory expects the filesystem |
|
341 |
# layout to match exactly; so we merge the first two elements in a |
|
342 |
# single one, so we get the real path in path[1:]) |
|
343 |
path = ['static_xstatic'] + path[2:] |
|
344 | ||
345 |
for directory in self.resolve_static_directories(path[0]): |
|
346 |
try: |
|
347 |
return StaticDirectory(directory, follow_symlinks=True)._q_traverse(path[1:]) |
|
348 |
except errors.TraversalError: |
|
349 |
continue |
|
350 |
raise errors.TraversalError() |
|
351 | ||
352 | 349 |
def _q_lookup(self, component): |
353 | 350 |
# is this a category ? |
354 | 351 |
try: |
355 |
- |