comparison roundup/cgi_client.py @ 167:a49c8a2ddd26

Added time logging and file uploading to the templates.
author Richard Jones <richard@users.sourceforge.net>
date Mon, 30 Jul 2001 08:12:17 +0000
parents 8f9a65510139
children 1573a02b3254
comparison
equal deleted inserted replaced
166:d469fb3beda1 167:a49c8a2ddd26
1 # $Id: cgi_client.py,v 1.12 2001-07-30 06:26:31 richard Exp $ 1 # $Id: cgi_client.py,v 1.13 2001-07-30 08:12:17 richard Exp $
2 2
3 import os, cgi, pprint, StringIO, urlparse, re, traceback 3 import os, cgi, pprint, StringIO, urlparse, re, traceback, mimetypes
4 4
5 import roundupdb, htmltemplate, date 5 import roundupdb, htmltemplate, date
6 6
7 class Unauthorised(ValueError): 7 class Unauthorised(ValueError):
8 pass 8 pass
224 if value != cl.get(self.nodeid, key): 224 if value != cl.get(self.nodeid, key):
225 changed.append(key) 225 changed.append(key)
226 props[key] = value 226 props[key] = value
227 cl.set(self.nodeid, **props) 227 cl.set(self.nodeid, **props)
228 228
229 # if this item has messages, generate an edit message 229 self._post_editnode(self.nodeid)
230 # TODO: don't send the edit message to the person who
231 # performed the edit
232 if (cl.getprops().has_key('messages') and
233 cl.getprops()['messages'].isMultilinkType and
234 cl.getprops()['messages'].classname == 'msg'):
235 nid = self.nodeid
236 m = []
237 for name, prop in cl.getprops().items():
238 # TODO: the None default is only here because we
239 # don't have schema migration :(
240 if prop.isMultilinkType:
241 value = cl.get(nid, name, [])
242 else:
243 value = cl.get(nid, name, None)
244 if prop.isLinkType:
245 link = self.db.classes[prop.classname]
246 key = link.getkey()
247 if value is not None and key:
248 value = link.get(value, key)
249 else:
250 value = '-'
251 elif prop.isMultilinkType:
252 l = []
253 link = self.db.classes[prop.classname]
254 for entry in value:
255 key = link.getkey()
256 if key:
257 l.append(link.get(entry, link.getkey()))
258 else:
259 l.append(entry)
260 value = ', '.join(l)
261 if name in changed:
262 chg = '*'
263 else:
264 chg = ' '
265 m.append('%s %s: %s'%(chg, name, value))
266
267 # handle the note
268 if self.form.has_key('__note'):
269 note = self.form['__note'].value
270 if '\n' in note:
271 summary = re.split(r'\n\r?', note)[0]
272 else:
273 summary = note
274 m.insert(0, '%s\n\n'%note)
275 else:
276 if len(changed) > 1:
277 plural = 's were'
278 else:
279 plural = ' was'
280 summary = 'This %s has been edited through the web '\
281 'and the %s value%s changed.'%(cn,
282 ', '.join(changed), plural)
283 m.insert(0, '%s\n\n'%summary)
284
285 # now create the message
286 content = '\n'.join(m)
287 message_id = self.db.msg.create(author='1', recipients=[],
288 date=date.Date('.'), summary=summary, content=content)
289 messages = cl.get(nid, 'messages')
290 messages.append(message_id)
291 props = {'messages': messages}
292 cl.set(nid, **props)
293
294 # and some nice feedback for the user 230 # and some nice feedback for the user
295 message = '%s edited ok'%', '.join(changed) 231 message = '%s edited ok'%', '.join(changed)
296 except: 232 except:
297 s = StringIO.StringIO() 233 s = StringIO.StringIO()
298 traceback.print_exc(None, s) 234 traceback.print_exc(None, s)
309 # use the template to display the item 245 # use the template to display the item
310 htmltemplate.item(self, self.TEMPLATES, self.db, self.classname, nodeid) 246 htmltemplate.item(self, self.TEMPLATES, self.db, self.classname, nodeid)
311 self.pagefoot() 247 self.pagefoot()
312 showissue = shownode 248 showissue = shownode
313 showmsg = shownode 249 showmsg = shownode
250
251 def showuser(self, message=None):
252 ''' display an item
253 '''
254 if self.user in ('admin', self.db.user.get(self.nodeid, 'username')):
255 self.shownode(message)
256 else:
257 raise Unauthorised
258
259 def showfile(self):
260 ''' display a file
261 '''
262 nodeid = self.nodeid
263 cl = self.db.file
264 type = cl.get(nodeid, 'type')
265 if type == 'message/rfc822':
266 type = 'text/plain'
267 self.header(headers={'Content-Type': type})
268 self.write(cl.get(nodeid, 'content'))
269
270 def _createnode(self):
271 ''' create a node based on the contents of the form
272 '''
273 cn = self.classname
274 cl = self.db.classes[cn]
275 props = {}
276 keys = self.form.keys()
277 num_re = re.compile('^\d+$')
278 for key in keys:
279 if not cl.properties.has_key(key):
280 continue
281 proptype = cl.properties[key]
282 if proptype.isStringType:
283 value = self.form[key].value.strip()
284 elif proptype.isDateType:
285 value = date.Date(self.form[key].value.strip())
286 elif proptype.isIntervalType:
287 value = date.Interval(self.form[key].value.strip())
288 elif proptype.isLinkType:
289 value = self.form[key].value.strip()
290 # handle key values
291 link = cl.properties[key].classname
292 if not num_re.match(value):
293 try:
294 value = self.db.classes[link].lookup(value)
295 except:
296 raise ValueError, 'property "%s": %s not a %s'%(
297 key, value, link)
298 elif proptype.isMultilinkType:
299 value = self.form[key]
300 if type(value) != type([]):
301 value = [i.strip() for i in value.value.split(',')]
302 else:
303 value = [i.value.strip() for i in value]
304 link = cl.properties[key].classname
305 l = []
306 for entry in map(str, value):
307 if not num_re.match(entry):
308 try:
309 entry = self.db.classes[link].lookup(entry)
310 except:
311 raise ValueError, \
312 'property "%s": %s not a %s'%(key,
313 entry, link)
314 l.append(entry)
315 l.sort()
316 value = l
317 props[key] = value
318 return cl.create(**props)
319
320 def _post_editnode(self, nid):
321 ''' do the linking and message sending part of the node creation
322 '''
323 cn = self.classname
324 cl = self.db.classes[cn]
325 # link if necessary
326 keys = self.form.keys()
327 for key in keys:
328 if key == ':multilink':
329 value = self.form[key].value
330 if type(value) != type([]): value = [value]
331 for value in value:
332 designator, property = value.split(':')
333 link, nodeid = roundupdb.splitDesignator(designator)
334 link = self.db.classes[link]
335 value = link.get(nodeid, property)
336 value.append(nid)
337 link.set(nodeid, **{property: value})
338 elif key == ':link':
339 value = self.form[key].value
340 if type(value) != type([]): value = [value]
341 for value in value:
342 designator, property = value.split(':')
343 link, nodeid = roundupdb.splitDesignator(designator)
344 link = self.db.classes[link]
345 link.set(nodeid, **{property: nid})
346
347 # if this item has messages,
348 if (cl.getprops().has_key('messages') and
349 cl.getprops()['messages'].isMultilinkType and
350 cl.getprops()['messages'].classname == 'msg'):
351 # generate an edit message - nosyreactor will send it
352 m = []
353 for name, prop in cl.getprops().items():
354 value = cl.get(nid, name)
355 if prop.isLinkType:
356 link = self.db.classes[prop.classname]
357 key = link.getkey()
358 if value is not None and key:
359 value = link.get(value, key)
360 else:
361 value = '-'
362 elif prop.isMultilinkType:
363 l = []
364 link = self.db.classes[prop.classname]
365 for entry in value:
366 key = link.getkey()
367 if key:
368 l.append(link.get(entry, link.getkey()))
369 else:
370 l.append(entry)
371 value = ', '.join(l)
372 m.append('%s: %s'%(name, value))
373
374 # handle the note
375 note = None
376 if self.form.has_key('__note'):
377 note = self.form['__note']
378 if note is not None and note.value:
379 note = note.value
380 if '\n' in note:
381 summary = re.split(r'\n\r?', note)[0]
382 else:
383 summary = note
384 m.append('\n%s\n'%note)
385 else:
386 summary = 'This %s has been created through the web.'%cn
387 m.append('\n%s\s'%summary)
388
389 # now create the message
390 content = '\n'.join(m)
391 message_id = self.db.msg.create(author='1', recipients=[],
392 date=date.Date('.'), summary=summary, content=content)
393 messages = cl.get(nid, 'messages')
394 messages.append(message_id)
395 props = {'messages': messages}
396 cl.set(nid, **props)
314 397
315 def newnode(self, message=None): 398 def newnode(self, message=None):
316 ''' Add a new node to the database. 399 ''' Add a new node to the database.
317 400
318 The form works in two modes: blank form and submission (that is, 401 The form works in two modes: blank form and submission (that is,
337 cn = self.classname 420 cn = self.classname
338 cl = self.db.classes[cn] 421 cl = self.db.classes[cn]
339 422
340 # possibly perform a create 423 # possibly perform a create
341 keys = self.form.keys() 424 keys = self.form.keys()
342 num_re = re.compile('^\d+$')
343 if [i for i in keys if i[0] != ':']: 425 if [i for i in keys if i[0] != ':']:
344 props = {} 426 props = {}
345 try: 427 try:
346 keys = self.form.keys() 428 nid = self._createnode()
347 for key in keys: 429 self._post_editnode(nid)
348 if not cl.properties.has_key(key):
349 continue
350 proptype = cl.properties[key]
351 if proptype.isStringType:
352 value = self.form[key].value.strip()
353 elif proptype.isDateType:
354 value = date.Date(self.form[key].value.strip())
355 elif proptype.isIntervalType:
356 value = date.Interval(self.form[key].value.strip())
357 elif proptype.isLinkType:
358 value = self.form[key].value.strip()
359 # handle key values
360 link = cl.properties[key].classname
361 if not num_re.match(value):
362 try:
363 value = self.db.classes[link].lookup(value)
364 except:
365 raise ValueError, 'property "%s": %s not a %s'%(
366 key, value, link)
367 elif proptype.isMultilinkType:
368 value = self.form[key]
369 if type(value) != type([]):
370 value = [i.strip() for i in value.value.split(',')]
371 else:
372 value = [i.value.strip() for i in value]
373 link = cl.properties[key].classname
374 l = []
375 for entry in map(str, value):
376 if not num_re.match(entry):
377 try:
378 entry = self.db.classes[link].lookup(entry)
379 except:
380 raise ValueError, \
381 'property "%s": %s not a %s'%(key,
382 entry, link)
383 l.append(entry)
384 l.sort()
385 value = l
386 props[key] = value
387 nid = cl.create(**props)
388
389 # link if necessary
390 for key in keys:
391 print key,
392 if key == ':multilink':
393 value = self.form[key].value
394 if type(value) != type([]): value = [value]
395 for value in value:
396 designator, property = value.split(':')
397 print 'miltilinking to ', designator, property
398 link, nodeid = roundupdb.splitDesignator(designator)
399 link = self.db.classes[link]
400 value = link.get(nodeid, property)
401 value.append(nid)
402 link.set(nodeid, **{property: value})
403 elif key == ':link':
404 value = self.form[key].value
405 if type(value) != type([]): value = [value]
406 for value in value:
407 designator, property = value.split(':')
408 print 'linking to ', designator, property
409 link, nodeid = roundupdb.splitDesignator(designator)
410 link = self.db.classes[link]
411 link.set(nodeid, **{property: nid})
412 else:
413 print 'ignoring'
414
415 # if this item has messages,
416 if (cl.getprops().has_key('messages') and
417 cl.getprops()['messages'].isMultilinkType and
418 cl.getprops()['messages'].classname == 'msg'):
419 # generate an edit message - nosyreactor will send it
420 m = []
421 for name, prop in cl.getprops().items():
422 value = cl.get(nid, name)
423 if prop.isLinkType:
424 link = self.db.classes[prop.classname]
425 key = link.getkey()
426 if value is not None and key:
427 value = link.get(value, key)
428 else:
429 value = '-'
430 elif prop.isMultilinkType:
431 l = []
432 link = self.db.classes[prop.classname]
433 for entry in value:
434 key = link.getkey()
435 if key:
436 l.append(link.get(entry, link.getkey()))
437 else:
438 l.append(entry)
439 value = ', '.join(l)
440 m.append('%s: %s'%(name, value))
441
442 # handle the note
443 note = None
444 if self.form.has_key('__note'):
445 note = self.form['__note']
446 if note and note.value:
447 note = note.value
448 if '\n' in note:
449 summary = re.split(r'\n\r?', note)[0]
450 else:
451 summary = note
452 m.append('\n%s\n'%note)
453 else:
454 summary = 'This %s has been created through the web.'%cn
455 m.append('\n%s\s'%summary)
456
457 # now create the message
458 content = '\n'.join(m)
459 message_id = self.db.msg.create(author='1', recipients=[],
460 date=date.Date('.'), summary=summary, content=content)
461 messages = cl.get(nid, 'messages')
462 messages.append(message_id)
463 props = {'messages': messages}
464 cl.set(nid, **props)
465
466 # and some nice feedback for the user 430 # and some nice feedback for the user
467 message = '%s created ok'%cn 431 message = '%s created ok'%cn
468 except: 432 except:
469 s = StringIO.StringIO() 433 s = StringIO.StringIO()
470 traceback.print_exc(None, s) 434 traceback.print_exc(None, s)
474 self.form) 438 self.form)
475 self.pagefoot() 439 self.pagefoot()
476 newissue = newnode 440 newissue = newnode
477 newuser = newnode 441 newuser = newnode
478 442
479 def showuser(self, message=None): 443 def newfile(self, message=None):
480 ''' display an item 444 ''' Add a new file to the database.
481 ''' 445
482 if self.user in ('admin', self.db.user.get(self.nodeid, 'username')): 446 This form works very much the same way as newnode - it just has a
483 self.shownode(message) 447 file upload.
484 else: 448 '''
485 raise Unauthorised 449 cn = self.classname
486 450 cl = self.db.classes[cn]
487 def showfile(self): 451
488 ''' display a file 452 # possibly perform a create
489 ''' 453 keys = self.form.keys()
490 nodeid = self.nodeid 454 if [i for i in keys if i[0] != ':']:
491 cl = self.db.file 455 try:
492 type = cl.get(nodeid, 'type') 456 file = self.form['content']
493 if type == 'message/rfc822': 457 self._post_editnode(cl.create(content=file.file.read(),
494 type = 'text/plain' 458 type=mimetypes.guess_type(file.filename)[0],
495 self.header(headers={'Content-Type': type}) 459 name=file.filename))
496 self.write(cl.get(nodeid, 'content')) 460 # and some nice feedback for the user
461 message = '%s created ok'%cn
462 except:
463 s = StringIO.StringIO()
464 traceback.print_exc(None, s)
465 message = '<pre>%s</pre>'%cgi.escape(s.getvalue())
466
467 self.pagehead('New %s'%self.classname.capitalize(), message)
468 htmltemplate.newitem(self, self.TEMPLATES, self.db, self.classname,
469 self.form)
470 self.pagefoot()
497 471
498 def classes(self, message=None): 472 def classes(self, message=None):
499 ''' display a list of all the classes in the database 473 ''' display a list of all the classes in the database
500 ''' 474 '''
501 if self.user == 'admin': 475 if self.user == 'admin':
543 def __del__(self): 517 def __del__(self):
544 self.db.close() 518 self.db.close()
545 519
546 # 520 #
547 # $Log: not supported by cvs2svn $ 521 # $Log: not supported by cvs2svn $
522 # Revision 1.12 2001/07/30 06:26:31 richard
523 # Added some documentation on how the newblah works.
524 #
548 # Revision 1.11 2001/07/30 06:17:45 richard 525 # Revision 1.11 2001/07/30 06:17:45 richard
549 # Features: 526 # Features:
550 # . Added ability for cgi newblah forms to indicate that the new node 527 # . Added ability for cgi newblah forms to indicate that the new node
551 # should be linked somewhere. 528 # should be linked somewhere.
552 # Fixed: 529 # Fixed:

Roundup Issue Tracker: http://roundup-tracker.org/