update user/role management (now it works)
This commit is contained in:
parent
e95a23ead8
commit
9b2589ca12
13 changed files with 225 additions and 219 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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()}
|
||||
|
|
|
@ -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()}
|
|
@ -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()}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
<%inherit file="/base.mako" />
|
||||
${parent.body()}
|
18
edbob/pyramid/templates/roles/crud.mako
Normal file
18
edbob/pyramid/templates/roles/crud.mako
Normal 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()}
|
|
@ -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()}
|
||||
|
|
|
@ -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()}
|
|
@ -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 '[ ]') + '</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')
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue