comparison roundup/hyperdb.py @ 1905:dc43e339e607

Centralised conversion of user-input data to hyperdb values (bug [SF#802405], bug [SF#817217], rfe [SF#816994])
author Richard Jones <richard@users.sourceforge.net>
date Tue, 11 Nov 2003 00:35:14 +0000
parents 969a14faf707
children 3bdd34547fa7
comparison
equal deleted inserted replaced
1904:9445caec3ff5 1905:dc43e339e607
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17 # 17 #
18 # $Id: hyperdb.py,v 1.90 2003-10-24 22:52:48 richard Exp $ 18 # $Id: hyperdb.py,v 1.91 2003-11-11 00:35:13 richard Exp $
19 19
20 """ 20 """
21 Hyperdatabase implementation, especially field types. 21 Hyperdatabase implementation, especially field types.
22 """ 22 """
23 23
569 569
570 def index(self, nodeid): 570 def index(self, nodeid):
571 '''Add (or refresh) the node to search indexes 571 '''Add (or refresh) the node to search indexes
572 ''' 572 '''
573 raise NotImplementedError 573 raise NotImplementedError
574
575 class HyperdbValueError(ValueError):
576 ''' Error converting a raw value into a Hyperdb value '''
577 pass
578
579 def convertLinkValue(db, propname, prop, value, idre=re.compile('\d+')):
580 ''' Convert the link value (may be id or key value) to an id value. '''
581 linkcl = db.classes[prop.classname]
582 if not idre.match(value):
583 if linkcl.getkey():
584 try:
585 value = linkcl.lookup(value)
586 except KeyError, message:
587 raise HyperdbValueError, 'property %s: %r is not a %s.'%(
588 propname, value, prop.classname)
589 else:
590 raise HyperdbValueError, 'you may only enter ID values '\
591 'for property %s'%propname
592 return value
593
594 def fixNewlines(text):
595 ''' Homogenise line endings.
596
597 Different web clients send different line ending values, but
598 other systems (eg. email) don't necessarily handle those line
599 endings. Our solution is to convert all line endings to LF.
600 '''
601 text = text.replace('\r\n', '\n')
602 return text.replace('\r', '\n')
603
604 def rawToHyperdb(db, klass, itemid, propname, value,
605 pwre=re.compile(r'{(\w+)}(.+)')):
606 ''' Convert the raw (user-input) value to a hyperdb-storable value. The
607 value is for the "propname" property on itemid (may be None for a
608 new item) of "klass" in "db".
609
610 The value is usually a string, but in the case of multilink inputs
611 it may be either a list of strings or a string with comma-separated
612 values.
613 '''
614 properties = klass.getprops()
615
616 # ensure it's a valid property name
617 propname = propname.strip()
618 try:
619 proptype = properties[propname]
620 except KeyError:
621 raise HyperdbValueError, '%r is not a property of %s'%(propname,
622 klass.classname)
623
624 # if we got a string, strip it now
625 if isinstance(value, type('')):
626 value = value.strip()
627
628 # convert the input value to a real property value
629 if isinstance(proptype, String):
630 # fix the CRLF/CR -> LF stuff
631 value = fixNewlines(value)
632 if isinstance(proptype, Password):
633 m = pwre.match(value)
634 if m:
635 # password is being given to us encrypted
636 p = password.Password()
637 p.scheme = m.group(1)
638 if p.scheme not in 'SHA crypt plaintext'.split():
639 raise HyperdbValueError, 'property %s: unknown encryption '\
640 'scheme %r'%(propname, p.scheme)
641 p.password = m.group(2)
642 value = p
643 else:
644 try:
645 value = password.Password(value)
646 except password.PasswordValueError, message:
647 raise HyperdbValueError, 'property %s: %s'%(propname, message)
648 elif isinstance(proptype, Date):
649 try:
650 tz = db.getUserTimezone()
651 value = date.Date(value).local(tz)
652 except ValueError, message:
653 raise HyperdbValueError, 'property %s: %r is an invalid '\
654 'date (%s)'%(propname, value, message)
655 elif isinstance(proptype, Interval):
656 try:
657 value = date.Interval(value)
658 except ValueError, message:
659 raise HyperdbValueError, 'property %s: %r is an invalid '\
660 'date interval (%s)'%(propname, value, message)
661 elif isinstance(proptype, Link):
662 if value == '-1' or not value:
663 value = None
664 else:
665 value = convertLinkValue(db, propname, proptype, value)
666
667 elif isinstance(proptype, Multilink):
668 # get the current item value if it's not a new item
669 if itemid and not itemid.startswith('-'):
670 curvalue = klass.get(itemid, propname)
671 else:
672 curvalue = []
673
674 # if the value is a comma-separated string then split it now
675 if isinstance(value, type('')):
676 value = value.split(',')
677
678 # handle each add/remove in turn
679 # keep an extra list for all items that are
680 # definitely in the new list (in case of e.g.
681 # <propname>=A,+B, which should replace the old
682 # list with A,B)
683 set = 1
684 newvalue = []
685 for item in value:
686 item = item.strip()
687
688 # skip blanks
689 if not item: continue
690
691 # handle +/-
692 remove = 0
693 if item.startswith('-'):
694 remove = 1
695 item = item[1:]
696 set = 0
697 elif item.startswith('+'):
698 item = item[1:]
699 set = 0
700
701 # look up the value
702 itemid = convertLinkValue(db, propname, proptype, item)
703
704 # perform the add/remove
705 if remove:
706 try:
707 curvalue.remove(itemid)
708 except ValueError:
709 raise HyperdbValueError, 'property %s: %r is not ' \
710 'currently an element'%(propname, item)
711 else:
712 newvalue.append(itemid)
713 if itemid not in curvalue:
714 curvalue.append(itemid)
715
716 # that's it, set the new Multilink property value,
717 # or overwrite it completely
718 if set:
719 value = newvalue
720 else:
721 value = curvalue
722
723 # TODO: one day, we'll switch to numeric ids and this will be
724 # unnecessary :(
725 value = [int(x) for x in value]
726 value.sort()
727 value = [str(x) for x in value]
728 elif isinstance(proptype, Boolean):
729 value = value.strip()
730 value = value.lower() in ('yes', 'true', 'on', '1')
731 elif isinstance(proptype, Number):
732 value = value.strip()
733 try:
734 value = float(value)
735 except ValueError:
736 raise HyperdbValueError, 'property %s: %r is not a number'%(
737 propname, value)
738 return value
574 739
575 class FileClass: 740 class FileClass:
576 ''' A class that requires the "content" property and stores it on 741 ''' A class that requires the "content" property and stores it on
577 disk. 742 disk.
578 ''' 743 '''

Roundup Issue Tracker: http://roundup-tracker.org/