Creation and deletion of content, iri file, and thumbnail are now transactional
authorrougeronj
Wed, 10 Oct 2012 18:00:00 +0200
changeset 840 b38c88bdefa2
parent 838 29114c745efd
child 841 7f237270b61c
Creation and deletion of content, iri file, and thumbnail are now transactional
src/ldt/ldt/ldt_utils/models.py
src/ldt/ldt/ldt_utils/views/content.py
src/ldt/ldt/locale/fr/LC_MESSAGES/django.mo
src/ldt/ldt/locale/fr/LC_MESSAGES/django.po
src/ldt/ldt/security/utils.py
--- a/src/ldt/ldt/ldt_utils/models.py	Wed Oct 10 16:19:10 2012 +0200
+++ b/src/ldt/ldt/ldt_utils/models.py	Wed Oct 10 18:00:00 2012 +0200
@@ -1,6 +1,7 @@
 from django.conf import settings
 from django.contrib.auth.models import User, Group
 from django.db import models
+from django.db import transaction
 from django.utils.translation import ugettext_lazy as _
 from guardian.shortcuts import assign, remove_perm, get_perms
 from ldt.core.models import Document
@@ -20,6 +21,9 @@
 import re
 import tagging.fields
 import uuid
+import logging
+from shutil import rmtree, move
+from django.core.files.storage import default_storage
 #from ldt.core.models import Document, Owner
 
 
@@ -170,6 +174,55 @@
         
         if not hasattr(Content, 'pol_positive'):
             self.__add_polemic_attributes()
+        
+    def delete(self):
+        super(Content, self).delete()
+        iri_file_path = self.iri_file_path()
+        thumbnail = os.path.join(settings.MEDIA_ROOT, unicode(self.image))
+        if os.path.exists(iri_file_path):
+            dir = os.path.dirname(iri_file_path)
+            temp = os.path.join(os.path.join(os.path.dirname(dir), "temp"), self.iri_id)             
+            try:
+                move(dir, temp)
+            except Exception, e:
+                raise e
+        if os.path.exists(thumbnail):
+            if os.path.basename(thumbnail) != os.path.basename(settings.DEFAULT_CONTENT_ICON):
+                temp_thumbnail = os.path.join(os.path.dirname(thumbnail), "temp")
+                try:    
+                    if not os.path.exists(temp_thumbnail):
+                        os.makedirs(temp_thumbnail)
+                    move(thumbnail, os.path.join(temp_thumbnail, os.path.basename(thumbnail)))            
+                except Exception, e:
+                    raise e
+
+    #del .iri, and .png from temp directory
+    def commit(self):
+        iri_file_path=self.iri_file_path()
+        dir = os.path.dirname(iri_file_path)
+        temp = os.path.join(os.path.join(os.path.dirname(dir), "temp"), self.iri_id)
+        thumbnail = os.path.join(settings.MEDIA_ROOT, unicode(self.image))
+        temp_thumbnail = os.path.join(os.path.dirname(thumbnail), "temp")
+        if os.path.exists(temp):
+            default_storage.delete(os.path.join(temp, os.path.basename(self.iriurl)))
+            os.rmdir(temp)
+        if os.path.exists(temp_thumbnail):
+            default_storage.delete(os.path.join(temp_thumbnail, os.path.basename(thumbnail)))
+            os.rmdir(temp_thumbnail)
+        
+    #move .iri, and .png to there original directory
+    def rollback(self):
+        iri_file_path=self.iri_file_path()
+        dir = os.path.dirname(iri_file_path)
+        temp = os.path.join(os.path.join(os.path.dirname(dir), "temp"), self.iri_id)
+        thumbnail = os.path.join(settings.MEDIA_ROOT, unicode(self.image))
+        temp_thumbnail = os.path.join(os.path.dirname(thumbnail), "temp")
+        if os.path.exists(temp):
+            move(temp, dir)
+            os.rmdir(os.path.dirname(temp))
+        if os.path.exists(temp_thumbnail):
+            move(os.path.join(temp_thumbnail, os.path.basename(thumbnail)), os.path.dirname(thumbnail))
+            os.rmdir(temp_thumbnail)
     
     def natural_key(self):
         return self.iri_id
@@ -230,8 +283,6 @@
     def save(self, *args, **kwargs):
         
         create_front_project = False
-        # update it
-        self.sync_iri_file()
         
         if not self.pk:
             create_front_project = True
@@ -244,6 +295,10 @@
             # save() has to be called first
             self.create_front_project()
             assign('ldt_utils.change_content', get_current_user(), self)
+            
+        # update it
+        # To put after project creation, to assume transaction
+        self.sync_iri_file()
 
             
     def __unicode__(self):
@@ -662,6 +717,17 @@
         else:
             return False
         
+    def has_annotations(self):
+        nb_annot = 0
+        doc = lxml.etree.fromstring(self.ldt)
+        res = doc.xpath("/iri/annotations/content/ensemble/decoupage")
+        for r in res:
+            nb_annot = nb_annot + r.find('elements').__len__()
+        if nb_annot == 0:
+            return False
+        else:
+            return True
+        
     def ldt_encoded(): #@NoSelf
         
         def fget(self):
@@ -743,6 +809,3 @@
         permissions = (
                        ('view_segment', 'Can view segment'),
                        )
-
-
-
--- a/src/ldt/ldt/ldt_utils/views/content.py	Wed Oct 10 16:19:10 2012 +0200
+++ b/src/ldt/ldt/ldt_utils/views/content.py	Wed Oct 10 18:00:00 2012 +0200
@@ -4,6 +4,7 @@
 from django.core.urlresolvers import reverse
 from django.forms.models import model_to_dict
 from django.core.files import File
+from django.db import transaction
 #from django.core.files.temp import NamedTemporaryFile
 from django.forms.util import ErrorList
 from django.http import HttpResponse, HttpResponseRedirect
@@ -29,8 +30,9 @@
 import requests
 import django.utils.simplejson as simplejson
 import urlparse  
-import tempfile 
+import tempfile
 
+@transaction.commit_manually
 def write_content_base(request, iri_id=None): 
     if iri_id:
         instance_content = Content.safe_objects.get(iri_id=iri_id) #@UndefinedVariable
@@ -44,282 +46,309 @@
     if instance_content:
         current_front_project = instance_content.front_project
     form_status = 'none'
