src/ldt/ldt/ldt_utils/models.py
author cavaliet
Thu, 04 Aug 2011 12:54:02 +0200
changeset 125 5c3ed9c919bb
parent 112 9886ab183b09
child 128 503e365a3af7
permissions -rwxr-xr-x
New search feature on top right corner. Advanced search included in published projects tab. Colored icons. Change css to avoid scroll on contents and projects table.

from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import ugettext_lazy as _
from ldt.core.models import Document, Owner
import ldt.indexation
from utils import (create_ldt, copy_ldt, create_empty_iri, update_iri, 
    generate_uuid)
import lucene
import lxml.etree
import mimetypes
import os.path
import tagging.fields
import uuid

class Author(models.Model):

    handle = models.CharField(max_length=512, unique=True, blank=True, null=True)
    email = models.EmailField(unique=False, blank=True, null=True)
    firstname = models.CharField(max_length=512, blank=True, null=True)
    lastname = models.CharField(max_length=512, blank=True, null=True)
    
    def __unicode__(self):
        return unicode(self.id) + " - " + self.handle + ", " + self.email + ", " + self.firstname + " " + self.lastname

class Media(models.Model):
    external_id = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('media.external_id'))
    external_permalink = models.URLField(max_length=1024, verify_exists=False, null=True, blank=True, verbose_name=_('media.external_permalink'))
    external_publication_url = models.URLField(max_length=1024, verify_exists=True, null=True, blank=True, verbose_name=_('media.external_publication_url'))
    external_src_url = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('media.external_src_url'))
    creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('media.creation_date'))
    media_creation_date = models.DateTimeField(null=True, blank=True, verbose_name=_('media.media_creation_date'))
    update_date = models.DateTimeField(auto_now=True, verbose_name=_('media.update_date'))
    videopath = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('media.videopath'))
    duration = models.IntegerField(null=True, blank=True, verbose_name=_('media.duration'))
    creator = models.ForeignKey(User, blank=True, null=True, verbose_name=_('media.creator'))
    description = models.TextField(null=True, blank=True, verbose_name=_('description'))
    title = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('title'))
    src = models.CharField(max_length=1024, unique=True, verbose_name=_('media.src'))
    mimetype_field = models.CharField(max_length=512, null=True, blank=True, verbose_name=_('media.mimetype'))
    
    def mimetype(): #@NoSelf
        def fget(self):
            if self.mimetype_field :
                return self.mimetype_field
            elif self.src:
                return mimetypes.guess_type(self.src.rstrip())
            else:
                return None
        
        def fset(self, value):
            self.mimetype_field = value
        
        return locals()
    mimetype = property(**mimetype())
    
    def stream_src(): #@NoSelf
        
        def fget(self):
            res_src = self.src.rstrip()
            if self.videopath and self.videopath.startswith("rtmp://") and "mp3:" not in res_src and "mp4:" not in res_src:
                extension = res_src.split(".")[-1]
                res_src = {
                    'flv': lambda s: s,
                    'mp3': lambda s: "%s:%s" % ("mp3", res_src[:-4]),
                    'mp4': lambda s: "%s:%s" % ("mp4", res_src),
                    'f4v': lambda s: "%s:%s" % ("mp4", res_src),
                    'mov': lambda s: "%s:%s" % ("mp4", res_src),
                }.get(extension, lambda s:s)(res_src)
            return res_src
        
        return locals()
    
    stream_src = property(**stream_src())
    
    def save(self, *args, **kwargs):
        super(Media, self).save(*args, **kwargs)
        for content in self.content_set.all():
            content.sync_iri_file()
    
    def __unicode__(self):
        strings = []
        if self.title:
            strings.append(unicode(self.title))
        else:
            strings.append(unicode(self.src))
        if self.external_id:
            strings.append(unicode(self.external_id))
        return "|".join(strings)


class ContentManager(models.Manager):
    def get_by_natural_key(self, iri_id):
        return self.get(iri_id=iri_id)

