Source code for uw.local.teaching.webui.authority

"""Authorization-related utility routines.

This includes authorization checkers for admin units and offerings, as well
as routines to format personnel lists for admin units and offerings.
"""

from operator import attrgetter
from itertools import groupby

from ll.xist.ns import html

from uw.web.html.form import render_checkbox
from uw.web.html.join import html_join

from uw.web.wsgi import parameter

from uw.local.util.format import format_person

[docs]def check_unit_authority (environ, cursor, unit, **params): """Check for authorization within the academic organization. For use with :func:`uw.web.wsgi.authority.check_authority`. Sets the “roles” parameter to the set of roles for which the user is authorized for the academic organization (unit). Grants access if any role is available to the user for the unit. """ roles = set (cursor.unit_get_permissions (unit_code=unit.unit_code, person_id=environ['remote_identity'].person_id)) parameter.set_param (environ, 'roles', roles) return bool (roles)
[docs]def check_admin_authority (environ, cursor, admin, **params): """Check for authorization within the admin unit. For use with :func:`uw.web.wsgi.authority.check_authority`. Sets the "roles" parameter to the set of roles for which the user is authorized for the admin unit. Always grants access, so the only actual effect of this is to set the "roles" parameter. If general access is to be denied to information, code must check that roles is non-empty and either suppress the information or report an error. """ roles = set (cursor.admin_get_permissions (admin_id=admin.admin_id, person_id=environ['remote_identity'].person_id)) parameter.set_param (environ, 'roles', roles) return True
[docs]def check_offering_authority (environ, cursor, term, admin, **params): """Check for authorization within the admin offering. For use with :func:`uw.web.wsgi.authority.check_authority`. Sets the "roles" parameter to the set of roles for which the user is authorized for the offering. Grants access if any role is available to the user for the offering. """ roles = set (cursor.offering_get_permissions (term_id=term.code (), admin_id=admin.admin_id, person_id=environ['remote_identity'].person_id)) parameter.set_param (environ, 'roles', roles) return bool (roles)
[docs]def check_global_authority (auth_roles=None): '''Checks for global authorization :param auth_roles: A list of global authorization roles. :return: a function that takes environ, cursor, and all other parameters then returns a boolean based on desired auth_roles. For use with :func:`uw.web.wsgi.authority.check_authority`. ''' def check_global_roles (environ, cursor, **params): global_roles = set (cursor.user_get_global_permissions (person_id=environ['remote_identity'].person_id)) if auth_roles is not None: global_roles &= set (auth_roles) result = bool (global_roles) else: result = True parameter.set_param (environ, 'global_roles', global_roles) return result return check_global_roles
[docs]def check_upload_authority (environ, cursor, exam, **params): """Check for authorization to upload examination masters. For use with :func:`uw.web.wsgi.authority.check_authority`. Grants access if the user is the designated examination author. """ return environ['remote_identity'].person_id == exam.exam_author_person_id
[docs]def format_scope (grant): """Format the scope of an authorization grant. Returns HTML showing the maintainer code with an appropriate tooltip. Additionally, includes a link to the admin unit providing the grant in the event the grant is from an admin unit rather than an offering. """ result = [html.span (grant.maintainer_code, title=grant.maintainer_description)] if grant.auth_admin_id is not None: result.append (html.a (grant.auth_admin_description, href="../../../admin/id/%d/" % grant.auth_admin_id)) return html_join (result, ' ')
[docs]def format_remove (grant, is_admin, is_isc, remove_admin_id): """Format the checkbox for removing an authorization grant. Parameters: grant -- the permissions grant as a DB row; is_admin -- the current user is authorized to make changes; remove_admin_id -- the admin_id whose page we are generating. Returns either an HTML checkbox <input> in the event that is makes sense and is allowed for the user to remove the grant, or None otherwise. """ if grant.maintainer_code == 'M' and (is_admin or (is_isc and grant.role_code == 'ISA')) and remove_admin_id == grant.auth_admin_id: return render_checkbox ("remove", value="%d-%s" % (grant.person_id, grant.role_code)) else: return None
[docs]def format_personnel_by_user (cursor, personnel, is_admin=False, is_isc=False, remove_admin_id=None): """Format offering personnel, ordered by person. Parameters: cursor -- DB connection cursor; personnel -- permissions grants as a list of DB rows; is_admin -- the current user is authorized to make changes; remove_admin_id -- the admin_id whose page we are generating. """ def format_grant (grant): result = [ html.td (grant.role_description + (' (Backup)' if grant.auth_backup else '')), html.td (format_scope (grant)) ] if is_admin or is_isc: result.append (html.td (format_remove (grant, is_admin, is_isc, remove_admin_id))) return result table = html.table (html.tr ( html.th ('User'), html.th ('Role'), html.th ('Scope'), )) if is_admin or is_isc: table[0].append (html.th ('Remove')) personnel = sorted (personnel, key=attrgetter ('surname', 'givennames', 'role_code')) for person_id, grants in groupby (personnel, attrgetter ('person_id')): grants = list (grants) table.append (html.tr ( html.td (format_person (cursor, person_id), rowspan=len (grants)), format_grant (grants[0]), )) for grant in grants[1:]: table.append (html.tr ( format_grant (grant), )) return table
[docs]def format_personnel_by_role (cursor, personnel, is_admin=False, is_isc=False, remove_admin_id=None): """Format offering personnel, ordered by role. Parameters: cursor -- DB connection cursor; personnel -- permissions grants as a list of DB rows; is_admin -- the current user is authorized to make changes; remove_admin_id -- the admin_id whose page we are generating. """ def format_grant (grant): result = [ html.td (format_person (cursor, grant.person_id) + [' (Backup)' if grant.auth_backup else '']), html.td (format_scope (grant)) ] if is_admin or is_isc: result.append (html.td (format_remove (grant, is_admin, is_isc, remove_admin_id))) return result table = html.table (html.tr ( html.th ('Role'), html.th ('User'), html.th ('Scope'), )) if is_admin or is_isc: table[0].append (html.th ('Remove')) personnel = sorted (personnel, key=attrgetter ('role_code', 'surname', 'givennames')) for role_code, grants in groupby (personnel, attrgetter ('role_code')): grants = list (grants) table.append (html.tr ( html.td (grants[0].role_description, rowspan=len (grants)), format_grant (grants[0]) )) for grant in grants[1:]: table.append (html.tr ( format_grant (grant), )) return table