-    if request.method == "POST":
-        
-        if instance_content is not None:
-            content_instance_val = model_to_dict(instance_content, exclude=ContentForm.Meta.exclude)
-        else:
-            content_instance_val = {}
-        
-        if instance_media is not None:
-            media_instance_val = model_to_dict(instance_media, exclude=MediaForm.Meta.exclude)
-        else:
-            media_instance_val = {}
-        #add prefix
-        
-        def add_prefix(_dict, prefix):
-            return dict([('%s-%s' % (prefix, key), value) for key,value in _dict.items()])
-        
-        content_instance_val = add_prefix(content_instance_val, "content")
-        media_instance_val= add_prefix(media_instance_val, "media")    
-                
-        for k in request.POST.keys():
-            value = request.POST.get(k)
-            content_instance_val[k] = value
-            media_instance_val[k] = value
+    errors_transaction = []
+    
+    # catch error from creating content, project, media
+    try:
+        if request.method == "POST":
+            
+            if instance_content is not None:
+                content_instance_val = model_to_dict(instance_content, exclude=ContentForm.Meta.exclude)
+            else:
+                content_instance_val = {}
             
-        content_instance_val['read_list'] = request.POST.getlist('read_list')
-        content_instance_val['write_list'] = request.POST.getlist('write_list')
-        content_instance_val['share'] = request.POST.get('share', True)
-        
-        content_form = ContentForm(content_instance_val, prefix="content", instance=instance_content)
-        media_form = MediaForm(media_instance_val, request.FILES, prefix="media", instance=instance_media)
-        picture_form = PictureForm(None, request.POST, request.FILES)
-   
-        if request.user.is_staff:
-            content_form.fields['front_project'].queryset = Project.objects.filter(contents__in=[instance_content])
-
-        
-        media_valid = media_form.is_valid()
-        content_valid = content_form.is_valid()
-        picture_valid = picture_form.is_valid()
-        if 'image' in request.POST.keys():
-            image_link = request.POST.get('url_image')
-            if picture_valid and image_link!='' :
-                try :
-                    r = requests.get(image_link)
-                    img_temp = tempfile.NamedTemporaryFile(suffix='.png')
-                    if img_temp:
-                        img_temp.write(r.content)
-                        img_temp.flush()
-                        picture_form.cleaned_data["image"]=File(img_temp) 
-                except Exception as inst:
-                    logging.debug("couldn't download video thumbnail from image_link : "+str(image_link))
-        logging.debug("write_content_base : valid form: for instance : " + repr(instance_media) + " -> media " + str(media_valid) + " content : for instance : " + repr(instance_content) + " : " + str(content_valid) + "picture : valid :" +str(picture_valid)+" loulou") #@UndefinedVariable
-        
-        if media_valid and content_valid and picture_valid:
-
-            # see if media must be created
-            cleaned_data = {}
-            cleaned_data.update(media_form.cleaned_data)
-            cleaned_data.pop("media_public")
+            if instance_media is not None:
+                media_instance_val = model_to_dict(instance_media, exclude=MediaForm.Meta.exclude)
+            else:
+                media_instance_val = {}
+            #add prefix
+            
+            def add_prefix(_dict, prefix):
+                return dict([('%s-%s' % (prefix, key), value) for key,value in _dict.items()])
             
-            media_input_type = content_form.cleaned_data["media_input_type"]
+            content_instance_val = add_prefix(content_instance_val, "content")
+            media_instance_val= add_prefix(media_instance_val, "media")    
+                    
+            for k in request.POST.keys():
+                value = request.POST.get(k)
+                content_instance_val[k] = value
+                media_instance_val[k] = value
+                
+            content_instance_val['read_list'] = request.POST.getlist('read_list')
+            content_instance_val['write_list'] = request.POST.getlist('write_list')
+            content_instance_val['share'] = request.POST.get('share', True)
             
