Skip to content

Commit

Permalink
Merge branch 'poc-flask-views' into poc-flask-views.session
Browse files Browse the repository at this point in the history
  • Loading branch information
brew committed May 26, 2016
2 parents d4367d4 + 8d2418f commit fd3926e
Show file tree
Hide file tree
Showing 16 changed files with 350 additions and 42 deletions.
13 changes: 6 additions & 7 deletions ckan/controllers/group.py
Expand Up @@ -159,6 +159,7 @@ def index(self):
sort_by = c.sort_by_selected = request.params.get('sort')
try:
self._check_access('site_read', context)
self._check_access('group_list', context)
except NotAuthorized:
abort(403, _('Not authorized to see this page'))

Expand Down Expand Up @@ -380,10 +381,6 @@ def bulk_process(self, id):
group_type = self._ensure_controller_matches_group_type(
id.split('@')[0])

if group_type != 'organization':
# FIXME: better error
raise Exception('Must be an organization')

# check we are org admin

context = {'model': model, 'session': model.Session,
Expand All @@ -401,6 +398,10 @@ def bulk_process(self, id):
except (NotFound, NotAuthorized):
abort(404, _('Group not found'))

if not c.group_dict['is_organization']:
# FIXME: better error
raise Exception('Must be an organization')

#use different form names so that ie7 can be detected
form_names = set(["bulk_action.public", "bulk_action.delete",
"bulk_action.private"])
Expand Down Expand Up @@ -443,9 +444,7 @@ def bulk_process(self, id):
get_action(action_functions[action])(context, data_dict)
except NotAuthorized:
abort(403, _('Not authorized to perform bulk update'))
base.redirect(h.url_for(controller='organization',
action='bulk_process',
id=id))
self._redirect_to_this_controller(action='bulk_process', id=id)

def new(self, data=None, errors=None, error_summary=None):
if data and 'type' in data:
Expand Down
25 changes: 21 additions & 4 deletions ckan/controllers/user.py
Expand Up @@ -35,6 +35,15 @@
unflatten = dictization_functions.unflatten


def set_repoze_user(user_id):
'''Set the repoze.who cookie to match a given user_id'''
if 'repoze.who.plugins' in request.environ:
rememberer = request.environ['repoze.who.plugins']['friendlyform']
identity = {'repoze.who.userid': user_id}
response.headerlist += rememberer.remember(request.environ,
identity)


class UserController(base.BaseController):
def __before__(self, action, **env):
base.BaseController.__before__(self, action, **env)
Expand Down Expand Up @@ -245,10 +254,7 @@ def _save_new(self, context):
return self.new(data_dict, errors, error_summary)
if not c.user:
# log the user in programatically
rememberer = request.environ['repoze.who.plugins']['friendlyform']
identity = {'repoze.who.userid': data_dict['name']}
response.headerlist += rememberer.remember(request.environ,
identity)
set_repoze_user(data_dict['name'])
h.redirect_to(controller='user', action='me', __ckan_no_root=True)
else:
# #1799 User has managed to register whilst logged in - warn user
Expand Down Expand Up @@ -321,6 +327,12 @@ def edit(self, id=None, data=None, errors=None, error_summary=None):

def _save_edit(self, id, context):
try:
if id in (c.userobj.id, c.userobj.name):
current_user = True
else:
current_user = False
old_username = c.userobj.name

data_dict = logic.clean_dict(unflatten(
logic.tuplize_dict(logic.parse_params(request.params))))
context['message'] = data_dict.get('log_message', '')
Expand All @@ -343,6 +355,11 @@ def _save_edit(self, id, context):

user = get_action('user_update')(context, data_dict)
h.flash_success(_('Profile updated'))

if current_user and data_dict['name'] != old_username:
# Changing currently logged in user's name.
# Update repoze.who cookie to match
set_repoze_user(data_dict['name'])
h.redirect_to(controller='user', action='read', id=user['name'])
except NotAuthorized:
abort(403, _('Unauthorized to edit user %s') % id)
Expand Down
23 changes: 17 additions & 6 deletions ckan/lib/plugins.py
Expand Up @@ -178,7 +178,7 @@ def register_group_plugins(map):
'/%s/{action}/{id}' % group_type,
controller=group_controller,
requirements=dict(action='|'.join(
['edit', 'authz', 'history', 'member_new',
['edit', 'authz', 'delete', 'history', 'member_new',
'member_delete', 'followers', 'follow',
'unfollow', 'admins', 'activity'])))
map.connect('%s_edit' % group_type, '/%s/edit/{id}' % group_type,
Expand All @@ -193,6 +193,13 @@ def register_group_plugins(map):
'/%s/activity/{id}/{offset}' % group_type,
controller=group_controller,
action='activity', ckan_icon='time'),
map.connect('%s_about' % group_type, '/%s/about/{id}' % group_type,
controller=group_controller,
action='about', ckan_icon='info-sign')
map.connect('%s_bulk_process' % group_type,
'/%s/bulk_process/{id}' % group_type,
controller=group_controller,
action='bulk_process', ckan_icon='sitemap')

if group_type in _group_plugins:
raise ValueError("An existing IGroupForm is "
Expand All @@ -201,12 +208,16 @@ def register_group_plugins(map):
_group_plugins[group_type] = plugin
_group_controllers[group_type] = group_controller

controller_obj = None
# If using one of the default controllers, tell it that it is allowed
# to handle other group_types.
# Import them here to avoid circular imports.
if group_controller == 'group':
# Tell the default group controller that it is allowed to
# handle other group_types.
# Import it here to avoid circular imports.
from ckan.controllers.group import GroupController
GroupController.add_group_type(group_type)
from ckan.controllers.group import GroupController as controller_obj
elif group_controller == 'organization':
from ckan.controllers.organization import OrganizationController as controller_obj
if controller_obj is not None:
controller_obj.add_group_type(group_type)

# Setup the fallback behaviour if one hasn't been defined.
if _default_group_plugin is None:
Expand Down
5 changes: 5 additions & 0 deletions ckan/pastertemplates/template/bin/travis-build.bash_tmpl
Expand Up @@ -22,6 +22,11 @@ echo "Creating the PostgreSQL user and database..."
sudo -u postgres psql -c "CREATE USER ckan_default WITH PASSWORD 'pass';"
sudo -u postgres psql -c 'CREATE DATABASE ckan_test WITH OWNER ckan_default;'

echo "SOLR config..."
# Solr is multicore for tests on ckan master, but it's easier to run tests on
# Travis single-core. See https://github.com/ckan/ckan/issues/2972
sed -i -e 's/solr_url.*/solr_url = http:\/\/127.0.0.1:8983\/solr/' ckan/test-core.ini

echo "Initialising the database..."
cd ckan
paster db init -c test-core.ini
Expand Down
2 changes: 1 addition & 1 deletion ckan/templates/group/index.html
Expand Up @@ -34,7 +34,7 @@ <h1 class="hide-heading">{{ _('Groups') }}</h1>
{% endif %}
{% endblock %}
{% block page_pagination %}
{{ c.page.pager() }}
{{ c.page.pager(q=c.q or '', sort=c.sort_by_selected or '') }}
{% endblock %}
{% endblock %}

Expand Down
31 changes: 24 additions & 7 deletions ckan/tests/controllers/test_group.py
Expand Up @@ -23,17 +23,34 @@ def test_bulk_process_throws_404_for_nonexistent_org(self):
action='bulk_process', id='does-not-exist')
app.get(url=bulk_process_url, status=404)

def test_page_thru_list_of_orgs(self):
orgs = [factories.Organization() for i in range(35)]
def test_page_thru_list_of_orgs_preserves_sort_order(self):
orgs = [factories.Organization() for _ in range(35)]
app = self._get_test_app()
org_url = url_for(controller='organization', action='index')
org_url = url_for(controller='organization',
action='index',
sort='name desc')
response = app.get(url=org_url)
assert orgs[0]['name'] in response
assert orgs[-1]['name'] not in response
assert orgs[-1]['name'] in response
assert orgs[0]['name'] not in response

response2 = response.click('2')
assert orgs[0]['name'] not in response2
assert orgs[-1]['name'] in response2
assert orgs[-1]['name'] not in response2
assert orgs[0]['name'] in response2

def test_page_thru_list_of_groups_preserves_sort_order(self):
groups = [factories.Group() for _ in range(35)]
app = self._get_test_app()
group_url = url_for(controller='group',
action='index',
sort='title desc')

response = app.get(url=group_url)
assert groups[-1]['title'] in response
assert groups[0]['title'] not in response

response2 = response.click(r'^2$')
assert groups[-1]['title'] not in response2
assert groups[0]['title'] in response2


def _get_group_new_page(app):
Expand Down
17 changes: 17 additions & 0 deletions ckan/tests/controllers/test_organization.py
@@ -1,6 +1,7 @@
from bs4 import BeautifulSoup
from nose.tools import assert_equal, assert_true
from routes import url_for
from mock import patch

from ckan.tests import factories, helpers
from ckan.tests.helpers import webtest_submit, submit_and_follow, assert_in
Expand Down Expand Up @@ -61,6 +62,22 @@ def test_all_fields_saved(self):
assert_equal(group['description'], 'Sciencey datasets')


class TestOrganizationList(helpers.FunctionalTestBase):
def setup(self):
super(TestOrganizationList, self).setup()
self.app = helpers._get_test_app()
self.user = factories.User()
self.user_env = {'REMOTE_USER': self.user['name'].encode('ascii')}
self.organization_list_url = url_for(controller='organization',
action='index')

@patch('ckan.logic.auth.get.organization_list', return_value={'success': False})
def test_error_message_shown_when_no_organization_list_permission(self, mock_check_access):
response = self.app.get(url=self.organization_list_url,
extra_environ=self.user_env,
status=403)


class TestOrganizationRead(helpers.FunctionalTestBase):
def setup(self):
super(TestOrganizationRead, self).setup()
Expand Down
94 changes: 94 additions & 0 deletions ckan/tests/controllers/test_user.py
Expand Up @@ -289,6 +289,100 @@ def test_email_change_with_password(self):
response = submit_and_follow(app, form, env, 'save')
assert_true('Profile updated' in response)

def test_edit_user_logged_in_username_change(self):

user_pass = 'pass'
user = factories.User(password=user_pass)
app = self._get_test_app()

# Have to do an actual login as this test relys on repoze cookie handling.
# 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'] = user_pass
# submit it
login_form.submit()

# Now the cookie is set, run the test
response = app.get(
url=url_for(controller='user', action='edit'),
)
# existing values in the form
form = response.forms['user-edit-form']

# new values
form['name'] = 'new-name'
response = submit_and_follow(app, form, name='save')
response = helpers.webtest_maybe_follow(response)

expected_url = url_for(controller='user', action='read', id='new-name')
assert response.request.path == expected_url

def test_edit_user_logged_in_username_change_by_name(self):
user_pass = 'pass'
user = factories.User(password=user_pass)
app = self._get_test_app()

# Have to do an actual login as this test relys on repoze cookie handling.
# 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'] = user_pass
# submit it
login_form.submit()

# Now the cookie is set, run the test
response = app.get(
url=url_for(controller='user', action='edit', id=user['name']),
)
# existing values in the form
form = response.forms['user-edit-form']

# new values
form['name'] = 'new-name'
response = submit_and_follow(app, form, name='save')
response = helpers.webtest_maybe_follow(response)

expected_url = url_for(controller='user', action='read', id='new-name')
assert response.request.path == expected_url

def test_edit_user_logged_in_username_change_by_id(self):
user_pass = 'pass'
user = factories.User(password=user_pass)
app = self._get_test_app()

# Have to do an actual login as this test relys on repoze cookie handling.
# 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'] = user_pass
# submit it
login_form.submit()

# Now the cookie is set, run the test
response = app.get(
url=url_for(controller='user', action='edit', id=user['id']),
)
# existing values in the form
form = response.forms['user-edit-form']

# new values
form['name'] = 'new-name'
response = submit_and_follow(app, form, name='save')
response = helpers.webtest_maybe_follow(response)

expected_url = url_for(controller='user', action='read', id='new-name')
assert response.request.path == expected_url

def test_perform_reset_for_key_change(self):
password = 'password'
params = {'password1': password, 'password2': password}
Expand Down
30 changes: 30 additions & 0 deletions ckan/tests/helpers.py
Expand Up @@ -188,6 +188,8 @@ def _apply_config_changes(cls, cfg):
def setup(self):
'''Reset the database and clear the search indexes.'''
reset_db()
if hasattr(self, '_test_app'):
self._test_app.reset()
search.clear_all()

@classmethod
Expand Down Expand Up @@ -412,3 +414,31 @@ def wrapper(*args, **kwargs):
return return_value
return nose.tools.make_decorator(func)(wrapper)
return decorator


def find_flask_app(test_app):
'''
Helper function to recursively search the wsgi stack in `test_app` until
the flask_app is discovered.
Relies on each layer of the stack having a reference to the app they
wrap in either a .app attribute or .apps list.
'''
if isinstance(test_app, ckan.config.middleware.CKANFlask):
return test_app

try:
app = test_app.apps['flask_app'].app
except (AttributeError, KeyError):
pass
else:
return find_flask_app(app)

try:
app = test_app.app
except AttributeError:
print('No .app attribute. '
'Have all layers of the stack got '
'a reference to the app they wrap?')
else:
return find_flask_app(app)
4 changes: 2 additions & 2 deletions ckan/tests/legacy/functional/test_pagination.py
Expand Up @@ -100,12 +100,12 @@ def teardown_class(self):

def test_group_index(self):
res = self.app.get(url_for(controller='group', action='index'))
assert 'href="/group?page=2"' in res, res
assert 'href="/group?sort=&amp;q=&amp;page=2"' in res, res
grp_numbers = scrape_search_results(res, 'group')
assert_equal(['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20'], grp_numbers)

res = self.app.get(url_for(controller='group', action='index', page=2))
assert 'href="/group?page=1"' in res
assert 'href="/group?sort=&amp;q=&amp;page=1"' in res
grp_numbers = scrape_search_results(res, 'group')
assert_equal(['21'], grp_numbers)

Expand Down

0 comments on commit fd3926e

Please sign in to comment.