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

Revision 622, 20.6 KB checked in by jdalbey, 6 years ago (diff)

LCS implement closed lane checkboxes

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