@@ -471,6 +471,67 @@ def raise_if_no_etag(self, class_name, item_id, input):
471471 "If-Match is missing or does not match."
472472 " Retrieve asset and retry modification if valid." )
473473
474+ def format_item (self , node , item_id , props = None , verbose = 1 ):
475+ ''' display class obj as requested by verbose and
476+ props.
477+ '''
478+ uid = self .db .getuid ()
479+ class_name = node .cl .classname
480+ result = {}
481+ try :
482+ # pn = propname
483+ for pn in sorted (props ):
484+ prop = props [pn ]
485+ if not self .db .security .hasPermission (
486+ 'View' , uid , class_name , pn , item_id
487+ ):
488+ continue
489+ v = getattr (node , pn )
490+ if isinstance (prop , (hyperdb .Link , hyperdb .Multilink )):
491+ linkcls = self .db .getclass (prop .classname )
492+ cp = '%s/%s/' % (self .data_path , prop .classname )
493+ if verbose and v :
494+ if isinstance (v , type ([])):
495+ r = []
496+ for id in v :
497+ d = dict (id = id , link = cp + id )
498+ if verbose > 1 :
499+ label = linkcls .labelprop ()
500+ d [label ] = linkcls .get (id , label )
501+ r .append (d )
502+ result [pn ] = r
503+ else :
504+ result [pn ] = dict (id = v , link = cp + v )
505+ if verbose > 1 :
506+ label = linkcls .labelprop ()
507+ result [pn ][label ] = linkcls .get (v , label )
508+ else :
509+ result [pn ] = v
510+ elif isinstance (prop , hyperdb .String ) and pn == 'content' :
511+ # Do not show the (possibly HUGE) content prop
512+ # unless very verbose, we display the standard
513+ # download link instead
514+ if verbose < 3 :
515+ u = self .db .config .TRACKER_WEB
516+ p = u + '%s%s/' % (class_name , node .id )
517+ result [pn ] = dict (link = p )
518+ else :
519+ result [pn ] = v
520+ elif isinstance (prop , hyperdb .Password ):
521+ if v != None : # locked users like anonymous have None
522+ result [pn ] = "[password hidden scheme %s]" % v .scheme
523+ else :
524+ # Don't divulge it's a locked account. Choose most
525+ # secure as default.
526+ result [pn ] = "[password hidden scheme PBKDF2]"
527+ else :
528+ result [pn ] = v
529+ except KeyError as msg :
530+ raise UsageError ("%s field not valid" % msg )
531+
532+ return result
533+
534+
474535 @Routing .route ("/data/<:class_name>" , 'GET' )
475536 @_data_decorator
476537 def get_collection (self , class_name , input ):
@@ -509,6 +570,7 @@ def get_collection(self, class_name, input):
509570 'index' : 1 # setting just size starts at page 1
510571 }
511572 verbose = 1
573+ display_props = {}
512574 for form_field in input .value :
513575 key = form_field .name
514576 value = form_field .value
@@ -518,6 +580,12 @@ def get_collection(self, class_name, input):
518580 page [key ] = value
519581 elif key == "@verbose" :
520582 verbose = int (value )
583+ elif key == "@fields" or key == "@attrs" :
584+ f = value .split ("," )
585+ if len (f ) == 1 :
586+ f = value .split ("," )
587+ for i in f :
588+ display_props [i ] = class_obj .properties [i ]
521589 else : # serve the filter purpose
522590 prop = class_obj .getprops ()[key ]
523591 # We drop properties without search permission silently
@@ -543,26 +611,31 @@ def get_collection(self, class_name, input):
543611 else :
544612 obj_list = class_obj .filter (None , filter_props )
545613
614+ # Sort list as specified by sortorder
615+ # This is more useful for things where there is an
616+ # explicit order. E.G. status has an order that is
617+ # roughly the progression of the issue through
618+ # the states so open is before closed.
619+ obj_list .sort ()
620+
621+ # add verbose elements. 2 and above get identifying label.
622+ if verbose > 1 :
623+ lp = class_obj .labelprop ()
624+ display_props [lp ] = class_obj .properties [lp ]
625+
546626 # extract result from data
547627 result = {}
548- result ['collection' ] = [
549- {'id' : item_id , 'link' : class_path + item_id }
550- for item_id in obj_list
628+ result ['collection' ]= []
629+ for item_id in obj_list :
551630 if self .db .security .hasPermission (
552- 'View' , uid , class_name , itemid = item_id
553- )
554- ]
555-
556- # add verbose elements. First identifying label.
557- if verbose > 1 :
558- label = class_obj .labelprop ()
559- for obj in result ['collection' ]:
560- id = obj ['id' ]
561- if self .db .security .hasPermission (
562- 'View' , uid , class_name , property = label ,
563- itemid = id
564- ):
565- obj [label ] = class_obj .get (id , label )
631+ 'View' , uid , class_name , itemid = item_id ):
632+ r = {'id' : item_id , 'link' : class_path + item_id }
633+ if display_props :
634+ r .update (self .format_item (class_obj .getnode (item_id ),
635+ item_id ,
636+ props = display_props ,
637+ verbose = verbose ))
638+ result ['collection' ].append (r )
566639
567640 result_len = len (result ['collection' ])
568641
@@ -657,66 +730,37 @@ def get_element(self, class_name, item_id, input):
657730 for form_field in input .value :
658731 key = form_field .name
659732 value = form_field .value
660- if key == "@fields" :
661- props = value .split ("," )
662- if key == "@protected" :
733+ if key == "@fields" or key == "@attrs" :
734+ if props is None :
735+ props = {}
736+ # support , or : separated elements
737+ f = value .split ("," )
738+ if len (f ) == 1 :
739+ f = value .split (":" )
740+ for i in f :
741+ props [i ] = class_obj .properties [i ]
742+ elif key == "@protected" :
663743 # allow client to request read only
664744 # properties like creator, activity etc.
745+ # used only if no @fields/@attrs
665746 protected = value .lower () == "true"
666- if key == "@verbose" :
747+ elif key == "@verbose" :
667748 verbose = int (value )
668749
669750 result = {}
670751 if props is None :
671752 props = class_obj .getprops (protected = protected )
753+ else :
754+ if verbose > 1 :
755+ lp = class_obj .labelprop ()
756+ props [lp ] = class_obj .properties [lp ]
672757
673- try :
674- for pn in sorted (props ):
675- prop = props [pn ]
676- if not self .db .security .hasPermission (
677- 'View' , uid , class_name , pn , itemid
678- ):
679- continue
680- v = getattr (node , pn )
681- if isinstance (prop , (hyperdb .Link , hyperdb .Multilink )):
682- linkcls = self .db .getclass (prop .classname )
683- cp = '%s/%s/' % (self .data_path , prop .classname )
684- if verbose and v :
685- if isinstance (v , type ([])):
686- r = []
687- for id in v :
688- d = dict (id = id , link = cp + id )
689- if verbose > 1 :
690- label = linkcls .labelprop ()
691- d [label ] = linkcls .get (id , label )
692- r .append (d )
693- result [pn ] = r
694- else :
695- result [pn ] = dict (id = v , link = cp + v )
696- if verbose > 1 :
697- label = linkcls .labelprop ()
698- result [pn ][label ] = linkcls .get (v , label )
699- else :
700- result [pn ] = v
701- elif isinstance (prop , hyperdb .String ) and pn == 'content' :
702- # Do not show the (possibly HUGE) content prop
703- # unless very verbose, we display the standard
704- # download link instead
705- if verbose < 3 :
706- u = self .db .config .TRACKER_WEB
707- p = u + '%s%s/' % (class_name , node .id )
708- result [pn ] = dict (link = p )
709- else :
710- result [pn ] = v
711- else :
712- result [pn ] = v
713- except KeyError as msg :
714- raise UsageError ("%s field not valid" % msg )
715758 result = {
716759 'id' : itemid ,
717760 'type' : class_name ,
718761 'link' : '%s/%s/%s' % (self .data_path , class_name , item_id ),
719- 'attributes' : dict (result ),
762+ 'attributes' : self .format_item (node , itemid , props = props ,
763+ verbose = verbose ),
720764 '@etag' : etag
721765 }
722766
0 commit comments