src/ldt/ldt/ldt_utils/views/content.py
author grandjoncl
Mon, 24 Sep 2012 11:29:35 +0200
changeset 793 87598228cfbb
parent 792 e4180c2d11eb
child 796 7d1267aa2f55
permissions -rw-r--r--
Correction of a bug when the image link doesn't exist

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.core.files.temp import NamedTemporaryFile
from django.forms.util import ErrorList
from django.http import HttpResponse
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 

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'        
    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()
        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)
            
            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'] = ''
                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(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)
                
                if content_form.cleaned_data['is_public']:
                    cached_assign('view_content', everyone, content)
                    if media:
                        cached_assign('view_media', everyone, media)
                else:
                    remove_perm('ldt_utils.view_content', everyone, content)
                    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 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:
        form_status = 'empty'
        initial = { 'media_input_type':"link"}
        if instance_content:
            initial['is_public'] = instance_content.is_public
        else:
            initial['is_public'] = True
        
        content_form = ContentForm(prefix="content", instance=instance_content, initial=initial)
        media_form = MediaForm(prefix="media", instance=instance_media) 
        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

@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
    
    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')
        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)
        form_status = "deleted"
        content_form = ContentForm()
        media_form = MediaForm()
        picture_form = PictureForm()   
    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)
        if iri_id:
            member_list, admin_list = get_userlist_model(Content.objects.get(iri_id=iri_id), request.user)
            
    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:
        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': get_userlist(request.user), '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 = []
    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 > 0:
                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


@login_required
def delete_content(request, iri_id=None):
    if not iri_id:
        iri_id = request.REQUEST.get("iri_id", None)
        
    if iri_id:
        Content.safe_objects.get(iri_id=iri_id).delete()


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]
        
def get_duration_json(src_video, data):
    if 'youtube' in src_video:
        duration=data['data']['duration']*1000
    elif 'vimeo' in src_video:
        duration=data[0]['duration']*1000
    else:
        duration=data['duration']*1000
    return duration
    
def get_title_json(src_video, data):
    if 'youtube' in src_video:
        title=data['data']['title']
    elif 'vimeo' in src_video:
        title=data[0]['title']
    else:
        title=data['title']
    return title


def get_json(src_video):
    if 'youtube' in src_video:
        url_data=urlparse.urlparse(src_video)
        query=urlparse.parse_qs(url_data.query)
        video_id=query['v'][0]
        lien='http://gdata.youtube.com/feeds/api/videos/'+video_id+'?v=2&alt=jsonc'
    elif 'vimeo' in src_video:
        url_data=urlparse.urlparse(src_video)
        url_path=url_data.path
        video_id=(url_path.split('/'))[1]
        lien='http://vimeo.com/api/v2/video/'+video_id+'.json'
    elif 'dailymotion' in src_video:
        url_data=urlparse.urlparse(src_video)
        video_path=url_data.path
        split_path=(video_path.split('/'))[2]
        video_id=(split_path.split('_'))[0]
        lien='https://api.dailymotion.com/video/'+video_id+'?fields=id,duration,title,thumbnail_medium_url'
    resp=requests.get(lien)
    data=simplejson.loads(resp.content)
    return data
    
def get_image_json(src_video, data):
    if 'youtube' in src_video:
        lien=data['data']['thumbnail']['sqDefault']
        filename=""+data['data']['id']+".jpg"
        download_path=settings.MEDIA_ROOT+"thumbnails\contents"
        file_path = "%s\%s" % (download_path, filename)
        video_thumbnail = file(file_path, "wb")
        image_web=urllib2.urlopen(lien)
        while True:
            buf = image_web.read(65536)
            if len(buf) == 0:
                break
            video_thumbnail.write(buf)
        video_thumbnail.close()
        image_web.close()
        fileAtt=os.stat(file_path)[0]
        if (not fileAtt & stat.S_IWRITE):
            os.chmod(file_path, stat.S_IWRITE)
    return file_path