source: tmcsimulator/branches/LCSv2/controllers/default.py @ 626

Revision 626, 22.0 KB checked in by jdalbey, 6 years ago (diff)

LCS Add revision number to Help page. Add resetdb page.

Line 
1# added comments for testing
2# Constants
3hwys = ['','1','5', '22', '55', '57', '73', '74', '91', '133', '142', '241', '261', '405', '605']
4hwyDirections = ['','NB', 'SB', 'NB/SB','EB','WB','EB/WB']
5# Names to appeaer in the username dropdown box
6users = []
7# Show the login page
8def index():
9    userfile = open('student_names.txt','r')
10    users = [line.strip() for line in userfile.readlines()]
11    users.insert(0,'')
12    form = FORM(LABEL('User:',_for='username', _class="label username-label"),
13                #INPUT(_name='username', _size='15', _style="font-size: 18px;"), BR(),
14                SELECT(users,_name='username',requires=IS_LENGTH(minsize=1,error_message='Must select a user from the list.')),BR(),
15                INPUT(_type='submit',_value="Log in", _class=" btn btn-primary", _style="margin-top: 3%;"))
16    if form.process().accepted:
17        # Put the username entry into the session variable
18        session.username = form.vars.username
19        redirect(URL('home'))
20    return dict(form=form)
21def home():
22    return dict(name=session.username)
23def help():
24    return dict()
25# List all the current records in the database - remove in final application
26def list():
27    highways = db().select(db.closures.ALL, orderby=db.closures.closureid)
28    return dict(highways = highways)
29# Show details of a single record - remove in final application
30def show():
31    # Retrieve the requested log entry from the database
32    # Assumes the requested entry exists in the db (no error handling yet)
33    hwy = db(db.closures.lognum == request.args(0)).select().first()
34    return dict(hwy=hwy)
35# Display a search form
36def search():
37    form = FORM(LABEL('ClosureID/Log:',_for='closureid', _class="label"), 
38                INPUT(_name='closureid',_size='7', _style="margin-right: 5px;"),
39                INPUT(_name='lognum',_size='3'),
40                XML('   '), 
41                LABEL('Route: ',_for='route', _class="label"), 
42                SELECT(hwys,_name='route'), XML('   '), 
43                LABEL('Direction: ',_for='direction', _class="label"),
44                SELECT(hwyDirections,_name='direction'), BR(),BR(), 
45                LABEL('Dates:',_for='startdate', _class="label"), 
46                INPUT(_name='startdate',_class='date'), 
47                XML('   '), 
48                LABEL('  to:',_for='enddate', _class="label"), 
49                INPUT(_name='enddate',_class='date'),BR(),
50                INPUT(_value="Search", _type='submit', _class="btn btn-primary btn-default", _style="margin:  7% 45% 2% 40%;"))
51    if form.process(onvalidation=special_validation).accepted:
52        # Put the form fields into the session variables
53        session.closureid = form.vars.closureid.strip().upper()
54        session.lognum = form.vars.lognum.strip()
55        session.startdate = form.vars.startdate.strip()
56        session.enddate = form.vars.enddate.strip()
57        session.route = form.vars.route
58        session.direction = form.vars.direction
59        redirect(URL('results'))
60    return dict(form=form)
61# Search Form: Special validation check to reject lognum without closureID
62def special_validation(form):
63    # Error if a lognum was given and no closure id
64    if (len(form.vars.lognum) > 0 and len(form.vars.closureid) == 0):
65       form.errors.lognum = 'Must provide a closureID when specifying a log number'
66# Show the item that was found in the search
67def results():
68    # query object is equivalent to the where clause in query
69    query = True
70    msg = ""
71    if (len(session.closureid) != 0):
72        query = (db.closures.closureid == session.closureid)
73        msg += " Closure ID = " + session.closureid   
74    if (len(session.lognum) != 0):
75        query = query & (db.closures.lognum == session.lognum)
76        msg += " Log number = " + session.lognum   
77    if (len(session.route) != 0):
78        query = query & (db.closures.route == session.route)
79        msg += " Route = " + session.route
80    if (len(session.direction) != 0):
81        query = query & (db.closures.direction == session.direction)
82        msg += " Route = " + session.route
83    if (len(session.startdate) != 0):
84        query = query & (db.closures.startdate >= session.startdate)
85        msg += "Start date = " + session.startdate
86    if (len(session.enddate) != 0):
87        query = query & (db.closures.enddate <= session.enddate)
88        msg += "End date = " + session.enddate
89   
90    # if no restrictions entered then get all entries
91    if query == True :
92        hwy = db().select(db.closures.ALL)
93        msg = "ALL"
94    else:
95        # get entries with the matching requirements
96        hwy = db(query).select()
97
98    count = len(hwy)
99    # Show the results in table format.  Get the radio call number from supervisor name lookup
100    header = THEAD(TR(TH(''), TH('DTM',BR(),'Area'), TH('Closure ID/',BR(),'Log No.'),TH('Route & Dir/',BR(),'Type of Closure'),TH('Start Date/',BR(),'End Date/',BR(),'Est. Delay'),TH('Facility/Lanes'),TH('Limits'),TH('Work'), TH('TMP:',BR(),'Cozeep/',BR(),'Detour'),TH('Requestor/',BR(),'Radio Call No.')))
101    multiform = []
102    # Iterates over all search results
103    for row in hwy:
104        statusfields = row.closureid +','+ row.lognum + ',1097,' + str(row.s1097user) +','+ str(row.startdate) + ',' + formatTime(row.starttime) +','+str(row.s1097date)+','+ formatTime(row.s1097time) + ',1098,' + str(row.s1098user) +','+ str(row.s1098date)+','+ formatTime(row.s1098time)+ ',1022,' + str(row.s1022user) +','+ str(row.s1022date)+','+ formatTime(row.s1022time)
105        # Each row contains a form with two buttons and columns with fields from database
106        multiform.append(TR(TD(
107                    XML("<button class='submit-button' onclick=\"showPopup(\'"),statusfields,XML("\')\">View History</button>"),BR(),
108                    FORM(
109                          INPUT(_type='submit',_name='btn2',_value='Show Status Form',_class="submit-button" ),
110                          INPUT(_type='hidden',_name='row',_value=row.closureid))),
111                          TD(row.closureid[0]),TD(row.closureid,HR(),row.lognum), TD(row.route,' ',row.direction,HR(),row.closuretype), TD(row.startdate,' ',formatTime(row.starttime),HR(),row.enddate,' ',formatTime(row.endtime),HR(),row.estdelay), TD(row.facility,HR(),row.closedlanes),
112TD(row.startlocation,HR(),row.endlocation), TD(row.worktype), TD(row.tmpcozeep,BR(),row.tmpdetour), TD(row.supervisor,HR(),db(db.supervisors.name == row.supervisor).select().first().radiocallnum) )) 
113
114    session.chosenid = request.vars.row #Pass the hidden field containing the closure ID
115    if request.vars.btn2:
116        redirect(URL('statuslist'))
117    return dict(msg=msg, count=count, highways=hwy, table=header, multiform=multiform)
118
119# Show a selected closure with a status update form
120def statuslist():
121    closedItems = []
122    if (session.chosenid):
123        if (type(session.chosenid) is str):
124            retrieved = db(db.closures.closureid == session.chosenid).select().first()
125            closedItems.append(retrieved) 
126        else:
127            # This logic is available to show multiple results, for possible future use.
128            for item in session.chosenid:
129                retrieved = db(db.closures.closureid == item).select().first()
130                closedItems.append(retrieved) 
131        # Build the table rows       
132        tblrows = TR()       
133        for row in closedItems:
134            # Construct the status radio buttons; disable if date already in database
135            statusflags = "disabled" if row.s1097date == "" else "" 
136            if row.s1097date == "":
137                btn = LABEL('1097'), INPUT(_type='radio', _name='statustype', _value='1097'+row.closureid)
138            else:
139                btn = LABEL('1097 ○',_class='labelgray'),
140            btngroup = btn
141            if row.s1098date == "":
142                btn = LABEL('1098'), INPUT(_type='radio', _name='statustype', _value='1098'+row.closureid)
143            else:
144                btn = LABEL('1098 ○',_class='labelgray'),
145            btngroup += btn
146            if row.s1022date == "":
147                btn = LABEL('1022'), INPUT(_type='radio', _name='statustype', _value='1022'+row.closureid)
148            else:
149                btn = LABEL('1022 ○',_class='labelgray'),
150            btngroup += btn
151
152            if row.s1097date != "" and row.s1098date != "" and row.s1022date != "":
153                btngroup += BR(),LABEL('Statuser:', _class='labelgray')
154            else:   
155                btngroup += BR(),LABEL('Statuser:'),INPUT(_name='statuser',_size='9'),BR(),BR(),INPUT(_type='submit',_value="submit status update",_class="submit-button")
156#            LABEL('1097 ○',_class='colorgray'), INPUT(_type='radio', _name='statustype', _value='1097'+row.closureid),LABEL('1098'), INPUT(_type='radio', _name='statustype', _value='1098'+row.closureid),LABEL('1022'), INPUT(_type='radio', _name='statustype', _value='1022'+row.closureid),BR(), LABEL('Statuser:'),INPUT(_name='statuser',_size='9')
157            tblrows += TR(TD(row.closureid,HR(),row.lognum),TD(row.route,' ',row.direction,HR(),row.closuretype),TD(row.startdate,HR(),row.enddate,HR(),row.estdelay),TD(row.supervisor,BR(),db(db.supervisors.name == row.supervisor).select().first().radiocallnum),TD(btngroup))
158        form = FORM(BR(), 
159                TABLE(THEAD(TR(TH('Closure ID/',BR(),'Log No.'), TH('Route & Dir',BR(),'Type of Closure'),TH('Start Date/',BR(),'End Date/',BR(),'Est. Delay'),TH('Requestor/',BR(),'Radio Call No.'),TH('Status'))),
160                    tblrows,
161                     
162                    _border='1', _cellpadding='5', _width="70%"))
163       
164    else:
165        msg = "No items were selected.  Use the checkbox in the lefthand column."
166        form = ""
167        return dict(msg=msg,form=form)
168   
169    if form.process().accepted:
170        #session.flash = 'Status submit acknowledgement appears here.'
171        session.statustype = form.vars.statustype
172        session.statuser = form.vars.statuser
173        redirect(URL('statusAck'))
174    return dict(form=form)
175
176# show status update acknowledgement - and update database
177def statusAck():
178    if (session.statustype):
179        if (type(session.statustype) is str):
180            msg = "You submitted a status update for " + session.statustype[4:] + ": " + session.statustype[0:4] 
181#           Perform the update on the database
182            # Construct the name of the field to update
183            fieldname = "s"+session.statustype[0:4]+"user"
184            db(db.closures.closureid == session.statustype[4:]).update(**{fieldname:session.statuser})
185            import datetime 
186            now = datetime.datetime.today()
187            fieldname = "s"+session.statustype[0:4]+"date"
188            db(db.closures.closureid == session.statustype[4:]).update(**{fieldname:now.strftime("%Y-%m-%d")})
189            fieldname = "s"+session.statustype[0:4]+"time"
190            db(db.closures.closureid == session.statustype[4:]).update(**{fieldname:now.strftime("%H%M")})
191        else:
192            msg = "error because only checking one box is allowed."
193    else:
194        msg = "Error no statustype checkbox was checked"
195       
196    return dict(msg=msg)
197# Utility functions for formatting
198def formatTime(msg):
199    if (msg):
200        return msg[0:2]+':'+msg[2:4]
201    else:
202        return ""
203
204# Create a new record
205def submit():
206    # Don't name this function 'request' because it creates a name conflict with http.request
207    hournames = ['','00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
208    closuretypes = ['', 'Lane', 'Full', 'Moving', 'One-Way Traffic', 'Alternating Lanes', 'Traffic Break']
209    facilities = ['', 'Connector', 'Conventional_Hwy', 'Mainline', 'Off Ramp', 'On Ramp', 'Rest Area', 'Surface Street']
210    worktypes = ['','AC Paving', 'Accident Investigation', 'Attenuator Repair', 'Blasting', 'Bridge Inspection', 'Bridge Work', 'Brush Fire', 'Chip Seal Operation', 'Concrete Pour', 'Core Drilling', 'Crack Seal Operation', 'Curb/Gutter/Sidewalk Work', 'Drainage Cleaning', 'Drainage Inspection', 'Drainage Work', 'Electrical Work', 'Emergency Work', 'Falsework Installation', 'Falsework Removal', 'Fence Work', 'Filming Activity', 'Fog Seal Operation', 'Graffiti Removal', 'Grinding and Paving', 'Grinding Operation', 'Guardrail Repair', 'Guardrail Work', 'Highway Construction', 'K-rail Installation', 'K-rail Removal', 'Landscape Work', 'Litter Removal', 'Maintenance Operation', 'Median Barrier Work', 'Miscellaneous Work', 'Pavement Marker Replacement', 'Pavement Repair', 'Pavement Work', 'Paving Operation', 'Pile Driving', 'Police Investigation', 'Roadway Excavation', 'Roadway Flooding', 'Sewer Work', 'Shoulder Work', 'Sign Work', 'Slab Replacement', 'Slide Removal', 'Slope Clearing', 'Soundwall Work', 'Special Event', 'Spray Operation', 'Striping Operation', 'Survey Work', 'Sweeping Operation', 'Traffic Signal Work', 'Tree Work', 'Utility Work', 'Vegetation Spraying']
211    supervisors = ['']  # List of names for the dropdown box
212    # Obtain all the supervisor names from the database
213    for row in db().select(db.supervisors.ALL):
214        supervisors.append(row.radiocallnum + ' ' + row.name)
215    crew = ['']  # List of names for the dropdown box
216    crewlookup = []
217    # Obtain all the crew names from the database
218    for row in db().select(db.crew.ALL):
219        crew.append(row.radiocallnum + ' ' + row.name)
220        crewlookup.append(row.radiocallnum + ' ' + row.name)
221    # Build the list of street locations and a hidden cross street lookup table
222    streets = ['']
223    streetlookup = []
224    for row in db().select(db.streets.ALL, orderby=db.streets.street):
225        streets.append(row.street)
226        streetlookup.append(row.route + ',' + row.street)
227    # Build the list of existing closures   
228    existingclosures = []
229    existingclosures.append("")
230    for row in db().select(db.closures.ALL, orderby=db.closures.closureid):
231        # Omit duplicate ID's (with different lognumbers)
232        if row.closureid not in existingclosures:
233            existingclosures.append(row.closureid)
234       
235    form = FORM(
236                LABEL('*Route',_for='route'), SELECT(hwys,_name='route', _id='routecombo', _onchange='routechanged()', requires=IS_LENGTH(minsize=1,error_message='route cannot be empty')), XML('&nbsp;&nbsp;&nbsp;'), 
237           LABEL('*Direction',_for='direction'), SELECT(hwyDirections,_name='direction', requires=IS_LENGTH(minsize=1,error_message='direction cannot be empty')), XML('&nbsp;&nbsp;&nbsp;'), 
238           LABEL('*Facility',_for='facility'), SELECT(facilities,_name='facility', _id='facilitycombo', requires=IS_LENGTH(minsize=1,error_message='facility cannot be empty')), BR(),BR(), 
239           TABLE(TR(TD(),TD(LABEL('*County')),TD(LABEL('*Location'))),
240                TR(TD(LABEL('BEGIN=')),TD(SELECT('ORA',_name='startcounty')),
241                TD(SELECT(streets,_name='startlocation',_id='startlocation')),
242           TR(TD(LABEL('END=')),TD(SELECT('ORA',_name='endcounty')),TD(SELECT(streets,_name='endlocation',_id='endlocation'))))),BR(),
243           LABEL('Date Range:'),BR(),
244           LABEL('From',_for='startdate'),INPUT(_name='startdate',_size='8',_class='date'), XML('&nbsp;&nbsp;&nbsp;'), 
245           LABEL('to:',_for='enddate'), INPUT(_name='enddate',_size='8',_class='date'),XML('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'), 
246           LABEL('Times',_for='starttime'),SELECT(hournames,_name='starttime'), 
247           LABEL(':',_for='starttimemin'),SELECT('','00','15','30','45','59',_name='starttimemin'), XML('&nbsp;&nbsp;'), 
248           LABEL('to:',_for='endtime'),SELECT(hournames,_name='endtime'), 
249           LABEL(':',_for='endtimemin'),SELECT('','00','15','30','45','59',_name='endtimemin'), BR(),BR(), 
250           TABLE(TR(TD(LABEL('*Type of Closure') ),
251                    TD(LABEL('*Type of Work')),
252                    TD(LABEL('Estimated Delay')),
253                    TD(LABEL('TMP Details'))), 
254                 TR(TD(SELECT(closuretypes,_name='closuretype',_id='closuretype', _onchange='closuretypechanged()',requires=IS_LENGTH(minsize=1,error_message='type of closure cannot be empty'))), 
255                    TD(SELECT(worktypes,_name='worktype', requires=IS_LENGTH(minsize=1,error_message='type of work cannot be empty'))), 
256                    TD(INPUT(_name='estdelay',_size='4'),'minutes'), 
257                    TD(INPUT(_type='checkbox',_name='cozeep'),'CoZeep MaZeep/CHP',BR(), 
258                       INPUT(_type='checkbox', _name='detour'),'Detour Available')),
259                 TR(TD(DIV(LABEL("Lanes closed"),DIV(INPUT(_type='checkbox', _name='lanes', _id='lanes', _value=' '), _id='boxes'),_id='lanechooser',_style='display:none')),
260                    TD(INPUT(_type='hidden', _name='lanecount', _id='lanecount', _value='4')),
261                    TD(),
262                    TD()),
263                 _width='100%' ),
264    TABLE(TR(TD(LABEL('*Supervisor')),
265            TD(LABEL('Field Rep'))
266            ), 
267          TR(TD(SELECT(supervisors,_name='supervisor', _id='supervisorcombo', _onchange='supervisorchanged()', requires=IS_LENGTH(minsize=1,error_message='supervisor cannot be empty'))),
268             TD(SELECT(crew,_name='fieldrep',_id='fieldrep')),
269             TD(XML("&nbsp;&nbsp;&nbsp;&nbsp;")),
270             TD('Is this an existing incident?',
271                INPUT(_type='radio',_name='existing',_value='No',_onclick='radioclicked()'),
272                'No',
273                INPUT(_type='radio',_name='existing',_value='Yes',value='Yes',_onclick='radioclicked()'),
274                'Yes'
275               )
276             ),
277          TR(TD(),TD(),TD(), TD('    Select closure ID:',SELECT(existingclosures,_name='existingid'),_id='closureselect'))),
278    TABLE(TR(TD( LABEL('Meeting Place/CHP Contact')),
279            TD(LABEL('Reason for Closure')),
280            TD(LABEL('Additional Remarks / Detour '))), 
281                  TR(TD(INPUT(_name='meeting', _size='25')),TD(INPUT(_name='reason',_size='25')),TD(INPUT(_name='remarks',_size='25'))) ), BR(), 
282            INPUT(_type='submit',_value='Submit Closure', _class="btn btn-primary btn-default", _style="margin:  2% 45% 2% 40%;"),
283            XML('\n'),SELECT(streetlookup,_name='stlookup', _id='stlookup', _class='hideme'), 
284SELECT(crewlookup,_name='crewlookup', _id='crewlookup', _class='hideme')) 
285
286    if form.process(onvalidation=validate_existing_id).accepted:
287        newLognum = calcNextLogNum(form.vars.existingid)
288        if newLognum == '1':
289            newID = calcNextClosureID(form.vars.route)
290        else:
291            newID = form.vars.existingid
292        supervisor_name = form.vars.supervisor[3:]
293        fieldrep_name = form.vars.fieldrep[5:]
294        selectedlanes = buildLanesClosedString(form.vars.lanes,form.vars.lanecount)
295        # Insert the record into the database
296        newrec = db.closures.insert(closureid=newID, lognum=newLognum, route=form.vars.route, direction=form.vars.direction, facility=form.vars.facility, startcounty=form.vars.startcounty, endcounty=form.vars.endcounty, startlocation=form.vars.startlocation, endlocation=form.vars.endlocation, startdate=form.vars.startdate, enddate=form.vars.enddate, starttime=form.vars.starttime+form.vars.starttimemin, endtime=form.vars.endtime+form.vars.endtimemin, closuretype=form.vars.closuretype, closedlanes=selectedlanes, worktype=form.vars.worktype, estdelay=form.vars.estdelay, tmpcozeep=getCheckbox(form.vars.cozeep), tmpdetour=getCheckbox(form.vars.detour), supervisor=supervisor_name, fieldrep=fieldrep_name, s1097date='', s1098date='', s1022date='' )
297        session.flash = 'New lane closure added: ' + newID + ' ' + newLognum + ': ' + selectedlanes
298        redirect(URL('search.html'))
299    return dict(form=form)
300
301# An unlinked page to allow admin to reset the database to simulation start state
302def resetdb():
303    form = FORM("Press this button to reset the closure database to its original state at the start of a simulation.",BR(),
304                "Warning: this will delete all the current closures.",BR(),
305                "Import filename is 'db_closures_start.csv'.",BR(),
306                INPUT(_value="Reset Database", _type='submit', _class="btn btn-primary btn-default"))
307    if form.process().accepted:
308        db(db.closures.id > 0).delete()   # remove all current records
309        with open('db_closures_start.csv', 'rb') as dumpfile:
310            db.closures.import_from_csv_file(dumpfile)  # import from starting state
311        session.flash = 'Closure database has been reset'
312        redirect(URL('search.html'))
313    return dict(form=form)
314
315# Validation for existing closure button
316# If user selected Yes (it's existing incident) then they must select a closure ID
317def validate_existing_id(form):
318    if form.vars.existing == 'Yes' and form.vars.existingid == '':
319        form.errors.existingid = "Existing incidents require selecting an existing closure ID"
320
321# Calculate the closure id to assign to the new closure
322def calcNextClosureID(routeNum):
323    # Retrieve the last existing closure on this route
324    #item = db(db.closures.closureid.startswith('T'+routeNum)).select().last() # defective
325    item = db(db.closures.route == routeNum).select().last() 
326    if (item != None):
327        currID = item.closureid
328        lastchar = currID[-1:]  # Get last character of ID
329        lastchar = chr(ord(lastchar) + 1) # increment it to next character (need bounds check)
330        newID = currID[:-1] + lastchar  # append char to ID
331        return newID
332    else:
333        return 'T'+routeNum+'AA'  # For a non-existing route
334   
335# If existing incident closure ID is provided, increment the log number by 1
336def calcNextLogNum(existingid):
337    if existingid != '':
338        item = db(db.closures.closureid.startswith(existingid)).select().last()
339        prevLog = int(item.lognum)
340        nextLog = prevLog + 1
341        return str(nextLog)
342    else:
343        return '1'
344
345
346# Convert checkbox value to YES/NO
347def getCheckbox(ckBox):
348    if (ckBox == "on"):
349        return "YES"
350    else:
351        return "NO"
352
353# Convert the lanes closed checkboxes into a human readable string
354# E.g.  #1 #3 of 4
355# Note: ckBoxGroup parameter contains only checked items
356def buildLanesClosedString(ckBoxGroup,lanecount):
357    result = ""
358    if ckBoxGroup is not None:
359        # Append each checked value to a string
360        for item in ckBoxGroup:
361            result = result + "#"+item + " "
362        result = result + "of " + lanecount
363    return result
Note: See TracBrowser for help on using the repository browser.