diff --git a/tailbone/forms/renderers/__init__.py b/tailbone/forms/renderers/__init__.py index 4ba8e0d3..4ebdfc1b 100644 --- a/tailbone/forms/renderers/__init__.py +++ b/tailbone/forms/renderers/__init__.py @@ -38,7 +38,7 @@ from .files import FileFieldRenderer from .people import (PersonFieldRenderer, PersonFieldLinkRenderer, CustomerFieldRenderer, CustomerFieldLinkRenderer) -from .users import UserFieldRenderer +from .users import UserFieldRenderer, PermissionsFieldRenderer from .employees import EmployeeFieldRenderer diff --git a/tailbone/forms/renderers/users.py b/tailbone/forms/renderers/users.py index ae4cc5a3..a3a92ffa 100644 --- a/tailbone/forms/renderers/users.py +++ b/tailbone/forms/renderers/users.py @@ -26,7 +26,13 @@ User Field Renderers from __future__ import unicode_literals, absolute_import +from rattail.db import model +from rattail.db.auth import has_permission, administrator_role + import formalchemy +from webhelpers.html import HTML, tags + +from tailbone.db import Session class UserFieldRenderer(formalchemy.TextFieldRenderer): @@ -39,3 +45,56 @@ class UserFieldRenderer(formalchemy.TextFieldRenderer): if not user: return '' return user.display_name + + +def PermissionsFieldRenderer(permissions, include_guest=False, include_authenticated=False): + + class PermissionsFieldRenderer(formalchemy.FieldRenderer): + + 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): + principal = self.field.model + if isinstance(principal, model.Role) and principal is administrator_role(Session()): + 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 groupkey in sorted(permissions, key=lambda k: permissions[k]['label'].lower()): + inner = HTML.tag('p', c=permissions[groupkey]['label']) + perms = permissions[groupkey]['perms'] + rendered = False + for key in sorted(perms, key=lambda p: perms[p]['label'].lower()): + checked = has_permission(Session(), principal, key, + include_guest=include_guest, + include_authenticated=include_authenticated) + if checked or not readonly: + label = perms[key]['label'] + if readonly: + span = HTML.tag('span', c="[X]" if checked else "[ ]") + inner += HTML.tag('p', class_='perm', c=span + ' ' + label) + else: + inner += tags.checkbox(self.name + '-' + key, + checked=checked, label=label) + rendered = True + if rendered: + html += HTML.tag('div', class_='group', c=inner) + if not html: + return "(none granted)" + return html + + def render(self, **kwargs): + return self._render(**kwargs) + + def render_readonly(self, **kwargs): + return self._render(readonly=True, **kwargs) + + return PermissionsFieldRenderer diff --git a/tailbone/templates/users/view.mako b/tailbone/templates/users/view.mako index 6dbc4c8a..be6d4800 100644 --- a/tailbone/templates/users/view.mako +++ b/tailbone/templates/users/view.mako @@ -1,6 +1,11 @@ ## -*- coding: utf-8 -*- <%inherit file="/master/view.mako" /> +<%def name="head_tags()"> + ${parent.head_tags()} + ${h.stylesheet_link(request.static_url('tailbone:static/css/perms.css'))} + + <%def name="context_menu_items()"> ${parent.context_menu_items()} % if version_count is not Undefined and request.has_perm('user.versions.view'): diff --git a/tailbone/views/roles.py b/tailbone/views/roles.py index 2217c314..ee666f14 100644 --- a/tailbone/views/roles.py +++ b/tailbone/views/roles.py @@ -32,6 +32,7 @@ from rattail.db.auth import has_permission, administrator_role, guest_role, auth import formalchemy from webhelpers.html import HTML, tags +from tailbone import forms from tailbone.db import Session from tailbone.views import MasterView from tailbone.views.continuum import VersionView, version_defaults @@ -49,60 +50,6 @@ class PermissionsField(formalchemy.Field): role.permissions = self.renderer.deserialize() -def PermissionsFieldRenderer(permissions, *args, **kwargs): - - class PermissionsFieldRenderer(formalchemy.FieldRenderer): - - 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): - role = self.field.model - admin = 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 groupkey in sorted(permissions, key=lambda k: permissions[k]['label'].lower()): - inner = HTML.tag('p', c=permissions[groupkey]['label']) - perms = permissions[groupkey]['perms'] - rendered = False - for key in sorted(perms, key=lambda p: perms[p]['label'].lower()): - checked = has_permission(Session(), role, key, - include_guest=False, - include_authenticated=False) - if checked or not readonly: - label = perms[key]['label'] - if readonly: - span = HTML.tag('span', c="[X]" if checked else "[ ]") - inner += HTML.tag('p', class_='perm', c=span + ' ' + label) - else: - inner += tags.checkbox(self.name + '-' + key, - checked=checked, label=label) - rendered = True - if rendered: - html += HTML.tag('div', class_='group', c=inner) - if not html: - return "(none granted)" - return html - - def render(self, **kwargs): - return self._render(**kwargs) - - def render_readonly(self, **kwargs): - return self._render(readonly=True, **kwargs) - - return PermissionsFieldRenderer - - class RolesView(MasterView): """ Master view for the Role model. @@ -122,7 +69,7 @@ class RolesView(MasterView): def configure_fieldset(self, fs): fs.append(PermissionsField('permissions')) permissions = self.request.registry.settings.get('tailbone_permissions', {}) - fs.permissions.set(renderer=PermissionsFieldRenderer(permissions)) + fs.permissions.set(renderer=forms.renderers.PermissionsFieldRenderer(permissions)) fs.configure( include=[ fs.name, diff --git a/tailbone/views/users.py b/tailbone/views/users.py index 61e979a9..650420a9 100644 --- a/tailbone/views/users.py +++ b/tailbone/views/users.py @@ -35,10 +35,10 @@ import formalchemy from formalchemy.fields import SelectFieldRenderer from webhelpers.html import HTML, tags +from tailbone import forms from tailbone.db import Session from tailbone.views import MasterView from tailbone.views.continuum import VersionView, version_defaults -from tailbone.forms import renderers def unique_username(value, field): @@ -159,7 +159,7 @@ class UsersView(MasterView): def configure_fieldset(self, fs): fs.username.set(validate=unique_username) fs.person.set(options=[]) - fs.person.set(renderer=renderers.PersonFieldLinkRenderer) + fs.person.set(renderer=forms.renderers.PersonFieldLinkRenderer) fs.append(PasswordField('password', label="Set Password")) fs.password.attrs(autocomplete='off') fs.append(formalchemy.Field('confirm_password', renderer=PasswordFieldRenderer)) @@ -177,6 +177,11 @@ class UsersView(MasterView): if self.viewing: del fs.password del fs.confirm_password + permissions = self.request.registry.settings.get('tailbone_permissions', {}) + renderer = forms.renderers.PermissionsFieldRenderer(permissions, + include_guest=True, + include_authenticated=True) + fs.append(formalchemy.Field('permissions', renderer=renderer)) class UserVersionView(VersionView):