class Content(models.Model):
    objects = ContentManager()
    
    iri_id = models.CharField(max_length=1024, unique=True, default=generate_uuid, verbose_name=_('content.iri_id'))
    iriurl = models.CharField(max_length=1024, verbose_name=_('content.iriurl'))
    creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('content.creation_date'))
    update_date = models.DateTimeField(auto_now=True, verbose_name=_('content.update_date'))
    title = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('content.title'))
    description = models.TextField(null=True, blank=True, verbose_name=_('content.description'))
    authors = models.ManyToManyField(Author, blank=True, verbose_name=_('content.authors'))
    duration = models.IntegerField(null=True, blank=True, verbose_name=_('content.duration'))
    content_creation_date = models.DateTimeField(null=True, blank=True, verbose_name=_('content.content_creation_date'))
    tags = tagging.fields.TagField(max_length=2048, null=True, blank=True)
    media_obj = models.ForeignKey('Media', blank=True, null=True)
    
    class Meta:
        ordering = ["title"]
    
    def natural_key(self):
        return self.iri_id
        
    # added for import
    def get_by_natural_key(self, iri_id):
        return self.get(iri_id=iri_id)

    def get_duration(self):
        if self.duration is None:
            doc = lxml.etree.parse(self.iri_file_path())
            res = doc.xpath("/iri/body/medias/media[@id='video']/video")
            if len(res) > 0:
                try:
                    self.duration = int(res[0].get(u'dur', 0) or 0)
                except:
                    self.duration = 0
            else:
                self.duration = 0
            self.save()
        return self.duration
    
    def mimetype(): #@NoSelf
        def fget(self):
            if self.media_obj:
                return self.media_obj.mimetype
            else:
                return None
        return locals()
    
    mimetype = property(**mimetype())
    
    def delete(self):
        super(Content, self).delete()
        writer = ldt.indexation.get_writer()
        try:
            writer.deleteDocuments(lucene.Term("iri_id", self.iri_id))
            writer.commit()
        finally:
            writer.close()
        
    def sync_iri_file(self):
        # create iri file if needed
        created = False
        try:
            iri_file_path = self.iri_file_path()
            if not os.path.exists(iri_file_path):
                dir = os.path.dirname(iri_file_path)
                if not os.path.exists(dir):
                    os.makedirs(dir)
                created = True
                file = open(iri_file_path, "w")
                create_empty_iri(file, self, "IRI")
            else:
                created = False
                update_iri(iri_file_path, self, "IRI")
                
        except Exception, e:
            if created:
                if os.path.exists(iri_file_path):
                    os.remove(iri_file_path)
            raise e
        
        
    #TODO: better manage the change in .iri name and error scenario (save in temp file + rename
    def save(self, *args, **kwargs):
        
        self.sync_iri_file()        
        # update it 
        super(Content, self).save(*args, **kwargs)
    
    def __unicode__(self):
        return str(self.id) + ": " + self.iri_id
        
    def iri_url(self, web_url=settings.WEB_URL):
        if 'http' in self.iriurl or 'https' in self.iriurl:
            return self.iriurl
        else:
            return unicode(web_url) + unicode(settings.MEDIA_URL) + u"ldt/" + unicode(self.iriurl)
    
    def iri_file_path(self):
        return os.path.join(os.path.join(os.path.join(settings.MEDIA_ROOT, "ldt"), self.iri_id), os.path.basename(self.iriurl))

    def iri_url_template(self):
        return "${web_url}${media_url}ldt/" + unicode(self.iri_id) + "/" + os.path.basename(self.iriurl)


    def __get_empty_media(self):
        if settings.EMPTY_MEDIA_EXTERNALID:
            empty_media = Media.objects.get(external_id=settings.EMPTY_MEDIA_EXTERNALID)
            return empty_media
        else:
            return None
            
    
    def stream_src(): #@NoSelf
        
        def fget(self):
            if self.media_obj is not None:
                return self.media_obj.stream_src
            else:
                empty_media = self.__get_empty_media()
                if empty_media:
                    return empty_media.stream_src
                else:
                    return ""
        
        return locals()
    
    stream_src = property(**stream_src())
    
    def videopath(): #@NoSelf
        doc = """simulate videopath""" #@UnusedVariable
       
        def fget(self):
            if self.media_obj is None:
                empty_media = self.__get_empty_media()
                if empty_media:
                    return empty_media.videopath
                else:
                    return None
            else:
                return self.media_obj.videopath
           
        def fset(self, value):
            if self.media_obj is not None:
                self.media_obj.videopath = value
                      
        return locals()
       
    videopath = property(**videopath())

    def src(): #@NoSelf
        doc = """simulate videopath""" #@UnusedVariable
       
        def fget(self):
            if self.media_obj is None:
                empty_media = self.__get_empty_media()
                if empty_media:
                    return empty_media.src
                else:
                    return None
            else:
                return self.media_obj.src
           
        def fset(self, value):
            if self.media_obj is None or self.media_obj.src != value:
                media, created = Media.objects.get_or_create(src=value, defaults={'src':value})                #@UnusedVariable
                self.media_obj = media
                self.save()
                      
        return locals()
       
    src = property(**src())

    def external_id(): #@NoSelf
        doc = """simulate externalid""" #@UnusedVariable
       
        def fget(self):
            if self.media_obj is None:
                empty_media = self.__get_empty_media()
                if empty_media:
                    return empty_media.external_id
                else: 
                    return None
            else:
                return self.media_obj.external_id
           
        def fset(self, value):
            if self.media_obj is not None:
                self.media_obj.external_id = value
                      
        return locals()
       
    external_id = property(**external_id())

        
        
