comparison roundup/cgi/client.py @ 1055:cf72eae57a2c

Fixed instance installation ... moved the htmlbase module into templates and call it <template>_htmlbase.py ... no more try/except in instance __init__! Added :required to form handling. Handle multiple values for single form items with decent error report.
author Richard Jones <richard@users.sourceforge.net>
date Thu, 05 Sep 2002 23:39:14 +0000
parents 3d8ea16347aa
children 1c2a2ecc1b03
comparison
equal deleted inserted replaced
1054:3d8ea16347aa 1055:cf72eae57a2c
1 # $Id: client.py,v 1.14 2002-09-05 05:25:23 richard Exp $ 1 # $Id: client.py,v 1.15 2002-09-05 23:39:12 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
112 4. render a template, resulting in HTML output 112 4. render a template, resulting in HTML output
113 113
114 In some situations, exceptions occur: 114 In some situations, exceptions occur:
115 - HTTP Redirect (generally raised by an action) 115 - HTTP Redirect (generally raised by an action)
116 - SendFile (generally raised by determine_context) 116 - SendFile (generally raised by determine_context)
117 serve up a FileClass "content" property
117 - SendStaticFile (generally raised by determine_context) 118 - SendStaticFile (generally raised by determine_context)
118 - Unauthorised (raised pretty much anywhere it needs to be) 119 serve up a file from the tracker "html" directory
119 - NotFound (see above... percolates up to the CGI interface) 120 - Unauthorised (generally raised by an action)
121 the action is cancelled, the request is rendered and an error
122 message is displayed indicating that permission was not
123 granted for the action to take place
124 - NotFound (raised wherever it needs to be)
125 percolates up to the CGI interface that called the client
120 ''' 126 '''
121 self.content_action = None 127 self.content_action = None
122 self.ok_message = [] 128 self.ok_message = []
123 self.error_message = [] 129 self.error_message = []
124 try: 130 try:
579 "messages" property. 585 "messages" property.
580 __file 586 __file
581 Create a file and attach it to the current node's 587 Create a file and attach it to the current node's
582 "files" property. Attach the file to the message created from 588 "files" property. Attach the file to the message created from
583 the __note if it's supplied. 589 the __note if it's supplied.
590
591 :required=property,property,...
592 The named properties are required to be filled in the form.
593
584 ''' 594 '''
585 cl = self.db.classes[self.classname] 595 cl = self.db.classes[self.classname]
586 596
587 # parse the props from the form 597 # parse the props from the form
588 try: 598 try:
651 return 0 661 return 0
652 662
653 def newItemAction(self): 663 def newItemAction(self):
654 ''' Add a new item to the database. 664 ''' Add a new item to the database.
655 665
656 This follows the same form as the editItemAction 666 This follows the same form as the editItemAction, with the same
667 special form values.
657 ''' 668 '''
658 cl = self.db.classes[self.classname] 669 cl = self.db.classes[self.classname]
659 670
660 # parse the props from the form 671 # parse the props from the form
661 try: 672 try:
1031 link = self.db.classes[link] 1042 link = self.db.classes[link]
1032 link.set(nodeid, **{property: nid}) 1043 link.set(nodeid, **{property: nid})
1033 1044
1034 1045
1035 def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')): 1046 def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
1036 '''Pull properties for the given class out of the form. 1047 ''' Pull properties for the given class out of the form.
1048
1049 If a ":required" parameter is supplied, then the names property values
1050 must be supplied or a ValueError will be raised.
1037 ''' 1051 '''
1052 required = []
1053 if form.has_key(':required'):
1054 value = form[':required']
1055 if isinstance(value, type([])):
1056 required = [i.value.strip() for i in value]
1057 else:
1058 required = [i.strip() for i in value.value.split(',')]
1059
1038 props = {} 1060 props = {}
1039 keys = form.keys() 1061 keys = form.keys()
1040 for key in keys: 1062 for key in keys:
1041 if not cl.properties.has_key(key): 1063 if not cl.properties.has_key(key):
1042 continue 1064 continue
1043 proptype = cl.properties[key] 1065 proptype = cl.properties[key]
1066
1067 # Get the form value. This value may be a MiniFieldStorage or a list
1068 # of MiniFieldStorages.
1069 value = form[key]
1070
1071 # make sure non-multilinks only get one value
1072 if not isinstance(proptype, hyperdb.Multilink):
1073 if isinstance(value, type([])):
1074 raise ValueError, 'You have submitted more than one value'\
1075 ' for the %s property'%key
1076 # we've got a MiniFieldStorage, so pull out the value and strip
1077 # surrounding whitespace
1078 value = value.value.strip()
1079
1044 if isinstance(proptype, hyperdb.String): 1080 if isinstance(proptype, hyperdb.String):
1081 pass
1045 value = form[key].value.strip() 1082 value = form[key].value.strip()
1046 elif isinstance(proptype, hyperdb.Password): 1083 elif isinstance(proptype, hyperdb.Password):
1047 value = form[key].value.strip()
1048 if not value: 1084 if not value:
1049 # ignore empty password values 1085 # ignore empty password values
1050 continue 1086 continue
1051 value = password.Password(value) 1087 value = password.Password(value)
1052 elif isinstance(proptype, hyperdb.Date): 1088 elif isinstance(proptype, hyperdb.Date):
1053 value = form[key].value.strip()
1054 if value: 1089 if value:
1055 value = date.Date(form[key].value.strip()) 1090 value = date.Date(form[key].value.strip())
1056 else: 1091 else:
1057 value = None 1092 value = None
1058 elif isinstance(proptype, hyperdb.Interval): 1093 elif isinstance(proptype, hyperdb.Interval):
1059 value = form[key].value.strip()
1060 if value: 1094 if value:
1061 value = date.Interval(form[key].value.strip()) 1095 value = date.Interval(form[key].value.strip())
1062 else: 1096 else:
1063 value = None 1097 value = None
1064 elif isinstance(proptype, hyperdb.Link): 1098 elif isinstance(proptype, hyperdb.Link):
1065 value = form[key].value.strip()
1066 # see if it's the "no selection" choice 1099 # see if it's the "no selection" choice
1067 if value == '-1': 1100 if value == '-1':
1068 value = None 1101 value = None
1069 else: 1102 else:
1070 # handle key values 1103 # handle key values
1075 except KeyError: 1108 except KeyError:
1076 raise ValueError, _('property "%(propname)s": ' 1109 raise ValueError, _('property "%(propname)s": '
1077 '%(value)s not a %(classname)s')%{'propname':key, 1110 '%(value)s not a %(classname)s')%{'propname':key,
1078 'value': value, 'classname': link} 1111 'value': value, 'classname': link}
1079 elif isinstance(proptype, hyperdb.Multilink): 1112 elif isinstance(proptype, hyperdb.Multilink):
1080 value = form[key] 1113 if isinstance(value, type([])):
1081 if not isinstance(value, type([])): 1114 # it's a list of MiniFieldStorages
1115 value = [i.value.strip() for i in value]
1116 else:
1117 # it's a MiniFieldStorage, but may be a comma-separated list
1118 # of values
1082 value = [i.strip() for i in value.value.split(',')] 1119 value = [i.strip() for i in value.value.split(',')]
1083 else:
1084 value = [i.value.strip() for i in value]
1085 link = cl.properties[key].classname 1120 link = cl.properties[key].classname
1086 l = [] 1121 l = []
1087 for entry in map(str, value): 1122 for entry in map(str, value):
1088 if entry == '': continue 1123 if entry == '': continue
1089 if not num_re.match(entry): 1124 if not num_re.match(entry):
1095 'propname':key, 'value': entry, 'classname': link} 1130 'propname':key, 'value': entry, 'classname': link}
1096 l.append(entry) 1131 l.append(entry)
1097 l.sort() 1132 l.sort()
1098 value = l 1133 value = l
1099 elif isinstance(proptype, hyperdb.Boolean): 1134 elif isinstance(proptype, hyperdb.Boolean):
1100 value = form[key].value.strip()
1101 props[key] = value = value.lower() in ('yes', 'true', 'on', '1') 1135 props[key] = value = value.lower() in ('yes', 'true', 'on', '1')
1102 elif isinstance(proptype, hyperdb.Number): 1136 elif isinstance(proptype, hyperdb.Number):
1103 value = form[key].value.strip()
1104 props[key] = value = int(value) 1137 props[key] = value = int(value)
1105 1138
1106 # get the old value 1139 # get the old value
1107 if nodeid: 1140 if nodeid:
1108 try: 1141 try:
1115 # if changed, set it 1148 # if changed, set it
1116 if value != existing: 1149 if value != existing:
1117 props[key] = value 1150 props[key] = value
1118 else: 1151 else:
1119 props[key] = value 1152 props[key] = value
1153
1154 # see if all the required properties have been supplied
1155 l = []
1156 for property in required:
1157 if not props.has_key(property):
1158 l.append(property)
1159 if l:
1160 raise ValueError, 'Required properties %s not supplied'%(', '.join(l))
1161
1120 return props 1162 return props
1121 1163
1122 1164

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