update user/role management (now it works)

This commit is contained in:
Lance Edgar 2012-11-12 07:41:03 -08:00
parent e95a23ead8
commit 9b2589ca12
13 changed files with 225 additions and 219 deletions

View file

@ -89,7 +89,9 @@ class Role(Base):
creator=lambda x: Permission(permission=x),
getset_factory=getset_factory)
_users = relationship(UserRole, backref='role')
_users = relationship(
UserRole, backref='role',
cascade='save-update, merge, delete, delete-orphan')
users = association_proxy('_users', 'user',
creator=lambda x: UserRole(user=x),
getset_factory=getset_factory)

View file

@ -54,6 +54,9 @@ class AlchemyGrid(Grid):
self._formalchemy_grid.prettify = prettify
self.noclick_fields = []
def __delattr__(self, attr):
delattr(self._formalchemy_grid, attr)
def __getattr__(self, attr):
return getattr(self._formalchemy_grid, attr)

View file

@ -1,17 +1,33 @@
/******************************
* perms.css
* Permission Lists
******************************/
div.field-couple.permissions div.field p.group {
div.field-wrapper.permissions div.field div.group {
margin-bottom: 10px;
}
div.field-wrapper.permissions div.field div.group p {
font-weight: bold;
}
div.field-couple.permissions div.field label {
div.field-wrapper.permissions div.field label {
float: none;
font-weight: normal;
}
div.field-couple.permissions div.field label input {
div.field-wrapper.permissions div.field label input {
margin-left: 15px;
margin-right: 10px;
}
div.field-wrapper.permissions div.field div.group p.perm {
font-weight: normal;
margin-left: 15px;
}
div.field-wrapper.permissions div.field div.group p.perm span {
font-family: monospace;
/* font-weight: bold; */
margin-right: 10px;
}

View file

@ -79,6 +79,13 @@ def context_found(event):
return has_permission(request.user, perm, session=Session())
request.has_perm = has_perm
def has_any_perm(perms):
for perm in perms:
if has_permission(request.user, perm, session=Session()):
return True
return False
request.has_any_perm = has_any_perm
def get_referrer(default=None):
if request.params.get('referrer'):
return request.params['referrer']

View file

@ -1,3 +1,18 @@
<%inherit file="/edbob/crud.mako" />
<%inherit file="/form.mako" />
<%def name="title()">${"New "+form.pretty_name if form.creating else form.pretty_name+' : '+h.literal(str(form.fieldset.model))}</%def>
<%def name="head_tags()">
${parent.head_tags()}
<script type="text/javascript">
$(function() {
$('a.delete').click(function() {
if (! confirm("Do you really wish to delete this object?")) {
return false;
}
});
});
</script>
</%def>
${parent.body()}

View file

@ -1,5 +0,0 @@
<%inherit file="/form.mako" />
<%def name="title()">${"New "+form.pretty_name if form.creating else form.pretty_name+' : '+h.literal(str(form.fieldset.model))}</%def>
${parent.body()}

View file

@ -1,7 +1,7 @@
<div class="fieldset">
% for field in fieldset.render_fields.itervalues():
% if field.requires_label:
<div class="field-wrapper">
<div class="field-wrapper ${field.name}">
${field.label_tag()|n}
<div class="field">
${field.render_readonly()}

View file

@ -1,2 +0,0 @@
<%inherit file="/base.mako" />
${parent.body()}

View file

@ -0,0 +1,18 @@
<%inherit file="edbob.pyramid:templates/crud.mako" />
<%def name="head_tags()">
${parent.head_tags()}
${h.stylesheet_link(request.static_url('edbob.pyramid:static/css/perms.css'))}
</%def>
<%def name="context_menu_items()">
<li>${h.link_to("Back to Roles", url('roles'))}</li>
% if form.readonly:
<li>${h.link_to("Edit this Role", url('role.update', uuid=form.fieldset.model.uuid))}</li>
% elif form.updating:
<li>${h.link_to("View this Role", url('role.read', uuid=form.fieldset.model.uuid))}</li>
% endif
<li>${h.link_to("Delete this Role", url('role.delete', uuid=form.fieldset.model.uuid), class_='delete')}</li>
</%def>
${parent.body()}

View file

@ -1,10 +1,11 @@
<%inherit file="/roles/base.mako" />
<%inherit file="/index.mako" />
<%inherit file="/grid.mako" />
<%def name="title()">Roles</%def>
<%def name="context_menu_items()">
<li>${h.link_to("Create a new Role", url('role.new'))}</li>
% if request.has_perm('roles.create'):
<li>${h.link_to("Create a new Role", url('role.create'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -1,15 +0,0 @@
<%inherit file="/roles/base.mako" />
<%inherit file="/crud.mako" />
<%def name="crud_name()">Role</%def>
<%def name="head_tags()">
${parent.head_tags()}
${h.stylesheet_link(request.static_url('edbob.pyramid:static/css/perms.css'))}
</%def>
<%def name="menu()">
<p>${h.link_to("Back to Roles", url('roles.list'))}</p>
</%def>
${parent.body()}

View file

@ -26,75 +26,83 @@
``edbob.pyramid.views.roles`` -- Role Views
"""
import transaction
from pyramid.httpexceptions import HTTPFound
from formalchemy import Field, FieldRenderer
from webhelpers.html import literal
from webhelpers.html.tags import checkbox, hidden
import formalchemy
from webhelpers.html import tags
from webhelpers.html.builder import HTML
import edbob
from edbob.db.auth import administrator_role, has_permission
from edbob.pyramid import filters
from edbob.pyramid import forms
from edbob.pyramid import grids
from edbob.db import auth
from edbob.pyramid import Session
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
def filter_map():
return filters.get_filter_map(
edbob.Role,
ilike=['name'])
default_permissions = [
def search_config(request, fmap):
return filters.get_search_config(
'roles.list', request, fmap,
include_filter_name=True,
filter_type_name='lk')
("People", [
('people.list', "List People"),
('people.read', "View Person"),
('people.create', "Create Person"),
('people.update', "Edit Person"),
('people.delete', "Delete Person"),
]),
def search_form(config):
return filters.get_search_form(config)
("Roles", [
('roles.list', "List Roles"),
('roles.read', "View Role"),
('roles.create', "Create Role"),
('roles.update', "Edit Role"),
('roles.delete', "Delete Role"),
]),
def grid_config(request, search, fmap):
return grids.get_grid_config(
'roles.list', request, search,
filter_map=fmap, sort='name')
def sort_map():
return grids.get_sort_map(edbob.Role, ['name'])
def query(config):
smap = sort_map()
q = Session.query(edbob.Role)
q = filters.filter_query(q, config)
q = grids.sort_query(q, config, smap)
return q
("Users", [
('users.list', "List Users"),
('users.read', "View User"),
('users.create', "Create User"),
('users.update', "Edit User"),
('users.delete', "Delete User"),
]),
]
def roles(request):
class RolesGrid(SearchableAlchemyGridView):
fmap = filter_map()
config = search_config(request, fmap)
search = search_form(config)
config = grid_config(request, search, fmap)
roles = grids.get_pager(query, config)
mapped_class = edbob.Role
config_prefix = 'roles'
sort = 'name'
g = forms.AlchemyGrid(
edbob.Role, roles, config,
gridurl=request.route_url('roles.list'),
objurl='role.edit')
def filter_map(self):
return self.make_filter_map(ilike=['name'])
g.configure(
include=[
g.name,
],
readonly=True)
def filter_config(self):
return self.make_filter_config(
include_filter_name=True,
filter_type_name='lk')
grid = g.render(class_='clickable roles')
return grids.render_grid(request, grid, search)
def sort_map(self):
return self.make_sort_map('name')
def grid(self):
g = self.make_grid()
g.configure(
include=[
g.name,
],
readonly=True)
if self.request.has_perm('roles.read'):
g.clickable = True
g.click_route_name = 'role.read'
if self.request.has_perm('roles.update'):
g.editable = True
g.edit_route_name = 'role.update'
if self.request.has_perm('roles.delete'):
g.deletable = True
g.delete_route_name = 'role.delete'
return g
class PermissionsField(Field):
class PermissionsField(formalchemy.Field):
def sync(self):
if not self.is_readonly():
@ -102,154 +110,108 @@ class PermissionsField(Field):
role.permissions = self.renderer.deserialize()
class PermissionsFieldRenderer(FieldRenderer):
def PermissionsFieldRenderer(permissions, *args, **kwargs):
available_permissions = [
("Batches", [
('batches.list', "List Batches"),
('batches.edit', "Edit Batch"),
('batches.create', "Create Batch"),
]),
("Roles", [
('roles.list', "List Roles"),
('roles.edit', "Edit Role"),
('roles.create', "Create Role"),
]),
]
def deserialize(self):
perms = []
i = len(self.name) + 1
for key in self.params:
if key.startswith(self.name):
perms.append(key[i:])
return perms
def _render(self, readonly=False, **kwargs):
# result = literal('')
# for group_name, group_label, perm_list in self.field.model_value:
# rendered_group_name = literal('<p class="permission-group">' + group_label + '</p>\n')
# if readonly:
# result += literal('<tr><td colspan="2">') + rendered_group_name + literal('</td></tr>')
# else:
# result += rendered_group_name
# result += literal('<div>')
# for perm_name, perm_label, checked in perm_list:
# if readonly:
# result += literal('<tr>'
# + '<td class="permission">' + ('[X]' if checked else '[&nbsp; ]') + '</td>'
# + '<td class="permission-label">' + perm_label + '</td>'
# + '</tr>\n')
# else:
# name = '.'.join((self.name, group_name, perm_name))
# result += check_box(name, label=perm_label, checked=checked)
# if not readonly:
# result += literal('</div>')
# if readonly:
# return literal('<table class="permissions">') + result + literal('</table>')
# return literal('<div class="permissions">') + result + literal('</div>')
role = self.field.model
if role is administrator_role(Session()):
res = literal('<p>This is the administrative role; '
'it has full access to the entire system.</p>')
if not readonly:
res += hidden(self.name, value='') # ugly hack..or good idea?
else:
res = ''
for group, perms in self.available_permissions:
res += literal('<p class="group">%s</p>' % group)
for perm, title in perms:
if readonly:
res += literal('<p>%s</p>' % title)
else:
checked = has_permission(role, perm)
res += checkbox(self.name + '-' + perm,
checked=checked, label=title)
return res
def render(self, **kwargs):
return self._render(**kwargs)
def render_readonly(self, **kwargs):
return self._render(readonly=True, **kwargs)
def role_fieldset(role, request):
fs = forms.make_fieldset(role, url=request.route_url,
url_action=request.current_route_url(),
route_name='roles.list')
perms = permissions
fs.append(PermissionsField('permissions',
renderer=PermissionsFieldRenderer))
class PermissionsFieldRenderer(formalchemy.FieldRenderer):
fs.configure(
include=[
fs.name,
fs.permissions,
])
permissions = perms
if not fs.edit:
del fs.permissions
def deserialize(self):
perms = []
i = len(self.name) + 1
for key in self.params:
if key.startswith(self.name):
perms.append(key[i:])
return perms
return fs
def _render(self, readonly=False, **kwargs):
role = self.field.model
admin = auth.administrator_role(Session())
if role is admin:
html = HTML.tag('p', c="This is the administrative role; "
"it has full access to the entire system.")
if not readonly:
html += tags.hidden(self.name, value='') # ugly hack..or good idea?
else:
html = ''
for group, perms in self.permissions:
inner = HTML.tag('p', c=group)
for perm, title in perms:
checked = auth.has_permission(role, perm, Session())
if readonly:
span = HTML.tag('span', c="[X]" if checked else "[ ]")
inner += HTML.tag('p', class_='perm', c=span + ' ' + title)
else:
checked = auth.has_permission(role, perm, Session())
inner += tags.checkbox(self.name + '-' + perm,
checked=checked, label=title)
html += HTML.tag('div', class_='group', c=inner)
return html
def render(self, **kwargs):
return self._render(**kwargs)
def render_readonly(self, **kwargs):
return self._render(readonly=True, **kwargs)
return PermissionsFieldRenderer
def new_role(request):
class RoleCrud(CrudView):
fs = role_fieldset(edbob.Role, request)
if request.POST:
fs.rebind(data=request.params)
if fs.validate():
mapped_class = edbob.Role
home_route = 'roles'
permissions = default_permissions
with transaction.manager:
fs.sync()
fs.model = Session.merge(fs.model)
request.session.flash("%s \"%s\" has been %s." % (
fs.crud_title, fs.get_display_text(),
'updated' if fs.edit else 'created'))
home = request.route_url('roles.list')
def fieldset(self, role):
fs = self.make_fieldset(role)
fs.append(PermissionsField(
'permissions',
renderer=PermissionsFieldRenderer(self.permissions)))
fs.configure(
include=[
fs.name,
fs.permissions,
])
return fs
return HTTPFound(location=home)
return {'fieldset': fs, 'crud': True}
def edit_role(request):
uuid = request.matchdict['uuid']
role = Session.query(edbob.Role).get(uuid) if uuid else None
assert role
fs = role_fieldset(role, request)
if request.POST:
fs.rebind(data=request.params)
if fs.validate():
with transaction.manager:
Session.add(fs.model)
fs.sync()
request.session.flash("%s \"%s\" has been %s." % (
fs.crud_title, fs.get_display_text(),
'updated' if fs.edit else 'created'))
home = request.route_url('roles.list')
return HTTPFound(location=home)
return {'fieldset': fs, 'crud': True}
def pre_delete(self, model):
admin = auth.administrator_role(Session())
guest = auth.guest_role(Session())
if model in (admin, guest):
self.request.session.flash("You may not delete the %s role." % str(model), 'error')
return HTTPFound(location=self.request.get_referrer())
def includeme(config):
config.add_route('roles', '/roles')
config.add_view(RolesGrid, route_name='roles',
renderer='/roles/index.mako',
permission='roles.list')
config.add_route('roles.list', '/roles')
config.add_view(roles, route_name='roles.list', renderer='/roles/index.mako',
permission='roles.list', http_cache=0)
settings = config.get_settings()
perms = settings.get('edbob.permissions')
if perms:
RoleCrud.permissions = perms
config.add_route('role.new', '/roles/new')
config.add_view(new_role, route_name='role.new', renderer='/roles/role.mako',
permission='roles.create', http_cache=0)
config.add_route('role.create', '/roles/new')
config.add_view(RoleCrud, attr='create', route_name='role.create',
renderer='/roles/crud.mako',
permission='roles.create')
config.add_route('role.edit', '/roles/{uuid}/edit')
config.add_view(edit_role, route_name='role.edit', renderer='/roles/role.mako',
permission='roles.edit', http_cache=0)
config.add_route('role.read', '/roles/{uuid}')
config.add_view(RoleCrud, attr='read', route_name='role.read',
renderer='/roles/crud.mako',
permission='roles.read')
config.add_route('role.update', '/roles/{uuid}/edit')
config.add_view(RoleCrud, attr='update', route_name='role.update',
renderer='/roles/crud.mako',
permission='roles.update')
config.add_route('role.delete', '/roles/{uuid}/delete')
config.add_view(RoleCrud, attr='delete', route_name='role.delete',
permission='roles.delete')

View file

@ -95,7 +95,7 @@ class _RolesFieldRenderer(SelectFieldRenderer):
role = roles.get(uuid)
res += literal('<li>%s</li>' % (
tags.link_to(role.name,
self.request.route_url('role.edit', uuid=role.uuid))))
self.request.route_url('role.read', uuid=role.uuid))))
res += literal('</ul>')
return res
@ -206,6 +206,10 @@ class UserCrud(CrudView):
fs.roles,
])
if self.readonly:
del fs.password
del fs.confirm_password
# if fs.edit and user.person:
if isinstance(user, edbob.User) and user.person:
fs.person.set(readonly=True,