Skip to content

Commit

Permalink
Revert "Remove authgroups UI and tests (that rely on that UI) and the…
Browse files Browse the repository at this point in the history
… controller)"

This reverts commit cbb8378.

Reverting last commit to implement just a subset of the removal for
release 1.7
  • Loading branch information
amercader committed May 1, 2012
1 parent cbb8378 commit bdc5ca3
Show file tree
Hide file tree
Showing 21 changed files with 1,103 additions and 22 deletions.
11 changes: 11 additions & 0 deletions ckan/config/routing.py
Expand Up @@ -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}')
Expand Down
201 changes: 201 additions & 0 deletions 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()
22 changes: 18 additions & 4 deletions ckan/forms/authz.py
Expand Up @@ -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)
Expand All @@ -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()
Expand All @@ -68,7 +81,8 @@ def authz_fieldset_builder(role_class):
],
include=[fs.username,
fs.authzgroupname,
fs.role]
fs.role,
fs.delete],
)
return fs

Expand Down Expand Up @@ -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)
Expand Down
15 changes: 15 additions & 0 deletions ckan/lib/helpers.py
Expand Up @@ -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)
Expand Down Expand Up @@ -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',
Expand Down
50 changes: 50 additions & 0 deletions ckan/templates/_util.html
Expand Up @@ -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')}"
Expand Down Expand Up @@ -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>
Expand Down
19 changes: 19 additions & 0 deletions ckan/templates/admin/authz.html
Expand Up @@ -26,6 +26,25 @@ <h3>Add Roles for Any User</h3>

<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" />
Expand Down
Empty file.

0 comments on commit bdc5ca3

Please sign in to comment.