Display Diary
John Hurst
Version 0.1.4
20050726:133108
Table of Contents
1. Introduction
This program is responsible for handling John's Appointments
Pages. There are two main parts to it: the display of the
current diary, and the appointment making confirmation page.
The diary display is the main point of entry. It reads a diary
file and generates a graphical web page which represents each
day's activities in a colour coded line of the display. Each
free time slot is displayed in green, and each engaged time slot
is displayed in red. Each time slot is a clickable link to the
script, which goes through a process of confirming a new
appointment.
The second part is this appointment confirmation process: the
requested date and time is displayed, and can be changed. The
length of the appointment is also changeable. Once the user
confirms the parameters of the appointment, it is checked
against the diary, and an appropriate message displayed. Note
that this program does NOT change the diary itself: that is done
by ajh in confirming the date and time. For this purpose, the
user's e-mail address is also collected. When a satisfactory
time is found, the details are emailed to ajh for confirmation.
2. Main Program
"ajhdiary.py" 1 =#!/usr/bin/python
<import definitions 2>
(year, month, day, hour, minute, second, weekday, yday, DST) = \
time.localtime(time.time())
today = datetime.date.today()
<define diary page parameters 8>
<define variables 3,29>
<define procedures 9,10,20,21,28,30,31,32,33>
<define generate web page 7>
<define confirm appointment times 19>
<define diary click handler 18>
<define grab details 24>
<define the email confirmation procedure 27>
<read diary file and collect appointments 5>
<collect cgi parameters and invoke appropriate part 6>
Define all import quotas and restrictions here
<import definitions 2> =from appointments import Appointment,acmp
{Note 2.1}
import cgi
import datetime
import os
import re
import string
import sys
import time
- {Note 2.1}
-
appointments is
a locally written module defining one class:
Appointment. The function acmp compares two
appointment instances and returns a cmp-type value for use in
comparisons.
<define variables 3> =year=2005
month=1
day=1
hour=0
minute=0
monthnames=["January","February","March","April","May","June",\
"July","August","September","October","November","December"]
<define server addresses 4>
Chunk referenced in 1Chunk defined in 3,
29
<define server addresses 4> =
3. Read the Diary
The diary is a text file, while each line representing a
single appointment. While the appointments may appear in any
order, in practice they are arranged chronologically, and
each day can be prefaced with a day of the week line. It is
generally assumed that appointments are wholly contained
within a single day, but multiple day appoints are possible,
and are represented by the end and start times running
across midnight.
Format of diary file:
diary = line * .
line = dayoftheweek ! appointment .
dayoftheweek = date ' '{11} '=== ' weekday ' ===' .
appointment = date ' ' starttime '-' endtime ' ' activity (' (' location ')')? .
date = YYYY MM DD .
YYYY = digit{4} .
MM = digit{2} .
DD = digit{2} .
starttime = time .
endtime = time .
time = hh mm .
hh = digit{2} .
mm = digit{2} .
weekday = 'Mon' | 'Tue' | 'Wed' | 'Thu' | 'Fri' | 'Sat' | 'Sun' .
Example of a diary file:
20050121 === Fri ===
20050121 1000-1100 Judy Sheard (75.G58)
20050123 === Sun ===
20050123 1000-1100 Church
20050124 === Mon ===
20050124 1000-1100 Kelsey (75.G58)
20050125 === Tue ===
20050125 1030-1500 Swinburne
20050126 === Wed ===
20050126 0000-0000 Australia Day
20050126 0000-0000 Leave
20050127 === Thu ===
20050127 0900-1600 Course Advice
<read diary file and collect appointments 5> =linepat=re.compile(r'(....)(..)(..) (..)(..)-(..)(..) ([^(]*)(\((.*)\))?$')
diaryfile=open('%s/diary' % webhomedir,'r')
apps=[]
for line in diaryfile.readlines():
line=string.rstrip(line)
{Note 5.1}
res=linepat.match(line)
{Note 5.2}
if res:
{Note 5.3}
start=datetime.datetime(year=int(res.group(1)),month=int(res.group(2)),\
day=int(res.group(3)),hour=int(res.group(4)),\
minute=int(res.group(5)))
end =datetime.datetime(year=int(res.group(1)),month=int(res.group(2)),\
day=int(res.group(3)),hour=int(res.group(6)),\
minute=int(res.group(7)))
activity=location=''
if res.group(8):
activity=res.group(8)
if res.group(10):
location=res.group(10)
newap=Appointment(start=start,end=end,activity=activity,location=location)
{Note 5.4}
apps.append(newap)
{Note 5.5}
diaryfile.close()
diaryfile=open('%s/diary.new' % webhomedir,'r')
{Note 5.6}
for line in diaryfile.readlines():
line=string.rstrip(line)
res=linepat.match(line)
if res:
start=datetime.datetime(year=int(res.group(1)),month=int(res.group(2)),\
day=int(res.group(3)),hour=int(res.group(4)),\
minute=int(res.group(5)))
end =datetime.datetime(year=int(res.group(1)),month=int(res.group(2)),\
day=int(res.group(3)),hour=int(res.group(6)),\
minute=int(res.group(7)))
activity=location=''
activity='unconfirmed'
if res.group(10):
location=res.group(10)
newap=Appointment(start=start,end=end,activity=activity,location=location)
apps.append(newap)
diaryfile.close()
apps.sort(acmp)
{Note 5.7}
- {Note 5.1}
- remove the end of line character
- {Note 5.2}
- Match the line for the
appointment non-terminal.
- {Note 5.3}
- we have an appointment, extract field values and make new appointment
- {Note 5.4}
- Make the new appointment
- {Note 5.5}
- and add it to the set of appointments so far
- {Note 5.6}
- repeat the above with the unconfirmed appointments in diary.new
- {Note 5.7}
- all done, sort the appointments into chronological order
4. Collect CGI Parameters
This is where the various phases of the appointments web page
are split off. Each phase is flagged by a cgi parameter, except
for the initial phase, that of the display of the diary, which
normally has no parameters (but can be explicitly invoked with a
diary parameter). Note also that the clicking of a time
bar in the diary display has no explicit phase parameter, but
relies upon the
<collect cgi parameters and invoke appropriate part 6> =
5. Generate Web Page
The front end to this program suite. When first invoked, the
ajhdiary program displays a graphical rendition of free
and busy times. Each time is a clickable link to make an
appointment. This routine is responsible for rendering this
diary page.
<define generate web page 7> =
<define diary page parameters 8> =
- {Note 8.1}
- hour of day when diary display
starts
- {Note 8.2}
- hour of day when diary display ends
- {Note 8.3}
- granularity in minutes of appointment times
- {Note 8.4}
- length in hours of display
- {Note 8.5}
- number of appointment start times
per hour
- {Note 8.6}
- number of appointment
start times per day
5.1 Procedures
The mergeflags procedure is used to reduce adjacent
time slots that have different engagements to one engagement
value. This is because the granularity of the appointments
is 5 minutes (adjustable in the chunk <define diary page parameters >), and appointments may overlap within
this range. The codes mean:
- A
- appointment at Caulfield
- L
- appointment at Clayton
- *
- appointment at unknown place
- a
- free at Caulfield
- l
- free at Clayton
- u
- unconfirmed appointment
<define procedures 9> =def
mergeflags(x,y):
if x==y: return x
else: return '-'
<define procedures 10> =def
withinApp(r,d,a):
s=a.start
rdate=datetime.date(year=r.year,month=r.month,day=r.day)
adate=datetime.date(year=s.year,month=s.month,day=s.day)
if rdate != adate: return 0
e=a.end
if s.hour==0 and s.minute==0:
#print a.activity
if re.match(r'.*(L|l)eave',a.activity):
return 'leave'
rtime=datetime.time(hour=r.hour,minute=r.minute)
stime=datetime.time(hour=s.hour,minute=s.minute)
etime=datetime.time(hour=e.hour,minute=e.minute)
if rtime<stime: return 0
if rtime>=etime: return 0
return "busy"
5.2 Initialization
We need to start the web diary display with today. Since
there may be appointments recorded before today, we skip any
of them, and then initialize the various variables required
for the web display.
<initialize web page variables 11> =
- {Note 11.1}
-
If there are any appointments, skip any that occur before
the first day of display (today).
- {Note 11.2}
- define the start date displayed
in the web page
- {Note 11.3}
- The number of days displayed in the web page
- {Note 11.4}
-
define the finish date displayed in the web page. This will be
lengthInDays long.
- {Note 11.5}
-
initialize all slots to free
<initialize web page 12> = print "Content-type: text/html\n\n"
<print web page heading 13> =print """
<HTML BGCOLOR="white">
<HEAD>
<TITLE>AJH Diary Page</TITLE>
</HEAD>
<BODY>
<H1>Welcome to John Hurst's Diary Page!</H1>
<P>The following table lists all of John Hurst's appointments for
the next eight weeks.</P>
<p>The first column is the date (in ISO format), followed by the day
of the week. Each appointment is indicated by a red bar
(<IMG SRC="http://localhost/ajh/graphics/bookedhour.gif"/>),
free times are shown in green
(<IMG SRC="http://localhost/ajh/graphics/freehour.gif"/>),
and unconfirmed times are shown as yellow
(<IMG SRC="http://localhost/ajh/graphics/tentativehour.gif"/>).
Times when I am on leave are shown as light blue
(<IMG SRC="http://localhost/ajh/graphics/Leave.png"/>).
Each hour interval is marked by a vertical black line.</p>
<P>Where details of my location are known, the campus is overprinted
on the red strip.</P>
<P>If you wish to contact me, or make an appointment, or schedule
a meeting, then position the cursor over the desired date and
time and click. You will be then asked to confirm the date, time
and duration of the appointment, and enter your personal details.
Note that red, yellow or blue times will be rejected, so you should
select only green areas. You can further refine the date and
time once you enter the confirm page.</P>
<P>Note that Mondays are normally "research days", when I am
based at Caulfield. </P>
"""
<print form 14> =
<skip saturdays and sundays 15> =weekday=date.weekday()
if weekday>=5: # sat or sun
if weekday>=6: # sun
print "<TR><TD> </TD></TR>"
print "<TR>"
print "<TD></TD><TD></TD>"
print "<TD></TD><TD></TD>"
for h in range(
hourSlotsInDay):
hs=h+
daystart; he=hs+1
imagename="%02d%02d.gif" % (hs,he)
print "<TD>"+hourmark+"</TD>"
print "<TD><IMG SRC=\"%s/graphics/%s\"/></TD>" % (server,imagename)
print "<TD>"+hourmark+"</TD>"
print "</TR>"
#print "<TR><TD> </TD></TR>"
while apps[curapp].start == date:
curapp=curapp+1
date=date+datetime.timedelta(days=1)
continue
<print a diary day 16> =print "<TR>"
print "<TD>"+date.strftime("%Y%m%d")+"</TD>"
print "<TD WIDTH=\"10\">"+" "+"</TD>"
print "<TD>"+date.strftime("%a")+"</TD>"
print "<TD WIDTH=\"10\">"+" "+"</TD>"
for h in range(0,
hourSlotsInDay):
print "<TD>"+hourmark+"</TD>"
hs=h+
daystart; he=hs+1
hourrange="%02d00-%02d00" % (hs,he)
if dayslots[h]==' ':
image="freehour.gif"; alt="free"
elif dayslots[h]=='h':
image="Leave.png"; alt="on leave"
elif dayslots[h]=='a':
image="Caulfield-free.png"; alt="Caulfield free"
elif dayslots[h]=='*':
image="bookedhour.gif"; alt="busy"
elif dayslots[h]=='L':
image="Clayton-appt.png"; alt="Clayton"
elif dayslots[h]=='A':
image="Caulfield-appt.png"; alt="Caulfield"
elif dayslots[h]=='u':
image="tentativehour.gif"; alt="unconfirmed"
else:
pass
if dayslots[h]!='-':
line="%s/graphics/%s\" ALT=\"%s %s\"" % (server,image,hourrange,alt)
button="INPUT type=\"image\" name=\"%s:%s %s\"" % (date,hourrange,alt)
line="<"+button+" SRC=\""+line+"></INPUT>"
else:
ms=0;me=5;
line=''
for k in range(h*quantaPerSlot,(h+1)*quantaPerSlot):
hourrange="%02d%02d-%02d%02d" % (hs,ms,hs,me)
if slots[k]==' 'or slots[k]=='a':
image="free.gif"; alt="free"
elif slots[k]=='u':
image="tentative.gif"; alt="unconfirmed"
else:
image="booked.gif"; alt="busy"
link="%s/graphics/%s\" ALT=\"%s %s\"" % (server,image,hourrange,alt)
button="INPUT type=\"image\" name=\"%s:%s %s\"" % (date,hourrange,alt)
line=line+"<"+button+" SRC=\""+link+"></INPUT>"
ms=ms+5;me=me+5
print "<TD>"+line+"</TD>"
print "<TD>"+hourmark+"</TD>"+"</TR>"
slots=[' ' for i in range(quantaInDay)]
<handle all appointments for this date 17> =while apps[curapp].start == date:
cur=apps[curapp]
#print cur
flag='*'
res0=re.match(r'Leave',cur.activity)
res1=re.match('Caulfield',cur.location)
res2=re.match('Caulfield Day',cur.activity)
res3=re.match(r'(Clayton)|(75\.)',cur.location)
res5=re.match(r'(CSE4213)',cur.activity)
res6=re.match(r'(unconfirmed)',cur.activity)
if res0:
{Note 17.1}
for i in range(quantaInDay):
slots[i]='h'
elif res3 or res5:
flag='L'
elif res1:
flag='A'
elif res2:
for i in range(quantaInDay):
if slots[i]==' ':
slots[i]='a'
elif res6:
flag='u'
if cur.start.hour > 0:
st=12*(cur.start.hour-
daystart)+cur.start.minute/quantum
en=12*(cur.end.hour-
daystart)+cur.end.minute/quantum
#print "st=%d,en=%d " % (st,en)
if st >= 0 and en < 12*(dayend-
daystart):
pass
else:
if st < 0:
st = 0
if en > 12*(dayend-
daystart):
en = 12*(dayend-
daystart)
#print "st=%d,en=%d " % (st,en)
for t in range(st,en):
if slots[t] != 'h':
{Note 17.2}
slots[t]=flag
#print slots
curapp=curapp+1
- {Note 17.1}
- 'Leave' overrides all other entries
- {Note 17.2}
- Don't override holidays!
6. Confirm Appointment Date and Time
There are two parts to the confirmation of appointment time,
because one entry point is from the diary page, and a click on a
time bar, while the other entry point is when the user changes
the time within the confirm page, and wishes to recheck the
availablity. The first is handled by doDiryClick, while
the second is handled by confirmAppointment.
6.1 The doDiaryClick procedure
doDiaryClick is called when the user clicks on a time
bar in the diary display. The handling of this requires a
little skullduggery, since the parameters passed to the cgi call
are x,y coordinates within the image bar, which are basically of
no use. However, the name of the image is part of the parameter
name, and hence we can use that to find which image was clicked,
and hence what date and time for which the user wishes to make
an appointment.
We do this by examining the first form parameter (which happens
to be the x coordinate, but that is of no consequence here). It
is of the form:
2005-02-01:1600-1700 free
which encodes the year, month, day, time range and activity.
By pattern matching against this, we determine the desired
appointment time, and pass that to the appointment time
confirmation process.
<define diary click handler 18> =def
doDiaryClick(form):
value=formkeys[0]
res=re.match(r'(.*)\.x$',value)
if res:
value=res.group(1)
else:
print "Cannot extract parameter from %s" % (value)
exit
res=re.match(r'(\d{4})-(\d{2})-(\d{2}):(\d{2})(\d{2})-(\d{2})(\d{2})(.*)$',value)
year=int(res.group(1))
month=int(res.group(2))
day=int(res.group(3))
sh=int(res.group(4))
sm=int(res.group(5))
eh=int(res.group(6))
em=int(res.group(7))
activity=res.group(8)
dur=60*(eh-sh)+(em-sm)
handleConfirm(year,month,day,sh,sm,eh,em,dur)
6.2 The confirmAppointment procedure
confirmAppointment is called when the users changes
the appointment date or time, and wishes to recheck the
availability. In this situation, all the date and time
parameters are passed directly, and we do not need to do the
same decoding trick used in doDiaryClick. However, we
still end up in the handleConfirm procedure as before.
<define confirm appointment times 19> =def
confirmAppointment(form):
year=int(form['year'].value)
monthname=form['month'].value
month=monthnames.index(monthname)+1
day=int(form['day'].value)
sh=int(form['hour'].value)
sm=int(form['minute'].value)
eh=sh; em=sm
duration=form['duration'].value
dur=
convertDurationToInteger(duration)
name='appoint'
value=form['appointtime'].value
#print "<P>Got appoint parms %04d,%02d,%02d</P>" % (year,month,day)
handleConfirm(year,month,day,sh,sm,eh,em,dur)
6.3 Support Operations for Appointment Confirmation
<define procedures 20> =def printReturn(msg):
print "<P>%s</P>" % (msg)
<define procedures 21> =def handleConfirm(year,month,day,sh,sm,eh,em,dur):
printHtmlHeaders("Confirm Appointment Data and Time")
monthname=monthnames[month-1]
print "<P>You have asked for an appointment on %d %s %4d, " % (day,monthname,year)
print "starting at %02d:%02d " % (sh,sm)
print "for %3d minutes" % (dur)
#print "Activity: %s</P>" % (activity)
req=datetime.datetime(year=year,month=month,day=day,hour=sh,minute=sm)
print """<P>If you wish, you can change the date, time or duration
before confirming. If you do change the date or time, make sure
to click the changed time button.</P>"""
<check time in appointments list 22>
<print check response 23>
print "<FORM action=\"%s/ajhdiary.py\" method=\"post\">" % (cgiserver)
print "<P>Date: "
popupMenu("year",[2005,2006,2007],year)
popupMenu("month",monthnames,monthname)
popupMenu("day",range(1,32),day)
print "</P><P>Time (24hr): "
popupMenu("hour",range(
daystart,dayend),sh)
popupMenu("minute",range(0,60,5),sm)
print "</P><P>Duration: "
duration=
convertDurationToString(dur)
durtimes=['0:05 mins','0:10 mins','0:15 mins','0:20 mins','0:30 mins','0:40 mins','0:45 mins','1:00 hour','1:15 hours','1:30 hours','2:00 hours','> 2 hours']
popupMenu("duration",durtimes,duration)
print "</P>"
datentime="%04d-%02d-%02d:%02d%02d-%02d%02d" % (year,month,day,sh,sm,eh,em)
print "<INPUT type=\"hidden\" name=\"appointtime\" value=\"%s\"/>" % (datentime)
msg="I've changed the time, please check if it is available"
mode='appoint'
print "<INPUT type=\"submit\" name=\"%s\" value=\"%s\"></INPUT>\n" % (mode,msg)
if not res:
msg="I'm happy with this time. Click to Confirm"
mode='details'
print "<INPUT type=\"submit\" name=\"%s\" value=\"%s\"></INPUT>\n" % (mode,msg)
print "</FORM>"
<check time in appointments list 22> =res=0
for ap in apps:
res =
withinApp(req,dur,ap)
if res: break
<print check response 23> =#print "<P>%s</P>" % (res)
if res=='leave':
print "<H2>"
printReturn("Sorry, John is on leave then. Please select another time.")
print "</H2>"
if res=='busy':
print "<H2>"
printReturn("Sorry, John is not available then. Please select another time.")
print "</H2>"
Chunk referenced in 21 24
7. Grab User Details
<define grab details 24> =
<define textBox 25>
<define hiddenData 26>
def
grabDetails(val):
printHtmlHeaders("Enter Your Details")
#print form
name=''
email=''
why=''
year=int(form['year'].value)
monthname=form['month'].value
month=monthnames.index(monthname)+1
day=int(form['day'].value)
sh=int(form['hour'].value)
sm=int(form['minute'].value)
eh=sh; em=sm
duration=form['duration'].value
dur=
convertDurationToInteger(duration)
if form.has_key('Name'):
name=form['Name'].value
if form.has_key('EMail'):
email=form['EMail'].value
if form.has_key('Purpose'):
why=form['Purpose'].value
loc=''
if form.has_key('Location'):
loc=form['Location'].value
req=datetime.datetime(year=year,month=month,day=day,hour=sh,minute=sm)
res=0
for ap in apps:
res = withinApp(req,dur,ap)
if res: break
if res:
<print check response 23>
print "<P>Please use your browser back button to return and correct the time</P>\n"
sys.exit(0)
#print "<P>Got appoint parms %04d,%02d,%02d</P>" % (year,month,day)
print "<P>You have asked to make an appointment for %d %s %4d, " % (day,monthname,year)
print "starting at %02d:%02d " % (sh,sm)
print "for %d minutes." % (dur)
#print "Activity: %s</P>" % (activity)
print "<P>Please enter the following details about yourself: "+\
"(Please bear in mind that the appointment is not confirmed "+\
"until these details are supplied)</P>"
req=datetime.datetime(year=year,month=month,day=day,hour=sh,minute=sm)
print "<FORM action=\"%s/ajhdiary.py?details\" method=\"post\">\n" % (cgiserver)
hiddenData('year',year)
hiddenData('month',monthname)
hiddenData('day',day)
hiddenData('hour',sh)
hiddenData('minute',sm)
hiddenData('duration',duration)
textBox("Please enter your name",'Name',name,1,40)
textBox("Please enter your email address"+\
" (this will be used to confirm your appointment,"+\
" so please type it carefully)", 'EMail',email,2,80)
textBox("Please enter the reason for this appointment",'Purpose',why,2,80)
popupMenu("Location",['Clayton','Caulfield'],loc)
print "<INPUT type=\"submit\" name=\"email\" value=\"%s\"></INPUT>\n" \
% "Details are correct, make appointment"
print "</FORM>\n"
pass
<define textBox 25> =def textBox(msg,name,val,rows,cols):
print "<P>%s<BR/>" % (msg)
print "<TEXTAREA name=\"%s\" rows=\"%d\" cols=\"%d\">" % \
(name,rows,cols)
print "%s</TEXTAREA></P>" % (val)
return
<define hiddenData 26> =def hiddenData(name,value):
print "<INPUT type=\"hidden\" name=\"%s\" value=\"%s\"/>" % (name,value)
return
8. EMail Confirmation Phase
8.1 Define the EMail Confirmation procedure
The email confirmation has very little to do, basically
collecting up the appointment data, and emailing it to ajh for
confirmation. It does a check to ensure that all data is
present, and asks the user to step back and reenter if all
data is not present. This is really a short cut to avoid
having another phase to check the data.
The new appointment data is appended to the tentative
appointments file, diary.new if all is OK. Note that
this file must be universally writeable, since the program
operates as user 'nobody'.
<define the email confirmation procedure 27> =def
doEMailConfirmation(form):
if form.has_key('EMail'):
adr=form['EMail'].value
else:
adr=''
if form.has_key('Name'):
sub=form['Name'].value
else:
sub=''
if form.has_key('Purpose'):
why=form['Purpose'].value
else:
why=''
year=int(form['year'].value)
month=monthnames.index(form['month'].value)+1
day=int(form['day'].value)
hrs=int(form['hour'].value)
mins=int(form['minute'].value)
duration=form['duration'].value
dur=
convertDurationToInteger(duration)
eh=hrs;em=mins+dur
while em>=60:
eh=eh+1; em=em-60
msg=sub + \
" has requested an appointment at " + \
form['Location'].value + \
" on " + \
form['year'].value + " " + \
form['month'].value + " " + \
form['day' ].value + " at " + \
("%02d:%02d" % (hrs,mins)) + \
(" for %s. " % (duration)) + \
"\n\nPurpose: " + why
if adr and sub and why:
printHtmlHeaders("Appointment Awaiting Confirmation")
sendEMail(adr,sub,msg)
tentf=open("%s/diary.new" % (
webhomedir),'a')
tentf.write("%04d%02d%02d %02d%02d-%02d%02d %s\n" % \
(year,month,day,hrs,mins,eh,em,why))
tentf.close()
else:
printHtmlHeaders("You have not entered all fields!")
print """<P>Please use your browser back button to return and
enter a value in each field.</P>"""
pass
8.2 Define the sendEMail Procedure
The sendEMail procedure is responsible for emailing
ajh the details of the appointment, so that it can be
confirmed. The actual details of confirmation are not part of
this program, but require the information in the
diary.new file to be transferred to the diary
file. This effectively converts yellow coloured tentative
appointments in the diary page to red coloured times.
The details of the actual command to send the email may be
system specific.
<define procedures 28> =def
sendEMail(adr,sub,msg):
msgf=open("%s/msg-Appointment" % (tmpdirectory),'w')
msgf.write("To: ajh@csse.monash.edu.au\n")
msgf.write("Cc: %s\n" % (adr))
msgf.write("From: Appointments@csse.monash.edu.au\n")
msgf.write("Reply-to: %s\n" % (adr))
msgf.write("Subject: Making Appointment for %s\n\n" % (sub))
msgf.write(msg)
msgf.close()
cmd="%s -t -v -oi <%s/msg-Appointment >/dev/null" % (
sendmail,
tmpdirectory)
os.system(cmd)
print "<P>Details of your appointment request have been emailed to John Hurst, who will confirm your appointment by email.</P>"
msg="Click here to return to Diary Page"
mode="diary"
print "<FORM action=\"%s/ajhdiary.py\" method=\"post\">" % (cgiserver)
print "<INPUT type=\"submit\" name=\"%s\" value=\"%s\"></INPUT>\n" % (mode,msg)
print "</FORM>"
return
9. Support Operations
needHeaders is a global variable that identifies whether
the Content/type http protocol header has to be issued
before generating any other output.
<define variables 29> = needHeaders = 1
Chunk referenced in 1Chunk defined in 3,
29
<define procedures 30> =def
printHtmlHeaders(title):
global needHeaders
if not needHeaders: return
print "Content-Type: text/html\n\n"
print """<HTML>
<head>
<TITLE>%s</TITLE>
</head>
<BODY BGCOLOR=\"#f0fff0\" LINK=\"#000080" VLINK=\"#c08000\" ALINK=\"#0000ff\">
""" % (title)
print "<h1>%s</h1>" % (title)
needHeaders = 0
<define procedures 31> =def popupMenu(name,options,default):
print "<SELECT name=\"%s\">" % (name)
for opt in options:
isdef=''
if opt==default: isdef=" selected"
print "<OPTION%s>%s</OPTION>" % (isdef,opt)
print "</SELECT>"
<define procedures 32> =def
convertDurationToString(d):
if d<60:
return "0:%02d mins" % (d)
if d==60: return "1:00 hour"
if d>120: return ">2 hours"
h=0
while d>60:
h=h+1
d=d-60
return "%d:%02d hours" % (h,d)
<define procedures 33> =def
convertDurationToInteger(d):
res=re.match(r'0:(\d{2}) mins',d)
if res: return int(res.group(1))
else:
res=re.match(r'(\d):(\d{2}) hour',d)
if res:
return 60*int(res.group(1))+int(res.group(2))
else:
return 121
{Note 33.1}
pass
- {Note 33.1}
- greater than two hours
10. Index
10.1 File Definitions
File Name |
Defined in |
ajhdiary.py |
1 |
10.2 Chunk Definitions
Chunk Name |
Defined in |
Used in |
check time in appointments list |
22 |
21 |
collect cgi parameters and invoke appropriate part |
6 |
1 |
current date |
35 |
|
current version |
34 |
|
define confirm appointment times |
19 |
1 |
define diary click handler |
18 |
1 |
define diary page parameters |
8 |
1 |
define generate web page |
7 |
1 |
define grab details |
24 |
1 |
define hiddenData |
26 |
24 |
define procedures |
9, 10, 20, 21, 28, 30, 31, 32, 33
|
1 |
define procedures |
9, 10, 20, 21, 28, 30, 31, 32, 33
|
1 |
define procedures |
9, 10, 20, 21, 28, 30, 31, 32, 33
|
1 |
define procedures |
9, 10, 20, 21, 28, 30, 31, 32, 33
|
1 |
define server addresses |
4 |
3 |
define textBox |
25 |
24 |
define the email confirmation procedure |
27 |
1 |
define variables |
3, 29
|
1 |
define variables |
3, 29
|
1 |
handle all appointments for this date |
17 |
14 |
import definitions |
2 |
1 |
initialize web page |
12 |
7 |
initialize web page variables |
11 |
7 |
print a diary day |
16 |
14 |
print check response |
23 |
21, 24
|
print form |
14 |
7 |
print web page heading |
13 |
7 |
read diary file and collect appointments |
5 |
1 |
skip saturdays and sundays |
15 |
14 |
10.3 Variable Definitions
Identifier |
Defined in |
Used in |
Document History
20050120:144523 |
ajh |
0.0.0 |
first version |
20050121:143848 |
ajh |
0.0.1 |
restructured to make more literate |
20050126:175733 |
ajh |
0.0.2 |
merged with make-appt, refined confirm appointment, and added (empty) grab details section |
20050128:103354 |
ajh |
0.1.0 |
extensive changes to bring it up to first production version |
20050128:134946 |
ajh |
0.1.1 |
added part hour displays in diary page |
20050129:180457 |
ajh |
0.1.2 |
cleaned up literacy and added variable markup |
20050425:202459 |
ajh |
0.1.3 |
fixed bug that stopped 8am appointments being displayed |
20050726:133108 |
ajh |
0.1.4 |
minor tidy up |
<current version 34> = 0.1.4
<current date 35> = 20050726:133108