index 463a43f56011f4fd43b2e5936d88f6bbfc0e5106..233de403cb6d1117e89834ea82e8daa3db14b3aa 100644 (file)
def db_nuke(config):
shutil.rmtree(config.DATABASE)
+class Binary:
+
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
+
+ def visit(self, visitor):
+ self.x.visit(visitor)
+ self.y.visit(visitor)
+
+class Unary:
+
+ def __init__(self, x):
+ self.x = x
+
+ def generate(self, atom):
+ return atom(self)
+
+ def visit(self, visitor):
+ self.x.visit(visitor)
+
+class Equals(Unary):
+
+ def evaluate(self, v):
+ return self.x in v
+
+ def visit(self, visitor):
+ visitor(self)
+
+class Not(Unary):
+
+ def evaluate(self, v):
+ return not self.x.evaluate(v)
+
+ def generate(self, atom):
+ return "NOT(%s)" % self.x.generate(atom)
+
+class Or(Binary):
+
+ def evaluate(self, v):
+ return self.x.evaluate(v) or self.y.evaluate(v)
+
+ def generate(self, atom):
+ return "(%s)OR(%s)" % (
+ self.x.generate(atom),
+ self.y.generate(atom))
+
+class And(Binary):
+
+ def evaluate(self, v):
+ return self.x.evaluate(v) and self.y.evaluate(v)
+
+ def generate(self, atom):
+ return "(%s)AND(%s)" % (
+ self.x.generate(atom),
+ self.y.generate(atom))
+
+def compile_expression(opcodes):
+
+ stack = []
+ push, pop = stack.append, stack.pop
+ for opcode in opcodes:
+ if opcode == -2: push(Not(pop()))
+ elif opcode == -3: push(And(pop(), pop()))
+ elif opcode == -4: push(Or(pop(), pop()))
+ else: push(Equals(opcode))
+
+ return pop()
+
+class Expression:
+
+ def __init__(self, v):
+ try:
+ opcodes = [int(x) for x in v]
+ if min(opcodes) >= -1: raise ValueError()
+
+ compiled = compile_expression(opcodes)
+ self.evaluate = lambda x: compiled.evaluate([int(y) for y in x])
+ except:
+ self.evaluate = lambda x: bool(set(x) & set(v))
+
#
# Now the database
#
description="User is allowed to edit "+cn)
self.security.addPermission(name="View", klass=cn,
description="User is allowed to access "+cn)
+ self.security.addPermission(name="Retire", klass=cn,
+ description="User is allowed to retire "+cn)
def getclasses(self):
"""Return a list of the names of all existing classes."""
- return sorted(self.classes)
+ l = self.classes.keys()
+ l.sort()
+ return l
def getclass(self, classname):
"""Get the Class object representing a particular class.
elif isinstance(prop, hyperdb.Interval) and v is not None:
d[k] = date.Interval(v)
elif isinstance(prop, hyperdb.Password) and v is not None:
- p = password.Password()
- p.unpack(v)
- d[k] = p
+ d[k] = password.Password(encrypted=v)
else:
d[k] = v
return d
self.transactions.append((self.doSetJournal, (classname, nodeid,
journal)))
+ def fix_journal(self, classname, journal):
+ """ fix password entries to correct type """
+ pwprops = {}
+ for pn, prop in self.getclass(classname).properties.iteritems():
+ if isinstance(prop, hyperdb.Password):
+ pwprops [pn] = 1
+ if not pwprops:
+ return journal
+ for j in journal:
+ if j[3] == 'set':
+ for k, v in j[4].items():
+ if k in pwprops:
+ j[4][k] = password.JournalPassword(j[4][k])
+ return journal
+
def getjournal(self, classname, nodeid):
""" get the journal for id
raise
if res:
# we have unsaved journal entries, return them
- return res
+ return self.fix_journal (classname, res)
raise IndexError('no such %s %s'%(classname, nodeid))
try:
journal = marshal.loads(db[nodeid])
db.close()
if res:
# we have some unsaved journal entries, be happy!
- return res
+ return self.fix_journal (classname, res)
raise IndexError('no such %s %s'%(classname, nodeid))
db.close()
# add all the saved journal entries for this node
for nodeid, date_stamp, user, action, params in journal:
res.append((nodeid, date.Date(date_stamp), user, action, params))
- return res
+ return self.fix_journal (classname, res)
def pack(self, pack_before):
""" Delete all journal entries except "create" before 'pack_before'.
raise TypeError('new property "%s" not a '
'Password'%propname)
propvalues[propname] = value
+ journalvalues[propname] = \
+ current and password.JournalPassword(current)
elif value is not None and isinstance(prop, hyperdb.Date):
if not isinstance(value, date.Date):
raise hyperdb.DatabaseError(_('Database open read-only'))
self.db.destroynode(self.classname, nodeid)
- def history(self, nodeid):
- """Retrieve the journal of edits on a particular node.
-
- 'nodeid' must be the id of an existing node of this class or an
- IndexError is raised.
-
- The returned list contains tuples of the form
-
- (nodeid, date, tag, action, params)
-
- 'date' is a Timestamp object specifying the time of the change and
- 'tag' is the journaltag specified when the database was opened.
- """
- if not self.do_journal:
- raise ValueError('Journalling is disabled for this class')
- return self.db.getjournal(self.classname, nodeid)
-
# Locating nodes:
def hasnode(self, nodeid):
"""Determine if the given nodeid actually exists
l.append((OTHER, k, [float(val) for val in v]))
filterspec = l
-
+
# now, find all the nodes that are active and pass filtering
matches = []
cldb = self.db.getclassdb(cn)
if not v:
match = not nv
else:
- # othewise, make sure this node has each of the
+ # otherwise, make sure this node has each of the
# required values
- for want in v:
- if want in nv:
- match = 1
- break
+ expr = Expression(v)
+ if expr.evaluate(nv): match = 1
elif t == STRING:
if nv is None:
nv = ''
elif isinstance(prop, hyperdb.Interval):
value = date.Interval(value)
elif isinstance(prop, hyperdb.Password):
- pwd = password.Password()
- pwd.unpack(value)
- value = pwd
+ value = password.Password(encrypted=value)
d[propname] = value
# get a new id if necessary
repr(action), repr(params)])
return r
- def import_journals(self, entries):
- """Import a class's journal.
-
- Uses setjournal() to set the journal for each item."""
- properties = self.getprops()
- d = {}
- for l in entries:
- nodeid, jdate, user, action, params = tuple(map(eval, l))
- r = d.setdefault(nodeid, [])
- if action == 'set':
- for propname, value in params.iteritems():
- prop = properties[propname]
- if value is None:
- pass
- elif isinstance(prop, hyperdb.Date):
- value = date.Date(value)
- elif isinstance(prop, hyperdb.Interval):
- value = date.Interval(value)
- elif isinstance(prop, hyperdb.Password):
- pwd = password.Password()
- pwd.unpack(value)
- value = pwd
- params[propname] = value
- r.append((nodeid, date.Date(jdate), user, action, params))
-
- for nodeid, l in d.iteritems():
- self.db.setjournal(self.classname, nodeid, l)
-
class FileClass(hyperdb.FileClass, Class):
"""This class defines a large chunk of data. To support this, it has a
mandatory String property "content" which is typically saved off