[ckan-changes] [okfn/ckan] bdc5ca: Revert "Remove authgroups UI and tests (that rely ...
GitHub
noreply at github.com
Tue May 1 17:37:42 UTC 2012
Branch: refs/heads/enhancement-kill-authgroups-ui
Home: https://github.com/okfn/ckan
Commit: bdc5ca3994a6e96cdff877b371b912d84f40993b
https://github.com/okfn/ckan/commit/bdc5ca3994a6e96cdff877b371b912d84f40993b
Author: amercader <amercadero at gmail.com>
Date: 2012-05-01 (Tue, 01 May 2012)
Changed paths:
M ckan/config/routing.py
A ckan/controllers/authorization_group.py
M ckan/forms/authz.py
M ckan/lib/helpers.py
M ckan/templates/_util.html
M ckan/templates/admin/authz.html
A ckan/templates/authorization_group/__init__.py
A ckan/templates/authorization_group/authz.html
A ckan/templates/authorization_group/edit.html
A ckan/templates/authorization_group/edit_form.html
A ckan/templates/authorization_group/index.html
A ckan/templates/authorization_group/layout.html
A ckan/templates/authorization_group/new.html
A ckan/templates/authorization_group/read.html
M ckan/templates/group/authz.html
M ckan/templates/layout_base.html
M ckan/templates/package/authz.html
M ckan/tests/functional/test_admin.py
A ckan/tests/functional/test_authorization_group.py
M ckan/tests/functional/test_edit_authz.py
M ckan/tests/functional/test_package_edit_authz.py
Log Message:
-----------
Revert "Remove authgroups UI and tests (that rely on that UI) and the controller)"
This reverts commit cbb83782e3d6a6ff4f0f853cf3afb165f1ae2f90.
Reverting last commit to implement just a subset of the removal for
release 1.7
diff --git a/ckan/config/routing.py b/ckan/config/routing.py
index b048798..43fa8fd 100644
--- a/ckan/config/routing.py
+++ b/ckan/config/routing.py
@@ -216,6 +216,17 @@ def make_map():
register_package_plugins(map)
register_group_plugins(map)
+ # authz group
+ map.redirect('/authorizationgroups', '/authorizationgroup')
+ map.redirect('/authorizationgroups/{url:.*}', '/authorizationgroup/{url}')
+ with SubMapper(map, controller='authorization_group') as m:
+ m.connect('/authorizationgroup', action='index')
+ m.connect('/authorizationgroup/list', action='list')
+ m.connect('/authorizationgroup/new', action='new')
+ m.connect('/authorizationgroup/edit/{id}', action='edit')
+ m.connect('/authorizationgroup/authz/{id}', action='authz')
+ m.connect('/authorizationgroup/{id}', action='read')
+
# tags
map.redirect('/tags', '/tag')
map.redirect('/tags/{url:.*}', '/tag/{url}')
diff --git a/ckan/controllers/authorization_group.py b/ckan/controllers/authorization_group.py
new file mode 100644
index 0000000..fa1b91a
--- /dev/null
+++ b/ckan/controllers/authorization_group.py
@@ -0,0 +1,201 @@
+import genshi
+
+from sqlalchemy.orm import eagerload_all
+from ckan.lib.base import *
+from pylons.i18n import get_lang, _
+import ckan.authz as authz
+import ckan.forms
+from ckan.lib.helpers import Page
+from ckan.logic import NotAuthorized, check_access
+
+class AuthorizationGroupController(BaseController):
+
+ def __init__(self):
+ BaseController.__init__(self)
+
+ def index(self):
+ from ckan.lib.helpers import Page
+ try:
+ context = {'model':model,'user': c.user or c.author}
+ check_access('site_read',context)
+ except NotAuthorized:
+ abort(401, _('Not authorized to see this page'))
+
+ query = ckan.authz.Authorizer().authorized_query(c.user, model.AuthorizationGroup)
+ query = query.options(eagerload_all('users'))
+ c.page = Page(
+ collection=query,
+ page=request.params.get('page', 1),
+ items_per_page=20
+ )
+ return render('authorization_group/index.html')
+
+ def _get_authgroup_by_name_or_id(self, id):
+ return model.AuthorizationGroup.by_name(id) or\
+ model.Session.query(model.AuthorizationGroup).get(id)
+
+ def read(self, id):
+ c.authorization_group = self._get_authgroup_by_name_or_id(id)
+ if c.authorization_group is None:
+ abort(404)
+ auth_for_read = self.authorizer.am_authorized(c, model.Action.READ,
+ c.authorization_group)
+ if not auth_for_read:
+ abort(401, _('Not authorized to read %s') % id.encode('utf8'))
+
+ import ckan.misc
+ c.authorization_group_admins = self.authorizer.get_admins(c.authorization_group)
+
+ c.page = Page(
+ collection=c.authorization_group.users,
+ page=request.params.get('page', 1),
+ items_per_page=50
+ )
+ return render('authorization_group/read.html')
+
+ def new(self):
+ record = model.AuthorizationGroup
+ c.error = ''
+
+ auth_for_create = self.authorizer.am_authorized(c, model.Action.AUTHZ_GROUP_CREATE, model.System())
+ if not auth_for_create:
+ abort(401, _('Unauthorized to create a group'))
+
+ is_admin = self.authorizer.is_sysadmin(c.user)
+
+ fs = ckan.forms.get_authorization_group_fieldset(is_admin=is_admin)
+
+ if request.params.has_key('save'):
+ # needed because request is nested
+ # multidict which is read only
+ params = dict(request.params)
+ c.fs = fs.bind(record, data=params or None, session=model.Session)
+ try:
+ self._update(c.fs, id, record.id)
+ except ValidationException, error:
+ fs = error.args[0]
+ c.form = self._render_edit_form(fs)
+ return render('authorization_group/edit.html')
+ # do not use groupname from id as may have changed
+ c.authzgroupname = c.fs.name.value
+ authorization_group = model.AuthorizationGroup.by_name(c.authzgroupname)
+ assert authorization_group
+ user = model.User.by_name(c.user)
+ model.setup_default_user_roles(authorization_group, [user])
+ users = [model.User.by_name(name) for name in \
+ request.params.getall('AuthorizationGroup-users-current')]
+ authorization_group.users = list(set(users))
+ usernames = request.params.getall('AuthorizationGroupUser--user_name')
+ for username in usernames:
+ if username:
+ usr = model.User.by_name(username)
+ if usr and usr not in authorization_group.users:
+ model.add_user_to_authorization_group(usr, authorization_group, model.Role.READER)
+ model.repo.commit_and_remove()
+ h.redirect_to(controller='authorization_group', action='read', id=c.authzgroupname)
+
+ c.form = self._render_edit_form(fs)
+ return render('authorization_group/new.html')
+
+ def edit(self, id=None): # allow id=None to allow posting
+ c.error = ''
+ authorization_group = self._get_authgroup_by_name_or_id(id)
+ if authorization_group is None:
+ abort(404, '404 Not Found')
+ am_authz = self.authorizer.am_authorized(c, model.Action.EDIT, authorization_group)
+ if not am_authz:
+ abort(401, _('User %r not authorized to edit %r') % (c.user, id))
+
+ is_admin = self.authorizer.is_sysadmin(c.user)
+
+ if not 'save' in request.params:
+ c.authorization_group = authorization_group
+ c.authorization_group_name = authorization_group.name
+
+ fs = ckan.forms.get_authorization_group_fieldset(is_admin=is_admin).bind(authorization_group)
+ c.form = self._render_edit_form(fs)
+ return render('authorization_group/edit.html')
+ else:
+ # id is the name (pre-edited state)
+ c.authorization_group_name = id
+ # needed because request is nested
+ # multidict which is read only
+ params = dict(request.params)
+ c.fs = ckan.forms.get_authorization_group_fieldset()\
+ .bind(authorization_group, data=params or None)
+ try:
+ self._update(c.fs, id, authorization_group.id)
+ # do not use groupname from id as may have changed
+ c.authorization_group = authorization_group
+ c.authorization_group_name = authorization_group.name
+ except ValidationException, error:
+ fs = error.args[0]
+ c.form = self._render_edit_form(fs)
+ return render('authorization_group/edit.html')
+ user = model.User.by_name(c.user)
+ users = [model.User.by_name(name) for name in \
+ request.params.getall('AuthorizationGroup-users-current')]
+ authorization_group.users = list(set(users))
+ usernames = request.params.getall('AuthorizationGroupUser--user_name')
+ for username in usernames:
+ if username:
+ usr = model.User.by_name(username)
+ if usr and usr not in authorization_group.users:
+ model.add_user_to_authorization_group(usr, authorization_group, model.Role.READER)
+ model.repo.commit_and_remove()
+ h.redirect_to(controller='authorization_group', action='read', id=c.authorization_group_name)
+
+ def authz(self, id):
+ authorization_group = self._get_authgroup_by_name_or_id(id)
+ if authorization_group is None:
+ abort(404, _('Group not found'))
+
+ c.authorization_group_name = authorization_group.name
+ c.authorization_group = authorization_group
+
+ c.authz_editable = self.authorizer.am_authorized(c, model.Action.EDIT_PERMISSIONS,
+ authorization_group)
+ if not c.authz_editable:
+ abort(401, gettext('User %r not authorized to edit %s authorizations') % (c.user, id))
+
+ roles = self._handle_update_of_authz(authorization_group)
+ self._prepare_authz_info_for_render(roles)
+ return render('authorization_group/authz.html')
+
+
+ def _render_edit_form(self, fs):
+ # errors arrive in c.error and fs.errors
+ c.fieldset = fs
+ c.fieldset2 = ckan.forms.get_authorization_group_user_fieldset()
+ return render('authorization_group/edit_form.html')
+
+ def _update(self, fs, group_name, group_id):
+ '''
+ Writes the POST data (associated with a group edit) to the database
+ @input c.error
+ '''
+ validation = fs.validate()
+ if not validation:
+ c.form = self._render_edit_form(fs)
+ raise ValidationException(fs)
+
+ try:
+ fs.sync()
+ except Exception, inst:
+ model.Session.rollback()
+ raise
+ else:
+ model.Session.commit()
+
+ def _update_authz(self, fs):
+ validation = fs.validate()
+ if not validation:
+ c.form = self._render_edit_form(fs)
+ raise ValidationException(fs)
+ try:
+ fs.sync()
+ except Exception, inst:
+ model.Session.rollback()
+ raise
+ else:
+ model.Session.commit()
diff --git a/ckan/forms/authz.py b/ckan/forms/authz.py
index e0e9628..ac7c512 100644
--- a/ckan/forms/authz.py
+++ b/ckan/forms/authz.py
@@ -30,6 +30,15 @@ def get_group_linker(action):
action,
action)
+def get_authorization_group_linker(action):
+ return lambda item: '<a href="%s" title="%s"><img src="http://m.okfn.org/kforge/images/icon-delete.png" alt="%s" class="icon" /></a>' % (
+ ckan_h.url_for(controller='authorization_group',
+ action='authz',
+ id=item.authorization_group.name,
+ role_to_delete=item.id),
+ action,
+ action)
+
class RolesRenderer(formalchemy.fields.FieldRenderer):
def render(self, **kwargs):
selected = kwargs.get('selected', None) or unicode(self.value)
@@ -49,14 +58,18 @@ def authz_fieldset_builder(role_class):
fs.append(
Field(u'delete', types.String, get_group_linker(u'delete')).readonly()
)
-
+ elif role_class == model.AuthorizationGroupRole:
+ fs.append(
+ Field(u'delete', types.String, get_authorization_group_linker(u'delete')).readonly()
+ )
+
fs.append(
# use getattr because though we should always have a user name,
# sometimes (due to error) we don't and want to avoid a 500 ...
Field(u'username', types.String,
lambda item: ckan_h.linked_user(getattr(item.user, 'name', ''))).readonly()
)
-
+
fs.append(
Field(u'authzgroupname', types.String,
lambda item: getattr(item.authorized_group, 'name', '')).readonly()
@@ -68,7 +81,8 @@ def authz_fieldset_builder(role_class):
],
include=[fs.username,
fs.authzgroupname,
- fs.role]
+ fs.role,
+ fs.delete],
)
return fs
@@ -104,7 +118,7 @@ def get_new_role_fieldset(role_class):
fieldsets = {}
def get_authz_fieldset(name):
- if not fieldsets:
+ if not fieldsets:
fieldsets['package_authz_fs'] = authz_fieldset_builder(model.PackageRole)
fieldsets['group_authz_fs'] = authz_fieldset_builder(model.GroupRole)
fieldsets['authorization_group_authz_fs'] = authz_fieldset_builder(model.AuthorizationGroupRole)
diff --git a/ckan/lib/helpers.py b/ckan/lib/helpers.py
index bb51502..ea8a4fe 100644
--- a/ckan/lib/helpers.py
+++ b/ckan/lib/helpers.py
@@ -438,6 +438,20 @@ def linked_user(user, maxlength=0):
return _icon + link_to(displayname,
url_for(controller='user', action='read', id=_name))
+def linked_authorization_group(authgroup, maxlength=0):
+ from ckan import model
+ if not isinstance(authgroup, model.AuthorizationGroup):
+ authgroup_name = unicode(authgroup)
+ authgroup = model.AuthorizationGroup.get(authgroup_name)
+ if not authgroup:
+ return authgroup_name
+ if authgroup:
+ displayname = authgroup.name or authgroup.id
+ if maxlength and len(display_name) > maxlength:
+ displayname = displayname[:maxlength] + '...'
+ return link_to(displayname,
+ url_for(controller='authorization_group', action='read', id=displayname))
+
def group_name_to_title(name):
from ckan import model
group = model.Group.by_name(name)
@@ -757,6 +771,7 @@ def process_names(items):
# am_authorized, # depreciated
'check_access',
'linked_user',
+ 'linked_authorization_group',
'group_name_to_title',
'markdown_extract',
'icon',
diff --git a/ckan/templates/_util.html b/ckan/templates/_util.html
index b76d73a..5aa7c07 100644
--- a/ckan/templates/_util.html
+++ b/ckan/templates/_util.html
@@ -89,6 +89,20 @@
</py:for>
</table>
+ <!--! List of authorization groups: pass in a collection of authorization groups and
+ this renders the standard group listing -->
+ <table class="table table-bordered table-striped table-condensed authorization_groups" py:def="authorization_group_list(authorization_groups)">
+ <tr><th>Title</th><th>Number of members</th></tr>
+ <py:for each="authorization_group in authorization_groups">
+ <tr>
+ <td><a href="${h.url_for(controller='authorization_group', action='read', id=authorization_group.name or authorization_group.id)}">
+ ${authorization_group.name or authorization_group.id}</a>
+ </td>
+ <td>${len(authorization_group.users)}</td>
+ </tr>
+ </py:for>
+ </table>
+
<!--! Dataset openness icons -->
<img py:def="package_license_icon(package)"
src="${h.url_for('/images/icons/door_%s.png' % 'open' if package.isopen() else 'grey')}"
@@ -195,6 +209,42 @@ <h5 class="heading" title="${related.title}">${h.markdown_extract(related.title,
</py:for>
</table>
+<!--! Copy and paste of above table. Only difference when created was the h.linked_user for the -->
+<!--! table rows. How to combine the two? -->
+ <table class="table table-bordered table-striped table-condensed" py:def="authz_form_group_table(id, roles, users, user_role_dict)">
+ <tr>
+ <th>User Group</th>
+ <py:for each="role in roles">
+ <th> ${role} </th>
+ </py:for>
+ </tr>
+ <py:for each="user in users">
+ <tr>
+ <td>
+ ${h.linked_authorization_group(user)}
+ </td>
+ <py:for each="role in roles">
+ <td>
+ <input type="hidden" name="${ h.literal( '%s$%s' % (user,role)) }" value="submitted"/>
+ <py:choose>
+ <py:when test="user_role_dict[(user,role)]">
+ <input type="checkbox"
+ name="${ h.literal( '%s$%s' % (user,role)) }"
+ checked='checked'/>
+ </py:when>
+ <py:otherwise>
+ <input type="checkbox"
+ name="${ h.literal( '%s$%s' % (user,role)) }"
+ />
+ </py:otherwise>
+ </py:choose>
+ </td>
+ </py:for>
+ </tr>
+ </py:for>
+ </table>
+
+
<table class="table table-bordered table-striped table-condensed" py:def="authz_add_table(roles)">
<tr>
diff --git a/ckan/templates/admin/authz.html b/ckan/templates/admin/authz.html
index f409f7a..7feaebd 100644
--- a/ckan/templates/admin/authz.html
+++ b/ckan/templates/admin/authz.html
@@ -26,6 +26,25 @@
<hr/>
+ <h3>Existing Roles for Authorization Groups</h3>
+
+ <form id="authzgroup_form" method="POST">
+ ${authz_form_group_table('authzgroup_form', c.roles, c.authz_groups, c.authz_groups_role_dict)}
+ <button type="submit" name="authz_save" class="btn btn-primary">Save Changes</button>
+ <div class="clear"></div>
+ </form>
+
+ <h3>Add Roles for Any Authorization Group</h3>
+
+ <form id="authzgroup_addform" method="POST">
+ ${authz_add_group_table(c.roles)}
+ <button type="submit" name="authz_add" class="btn btn-primary">Add Role</button>
+ <div class="clear"></div>
+ </form>
+
+
+
+
</div>
<xi:include href="layout.html" />
diff --git a/ckan/templates/authorization_group/__init__.py b/ckan/templates/authorization_group/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/ckan/templates/authorization_group/authz.html b/ckan/templates/authorization_group/authz.html
new file mode 100644
index 0000000..12643d2
--- /dev/null
+++ b/ckan/templates/authorization_group/authz.html
@@ -0,0 +1,46 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+
+ <py:def function="page_title">${c.authorization_group_name} - Authorization - AuthorizationGroups</py:def>
+ <py:def function="page_heading">Authorization: ${c.authorization_group_name}</py:def>
+
+ <div py:match="content">
+ <h3>Update Existing Roles</h3>
+
+ <form id="theform" method="POST">
+ ${authz_form_table('theform', c.roles, c.users, c.user_role_dict)}
+ <button type="submit" name="save">
+ Save
+ </button>
+ </form>
+
+ <h3>Add Roles for Any User</h3>
+
+ <form id="addform" method="POST">
+ ${authz_add_table(c.roles)}
+ <button type="submit" name="add"> Add </button>
+ </form>
+
+ <hr/>
+
+ <h3>Existing Roles for Authorization Groups</h3>
+
+ <form id="authzgroup_form" method="POST">
+ ${authz_form_group_table('authzgroup_form', c.roles, c.authz_groups, c.authz_groups_role_dict)}
+ <button type="submit" name="authz_save">
+ Save
+ </button>
+ </form>
+
+ <h3>Add Roles for Any Authorization Group</h3>
+
+ <form id="authzgroup_addform" method="POST">
+ ${authz_add_group_table(c.roles)}
+ <button type="submit" name="authz_add"> Add </button>
+ </form>
+
+ </div>
+
+ <xi:include href="layout.html" />
+</html>
diff --git a/ckan/templates/authorization_group/edit.html b/ckan/templates/authorization_group/edit.html
new file mode 100644
index 0000000..ade0f54
--- /dev/null
+++ b/ckan/templates/authorization_group/edit.html
@@ -0,0 +1,14 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+
+ <py:def function="page_title">${c.authorization_group_name} - Edit - Authorization Groups</py:def>
+ <py:def function="page_heading">Edit: ${c.authorization_group.name if c.authorization_group else ''}</py:def>
+
+ <div py:match="content">
+ ${Markup(c.form)}
+ </div>
+
+ <xi:include href="layout.html" />
+</html>
+
diff --git a/ckan/templates/authorization_group/edit_form.html b/ckan/templates/authorization_group/edit_form.html
new file mode 100644
index 0000000..2934280
--- /dev/null
+++ b/ckan/templates/authorization_group/edit_form.html
@@ -0,0 +1,30 @@
+<form
+ class="form-horizontal ${'has-errors' if c.errors or c.fieldset.errors else ''}"
+ id="group-edit"
+ action=""
+ method="post"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ >
+
+ ${h.literal(c.fieldset.render())}
+
+ <fieldset>
+ <legend>Users</legend>
+ <div class="control-group" py:for="user in c.fieldset.model.users">
+ <label class="control-label" for="AuthorizationGroup-users_${user.name}" style="display: inline;">${user.name}</label>
+ <div class="controls">
+ <label class="checkbox">
+ <input checked="checked" id="AuthorizationGroup-users-current"
+ name="AuthorizationGroup-users-current" type="checkbox" value="${user.name}" />
+ </label>
+ </div>
+ </div>
+ <p py:if="not c.fieldset.model.users">There are no users currently in this group.</p>
+ </fieldset>
+
+ ${h.literal(c.fieldset2.render())}
+
+ <br/>
+ ${h.submit('save', _('Save'))}
+</form>
diff --git a/ckan/templates/authorization_group/index.html b/ckan/templates/authorization_group/index.html
new file mode 100644
index 0000000..a135ac9
--- /dev/null
+++ b/ckan/templates/authorization_group/index.html
@@ -0,0 +1,18 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+
+ <py:def function="page_title">Authorization Groups</py:def>
+ <py:def function="page_heading">Authorization Groups</py:def>
+
+ <div py:match="content">
+ <p i18n:msg="item_count">There are <strong>${c.page.item_count}</strong> authorization groups.</p>
+
+ ${c.page.pager()}
+ ${authorization_group_list(c.page.items)}
+ ${c.page.pager()}
+ </div>
+
+ <xi:include href="layout.html" />
+</html>
diff --git a/ckan/templates/authorization_group/layout.html b/ckan/templates/authorization_group/layout.html
new file mode 100644
index 0000000..e575f8d
--- /dev/null
+++ b/ckan/templates/authorization_group/layout.html
@@ -0,0 +1,43 @@
+<html
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip=""
+ >
+
+ <py:match path="minornavigation">
+ <ul class="nav nav-pills">
+ <li class="${'active' if c.action=='index' else ''}">${h.subnav_link(h.icon('page_white_stack') + _('List'), controller='authorization_group', action='index')}</li>
+ <py:if test="c.authorization_group">
+ <li class="divider">|</li>
+ <li class="${'active' if c.action=='read' else ''}">${h.subnav_link(h.icon('authorization_group') + _('View'), controller='authorization_group', action='read', id=c.authorization_group.name or c.authorization_group.id)}</li>
+ <li class="${'active' if c.action=='edit' else ''}" py:if="h.check_access('authorization_group_update',{'id':c.authorization_group.id})">
+ ${h.subnav_link(h.icon('authorization_group_edit') + _('Edit'), controller='authorization_group', action='edit', id=c.authorization_group.name or c.authorization_group.id)}
+ </li>
+ <li class="${'active' if c.action=='authz' else ''}" py:if="h.check_access('authorization_group_edit_permissions',{'id':c.authorization_group.id})">
+ ${h.subnav_link(h.icon('lock') + _('Authorization'), controller='authorization_group', action='authz', id=c.authorization_group.name or c.authorization_group.id)}
+ </li>
+ </py:if>
+ </ul>
+ </py:match>
+
+ <py:match path="primarysidebar">
+ <li class="widget-container widget_text">
+ <h2>Authorization Groups</h2>
+ <p i18n:msg="">Instead of specifying the privileges of specific users on a dataset or group,
+ you can also specify a set of users that will share the same rights. To do that, an
+ <strong>authorization group</strong> can be set-up and users can be added to it.</p>
+ <p>
+ <span class="ckan_logged_in" style="display: none;" i18n:msg="">
+ To create a new authorization group, please first <a href="${h.url_for(controller='user',action='login', id=None)}">login</a>.
+ </span>
+ <span class="ckan_logged_out">
+ <a href="${h.url_for(controller='authorization_group',action='new', id=None)}">Create a new authorization group</a>
+ </span>
+ </p>
+ </li>
+ </py:match>
+
+ <xi:include href="../layout.html" />
+</html>
diff --git a/ckan/templates/authorization_group/new.html b/ckan/templates/authorization_group/new.html
new file mode 100644
index 0000000..0dbcc2a
--- /dev/null
+++ b/ckan/templates/authorization_group/new.html
@@ -0,0 +1,14 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+
+ <py:def function="page_title">New - Authorization Groups</py:def>
+ <py:def function="page_heading">New Authorization Group</py:def>
+
+ <div py:match="content">
+ ${Markup(c.form)}
+ </div>
+
+ <xi:include href="layout.html" />
+</html>
+
diff --git a/ckan/templates/authorization_group/read.html b/ckan/templates/authorization_group/read.html
new file mode 100644
index 0000000..01ecec0
--- /dev/null
+++ b/ckan/templates/authorization_group/read.html
@@ -0,0 +1,20 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+
+ <py:def function="page_title">${c.authorization_group.name} - Authorization Groups</py:def>
+ <py:def function="page_heading">${c.authorization_group.name}</py:def>
+
+ <div py:match="content">
+ <h3>Members</h3>
+ <p i18n:msg="item_count">There are ${c.page.item_count} users in this authorization group.</p>
+ ${c.page.pager()}
+ ${user_list(c.page.items)}
+ ${c.page.pager()}
+ </div>
+
+ <xi:include href="layout.html" />
+</html>
+
+
diff --git a/ckan/templates/group/authz.html b/ckan/templates/group/authz.html
index 1d9d9dc..0b778b2 100644
--- a/ckan/templates/group/authz.html
+++ b/ckan/templates/group/authz.html
@@ -1,10 +1,10 @@
<html xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip="">
-
+
<py:def function="page_title">Authorization: ${c.group.display_name}</py:def>
<py:def function="page_heading">Authorization: ${c.group.display_name}</py:def>
-
+
<div py:match="content">
<h3>Update Existing Roles</h3>
@@ -23,6 +23,23 @@
<div class="clear"></div>
</form>
+ <hr/>
+
+ <h3>Update Existing Roles for Authorization Groups</h3>
+
+ <form id="authzgroup_form" method="POST">
+ ${authz_form_group_table('authzgroup_form', c.roles, c.authz_groups, c.authz_groups_role_dict)}
+ <button type="submit" name="authz_save" class="btn btn-primary">Save Changes</button>
+ <div class="clear"></div>
+ </form>
+
+ <h3>Add Roles for Any Authorization Group</h3>
+
+ <form id="authzgroup_addform" method="POST">
+ ${authz_add_group_table(c.roles)}
+ <button type="submit" name="authz_add" class="btn btn-primary">Add Role</button>
+ <div class="clear"></div>
+ </form>
</div>
diff --git a/ckan/templates/layout_base.html b/ckan/templates/layout_base.html
index f2d51dd..8913814 100644
--- a/ckan/templates/layout_base.html
+++ b/ckan/templates/layout_base.html
@@ -177,6 +177,11 @@ <h3 class="widget-title">Sections</h3>
</a>
</li>
<li>
+ <a href="${h.url(controller='authorization_group', action='index')}">
+ Authorization Groups
+ </a>
+ </li>
+ <li>
<a href="${h.url_for('ckanadmin_index')}">
Site Admin
</a>
diff --git a/ckan/templates/package/authz.html b/ckan/templates/package/authz.html
index 5849265..aca6146 100644
--- a/ckan/templates/package/authz.html
+++ b/ckan/templates/package/authz.html
@@ -1,7 +1,7 @@
<html xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip="">
-
+
<py:def function="page_title">Authorization: ${c.pkgtitle or c.pkgname}</py:def>
<py:def function="page_heading">Authorization: ${c.pkgtitle or c.pkgname}</py:def>
@@ -22,6 +22,25 @@
<button type="submit" name="add" class="btn btn-primary">Add Role</button>
<div class="clear"></div>
</form>
+
+ <hr/>
+
+ <h3>Update Existing Roles for Authorization Groups</h3>
+
+ <form id="authzgroup_form" method="POST">
+ ${authz_form_group_table('authzgroup_form', c.roles, c.authz_groups, c.authz_groups_role_dict)}
+ <button type="submit" name="authz_save" class="btn btn-primary">Save Changes</button>
+ <div class="clear"></div>
+ </form>
+
+ <h3>Add Roles for Any Authorization Group</h3>
+
+ <form id="authzgroup_addform" method="POST">
+ ${authz_add_group_table(c.roles)}
+ <button type="submit" name="authz_add" class="btn btn-primary">Add Role</button>
+ <div class="clear"></div>
+ </form>
+
</div>
<xi:include href="layout.html" />
diff --git a/ckan/tests/functional/test_admin.py b/ckan/tests/functional/test_admin.py
index 448dcda..416f1b0 100644
--- a/ckan/tests/functional/test_admin.py
+++ b/ckan/tests/functional/test_admin.py
@@ -34,7 +34,7 @@ def setup_class(cls):
# Creating a couple of authorization groups, which are enough to break
# some things just by their existence
for ag_name in [u'anauthzgroup', u'anotherauthzgroup']:
- ag=model.AuthorizationGroup.by_name(ag_name)
+ ag=model.AuthorizationGroup.by_name(ag_name)
if not ag: #may already exist, if not create
ag=model.AuthorizationGroup(name=ag_name)
model.Session.add(ag)
@@ -72,6 +72,10 @@ def get_user_form():
response = get_response()
return response.forms['theform']
+ def get_authzgroup_form():
+ response = get_response()
+ return response.forms['authzgroup_form']
+
def check_and_set_checkbox(theform, user, role, should_be, set_to):
user_role_string = '%s$%s' % (user, role)
checkboxes = [x for x in theform.fields[user_role_string] \
@@ -94,7 +98,7 @@ def submit(form):
def authz_submit(form):
return form.submit('authz_save', extra_environ=as_testsysadmin)
-
+
# get and store the starting state of the system roles
original_user_roles = get_system_user_roles()
original_authzgroup_roles = get_system_authzgroup_roles()
@@ -121,12 +125,17 @@ def authz_submit(form):
# and check that's the state in the database now
assert get_system_user_roles() == expected_user_roles
+ assert get_system_authzgroup_roles() == expected_authzgroup_roles
# try again, this time we expect the box to be ticked already
submit(check_and_set_checkbox(get_user_form(), u'visitor', u'admin', True, True))
# performing the action twice shouldn't have changed anything
assert get_system_user_roles() == expected_user_roles
+ assert get_system_authzgroup_roles() == expected_authzgroup_roles
+
+ # now let's make the authzgroup which already has a system role an admin
+ authz_submit(check_and_set_checkbox(get_authzgroup_form(), u'anauthzgroup', u'admin', False, True))
# update expected state to reflect the change we should just have made
expected_authzgroup_roles.append((u'anauthzgroup', u'admin'))
@@ -134,12 +143,15 @@ def authz_submit(form):
# check that's happened
assert get_system_user_roles() == expected_user_roles
+ assert get_system_authzgroup_roles() == expected_authzgroup_roles
# put it back how it was
submit(check_and_set_checkbox(get_user_form(), u'visitor', u'admin', True, False))
+ authz_submit(check_and_set_checkbox(get_authzgroup_form(), u'anauthzgroup', u'admin', True, False))
# should be back to our starting state
assert original_user_roles == get_system_user_roles()
+ assert original_authzgroup_roles == get_system_authzgroup_roles()
# now test making multiple changes
@@ -150,7 +162,7 @@ def authz_submit(form):
check_and_set_checkbox(form, u'visitor', u'editor', False, True)
check_and_set_checkbox(form, u'visitor', u'reader', False, False)
check_and_set_checkbox(form, u'logged_in', u'editor', True, False)
- check_and_set_checkbox(form, u'logged_in', u'reader', False, True)
+ check_and_set_checkbox(form, u'logged_in', u'reader', False, True)
submit(form)
roles=get_system_user_roles()
@@ -167,6 +179,8 @@ def get_roles_by_name(user=None, group=None):
return [y for (x,y) in get_system_user_roles() if x==user]
elif group:
return [y for (x,y) in get_system_authzgroup_roles() if x==group]
+ else:
+ assert False, 'miscalled'
# now we test the box for giving roles to an arbitrary user
@@ -195,6 +209,20 @@ def get_roles_by_name(user=None, group=None):
assert get_roles_by_name(group=u'anotherauthzgroup') == [], \
"should not have roles"
+ form = get_response().forms['authzgroup_addform']
+ form.fields['new_user_name'][0].value='anotherauthzgroup'
+ checkbox = [x for x in form.fields['reader'] \
+ if x.__class__.__name__ == 'Checkbox'][0]
+ assert checkbox.checked == False
+ checkbox.checked=True
+
+ response = form.submit('authz_add', extra_environ=as_testsysadmin)
+ assert "Authorization Group Added" in response, "don't see flash message"
+
+
+ assert get_roles_by_name(group=u'anotherauthzgroup') == [u'reader'], \
+ "should be a reader now"
+
class TestAdminTrashController(WsgiAppCase):
def setup(cls):
@@ -238,7 +266,7 @@ def test_purge_package(self):
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],
diff --git a/ckan/tests/functional/test_authorization_group.py b/ckan/tests/functional/test_authorization_group.py
new file mode 100644
index 0000000..3d223a5
--- /dev/null
+++ b/ckan/tests/functional/test_authorization_group.py
@@ -0,0 +1,440 @@
+from nose.plugins.skip import SkipTest
+from nose.tools import assert_equal
+
+from ckan.tests import *
+from ckan.authz import Authorizer
+import ckan.model as model
+from base import FunctionalTestCase
+from ckan.tests import search_related
+
+class TestAuthorizationGroup(FunctionalTestCase):
+
+ @classmethod
+ def setup_class(self):
+ model.Session.remove()
+ model.repo.init_db()
+ CreateTestData.create()
+ model.repo.new_revision()
+ treasury = model.AuthorizationGroup(name=u'treasury')
+ health = model.AuthorizationGroup(name=u'health')
+ model.Session.add(treasury)
+ model.Session.add(health)
+ model.add_user_to_authorization_group(model.User.by_name(u"russianfan"),
+ treasury, model.Role.ADMIN)
+ model.repo.commit_and_remove()
+
+ @classmethod
+ def teardown_class(self):
+ model.Session.remove()
+ model.repo.rebuild_db()
+ model.Session.remove()
+
+ def test_index(self):
+ offset = url_for(controller='authorization_group', action='index')
+ res = self.app.get(offset, extra_environ={'REMOTE_USER': 'russianfan'})
+ assert '<h2>Authorization Groups</h2>' in res, res
+ group_count = Authorizer.authorized_query(u'russianfan', model.AuthorizationGroup).count()
+ assert 'There are %s authorization groups.' % group_count in self.strip_tags(res), res
+ authz_groupname = u'treasury'
+ authz_group = model.AuthorizationGroup.by_name(unicode(authz_groupname))
+ group_users_count = len(authz_group.users)
+ self.check_named_element(res, 'tr', authz_groupname, group_users_count)
+ #res = res.click(authz_groupname)
+ #assert authz_groupname in res, res
+
+ def test_read(self):
+ name = u'treasury'
+ offset = url_for(controller='authorization_group', action='read', id=name)
+ res = self.app.get(offset, extra_environ={'REMOTE_USER': 'russianfan'})
+ main_res = self.main_div(res)
+ assert '%s - Authorization Groups' % name in res, res
+ #assert 'edit' in main_res, main_res
+ assert name in res, res
+
+ def test_new(self):
+ offset = url_for(controller='authorization_group', action='index')
+ res = self.app.get(offset, extra_environ={'REMOTE_USER': 'russianfan'})
+ assert 'Create a new authorization group' in res, res
+
+
+class TestEdit(TestController):
+ groupname = u'treasury'
+
+ @classmethod
+ def setup_class(self):
+ model.Session.remove()
+ CreateTestData.create()
+ model.repo.new_revision()
+ treasury = model.AuthorizationGroup(name=u'treasury')
+ health = model.AuthorizationGroup(name=u'health')
+ model.Session.add(treasury)
+ model.Session.add(health)
+ model.add_user_to_authorization_group(model.User.by_name(u"russianfan"),
+ treasury, model.Role.ADMIN)
+ model.repo.commit_and_remove()
+
+ self.username = u'testusr'
+ model.repo.new_revision()
+ model.Session.add(model.User(name=self.username))
+ model.repo.commit_and_remove()
+
+ @classmethod
+ def teardown_class(self):
+ model.Session.remove()
+ model.repo.rebuild_db()
+ model.Session.remove()
+
+ def test_0_not_authz(self):
+ offset = url_for(controller='authorization_group', action='edit', id=self.groupname)
+ # 401 gets caught by repoze.who and turned into redirect
+ res = self.app.get(offset, status=[302, 401])
+ res = res.follow()
+ assert res.request.url.startswith('/user/login')
+
+ def test_1_read_allowed_for_admin(self):
+ raise SkipTest()
+ offset = url_for(controller='authorization_group', action='edit', id=self.groupname)
+ res = self.app.get(offset, status=200, extra_environ={'REMOTE_USER': 'russianfan'})
+ assert 'Edit Authorization Group: %s' % self.groupname in res, res
+
+ def test_2_edit(self):
+ raise SkipTest()
+ offset = url_for(controller='authorization_group', action='edit', id=self.groupname)
+ res = self.app.get(offset, status=200, extra_environ={'REMOTE_USER': 'russianfan'})
+ assert 'Edit Authorization Group: %s' % self.groupname in res, res
+
+ form = res.forms['group-edit']
+ group = model.AuthorizationGroup.by_name(self.groupname)
+ usr = model.User.by_name(self.username)
+ form['AuthorizationGroupUser--user_name'] = usr.name
+
+ res = form.submit('save', status=302, extra_environ={'REMOTE_USER': 'russianfan'})
+ # should be read page
+ # assert 'Groups - %s' % self.groupname in res, res
+
+ model.Session.remove()
+ group = model.AuthorizationGroup.by_name(self.groupname)
+
+ # now look at packages
+ assert len(group.users) == 2
+
+
+class TestNew(FunctionalTestCase):
+ groupname = u'treasury'
+
+ @classmethod
+ def setup_class(self):
+ CreateTestData.create_user('tester1')
+ CreateTestData.create_user('tester2')
+ CreateTestData.create_user('tester3')
+
+ self.extra_environ = {'REMOTE_USER': 'tester1'}
+
+ @classmethod
+ def teardown_class(self):
+ model.repo.rebuild_db()
+
+ def test_0_new(self):
+ offset = url_for(controller='authorization_group', action='new', id=None)
+ res = self.app.get(offset, status=200, extra_environ=self.extra_environ)
+ assert 'New Authorization Group' in res, res
+
+ form = res.forms['group-edit']
+ form['AuthorizationGroup--name'] = 'testname'
+
+ # can't test users - needs javascript
+ #form['AuthorizationGroupUser--user_name'] = 'tester2'
+
+ res = form.submit('save', status=302, extra_environ=self.extra_environ)
+ res = res.follow()
+
+ # should be read page
+ main_res = self.main_div(res)
+ assert 'testname' in main_res, main_res
+
+ # test created object
+ auth_group = model.AuthorizationGroup.by_name('testname')
+ assert auth_group
+ assert_equal(auth_group.name, 'testname')
+
+ def test_0_new_without_name(self):
+ offset = url_for(controller='authorization_group', action='new', id=None)
+ res = self.app.get(offset, status=200, extra_environ=self.extra_environ)
+ assert 'New Authorization Group' in res, res
+
+ form = res.forms['group-edit']
+ # don't set name
+
+ res = form.submit('save', status=200, extra_environ=self.extra_environ)
+ assert 'Error' in res, res
+ assert 'Name: Please enter a value' in res, res
+
+
+class TestAuthorizationGroupWalkthrough(FunctionalTestCase):
+
+ @classmethod
+ def setup_class(self):
+ model.Session.remove()
+ model.repo.init_db()
+ CreateTestData.create()
+ model.repo.commit_and_remove()
+
+
+ @classmethod
+ def teardown_class(self):
+ model.Session.remove()
+ model.repo.rebuild_db()
+ model.Session.remove()
+
+
+ ## THIS WALKTHROUGH IS NOW COMPLETELY BROKEN BY THE CHANGES I MADE TO THE AUTHZ PAGE
+
+
+ # def test_authzgroups_walkthrough(self):
+ # # very long test sequence repeating the series of things I did to
+ # # convince myself that the authzgroups system worked as expected,
+ # # starting off with the default test data
+
+ # # The first thing to notice is that the authzgroup page:
+ # auth_group_index_url = url_for(controller='/authorization_group', action='index')
+ # # displays differently for different users.
+
+ # def get_page(url, expect_status, username, assert_text=None, error_text=None):
+ # res= self.app.get(url,
+ # status=expect_status,
+ # extra_environ={'REMOTE_USER': username})
+ # if assert_text and assert_text not in res:
+ # errorstring = error_text + ' ( "' + assert_text + \
+ # '" not found in result of getting "' + \
+ # url + '" as user "' + username + '" )'
+ # assert False, errorstring
+ # return res
+
+ # # testsysadmin sees the true picture, where the test data contains two groups
+ # get_page(auth_group_index_url, 200, 'testsysadmin',
+ # 'There are <strong>2</strong> authorization groups',
+ # 'Should be accurate for testsysadmin')
+
+ # # But if we look at the same page as annafan, who does not have read
+ # # permissions on these groups, we should see neither
+ # get_page(auth_group_index_url, 200, 'annafan',
+ # 'There are <strong>0</strong> authorization groups',
+ # 'Should lie to annafan about number of groups')
+
+ # # There is a page for each group
+ # anauthzgroup_url = url_for(controller='/authorization_group',
+ # action='read',
+ # id='anauthzgroup')
+ # # And an edit page
+ # anauthzgroup_edit_url = url_for(controller='/authorization_group',
+ # action='edit',
+ # id='anauthzgroup')
+
+ # # testsysadmin should be able to see this, and check that there are no members
+ # get_page(anauthzgroup_url, 200, 'testsysadmin',
+ # 'There are 0 users in this',
+ # 'should be no users in anauthzgroup')
+
+ # # now testsysadmin adds annafan to anauthzgroup via the edit page
+ # res = get_page(anauthzgroup_edit_url, 200, 'testsysadmin')
+ # group_edit_form = res.forms['group-edit']
+ # group_edit_form['AuthorizationGroupUser--user_name'] = u'annafan'
+ # submit_res = group_edit_form.submit('save',
+ # extra_environ={'REMOTE_USER': 'testsysadmin'})
+
+ # # adding a user to a group should both make her a member, and give her
+ # # read permission on the group. We'll check those things have actually
+ # # happened by looking directly in the model.
+ # anauthzgroup = model.AuthorizationGroup.by_name('anauthzgroup')
+ # anauthzgroup_users = [x.name for x in anauthzgroup.users]
+ # anauthzgroup_user_roles = [(x.user.name, x.role) for x in anauthzgroup.roles if x.user]
+ # assert anauthzgroup_users == [u'annafan'], \
+ # 'anauthzgroup should contain annafan (only)'
+ # assert anauthzgroup_user_roles == [(u'annafan', u'reader')],\
+ # 'annafan should be a reader'
+
+ # # Since annafan has been added to anauthzgroup, which is an admin on
+ # # anotherauthzgroup, she should now be able to see both the groups.
+ # get_page(auth_group_index_url, 200, 'annafan',
+ # 'There are <strong>2</strong> auth',
+ # "annafan should now be able to see both groups")
+
+ # # When annafan looks at the page for anauthzgroup now
+ # # She should see that there's one user:
+ # get_page(anauthzgroup_url, 200,'annafan',
+ # 'There are 1 users in this',
+ # 'annafan should be able to see the list of members')
+
+ # # Which is her, so her name should be in there somewhere:
+ # get_page(anauthzgroup_url, 200,'annafan',
+ # 'annafan',
+ # 'annafan should be listed as a member')
+
+ # # But she shouldn't be able to see the edit page for that group.
+
+ # # The behaviour of the test setup here is a bit weird, since in the
+ # # browser she gets redirected to the login page, but from these tests,
+ # # she just gets a 401, with no apparent redirect. Sources inform me
+ # # that this is normal, and to do with repoze being in the application
+ # # stack but not in the test stack.
+ # get_page(anauthzgroup_edit_url, 401, 'annafan',
+ # 'not authorized to edit',
+ # 'annafan should not be able to edit the list of members')
+ # # this behaviour also means that we get a flash message left over, which appears on
+ # # whatever the next page is.
+
+ # # I'm going to assert that behaviour here, just to note it. It's most
+ # # definitely not required functionality! We'll do a dummy fetch of the
+ # # main page for anauthzgroup, which will have the errant flash message
+ # get_page(anauthzgroup_url, 200, 'annafan',
+ # 'not authorized to edit',
+ # 'flash message should carry over to next fetch')
+
+ # # But if we do the dummy fetch twice, the flash message should have gone
+ # res = get_page(anauthzgroup_url, 200, 'annafan')
+ # assert 'not authorized to edit' not in res, 'flash message should have gone'
+
+ # # Since annafan is now a member of anauthzgroup, she should have admin privileges
+ # # on anotherauthzgroup
+ # anotherauthzgroup_edit_url = url_for(controller='/authorization_group',
+ # action='edit',
+ # id='anotherauthzgroup')
+
+ # # Which means that she can go to the edit page:
+ # res = get_page(anotherauthzgroup_edit_url, 200, 'annafan',
+ # 'There are no users',
+ # "There shouldn't be any users in anotherauthzgroup")
+
+ # # And change the name of the group
+ # # The group name editing box has a name dependent on the id of the group,
+ # # so we find it by regex in the page.
+ # import re
+ # p = re.compile('AuthorizationGroup-.*-name')
+ # groupnamebox = [ v for k,v in res.forms['group-edit'].fields.items() if p.match(k)][0][0]
+ # groupnamebox.value = 'annasauthzgroup'
+ # res = res.forms['group-edit'].submit('save', extra_environ={'REMOTE_USER': 'annafan'})
+ # res = res.follow()
+
+ # ## POTENTIAL BUG:
+ # # note that she could change the name of the group to anauthzgroup,
+ # # which causes problems due to the name collision. This should be
+ # # guarded against.
+
+
+ # # annafan should still be able to see the admin and edit pages of the
+ # # newly renamed group by virtue of being a member of anauthzgroup
+ # annasauthzgroup_authz_url = url_for(controller='/authorization_group',
+ # action='authz',
+ # id='annasauthzgroup')
+
+ # annasauthzgroup_edit_url = url_for(controller='/authorization_group',
+ # action='edit',
+ # id='annasauthzgroup')
+
+
+ # res = get_page(annasauthzgroup_authz_url, 200, 'annafan',
+ # 'Authorization for authorization group: annasauthzgroup',
+ # 'should be authz page')
+
+ # # annafan has the power to remove anauthzgroup's admin role on her group
+ # # The button to remove that role is a link, rather than a submit. I
+ # # assume there is a better way to do this than searching by regex, but I
+ # # can't find it.
+ # import re
+ # delete_links = re.compile('<a href="(.*)" title="delete">').findall(res.body)
+ # assert len(delete_links) == 1, "There should only be one delete link here"
+ # delete_link = delete_links[0]
+
+ # # Paranoid check, try to follow link without credentials. Should be redirected.
+ # res = self.app.get(delete_link, status=302)
+ # res = res.follow()
+ # assert 'Not authorized to edit authorization for group' in res,\
+ # "following link without credentials should result in redirection to login page"
+
+ # # Now follow it as annafan, which should work.
+ # get_page(delete_link, 200,'annafan',
+ # "Deleted role 'admin' for authorization group 'anauthzgroup'",
+ # "Page should mention the deleted role")
+
+ # # Trying it a second time should fail since she's now not an admin.
+ # get_page(delete_link, 401,'annafan')
+
+ # # No one should now have any rights on annasauthzgroup, including
+ # # annafan herself. So this should fail too. Again, get a 401 error
+ # # here, but in the browser we get redirected if we try.
+ # get_page(annasauthzgroup_authz_url, 401,'annafan')
+
+ # # testsysadmin can put her back.
+ # # It appears that the select boxes on this form need to be set by id
+ # anauthzgroupid = model.AuthorizationGroup.by_name(u'anauthzgroup').id
+ # annafanid = model.User.by_name(u'annafan').id
+
+ # # first try to make both anauthzgroup and annafan editors. This should fail.
+ # res = get_page(annasauthzgroup_authz_url,200, 'testsysadmin')
+ # gaf= res.forms['group-authz']
+ # gaf['AuthorizationGroupRole--authorized_group_id'] = anauthzgroupid
+ # gaf['AuthorizationGroupRole--role'] = 'editor'
+ # gaf['AuthorizationGroupRole--user_id'] = annafanid
+ # res = gaf.submit('save', status=200, extra_environ={'REMOTE_USER': 'testsysadmin'})
+ # assert 'Please select either a user or an authorization group, not both.' in res,\
+ # 'request should fail if you change both user and authz group'
+
+ # # settle for just doing one at a time. make anauthzgroup an editor
+ # res = get_page(annasauthzgroup_authz_url, 200, 'testsysadmin')
+ # gaf= res.forms['group-authz']
+ # gaf['AuthorizationGroupRole--authorized_group_id'] = anauthzgroupid
+ # gaf['AuthorizationGroupRole--role'] = 'editor'
+ # res = gaf.submit('save',status=200, extra_environ={'REMOTE_USER': 'testsysadmin'})
+ # assert "Added role 'editor' for authorization group 'anauthzgroup'" in res, \
+ # "no flash message"
+
+ # # and make annafan a reader
+ # res = get_page(annasauthzgroup_authz_url, 200, 'testsysadmin')
+ # gaf= res.forms['group-authz']
+ # gaf['AuthorizationGroupRole--user_id'] = annafanid
+ # gaf['AuthorizationGroupRole--role'] = 'reader'
+ # res = gaf.submit('save', status=200, extra_environ={'REMOTE_USER': 'testsysadmin'})
+ # assert "Added role 'reader' for user 'annafan'" in res, "no flash message"
+
+ # # annafan should now be able to add her friends to annasauthzgroup
+ # res = get_page(annasauthzgroup_edit_url, 200, 'annafan')
+ # res.forms['group-edit']['AuthorizationGroupUser--user_name']='tester'
+ # # this follows the post/redirect/get pattern
+ # res = res.forms['group-edit'].submit('save', status=302,
+ # extra_environ={'REMOTE_USER': 'annafan'})
+ # res = res.follow(status=200, extra_environ={'REMOTE_USER': 'annafan'})
+ # # and she gets redirected to the group view page
+ # assert 'tester' in res, 'tester not added?'
+
+ # # she needs to do them one by one
+ # res = get_page(annasauthzgroup_edit_url, 200, 'annafan',
+ # 'tester',
+ # 'tester not in edit form')
+ # res.forms['group-edit']['AuthorizationGroupUser--user_name']='russianfan'
+ # res = res.forms['group-edit'].submit('save', status=302, extra_environ={'REMOTE_USER': 'annafan'})
+ # res = res.follow(status=200, extra_environ={'REMOTE_USER': 'annafan'})
+
+ # # and finally adds herself
+ # res = self.app.get(annasauthzgroup_edit_url, status=200, extra_environ={'REMOTE_USER': 'annafan'})
+ # assert 'russianfan' in res, 'russianfan not added?'
+ # res.forms['group-edit']['AuthorizationGroupUser--user_name']='annafan'
+ # res = res.forms['group-edit'].submit('save', status=302, extra_environ={'REMOTE_USER': 'annafan'})
+ # res = res.follow(status=200, extra_environ={'REMOTE_USER': 'annafan'})
+ # assert 'annafan' in res, 'annafan not added?'
+
+ # # finally let's check that annafan can create a completely new authzgroup
+ # new_authzgroup_url = url_for(controller='/authorization_group', action='new')
+ # res = get_page(new_authzgroup_url, 200,'annafan',
+ # 'New Authorization Group',
+ # "wrong page?")
+ # gef = res.forms['group-edit']
+ # gef['AuthorizationGroup--name']="newgroup"
+ # gef['AuthorizationGroupUser--user_name'] = "russianfan"
+ # res = gef.submit('save', status=302, extra_environ={'REMOTE_USER': 'annafan'})
+ # #post/redirect/get
+ # res = res.follow(status=200, extra_environ={'REMOTE_USER': 'annafan'})
+
+ # assert 'newgroup' in res, "should have redirected to the newgroup page"
+ # assert 'russianfan' in res, "no russianfan"
+ # assert 'There are 1 users in this authorization group' in res, "missing text"
+
diff --git a/ckan/tests/functional/test_edit_authz.py b/ckan/tests/functional/test_edit_authz.py
index 4573fbd..941332d 100644
--- a/ckan/tests/functional/test_edit_authz.py
+++ b/ckan/tests/functional/test_edit_authz.py
@@ -77,7 +77,6 @@ def teardown_class(self):
model.repo.rebuild_db()
def test_access_to_authz(self):
- raise SkipTest()
#for each of the three authz pages, check that the access permissions work correctly
for (c,i) in [('package', self.pkg),('group', self.group),('authorization_group', self.authzgroup)]:
offset = url_for(controller=c, action='authz', id=i)
@@ -119,7 +118,8 @@ def authzgroup_roles(self):
# check that the authz page for each object contains certain key strings
def test_2_read_ok(self):
for (c,i,m) in [('package', self.pkg, self.package_roles),\
- ('group', self.group, self.group_roles)]:
+ ('group', self.group, self.group_roles),\
+ ('authorization_group', self.authzgroup, self.authzgroup_roles)]:
offset = url_for(controller=c, action='authz', id=i)
res = self.app.get(offset, extra_environ={'REMOTE_USER': self.admin})
assert i in res, res
@@ -162,7 +162,8 @@ def change_roles(self, user):
# loop variables here are the controller string, the name of the object we're changing, and three functions,
# the first fn gets the roles which we'd like to change, and the other two get the roles which we'd like to stay the same.
for (c,i,var,const1,const2) in [('package', self.pkg, self.package_roles, self.group_roles, self.authzgroup_roles),\
- ('group', self.group, self.group_roles, self.package_roles, self.authzgroup_roles)]:
+ ('group', self.group, self.group_roles, self.package_roles, self.authzgroup_roles),\
+ ('authorization_group', self.authzgroup, self.authzgroup_roles, self.package_roles, self.group_roles)]:
# load authz page
offset = url_for(controller=c, action='authz', id=i)
@@ -231,7 +232,8 @@ def delete_role_as(self,user):
# loop variables here are the controller string, the name of the object we're changing, and three functions,
# the first fn gets the roles which we'd like to change, and the other two get the roles which we'd like to stay the same.
for (c,i,var,const1,const2) in [('package', self.pkg, self.package_roles, self.group_roles, self.authzgroup_roles),\
- ('group', self.group, self.group_roles, self.package_roles, self.authzgroup_roles)]:
+ ('group', self.group, self.group_roles, self.package_roles, self.authzgroup_roles),\
+ ('authorization_group', self.authzgroup, self.authzgroup_roles, self.package_roles, self.group_roles)]:
# get the authz page, check that visitor's in there
# remove visitor's role on the package
@@ -338,7 +340,8 @@ def add_change_delete_authzgroup_as(self, user):
('logged_in', 'editor')]
for (c,i,var,const1,const2) in [('package', self.pkg, self.package_roles, self.group_roles, self.authzgroup_roles),\
- ('group', self.group, self.group_roles, self.package_roles, self.authzgroup_roles)]:
+ ('group', self.group, self.group_roles, self.package_roles, self.authzgroup_roles),\
+ ('authorization_group', self.authzgroup, self.authzgroup_roles, self.package_roles, self.group_roles)]:
# get the authz page, check that it contains the object name
offset = url_for(controller=c, action='authz', id=i)
@@ -412,9 +415,7 @@ def add_change_delete_authzgroup_as(self, user):
def test_5_admin_changes_adds_deletes_authzgroup(self):
- raise SkipTest()
self.add_change_delete_authzgroup_as(self.admin)
def test_5_sysadmin_changes_adds_deletes_authzgroup(self):
- raise SkipTest()
self.add_change_delete_authzgroup_as(self.sysadmin)
diff --git a/ckan/tests/functional/test_package_edit_authz.py b/ckan/tests/functional/test_package_edit_authz.py
index e308643..8f80a27 100644
--- a/ckan/tests/functional/test_package_edit_authz.py
+++ b/ckan/tests/functional/test_package_edit_authz.py
@@ -14,7 +14,7 @@ def setup_class(self):
# two packages test6 and test6a, m-a is admin on both
model.repo.init_db()
model.repo.new_revision()
-
+
self.sysadmin = 'madeup-sysadmin'
sysadmin_user = model.User(name=unicode(self.sysadmin))
self.admin = 'madeup-administrator'
@@ -51,7 +51,7 @@ def test_0_nonadmin_cannot_edit_authz(self):
res = self.app.get(offset, status=[302, 401])
res = res.follow()
assert res.request.url.startswith('/user/login')
-
+
def test_1_admin_has_access(self):
offset = url_for(controller='package', action='authz', id=self.pkgname)
res = self.app.get(offset, extra_environ={'REMOTE_USER':
@@ -61,7 +61,7 @@ def test_1_sysadmin_has_access(self):
offset = url_for(controller='package', action='authz', id=self.pkgname)
res = self.app.get(offset, extra_environ={'REMOTE_USER':
self.sysadmin})
-
+
def test_2_read_ok(self):
offset = url_for(controller='package', action='authz', id=self.pkgname)
res = self.app.get(offset, extra_environ={'REMOTE_USER':
@@ -215,7 +215,7 @@ def delete_role_as(self,user):
check_and_set_checkbox(form, u'visitor', u'reader', True, False)
check_and_set_checkbox(form, u'visitor', u'editor', False, True)
res = form.submit('save', extra_environ={'REMOTE_USER': user})
-
+
# check that the page contains strings for everyone
assert 'visitor' in res
assert 'madeup-administrator' in res
@@ -235,3 +235,79 @@ def test_4_sysadmin_deletes_role(self):
self.delete_role_as(self.sysadmin)
+ def test_5_add_change_delete_authzgroup(self):
+ user=self.admin
+
+ # get the authz page, check that authzgroup isn't in there
+ offset = url_for(controller='package', action='authz', id=self.pkgname)
+ res = self.app.get(offset, extra_environ={'REMOTE_USER':user})
+ assert self.pkgname in res
+
+ # check the state of the database
+ self.assert_package_roles_to_be([
+ ('madeup-administrator', 'admin'),
+ ('visitor', 'editor'),
+ ('logged_in', 'editor')])
+
+ # and that corresponding user strings are in the authz page
+ assert 'visitor' in res
+ assert 'madeup-administrator' in res
+ assert 'logged_in' in res
+ assert 'madeup-authzgroup' not in res
+
+ # add madeup-authzgroup as an admin
+ form = res.forms['authzgroup_addform']
+ form.fields['new_user_name'][0].value='madeup-authzgroup'
+ checkbox = [x for x in form.fields['admin'] \
+ if x.__class__.__name__ == 'Checkbox'][0]
+ # check the checkbox is currently unticked
+ assert checkbox.checked == False
+ # tick it and submit
+ checkbox.checked=True
+ res = form.submit('authz_add', extra_environ={'REMOTE_USER':user})
+ assert "User role(s) added" in res, "don't see flash message"
+
+ # examine the new page for user names/authzgroup names
+ assert 'visitor' in res
+ assert 'madeup-administrator' in res
+ assert 'logged_in' in res
+ assert 'madeup-authzgroup' in res
+
+ # and ensure that the database has changed as expected
+ self.assert_package_roles_to_be([
+ ('madeup-authzgroup', 'admin'),
+ ('madeup-administrator', 'admin'),
+ ('visitor', 'editor'),
+ ('logged_in', 'editor')])
+
+ # check that the checkbox states are what we think they should be
+ # and change madeup-authzgroup from admin to editor
+ form = res.forms['authzgroup_form']
+ check_and_set_checkbox(form, u'madeup-authzgroup', u'editor', False, True)
+ check_and_set_checkbox(form, u'madeup-authzgroup', u'admin', True, False)
+ res = form.submit('authz_save', extra_environ={'REMOTE_USER': user})
+
+ #check database has changed.
+ self.assert_package_roles_to_be([
+ ('madeup-authzgroup', 'editor'),
+ ('madeup-administrator', 'admin'),
+ ('visitor', 'editor'),
+ ('logged_in', 'editor')])
+
+ # now remove madeup-authzgroup entirely
+ form = res.forms['authzgroup_form']
+ check_and_set_checkbox(form, u'madeup-authzgroup', u'editor', True, False)
+ check_and_set_checkbox(form, u'madeup-authzgroup', u'admin', False, False)
+ res = form.submit('authz_save', extra_environ={'REMOTE_USER': user})
+
+ #check database is back to normal
+ self.assert_package_roles_to_be([
+ ('madeup-administrator', 'admin'),
+ ('visitor', 'editor'),
+ ('logged_in', 'editor')])
+
+ # and that page contains only the expected strings
+ assert 'visitor' in res
+ assert 'madeup-administrator' in res
+ assert 'logged_in' in res
+ assert 'madeup-authzgroup' not in res
================================================================
Commit: 3c252f7420114c619fbfbeac5a2f1f11a30e59c7
https://github.com/okfn/ckan/commit/3c252f7420114c619fbfbeac5a2f1f11a30e59c7
Author: amercader <amercadero at gmail.com>
Date: 2012-05-01 (Tue, 01 May 2012)
Changed paths:
M ckan/templates/authorization_group/authz.html
M ckan/templates/authorization_group/edit.html
M ckan/templates/authorization_group/index.html
M ckan/templates/authorization_group/new.html
M ckan/templates/authorization_group/read.html
M ckan/templates/layout_base.html
Log Message:
-----------
[2366] Removed Auth groups link from footer and added deprecation notice
diff --git a/ckan/templates/authorization_group/authz.html b/ckan/templates/authorization_group/authz.html
index 12643d2..1c5378c 100644
--- a/ckan/templates/authorization_group/authz.html
+++ b/ckan/templates/authorization_group/authz.html
@@ -6,6 +6,12 @@
<py:def function="page_heading">Authorization: ${c.authorization_group_name}</py:def>
<div py:match="content">
+
+ <div class="alert alert-error">
+ Warning: Authorization groups are deprecated and no longer supported. They will be removed
+ completely on the next CKAN release.
+ </div>
+
<h3>Update Existing Roles</h3>
<form id="theform" method="POST">
diff --git a/ckan/templates/authorization_group/edit.html b/ckan/templates/authorization_group/edit.html
index ade0f54..a404ce2 100644
--- a/ckan/templates/authorization_group/edit.html
+++ b/ckan/templates/authorization_group/edit.html
@@ -6,6 +6,12 @@
<py:def function="page_heading">Edit: ${c.authorization_group.name if c.authorization_group else ''}</py:def>
<div py:match="content">
+
+ <div class="alert alert-error">
+ Warning: Authorization groups are deprecated and no longer supported. They will be removed
+ completely on the next CKAN release.
+ </div>
+
${Markup(c.form)}
</div>
diff --git a/ckan/templates/authorization_group/index.html b/ckan/templates/authorization_group/index.html
index a135ac9..281f3d1 100644
--- a/ckan/templates/authorization_group/index.html
+++ b/ckan/templates/authorization_group/index.html
@@ -7,6 +7,12 @@
<py:def function="page_heading">Authorization Groups</py:def>
<div py:match="content">
+
+ <div class="alert alert-error">
+ Warning: Authorization groups are deprecated and no longer supported. They will be removed
+ completely on the next CKAN release.
+ </div>
+
<p i18n:msg="item_count">There are <strong>${c.page.item_count}</strong> authorization groups.</p>
${c.page.pager()}
diff --git a/ckan/templates/authorization_group/new.html b/ckan/templates/authorization_group/new.html
index 0dbcc2a..1eb973b 100644
--- a/ckan/templates/authorization_group/new.html
+++ b/ckan/templates/authorization_group/new.html
@@ -6,6 +6,12 @@
<py:def function="page_heading">New Authorization Group</py:def>
<div py:match="content">
+
+ <div class="alert alert-error">
+ Warning: Authorization groups are deprecated and no longer supported. They will be removed
+ completely on the next CKAN release.
+ </div>
+
${Markup(c.form)}
</div>
diff --git a/ckan/templates/authorization_group/read.html b/ckan/templates/authorization_group/read.html
index 01ecec0..3c2c7ba 100644
--- a/ckan/templates/authorization_group/read.html
+++ b/ckan/templates/authorization_group/read.html
@@ -7,6 +7,12 @@
<py:def function="page_heading">${c.authorization_group.name}</py:def>
<div py:match="content">
+
+ <div class="alert alert-error">
+ Warning: Authorization groups are deprecated and no longer supported. They will be removed
+ completely on the next CKAN release.
+ </div>
+
<h3>Members</h3>
<p i18n:msg="item_count">There are ${c.page.item_count} users in this authorization group.</p>
${c.page.pager()}
diff --git a/ckan/templates/layout_base.html b/ckan/templates/layout_base.html
index 8913814..f2d51dd 100644
--- a/ckan/templates/layout_base.html
+++ b/ckan/templates/layout_base.html
@@ -177,11 +177,6 @@ <h3 class="widget-title">Sections</h3>
</a>
</li>
<li>
- <a href="${h.url(controller='authorization_group', action='index')}">
- Authorization Groups
- </a>
- </li>
- <li>
<a href="${h.url_for('ckanadmin_index')}">
Site Admin
</a>
================================================================
Compare: https://github.com/okfn/ckan/compare/cbb8378...3c252f7
More information about the ckan-changes
mailing list