-            if media_input_type == "none":
-                media = None
-            elif media_input_type == "link":
-                media = content_form.cleaned_data["media_obj"]
-                created = False
-            elif media_input_type == "create":
-                del cleaned_data["media_file"]
-                if not cleaned_data['videopath']:
-                    cleaned_data['videopath'] = settings.STREAM_URL
-                # if the source is already http:// or rtmp:// we don't have to add STREAM_URL
-                if cleaned_data['src'].startswith("rtmp://") or cleaned_data['src'].startswith("http://"):
-                    cleaned_data['videopath'] = ''
-                media, created = Media.objects.get_or_create(src=cleaned_data['src'], defaults=cleaned_data) #@UndefinedVariable
-            elif media_input_type == "url" or media_input_type == "upload" :
-                # copy file
-                #complet src
-                destination_file = None
-                source_file = None
-                try:
-                    if media_input_type == "url":
-                        url = cleaned_data["external_src_url"]
-                        source_file = urllib2.urlopen(url)
-                        source_filename = source_file.info().get('Content-Disposition', None)
-                        if not source_filename:
-                            source_filename = urlparse.urlparse(url).path.rstrip("/").split('/')[-1]
-                    elif media_input_type == "upload":
-                        #source_file = request.FILES['media-media_file']
-                        # At this point the file has already be uploaded thanks to the upload view, and original file name is sent through a post var
-                        source_filename = request.POST["media-local_file_name"]
-                    
-                    source_filename = ldt_utils_path.sanitize_filename(source_filename)
-                    destination_filepath = os.path.join(settings.STREAM_PATH, source_filename)
-                    base_source_filename = source_filename
-                    extension = base_source_filename.split(".")[-1]
-                    if extension == base_source_filename:
-                        extension = ""
-                        base_basename_filename = base_source_filename
-                    else:
-                        base_basename_filename = base_source_filename[:-1 * (len(extension) + 1)]
-                    i = 0
-                    
-                    while os.path.exists(destination_filepath):
-                        base_source_filename = "%s.%d.%s" % (base_basename_filename, i, extension)
-                        destination_filepath = os.path.join(settings.STREAM_PATH, base_source_filename)
-                        i += 1
-                    
-                    if media_input_type == "url":
-                        # we upload the file if we are in url case
-                        destination_file = open(destination_filepath, "wb")
-                        chunck = source_file.read(2048)
-                        while chunck:
-                            destination_file.write(chunck)
-                            chunck = source_file.read(2048)
-                        
-                    elif media_input_type == "upload":
-                        # The media file has been uploaded in the session temp folder 
-                        # so we just have to move to the regular folder and rename it.
-                        if os.path.exists(os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", source_filename)):
-                            os.rename(os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", source_filename), os.path.join(settings.STREAM_PATH, base_source_filename))
-                    
-                    
-                    src_prefix = settings.STREAM_SRC_PREFIX.rstrip("/")
-                    if len(src_prefix) > 0:
-                        cleaned_data["src"] = src_prefix + "/" + base_source_filename
-                    else:
-                        cleaned_data["src"] = base_source_filename
-                    
-                    
-                except Exception as inst:
-                    logging.debug("write_content_base : POST error when processing file:" + str(inst)) #@UndefinedVariable
-                    form_status = "error"
-                    #set error for form
-                    if media_input_type == "url":
-                        errors = media_form._errors.setdefault("external_src_url", ErrorList())
-                        errors.append(_("Problem when downloading file from url : ") + url)
-                    elif media_input_type == "upload":
-                        errors = media_form._errors.setdefault("media_file", ErrorList())
-                        errors.append(_("Problem when uploading file : ") + str(inst))
-                finally:
-                    if media_input_type == "url":
-                        if destination_file:
-                            destination_file.close()
-                        if source_file:
-                            source_file.close()
+            content_form = ContentForm(content_instance_val, prefix="content", instance=instance_content)
+            media_form = MediaForm(media_instance_val, request.FILES, prefix="media", instance=instance_media)
+            picture_form = PictureForm(None, request.POST, request.FILES)
+       
+            if request.user.is_staff:
+                content_form.fields['front_project'].queryset = Project.objects.filter(contents__in=[instance_content])
+    
+            
+            media_valid = media_form.is_valid()
+            content_valid = content_form.is_valid()
+            picture_valid = picture_form.is_valid()
+            if 'image' in request.POST.keys():
+                image_link = request.POST.get('url_image')
+                if picture_valid and image_link!='' :
+                    try :
+                        r = requests.get(image_link)
+                        img_temp = tempfile.NamedTemporaryFile(suffix='.png')
+                        if img_temp:
+                            img_temp.write(r.content)
+                            img_temp.flush()
+                            picture_form.cleaned_data["image"]=File(img_temp) 
+                    except Exception as inst:
+                        logging.debug("couldn't download video thumbnail from image_link : "+str(image_link))
+            logging.debug("write_content_base : valid form: for instance : " + repr(instance_media) + " -> media " + str(media_valid) + " content : for instance : " + repr(instance_content) + " : " + str(content_valid) + "picture : valid :" +str(picture_valid)+" loulou") #@UndefinedVariable
+            
+            if media_valid and content_valid and picture_valid:
+    
+                # see if media must be created
+                cleaned_data = {}
+                cleaned_data.update(media_form.cleaned_data)
+                cleaned_data.pop("media_public")
                 
+                media_input_type = content_form.cleaned_data["media_input_type"]
                 
-                if form_status != "error":
-                    #try:
+                if media_input_type == "none":
+                    media = None
+                elif media_input_type == "link":
+                    media = content_form.cleaned_data["media_obj"]
+                    created = False
+                elif media_input_type == "create":
                     del cleaned_data["media_file"]
                     if not cleaned_data['videopath']:
                         cleaned_data['videopath'] = settings.STREAM_URL
+                    # if the source is already http:// or rtmp:// we don't have to add STREAM_URL
+                    if cleaned_data['src'].startswith("rtmp://") or cleaned_data['src'].startswith("http://"):
+                        cleaned_data['videopath'] = ''
+                    media, created = Media.objects.get_or_create(src=cleaned_data['src'], defaults=cleaned_data) #@UndefinedVariable
+                elif media_input_type == "url" or media_input_type == "upload" :
+                    # copy file
+                    #complet src
+                    destination_file = None
+                    source_file = None
+                    try:
+                        if media_input_type == "url":
+                            url = cleaned_data["external_src_url"]
+                            source_file = urllib2.urlopen(url)
+                            source_filename = source_file.info().get('Content-Disposition', None)
+                            if not source_filename:
+                                source_filename = urlparse.urlparse(url).path.rstrip("/").split('/')[-1]
+                        elif media_input_type == "upload":
+                            #source_file = request.FILES['media-media_file']
+                            # At this point the file has already be uploaded thanks to the upload view, and original file name is sent through a post var
+                            source_filename = request.POST["media-local_file_name"]
+                        
+                        source_filename = ldt_utils_path.sanitize_filename(source_filename)
+                        destination_filepath = os.path.join(settings.STREAM_PATH, source_filename)
+                        base_source_filename = source_filename
+                        extension = base_source_filename.split(".")[-1]
+                        if extension == base_source_filename:
+                            extension = ""
+                            base_basename_filename = base_source_filename
+                        else:
+                            base_basename_filename = base_source_filename[:-1 * (len(extension) + 1)]
+                        i = 0
+                        
+                        while os.path.exists(destination_filepath):
+                            base_source_filename = "%s.%d.%s" % (base_basename_filename, i, extension)
+                            destination_filepath = os.path.join(settings.STREAM_PATH, base_source_filename)
+                            i += 1
+                        
+                        if media_input_type == "url":
+                            # we upload the file if we are in url case
+                            destination_file = open(destination_filepath, "wb")
+                            chunck = source_file.read(2048)
+                            while chunck:
+                                destination_file.write(chunck)
+                                chunck = source_file.read(2048)
+                            
+                        elif media_input_type == "upload":
+                            # The media file has been uploaded in the session temp folder 
+                            # so we just have to move to the regular folder and rename it.
+                            if os.path.exists(os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", source_filename)):
+                                os.rename(os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", source_filename), os.path.join(settings.STREAM_PATH, base_source_filename))
+                        
+                        
+                        src_prefix = settings.STREAM_SRC_PREFIX.rstrip("/")
+                        if len(src_prefix) > 0:
+                            cleaned_data["src"] = src_prefix + "/" + base_source_filename
+                        else:
+                            cleaned_data["src"] = base_source_filename
+                        
+                        
+                    except Exception as inst:
+                        logging.debug("write_content_base : POST error when processing file:" + str(inst)) #@UndefinedVariable
+                        form_status = "error"
+                        #set error for form
+                        if media_input_type == "url":
+                            errors = media_form._errors.setdefault("external_src_url", ErrorList())
+                            errors.append(_("Problem when downloading file from url : ") + url)
+                        elif media_input_type == "upload":
+                            errors = media_form._errors.setdefault("media_file", ErrorList())
+                            errors.append(_("Problem when uploading file : ") + str(inst))
+                    finally:
+                        if media_input_type == "url":
+                            if destination_file:
+                                destination_file.close()
+                            if source_file:
+                                source_file.close()
+                    
+                    
+                    if form_status != "error":
+                        #try:
+                        del cleaned_data["media_file"]
+                        if not cleaned_data['videopath']:
+                            cleaned_data['videopath'] = settings.STREAM_URL
+                        mimetype = cleaned_data.get('mimetype_field', None)
+                        if not mimetype:
+                            mimetype = mimetypes.guess_type(cleaned_data['src'])
+                        cleaned_data['mimetype_field'] = mimetype
+                        media, created = Media.safe_objects.get_or_create(src=cleaned_data['src'], defaults=cleaned_data) #@UndefinedVariable
+                        cached_assign('view_media', request.user, media)
+                    else:
+                        media = None
+                        
+    
+                if media and not created:
+                    for attribute in ('external_id', 'external_permalink', 'external_publication_url', 'external_src_url', 'media_creation_date', 'videopath', 'duration', 'description', 'title', 'front_project'):
+                        setattr(media, attribute, cleaned_data.get(attribute))
                     mimetype = cleaned_data.get('mimetype_field', None)
                     if not mimetype:
-                        mimetype = mimetypes.guess_type(cleaned_data['src'])
-                    cleaned_data['mimetype_field'] = mimetype
-                    media, created = Media.safe_objects.get_or_create(src=cleaned_data['src'], defaults=cleaned_data) #@UndefinedVariable
+                        mimetype = mimetypes.guess_type(media.src)
+                    media.mimetype_field = mimetype
                     cached_assign('view_media', request.user, media)
-                else:
-                    media = None
-                    
-
-            if media and not created:
-                for attribute in ('external_id', 'external_permalink', 'external_publication_url', 'external_src_url', 'media_creation_date', 'videopath', 'duration', 'description', 'title', 'front_project'):
-                    setattr(media, attribute, cleaned_data.get(attribute))
-                mimetype = cleaned_data.get('mimetype_field', None)
-                if not mimetype:
-                    mimetype = mimetypes.guess_type(media.src)
-                media.mimetype_field = mimetype
-                cached_assign('view_media', request.user, media)
-                cached_assign('change_media', request.user, media)
-                media.save()
-            
-            if form_status != "error": 
-                content_defaults = {}
-                content_defaults.update(content_form.cleaned_data)
-                content_defaults['media_obj'] = media
-                               
-                for key in ["media_input_type", "groups", "is_public", "read_list", "write_list", "share" ]:
-                    del content_defaults[key]
-                     
-                content, created = Content.safe_objects.get_or_create(iri_id=content_form.cleaned_data['iri_id'], defaults=content_defaults) #@UndefinedVariable
-                
-                if not created and not request.user.has_perm('ldt_utils.change_content', content):
-                    raise AttributeError("%s is not allowed to change content %s" % (request.user, content))
-                
-                cached_assign('change_content', request.user, content)
-                cached_assign('view_content', request.user, content)
-                everyone = Group.objects.get(name=settings.PUBLIC_GROUP_NAME)
+                    cached_assign('change_media', request.user, media)
+                    media.save()
                 
-                if media_form.cleaned_data['media_public']:
-                    cached_assign('view_content', everyone, content)
-                    if media:
-                        cached_assign('view_media', everyone, media)
-                else:
-                    remove_perm('ldt_utils.view_media', everyone, media)
-                    if media:
-                        assign_perm_to_obj(media, content_form.cleaned_data['read_list'], content_form.cleaned_data['write_list'], request.user)
-                    assign_perm_to_obj(content, content_form.cleaned_data['read_list'], content_form.cleaned_data['write_list'], request.user)
-                    if content_form.cleaned_data['is_public']:
+                if form_status != "error": 
+                    content_defaults = {}
+                    content_defaults.update(content_form.cleaned_data)
+                    content_defaults['media_obj'] = media
+                                   
+                    for key in ["media_input_type", "groups", "is_public", "read_list", "write_list", "share" ]:
+                        del content_defaults[key]
+                         
+                    content, created = Content.safe_objects.get_or_create(iri_id=content_form.cleaned_data['iri_id'], defaults=content_defaults) #@UndefinedVariable
+                    
+                    if not created and not request.user.has_perm('ldt_utils.change_content', content):
+                        raise AttributeError("%s is not allowed to change content %s" % (request.user, content))
+                    
+                    cached_assign('change_content', request.user, content)
+                    cached_assign('view_content', request.user, content)
+                    everyone = Group.objects.get(name=settings.PUBLIC_GROUP_NAME)
+                    
+                    if media_form.cleaned_data['media_public']:
                         cached_assign('view_content', everyone, content)
+                        if media:
+                            cached_assign('view_media', everyone, media)
                     else:
-                        remove_perm('ldt_utils.view_content', everyone, content)
-                
-                if not created:
-                    for attribute in ('iriurl', 'title', 'description', 'duration', 'content_creation_date', 'tags', 'media_obj'):
-                        setattr(content, attribute, content_defaults[attribute])
-                        
-                    if request.user.is_staff and content_defaults.has_key('front_project'):
-                        content.front_project = content_defaults['front_project']
+                        remove_perm('ldt_utils.view_media', everyone, media)
+                        if media:
+                            assign_perm_to_obj(media, content_form.cleaned_data['read_list'], content_form.cleaned_data['write_list'], request.user)
+                        assign_perm_to_obj(content, content_form.cleaned_data['read_list'], content_form.cleaned_data['write_list'], request.user)
+                        if content_form.cleaned_data['is_public']:
+                            cached_assign('view_content', everyone, content)
+                        else:
+                            remove_perm('ldt_utils.view_content', everyone, content)
                     
-                content.save()
-                picture_form.model = content
-                picture_form.save()  
-                form_status = 'saved'
-                media_form = MediaForm(instance=media, prefix="media")
-                content_form = ContentForm(instance=content, prefix="content")
-                picture_form = PictureForm()
-        else:
-            form_status = 'error'
-    else:
-        form_status = 'empty'
-        initial_c = { 'media_input_type':"link"}
-        initial_m = {}
-        if instance_media:
-            initial_m['media_public'] = instance_media.is_public
+                    if not created:
+                        for attribute in ('iriurl', 'title', 'description', 'duration', 'content_creation_date', 'tags', 'media_obj'):
+                            setattr(content, attribute, content_defaults[attribute])
+                            
+                        if request.user.is_staff and content_defaults.has_key('front_project'):
+                            content.front_project = content_defaults['front_project']
+                        
+                    content.save()
+                    picture_form.model = content
+                    picture_form.save()  
+                    form_status = 'saved'
+                    media_form = MediaForm(instance=media, prefix="media")
+                    content_form = ContentForm(instance=content, prefix="content")
+                    picture_form = PictureForm()
+            else:
+                form_status = 'error'
         else:
-            initial_m['media_public'] = True
-        if instance_content:
-            initial_c['is_public'] = instance_content.is_public
-        else:
-            initial_c['is_public'] = True
-        content_form = ContentForm(prefix="content", instance=instance_content, initial=initial_c)
-        media_form = MediaForm(prefix="media", instance=instance_media, initial=initial_m) 
-        picture_form = PictureForm() 
-                
-        if instance_content is not None:
-            content_form.media_input_type = "link"
-                   
-            if request.user.is_staff:
-                content_form.fields['front_project'].queryset = Project.objects.filter(contents__in=[instance_content])
-                
-    return content_form, media_form, picture_form, form_status, current_front_project
+            form_status = 'empty'
+            initial_c = { 'media_input_type':"link"}
+            initial_m = {}
+            if instance_media:
+                initial_m['media_public'] = instance_media.is_public
+            else:
+                initial_m['media_public'] = True
+            if instance_content:
+                initial_c['is_public'] = instance_content.is_public
+            else:
+                initial_c['is_public'] = True
+            content_form = ContentForm(prefix="content", instance=instance_content, initial=initial_c)
+            media_form = MediaForm(prefix="media", instance=instance_media, initial=initial_m) 
+            picture_form = PictureForm() 
+                    
+            if instance_content is not None:
+                content_form.media_input_type = "link"
+                       
+                if request.user.is_staff:
+                    content_form.fields['front_project'].queryset = Project.objects.filter(contents__in=[instance_content])
+    except:
+        transaction.rollback()
+        errors_transaction.append(_("Content creation failure"))
+        return False, False, False, False, False, errors_transaction
+    else:
+        #Try to make sure the commit succeeded or not.
+        try:
+            transaction.commit()
+        except:
+            transaction.rollback()
+            errors_transaction.append(_("Commit of the content creation failed"))
+            return False, False, False, False, False, errors_transaction
+    return content_form, media_form, picture_form, form_status, current_front_project, errors_transaction
 
 @login_required
 def write_content(request, iri_id=None):  
     submit_action = request.REQUEST.get("submit_button", False) 
     member_list = admin_list = []
     current_front_project = None
+    deleted = None
     
-    if submit_action == "prepare_delete": 
-        errors, titles = prepare_delete_content(request, iri_id)
-        if errors and len(errors) > 0:
-            message = ungettext("There is %(count)d error when deleting content", "There are %(count)d errors when deleting content", len(errors)) % { 'count': len(errors)}
-            title_msg = _('title error deleting content')
+    if submit_action == "prepare_delete":
+        errors, titles, delete, message_temp = prepare_delete_content(request, iri_id)
+        #if there is only front_project, with no annotations, delete without confirmation
+        if delete:
+            deleted, errors_transaction = delete_content(request, iri_id)
+            content_form = ContentForm()
+            form_status="deleted"
         else:
-            message = _("Confirm delete content %(titles)s") % { 'titles' : ",".join(titles) }
-            title_msg = _("confirm delete content")
-        return render_to_response('ldt/ldt_utils/error_confirm.html', {'errors':errors, 'message':message, 'title': title_msg}, context_instance=RequestContext(request))  
+            if errors and len(errors) > 0:
+                message = ungettext("There is %(count)d error when deleting content", "There are %(count)d errors when deleting content", len(errors)) % { 'count': len(errors)}
+                title_msg = _('title error deleting content')
+            else:
+                if len(message_temp)>0:
+                    message = message_temp
+                else:    
+                    message = _("Confirm delete content %(titles)s") % { 'titles' : ",".join(titles) }
+                title_msg = _("confirm delete content")
+            return render_to_response('ldt/ldt_utils/error_confirm.html', {'errors':errors, 'message':message, 'title': title_msg}, context_instance=RequestContext(request))  
     elif submit_action == "delete":
-        delete_content(request, iri_id)
+        deleted, errors_transaction = delete_content(request, iri_id)
+        content_form = contentForm()
         form_status = "deleted"
-        content_form = ContentForm()
-        media_form = MediaForm()
-        picture_form = PictureForm()
     elif submit_action == "prepare_reset":
         errors=[]
         content_temp = Content.objects.get(iri_id=iri_id)
-        if content_temp.front_project.state==2:
-            errors.append(_("Please unpublish the front project %(title)s") % {'title':content_temp.front_project.title})
-            message=_("The front project is published")
-            title = _("confirm reset")
+        if content_temp.front_project is not None:
+            if content_temp.front_project.state==2:
+                errors.append(_("Please unpublish the front project %(title)s") % {'title':content_temp.front_project.title})
+                message=_("The front project is published")
+                title = _("confirm reset")
+            else:
+                message = _("please confirm reseting project %(title)s") % {'title':content_temp.front_project.title}
+                title = _("confirm reset")
         else:
-            message = _("please confirm reseting project %(title)s") % {'title':content_temp.front_project.title}
-            title = _("confirm reset")
+            content_temp.create_front_project()
+            return redirect("root-view")
         return render_to_response('ldt/ldt_utils/reset_confirm.html', {'errors':errors, 'message':message, 'title': title}, context_instance=RequestContext(request))
     elif submit_action == "reset":
         #TODO : verifier index de la recherche maj
@@ -328,12 +357,11 @@
         content.create_front_project()
         content.save()
         project_temp.delete()
-        form_status= 'saved'
         return HttpResponseRedirect(reverse('ldt.ldt_utils.views.content.write_content', kwargs={'iri_id':iri_id}))
     elif submit_action=="close":
         return redirect("root-view")
     else:
-        content_form, media_form, picture_form, form_status, current_front_project = write_content_base(request, iri_id)
+        content_form, media_form, picture_form, form_status, current_front_project, errors_transaction = write_content_base(request, iri_id)        
         if iri_id:
             content_temp = Content.objects.get(iri_id=iri_id)
             media_temp = content_temp.media_obj
@@ -341,6 +369,13 @@
                 member_list, admin_list = get_userlist_model(media_temp, request.user)
             else:
                 member_list, admin_list = get_userlist_model(content_temp, request.user)
+    
+    # Deleted is False if an error occurred during deletion
+    if (deleted == False)  or (content_form == False and media_form == False and picture_form == False and form_status == False and current_front_project == False):
+        message=_("An error occurred - Please try again or contact webmaster")
+        title = _("Error")
+        return render_to_response('ldt/ldt_utils/error_confirm.html', {'errors':errors_transaction, 'message':message, 'title': title}, context_instance=RequestContext(request))
+    
     if iri_id:
         create_content_action = reverse('ldt.ldt_utils.views.content.write_content', kwargs={'iri_id':iri_id})
         img_container = content_form.instance
@@ -369,6 +404,8 @@
 def prepare_delete_content(request, iri_id=None): 
     errors = []
     titles = []
+    delete = False
+    message={}
     if not iri_id:
         iri_id = request.REQUEST.get("iri_id", None)
         
@@ -377,21 +414,53 @@
             titles.append(unicode(content.title))
             projects = content.project_set.all()
             projects_nb = len(projects)
-            if projects_nb > 0:
+            if projects_nb > 1:
                 project_titles = map(lambda p: unicode(p.title), projects)
                 errors.append(ungettext("Content '%(title)s' is referenced by this project : %(project_titles)s. Please delete it beforehand.", "Content '%(title)s' is referenced by %(count)d projects: %(project_titles)s. Please delete them beforehand.", projects_nb) % {'title':unicode(content.title), 'count':projects_nb, 'project_titles': ",".join(project_titles)})
- 
-    return errors, titles
+            elif projects_nb == 1:
+                if not projects[0].has_annotations():
+                    delete = True
+                else:
+                    message = _("The project '%(project_title)s' pointing on the content '%(title)s' has several annotations. Do you want to delete the content and the project anyway ?")% {'project_title':unicode(projects[0].title), 'title':unicode(content.title)}
+            elif project_nb == 0:
+                delete = True
+    return errors, titles, delete, message
 
 
 @login_required
+@transaction.commit_manually
 def delete_content(request, iri_id=None):
+    #Delete the project, the media if exists, and the content
+    errors_transaction=[]  
     if not iri_id:
-        iri_id = request.REQUEST.get("iri_id", None)
-        
+        iri_id = request.REQUEST.get("iri_id", None)  
     if iri_id:
-        Content.safe_objects.get(iri_id=iri_id).delete()
-
+        content = Content.safe_objects.get(iri_id=iri_id)
+        try:
+            if content.media_obj is not None:
+                contents_media = Content.safe_objects.filter(media_obj = content.media_obj)
+                #check if the media is ref by severals content
+                if len(contents_media) < 2:
+                    Media.safe_objects.get(id=content.media_obj.id).delete()
+            project = content.front_project
+            content.delete()
+            if project is not None:
+                Project.safe_objects.get(ldt_id= project.ldt_id).delete()
+        except:
+            content.rollback()
+            transaction.rollback()
+            errors_transaction.append(_("Content deletion failure"))
+            return False, errors_transaction
+        else:
+            try:
+                transaction.commit()
+                content.commit()
+                return True, errors_transaction
+            except:
+                transaction.rollback()
+                content.rollback()
+                errors_transaction.append(_("Commit of the content deletion failed"))
+                return False, errors_transaction
 
 def upload(request):
     if request.method == 'POST':
Binary file src/ldt/ldt/locale/fr/LC_MESSAGES/django.mo has changed
--- a/src/ldt/ldt/locale/fr/LC_MESSAGES/django.po	Wed Oct 10 16:19:10 2012 +0200
+++ b/src/ldt/ldt/locale/fr/LC_MESSAGES/django.po	Wed Oct 10 18:00:00 2012 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-10-08 11:10+0200\n"
+"POT-Creation-Date: 2012-10-10 17:49+0200\n"
 "PO-Revision-Date: 2010-03-09 15:52+0100\n"
 "Last-Translator: Yves-Marie Haussonne <ymh.work@gmail.com>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -18,7 +18,7 @@
 
 #: .\forms\fields.py:17
 msgid "Enter a valid duration format"
-msgstr ""
+msgstr "Entrez un format de durée valide"
 
 #: .\forms\widgets.py:21
 msgid "Date"
@@ -37,7 +37,7 @@
 msgid "all"
 msgstr "tous"
 
-#: .\ldt_utils\forms.py:33 .\ldt_utils\models.py:53
+#: .\ldt_utils\forms.py:33 .\ldt_utils\models.py:57
 #: .\ldt_utils\templates\ldt\ldt_utils\content_list.html.py:69
 msgid "title"
 msgstr "titre"
@@ -62,7 +62,7 @@
 msgid "Content Tag"
 msgstr "Catégorie de contenu"
 
-#: .\ldt_utils\forms.py:52 .\ldt_utils\models.py:155
+#: .\ldt_utils\forms.py:52 .\ldt_utils\models.py:159
 msgid "content.content_creation_date"
 msgstr "Date de création du contenu"
 
@@ -94,119 +94,119 @@
 msgid "content.front_project"
 msgstr "Choisir le front project"
 
-#: .\ldt_utils\forms.py:57 .\ldt_utils\models.py:154
+#: .\ldt_utils\forms.py:57 .\ldt_utils\models.py:158
 msgid "content.duration"
 msgstr "Durée"
 
-#: .\ldt_utils\models.py:42
+#: .\ldt_utils\models.py:46
 msgid "media.external_id"
 msgstr "id externe"
 
-#: .\ldt_utils\models.py:43
+#: .\ldt_utils\models.py:47
 msgid "media.external_permalink"
 msgstr "permalien externe"
 
-#: .\ldt_utils\models.py:44
+#: .\ldt_utils\models.py:48
 msgid "media.external_publication_url"
 msgstr "url de publication externe"
 
-#: .\ldt_utils\models.py:45
+#: .\ldt_utils\models.py:49
 msgid "media.external_src_url"
 msgstr "url source"
 
-#: .\ldt_utils\models.py:46
+#: .\ldt_utils\models.py:50
 msgid "media.creation_date"
 msgstr "Date de création"
 
-#: .\ldt_utils\models.py:47
+#: .\ldt_utils\models.py:51
 msgid "media.media_creation_date"
 msgstr "Date de création du média"
 
-#: .\ldt_utils\models.py:48
+#: .\ldt_utils\models.py:52
 msgid "media.update_date"
 msgstr "Date de maj"
 
-#: .\ldt_utils\models.py:49
+#: .\ldt_utils\models.py:53
 msgid "media.videopath"
 msgstr "videopath"
 
-#: .\ldt_utils\models.py:50
+#: .\ldt_utils\models.py:54
 msgid "media.duration"
 msgstr "Durée du contenu (ms)"
 
-#: .\ldt_utils\models.py:51
+#: .\ldt_utils\models.py:55
 msgid "media.creator"
 msgstr "Créateur"
 
-#: .\ldt_utils\models.py:52
+#: .\ldt_utils\models.py:56
 msgid "description"
 msgstr "description"
 
-#: .\ldt_utils\models.py:54
+#: .\ldt_utils\models.py:58
 msgid "media.src"
 msgstr "Sources"
 
-#: .\ldt_utils\models.py:56
+#: .\ldt_utils\models.py:60
 msgid "media.src_hash"
 msgstr "Hash de la source"
 
-#: .\ldt_utils\models.py:57
+#: .\ldt_utils\models.py:61
 msgid "media.mimetype"
 msgstr "mimetype"
 
-#: .\ldt_utils\models.py:147
+#: .\ldt_utils\models.py:151
 msgid "content.iri_id"
 msgstr "iri id"
 
-#: .\ldt_utils\models.py:148
+#: .\ldt_utils\models.py:152
 msgid "content.iriurl"
 msgstr "iri url"
 
-#: .\ldt_utils\models.py:149
+#: .\ldt_utils\models.py:153
 msgid "content.creation_date"
 msgstr "date de création"
 
-#: .\ldt_utils\models.py:150
+#: .\ldt_utils\models.py:154
 msgid "content.update_date"
 msgstr "Date de maj"
 
-#: .\ldt_utils\models.py:151
+#: .\ldt_utils\models.py:155
 msgid "content.title"
 msgstr "titre"
 
-#: .\ldt_utils\models.py:152
+#: .\ldt_utils\models.py:156
 msgid "content.description"
 msgstr "Description"
 
-#: .\ldt_utils\models.py:153
+#: .\ldt_utils\models.py:157
 msgid "content.authors"
 msgstr "Auteurs"
 
-#: .\ldt_utils\models.py:472
+#: .\ldt_utils\models.py:527
 msgid "content_stat.content"
 msgstr "statistiques d'annotation"
 
-#: .\ldt_utils\models.py:473
+#: .\ldt_utils\models.py:528
 msgid "content_stat.annotations_volume"
 msgstr "Volume d'annotations"
 
-#: .\ldt_utils\models.py:474
+#: .\ldt_utils\models.py:529
 msgid "content_stat.polemics_volume"
 msgstr "Volume d'annotations"
 
-#: .\ldt_utils\models.py:475
+#: .\ldt_utils\models.py:530
 msgid "content.nb_annotation"
 msgstr "nombre d'annotations"
 
-#: .\ldt_utils\models.py:476
+#: .\ldt_utils\models.py:531
 msgid "content.last_annotated"
 msgstr "annoté pour la dernière foiss"
 
-#: .\ldt_utils\models.py:531
+#: .\ldt_utils\models.py:586
 msgid "created by"
 msgstr "créé par"
 
-#: .\ldt_utils\models.py:532
+#: .\ldt_utils\models.py:587
 msgid "changed by"
 msgstr "modifié par"
 
@@ -313,7 +313,7 @@
 msgstr "<b>Lignes</b> de temps"
 
 #: .\ldt_utils\templates\front\front_base.html.py:59
-#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:67
+#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:68
 msgid "My projects"
 msgstr "Mes projets"
 
@@ -412,8 +412,8 @@
 #: .\ldt_utils\templates\ldt\ldt_utils\groups.html.py:113
 #: .\ldt_utils\templates\ldt\ldt_utils\ldt_list.html.py:80
 #: .\ldt_utils\templates\ldt\ldt_utils\published_projects.html.py:70
-#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:55
-#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:70
+#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:56
+#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:71
 #: .\ldt_utils\templates\ldt\ldt_utils\partial\permissions.html.py:129
 #: .\templates\ldt\ldt_base.html.py:127
 msgid "search"
@@ -504,7 +504,7 @@
 msgstr "Copier votre projet"
 
 #: .\ldt_utils\templates\ldt\ldt_utils\copy_ldt.html.py:17
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:88
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:96
 msgid "Title"
 msgstr "Titre"
 
@@ -537,7 +537,7 @@
 "resoumettre le formulaire media après avoir fait les changements suivants:"
 
 #: .\ldt_utils\templates\ldt\ldt_utils\create_content.html.py:85
-#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:52
+#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:53
 msgid "Create content"
 msgstr "Créer un contenu"
 
@@ -546,7 +546,7 @@
 msgstr "Front project actuel"
 
 #: .\ldt_utils\templates\ldt\ldt_utils\create_content.html.py:127
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:141
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:149
 #: .\ldt_utils\templates\ldt\ldt_utils\reset_confirm.html.py:39
 #: .\ldt_utils\templates\ldt\ldt_utils\reset_confirm_popup.html.py:54
 msgid "reset_front_project"
@@ -558,7 +558,7 @@
 
 #: .\ldt_utils\templates\ldt\ldt_utils\create_content.html.py:145
 #: .\ldt_utils\templates\ldt\ldt_utils\create_group.html.py:101
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:137
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:145
 #: .\ldt_utils\templates\ldt\ldt_utils\error_confirm.html.py:37
 #: .\ldt_utils\templates\ldt\ldt_utils\error_confirm_popup.html.py:53
 #: .\ldt_utils\templates\ldt\ldt_utils\reset_confirm.html.py:38
@@ -615,75 +615,75 @@
 msgid "hide"
 msgstr "Réduire"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:82
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:90
 msgid "Update your project"
 msgstr "Mettre à jour votre projet Lignes de Temps"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:82
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:90
 msgid "Create your project"
 msgstr "Créer votre projet Lignes de Temps"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:93
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:101
 msgid "Description :"
 msgstr "Description :"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:98
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:106
 msgid "List of contents"
 msgstr "Liste de contenus"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:112
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:120
 #: .\ldt_utils\templates\ldt\ldt_utils\partial\contentslist.html.py:21
 #: .\ldt_utils\templates\ldt\ldt_utils\partial\projectslist.html.py:12
 #: .\ldt_utils\templates\ldt\ldt_utils\partial\publishedprojectslist.html.py:12
 msgid "name"
 msgstr "Nom"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:128
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:136
 msgid "More options"
 msgstr "Plus d'options"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:139
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:147
 msgid "delete_project"
 msgstr "Effacer"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:143
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:151
 msgid "update_project"
 msgstr "Mettre à jour"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:145
+#: .\ldt_utils\templates\ldt\ldt_utils\create_ldt.html.py:153
 msgid "create_project"
 msgstr "Créer un nouveau projet Ligne de Temps"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:57
+#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:60
 msgid "Hide Player"
 msgstr "Masquer le Lecteur métadata "
 
-#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:61
-#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:74
+#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:64
+#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:77
 msgid "Show Player"
 msgstr "Afficher le Lecteur métadata"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:71
+#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:74
 msgid "project id"
 msgstr "Identifiant du projet "
 
-#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:71
+#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:74
 msgid "Select"
 msgstr "Sélectionner"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:80
+#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:83
 msgid "popup_player"
 msgstr "Code Lecteur métadata"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:80
+#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:83
 msgid "popup_seo_body"
 msgstr "Code SEO"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:80
+#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:83
 msgid "popup_seo_meta"
 msgstr "Code balise meta en-tête"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:80
+#: .\ldt_utils\templates\ldt\ldt_utils\embed_popup.html.py:83
 msgid "popup_links"
 msgstr "Liste de liens"
 
@@ -753,7 +753,7 @@
 msgstr "Projets publiés"
 
 #: .\ldt_utils\templates\ldt\ldt_utils\published_projects.html.py:68
-#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:68
+#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:69
 msgid "Create project"
 msgstr "Créer un nouveau projet d'indexation"
 
@@ -788,7 +788,7 @@
 msgid "Page %(number)s of  %(num_pages)s"
 msgstr "Page %(number)s de  %(num_pages)s"
 
-#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:51
+#: .\ldt_utils\templates\ldt\ldt_utils\workspace_base.html.py:52
 msgid "content list"
 msgstr "Liste des contenus"
 
@@ -923,54 +923,71 @@
 msgid "Project published"
 msgstr "Projet publié"
 
-#: .\ldt_utils\views\content.py:183
+#: .\ldt_utils\views\content.py:189
 msgid "Problem when downloading file from url : "
 msgstr "Problème lors du téléchargement du fichier : "
 
-#: .\ldt_utils\views\content.py:186
+#: .\ldt_utils\views\content.py:192
 msgid "Problem when uploading file : "
 msgstr "Problème lors de l'upload du fichier : "
 
-#: .\ldt_utils\views\content.py:301
+#: .\ldt_utils\views\content.py:297
+msgid "Content creation failure"
+msgstr "Echec lors de la creation du contenu"
+
+#: .\ldt_utils\views\content.py:305
+msgid "Commit of the content creation failed"
+msgstr "Echec lors du commit de la creation du contenu"
+
+#: .\ldt_utils\views\content.py:325
 #, python-format
 msgid "There is %(count)d error when deleting content"
 msgid_plural "There are %(count)d errors when deleting content"
 msgstr[0] "Il y a %(count)d erreur lors de l'effacement du contenu"
 msgstr[1] "Il y a %(count)d erreurs lors de l'effacement du contenu"
 
-#: .\ldt_utils\views\content.py:302
+#: .\ldt_utils\views\content.py:326
 msgid "title error deleting content"
 msgstr "Erreur lors de l'effacement du contenu"
 
-#: .\ldt_utils\views\content.py:304
+#: .\ldt_utils\views\content.py:331
 #, python-format
 msgid "Confirm delete content %(titles)s"
 msgstr "Veuillez confirmer l'effacement du contenu %(titles)s"
 
-#: .\ldt_utils\views\content.py:305
+#: .\ldt_utils\views\content.py:332
 msgid "confirm delete content"
 msgstr "Confirmation effacement contenu"
 
-#: .\ldt_utils\views\content.py:317
+#: .\ldt_utils\views\content.py:343
 #, python-format
 msgid "Please unpublish the front project %(title)s"
 msgstr "Veuillez dépublier le projet : %(title)s"
 
-#: .\ldt_utils\views\content.py:318
+#: .\ldt_utils\views\content.py:344
 msgid "The front project is published"
 msgstr "Projet publié"
 
-#: .\ldt_utils\views\content.py:319 .\ldt_utils\views\content.py:322
+#: .\ldt_utils\views\content.py:345 .\ldt_utils\views\content.py:348
 #: .\ldt_utils\views\project.py:137
 msgid "confirm reset"
 msgstr "Confirmer la réinitialisation"
 
-#: .\ldt_utils\views\content.py:321 .\ldt_utils\views\project.py:136
+#: .\ldt_utils\views\content.py:347 .\ldt_utils\views\project.py:136
 #, python-format
 msgid "please confirm reseting project %(title)s"
 msgstr "Veuillez confirmer la réinitialisation du projet %(title)s"
 
-#: .\ldt_utils\views\content.py:382
+#: .\ldt_utils\views\content.py:375
+msgid "An error occurred - Please try again or contact webmaster"
+msgstr "Une erreur est apparue - Merci de réessayer ou de contacter le webmaster"
+
+#: .\ldt_utils\views\content.py:376
+#, fuzzy
+msgid "Error"
+msgstr "Erreur"
+
+#: .\ldt_utils\views\content.py:419
 #, python-format
 msgid ""
 "Content '%(title)s' is referenced by this project : %(project_titles)s. "
@@ -985,8 +1002,26 @@
 "Le contenu '%(title)s' est référencé par les projets suivants : '%"
 "(project_titles)s'.Veuillez les effacer préalablement."
 
+#: .\ldt_utils\views\content.py:424
+#, python-format
+msgid ""
+"The project '%(project_title)s' pointing on the content '%(title)s' has "
+"several annotations. Do you want to delete the content and the project "
+"anyway ?"
+msgstr ""
+"Le projet '%(project_title)s' référençant le contenu '%(title)s' comporte "
+"plusieurs annotations. Voulez vous quand même supprimer le contenu ?"
+
+#: .\ldt_utils\views\content.py:452
+msgid "Content deletion failure"
+msgstr "Echec lors de la suppression du contenu"
+
+#: .\ldt_utils\views\content.py:462
+msgid "Commit of the content deletion failed"
+msgstr "Echec lors du commit de la suppression du contenu"
+
 #: .\ldt_utils\views\json.py:40 .\ldt_utils\views\rdf.py:15
-#: .\ldt_utils\views\workspace.py:173
+#: .\ldt_utils\views\workspace.py:175
 msgid "You can not access this project"
 msgstr "vous n'avez pas l'autorisation d'accéder à ce projet"
 
@@ -1025,11 +1060,11 @@
 #: .\ldt_utils\views\workspace.py:125
 msgid ""
 "The content does not exists or you are not allowed to access this content"
-msgstr ""
+msgstr "Ce contenu n'existe pas, ou vous n'êtes pas autorisé a y acceder"
 
 #: .\ldt_utils\views\workspace.py:129
 msgid "Parameters project_id or content_id must be given in the url"
-msgstr ""
+msgstr "Les paramètres project_id et content_id doivent être passés dans l'URL"
 
 #: .\templates\admin\cms_change_form.html.py:30
 msgid "Approve page deletion"
--- a/src/ldt/ldt/security/utils.py	Wed Oct 10 16:19:10 2012 +0200
+++ b/src/ldt/ldt/security/utils.py	Wed Oct 10 18:00:00 2012 +0200
@@ -41,9 +41,10 @@
     
     new_content = c_cls.safe_objects.filter(iri_id=content.iri_id)
     if new_content:
-        media = m_cls.safe_objects.filter(id=new_content[0].media_obj.id)
-        if not media:
-            return True
+        if new_content[0].media_obj:
+            media = m_cls.safe_objects.filter(id=new_content[0].media_obj.id)
+            if not media:
+                return True
     return False
 
 def add_change_attr(user, obj_list):