Page Source
from utils.display import Display, Modal, Database, Arguments
from utils.controls import *
from utils.output import *
from utils.web_exc import WebError
import queries, debugging
from utils import misc, bounce
from utils.static_strings import StaticStringControl
from config import docroot
import string, os
import time
# <page>/y/q/s/n/kw
# Gives schedules for year y, qtr q (AUT/WIN/..), subject s (CS or CSPP)
# and number n (105/106),containing keyword kw/reg_exp.
# A blank argument stands for any/all,
# i.e. blank year and WIN qtr means any year WIN qtr
# Just instantiate the given output class
# checks the number of arguments given
# if only year given then also adds a Quarter column
# if year not given then also add a year column
class TableContainerControl(ContainerControl):
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
# the display will always be a ScheduleDisplay Instance
def output_disp(self, display, container):
qtrcol = None
yearcol = None
if display.multiple_qtrs:
qtrcol = 1
if display.multiple_years:
yearcol=1
rv = ScheduleTable(qtrcol=qtrcol,yearcol=yearcol,*self.args,**self.kwargs)
container.append(rv)
return rv
output_form = output_disp # same thing
class ScheduleTable(TABLE):
def __init__(self,qtrcol=None,yearcol=None,*args,**kwargs):
self.qtrcol = qtrcol
self.yearcol=yearcol
TABLE.__init__(self,*args,**kwargs)
class IsQtrControl(IfThenElseControl):
def __init__(self,thenc):
IfThenElseControl.__init__(self,thenc)
def condition(self,display): # 1 if multiple qtarters
return display.multiple_qtrs
class IsYearControl(IfThenElseControl):
def __init__(self,thenc):
IfThenElseControl.__init__(self,thenc)
def condition(self,display):
return display.multiple_years
class InstrControl(Control):
"""Output a comma separated list of links to each instructors homepage
The information is assumed to be in the field display.instructors
which is expected to be a list of dictionaries"""
def output_disp(self,display,container):
ans = []
for dict in display.instructors:
if dict['pseudo']:
op = dict['lname']
else:
op = '<a href="%(person:'+ dict['login']+ ')s">'
op = op % display.urls()
op = (op+ '%(fname)s') % dict
if dict['mname'] != '':
op = (op+ ' %(mname)s') % dict
op = (op+ ' %(lname)s</a>') % dict
ans = ans + [op]
container.append(string.join(ans,", "))
class HeaderControl(Control):
def output_disp(self, display, container):
# The display object should be a ScheduleDisplay object
# otherwise will not work
# migration to guava (Adam Shaw)
container.append("<h1><font color='red'>This information is no longer updated.</font></h1>")
container.append("<h1><font color='red'>Please follow this </font><a href='http://course-info.cs.uchicago.edu'>link</a><font color='red'> to current information.</font></h1>")
container.append("<h2>Courses</h2>")
if display.args['quarter']:
qtr = display.args['quarter']
else:
qtr = ''
if display.args['year']:
year = int(display.args['year'])
else:
year = 0
quarters = [('All',''),
('Autumn','AUT'),
('Winter','WIN'),
('Spring','SPR'),
('Summer','SUM')]
y = time.gmtime(time.time())[0] # get the current year
# we have a UL (bulleted list) of a link and a form
# The form has some text followed by two select thingies and a Go thingie.
form = Container([ # initialise a Container of output objects
'<form method="post" enctype="multipart/form-data" action="%s">'
% ("%(sect:courses)s" % display.urls()),
"View Schedule for",
SELECT(name="year",options=[(y-1,y-1),(y,y),(y+1,y+1)],default=year), # Select year
SELECT(options=quarters,name="quarter",default=qtr), # select quarter
SUBMIT_INPUT({'value':'Go'}), # Go
' <a href="%(sect:courses)s/search">Advanced Search</a> ' % display.urls(),
# Search
'</form>'
]) # end form
# Once form object is done, this will in terms of the FORM() object
ul = BulletColumns([
'<a href="%(sect:courses)s/description"> Course Descriptions </a><br />' % display.urls(),
form
]) # end ul
container.append(ul)
class CaveatControl(IfThenElseControl):
"""Show the if control exactly if show_caveat has been set to true earlier."""
def condition(self, display):
return display.show_caveat
class ScheduleDisplay(Display, Database, Arguments, Modal):
multiple_container_control = CoalesceContainerControl([
HeaderControl(),
CaveatControl(StaticStringControl("schedule_tentative")),
DisplayTitleControl(head_level=2),
TableContainerControl(attrs={ 'width' : '100%',
'border' : 0,
'cellspacing' : 0,
'cellpadding' : 3}) ,
StaticStringControl("read_rsrch")
],
representative=3) # the active control is the 2nd one. Index starts at 0
multiple_row_container_control = SimpleContainerControl(TR)
# <div class="sched_entry course">
# <span class="sp_field_content sp_title"></span>
# <div class="sched_entry course_info">
# <span class="sp_field_content sp_course"></span>
# <span class="sp_field_content sp_year"></span>
# <span class="sp_field_content sp_quarter"></span>
# <div class="sched_entry instructor"></div>
# <div class="sched_entry timeday"></div>
# <div class="sched_entry room"></div>
# <div class="sched_entry remarks"></div>
# <div class="sched_entry homepage"></div>
# </div>
# </div>
multiple_controls = [
DivControl("sched_entry course", '',
CoalesceControl([
SpanControl("sp_field_content sp_title", '',
LinkControl("title",
"%(sect:courses)s/info/%(!year)s/%(!quarter)s/%(!scourse)s",
FieldControl("title",nbsppad=1))
),
DivControl("sched_entry course_info", '',
CoalesceControl([
SpanControl("sp_field_content sp_course", '', FieldControl("course",nbsppad=1)),
IsYearControl(SpanControl("sp_field_content sp_year", '', FieldControl("year"))),
IsQtrControl(SpanControl("sp_field_content sp_quarter", '', FieldControl("quarter"))),
DivControl("shed_entry instructor", '', InstrControl()),
DivControl("sched_entry timeday", '', FieldControl("timeday",nbsppad=1)),
DivControl("sched_entry room", '', FieldControl("room",nbsppad=1)),
IfExistsControl("remarks",
DivControl("sched_entry remarks", '',
FieldControl("remarks",nbsppad=1)
)
),
IfExistsControl("homepage",
DivControl("sched_entry homepage", '',
LinkControl(field="homepage", url="%(!homepage)s", subcontrol="Course Homepage")
)
),
])
),
])
)]
def handle_type_check(self,page,message):
self.generate_error_page(page,"Type Check Failed","The argument to %s was not an integer" % message)
def process_arguments(self):
"parse the arguments got either thru cmd line or POST DATA"
self.defqtr,self.defyear = misc.current_qtr()
self.args = self.process_search_arguments(argnames=['year','quarter','subject','c_number','keywords','room'],
noargs=[self.defyear,self.defqtr],space2plus=1,IntCheck=['year','c_number'])
if type(self.args) == StringType: # either year or c_number was not a number
raise WebError("type_check()",self.args) # should result in a call to handle_type_check
# Throw out quarter if it's not legit
if self.args['quarter'] not in ['WIN','SPR','SUM','AUT']:
self.args['quarter'] = None
# Add 00 if we got a 3 digit course number
cnum = self.args['c_number'] # It is an integer here
if cnum and (cnum < 1000):
self.args['c_number'] = cnum*100
def add_nav_links(self,page):
if perms.may(self.req.login,'add','courses'):
page.add_navigation("%(sect:courses)s/add" % self.req.urls(),"Add Course")
if perms.may(self.req.login,'add','schedules'):
page.add_navigation("%(sect:courses)s/add_schedule" % self.req.urls(), "Add Schedule")
def make_page(self,page):
self.process_arguments()
page.set_type("courses")
page.set_title("Course Schedule. "+(self.get_criteria() or ""))
self.add_nav_links(page)
# show caveat if requested quarter is more than a quarter in the future
# or if no year specified
Q = {}; Q['WIN']=0; Q['SPR']=1; Q['SUM']=2; Q['AUT']=3; Q[None]=3
self.show_caveat = self.args['year'] == None or \
4*self.args['year']+Q[self.args['quarter']] > 4*self.defyear+Q[self.defqtr]+1
page.append(self.multiple_database())
def is_multiple(self): # only multiple mode
return 1
def get_multiple_title(self):
return "Course Schedule"
def get_criteria(self):
ans = ""
if not self.args:
return ""
dispnames = [ ('Quarter','quarter'),
('Year','year'),
('Subject','subject'),
('Room','room'),
('Course number','c_number')
]
ans = "Criteria: "
for (user,key) in dispnames:
if self.args[key]: # if key was part of the search criteria
ans = ans + " " + str(self.args[key]) # some args are integers
if self.args['keywords']: # if there was keyword criteria
ans = ans + ". Keywords: '%s'" % self.args['keywords']
return ans
def db_rows(self):
return self.query.count()
def db_query(self):
self.multiple_qtrs = None
self.multiple_years = None
tables=["schedules as s", "people as p", "courses as c", "instructorship as i"]
columns={"course" : "concat(s.subject,' ',s.course_num,'-',s.course_sec)",
"scourse" : "concat(s.subject,s.course_num,'-',s.course_sec)",
"homepage":"s.homepage",
"pseudo":"pseudo",
"course_num":"c.course_num",
"course_sec":"s.course_sec",
"title" :"c.title",
"login":"login", # The instructor from instructorship if only one
"fname":"fname",
"mname":"mname",
"lname":"lname",
"timeday":"s.timeday",
"room":"s.room",
"remarks":"s.remarks",
"year":"s.year",
"quarter":"s.quarter",
"retired" : "retired",
"subject":"c.subject",
"retire_date":"s.retire_date",
"sched_id" : "s.sched_id",
"num" : "count(*)" # number of instructors
}
wc = " i.instructor=login AND s.course_num=c.course_num AND s.subject=c.subject "
wc = wc + " AND s.retire_date=c.retire_date AND s.sched_id=i.sched_id "
if self.args['room']: # if room specified
wc = wc + " AND s.room rlike %(room)s "
if self.args['year']: # if year specified
wc = wc + " AND s.year=%(year)s "
else:
self.multiple_years = 1
if self.args['quarter']: #if specific quarter requested
wc = wc + " AND s.quarter=%(quarter)s "
else:
self.multiple_qtrs = 1
if self.args['subject']: # if subject specified
wc = wc + " AND s.subject=%(subject)s "
if self.args['c_number']: # if course number specified
wc = wc + " AND s.course_num=%(c_number)s "
if self.args['keywords']: # if keywords specified
wc = wc + " AND ( (lower(c.title) rlike lower(%(keywords)s)) OR "
wc = wc + "(lower(s.instructor) rlike lower(%(keywords)s)) OR "
wc = wc + "(lower(lname) rlike lower(%(keywords)s)) ) "
# convert data into secure SQL suitable form. This should not be done earlier
# as None becomes 'NULL'. If no condition on year was given (year=None).
# dont want a query like "where year=NULL". Dont modify self.args as
# other controls (HeaderControl) reads it to display default arguments
SQLargs = {}
for k,v in self.args.items():
SQLargs[k] = queries.represent_value(v)
wc = wc % SQLargs
groupby = "i.sched_id"; # group by this
order=('year DESC','subject', 'course_num', 'course_sec') # year in descending order
q = queries.Select(tables=tables,columns = columns,where=wc,order=order,groupby=groupby)
q.execute() # if no records returned then empty table displayed
self.query = q
def db_fetch(self):
self.fields = self.query.fetch()
if not self.fields:
return self.fields; # finished with the data
if self.fields['num'] > 1: # More than one instructor then get their info
tables=["instructorship","people"]
columns={ 'lname' : 'lname',
'fname' : 'fname',
'mname' : 'mname',
'login' : 'login',
'pseudo': 'pseudo or retired' }
wc = "login = instructor and sched_id="
wc = wc + queries.represent_value(self.fields['sched_id'])
q = queries.Select(tables=tables,columns=columns,where=wc)
q.execute()
self.instructors = q.fetchall() # get all the instructors
else:
self.instructors = [{'lname' : self.fields['lname'],
'fname': self.fields['fname'],
'mname': self.fields['mname'],
'login': self.fields['login'],
'pseudo':self.fields['pseudo'] or self.fields['retired']}]
self.fields['year'] = int(self.fields['year']) # else year is 2004L; python complains about 'long int'
return self.fields
def new(req):
return ScheduleDisplay(req)