|
59 | 59 | import re |
60 | 60 | import time |
61 | 61 |
|
62 | | -from hashlib import md5 |
63 | | - |
64 | 62 | # roundup modules |
65 | 63 | from roundup import hyperdb, date, password, roundupdb, security, support |
66 | | -from roundup.anypy.strings import b2s, bs2b, us2s, repr_export, eval_import |
| 64 | +from roundup.anypy.strings import us2s, repr_export, eval_import |
67 | 65 | from roundup.backends.blobfiles import FileStorage |
68 | 66 | from roundup.backends.indexer_common import get_indexer |
69 | 67 | from roundup.backends.indexer_common import Indexer as CommonIndexer |
@@ -3411,170 +3409,19 @@ def export_journals(self): |
3411 | 3409 |
|
3412 | 3410 |
|
3413 | 3411 | class FileClass(hyperdb.FileClass, Class): |
3414 | | - """This class defines a large chunk of data. To support this, it has a |
3415 | | - mandatory String property "content" which is typically saved off |
3416 | | - externally to the hyperdb. |
3417 | | -
|
3418 | | - The default MIME type of this data is defined by the |
3419 | | - "default_mime_type" class attribute, which may be overridden by each |
3420 | | - node if the class defines a "type" String property. |
3421 | | - """ |
| 3412 | + # Use for explicit upcalls in generic code, for py2 compat we cannot |
| 3413 | + # use super() without making everything a new-style class. |
| 3414 | + subclass = Class |
3422 | 3415 | def __init__(self, db, classname, **properties): |
3423 | | - """The newly-created class automatically includes the "content" |
3424 | | - and "type" properties. |
3425 | | - """ |
3426 | | - if 'content' not in properties: |
3427 | | - properties['content'] = hyperdb.String(indexme='yes') |
3428 | | - if 'type' not in properties: |
3429 | | - properties['type'] = hyperdb.String() |
| 3416 | + self._update_properties(properties) |
3430 | 3417 | Class.__init__(self, db, classname, **properties) |
3431 | 3418 |
|
3432 | | - def create(self, **propvalues): |
3433 | | - """ snaffle the file propvalue and store in a file |
3434 | | - """ |
3435 | | - # we need to fire the auditors now, or the content property won't |
3436 | | - # be in propvalues for the auditors to play with |
3437 | | - self.fireAuditors('create', None, propvalues) |
3438 | | - |
3439 | | - # now remove the content property so it's not stored in the db |
3440 | | - content = propvalues['content'] |
3441 | | - del propvalues['content'] |
3442 | | - |
3443 | | - # do the database create |
3444 | | - newid = self.create_inner(**propvalues) |
3445 | | - |
3446 | | - # figure the mime type |
3447 | | - mime_type = propvalues.get('type', self.default_mime_type) |
3448 | | - |
3449 | | - # and index! |
3450 | | - if self.properties['content'].indexme: |
3451 | | - index_content = content |
3452 | | - if bytes != str and isinstance(content, bytes): |
3453 | | - index_content = content.decode('utf-8', errors='ignore') |
3454 | | - self.db.indexer.add_text((self.classname, newid, 'content'), |
3455 | | - index_content, mime_type) |
3456 | | - |
3457 | | - # store off the content as a file |
3458 | | - self.db.storefile(self.classname, newid, None, bs2b(content)) |
3459 | | - |
3460 | | - # fire reactors |
3461 | | - self.fireReactors('create', newid, None) |
3462 | | - |
3463 | | - return newid |
3464 | | - |
3465 | | - def get(self, nodeid, propname, default=_marker, cache=1): |
3466 | | - """ Trap the content propname and get it from the file |
3467 | | -
|
3468 | | - 'cache' exists for backwards compatibility, and is not used. |
3469 | | - """ |
3470 | | - poss_msg = 'Possibly a access right configuration problem.' |
3471 | | - if propname == 'content': |
3472 | | - try: |
3473 | | - return b2s(self.db.getfile(self.classname, nodeid, None)) |
3474 | | - except IOError as strerror: |
3475 | | - # BUG: by catching this we donot see an error in the log. |
3476 | | - return 'ERROR reading file: %s%s\n%s\n%s' % ( |
3477 | | - self.classname, nodeid, poss_msg, strerror) |
3478 | | - except UnicodeDecodeError: |
3479 | | - # if content is not text (e.g. jpeg file) we get |
3480 | | - # unicode error trying to convert to string in python 3. |
3481 | | - # trap it and supply an error message. Include md5sum |
3482 | | - # of content as this string is included in the etag |
3483 | | - # calculation of the object. |
3484 | | - return ('%s%s is not text, retrieve using ' |
3485 | | - 'binary_content property. mdsum: %s') % ( |
3486 | | - self.classname, nodeid, |
3487 | | - md5(self.db.getfile( |
3488 | | - self.classname, |
3489 | | - nodeid, |
3490 | | - None)).hexdigest()) # nosec - bandit md5 use ok |
3491 | | - elif propname == 'binary_content': |
3492 | | - return self.db.getfile(self.classname, nodeid, None) |
3493 | | - |
3494 | | - if default is not _marker: |
3495 | | - return Class.get(self, nodeid, propname, default) |
3496 | | - else: |
3497 | | - return Class.get(self, nodeid, propname) |
3498 | | - |
3499 | | - def set(self, itemid, **propvalues): |
3500 | | - """ Snarf the "content" propvalue and update it in a file |
3501 | | - """ |
3502 | | - self.fireAuditors('set', itemid, propvalues) |
3503 | | - oldvalues = copy.deepcopy(self.db.getnode(self.classname, itemid)) |
3504 | | - |
3505 | | - # now remove the content property so it's not stored in the db |
3506 | | - content = None |
3507 | | - if 'content' in propvalues: |
3508 | | - content = propvalues['content'] |
3509 | | - del propvalues['content'] |
3510 | | - |
3511 | | - # do the database create |
3512 | | - propvalues = self.set_inner(itemid, **propvalues) |
3513 | | - |
3514 | | - # do content? |
3515 | | - if content: |
3516 | | - # store and possibly index |
3517 | | - self.db.storefile(self.classname, itemid, None, bs2b(content)) |
3518 | | - if self.properties['content'].indexme: |
3519 | | - mime_type = self.get(itemid, 'type', self.default_mime_type) |
3520 | | - index_content = content |
3521 | | - if bytes != str and isinstance(content, bytes): |
3522 | | - index_content = content.decode('utf-8', errors='ignore') |
3523 | | - self.db.indexer.add_text((self.classname, itemid, 'content'), |
3524 | | - index_content, mime_type) |
3525 | | - propvalues['content'] = content |
3526 | | - |
3527 | | - # fire reactors |
3528 | | - self.fireReactors('set', itemid, oldvalues) |
3529 | | - return propvalues |
3530 | | - |
3531 | | - def index(self, nodeid): |
3532 | | - """ Add (or refresh) the node to search indexes. |
3533 | | -
|
3534 | | - Use the content-type property for the content property. |
3535 | | - """ |
3536 | | - # find all the String properties that have indexme |
3537 | | - for prop, propclass in self.getprops().items(): |
3538 | | - if prop == 'content' and propclass.indexme: |
3539 | | - mime_type = self.get(nodeid, 'type', self.default_mime_type) |
3540 | | - index_content = self.get(nodeid, 'binary_content') |
3541 | | - if bytes != str and isinstance(index_content, bytes): |
3542 | | - index_content = index_content.decode('utf-8', |
3543 | | - errors='ignore') |
3544 | | - self.db.indexer.add_text((self.classname, nodeid, 'content'), |
3545 | | - index_content, mime_type) |
3546 | | - elif isinstance(propclass, hyperdb.String) and propclass.indexme: |
3547 | | - # index them under (classname, nodeid, property) |
3548 | | - try: |
3549 | | - value = str(self.get(nodeid, prop)) |
3550 | | - except IndexError: |
3551 | | - # node has been destroyed |
3552 | | - continue |
3553 | | - self.db.indexer.add_text((self.classname, nodeid, prop), value) |
3554 | | - |
3555 | | - |
3556 | | -# XXX deviation from spec - was called ItemClass |
3557 | 3419 | class IssueClass(Class, roundupdb.IssueClass): |
3558 | | - # Overridden methods: |
| 3420 | + # Use for explicit upcalls in generic code, for py2 compat we cannot |
| 3421 | + # use super() without making everything a new-style class. |
| 3422 | + subclass = Class |
3559 | 3423 | def __init__(self, db, classname, **properties): |
3560 | | - """The newly-created class automatically includes the "messages", |
3561 | | - "files", "nosy", and "superseder" properties. If the 'properties' |
3562 | | - dictionary attempts to specify any of these properties or a |
3563 | | - "creation", "creator", "activity" or "actor" property, a ValueError |
3564 | | - is raised. |
3565 | | - """ |
3566 | | - if 'title' not in properties: |
3567 | | - properties['title'] = hyperdb.String(indexme='yes') |
3568 | | - if 'messages' not in properties: |
3569 | | - properties['messages'] = hyperdb.Multilink("msg") |
3570 | | - if 'files' not in properties: |
3571 | | - properties['files'] = hyperdb.Multilink("file") |
3572 | | - if 'nosy' not in properties: |
3573 | | - # note: journalling is turned off as it really just wastes |
3574 | | - # space. this behaviour may be overridden in an instance |
3575 | | - properties['nosy'] = hyperdb.Multilink("user", do_journal="no") |
3576 | | - if 'superseder' not in properties: |
3577 | | - properties['superseder'] = hyperdb.Multilink(classname) |
| 3424 | + self._update_properties(classname, properties) |
3578 | 3425 | Class.__init__(self, db, classname, **properties) |
3579 | 3426 |
|
3580 | 3427 | # vim: set et sts=4 sw=4 : |
0 commit comments