comparison roundup/rest.py @ 5604:ed02a1e0aa5d REST-rebased

Fix actions Permission for retire in roundup/actions.py was with 'Edit' permission, not 'Retire' permission. Add a 'restore' action to roundup/actions.py. Both are now correctly used in rest.py and xmlrpc.py (the latter had some errors when printint error messages). Also reworked the rest implementation: Despite the warnings in the roundup API in hyperdb.py the DELETE http method would *destroy* and not *retire* an item. This has been fixed. We also do not allow retire of a complete class (although this was implemented) because this seems to dangerous and we see no use-case.
author Ralf Schlatterbeck <rsc@runtux.com>
date Wed, 30 Jan 2019 14:12:27 +0100
parents c40d04915e23
children aa4c271514ae
comparison
equal deleted inserted replaced
5603:79da1ca2f94b 5604:ed02a1e0aa5d
241 241
242 def __init__(self, client, db): 242 def __init__(self, client, db):
243 self.client = client 243 self.client = client
244 self.db = db 244 self.db = db
245 self.translator = client.translator 245 self.translator = client.translator
246 self.actions = client.instance.actions.copy() 246 # This used to be initialized from client.instance.actions which
247 self.actions.update({'retire': actions.Retire}) 247 # would include too many actions that do not make sense in the
248 # REST-API context, so for now we only permit the retire and
249 # restore actions.
250 self.actions = dict (retire = actions.Retire, restore = actions.Restore)
248 251
249 protocol = 'http' 252 protocol = 'http'
250 host = self.client.env['HTTP_HOST'] 253 host = self.client.env['HTTP_HOST']
251 tracker = self.client.env['TRACKER_NAME'] 254 tracker = self.client.env['TRACKER_NAME']
252 self.base_path = '%s://%s/%s/rest' % (protocol, host, tracker) 255 self.base_path = '%s://%s/%s/rest' % (protocol, host, tracker)
714 return 200, result 717 return 200, result
715 718
716 @Routing.route("/data/<:class_name>", 'DELETE') 719 @Routing.route("/data/<:class_name>", 'DELETE')
717 @_data_decorator 720 @_data_decorator
718 def delete_collection(self, class_name, input): 721 def delete_collection(self, class_name, input):
719 """DELETE all objects in a class 722 """DELETE (retire) all objects in a class
723 There is currently no use-case, so this is disabled and
724 always returns Unauthorised.
720 725
721 Args: 726 Args:
722 class_name (string): class name of the resource (Ex: issue, msg) 727 class_name (string): class name of the resource (Ex: issue, msg)
723 input (list): the submitted form of the user 728 input (list): the submitted form of the user
724 729
726 int: http status code 200 (OK) 731 int: http status code 200 (OK)
727 dict: 732 dict:
728 status (string): 'ok' 733 status (string): 'ok'
729 count (int): number of deleted objects 734 count (int): number of deleted objects
730 """ 735 """
736 raise Unauthorised('Deletion of a whole class disabled')
731 if class_name not in self.db.classes: 737 if class_name not in self.db.classes:
732 raise NotFound('Class %s not found' % class_name) 738 raise NotFound('Class %s not found' % class_name)
733 if not self.db.security.hasPermission( 739 if not self.db.security.hasPermission(
734 'Delete', self.db.getuid(), class_name 740 'Retire', self.db.getuid(), class_name
735 ): 741 ):
736 raise Unauthorised('Permission to delete %s denied' % class_name) 742 raise Unauthorised('Permission to delete %s denied' % class_name)
737 743
738 class_obj = self.db.getclass(class_name) 744 class_obj = self.db.getclass(class_name)
739 for item_id in class_obj.list(): 745 for item_id in class_obj.list():
740 if not self.db.security.hasPermission( 746 if not self.db.security.hasPermission(
741 'Delete', self.db.getuid(), class_name, itemid=item_id 747 'Retire', self.db.getuid(), class_name, itemid=item_id
742 ): 748 ):
743 raise Unauthorised( 749 raise Unauthorised(
744 'Permission to delete %s %s denied' % (class_name, item_id) 750 'Permission to retire %s %s denied' % (class_name, item_id)
745 ) 751 )
746 752
747 count = len(class_obj.list()) 753 count = len(class_obj.list())
748 for item_id in class_obj.list(): 754 for item_id in class_obj.list():
749 self.db.destroynode(class_name, item_id) 755 class_obj.retire (item_id)
750 756
751 self.db.commit() 757 self.db.commit()
752 result = { 758 result = {
753 'status': 'ok', 759 'status': 'ok',
754 'count': count 760 'count': count
757 return 200, result 763 return 200, result
758 764
759 @Routing.route("/data/<:class_name>/<:item_id>", 'DELETE') 765 @Routing.route("/data/<:class_name>/<:item_id>", 'DELETE')
760 @_data_decorator 766 @_data_decorator
761 def delete_element(self, class_name, item_id, input): 767 def delete_element(self, class_name, item_id, input):
762 """DELETE an object in a class 768 """DELETE (retire) an object in a class
763 769
764 Args: 770 Args:
765 class_name (string): class name of the resource (Ex: issue, msg) 771 class_name (string): class name of the resource (Ex: issue, msg)
766 item_id (string): id of the resource (Ex: 12, 15) 772 item_id (string): id of the resource (Ex: 12, 15)
767 input (list): the submitted form of the user 773 input (list): the submitted form of the user
771 dict: 777 dict:
772 status (string): 'ok' 778 status (string): 'ok'
773 """ 779 """
774 if class_name not in self.db.classes: 780 if class_name not in self.db.classes:
775 raise NotFound('Class %s not found' % class_name) 781 raise NotFound('Class %s not found' % class_name)
782 class_obj = self.db.classes [class_name]
776 if not self.db.security.hasPermission( 783 if not self.db.security.hasPermission(
777 'Delete', self.db.getuid(), class_name, itemid=item_id 784 'Retire', self.db.getuid(), class_name, itemid=item_id
778 ): 785 ):
779 raise Unauthorised( 786 raise Unauthorised(
780 'Permission to delete %s %s denied' % (class_name, item_id) 787 'Permission to retire %s %s denied' % (class_name, item_id)
781 ) 788 )
782 789
783 self.db.destroynode(class_name, item_id) 790 class_obj.retire (item_id)
784 self.db.commit() 791 self.db.commit()
785 result = { 792 result = {
786 'status': 'ok' 793 'status': 'ok'
787 } 794 }
788 795

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