160 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			160 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)
 |