Add ability to download roles / permissions matrix as Excel file

This commit is contained in:
Lance Edgar 2020-06-22 16:00:33 -05:00
parent 6463df7224
commit e5f0831369
2 changed files with 89 additions and 0 deletions

View file

@ -0,0 +1,12 @@
## -*- coding: utf-8; -*-
<%inherit file="/principal/index.mako" />
<%def name="context_menu_items()">
${parent.context_menu_items()}
% if master.has_perm('download_permissions_matrix'):
<li>${h.link_to("Download Permissions Matrix", url('roles.download_permissions_matrix'))}</li>
% endif
</%def>
${parent.body()}

View file

@ -26,12 +26,16 @@ Role Views
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
import os
import six import six
from sqlalchemy import orm from sqlalchemy import orm
from openpyxl.styles import Font, PatternFill
from rattail.db import model from rattail.db import model
from rattail.db.auth import (has_permission, grant_permission, revoke_permission, from rattail.db.auth import (has_permission, grant_permission, revoke_permission,
administrator_role, guest_role, authenticated_role) administrator_role, guest_role, authenticated_role)
from rattail.excel import ExcelWriter
import colander import colander
from deform import widget as dfwidget from deform import widget as dfwidget
@ -278,6 +282,69 @@ class RolesView(PrincipalMasterView):
roles.append(role) roles.append(role)
return roles return roles
def download_permissions_matrix(self):
"""
View which renders the complete role / permissions matrix data into an
Excel spreadsheet, and returns that file.
"""
roles = self.Session.query(model.Role)\
.order_by(model.Role.name)\
.all()
permissions = self.get_available_permissions()
# prep the excel writer
path = os.path.join(self.rattail_config.workdir(),
'permissions-matrix.xlsx')
writer = ExcelWriter(path, None)
sheet = writer.sheet
# write header
sheet.cell(row=1, column=1, value="")
for i, role in enumerate(roles, 2):
sheet.cell(row=1, column=i, value=role.name)
# font and fill pattern for permission group rows
bold = Font(bold=True)
group_fill = PatternFill(patternType='solid',
fgColor='d9d9d9',
bgColor='d9d9d9')
# now we'll write the rows
writing_row = 2
for groupkey in sorted(permissions, key=lambda k: permissions[k]['label'].lower()):
group = permissions[groupkey]
# group label is bold, with fill pattern
cell = sheet.cell(row=writing_row, column=1, value=group['label'])
cell.font = bold
cell.fill = group_fill
# continue fill pattern for rest of group row
for col, role in enumerate(roles, 2):
cell = sheet.cell(row=writing_row, column=col)
cell.fill = group_fill
# okay, that row is done
writing_row += 1
# now we list each perm in the group
perms = group['perms']
for key in sorted(perms, key=lambda p: perms[p]['label'].lower()):
sheet.cell(row=writing_row, column=1, value=perms[key]['label'])
# and show an 'X' for any role which has this perm
for col, role in enumerate(roles, 2):
if has_permission(self.Session(), role, key, include_guest=False):
sheet.cell(row=writing_row, column=col, value="X")
writing_row += 1
writer.auto_resize()
writer.auto_freeze()
writer.save()
return self.file_response(path)
@classmethod @classmethod
def defaults(cls, config): def defaults(cls, config):
cls._principal_defaults(config) cls._principal_defaults(config)
@ -286,6 +353,8 @@ class RolesView(PrincipalMasterView):
@classmethod @classmethod
def _role_defaults(cls, config): def _role_defaults(cls, config):
route_prefix = cls.get_route_prefix()
url_prefix = cls.get_url_prefix()
permission_prefix = cls.get_permission_prefix() permission_prefix = cls.get_permission_prefix()
# extra permissions for editing built-in roles etc. # extra permissions for editing built-in roles etc.
@ -296,6 +365,14 @@ class RolesView(PrincipalMasterView):
config.add_tailbone_permission(permission_prefix, '{}.edit_my'.format(permission_prefix), config.add_tailbone_permission(permission_prefix, '{}.edit_my'.format(permission_prefix),
"Edit Role(s) to which current user belongs") "Edit Role(s) to which current user belongs")
# download permissions matrix
config.add_tailbone_permission(permission_prefix, '{}.download_permissions_matrix'.format(permission_prefix),
"Download complete Role/Permissions matrix")
config.add_route('{}.download_permissions_matrix'.format(route_prefix), '{}/permissions-matrix'.format(url_prefix),
request_method='GET')
config.add_view(cls, attr='download_permissions_matrix', route_name='{}.download_permissions_matrix'.format(route_prefix),
permission='{}.download_permissions_matrix'.format(permission_prefix))
class PermissionsWidget(dfwidget.Widget): class PermissionsWidget(dfwidget.Widget):
template = 'permissions' template = 'permissions'