Skip to content

Commit 4d7734d

Browse files
author
Richard Jones
committed
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.
1 parent e0e7cd8 commit 4d7734d

File tree

6 files changed

+102
-51
lines changed

6 files changed

+102
-51
lines changed

TODO.txt

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,14 @@ pending web: search "refinement"
4747
query values
4848
pending web: have roundup.cgi pick up instance config from the environment
4949
pending web: UNIX init.d script for roundup-server
50+
pending web: rewritten documentation (can come after the beta though so stuff
51+
is settled)
52+
pending web: modify cgitb to handle PageTemplate errors better (see how
53+
Zope handles __traceback_supplement__ and __traceback_info__)
54+
pending web: title is stoopid
5055

51-
New templating TODO:
52-
. rewritten documentation (can come after the beta though so stuff is settled)
53-
. modify cgitb to handle PageTemplate errors better
54-
. add :required to edit action
55-
active web: title is stoopid
56-
active hyperdb: full-text searching doesn't appear to match stuff in titles,
57-
even though they're supposed to be indexed...
58-
59-
ongoing: any bugs
6056
bug: request.url is incorrect in cgi-bin environments
6157

62-
rejected instance: the use of non-Python configuration files (ConfigParser)
6358
done web: Re-enable link backrefs from messages (feature request #568714) (RJ)
6459
done web: have the page layout (header/footer) be templatable (RJ)
6560
done web: fixing the templating so it works (RJ)
@@ -79,7 +74,10 @@ done mailgw: better help message (feature request #558562) (RJ)
7974
done security: add info from doc/security.txt to design doc (RJ)
8075
done security: switch to sessions for web authentication (RJ)
8176
done security: implement and use the new logical control mechanisms
82-
done web: saving of named queries (GM)
77+
done web: saving of named queries (GM, RJ)
8378
done web: handle "not found", access and item page render errors better (RJ)
8479
done web: fix double-submit by having new-item-submit redirect at end (RJ)
85-
done web: daemonify roundup-server (fork, logfile, pidfile)
80+
done web: daemonify roundup-server (fork, logfile, pidfile) (RJ)
81+
82+
rejected instance: the use of non-Python configuration files (ConfigParser)
83+

roundup/cgi/client.py

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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 $
22

33
__doc__ = """
44
WWW request handler (also used in the stand-alone server).
@@ -114,9 +114,15 @@ def main(self):
114114
In some situations, exceptions occur:
115115
- HTTP Redirect (generally raised by an action)
116116
- SendFile (generally raised by determine_context)
117+
serve up a FileClass "content" property
117118
- SendStaticFile (generally raised by determine_context)
118-
- Unauthorised (raised pretty much anywhere it needs to be)
119-
- NotFound (see above... percolates up to the CGI interface)
119+
serve up a file from the tracker "html" directory
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
120126
'''
121127
self.content_action = None
122128
self.ok_message = []
@@ -581,6 +587,10 @@ def editItemAction(self):
581587
Create a file and attach it to the current node's
582588
"files" property. Attach the file to the message created from
583589
the __note if it's supplied.
590+
591+
:required=property,property,...
592+
The named properties are required to be filled in the form.
593+
584594
'''
585595
cl = self.db.classes[self.classname]
586596

@@ -653,7 +663,8 @@ def editItemPermission(self, props):
653663
def newItemAction(self):
654664
''' Add a new item to the database.
655665
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.
657668
'''
658669
cl = self.db.classes[self.classname]
659670

@@ -1033,36 +1044,58 @@ def _post_editnode(self, nid):
10331044

10341045

10351046
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.
10371051
'''
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+
10381060
props = {}
10391061
keys = form.keys()
10401062
for key in keys:
10411063
if not cl.properties.has_key(key):
10421064
continue
10431065
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+
10441080
if isinstance(proptype, hyperdb.String):
1081+
pass
10451082
value = form[key].value.strip()
10461083
elif isinstance(proptype, hyperdb.Password):
1047-
value = form[key].value.strip()
10481084
if not value:
10491085
# ignore empty password values
10501086
continue
10511087
value = password.Password(value)
10521088
elif isinstance(proptype, hyperdb.Date):
1053-
value = form[key].value.strip()
10541089
if value:
10551090
value = date.Date(form[key].value.strip())
10561091
else:
10571092
value = None
10581093
elif isinstance(proptype, hyperdb.Interval):
1059-
value = form[key].value.strip()
10601094
if value:
10611095
value = date.Interval(form[key].value.strip())
10621096
else:
10631097
value = None
10641098
elif isinstance(proptype, hyperdb.Link):
1065-
value = form[key].value.strip()
10661099
# see if it's the "no selection" choice
10671100
if value == '-1':
10681101
value = None
@@ -1077,11 +1110,13 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
10771110
'%(value)s not a %(classname)s')%{'propname':key,
10781111
'value': value, 'classname': link}
10791112
elif isinstance(proptype, hyperdb.Multilink):
1080-
value = form[key]
1081-
if not isinstance(value, type([])):
1082-
value = [i.strip() for i in value.value.split(',')]
1083-
else:
1113+
if isinstance(value, type([])):
1114+
# it's a list of MiniFieldStorages
10841115
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
1119+
value = [i.strip() for i in value.value.split(',')]
10851120
link = cl.properties[key].classname
10861121
l = []
10871122
for entry in map(str, value):
@@ -1097,10 +1132,8 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
10971132
l.sort()
10981133
value = l
10991134
elif isinstance(proptype, hyperdb.Boolean):
1100-
value = form[key].value.strip()
11011135
props[key] = value = value.lower() in ('yes', 'true', 'on', '1')
11021136
elif isinstance(proptype, hyperdb.Number):
1103-
value = form[key].value.strip()
11041137
props[key] = value = int(value)
11051138

11061139
# get the old value
@@ -1117,6 +1150,15 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
11171150
props[key] = value
11181151
else:
11191152
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+
11201162
return props
11211163

11221164

roundup/init.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: init.py,v 1.21 2002-08-16 04:25:03 richard Exp $
18+
# $Id: init.py,v 1.22 2002-09-05 23:39:12 richard Exp $
1919

2020
__doc__ = """
2121
Init (create) a roundup instance.
@@ -89,6 +89,7 @@ def install(instance_home, template, backend):
8989
# first, copy the template dir over
9090
from roundup.templates import builder
9191

92+
# copy the roundup.templates.<template> package contents to the instance dir
9293
template_dir = os.path.split(__file__)[0]
9394
template_name = template
9495
template = os.path.join(template_dir, 'templates', template)
@@ -114,6 +115,9 @@ def initialise(instance_home, adminpw):
114115

115116
#
116117
# $Log: not supported by cvs2svn $
118+
# Revision 1.21 2002/08/16 04:25:03 richard
119+
# cleanup: moved templatebuilder into templates.builder
120+
#
117121
# Revision 1.20 2002/07/14 02:05:53 richard
118122
# . all storage-specific code (ie. backend) is now implemented by the backends
119123
#

roundup/templates/.cvsignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
*.pyc
22
*.pyo
33
*.cover
4+
*_htmlbase.py
5+
*_htmlbase.pyc

roundup/templates/builder.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: builder.py,v 1.1 2002-08-16 04:25:03 richard Exp $
19-
import errno, re
18+
# $Id: builder.py,v 1.2 2002-09-05 23:39:13 richard Exp $
19+
import os, sys, glob, errno, re
2020

2121
__doc__ = """
2222
Collect template parts and create instance template files.
@@ -29,14 +29,19 @@
2929
"""
3030

3131
def makeHtmlBase(templateDir):
32-
""" make a htmlbase.py file in the given templateDir, from the
33-
contents of templateDir/html """
34-
import os, glob, re
32+
''' make a <template>_htmlbase.py file in rondup.tempaltes, from the
33+
contents of templateDir/html
34+
'''
3535
print "packing up templates in", templateDir
36+
3637
filelist = glob.glob(os.path.join(templateDir, 'html', '*'))
3738
filelist = filter(os.path.isfile, filelist) # only want files
3839
filelist.sort()
39-
fd = open(os.path.join(templateDir, 'htmlbase.py'), 'w')
40+
41+
# ok, figure the template name and templates dir
42+
dir, name = os.path.split(templateDir)
43+
44+
fd = open(os.path.join(dir, '%s_htmlbase.py'%name), 'w')
4045
fd.write(preamble)
4146
for file in filelist:
4247
# skip the backup files created by richard's vim
@@ -49,16 +54,16 @@ def makeHtmlBase(templateDir):
4954
fd.close()
5055

5156
def installHtmlBase(template, installDir):
52-
""" passed a template package and an installDir, unpacks the html files into
53-
the installdir """
54-
import os,sys,re
55-
56-
tdir = __import__('roundup.templates.%s.htmlbase'%template).templates
57-
if hasattr(tdir, template):
58-
tmod = getattr(tdir, template)
57+
''' passed a template name and an installDir, unpacks the html files into
58+
the installdir
59+
'''
60+
tmod = '%s_htmlbase'%template
61+
tdir = __import__('roundup.templates.'+tmod).templates
62+
if hasattr(tdir, tmod):
63+
htmlbase = getattr(tdir, tmod)
5964
else:
60-
raise "TemplateError", "couldn't find roundup.template.%s.htmlbase"%template
61-
htmlbase = tmod.htmlbase
65+
raise "TemplateError", \
66+
"couldn't find roundup.templates.%s_htmlbase"%template
6267
installDir = os.path.join(installDir, 'html')
6368
try:
6469
os.makedirs(installDir)
@@ -76,10 +81,7 @@ def installHtmlBase(template, installDir):
7681
data = getattr(htmlbase, mangledfile)
7782
outfd.write(data)
7883

79-
80-
8184
if __name__ == "__main__":
82-
import sys
8385
if len(sys.argv) == 2:
8486
makeHtmlBase(sys.argv[1])
8587
elif len(sys.argv) == 3:
@@ -89,6 +91,9 @@ def installHtmlBase(template, installDir):
8991

9092
#
9193
# $Log: not supported by cvs2svn $
94+
# Revision 1.1 2002/08/16 04:25:03 richard
95+
# cleanup: moved templatebuilder into templates.builder
96+
#
9297
# Revision 1.14 2002/02/05 09:59:05 grubert
9398
# . makeHtmlBase: re.sub under python 2.2 did not replace '.', string.replace does it.
9499
#

roundup/templates/classic/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: __init__.py,v 1.5 2001-08-07 00:24:43 richard Exp $
18+
# $Id: __init__.py,v 1.6 2002-09-05 23:39:14 richard Exp $
1919

2020
import sys
2121
from instance_config import *
22-
try:
23-
from dbinit import *
24-
except:
25-
pass # in install dir (probably :)
22+
from dbinit import *
2623
from interfaces import *
2724

2825
#
2926
# $Log: not supported by cvs2svn $
27+
# Revision 1.5 2001/08/07 00:24:43 richard
28+
# stupid typo
29+
#
3030
# Revision 1.4 2001/08/07 00:15:51 richard
3131
# Added the copyright/license notice to (nearly) all files at request of
3232
# Bizar Software.

0 commit comments

Comments
 (0)