diff --git a/ckan/config/environment.py b/ckan/config/environment.py
index 0a1269c64df..73c5ae0b9b5 100644
--- a/ckan/config/environment.py
+++ b/ckan/config/environment.py
@@ -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]
diff --git a/ckan/config/who.ini b/ckan/config/who.ini
index 01fc7c07bc8..293569878dd 100644
--- a/ckan/config/who.ini
+++ b/ckan/config/who.ini
@@ -49,7 +49,8 @@ plugins =
auth_tkt
[authenticators]
-plugins =
+plugins =
+ auth_tkt
ckan.lib.authenticator:OpenIDAuthenticator
ckan.lib.authenticator:UsernamePasswordAuthenticator
diff --git a/ckan/lib/cli.py b/ckan/lib/cli.py
index 83424b71e16..70709acf3dd 100644
--- a/ckan/lib/cli.py
+++ b/ckan/lib/cli.py
@@ -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',
@@ -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)
diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py
index 43b39ac120d..0eadc45e9f0 100644
--- a/ckan/logic/action/create.py
+++ b/ckan/logic/action/create.py
@@ -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})
diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
index d1ea5d081aa..155566c79fd 100644
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -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']
diff --git a/ckan/logic/auth/create.py b/ckan/logic/auth/create.py
index 8df9c964fcf..d7f9f598cb2 100644
--- a/ckan/logic/auth/create.py
+++ b/ckan/logic/auth/create.py
@@ -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):
diff --git a/ckan/new_tests/lib/test_base.py b/ckan/new_tests/lib/test_base.py
index 04656093928..e728c38c513 100644
--- a/ckan/new_tests/lib/test_base.py
+++ b/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('Dashboard',
+ '{0}'
+ .format(user['fullname']))
+ # and we're definitely not back on the login page.
+ final_response.mustcontain(no='
Login
')
+
+ 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('
The Data API builds directly on ElasticSearch, with a resource API
- endpoint being equivalent to a single index 'type' in ElasticSearch.
- This means you can directly re-use ElasticSearch
- client libraries when connecting to the API endpoint.
-
-
-
-
-
-
-
diff --git a/ckan/templates_legacy/group/index.html b/ckan/templates_legacy/group/index.html
deleted file mode 100644
index 8502df970ce..00000000000
--- a/ckan/templates_legacy/group/index.html
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
- Groups of Datasets
- Groups of Datasets
-
-
-
-
What Are Groups?
- Whilst tags are great at collecting datasets together, there are occasions when you want to restrict users from editing a collection. A group can be set-up to specify which users have permission to add or remove datasets from it.
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/ckan/templates_legacy/home/__init__.py b/ckan/templates_legacy/home/__init__.py
deleted file mode 100644
index 3c43ff00baa..00000000000
--- a/ckan/templates_legacy/home/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# empty file needed for pylons to find templates in this directory
\ No newline at end of file
diff --git a/ckan/templates_legacy/home/about.html b/ckan/templates_legacy/home/about.html
deleted file mode 100644
index 05b5bc99fb3..00000000000
--- a/ckan/templates_legacy/home/about.html
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
- About
-
-
-
About ${g.site_title}
-
-
-
-
-
What was the average price of a house in the UK in 1935? When will India's projected population overtake that of China? Where can you see publicly-funded art in Seattle? Data to answer many, many questions like these is out there on the Internet somewhere - but it is not always easy to find.
-
-
${g.site_title} is a community-run catalogue of useful sets of data on the Internet. You can collect links here to data from around the web for yourself and others to use, or search for data that others have collected. Depending on the type of data (and its conditions of use), ${g.site_title} may also be able to store a copy of the data or host it in a database, and provide some basic visualisation tools.
This site is running a powerful piece of open-source data cataloguing software called CKAN, written and maintained by the Open Knowledge Foundation. Each 'dataset' record on CKAN contains a description of the data and other useful information, such as what formats it is available in, who owns it and whether it is freely available, and what subject areas the data is about. Other users can improve or add to this information (CKAN keeps a fully versioned history).
-
-
CKAN powers a number of data catalogues on the Internet. The Data Hub is an openly editable open data catalogue, in the style of Wikipedia. The UK Government uses CKAN to run data.gov.uk, which currently lists 8,000 government datasets. Official public data from most European countries is listed in a CKAN catalogue at publicdata.eu. There is a comprehensive list of catalogues like these around the world at datacatalogs.org, which is itself powered by CKAN.
-
-
-
Open data and the Open Knowledge Foundation
-
-
Most of the data indexed at ${g.site_title} is openly licensed, meaning anyone is free to use or re-use it however they like. Perhaps someone will take that nice dataset of a city's public art that you found, and add it to a tourist map - or even make a neat app for your phone that'll help you find artworks when you visit the city. Open data means more enterprise, collaborative science and transparent government. You can read more about open data in the Open Data Handbook.
-
-
The Open Knowledge Foundation is a non-profit organisation promoting open knowledge: writing and improving CKAN is one of the ways we do that. If you want to get involved with its design or code, join the discussion or development mailing lists, or take a look at the OKFN site to find out about our other projects.
This is an old revision of this dataset, as edited at ${h.render_datetime(c.pkg_revision_timestamp, with_hours=True)}. It may differ significantly from the current revision.
-
This is the current revision of this dataset, as edited at ${h.render_datetime(c.pkg_revision_timestamp, with_hours=True)}.
- You can also access this registry using the
- ${h.link_to(_('API'), h.url_for(controller='api', action='get_api', id=None, ver=3))}
- (see ${h.link_to(_('API Docs'), 'http://docs.ckan.org/en/latest/api/')})
- or download a full ${dumps_format}
- dump.
-
-
-
-
-
-
-
- ${field_list()}
-
-
There was an error while searching.
- Please try again.
-
-
-
-
diff --git a/ckan/tests/functional/test_activity.py b/ckan/tests/functional/test_activity.py
index fa4b80423c0..7458651bdc9 100644
--- a/ckan/tests/functional/test_activity.py
+++ b/ckan/tests/functional/test_activity.py
@@ -49,7 +49,7 @@ def test_user_activity(self):
'allow_partial_update': True,
}
user = user_create(context, user_dict)
- offset = url_for(controller='user', action='read', id=user['id'])
+ offset = url_for(controller='user', action='activity', id=user['id'])
result = self.app.get(offset, status=200)
stripped = self.strip_tags(result)
assert '%s signed up' % user['fullname'] in stripped, stripped
@@ -231,8 +231,8 @@ def test_user_activity(self):
# By now we've created >15 activities, but only the latest 15 should
# appear on the page.
result = self.app.get(offset, status=200)
- assert result.body.count('
') \
- == 15
+ assert result.body.count('') \
+ == 15, result.body.count('')
# The user's dashboard page should load successfully and have the
# latest 15 activities on it.
@@ -241,4 +241,5 @@ def test_user_activity(self):
str(ckan.model.User.get('billybeane').apikey)}
result = self.app.post(offset, extra_environ=extra_environ,
status=200)
- assert result.body.count('
') == 15
+ assert result.body.count('') == 15, \
+ result.body.count('')
diff --git a/ckan/tests/functional/test_admin.py b/ckan/tests/functional/test_admin.py
index 38083df569e..4be776c0bf6 100644
--- a/ckan/tests/functional/test_admin.py
+++ b/ckan/tests/functional/test_admin.py
@@ -149,124 +149,3 @@ def get_roles_by_name(user=None, group=None):
assert get_roles_by_name(user=u'tester') == ['admin'], \
"tester should be an admin now"
-
-
-class TestAdminTrashController(WsgiAppCase):
- def setup(cls):
- CreateTestData.create()
-
- def teardown(self):
- model.repo.rebuild_db()
-
- def test_purge_revision(self):
- as_testsysadmin = {'REMOTE_USER': 'testsysadmin'}
-
- # Put a revision in deleted state
- rev = model.repo.youngest_revision()
- revid = rev.id
- rev.state = model.State.DELETED
- model.Session.commit()
-
- # check it shows up on trash page and
- url = url_for('ckanadmin', action='trash')
- response = self.app.get(url, extra_environ=as_testsysadmin)
- assert revid in response, response
-
- # check it can be successfully purged
- form = response.forms['form-purge-revisions']
- res = form.submit('purge-revisions', status=[302], extra_environ=as_testsysadmin)
- res = res.follow(extra_environ=as_testsysadmin)
- assert not revid in res, res
- rev = model.Session.query(model.Revision).filter_by(id=revid).first()
- assert rev is None, rev
-
- def test_purge_package(self):
- as_testsysadmin = {'REMOTE_USER': 'testsysadmin'}
-
- # Put packages in deleted state
- rev = model.repo.new_revision()
- pkg = model.Package.by_name(u'warandpeace')
- pkg.state = model.State.DELETED
- model.repo.commit_and_remove()
-
- # Check shows up on trash page
- url = url_for('ckanadmin', action='trash')
- response = self.app.get(url, extra_environ=as_testsysadmin)
- assert 'dataset/warandpeace' in response, response
-
- # Check we get correct error message on attempted purge
- form = response.forms['form-purge-packages']
- response = form.submit('purge-packages', status=[302],
- extra_environ=as_testsysadmin)
- response = response.follow(extra_environ=as_testsysadmin)
- assert 'Cannot purge package' in response, response
- assert 'dataset/warandpeace' in response
-
- # now check we really can purge when things are ok
- model.repo.new_revision()
- pkg = model.Package.by_name(u'annakarenina')
- pkg.state = model.State.DELETED
- model.repo.commit_and_remove()
-
- response = self.app.get(url, extra_environ=as_testsysadmin)
- assert 'dataset/warandpeace' in response, response
- assert 'dataset/annakarenina' in response, response
-
- form = response.forms['form-purge-packages']
- res = form.submit('purge-packages', status=[302], extra_environ=as_testsysadmin)
- res = res.follow(extra_environ=as_testsysadmin)
-
- pkgs = model.Session.query(model.Package).all()
- assert len(pkgs) == 0
-
- def test_purge_youngest_revision(self):
- as_testsysadmin = {'REMOTE_USER': 'testsysadmin'}
-
- id = u'warandpeace'
- log_message = 'test_1234'
- edit_url = url_for(controller='package', action='edit', id=id)
-
- # Manually create a revision
- res = self.app.get(edit_url, extra_environ=as_testsysadmin)
- fv = res.forms['dataset-edit']
- fv['title'] = 'RevisedTitle'
- fv['log_message'] = log_message
- res = fv.submit('save', extra_environ=as_testsysadmin)
-
- # Delete that revision
- rev = model.repo.youngest_revision()
- assert rev.message == log_message
- rev.state = model.State.DELETED
- model.Session.commit()
-
- # Run a purge
- url = url_for('ckanadmin', action='trash')
- res = self.app.get(url, extra_environ=as_testsysadmin)
- form = res.forms['form-purge-revisions']
- res = form.submit('purge-revisions', status=[302], extra_environ=as_testsysadmin)
- res = res.follow(extra_environ=as_testsysadmin)
-
- # Verify the edit page can be loaded (ie. does not 404)
- res = self.app.get(edit_url, extra_environ=as_testsysadmin)
-
- def test_undelete(self):
- as_testsysadmin = {'REMOTE_USER': 'testsysadmin'}
-
- rev = model.repo.youngest_revision()
- rev_id = rev.id
- rev.state = model.State.DELETED
- model.Session.commit()
-
- # Click undelete
- url = url_for('ckanadmin', action='trash')
- res = self.app.get(url, extra_environ=as_testsysadmin)
- form = res.forms['undelete-'+rev.id]
- res = form.submit('action', status=[302], extra_environ=as_testsysadmin)
- res = res.follow(extra_environ=as_testsysadmin)
-
- assert 'Revision updated' in res
- assert not 'DELETED' in res
-
- rev = model.repo.youngest_revision()
- assert rev.id == rev_id
- assert rev.state == model.State.ACTIVE
diff --git a/ckan/tests/functional/test_follow.py b/ckan/tests/functional/test_follow.py
deleted file mode 100644
index acb97deb0ac..00000000000
--- a/ckan/tests/functional/test_follow.py
+++ /dev/null
@@ -1,199 +0,0 @@
-from pylons.test import pylonsapp
-import paste.fixture
-import ckan
-from routes import url_for
-from ckan.tests.html_check import HtmlCheckMethods
-import json
-
-class TestFollow(HtmlCheckMethods):
-
- @classmethod
- def setupClass(cls):
- ckan.tests.CreateTestData.create()
- cls.testsysadmin = ckan.model.User.get('testsysadmin')
- cls.annafan = ckan.model.User.get('annafan')
- cls.russianfan = ckan.model.User.get('russianfan')
- cls.tester = ckan.model.User.get('tester')
- cls.joeadmin = ckan.model.User.get('joeadmin')
- cls.warandpeace = ckan.model.Package.get('warandpeace')
- cls.annakarenina = ckan.model.Package.get('annakarenina')
- cls.app = paste.fixture.TestApp(pylonsapp)
-
- # Make three users follow annakarenina.
- params = {'id': 'annakarenina'}
- extra_environ = {'Authorization': str(cls.joeadmin.apikey)}
- response = cls.app.post('/api/action/follow_dataset',
- params=json.dumps(params), extra_environ=extra_environ).json
- assert response['success'] is True
- params = {'id': 'annakarenina'}
- extra_environ = {'Authorization': str(cls.annafan.apikey)}
- response = cls.app.post('/api/action/follow_dataset',
- params=json.dumps(params), extra_environ=extra_environ).json
- assert response['success'] is True
- params = {'id': 'annakarenina'}
- extra_environ = {'Authorization': str(cls.russianfan.apikey)}
- response = cls.app.post('/api/action/follow_dataset',
- params=json.dumps(params), extra_environ=extra_environ).json
- assert response['success'] is True
-
- # Make two users follow annafan.
- params = {'id': 'annafan'}
- extra_environ = {'Authorization': str(cls.russianfan.apikey)}
- response = cls.app.post('/api/action/follow_user',
- params=json.dumps(params), extra_environ=extra_environ).json
- assert response['success'] is True
- params = {'id': 'annafan'}
- extra_environ = {'Authorization': str(cls.tester.apikey)}
- response = cls.app.post('/api/action/follow_user',
- params=json.dumps(params), extra_environ=extra_environ).json
- assert response['success'] is True
-
- @classmethod
- def teardownClass(cls):
- ckan.model.repo.rebuild_db()
-
- def test_dataset_read_not_logged_in(self):
- offset = url_for(controller='package', action='read',
- id='warandpeace')
- result = self.app.get(offset)
- assert 'href="/dataset/followers/warandpeace"' in result
- assert 'Followers (0)' in result
- assert 'id="dataset_follow_button"' not in result
-
- offset = url_for(controller='package', action='read',
- id='annakarenina')
- result = self.app.get(offset)
- assert 'href="/dataset/followers/annakarenina"' in result
- assert 'Followers (3)' in result
- assert 'id="dataset_follow_button"' not in result
-
- def test_dataset_followers_not_logged_in(self):
- '''Not-logged-in users cannot see /dataset/followers/ pages.'''
- offset = url_for(controller='package', action='followers',
- id='warandpeace')
- result = self.app.get(offset)
- assert result.status == 302
- assert '/user/login' in result.header_dict['location']
-
- def test_user_read_not_logged_in(self):
- offset = url_for(controller='user', action='read',
- id='joeadmin')
- result = self.app.get(offset)
- assert 'href="/user/followers/joeadmin"' in result
- assert 'Followers (0)' in result
- assert 'id="user_follow_button"' not in result
-
- offset = url_for(controller='user', action='read',
- id='annafan')
- result = self.app.get(offset)
- assert 'href="/user/followers/annafan"' in result
- assert 'Followers (2)' in result
- assert 'id="user_follow_button"' not in result
-
- def test_user_followers_not_logged_in(self):
- offset = url_for(controller='user', action='followers',
- id='joeadmin')
- result = self.app.get(offset)
- assert result.status == 302
- assert '/user/login' in result.header_dict['location']
-
- def test_own_user_read_logged_in(self):
- offset = url_for(controller='user', action='read',
- id='joeadmin')
- extra_environ = {'Authorization': str(self.joeadmin.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'href="/user/followers/joeadmin"' in result
- assert 'My Followers (0)' in result
- assert 'id="user_follow_button"' not in result
-
- offset = url_for(controller='user', action='read',
- id='annafan')
- extra_environ = {'Authorization': str(self.annafan.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'href="/user/followers/annafan"' in result
- assert 'My Followers (2)' in result
- assert 'id="user_follow_button"' not in result
-
- def test_own_user_followers_logged_in(self):
- offset = url_for(controller='user', action='followers',
- id='joeadmin')
- extra_environ = {'Authorization': str(self.testsysadmin.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'href="/user/followers/joeadmin"' in result
- assert 'Followers (0)' in result
- assert 'id="user_follow_button"' in result
- assert '
' not in result
-
- def test_dataset_read_logged_in(self):
- offset = url_for(controller='package', action='read',
- id='warandpeace')
- extra_environ = {'Authorization': str(self.testsysadmin.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'href="/dataset/followers/warandpeace"' in result
- assert 'Followers (0)' in result
- assert 'id="dataset_follow_button"' in result
-
- offset = url_for(controller='package', action='read',
- id='annakarenina')
- extra_environ = {'Authorization': str(self.tester.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'href="/dataset/followers/annakarenina"' in result
- assert 'Followers (3)' in result
- assert 'id="dataset_follow_button"' in result
-
- def test_dataset_follow_logged_in(self):
- offset = url_for(controller='package', action='followers',
- id='warandpeace')
- extra_environ = {'Authorization': str(self.testsysadmin.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'id="dataset_follow_button"' in result
- assert 'Followers (0)' in result
- assert 'id="dataset_follow_button"' in result
- assert '
' not in result
-
- offset = url_for(controller='package', action='followers',
- id='annakarenina')
- extra_environ = {'Authorization': str(self.testsysadmin.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'href="/dataset/followers/annakarenina"' in result
- assert 'Followers (3)' in result
- assert 'id="dataset_follow_button"' in result
- assert str(result).count('
') == 3
- assert self.joeadmin.display_name in result
- assert self.annafan.display_name in result
- assert self.russianfan.display_name in result
-
- # joeadmin is following annakarenina so he should see an Unfollow
- # button.
- offset = url_for(controller='package', action='followers',
- id='annakarenina')
- extra_environ = {'Authorization': str(self.testsysadmin.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'Unfollow' in result
-
- def test_user_read_logged_in(self):
- offset = url_for(controller='user', action='read',
- id='joeadmin')
- extra_environ = {'Authorization': str(self.tester.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'href="/user/followers/joeadmin"' in result
- assert 'Followers (0)' in result
- assert 'id="user_follow_button"' in result
-
- offset = url_for(controller='user', action='read',
- id='annafan')
- extra_environ = {'Authorization': str(self.tester.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'href="/user/followers/annafan"' in result
- assert 'Followers (2)' in result
- assert 'id="user_follow_button"' in result
-
- def test_user_follow_logged_in(self):
- offset = url_for(controller='user', action='followers',
- id='joeadmin')
- extra_environ = {'Authorization': str(self.testsysadmin.apikey)}
- result = self.app.get(offset, extra_environ=extra_environ)
- assert 'href="/user/followers/joeadmin"' in result
- assert 'Followers (0)' in result
- assert '
' not in result
- assert 'id="user_follow_button"' in result
diff --git a/ckan/tests/functional/test_group.py b/ckan/tests/functional/test_group.py
index cae3ffe74fb..4d091615f6e 100644
--- a/ckan/tests/functional/test_group.py
+++ b/ckan/tests/functional/test_group.py
@@ -57,51 +57,6 @@ def test_atom_feed_page_negative(self):
res = self.app.get(offset, expect_errors=True)
assert '"page" parameter must be a positive integer' in res, res
- def test_children(self):
- if model.engine_is_sqlite():
- from nose import SkipTest
- raise SkipTest("Can't use CTE for sqlite")
-
- group_name = 'deletetest'
- CreateTestData.create_groups([{'name': group_name,
- 'packages': []},
- {'name': "parent_group",
- 'packages': []}],
- admin_user_name='testsysadmin')
-
- parent = model.Group.by_name("parent_group")
- group = model.Group.by_name(group_name)
-
- rev = model.repo.new_revision()
- rev.author = "none"
-
- member = model.Member(group_id=group.id, table_id=parent.id,
- table_name='group', capacity='member')
- model.Session.add(member)
- model.repo.commit_and_remove()
-
- offset = url_for(controller='group', action='edit', id=group_name)
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- main_res = self.main_div(res)
- assert 'Edit: %s' % group.title in main_res, main_res
- assert 'value="active" selected' in main_res, main_res
-
- parent = model.Group.by_name("parent_group")
- assert_equal(len(parent.get_children_groups()), 1)
-
- # delete
- form = res.forms['group-edit']
- form['state'] = 'deleted'
- res = form.submit('save', status=302,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
-
- group = model.Group.by_name(group_name)
- assert_equal(group.state, 'deleted')
-
- parent = model.Group.by_name("parent_group")
- assert_equal(len(parent.get_children_groups()), 0)
-
def test_sorting(self):
model.repo.rebuild_db()
@@ -154,103 +109,11 @@ def test_sorting(self):
assert results[0]['name'] == u'beta', results[0]['name']
assert results[1]['name'] == u'delta', results[1]['name']
- def test_mainmenu(self):
- # the home page does a package search so have to skip this test if
- # search is not supported
- if not is_search_supported():
- from nose import SkipTest
- raise SkipTest("Search not supported")
-
- offset = url_for(controller='home', action='index')
- res = self.app.get(offset)
- assert 'Groups' in res, res
- assert 'Groups' in res, res
- res = res.click(href='/group', index=0)
- assert "Dave's books" in res, res
-
- def test_index(self):
- offset = url_for(controller='group', action='index')
- res = self.app.get(offset)
- assert re.search('
\s*Groups', res.body)
- groupname = 'david'
- group = model.Group.by_name(unicode(groupname))
- group_title = group.title
- group_packages_count = len(group.packages())
- group_description = group.description
- self.check_named_element(res, 'tr', group_title,
- group_packages_count,
- group_description)
- res = res.click(group_title)
- assert groupname in res
-
def test_read_non_existent(self):
name = u'group_does_not_exist'
offset = url_for(controller='group', action='read', id=name)
res = self.app.get(offset, status=404)
- def test_read_plugin_hook(self):
- plugins.load('test_group_plugin')
- name = u'david'
- offset = url_for(controller='group', action='read', id=name)
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- p = plugins.get_plugin('test_group_plugin')
- assert p.calls['read'] == 1, p.calls
- plugins.unload('test_group_plugin')
-
- def test_read_and_authorized_to_edit(self):
- name = u'david'
- title = u'Dave\'s books'
- pkgname = u'warandpeace'
- offset = url_for(controller='group', action='read', id=name)
- res = self.app.get(offset,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- assert title in res, res
- assert 'edit' in res
- assert name in res
-
- def test_new_page(self):
- offset = url_for(controller='group', action='new')
- res = self.app.get(offset,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- assert 'Add A Group' in res, res
-
-
-class TestGroupWithSearch(FunctionalTestCase):
-
- @classmethod
- def setup_class(self):
- setup_test_search_index()
- model.Session.remove()
- CreateTestData.create()
-
- @classmethod
- def teardown_class(self):
- model.repo.rebuild_db()
-
- def test_read(self):
- # Relies on the search index being available
- name = u'david'
- title = u'Dave\'s books'
- pkgname = u'warandpeace'
- group = model.Group.by_name(name)
- for group_ref in (group.name, group.id):
- offset = url_for(controller='group', action='read', id=group_ref)
- res = self.app.get(offset)
- main_res = self.main_div(res)
- assert title in res, res
- #assert 'edit' not in main_res, main_res
- # Administrator no longer exists for the group due to auth changes
- # assert 'Administrators' in res, res
- # assert 'russianfan' in main_res, main_res
- assert name in res, res
- no_datasets_found = int(re.search('(\d*) datasets found',
- main_res).groups()[0])
- assert_equal(no_datasets_found, 2)
- pkg = model.Package.by_name(pkgname)
- res = res.click(pkg.title)
- assert '%s - Datasets' % pkg.title in res
-
class TestEdit(FunctionalTestCase):
@@ -278,178 +141,11 @@ def test_0_not_authz(self):
res = res.follow()
assert res.request.url.startswith('/user/login')
- def test_2_edit(self):
- group = model.Group.by_name(self.groupname)
- offset = url_for(controller='group', action='edit', id=self.groupname)
- print offset
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- assert 'Edit: %s' % group.title in res, res
-
- form = res.forms['group-edit']
- titlefn = 'title'
- descfn = 'description'
- newtitle = 'xxxxxxx'
- newdesc = '''### Lots of stuff here
-
-Ho ho ho
-'''
-
- form[titlefn] = newtitle
- form[descfn] = newdesc
- pkg = model.Package.by_name(self.packagename)
- form['packages__2__name'] = pkg.name
-
- res = form.submit('save', status=302,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- # should be read page
- # assert 'Groups - %s' % self.groupname in res, res
-
- model.Session.remove()
- group = model.Group.by_name(self.groupname)
- assert group.title == newtitle, group
- assert group.description == newdesc, group
-
- # now look at datasets
- assert len(group.packages()) == 3
-
- def test_4_new_duplicate_package(self):
- prefix = ''
-
- # Create group
- group_name = u'testgrp4'
- CreateTestData.create_groups([{'name': group_name,
- 'packages': [self.packagename]}],
- admin_user_name='testsysadmin')
-
- # Add same package again
- offset = url_for(controller='group', action='edit', id=group_name)
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- fv = res.forms['group-edit']
- fv['packages__1__name'] = self.packagename
- res = fv.submit('save', status=302,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- res = res.follow()
- assert group_name in res, res
- model.Session.remove()
-
- # check package only added to the group once
- group = model.Group.by_name(group_name)
- pkg_names = [pkg.name for pkg in group.packages()]
- assert_equal(pkg_names, [self.packagename])
-
- def test_edit_plugin_hook(self):
- plugins.load('test_group_plugin')
- offset = url_for(controller='group', action='edit', id=self.groupname)
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- form = res.forms['group-edit']
- group = model.Group.by_name(self.groupname)
- form['title'] = "huhuhu"
- res = form.submit('save', status=302,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- p = plugins.get_plugin('test_group_plugin')
- assert p.calls['edit'] == 1, p.calls
- plugins.unload('test_group_plugin')
-
- def test_edit_image_url(self):
- group = model.Group.by_name(self.groupname)
- offset = url_for(controller='group', action='edit', id=self.groupname)
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
-
- form = res.forms['group-edit']
- image_url = u'http://url.to/image_url'
- form['image_url'] = image_url
- res = form.submit('save', status=302,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
-
- model.Session.remove()
- group = model.Group.by_name(self.groupname)
- assert group.image_url == image_url, group
-
- def test_edit_change_name(self):
- group = model.Group.by_name(self.groupname)
- offset = url_for(controller='group', action='edit', id=self.groupname)
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- assert 'Edit: %s' % group.title in res, res
-
- def update_group(res, name, with_pkg=True):
- form = res.forms['group-edit']
- titlefn = 'title'
- descfn = 'description'
- newtitle = 'xxxxxxx'
- newdesc = '''### Lots of stuff here
-
- Ho ho ho
- '''
- form[titlefn] = newtitle
- form[descfn] = newdesc
- form['name'] = name
- if with_pkg:
- pkg = model.Package.by_name(self.packagename)
- form['packages__2__name'] = pkg.name
-
- res = form.submit('save', status=302,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- update_group(res, self.groupname, True)
- update_group(res, 'newname', False)
-
- model.Session.remove()
- group = model.Group.by_name('newname')
-
- # We have the datasets in the DB, but we should also see that many
- # on the group read page.
- assert len(group.packages()) == 3
-
- offset = url_for(controller='group', action='read', id='newname')
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
-
- ds = res.body
- ds = ds[ds.index('datasets') - 10: ds.index('datasets') + 10]
- assert '3 datasets found' in res, ds
-
- # reset the group to how we found it
- offset = url_for(controller='group', action='edit', id='newname')
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
-
- update_group(res, self.groupname, True)
-
def test_edit_non_existent(self):
name = u'group_does_not_exist'
offset = url_for(controller='group', action='edit', id=name)
res = self.app.get(offset, status=404)
- def test_delete(self):
- group_name = 'deletetest'
- CreateTestData.create_groups([{'name': group_name,
- 'packages': [self.packagename]}],
- admin_user_name='testsysadmin')
-
- group = model.Group.by_name(group_name)
- offset = url_for(controller='group', action='edit', id=group_name)
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- main_res = self.main_div(res)
- assert 'Edit: %s' % group.title in main_res, main_res
- assert 'value="active" selected' in main_res, main_res
-
- # delete
- form = res.forms['group-edit']
- form['state'] = 'deleted'
- res = form.submit('save', status=302,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
-
- group = model.Group.by_name(group_name)
- assert_equal(group.state, 'deleted')
- res = self.app.get(offset, status=302)
- res = res.follow()
- assert res.request.url.startswith('/user/login'), res.request.url
-
class TestNew(FunctionalTestCase):
groupname = u'david'
@@ -477,90 +173,6 @@ def test_1_not_authz(self):
res = res.follow()
assert res.request.url.startswith('/user/login')
- def test_2_new(self):
- prefix = ''
- group_name = u'testgroup'
- group_title = u'Test Title'
- group_description = u'A Description'
-
- # Open 'Add A Group' page
- offset = url_for(controller='group', action='new')
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- assert 'Add A Group' in res, res
- fv = res.forms['group-edit']
- assert fv[prefix + 'name'].value == '', fv.fields
- assert fv[prefix + 'title'].value == ''
- assert fv[prefix + 'description'].value == ''
- assert fv['packages__0__name'].value == '', \
- fv['Member--package_name'].value
-
- # Edit form
- fv[prefix + 'name'] = group_name
- fv[prefix + 'title'] = group_title
- fv[prefix + 'description'] = group_description
- pkg = model.Package.by_name(self.packagename)
- fv['packages__0__name'] = pkg.name
- res = fv.submit('save', status=302,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- res = res.follow()
- assert '%s' % group_title in res, res
-
- model.Session.remove()
- group = model.Group.by_name(group_name)
- assert group.title == group_title, group
- assert group.description == group_description, group
- assert len(group.packages()) == 1
- pkg = model.Package.by_name(self.packagename)
- assert group.packages() == [pkg]
-
- def test_3_new_duplicate_group(self):
- prefix = ''
-
- # Create group
- group_name = u'testgrp1'
- offset = url_for(controller='group', action='new')
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- assert 'Add A Group' in res, res
- fv = res.forms['group-edit']
- assert fv[prefix + 'name'].value == '', fv.fields
- fv[prefix + 'name'] = group_name
- res = fv.submit('save', status=302,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- res = res.follow()
- assert group_name in res, res
- model.Session.remove()
-
- # Create duplicate group
- group_name = u'testgrp1'
- offset = url_for(controller='group', action='new')
- res = self.app.get(offset, status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- assert 'Add A Group' in res, res
- fv = res.forms['group-edit']
- assert fv[prefix + 'name'].value == '', fv.fields
- fv[prefix + 'name'] = group_name
- res = fv.submit('save', status=200,
- extra_environ={'REMOTE_USER': 'testsysadmin'})
- assert 'Group name already exists' in res, res
- self.check_tag(res, '