comparison roundup/cgi/client.py @ 1002:1798d2fa9fec

Hack hack... . Lots of cleanup in the classic html (stylesheet, search page, index page, ...) . Reinstated searching, but not query saving yet . Filtering only allows sorting and grouping by one property - all backends now implement this behaviour. . Nosy list journalling turned off by default, everything else is on. . Added some convenience methods (reverse, propchanged, [item] accesses, ...) . Did I mention the stylesheet is much cleaner now? :)
author Richard Jones <richard@users.sourceforge.net>
date Sun, 01 Sep 2002 04:32:30 +0000
parents 55ab0c5b49f9
children f89b8d32291b
comparison
equal deleted inserted replaced
1001:7fea15e6cdfe 1002:1798d2fa9fec
1 # $Id: client.py,v 1.1 2002-08-30 08:28:44 richard Exp $ 1 # $Id: client.py,v 1.2 2002-09-01 04:32:30 richard Exp $
2 2
3 __doc__ = """ 3 __doc__ = """
4 WWW request handler (also used in the stand-alone server). 4 WWW request handler (also used in the stand-alone server).
5 """ 5 """
6 6
294 'edit': 'edititem_action', 294 'edit': 'edititem_action',
295 'new': 'newitem_action', 295 'new': 'newitem_action',
296 'login': 'login_action', 296 'login': 'login_action',
297 'logout': 'logout_action', 297 'logout': 'logout_action',
298 'register': 'register_action', 298 'register': 'register_action',
299 'search': 'search_action',
299 } 300 }
300 def handle_action(self): 301 def handle_action(self):
301 ''' Determine whether there should be an _action called. 302 ''' Determine whether there should be an _action called.
302 303
303 The action is defined by the form variable :action which 304 The action is defined by the form variable :action which
306 "edit" -> self.edititem_action 307 "edit" -> self.edititem_action
307 "new" -> self.newitem_action 308 "new" -> self.newitem_action
308 "login" -> self.login_action 309 "login" -> self.login_action
309 "logout" -> self.logout_action 310 "logout" -> self.logout_action
310 "register" -> self.register_action 311 "register" -> self.register_action
312 "search" -> self.search_action
311 313
312 ''' 314 '''
313 if not self.form.has_key(':action'): 315 if not self.form.has_key(':action'):
314 return None 316 return None
315 try: 317 try:
510 __file 512 __file
511 Create a file and attach it to the current node's 513 Create a file and attach it to the current node's
512 "files" property. Attach the file to the message created from 514 "files" property. Attach the file to the message created from
513 the __note if it's supplied. 515 the __note if it's supplied.
514 ''' 516 '''
515 cn = self.classname 517 cl = self.db.classes[self.classname]
516 cl = self.db.classes[cn]
517 518
518 # check permission 519 # check permission
519 userid = self.db.user.lookup(self.user) 520 userid = self.db.user.lookup(self.user)
520 if not self.db.security.hasPermission('Edit', userid, cn): 521 if not self.db.security.hasPermission('Edit', userid, self.classname):
521 self.error_message.append( 522 self.error_message.append(
522 _('You do not have permission to edit %s' %cn)) 523 _('You do not have permission to edit %(classname)s' %
524 self.__dict__))
525 return
523 526
524 # perform the edit 527 # perform the edit
525 props = parsePropsFromForm(self.db, cl, self.form, self.nodeid) 528 try:
526 529 props = parsePropsFromForm(self.db, cl, self.form, self.nodeid)
527 # make changes to the node 530
528 props = self._changenode(props) 531 # make changes to the node
529 532 props = self._changenode(props)
530 # handle linked nodes 533
531 self._post_editnode(self.nodeid) 534 # handle linked nodes
535 self._post_editnode(self.nodeid)
536
537 except (ValueError, KeyError), message:
538 self.error_message.append(_('Error: ') + str(message))
539 return
532 540
533 # commit now that all the tricky stuff is done 541 # commit now that all the tricky stuff is done
534 self.db.commit() 542 self.db.commit()
535 543
536 # and some nice feedback for the user 544 # and some nice feedback for the user
543 message = _('file added') 551 message = _('file added')
544 else: 552 else:
545 message = _('nothing changed') 553 message = _('nothing changed')
546 554
547 # redirect to the item's edit page 555 # redirect to the item's edit page
548 raise Redirect, '%s/%s%s?:ok_message=%s'%(self.base, cn, self.nodeid, 556 raise Redirect, '%s/%s%s?:ok_message=%s'%(self.base, self.classname,
549 urllib.quote(message)) 557 self.nodeid, urllib.quote(message))
550 558
551 def newitem_action(self): 559 def newitem_action(self):
552 ''' Add a new item to the database. 560 ''' Add a new item to the database.
553 561
554 This follows the same form as the edititem_action 562 This follows the same form as the edititem_action
555 ''' 563 '''
556 # check permission 564 # check permission
557 cn = self.classname
558 userid = self.db.user.lookup(self.user) 565 userid = self.db.user.lookup(self.user)
559 if not self.db.security.hasPermission('Edit', userid, cn): 566 if not self.db.security.hasPermission('Edit', userid, self.classname):
560 self.error_message.append( 567 self.error_message.append(
561 _('You do not have permission to create %s' %cn)) 568 _('You do not have permission to create %s' %self.classname))
562 569
563 # XXX 570 # XXX
564 # cl = self.db.classes[cn] 571 # cl = self.db.classes[cn]
565 # if self.form.has_key(':multilink'): 572 # if self.form.has_key(':multilink'):
566 # link = self.form[':multilink'].value 573 # link = self.form[':multilink'].value
581 588
582 # render the newly created item 589 # render the newly created item
583 self.nodeid = nid 590 self.nodeid = nid
584 591
585 # and some nice feedback for the user 592 # and some nice feedback for the user
586 message = _('%(classname)s created ok')%{'classname': cn} 593 message = _('%(classname)s created ok')%self.__dict__
594 except (ValueError, KeyError), message:
595 self.error_message.append(_('Error: ') + str(message))
596 return
587 except: 597 except:
588 # oops 598 # oops
589 self.db.rollback() 599 self.db.rollback()
590 s = StringIO.StringIO() 600 s = StringIO.StringIO()
591 traceback.print_exc(None, s) 601 traceback.print_exc(None, s)
592 self.error_message.append('<pre>%s</pre>'%cgi.escape(s.getvalue())) 602 self.error_message.append('<pre>%s</pre>'%cgi.escape(s.getvalue()))
603 return
593 604
594 # redirect to the new item's page 605 # redirect to the new item's page
595 raise Redirect, '%s/%s%s?:ok_message=%s'%(self.base, cn, nid, 606 raise Redirect, '%s/%s%s?:ok_message=%s'%(self.base, self.classname,
596 urllib.quote(message)) 607 nid, urllib.quote(message))
597 608
598 def genericedit_action(self): 609 def genericedit_action(self):
599 ''' Performs an edit of all of a class' items in one go. 610 ''' Performs an edit of all of a class' items in one go.
600 611
601 The "rows" CGI var defines the CSV-formatted entries for the 612 The "rows" CGI var defines the CSV-formatted entries for the
602 class. New nodes are identified by the ID 'X' (or any other 613 class. New nodes are identified by the ID 'X' (or any other
603 non-existent ID) and removed lines are retired. 614 non-existent ID) and removed lines are retired.
604 ''' 615 '''
605 userid = self.db.user.lookup(self.user) 616 userid = self.db.user.lookup(self.user)
606 if not self.db.security.hasPermission('Edit', userid): 617 if not self.db.security.hasPermission('Edit', userid, self.classname):
607 raise Unauthorised, _("You do not have permission to access"\ 618 raise Unauthorised, _("You do not have permission to access"\
608 " %(action)s.")%{'action': self.classname} 619 " %(action)s.")%{'action': self.classname}
609 w = self.write 620 cl = self.db.classes[self.classname]
610 cn = self.classname
611 cl = self.db.classes[cn]
612 idlessprops = cl.getprops(protected=0).keys() 621 idlessprops = cl.getprops(protected=0).keys()
613 props = ['id'] + idlessprops 622 props = ['id'] + idlessprops
614 623
615 # get the CSV module 624 # get the CSV module
616 try: 625 try:
636 nodeid, values = values[0], values[1:] 645 nodeid, values = values[0], values[1:]
637 found[nodeid] = 1 646 found[nodeid] = 1
638 647
639 # confirm correct weight 648 # confirm correct weight
640 if len(idlessprops) != len(values): 649 if len(idlessprops) != len(values):
641 w(_('Not enough values on line %(line)s'%{'line':line})) 650 message=(_('Not enough values on line %(line)s'%{'line':line}))
642 return 651 return
643 652
644 # extract the new values 653 # extract the new values
645 d = {} 654 d = {}
646 for name, value in zip(idlessprops, values): 655 for name, value in zip(idlessprops, values):
666 cl.retire(nodeid) 675 cl.retire(nodeid)
667 676
668 message = _('items edited OK') 677 message = _('items edited OK')
669 678
670 # redirect to the class' edit page 679 # redirect to the class' edit page
671 raise Redirect, '%s/%s?:ok_message=%s'%(self.base, cn, 680 raise Redirect, '%s/%s?:ok_message=%s'%(self.base, self.classname,
672 urllib.quote(message)) 681 urllib.quote(message))
673 682
674 def _changenode(self, props): 683 def _changenode(self, props):
675 ''' change the node based on the contents of the form 684 ''' change the node based on the contents of the form
676 ''' 685 '''
795 designator, property = value.split(':') 804 designator, property = value.split(':')
796 link, nodeid = hyperdb.splitDesignator(designator) 805 link, nodeid = hyperdb.splitDesignator(designator)
797 link = self.db.classes[link] 806 link = self.db.classes[link]
798 link.set(nodeid, **{property: nid}) 807 link.set(nodeid, **{property: nid})
799 808
809 def search_action(self):
810 ''' Mangle some of the form variables.
811
812 Set the form ":filter" variable based on the values of the
813 filter variables - if they're set to anything other than
814 "dontcare" then add them to :filter.
815 '''
816 # add a faked :filter form variable for each filtering prop
817 props = self.db.classes[self.classname].getprops()
818 for key in self.form.keys():
819 if not props.has_key(key): continue
820 if not self.form[key].value: continue
821 self.form.value.append(cgi.MiniFieldStorage(':filter', key))
800 822
801 def remove_action(self, dre=re.compile(r'([^\d]+)(\d+)')): 823 def remove_action(self, dre=re.compile(r'([^\d]+)(\d+)')):
802 # XXX handle this ! 824 # XXX handle this !
803 target = self.index_arg(':target')[0] 825 target = self.index_arg(':target')[0]
804 m = dre.match(target) 826 m = dre.match(target)
836 continue 858 continue
837 proptype = cl.properties[key] 859 proptype = cl.properties[key]
838 if isinstance(proptype, hyperdb.String): 860 if isinstance(proptype, hyperdb.String):
839 value = form[key].value.strip() 861 value = form[key].value.strip()
840 elif isinstance(proptype, hyperdb.Password): 862 elif isinstance(proptype, hyperdb.Password):
841 value = password.Password(form[key].value.strip()) 863 value = form[key].value.strip()
864 if not value:
865 # ignore empty password values
866 continue
867 value = password.Password(value)
842 elif isinstance(proptype, hyperdb.Date): 868 elif isinstance(proptype, hyperdb.Date):
843 value = form[key].value.strip() 869 value = form[key].value.strip()
844 if value: 870 if value:
845 value = date.Date(form[key].value.strip()) 871 value = date.Date(form[key].value.strip())
846 else: 872 else:

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