summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 09f216d)
raw | patch | inline | side by side (parent: 09f216d)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 5 Oct 2001 02:23:24 +0000 (02:23 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 5 Oct 2001 02:23:24 +0000 (02:23 +0000) |
on the command-line.
. hyperdb Class getprops() method may now return only the mutable
properties.
. Login now uses cookies, which makes it a whole lot more flexible. We can
now support anonymous user access (read-only, unless there's an
"anonymous" user, in which case write access is permitted). Login
handling has been moved into cgi_client.Client.main()
. The "extended" schema is now the default in roundup init.
. The schemas have had their page headings modified to cope with the new
login handling. Existing installations should copy the interfaces.py
file from the roundup lib directory to their instance home.
. Incorrectly had a Bizar Software copyright on the cgitb.py module from
Ping - has been removed.
. Fixed a whole bunch of places in the CGI interface where we should have
been returning Not Found instead of throwing an exception.
. Fixed a deviation from the spec: trying to modify the 'id' property of
an item now throws an exception.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@272 57a73879-2fb5-44c3-a270-3262357dd7e2
. hyperdb Class getprops() method may now return only the mutable
properties.
. Login now uses cookies, which makes it a whole lot more flexible. We can
now support anonymous user access (read-only, unless there's an
"anonymous" user, in which case write access is permitted). Login
handling has been moved into cgi_client.Client.main()
. The "extended" schema is now the default in roundup init.
. The schemas have had their page headings modified to cope with the new
login handling. Existing installations should copy the interfaces.py
file from the roundup lib directory to their instance home.
. Incorrectly had a Bizar Software copyright on the cgitb.py module from
Ping - has been removed.
. Fixed a whole bunch of places in the CGI interface where we should have
been returning Not Found instead of throwing an exception.
. Fixed a deviation from the spec: trying to modify the 'id' property of
an item now throws an exception.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@272 57a73879-2fb5-44c3-a270-3262357dd7e2
diff --git a/CHANGES.txt b/CHANGES.txt
index 49159f5813b765cee0b25f1a667fc338c22f07c9..29abac0b058a739a39f0734f9168617830fda747 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
are given with the most recent entry first.
2001-??-?? - 0.2.9
+Feature:
+ . roundup-admin create now prompts for property info if none is supplied
+ on the command-line.
+ . hyperdb Class getprops() method may now return only the mutable
+ properties.
+ . CGI interfaces now generate a top-level index of their known instances.
+
+Changed:
+ . Login now uses cookies, which makes it a whole lot more flexible. We can
+ now support anonymous user access (read-only, unless there's an
+ "anonymous" user, in which case write access is permitted). Login
+ handling has been moved into cgi_client.Client.main()
+ . The "extended" schema is now the default in roundup init.
+ . The schemas have had their page headings modified to cope with the new
+ login handling. Existing installations should copy the interfaces.py
+ file from the roundup lib directory to their instance home.
+
Fixed:
+ . Incorrectly had a Bizar Software copyright on the cgitb.py module from
+ Ping - has been removed.
. Pretty time interval wasn't handling > 1 month properly.
. Generation of links to Link/Multilink in indexes. (thanks Hubert Hoegl)
. AssignedTo wasn't in the "classic" schema's item page.
-
+ . Fixed a whole bunch of places in the CGI interface where we should have
+ been returning Not Found instead of throwing an exception.
+ . Fixed a deviation from the spec: trying to modify the 'id' property of
+ an item now throws an exception.
+ . The plain() template function now html-escapes the content.
2001-08-30 - 0.2.8
Fixed:
diff --git a/cgi-bin/roundup.cgi b/cgi-bin/roundup.cgi
index 709582583d64d06667d6133b4c24227253733ede..5a5f72847d0f4b3916e06d83c563c919a96b810e 100755 (executable)
--- a/cgi-bin/roundup.cgi
+++ b/cgi-bin/roundup.cgi
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: roundup.cgi,v 1.12 2001-10-01 05:55:41 richard Exp $
+# $Id: roundup.cgi,v 1.13 2001-10-05 02:23:24 richard Exp $
# python version check
import sys
traceback.print_exc(None, s)
print cgi.escape(s.getvalue()), "</pre>"
-def main(instance, out):
- from roundup import cgi_client
- db = instance.open('admin')
- auth = os.environ.get("HTTP_CGI_AUTHORIZATION", None)
- message = 'Unauthorised'
- if auth:
- import binascii
- l = binascii.a2b_base64(auth.split(' ')[1]).split(':')
- user = l[0]
- password = None
- if len(l) > 1:
- password = l[1]
- try:
- uid = db.user.lookup(user)
- except KeyError:
- auth = None
- message = 'Username not recognised'
- else:
- if password != db.user.get(uid, 'password'):
- message = 'Incorrect password'
- auth = None
- if not auth:
- out.write('Content-Type: text/html\n')
- out.write('Status: 401\n')
- out.write('WWW-Authenticate: basic realm="Roundup"\n\n')
- keys = os.environ.keys()
- keys.sort()
- out.write(message)
- return
- client = instance.Client(out, db, os.environ, user)
- try:
- client.main()
- except cgi_client.Unauthorised:
- out.write('Content-Type: text/html\n')
- out.write('Status: 403\n\n')
- out.write('Unauthorised')
-
-def index(out):
- ''' Print up an index of the available instances
- '''
- import urllib
- w = out.write
- w("Content-Type: text/html\n\n")
- w('<html><head><title>Roundup instances index</title><head>\n')
- w('<body><h1>Roundup instances index</h1><ol>\n')
- for instance in ROUNDUP_INSTANCE_HOMES.keys():
- w('<li><a href="%s/index">%s</a>\n'%(urllib.quote(instance),
- instance))
- w('</ol></body></html>')
-
-#
-# Now do the actual CGI handling
-#
-out, err = sys.stdout, sys.stderr
-try:
- sys.stdout = sys.stderr = LOG
+def main(out, err):
import os, string
import roundup.instance
path = string.split(os.environ['PATH_INFO'], '/')
instance = path[1]
+ os.environ['INSTANCE_NAME'] = instance
os.environ['PATH_INFO'] = string.join(path[2:], '/')
if ROUNDUP_INSTANCE_HOMES.has_key(instance):
instance_home = ROUNDUP_INSTANCE_HOMES[instance]
instance = roundup.instance.open(instance_home)
- main(instance, out)
+ from roundup import cgi_client
+ client = instance.Client(instance, out, os.environ)
+ try:
+ client.main()
+ except cgi_client.Unauthorised:
+ out.write('Content-Type: text/html\n')
+ out.write('Status: 403\n\n')
+ out.write('Unauthorised')
+ except cgi_client.NotFound:
+ out.write('Content-Type: text/html\n')
+ out.write('Status: 404\n\n')
+ out.write('Not found: %s'%client.path)
else:
- index(out)
+ import urllib
+ w = out.write
+ w("Content-Type: text/html\n\n")
+ w('<html><head><title>Roundup instances index</title><head>\n')
+ w('<body><h1>Roundup instances index</h1><ol>\n')
+ for instance in ROUNDUP_INSTANCE_HOMES.keys():
+ w('<li><a href="%s/index">%s</a>\n'%(urllib.quote(instance),
+ instance))
+ w('</ol></body></html>')
+
+#
+# Now do the actual CGI handling
+#
+out, err = sys.stdout, sys.stderr
+try:
+ sys.stdout = sys.stderr = LOG
+ main(out, err)
except:
sys.stdout, sys.stderr = out, err
out.write('Content-Type: text/html\n\n')
#
# $Log: not supported by cvs2svn $
+# Revision 1.12 2001/10/01 05:55:41 richard
+# Fixes to the top-level index
+#
# Revision 1.11 2001/09/29 13:27:00 richard
# CGI interfaces now spit up a top-level index of all the instances they can
# serve.
diff --git a/roundup-admin b/roundup-admin
index e8082a421ecd5008fcb92d2c926d9438b9256f32..86bc4ae7441976703c121d78f222104a6edf2e93 100755 (executable)
--- a/roundup-admin
+++ b/roundup-admin
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: roundup-admin,v 1.20 2001-10-04 02:12:42 richard Exp $
+# $Id: roundup-admin,v 1.21 2001-10-05 02:23:24 richard Exp $
import sys
if int(sys.version[0]) < 2:
if template not in templates:
print 'Templates:', ', '.join(templates)
while template not in templates:
- template = raw_input('Select template [classic]: ').strip()
+ template = raw_input('Select template [extended]: ').strip()
if not template:
- template = 'classic'
+ template = 'extended'
import roundup.backends
backends = roundup.backends.__all__
#
# $Log: not supported by cvs2svn $
+# Revision 1.20 2001/10/04 02:12:42 richard
+# Added nicer command-line item adding: passing no arguments will enter an
+# interactive more which asks for each property in turn. While I was at it, I
+# fixed an implementation problem WRT the spec - I wasn't raising a
+# ValueError if the key property was missing from a create(). Also added a
+# protected=boolean argument to getprops() so we can list only the mutable
+# properties (defaults to yes, which lists the immutables).
+#
# Revision 1.19 2001/10/01 06:40:43 richard
# made do_get have the args in the correct order
#
diff --git a/roundup-server b/roundup-server
index fb905d17c58298a2ca484ba1f616275e2f90e442..3c6c9e53fd66a94768824f45eeeb941795c07ac6 100755 (executable)
--- a/roundup-server
+++ b/roundup-server
Based on CGIHTTPServer in the Python library.
-$Id: roundup-server,v 1.12 2001-09-29 13:27:00 richard Exp $
+$Id: roundup-server,v 1.13 2001-10-05 02:23:24 richard Exp $
"""
import sys
sys.stdin = self.rfile
try:
self.inner_run_cgi()
+ except cgi_client.NotFound:
+ self.send_error(404, self.path)
except cgi_client.Unauthorised:
self.wfile.write('Content-Type: text/html\n')
- self.wfile.write('Status: 403\n')
- self.wfile.write('Unauthorised')
+ self.wfile.write('Status: 403\n\n')
+ self.wfile.write('You are not authorised to access this URL.')
except:
try:
reload(cgitb)
if rest == '/':
return self.index()
l_path = string.split(rest, '/')
- instance = urllib.unquote(l_path[1])
- if self.ROUNDUP_INSTANCE_HOMES.has_key(instance):
- instance_home = self.ROUNDUP_INSTANCE_HOMES[instance]
+ instance_name = urllib.unquote(l_path[1])
+ if self.ROUNDUP_INSTANCE_HOMES.has_key(instance_name):
+ instance_home = self.ROUNDUP_INSTANCE_HOMES[instance_name]
instance = roundup.instance.open(instance_home)
else:
- return self.index()
+ raise cgi_client.NotFound
# figure out what the rest of the path is
if len(l_path) > 2:
# Set up the CGI environment
env = {}
+ env['INSTANCE_NAME'] = instance_name
env['REQUEST_METHOD'] = self.command
env['PATH_INFO'] = urllib.unquote(rest)
if query:
#finally:
# del sys.path[0]
- # initialise the roundupdb, check for auth
- db = instance.open('admin')
- message = 'Unauthorised'
- auth = self.headers.getheader('authorization')
- if auth:
- l = binascii.a2b_base64(auth.split(' ')[1]).split(':')
- user = l[0]
- password = None
- if len(l) > 1:
- password = l[1]
- try:
- uid = db.user.lookup(user)
- except KeyError:
- auth = None
- message = 'Username not recognised'
- else:
- if password != db.user.get(uid, 'password'):
- message = 'Incorrect password'
- auth = None
- db.close()
- del db
- if not auth:
- self.send_response(401)
- self.send_header('Content-Type', 'text/html')
- self.send_header('WWW-Authenticate', 'basic realm="Roundup"')
- self.end_headers()
- self.wfile.write(message)
- return
-
self.send_response(200, "Script output follows")
# do the roundup thang
- db = instance.open(user)
- client = instance.Client(self.wfile, db, env, user)
+ client = instance.Client(instance, self.wfile, env)
client.main()
+
do_POST = run_cgi
nobody = None
#
# $Log: not supported by cvs2svn $
+# Revision 1.12 2001/09/29 13:27:00 richard
+# CGI interfaces now spit up a top-level index of all the instances they can
+# serve.
+#
# Revision 1.11 2001/08/07 00:24:42 richard
# stupid typo
#
diff --git a/roundup/cgi_client.py b/roundup/cgi_client.py
index 1cb3113307c71a1dfc8ddd60af2eb571941bbe54..33d2381fcc9f64840f1abee93563bdc19f3550a7 100644 (file)
--- a/roundup/cgi_client.py
+++ b/roundup/cgi_client.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: cgi_client.py,v 1.26 2001-09-12 08:31:42 richard Exp $
+# $Id: cgi_client.py,v 1.27 2001-10-05 02:23:24 richard Exp $
import os, cgi, pprint, StringIO, urlparse, re, traceback, mimetypes
+import base64, Cookie, time
import roundupdb, htmltemplate, date, hyperdb
class Unauthorised(ValueError):
pass
+class NotFound(ValueError):
+ pass
+
class Client:
- def __init__(self, out, db, env, user):
+ '''
+
+ A note about login
+ ------------------
+
+ If the user has no login cookie, then they are anonymous. There
+ are two levels of anonymous use. If there is no 'anonymous' user, there
+ is no login at all and the database is opened in read-only mode. If the
+ 'anonymous' user exists, the user is logged in using that user (though
+ there is no cookie). This allows them to modify the database, and all
+ modifications are attributed to the 'anonymous' user.
+ '''
+
+ def __init__(self, instance, out, env):
+ self.instance = instance
self.out = out
- self.db = db
self.env = env
- self.user = user
self.path = env['PATH_INFO']
self.split_path = self.path.split('/')
else:
message = ''
style = open(os.path.join(self.TEMPLATES, 'style.css')).read()
- userid = self.db.user.lookup(self.user)
+ if self.user is not None:
+ userid = self.db.user.lookup(self.user)
+ user_info = '(login: <a href="user%s">%s</a>)'%(userid, self.user)
+ else:
+ user_info = ''
self.write('''<html><head>
<title>%s</title>
<style type="text/css">%s</style>
<body bgcolor=#ffffff>
%s
<table width=100%% border=0 cellspacing=0 cellpadding=2>
-<tr class="location-bar"><td><big><strong>%s</strong></big>
-(login: <a href="user%s">%s</a>)</td></tr>
+<tr class="location-bar"><td><big><strong>%s</strong></big> %s</td></tr>
</table>
-'''%(title, style, message, title, userid, self.user))
+'''%(title, style, message, title, user_info))
def pagefoot(self):
if self.debug:
filterspec = {}
for key in self.form.keys():
if key[0] == ':': continue
+ if not props.has_key(key): continue
prop = props[key]
value = self.form[key]
if (isinstance(prop, hyperdb.Link) or
else:
raise Unauthorised
- def main(self, dre=re.compile(r'([^\d]+)(\d+)'), nre=re.compile(r'new(\w+)')):
+ def login(self, message=None):
+ self.pagehead('Login to roundup', message)
+ self.write('''
+<table>
+<tr><td colspan=2 class="strong-header">Existing User Login</td></tr>
+<form action="login_action" method=POST>
+<tr><td align=right>Login name: </td>
+ <td><input name="__login_name"></td></tr>
+<tr><td align=right>Password: </td>
+ <td><input type="password" name="__login_password"></td></tr>
+<tr><td></td>
+ <td><input type="submit" value="Log In"></td></tr>
+</form>
+
+<p>
+<tr><td colspan=2 class="strong-header">New User Registration</td></tr>
+<tr><td colspan=2><em>marked items</em> are optional...</td></tr>
+<form action="newuser_action" method=POST>
+<tr><td align=right><em>Name: </em></td>
+ <td><input name="__newuser_realname"></td></tr>
+<tr><td align=right><em>Organisation: </em></td>
+ <td><input name="__newuser_organisation"></td></tr>
+<tr><td align=right>E-Mail Address: </td>
+ <td><input name="__newuser_address"></td></tr>
+<tr><td align=right><em>Phone: </em></td>
+ <td><input name="__newuser_phone"></td></tr>
+<tr><td align=right>Preferred Login name: </td>
+ <td><input name="__newuser_username"></td></tr>
+<tr><td align=right>Password: </td>
+ <td><input type="password" name="__newuser_password"></td></tr>
+<tr><td align=right>Password Again: </td>
+ <td><input type="password" name="__newuser_confirm"></td></tr>
+<tr><td></td>
+ <td><input type="submit" value="Register"></td></tr>
+</form>
+</table>
+''')
+
+ def login_action(self, message=None):
+ self.user = self.form['__login_name'].value
+ password = self.form['__login_password'].value
+ # make sure the user exists
+ try:
+ uid = self.db.user.lookup(self.user)
+ except KeyError:
+ name = self.user
+ self.make_user_anonymous()
+ return self.login(message='No such user "%s"'%name)
+
+ # and that the password is correct
+ if password != self.db.user.get(uid, 'password'):
+ return self.login(message='Incorrect password')
+
+ # construct the cookie
+ uid = self.db.user.lookup(self.user)
+ user = base64.encodestring('%s:%s'%(self.user, password))[:-1]
+ path = '/'.join((self.env['SCRIPT_NAME'], self.env['INSTANCE_NAME'],
+ ''))
+ cookie = Cookie.SmartCookie()
+ cookie['roundup_user'] = user
+ cookie['roundup_user']['path'] = path
+ self.header({'Set-Cookie': str(cookie)})
+ return self.index()
+
+ def make_user_anonymous(self):
+ # make us anonymous if we can
+ try:
+ self.db.user.lookup('anonymous')
+ self.user = 'anonymous'
+ except KeyError:
+ self.user = None
+
+ def logout(self, message=None):
+ self.make_user_anonymous()
+ # construct the logout cookie
+ path = '/'.join((self.env['SCRIPT_NAME'], self.env['INSTANCE_NAME'],
+ ''))
+ cookie = Cookie.SmartCookie()
+ cookie['roundup_user'] = 'deleted'
+ cookie['roundup_user']['path'] = path
+ cookie['roundup_user']['expires'] = 0
+ cookie['roundup_user']['max-age'] = 0
+ self.header({'Set-Cookie': str(cookie)})
+ return self.index()
+
+ def newuser_action(self, message=None):
+ ''' create a new user based on the contents of the form and then
+ set the cookie
+ '''
+ # TODO: pre-check the required fields and username key property
+ cl = self.db.classes['user']
+ props, dummy = parsePropsFromForm(cl, self.form)
+ uid = cl.create(**props)
+ self.user = self.db.user.get(uid, 'username')
+ password = self.db.user.get(uid, 'password')
+ # construct the cookie
+ uid = self.db.user.lookup(self.user)
+ user = base64.encodestring('%s:%s'%(self.user, password))[:-1]
+ path = '/'.join((self.env['SCRIPT_NAME'], self.env['INSTANCE_NAME'],
+ ''))
+ cookie = Cookie.SmartCookie()
+ cookie['roundup_user'] = user
+ cookie['roundup_user']['path'] = path
+ self.header({'Set-Cookie': str(cookie)})
+ return self.index()
+
+ def main(self, dre=re.compile(r'([^\d]+)(\d+)'),
+ nre=re.compile(r'new(\w+)')):
+
+ # determine the uid to use
+ self.db = self.instance.open('admin')
+ cookie = Cookie.Cookie(self.env.get('HTTP_COOKIE', ''))
+ user = 'anonymous'
+ if (cookie.has_key('roundup_user') and
+ cookie['roundup_user'].value != 'deleted'):
+ cookie = cookie['roundup_user'].value
+ user, password = base64.decodestring(cookie).split(':')
+ # make sure the user exists
+ try:
+ uid = self.db.user.lookup(user)
+ # now validate the password
+ if password != self.db.user.get(uid, 'password'):
+ user = 'anonymous'
+ except KeyError:
+ user = 'anonymous'
+
+ # make sure the anonymous user is valid if we're using it
+ if user == 'anonymous':
+ self.make_user_anonymous()
+ else:
+ self.user = user
+ self.db.close()
+
+ # re-open the database for real, using the user
+ self.db = self.instance.open(self.user)
+
+ # now figure which function to call
path = self.split_path
if not path or path[0] in ('', 'index'):
self.index()
if path[0] == 'list_classes':
self.classes()
return
+ if path[0] == 'login':
+ self.login()
+ return
+ if path[0] == 'login_action':
+ self.login_action()
+ return
+ if path[0] == 'newuser_action':
+ self.newuser_action()
+ return
+ if path[0] == 'logout':
+ self.logout()
+ return
m = dre.match(path[0])
if m:
self.classname = m.group(1)
self.nodeid = m.group(2)
- getattr(self, 'show%s'%self.classname)()
+ try:
+ cl = self.db.classes[self.classname]
+ except KeyError:
+ raise NotFound
+ try:
+ cl.get(self.nodeid, 'id')
+ except IndexError:
+ raise NotFound
+ try:
+ getattr(self, 'show%s'%self.classname)()
+ except AttributeError:
+ raise NotFound
return
m = nre.match(path[0])
if m:
self.classname = m.group(1)
- getattr(self, 'new%s'%self.classname)()
+ try:
+ getattr(self, 'new%s'%self.classname)()
+ except AttributeError:
+ raise NotFound
return
self.classname = path[0]
+ try:
+ self.db.getclass(self.classname)
+ except KeyError:
+ raise NotFound
self.list()
else:
raise 'ValueError', 'Path not understood'
#
# $Log: not supported by cvs2svn $
+# Revision 1.26 2001/09/12 08:31:42 richard
+# handle cases where mime type is not guessable
+#
# Revision 1.25 2001/08/29 05:30:49 richard
# change messages weren't being saved when there was no-one on the nosy list.
#
diff --git a/roundup/hyperdb.py b/roundup/hyperdb.py
index 367abac6dd8847da3c0bfc9380bd4b042177b88a..32729f19d2e9d91fc662c7f6bd3ffddbcc2a7176 100644 (file)
--- a/roundup/hyperdb.py
+++ b/roundup/hyperdb.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: hyperdb.py,v 1.20 2001-10-04 02:12:42 richard Exp $
+# $Id: hyperdb.py,v 1.21 2001-10-05 02:23:24 richard Exp $
# standard python modules
import cPickle, re, string
IndexError is raised. 'propname' must be the name of a property
of this class or a KeyError is raised.
"""
+ d = self.db.getnode(self.classname, nodeid)
if propname == 'id':
return nodeid
- d = self.db.getnode(self.classname, nodeid)
if not d.has_key(propname) and default is not _marker:
return default
return d[propname]
#
# $Log: not supported by cvs2svn $
+# Revision 1.20 2001/10/04 02:12:42 richard
+# Added nicer command-line item adding: passing no arguments will enter an
+# interactive more which asks for each property in turn. While I was at it, I
+# fixed an implementation problem WRT the spec - I wasn't raising a
+# ValueError if the key property was missing from a create(). Also added a
+# protected=boolean argument to getprops() so we can list only the mutable
+# properties (defaults to yes, which lists the immutables).
+#
# Revision 1.19 2001/08/29 04:47:18 richard
# Fixed CGI client change messages so they actually include the properties
# changed (again).
diff --git a/roundup/mailgw.py b/roundup/mailgw.py
index 19151b2108934e9c711511fe468dcfcd023e0a7c..9ce05937f54bc4c881116f90f5650421715247de 100644 (file)
--- a/roundup/mailgw.py
+++ b/roundup/mailgw.py
an exception, the original message is bounced back to the sender with the
explanatory message given in the exception.
-$Id: mailgw.py,v 1.15 2001-08-30 06:01:17 richard Exp $
+$Id: mailgw.py,v 1.16 2001-10-05 02:23:24 richard Exp $
'''
elif isinstance(type, hyperdb.Multilink):
props[key] = value.split(',')
+ #
# handle the users
+ #
author = self.db.uidFromAddress(message.getaddrlist('from')[0])
recipients = []
for recipient in message.getaddrlist('to') + message.getaddrlist('cc'):
#
# $Log: not supported by cvs2svn $
+# Revision 1.15 2001/08/30 06:01:17 richard
+# Fixed missing import in mailgw :(
+#
# Revision 1.14 2001/08/13 23:02:54 richard
# Make the mail parser a little more robust.
#
index bee173eb01d0925a32fb2f4e7c6c10611dfe6c9f..f32f5b217532d5e4e7703d389c3fef4c0d6286aa 100644 (file)
@@ -182,7 +182,7 @@ issueDOTitem = """<!-- dollarId: issue.item,v 1.5 2001/07/30 08:03:56 richard Ex
"""
-msgDOTindex = """<!-- dollarId: msg.index,v 1.1 2001/07/23 04:21:20 richard Exp dollar-->
+msgDOTindex = """<!-- dollarId: msg.index,v 1.3 2001/09/27 06:45:58 richard Exp dollar-->
<tr class="row-hilite">
<property name="date">
<td><display call="link('date')"></td>
index b3db3c7f12438b0ab21fc8477e0a8866a2ed5fe1..77fd54fe193bb7cf7697f588324d5cce081cb46e 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: interfaces.py,v 1.9 2001-08-07 00:24:43 richard Exp $
+# $Id: interfaces.py,v 1.10 2001-10-05 02:23:24 richard Exp $
import instance_config, urlparse, os
from roundup import cgi_client, mailgw
else:
message = ''
style = open(os.path.join(self.TEMPLATES, 'style.css')).read()
- userid = self.db.user.lookup(self.user)
+ user_name = self.user or ''
if self.user == 'admin':
- extras = ' | <a href="list_classes">Class List</a>'
+ admin_links = ' | <a href="list_classes">Class List</a>'
else:
- extras = ''
+ admin_links = ''
+ if self.user not in (None, 'anonymous'):
+ userid = self.db.user.lookup(self.user)
+ user_info = '''
+<a href="issue?assignedto=%s&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=priority">My Issues</a> |
+<a href="support?assignedto=%s&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=customername">My Support</a> |
+<a href="user%s">My Details</a> | <a href="logout">Logout</a>
+'''%(userid, userid, userid)
+ else:
+ user_info = '<a href="login">Login</a>'
+ if self.user is not None:
+ add_links = '''
+| Add
+<a href="newissue">Issue</a>,
+<a href="newsupport">Support</a>,
+<a href="newuser">User</a>
+'''
+ else:
+ add_links = ''
self.write('''<html><head>
<title>%s</title>
<style type="text/css">%s</style>
| Unassigned
<a href="issue?assignedto=admin&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=priority">Issues</a>,
<a href="support?assignedto=admin&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=customername">Support</a>
-| Add
-<a href="newissue">Issue</a>,
-<a href="newsupport">Support</a>,
-<a href="newuser">User</a>
+%s
%s</td>
-<td align=right>
-<a href="issue?assignedto=%s&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=priority">My Issues</a> |
-<a href="support?assignedto=%s&status=unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=activity&:columns=id,activity,status,title,assignedto&:group=customername">My Support</a> |
-<a href="user%s">My Details</a></td>
+<td align=right>%s</td>
</table>
-'''%(title, style, message, title, self.user, extras, userid, userid, userid))
+'''%(title, style, message, title, user_name, add_links, admin_links,
+ user_info))
class MailGW(mailgw.MailGW):
''' derives basic mail gateway implementation from the standard module,
#
# $Log: not supported by cvs2svn $
+# Revision 1.9 2001/08/07 00:24:43 richard
+# stupid typo
+#
# Revision 1.8 2001/08/07 00:15:51 richard
# Added the copyright/license notice to (nearly) all files at request of
# Bizar Software.