"""Seat and sequence number assignment order.
Implements the screens for editing the seat and sequence number assignment
order. Also provides a function to format the assignment order for
convenient display.
"""
from operator import attrgetter
from ll.xist.ns import html
from uw.web.html.form import render_checkbox, render_hidden, render_select
from uw.web.html.format import make_table_format, format_return, format_datetime
from uw.web.html.join import english_join
from uw.web.wsgi.delegate import delegate_action, delegate_get_post, status
from uw.web.wsgi.form import use_form_param, parse_form_value
from uw.web.wsgi.function import return_html
from .delegate import division_delegate
from .exam_edit import exam_may_edit_seat
from .ui import nullif
@return_html
def order_edit_get_handler (cursor, term, admin, roles, exam):
"""GET handler for the exam order editor.
:param cursor: DB connection cursor.
:param term: Object representing a UW term.
:param admin: A database row representing an admin unit.
:param roles: A list of user roles for a particular admin unit.
:param exam: A database row representing an examination.
:return: An HTML page containing an editor for adjusting the exam sorting and division
order for the relevant examination.
"""
result = [format_return ('Main Menu', None, None, 'Offering', None, 'Assessment')]
order_options = cursor.order_by_exam (exam_id=exam.exam_id, all=True)
order_exam = [r for r in order_options if r.in_use]
at_end_index = 1 + max([0] + [r.division_order_index for r in order_exam if r.division_order_index])
result.append (html.h3 ('Seat Assignment and Sequence Number Order'))
result.append (format_order (cursor, exam, order_exam, exam.master_count))
cols = [('Assign sequence order by', attrgetter ('order_type_description')),
('Assign seats', lambda r: ('Yes ', html.a ('Edit…', href='./%s' % r.division_seq) if r.division_seq > 0 else None) if r.assign_seats_by else 'No'),
('Cover display', lambda r: ('Yes' if r.cover_display else 'No') if r.division_seq > 0 else None)]
if at_end_index > 1:
cols.append(('Priority', lambda r: (html.form (
render_hidden ("division_seq", r.division_seq),
render_select ("division_order_index",
[(s.division_order_index, s.division_order_index + 1) for s in order_exam if s.division_seq > 0],
value=r.division_order_index),
html.input (type="submit", name="!move", value="Move!"),
method="post", action="")) if r.division_seq > 0 else None))
cols.append(('Delete', lambda r: html.form (
render_hidden ("division_seq", r.division_seq),
html.input (type="submit", name="!delete", value="Delete!"),
method="post", action="")))
table = (make_table_format (*cols) (order_exam))
result.append (table)
result.append (html.p ('You may use the following form to change the above order:'))
result.append (html.form (html.p (
'Insert new sort key ',
render_select ("division_seq", list (map (attrgetter ('division_seq', 'order_type_description'), order_options))),
'; ',
html.label ('Assign seats: ', render_checkbox("assign_seats_by")),
'; ',
html.label ('Cover display: ', render_checkbox("cover_display")),
'; ',
html.input (type="submit", name="!insert", value="Insert!"),
),
method="post", action=""
))
result.append (html.p ('You can enable more sorting methods by creating new class divisions using the ', html.a ('class division editor', href="../../../division/create"), '.'))
return '%s (%s) %s: Update Seat/Sequence Number Assignment Order' % (admin.admin_description, term.description (), exam.title), result
@use_form_param
@return_html
def order_edit_post_handler (cursor, term, admin, roles, exam, form):
"""POST handler for the exam order editor.
:param cursor: DB connection cursor.
:param term: Object representing a UW term.
:param admin: A database row representing an admin unit.
:param roles: A list of user roles for a particular admin unit.
:param exam: A database row representing an examination.
:param form:
:return: Redirects user to the exam order editor and performs requested delete,
move, and insert for the relevant examination depending on form results.
"""
if not 'ISC' in roles:
raise status.HTTPForbidden ()
if not exam_may_edit_seat (exam) or exam.master_accepted:
raise status.HTTPFound (".")
division_seq = parse_form_value (form.optional_field_value ("division_seq"), int)
if not division_seq:
return 'Error: No assignment order type selected', html.p ('Please select an assignment order from the drop-down and try again. ', html.a ('Go back.', href="javascript:history.go(-1)"))
division_order_index = cursor.execute_required_value ("select coalesce(max(division_order_index) + 1, 0) from exam_sort_order_complete where exam_id = %(exam_id)s", exam_id=exam.exam_id) if division_seq > 0 else None
cover_display = form.optional_field_value ("cover_display") is not None
assign_seats_by = form.optional_field_value ("assign_seats_by") is not None
if "!delete" in form:
cursor.callproc_none ("order_exam_delete", exam.exam_id, division_seq)
elif "!move" in form:
division_order_index = form.required_field_value ("division_order_index")
cursor.callproc_none ("exam_division_order_index_set", exam.exam_id, division_seq, division_order_index)
elif "!insert" in form and not "!no" in form:
if division_seq < 0:
if "!yes" in form:
cursor.callproc_none ("order_exam_delete", exam.exam_id, parse_form_value (form.required_field_value("old_division_seq"), int))
order = cursor.execute_optional_tuple ("select *, new_division_seq != old_division_seq as is_new from (select division_seq as old_division_seq, order_type_description as old_sort_order_description from exam_sort_order_complete where exam_id = %(exam_id)s and division_seq < 0 and in_use) as old, (select division_seq as new_division_seq, order_type_description as new_sort_order_description from exam_sort_order_complete where (exam_id, division_seq) = (%(exam_id)s, %(division_seq)s)) as new", division_seq=division_seq, exam_id=exam.exam_id)
if order and order.is_new:
result = []
result.append ([html.p ("In order to sort exam by %s, the current exam sorting of %s will be deleted." % (order.new_sort_order_description, order.old_sort_order_description)),
html.p ("Are you sure you want to continue?")])
result.append (html.form (
render_hidden ("division_seq", division_seq),
render_hidden ("division_order_index", division_order_index),
render_hidden ("assign_seats_by", "") if assign_seats_by else None,
render_hidden ("!insert", "Insert"),
render_hidden ("old_division_seq", order.old_division_seq),
html.input(type="submit", name="!yes", value="Yes"),
html.input(type="submit", name="!no", value="No"),
method="post", action=""))
return 'Delete ' + order.old_sort_order_description + ' Exam Ordering', result
cursor.callproc_none ("order_exam_set", exam.exam_id, division_seq, division_order_index, cover_display, assign_seats_by)
cursor.callproc_none ("exam_candidate_update", exam.exam_id)
raise status.HTTPFound ("")
@return_html
def division_sitting_get_hanlder (cursor, term, admin, roles, exam, division):
result = [format_return (None, 'Assessment', dot='Assignment Order Editor')]
division_values = cursor.execute_tuples ("select term_id, admin_id, division_seq, division_value from division_student_complete where (term_id, admin_id, division_seq) = (%(term_id)s, %(admin_id)s, %(division_seq)s) and dropped is null group by term_id, admin_id, division_seq, division_value order by division_value", term_id=exam.term_id, admin_id=exam.admin_id, division_seq=division.division_seq)
sittings = cursor.sittings_by_exam (exam_id=exam.exam_id)
table = make_table_format (
('Division Value', attrgetter ('division_value')),
('Sitting', lambda d: render_select (
"%s" % d.division_value, [(r.sitting_id, 'At %s with %s' % (format_datetime (r.start_time), r.admin_description)) for r in sittings], blank=True,
value=cursor.execute_optional_value ("select sitting_id from division_division_exam_sitting where (exam_id, division_seq, division_value) = (%(exam_id)s, %(division_seq)s, %(division_value)s)", exam_id=exam.exam_id, division_seq=division.division_seq, division_value=d.division_value),))
)(division_values)
result.append (html.form ((table, html.input (type="submit", name="!update", value="Update!")), method="post", action=""))
return '%s (%s) %s: Update Division Value Sitting Assignment' % (admin.admin_description, term.description (), exam.title), result
@use_form_param
@return_html
def division_sitting_post_handler (cursor, term, admin, roles, exam, division, form):
if not 'ISC' in roles:
raise status.HTTPForbidden ()
if '!update' in form:
division_values = cursor.execute_tuples ("select term_id, admin_id, division_seq, division_value from division_student_complete where (term_id, admin_id, division_seq) = (%(term_id)s, %(admin_id)s, %(division_seq)s) group by term_id, admin_id, division_seq, division_value order by division_value", term_id=exam.term_id, admin_id=exam.admin_id, division_seq=division.division_seq)
for division_value in division_values:
sitting_id = form.optional_field_value (division_value.division_value)
cursor.callproc_none ("division_division_exam_sitting_set", exam.exam_id, division.division_seq, division_value.division_value, nullif (sitting_id))
cursor.callproc_none ("exam_candidate_update", exam.exam_id)
raise status.HTTPFound (".")
order_edit_handler = division_delegate (delegate_get_post (order_edit_get_handler, order_edit_post_handler),
delegate_get_post (division_sitting_get_hanlder, division_sitting_post_handler))