src/ldt/ldt/ldt_utils/views/content.py
author rougeronj
Fri, 19 Oct 2012 16:10:22 +0200
changeset 883 0d9c00ae2755
parent 876 8fd46e270e23
parent 882 9520fb2810e2
child 898 94ad1a394732
permissions -rw-r--r--
Merge with 2ade832d146239bf9f24105a93cf7abb023f3daa

from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group
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
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.utils.translation import ugettext as _, ungettext
from ldt.ldt_utils.forms import ContentForm, MediaForm
from guardian.shortcuts import remove_perm
from ldt.ldt_utils.models import Content, Media, Project
from ldt.security.utils import assign_perm_to_obj, add_change_attr, get_userlist, get_userlist_model
from ldt.security.cache import cached_assign
from ldt.user.forms import PictureForm
from tagging.models import Tag, TaggedItem
import ldt.utils.path as ldt_utils_path
import logging
import mimetypes
import os, stat
import urllib2
import subprocess
import re
import datetime
import math
import requests
import django.utils.simplejson as simplejson
import urlparse  
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
        instance_media = instance_content.media_obj
        logging.debug("write_content_base : valid form: for instance : media -> " + repr(instance_media) + " content : for instance : " + repr(instance_content)) #@UndefinedVariable
    else:
        logging.debug("No iri_id") #@UndefinedVariable
        instance_content = None
        instance_media = None
    current_front_project = None
    if instance_content:
        current_front_project = instance_content.front_project
    form_status = 'none'
    errors_transaction = []
    transaction_succeed = True
    
    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
            
        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)) #@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 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'] = ''
                try:
                    media, created = Media.objects.get_or_create(src=cleaned_data['src'], defaults=cleaned_data) #@UndefinedVariable
                except:
                    transaction_succeed = False
            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)
                    except:
                        transaction_succeed = False
                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]
                
                try:   
                    content, created = Content.safe_objects.get_or_create(iri_id=content_form.cleaned_data['iri_id'], defaults=content_defaults) #@UndefinedVariable
                except:
                    transaction_succeed = False
                    
                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_media', everyone, media)
                    assign_perm_to_obj(content, content_form.cleaned_data['read_list'], content_form.cleaned_data['write_list'], request.user)
                    if media:
                        assign_perm_to_obj(media, 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)
                
                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']
                
                try:
                    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()
                except:
                    transaction_succeed = False
        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
        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])
    
    if transaction_succeed:
        #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
    else:
        transaction.rollback()
        errors_transaction.append(_("Content creation failure"))
        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, message_temp = 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')
        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":
        deleted, errors_transaction = delete_content(request, iri_id)
        content_form = ContentForm()
        form_status = "deleted"
    elif submit_action == "prepare_reset":
        errors=[]
        content_temp = Content.objects.get(iri_id=iri_id)
        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:
            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
        content = Content.objects.get(iri_id=iri_id)
        project_temp = content.front_project
        content.create_front_project()
        content.save()
        project_temp.delete()
        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, 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
            if media_temp:
                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

    else:
        create_content_action = reverse('ldt.ldt_utils.views.content.write_content')
        img_container = ''
    
    session_key = request.COOKIES[settings.SESSION_COOKIE_NAME]
    cookie_name = settings.SESSION_COOKIE_NAME
    # Media.safe_objects.all() does not return the good list of media, so we get them from the Content.safe_objects
    content_form.fields["media_obj"].queryset = Media.objects.filter(id__in=Content.safe_objects.values_list('media_obj', flat=True))
    
    if form_status=='saved' or form_status=='deleted':
        return redirect("root-view") 
    else:
        group_list = Group.objects.all()
        group_list = group_list.exclude(name=settings.PUBLIC_GROUP_NAME)
        group_list = [{'name': u.name, 'id': u.id, 'type': 'group'} for u in group_list[0:settings.MAX_USERS_SEARCH]]
        elem_list = get_userlist(request.user) + group_list
        return render_to_response('ldt/ldt_utils/create_content.html', {'content_form': content_form, 'media_form': media_form, 'form_status': form_status, 'create_content_': create_content_action,
                                                                    'elem_list':elem_list, 'member_list': member_list, 'admin_list': admin_list,  'iri_id': iri_id, 'session_key':session_key,
                                                                    'cookie_name':cookie_name, 'img_container': img_container, 'profile_picture_form': picture_form,
                                                                    'current_front_project':current_front_project}, context_instance=RequestContext(request))
@login_required
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)
        
    if iri_id:
        for content in Content.safe_objects.filter(iri_id=iri_id): 
            titles.append(unicode(content.title))
            projects = content.project_set.all()
            projects_nb = len(projects)
            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)})
            elif projects_nb == 1:
                if projects[0].has_annotations():
                    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)}
    return errors, titles, 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)  
    if iri_id:
        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':
        for field_name in request.FILES:
            # We get the file name
            source_file = request.FILES[field_name]
            source_filename = source_file.name
            # We sanitize the file name : no space, only lower case.
            source_filename = ldt_utils_path.sanitize_filename(source_filename)
            # We create the session temp folder if necessary
            if not os.path.exists(os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME])):
                os.makedirs(os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME]))
            destination_filepath = os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", source_filename)
            # We delete the existing file if necessary
            if os.path.exists(destination_filepath):
                os.remove(destination_filepath)
            
            destination_file = open(destination_filepath, "wb")
            
            for chunk in source_file.chunks():
                destination_file.write(chunk)
            destination_file.close()
            
        # indicate that everything is OK for SWFUpload
        return HttpResponse("ok", mimetype="text/plain")
    else:
        return HttpResponse("notok", mimetype="text/plain")

