--- 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)