tailbone/tailbone/views/roles.py
2017-12-06 12:40:27 -06:00

161 lines
5.7 KiB
Python

# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2017 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Role Views
"""
from __future__ import unicode_literals, absolute_import
import six
from sqlalchemy import orm
from rattail.db import model
from rattail.db.auth import has_permission, administrator_role, guest_role, authenticated_role
import colander
from deform import widget as dfwidget
from tailbone import grids
from tailbone.db import Session
from tailbone.views.principal import PrincipalMasterView, PermissionsRenderer
class RolesView(PrincipalMasterView):
"""
Master view for the Role model.
"""
model_class = model.Role
has_versions = True
grid_columns = [
'name',
'session_timeout',
]
form_fields = [
'name',
'session_timeout',
'permissions',
]
def configure_grid(self, g):
super(RolesView, self).configure_grid(g)
g.filters['name'].default_active = True
g.filters['name'].default_verb = 'contains'
g.set_sort_defaults('name')
g.set_link('name')
def configure_form(self, f):
super(RolesView, self).configure_form(f)
role = f.model_instance
# permissions
self.tailbone_permissions = self.request.registry.settings.get('tailbone_permissions', {})
f.set_renderer('permissions', PermissionsRenderer(permissions=self.tailbone_permissions))
f.set_node('permissions', colander.Set())
f.set_widget('permissions', PermissionsWidget(permissions=self.tailbone_permissions))
if self.editing:
granted = []
for groupkey in self.tailbone_permissions:
for key in self.tailbone_permissions[groupkey]['perms']:
if has_permission(self.Session(), role, key, include_guest=False, include_authenticated=False):
granted.append(key)
f.set_default('permissions', granted)
# session_timeout
f.set_renderer('session_timeout', self.render_session_timeout)
if self.editing and role is guest_role(self.Session()):
f.set_readonly('session_timeout')
def render_session_timeout(self, role, field):
if role is guest_role(self.Session()):
return "(not applicable)"
if role.session_timeout is None:
return ""
return six.text_type(role.session_timeout)
def objectify(self, form, data):
role = super(RolesView, self).objectify(form, data)
role.permissions = data['permissions']
return role
def template_kwargs_view(self, **kwargs):
role = kwargs['instance']
if role.users:
users = sorted(role.users, key=lambda u: u.username)
actions = [
grids.GridAction('view', icon='zoomin',
url=lambda r, i: self.request.route_url('users.view', uuid=r.uuid))
]
kwargs['users'] = grids.Grid(None, users, ['username'], request=self.request, model_class=model.User,
main_actions=actions)
else:
kwargs['users'] = None
kwargs['guest_role'] = guest_role(self.Session())
kwargs['authenticated_role'] = authenticated_role(self.Session())
return kwargs
def before_delete(self, role):
admin = administrator_role(self.Session())
guest = guest_role(self.Session())
authenticated = authenticated_role(self.Session())
if role in (admin, guest, authenticated):
self.request.session.flash("You may not delete the {} role.".format(role.name), 'error')
return self.redirect(self.request.get_referrer(default=self.request.route_url('roles')))
def find_principals_with_permission(self, session, permission):
# TODO: this should search Permission table instead, and work backward to Role?
all_roles = session.query(model.Role)\
.order_by(model.Role.name)\
.options(orm.joinedload(model.Role._permissions))
roles = []
for role in all_roles:
if has_permission(session, role, permission):
roles.append(role)
return roles
class PermissionsWidget(dfwidget.Widget):
template = 'permissions'
permissions = None
true_val = 'true'
def deserialize(self, field, pstruct):
return [key for key, val in pstruct.items()
if val == self.true_val]
def get_checked_value(self, cstruct, value):
if cstruct is colander.null:
return False
return value in cstruct
def serialize(self, field, cstruct, **kw):
kw.setdefault('permissions', self.permissions)
template = self.template
values = self.get_template_values(field, cstruct, kw)
return field.renderer(template, **values)
def includeme(config):
RolesView.defaults(config)