1515# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717#
18- # $Id: cgi_client.py,v 1.112 2002-03-12 22:52:26 richard Exp $
18+ # $Id: cgi_client.py,v 1.113 2002-03-14 23:59:24 richard Exp $
1919
2020__doc__ = """
2121WWW request handler (also used in the stand-alone server).
2222"""
2323
24- import os , cgi , StringIO , urlparse , re , traceback , mimetypes
24+ import os , cgi , StringIO , urlparse , re , traceback , mimetypes , urllib
2525import binascii , Cookie , time , random
2626
2727import roundupdb , htmltemplate , date , hyperdb , password
@@ -58,7 +58,7 @@ def __init__(self, instance, request, env, form=None):
5858 port = self .env ['SERVER_PORT' ]
5959 if port != '80' : machine = machine + ':' + port
6060 self .base = urlparse .urlunparse (('http' , env ['HTTP_HOST' ], url ,
61- None , None , None ))
61+ None , None , None ))
6262
6363 if form is None :
6464 self .form = cgi .FieldStorage (environ = env )
@@ -77,8 +77,8 @@ def getuid(self):
7777 def header (self , headers = None ):
7878 '''Put up the appropriate header.
7979 '''
80- if headers is None :
81- headers = {'Content-Type' :'text/html' }
80+ if headers is None :
81+ headers = {'Content-Type' :'text/html' }
8282 if not headers .has_key ('Content-Type' ):
8383 headers ['Content-Type' ] = 'text/html'
8484 self .request .send_response (200 )
@@ -107,36 +107,114 @@ def header(self, headers=None):
107107
108108</script>
109109'''
110+ def make_index_link (self , name ):
111+ '''Turn a configuration entry into a hyperlink...
112+ '''
113+ # get the link label and spec
114+ spec = getattr (self .instance , name + '_INDEX' )
115+
116+ d = {}
117+ d [':sort' ] = ',' .join (map (urllib .quote , spec ['SORT' ]))
118+ d [':group' ] = ',' .join (map (urllib .quote , spec ['GROUP' ]))
119+ d [':filter' ] = ',' .join (map (urllib .quote , spec ['FILTER' ]))
120+ d [':columns' ] = ',' .join (map (urllib .quote , spec ['COLUMNS' ]))
121+
122+ # snarf the filterspec
123+ filterspec = spec ['FILTERSPEC' ].copy ()
124+
125+ # now format the filterspec
126+ for k , l in filterspec .items ():
127+ # fix up the assignedto if needed
128+ if k == 'assignedto' and l is None :
129+ l = [self .db .user .lookup (self .user )]
130+
131+ # add
132+ d [urllib .quote (k )] = ',' .join (map (urllib .quote , l ))
133+
134+ # finally, format the URL
135+ return '<a href="%s?%s">%s</a>' % (spec ['CLASS' ],
136+ '&' .join ([k + '=' + v for k ,v in d .items ()]), spec ['LABEL' ])
137+
110138
111139 def pagehead (self , title , message = None ):
140+ '''Display the page heading, with information about the tracker and
141+ links to more information
142+ '''
143+
144+ # include any important message
112145 if message is not None :
113146 message = _ ('<div class="system-msg">%(message)s</div>' )% locals ()
114147 else :
115148 message = ''
149+
150+ # style sheet (CSS)
116151 style = open (os .path .join (self .instance .TEMPLATES , 'style.css' )).read ()
152+
153+ # figure who the user is
117154 user_name = self .user or ''
118- if self .user == 'admin' :
119- admin_links = _ (' | <a href="list_classes">Class List</a>' \
120- ' | <a href="user">User List</a>' \
121- ' | <a href="newuser">Add User</a>' )
122- else :
123- admin_links = ''
124- if self .user not in (None , 'anonymous' ):
155+ if user_name not in ('' , 'anonymous' ):
125156 userid = self .db .user .lookup (self .user )
157+ else :
158+ userid = None
159+
160+ # figure all the header links
161+ if hasattr (self .instance , 'HEADER_INDEX_LINKS' ):
162+ links = []
163+ for name in self .instance .HEADER_INDEX_LINKS :
164+ spec = getattr (self .instance , name + '_INDEX' )
165+ # skip if we need to fill in the logged-in user id there's
166+ # no user logged in
167+ if (spec ['FILTERSPEC' ].has_key ('assignedto' ) and
168+ spec ['FILTERSPEC' ]['assignedto' ] is None and
169+ userid is None ):
170+ continue
171+ links .append (self .make_index_link (name ))
172+ else :
173+ # no config spec - hard-code
174+ links = [
175+ _ ('All <a href="issue?status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=-activity&:filter=status&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>' ),
176+ _ ('Unassigned <a href="issue?assignedto=-1&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=-activity&:filter=status,assignedto&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>' )
177+ ]
178+
179+ # if they're logged in, include links to their information, and the
180+ # ability to add an issue
181+ if user_name not in ('' , 'anonymous' ):
126182 user_info = _ ('''
127- <a href="issue?assignedto=%(userid)s&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:filter=status,assignedto&:sort=-activity&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">My Issues</a> |
128183<a href="user%(userid)s">My Details</a> | <a href="logout">Logout</a>
129184''' )% locals ()
185+
186+ # figure the "add class" links
187+ if hasattr (self .instance , 'HEADER_ADD_LINKS' ):
188+ classes = self .instance .HEADER_ADD_LINKS
189+ else :
190+ classes = ['issue' ]
191+ l = []
192+ for class_name in classes :
193+ cap_class = class_name .capitalize ()
194+ links .append (_ ('Add <a href="new%(class_name)s">'
195+ '%(cap_class)s</a>' )% locals ())
196+
197+ # if there's no config header link spec, force a user link here
198+ if not hasattr (self .instance , 'HEADER_INDEX_LINKS' ):
199+ links .append (_ ('<a href="issue?assignedto=%(userid)s&status=-1,unread,chatting,open,pending&:filter=status,resolution,assignedto&:sort=-activity&:columns=id,activity,status,resolution,title,creator&:group=type&show_customization=1">My Issues</a>' )% locals ())
130200 else :
131201 user_info = _ ('<a href="login">Login</a>' )
132- if self .user is not None :
133- add_links = _ ('''
134- | Add
135- <a href="newissue">Issue</a>
136- ''' )
137- else :
138202 add_links = ''
203+
204+ # if the user is admin, include admin links
205+ admin_links = ''
206+ if user_name == 'admin' :
207+ links .append (_ ('<a href="list_classes">Class List</a>' ))
208+ links .append (_ ('<a href="user">User List</a>' ))
209+ links .append (_ ('<a href="newuser">Add User</a>' ))
210+
211+ # now we have all the links, join 'em
212+ links = '\n | ' .join (links )
213+
214+ # include the javascript bit
139215 global_javascript = self .global_javascript % self .__dict__
216+
217+ # finally, format the header
140218 self .write (_ ('''<html><head>
141219<title>%(title)s</title>
142220<style type="text/css">%(style)s</style>
@@ -148,12 +226,7 @@ def pagehead(self, title, message=None):
148226<tr class="location-bar"><td><big><strong>%(title)s</strong></big></td>
149227<td align=right valign=bottom>%(user_name)s</td></tr>
150228<tr class="location-bar">
151- <td align=left>All
152- <a href="issue?status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=-activity&:filter=status&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>
153- | Unassigned
154- <a href="issue?assignedto=-1&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=-activity&:filter=status,assignedto&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>
155- %(add_links)s
156- %(admin_links)s</td>
229+ <td align=left>%(links)s</td>
157230<td align=right>%(user_info)s</td>
158231</table>
159232''' )% locals ())
@@ -247,34 +320,44 @@ def customization_widget(self):
247320
248321 return visible
249322
323+ # TODO: make this go away some day...
250324 default_index_sort = ['-activity' ]
251325 default_index_group = ['priority' ]
252326 default_index_filter = ['status' ]
253327 default_index_columns = ['id' ,'activity' ,'title' ,'status' ,'assignedto' ]
254328 default_index_filterspec = {'status' : ['1' , '2' , '3' , '4' , '5' , '6' , '7' ]}
329+
255330 def index (self ):
256- ''' put up an index
331+ ''' put up an index - no class specified
257332 '''
258- self .classname = 'issue'
259333 # see if the web has supplied us with any customisation info
260334 defaults = 1
261335 for key in ':sort' , ':group' , ':filter' , ':columns' :
262336 if self .form .has_key (key ):
263337 defaults = 0
264338 break
265339 if defaults :
266- # no info supplied - use the defaults
267- sort = self .default_index_sort
268- group = self .default_index_group
269- filter = self .default_index_filter
270- columns = self .default_index_columns
271- filterspec = self .default_index_filterspec
340+ # try the instance config first
341+ if hasattr (self .instance , 'DEFAULT_INDEX_CLASS' ):
342+ self .classname = self .instance .DEFAULT_INDEX_CLASS
343+ sort = self .instance .DEFAULT_INDEX_SORT
344+ group = self .instance .DEFAULT_INDEX_GROUP
345+ filter = self .instance .DEFAULT_INDEX_FILTER
346+ columns = self .instance .DEFAULT_INDEX_COLUMNS
347+ filterspec = self .instance .DEFAULT_INDEX_FILTERSPEC
348+
349+ else :
350+ # nope - fall back on the old way of doing it
351+ self .classname = 'issue'
352+ sort = self .default_index_sort
353+ group = self .default_index_group
354+ filter = self .default_index_filter
355+ columns = self .default_index_columns
356+ filterspec = self .default_index_filterspec
272357 else :
273- sort = self .index_arg (':sort' )
274- group = self .index_arg (':group' )
275- filter = self .index_arg (':filter' )
276- columns = self .index_arg (':columns' )
277- filterspec = self .index_filterspec (filter )
358+ # make list() extract the info from the CGI environ
359+ self .classname = 'issue'
360+ sort = group = filter = columns = filterspec = None
278361 return self .list (columns = columns , filter = filter , group = group ,
279362 sort = sort , filterspec = filterspec )
280363
@@ -536,7 +619,7 @@ def _createnode(self):
536619
537620 # set status to 'unread' if not specified - a status of '- no
538621 # selection -' doesn't make sense
539- if not props .has_key ('status' ):
622+ if not props .has_key ('status' ) and cl . getprops (). has_key ( 'status' ) :
540623 try :
541624 unread_id = self .db .status .lookup ('unread' )
542625 except KeyError :
@@ -1192,60 +1275,6 @@ class ExtendedClient(Client):
11921275 default_index_columns = ['activity' ,'status' ,'title' ,'assignedto' ]
11931276 default_index_filterspec = {'status' : ['1' , '2' , '3' , '4' , '5' , '6' , '7' ]}
11941277
1195- def pagehead (self , title , message = None ):
1196- if message is not None :
1197- message = _ ('<div class="system-msg">%(message)s</div>' )% locals ()
1198- else :
1199- message = ''
1200- style = open (os .path .join (self .instance .TEMPLATES , 'style.css' )).read ()
1201- user_name = self .user or ''
1202- if self .user == 'admin' :
1203- admin_links = _ (' | <a href="list_classes">Class List</a>' \
1204- ' | <a href="user">User List</a>' \
1205- ' | <a href="newuser">Add User</a>' )
1206- else :
1207- admin_links = ''
1208- if self .user not in (None , 'anonymous' ):
1209- userid = self .db .user .lookup (self .user )
1210- user_info = _ ('''
1211- <a href="issue?assignedto=%(userid)s&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:filter=status,assignedto&:sort=-activity&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">My Issues</a> |
1212- <a href="support?assignedto=%(userid)s&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:filter=status,assignedto&:sort=-activity&:columns=id,activity,status,title,assignedto&:group=customername&show_customization=1">My Support</a> |
1213- <a href="user%(userid)s">My Details</a> | <a href="logout">Logout</a>
1214- ''' )% locals ()
1215- else :
1216- user_info = _ ('<a href="login">Login</a>' )
1217- if self .user is not None :
1218- add_links = _ ('''
1219- | Add
1220- <a href="newissue">Issue</a>,
1221- <a href="newsupport">Support</a>,
1222- ''' )
1223- else :
1224- add_links = ''
1225- global_javascript = self .global_javascript % self .__dict__
1226- self .write (_ ('''<html><head>
1227- <title>%(title)s</title>
1228- <style type="text/css">%(style)s</style>
1229- </head>
1230- %(global_javascript)s
1231- <body bgcolor=#ffffff>
1232- %(message)s
1233- <table width=100%% border=0 cellspacing=0 cellpadding=2>
1234- <tr class="location-bar"><td><big><strong>%(title)s</strong></big></td>
1235- <td align=right valign=bottom>%(user_name)s</td></tr>
1236- <tr class="location-bar">
1237- <td align=left>All
1238- <a href="issue?status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:filter=status&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>,
1239- <a href="support?status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:filter=status&:columns=id,activity,status,title,assignedto&:group=customername&show_customization=1">Support</a>
1240- | Unassigned
1241- <a href="issue?assignedto=-1&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=-activity&:filter=status,assignedto&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>,
1242- <a href="support?assignedto=-1&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=-activity&:filter=status,assignedto&:columns=id,activity,status,title,assignedto&:group=customername&show_customization=1">Support</a>
1243- %(add_links)s
1244- %(admin_links)s</td>
1245- <td align=right>%(user_info)s</td>
1246- </table>
1247- ''' )% locals ())
1248-
12491278def parsePropsFromForm (db , cl , form , nodeid = 0 ):
12501279 '''Pull properties for the given class out of the form.
12511280 '''
@@ -1327,6 +1356,9 @@ def parsePropsFromForm(db, cl, form, nodeid=0):
13271356
13281357#
13291358# $Log: not supported by cvs2svn $
1359+ # Revision 1.112 2002/03/12 22:52:26 richard
1360+ # more pychecker warnings removed
1361+ #
13301362# Revision 1.111 2002/02/25 04:32:21 richard
13311363# ahem
13321364#
0 commit comments