comparison roundup/cgi/client.py @ 1818:85fd3d0e7d81

Actually use FormError, so we can move the handling up to inner_main(). Implement newItemAction using editItemAction, removing duplication.
author Johannes Gijsbers <jlgijsbers@users.sourceforge.net>
date Wed, 24 Sep 2003 14:53:58 +0000
parents ea43cb3c157f
children 4ac11e7fa11a
comparison
equal deleted inserted replaced
1817:3d180e08fae0 1818:85fd3d0e7d81
1 # $Id: client.py,v 1.139 2003-09-10 13:04:05 jlgijsbers Exp $ 1 # $Id: client.py,v 1.140 2003-09-24 14:53:58 jlgijsbers 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
29 pass 29 pass
30 30
31 # used by a couple of routines 31 # used by a couple of routines
32 chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' 32 chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
33 33
34 # XXX actually _use_ FormError
35 class FormError(ValueError): 34 class FormError(ValueError):
36 ''' An "expected" exception occurred during form parsing. 35 ''' An "expected" exception occurred during form parsing.
37 - ie. something we know can go wrong, and don't want to alarm the 36 - ie. something we know can go wrong, and don't want to alarm the
38 user with 37 user with
39 38
278 self.error_message.append(message) 277 self.error_message.append(message)
279 self.write(self.renderContext()) 278 self.write(self.renderContext())
280 except NotFound: 279 except NotFound:
281 # pass through 280 # pass through
282 raise 281 raise
282 except FormError, e:
283 self.error_message.append(_('Form Error: ') + str(e))
284 self.write(self.renderContext())
283 except: 285 except:
284 # everything else 286 # everything else
285 self.write(cgitb.html()) 287 self.write(cgitb.html())
286 288
287 def clean_sessions(self): 289 def clean_sessions(self):
724 '''Attempt to create a new user based on the contents of the form 726 '''Attempt to create a new user based on the contents of the form
725 and then set the cookie. 727 and then set the cookie.
726 728
727 return 1 on successful login 729 return 1 on successful login
728 ''' 730 '''
729 # parse the props from the form 731 props = self.parsePropsFromForm()[0][('user', None)]
730 try:
731 props = self.parsePropsFromForm()[0][('user', None)]
732 except (ValueError, KeyError), message:
733 self.error_message.append(_('Error: ') + str(message))
734 return
735 732
736 # make sure we're allowed to register 733 # make sure we're allowed to register
737 if not self.registerPermission(props): 734 if not self.registerPermission(props):
738 raise Unauthorised, _("You do not have permission to register") 735 raise Unauthorised, _("You do not have permission to register")
739 736
932 def editItemAction(self): 929 def editItemAction(self):
933 ''' Perform an edit of an item in the database. 930 ''' Perform an edit of an item in the database.
934 931
935 See parsePropsFromForm and _editnodes for special variables 932 See parsePropsFromForm and _editnodes for special variables
936 ''' 933 '''
937 # parse the props from the form 934 props, links = self.parsePropsFromForm()
938 try:
939 props, links = self.parsePropsFromForm()
940 except (ValueError, KeyError), message:
941 self.error_message.append(_('Parse Error: ') + str(message))
942 return
943 935
944 # handle the props 936 # handle the props
945 try: 937 try:
946 message = self._editnodes(props, links) 938 message = self._editnodes(props, links)
947 except (ValueError, KeyError, IndexError), message: 939 except (ValueError, KeyError, IndexError), message:
953 945
954 # redirect to the item's edit page 946 # redirect to the item's edit page
955 raise Redirect, '%s%s%s?@ok_message=%s&@template=%s'%(self.base, 947 raise Redirect, '%s%s%s?@ok_message=%s&@template=%s'%(self.base,
956 self.classname, self.nodeid, urllib.quote(message), 948 self.classname, self.nodeid, urllib.quote(message),
957 urllib.quote(self.template)) 949 urllib.quote(self.template))
950
951 newItemAction = editItemAction
958 952
959 def editItemPermission(self, props): 953 def editItemPermission(self, props):
960 ''' Determine whether the user has permission to edit this item. 954 ''' Determine whether the user has permission to edit this item.
961 955
962 Base behaviour is to check the user can edit this class. If we're 956 Base behaviour is to check the user can edit this class. If we're
977 if self.nodeid == self.userid: 971 if self.nodeid == self.userid:
978 return 1 972 return 1
979 if self.db.security.hasPermission('Edit', self.userid, self.classname): 973 if self.db.security.hasPermission('Edit', self.userid, self.classname):
980 return 1 974 return 1
981 return 0 975 return 0
982
983 def newItemAction(self):
984 ''' Add a new item to the database.
985
986 This follows the same form as the editItemAction, with the same
987 special form values.
988 '''
989 # parse the props from the form
990 try:
991 props, links = self.parsePropsFromForm()
992 except (ValueError, KeyError), message:
993 self.error_message.append(_('Error: ') + str(message))
994 return
995
996 # handle the props - edit or create
997 try:
998 # when it hits the None element, it'll set self.nodeid
999 messages = self._editnodes(props, links)
1000
1001 except (ValueError, KeyError, IndexError), message:
1002 # these errors might just be indicative of user dumbness
1003 self.error_message.append(_('Error: ') + str(message))
1004 return
1005
1006 # commit now that all the tricky stuff is done
1007 self.db.commit()
1008
1009 # redirect to the new item's page
1010 raise Redirect, '%s%s%s?@ok_message=%s&@template=%s'%(self.base,
1011 self.classname, self.nodeid, urllib.quote(messages),
1012 urllib.quote(self.template))
1013 976
1014 def newItemPermission(self, props): 977 def newItemPermission(self, props):
1015 ''' Determine whether the user has permission to create (edit) this 978 ''' Determine whether the user has permission to create (edit) this
1016 item. 979 item.
1017 980
1630 if d['link']: 1593 if d['link']:
1631 value = [] 1594 value = []
1632 for entry in extractFormList(form[key]): 1595 for entry in extractFormList(form[key]):
1633 m = self.FV_DESIGNATOR.match(entry) 1596 m = self.FV_DESIGNATOR.match(entry)
1634 if not m: 1597 if not m:
1635 raise ValueError, \ 1598 raise FormError, \
1636 'link "%s" value "%s" not a designator'%(key, entry) 1599 'link "%s" value "%s" not a designator'%(key, entry)
1637 value.append((m.group(1), m.group(2))) 1600 value.append((m.group(1), m.group(2)))
1638 1601
1639 # make sure the link property is valid 1602 # make sure the link property is valid
1640 if (not isinstance(propdef[propname], hyperdb.Multilink) and 1603 if (not isinstance(propdef[propname], hyperdb.Multilink) and
1641 not isinstance(propdef[propname], hyperdb.Link)): 1604 not isinstance(propdef[propname], hyperdb.Link)):
1642 raise ValueError, '%s %s is not a link or '\ 1605 raise FormError, '%s %s is not a link or '\
1643 'multilink property'%(cn, propname) 1606 'multilink property'%(cn, propname)
1644 1607
1645 all_links.append((cn, nodeid, propname, value)) 1608 all_links.append((cn, nodeid, propname, value))
1646 continue 1609 continue
1647 1610
1658 mlaction = 'add' 1621 mlaction = 'add'
1659 1622
1660 # does the property exist? 1623 # does the property exist?
1661 if not propdef.has_key(propname): 1624 if not propdef.has_key(propname):
1662 if mlaction != 'set': 1625 if mlaction != 'set':
1663 raise ValueError, 'You have submitted a %s action for'\ 1626 raise FormError, 'You have submitted a %s action for'\
1664 ' the property "%s" which doesn\'t exist'%(mlaction, 1627 ' the property "%s" which doesn\'t exist'%(mlaction,
1665 propname) 1628 propname)
1666 # the form element is probably just something we don't care 1629 # the form element is probably just something we don't care
1667 # about - ignore it 1630 # about - ignore it
1668 continue 1631 continue
1676 if isinstance(proptype, hyperdb.Multilink): 1639 if isinstance(proptype, hyperdb.Multilink):
1677 value = extractFormList(value) 1640 value = extractFormList(value)
1678 else: 1641 else:
1679 # multiple values are not OK 1642 # multiple values are not OK
1680 if isinstance(value, type([])): 1643 if isinstance(value, type([])):
1681 raise ValueError, 'You have submitted more than one value'\ 1644 raise FormError, 'You have submitted more than one value'\
1682 ' for the %s property'%propname 1645 ' for the %s property'%propname
1683 # value might be a file upload... 1646 # value might be a file upload...
1684 if not hasattr(value, 'filename') or value.filename is None: 1647 if not hasattr(value, 'filename') or value.filename is None:
1685 # nope, pull out the value and strip it 1648 # nope, pull out the value and strip it
1686 value = value.value.strip() 1649 value = value.value.strip()
1699 for key, d in matches: 1662 for key, d in matches:
1700 if d['confirm'] and d['propname'] == propname: 1663 if d['confirm'] and d['propname'] == propname:
1701 confirm = form[key] 1664 confirm = form[key]
1702 break 1665 break
1703 else: 1666 else:
1704 raise ValueError, 'Password and confirmation text do '\ 1667 raise FormError, 'Password and confirmation text do '\
1705 'not match' 1668 'not match'
1706 if isinstance(confirm, type([])): 1669 if isinstance(confirm, type([])):
1707 raise ValueError, 'You have submitted more than one value'\ 1670 raise FormError, 'You have submitted more than one value'\
1708 ' for the %s property'%propname 1671 ' for the %s property'%propname
1709 if value != confirm.value: 1672 if value != confirm.value:
1710 raise ValueError, 'Password and confirmation text do '\ 1673 raise FormError, 'Password and confirmation text do '\
1711 'not match' 1674 'not match'
1712 value = password.Password(value) 1675 value = password.Password(value)
1713 1676
1714 elif isinstance(proptype, hyperdb.Link): 1677 elif isinstance(proptype, hyperdb.Link):
1715 # see if it's the "no selection" choice 1678 # see if it's the "no selection" choice
1723 link = proptype.classname 1686 link = proptype.classname
1724 if not num_re.match(value): 1687 if not num_re.match(value):
1725 try: 1688 try:
1726 value = db.classes[link].lookup(value) 1689 value = db.classes[link].lookup(value)
1727 except KeyError: 1690 except KeyError:
1728 raise ValueError, _('property "%(propname)s": ' 1691 raise FormError, _('property "%(propname)s": '
1729 '%(value)s not a %(classname)s')%{ 1692 '%(value)s not a %(classname)s')%{
1730 'propname': propname, 'value': value, 1693 'propname': propname, 'value': value,
1731 'classname': link} 1694 'classname': link}
1732 except TypeError, message: 1695 except TypeError, message:
1733 raise ValueError, _('you may only enter ID values ' 1696 raise FormError, _('you may only enter ID values '
1734 'for property "%(propname)s": %(message)s')%{ 1697 'for property "%(propname)s": %(message)s')%{
1735 'propname': propname, 'message': message} 1698 'propname': propname, 'message': message}
1736 elif isinstance(proptype, hyperdb.Multilink): 1699 elif isinstance(proptype, hyperdb.Multilink):
1737 # perform link class key value lookup if necessary 1700 # perform link class key value lookup if necessary
1738 link = proptype.classname 1701 link = proptype.classname
1742 if not entry: continue 1705 if not entry: continue
1743 if not num_re.match(entry): 1706 if not num_re.match(entry):
1744 try: 1707 try:
1745 entry = link_cl.lookup(entry) 1708 entry = link_cl.lookup(entry)
1746 except KeyError: 1709 except KeyError:
1747 raise ValueError, _('property "%(propname)s": ' 1710 raise FormError, _('property "%(propname)s": '
1748 '"%(value)s" not an entry of %(classname)s')%{ 1711 '"%(value)s" not an entry of %(classname)s')%{
1749 'propname': propname, 'value': entry, 1712 'propname': propname, 'value': entry,
1750 'classname': link} 1713 'classname': link}
1751 except TypeError, message: 1714 except TypeError, message:
1752 raise ValueError, _('you may only enter ID values ' 1715 raise FormError, _('you may only enter ID values '
1753 'for property "%(propname)s": %(message)s')%{ 1716 'for property "%(propname)s": %(message)s')%{
1754 'propname': propname, 'message': message} 1717 'propname': propname, 'message': message}
1755 l.append(entry) 1718 l.append(entry)
1756 l.sort() 1719 l.sort()
1757 1720
1773 # the list 1736 # the list
1774 for entry in l: 1737 for entry in l:
1775 try: 1738 try:
1776 existing.remove(entry) 1739 existing.remove(entry)
1777 except ValueError: 1740 except ValueError:
1778 raise ValueError, _('property "%(propname)s": ' 1741 raise FormError, _('property "%(propname)s": '
1779 '"%(value)s" not currently in list')%{ 1742 '"%(value)s" not currently in list')%{
1780 'propname': propname, 'value': entry} 1743 'propname': propname, 'value': entry}
1781 else: 1744 else:
1782 # add - easy, just don't dupe 1745 # add - easy, just don't dupe
1783 for entry in l: 1746 for entry in l:
1824 elif isinstance(proptype, hyperdb.Boolean): 1787 elif isinstance(proptype, hyperdb.Boolean):
1825 value = value.lower() in ('yes', 'true', 'on', '1') 1788 value = value.lower() in ('yes', 'true', 'on', '1')
1826 elif isinstance(proptype, hyperdb.Number): 1789 elif isinstance(proptype, hyperdb.Number):
1827 value = float(value) 1790 value = float(value)
1828 except ValueError, msg: 1791 except ValueError, msg:
1829 raise ValueError, _('Error with %s property: %s')%( 1792 raise FormError, _('Error with %s property: %s')%(
1830 propname, msg) 1793 propname, msg)
1831 1794
1832 # register that we got this property 1795 # register that we got this property
1833 if value: 1796 if value:
1834 got_props[this][propname] = 1 1797 got_props[this][propname] = 1
1840 except KeyError: 1803 except KeyError:
1841 # this might be a new property for which there is 1804 # this might be a new property for which there is
1842 # no existing value 1805 # no existing value
1843 if not propdef.has_key(propname): 1806 if not propdef.has_key(propname):
1844 raise 1807 raise
1808 except IndexError, message:
1809 raise FormError(str(message))
1845 1810
1846 # make sure the existing multilink is sorted 1811 # make sure the existing multilink is sorted
1847 if isinstance(proptype, hyperdb.Multilink): 1812 if isinstance(proptype, hyperdb.Multilink):
1848 existing.sort() 1813 existing.sort()
1849 1814
1896 else: 1861 else:
1897 p = 'property' 1862 p = 'property'
1898 s.append('Required %s %s %s not supplied'%(thing[0], p, 1863 s.append('Required %s %s %s not supplied'%(thing[0], p,
1899 ', '.join(required))) 1864 ', '.join(required)))
1900 if s: 1865 if s:
1901 raise ValueError, '\n'.join(s) 1866 raise FormError, '\n'.join(s)
1902 1867
1903 # When creating a FileClass node, it should have a non-empty content 1868 # When creating a FileClass node, it should have a non-empty content
1904 # property to be created. When editing a FileClass node, it should 1869 # property to be created. When editing a FileClass node, it should
1905 # either have a non-empty content property or no property at all. In 1870 # either have a non-empty content property or no property at all. In
1906 # the latter case, nothing will change. 1871 # the latter case, nothing will change.
1908 if isinstance(self.db.classes[cn], hyperdb.FileClass): 1873 if isinstance(self.db.classes[cn], hyperdb.FileClass):
1909 if id == '-1': 1874 if id == '-1':
1910 if not props.get('content', ''): 1875 if not props.get('content', ''):
1911 del all_props[(cn, id)] 1876 del all_props[(cn, id)]
1912 elif props.has_key('content') and not props['content']: 1877 elif props.has_key('content') and not props['content']:
1913 raise ValueError, _('File is empty') 1878 raise FormError, _('File is empty')
1914 return all_props, all_links 1879 return all_props, all_links
1915 1880
1916 def fixNewlines(text): 1881 def fixNewlines(text):
1917 ''' Homogenise line endings. 1882 ''' Homogenise line endings.
1918 1883

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