"""Room Editor UI pages
This currently consists of only the note editor, includes handlers
for editing, deleting, and updating room notes. Will also include
the room editor which allows the user to edit room maps
"""
import psycopg2, json
from ll.xist.ns import html, specials
from uw.web.html.form import render_select, render_checkbox
from uw.web.html.format import format_email, format_return
from uw.web.wsgi import status
from uw.web.wsgi.delegate import delegate_action, delegate_get_post
from uw.web.wsgi.function import return_html, return_json
from .delegate import room_delegate
[docs]def note_instructions (cursor, room):
"""Displays the description and instructions for the room_note
:param cursor: DB connection cursor
:param room: A database row representing a room
:return: a list of html elements to be added to the page
:rtype: list
"""
result = [html.p ("This description will be displayed in the exam schedule portal \
to provide instructions on how to locate the room.")]
room_note = cursor.execute_optional_value ("select room_note from room_room where room_id = %(room_id)s",
room_id=room.room_id)
if not room_note:
result.append (html.p ("There is currently no room note."))
else:
result.append (html.p ("Current room note: " + specials.literal (room_note)))
return result
[docs]def note_section (cursor, room):
"""Displays the note editor section
:param cursor: DB connection cursor
:param room: A database row representing a room
:return: a list of html elements to be added to the note editor page
including the instructions, the CKEditor, and form buttons
:rtype: list
"""
result = [(html.h2 ("Room Note"))]
result.append (note_instructions (cursor, room))
result.append (html.p ("To edit the room note, enter the text below then click Update"))
result.append (html.textarea (room.room_note, name="room_note", id="room_note", rows=5, cols=40))
result.append (html.script ("CKEDITOR.replace ('room_note', \
{language: 'en', \
toolbar: [{ name: 'document', items : [ 'Source'] }, \
{ name: 'clipboard', items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] }, \
{ name: 'editing', items : ['SpellChecker'] },{ name: 'basicstyles', items : [ 'Bold','Italic','Underline','Strike'] }, \
{ name: 'paragraph', items : [ 'NumberedList','BulletedList','-','Outdent','Indent','-'] }, \
{ name: 'links', items : [ 'Link','Unlink'] }, \
{ name: 'insert', items : ['Image'] }, \
{ name: 'styles',items : [ 'Styles','Format'] }, \
{ name: 'tools',items : [ 'Maximize', 'About' ]}]})",
type="text/javascript"))
result.append (html.p (html.input (type="submit", name='!update_note', value="Update"),
html.input (type="submit", name='!delete_note', value="Delete")))
return result
@return_html
def note_edit_get_handler (cursor, room, form, global_roles):
"""Note editor GET URL handler.
:param cursor: DB connection cursor
:param room: A database row representing a room
:param form: the form results
:return: tuple of (building code and room code, html elements to be added to
the note editor page)
:rtype: (str, list)
Displays the current room note and CKEditor text area,
includes form controls for updating the room note to the
CKEditor input and deleting the room note.
"""
result = [html.p ("Return to ", html.a ("Room Index", href="../../../../../room/"),
", ", html.a ("Room Information-%s %s" % (room.building_code, room.room_code), href="../../../../id/%s/" % room.room_id))]
result.append (html.form (note_section (cursor, room), method='post', action=''))
return '%s %s Note Editor' % (room.building_code, room.room_code), result
@return_html
def note_edit_post_handler (cursor, room, form, global_roles):
"""Note editor POST URL handler.
:param cursor: DB connection cursor
:param room: A database row representing a room
:param form: the form results
Implements actions based on form results. These can be one of:
- Deletes current room note from the room
- Updates current room note
If an error occurs, the error message is shown to the user.
"""
if '!update_note' in form:
room_note = form.optional_field_value ('room_note')
if not room_note:
room_note = None
if '!delete_note' in form:
room_note = None
try:
cursor.execute_none ("update room_room set room_note = %(room_note)s where room_id = %(room_id)s",
room_note=room_note, room_id=room.room_id)
except psycopg2.Error as error:
return 'Please Go Back', [html.p ("Invalid Room Note please enter a valid XML fragment."),
'Please contact ', format_email ('odyssey@uwaterloo.ca'), ' for more assistance.',
html.p ("The following error message occured:"),
html.p (error.pgerror)]
raise status.HTTPFound ("../../../../id/%s/" % room.room_id)
note_edit_handler = delegate_get_post (note_edit_get_handler, note_edit_post_handler)
@return_html
def room_edit_get_handler (cursor, room, form, global_roles):
"""Room map editor GET URL handler.
:param cursor: DB connection cursor
:param room: A database row representing a room
:param form: the form results
:return: tuple of (building and room code, room map editor)
:rtype: (str, list)
Displays a form for editing the room map with live display of
what the room map will look like.
"""
result = [format_return ('Main Menu', 'Room Index', None, None)]
if room.room_effective is not None:
raise status.HTTPForbidden ()
form = []
form.append (html.table (
html.tr (
html.th ('Room Width:'),
html.td (html.input (type="number", name="room-width", class_="room-seating-input", value=room.room_width, onkeypress="return event.charCode >= 48", min="1", required="")),
),
html.tr (
html.th ('Room Depth:'),
html.td (html.input (type="number", name="room-depth", class_="room-seating-input", value=room.room_depth, onkeypress="return event.charCode >= 48", min="1", required="")),
),
))
seat_types = cursor.execute_tuples ("select seat_type_code, seat_type_description from room_seat_type")
seat_types.append(("NO SEAT", "No Seat"))
form.append (html.div (
render_checkbox ("s", class_="seat-checkbox-template"),
html.span ('Change selected seats: '),
render_select ('', ((code, '%s - %s' % (code, label)) for code, label in seat_types), value="TBL", class_="seat-type-selector"),
html.p (html.input (type="button", value="Update Selected Seats", class_="seat-type-update-selected")),
))
form.append (html.div (class_="room-seats-editor"))
form.append (html.p ('Note: left/right arrows are for creating aisles between seats. A red border between two seats indicates an aisle between them.'))
form.append (html.input (type="hidden", name="room-seat-json", value=json.dumps (cursor.execute_tuples ("select * from room_seat where room_id = %(room_id)s", room_id=room.room_id))))
form.append (html.input (type="hidden", name="room-aisle-json", value=json.dumps (cursor.execute_tuples ("select * from room_row_aisle where room_id = %(room_id)s", room_id=room.room_id))))
form.append (html.p (html.input (type="submit", value="Submit", class_="create-room-button")))
result.append (html.form (form, class_="create-room-form", action=""))
result.append (html.p (class_="room-editor-error text-error"))
return 'Room Editor—%s %s' % (room.building_code, room.room_code), result
@return_json
def room_edit_post_handler (cursor, room, form, global_roles):
"""Room map editor POST URL handler.
:param cursor: DB connection cursor
:param room: A database row representing a room
:param form: the form results
:return: JSON object of room id
:rtype: str
Implements the room map designed in the GET handler.
"""
# Cheap hack to get around deleting the proper seats and aisles
cursor.callproc_none ("room_edit_resize", room.room_id, 0, 0)
# Resize to new room size
room_width = form.required_field_value ('room-width')
room_depth = form.required_field_value ('room-depth')
cursor.callproc_none ("room_edit_resize", room.room_id, room_width, room_depth)
# Add new set of seats
seats = form.multiple_field_value ('seats')
for seat in seats:
seat_row, seat_col, seat_type_code = seat.split('-')
cursor.callproc_none ("room_edit_seat", room.room_id, seat_col, seat_row, seat_type_code)
# Add new set of aisles
aisles = form.multiple_field_value ('aisles')
for aisle in aisles:
seat_col_left, seat_col_right, seat_row = aisle.split('-')
cursor.callproc_none ("room_edit_aisle", room.room_id, seat_col_left, seat_col_right, seat_row, True)
json_reply = json.dumps ({'id': room.room_id})
return json_reply
room_edit_handler = delegate_get_post (room_edit_get_handler, room_edit_post_handler)
room_edit_handler = delegate_action (None, {
'id': room_delegate (None, delegate_action (room_edit_handler, {
'note': note_edit_handler,})),
})