Skip to content

Commit

Permalink
Merge branch 'master' into 2041-munge-filename
Browse files Browse the repository at this point in the history
  • Loading branch information
brew committed Nov 19, 2014
2 parents 87fd74c + 0ddd6fd commit eddd090
Show file tree
Hide file tree
Showing 124 changed files with 298 additions and 7,801 deletions.
4 changes: 4 additions & 0 deletions ckan/config/environment.py
Expand Up @@ -290,6 +290,10 @@ def update_config():
if asbool(config.get('ckan.legacy_templates', 'no')):
# We want the new template path for extra snippets like the
# dataviewer and also for some testing stuff
msg = 'Support for Genshi templates is deprecated and will be removed'\
' in a future release'
log.warn(msg)

template_paths = [legacy_templates_path, jinja2_templates_path]
else:
template_paths = [jinja2_templates_path, legacy_templates_path]
Expand Down
3 changes: 2 additions & 1 deletion ckan/config/who.ini
Expand Up @@ -49,7 +49,8 @@ plugins =
auth_tkt

[authenticators]
plugins =
plugins =
auth_tkt
ckan.lib.authenticator:OpenIDAuthenticator
ckan.lib.authenticator:UsernamePasswordAuthenticator

Expand Down
22 changes: 16 additions & 6 deletions ckan/lib/cli.py
Expand Up @@ -106,7 +106,7 @@ class CkanCommand(paste.script.command.Command):
'''
parser = paste.script.command.Command.standard_parser(verbose=True)
parser.add_option('-c', '--config', dest='config',
default='development.ini', help='Config file to use.')
help='Config file to use.')
parser.add_option('-f', '--file',
action='store',
dest='file_path',
Expand All @@ -116,12 +116,22 @@ class CkanCommand(paste.script.command.Command):

def _get_config(self):
from paste.deploy import appconfig
if not self.options.config:
msg = 'No config file supplied'
raise self.BadCommand(msg)
self.filename = os.path.abspath(self.options.config)

if self.options.config:
self.filename = os.path.abspath(self.options.config)
config_source = '-c parameter'
elif os.environ.get('CKAN_INI'):
self.filename = os.environ.get('CKAN_INI')
config_source = '$CKAN_INI'
else:
self.filename = 'development.ini'
config_source = 'default value'

if not os.path.exists(self.filename):
raise AssertionError('Config filename %r does not exist.' % self.filename)
msg = 'Config file not found: %s' % self.filename
msg += '\n(Given by: %s)' % config_source
raise self.BadCommand(msg)

fileConfig(self.filename)
return appconfig('config:' + self.filename)

Expand Down
1 change: 0 additions & 1 deletion ckan/logic/action/create.py
Expand Up @@ -262,7 +262,6 @@ def resource_create(context, data_dict):
user = context['user']

package_id = _get_or_bust(data_dict, 'package_id')
data_dict.pop('package_id')
_get_or_bust(data_dict, 'url')

pkg_dict = _get_action('package_show')(context, {'id': package_id})
Expand Down
2 changes: 1 addition & 1 deletion ckan/logic/action/get.py
Expand Up @@ -1027,7 +1027,7 @@ def resource_show(context, data_dict):
if resource_dict['id'] == id:
break
else:
logging.error('Could not find resource ' + id)
log.error('Could not find resource ' + id)
raise NotFound(_('Resource was not found.'))

resource_dict['package_id'] = pkg_dict['id']
Expand Down
37 changes: 30 additions & 7 deletions ckan/logic/auth/create.py
Expand Up @@ -63,17 +63,40 @@ def related_create(context, data_dict=None):


def resource_create(context, data_dict):
# resource_create runs through package_update, no need to
# check users eligibility to add resource to package here.
model = context['model']
user = context.get('user')

package_id = data_dict.get('package_id')
if not package_id and data_dict.get('id'):
# This can happen when auth is deferred, eg from `resource_view_create`
resource = logic_auth.get_resource_object(context, data_dict)
package_id = resource.package_id

if not package_id:
raise logic.NotFound(
_('No dataset id provided, cannot check auth.')
)

# check authentication against package
pkg = model.Package.get(package_id)
if not pkg:
raise logic.NotFound(
_('No package found for this resource, cannot check auth.')
)

pkg_dict = {'id': pkg.id}
authorized = new_authz.is_authorized('package_update', context, pkg_dict).get('success')

# FIXME This is identical behaviour to what existed but feels like we
# should be using package_update permissions and have better errors. I
# am also not sure about the need for the group issue
return new_authz.is_authorized('package_create', context, data_dict)
if not authorized:
return {'success': False,
'msg': _('User %s not authorized to create resources on dataset %s') %
(str(user), package_id)}
else:
return {'success': True}


def resource_view_create(context, data_dict):
return resource_create(context, data_dict)
return resource_create(context, {'id': data_dict['resource_id']})


def package_relationship_create(context, data_dict):
Expand Down
85 changes: 84 additions & 1 deletion ckan/new_tests/lib/test_base.py
@@ -1,6 +1,89 @@
from nose import tools as nose_tools

from ckan.new_tests import helpers
import ckan.new_tests.factories as factories
import ckan.new_tests.helpers as helpers


class TestLoginView(helpers.FunctionalTestBase):

def _maybe_follow(self, response, **kw):
"""
Follow all redirects. If this response is not a redirect, do nothing.
Returns another response object.
(backported from WebTest 2.0.1)
"""
remaining_redirects = 100 # infinite loops protection

while 300 <= response.status_int < 400 and remaining_redirects:
response = response.follow(**kw)
remaining_redirects -= 1

assert remaining_redirects > 0, "redirects chain looks infinite"
return response

def test_registered_user_login(self):
'''
Registered user can submit valid login details at /user/login and
be returned to appropriate place.
'''
app = helpers._get_test_app()

# make a user
user = factories.User()

# get the form
response = app.get('/user/login')
# ...it's the second one
login_form = response.forms[1]

# fill it in
login_form['login'] = user['name']
login_form['password'] = 'pass'

# submit it
submit_response = login_form.submit()
# let's go to the last redirect in the chain
final_response = self._maybe_follow(submit_response)

# the response is the user dashboard, right?
final_response.mustcontain('<a href="/dashboard">Dashboard</a>',
'<span class="username">{0}</span>'
.format(user['fullname']))
# and we're definitely not back on the login page.
final_response.mustcontain(no='<h1 class="page-heading">Login</h1>')

def test_registered_user_login_bad_password(self):
'''
Registered user is redirected to appropriate place if they submit
invalid login details at /user/login.
'''
app = helpers._get_test_app()

# make a user
user = factories.User()

# get the form
response = app.get('/user/login')
# ...it's the second one
login_form = response.forms[1]

# fill it in
login_form['login'] = user['name']
login_form['password'] = 'badpass'

# submit it
submit_response = login_form.submit()
# let's go to the last redirect in the chain
final_response = self._maybe_follow(submit_response)

# the response is the login page again
final_response.mustcontain('<h1 class="page-heading">Login</h1>',
'Login failed. Bad username or password.')
# and we're definitely not on the dashboard.
final_response.mustcontain(no='<a href="/dashboard">Dashboard</a>'),
final_response.mustcontain(no='<span class="username">{0}</span>'
.format(user['fullname']))


class TestCORS(helpers.FunctionalTestBase):
Expand Down
26 changes: 26 additions & 0 deletions ckan/new_tests/logic/action/test_create.py
Expand Up @@ -172,6 +172,32 @@ def setup_class(cls):
def setup(self):
model.repo.rebuild_db()

def test_resource_create(self):
context = {}
params = {
'package_id': factories.Dataset()['id'],
'url': 'http://data',
'name': 'A nice resource',
}
result = helpers.call_action('resource_create', context, **params)

id = result.pop('id')

assert id

params.pop('package_id')
for key in params.keys():
assert_equals(params[key], result[key])

def test_it_requires_package_id(self):

data_dict = {
'url': 'http://data',
}

assert_raises(logic.ValidationError, helpers.call_action,
'resource_create', **data_dict)

def test_it_requires_url(self):
user = factories.User()
dataset = factories.Dataset(user=user)
Expand Down
15 changes: 13 additions & 2 deletions ckan/new_tests/logic/action/test_get.py
Expand Up @@ -340,18 +340,21 @@ def test_organization_show_private_packages_not_returned(self):
assert org_dict['packages'][0]['name'] == 'dataset_1'
assert org_dict['package_count'] == 1

def test_user_get(self):
def test_user_show_default_values(self):

user = factories.User()

## auth_ignored
got_user = helpers.call_action('user_show', id=user['id'])

assert 'password' not in got_user
assert 'reset_key' not in got_user
assert 'apikey' not in got_user
assert 'email' not in got_user

def test_user_show_keep_email(self):

user = factories.User()

got_user = helpers.call_action('user_show',
context={'keep_email': True},
id=user['id'])
Expand All @@ -361,6 +364,10 @@ def test_user_get(self):
assert 'password' not in got_user
assert 'reset_key' not in got_user

def test_user_show_keep_apikey(self):

user = factories.User()

got_user = helpers.call_action('user_show',
context={'keep_apikey': True},
id=user['id'])
Expand All @@ -370,6 +377,10 @@ def test_user_get(self):
assert 'password' not in got_user
assert 'reset_key' not in got_user

def test_user_show_sysadmin_values(self):

user = factories.User()

sysadmin = factories.User(sysadmin=True)

got_user = helpers.call_action('user_show',
Expand Down
100 changes: 100 additions & 0 deletions ckan/new_tests/logic/auth/test_create.py
Expand Up @@ -105,3 +105,103 @@ def test_user_invite_delegates_correctly_to_group_member_create(self, gmc):
gmc.return_value = {'success': True}
result = helpers.call_auth('user_invite', context=context, **data_dict)
assert result is True


class TestCreateResources(object):

@classmethod
def setup_class(cls):

helpers.reset_db()

def test_authorized_if_user_has_permissions_on_dataset(self):

user = factories.User()

dataset = factories.Dataset(user=user)

resource = {'package_id': dataset['id'],
'title': 'Resource',
'url': 'http://test',
'format': 'csv'}

context = {'user': user['name'], 'model': core_model}
response = helpers.call_auth('resource_create',
context=context, **resource)
assert_equals(response, True)

def test_not_authorized_if_user_has_no_permissions_on_dataset(self):

org = factories.Organization()

user = factories.User()

member = {'username': user['name'],
'role': 'admin',
'id': org['id']}
helpers.call_action('organization_member_create', **member)

user_2 = factories.User()

dataset = factories.Dataset(user=user, owner_org=org['id'])

resource = {'package_id': dataset['id'],
'title': 'Resource',
'url': 'http://test',
'format': 'csv'}

context = {'user': user_2['name'], 'model': core_model}
nose.tools.assert_raises(logic.NotAuthorized, helpers.call_auth,
'resource_create', context=context,
**resource)

def test_not_authorized_if_not_logged_in(self):

resource = {'title': 'Resource',
'url': 'http://test',
'format': 'csv'}

context = {'user': None, 'model': core_model}
nose.tools.assert_raises(logic.NotAuthorized, helpers.call_auth,
'resource_create', context=context,
**resource)

def test_sysadmin_is_authorized(self):

sysadmin = factories.Sysadmin()

resource = {'title': 'Resource',
'url': 'http://test',
'format': 'csv'}

context = {'user': sysadmin['name'], 'model': core_model}
response = helpers.call_auth('resource_create',
context=context, **resource)
assert_equals(response, True)

def test_raises_not_found_if_no_package_id_provided(self):

user = factories.User()

resource = {'title': 'Resource',
'url': 'http://test',
'format': 'csv'}

context = {'user': user['name'], 'model': core_model}
nose.tools.assert_raises(logic.NotFound, helpers.call_auth,
'resource_create', context=context,
**resource)

def test_raises_not_found_if_dataset_was_not_found(self):

user = factories.User()

resource = {'package_id': 'does_not_exist',
'title': 'Resource',
'url': 'http://test',
'format': 'csv'}

context = {'user': user['name'], 'model': core_model}
nose.tools.assert_raises(logic.NotFound, helpers.call_auth,
'resource_create', context=context,
**resource)

0 comments on commit eddd090

Please sign in to comment.