diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b7c5f3a528..c694e789d57 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,24 @@ Changelog v.2.9.0 TBA ================== + * This version requires changes to the ``who.ini`` configuration file. If your + setup doesn't use the one bundled with this repo, you will have to manually + change the following lines:: + + use = ckan.lib.auth_tkt:make_plugin + + to:: + + use = ckan.lib.repoze_plugins.auth_tkt:make_plugin + + And also:: + + use = repoze.who.plugins.friendlyform:FriendlyFormPlugin + + to:: + + use = ckan.lib.repoze_plugins.friendly_form:FriendlyFormPlugin + * When upgrading from previous CKAN versions, the Activity Stream needs a migrate_package_activity.py running for displaying the history of dataset changes. This can be performed while CKAN is running or stopped (whereas the diff --git a/ckan/cli/less.py b/ckan/cli/less.py index 20945716a9e..28667f60dd4 100644 --- a/ckan/cli/less.py +++ b/ckan/cli/less.py @@ -61,7 +61,7 @@ def less(): directory = output[0].strip() if not directory: error_shout(u'Command "{}" returned nothing. Check that npm is ' - u'installed.'.format(' '.join(command))) + u'installed.'.format(u' '.join(command))) less_bin = os.path.join(directory, u'lessc') public = config.get(u'ckan.base_public_folder') diff --git a/ckan/cli/tracking.py b/ckan/cli/tracking.py index 73a1f6de653..f7a6c13000b 100644 --- a/ckan/cli/tracking.py +++ b/ckan/cli/tracking.py @@ -145,7 +145,8 @@ def update_tracking(engine, summary_date): sql = u'''UPDATE tracking_summary t SET package_id = COALESCE( (SELECT id FROM package p - WHERE p.name = regexp_replace(' ' || t.url, '^[ ]{1}(/\w{2}){0,1}' || %s, '')) + WHERE p.name = regexp_replace + (' ' || t.url, '^[ ]{1}(/\\w{2}){0,1}' || %s, '')) ,'~~not~found~~') WHERE t.package_id IS NULL AND tracking_type = 'page';''' @@ -202,8 +203,8 @@ def update_tracking_solr(engine, start_date): total = len(package_ids) not_found = 0 - click.echo('{} package index{} to be rebuilt starting from {}'.format( - total, '' if total < 2 else 'es', start_date) + click.echo(u'{} package index{} to be rebuilt starting from {}'.format( + total, u'' if total < 2 else u'es', start_date) ) from ckan.lib.search import rebuild diff --git a/ckan/config/who.ini b/ckan/config/who.ini index 885a497b5b4..eb2a5a52c80 100644 --- a/ckan/config/who.ini +++ b/ckan/config/who.ini @@ -1,10 +1,10 @@ [plugin:auth_tkt] -use = ckan.lib.auth_tkt:make_plugin +use = ckan.lib.repoze_plugins.auth_tkt:make_plugin # If no secret key is defined here, beaker.session.secret will be used #secret = somesecret [plugin:friendlyform] -use = repoze.who.plugins.friendlyform:FriendlyFormPlugin +use = ckan.lib.repoze_plugins.friendly_form:FriendlyFormPlugin login_form_url= /user/login login_handler_path = /login_generic logout_handler_path = /user/logout @@ -13,10 +13,6 @@ post_login_url = /user/logged_in post_logout_url = /user/logged_out charset = utf-8 -#[plugin:basicauth] -#use = repoze.who.plugins.basicauth:make_plugin -#realm = 'CKAN' - [general] request_classifier = repoze.who.classifiers:default_request_classifier challenge_decider = repoze.who.classifiers:default_challenge_decider @@ -34,4 +30,3 @@ plugins = [challengers] plugins = friendlyform;browser -# basicauth diff --git a/ckan/lib/repoze_plugins/__init__.py b/ckan/lib/repoze_plugins/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ckan/lib/auth_tkt.py b/ckan/lib/repoze_plugins/auth_tkt.py similarity index 79% rename from ckan/lib/auth_tkt.py rename to ckan/lib/repoze_plugins/auth_tkt.py index 36faea5643f..75af0258111 100644 --- a/ckan/lib/auth_tkt.py +++ b/ckan/lib/repoze_plugins/auth_tkt.py @@ -19,7 +19,7 @@ def __init__(self, httponly, *args, **kwargs): self.httponly = httponly def _get_cookies(self, *args, **kwargs): - ''' + u''' Override method in superclass to ensure HttpOnly is set appropriately. ''' super_cookies = super(CkanAuthTktCookiePlugin, self). \ @@ -46,29 +46,29 @@ def make_plugin(secret=None, # ckan specifics: # Get secret from beaker setting if necessary - if secret is None or secret == 'somesecret': - secret = config['beaker.session.secret'] + if secret is None or secret == u'somesecret': + secret = config[u'beaker.session.secret'] # Session timeout and reissue time for auth cookie - if timeout is None and config.get('who.timeout'): - timeout = config.get('who.timeout') - if reissue_time is None and config.get('who.reissue_time'): - reissue_time = config.get('who.reissue_time') + if timeout is None and config.get(u'who.timeout'): + timeout = config.get(u'who.timeout') + if reissue_time is None and config.get(u'who.reissue_time'): + reissue_time = config.get(u'who.reissue_time') if timeout is not None and reissue_time is None: reissue_time = int(math.ceil(int(timeout) * 0.1)) # Set httponly based on config value. Default is True - httponly = config.get('who.httponly', True) + httponly = config.get(u'who.httponly', True) # Set secure based on config value. Default is False - secure = config.get('who.secure', False) + secure = config.get(u'who.secure', False) # back to repoze boilerplate if (secret is None and secretfile is None): - raise ValueError("One of 'secret' or 'secretfile' must not be None.") + raise ValueError(u"One of 'secret' or 'secretfile' must not be None.") if (secret is not None and secretfile is not None): - raise ValueError("Specify only one of 'secret' or 'secretfile'.") + raise ValueError(u"Specify only one of 'secret' or 'secretfile'.") if secretfile: secretfile = os.path.abspath(os.path.expanduser(secretfile)) if not os.path.exists(secretfile): - raise ValueError("No such 'secretfile': %s" % secretfile) + raise ValueError(u"No such 'secretfile': %s" % secretfile) secret = open(secretfile).read().strip() if timeout: timeout = int(timeout) diff --git a/ckan/lib/repoze_plugins/friendly_form.py b/ckan/lib/repoze_plugins/friendly_form.py new file mode 100644 index 00000000000..95f89680e4d --- /dev/null +++ b/ckan/lib/repoze_plugins/friendly_form.py @@ -0,0 +1,318 @@ +# -*- coding: utf-8 -*- + +# +# This is a modified version of repoze.who-friendlyform, written by +# Gustavo Narea +# +# Modifications include: +# * Python 3 support +# * Replace usage of paster methods with webob ones +# + +############################################################################## +# +# Copyright (c) 2009-2010, Gustavo Narea and +# contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the BSD-like license at +# http://www.repoze.org/LICENSE.txt. A copy of the license should accompany +# this distribution. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL +# EXPRESS OR IMPLIED WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND +# FITNESS FOR A PARTICULAR PURPOSE. +# +############################################################################## + +u'''Collection of :mod:`repoze.who` friendly forms''' + +from six.moves.urllib.parse import urlparse, urlunparse, urlencode, parse_qs + +from webob import Request, UnicodeMultiDict +from webob.exc import HTTPFound, HTTPUnauthorized +from zope.interface import implements + +from repoze.who.interfaces import IChallenger, IIdentifier + +__all__ = [u'FriendlyFormPlugin'] + + +def construct_url(environ): + return Request(environ).url + + +class FriendlyFormPlugin(object): + u''' + :class:`RedirectingFormPlugin + `-like form plugin with + more features. + + It is like ``RedirectingFormPlugin``, but provides us with the following + features: + + * Users are not challenged on logout, unless the referrer URL is a + private one (but that's up to the application). + * Developers may define post-login and/or post-logout pages. + * In the login URL, the amount of failed logins is available in the + environ. It's also increased by one on every login try. This counter + will allow developers not using a post-login page to handle logins that + fail/succeed. + + You should keep in mind that if you're using a post-login or a post-logout + page, that page will receive the referrer URL as a query string variable + whose name is 'came_from'. + + Forms can be submitted with any encoding (non-ASCII credentials are + supported) and ISO-8859-1 (aka 'Latin-1') is the default one. + + ''' + implements(IChallenger, IIdentifier) + + classifications = { + IIdentifier: [u'browser'], + IChallenger: [u'browser'], + } + + def __init__(self, login_form_url, login_handler_path, post_login_url, + logout_handler_path, post_logout_url, rememberer_name, + login_counter_name=None, charset=u'iso-8859-1'): + u''' + + :param login_form_url: The URL/path where the login form is located. + :type login_form_url: str + :param login_handler_path: The URL/path where the login form is + submitted to (where it is processed by this plugin). + :type login_handler_path: str + :param post_login_url: The URL/path where the user should be redirected + to after login (even if wrong credentials were provided). + :type post_login_url: str + :param logout_handler_path: The URL/path where the user is logged out. + :type logout_handler_path: str + :param post_logout_url: The URL/path where the user should be + redirected to after logout. + :type post_logout_url: str + :param rememberer_name: The name of the repoze.who identifier which + acts as rememberer. + :type rememberer_name: str + :param login_counter_name: The name of the query string variable which + will represent the login counter. + :type login_counter_name: str + :param charset: The character encoding to be assumed when the user + agent does not submit the form with an explicit charset. + :type charset: :class:`str` + + The login counter variable's name will be set to ``__logins`` if + ``login_counter_name`` equals None. + + .. versionchanged:: 1.0.1 + Added the ``charset`` argument. + + ''' + self.login_form_url = login_form_url + self.login_handler_path = login_handler_path + self.post_login_url = post_login_url + self.logout_handler_path = logout_handler_path + self.post_logout_url = post_logout_url + self.rememberer_name = rememberer_name + self.login_counter_name = login_counter_name + if not login_counter_name: + self.login_counter_name = u'__logins' + self.charset = charset + + # IIdentifier + def identify(self, environ): + u''' + Override the parent's identifier to introduce a login counter + (possibly along with a post-login page) and load the login counter into + the ``environ``. + + ''' + request = Request(environ, charset=self.charset) + + path_info = environ[u'PATH_INFO'] + script_name = environ.get(u'SCRIPT_NAME') or u'/' + query = request.GET + + if path_info == self.login_handler_path: + # We are on the URL where repoze.who processes authentication. # + # Let's append the login counter to the query string of the + # 'came_from' URL. It will be used by the challenge below if + # authorization is denied for this request. + form = dict(request.POST) + form.update(query) + try: + login = form[u'login'] + password = form[u'password'] + except KeyError: + credentials = None + else: + if request.charset == u'us-ascii': + credentials = { + u'login': str(login), + u'password': str(password), + } + else: + credentials = {u'login': login, u'password': password} + + try: + credentials[u'max_age'] = form[u'remember'] + except KeyError: + pass + + referer = environ.get(u'HTTP_REFERER', script_name) + destination = form.get(u'came_from', referer) + + if self.post_login_url: + # There's a post-login page, so we have to replace the + # destination with it. + destination = self._get_full_path(self.post_login_url, + environ) + if u'came_from' in query: + # There's a referrer URL defined, so we have to pass it to + # the post-login page as a GET variable. + destination = self._insert_qs_variable(destination, + u'came_from', + query[u'came_from']) + failed_logins = self._get_logins(environ, True) + new_dest = self._set_logins_in_url(destination, failed_logins) + environ[u'repoze.who.application'] = HTTPFound(location=new_dest) + return credentials + + elif path_info == self.logout_handler_path: + # We are on the URL where repoze.who logs the user out. # + r = Request(environ) + params = dict(list(r.GET.items()) + list(r.POST.items())) + form = UnicodeMultiDict(params) + form.update(query) + referer = environ.get(u'HTTP_REFERER', script_name) + came_from = form.get(u'came_from', referer) + # set in environ for self.challenge() to find later + environ[u'came_from'] = came_from + environ[u'repoze.who.application'] = HTTPUnauthorized() + return None + + elif path_info == self.login_form_url or self._get_logins(environ): + # We are on the URL that displays the from OR any other page # + # where the login counter is included in the query string. # + # So let's load the counter into the environ and then hide it from + # the query string (it will cause problems in frameworks like TG2, + # where this unexpected variable would be passed to the controller) + environ[u'repoze.who.logins'] = self._get_logins(environ, True) + # Hiding the GET variable in the environ: + if self.login_counter_name in query: + del query[self.login_counter_name] + environ[u'QUERY_STRING'] = urlencode(query, doseq=True) + + # IChallenger + def challenge(self, environ, status, app_headers, forget_headers): + u''' + Override the parent's challenge to avoid challenging the user on + logout, introduce a post-logout page and/or pass the login counter + to the login form. + + ''' + url_parts = list(urlparse(self.login_form_url)) + query = url_parts[4] + query_elements = parse_qs(query) + came_from = environ.get(u'came_from', construct_url(environ)) + query_elements[u'came_from'] = came_from + url_parts[4] = urlencode(query_elements, doseq=True) + login_form_url = urlunparse(url_parts) + login_form_url = self._get_full_path(login_form_url, environ) + destination = login_form_url + # Configuring the headers to be set: + cookies = [ + (h, v) for (h, v) in app_headers if h.lower() == u'set-cookie' + ] + headers = forget_headers + cookies + + if environ[u'PATH_INFO'] == self.logout_handler_path: + # Let's log the user out without challenging. + came_from = environ.get(u'came_from') + if self.post_logout_url: + # Redirect to a predefined u'post logout' URL. + destination = self._get_full_path(self.post_logout_url, + environ) + if came_from: + destination = self._insert_qs_variable( + destination, u'came_from', came_from) + else: + # Redirect to the referrer URL. + script_name = environ.get(u'SCRIPT_NAME', u'') + destination = came_from or script_name or u'/' + + elif u'repoze.who.logins' in environ: + # Login failed! Let's redirect to the login form and include + # the login counter in the query string + environ[u'repoze.who.logins'] += 1 + # Re-building the URL: + destination = self._set_logins_in_url( + destination, environ[u'repoze.who.logins']) + + return HTTPFound(location=destination, headers=headers) + + # IIdentifier + def remember(self, environ, identity): + rememberer = self._get_rememberer(environ) + return rememberer.remember(environ, identity) + + # IIdentifier + def forget(self, environ, identity): + rememberer = self._get_rememberer(environ) + return rememberer.forget(environ, identity) + + def _get_rememberer(self, environ): + rememberer = environ[u'repoze.who.plugins'][self.rememberer_name] + return rememberer + + def _get_full_path(self, path, environ): + u''' + Return the full path to ``path`` by prepending the SCRIPT_NAME. + + If ``path`` is a URL, do nothing. + + ''' + if path.startswith(u'/'): + path = environ.get(u'SCRIPT_NAME', u'') + path + return path + + def _get_logins(self, environ, force_typecast=False): + u''' + Return the login counter from the query string in the ``environ``. + + If it's not possible to convert it into an integer and + ``force_typecast`` is ``True``, it will be set to zero (int(0)). + Otherwise, it will be ``None`` or an string. + + ''' + variables = Request(environ).queryvars + failed_logins = variables.get(self.login_counter_name) + if force_typecast: + try: + failed_logins = int(failed_logins) + except (ValueError, TypeError): + failed_logins = 0 + return failed_logins + + def _set_logins_in_url(self, url, logins): + u''' + Insert the login counter variable with the ``logins`` value into + ``url`` and return the new URL. + + ''' + return self._insert_qs_variable(url, self.login_counter_name, logins) + + def _insert_qs_variable(self, url, var_name, var_value): + u''' + Insert the variable ``var_name`` with value ``var_value`` in the query + string of ``url`` and return the new URL. + + ''' + url_parts = list(urlparse(url)) + query_parts = parse_qs(url_parts[4]) + query_parts[var_name] = var_value + url_parts[4] = urlencode(query_parts, doseq=True) + return urlunparse(url_parts) + + def __repr__(self): + return u'<%s %s>' % (self.__class__.__name__, id(self)) diff --git a/ckan/templates/group/edit_base.html b/ckan/templates/group/edit_base.html index 2c2e5ed3e75..1d7d2c59b68 100644 --- a/ckan/templates/group/edit_base.html +++ b/ckan/templates/group/edit_base.html @@ -17,8 +17,8 @@ {% endblock %} {% block content_primary_nav %} - {{ h.build_nav_icon(group_type + '.edit', _('Edit'), id=group_dict.name) }} - {{ h.build_nav_icon(group_type + '.members', _('Members'), id=group_dict.name) }} + {{ h.build_nav_icon(group_type + '.edit', _('Edit'), id=group_dict.name, icon='pencil-square-o') }} + {{ h.build_nav_icon(group_type + '.members', _('Members'), id=group_dict.name, icon='users') }} {% endblock %} {% block secondary_content %} diff --git a/ckan/templates/group/read_base.html b/ckan/templates/group/read_base.html index f98b135175b..948be560086 100644 --- a/ckan/templates/group/read_base.html +++ b/ckan/templates/group/read_base.html @@ -14,9 +14,9 @@ {% endblock %} {% block content_primary_nav %} - {{ h.build_nav_icon(group_type + '.read', _('Datasets'), id=group_dict.name) }} - {{ h.build_nav_icon(group_type + '.activity', _('Activity Stream'), id=group_dict.name, offset=0) }} - {{ h.build_nav_icon(group_type + '.about', _('About'), id=group_dict.name) }} + {{ h.build_nav_icon(group_type + '.read', _('Datasets'), id=group_dict.name, icon='sitemap') }} + {{ h.build_nav_icon(group_type + '.activity', _('Activity Stream'), id=group_dict.name, offset=0, icon='clock-o') }} + {{ h.build_nav_icon(group_type + '.about', _('About'), id=group_dict.name, icon='info-circle') }} {% endblock %} {% block secondary_content %} diff --git a/ckan/templates/organization/edit_base.html b/ckan/templates/organization/edit_base.html index eac8ab38724..0edd0894455 100644 --- a/ckan/templates/organization/edit_base.html +++ b/ckan/templates/organization/edit_base.html @@ -19,9 +19,9 @@ {% endblock %} {% block content_primary_nav %} - {{ h.build_nav_icon(group_type + '.edit', _('Edit'), id=group_dict.name) }} - {{ h.build_nav_icon(group_type + '.bulk_process', _('Datasets'), id=group_dict.name) }} - {{ h.build_nav_icon(group_type + '.members', _('Members'), id=group_dict.name) }} + {{ h.build_nav_icon(group_type + '.edit', _('Edit'), id=group_dict.name, icon='pencil-square-o') }} + {{ h.build_nav_icon(group_type + '.bulk_process', _('Datasets'), id=group_dict.name, icon='sitemap') }} + {{ h.build_nav_icon(group_type + '.members', _('Members'), id=group_dict.name, icon='users') }} {% endblock %} {% block secondary_content %} diff --git a/ckan/templates/organization/read_base.html b/ckan/templates/organization/read_base.html index 8f70ef91fdc..eff8900e09e 100644 --- a/ckan/templates/organization/read_base.html +++ b/ckan/templates/organization/read_base.html @@ -14,9 +14,9 @@ {% endblock %} {% block content_primary_nav %} - {{ h.build_nav_icon(group_type + '.read', _('Datasets'), id=group_dict.name) }} - {{ h.build_nav_icon(group_type + '.activity', _('Activity Stream'), id=group_dict.name, offset=0) }} - {{ h.build_nav_icon(group_type + '.about', _('About'), id=group_dict.name) }} + {{ h.build_nav_icon(group_type + '.read', _('Datasets'), id=group_dict.name, icon='sitemap') }} + {{ h.build_nav_icon(group_type + '.activity', _('Activity Stream'), id=group_dict.name, offset=0, icon='clock-o') }} + {{ h.build_nav_icon(group_type + '.about', _('About'), id=group_dict.name, icon='info-circle') }} {% endblock %} {% block secondary_content %} diff --git a/ckan/templates/package/edit_base.html b/ckan/templates/package/edit_base.html index 4c213c0f8e0..266b430cada 100644 --- a/ckan/templates/package/edit_base.html +++ b/ckan/templates/package/edit_base.html @@ -14,8 +14,8 @@ {% endblock %} {% block content_primary_nav %} - {{ h.build_nav_icon('dataset.edit', _('Edit metadata'), id=pkg.name) }} - {{ h.build_nav_icon('dataset.resources', _('Resources'), id=pkg.name) }} + {{ h.build_nav_icon('dataset.edit', _('Edit metadata'), id=pkg.name, icon='pencil-square-o') }} + {{ h.build_nav_icon('dataset.resources', _('Resources'), id=pkg.name, icon='bars') }} {% endblock %} {% block secondary_content %} diff --git a/ckan/templates/package/read_base.html b/ckan/templates/package/read_base.html index 0f0a458e791..adfab65eb55 100644 --- a/ckan/templates/package/read_base.html +++ b/ckan/templates/package/read_base.html @@ -18,9 +18,9 @@ {% endblock %} {% block content_primary_nav %} - {{ h.build_nav_icon('dataset.read', _('Dataset'), id=pkg.id if is_activity_archive else pkg.name) }} - {{ h.build_nav_icon('dataset.groups', _('Groups'), id=pkg.id if is_activity_archive else pkg.name) }} - {{ h.build_nav_icon('dataset.activity', _('Activity Stream'), id=pkg.id if is_activity_archive else pkg.name) }} + {{ h.build_nav_icon('dataset.read', _('Dataset'), id=pkg.id if is_activity_archive else pkg.name, icon='sitemap') }} + {{ h.build_nav_icon('dataset.groups', _('Groups'), id=pkg.id if is_activity_archive else pkg.name, icon='users') }} + {{ h.build_nav_icon('dataset.activity', _('Activity Stream'), id=pkg.id if is_activity_archive else pkg.name, icon='clock-o') }} {% endblock %} {% block secondary_content %} diff --git a/ckan/templates/package/resource_edit_base.html b/ckan/templates/package/resource_edit_base.html index 7803d1f4ea3..55211ceecd0 100644 --- a/ckan/templates/package/resource_edit_base.html +++ b/ckan/templates/package/resource_edit_base.html @@ -21,9 +21,9 @@ {% endblock %} {% block content_primary_nav %} - {{ h.build_nav_icon('resource.edit', _('Edit resource'), id=pkg.name, resource_id=res.id) }} + {{ h.build_nav_icon('resource.edit', _('Edit resource'), id=pkg.name, resource_id=res.id, icon='pencil-square-o') }} {% block inner_primary_nav %}{% endblock %} - {{ h.build_nav_icon('resource.views', _('Views'), id=pkg.name, resource_id=res.id) }} + {{ h.build_nav_icon('resource.views', _('Views'), id=pkg.name, resource_id=res.id, icon='bars') }} {% endblock %} {% block primary_content_inner %} diff --git a/ckan/templates/user/dashboard.html b/ckan/templates/user/dashboard.html index 2ff76c35f3b..cf3edcbecbc 100644 --- a/ckan/templates/user/dashboard.html +++ b/ckan/templates/user/dashboard.html @@ -16,10 +16,10 @@ {% link_for _('Edit settings'), named_route='user.edit', id=user.name, class_='btn btn-default', icon='cog' %} {% endblock %} diff --git a/ckan/templates/user/read_base.html b/ckan/templates/user/read_base.html index e5e635abd54..e78e1812a70 100644 --- a/ckan/templates/user/read_base.html +++ b/ckan/templates/user/read_base.html @@ -16,8 +16,8 @@ {% endblock %} {% block content_primary_nav %} - {{ h.build_nav_icon('user.read', _('Datasets'), id=user.name) }} - {{ h.build_nav_icon('user.activity', _('Activity Stream'), id=user.name) }} + {{ h.build_nav_icon('user.read', _('Datasets'), id=user.name, icon='sitemap') }} + {{ h.build_nav_icon('user.activity', _('Activity Stream'), id=user.name, icon='clock-o') }} {% endblock %} {% block secondary_content %} diff --git a/ckan/tests/lib/test_auth_tkt.py b/ckan/tests/lib/test_auth_tkt.py index dbddcfbb0dd..d185beb4449 100644 --- a/ckan/tests/lib/test_auth_tkt.py +++ b/ckan/tests/lib/test_auth_tkt.py @@ -3,7 +3,7 @@ from nose import tools as nose_tools from ckan.tests import helpers -from ckan.lib.auth_tkt import make_plugin +from ckan.lib.repoze_plugins.auth_tkt import make_plugin class TestCkanAuthTktCookiePlugin(helpers.FunctionalTestBase): diff --git a/ckan/tests/test_coding_standards.py b/ckan/tests/test_coding_standards.py index 3822619f3e4..944c57ca809 100644 --- a/ckan/tests/test_coding_standards.py +++ b/ckan/tests/test_coding_standards.py @@ -264,7 +264,6 @@ def find_unprefixed_string_literals(filename): u'ckan/lib/activity_streams.py', u'ckan/lib/activity_streams_session_extension.py', u'ckan/lib/app_globals.py', - u'ckan/lib/auth_tkt.py', u'ckan/lib/authenticator.py', u'ckan/lib/base.py', u'ckan/lib/captcha.py', @@ -298,6 +297,7 @@ def find_unprefixed_string_literals(filename): u'ckan/lib/search/index.py', u'ckan/lib/search/query.py', u'ckan/lib/search/sql.py', + u'ckan/lib/repoze_plugins/auth_tkt.py', u'ckan/lib/uploader.py', u'ckan/logic/__init__.py', u'ckan/logic/action/__init__.py',