| 1 | # Constants |
|---|
| 2 | hwys = ['','1','5', '22', '55', '57', '73', '74', '91', '133', '142', '241', '261', '405', '605'] |
|---|
| 3 | hwyDirections = ['','NB', 'SB', 'NB/SB','EB','WB','EB/WB'] |
|---|
| 4 | # Show the login page |
|---|
| 5 | def index(): |
|---|
| 6 | form = FORM(LABEL('Username:',_for='username', _class="label"), |
|---|
| 7 | INPUT(_name='username',_size='10'),BR(), |
|---|
| 8 | INPUT(_type='submit', _class="submit-button btn btn-primary")) |
|---|
| 9 | if form.process().accepted: |
|---|
| 10 | # Put the username entry into the session variable |
|---|
| 11 | session.username = form.vars.username |
|---|
| 12 | redirect(URL('home')) |
|---|
| 13 | return dict(form=form) |
|---|
| 14 | def home(): |
|---|
| 15 | return dict(name=session.username) |
|---|
| 16 | def help(): |
|---|
| 17 | return dict() |
|---|
| 18 | # List all the current records in the database - remove in final application |
|---|
| 19 | def list(): |
|---|
| 20 | highways = db().select(db.closures.ALL, orderby=db.closures.lognum) |
|---|
| 21 | return dict(highways = highways) |
|---|
| 22 | # Show details of a single record - remove in final application |
|---|
| 23 | def show(): |
|---|
| 24 | # Retrieve the requested log entry from the database |
|---|
| 25 | # Assumes the requested entry exists in the db (no error handling yet) |
|---|
| 26 | hwy = db(db.closures.lognum == request.args(0)).select().first() |
|---|
| 27 | return dict(hwy=hwy) |
|---|
| 28 | # Display a search form |
|---|
| 29 | def search(): |
|---|
| 30 | form = FORM(LABEL('ClosureID/Log:',_for='closureid', _class="label"), INPUT(_name='closureid',_size='7'),INPUT(_name='lognum',_size='3'),XML(' '), LABEL('Route: ',_for='route', _class="label"), SELECT(hwys,_name='route'), XML(' '), LABEL('Direction: ',_for='direction', _class="label"), SELECT(hwyDirections,_name='direction'), BR(),BR(),LABEL('Dates:',_for='startdate', _class="label") ,INPUT(_name='startdate',_class='date'), XML(' '), LABEL(' to:',_for='enddate', _class="label"), INPUT(_name='enddate',_class='date'),BR(),BR(),INPUT(_type='submit', _class="submit-button btn btn-primary")) |
|---|
| 31 | if form.process().accepted: |
|---|
| 32 | # Put the form fields into the session variables |
|---|
| 33 | session.closureid = form.vars.closureid |
|---|
| 34 | session.lognum = form.vars.lognum |
|---|
| 35 | session.startdate = form.vars.startdate |
|---|
| 36 | session.enddate = form.vars.enddate |
|---|
| 37 | session.route = form.vars.route |
|---|
| 38 | session.direction = form.vars.direction |
|---|
| 39 | redirect(URL('results')) |
|---|
| 40 | return dict(form=form) |
|---|
| 41 | # Show the item that was found in the search |
|---|
| 42 | def results(): |
|---|
| 43 | if (len(session.closureid) != 0): |
|---|
| 44 | hwy = db(db.closures.closureid == session.closureid).select() |
|---|
| 45 | msg = "Closure ID = " + session.closureid |
|---|
| 46 | elif (len(session.route) != 0): |
|---|
| 47 | hwy = db(db.closures.route == session.route).select() |
|---|
| 48 | msg = "route = " + session.route |
|---|
| 49 | elif (len(session.startdate) == 10): |
|---|
| 50 | hwy = db(db.closures.startdate >= session.startdate).select() |
|---|
| 51 | msg = "Start Date >= " + session.startdate |
|---|
| 52 | else: |
|---|
| 53 | hwy = db().select(db.closures.ALL) |
|---|
| 54 | msg = "ALL" |
|---|
| 55 | count = len(hwy) |
|---|
| 56 | # Show the results in table format. Get the radio call number from supervisor name lookup |
|---|
| 57 | 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'),TH('Limits'),TH('Work'), TH('TMP:',BR(),'Cozeep/',BR(),'Detour'),TH('Requestor/',BR(),'Radio Call No.'))) |
|---|
| 58 | multiform = [] |
|---|
| 59 | # Iterates over all search results |
|---|
| 60 | for row in hwy: |
|---|
| 61 | 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) |
|---|
| 62 | # Each row contains a form with two buttons and columns with fields from database |
|---|
| 63 | multiform.append(TR(TD( |
|---|
| 64 | XML("<button class='submit-button' onclick=showPopup(\'"),statusfields,XML("\')>View History</button>"),BR(), |
|---|
| 65 | FORM( |
|---|
| 66 | INPUT(_type='submit',_name='btn2',_value='Show Status Form',_class="submit-button" ), |
|---|
| 67 | INPUT(_type='hidden',_name='row',_value=row.closureid))), |
|---|
| 68 | 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),TD(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) )) |
|---|
| 69 | |
|---|
| 70 | session.chosenid = request.vars.row #Pass the hidden field containing the closure ID |
|---|
| 71 | if request.vars.btn2: |
|---|
| 72 | redirect(URL('statuslist')) |
|---|
| 73 | |
|---|
| 74 | return dict(msg=msg, count=count, highways=hwy, table=header, multiform=multiform) |
|---|
| 75 | |
|---|
| 76 | # Show the status box next to each search result |
|---|
| 77 | def statuslist(): |
|---|
| 78 | closedItems = [] |
|---|
| 79 | if (session.chosenid): |
|---|
| 80 | if (type(session.chosenid) is str): |
|---|
| 81 | retrieved = db(db.closures.closureid == session.chosenid).select().first() |
|---|
| 82 | closedItems.append(retrieved) |
|---|
| 83 | else: |
|---|
| 84 | # This logic is available to show multiple results, for possible future use. |
|---|
| 85 | for item in session.chosenid: |
|---|
| 86 | retrieved = db(db.closures.closureid == item).select().first() |
|---|
| 87 | closedItems.append(retrieved) |
|---|
| 88 | |
|---|
| 89 | form = FORM(BR(), |
|---|
| 90 | 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'))), |
|---|
| 91 | [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(LABEL('1097'), INPUT(_type='checkbox', _name='statustype', _value='1097'+row.closureid),LABEL('1098'), INPUT(_type='checkbox', _name='statustype', _value='1098'+row.closureid),LABEL('1022'), INPUT(_type='checkbox', _name='statustype', _value='1022'+row.closureid),BR(), LABEL('Statuser:'),INPUT(_name='statuser',_size='9'))) for row in closedItems], |
|---|
| 92 | _border='1', _cellpadding='5'),INPUT(_type='submit',_value="submit status form",_class="submit-button"),) |
|---|
| 93 | |
|---|
| 94 | else: |
|---|
| 95 | msg = "No items were selected. Use the checkbox in the lefthand column." |
|---|
| 96 | form = "" |
|---|
| 97 | return dict(msg=msg,form=form) |
|---|
| 98 | |
|---|
| 99 | if form.process().accepted: |
|---|
| 100 | #session.flash = 'Status submit acknowledgement appears here.' |
|---|
| 101 | session.statustype = form.vars.statustype |
|---|
| 102 | session.statuser = form.vars.statuser |
|---|
| 103 | redirect(URL('statusAck')) |
|---|
| 104 | return dict(form=form) |
|---|
| 105 | |
|---|
| 106 | # show status update acknowledgement - and update database |
|---|
| 107 | def statusAck(): |
|---|
| 108 | if (session.statustype): |
|---|
| 109 | if (type(session.statustype) is str): |
|---|
| 110 | msg = "You submitted a status update for " + session.statustype[4:] + ": " + session.statustype[0:4] |
|---|
| 111 | # Perform the update on the database |
|---|
| 112 | # Construct the name of the field to update |
|---|
| 113 | fieldname = "s"+session.statustype[0:4]+"user" |
|---|
| 114 | db(db.closures.closureid == session.statustype[4:]).update(**{fieldname:session.statuser}) |
|---|
| 115 | import datetime |
|---|
| 116 | now = datetime.datetime.today() |
|---|
| 117 | fieldname = "s"+session.statustype[0:4]+"date" |
|---|
| 118 | db(db.closures.closureid == session.statustype[4:]).update(**{fieldname:now.strftime("%Y%m%d")}) |
|---|
| 119 | fieldname = "s"+session.statustype[0:4]+"time" |
|---|
| 120 | db(db.closures.closureid == session.statustype[4:]).update(**{fieldname:now.strftime("%H%M")}) |
|---|
| 121 | else: |
|---|
| 122 | msg = "error because only checking one box is allowed." |
|---|
| 123 | else: |
|---|
| 124 | msg = "Error no statustype checkbox was checked" |
|---|
| 125 | |
|---|
| 126 | return dict(msg=msg) |
|---|
| 127 | # Utility functions for formatting |
|---|
| 128 | def formatTime(msg): |
|---|
| 129 | if (msg): |
|---|
| 130 | return msg[0:2]+':'+msg[2:4] |
|---|
| 131 | else: |
|---|
| 132 | return "" |
|---|
| 133 | # Create a new record |
|---|
| 134 | def submit(): |
|---|
| 135 | # Don't name this function 'request' because it creates a name conflict with http.request |
|---|
| 136 | 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'] |
|---|
| 137 | closuretypes = ['', 'Lane', 'Full', 'Moving', 'One-Way Traffic', 'Alternating Lanes', 'Traffic Break'] |
|---|
| 138 | facilities = ['', 'Connector', 'Conventional_Hwy', 'Mainline', 'Off Ramp', 'On Ramp', 'Rest Area', 'Surface Street'] |
|---|
| 139 | 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'] |
|---|
| 140 | supervisors = [''] # List of names for the dropdown box |
|---|
| 141 | # Obtain all the supervisor names from the database |
|---|
| 142 | for row in db().select(db.supervisors.ALL): |
|---|
| 143 | supervisors.append(row.name) |
|---|
| 144 | # Build the list of street locations and a hidden cross street lookup table |
|---|
| 145 | streets = [''] |
|---|
| 146 | streetlookup = [] |
|---|
| 147 | for row in db().select(db.streets.ALL, orderby=db.streets.street): |
|---|
| 148 | streets.append(row.street) |
|---|
| 149 | streetlookup.append(row.route + ',' + row.street) |
|---|
| 150 | |
|---|
| 151 | form = FORM( |
|---|
| 152 | LABEL('*Route',_for='route'), SELECT(hwys,_name='route', _id='routecombo', _onchange='routechanged()', requires=IS_LENGTH(minsize=1,error_message='route cannot be empty')), XML(' '), |
|---|
| 153 | LABEL('*Direction',_for='direction'), SELECT(hwyDirections,_name='direction', requires=IS_LENGTH(minsize=1,error_message='direction cannot be empty')), XML(' '), |
|---|
| 154 | LABEL('*Facility',_for='facility'), SELECT(facilities,_name='facility', requires=IS_LENGTH(minsize=1,error_message='facility cannot be empty')), BR(),BR(), |
|---|
| 155 | TABLE(TR(TD(),TD('*County'),TD('*Location')),TR(TD('BEGIN='),TD(SELECT('ORA',_name='startcounty')),TD(SELECT(streets,_name='startlocation',_id='startlocation')), |
|---|
| 156 | TR(TD('END='),TD(SELECT('ORA',_name='endcounty')),TD(SELECT(streets,_name='endlocation',_id='endlocation'))))),BR(), |
|---|
| 157 | 'Date Range:',BR(), |
|---|
| 158 | LABEL('From',_for='startdate'),INPUT(_name='startdate',_size='8',_class='date'), XML(' '), |
|---|
| 159 | LABEL('to:',_for='enddate'), INPUT(_name='enddate',_size='8',_class='date'),XML(' '), |
|---|
| 160 | LABEL('Times',_for='starttime'),SELECT(hournames,_name='starttime'), |
|---|
| 161 | LABEL(':',_for='starttimemin'),SELECT('','00','15','30','45','59',_name='starttimemin'), XML(' '), |
|---|
| 162 | LABEL('to:',_for='endtime'),SELECT(hournames,_name='endtime'), |
|---|
| 163 | LABEL(':',_for='endtimemin'),SELECT('','00','15','30','45','59',_name='endtimemin'), BR(),BR(), |
|---|
| 164 | TABLE(TR(TD('*Type of Closure'),TD('*Type of Work'),TD('Estimated Delay'),TD('TMP Details')), |
|---|
| 165 | TR(TD(SELECT(closuretypes,_name='closuretype',requires=IS_LENGTH(minsize=1,error_message='type of closure cannot be empty'))), |
|---|
| 166 | TD(SELECT(worktypes,_name='worktype', requires=IS_LENGTH(minsize=1,error_message='type of work cannot be empty'))), |
|---|
| 167 | TD(INPUT(_name='estdelay',_size='4'),'minutes'), |
|---|
| 168 | TD(INPUT(_type='checkbox',_name='cozeep'),'CoZeep MaZeep/CHP',BR(), |
|---|
| 169 | INPUT(_type='checkbox', _name='detour'),'Detour Available')), |
|---|
| 170 | _width='100%' ), |
|---|
| 171 | TABLE(TR(TD('*Supervisor'),TD('Field Rep')), |
|---|
| 172 | TR(TD(SELECT(supervisors,_name='supervisor', requires=IS_LENGTH(minsize=1,error_message='supervisor cannot be empty'))), |
|---|
| 173 | TD(SELECT(supervisors,_name='fieldrep')))), |
|---|
| 174 | TABLE(TR(TD('Meeting Place/CHP Contact'),TD('Reason for Closure'),TD('Additional Remarks / Detour ')), |
|---|
| 175 | TR(TD(INPUT(_name='meeting')),TD(INPUT(_name='reason',_size='40')),TD(INPUT(_name='remarks',_size='40'))) ), BR(), |
|---|
| 176 | INPUT(_type='submit',_value='Submit Closure'),XML('\n'),SELECT(streetlookup,_name='stlookup', _id='stlookup', _class='hideme')) |
|---|
| 177 | if form.process().accepted: |
|---|
| 178 | newID = calcNextClosure(form.vars.route) |
|---|
| 179 | # Insert the record into the database |
|---|
| 180 | newrec = db.closures.insert(closureid=newID, lognum='1', 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, worktype=form.vars.worktype, estdelay=form.vars.estdelay, tmpcozeep=getCheckbox(form.vars.cozeep), tmpdetour=getCheckbox(form.vars.detour), supervisor=form.vars.supervisor, fieldrep=form.vars.fieldrep, ) |
|---|
| 181 | session.flash = 'New lane closure added: ' + newID |
|---|
| 182 | redirect(URL('index.html')) |
|---|
| 183 | return dict(form=form) |
|---|
| 184 | |
|---|
| 185 | # Calculate the closure id to assign to the new closure |
|---|
| 186 | def calcNextClosure(routeNum): |
|---|
| 187 | # Retrieve any existing closures on this route |
|---|
| 188 | item = db(db.closures.closureid.startswith('T'+routeNum)).select().last() # Might need to sort these |
|---|
| 189 | if (item != None): |
|---|
| 190 | currID = item.closureid |
|---|
| 191 | lastchar = currID[-1:] # Get last character of ID |
|---|
| 192 | lastchar = chr(ord(lastchar) + 1) # increment it to next character (need bounds check) |
|---|
| 193 | newID = currID[:-1] + lastchar # append char to ID |
|---|
| 194 | return newID |
|---|
| 195 | else: |
|---|
| 196 | return 'T'+routeNum+'AA' # For a non-existing route |
|---|
| 197 | |
|---|
| 198 | # Convert checkbox value to YES/NO |
|---|
| 199 | def getCheckbox(ckBox): |
|---|
| 200 | if (ckBox == "on"): |
|---|
| 201 | return "YES" |
|---|
| 202 | else: |
|---|
| 203 | return "NO" |
|---|