Skip to content

Commit

Permalink
Reimplement the read.rdf template lost in genshi purge
Browse files Browse the repository at this point in the history
Fixes #2063 by re-adding the missing template, but implemented with
jinja instead.  The accept-header checks have been simplified as the
different loaders are no longer required.

N3 template is still broken but is included for completeness
  • Loading branch information
rossjones committed Nov 20, 2014
1 parent 0ddd6fd commit c851bbc
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 33 deletions.
19 changes: 9 additions & 10 deletions ckan/controllers/package.py
Expand Up @@ -313,10 +313,10 @@ def pager_url(q=None, page=None):
extra_vars={'dataset_type': package_type})

def _content_type_from_extension(self, ext):
ct, mu, ext = accept.parse_extension(ext)
ct, ext = accept.parse_extension(ext)
if not ct:
return None, None, None,
return ct, ext, (NewTextTemplate, MarkupTemplate)[mu]
return None, None
return ct, ext

def _content_type_from_accept(self):
"""
Expand All @@ -325,8 +325,8 @@ def _content_type_from_accept(self):
it accurately. TextTemplate must be used for non-xml templates
whilst all that are some sort of XML should use MarkupTemplate.
"""
ct, mu, ext = accept.parse_header(request.headers.get('Accept', ''))
return ct, ext, (NewTextTemplate, MarkupTemplate)[mu]
ct, ext = accept.parse_header(request.headers.get('Accept', ''))
return ct, ext

def resources(self, id):
package_type = self._get_package_type(id.split('@')[0])
Expand Down Expand Up @@ -358,16 +358,15 @@ def resources(self, id):

def read(self, id, format='html'):
if not format == 'html':
ctype, extension, loader = \
ctype, extension = \
self._content_type_from_extension(format)
if not ctype:
# An unknown format, we'll carry on in case it is a
# revision specifier and re-constitute the original id
id = "%s.%s" % (id, format)
ctype, format, loader = "text/html; charset=utf-8", "html", \
MarkupTemplate
ctype, format = "text/html; charset=utf-8", "html"
else:
ctype, format, loader = self._content_type_from_accept()
ctype, format = self._content_type_from_accept()

response.headers['Content-Type'] = ctype

Expand Down Expand Up @@ -427,7 +426,7 @@ def read(self, id, format='html'):
template = template[:template.index('.') + 1] + format

