Mercurial > p > roundup > code
comparison roundup/volatiledb.py @ 902:b0d3d3535998
Bugger it. Here's the current shape of the new security implementation.
Still to do:
. call the security funcs from cgi and mailgw
. change shipped templates to include correct initialisation and remove
the old config vars
... that seems like a lot. The bulk of the work has been done though. Honest :)
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Thu, 25 Jul 2002 07:14:06 +0000 |
| parents | |
| children | 502a5ae11cc5 |
comparison
equal
deleted
inserted
replaced
| 901:31a62bcb9c80 | 902:b0d3d3535998 |
|---|---|
| 1 import weakref, re | |
| 2 | |
| 3 from roundup import hyperdb | |
| 4 from roundup.hyperdb import String, Password, Date, Interval, Link, \ | |
| 5 Multilink, DatabaseError, Boolean, Number | |
| 6 | |
| 7 class VolatileClass(hyperdb.Class): | |
| 8 ''' This is a class that just sits in memory, no saving to disk. | |
| 9 It has no journal. | |
| 10 ''' | |
| 11 def __init__(self, db, classname, **properties): | |
| 12 ''' Set up an in-memory store for the nodes of this class | |
| 13 ''' | |
| 14 self.db = weakref.proxy(db) # use a weak ref to avoid circularity | |
| 15 self.classname = classname | |
| 16 self.properties = properties | |
| 17 self.id_counter = 1 | |
| 18 self.store = {} | |
| 19 self.by_key = {} | |
| 20 self.key = '' | |
| 21 db.addclass(self) | |
| 22 | |
| 23 def setkey(self, propname): | |
| 24 prop = self.getprops()[propname] | |
| 25 if not isinstance(prop, String): | |
| 26 raise TypeError, 'key properties must be String' | |
| 27 self.key = propname | |
| 28 | |
| 29 def getprops(self, protected=1): | |
| 30 d = self.properties.copy() | |
| 31 if protected: | |
| 32 d['id'] = String() | |
| 33 return d | |
| 34 | |
| 35 def create(self, **propvalues): | |
| 36 ''' Create a new node in the in-memory store | |
| 37 ''' | |
| 38 if propvalues.has_key('id'): | |
| 39 raise KeyError, '"id" is reserved' | |
| 40 newid = str(self.id_counter) | |
| 41 self.id_counter += 1 | |
| 42 | |
| 43 # get the key value, validate it | |
| 44 if self.key: | |
| 45 keyvalue = propvalues[self.key] | |
| 46 try: | |
| 47 self.lookup(keyvalue) | |
| 48 except KeyError: | |
| 49 pass | |
| 50 else: | |
| 51 raise ValueError, 'node with key "%s" exists'%keyvalue | |
| 52 self.by_key[keyvalue] = newid | |
| 53 | |
| 54 # validate propvalues | |
| 55 num_re = re.compile('^\d+$') | |
| 56 | |
| 57 for key, value in propvalues.items(): | |
| 58 | |
| 59 # try to handle this property | |
| 60 try: | |
| 61 prop = self.properties[key] | |
| 62 except KeyError: | |
| 63 raise KeyError, '"%s" has no property "%s"'%(self.classname, | |
| 64 key) | |
| 65 | |
| 66 if isinstance(prop, Link): | |
| 67 if type(value) != type(''): | |
| 68 raise ValueError, 'link value must be String' | |
| 69 link_class = self.properties[key].classname | |
| 70 # if it isn't a number, it's a key | |
| 71 if not num_re.match(value): | |
| 72 try: | |
| 73 value = self.db.classes[link_class].lookup(value) | |
| 74 except (TypeError, KeyError): | |
| 75 raise IndexError, 'new property "%s": %s not a %s'%( | |
| 76 key, value, link_class) | |
| 77 elif not self.db.hasnode(link_class, value): | |
| 78 raise IndexError, '%s has no node %s'%(link_class, value) | |
| 79 | |
| 80 # save off the value | |
| 81 propvalues[key] = value | |
| 82 | |
| 83 elif isinstance(prop, Multilink): | |
| 84 if type(value) != type([]): | |
| 85 raise TypeError, 'new property "%s" not a list of ids'%key | |
| 86 | |
| 87 # clean up and validate the list of links | |
| 88 link_class = self.properties[key].classname | |
| 89 l = [] | |
| 90 for entry in value: | |
| 91 if type(entry) != type(''): | |
| 92 raise ValueError, '"%s" link value (%s) must be '\ | |
| 93 'String'%(key, value) | |
| 94 # if it isn't a number, it's a key | |
| 95 if not num_re.match(entry): | |
| 96 try: | |
| 97 entry = self.db.classes[link_class].lookup(entry) | |
| 98 except (TypeError, KeyError): | |
| 99 raise IndexError, 'new property "%s": %s not a %s'%( | |
| 100 key, entry, self.properties[key].classname) | |
| 101 l.append(entry) | |
| 102 value = l | |
| 103 propvalues[key] = value | |
| 104 | |
| 105 # handle additions | |
| 106 for id in value: | |
| 107 if not self.db.hasnode(link_class, id): | |
| 108 raise IndexError, '%s has no node %s'%(link_class, id) | |
| 109 | |
| 110 elif isinstance(prop, String): | |
| 111 if type(value) != type(''): | |
| 112 raise TypeError, 'new property "%s" not a string'%key | |
| 113 | |
| 114 elif isinstance(prop, Password): | |
| 115 if not isinstance(value, password.Password): | |
| 116 raise TypeError, 'new property "%s" not a Password'%key | |
| 117 | |
| 118 elif isinstance(prop, Date): | |
| 119 if value is not None and not isinstance(value, date.Date): | |
| 120 raise TypeError, 'new property "%s" not a Date'%key | |
| 121 | |
| 122 elif isinstance(prop, Interval): | |
| 123 if value is not None and not isinstance(value, date.Interval): | |
| 124 raise TypeError, 'new property "%s" not an Interval'%key | |
| 125 | |
| 126 # make sure there's data where there needs to be | |
| 127 for key, prop in self.properties.items(): | |
| 128 if propvalues.has_key(key): | |
| 129 continue | |
| 130 if key == self.key: | |
| 131 raise ValueError, 'key property "%s" is required'%key | |
| 132 if isinstance(prop, Multilink): | |
| 133 propvalues[key] = [] | |
| 134 else: | |
| 135 propvalues[key] = None | |
| 136 | |
| 137 # done | |
| 138 self.store[newid] = propvalues | |
| 139 | |
| 140 return newid | |
| 141 | |
| 142 _marker = [] | |
| 143 def get(self, nodeid, propname, default=_marker, cache=1): | |
| 144 ''' Get the node from the in-memory store | |
| 145 ''' | |
| 146 if propname == 'id': | |
| 147 return nodeid | |
| 148 return self.store[nodeid][propname] | |
| 149 | |
| 150 def set(self, nodeid, **propvalues): | |
| 151 ''' Set properties on the node in the in-memory store | |
| 152 ''' | |
| 153 if not propvalues: | |
| 154 return | |
| 155 | |
| 156 if propvalues.has_key('id'): | |
| 157 raise KeyError, '"id" is reserved' | |
| 158 | |
| 159 node = self.store[nodeid] | |
| 160 num_re = re.compile('^\d+$') | |
| 161 | |
| 162 for propname, value in propvalues.items(): | |
| 163 # check to make sure we're not duplicating an existing key | |
| 164 if propname == self.key and node[propname] != value: | |
| 165 try: | |
| 166 self.lookup(value) | |
| 167 except KeyError: | |
| 168 pass | |
| 169 else: | |
| 170 raise ValueError, 'node with key "%s" exists'%value | |
| 171 | |
| 172 # this will raise the KeyError if the property isn't valid | |
| 173 # ... we don't use getprops() here because we only care about | |
| 174 # the writeable properties. | |
| 175 prop = self.properties[propname] | |
| 176 | |
| 177 # if the value's the same as the existing value, no sense in | |
| 178 # doing anything | |
| 179 if node.has_key(propname) and value == node[propname]: | |
| 180 del propvalues[propname] | |
| 181 continue | |
| 182 | |
| 183 # do stuff based on the prop type | |
| 184 if isinstance(prop, Link): | |
| 185 link_class = self.properties[propname].classname | |
| 186 # if it isn't a number, it's a key | |
| 187 if type(value) != type(''): | |
| 188 raise ValueError, 'link value must be String' | |
| 189 if not num_re.match(value): | |
| 190 try: | |
| 191 value = self.db.classes[link_class].lookup(value) | |
| 192 except (TypeError, KeyError): | |
| 193 raise IndexError, 'new property "%s": %s not a %s'%( | |
| 194 propname, value, self.properties[propname].classname) | |
| 195 | |
| 196 if not self.db.hasnode(link_class, value): | |
| 197 raise IndexError, '%s has no node %s'%(link_class, value) | |
| 198 | |
| 199 elif isinstance(prop, Multilink): | |
| 200 if type(value) != type([]): | |
| 201 raise TypeError, 'new property "%s" not a list of'\ | |
| 202 ' ids'%propname | |
| 203 link_class = self.properties[propname].classname | |
| 204 l = [] | |
| 205 for entry in value: | |
| 206 # if it isn't a number, it's a key | |
| 207 if type(entry) != type(''): | |
| 208 raise ValueError, 'new property "%s" link value ' \ | |
| 209 'must be a string'%propname | |
| 210 if not num_re.match(entry): | |
| 211 try: | |
| 212 entry = self.db.classes[link_class].lookup(entry) | |
| 213 except (TypeError, KeyError): | |
| 214 raise IndexError, 'new property "%s": %s not a %s'%( | |
| 215 propname, entry, | |
| 216 self.properties[propname].classname) | |
| 217 l.append(entry) | |
| 218 value = l | |
| 219 propvalues[propname] = value | |
| 220 | |
| 221 elif isinstance(prop, String): | |
| 222 if value is not None and type(value) != type(''): | |
| 223 raise TypeError, 'new property "%s" not a string'%propname | |
| 224 | |
| 225 elif isinstance(prop, Password): | |
| 226 if not isinstance(value, password.Password): | |
| 227 raise TypeError, 'new property "%s" not a Password'%propname | |
| 228 propvalues[propname] = value | |
| 229 | |
| 230 elif value is not None and isinstance(prop, Date): | |
| 231 if not isinstance(value, date.Date): | |
| 232 raise TypeError, 'new property "%s" not a Date'% propname | |
| 233 propvalues[propname] = value | |
| 234 | |
| 235 elif value is not None and isinstance(prop, Interval): | |
| 236 if not isinstance(value, date.Interval): | |
| 237 raise TypeError, 'new property "%s" not an '\ | |
| 238 'Interval'%propname | |
| 239 propvalues[propname] = value | |
| 240 | |
| 241 elif value is not None and isinstance(prop, Number): | |
| 242 try: | |
| 243 float(value) | |
| 244 except ValueError: | |
| 245 raise TypeError, 'new property "%s" not numeric'%propname | |
| 246 | |
| 247 elif value is not None and isinstance(prop, Boolean): | |
| 248 try: | |
| 249 int(value) | |
| 250 except ValueError: | |
| 251 raise TypeError, 'new property "%s" not boolean'%propname | |
| 252 | |
| 253 node[propname] = value | |
| 254 | |
| 255 # do the set | |
| 256 self.store[nodeid] = node | |
| 257 | |
| 258 def lookup(self, keyvalue): | |
| 259 ''' look up the key node in the store | |
| 260 ''' | |
| 261 return self.by_key[keyvalue] | |
| 262 | |
| 263 def hasnode(self, nodeid): | |
| 264 nodeid = str(nodeid) | |
| 265 return self.store.has_key(nodeid) | |
| 266 | |
| 267 def list(self): | |
| 268 l = self.store.keys() | |
| 269 l.sort() | |
| 270 return l | |
| 271 | |
| 272 def index(self, nodeid): | |
| 273 pass | |
| 274 |
