Make css url rewriting also works with absolute pats #5

Merged
merged 4 commits into from Jan 9, 2013
View
@@ -1,7 +1,5 @@
import codecs
import hashlib
-import os
-import os.path
import re
import urlparse
@@ -29,7 +27,7 @@ def _is_in_clipboard(filer_file):
def _construct_logical_folder_path(filer_file):
- return os.path.join(*(folder.name for folder in filer_file.logical_path))
+ return '/%s/' % '/'.join((folder.name for folder in filer_file.logical_path))
def _get_commented_regions(content):
@@ -134,7 +132,7 @@ def resolve_resource_urls(instance, **kwargs):
in css files.
django-filer has two concepts of urls:
- * the logical url: media/images/foobar.png
+ * the logical url: /media/images/foobar.png
* the actual url: filer_public/2012/11/22/foobar.png
Example: the css as written by the an end user uses logical urls:
@@ -155,7 +153,7 @@ def resolve_resource_urls(instance, **kwargs):
After url rewriting the above css example will look like:
.button.nice {
- background: url('filer_public/2012/11/22/foobar.png') /* logicalurl('media/images/misc/foobar.png') /* ;
+ background: url('filer_public/2012/11/22/foobar.png') /* logicalurl('/media/images/misc/foobar.png') /* ;
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.5);
}
@@ -191,9 +189,7 @@ def change_urls(match):
# or explicitly specifies a hostname; these are resources
# not served from filer
return match.group()
- relative_path = url
- logical_file_path = os.path.normpath(
- os.path.join(logical_folder_path, relative_path))
+ logical_file_path = urlparse.urljoin(logical_folder_path, url)
if not logical_file_path in local_cache:
local_cache[logical_file_path] = _RESOURCE_URL_TEMPLATE % (
filerfile(logical_file_path), logical_file_path)
@@ -212,7 +208,7 @@ def update_referencing_css_files(instance, **kwargs):
reference the resource pointed by 'instance'.
References are found by parsing all css files and looking for comments such as:
- /* logicalurl('media/images/misc/foobar.png') */
+ /* logicalurl('/media/images/misc/foobar.png') */
If the url between parentheses matches the logical url of the resource
being saved, the actual url (which percedes the comment)
@@ -224,7 +220,7 @@ def update_referencing_css_files(instance, **kwargs):
if _is_in_clipboard(resource_file):
return
resource_name = _get_filer_file_name(resource_file)
- logical_file_path = os.path.join(
+ logical_file_path = urlparse.urljoin(
_construct_logical_folder_path(resource_file),
resource_name)
css_files = File.objects.filter(original_filename__endswith=".css")
@@ -252,7 +248,9 @@ def update_referencing_css_files(instance, **kwargs):
def clear_urls_cache(instance, **kwargs):
"""Clears urls cached by the filerfile tag. """
- logical_file_path = os.path.join(
+ if _is_in_clipboard(instance):
+ return
+ logical_file_path = urlparse.urljoin(
_construct_logical_folder_path(instance),
instance.original_filename)
cache_key = get_filerfile_cache_key(logical_file_path)
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
@@ -0,0 +1,154 @@
+import hashlib
+import os.path
+import re
+import shutil
+
+from django.core.cache import cache
+from django.core.files.base import File as DjangoFile, ContentFile
+from django.test import TestCase
+
+from filer.models.filemodels import File
+from filer.models.foldermodels import Folder
+from filer.settings import FILER_PUBLICMEDIA_STORAGE
+from filer.tests.helpers import create_superuser
+
+from filertags.signals import _ALREADY_PARSED_MARKER, _LOGICAL_URL_TEMPLATE
+
+
+class CssRewriteTest(TestCase):
+
+ def _get_test_usermedia_location(self):
+ HERE = os.path.dirname(os.path.realpath(__file__))
+ return os.path.join(HERE, 'tmp_user_media')
+
+ def setUp(self):
+ self.superuser = create_superuser()
+ self.client.login(username='admin', password='secret')
+ media_folder = Folder.objects.create(name='media')
+ producer = Folder.objects.create(name='producer', parent=media_folder)
+ self.producer_css = Folder.objects.create(name='css', parent=producer)
+ self.producer_images = Folder.objects.create(name='images', parent=producer)
+ self.usual_location = FILER_PUBLICMEDIA_STORAGE.location
+ # all files generated during these tests are written to ./tmp_user_media
+ # and get deleted afterwards (see tearDown)
+ FILER_PUBLICMEDIA_STORAGE.location = self._get_test_usermedia_location()
+
+ def tearDown(self):
+ cache.clear()
+ shutil.rmtree(FILER_PUBLICMEDIA_STORAGE.location)
+ FILER_PUBLICMEDIA_STORAGE.location = self.usual_location
+
+ def create_file(self, name, folder, content=None):
+ if content is None:
+ file_obj = DjangoFile(
+ open(os.path.join(os.path.dirname(__file__), 'test_files', name)),
+ name=name)
+ else:
+ file_obj = ContentFile(content, name)
+ return File.objects.create(owner=self.superuser,
+ original_filename=name,
+ file=file_obj,
+ folder=folder)
+
+ def test_abslute_url_css_before_image(self):
+ css = self.create_file('absolute_url_to_image.css', self.producer_css,
+ content="""\
+.pledge-block {
+ background: url('/media/producer/images/foobar.png');
+}
+""")
+ css_content = open(css.path).read()
+ self.assertTrue(css_content.startswith(_ALREADY_PARSED_MARKER))
+ self.assertIn("url('')", css_content)
+ logical_url = _LOGICAL_URL_TEMPLATE % '/media/producer/images/foobar.png'
+ self.assertIn(logical_url, css_content)
+ image = self.create_file('foobar.png', self.producer_images)
+ updated_css = File.objects.get(pk=css.pk)
+ new_content = open(updated_css.path).read()
+ self.assertIsNotNone(re.search(r"\burl\('[^']*foobar[^']*png'\)", new_content))
+
+ def _verify_css_is_corectly_rewritten(self, css):
+ css_content = open(css.path).read()
+ self.assertTrue(css_content.startswith(_ALREADY_PARSED_MARKER))
+ logical_url = _LOGICAL_URL_TEMPLATE % '/media/producer/images/foobar.png'
+ self.assertIn(logical_url, css_content)
+ self.assertIsNotNone(re.search(r"\burl\('[^']*foobar[^']*png'\)", css_content))
+
+ def test_abslute_url_image_before_css(self):
+ image = self.create_file('foobar.png', self.producer_images)
+ css = self.create_file('absolute_url_to_image.css', self.producer_css,
+ content="""\
+.pledge-block {
+ background: url('/media/producer/images/foobar.png');
+}
+""")
+ self._verify_css_is_corectly_rewritten(css)
+
+ def test_relative_url_image_before_css(self):
+ image = self.create_file('foobar.png', self.producer_images)
+ css = self.create_file('relative_url_to_image.css', self.producer_css,
+ content="""\
+.pledge-block {
+ background: url('../images/foobar.png');
+}
+""")
+ self._verify_css_is_corectly_rewritten(css)
+
+ def test_double_quoted_url(self):
+ image = self.create_file('foobar.png', self.producer_images)
+ css = self.create_file('relative_url_to_image.css', self.producer_css,
+ content="""\
+.pledge-block {
+ background: url( " ../images/foobar.png " );
+}
+""")
+ self._verify_css_is_corectly_rewritten(css)
+
+ def test_unquoted_url(self):
+ image = self.create_file('foobar.png', self.producer_images)
+ css = self.create_file('relative_url_to_image.css', self.producer_css,
+ content="""\
+.pledge-block {
+ background: url( ../images/foobar.png );
+}
+""")
+ self._verify_css_is_corectly_rewritten(css)
+
+ def test_commented_url(self):
+ original_content = """\
+.pledge-block {
+/* background: url( ../images/foobar.png ); */
+}
+"""
+ css = self.create_file('relative_url_to_image.css', self.producer_css,
+ content=original_content)
+ css_content = open(css.path).read()
+ # css remains unchanged since the url statement is within a comment
+ expected_content = '%s\n%s' % (_ALREADY_PARSED_MARKER, original_content)
+ self.assertEqual(expected_content, css_content)
+
+ def test_non_http_schema(self):
+ original_content = """\
+.pledge-block {
+ background: url(data:image/png;base64,iVBORw0KGgoAA);
+}
+"""
+ css = self.create_file('relative_url_to_image.css', self.producer_css,
+ content=original_content)
+ css_content = open(css.path).read()
+ expected_content = '%s\n%s' % (_ALREADY_PARSED_MARKER, original_content)
+ self.assertEqual(expected_content, css_content)
+
+ def test_file_size_and_hash(self):
+ image = self.create_file('foobar.png', self.producer_images)
+ css = self.create_file('relative_url_to_image.css', self.producer_css,
+ content="""\
+.pledge-block {
+ background: url('../images/foobar.png');
+}
+""")
+ css_content = open(css.path).read()
+ self.assertEqual(len(css_content), css.size)
+ sha = hashlib.sha1()
+ sha.update(css_content)
+ self.assertEqual(sha.hexdigest(), css.sha1)