class Project(Document):  
    STATE_CHOICES = (
    (1, 'edition'),
    (2, 'published'),
    (3, 'moderated'),
    (4, 'rejected'),
    (5, 'deleted')
    )
    ldt_id = models.CharField(max_length=1024, unique=True)
    ldt = models.TextField(null=True)
    title = models.CharField(max_length=1024)
    contents = models.ManyToManyField(Content)
    creation_date = models.DateTimeField(auto_now_add=True)
    modification_date = models.DateTimeField(auto_now=True)
    created_by = models.CharField(_("created by"), max_length=70)
    changed_by = models.CharField(_("changed by"), max_length=70)
    state = models.IntegerField(choices=STATE_CHOICES, default=1)
    
    class Meta:
        ordering = ["title"]

    
    def __unicode__(self):
        return unicode(self.id) + u"::" + unicode(self.ldt_id) + u"::" + unicode(self.title)
    
    def get_description(self, doc=None):
        
        if doc is None:
            doc = lxml.etree.fromstring(self.ldt)
        
        res = doc.xpath("/iri/project")
        if len(res) > 0:
            return res[0].get(u'abstract')
        else:
            return None

    def stream_mode(): #@NoSelf
        def fget(self):
            modes = []
            for content in self.contents.all():
                mimetype = content.mimetype
                if mimetype:
                    mode = mimetype.split("/")[0]
                    if "audio" == mode or "video" == mode:
                        modes.append(mode)
                    else:
                        modes.append("video")
                else:
                    modes.append("video")
            def filter_video(current, item):
                if not current:
                    return item
                elif current == item:
                    return item
                else:
                    return "video"
            return reduce(filter_video, modes)
        return locals()
    
    stream_mode = property(**stream_mode())

    @staticmethod
    def create_project(user, title, contents):
        owner = Owner.objects.get(user=user) #@UndefinedVariable
        project = Project(title=title, owner=owner)
        project.ldt_id = str(uuid.uuid1()) #@UndefinedVariable
        project.created_by = user.username
        project.changed_by = user.username
        project.state = 1
        project.save()
        for content in contents:
            project.contents.add(content)
        project.save()
        return create_ldt(project, user)

    def copy_project(self, user, title):
        owner = Owner.objects.get(user=user) #@UndefinedVariable
        project = Project(title=title, owner=owner)
        project = copy_ldt(self, project, user)
        project.save()
        for content in self.contents.all():
            project.contents.add(content)
        project.save()
        return project
    
    def checkAccess(self, user):
        if (user and user.is_staff) or self.state == 2: 
            return True
        else:
            return False
        

class Segment(models.Model):
    
    project_obj = models.ForeignKey(Project, null=True)
    content = models.ForeignKey(Content)
    project_id = models.CharField(max_length=1024, unique=False, blank=True, null=True)
    iri_id = models.CharField(max_length=1024, unique=False)
    ensemble_id = models.CharField(max_length=1024, unique=False)
    cutting_id = models.CharField(max_length=1024, unique=False)    
    element_id = models.CharField(max_length=1024, unique=False)
    tags = tagging.fields.TagField(max_length=2048, null=True, blank=True, unique=False)
    title = models.CharField(max_length=2048, unique=False, null=True, blank=True)
    duration = models.IntegerField(null=True)
    start_ts = models.IntegerField(null=True)
    author = models.CharField(max_length=1024, unique=False, null=True, blank=True)
    date = models.CharField(max_length=128, unique=False, null=True, blank=True)
    abstract = models.TextField(null=True, blank=True)
    
    def __unicode__(self):
        return "/".join((unicode(self.project_id), unicode(self.iri_id), unicode(self.ensemble_id), unicode(self.cutting_id), unicode(self.element_id)))
    
    class Meta:
        unique_together = (('project_id', 'iri_id', 'ensemble_id', 'cutting_id', 'element_id'),)