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

"""Admin-unit related UI pages.

This includes the main admin unit display as well as the display of information
related to each admin unit.  The form to adjust role authorizations is also
included.
"""

from operator import attrgetter
from functools import partial

from ll.xist.ns import html

from uw.web.wsgi import status
from uw.web.wsgi.authority import check_authority
from uw.web.wsgi.delegate import *
from uw.web.wsgi.form import use_form_param
from uw.web.wsgi.function import return_html

from uw.web.html.form import render_select, render_checkbox
from uw.web.html.format import make_table_format, format_return
from uw.web.html.join import english_join, html_join

from uw.local import termtools
from uw.local.util.format import person_search_form_url, format_person, format_aff

from ...util.identity import use_remote_identity
from ..db.aids import get_aid_classes
from .admin_account_edit import render_admin_account_section, account_get_handler, account_post_handler
from .ui import format_duration
from .authority import check_admin_authority
from .personnel import format_personnel

[docs]def list_admin_units (admins, url_prefix, enhance_row=None): """Format a list of admin units as an HTML <table>. :param admins: a list of admin unit DB rows :param url_prefix: the URL prefix for links to the admin units :return: and HTML table with one row for each admin unit in admins, including a link to each admin unit :rtype: HTML table <table> *** TODO: use make_table_format? *** TODO: use enhance_row for some invocation? Why is it available? """ result = html.table () row = html.tr ( html.th ('ID'), html.th ('Description'), html.th ('Effective'), html.th ('Expires'), ) if enhance_row is not None: enhance_row (None, row) result.append (row) for admin in admins: row = html.tr ( html.td (html.a (admin.admin_id, href="%s%s/" % (url_prefix, admin.admin_id))), html.td (admin.admin_description), html.td (str (admin.admin_effective)), html.td (str (admin.admin_expires)), ) if enhance_row is not None: enhance_row (admin, row) result.append (row) return result
@delegate_get_post @return_html def admin_index (cursor): """Admin unit complete list URL handler. :param cursor: DB connection cursor :return: tuple of (title, list of every admin unit) :rtype: (str, list) """ result = [format_return ('Main Menu', 'Admin Units by UW Unit')] admins = cursor.execute_tuples ("select admin_id, admin_description, lower (admin_effective) as admin_effective, upper (admin_effective) as admin_expires from teaching_admin order by admin_description") result.append (list_admin_units (admins, "")) return "Admin Index", result
[docs]def render_admin (admins, admin_id): """Render a collection of admin units as a hierarchical HTML list. :param admins: the admin units to render :param admin_id: the starting admin unit :return: an HTML <a> for the specified starting admin unit, followed by an HTML <ul>, if necessary, containing any other admin units in the collection which are contained within the starting admin unit :rtype: list """ result = [] admin = admins[admin_id] result.append (html.a ('%d%s' % (admin.admin_id, admin.admin_description), href="id/%d/" % admin.admin_id)) contained = sorted ( [r for r in [admins.get (id) for id in admin.contained] if r is not None], key=attrgetter ('admin_description') ) if contained: result.append (html.ul (html.li (render_admin (admins, admin.admin_id)) for admin in contained)) return result
@delegate_get_post @use_remote_identity @return_html def admin_unit_index (cursor, remote_identity): """User admin unit index URL handler. :param cursor: DB connection cursor :return: list of the admin units for which the user is authorized, with links to each one :rtype: (str, list) """ result = [format_return ('Main Menu')] result.append (html.h2 ('Your Admin Units')) admins = cursor.execute_tuples ("select distinct admin_id, admin_description from teaching_admin natural join auth_admin_personnel where current_date <@ role_effective and person_id = %(person_id)s order by admin_description", person_id=remote_identity.person_id) if admins: result.append (html.p ('You are directly authorized for the following admin units:')) result.append (html.ul ( html.li (html.a (admin.admin_description, href="id/%d/" % admin.admin_id)) for admin in admins )) else: result.append (html.p ('You are not authorized for any admin units.')) result.append (html.h2 ('Admin Unit Structure')) admins = cursor.execute_tuples ("select *, (select coalesce (array_agg (inner_admin_id), array[]::integer[]) from teaching_admin_contains where outer_admin_id = admin_id) as contained from teaching_admin ta where admin_level <= 10") admins = dict ((r.admin_id, r) for r in admins) result.append (render_admin (admins, 20000)) return "Admin Units by UW Unit", result @use_remote_identity @return_html def admin_get_handler (cursor, admin, remote_identity, roles): """Admin unit view GET URL handler. :param cursor: DB connection cursor :param admin: the relevant admin unit :param roles: the active permissions roles :return: information about the admin unit :rtype: (str, list) """ result = [format_return ('Main Menu', 'Admin Units by UW Unit', None)] admin_info = cursor.admin_info_by_id (admin_id=admin.admin_id) if admin_info.group_code is not None: # Group admin result.append (html.p ( 'This is the group admin unit for ', html.b (admin_info.group_code), '.', )) elif admin_info.unit_code is not None: # Unit admin result.append (html.p ( 'This is the unit admin unit for ', html.b (admin_info.unit_code), '.', )) elif admin_info.subject_code is not None: # Subject admin result.append (html.p ( 'This is the subject admin unit for ', html.b (admin_info.subject_code, '/', admin_info.career_code), '.', )) elif admin_info.course_id is not None or admin_info.course_ids is not None: heldwith = admin_info.course_ids is not None # Course admin or course heldwith admin result.append (html.p ( 'This is the (session ', admin_info.session_code, ') course ', 'heldwith ' if heldwith else '', 'admin unit for ', 'heldwith courses ' if heldwith else '', english_join (*admin_info.course_descriptions), '. It will ', '' if admin_info.split_by_instructor else 'not ', 'be split by instructor by default.', )) if not heldwith and 'ISC' in roles: result.append (html.form ( html.p ( 'Update default split by instructor: ', html.label ( render_checkbox ("split", admin_info.split_by_instructor), 'Split by default', ), ' ', html.input (type="submit", name="!split", value="Update!"), ), method="post", action="" )) elif admin_info.parent_admin_id is not None: # Course instructors admin parent_admin = cursor.admin_by_id (admin_id=admin_info.parent_admin_id) result.append (html.p ( 'This is the course instructors admin unit for ', html.a (parent_admin.admin_description, href="../%d/" % parent_admin.admin_id), ' when taught by ', english_join (*[format_person (cursor, person_id) for person_id in admin_info.instructor_person_ids]), '.', )) else: # Ad hoc result.append (html.p ('This is an ad hoc admin unit.')) result.append (html.h2 ('Terms Offered')) table = html.table (html.tr ( html.th ('Term'), html.th ('Instructors'), )) offerings = cursor.execute_tuples ("select term_id, (select coalesce (array_agg (person_id), array[]::integer[]) from auth_offering_personnel_complete where (term_id, admin_id, role_code) = (tat.term_id, tat.admin_id, 'INST')) as instructors, exists (select * from auth_offering_personnel_complete where (term_id, admin_id, person_id) = (tat.term_id, tat.admin_id, %(person_id)s)) as authorized from teaching_admin_term as tat where admin_id=%(admin_id)s order by term_id desc", admin_id=admin.admin_id, person_id=remote_identity.person_id) for offering in offerings: term = termtools.fromCode (offering.term_id) description = term.description () if offering.authorized: description = html.a (description, href="../../../term/%s/%s/" % (term.code (), admin.admin_id)) table.append (html.tr ( html.td (description), html.td ( html_join ( (format_person (cursor, p) for p in offering.instructors), sep=html.br () ) ), )) result.append (table if offerings else 'There are no terms available.') personnel = cursor.personnel_by_admin (admin_id=admin.admin_id) result.append (html.h2 ('Personnel')) result.append (format_personnel (cursor, None, admin, personnel, roles)) result.append (html.h2 ('Related Admin Units')) children = cursor.execute_tuples ("select * from teaching_admin_contains join teaching_admin on (admin_id = inner_admin_id) where outer_admin_id = %(admin_id)s order by admin_description", admin_id=admin.admin_id) if children: result.append (html.h3 ('Children')) result.append (html.ul (html_join ((html.li (html.a (r.admin_description, href="../%s/" % r.admin_id)) for r in children)))) parents = cursor.execute_tuples ("select * from teaching_admin_contains join teaching_admin on (admin_id = outer_admin_id) where inner_admin_id = %(admin_id)s order by admin_description", admin_id=admin.admin_id) if parents: result.append (html.h3 ('Parents')) result.append (html.ul (html_join ((html.li (html.a (r.admin_description, href="../%s/" % r.admin_id)) for r in parents)))) result.append (render_admin_account_section (cursor, admin, roles)) result.append (html.h2 ('Printing')) print_info = cursor.execute_optional_tuple ("select pafa.admin_id, inherit_admin_id, admin_contact, admin_description, exam_print_admin_account (pafa.admin_id) from print_admin_finance_account_complete pafa join teaching_admin ta on (ta.admin_id = inherit_admin_id) where pafa.admin_id = %(admin_id)s", admin_id=admin.admin_id) if print_info is None: result.append (html.p ( 'Printing information is not set up for this admin unit.' )) else: result.append (html.p ( 'Printing by this admin unit will be billed to ', html.b (format_aff (print_info.exam_print_admin_account)), '. ', 'The billing contact is ', format_person (cursor, print_info.admin_contact), '. ', 'Billing information is controlled by ', html.a (print_info.admin_description, href="../%d/" % print_info.inherit_admin_id), '.', )) return "%s: General Information" % admin.admin_description, result @use_form_param @return_html def admin_post_handler (cursor, admin, roles, form): """Admin unit view POST URL handler. :param cursor: DB connection cursor :param admin: the relevant admin unit :param roles: the active permissions roles :param form: CGI form results Form actions are: - remove an admin unit authorization grant - create an admin unit authorization grant - adjust the default split by instructor status """ if "!remove" in form: if not 'ADMIN' in roles: raise status.HTTPForbidden () for role in form.multiple_field_value ("remove"): person_id, role_code = role.split ('-') cursor.callproc_none ("auth_admin_manual_authorize", False, admin.admin_id, person_id, role_code) elif "!authorize" in form: if not 'ADMIN' in roles: raise status.HTTPForbidden () person_id = form.optional_field_value ("person_id") if person_id == "other": userid = form.required_field_value ("userid") person_id = cursor.execute_optional_value ("select person_id from person_identity_complete where userid=%(userid)s", userid=userid) if person_id is None: return 'Error: No such person', html.p ( 'No person with userid “', userid, '” found. ', html.a ('WatIAM Search', target="_blank", href=person_search_form_url), ' may be helpful in finding the right person.', ) role_code = form.required_field_value ("role") if not role_code: return 'Error: No role selected', [ html.p ('Please go back and select a role to grant to the selected person.')] backup = "backup" in form cursor.callproc_none ("auth_admin_manual_authorize", True, admin.admin_id, person_id, role_code, backup) elif "!split" in form: if not 'ISC' in roles: raise status.HTTPForbidden () split = "split" in form cursor.execute_none ("update teaching_admin_course set split_by_instructor=%(split)s where admin_id = %(admin_id)s", admin_id=admin.admin_id, split=split) raise status.HTTPFound ("") admin_handler = check_authority (check_admin_authority, delegate_action (delegate_get_post (admin_get_handler, admin_post_handler), { "account": delegate_get_post (account_get_handler, account_post_handler), }))