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 django.conf.urls import url
from tastypie import fields
from tastypie.authorization import Authorization
from tastypie.exceptions import NotFound, BadRequest
from tastypie.resources import Resource
from tastypie.utils import trailing_slash
class AnnotationObject(object):
def __init__(self, id="", project="", type="", type_title="", ensemble="", media="", begin=0, end=0, content=None, tags=None, meta=None): # @ReservedAssignment
self.id = id
self.project = project
self.type = type
self.type_title = type_title
self.ensemble = ensemble
self.media = media
self.begin = begin
self.end = end
self.content = content if content is not None else {"title":"", "description":""}
self.tags = tags if tags is not None else []
self.meta = meta if meta is not None else {"creator":"", "created":""}
class AnnotationResource(Resource):
# For the moment, these attributes are useless. We just prepare relations to AnnotationObject
id = fields.CharField(attribute='id')
project = fields.CharField(attribute='project')
type = fields.CharField(attribute='type')
type_title = fields.CharField(attribute='type_title')
media = fields.CharField(attribute='media')
begin = fields.IntegerField(attribute='begin')
end = fields.IntegerField(attribute='end')
content = fields.DictField(attribute='content')
tags = fields.ListField(attribute='tags')
meta = fields.DictField(attribute='meta')
class Meta:
allowed_methods = ['post', 'put', 'delete']
resource_name = 'annotations'
object_class = AnnotationObject
authorization = Authorization()
# always_return_data = True because we want the api returns the data with the updated ids
always_return_data = True
include_resource_uri = False
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/(?P<element_id>[^/]*?)(?:/(?P<project_id>[^/]*?)(?:/(?P<iri_id>[^/]*?)(?:/(?P<grouping_id>[^/]*?)(?:/(?P<cutting_id>[^/]*?))?)?)?)?%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
]
def extract_annotation_data(self, data):
# This method extracts and validates the data we receive from the user for adding or editing an annotation
project_id = ""
if data.has_key('project') :
project_id = data["project"]
if data.has_key('media') :
iri_id = data["media"]
else :
raise BadRequest
if project_id and project_id != "" :
try:
project = Project.objects.get(ldt_id=project_id)
except Project.DoesNotExist:
raise NotFound("Project not found. project_id = " + project_id)
else :
# If the project's is not defined, we get or create the content's front project.
try:
content = Content.objects.get(iri_id=iri_id)
except Content.DoesNotExist:
raise NotFound("Content not found. iri_id = " + iri_id)
project = content.get_or_create_front_project()
project_id = project.ldt_id
ann_duration = 0
ann_begin = 0
ann_end = 0
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_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', '')
ann_id = data.get("id", "")
ann_title = data.get('content', {}).get('title', "")
ann_description = data.get('content', {}).get('description')
ann_tags = data.get('tags', [])
content = project.contents.get(iri_id=iri_id)
return {
"project_obj" : project,
"project_id" : project_id,
"content_obj" : content,
"iri_id" : iri_id,
"ann_type_id" : ann_type_id,
"ann_type_title" : ann_type_title,
"ann_id" : ann_id,
"ann_content" : {
"title" : ann_title,
"description" : ann_description,
"audio" : {
"src" : ann_audio_src,
"href" : ann_audio_href,
},
},
"ann_meta" : {
"creator" : ann_author,
"created" : ann_date,
},
"ann_tags" : ann_tags,
"ann_begin" : ann_begin,
"ann_end" : ann_end,
"ann_duration" : ann_duration,
}
def obj_delete_list(self, bundle, **kwargs):
return True
def obj_create(self, bundle, **kwargs):
# 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
try:
type_id, new_id, ensemble_id = adder.add(
data_dict['iri_id'], # media
data_dict['ann_type_id'], # cutting_id
data_dict['ann_type_title'], # cutting_title
data_dict['ann_content']['title'], # title
data_dict['ann_content']['description'], # text
data_dict['ann_tags'], # tags_list
data_dict['ann_begin'], # begin
data_dict['ann_duration'], # dur
data_dict['ann_meta']['creator'], # author
data_dict['ann_meta']['created'], # date
None,
"2194379",
data_dict['ann_content']['audio']['src'],
data_dict['ann_content']['audio']['href']
)
if not new_id:
raise BadRequest
# We update the ids
data_dict['ann_type_id'] = type_id
data_dict['ensemble_id'] = ensemble_id
data_dict['ann_id'] = new_id
# add segment
add_segment({
"project" : data_dict["project_obj"],
"content" : data_dict["content_obj"],
"ensemble_id" : data_dict["ensemble_id"],
"cutting_id" : data_dict['ann_type_id'],
"element_id" : data_dict['ann_id'],
"title" : data_dict['ann_content']['title'],
"abstract" : data_dict['ann_content']['description'],
"tags" : ",".join(data_dict['ann_tags']),
"start_ts" : data_dict['ann_begin'],
"duration" : data_dict['ann_duration'],
"author" : data_dict['ann_meta']['creator'],
"date" : data_dict['ann_meta']['created'],
"audio_src" : data_dict['ann_content']['audio']['src'],
"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)
finally:
protect_models()
# We update the AnnotationObject for the returned datas to be correct.
print(data_dict)
bundle.obj = AnnotationObject(
id=data_dict["ann_id"],
project=data_dict["project_id"],
type=data_dict["ann_type_id"],
type_title=data_dict["ann_type_title"],
ensemble=data_dict['ensemble_id'],
media=data_dict["iri_id"],
begin=data_dict["ann_begin"],
end=data_dict["ann_end"],
content=data_dict['ann_content'],
tags=data_dict['ann_tags'],
meta=data_dict['ann_meta']
)
print(data_dict["ann_content"])
print(bundle.obj.content)
return bundle
def obj_update(self, bundle, **kwargs):
data_dict = self.extract_annotation_data(bundle.data)
if not data_dict['ann_id']:
data_dict['ann_id'] = kwargs["element_id"]
adder = LdtAnnotation(data_dict["project_obj"])
try:
unprotect_models() # Allows anonymous user to modify models in this request only
ensemble_id = adder.edit(
data_dict['ann_id'], # annotation_id
data_dict['iri_id'], # media
data_dict['ann_type_id'], # cutting_id
data_dict['ann_type_title'], # cutting_title
data_dict['ann_content']['title'], # title
data_dict['ann_content']['description'], # text
data_dict['ann_tags'], # tags_list
data_dict['ann_begin'], # begin
data_dict['ann_duration'], # dur
data_dict['ann_meta']['creator'], # author
data_dict['ann_meta']['created'], # date
None,
"2194379",
data_dict['ann_content']['audio']['src'],
data_dict['ann_content']['audio']['href']
)
if not ensemble_id:
raise BadRequest
# We update the id
data_dict['ensemble_id'] = ensemble_id
# add segment
edit_segment(
data_dict["project_id"],
data_dict["iri_id"],
data_dict["ensemble_id"],
data_dict['ann_type_id'],
data_dict["ann_id"],
params={
"project" : data_dict["project_obj"],
"content" : data_dict["content_obj"],
"ensemble_id" : data_dict["ensemble_id"],
"cutting_id" : data_dict['ann_type_id'],
"element_id" : data_dict['ann_id'],
"title" : data_dict['ann_content']['title'],
"abstract" : data_dict['ann_content']['description'],
"tags" : ",".join(data_dict['ann_tags']),
"start_ts" : data_dict['ann_begin'],
"duration" : data_dict['ann_duration'],
"author" : data_dict['ann_meta']['creator'],
"date" : data_dict['ann_meta']['created'],
"audio_src" : data_dict['ann_content']['audio']['src'],
"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)
finally:
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"],
type=data_dict["ann_type_id"],
type_title=data_dict["ann_type_title"],
ensemble=data_dict['ensemble_id'],
media=data_dict["iri_id"],
begin=data_dict["ann_begin"],
end=data_dict["ann_end"],
content=data_dict['ann_content'],
tags=data_dict['ann_tags'],
meta=data_dict['ann_meta']
)
return bundle
def obj_delete(self, bundle, **kwargs):
query_args = {
'project_id' : kwargs.get("project_id", None),
'iri_id' : kwargs.get("iri_id", None),
'ensemble_id' : kwargs.get("grouping_id", None),
'cutting_id' : kwargs.get("cutting_id", None),
'element_id' : kwargs.get("element_id", None)
}
query_args = { k: v for k,v in query_args.items() if v }
try:
seg_to_delete = Segment.objects.get(**query_args)
except Segment.DoesNotExist:
raise NotFound("Segment not found. element_id = " + query_args['element_id'])
except Segment.MultipleObjectsReturned:
raise NotFound("Multiple segments found. element_id = " + query_args['element_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)
try:
unprotect_models()
deleted = adder.delete(query_args['element_id'], iri_id, ann_type_id)
if not deleted:
raise BadRequest
delete_segment(project, project_id, iri_id, ensemble_id, ann_type_id, query_args['element_id'])
adder.save()
finally:
protect_models()
return bundle
def get_resource_uri(self, bundle_or_obj=None, url_name='api_dispatch_list'):
return ''