guest role; guide section ticking
This commit is contained in:
@@ -6,7 +6,8 @@ from werkzeug.security import generate_password_hash
|
||||
|
||||
from shopdb.extensions import db
|
||||
from shopdb.core.models import (
|
||||
User, Role, Permission, AuditLog, full_permission_catalog)
|
||||
User, Role, Permission, AuditLog, full_permission_catalog,
|
||||
guest_grantable_permissions)
|
||||
from shopdb.utils.responses import success_response, error_response, ErrorCodes
|
||||
from shopdb.utils.authz import require_role
|
||||
|
||||
@@ -266,6 +267,9 @@ def list_permissions():
|
||||
def list_roles():
|
||||
"""List all roles with their permissions."""
|
||||
roles = Role.query.order_by(Role.rolename).all()
|
||||
# What a guest MAY be granted, so the grid can grey out the rest rather
|
||||
# than letting somebody tick a box the API will refuse.
|
||||
guestgrantable = sorted(guest_grantable_permissions())
|
||||
return success_response([{
|
||||
'roleid': r.roleid,
|
||||
'rolename': r.rolename,
|
||||
@@ -273,7 +277,9 @@ def list_roles():
|
||||
'color': r.color,
|
||||
'usercount': r.users.count(),
|
||||
'permissions': [p.name for p in r.permissions],
|
||||
'isadmin': r.rolename == 'admin'
|
||||
'isadmin': r.rolename == 'admin',
|
||||
'isguest': r.rolename == Role.GUEST,
|
||||
'grantable': guestgrantable if r.rolename == Role.GUEST else None,
|
||||
} for r in roles])
|
||||
|
||||
|
||||
@@ -344,6 +350,20 @@ def update_role(roleid: int):
|
||||
|
||||
# Update permissions
|
||||
if 'permissions' in data and role.rolename != 'admin':
|
||||
# The guest role is anyone with no account, so what it may hold is
|
||||
# bounded: reads, plus the handful of writes a plugin has explicitly
|
||||
# declared safe to do anonymously. Refused at the door rather than
|
||||
# warned about - a checkbox that quietly makes deleting an asset
|
||||
# anonymous is not a warning anybody reads twice.
|
||||
if role.rolename == Role.GUEST:
|
||||
allowed = guest_grantable_permissions()
|
||||
refused = sorted(set(data['permissions']) - allowed)
|
||||
if refused:
|
||||
return error_response(
|
||||
ErrorCodes.VALIDATION_ERROR,
|
||||
'The guest role cannot hold {}. A guest may be granted any '
|
||||
'view permission, and only writes a plugin has declared '
|
||||
'safe to do without an account.'.format(', '.join(refused)))
|
||||
old_perms = [p.name for p in role.permissions]
|
||||
perms = Permission.query.filter(Permission.name.in_(data['permissions'])).all()
|
||||
new_perms = [p.name for p in perms]
|
||||
@@ -377,6 +397,14 @@ def delete_role(roleid: int):
|
||||
if role.rolename == 'admin':
|
||||
return error_response(ErrorCodes.VALIDATION_ERROR, 'Cannot delete the admin role')
|
||||
|
||||
# Deleting the guest role does not close the door, it removes the only
|
||||
# place the door is described. Revoke its permissions instead.
|
||||
if role.rolename == Role.GUEST:
|
||||
return error_response(
|
||||
ErrorCodes.VALIDATION_ERROR,
|
||||
'Cannot delete the guest role. To close guest access, clear its '
|
||||
'permissions.')
|
||||
|
||||
if role.users.count() > 0:
|
||||
return error_response(ErrorCodes.VALIDATION_ERROR, f'Role is assigned to {role.users.count()} user(s)')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user