web/ldt/ldt_utils/models.py
changeset 1 eb9188f2ee4f
child 9 505a1c4cac67
equal deleted inserted replaced
0:85b071fb75b2 1:eb9188f2ee4f
       
     1 from django.conf import settings
       
     2 from django.db import models
       
     3 from django.utils.translation import ugettext_lazy as _
       
     4 from ldt.core.models import Document, Owner
       
     5 from django.contrib.auth.models import User
       
     6 import tagging.fields
       
     7 from utils import create_ldt, copy_ldt, create_empty_iri, update_iri, generate_uuid
       
     8 import lxml.etree
       
     9 import os.path
       
    10 import uuid
       
    11 import lucene
       
    12 from ldt.ldt_utils import STORE, ANALYZER
       
    13 
       
    14 class Author(models.Model):
       
    15 
       
    16     handle = models.CharField(max_length=512, unique=True, blank=True, null=True)
       
    17     email = models.EmailField(unique=False, blank=True, null=True)
       
    18     firstname = models.CharField(max_length=512, blank=True, null=True)
       
    19     lastname = models.CharField(max_length=512, blank=True, null=True)
       
    20     
       
    21     def __unicode__(self):
       
    22         return unicode(self.id) + " - " + self.handle + ", " + self.email + ", " + self.firstname + " " + self.lastname
       
    23 
       
    24 class Media(models.Model):
       
    25     external_id = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('media.external_id'))
       
    26     external_permalink = models.URLField(max_length=1024, verify_exists=False, null=True, blank=True, verbose_name=_('media.external_permalink'))
       
    27     external_publication_url = models.URLField(max_length=1024, verify_exists=True, null=True, blank=True, verbose_name=_('media.external_publication_url'))
       
    28     external_src_url = models.URLField(max_length=1024, verify_exists=False, null=True, blank=True, verbose_name=_('media.external_src_url'))
       
    29     creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('media.creation_date'))
       
    30     media_creation_date = models.DateTimeField(null=True, blank=True, verbose_name=_('media.media_creation_date'))
       
    31     update_date = models.DateTimeField(auto_now=True, verbose_name=_('media.update_date'))
       
    32     videopath = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('media.videopath'))
       
    33     duration = models.IntegerField(null=True, blank=True, verbose_name=_('media.duration'))
       
    34     creator = models.ForeignKey(User, blank=True, null=True, verbose_name=_('media.creator'))
       
    35     description = models.TextField(null=True, blank=True, verbose_name=_('description'))
       
    36     title = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('title'))
       
    37     src = models.CharField(max_length=1024, unique=True, verbose_name=_('media.src'))
       
    38     
       
    39     def stream_src():
       
    40         
       
    41         def fget(self):
       
    42             res_src = self.src.rstrip()
       
    43             if self.videopath and self.videopath.startswith("rtmp://"):
       
    44                 extension = res_src.split(".")[-1]
       
    45                 res_src = {
       
    46                     'flv': lambda s: s,
       
    47                     'mp3': lambda s: "%s:%s" %("mp3",res_src[:-4]),
       
    48                     'mp4': lambda s: "%s:%s" %("mp4",res_src[:-4]),
       
    49                     'f4v': lambda s: "%s:%s" %("mp4",res_src[:-4]),
       
    50                 }.get(extension, lambda s:s)(res_src.lower())
       
    51             return res_src
       
    52         
       
    53         return locals()
       
    54     
       
    55     stream_src = property(**stream_src())    
       
    56     
       
    57     def save(self, *args, **kwargs):
       
    58         super(Media, self).save(*args, **kwargs)
       
    59         for content in self.content_set.all():
       
    60             content.sync_iri_file()
       
    61     
       
    62     def __unicode__(self):
       
    63         strings = []
       
    64         if self.title:
       
    65             strings.append(unicode(self.title))
       
    66         else:
       
    67             strings.append(unicode(self.src))
       
    68         if self.external_id:
       
    69             strings.append(unicode(self.external_id))
       
    70         return "|".join(strings)
       
    71 
       
    72 
       
    73 class Content(models.Model):
       
    74     iri_id = models.CharField(max_length=1024, unique=True, default=generate_uuid, verbose_name=_('content.iri_id'))
       
    75     iriurl = models.CharField(max_length=1024, verbose_name=_('content.iriurl'))
       
    76     creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('content.creation_date'))
       
    77     update_date = models.DateTimeField(auto_now=True, verbose_name=_('content.update_date'))
       
    78     title = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('content.title'))
       
    79     description = models.TextField(null=True, blank=True, verbose_name=_('content.description'))
       
    80     authors = models.ManyToManyField(Author, blank=True, verbose_name=_('content.authors'))
       
    81     duration = models.IntegerField(null=True, blank=True, verbose_name=_('content.duration'))
       
    82     content_creation_date = models.DateTimeField(null=True, blank=True, verbose_name=_('content.content_creation_date'))
       
    83     tags = tagging.fields.TagField(max_length=2048, null=True, blank=True )
       
    84     media_obj = models.ForeignKey('Media', blank=True, null=True )
       
    85     
       
    86     class Meta:
       
    87         ordering = ["title"]
       
    88 
       
    89     def get_duration(self):
       
    90         if self.duration is None:
       
    91             doc = lxml.etree.parse(self.iri_file_path())
       
    92             res = doc.xpath("/iri/body/medias/media[@id='video']/video")
       
    93             if len(res) > 0:
       
    94                 try:
       
    95                     self.duration = int(res[0].get(u'dur',0) or 0)
       
    96                 except:
       
    97                     self.duration = 0
       
    98             else:
       
    99                 self.duration = 0
       
   100             self.save()
       
   101         return self.duration
       
   102     
       
   103     def delete(self):
       
   104         super(Content, self).delete()
       
   105         writer = lucene.IndexWriter(STORE, ANALYZER, True, lucene.IndexWriter.MaxFieldLength.UNLIMITED)
       
   106         writer.deleteDocuments(lucene.Term("iri_id", self.iri_id))
       
   107         writer.commit()
       
   108         
       
   109     def sync_iri_file(self):
       
   110         # create iri file if needed
       
   111         created = False
       
   112         try:
       
   113             iri_file_path = self.iri_file_path()
       
   114             if not os.path.exists(iri_file_path):
       
   115                 dir = os.path.dirname(iri_file_path)
       
   116                 if not os.path.exists(dir):
       
   117                     os.makedirs(dir)
       
   118                 created = True
       
   119                 file = open(iri_file_path,"w")
       
   120                 create_empty_iri(file, self, "IRI")
       
   121             else:
       
   122                 created = False
       
   123                 update_iri(iri_file_path, self, "IRI")
       
   124                 
       
   125         except Exception, e:
       
   126             if created:
       
   127                 if os.path.exists(iri_file_path):
       
   128                     os.remove(iri_file_path)
       
   129             raise e
       
   130         
       
   131         
       
   132     #TODO: better manage the change in .iri name and error scenario (save in temp file + rename
       
   133     def save(self, *args, **kwargs):
       
   134         
       
   135         self.sync_iri_file()        
       
   136         # update it 
       
   137         super(Content, self).save(*args, **kwargs)
       
   138     
       
   139     def __unicode__(self):
       
   140         return str(self.id) + ": " + self.iri_id
       
   141         
       
   142     def iri_url(self, web_url=settings.WEB_URL):
       
   143         if 'http' in self.iriurl or 'https' in self.iriurl:
       
   144             return self.iriurl
       
   145         else:
       
   146             return unicode(web_url) + unicode(settings.MEDIA_URL)+u"media/ldt/"+unicode(self.iriurl)
       
   147     
       
   148     def iri_file_path(self):
       
   149         return os.path.join(os.path.join(os.path.join(os.path.join(settings.MEDIA_ROOT, "media"), "ldt"), self.iri_id), os.path.basename(self.iriurl))
       
   150 
       
   151     def iri_url_template(self):
       
   152         return "${web_url}${media_url}media/ldt/" + unicode(self.iri_id) + "/" + os.path.basename(self.iriurl)
       
   153 
       
   154 
       
   155     def __get_empty_media(self):
       
   156         if settings.EMPTY_MEDIA_EXTERNALID:
       
   157             empty_media = Media.objects.get(externalid=settings.EMPTY_MEDIA_EXTERNALID)
       
   158             return empty_media
       
   159         else:
       
   160             return None
       
   161             
       
   162     
       
   163     def stream_src():
       
   164         
       
   165         def fget(self):
       
   166             if self.media_obj is not None:
       
   167                 return self.media_obj.stream_src
       
   168             else:
       
   169                 return None
       
   170         
       
   171         return locals()
       
   172     
       
   173     stream_src = property(**stream_src())
       
   174     
       
   175     def videopath(): #@NoSelf
       
   176         doc = """simulate videopath""" #@UnusedVariable
       
   177        
       
   178         def fget(self):
       
   179             if self.media_obj is None:
       
   180                 empty_media = self.__get_empty_media()
       
   181                 if empty_media:
       
   182                     return empty_media.videopath
       
   183                 else: 
       
   184                     return None
       
   185             else:
       
   186                 return self.media_obj.videopath
       
   187            
       
   188         def fset(self, value):
       
   189             if self.media_obj is not None:
       
   190                 self.media_obj.videopath = value
       
   191                       
       
   192         return locals()
       
   193        
       
   194     videopath = property(**videopath())
       
   195 
       
   196     def src(): #@NoSelf
       
   197         doc = """simulate videopath""" #@UnusedVariable
       
   198        
       
   199         def fget(self):
       
   200             if self.media_obj is None:
       
   201                 empty_media = self.__get_empty_media()
       
   202                 if empty_media:
       
   203                     return empty_media.src
       
   204                 else:
       
   205                     return None
       
   206             else:
       
   207                 return self.media_obj.src
       
   208            
       
   209         def fset(self, value):
       
   210             if self.media_obj is None or self.media_obj.src != value:
       
   211                 media, created = Media.objects.get_or_create(src=value, defaults={'src':value})                
       
   212                 self.media_obj = media
       
   213                 self.save()
       
   214                       
       
   215         return locals()
       
   216        
       
   217     src = property(**src())
       
   218 
       
   219     def external_id(): #@NoSelf
       
   220         doc = """simulate externalid""" #@UnusedVariable
       
   221        
       
   222         def fget(self):
       
   223             if self.media_obj is None:
       
   224                 empty_media = self.__get_empty_media()
       
   225                 if empty_media:
       
   226                     return empty_media.external_id
       
   227                 else: 
       
   228                     return None
       
   229             else:
       
   230                 return self.media_obj.external_id
       
   231            
       
   232         def fset(self, value):
       
   233             if self.media_obj is not None:
       
   234                 self.media_obj.external_id = value
       
   235                       
       
   236         return locals()
       
   237        
       
   238     external_id = property(**external_id())
       
   239 
       
   240         
       
   241         
       
   242 class Project(Document):  
       
   243     STATE_CHOICES=(
       
   244     (1, 'edition'),
       
   245     (2, 'published'),
       
   246     (3, 'moderated'),
       
   247     (4, 'rejected'),
       
   248     (5, 'deleted')
       
   249     )
       
   250     ldt_id = models.CharField(max_length=1024, unique=True)
       
   251     ldt = models.TextField(null=True)
       
   252     title = models.CharField(max_length=1024)
       
   253     contents = models.ManyToManyField(Content)
       
   254     creation_date = models.DateTimeField(auto_now_add=True)
       
   255     modification_date = models.DateTimeField(auto_now=True)
       
   256     created_by = models.CharField(_("created by"), max_length=70)
       
   257     changed_by = models.CharField(_("changed by"), max_length=70)
       
   258     state = models.IntegerField(choices=STATE_CHOICES, default=1)
       
   259     
       
   260     class Meta:
       
   261         ordering = ["title"]
       
   262 
       
   263     
       
   264     def __unicode__(self):
       
   265         return unicode(self.id) + u": " + unicode(self.ldt_id)
       
   266     
       
   267     def get_description(self, doc=None):
       
   268         
       
   269         if doc is None:
       
   270             doc = lxml.etree.fromstring(self.ldt)
       
   271         
       
   272         res = doc.xpath("/iri/project")
       
   273         if len(res) > 0:
       
   274             return res[0].get(u'abstract')
       
   275         else:
       
   276             return None
       
   277         
       
   278 
       
   279     @staticmethod
       
   280     def create_project(user, title, contents):
       
   281         owner = Owner.objects.get(user=user)
       
   282         project = Project(title=title, owner=owner)
       
   283         project.ldt_id = str(uuid.uuid1())
       
   284         project.created_by=user.username
       
   285         project.changed_by=user.username
       
   286         project.state = 1
       
   287         project.save()
       
   288         for content in contents:
       
   289             project.contents.add(content)
       
   290         project.save()
       
   291         return create_ldt(project, user)
       
   292 
       
   293     def copy_project(self, user, title):
       
   294         owner = Owner.objects.get(user=user)
       
   295         project = Project(title=title, owner=owner)
       
   296         project = copy_ldt(self, project, user)
       
   297         project.save()
       
   298         for content in self.contents.all():
       
   299             project.contents.add(content)
       
   300         project.save()
       
   301         return project
       
   302     
       
   303     def checkAccess(self, user):
       
   304         if (user and user.is_staff) or self.state == 2: 
       
   305             return True
       
   306         else:
       
   307             return False
       
   308         
       
   309 
       
   310 class Segment(models.Model):
       
   311     
       
   312     project_obj = models.ForeignKey(Project, null=True)
       
   313     content = models.ForeignKey(Content)
       
   314     project_id = models.CharField(max_length=1024, unique=False, blank=True, null=True)
       
   315     iri_id = models.CharField(max_length=1024, unique=False)
       
   316     ensemble_id = models.CharField(max_length=1024, unique=False)
       
   317     cutting_id = models.CharField(max_length=1024, unique=False)    
       
   318     element_id = models.CharField(max_length=1024, unique=False)
       
   319     tags = tagging.fields.TagField(max_length=2048, null=True, blank=True, unique=False)
       
   320     title = models.CharField(max_length=2048, unique=False, null=True, blank=True)
       
   321     duration = models.IntegerField(null=True)
       
   322     start_ts = models.IntegerField(null=True)
       
   323     author = models.CharField(max_length=1024, unique=False, null=True, blank=True)
       
   324     date = models.CharField(max_length=128, unique=False, null=True, blank=True)
       
   325     abstract = models.TextField(null=True, blank=True)
       
   326     
       
   327     def __unicode__(self):
       
   328         return "/".join((unicode(self.project_id), unicode(self.iri_id), unicode(self.ensemble_id), unicode(self.cutting_id), unicode(self.element_id)))
       
   329     
       
   330     class Meta:
       
   331         unique_together = (('project_id', 'iri_id', 'ensemble_id', 'cutting_id', 'element_id'),)
       
   332 
       
   333