@@ -1,3 +1,9 @@ | |||||
Version 0.8.5a1 | |||||
============================================================ | |||||
* Added ability to specify safe characters in `content_url`, | |||||
`media_url` functions and `urlencode` filter. (Issue #103) | |||||
Version 0.8.4 | Version 0.8.4 | ||||
============================================================ | ============================================================ | ||||
@@ -1,4 +1,4 @@ | |||||
Version 0.8.4 | |||||
Version 0.8.5a1 | |||||
A brand new **hyde** | A brand new **hyde** | ||||
==================== | ==================== | ||||
@@ -53,8 +53,8 @@ class UrlCleanerPlugin(Plugin): | |||||
def clean_url(urlgetter): | def clean_url(urlgetter): | ||||
@wraps(urlgetter) | @wraps(urlgetter) | ||||
def wrapper(site, path): | |||||
url = urlgetter(site, path) | |||||
def wrapper(site, path, safe=None): | |||||
url = urlgetter(site, path, safe) | |||||
index_file_names = getattr(settings, | index_file_names = getattr(settings, | ||||
'index_file_names', | 'index_file_names', | ||||
['index.html']) | ['index.html']) | ||||
@@ -36,29 +36,32 @@ class SilentUndefined(Undefined): | |||||
return self | return self | ||||
@contextfunction | @contextfunction | ||||
def media_url(context, path): | |||||
def media_url(context, path, safe=None): | |||||
""" | """ | ||||
Returns the media url given a partial path. | Returns the media url given a partial path. | ||||
""" | """ | ||||
return context['site'].media_url(path) | |||||
return context['site'].media_url(path, safe) | |||||
@contextfunction | @contextfunction | ||||
def content_url(context, path): | |||||
def content_url(context, path, safe=None): | |||||
""" | """ | ||||
Returns the content url given a partial path. | Returns the content url given a partial path. | ||||
""" | """ | ||||
return context['site'].content_url(path) | |||||
return context['site'].content_url(path, safe) | |||||
@contextfunction | @contextfunction | ||||
def full_url(context, path): | |||||
def full_url(context, path, safe=None): | |||||
""" | """ | ||||
Returns the full url given a partial path. | Returns the full url given a partial path. | ||||
""" | """ | ||||
return context['site'].full_url(path) | |||||
return context['site'].full_url(path, safe) | |||||
@contextfilter | @contextfilter | ||||
def urlencode(ctx, url): | |||||
return quote(url.encode('utf8')) | |||||
def urlencode(ctx, url, safe=None): | |||||
if safe is not None: | |||||
return quote(url.encode('utf8'), safe) | |||||
else: | |||||
return quote(url.encode('utf8')) | |||||
@contextfilter | @contextfilter | ||||
def urldecode(ctx, url): | def urldecode(ctx, url): | ||||
@@ -51,7 +51,6 @@ class Processable(object): | |||||
""" | """ | ||||
return self.source.path | return self.source.path | ||||
class Resource(Processable): | class Resource(Processable): | ||||
""" | """ | ||||
Represents any file that is processed by hyde | Represents any file that is processed by hyde | ||||
@@ -412,33 +411,46 @@ class Site(object): | |||||
""" | """ | ||||
self.content.load() | self.content.load() | ||||
def content_url(self, path): | |||||
def content_url(self, path, safe=None): | |||||
""" | """ | ||||
Returns the content url by appending the base url from the config | Returns the content url by appending the base url from the config | ||||
with the given path. | |||||
with the given path. The return value is url encoded. | |||||
""" | """ | ||||
return quote(Folder(self.config.base_url).child(path).replace(os.sep, '/').encode("utf-8")) | |||||
fpath = Folder(self.config.base_url) \ | |||||
.child(path) \ | |||||
.replace(os.sep, '/').encode("utf-8") | |||||
if safe is not None: | |||||
return quote(fpath, safe) | |||||
else: | |||||
return quote(fpath) | |||||
def media_url(self, path): | |||||
def media_url(self, path, safe=None): | |||||
""" | """ | ||||
Returns the media url by appending the media base url from the config | Returns the media url by appending the media base url from the config | ||||
with the given path. | |||||
with the given path. The return value is url encoded. | |||||
""" | """ | ||||
return quote(Folder(self.config.media_url).child(path).replace(os.sep, '/').encode("utf-8")) | |||||
fpath = Folder(self.config.media_url) \ | |||||
.child(path) \ | |||||
.replace(os.sep, '/').encode("utf-8") | |||||
if safe is not None: | |||||
return quote(fpath, safe) | |||||
else: | |||||
return quote(fpath) | |||||
def full_url(self, path): | |||||
def full_url(self, path, safe=None): | |||||
""" | """ | ||||
Determines if the given path is media or content based on the | Determines if the given path is media or content based on the | ||||
configuration and returns the appropriate url. | |||||
configuration and returns the appropriate url. The return value | |||||
is url encoded. | |||||
""" | """ | ||||
if urlparse.urlparse(path)[:2] != ("",""): | if urlparse.urlparse(path)[:2] != ("",""): | ||||
return path | return path | ||||
if self.is_media(path): | if self.is_media(path): | ||||
relative_path = File(path).get_relative_path( | relative_path = File(path).get_relative_path( | ||||
Folder(self.config.media_root)) | Folder(self.config.media_root)) | ||||
return self.media_url(relative_path) | |||||
return self.media_url(relative_path, safe) | |||||
else: | else: | ||||
return self.content_url(path) | |||||
return self.content_url(path, safe) | |||||
def is_media(self, path): | def is_media(self, path): | ||||
""" | """ | ||||
@@ -197,6 +197,18 @@ class TestSiteWithConfig(object): | |||||
path = 'blog/2010/december' | path = 'blog/2010/december' | ||||
assert s.content_url(path) == "/" + path | assert s.content_url(path) == "/" + path | ||||
def test_content_url_encoding(self): | |||||
s = Site(self.SITE_PATH, config=self.config) | |||||
s.load() | |||||
path = '".jpg' | |||||
assert s.content_url(path) == quote("/" + path) | |||||
def test_content_url_encoding_safe(self): | |||||
s = Site(self.SITE_PATH, config=self.config) | |||||
s.load() | |||||
path = '".jpg/abc' | |||||
assert s.content_url(path, "") == quote("/" + path, "") | |||||
def test_media_url(self): | def test_media_url(self): | ||||
s = Site(self.SITE_PATH, config=self.config) | s = Site(self.SITE_PATH, config=self.config) | ||||
s.load() | s.load() | ||||
@@ -3,4 +3,4 @@ | |||||
Handles hyde version | Handles hyde version | ||||
TODO: Use fabric like versioning scheme | TODO: Use fabric like versioning scheme | ||||
""" | """ | ||||
__version__ = '0.8.4' | |||||
__version__ = '0.8.5a1' |