def remove_temp_file(request):
    # The filename arrives with a GET var.
    file_path = os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", ldt_utils_path.sanitize_filename(request.GET["filename"]))
    if os.path.exists(file_path):
        os.remove(file_path)
    return HttpResponse("remove ok", mimetype="text/plain")

def get_duration(request):
    try:
        # The filename arrives with a GET var.
        file_path = os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", ldt_utils_path.sanitize_filename(request.GET["filename"]))
        if hasattr(settings, 'FFMPEG_PATH') and os.path.exists(file_path):
            output = str(subprocess.Popen([settings.FFMPEG_PATH, "-i", file_path], stderr=subprocess.PIPE).communicate()[1])
            m = re.search("Duration:\s*?([\d.:]+)", output, re.M)
            dur_arr = m.group(1).split(":")
            td = datetime.timedelta(hours=int(dur_arr[0]), minutes=int(dur_arr[1]), seconds=float(dur_arr[2]))
            str_duration = str((td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / 10 ** 3)
            return HttpResponse(str_duration, mimetype="text/plain")
        else:
            return HttpResponse("", mimetype="text/plain")
    except Exception as inst:
        return HttpResponse(str(inst), mimetype="text/plain")

    
@login_required
def contents_filter(request, filter_c): 
    if filter_c and len(filter_c) > 0 and filter_c[0] == '_':
        filter_c = filter_c[1:]
    
    num_page = 0
    if request.GET.has_key('num_page'):
        num_page = int(request.GET["num_page"])
    tag_filter = ""
    if request.GET.has_key('tag_filter'):
        tag_filter = request.GET["tag_filter"]
    
    # We paginate the content list, in case of filter_c or not
    if filter_c and not tag_filter :
        content_nb = Content.safe_objects.filter(title__icontains=filter_c).count()
        nb_ct_pages = int(math.ceil(content_nb / settings.LDT_MAX_CONTENTS_PER_PAGE)) + 1
        content_list = Content.safe_objects.filter(title__icontains=filter_c)[(num_page*settings.LDT_MAX_CONTENTS_PER_PAGE):((num_page+1)*settings.LDT_MAX_CONTENTS_PER_PAGE)] #@UndefinedVariable
    elif filter_c and tag_filter :
        #TaggedItem.objects.get_by_model(Content.objects.all(), '"'+tag_filter+'"')
        content_nb = TaggedItem.objects.get_by_model(Content.safe_objects.filter(title__icontains=filter_c), '"'+tag_filter+'"').count()
        nb_ct_pages = int(math.ceil(content_nb / settings.LDT_MAX_CONTENTS_PER_PAGE)) + 1
        content_list = TaggedItem.objects.get_by_model(Content.safe_objects.filter(title__icontains=filter_c), '"'+tag_filter+'"')[(num_page*settings.LDT_MAX_CONTENTS_PER_PAGE):((num_page+1)*settings.LDT_MAX_CONTENTS_PER_PAGE)] #@UndefinedVariable
    elif tag_filter and not filter_c:
        content_nb = TaggedItem.objects.get_by_model(Content.safe_objects.all(), '"'+tag_filter+'"').count()
        nb_ct_pages = int(math.ceil(content_nb / settings.LDT_MAX_CONTENTS_PER_PAGE)) +1
        content_list = TaggedItem.objects.get_by_model(Content.safe_objects.all(), '"'+tag_filter+'"')[(num_page*settings.LDT_MAX_CONTENTS_PER_PAGE):((num_page+1)*settings.LDT_MAX_CONTENTS_PER_PAGE)] #@UndefinedVariable
    else:
        content_nb, nb_ct_pages, content_list = get_contents_page(num_page, request.user)
    #Change attributes with object permissions
    content_list = add_change_attr(request.user, content_list)
    # Get the all tags list
    tag_cloud = get_content_tags()
    
    is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
    return render_to_response("ldt/ldt_utils/partial/contentslist.html",
                              {'contents': content_list, 'nb_ct_pages': nb_ct_pages, 'content_nb': content_nb, 'current_content_page':float(num_page),
                               'tag_cloud': tag_cloud, 'current_content_tag':tag_filter, 'is_gecko': is_gecko
                               },
                              context_instance=RequestContext(request))
    

def get_contents_page(num_page, user):
    content_nb = float(Content.safe_objects.count()) #@UndefinedVariable
    nb_ct_pages = int(math.ceil(content_nb / settings.LDT_MAX_CONTENTS_PER_PAGE))
    content_list = add_change_attr(user, Content.safe_objects.all()[(num_page*settings.LDT_MAX_CONTENTS_PER_PAGE):((num_page+1)*settings.LDT_MAX_CONTENTS_PER_PAGE)]) #@UndefinedVariable
    return content_nb, nb_ct_pages, content_list


def get_content_tags(limit=None, steps=10):
    if limit is None:
        return Tag.objects.cloud_for_model(Content, steps=steps)
    else :
        return Tag.objects.cloud_for_model(Content, steps=steps)[:limit]