# HG changeset patch # User durandn # Date 1441639508 -7200 # Node ID 19d1f3311e893ba786046582f986389083a048f7 # Parent 830aa4c34caae4ea6ed528c900df81f8f8fd4955 added annotation deletion into tastypie API diff -r 830aa4c34caa -r 19d1f3311e89 src/ldt/ldt/api/ldt/resources/annotation.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 '' diff -r 830aa4c34caa -r 19d1f3311e89 src/ldt/ldt/api/ldt/tests/tests_annotation.py --- 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 diff -r 830aa4c34caa -r 19d1f3311e89 src/ldt/ldt/ldt_utils/utils.py --- 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)