try:
return render(template, loader_class=loader,
return render(template,
extra_vars={'dataset_type': package_type})
except ckan.lib.render.TemplateNotFound:
msg = _("Viewing {package_type} datasets in {format} format is "
Expand Down
10 changes: 5 additions & 5 deletions ckan/lib/accept.py
Expand Up @@ -9,10 +9,10 @@
accept_re = re.compile("^(?P<ct>[^;]+)[ \t]*(;[ \t]*q=(?P<q>[0-9.]+)){0,1}$")

accept_types = {
# Name : ContentType, Is Markup?, Extension
"text/html": ("text/html; charset=utf-8", True, 'html'),
"text/n3": ("text/n3; charset=utf-8", False, 'n3'),
"application/rdf+xml": ("application/rdf+xml; charset=utf-8", True, 'rdf'),
# Name : ContentType, Extension
"text/html": ("text/html; charset=utf-8", 'html'),
"text/n3": ("text/n3; charset=utf-8", 'n3'),
"application/rdf+xml": ("application/rdf+xml; charset=utf-8", 'rdf'),
}
accept_by_extension = {
"rdf": "application/rdf+xml",
Expand All @@ -28,7 +28,7 @@ def parse_extension(file_ext):
ext = accept_by_extension.get(file_ext, None)
if ext:
return accept_types[ext]
return (None, None, None,)
return (None, None)


def parse_header(accept_header=''):
Expand Down
4 changes: 2 additions & 2 deletions ckan/plugins/interfaces.py
Expand Up @@ -963,8 +963,8 @@ def read_template(self):
``'package/read.html'``.
If the user requests the dataset in a format other than HTML
(CKAN supports returning datasets in RDF or N3 format by appending .rdf
or .n3 to the dataset read URL, see
(CKAN supports returning datasets in RDF format by appending .rdf
to the dataset read URL, see
:doc:`/maintaining/linked-data-and-rdf`) then CKAN will try to render a
template file with the same path as returned by this function, but a
different filename extension, e.g. ``'package/read.rdf'``. If your
Expand Down
45 changes: 45 additions & 0 deletions ckan/templates/package/read.n3
@@ -0,0 +1,45 @@
@prefix : <http://www.w3.org/2000/01/rdf-schema#> .
@prefix dcat: <http://www.w3.org/ns/dcat#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

<{{ h.url_for(controller='package',action='read',id=c.pkg_dict['name'], qualified=True)}}>
a dcat:Dataset;
dct:description "{{c.pkg_dict['notes']}}";
dct:identifier "{{c.pkg_dict['name']}}";
dct:relation [
rdf:value "";
:label "change_note" ],
[
rdf:value "";
:label "definition_note" ],
[
rdf:value "";
:label "editorial_note" ],
[
rdf:value "";
:label "example_note" ],
[
rdf:value "";
:label "history_note" ],
[
rdf:value "";
:label "scope_note" ],
[
rdf:value "";
:label "skos_note" ],
[
rdf:value "";
:label "temporal_granularity" ],
[
rdf:value "";
:label "type_of_dataset" ],
[
rdf:value "";
:label "update_frequency" ];
dct:title "{{c.pkg_dict['title']}}";
:label "{{c.pkg_dict['name']}}";
= <urn:uuid:{{c.pkg_dict['id']}}>;
foaf:homepage <{{ h.url_for(controller='package',action='read',id=c.pkg_dict['name'], qualified=True)}}> .
72 changes: 72 additions & 0 deletions ckan/templates/package/read.rdf
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
xmlns:py="http://genshi.edgewall.org/"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dcat="http://www.w3.org/ns/dcat#"
xmlns:dct="http://purl.org/dc/terms/"
>
<dcat:Dataset rdf:about="{{ h.url_for(controller='package',action='read',id=c.pkg_dict['name'], qualified=True) }}">
<owl:sameAs rdf:resource="urn:uuid:{{c.pkg_dict['id']}}"/>
<dct:description>{{c.pkg_dict['notes']}}</dct:description>
{% for tag_dict in c.pkg_dict['tags'] %}
<dcat:keyword>{{ tag_dict["name"] }}</dcat:keyword>
{% endfor %}
<foaf:homepage rdf:resource="{{ h.url_for(controller='package',action='read',id=c.pkg_dict['name'], qualified=True)}}"/>
<rdfs:label>{{c.pkg_dict['name']}}</rdfs:label>

<dct:identifier>{{c.pkg_dict['name']}}</dct:identifier>
<dct:title>{{c.pkg_dict['title']}}</dct:title>
{% for rsc_dict in c.pkg_dict['resources'] %}
<dcat:distribution>
<dcat:Distribution>
<dcat:accessURL rdf:resource="{{ rsc_dict['url'] }}"/>
{% if rsc_dict.get('format')%}
<dct:format>
<dct:IMT>
<rdf:value>{{rsc_dict.get('format')}}</rdf:value>
<rdfs:label>{{rsc_dict.get('format')}}</rdfs:label>
</dct:IMT>
</dct:format>
{% endif %}
{% if rsc_dict.get('name')%}<dct:title>{{rsc_dict.get('name')}}</dct:title>{% endif %}
</dcat:Distribution>
</dcat:distribution>
{% endfor %}
{% if c.pkg_dict.get('author', None) %}
<dct:creator>
<rdf:Description>
<foaf:name>{{ c.pkg_dict['author'] }}</foaf:name>
{% if c.pkg_dict.get('maintainer_email', None)%}
<foaf:mbox rdf:resource="mailto:{{c.pkg_dict['author_email']}}"/>
{% endif %}
</rdf:Description>
</dct:creator>
{% endif %}
{% if c.pkg_dict.get('maintainer', None)%}
<dct:contributor>
<rdf:Description>
<foaf:name>{{ c.pkg_dict['maintainer'] }}</foaf:name>
{% if c.pkg_dict.get('maintainer_email', None) %}
<foaf:mbox rdf:resource="mailto:{{c.pkg_dict['maintainer_email']}}"/>
{% endif %}
</rdf:Description>
</dct:contributor>
{% endif %}

{% if c.pkg_dict.get('license_url', None) %}
<dct:rights rdf:resource="{{c.pkg_dict['license_url']}}"/>
{% endif %}

{% for extra_dict in c.pkg_dict.get('extras',None) %}
<dct:relation>
<rdf:Description>
<rdfs:label>{{extra_dict.get('key','')}}</rdfs:label>
<rdf:value>{{extra_dict.get('value','')}}</rdf:value>
</rdf:Description>
</dct:relation>
{% endfor %}
</dcat:Dataset>
</rdf:RDF>
12 changes: 12 additions & 0 deletions ckan/tests/functional/test_package.py
Expand Up @@ -238,6 +238,18 @@ def check_link(res, controller, id):
assert 'decoy</a>' not in res, res
assert 'decoy"' not in res, res

def test_read_rdf(self):
name = 'annakarenina'
offset = url_for(controller='package', action='read', id=name) + ".rdf"
res = self.app.get(offset, status=200)
assert 'dcat' in res, res

def test_read_n3(self):
name = 'annakarenina'
offset = url_for(controller='package', action='read', id=name) + ".n3"
res = self.app.get(offset, status=200)
assert 'dcat' in res, res

def test_read_plugin_hook(self):
plugins.load('test_package_controller_plugin')
plugin = plugins.get_plugin('test_package_controller_plugin')
Expand Down
24 changes: 8 additions & 16 deletions ckan/tests/lib/test_accept.py
Expand Up @@ -4,55 +4,47 @@

class TestAccept:
def test_accept_invalid(self):
ct, markup, ext = accept.parse_header(None)
ct, ext = accept.parse_header(None)
assert_equal( ct, "text/html; charset=utf-8")
assert_equal( markup, True)
assert_equal( ext, "html")

def test_accept_invalid2(self):
ct, markup, ext = accept.parse_header("")
ct, ext = accept.parse_header("")
assert_equal( ct, "text/html; charset=utf-8")
assert_equal( markup, True)
assert_equal( ext, "html")

def test_accept_invalid3(self):
ct, markup, ext = accept.parse_header("wombles")
ct, ext = accept.parse_header("wombles")
assert_equal( ct, "text/html; charset=utf-8")
assert_equal( markup, True)
assert_equal( ext, "html")


def test_accept_valid(self):
a = "text/turtle,application/turtle,application/rdf+xml,text/plain;q=0.8,*/*;q=.5"
ct, markup, ext = accept.parse_header(a)
ct, ext = accept.parse_header(a)
assert_equal( ct, "application/rdf+xml; charset=utf-8")
assert_equal( markup, True)
assert_equal( ext, "rdf")

def test_accept_valid2(self):
a = "text/turtle,application/turtle,application/rdf+xml;q=0.9,text/plain;q=0.8,*/*;q=.5"
ct, markup, ext = accept.parse_header(a)
ct, ext = accept.parse_header(a)
assert_equal( ct, "application/rdf+xml; charset=utf-8")
assert_equal( markup, True)
assert_equal( ext, "rdf")

def test_accept_valid4(self):
a = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
ct, markup, ext = accept.parse_header(a)
ct, ext = accept.parse_header(a)
assert_equal( ct, "text/html; charset=utf-8")
assert_equal( markup, True)
assert_equal( ext, "html")

def test_accept_valid5(self):
a = "application/rdf+xml;q=0.5,application/xhtml+xml,text/html;q=0.9"
ct, markup, ext = accept.parse_header(a)
ct, ext = accept.parse_header(a)
assert_equal( ct, "text/html; charset=utf-8")
assert_equal( markup, True)
assert_equal( ext, "html")

def test_accept_valid6(self):
a = "application/rdf+xml;q=0.9,application/xhtml+xml,text/html;q=0.5"
ct, markup, ext = accept.parse_header(a)
ct, ext = accept.parse_header(a)
assert_equal( ct, "application/rdf+xml; charset=utf-8")
assert_equal( markup, True)
assert_equal( ext, "rdf")

0 comments on commit c851bbc

Please sign in to comment.