Skip to content

Commit

Permalink
Merge branch 'release-v2.5.7' into release-v2.5-latest
Browse files Browse the repository at this point in the history
  • Loading branch information
amercader committed Sep 26, 2017
2 parents efe1b8d + 333095f commit 5a033dc
Show file tree
Hide file tree
Showing 12 changed files with 57 additions and 22 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Expand Up @@ -7,6 +7,13 @@
Changelog
---------

v2.5.7 2017-09-27
=================

* Allow overriding email headers (#3781)
* Support non-root instances on fanstatic (#3618)
* Add missing close button on organization page (#3814)

v2.5.6 2017-08-02
=================

Expand Down
2 changes: 1 addition & 1 deletion ckan/__init__.py
@@ -1,4 +1,4 @@
__version__ = '2.5.6'
__version__ = '2.5.7'

__description__ = 'CKAN Software'
__long_description__ = \
Expand Down
5 changes: 5 additions & 0 deletions ckan/config/middleware.py
Expand Up @@ -5,6 +5,7 @@
import json
import hashlib
import os
import re

import sqlalchemy as sa
from beaker.middleware import CacheMiddleware, SessionMiddleware
Expand Down Expand Up @@ -95,6 +96,10 @@ def make_app(conf, full_stack=True, static_files=True, **app_conf):
'bottom': True,
'bundle': True,
}
root_path = config.get('ckan.root_path', None)
if root_path:
root_path = re.sub('/{{LANG}}', '', root_path)
fanstatic_config['base_url'] = root_path
app = Fanstatic(app, **fanstatic_config)

for plugin in PluginImplementations(IMiddleware):
Expand Down
2 changes: 1 addition & 1 deletion ckan/controllers/package.py
Expand Up @@ -1106,7 +1106,7 @@ def resource_read(self, id, resource_id):
except KeyError:
c.package['isopen'] = False

# TODO: find a nicer way of doing this
# Deprecated: c.datastore_api - use h.action_url instead
c.datastore_api = '%s/api/action' % \
config.get('ckan.site_url', '').rstrip('/')

Expand Down
9 changes: 9 additions & 0 deletions ckan/lib/helpers.py
Expand Up @@ -17,6 +17,7 @@
import copy
import urlparse
from urllib import urlencode
import uuid

from paste.deploy.converters import asbool
from webhelpers.html import HTML, literal, url_escape
Expand Down Expand Up @@ -2164,6 +2165,13 @@ def mail_to(email_address, name):
return html


def sanitize_id(id_):
'''Given an id (uuid4), if it has any invalid characters it raises
ValueError.
'''
return str(uuid.UUID(id_))


# these are the functions that will end up in `h` template helpers
__allowed_functions__ = [
# functions defined in ckan.lib.helpers
Expand Down Expand Up @@ -2285,4 +2293,5 @@ def mail_to(email_address, name):
'view_resource_url',
'license_options',
'clean_html',
'sanitize_id',
]
7 changes: 5 additions & 2 deletions ckan/lib/mailer.py
Expand Up @@ -5,7 +5,6 @@
from email.mime.text import MIMEText
from email.header import Header
from email import Utils
from urlparse import urljoin

from pylons import config
import paste.deploy.converters
Expand All @@ -32,7 +31,11 @@ def _mail_recipient(recipient_name, recipient_email,
mail_from = config.get('smtp.mail_from')
body = add_msg_niceties(recipient_name, body, sender_name, sender_url)
msg = MIMEText(body.encode('utf-8'), 'plain', 'utf-8')
for k, v in headers.items(): msg[k] = v
for k, v in headers.items():
if k in msg.keys():
msg.replace_header(k, v)
else:
msg.add_header(k, v)
subject = Header(subject.encode('utf-8'), 'utf-8')
msg['Subject'] = subject
msg['From'] = _("%s <%s>") % (sender_name, mail_from)
Expand Down
25 changes: 12 additions & 13 deletions ckan/templates/ajax_snippets/api_info.html
@@ -1,18 +1,18 @@
{#
Displays information about accessing a resource via the API.

datastore_root_url - The root API url.
resource_id - The resource id
embedded - If true will not include the "modal" classes on the snippet.

Example

{% snippet 'ajax_snippets/api_info.html', datastore_root_url=datastore_root_url, resource_id=resource_id, embedded=true %}
{% snippet 'ajax_snippets/api_info.html', resource_id=resource_id, embedded=true %}

#}

{% set sql_example_url = datastore_root_url + '/datastore_search_sql?sql=SELECT * from "' + resource_id + '" WHERE title LIKE \'jones\'' %}

{% set resource_id = h.sanitize_id(resource_id) %}
{% set sql_example_url = h.url_for(controller='api', action='action', ver=3, logic_function='datastore_search_sql', qualified=True) + '?sql=SELECT * from "' + resource_id + '" WHERE title LIKE \'jones\'' %}
{# not urlencoding the sql because its clearer #}
<div{% if not embedded %} class="modal"{% endif %}>
<div class="modal-header">
<h3>
Expand Down Expand Up @@ -40,19 +40,19 @@ <h3>
<tbody>
<tr>
<th scope="row">{{ _('Create') }}</th>
<td><code>{{ datastore_root_url }}/datastore_create</code></td>
<td><code>{{ h.url_for(controller='api', action='action', ver=3, logic_function='datastore_create', qualified=True) }}</code></td>
</tr>
<tr>
<th scope="row">{{ _('Update / Insert') }}</th>
<td><code>{{ datastore_root_url }}/datastore_upsert</code></td>
<td><code>{{ h.url_for(controller='api', action='action', ver=3, logic_function='datastore_upsert', qualified=True) }}</code></td>
</tr>
<tr>
<th scope="row">{{ _('Query') }}</th>
<td><code>{{ datastore_root_url }}/datastore_search</code></td>
<td><code>{{ h.url_for(controller='api', action='action', ver=3, logic_function='datastore_search', qualified=True) }}</code></td>
</tr>
<tr>
<th scope="row">{{ _('Query (via SQL)') }}</th>
<td><code>{{ datastore_root_url }}/datastore_search_sql</code></td>
<td><code>{{ h.url_for(controller='api', action='action', ver=3, logic_function='datastore_search_sql', qualified=True) }}</code></td>
</tr>

</tbody>
Expand All @@ -69,13 +69,12 @@ <h3>
<div class="accordion-inner">
<strong>{{ _('Query example (first 5 results)') }}</strong>
<p>
<code><a href="{{ datastore_root_url }}/datastore_search?resource_id={{resource_id}}&limit=5" target="_blank">{{ datastore_root_url }}/datastore_search?resource_id={{resource_id}}&limit=5</a></code>
<code><a href="{{ h.url_for(controller='api', action='action', ver=3, logic_function='datastore_search', resource_id=resource_id, limit=5, qualified=True) }}" target="_blank">{{ h.url_for(controller='api', action='action', ver=3, logic_function='datastore_search', resource_id=resource_id, limit=5, qualified=True) }}</a></code>
</p>

<strong>{{ _('Query example (results containing \'jones\')') }}</strong>
<p>
<code><a href="{{ datastore_root_url }}/datastore_search?resource_id={{resource_id}}&q=jones"
target="_blank">{{ datastore_root_url }}/datastore_search?resource_id={{resource_id}}&q=jones</a></code>
<code><a href="{{ h.url_for(controller='api', action='action', ver=3, logic_function='datastore_search', resource_id=resource_id, q='jones', qualified=True) }}" target="_blank">{{ h.url_for(controller='api', action='action', ver=3, logic_function='datastore_search', resource_id=resource_id, q='jones', qualified=True) }}</a></code>
</p>

<strong>{{ _('Query example (via SQL statement)') }}</strong>
Expand All @@ -102,7 +101,7 @@ <h3>
q: 'jones' // query for 'jones'
};
$.ajax({
url: '{{ datastore_root_url }}/datastore_search',
url: '{{ h.url_for(controller='api', action='action', ver=3, logic_function='datastore_search', qualified=True) }}',
data: data,
dataType: 'jsonp',
success: function(data) {
Expand All @@ -121,7 +120,7 @@ <h3>
<div class="accordion-inner">
<pre>
import urllib
url = '{{ datastore_root_url }}/datastore_search?resource_id={{resource_id}}&amp;limit=5&amp;q=title:jones'
url = '{{ h.url_for(qualified=True, controller='api', action='action', ver=3, logic_function='datastore_search', resource_id=resource_id, limit=5) + '&q=title:jones' }}' {# not urlencoding the ":" because its clearer #}
fileobj = urllib.urlopen(url)
print fileobj.read()
</pre>
Expand Down
2 changes: 1 addition & 1 deletion ckan/templates/group/read.html
Expand Up @@ -38,6 +38,6 @@
{{ h.snippet('snippets/facet_list.html', title=c.facet_titles[facet], name=facet, extras={'id':c.group_dict.id}) }}
{% endfor %}
</div>
<a class="close no-text hide-filters"><i class="fa fa-times-circle"></i><span class="text">close</span></a>
<a class="close no-text hide-filters"><i class="icon-remove-sign"></i><span class="text">close</span></a>
</div>
{% endblock %}
2 changes: 1 addition & 1 deletion ckan/templates/organization/read.html
Expand Up @@ -41,6 +41,6 @@
{{ h.snippet('snippets/facet_list.html', title=c.facet_titles[facet], name=facet, extras={'id':c.group_dict.id}) }}
{% endfor %}
</div>
<a class="close no-text hide-filters"><i class="fa fa-times-circle"></i><span class="text">close</span></a>
<a class="close no-text hide-filters"><i class="icon-remove-sign"></i><span class="text">close</span></a>
</div>
{% endblock %}
2 changes: 1 addition & 1 deletion ckan/templates/package/resource_read.html
Expand Up @@ -46,7 +46,7 @@
</li>
{% endif %}
{% if 'datastore' in g.plugins %}
<li>{% snippet 'package/snippets/data_api_button.html', resource=res, datastore_root_url=c.datastore_api %}</li>
<li>{% snippet 'package/snippets/data_api_button.html', resource=res %}</li>
{% endif %}
{% endblock %}
</ul>
Expand Down
3 changes: 1 addition & 2 deletions ckan/templates/package/snippets/data_api_button.html
@@ -1,11 +1,10 @@
{# Data API Help Button

resource: the resource
datastore_root_url: the root url of the datastore

#}
{% if resource.datastore_active %}
{% set loading_text = _('Loading...') %}
{% set api_info_url = h.url_for(controller='api', action='snippet', ver=1, snippet_path='api_info.html', datastore_root_url=datastore_root_url, resource_id=resource.id) %}
{% set api_info_url = h.url_for(controller='api', action='snippet', ver=1, snippet_path='api_info.html', resource_id=resource.id) %}
<a class="btn btn-success" href="{{ api_info_url }}" data-module="api-info" data-module-template="{{ api_info_url }}" data-loading-text="{{ loading_text }}"><i class="icon-beaker icon-large"></i> {{ _('Data API') }}</a>
{% endif %}
13 changes: 13 additions & 0 deletions ckan/tests/test_none_root.py
@@ -0,0 +1,13 @@
import ckan.plugins as p
import ckan.tests.helpers as helpers


class TestNoneRootCKAN():
@helpers.change_config(u'ckan.root_path', u'/data/{{LANG}}')
def test_resource_url(self):
app = helpers._get_test_app()
p.load(u'example_theme_v15_fanstatic')
content = app.get(u'/en/base.html')
assert u'example_theme.min.css' in content
assert u'href="/data/fanstatic/example_theme' in content
p.unload(u'example_theme_v15_fanstatic')

0 comments on commit 5a033dc

Please sign in to comment.