added annotation deletion into tastypie API
authordurandn
Mon, 07 Sep 2015 17:25:08 +0200
changeset 1427 19d1f3311e89
parent 1426 830aa4c34caa
child 1428 26e3ee748327
added annotation deletion into tastypie API
src/ldt/ldt/api/ldt/resources/annotation.py
src/ldt/ldt/api/ldt/tests/tests_annotation.py
src/ldt/ldt/ldt_utils/utils.py
--- a/src/ldt/ldt/api/ldt/resources/annotation.py	Thu Sep 03 18:38:47 2015 +0200
+++ b/src/ldt/ldt/api/ldt/resources/annotation.py	Mon Sep 07 17:25:08 2015 +0200
@@ -1,5 +1,5 @@
-from ldt.ldt_utils.contentindexer import add_segment, edit_segment
-from ldt.ldt_utils.models import Project, Content
+from ldt.ldt_utils.contentindexer import add_segment, edit_segment, delete_segment
+from ldt.ldt_utils.models import Project, Content, Segment
 from ldt.ldt_utils.utils import LdtAnnotation
 from ldt.security import protect_models, unprotect_models
 from tastypie import fields
@@ -36,7 +36,7 @@
     meta = fields.DictField(attribute = 'meta')
     
     class Meta:
-        allowed_methods = ['post', 'put']
+        allowed_methods = ['post', 'put', 'delete']
         resource_name = 'annotations'
         object_class = AnnotationObject
         authorization = Authorization()
@@ -70,20 +70,19 @@
             project = content.get_or_create_front_project()
             project_id = project.ldt_id
         
-        ann_duration = str(data['end'] - data['begin'])
-        ann_begin = str(data['begin'])
-        ann_end = str(data['end'])
-        # We test if the annotation has audio node
-        ann_audio_src = ""
-        ann_audio_href = ""
-        if data['content'].has_key('audio') :
-            if data['content']['audio'].has_key('src') :
-                ann_audio_src = data['content']['audio']['src']
-            if data['content']['audio'].has_key('href') :
-                ann_audio_href = data['content']['audio']['href']
+        ann_duration = -1
+        ann_begin = -1
+        ann_end = -1
+        if (data.has_key('begin') and data.has_key('end')):
+            ann_duration = str(data['end'] - data['begin'])
+            ann_begin = str(data['begin'])
+            ann_end = str(data['end'])
         
-        ann_author = data['meta']['creator']
-        ann_date = data['meta']['created']
+        ann_audio_src = data.get('content', {}).get('audio', {}).get('src', "")
+        ann_audio_href = data.get('content', {}).get('audio', {}).get('href', "")
+        
+        ann_author = data.get('meta', {}).get('creator', "")
+        ann_date = data.get('meta', {}).get('created', "")
         
         ann_type_id = data.get('type', '')
         ann_type_title = data.get('type_title', '')
@@ -127,8 +126,9 @@
         # Here the a has the datas for only one annotation. Tastypie's post allows only one resource addition 
         data_dict = self.extract_annotation_data(bundle.data)
         adder = LdtAnnotation(data_dict["project_obj"])
+        
         unprotect_models() # Allows anonymous user to modify models in this request only
-        
+
         type_id, new_id, ensemble_id = adder.add(
             data_dict['iri_id'], # media
             data_dict['ann_type_id'], # cutting_id
@@ -145,6 +145,7 @@
             data_dict['ann_content']['audio']['src'], 
             data_dict['ann_content']['audio']['href']
         )
+
         if not new_id:
             protect_models()
             raise BadRequest
@@ -194,6 +195,9 @@
     
     def obj_update(self, bundle, **kwargs):
         data_dict = self.extract_annotation_data(bundle.data)
+        if data_dict['ann_id'] == "":
+            data_dict['ann_id'] == kwargs["pk"]
+        
         adder = LdtAnnotation(data_dict["project_obj"])
         unprotect_models() # Allows anonymous user to modify models in this request only
         
@@ -217,10 +221,8 @@
         if not ensemble_id:
             protect_models()
             raise BadRequest
-        
         # We update the id
         data_dict['ensemble_id'] = ensemble_id
