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.82 2001-12-15 19:24:39 rochecompaan Exp $
18+ # $Id: cgi_client.py,v 1.83 2001-12-15 23:51:01 richard Exp $
1919
2020__doc__ = """
2121WWW request handler (also used in the stand-alone server).
@@ -324,6 +324,8 @@ def shownode(self, message=None):
324324 ', ' .join (changed .keys ())}
325325 elif self .form .has_key ('__note' ) and self .form ['__note' ].value :
326326 message = _ ('note added' )
327+ elif self .form .has_key ('__file' ):
328+ message = _ ('file added' )
327329 else :
328330 message = _ ('nothing changed' )
329331 except :
@@ -348,75 +350,34 @@ def shownode(self, message=None):
348350 showissue = shownode
349351 showmsg = shownode
350352
351- def showuser (self , message = None ):
352- '''Display a user page for editing. Make sure the user is allowed
353- to edit this node, and also check for password changes.
353+ def _changenode (self , props ):
354+ ''' change the node based on the contents of the form
354355 '''
355- if self .user == 'anonymous' :
356- raise Unauthorised
357-
358- user = self .db .user
359-
360- # get the username of the node being edited
361- node_user = user .get (self .nodeid , 'username' )
362-
363- if self .user not in ('admin' , node_user ):
364- raise Unauthorised
365-
366- #
367- # perform any editing
368- #
369- keys = self .form .keys ()
370- num_re = re .compile ('^\d+$' )
371- if keys :
372- try :
373- props , changed = parsePropsFromForm (self .db , user , self .form ,
374- self .nodeid )
375- set_cookie = 0
376- if self .nodeid == self .getuid () and changed .has_key ('password' ):
377- password = self .form ['password' ].value .strip ()
378- if password :
379- set_cookie = password
380- else :
381- # no password was supplied - don't change it
382- del props ['password' ]
383- del changed ['password' ]
384- user .set (self .nodeid , ** props )
385- # and some feedback for the user
386- message = _ ('%(changes)s edited ok' )% {'changes' :
387- ', ' .join (changed .keys ())}
388- except :
389- self .db .rollback ()
390- s = StringIO .StringIO ()
391- traceback .print_exc (None , s )
392- message = '<pre>%s</pre>' % cgi .escape (s .getvalue ())
356+ cl = self .db .classes [self .classname ]
357+ # set status to chatting if 'unread' or 'resolved'
358+ try :
359+ # determine the id of 'unread','resolved' and 'chatting'
360+ unread_id = self .db .status .lookup ('unread' )
361+ resolved_id = self .db .status .lookup ('resolved' )
362+ chatting_id = self .db .status .lookup ('chatting' )
363+ except KeyError :
364+ pass
393365 else :
394- set_cookie = 0
395-
396- # fix the cookie if the password has changed
397- if set_cookie :
398- self .set_cookie (self .user , set_cookie )
399-
400- #
401- # now the display
402- #
403- self .pagehead (_ ('User: %(user)s' )% {'user' : node_user }, message )
404-
405- # use the template to display the item
406- item = htmltemplate .ItemTemplate (self , self .TEMPLATES , 'user' )
407- item .render (self .nodeid )
408- self .pagefoot ()
409-
410- def showfile (self ):
411- ''' display a file
412- '''
413- nodeid = self .nodeid
414- cl = self .db .file
415- mime_type = cl .get (nodeid , 'type' )
416- if mime_type == 'message/rfc822' :
417- mime_type = 'text/plain'
418- self .header (headers = {'Content-Type' : mime_type })
419- self .write (cl .get (nodeid , 'content' ))
366+ if (props ['status' ] == unread_id or props ['status' ] == resolved_id ):
367+ props ['status' ] = chatting_id
368+ # add assignedto to the nosy list
369+ if props .has_key ('assignedto' ):
370+ assignedto_id = props ['assignedto' ]
371+ if assignedto_id not in props ['nosy' ]:
372+ props ['nosy' ].append (assignedto_id )
373+ # create the message
374+ message , files = self ._handle_message ()
375+ if message :
376+ props ['messages' ] = cl .get (self .nodeid , 'messages' ) + [message ]
377+ if files :
378+ props ['files' ] = cl .get (self .nodeid , 'files' ) + files
379+ # make the changes
380+ cl .set (self .nodeid , ** props )
420381
421382 def _createnode (self ):
422383 ''' create a node based on the contents of the form
@@ -436,47 +397,22 @@ def _createnode(self):
436397 # add assignedto to the nosy list
437398 if props .has_key ('assignedto' ):
438399 assignedto_id = props ['assignedto' ]
439- if props .has_key ('nosy' ) and not assignedto_id in props ['nosy' ]:
400+ if props .has_key ('nosy' ) and assignedto_id not in props ['nosy' ]:
440401 props ['nosy' ].append (assignedto_id )
441402 else :
442403 props ['nosy' ] = [assignedto_id ]
443- # check for messages
444- message = self ._handle_message ()
404+ # check for messages and files
405+ message , files = self ._handle_message ()
445406 if message :
446407 props ['messages' ] = [message ]
408+ if files :
409+ props ['files' ] = files
447410 # create the node and return it's id
448411 return cl .create (** props )
449412
450- def _changenode (self , props ):
451- ''' change the node based on the contents of the form
452- '''
453- cl = self .db .classes [self .classname ]
454- # set status to chatting if 'unread' or 'resolved'
455- try :
456- # determine the id of 'unread','resolved' and 'chatting'
457- unread_id = self .db .status .lookup ('unread' )
458- resolved_id = self .db .status .lookup ('resolved' )
459- chatting_id = self .db .status .lookup ('chatting' )
460- except KeyError :
461- pass
462- else :
463- if (props ['status' ] == unread_id or props ['status' ] == resolved_id ):
464- props ['status' ] = chatting_id
465- # add assignedto to the nosy list
466- if props .has_key ('assignedto' ):
467- assignedto_id = props ['assignedto' ]
468- if not assignedto_id in props ['nosy' ]:
469- props ['nosy' ].append (assignedto_id )
470- # create the message
471- message = self ._handle_message ()
472- if message :
473- props ['messages' ] = cl .get (self .nodeid , 'messages' ) + [message ]
474- # make the changes
475- cl .set (self .nodeid , ** props )
476-
477413 def _handle_message (self ):
478- ''' generate and edit message '''
479-
414+ ''' generate and edit message
415+ '''
480416 # handle file attachments
481417 files = []
482418 if self .form .has_key ('__file' ):
@@ -494,16 +430,18 @@ def _handle_message(self):
494430 cl = self .db .classes [self .classname ]
495431 props = cl .getprops ()
496432 note = None
433+ # in a nutshell, don't do anything if there's no note or there's no
434+ # nosy
497435 if self .form .has_key ('__note' ):
498436 note = self .form ['__note' ].value
499437 if not props .has_key ('messages' ):
500- return
438+ return None , files
501439 if not isinstance (props ['messages' ], hyperdb .Multilink ):
502- return
440+ return None , files
503441 if not props ['messages' ].classname == 'msg' :
504- return
442+ return None , files
505443 if not (self .form .has_key ('nosy' ) or note ):
506- return
444+ return None , files
507445
508446 # handle the note
509447 if note :
@@ -512,22 +450,32 @@ def _handle_message(self):
512450 else :
513451 summary = note
514452 m = ['%s\n ' % note ]
515- else :
516- summary = _ ('This %(classname)s has been edited through'
517- ' the web.\n ' )% {'classname' : cn }
518- m = [summary ]
453+ elif not files :
454+ # don't generate a useless message
455+ return None , files
519456
520- # now create the message
457+ # now create the message, attaching the files
521458 content = '\n ' .join (m )
522459 message_id = self .db .msg .create (author = self .getuid (),
523460 recipients = [], date = date .Date ('.' ), summary = summary ,
524461 content = content , files = files )
525462
526463 # update the messages property
527- return message_id
464+ return message_id , files
528465
529466 def _post_editnode (self , nid ):
530- ''' do the linking part of the node creation
467+ '''Do the linking part of the node creation.
468+
469+ If a form element has :link or :multilink appended to it, its
470+ value specifies a node designator and the property on that node
471+ to add _this_ node to as a link or multilink.
472+
473+ This is typically used on, eg. the file upload page to indicated
474+ which issue to link the file to.
475+
476+ TODO: I suspect that this and newfile will go away now that
477+ there's the ability to upload a file using the issue __file form
478+ element!
531479 '''
532480 cn = self .classname
533481 cl = self .db .classes [cn ]
@@ -603,7 +551,39 @@ def newnode(self, message=None):
603551
604552 self .pagefoot ()
605553 newissue = newnode
606- newuser = newnode
554+
555+ def newuser (self , message = None ):
556+ ''' Add a new user to the database.
557+
558+ Don't do any of the message or file handling, just create the node.
559+ '''
560+ cn = self .classname
561+ cl = self .db .classes [cn ]
562+
563+ # possibly perform a create
564+ keys = self .form .keys ()
565+ if [i for i in keys if i [0 ] != ':' ]:
566+ try :
567+ props , dummy = parsePropsFromForm (self .db , cl , self .form )
568+ nid = cl .create (** props )
569+ # handle linked nodes
570+ self ._post_editnode (nid )
571+ # and some nice feedback for the user
572+ message = _ ('%(classname)s created ok' )% {'classname' : cn }
573+ except :
574+ self .db .rollback ()
575+ s = StringIO .StringIO ()
576+ traceback .print_exc (None , s )
577+ message = '<pre>%s</pre>' % cgi .escape (s .getvalue ())
578+ self .pagehead (_ ('New %(classname)s' )% {'classname' :
579+ self .classname .capitalize ()}, message )
580+
581+ # call the template
582+ newitem = htmltemplate .NewItemTemplate (self , self .TEMPLATES ,
583+ self .classname )
584+ newitem .render (self .form )
585+
586+ self .pagefoot ()
607587
608588 def newfile (self , message = None ):
609589 ''' Add a new file to the database.
@@ -642,6 +622,76 @@ def newfile(self, message=None):
642622 newitem .render (self .form )
643623 self .pagefoot ()
644624
625+ def showuser (self , message = None ):
626+ '''Display a user page for editing. Make sure the user is allowed
627+ to edit this node, and also check for password changes.
628+ '''
629+ if self .user == 'anonymous' :
630+ raise Unauthorised
631+
632+ user = self .db .user
633+
634+ # get the username of the node being edited
635+ node_user = user .get (self .nodeid , 'username' )
636+
637+ if self .user not in ('admin' , node_user ):
638+ raise Unauthorised
639+
640+ #
641+ # perform any editing
642+ #
643+ keys = self .form .keys ()
644+ num_re = re .compile ('^\d+$' )
645+ if keys :
646+ try :
647+ props , changed = parsePropsFromForm (self .db , user , self .form ,
648+ self .nodeid )
649+ set_cookie = 0
650+ if self .nodeid == self .getuid () and changed .has_key ('password' ):
651+ password = self .form ['password' ].value .strip ()
652+ if password :
653+ set_cookie = password
654+ else :
655+ # no password was supplied - don't change it
656+ del props ['password' ]
657+ del changed ['password' ]
658+ user .set (self .nodeid , ** props )
659+ # and some feedback for the user
660+ message = _ ('%(changes)s edited ok' )% {'changes' :
661+ ', ' .join (changed .keys ())}
662+ except :
663+ self .db .rollback ()
664+ s = StringIO .StringIO ()
665+ traceback .print_exc (None , s )
666+ message = '<pre>%s</pre>' % cgi .escape (s .getvalue ())
667+ else :
668+ set_cookie = 0
669+
670+ # fix the cookie if the password has changed
671+ if set_cookie :
672+ self .set_cookie (self .user , set_cookie )
673+
674+ #
675+ # now the display
676+ #
677+ self .pagehead (_ ('User: %(user)s' )% {'user' : node_user }, message )
678+
679+ # use the template to display the item
680+ item = htmltemplate .ItemTemplate (self , self .TEMPLATES , 'user' )
681+ item .render (self .nodeid )
682+ self .pagefoot ()
683+
684+ def showfile (self ):
685+ ''' display a file
686+ '''
687+ nodeid = self .nodeid
688+ cl = self .db .file
689+ mime_type = cl .get (nodeid , 'type' )
690+ if mime_type == 'message/rfc822' :
691+ mime_type = 'text/plain'
692+ self .header (headers = {'Content-Type' : mime_type })
693+ self .write (cl .get (nodeid , 'content' ))
694+
645695 def classes (self , message = None ):
646696 ''' display a list of all the classes in the database
647697 '''
@@ -1100,6 +1150,13 @@ def parsePropsFromForm(db, cl, form, nodeid=0):
11001150
11011151#
11021152# $Log: not supported by cvs2svn $
1153+ # Revision 1.82 2001/12/15 19:24:39 rochecompaan
1154+ # . Modified cgi interface to change properties only once all changes are
1155+ # collected, files created and messages generated.
1156+ # . Moved generation of change note to nosyreactors.
1157+ # . We now check for changes to "assignedto" to ensure it's added to the
1158+ # nosy list.
1159+ #
11031160# Revision 1.81 2001/12/12 23:55:00 richard
11041161# Fixed some problems with user editing
11051162#
0 commit comments