-        
         #add segment
         edit_segment(
             data_dict["project_id"],
@@ -245,10 +247,12 @@
                 "audio_href" : data_dict['ann_content']['audio']['href'],
                 "polemics": adder.get_polemic_syntax(data_dict['ann_content']['title'])
             })
+        
         # We save the added annotation and reprotect the contents and projects
         adder.save(must_reindex=False)
         protect_models()
         # We update the AnnotationObject for the returned datas to be correct.
+        
         bundle.obj = AnnotationObject(
             id = data_dict["ann_id"], 
             project = data_dict["project_id"], 
@@ -264,6 +268,31 @@
         )
         return bundle
     
+    def obj_delete(self, bundle, **kwargs):
+        ann_id = kwargs.get("pk", "")
+        try: 
+            seg_to_delete = Segment.objects.get(element_id = ann_id)
+        except Segment.DoesNotExist:
+            raise NotFound("Segment not found. element_id = " + ann_id)
+        project_id = seg_to_delete.project_id
+        try:
+            project = Project.objects.get(ldt_id = project_id)
+        except Project.DoesNotExist:
+            raise NotFound("Project not found. ldt_id = " + project_id)
+        ann_type_id = seg_to_delete.cutting_id
+        ensemble_id = seg_to_delete.ensemble_id
+        iri_id = seg_to_delete.iri_id
+        adder = LdtAnnotation(project)
+        unprotect_models()
+        deleted = adder.delete(ann_id, iri_id, ann_type_id)
+        if not deleted:
+            protect_models()
+            raise BadRequest
+        delete_segment(project, project_id, iri_id, ensemble_id, ann_type_id, ann_id)
+        adder.save()
+        protect_models()
+        return bundle
+        
     def get_resource_uri(self, bundle_or_obj=None, url_name='api_dispatch_list'):
         return ''
 
--- a/src/ldt/ldt/api/ldt/tests/tests_annotation.py	Thu Sep 03 18:38:47 2015 +0200
+++ b/src/ldt/ldt/api/ldt/tests/tests_annotation.py	Mon Sep 07 17:25:08 2015 +0200
@@ -90,7 +90,16 @@
         self.assertEqual("admin", edited_annotation.author)
         self.assertEqual("2015-07-20T10:33:46.282Z", edited_annotation.date)
         self.assertEqual("added_tag", edited_annotation.get_tags())
+    
+    def testDeletion(self):
+        post_resp = self.api_client.client.post(reverse('api_dispatch_list', kwargs={'api_name':'1.0', 'resource_name':'annotations'}), content_type='application/json', data=self.test_annotation_json)       
+        ann_id = json.loads(post_resp.content)["id"]
         
+        delete_resp = self.api_client.client.delete(reverse('api_dispatch_detail', kwargs={'api_name':'1.0', 'resource_name':'annotations', 'pk': ann_id}))
         
+        deleted_annotation = Segment.objects.filter(element_id = ann_id)
+        self.assertFalse(deleted_annotation.exists())
+        with self.assertRaises(Segment.DoesNotExist):
+            Segment.objects.get(element_id=ann_id)
     def tearDown(self):
         pass
\ No newline at end of file
--- a/src/ldt/ldt/ldt_utils/utils.py	Thu Sep 03 18:38:47 2015 +0200
+++ b/src/ldt/ldt/ldt_utils/utils.py	Mon Sep 07 17:25:08 2015 +0200
@@ -170,7 +170,48 @@
         self.ldtdoc = lxml.etree.parse(StringIO(project.ldt_encoded), self.parser)
         self.to_add = True
     
+    def find_annotation_element(self, ann_id, media, cutting_id):
+        """
+        Find an annotation element in the xml
+        """
+        # We check if the project references the media.
+        path_media = self.ldtdoc.xpath('/iri/medias/media[@id="%s"]' % media)
+        if len(path_media) == 0:
+            self.to_add = False
+            return False       
+        # We get the content node
+        path_annotations = self.ldtdoc.xpath('/iri/annotations')[0]
+        path_content = path_annotations.xpath('content[@id="%s"]' % media)
+        if len(path_content) == 0:
+            # If the content node does not exist, we abort as this should be an edition operation
+            return False
+        # We check if cutting_id is provided, if it isn't we abort as this is an edition operation
+        if cutting_id is None or cutting_id=="" :
+            return False
+        # We get the ensemble node
+        path_ensemble = path_content[0].xpath('ensemble[decoupage[@id="%s"]]' % cutting_id)
+        if len(path_ensemble) == 0:
+            # If the ensemble node does not exist, we abort as this should be an edition operation
+            return False
+        # We get the elements node in the good decoupage node
+        ensemble_id = path_ensemble[0].get('id')
+        decoupage_elements = path_ensemble[0].xpath('decoupage[@id="%s"]/elements' % cutting_id)
+        if len(decoupage_elements) == 0:
+            # If the decoupage node does not exist, we abort as this should be an edition operation 
+            return False
+        # We get the annotation/element node
+        elements = decoupage_elements[0].xpath('element[@id="%s"]' % ann_id)
+        if len(elements) == 0:
+            # If the element doesn't exist there was a mistake calling edit method so we abort
+            return False
+        
+        element = elements[0]
+        return element, ensemble_id
+    
     def update_annotation_element(self, element, title, text, begin, dur, author, date, color, audio_src, audio_href, tags_list):       
+        """
+        Updates an annotation element in the xml
+        """
         element.set('begin', begin)
         element.set('dur', dur)
         element.set('author', author)
@@ -335,52 +376,19 @@
         if dur < 0:
             self.to_add = False
             return False
-        
-        # We check if the project references the media.
-        path_media = self.ldtdoc.xpath('/iri/medias/media[@id="%s"]' % media)
-        if len(path_media) == 0:
-            self.to_add = False
-            return False
-        
-        # We get the content node
-        path_annotations = self.ldtdoc.xpath('/iri/annotations')[0]
-        path_content = path_annotations.xpath('content[@id="%s"]' % media)
-        if len(path_content) == 0:
-            # If the content node does not exist, we abort as this should be an edition operation
-            return False
-        
-        # We check if cutting_id is provided, if it isn't we abort as this is an edition operation
-        if cutting_id is None or cutting_id=="" :
-            return False
-        # We get the ensemble node
-        path_ensemble = path_content[0].xpath('ensemble[decoupage[@id="%s"]]' % cutting_id)
-        
-        if len(path_ensemble) == 0:
-            # If the ensemble node does not exist, we abort as this should be an edition operation
+        element, ensemble_id = self.find_annotation_element(ann_id, media, cutting_id)
+        if element is False:
             return False
-        #else:
-        #    path_ensemble = path_content[0].xpath('ensemble')
-            
-        # We get the elements node in the good decoupage node
-        ensemble_id = path_ensemble[0].get('id')
-        decoupage_elements = path_ensemble[0].xpath('decoupage[@id="%s"]/elements' % cutting_id)
-        if len(decoupage_elements) == 0:
-            # If the decoupage node does not exist, we abort as this should be an edition operation 
+        self.update_annotation_element(element, title, text, begin, dur, author, date, color, audio_src, audio_href, tags_list)
+        return ensemble_id
+    
+    def delete(self, ann_id, media, cutting_id):
+        element, ensemble_id = self.find_annotation_element(ann_id, media, cutting_id)
+        if element is False:
             return False
-        #else:
-        #    cutting_id = path_ensemble[0].xpath('decoupage[title="%s"]' % cutting_title)[0].get('id')     
-        
-        # We get the annotation/element node
-        elements = decoupage_elements[0].xpath('element[@id="%s"]' % ann_id)
-        if len(elements) == 0:
-            # If the element doesn't exist there was a mistake calling edit method so we abort
-            return False
-        
-        element = elements[0]
-        self.update_annotation_element(element, title, text, begin, dur, author, date, color, audio_src, audio_href, tags_list)
-           
+        element.getparent().remove(element)
         return ensemble_id
-        
+    
     def save(self, must_reindex=True):
         if self.to_add:
             self.project.ldt = lxml.etree.tostring(self.ldtdoc, pretty_print=True)