# HG changeset patch # User ymh # Date 1305568836 -7200 # Node ID 4535dafa6007c35934d729e64d67a2b014ce2c12 # Parent 06b1221142ac717ab18b4b6f419709fb4d30c622 improve releasing of resources when indexing + convert line endings to unix diff -r 06b1221142ac -r 4535dafa6007 .hgignore --- a/.hgignore Mon May 16 17:43:34 2011 +0200 +++ b/.hgignore Mon May 16 20:00:36 2011 +0200 @@ -42,4 +42,4 @@ syntax: regexp ^src/ldt/distribute-0\.6\.14-py2\.6\.egg$ syntax: regexp -^src/ldt/MANIFEST\.in$ \ No newline at end of file +^src/ldt/MANIFEST\.in$ diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/core/handlers/modwsgi.py --- a/src/ldt/ldt/core/handlers/modwsgi.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/core/handlers/modwsgi.py Mon May 16 20:00:36 2011 +0200 @@ -1,26 +1,26 @@ -import os -import sys -import site - -def application(environ, start_response): - os.environ['DJANGO_SETTINGS_MODULE'] = environ['DJANGO_SETTINGS_MODULE'] - - prev_sys_path = list(sys.path) - - sys.path.append(environ['PROJECT_PATH']) - for path in environ.get('PYTHON_PATH', "").split(os.pathsep): - if path: - site.addsitedir(path) - - new_sys_path = [] - for item in list(sys.path): - if item not in prev_sys_path: - new_sys_path.append(item) - sys.path.remove(item) - sys.path[:0] = new_sys_path - - import django.core.handlers.wsgi - - _application = django.core.handlers.wsgi.WSGIHandler() - - return _application(environ, start_response) +import os +import sys +import site + +def application(environ, start_response): + os.environ['DJANGO_SETTINGS_MODULE'] = environ['DJANGO_SETTINGS_MODULE'] + + prev_sys_path = list(sys.path) + + sys.path.append(environ['PROJECT_PATH']) + for path in environ.get('PYTHON_PATH', "").split(os.pathsep): + if path: + site.addsitedir(path) + + new_sys_path = [] + for item in list(sys.path): + if item not in prev_sys_path: + new_sys_path.append(item) + sys.path.remove(item) + sys.path[:0] = new_sys_path + + import django.core.handlers.wsgi + + _application = django.core.handlers.wsgi.WSGIHandler() + + return _application(environ, start_response) diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/ldt_utils/admin.py --- a/src/ldt/ldt/ldt_utils/admin.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/ldt_utils/admin.py Mon May 16 20:00:36 2011 +0200 @@ -48,17 +48,18 @@ if form.is_valid(): # try: writer = ldt.indexation.get_writer() - contentList = form.cleaned_data["contents"] - indexer = ContentIndexer(contentList, writer) - indexer.index_all() - - index_projects = form.cleaned_data["index_projects"] - if index_projects: - projectList = Project.objects.filter(contents__in=contentList).distinct() #filter(contents__in=contentList) @UndefinedVariable - indexer = ProjectIndexer(projectList, writer) + try: + contentList = form.cleaned_data["contents"] + indexer = ContentIndexer(contentList, writer) indexer.index_all() - - writer.close() + + index_projects = form.cleaned_data["index_projects"] + if index_projects: + projectList = Project.objects.filter(contents__in=contentList).distinct() #filter(contents__in=contentList) @UndefinedVariable + indexer = ProjectIndexer(projectList, writer) + indexer.index_all() + finally: + writer.close() message = "Indexation ok : " + repr(form.cleaned_data["contents"]) form = ReindexForm() # except Exception, inst: diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/ldt_utils/contentindexer.py --- a/src/ldt/ldt/ldt_utils/contentindexer.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/ldt_utils/contentindexer.py Mon May 16 20:00:36 2011 +0200 @@ -1,196 +1,197 @@ -from django.conf import settings -from django.db.models.signals import post_save -from django.dispatch import receiver -from ldt.ldt_utils.models import Segment, Content, Project -from ldt.ldt_utils.utils import reduce_text_node -import ldt.indexation -import lucene -import lxml.etree -import urllib #@UnresolvedImport -# import ldt.utils.log - -def Property(func): - return property(**func()) - - -class LdtIndexer(object): - - def __init__(self, writer, decoupage_blackList=settings.DECOUPAGE_BLACKLIST): - self.__decoupage_blacklist = decoupage_blackList - self.__writer = writer - - @Property - def decoupage_blacklist(): #@NoSelf - doc = """get blacklist""" #@UnusedVariable - - def fget(self): - if self.__decoupage_blacklist is None: - self.__decoupage_blacklist = () - return self.__decoupage_blacklist - - def fset(self, value): - self.__decoupage_blacklist = value - - def fdel(self): - del self.__decoupage_blacklist - - return locals() - - @Property - def writer(): #@NoSelf - def fget(self): - return self.__writer - return locals() - - def index_all(self): - raise NotImplemented - - def index_ensemble(self, ensemble, content, project=None): - ensembleId = ensemble.get(u"id", None) - - for decoupageNode in ensemble.getchildren(): - if decoupageNode.tag != "decoupage" or decoupageNode.get(u"id", None) in self.decoupage_blacklist: - continue - - decoupId = decoupageNode.get(u"id", None) - res = decoupageNode.xpath("elements/element") - for elementNode in res: - - elementId = elementNode.get(u"id", None) - tags = elementNode.get(u"tags", None) - - if tags is not None: - tags.replace(u",", u";") - - if tags is None or len(tags) == 0: - tags = u"" - restagnode = elementNode.xpath("tag/text()", smart_strings=False) - for tagnode in restagnode: - tags = tags + u" ; " + tagnode - - if tags is None or len(tags) == 0: - tags = u"" - restagnode = elementNode.xpath("tags/tag/text()", smart_strings=False) - - for tagnode in restagnode: - tags = tags + u" ; " + tagnode - - if tags is None: - tags = u"" - tags = u";".join([tag[0:50] for tag in tags.split(u";")]) - - - title = reduce_text_node(elementNode, "title/text()") - abstract = reduce_text_node(elementNode, "abstract/text()") - - author = elementNode.get("author", "") - start_ts = int(float(elementNode.get("begin", "-1"))) - duration = int(float(elementNode.get("dur", "0"))) - date_str = elementNode.get("date", "") - ldt_id = u"" - if project: - ldt_id = project.ldt_id - - doc = lucene.Document() - doc.add(lucene.Field("type_doc", "annotation", lucene.Field.Store.NO, lucene.Field.Index.NOT_ANALYZED)) - doc.add(lucene.Field("iri_id", content.iri_id, lucene.Field.Store.YES, lucene.Field.Index.NOT_ANALYZED)) - doc.add(lucene.Field("project_id", ldt_id, lucene.Field.Store.YES, lucene.Field.Index.NOT_ANALYZED)) - doc.add(lucene.Field("ensemble_id", ensembleId, lucene.Field.Store.YES, lucene.Field.Index.NO)) - doc.add(lucene.Field("decoupage_id", decoupId, lucene.Field.Store.YES, lucene.Field.Index.NO)) - doc.add(lucene.Field("element_id", elementId, lucene.Field.Store.YES, lucene.Field.Index.NO)) - doc.add(lucene.Field("tags", tags, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) - doc.add(lucene.Field("title", title, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) - doc.add(lucene.Field("abstract", abstract, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) - doc.add(lucene.Field("all", " ".join([tags, title, abstract]), lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) - - seg = Segment(content=content, - iri_id=content.iri_id, - ensemble_id=ensembleId, - cutting_id=decoupId, - element_id=elementId, - tags=tags, - title=title, - abstract=abstract, - duration=duration, - author=author, - start_ts=start_ts, - date=date_str, - project_obj=project, - project_id=ldt_id) - seg.save() - self.writer.addDocument(doc) - - - -class ContentIndexer(LdtIndexer): - - def __init__(self, contentList, writer, decoupage_blackList=settings.DECOUPAGE_BLACKLIST): - super(ContentIndexer, self).__init__(writer, decoupage_blackList) - self.__contentList = contentList - - def index_all(self): - for content in self.__contentList: - self.index_content(content) - - def index_content(self, content): - url = content.iri_url() - filepath = urllib.urlopen(url) - doc = lxml.etree.parse(filepath) #@UndefinedVariable - - self.writer.deleteDocuments(lucene.Term("iri_id", content.iri_id)) - Segment.objects.filter(iri_id=content.iri_id).delete() #@UndefinedVariable - - res = doc.xpath("/iri/body/ensembles/ensemble") - - for ensemble in res: - self.index_ensemble(ensemble, content) - - self.writer.commit() - - -class ProjectIndexer(LdtIndexer): - - def __init__(self, projectList, writer, decoupage_blackList=settings.DECOUPAGE_BLACKLIST): - super(ProjectIndexer, self).__init__(writer, decoupage_blackList) - self.__projectList = projectList - - def index_all(self): - for project in self.__projectList: - self.index_project(project) - - def index_project(self, project): - - # pocketfilms.utils.log.debug("Indexing project : "+str(project.iri_id)) - doc = lxml.etree.fromstring(project.ldt) #@UndefinedVariable - - self.writer.deleteDocuments(lucene.Term("project_id", project.ldt_id)) - Segment.objects.filter(project_obj__ldt_id=project.ldt_id).delete() #@UndefinedVariable - - res = doc.xpath("/iri/annotations/content") - - for content in res: - contentId = content.get(u"id", None) - content_obj = None - - clist = Content.objects.filter(iri_id = contentId) #@UndefinedVariable - if len(clist) > 0: - content_obj = clist[0] - - for ensemble in content.getchildren(): - self.index_ensemble(ensemble, content_obj, project) - - self.writer.commit() - -@receiver(post_save, sender=Project) -def index_project(sender, **kwargs): - if settings.AUTO_INDEX_AFTER_SAVE: - instance = kwargs['instance'] - writer = ldt.indexation.get_writer() - if instance.state != 2: - writer.deleteDocuments(lucene.Term("project_id", instance.ldt_id)) - Segment.objects.filter(project_obj__ldt_id=instance.ldt_id).delete() #@UndefinedVariable - else: - projectIndexer = ProjectIndexer([instance], writer) - projectIndexer.index_all() - - +from django.conf import settings +from django.db.models.signals import post_save +from django.dispatch import receiver +from ldt.ldt_utils.models import Segment, Content, Project +from ldt.ldt_utils.utils import reduce_text_node +import ldt.indexation +import lucene +import lxml.etree +import urllib #@UnresolvedImport +# import ldt.utils.log + +def Property(func): + return property(**func()) + + +class LdtIndexer(object): + + def __init__(self, writer, decoupage_blackList=settings.DECOUPAGE_BLACKLIST): + self.__decoupage_blacklist = decoupage_blackList + self.__writer = writer + + @Property + def decoupage_blacklist(): #@NoSelf + doc = """get blacklist""" #@UnusedVariable + + def fget(self): + if self.__decoupage_blacklist is None: + self.__decoupage_blacklist = () + return self.__decoupage_blacklist + + def fset(self, value): + self.__decoupage_blacklist = value + + def fdel(self): + del self.__decoupage_blacklist + + return locals() + + @Property + def writer(): #@NoSelf + def fget(self): + return self.__writer + return locals() + + def index_all(self): + raise NotImplemented + + def index_ensemble(self, ensemble, content, project=None): + ensembleId = ensemble.get(u"id", None) + + for decoupageNode in ensemble.getchildren(): + if decoupageNode.tag != "decoupage" or decoupageNode.get(u"id", None) in self.decoupage_blacklist: + continue + + decoupId = decoupageNode.get(u"id", None) + res = decoupageNode.xpath("elements/element") + for elementNode in res: + + elementId = elementNode.get(u"id", None) + tags = elementNode.get(u"tags", None) + + if tags is not None: + tags.replace(u",", u";") + + if tags is None or len(tags) == 0: + tags = u"" + restagnode = elementNode.xpath("tag/text()", smart_strings=False) + for tagnode in restagnode: + tags = tags + u" ; " + tagnode + + if tags is None or len(tags) == 0: + tags = u"" + restagnode = elementNode.xpath("tags/tag/text()", smart_strings=False) + + for tagnode in restagnode: + tags = tags + u" ; " + tagnode + + if tags is None: + tags = u"" + tags = u";".join([tag[0:50] for tag in tags.split(u";")]) + + + title = reduce_text_node(elementNode, "title/text()") + abstract = reduce_text_node(elementNode, "abstract/text()") + + author = elementNode.get("author", "") + start_ts = int(float(elementNode.get("begin", "-1"))) + duration = int(float(elementNode.get("dur", "0"))) + date_str = elementNode.get("date", "") + ldt_id = u"" + if project: + ldt_id = project.ldt_id + + doc = lucene.Document() + doc.add(lucene.Field("type_doc", "annotation", lucene.Field.Store.NO, lucene.Field.Index.NOT_ANALYZED)) + doc.add(lucene.Field("iri_id", content.iri_id, lucene.Field.Store.YES, lucene.Field.Index.NOT_ANALYZED)) + doc.add(lucene.Field("project_id", ldt_id, lucene.Field.Store.YES, lucene.Field.Index.NOT_ANALYZED)) + doc.add(lucene.Field("ensemble_id", ensembleId, lucene.Field.Store.YES, lucene.Field.Index.NO)) + doc.add(lucene.Field("decoupage_id", decoupId, lucene.Field.Store.YES, lucene.Field.Index.NO)) + doc.add(lucene.Field("element_id", elementId, lucene.Field.Store.YES, lucene.Field.Index.NO)) + doc.add(lucene.Field("tags", tags, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) + doc.add(lucene.Field("title", title, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) + doc.add(lucene.Field("abstract", abstract, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) + doc.add(lucene.Field("all", " ".join([tags, title, abstract]), lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) + + seg = Segment(content=content, + iri_id=content.iri_id, + ensemble_id=ensembleId, + cutting_id=decoupId, + element_id=elementId, + tags=tags, + title=title, + abstract=abstract, + duration=duration, + author=author, + start_ts=start_ts, + date=date_str, + project_obj=project, + project_id=ldt_id) + seg.save() + self.writer.addDocument(doc) + + + +class ContentIndexer(LdtIndexer): + + def __init__(self, contentList, writer, decoupage_blackList=settings.DECOUPAGE_BLACKLIST): + super(ContentIndexer, self).__init__(writer, decoupage_blackList) + self.__contentList = contentList + + def index_all(self): + for content in self.__contentList: + self.index_content(content) + + def index_content(self, content): + url = content.iri_url() + filepath = urllib.urlopen(url) + doc = lxml.etree.parse(filepath) #@UndefinedVariable + + self.writer.deleteDocuments(lucene.Term("iri_id", content.iri_id)) + Segment.objects.filter(iri_id=content.iri_id).delete() #@UndefinedVariable + + res = doc.xpath("/iri/body/ensembles/ensemble") + + for ensemble in res: + self.index_ensemble(ensemble, content) + + self.writer.commit() + + +class ProjectIndexer(LdtIndexer): + + def __init__(self, projectList, writer, decoupage_blackList=settings.DECOUPAGE_BLACKLIST): + super(ProjectIndexer, self).__init__(writer, decoupage_blackList) + self.__projectList = projectList + + def index_all(self): + for project in self.__projectList: + self.index_project(project) + + def index_project(self, project): + + # pocketfilms.utils.log.debug("Indexing project : "+str(project.iri_id)) + doc = lxml.etree.fromstring(project.ldt) #@UndefinedVariable + + self.writer.deleteDocuments(lucene.Term("project_id", project.ldt_id)) + Segment.objects.filter(project_obj__ldt_id=project.ldt_id).delete() #@UndefinedVariable + + res = doc.xpath("/iri/annotations/content") + + for content in res: + contentId = content.get(u"id", None) + content_obj = None + + clist = Content.objects.filter(iri_id = contentId) #@UndefinedVariable + if len(clist) > 0: + content_obj = clist[0] + + for ensemble in content.getchildren(): + self.index_ensemble(ensemble, content_obj, project) + + self.writer.commit() + +@receiver(post_save, sender=Project) +def index_project(sender, **kwargs): + if settings.AUTO_INDEX_AFTER_SAVE: + instance = kwargs['instance'] + writer = ldt.indexation.get_writer() + try: + if instance.state != 2: + writer.deleteDocuments(lucene.Term("project_id", instance.ldt_id)) + Segment.objects.filter(project_obj__ldt_id=instance.ldt_id).delete() #@UndefinedVariable + else: + projectIndexer = ProjectIndexer([instance], writer) + projectIndexer.index_all() + finally: + writer.close() diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/ldt_utils/forms.py --- a/src/ldt/ldt/ldt_utils/forms.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/ldt_utils/forms.py Mon May 16 20:00:36 2011 +0200 @@ -1,82 +1,82 @@ -from django import forms -from django.utils.translation import ugettext_lazy as _ -from ldt.forms import widgets as ldt_widgets -from models import Project, Content, Media -from utils import generate_uuid - -class LdtImportForm(forms.Form): - importFile = forms.FileField() - videoPath = forms.CharField(required=False) - flatten = forms.BooleanField(required=False, initial=True) - -class LdtAddForm(forms.ModelForm): - title = forms.CharField() - contents = forms.ModelMultipleChoiceField(Content.objects.all()) #@UndefinedVariable - # owner = forms.ModelChoiceField(Author.objects.all()) - class Meta: - model = Project - exclude = ("ldt_id", "ldt", "created_by", "changed_by", "creation_date", "modification_date", "state", "owner") - -class ReindexForm(forms.Form): - contents = forms.ModelMultipleChoiceField(Content.objects.all()) #@UndefinedVariable - index_projects = forms.BooleanField(required=False, initial=False) - -class SearchForm(forms.Form): - search = forms.CharField() - field = forms.ChoiceField([(u"all", u"all"), (u"title", u"title"), (u"abstract", u"resume"), (u"tags", u"tags")]) - -class AddProjectForm (forms.Form): - title = forms.CharField(widget=forms.TextInput(attrs={'class':'inputbox required'})) - -class CopyProjectForm (forms.Form): - title = forms.CharField() - - -class ContentForm(forms.ModelForm): - - #iri_id = forms.CharField(max_length=1024, widget=forms.HiddenInput, initial=generate_uuid) - iriurl = forms.CharField(max_length=1024, widget=forms.HiddenInput, required=False) - content_creation_date = forms.SplitDateTimeField(widget=ldt_widgets.LdtSplitDateTime, required=False, label=_("content.content_creation_date")) - media_input_type = forms.ChoiceField(required=False, label=_("content.media_input_type"), choices=(("upload", _("file_upload")), ("url", _("url")), ("link", _("existing_media")), ("create", _("create_media")), ("none", _("none_media")))) - - def clean_iri_id(self): - data = self.cleaned_data.get('iri_id') - if not data: - data = generate_uuid() - return data - - def clean(self): - cleaned_data = self.cleaned_data - iriurl_data = cleaned_data.get('iriurl') - iri_id_data = cleaned_data['iri_id'] - if not iriurl_data: - iriurl_data = "%s/%s.iri" % (iri_id_data, iri_id_data) - cleaned_data['iriurl'] = iriurl_data - return cleaned_data - - class Meta: - model = Content - exclude = ("creation_date", "update_date", "authors") - widgets = { - 'iri_id': forms.HiddenInput, - } - - class Media: - css = { - 'all' : ('admin/css/forms.css', 'admin/css/base.css', 'admin/css/widgets.css') - } - -class MediaForm(forms.ModelForm): - - media_creation_date = forms.SplitDateTimeField(widget=ldt_widgets.LdtSplitDateTime, required=False) - media_file = forms.FileField(required=False); - src = forms.CharField(required=False, max_length=1024) - - class Meta: - model = Media - exclude = ("creation_date", "update_date", "creator") - - class Media: - css = { - 'all' : ('admin/css/forms.css', 'admin/css/base.css', 'admin/css/widgets.css') - } +from django import forms +from django.utils.translation import ugettext_lazy as _ +from ldt.forms import widgets as ldt_widgets +from models import Project, Content, Media +from utils import generate_uuid + +class LdtImportForm(forms.Form): + importFile = forms.FileField() + videoPath = forms.CharField(required=False) + flatten = forms.BooleanField(required=False, initial=True) + +class LdtAddForm(forms.ModelForm): + title = forms.CharField() + contents = forms.ModelMultipleChoiceField(Content.objects.all()) #@UndefinedVariable + # owner = forms.ModelChoiceField(Author.objects.all()) + class Meta: + model = Project + exclude = ("ldt_id", "ldt", "created_by", "changed_by", "creation_date", "modification_date", "state", "owner") + +class ReindexForm(forms.Form): + contents = forms.ModelMultipleChoiceField(Content.objects.all()) #@UndefinedVariable + index_projects = forms.BooleanField(required=False, initial=False) + +class SearchForm(forms.Form): + search = forms.CharField() + field = forms.ChoiceField([(u"all", u"all"), (u"title", u"title"), (u"abstract", u"resume"), (u"tags", u"tags")]) + +class AddProjectForm (forms.Form): + title = forms.CharField(widget=forms.TextInput(attrs={'class':'inputbox required'})) + +class CopyProjectForm (forms.Form): + title = forms.CharField() + + +class ContentForm(forms.ModelForm): + + #iri_id = forms.CharField(max_length=1024, widget=forms.HiddenInput, initial=generate_uuid) + iriurl = forms.CharField(max_length=1024, widget=forms.HiddenInput, required=False) + content_creation_date = forms.SplitDateTimeField(widget=ldt_widgets.LdtSplitDateTime, required=False, label=_("content.content_creation_date")) + media_input_type = forms.ChoiceField(required=False, label=_("content.media_input_type"), choices=(("upload", _("file_upload")), ("url", _("url")), ("link", _("existing_media")), ("create", _("create_media")), ("none", _("none_media")))) + + def clean_iri_id(self): + data = self.cleaned_data.get('iri_id') + if not data: + data = generate_uuid() + return data + + def clean(self): + cleaned_data = self.cleaned_data + iriurl_data = cleaned_data.get('iriurl') + iri_id_data = cleaned_data['iri_id'] + if not iriurl_data: + iriurl_data = "%s/%s.iri" % (iri_id_data, iri_id_data) + cleaned_data['iriurl'] = iriurl_data + return cleaned_data + + class Meta: + model = Content + exclude = ("creation_date", "update_date", "authors") + widgets = { + 'iri_id': forms.HiddenInput, + } + + class Media: + css = { + 'all' : ('admin/css/forms.css', 'admin/css/base.css', 'admin/css/widgets.css') + } + +class MediaForm(forms.ModelForm): + + media_creation_date = forms.SplitDateTimeField(widget=ldt_widgets.LdtSplitDateTime, required=False) + media_file = forms.FileField(required=False); + src = forms.CharField(required=False, max_length=1024) + + class Meta: + model = Media + exclude = ("creation_date", "update_date", "creator") + + class Media: + css = { + 'all' : ('admin/css/forms.css', 'admin/css/base.css', 'admin/css/widgets.css') + } diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/ldt_utils/models.py --- a/src/ldt/ldt/ldt_utils/models.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/ldt_utils/models.py Mon May 16 20:00:36 2011 +0200 @@ -1,390 +1,393 @@ -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 Content(models.Model): - 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 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() - writer.deleteDocuments(lucene.Term("iri_id", self.iri_id)) - writer.commit() - - 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(os.path.join(settings.MEDIA_ROOT, "media"), "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'),) - - +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 Content(models.Model): + 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 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(os.path.join(settings.MEDIA_ROOT, "media"), "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'),) + + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/copy_ldt.html --- a/src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/copy_ldt.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/copy_ldt.html Mon May 16 20:00:36 2011 +0200 @@ -1,24 +1,24 @@ -{% extends "ldt/ldt_raw_base.html" %} - -{% load i18n %} {# form of copy of project ldt #} -{% block css_import %} - {{ block.super }} - - - -{% endblock %} -{% block body %} -
-
{% trans "Copy your project" %}
- -
{% csrf_token %} -
- - -
-
- -
-
-
-{% endblock %} +{% extends "ldt/ldt_raw_base.html" %} + +{% load i18n %} {# form of copy of project ldt #} +{% block css_import %} + {{ block.super }} + + + +{% endblock %} +{% block body %} +
+
{% trans "Copy your project" %}
+ +
{% csrf_token %} +
+ + +
+
+ +
+
+
+{% endblock %} diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/save_done.html --- a/src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/save_done.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/ldt_utils/templates/ldt/ldt_utils/save_done.html Mon May 16 20:00:36 2011 +0200 @@ -1,5 +1,5 @@ -

done

-

{{ldt}} -

-

{{id}}

+

done

+

{{ldt}} +

+

{{id}}

title:{{title}}

\ No newline at end of file diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/ldt_utils/tests.py --- a/src/ldt/ldt/ldt_utils/tests.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/ldt_utils/tests.py Mon May 16 20:00:36 2011 +0200 @@ -1,168 +1,168 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" - -from django.conf import settings -from django.test import TestCase -from ldt.core.models import Owner -from models import Project, Content -from utils import LdtUtils, create_ldt, create_empty_iri, copy_ldt -import lxml.etree -import tempfile -import unittest -import uuid - - - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.failUnlessEqual(1 + 1, 2) - -__test__ = {"doctest": """ -Another way to test that 1 + 1 is equal to 2. - ->>> 1 + 1 == 2 -True -"""} - - - -class UtilsTest(unittest.TestCase): - def setUp(self): - self.user = Owner() - self.user.username = "toto" - self.LU = LdtUtils() - - self.project = Project(title="titleproj1", owner=self.user) - self.project.ldt = ' CA: prof et admin <abstract/> <audio source=""/> <tags/> </element> <element id="s_0050F043-3AD2-0A7C-6699-D2A03A1EBA02" begin="5052858" dur="124407" author="" date="2010/09/02" color="10053375" src=""> <title>conseil de classe Reprise de la figure precedente TC: prof et admin Conseil de classe conseil de classe Reprise de la figure precedente Bout a bout 1 ' - self.project.id = "11" - self.project.ldt_id = str(uuid.uuid1()) - self.project.save() - - self.projectcopy = Project(title="the2ndproject") - self.projectcopy.id = "22" - - def tearDown(self): - self.project.delete() - self.projectcopy.delete() - #self.cont1.delete() - #self.cont2.delete() - - def test_generate_ldt(self): - self.cont1 = Content(iriurl="id1/iriurl1") - self.cont1.iri_id = "id1" - self.cont1.save() - - self.cont2 = Content(iriurl="id2/iriurl2") - self.cont2.iri_id = "id2" - self.cont2.save() - - self.project.contents.add(self.cont1, self.cont2) - - f = tempfile.TemporaryFile(mode='r+') - self.LU.generateLdt(Content.objects.all(), f) - f.seek(0) - ldoc = lxml.etree.parse(f) - self.assertEqual(ldoc.xpath("/iri/displays/display/content")[9].get("id"), self.cont2.iri_id) - self.assertEqual(ldoc.xpath("/iri/medias/media")[8].get("id"), self.cont1.iri_id) - f.close() - - def test_generate_init(self): - self.cont3 = Content(iriurl="id3/iriurl1") - self.cont3.iri_id = "id3" - self.cont3.save() - - self.cont4 = Content(iriurl="id4/iriurl2") - self.cont4.iri_id = "id4" - self.cont4.save() - - self.project.contents.add(self.cont3, self.cont4) - ldoc = self.LU.generateInit(None, None) - self.assertEqual(ldoc.xpath("/iri/files/init")[0].tag, "init") - self.assertEqual(ldoc.xpath("/iri/files/library")[0].tag, "library") - self.assertEqual(ldoc.xpath("/iri/files/init/file")[0].get("video"), settings.STREAM_URL) - - def test_create_ldt(self): - self.cont5 = Content(iriurl="id5/iriurl1") - self.cont5.iri_id = "id5" - self.cont5.save() - - self.cont6 = Content(iriurl="id6/iriurl2") - self.cont6.iri_id = "id6" - self.cont6.save() - - self.project.contents.add(self.cont5, self.cont6) - self.project.ldt = "" - create_ldt(self.project, self.user) - ldt = lxml.etree.fromstring(self.project.ldt) - self.assertEqual(ldt.xpath("/iri")[0].tag, "iri") - self.assertEqual(ldt.xpath("/iri/project")[0].get("title"), self.project.title) - self.assertEqual(ldt.xpath("/iri/medias/media")[0].get("src"), self.cont5.iri_url()) - self.assertEqual(ldt.xpath("/iri/medias/media")[1].get("id"), self.cont6.iri_id) - - def test_copy_ldt(self): - self.cont7 = Content(iriurl="id7/iriurl1") - self.cont7.iri_id = "id7" - self.cont7.save() - - self.cont8 = Content(iriurl="id8/iriurl2") - self.cont8.iri_id = "id8" - self.cont8.save() - - self.project.contents.add(self.cont7, self.cont8) - copy_ldt(self.project, self.projectcopy, self.user) - ldt1 = lxml.etree.fromstring(self.project.ldt) - ldt2 = lxml.etree.fromstring(self.projectcopy.ldt) - self.assertTrue(ldt1.xpath("/iri/project")[0].get("id") != ldt2.xpath("/iri/project")[0].get("id")) - self.assertEqual(ldt1.xpath("/iri/medias/media")[0].get("id"), ldt2.xpath("/iri/medias/media")[0].get("id")) - self.assertEqual(ldt1.xpath("/iri/annotations/content/ensemble")[0].get("title"), ldt2.xpath("/iri/annotations/content/ensemble")[0].get("title")) - self.assertEqual(ldt1.xpath("/iri/annotations/content/ensemble/decoupage")[0].get("id"), ldt2.xpath("/iri/annotations/content/ensemble/decoupage")[0].get("id")) - self.assertEqual(ldt1.xpath("/iri/annotations/content/ensemble/decoupage/title")[1].text, ldt2.xpath("/iri/annotations/content/ensemble/decoupage/title")[1].text.strip("\n\t")) - - def test_create_empty_iri(self): - self.cont9 = Content(iriurl="id9/iriurl1") - self.cont9.iri_id = "id9" - self.cont9.save() - - self.cont10 = Content(iriurl="id10/iriurl2") - self.cont10.iri_id = "id10" - self.cont10.save() - - self.project.contents.add(self.cont9, self.cont10) - tmp = tempfile.TemporaryFile(mode='r+') - create_empty_iri(tmp, self.cont9, "admin") - tmp.seek(0) - ldoc = lxml.etree.parse(tmp) - self.assertEqual(ldoc.xpath("/iri/head/meta")[0].get("content"), self.cont9.iri_id) - self.assertEqual(ldoc.xpath("/iri/body/medias/media/video")[0].get("id"), self.cont9.iri_id) - tmp.close() - - - - -class ViewsTest(unittest.TestCase): - def setUp(self): - self.project = Project() - self.project.id = "121" - self.project.save() - self.project.ldt = ' CA: prof et admin <abstract/> <audio source=""/> <tags/> </element> <element id="s_0050F043-3AD2-0A7C-6699-D2A03A1EBA02" begin="5052858" dur="124407" author="" date="2010/09/02" color="10053375" src=""> <title>conseil de classe Reprise de la figure precedente TC: prof et admin Conseil de classe conseil de classe Reprise de la figure precedente Bout a bout 1 ' - - self.cont1 = Content(iriurl="/laurentcantet_entrelesmurs/iriurl1") - self.cont1.iri_id = 'laurentcantet_entrelesmurs' - self.cont1.save() - - self.cont2 = Content(iriurl="/content_notinldt/iriurl2") - self.cont2.iri_id = 'content_notinldt' - self.cont2.save() - - self.project.contents.add(self.cont1, self.cont2) - - def tearDown(self): - self.project.delete() - +""" +This file demonstrates two different styles of tests (one doctest and one +unittest). These will both pass when you run "manage.py test". + +Replace these with more appropriate tests for your application. +""" + +from django.conf import settings +from django.test import TestCase +from ldt.core.models import Owner +from models import Project, Content +from utils import LdtUtils, create_ldt, create_empty_iri, copy_ldt +import lxml.etree +import tempfile +import unittest +import uuid + + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.failUnlessEqual(1 + 1, 2) + +__test__ = {"doctest": """ +Another way to test that 1 + 1 is equal to 2. + +>>> 1 + 1 == 2 +True +"""} + + + +class UtilsTest(unittest.TestCase): + def setUp(self): + self.user = Owner() + self.user.username = "toto" + self.LU = LdtUtils() + + self.project = Project(title="titleproj1", owner=self.user) + self.project.ldt = ' CA: prof et admin <abstract/> <audio source=""/> <tags/> </element> <element id="s_0050F043-3AD2-0A7C-6699-D2A03A1EBA02" begin="5052858" dur="124407" author="" date="2010/09/02" color="10053375" src=""> <title>conseil de classe Reprise de la figure precedente TC: prof et admin Conseil de classe conseil de classe Reprise de la figure precedente Bout a bout 1 ' + self.project.id = "11" + self.project.ldt_id = str(uuid.uuid1()) + self.project.save() + + self.projectcopy = Project(title="the2ndproject") + self.projectcopy.id = "22" + + def tearDown(self): + self.project.delete() + self.projectcopy.delete() + #self.cont1.delete() + #self.cont2.delete() + + def test_generate_ldt(self): + self.cont1 = Content(iriurl="id1/iriurl1") + self.cont1.iri_id = "id1" + self.cont1.save() + + self.cont2 = Content(iriurl="id2/iriurl2") + self.cont2.iri_id = "id2" + self.cont2.save() + + self.project.contents.add(self.cont1, self.cont2) + + f = tempfile.TemporaryFile(mode='r+') + self.LU.generateLdt(Content.objects.all(), f) + f.seek(0) + ldoc = lxml.etree.parse(f) + self.assertEqual(ldoc.xpath("/iri/displays/display/content")[9].get("id"), self.cont2.iri_id) + self.assertEqual(ldoc.xpath("/iri/medias/media")[8].get("id"), self.cont1.iri_id) + f.close() + + def test_generate_init(self): + self.cont3 = Content(iriurl="id3/iriurl1") + self.cont3.iri_id = "id3" + self.cont3.save() + + self.cont4 = Content(iriurl="id4/iriurl2") + self.cont4.iri_id = "id4" + self.cont4.save() + + self.project.contents.add(self.cont3, self.cont4) + ldoc = self.LU.generateInit(None, None) + self.assertEqual(ldoc.xpath("/iri/files/init")[0].tag, "init") + self.assertEqual(ldoc.xpath("/iri/files/library")[0].tag, "library") + self.assertEqual(ldoc.xpath("/iri/files/init/file")[0].get("video"), settings.STREAM_URL) + + def test_create_ldt(self): + self.cont5 = Content(iriurl="id5/iriurl1") + self.cont5.iri_id = "id5" + self.cont5.save() + + self.cont6 = Content(iriurl="id6/iriurl2") + self.cont6.iri_id = "id6" + self.cont6.save() + + self.project.contents.add(self.cont5, self.cont6) + self.project.ldt = "" + create_ldt(self.project, self.user) + ldt = lxml.etree.fromstring(self.project.ldt) + self.assertEqual(ldt.xpath("/iri")[0].tag, "iri") + self.assertEqual(ldt.xpath("/iri/project")[0].get("title"), self.project.title) + self.assertEqual(ldt.xpath("/iri/medias/media")[0].get("src"), self.cont5.iri_url()) + self.assertEqual(ldt.xpath("/iri/medias/media")[1].get("id"), self.cont6.iri_id) + + def test_copy_ldt(self): + self.cont7 = Content(iriurl="id7/iriurl1") + self.cont7.iri_id = "id7" + self.cont7.save() + + self.cont8 = Content(iriurl="id8/iriurl2") + self.cont8.iri_id = "id8" + self.cont8.save() + + self.project.contents.add(self.cont7, self.cont8) + copy_ldt(self.project, self.projectcopy, self.user) + ldt1 = lxml.etree.fromstring(self.project.ldt) + ldt2 = lxml.etree.fromstring(self.projectcopy.ldt) + self.assertTrue(ldt1.xpath("/iri/project")[0].get("id") != ldt2.xpath("/iri/project")[0].get("id")) + self.assertEqual(ldt1.xpath("/iri/medias/media")[0].get("id"), ldt2.xpath("/iri/medias/media")[0].get("id")) + self.assertEqual(ldt1.xpath("/iri/annotations/content/ensemble")[0].get("title"), ldt2.xpath("/iri/annotations/content/ensemble")[0].get("title")) + self.assertEqual(ldt1.xpath("/iri/annotations/content/ensemble/decoupage")[0].get("id"), ldt2.xpath("/iri/annotations/content/ensemble/decoupage")[0].get("id")) + self.assertEqual(ldt1.xpath("/iri/annotations/content/ensemble/decoupage/title")[1].text, ldt2.xpath("/iri/annotations/content/ensemble/decoupage/title")[1].text.strip("\n\t")) + + def test_create_empty_iri(self): + self.cont9 = Content(iriurl="id9/iriurl1") + self.cont9.iri_id = "id9" + self.cont9.save() + + self.cont10 = Content(iriurl="id10/iriurl2") + self.cont10.iri_id = "id10" + self.cont10.save() + + self.project.contents.add(self.cont9, self.cont10) + tmp = tempfile.TemporaryFile(mode='r+') + create_empty_iri(tmp, self.cont9, "admin") + tmp.seek(0) + ldoc = lxml.etree.parse(tmp) + self.assertEqual(ldoc.xpath("/iri/head/meta")[0].get("content"), self.cont9.iri_id) + self.assertEqual(ldoc.xpath("/iri/body/medias/media/video")[0].get("id"), self.cont9.iri_id) + tmp.close() + + + + +class ViewsTest(unittest.TestCase): + def setUp(self): + self.project = Project() + self.project.id = "121" + self.project.save() + self.project.ldt = ' CA: prof et admin <abstract/> <audio source=""/> <tags/> </element> <element id="s_0050F043-3AD2-0A7C-6699-D2A03A1EBA02" begin="5052858" dur="124407" author="" date="2010/09/02" color="10053375" src=""> <title>conseil de classe Reprise de la figure precedente TC: prof et admin Conseil de classe conseil de classe Reprise de la figure precedente Bout a bout 1 ' + + self.cont1 = Content(iriurl="/laurentcantet_entrelesmurs/iriurl1") + self.cont1.iri_id = 'laurentcantet_entrelesmurs' + self.cont1.save() + + self.cont2 = Content(iriurl="/content_notinldt/iriurl2") + self.cont2.iri_id = 'content_notinldt' + self.cont2.save() + + self.project.contents.add(self.cont1, self.cont2) + + def tearDown(self): + self.project.delete() + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/ldt_utils/urls.py --- a/src/ldt/ldt/ldt_utils/urls.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/ldt_utils/urls.py Mon May 16 20:00:36 2011 +0200 @@ -1,54 +1,54 @@ -from django.conf.urls.defaults import patterns, url -from ldt.management import test_ldt - -# Uncomment the next two lines to enable the admin: -# from django.contrib import admin -# admin.autodiscover() - -urlpatterns = patterns('ldt.ldt_utils', - url(r'^searchInit/(?P.*)/(?P.*)$', 'views.searchInit'), - url(r'^searchForm/$', 'views.searchForm'), - url(r'^search/$', 'views.searchIndex'), - url(r'^search/(?P.*)/(?P.*)$', 'views.searchIndexGet'), - url(r'^searchLdt/(?P.*)/(?P.*)$', 'views.searchLdt'), - url(r'^searchSeg/(?P.*)/(?P.*)$', 'views.searchSegments'), - url(r'^index/(?P.*)$', 'views.index'), - url(r'^init/(?P.*)/(?P.*)$', 'views.init', name='ldt_init'), - url(r'^ldt/(?P.*)$', 'views.ldt'), - url(r'^search/loading/$', 'views.loading'), - url(r'^create/(?P.*)$', 'views.create_project'), - url(r'^copy/(?P.*)$', 'views.copy_project'), - url(r'^update/(?P.*)$', 'views.update_project'), - url(r'^cljson/id/(?P.*)$', 'views.project_json_id'), - url(r'^cljson/externalid/(?P.*)$', 'views.project_json_externalid'), - url(r'^rdf/id/(?P.*)$', 'views.project_annotations_rdf'), - url(r'^/?$', "views.workspace", name="root-view"), - url(r'^filterprojects/_(?P[\w\%\_\-\+]*?)/(?Ptrue|false)/(?P\d)$', "views.projectsfilter",), - url(r'^filtercontents/_(?P[\w\%\_\-\+]*?)/$', "views.contentsfilter",), - (r'^embedpopup/?$', "views.popup_embed"), -) - -urlpatterns += patterns('', - url('^jsi18n', 'django.views.i18n.javascript_catalog', name='jsi18n'), -) - - -if test_ldt(): - urlpatterns += patterns('ldt.ldt_utils', - url(r'^space/content/$', 'views.list_content'), - url(r'^space/content/create/$', 'views.write_content'), - url(r'^space/content/update/(?P[\w-]+)$', 'views.write_content'), - url(r'^space/ldt/$', 'views.list_ldt'), - url(r'^space/ldt/indexproject/(?P.*)$', 'views.indexProject'), - url(r'^space/ldt/indexprojectfull/(?P.*)$', 'views.indexProjectFull'), - url(r'^space/ldt/init/(?P.*)/(?P.+)$', 'views.init', name='space_ldt_init'), - url(r'^space/ldt/project/(?P.*)$', 'views.ldtProject'), - url(r'^space/ldt/create/$', 'views.create_ldt_view'), - url(r'^space/ldt/created_done/$', 'views.created_ldt'), - url(r'^space/ldt/save/$', 'views.save_ldtProject'), - url(r'^space/ldt/publish/(?P[\w-]*)(?:/(?Ptrue|false))?$', 'views.publish'), - url(r'^space/ldt/unpublish/(?P[\w-]*)(?:/(?Ptrue|false))?$', 'views.unpublish'), - url(r'^space/upload/$', 'views.upload'), - url(r'^space/removetempfile/$', 'views.removetempfile'), - -) +from django.conf.urls.defaults import patterns, url +from ldt.management import test_ldt + +# Uncomment the next two lines to enable the admin: +# from django.contrib import admin +# admin.autodiscover() + +urlpatterns = patterns('ldt.ldt_utils', + url(r'^searchInit/(?P.*)/(?P.*)$', 'views.searchInit'), + url(r'^searchForm/$', 'views.searchForm'), + url(r'^search/$', 'views.searchIndex'), + url(r'^search/(?P.*)/(?P.*)$', 'views.searchIndexGet'), + url(r'^searchLdt/(?P.*)/(?P.*)$', 'views.searchLdt'), + url(r'^searchSeg/(?P.*)/(?P.*)$', 'views.searchSegments'), + url(r'^index/(?P.*)$', 'views.index'), + url(r'^init/(?P.*)/(?P.*)$', 'views.init', name='ldt_init'), + url(r'^ldt/(?P.*)$', 'views.ldt'), + url(r'^search/loading/$', 'views.loading'), + url(r'^create/(?P.*)$', 'views.create_project'), + url(r'^copy/(?P.*)$', 'views.copy_project'), + url(r'^update/(?P.*)$', 'views.update_project'), + url(r'^cljson/id/(?P.*)$', 'views.project_json_id'), + url(r'^cljson/externalid/(?P.*)$', 'views.project_json_externalid'), + url(r'^rdf/id/(?P.*)$', 'views.project_annotations_rdf'), + url(r'^/?$', "views.workspace", name="root-view"), + url(r'^filterprojects/_(?P[\w\%\_\-\+]*?)/(?Ptrue|false)/(?P\d)$', "views.projectsfilter",), + url(r'^filtercontents/_(?P[\w\%\_\-\+]*?)/$', "views.contentsfilter",), + (r'^embedpopup/?$', "views.popup_embed"), +) + +urlpatterns += patterns('', + url('^jsi18n', 'django.views.i18n.javascript_catalog', name='jsi18n'), +) + + +if test_ldt(): + urlpatterns += patterns('ldt.ldt_utils', + url(r'^space/content/$', 'views.list_content'), + url(r'^space/content/create/$', 'views.write_content'), + url(r'^space/content/update/(?P[\w-]+)$', 'views.write_content'), + url(r'^space/ldt/$', 'views.list_ldt'), + url(r'^space/ldt/indexproject/(?P.*)$', 'views.indexProject'), + url(r'^space/ldt/indexprojectfull/(?P.*)$', 'views.indexProjectFull'), + url(r'^space/ldt/init/(?P.*)/(?P.+)$', 'views.init', name='space_ldt_init'), + url(r'^space/ldt/project/(?P.*)$', 'views.ldtProject'), + url(r'^space/ldt/create/$', 'views.create_ldt_view'), + url(r'^space/ldt/created_done/$', 'views.created_ldt'), + url(r'^space/ldt/save/$', 'views.save_ldtProject'), + url(r'^space/ldt/publish/(?P[\w-]*)(?:/(?Ptrue|false))?$', 'views.publish'), + url(r'^space/ldt/unpublish/(?P[\w-]*)(?:/(?Ptrue|false))?$', 'views.unpublish'), + url(r'^space/upload/$', 'views.upload'), + url(r'^space/removetempfile/$', 'views.removetempfile'), + +) diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/ldt_utils/views.py --- a/src/ldt/ldt/ldt_utils/views.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/ldt_utils/views.py Mon May 16 20:00:36 2011 +0200 @@ -1,892 +1,901 @@ -from django.conf import settings -from django.contrib.auth.decorators import login_required -from django.core.urlresolvers import reverse -from django.db.models import Q -from django.forms.models import model_to_dict -from django.forms.util import ErrorList -from django.http import (HttpResponse, HttpResponseRedirect, - HttpResponseForbidden, HttpResponseServerError) -from django.shortcuts import (render_to_response, get_object_or_404, - get_list_or_404) -from django.template import RequestContext -from django.template.loader import render_to_string -from django.utils import simplejson -from django.utils.html import escape -from django.utils.translation import ugettext as _, ungettext -from forms import (LdtAddForm, SearchForm, AddProjectForm, CopyProjectForm, - ContentForm, MediaForm) -from ldt.core.models import Owner -from ldt.ldt_utils.models import Content -from ldt.ldt_utils.utils import boolean_convert, LdtUtils, LdtSearch -from lxml.html import fragment_fromstring -from models import Media, Project -from projectserializer import ProjectSerializer -from urllib2 import urlparse -import base64 -import django.core.urlresolvers -import ldt.auth as ldt_auth -import ldt.utils.path as ldt_utils_path -import logging -import lxml.etree -import mimetypes -import os -import urllib2 - - -@login_required -def workspace(request): - - # list of contents - content_list = Content.objects.all() #@UndefinedVariable - - # get list of projects - project_list = Project.objects.all() #@UndefinedVariable - - is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1); - - # render list - return render_to_response("ldt/ldt_utils/workspace.html", - {'contents': content_list, 'projects': project_list, - 'is_gecko': is_gecko}, - context_instance=RequestContext(request)) - - -def popup_embed(request): - - json_url = request.GET.get("json_url") - player_id = request.GET.get("player_id") - ldt_id = request.GET.get("ldt_id") - - - project = Project.objects.get(ldt_id=ldt_id); #@UndefinedVariable - - stream_mode = project.stream_mode - if stream_mode != "video": - stream_mode = 'radio' - - player_width = 650 - player_height = 480 - - if stream_mode == 'radio': - player_height = 1 - - if not ldt_auth.checkAccess(request.user, project): - return HttpResponseForbidden(_("You can not access this project")) - - ps = ProjectSerializer(project, from_contents=False, from_display=True) - annotations = ps.getAnnotations(first_cutting=True) - - rend_dict = {'json_url':json_url, 'player_id':player_id, 'annotations':annotations, 'ldt_id': ldt_id, 'stream_mode': stream_mode, 'player_width': player_width, 'player_height': player_height} - - embed_rendered = dict((typestr, - (lambda s:escape(lxml.etree.tostring(fragment_fromstring(render_to_string("ldt/ldt_utils/partial/embed_%s.html" % (s), rend_dict, context_instance=RequestContext(request))), pretty_print=True)))(typestr)) - for typestr in ('player', 'seo_body', 'seo_meta', 'links')) - - rend_dict['embed_rendered'] = embed_rendered - - return render_to_response("ldt/ldt_utils/embed_popup.html", - rend_dict, - context_instance=RequestContext(request)) - - - -@login_required -def projectsfilter(request, filter, is_owner=False, status=0): - - is_owner = boolean_convert(is_owner) - status = int(status) - query = Q() - - if is_owner: - owner = None - try: - owner = Owner.objects.get(user=request.user) #@UndefinedVariable - except: - return HttpResponseServerError("

User not found

") - query &= Q(owner=owner) - - if status > 0: - query &= Q(state=status) - - if filter: - if len(filter) > 0 and filter[0] == '_': - filter = filter[1:] - query &= Q(title__icontains=filter) - - project_list = Project.objects.filter(query) #@UndefinedVariable - - is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1); - - return render_to_response("ldt/ldt_utils/partial/projectslist.html", - {'projects': project_list, 'is_gecko': is_gecko}, - context_instance=RequestContext(request)) - - - -@login_required -def contentsfilter(request, filter): - if filter and len(filter) > 0 and filter[0] == '_': - filter = filter[1:] - - if filter: - content_list = Content.objects.filter(title__icontains=filter) #@UndefinedVariable - else: - content_list = Content.objects.all() #@UndefinedVariable - - return render_to_response("ldt/ldt_utils/partial/contentslist.html", - {'contents': content_list}, - context_instance=RequestContext(request)) - - -def searchForm(request): - form = SearchForm() - return render_to_response('ldt/ldt_utils/search_form.html', {'form': form} , context_instance=RequestContext(request)) - -def searchIndex(request): - - sform = SearchForm(request.POST) - if sform.is_valid(): - search = sform.cleaned_data["search"] - - - queryStr = base64.urlsafe_b64encode(search.encode('utf8')) - field = request.POST["field"] - language_code = request.LANGUAGE_CODE[:2] - - url = settings.WEB_URL + django.core.urlresolvers.reverse("ldt.ldt_utils.views.searchInit", args=[field, queryStr]) - return render_to_response('ldt/ldt_utils/init_ldt.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': url}, context_instance=RequestContext(request)) - else: - resp = HttpResponse() - resp.write("Error : No result"); - -def searchIndexGet(request, field, query): - - language_code = request.LANGUAGE_CODE[:2] - url = settings.WEB_URL + django.core.urlresolvers.reverse("ldt.ldt_utils.views.searchInit", args=[field, query]) - return render_to_response('ldt/ldt_utils/init_ldt.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': url}, context_instance=RequestContext(request)) - -def searchInit(request, field, query): - - ldtgen = LdtUtils() - - doc = ldtgen.generateInit([field, query], 'ldt.ldt_utils.views.searchLdt', 'ldt.ldt_utils.views.searchSegments') - - resp = HttpResponse(mimetype="text/xml;charset=utf-8") - doc.write(resp, pretty_print=True) - return resp - -def searchLdt(request, field, query, edition=None): - - contentList = [] - resp = HttpResponse(mimetype="text/xml") - queryStr = "" - - if query and len(query) > 0: - queryStr = base64.urlsafe_b64decode(query.encode("ascii")).decode("utf8") - searcher = LdtSearch() - ids = {} - - for result in searcher.query(field, queryStr): - ids[result["iri_id"]] = "" - - id_list = ids.keys() - - #if edition is not None: - # ids_editions = map(lambda t:t[0], filter(lambda id: id[0] is not None, Speak.objects.filter(session__day__edition=edition).order_by("session__start_ts", "order").values_list("content__iri_id"))) - # id_list = filter(lambda id: id in id_list, ids_editions) - - contentList = Content.objects.filter(iri_id__in=id_list) #@UndefinedVariable - - - ldtgen = LdtUtils() - ldtgen.generateLdt(contentList, file=resp, title=u"Recherche : " + queryStr) - - return resp - - -def searchSegments(request, field, query, edition=None): - - if query and len(query) > 0: - searcher = LdtSearch() - - queryStr = base64.urlsafe_b64decode(query.encode("ascii")).decode("utf8") - res = searcher.query(field, queryStr) - else: - res = [] - - iri_ids = None - - #if edition is not None: - # iri_ids = map(lambda t:t[0], filter(lambda id: id[0] is not None, Speak.objects.filter(session__day__edition=edition).order_by("session__start_ts", "order").values_list("content__iri_id"))) - - iri = lxml.etree.Element('iri') - doc = lxml.etree.ElementTree(iri) - - for resultMap in res: - if iri_ids is None or resultMap['iri_id'] in iri_ids: - seg = lxml.etree.SubElement(iri, 'seg') - seg.set('idctt', resultMap['iri_id']) - seg.set('idens', resultMap['ensemble_id']) - seg.set('iddec', resultMap['decoupage_id']) - seg.set('idseg', resultMap['element_id']) - seg.set('idvue', "") - seg.set('crit', "") - - return doc - - return HttpResponse(lxml.etree.tostring(doc, pretty_print=True), mimetype="text/xml;charset=utf-8") - - - -@login_required -def list_ldt(request): - contents = Content.objects.all() #@UndefinedVariable - try: - owner = Owner.objects.get(user=request.user) #@UndefinedVariable - except: - return HttpResponseRedirect(settings.LOGIN_URL) - ldtProjects = Project.objects.filter(owner=owner) #@UndefinedVariable - context = { - 'contents': contents, - 'projects': ldtProjects.reverse(), - } - return render_to_response('ldt/ldt_utils/ldt_list.html', context, context_instance=RequestContext(request)) - -@login_required -def list_content(request): - contents = Content.objects.all() #@UndefinedVariable - context = { - 'contents': contents, - } - return render_to_response('ldt/ldt_utils/content_list.html', context, context_instance=RequestContext(request)) - -@login_required -def create_ldt_view(request): - if request.method == "POST" : - form = LdtAddForm(request.POST) - if form.is_valid(): - user = request.user - Project.create_project(title=form.cleaned_data['title'], user=user, contents=form.cleaned_data['contents']) - form_status = "saved" - contents = [] - else: - form = LdtAddForm() - contents = Content.objects.all() #@UndefinedVariable - form_status = "none" - - return render_to_response('ldt/ldt_utils/create_ldt.html', {'contents': contents, 'form': form, 'form_status':form_status, 'create_project_action':reverse(create_ldt_view)}, context_instance=RequestContext(request)) - -def created_ldt(request): - return render_to_response('ldt/ldt_utils/save_done.html', context_instance=RequestContext(request)) - -def indexProject(request, id): - - urlStr = settings.WEB_URL + reverse("space_ldt_init", args=['ldtProject', id]) - posturl = settings.WEB_URL + reverse("ldt.ldt_utils.views.save_ldtProject") - language_code = request.LANGUAGE_CODE[:2] - - ldt = get_object_or_404(Project, ldt_id=id) - if ldt.state == 2: #published - readonly = 'true' - else: - readonly = 'false' - - return render_to_response('ldt/ldt_utils/init_ldt.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': urlStr, 'posturl': posturl, 'id': id, 'readonly': readonly}, context_instance=RequestContext(request)) - -def indexProjectFull(request, id): - - urlStr = settings.WEB_URL + reverse("space_ldt_init", args=['ldtProject', id]) - posturl = settings.WEB_URL + reverse("ldt.ldt_utils.views.save_ldtProject") - language_code = request.LANGUAGE_CODE[:2] - - ldt = get_object_or_404(Project, ldt_id=id) - if ldt.state == 2: #published - readonly = 'true' - else: - readonly = 'false' - - return render_to_response('ldt/ldt_utils/init_ldt_full.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': urlStr, 'posturl': posturl, 'id': id, 'readonly': readonly}, context_instance=RequestContext(request)) - -def init(request, method, url): - ldtgen = LdtUtils() - - doc = ldtgen.generateInit([url], 'ldt.ldt_utils.views.' + method, None) - - resp = HttpResponse(mimetype="text/xml") - resp['Cache-Control'] = 'no-cache, must-revalidate' - resp['Pragma'] = 'no-cache' - - resp.write(lxml.etree.tostring(doc, pretty_print=True, xml_declaration=True, encoding="utf-8")) - return resp - -def ldtProject(request, id): - resp = HttpResponse(mimetype="text/xml") - resp['Cache-Control'] = 'no-cache, must-revalidate' - resp['Pragma'] = 'no-cache' - - project = Project.objects.get(ldt_id=id) #@UndefinedVariable - resp.write(project.ldt) - return resp - - -def project_json_id(request, id): - - project = get_object_or_404(Project, ldt_id=id) - - return project_json(request, project, False) - - -def project_json_externalid(request, id): - - res_proj = get_list_or_404(Project.objects.order_by('-modification_date'), contents__external_id=id) #@UndefinedVariable - - return project_json(request, res_proj[0], False) - - - -def project_json(request, project, serialize_contents=True): - - if not ldt_auth.checkAccess(request.user, project): - return HttpResponseForbidden(_("You can not access this project")) - - mimetype = request.REQUEST.get("mimetype") - if mimetype is None: - mimetype = "application/json; charset=utf-8" - else: - mimetype = mimetype.encode("utf-8") - if "charset" not in mimetype: - mimetype += "; charset=utf-8" - resp = HttpResponse(mimetype=mimetype) - resp['Cache-Control'] = 'no-cache, must-revalidate' - resp['Pragma'] = 'no-cache' - - indent = request.REQUEST.get("indent") - if indent is None: - indent = settings.LDT_JSON_DEFAULT_INDENT - else: - indent = int(indent) - - callback = request.REQUEST.get("callback") - escape_str = request.REQUEST.get("escape") - escape_bool = False - if escape_str: - escape_bool = {'true': True, 'false': False, "0": False, "1": True}.get(escape_str.lower()) - - - ps = ProjectSerializer(project, serialize_contents) - project_dict = ps.serialize_to_cinelab() - - json_str = simplejson.dumps(project_dict, ensure_ascii=False, indent=indent) - - if callback is not None: - json_str = "%s(%s)" % (callback, json_str) - - if escape_bool: - json_str = escape(json_str) - - resp.write(json_str) - - return resp - -def project_annotations_rdf(request, ldt_id): - - project = Project.objects.get(ldt_id=ldt_id); #@UndefinedVariable - - if not ldt_auth.checkAccess(request.user, project): - return HttpResponseForbidden(_("You can not access this project")) - - mimetype = request.REQUEST.get("mimetype") - if mimetype is None: - mimetype = "application/rdf+xml; charset=utf-8" - else: - mimetype = mimetype.encode("utf-8") - if "charset" not in mimetype: - mimetype += "; charset=utf-8" - resp = HttpResponse(mimetype=mimetype) - resp['Cache-Control'] = 'no-cache, must-revalidate' - resp['Pragma'] = 'no-cache' - - ps = ProjectSerializer(project, from_contents=False, from_display=True) - annotations = ps.getAnnotations(first_cutting=True) - - rdf_ns = u"http://www.w3.org/1999/02/22-rdf-syntax-ns#" - dc_ns = u"http://purl.org/dc/elements/1.1/" - rdf = u"{%s}" % rdf_ns - dc = u"{%s}" % dc_ns - nsmap = {u'rdf' : rdf_ns, u'dc':dc_ns} - - rdf_root = lxml.etree.Element(rdf + u"RDF", nsmap=nsmap) - - logging.debug("RDF annotations : " + repr(annotations)) #@UndefinedVariable - - for annotation in annotations: - uri = u"" - if 'uri' in annotation and annotation['uri']: - uri = unicode(annotation['uri']) - annot_desc = lxml.etree.SubElement(rdf_root, rdf + u"Description") - annot_desc.set(rdf + u'about', uri) - if annotation['title']: - lxml.etree.SubElement(annot_desc, dc + 'title').text = lxml.etree.CDATA(unicode(annotation['title'])) - if annotation['desc']: - lxml.etree.SubElement(annot_desc, dc + 'description').text = lxml.etree.CDATA(unicode(annotation['desc'])) - if annotation['tags']: - for tag in annotation['tags']: - lxml.etree.SubElement(annot_desc, dc + 'subject').text = lxml.etree.CDATA(unicode(tag)) - lxml.etree.SubElement(annot_desc, dc + 'coverage').text = u"start=%s, duration=%s" % (annotation['begin'], annotation['duration']) - - resp.write(u"\n") - resp.write(u"\n") - - resp.write(lxml.etree.tostring(rdf_root, xml_declaration=False, encoding="utf-8", pretty_print=True)) - - return resp - -def save_ldtProject(request): - if request.method == "POST": - ldt = request.POST['ldt'] - id = request.POST['id'] - ldtproject = Project.objects.get(ldt_id=id) #@UndefinedVariable - - #save xml ldt - ldtproject.ldt = ldt - - - doc = lxml.etree.fromstring(ldtproject.ldt.encode("utf-8")) - result = doc.xpath("/iri/project") - - #set new title - ldtproject.title = result[0].get("title") - - #get new content list - new_contents = [] - result = doc.xpath("/iri/medias/media") - for medianode in result: - id = medianode.get("id") - new_contents.append(id) - - #set new content list - for c in ldtproject.contents.all(): - if not c.iri_id in new_contents: - ldtproject.contents.remove(c) - - ldtproject.save() - else: - ldt = '' - new_contents = [] - - return render_to_response('ldt/ldt_utils/save_done.html', {'ldt': ldt, 'id':id, 'title':ldtproject.title, 'contents': new_contents}, context_instance=RequestContext(request)) - - - -@login_required -def publish(request, id, redirect=True): - ldt = get_object_or_404(Project, ldt_id=id) - ldt.state = 2 #published - ldt.save() - redirect = boolean_convert(redirect) - if redirect: - return HttpResponseRedirect(reverse("ldt.ldt_utils.views.list_ldt")) - else: - return HttpResponse(simplejson.dumps({'res':True, 'ldt': {'id': ldt.id, 'state':ldt.state, 'ldt_id': ldt.ldt_id}}, ensure_ascii=False), mimetype='application/json') - -@login_required -def unpublish(request, id, redirect=True): - ldt = get_object_or_404(Project, ldt_id=id) - ldt.state = 1 #edition - ldt.save() - redirect = boolean_convert(redirect) - if redirect: - return HttpResponseRedirect(reverse("ldt.ldt_utils.views.list_ldt")) - else: - return HttpResponse(simplejson.dumps({'res':True, 'ldt': {'id': ldt.id, 'state':ldt.state, 'ldt_id': ldt.ldt_id}}, ensure_ascii=False), mimetype='application/json') - - -def index(request, url): - - urlStr = settings.WEB_URL + reverse("ldt_init", args=['ldt', url]) - language_code = request.LANGUAGE_CODE[:2] - - return render_to_response('ldt/ldt_utils/init_ldt.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': urlStr, 'weburl':settings.WEB_URL + settings.BASE_URL}, context_instance=RequestContext(request)) - - -def ldt(request, url, startSegment=None): - - resp = HttpResponse(mimetype="text/xml; charset=utf-8") - resp['Cache-Control'] = 'no-cache' - - contentList = Content.objects.filter(iri_id=url) #@UndefinedVariable - - ldtgen = LdtUtils() - ldtgen.generateLdt(contentList, file=resp, title=contentList[0].title, startSegment=startSegment) - - return resp - - -def loading(request): - return render_to_response('ldt/ldt_utils/loading.html', context_instance=RequestContext(request)) - - -@login_required -def create_project(request, iri_id): - - content = get_object_or_404(Content, iri_id=iri_id) - contents = [ content, ] - if request.method == "POST" : - form = AddProjectForm(request.POST) - if form.is_valid(): - user = request.user - project = Project.create_project(title=form.cleaned_data['title'], user=user, contents=contents) - # Modal window is not used with firefox - is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1); - if is_gecko : - return HttpResponseRedirect(reverse('ldt.ldt_utils.views.indexProjectFull', args=[project.ldt_id])) - else: - return HttpResponseRedirect(reverse('ldt.ldt_utils.views.indexProject', args=[project.ldt_id])) - else: - form = AddProjectForm() - # Modal window is not used with firefox, so we ask to submit the form in _parent in firefox case. - target_parent = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1); - return render_to_response('ldt/ldt_utils/create_ldt.html', {'form':form, 'contents':contents, 'create_project_action':reverse("ldt.ldt_utils.views.create_project", args=[iri_id]), 'target_parent':target_parent}, context_instance=RequestContext(request)) - -@login_required -def update_project(request, ldt_id): - - project = get_object_or_404(Project, ldt_id=ldt_id) - contents = project.contents.all() - if request.method == "POST" : - submit_action = request.REQUEST.get("submit_button", False) - if submit_action == "prepare_delete": - errors = [] - if project.state == 2: - errors.append(_("the project %(title)s is published. please unpublish before deleting.") % {'title':project.title}) - message = _("can not delete the project. Please correct the following error") - title = _('title error deleting project') - else: - message = _("please confirm deleting project %(title)s") % {'title':project.title} - title = _("confirm deletion") - return render_to_response('ldt/ldt_utils/error_confirm.html', {'errors':errors, 'message':message, 'title': title}, context_instance=RequestContext(request)) - elif submit_action == "delete": - if project.state != 2: - project.delete() - form_status = 'deleted' - form = AddProjectForm() - else: - form_status = 'saved' - form = AddProjectForm(request.POST) - if form.is_valid(): - if project.title != form.cleaned_data['title']: - project.title = form.cleaned_data['title'] - ldt = lxml.etree.fromstring(project.ldt.encode("utf-8")) - res = ldt.xpath("/iri/project") - res[0].set("title", project.title) - project.ldt = lxml.etree.tostring(ldt, pretty_print=True) - project.save() - else: - form = AddProjectForm({'title':unicode(project.title)}) - form_status = 'none' - - return render_to_response('ldt/ldt_utils/create_ldt.html', {'form':form, 'form_status':form_status, 'ldt_id': ldt_id, 'contents':contents, 'create_project_action':reverse("ldt.ldt_utils.views.update_project", args=[ldt_id])}, context_instance=RequestContext(request)) - - -@login_required -def copy_project(request, ldt_id): - - project = get_object_or_404(Project, ldt_id=ldt_id) - if request.method == "POST" : - form = CopyProjectForm(request.POST) - if form.is_valid(): - user = request.user - project = project.copy_project(title=request.POST['title'], user=user) - return HttpResponseRedirect(reverse('ldt.ldt_utils.views.indexProject', args=[project.ldt_id])) - else: - form = CopyProjectForm - return render_to_response('ldt/ldt_utils/copy_ldt.html', {'form':form, 'project':project}, context_instance=RequestContext(request)) - - -def write_content_base(request, iri_id=None): - - if iri_id: - instance_content = Content.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 - - 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): - for key, value in dict.items(): - dict['%s-%s' % (prefix, key)] = value - del(dict[key]) - - add_prefix(content_instance_val, "content") - 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_form = ContentForm(content_instance_val, prefix="content", instance=instance_content) - media_form = MediaForm(media_instance_val, request.FILES, prefix="media", instance=instance_media) - - media_valid = media_form.is_valid() - content_valid = content_form.is_valid() - - 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)) #@UndefinedVariable - - if media_valid and content_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.objects.get_or_create(src=cleaned_data['src'], defaults=cleaned_data) #@UndefinedVariable - 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'): - 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 - - media.save() - - - if form_status != "error": - #try: - content_defaults = {} - content_defaults.update(content_form.cleaned_data) - content_defaults['media_obj'] = media - del content_defaults["media_input_type"] - content, created = Content.objects.get_or_create(iri_id=content_form.cleaned_data['iri_id'], defaults=content_defaults) #@UndefinedVariable - if not created: - for attribute in ('iriurl', 'title', 'description', 'duration', 'content_creation_date', 'tags', 'media_obj'): - setattr(content, attribute, content_defaults[attribute]) - content.save() - form_status = 'saved' - media_form = MediaForm(instance=media, prefix="media") - content_form = ContentForm(instance=content, prefix="content") - else: - form_status = 'error' - else: - form_status = 'empty' - initial = { 'media_input_type':"link"} - - content_form = ContentForm(prefix="content", instance=instance_content, initial=initial) - media_form = MediaForm(prefix="media", instance=instance_media) - - if instance_content is not None: - content_form.media_input_type = "link" - - return content_form, media_form, form_status - -@login_required -def write_content(request, iri_id=None): - - submit_action = request.REQUEST.get("submit_button", False) - - 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() - else: - content_form, media_form, form_status = write_content_base(request, iri_id) - - if iri_id: - create_content_action = reverse('ldt.ldt_utils.views.write_content', kwargs={'iri_id':iri_id}) - else: - create_content_action = reverse('ldt.ldt_utils.views.write_content') - - session_key = request.COOKIES[settings.SESSION_COOKIE_NAME] - cookie_name = settings.SESSION_COOKIE_NAME - - return render_to_response('ldt/ldt_utils/create_content.html', {'content_form': content_form, 'media_form': media_form, 'form_status': form_status, 'create_content_action': create_content_action, 'iri_id': iri_id, 'session_key':session_key, 'cookie_name':cookie_name}, 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.objects.filter(iri_id=iri_id): #@UndefinedVariable - 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.objects.filter(iri_id=iri_id).delete() #@UndefinedVariable - - -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 removetempfile(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") - +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.core.urlresolvers import reverse +from django.db.models import Q +from django.forms.models import model_to_dict +from django.forms.util import ErrorList +from django.http import (HttpResponse, HttpResponseRedirect, + HttpResponseForbidden, HttpResponseServerError) +from django.shortcuts import (render_to_response, get_object_or_404, + get_list_or_404) +from django.template import RequestContext +from django.template.loader import render_to_string +from django.utils import simplejson +from django.utils.html import escape +from django.utils.translation import ugettext as _, ungettext +from forms import (LdtAddForm, SearchForm, AddProjectForm, CopyProjectForm, + ContentForm, MediaForm) +from ldt.core.models import Owner +from ldt.ldt_utils.models import Content +from ldt.ldt_utils.utils import boolean_convert, LdtUtils, LdtSearch +from lxml.html import fragment_fromstring +from models import Media, Project +from projectserializer import ProjectSerializer +from urllib2 import urlparse +import base64 +import django.core.urlresolvers +import ldt.auth as ldt_auth +import ldt.utils.path as ldt_utils_path +import logging +import lxml.etree +import mimetypes +import os +import urllib2 + + +@login_required +def workspace(request): + + # list of contents + content_list = Content.objects.all() #@UndefinedVariable + + # get list of projects + project_list = Project.objects.all() #@UndefinedVariable + + is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1); + + # render list + return render_to_response("ldt/ldt_utils/workspace.html", + {'contents': content_list, 'projects': project_list, + 'is_gecko': is_gecko}, + context_instance=RequestContext(request)) + + +def popup_embed(request): + + json_url = request.GET.get("json_url") + player_id = request.GET.get("player_id") + ldt_id = request.GET.get("ldt_id") + + + project = Project.objects.get(ldt_id=ldt_id); #@UndefinedVariable + + stream_mode = project.stream_mode + if stream_mode != "video": + stream_mode = 'radio' + + player_width = 650 + player_height = 480 + + if stream_mode == 'radio': + player_height = 1 + + if not ldt_auth.checkAccess(request.user, project): + return HttpResponseForbidden(_("You can not access this project")) + + ps = ProjectSerializer(project, from_contents=False, from_display=True) + annotations = ps.getAnnotations(first_cutting=True) + + rend_dict = {'json_url':json_url, 'player_id':player_id, 'annotations':annotations, 'ldt_id': ldt_id, 'stream_mode': stream_mode, 'player_width': player_width, 'player_height': player_height} + + embed_rendered = dict((typestr, + (lambda s:escape(lxml.etree.tostring(fragment_fromstring(render_to_string("ldt/ldt_utils/partial/embed_%s.html" % (s), rend_dict, context_instance=RequestContext(request))), pretty_print=True)))(typestr)) + for typestr in ('player', 'seo_body', 'seo_meta', 'links')) + + rend_dict['embed_rendered'] = embed_rendered + + return render_to_response("ldt/ldt_utils/embed_popup.html", + rend_dict, + context_instance=RequestContext(request)) + + + +@login_required +def projectsfilter(request, filter, is_owner=False, status=0): + + is_owner = boolean_convert(is_owner) + status = int(status) + query = Q() + + if is_owner: + owner = None + try: + owner = Owner.objects.get(user=request.user) #@UndefinedVariable + except: + return HttpResponseServerError("

User not found

") + query &= Q(owner=owner) + + if status > 0: + query &= Q(state=status) + + if filter: + if len(filter) > 0 and filter[0] == '_': + filter = filter[1:] + query &= Q(title__icontains=filter) + + project_list = Project.objects.filter(query) #@UndefinedVariable + + is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1); + + return render_to_response("ldt/ldt_utils/partial/projectslist.html", + {'projects': project_list, 'is_gecko': is_gecko}, + context_instance=RequestContext(request)) + + + +@login_required +def contentsfilter(request, filter): + if filter and len(filter) > 0 and filter[0] == '_': + filter = filter[1:] + + if filter: + content_list = Content.objects.filter(title__icontains=filter) #@UndefinedVariable + else: + content_list = Content.objects.all() #@UndefinedVariable + + return render_to_response("ldt/ldt_utils/partial/contentslist.html", + {'contents': content_list}, + context_instance=RequestContext(request)) + + +def searchForm(request): + form = SearchForm() + return render_to_response('ldt/ldt_utils/search_form.html', {'form': form} , context_instance=RequestContext(request)) + +def searchIndex(request): + + sform = SearchForm(request.POST) + if sform.is_valid(): + search = sform.cleaned_data["search"] + + + queryStr = base64.urlsafe_b64encode(search.encode('utf8')) + field = request.POST["field"] + language_code = request.LANGUAGE_CODE[:2] + + url = settings.WEB_URL + django.core.urlresolvers.reverse("ldt.ldt_utils.views.searchInit", args=[field, queryStr]) + return render_to_response('ldt/ldt_utils/init_ldt.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': url}, context_instance=RequestContext(request)) + else: + resp = HttpResponse() + resp.write("Error : No result"); + +def searchIndexGet(request, field, query): + + language_code = request.LANGUAGE_CODE[:2] + url = settings.WEB_URL + django.core.urlresolvers.reverse("ldt.ldt_utils.views.searchInit", args=[field, query]) + return render_to_response('ldt/ldt_utils/init_ldt.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': url}, context_instance=RequestContext(request)) + +def searchInit(request, field, query): + + ldtgen = LdtUtils() + + doc = ldtgen.generateInit([field, query], 'ldt.ldt_utils.views.searchLdt', 'ldt.ldt_utils.views.searchSegments') + + resp = HttpResponse(mimetype="text/xml;charset=utf-8") + doc.write(resp, pretty_print=True) + return resp + +def searchLdt(request, field, query, edition=None): + + contentList = [] + resp = HttpResponse(mimetype="text/xml") + queryStr = "" + + if query and len(query) > 0: + queryStr = base64.urlsafe_b64decode(query.encode("ascii")).decode("utf8") + searcher = LdtSearch() + ids = {} + + for result in searcher.query(field, queryStr): + ids[result["iri_id"]] = "" + + id_list = ids.keys() + + #if edition is not None: + # ids_editions = map(lambda t:t[0], filter(lambda id: id[0] is not None, Speak.objects.filter(session__day__edition=edition).order_by("session__start_ts", "order").values_list("content__iri_id"))) + # id_list = filter(lambda id: id in id_list, ids_editions) + + contentList = Content.objects.filter(iri_id__in=id_list) #@UndefinedVariable + + + ldtgen = LdtUtils() + ldtgen.generateLdt(contentList, file=resp, title=u"Recherche : " + queryStr) + + return resp + + +def searchSegments(request, field, query, edition=None): + + if query and len(query) > 0: + searcher = LdtSearch() + + queryStr = base64.urlsafe_b64decode(query.encode("ascii")).decode("utf8") + res = searcher.query(field, queryStr) + else: + res = [] + + iri_ids = None + + #if edition is not None: + # iri_ids = map(lambda t:t[0], filter(lambda id: id[0] is not None, Speak.objects.filter(session__day__edition=edition).order_by("session__start_ts", "order").values_list("content__iri_id"))) + + iri = lxml.etree.Element('iri') + doc = lxml.etree.ElementTree(iri) + + for resultMap in res: + if iri_ids is None or resultMap['iri_id'] in iri_ids: + seg = lxml.etree.SubElement(iri, 'seg') + seg.set('idctt', resultMap['iri_id']) + seg.set('idens', resultMap['ensemble_id']) + seg.set('iddec', resultMap['decoupage_id']) + seg.set('idseg', resultMap['element_id']) + seg.set('idvue', "") + seg.set('crit', "") + + return doc + + return HttpResponse(lxml.etree.tostring(doc, pretty_print=True), mimetype="text/xml;charset=utf-8") + + + +@login_required +def list_ldt(request): + contents = Content.objects.all() #@UndefinedVariable + try: + owner = Owner.objects.get(user=request.user) #@UndefinedVariable + except: + return HttpResponseRedirect(settings.LOGIN_URL) + ldtProjects = Project.objects.filter(owner=owner) #@UndefinedVariable + context = { + 'contents': contents, + 'projects': ldtProjects.reverse(), + } + return render_to_response('ldt/ldt_utils/ldt_list.html', context, context_instance=RequestContext(request)) + +@login_required +def list_content(request): + contents = Content.objects.all() #@UndefinedVariable + context = { + 'contents': contents, + } + return render_to_response('ldt/ldt_utils/content_list.html', context, context_instance=RequestContext(request)) + +@login_required +def create_ldt_view(request): + if request.method == "POST" : + form = LdtAddForm(request.POST) + if form.is_valid(): + user = request.user + Project.create_project(title=form.cleaned_data['title'], user=user, contents=form.cleaned_data['contents']) + form_status = "saved" + contents = [] + else: + form = LdtAddForm() + contents = Content.objects.all() #@UndefinedVariable + form_status = "none" + + return render_to_response('ldt/ldt_utils/create_ldt.html', {'contents': contents, 'form': form, 'form_status':form_status, 'create_project_action':reverse(create_ldt_view)}, context_instance=RequestContext(request)) + +def created_ldt(request): + return render_to_response('ldt/ldt_utils/save_done.html', context_instance=RequestContext(request)) + +def index_segment(request, project_id, content_id, cutting_id, ensemble_id, segment_id): + pass + +def init_segment(request, project_id, content_id, cutting_id, ensemble_id, segment_id): + pass + +def ldt_segment(request, project_id, content_id, cutting_id, ensemble_id, segment_id): + pass + +def indexProject(request, id): + + urlStr = settings.WEB_URL + reverse("space_ldt_init", args=['ldtProject', id]) + posturl = settings.WEB_URL + reverse("ldt.ldt_utils.views.save_ldtProject") + language_code = request.LANGUAGE_CODE[:2] + + ldt = get_object_or_404(Project, ldt_id=id) + if ldt.state == 2: #published + readonly = 'true' + else: + readonly = 'false' + + return render_to_response('ldt/ldt_utils/init_ldt.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': urlStr, 'posturl': posturl, 'id': id, 'readonly': readonly}, context_instance=RequestContext(request)) + +def indexProjectFull(request, id): + + urlStr = settings.WEB_URL + reverse("space_ldt_init", args=['ldtProject', id]) + posturl = settings.WEB_URL + reverse("ldt.ldt_utils.views.save_ldtProject") + language_code = request.LANGUAGE_CODE[:2] + + ldt = get_object_or_404(Project, ldt_id=id) + if ldt.state == 2: #published + readonly = 'true' + else: + readonly = 'false' + + return render_to_response('ldt/ldt_utils/init_ldt_full.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': urlStr, 'posturl': posturl, 'id': id, 'readonly': readonly}, context_instance=RequestContext(request)) + +def init(request, method, url): + ldtgen = LdtUtils() + + doc = ldtgen.generateInit([url], 'ldt.ldt_utils.views.' + method, None) + + resp = HttpResponse(mimetype="text/xml") + resp['Cache-Control'] = 'no-cache, must-revalidate' + resp['Pragma'] = 'no-cache' + + resp.write(lxml.etree.tostring(doc, pretty_print=True, xml_declaration=True, encoding="utf-8")) + return resp + +def ldtProject(request, id): + resp = HttpResponse(mimetype="text/xml") + resp['Cache-Control'] = 'no-cache, must-revalidate' + resp['Pragma'] = 'no-cache' + + project = Project.objects.get(ldt_id=id) #@UndefinedVariable + resp.write(project.ldt) + return resp + + +def project_json_id(request, id): + + project = get_object_or_404(Project, ldt_id=id) + + return project_json(request, project, False) + + +def project_json_externalid(request, id): + + res_proj = get_list_or_404(Project.objects.order_by('-modification_date'), contents__external_id=id) #@UndefinedVariable + + return project_json(request, res_proj[0], False) + + + +def project_json(request, project, serialize_contents=True): + + if not ldt_auth.checkAccess(request.user, project): + return HttpResponseForbidden(_("You can not access this project")) + + mimetype = request.REQUEST.get("mimetype") + if mimetype is None: + mimetype = "application/json; charset=utf-8" + else: + mimetype = mimetype.encode("utf-8") + if "charset" not in mimetype: + mimetype += "; charset=utf-8" + resp = HttpResponse(mimetype=mimetype) + resp['Cache-Control'] = 'no-cache, must-revalidate' + resp['Pragma'] = 'no-cache' + + indent = request.REQUEST.get("indent") + if indent is None: + indent = settings.LDT_JSON_DEFAULT_INDENT + else: + indent = int(indent) + + callback = request.REQUEST.get("callback") + escape_str = request.REQUEST.get("escape") + escape_bool = False + if escape_str: + escape_bool = {'true': True, 'false': False, "0": False, "1": True}.get(escape_str.lower()) + + + ps = ProjectSerializer(project, serialize_contents) + project_dict = ps.serialize_to_cinelab() + + json_str = simplejson.dumps(project_dict, ensure_ascii=False, indent=indent) + + if callback is not None: + json_str = "%s(%s)" % (callback, json_str) + + if escape_bool: + json_str = escape(json_str) + + resp.write(json_str) + + return resp + +def project_annotations_rdf(request, ldt_id): + + project = Project.objects.get(ldt_id=ldt_id); #@UndefinedVariable + + if not ldt_auth.checkAccess(request.user, project): + return HttpResponseForbidden(_("You can not access this project")) + + mimetype = request.REQUEST.get("mimetype") + if mimetype is None: + mimetype = "application/rdf+xml; charset=utf-8" + else: + mimetype = mimetype.encode("utf-8") + if "charset" not in mimetype: + mimetype += "; charset=utf-8" + resp = HttpResponse(mimetype=mimetype) + resp['Cache-Control'] = 'no-cache, must-revalidate' + resp['Pragma'] = 'no-cache' + + ps = ProjectSerializer(project, from_contents=False, from_display=True) + annotations = ps.getAnnotations(first_cutting=True) + + rdf_ns = u"http://www.w3.org/1999/02/22-rdf-syntax-ns#" + dc_ns = u"http://purl.org/dc/elements/1.1/" + rdf = u"{%s}" % rdf_ns + dc = u"{%s}" % dc_ns + nsmap = {u'rdf' : rdf_ns, u'dc':dc_ns} + + rdf_root = lxml.etree.Element(rdf + u"RDF", nsmap=nsmap) + + logging.debug("RDF annotations : " + repr(annotations)) #@UndefinedVariable + + for annotation in annotations: + uri = u"" + if 'uri' in annotation and annotation['uri']: + uri = unicode(annotation['uri']) + annot_desc = lxml.etree.SubElement(rdf_root, rdf + u"Description") + annot_desc.set(rdf + u'about', uri) + if annotation['title']: + lxml.etree.SubElement(annot_desc, dc + 'title').text = lxml.etree.CDATA(unicode(annotation['title'])) + if annotation['desc']: + lxml.etree.SubElement(annot_desc, dc + 'description').text = lxml.etree.CDATA(unicode(annotation['desc'])) + if annotation['tags']: + for tag in annotation['tags']: + lxml.etree.SubElement(annot_desc, dc + 'subject').text = lxml.etree.CDATA(unicode(tag)) + lxml.etree.SubElement(annot_desc, dc + 'coverage').text = u"start=%s, duration=%s" % (annotation['begin'], annotation['duration']) + + resp.write(u"\n") + resp.write(u"\n") + + resp.write(lxml.etree.tostring(rdf_root, xml_declaration=False, encoding="utf-8", pretty_print=True)) + + return resp + +def save_ldtProject(request): + if request.method == "POST": + ldt = request.POST['ldt'] + id = request.POST['id'] + ldtproject = Project.objects.get(ldt_id=id) #@UndefinedVariable + + #save xml ldt + ldtproject.ldt = ldt + + + doc = lxml.etree.fromstring(ldtproject.ldt.encode("utf-8")) + result = doc.xpath("/iri/project") + + #set new title + ldtproject.title = result[0].get("title") + + #get new content list + new_contents = [] + result = doc.xpath("/iri/medias/media") + for medianode in result: + id = medianode.get("id") + new_contents.append(id) + + #set new content list + for c in ldtproject.contents.all(): + if not c.iri_id in new_contents: + ldtproject.contents.remove(c) + + ldtproject.save() + else: + ldt = '' + new_contents = [] + + return render_to_response('ldt/ldt_utils/save_done.html', {'ldt': ldt, 'id':id, 'title':ldtproject.title, 'contents': new_contents}, context_instance=RequestContext(request)) + + + +@login_required +def publish(request, id, redirect=True): + ldt = get_object_or_404(Project, ldt_id=id) + ldt.state = 2 #published + ldt.save() + redirect = boolean_convert(redirect) + if redirect: + return HttpResponseRedirect(reverse("ldt.ldt_utils.views.list_ldt")) + else: + return HttpResponse(simplejson.dumps({'res':True, 'ldt': {'id': ldt.id, 'state':ldt.state, 'ldt_id': ldt.ldt_id}}, ensure_ascii=False), mimetype='application/json') + +@login_required +def unpublish(request, id, redirect=True): + ldt = get_object_or_404(Project, ldt_id=id) + ldt.state = 1 #edition + ldt.save() + redirect = boolean_convert(redirect) + if redirect: + return HttpResponseRedirect(reverse("ldt.ldt_utils.views.list_ldt")) + else: + return HttpResponse(simplejson.dumps({'res':True, 'ldt': {'id': ldt.id, 'state':ldt.state, 'ldt_id': ldt.ldt_id}}, ensure_ascii=False), mimetype='application/json') + + +def index(request, url): + + urlStr = settings.WEB_URL + reverse("ldt_init", args=['ldt', url]) + language_code = request.LANGUAGE_CODE[:2] + + return render_to_response('ldt/ldt_utils/init_ldt.html', {'LDT_MEDIA_PREFIX': settings.LDT_MEDIA_PREFIX, 'colorurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/color.xml', 'i18nurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/pkg/i18n', 'language': language_code, 'baseurl': settings.LDT_MEDIA_PREFIX + 'swf/ldt/', 'url': urlStr, 'weburl':settings.WEB_URL + settings.BASE_URL}, context_instance=RequestContext(request)) + + +def ldt(request, url, startSegment=None): + + resp = HttpResponse(mimetype="text/xml; charset=utf-8") + resp['Cache-Control'] = 'no-cache' + + contentList = Content.objects.filter(iri_id=url) #@UndefinedVariable + + ldtgen = LdtUtils() + ldtgen.generateLdt(contentList, file=resp, title=contentList[0].title, startSegment=startSegment) + + return resp + + +def loading(request): + return render_to_response('ldt/ldt_utils/loading.html', context_instance=RequestContext(request)) + + +@login_required +def create_project(request, iri_id): + + content = get_object_or_404(Content, iri_id=iri_id) + contents = [ content, ] + if request.method == "POST" : + form = AddProjectForm(request.POST) + if form.is_valid(): + user = request.user + project = Project.create_project(title=form.cleaned_data['title'], user=user, contents=contents) + # Modal window is not used with firefox + is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1); + if is_gecko : + return HttpResponseRedirect(reverse('ldt.ldt_utils.views.indexProjectFull', args=[project.ldt_id])) + else: + return HttpResponseRedirect(reverse('ldt.ldt_utils.views.indexProject', args=[project.ldt_id])) + else: + form = AddProjectForm() + # Modal window is not used with firefox, so we ask to submit the form in _parent in firefox case. + target_parent = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1); + return render_to_response('ldt/ldt_utils/create_ldt.html', {'form':form, 'contents':contents, 'create_project_action':reverse("ldt.ldt_utils.views.create_project", args=[iri_id]), 'target_parent':target_parent}, context_instance=RequestContext(request)) + +@login_required +def update_project(request, ldt_id): + + project = get_object_or_404(Project, ldt_id=ldt_id) + contents = project.contents.all() + if request.method == "POST" : + submit_action = request.REQUEST.get("submit_button", False) + if submit_action == "prepare_delete": + errors = [] + if project.state == 2: + errors.append(_("the project %(title)s is published. please unpublish before deleting.") % {'title':project.title}) + message = _("can not delete the project. Please correct the following error") + title = _('title error deleting project') + else: + message = _("please confirm deleting project %(title)s") % {'title':project.title} + title = _("confirm deletion") + return render_to_response('ldt/ldt_utils/error_confirm.html', {'errors':errors, 'message':message, 'title': title}, context_instance=RequestContext(request)) + elif submit_action == "delete": + if project.state != 2: + project.delete() + form_status = 'deleted' + form = AddProjectForm() + else: + form_status = 'saved' + form = AddProjectForm(request.POST) + if form.is_valid(): + if project.title != form.cleaned_data['title']: + project.title = form.cleaned_data['title'] + ldt = lxml.etree.fromstring(project.ldt.encode("utf-8")) + res = ldt.xpath("/iri/project") + res[0].set("title", project.title) + project.ldt = lxml.etree.tostring(ldt, pretty_print=True) + project.save() + else: + form = AddProjectForm({'title':unicode(project.title)}) + form_status = 'none' + + return render_to_response('ldt/ldt_utils/create_ldt.html', {'form':form, 'form_status':form_status, 'ldt_id': ldt_id, 'contents':contents, 'create_project_action':reverse("ldt.ldt_utils.views.update_project", args=[ldt_id])}, context_instance=RequestContext(request)) + + +@login_required +def copy_project(request, ldt_id): + + project = get_object_or_404(Project, ldt_id=ldt_id) + if request.method == "POST" : + form = CopyProjectForm(request.POST) + if form.is_valid(): + user = request.user + project = project.copy_project(title=request.POST['title'], user=user) + return HttpResponseRedirect(reverse('ldt.ldt_utils.views.indexProject', args=[project.ldt_id])) + else: + form = CopyProjectForm + return render_to_response('ldt/ldt_utils/copy_ldt.html', {'form':form, 'project':project}, context_instance=RequestContext(request)) + + +def write_content_base(request, iri_id=None): + + if iri_id: + instance_content = Content.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 + + 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): + for key, value in dict.items(): + dict['%s-%s' % (prefix, key)] = value + del(dict[key]) + + add_prefix(content_instance_val, "content") + 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_form = ContentForm(content_instance_val, prefix="content", instance=instance_content) + media_form = MediaForm(media_instance_val, request.FILES, prefix="media", instance=instance_media) + + media_valid = media_form.is_valid() + content_valid = content_form.is_valid() + + 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)) #@UndefinedVariable + + if media_valid and content_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.objects.get_or_create(src=cleaned_data['src'], defaults=cleaned_data) #@UndefinedVariable + 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'): + 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 + + media.save() + + + if form_status != "error": + #try: + content_defaults = {} + content_defaults.update(content_form.cleaned_data) + content_defaults['media_obj'] = media + del content_defaults["media_input_type"] + content, created = Content.objects.get_or_create(iri_id=content_form.cleaned_data['iri_id'], defaults=content_defaults) #@UndefinedVariable + if not created: + for attribute in ('iriurl', 'title', 'description', 'duration', 'content_creation_date', 'tags', 'media_obj'): + setattr(content, attribute, content_defaults[attribute]) + content.save() + form_status = 'saved' + media_form = MediaForm(instance=media, prefix="media") + content_form = ContentForm(instance=content, prefix="content") + else: + form_status = 'error' + else: + form_status = 'empty' + initial = { 'media_input_type':"link"} + + content_form = ContentForm(prefix="content", instance=instance_content, initial=initial) + media_form = MediaForm(prefix="media", instance=instance_media) + + if instance_content is not None: + content_form.media_input_type = "link" + + return content_form, media_form, form_status + +@login_required +def write_content(request, iri_id=None): + + submit_action = request.REQUEST.get("submit_button", False) + + 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() + else: + content_form, media_form, form_status = write_content_base(request, iri_id) + + if iri_id: + create_content_action = reverse('ldt.ldt_utils.views.write_content', kwargs={'iri_id':iri_id}) + else: + create_content_action = reverse('ldt.ldt_utils.views.write_content') + + session_key = request.COOKIES[settings.SESSION_COOKIE_NAME] + cookie_name = settings.SESSION_COOKIE_NAME + + return render_to_response('ldt/ldt_utils/create_content.html', {'content_form': content_form, 'media_form': media_form, 'form_status': form_status, 'create_content_action': create_content_action, 'iri_id': iri_id, 'session_key':session_key, 'cookie_name':cookie_name}, 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.objects.filter(iri_id=iri_id): #@UndefinedVariable + 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.objects.filter(iri_id=iri_id).delete() #@UndefinedVariable + + +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 removetempfile(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") + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/settings.py --- a/src/ldt/ldt/settings.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/settings.py Mon May 16 20:00:36 2011 +0200 @@ -1,77 +1,77 @@ -import logging -from django.conf import settings - - -# EMAIL_HOST='smtp.gmail.com' -# EMAIL_HOST_USER = 'wujingwen1112@gmail.com' -# EMAIL_HOST_PASSWORD='jingwen1112' -# EMAIL_PORT='587' -# EMAIL_USE_TLS = True -#DEFAULT_FROM_EMAIL = "admin@domain.com" -#SERVER_EMAIL = "admin@domain.com" - -INSTALLED_APPS = ( - 'django_extensions', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.admin', - 'registration', - 'tagging', - 'ldt', - 'ldt.core', - 'ldt.ldt_utils', - 'ldt.text', - 'ldt.user', - 'ldt.management', - 'oauth_provider', - 'django_openid_consumer', - 'piston', - 'social_auth', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'ldt.ldt_utils.middleware.swfupload.SWFUploadMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.middleware.locale.LocaleMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django_openid_consumer.middleware.OpenIDMiddleware', -) - - - -WEB_URL = getattr(settings, 'WEB_URL', '') -BASE_URL = getattr(settings, 'BASE_URL', '') -STATIC_URL = getattr(settings, 'STATIC_URL', '') -MEDIA_URL = getattr(settings, 'MEDIA_URL', '') -MEDIA_ROOT = getattr(settings, 'MEDIA_ROOT', '') -SITE_ID = getattr(settings, 'SITE_ID', 1) -DEBUG = getattr(settings, 'DEBUG', True) -MANAGERS = settings.MANAGERS -INSTALLED_APPS = settings.INSTALLED_APPS -LANGUAGES = settings.LANGUAGES -DECOUPAGE_BLACKLIST = getattr(settings, 'DECOUPAGE_BLACKLIST', 'de_PPP') -STREAM_URL = getattr(settings, 'STREAM_URL', '') -STREAM_PATH = getattr(settings, 'STREAM_PATH', '') -STREAM_SRC_PREFIX = getattr(settings, 'STREAM_SRC_PREFIX', '') -LOG_FILE = getattr(settings, 'LOG_FILE', '') -LOG_LEVEL = getattr(settings, 'LOG_LEVEL', logging.INFO) -EMPTY_MEDIA_EXTERNALID = getattr(settings, 'EMPTY_MEDIA_EXTERNALID', None) - -GLOBAL_LOG_LEVEL = LOG_LEVEL -GLOBAL_LOG_HANDLERS = [logging.FileHandler(LOG_FILE)] - -TEST_WEBSERVER_ADDRPORT = getattr(settings, 'TEST_WEBSERVER_ADDRPORT', '127.0.0.1:8000') - -ACCOUNT_ACTIVATION_DAYS = getattr(settings, 'ACCOUNT_ACTIVATION_DAYS', 7) -LDT_MEDIA_PREFIX = getattr(settings, 'LDT_MEDIA_PREFIX', MEDIA_URL + 'ldt/') -LDT_MAX_SEARCH_NUMBER = 50 -LDT_JSON_DEFAULT_INDENT = 2 - -AUTO_INDEX_AFTER_SAVE = getattr(settings, 'AUTO_INDEX_AFTER_SAVE', True) - +import logging +from django.conf import settings + + +# EMAIL_HOST='smtp.gmail.com' +# EMAIL_HOST_USER = 'wujingwen1112@gmail.com' +# EMAIL_HOST_PASSWORD='jingwen1112' +# EMAIL_PORT='587' +# EMAIL_USE_TLS = True +#DEFAULT_FROM_EMAIL = "admin@domain.com" +#SERVER_EMAIL = "admin@domain.com" + +INSTALLED_APPS = ( + 'django_extensions', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.admin', + 'registration', + 'tagging', + 'ldt', + 'ldt.core', + 'ldt.ldt_utils', + 'ldt.text', + 'ldt.user', + 'ldt.management', + 'oauth_provider', + 'django_openid_consumer', + 'piston', + 'social_auth', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'ldt.ldt_utils.middleware.swfupload.SWFUploadMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django_openid_consumer.middleware.OpenIDMiddleware', +) + + + +WEB_URL = getattr(settings, 'WEB_URL', '') +BASE_URL = getattr(settings, 'BASE_URL', '') +STATIC_URL = getattr(settings, 'STATIC_URL', '') +MEDIA_URL = getattr(settings, 'MEDIA_URL', '') +MEDIA_ROOT = getattr(settings, 'MEDIA_ROOT', '') +SITE_ID = getattr(settings, 'SITE_ID', 1) +DEBUG = getattr(settings, 'DEBUG', True) +MANAGERS = settings.MANAGERS +INSTALLED_APPS = settings.INSTALLED_APPS +LANGUAGES = settings.LANGUAGES +DECOUPAGE_BLACKLIST = getattr(settings, 'DECOUPAGE_BLACKLIST', 'de_PPP') +STREAM_URL = getattr(settings, 'STREAM_URL', '') +STREAM_PATH = getattr(settings, 'STREAM_PATH', '') +STREAM_SRC_PREFIX = getattr(settings, 'STREAM_SRC_PREFIX', '') +LOG_FILE = getattr(settings, 'LOG_FILE', '') +LOG_LEVEL = getattr(settings, 'LOG_LEVEL', logging.INFO) +EMPTY_MEDIA_EXTERNALID = getattr(settings, 'EMPTY_MEDIA_EXTERNALID', None) + +GLOBAL_LOG_LEVEL = LOG_LEVEL +GLOBAL_LOG_HANDLERS = [logging.FileHandler(LOG_FILE)] + +TEST_WEBSERVER_ADDRPORT = getattr(settings, 'TEST_WEBSERVER_ADDRPORT', '127.0.0.1:8000') + +ACCOUNT_ACTIVATION_DAYS = getattr(settings, 'ACCOUNT_ACTIVATION_DAYS', 7) +LDT_MEDIA_PREFIX = getattr(settings, 'LDT_MEDIA_PREFIX', MEDIA_URL + 'ldt/') +LDT_MAX_SEARCH_NUMBER = 50 +LDT_JSON_DEFAULT_INDENT = 2 + +AUTO_INDEX_AFTER_SAVE = getattr(settings, 'AUTO_INDEX_AFTER_SAVE', True) + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/css/LdtPlayer.css --- a/src/ldt/ldt/static/ldt/css/LdtPlayer.css Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/css/LdtPlayer.css Mon May 16 20:00:36 2011 +0200 @@ -1,165 +1,165 @@ - #demo-frame > div.demo { padding: 5px !important; }; - - button.ui-button-icon-only { - height:1.5em; - width:1.5em; - } - - #Ldt-loader { - background:url(imgs/loader.gif) no-repeat; - width:20px; - height:16px; - float:left; - } - - #Ldt-controler { - font-size: 62.5%; - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - background-color:#eeeeee; - height:35px; - padding:5px; - } - - .Ldt-iri-chapter{ - padding-top:10px; - padding-bottom:5px; - border-left:solid 1px #000; - border-right:solid 1px #000; - } - - .tooltip { - display:none; - background:transparent url(imgs/white_arrow_mini.png); - font-size:12px; - height:55px; - width:180px; - padding:10px; - padding-left:15px; - padding-top:15px; - padding-right:15px; - color:#000; - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - } - #Ldt-Root{ - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - } - #Ldt-Hat{ - height:3px; - } - #Ldt-Annotations{ - padding-left:5px; - width:470px; - float:left; - font-size: 62.5%; - } - #Ldt-SaTitle{ - padding-top:2px; - padding-bottom:5px; - font-size:18px; - height:22p; - } - #Ldt-SaDescription{ - font-size:12px; - } - #Ldt-Show-Arrow-container{ - margin-left:60px; - } - #Ldt-Show-Arrow{ - position:relative; - background:url(imgs/grey_arrow_Show.png); - width:27px; - height:13px; - margin-top:12px; - margin-left:-10px; - } - - #Ldt-Show-Tags{ - position:relative; - height:13px; - margin-top:-10px; - border: solid 1px #000; - } - #Ldt-ShowAnnotation-video{ - position:absolute; - z-index: 999; - padding:5px; - background:url(imgs/transBlack.png); - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - color:#FFF; - } - #Ldt-ShowAnnotation-audio{ - position:relative; - padding:5px; - background-color:#cfcfcf; - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - color:#4D4D4D; - } - #Ldt-SaKeyword{ - background-color:#b9b9b9; - color:#4D4D4D; - padding:5px; - font-weight:bold; - text-align:left; - float:left; - font-size:10px; - } - #Ldt-SaShareTools{ - text-align:right; - float:right; - } - - - #Ldt-PlaceHolder{ - position:absolue; - float:none; - } - - .Ldt-mode-radio{ - visibility:hidden; - height:0px; - display:none - } - - .Ldt-Control1{ - width:60px; - float:left; - } - .Ldt-Control2{ - padding-left:10px; - width:60px; - float:left; - } - .Ldt-cleaner { - clear:both; - } - .share { - background:url('imgs/widget20.png') no-repeat scroll 0 0 transparent ; - display:block; - height:16px; - line-height:16px !important; - overflow:hidden; - width:16px; - float:left; - cursor:pointer; - margin:2px; - } - .shareFacebook{ - background-position:0 -704px; - } - .shareMySpace{ - background-position:0 -736px; - } - .shareTwitter{ - background-position:0 -1072px; - } - .shareGoogle{ - background-position:0 -752px; - } - .shareDelicious{ - background-position:0 -672px; - } - .shareJamesPot{ - background-position:0 -1808px; - } - + #demo-frame > div.demo { padding: 5px !important; }; + + button.ui-button-icon-only { + height:1.5em; + width:1.5em; + } + + #Ldt-loader { + background:url(imgs/loader.gif) no-repeat; + width:20px; + height:16px; + float:left; + } + + #Ldt-controler { + font-size: 62.5%; + font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; + background-color:#eeeeee; + height:35px; + padding:5px; + } + + .Ldt-iri-chapter{ + padding-top:10px; + padding-bottom:5px; + border-left:solid 1px #000; + border-right:solid 1px #000; + } + + .tooltip { + display:none; + background:transparent url(imgs/white_arrow_mini.png); + font-size:12px; + height:55px; + width:180px; + padding:10px; + padding-left:15px; + padding-top:15px; + padding-right:15px; + color:#000; + font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; + } + #Ldt-Root{ + font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; + } + #Ldt-Hat{ + height:3px; + } + #Ldt-Annotations{ + padding-left:5px; + width:470px; + float:left; + font-size: 62.5%; + } + #Ldt-SaTitle{ + padding-top:2px; + padding-bottom:5px; + font-size:18px; + height:22p; + } + #Ldt-SaDescription{ + font-size:12px; + } + #Ldt-Show-Arrow-container{ + margin-left:60px; + } + #Ldt-Show-Arrow{ + position:relative; + background:url(imgs/grey_arrow_Show.png); + width:27px; + height:13px; + margin-top:12px; + margin-left:-10px; + } + + #Ldt-Show-Tags{ + position:relative; + height:13px; + margin-top:-10px; + border: solid 1px #000; + } + #Ldt-ShowAnnotation-video{ + position:absolute; + z-index: 999; + padding:5px; + background:url(imgs/transBlack.png); + font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; + color:#FFF; + } + #Ldt-ShowAnnotation-audio{ + position:relative; + padding:5px; + background-color:#cfcfcf; + font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; + color:#4D4D4D; + } + #Ldt-SaKeyword{ + background-color:#b9b9b9; + color:#4D4D4D; + padding:5px; + font-weight:bold; + text-align:left; + float:left; + font-size:10px; + } + #Ldt-SaShareTools{ + text-align:right; + float:right; + } + + + #Ldt-PlaceHolder{ + position:absolue; + float:none; + } + + .Ldt-mode-radio{ + visibility:hidden; + height:0px; + display:none + } + + .Ldt-Control1{ + width:60px; + float:left; + } + .Ldt-Control2{ + padding-left:10px; + width:60px; + float:left; + } + .Ldt-cleaner { + clear:both; + } + .share { + background:url('imgs/widget20.png') no-repeat scroll 0 0 transparent ; + display:block; + height:16px; + line-height:16px !important; + overflow:hidden; + width:16px; + float:left; + cursor:pointer; + margin:2px; + } + .shareFacebook{ + background-position:0 -704px; + } + .shareMySpace{ + background-position:0 -736px; + } + .shareTwitter{ + background-position:0 -1072px; + } + .shareGoogle{ + background-position:0 -752px; + } + .shareDelicious{ + background-position:0 -672px; + } + .shareJamesPot{ + background-position:0 -1808px; + } + \ No newline at end of file diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/css/blueprint/plugins/fancy-type/screen.css --- a/src/ldt/ldt/static/ldt/css/blueprint/plugins/fancy-type/screen.css Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/css/blueprint/plugins/fancy-type/screen.css Mon May 16 20:00:36 2011 +0200 @@ -1,71 +1,71 @@ -/* -------------------------------------------------------------- - - fancy-type.css - * Lots of pretty advanced classes for manipulating text. - - See the Readme file in this folder for additional instructions. - --------------------------------------------------------------- */ - -/* Indentation instead of line shifts for sibling paragraphs. */ - p + p { text-indent:2em; margin-top:-1.5em; } - form p + p { text-indent: 0; } /* Don't want this in forms. */ - - -/* For great looking type, use this code instead of asdf: - asdf - Best used on prepositions and ampersands. */ - -.alt { - color: #666; - font-family: "Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua", Georgia, serif; - font-style: italic; - font-weight: normal; -} - - -/* For great looking quote marks in titles, replace "asdf" with: - asdf” - (That is, when the title starts with a quote mark). - (You may have to change this value depending on your font size). */ - -.dquo { margin-left: -.5em; } - - -/* Reduced size type with incremental leading - (http://www.markboulton.co.uk/journal/comments/incremental_leading/) - - This could be used for side notes. For smaller type, you don't necessarily want to - follow the 1.5x vertical rhythm -- the line-height is too much. - - Using this class, it reduces your font size and line-height so that for - every four lines of normal sized type, there is five lines of the sidenote. eg: - - New type size in em's: - 10px (wanted side note size) / 12px (existing base size) = 0.8333 (new type size in ems) - - New line-height value: - 12px x 1.5 = 18px (old line-height) - 18px x 4 = 72px - 72px / 5 = 14.4px (new line height) - 14.4px / 10px = 1.44 (new line height in em's) */ - -p.incr, .incr p { - font-size: 10px; - line-height: 1.44em; - margin-bottom: 1.5em; -} - - -/* Surround uppercase words and abbreviations with this class. - Based on work by Jørgen Arnor GÃ¥rdsø Lom [http://twistedintellect.com/] */ - -.caps { - font-variant: small-caps; - letter-spacing: 1px; - text-transform: lowercase; - font-size:1.2em; - line-height:1%; - font-weight:bold; - padding:0 2px; -} +/* -------------------------------------------------------------- + + fancy-type.css + * Lots of pretty advanced classes for manipulating text. + + See the Readme file in this folder for additional instructions. + +-------------------------------------------------------------- */ + +/* Indentation instead of line shifts for sibling paragraphs. */ + p + p { text-indent:2em; margin-top:-1.5em; } + form p + p { text-indent: 0; } /* Don't want this in forms. */ + + +/* For great looking type, use this code instead of asdf: + asdf + Best used on prepositions and ampersands. */ + +.alt { + color: #666; + font-family: "Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua", Georgia, serif; + font-style: italic; + font-weight: normal; +} + + +/* For great looking quote marks in titles, replace "asdf" with: + asdf” + (That is, when the title starts with a quote mark). + (You may have to change this value depending on your font size). */ + +.dquo { margin-left: -.5em; } + + +/* Reduced size type with incremental leading + (http://www.markboulton.co.uk/journal/comments/incremental_leading/) + + This could be used for side notes. For smaller type, you don't necessarily want to + follow the 1.5x vertical rhythm -- the line-height is too much. + + Using this class, it reduces your font size and line-height so that for + every four lines of normal sized type, there is five lines of the sidenote. eg: + + New type size in em's: + 10px (wanted side note size) / 12px (existing base size) = 0.8333 (new type size in ems) + + New line-height value: + 12px x 1.5 = 18px (old line-height) + 18px x 4 = 72px + 72px / 5 = 14.4px (new line height) + 14.4px / 10px = 1.44 (new line height in em's) */ + +p.incr, .incr p { + font-size: 10px; + line-height: 1.44em; + margin-bottom: 1.5em; +} + + +/* Surround uppercase words and abbreviations with this class. + Based on work by Jørgen Arnor GÃ¥rdsø Lom [http://twistedintellect.com/] */ + +.caps { + font-variant: small-caps; + letter-spacing: 1px; + text-transform: lowercase; + font-size:1.2em; + line-height:1%; + font-weight:bold; + padding:0 2px; +} diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/css/ldt.css --- a/src/ldt/ldt/static/ldt/css/ldt.css Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/css/ldt.css Mon May 16 20:00:36 2011 +0200 @@ -1,122 +1,122 @@ -#addldtform -{ - font-size: 16px; - background: #ffffff scroll repeat 0 0; - border: 1px solid #666666; - text-align: left; - width: 700px; -} - -#addldtform .title -{ - color: #666666; - font-weight:bold !important; - font-size:16px; - position: relative; - padding:8px 12px; -} - -#addldtform .title .closebutton -{ - float: right; - text-decoration: none; - color:#666666; -} - - -#addldtform .form-row -{ - border-bottom: 1px solid #eeeeee; - font-size: 15px; - padding: 8px 12px; -} - -#addldtform label -{ - float: left; - padding: 3px 8px 0 0; - width:8em; - color: #333333 !important; - font-weight: bold !important; -} -#addldtform input -{ - font-size: 15px; - font-weight: normal; - padding:2px 3px; - vertical-align: middle; - margin : 2px 0; - background-color: #ffffff; - border: 1px solid #cccccc; -} - -#addldtform .checkbox -{ - padding: 6px 3px 3px 30px; -} - -#addldtform .submit-row input -{ - color:black; - border-color:#DDDDDD #AAAAAA #AAAAAA #DDDDDD; - background:#dddddd; - padding: 3px; - margin:0 10px 10px 10px; -} -/* -#ldtlist{ - width:60%; - overflow:auto; - padding:1em; -} -*/ -#ldtlist table { - border-collapse: collapse; - border-color: #ccc; - width:100%; -} -#ldtlist table caption{ - color:black; - font-size:15px; - font-weight:bold; - padding:5px; - text-align:left; - text-transform:uppercase; -} -#ldtlist td, th { - font-size: 11px; - line-height: 13px; - border-bottom: 1px solid #eee; - vertical-align: top; - padding: 5px; - font-family: "Lucida Grande", Verdana, Arial, sans-serif; -} - - -#ldtlist table thead { - color: #666; - padding: 2px 5px; - font-size: 13px; - background: #e1e1e1 url(../../admin/img/admin/nav-bg.gif) top left repeat-x; - border-left: 1px solid #ddd; - border-bottom: 1px solid #ddd; - white-space: nowrap; - vertical-align: middle; - font-weight: bold; - text-align: center; -} - -#ldtlist table tbody td { - border-left: 1px solid #ddd; - text-align: center; -} - -#ldtlist table tbody td:first-child { - border-left: 0; - border-right: 1px solid #ddd; - text-align: left; -} - -#ldtlist table tfoot { - color: #666; -} +#addldtform +{ + font-size: 16px; + background: #ffffff scroll repeat 0 0; + border: 1px solid #666666; + text-align: left; + width: 700px; +} + +#addldtform .title +{ + color: #666666; + font-weight:bold !important; + font-size:16px; + position: relative; + padding:8px 12px; +} + +#addldtform .title .closebutton +{ + float: right; + text-decoration: none; + color:#666666; +} + + +#addldtform .form-row +{ + border-bottom: 1px solid #eeeeee; + font-size: 15px; + padding: 8px 12px; +} + +#addldtform label +{ + float: left; + padding: 3px 8px 0 0; + width:8em; + color: #333333 !important; + font-weight: bold !important; +} +#addldtform input +{ + font-size: 15px; + font-weight: normal; + padding:2px 3px; + vertical-align: middle; + margin : 2px 0; + background-color: #ffffff; + border: 1px solid #cccccc; +} + +#addldtform .checkbox +{ + padding: 6px 3px 3px 30px; +} + +#addldtform .submit-row input +{ + color:black; + border-color:#DDDDDD #AAAAAA #AAAAAA #DDDDDD; + background:#dddddd; + padding: 3px; + margin:0 10px 10px 10px; +} +/* +#ldtlist{ + width:60%; + overflow:auto; + padding:1em; +} +*/ +#ldtlist table { + border-collapse: collapse; + border-color: #ccc; + width:100%; +} +#ldtlist table caption{ + color:black; + font-size:15px; + font-weight:bold; + padding:5px; + text-align:left; + text-transform:uppercase; +} +#ldtlist td, th { + font-size: 11px; + line-height: 13px; + border-bottom: 1px solid #eee; + vertical-align: top; + padding: 5px; + font-family: "Lucida Grande", Verdana, Arial, sans-serif; +} + + +#ldtlist table thead { + color: #666; + padding: 2px 5px; + font-size: 13px; + background: #e1e1e1 url(../../admin/img/admin/nav-bg.gif) top left repeat-x; + border-left: 1px solid #ddd; + border-bottom: 1px solid #ddd; + white-space: nowrap; + vertical-align: middle; + font-weight: bold; + text-align: center; +} + +#ldtlist table tbody td { + border-left: 1px solid #ddd; + text-align: center; +} + +#ldtlist table tbody td:first-child { + border-left: 0; + border-right: 1px solid #ddd; + text-align: left; +} + +#ldtlist table tfoot { + color: #666; +} diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/js/jquery.nyroModal-ie6.min.js --- a/src/ldt/ldt/static/ldt/js/jquery.nyroModal-ie6.min.js Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/js/jquery.nyroModal-ie6.min.js Mon May 16 20:00:36 2011 +0200 @@ -1,9 +1,9 @@ -/* - * nyroModal v2.alpha - * for IE6 - * - */ -jQuery(function($,undefined){var $b=$('body'),$w=$(window),$h=$('html'),shown=0,zIndex=100;function isFullScreen(){return screen.height==$w.height()+58;};$b.append('');$.nmObj({_reposition:function(){var elts=this.elts.cont.find('.nmReposition');if(elts.length){var outer=this.getInternal()._getOuter($b),fs=isFullScreen();var space={top:-(fs?outer.h.border/2:0),left:-(fs?outer.w.border/2:0)};elts.each(function(){var me=$(this),offset=me.offset();me.css({top:offset.top-space.top,left:offset.left-space.left});});this.elts.cont.after(elts);} -this.elts.cont.css('overflow','auto');}});$.nmInternal({_calculateFullSize:function(){var scrollHeight=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),offsetHeight=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),scrollWidth=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth),offsetWidth=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);this.fullSize={wW:$w.width(),wH:$w.height()};this.fullSize.h=scrollHeight=$b.outerHeight(true)){h=$w.height()+'px';}else -w+=20;w+='px';$b.css({width:w,height:h,position:'static',overflow:'hidden'});}},beforeShowBg:function(nm){var space=nm.getInternal()._getSpaceReposition(),outer=nm.getInternal()._getOuter($b);nm.elts.bg.css({position:'absolute',top:space.top,left:space.left,width:nm.getInternal().fullSize.viewW+200,height:nm.getInternal().fullSize.viewH+200});shown++;},afterHideBg:function(nm){if(nm.store.ie6){nm.store.ie6=false;shown--;} +/* + * nyroModal v2.alpha + * for IE6 + * + */ +jQuery(function($,undefined){var $b=$('body'),$w=$(window),$h=$('html'),shown=0,zIndex=100;function isFullScreen(){return screen.height==$w.height()+58;};$b.append('');$.nmObj({_reposition:function(){var elts=this.elts.cont.find('.nmReposition');if(elts.length){var outer=this.getInternal()._getOuter($b),fs=isFullScreen();var space={top:-(fs?outer.h.border/2:0),left:-(fs?outer.w.border/2:0)};elts.each(function(){var me=$(this),offset=me.offset();me.css({top:offset.top-space.top,left:offset.left-space.left});});this.elts.cont.after(elts);} +this.elts.cont.css('overflow','auto');}});$.nmInternal({_calculateFullSize:function(){var scrollHeight=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),offsetHeight=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),scrollWidth=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth),offsetWidth=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);this.fullSize={wW:$w.width(),wH:$w.height()};this.fullSize.h=scrollHeight=$b.outerHeight(true)){h=$w.height()+'px';}else +w+=20;w+='px';$b.css({width:w,height:h,position:'static',overflow:'hidden'});}},beforeShowBg:function(nm){var space=nm.getInternal()._getSpaceReposition(),outer=nm.getInternal()._getOuter($b);nm.elts.bg.css({position:'absolute',top:space.top,left:space.left,width:nm.getInternal().fullSize.viewW+200,height:nm.getInternal().fullSize.viewH+200});shown++;},afterHideBg:function(nm){if(nm.store.ie6){nm.store.ie6=false;shown--;} if(shown==0){$h.css({overflow:''});$b.css({width:'',height:'',position:'',overflow:''});}},size:function(nm){if(!nm._hasFilter('image')&&!nm._hasFilter('swf')){if(nm.sizes.h<250)nm.sizes.h=250;if(nm.sizes.w<250)nm.sizes.w=250;else if(nm.sizes.w>1000)nm.sizes.w=1000;}},close:function(nm){if(nm.store.ie6){nm.store.ie6=false;shown--;}},beforeShowLoad:function(nm){var space=nm.getInternal()._getSpaceReposition(),outer=nm.getInternal()._getOuter(nm.elts.load);nm.elts.load.css({'z-index':zIndex++,position:'absolute',top:space.top+(nm.getInternal().fullSize.viewH-nm.elts.load.height()-outer.h.margin)/2,left:space.left+(nm.getInternal().fullSize.viewW-nm.elts.load.width()-outer.w.margin)/2});},beforeShowCont:function(nm){var space=nm.getInternal()._getSpaceReposition(),outer=nm.getInternal()._getOuter(nm.elts.cont);nm.elts.cont.css({'z-index':zIndex++,position:'absolute',top:space.top+(nm.getInternal().fullSize.viewH-outer.h.total-nm.sizes.h)/2,left:space.left+(nm.getInternal().fullSize.viewW-outer.w.total-nm.sizes.w)/2});}}});}); \ No newline at end of file diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/js/jquery.nyroModal.min.js --- a/src/ldt/ldt/static/ldt/js/jquery.nyroModal.min.js Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/js/jquery.nyroModal.min.js Mon May 16 20:00:36 2011 +0200 @@ -1,7 +1,7 @@ -/* - * nyroModal v2.0.0 - * Core - * +/* + * nyroModal v2.0.0 + * Core + * * * Included parts: * - anims.fade diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/js/swfupload/swfupload.cookies.js --- a/src/ldt/ldt/static/ldt/js/swfupload/swfupload.cookies.js Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/js/swfupload/swfupload.cookies.js Mon May 16 20:00:36 2011 +0200 @@ -1,53 +1,53 @@ -/* - Cookie Plug-in - - This plug in automatically gets all the cookies for this site and adds them to the post_params. - Cookies are loaded only on initialization. The refreshCookies function can be called to update the post_params. - The cookies will override any other post params with the same name. -*/ - -var SWFUpload; -if (typeof(SWFUpload) === "function") { - SWFUpload.prototype.initSettings = function (oldInitSettings) { - return function () { - if (typeof(oldInitSettings) === "function") { - oldInitSettings.call(this); - } - - this.refreshCookies(false); // The false parameter must be sent since SWFUpload has not initialzed at this point - }; - }(SWFUpload.prototype.initSettings); - - // refreshes the post_params and updates SWFUpload. The sendToFlash parameters is optional and defaults to True - SWFUpload.prototype.refreshCookies = function (sendToFlash) { - if (sendToFlash === undefined) { - sendToFlash = true; - } - sendToFlash = !!sendToFlash; - - // Get the post_params object - var postParams = this.settings.post_params; - - // Get the cookies - var i, cookieArray = document.cookie.split(';'), caLength = cookieArray.length, c, eqIndex, name, value; - for (i = 0; i < caLength; i++) { - c = cookieArray[i]; - - // Left Trim spaces - while (c.charAt(0) === " ") { - c = c.substring(1, c.length); - } - eqIndex = c.indexOf("="); - if (eqIndex > 0) { - name = c.substring(0, eqIndex); - value = c.substring(eqIndex + 1); - postParams[name] = value; - } - } - - if (sendToFlash) { - this.setPostParams(postParams); - } - }; - -} +/* + Cookie Plug-in + + This plug in automatically gets all the cookies for this site and adds them to the post_params. + Cookies are loaded only on initialization. The refreshCookies function can be called to update the post_params. + The cookies will override any other post params with the same name. +*/ + +var SWFUpload; +if (typeof(SWFUpload) === "function") { + SWFUpload.prototype.initSettings = function (oldInitSettings) { + return function () { + if (typeof(oldInitSettings) === "function") { + oldInitSettings.call(this); + } + + this.refreshCookies(false); // The false parameter must be sent since SWFUpload has not initialzed at this point + }; + }(SWFUpload.prototype.initSettings); + + // refreshes the post_params and updates SWFUpload. The sendToFlash parameters is optional and defaults to True + SWFUpload.prototype.refreshCookies = function (sendToFlash) { + if (sendToFlash === undefined) { + sendToFlash = true; + } + sendToFlash = !!sendToFlash; + + // Get the post_params object + var postParams = this.settings.post_params; + + // Get the cookies + var i, cookieArray = document.cookie.split(';'), caLength = cookieArray.length, c, eqIndex, name, value; + for (i = 0; i < caLength; i++) { + c = cookieArray[i]; + + // Left Trim spaces + while (c.charAt(0) === " ") { + c = c.substring(1, c.length); + } + eqIndex = c.indexOf("="); + if (eqIndex > 0) { + name = c.substring(0, eqIndex); + value = c.substring(eqIndex + 1); + postParams[name] = value; + } + } + + if (sendToFlash) { + this.setPostParams(postParams); + } + }; + +} diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/js/swfupload/swfupload.js --- a/src/ldt/ldt/static/ldt/js/swfupload/swfupload.js Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/js/swfupload/swfupload.js Mon May 16 20:00:36 2011 +0200 @@ -1,980 +1,980 @@ -/** - * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com - * - * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/ - * - * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License: - * http://www.opensource.org/licenses/mit-license.php - * - * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License: - * http://www.opensource.org/licenses/mit-license.php - * - */ - - -/* ******************* */ -/* Constructor & Init */ -/* ******************* */ -var SWFUpload; - -if (SWFUpload == undefined) { - SWFUpload = function (settings) { - this.initSWFUpload(settings); - }; -} - -SWFUpload.prototype.initSWFUpload = function (settings) { - try { - this.customSettings = {}; // A container where developers can place their own settings associated with this instance. - this.settings = settings; - this.eventQueue = []; - this.movieName = "SWFUpload_" + SWFUpload.movieCount++; - this.movieElement = null; - - - // Setup global control tracking - SWFUpload.instances[this.movieName] = this; - - // Load the settings. Load the Flash movie. - this.initSettings(); - this.loadFlash(); - this.displayDebugInfo(); - } catch (ex) { - delete SWFUpload.instances[this.movieName]; - throw ex; - } -}; - -/* *************** */ -/* Static Members */ -/* *************** */ -SWFUpload.instances = {}; -SWFUpload.movieCount = 0; -SWFUpload.version = "2.2.0 2009-03-25"; -SWFUpload.QUEUE_ERROR = { - QUEUE_LIMIT_EXCEEDED : -100, - FILE_EXCEEDS_SIZE_LIMIT : -110, - ZERO_BYTE_FILE : -120, - INVALID_FILETYPE : -130 -}; -SWFUpload.UPLOAD_ERROR = { - HTTP_ERROR : -200, - MISSING_UPLOAD_URL : -210, - IO_ERROR : -220, - SECURITY_ERROR : -230, - UPLOAD_LIMIT_EXCEEDED : -240, - UPLOAD_FAILED : -250, - SPECIFIED_FILE_ID_NOT_FOUND : -260, - FILE_VALIDATION_FAILED : -270, - FILE_CANCELLED : -280, - UPLOAD_STOPPED : -290 -}; -SWFUpload.FILE_STATUS = { - QUEUED : -1, - IN_PROGRESS : -2, - ERROR : -3, - COMPLETE : -4, - CANCELLED : -5 -}; -SWFUpload.BUTTON_ACTION = { - SELECT_FILE : -100, - SELECT_FILES : -110, - START_UPLOAD : -120 -}; -SWFUpload.CURSOR = { - ARROW : -1, - HAND : -2 -}; -SWFUpload.WINDOW_MODE = { - WINDOW : "window", - TRANSPARENT : "transparent", - OPAQUE : "opaque" -}; - -// Private: takes a URL, determines if it is relative and converts to an absolute URL -// using the current site. Only processes the URL if it can, otherwise returns the URL untouched -SWFUpload.completeURL = function(url) { - if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) { - return url; - } - - var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : ""); - - var indexSlash = window.location.pathname.lastIndexOf("/"); - if (indexSlash <= 0) { - path = "/"; - } else { - path = window.location.pathname.substr(0, indexSlash) + "/"; - } - - return /*currentURL +*/ path + url; - -}; - - -/* ******************** */ -/* Instance Members */ -/* ******************** */ - -// Private: initSettings ensures that all the -// settings are set, getting a default value if one was not assigned. -SWFUpload.prototype.initSettings = function () { - this.ensureDefault = function (settingName, defaultValue) { - this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName]; - }; - - // Upload backend settings - this.ensureDefault("upload_url", ""); - this.ensureDefault("preserve_relative_urls", false); - this.ensureDefault("file_post_name", "Filedata"); - this.ensureDefault("post_params", {}); - this.ensureDefault("use_query_string", false); - this.ensureDefault("requeue_on_error", false); - this.ensureDefault("http_success", []); - this.ensureDefault("assume_success_timeout", 0); - - // File Settings - this.ensureDefault("file_types", "*.*"); - this.ensureDefault("file_types_description", "All Files"); - this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited" - this.ensureDefault("file_upload_limit", 0); - this.ensureDefault("file_queue_limit", 0); - - // Flash Settings - this.ensureDefault("flash_url", "swfupload.swf"); - this.ensureDefault("prevent_swf_caching", true); - - // Button Settings - this.ensureDefault("button_image_url", ""); - this.ensureDefault("button_width", 1); - this.ensureDefault("button_height", 1); - this.ensureDefault("button_text", ""); - this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;"); - this.ensureDefault("button_text_top_padding", 0); - this.ensureDefault("button_text_left_padding", 0); - this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES); - this.ensureDefault("button_disabled", false); - this.ensureDefault("button_placeholder_id", ""); - this.ensureDefault("button_placeholder", null); - this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW); - this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW); - - // Debug Settings - this.ensureDefault("debug", false); - this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API - - // Event Handlers - this.settings.return_upload_start_handler = this.returnUploadStart; - this.ensureDefault("swfupload_loaded_handler", null); - this.ensureDefault("file_dialog_start_handler", null); - this.ensureDefault("file_queued_handler", null); - this.ensureDefault("file_queue_error_handler", null); - this.ensureDefault("file_dialog_complete_handler", null); - - this.ensureDefault("upload_start_handler", null); - this.ensureDefault("upload_progress_handler", null); - this.ensureDefault("upload_error_handler", null); - this.ensureDefault("upload_success_handler", null); - this.ensureDefault("upload_complete_handler", null); - - this.ensureDefault("debug_handler", this.debugMessage); - - this.ensureDefault("custom_settings", {}); - - // Other settings - this.customSettings = this.settings.custom_settings; - - // Update the flash url if needed - if (!!this.settings.prevent_swf_caching) { - this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime(); - } - - if (!this.settings.preserve_relative_urls) { - //this.settings.flash_url = SWFUpload.completeURL(this.settings.flash_url); // Don't need to do this one since flash doesn't look at it - this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url); - this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url); - } - - delete this.ensureDefault; -}; - -// Private: loadFlash replaces the button_placeholder element with the flash movie. -SWFUpload.prototype.loadFlash = function () { - var targetElement, tempParent; - - // Make sure an element with the ID we are going to use doesn't already exist - if (document.getElementById(this.movieName) !== null) { - throw "ID " + this.movieName + " is already in use. The Flash Object could not be added"; - } - - // Get the element where we will be placing the flash movie - targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder; - - if (targetElement == undefined) { - throw "Could not find the placeholder element: " + this.settings.button_placeholder_id; - } - - // Append the container and load the flash - tempParent = document.createElement("div"); - tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers) - targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement); - - // Fix IE Flash/Form bug - if (window[this.movieName] == undefined) { - window[this.movieName] = this.getMovieElement(); - } - -}; - -// Private: getFlashHTML generates the object tag needed to embed the flash in to the document -SWFUpload.prototype.getFlashHTML = function () { - // Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay - return ['', - '', - '', - '', - '', - '', - '', - ''].join(""); -}; - -// Private: getFlashVars builds the parameter string that will be passed -// to flash in the flashvars param. -SWFUpload.prototype.getFlashVars = function () { - // Build a string from the post param object - var paramString = this.buildParamString(); - var httpSuccessString = this.settings.http_success.join(","); - - // Build the parameter string - return ["movieName=", encodeURIComponent(this.movieName), - "&uploadURL=", encodeURIComponent(this.settings.upload_url), - "&useQueryString=", encodeURIComponent(this.settings.use_query_string), - "&requeueOnError=", encodeURIComponent(this.settings.requeue_on_error), - "&httpSuccess=", encodeURIComponent(httpSuccessString), - "&assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout), - "&params=", encodeURIComponent(paramString), - "&filePostName=", encodeURIComponent(this.settings.file_post_name), - "&fileTypes=", encodeURIComponent(this.settings.file_types), - "&fileTypesDescription=", encodeURIComponent(this.settings.file_types_description), - "&fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit), - "&fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit), - "&fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit), - "&debugEnabled=", encodeURIComponent(this.settings.debug_enabled), - "&buttonImageURL=", encodeURIComponent(this.settings.button_image_url), - "&buttonWidth=", encodeURIComponent(this.settings.button_width), - "&buttonHeight=", encodeURIComponent(this.settings.button_height), - "&buttonText=", encodeURIComponent(this.settings.button_text), - "&buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding), - "&buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding), - "&buttonTextStyle=", encodeURIComponent(this.settings.button_text_style), - "&buttonAction=", encodeURIComponent(this.settings.button_action), - "&buttonDisabled=", encodeURIComponent(this.settings.button_disabled), - "&buttonCursor=", encodeURIComponent(this.settings.button_cursor) - ].join(""); -}; - -// Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload -// The element is cached after the first lookup -SWFUpload.prototype.getMovieElement = function () { - if (this.movieElement == undefined) { - this.movieElement = document.getElementById(this.movieName); - } - - if (this.movieElement === null) { - throw "Could not find Flash element"; - } - - return this.movieElement; -}; - -// Private: buildParamString takes the name/value pairs in the post_params setting object -// and joins them up in to a string formatted "name=value&name=value" -SWFUpload.prototype.buildParamString = function () { - var postParams = this.settings.post_params; - var paramStringPairs = []; - - if (typeof(postParams) === "object") { - for (var name in postParams) { - if (postParams.hasOwnProperty(name)) { - paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString())); - } - } - } - - return paramStringPairs.join("&"); -}; - -// Public: Used to remove a SWFUpload instance from the page. This method strives to remove -// all references to the SWF, and other objects so memory is properly freed. -// Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state. -// Credits: Major improvements provided by steffen -SWFUpload.prototype.destroy = function () { - try { - // Make sure Flash is done before we try to remove it - this.cancelUpload(null, false); - - - // Remove the SWFUpload DOM nodes - var movieElement = null; - movieElement = this.getMovieElement(); - - if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE - // Loop through all the movie's properties and remove all function references (DOM/JS IE 6/7 memory leak workaround) - for (var i in movieElement) { - try { - if (typeof(movieElement[i]) === "function") { - movieElement[i] = null; - } - } catch (ex1) {} - } - - // Remove the Movie Element from the page - try { - movieElement.parentNode.removeChild(movieElement); - } catch (ex) {} - } - - // Remove IE form fix reference - window[this.movieName] = null; - - // Destroy other references - SWFUpload.instances[this.movieName] = null; - delete SWFUpload.instances[this.movieName]; - - this.movieElement = null; - this.settings = null; - this.customSettings = null; - this.eventQueue = null; - this.movieName = null; - - - return true; - } catch (ex2) { - return false; - } -}; - - -// Public: displayDebugInfo prints out settings and configuration -// information about this SWFUpload instance. -// This function (and any references to it) can be deleted when placing -// SWFUpload in production. -SWFUpload.prototype.displayDebugInfo = function () { - this.debug( - [ - "---SWFUpload Instance Info---\n", - "Version: ", SWFUpload.version, "\n", - "Movie Name: ", this.movieName, "\n", - "Settings:\n", - "\t", "upload_url: ", this.settings.upload_url, "\n", - "\t", "flash_url: ", this.settings.flash_url, "\n", - "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n", - "\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n", - "\t", "http_success: ", this.settings.http_success.join(", "), "\n", - "\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n", - "\t", "file_post_name: ", this.settings.file_post_name, "\n", - "\t", "post_params: ", this.settings.post_params.toString(), "\n", - "\t", "file_types: ", this.settings.file_types, "\n", - "\t", "file_types_description: ", this.settings.file_types_description, "\n", - "\t", "file_size_limit: ", this.settings.file_size_limit, "\n", - "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n", - "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n", - "\t", "debug: ", this.settings.debug.toString(), "\n", - - "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n", - - "\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n", - "\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n", - "\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n", - "\t", "button_width: ", this.settings.button_width.toString(), "\n", - "\t", "button_height: ", this.settings.button_height.toString(), "\n", - "\t", "button_text: ", this.settings.button_text.toString(), "\n", - "\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n", - "\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n", - "\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n", - "\t", "button_action: ", this.settings.button_action.toString(), "\n", - "\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n", - - "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n", - "Event Handlers:\n", - "\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n", - "\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n", - "\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n", - "\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n", - "\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n", - "\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n", - "\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n", - "\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n", - "\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n", - "\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n" - ].join("") - ); -}; - -/* Note: addSetting and getSetting are no longer used by SWFUpload but are included - the maintain v2 API compatibility -*/ -// Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used. -SWFUpload.prototype.addSetting = function (name, value, default_value) { - if (value == undefined) { - return (this.settings[name] = default_value); - } else { - return (this.settings[name] = value); - } -}; - -// Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found. -SWFUpload.prototype.getSetting = function (name) { - if (this.settings[name] != undefined) { - return this.settings[name]; - } - - return ""; -}; - - - -// Private: callFlash handles function calls made to the Flash element. -// Calls are made with a setTimeout for some functions to work around -// bugs in the ExternalInterface library. -SWFUpload.prototype.callFlash = function (functionName, argumentArray) { - argumentArray = argumentArray || []; - - var movieElement = this.getMovieElement(); - var returnValue, returnString; - - // Flash's method if calling ExternalInterface methods (code adapted from MooTools). - try { - returnString = movieElement.CallFunction('' + __flash__argumentsToXML(argumentArray, 0) + ''); - returnValue = eval(returnString); - } catch (ex) { - throw "Call to " + functionName + " failed"; - } - - // Unescape file post param values - if (returnValue != undefined && typeof returnValue.post === "object") { - returnValue = this.unescapeFilePostParams(returnValue); - } - - return returnValue; -}; - -/* ***************************** - -- Flash control methods -- - Your UI should use these - to operate SWFUpload - ***************************** */ - -// WARNING: this function does not work in Flash Player 10 -// Public: selectFile causes a File Selection Dialog window to appear. This -// dialog only allows 1 file to be selected. -SWFUpload.prototype.selectFile = function () { - this.callFlash("SelectFile"); -}; - -// WARNING: this function does not work in Flash Player 10 -// Public: selectFiles causes a File Selection Dialog window to appear/ This -// dialog allows the user to select any number of files -// Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names. -// If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around -// for this bug. -SWFUpload.prototype.selectFiles = function () { - this.callFlash("SelectFiles"); -}; - - -// Public: startUpload starts uploading the first file in the queue unless -// the optional parameter 'fileID' specifies the ID -SWFUpload.prototype.startUpload = function (fileID) { - this.callFlash("StartUpload", [fileID]); -}; - -// Public: cancelUpload cancels any queued file. The fileID parameter may be the file ID or index. -// If you do not specify a fileID the current uploading file or first file in the queue is cancelled. -// If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter. -SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) { - if (triggerErrorEvent !== false) { - triggerErrorEvent = true; - } - this.callFlash("CancelUpload", [fileID, triggerErrorEvent]); -}; - -// Public: stopUpload stops the current upload and requeues the file at the beginning of the queue. -// If nothing is currently uploading then nothing happens. -SWFUpload.prototype.stopUpload = function () { - this.callFlash("StopUpload"); -}; - -/* ************************ - * Settings methods - * These methods change the SWFUpload settings. - * SWFUpload settings should not be changed directly on the settings object - * since many of the settings need to be passed to Flash in order to take - * effect. - * *********************** */ - -// Public: getStats gets the file statistics object. -SWFUpload.prototype.getStats = function () { - return this.callFlash("GetStats"); -}; - -// Public: setStats changes the SWFUpload statistics. You shouldn't need to -// change the statistics but you can. Changing the statistics does not -// affect SWFUpload accept for the successful_uploads count which is used -// by the upload_limit setting to determine how many files the user may upload. -SWFUpload.prototype.setStats = function (statsObject) { - this.callFlash("SetStats", [statsObject]); -}; - -// Public: getFile retrieves a File object by ID or Index. If the file is -// not found then 'null' is returned. -SWFUpload.prototype.getFile = function (fileID) { - if (typeof(fileID) === "number") { - return this.callFlash("GetFileByIndex", [fileID]); - } else { - return this.callFlash("GetFile", [fileID]); - } -}; - -// Public: addFileParam sets a name/value pair that will be posted with the -// file specified by the Files ID. If the name already exists then the -// exiting value will be overwritten. -SWFUpload.prototype.addFileParam = function (fileID, name, value) { - return this.callFlash("AddFileParam", [fileID, name, value]); -}; - -// Public: removeFileParam removes a previously set (by addFileParam) name/value -// pair from the specified file. -SWFUpload.prototype.removeFileParam = function (fileID, name) { - this.callFlash("RemoveFileParam", [fileID, name]); -}; - -// Public: setUploadUrl changes the upload_url setting. -SWFUpload.prototype.setUploadURL = function (url) { - this.settings.upload_url = url.toString(); - this.callFlash("SetUploadURL", [url]); -}; - -// Public: setPostParams changes the post_params setting -SWFUpload.prototype.setPostParams = function (paramsObject) { - this.settings.post_params = paramsObject; - this.callFlash("SetPostParams", [paramsObject]); -}; - -// Public: addPostParam adds post name/value pair. Each name can have only one value. -SWFUpload.prototype.addPostParam = function (name, value) { - this.settings.post_params[name] = value; - this.callFlash("SetPostParams", [this.settings.post_params]); -}; - -// Public: removePostParam deletes post name/value pair. -SWFUpload.prototype.removePostParam = function (name) { - delete this.settings.post_params[name]; - this.callFlash("SetPostParams", [this.settings.post_params]); -}; - -// Public: setFileTypes changes the file_types setting and the file_types_description setting -SWFUpload.prototype.setFileTypes = function (types, description) { - this.settings.file_types = types; - this.settings.file_types_description = description; - this.callFlash("SetFileTypes", [types, description]); -}; - -// Public: setFileSizeLimit changes the file_size_limit setting -SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) { - this.settings.file_size_limit = fileSizeLimit; - this.callFlash("SetFileSizeLimit", [fileSizeLimit]); -}; - -// Public: setFileUploadLimit changes the file_upload_limit setting -SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) { - this.settings.file_upload_limit = fileUploadLimit; - this.callFlash("SetFileUploadLimit", [fileUploadLimit]); -}; - -// Public: setFileQueueLimit changes the file_queue_limit setting -SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) { - this.settings.file_queue_limit = fileQueueLimit; - this.callFlash("SetFileQueueLimit", [fileQueueLimit]); -}; - -// Public: setFilePostName changes the file_post_name setting -SWFUpload.prototype.setFilePostName = function (filePostName) { - this.settings.file_post_name = filePostName; - this.callFlash("SetFilePostName", [filePostName]); -}; - -// Public: setUseQueryString changes the use_query_string setting -SWFUpload.prototype.setUseQueryString = function (useQueryString) { - this.settings.use_query_string = useQueryString; - this.callFlash("SetUseQueryString", [useQueryString]); -}; - -// Public: setRequeueOnError changes the requeue_on_error setting -SWFUpload.prototype.setRequeueOnError = function (requeueOnError) { - this.settings.requeue_on_error = requeueOnError; - this.callFlash("SetRequeueOnError", [requeueOnError]); -}; - -// Public: setHTTPSuccess changes the http_success setting -SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) { - if (typeof http_status_codes === "string") { - http_status_codes = http_status_codes.replace(" ", "").split(","); - } - - this.settings.http_success = http_status_codes; - this.callFlash("SetHTTPSuccess", [http_status_codes]); -}; - -// Public: setHTTPSuccess changes the http_success setting -SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) { - this.settings.assume_success_timeout = timeout_seconds; - this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]); -}; - -// Public: setDebugEnabled changes the debug_enabled setting -SWFUpload.prototype.setDebugEnabled = function (debugEnabled) { - this.settings.debug_enabled = debugEnabled; - this.callFlash("SetDebugEnabled", [debugEnabled]); -}; - -// Public: setButtonImageURL loads a button image sprite -SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) { - if (buttonImageURL == undefined) { - buttonImageURL = ""; - } - - this.settings.button_image_url = buttonImageURL; - this.callFlash("SetButtonImageURL", [buttonImageURL]); -}; - -// Public: setButtonDimensions resizes the Flash Movie and button -SWFUpload.prototype.setButtonDimensions = function (width, height) { - this.settings.button_width = width; - this.settings.button_height = height; - - var movie = this.getMovieElement(); - if (movie != undefined) { - movie.style.width = width + "px"; - movie.style.height = height + "px"; - } - - this.callFlash("SetButtonDimensions", [width, height]); -}; -// Public: setButtonText Changes the text overlaid on the button -SWFUpload.prototype.setButtonText = function (html) { - this.settings.button_text = html; - this.callFlash("SetButtonText", [html]); -}; -// Public: setButtonTextPadding changes the top and left padding of the text overlay -SWFUpload.prototype.setButtonTextPadding = function (left, top) { - this.settings.button_text_top_padding = top; - this.settings.button_text_left_padding = left; - this.callFlash("SetButtonTextPadding", [left, top]); -}; - -// Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button -SWFUpload.prototype.setButtonTextStyle = function (css) { - this.settings.button_text_style = css; - this.callFlash("SetButtonTextStyle", [css]); -}; -// Public: setButtonDisabled disables/enables the button -SWFUpload.prototype.setButtonDisabled = function (isDisabled) { - this.settings.button_disabled = isDisabled; - this.callFlash("SetButtonDisabled", [isDisabled]); -}; -// Public: setButtonAction sets the action that occurs when the button is clicked -SWFUpload.prototype.setButtonAction = function (buttonAction) { - this.settings.button_action = buttonAction; - this.callFlash("SetButtonAction", [buttonAction]); -}; - -// Public: setButtonCursor changes the mouse cursor displayed when hovering over the button -SWFUpload.prototype.setButtonCursor = function (cursor) { - this.settings.button_cursor = cursor; - this.callFlash("SetButtonCursor", [cursor]); -}; - -/* ******************************* - Flash Event Interfaces - These functions are used by Flash to trigger the various - events. - - All these functions a Private. - - Because the ExternalInterface library is buggy the event calls - are added to a queue and the queue then executed by a setTimeout. - This ensures that events are executed in a determinate order and that - the ExternalInterface bugs are avoided. -******************************* */ - -SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) { - // Warning: Don't call this.debug inside here or you'll create an infinite loop - - if (argumentArray == undefined) { - argumentArray = []; - } else if (!(argumentArray instanceof Array)) { - argumentArray = [argumentArray]; - } - - var self = this; - if (typeof this.settings[handlerName] === "function") { - // Queue the event - this.eventQueue.push(function () { - this.settings[handlerName].apply(this, argumentArray); - }); - - // Execute the next queued event - setTimeout(function () { - self.executeNextEvent(); - }, 0); - - } else if (this.settings[handlerName] !== null) { - throw "Event handler " + handlerName + " is unknown or is not a function"; - } -}; - -// Private: Causes the next event in the queue to be executed. Since events are queued using a setTimeout -// we must queue them in order to garentee that they are executed in order. -SWFUpload.prototype.executeNextEvent = function () { - // Warning: Don't call this.debug inside here or you'll create an infinite loop - - var f = this.eventQueue ? this.eventQueue.shift() : null; - if (typeof(f) === "function") { - f.apply(this); - } -}; - -// Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have -// properties that contain characters that are not valid for JavaScript identifiers. To work around this -// the Flash Component escapes the parameter names and we must unescape again before passing them along. -SWFUpload.prototype.unescapeFilePostParams = function (file) { - var reg = /[$]([0-9a-f]{4})/i; - var unescapedPost = {}; - var uk; - - if (file != undefined) { - for (var k in file.post) { - if (file.post.hasOwnProperty(k)) { - uk = k; - var match; - while ((match = reg.exec(uk)) !== null) { - uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16))); - } - unescapedPost[uk] = file.post[k]; - } - } - - file.post = unescapedPost; - } - - return file; -}; - -// Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working) -SWFUpload.prototype.testExternalInterface = function () { - try { - return this.callFlash("TestExternalInterface"); - } catch (ex) { - return false; - } -}; - -// Private: This event is called by Flash when it has finished loading. Don't modify this. -// Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded. -SWFUpload.prototype.flashReady = function () { - // Check that the movie element is loaded correctly with its ExternalInterface methods defined - var movieElement = this.getMovieElement(); - - if (!movieElement) { - this.debug("Flash called back ready but the flash movie can't be found."); - return; - } - - this.cleanUp(movieElement); - - this.queueEvent("swfupload_loaded_handler"); -}; - -// Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE. -// This function is called by Flash each time the ExternalInterface functions are created. -SWFUpload.prototype.cleanUp = function (movieElement) { - // Pro-actively unhook all the Flash functions - try { - if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE - this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)"); - for (var key in movieElement) { - try { - if (typeof(movieElement[key]) === "function") { - movieElement[key] = null; - } - } catch (ex) { - } - } - } - } catch (ex1) { - - } - - // Fix Flashes own cleanup code so if the SWFMovie was removed from the page - // it doesn't display errors. - window["__flash__removeCallback"] = function (instance, name) { - try { - if (instance) { - instance[name] = null; - } - } catch (flashEx) { - - } - }; - -}; - - -/* This is a chance to do something before the browse window opens */ -SWFUpload.prototype.fileDialogStart = function () { - this.queueEvent("file_dialog_start_handler"); -}; - - -/* Called when a file is successfully added to the queue. */ -SWFUpload.prototype.fileQueued = function (file) { - file = this.unescapeFilePostParams(file); - this.queueEvent("file_queued_handler", file); -}; - - -/* Handle errors that occur when an attempt to queue a file fails. */ -SWFUpload.prototype.fileQueueError = function (file, errorCode, message) { - file = this.unescapeFilePostParams(file); - this.queueEvent("file_queue_error_handler", [file, errorCode, message]); -}; - -/* Called after the file dialog has closed and the selected files have been queued. - You could call startUpload here if you want the queued files to begin uploading immediately. */ -SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) { - this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]); -}; - -SWFUpload.prototype.uploadStart = function (file) { - file = this.unescapeFilePostParams(file); - this.queueEvent("return_upload_start_handler", file); -}; - -SWFUpload.prototype.returnUploadStart = function (file) { - var returnValue; - if (typeof this.settings.upload_start_handler === "function") { - file = this.unescapeFilePostParams(file); - returnValue = this.settings.upload_start_handler.call(this, file); - } else if (this.settings.upload_start_handler != undefined) { - throw "upload_start_handler must be a function"; - } - - // Convert undefined to true so if nothing is returned from the upload_start_handler it is - // interpretted as 'true'. - if (returnValue === undefined) { - returnValue = true; - } - - returnValue = !!returnValue; - - this.callFlash("ReturnUploadStart", [returnValue]); -}; - - - -SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) { - file = this.unescapeFilePostParams(file); - this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]); -}; - -SWFUpload.prototype.uploadError = function (file, errorCode, message) { - file = this.unescapeFilePostParams(file); - this.queueEvent("upload_error_handler", [file, errorCode, message]); -}; - -SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) { - file = this.unescapeFilePostParams(file); - this.queueEvent("upload_success_handler", [file, serverData, responseReceived]); -}; - -SWFUpload.prototype.uploadComplete = function (file) { - file = this.unescapeFilePostParams(file); - this.queueEvent("upload_complete_handler", file); -}; - -/* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the - internal debug console. You can override this event and have messages written where you want. */ -SWFUpload.prototype.debug = function (message) { - this.queueEvent("debug_handler", message); -}; - - -/* ********************************** - Debug Console - The debug console is a self contained, in page location - for debug message to be sent. The Debug Console adds - itself to the body if necessary. - - The console is automatically scrolled as messages appear. - - If you are using your own debug handler or when you deploy to production and - have debug disabled you can remove these functions to reduce the file size - and complexity. -********************************** */ - -// Private: debugMessage is the default debug_handler. If you want to print debug messages -// call the debug() function. When overriding the function your own function should -// check to see if the debug setting is true before outputting debug information. -SWFUpload.prototype.debugMessage = function (message) { - if (this.settings.debug) { - var exceptionMessage, exceptionValues = []; - - // Check for an exception object and print it nicely - if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") { - for (var key in message) { - if (message.hasOwnProperty(key)) { - exceptionValues.push(key + ": " + message[key]); - } - } - exceptionMessage = exceptionValues.join("\n") || ""; - exceptionValues = exceptionMessage.split("\n"); - exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: "); - SWFUpload.Console.writeLine(exceptionMessage); - } else { - SWFUpload.Console.writeLine(message); - } - } -}; - -SWFUpload.Console = {}; -SWFUpload.Console.writeLine = function (message) { - var console, documentForm; - - try { - console = document.getElementById("SWFUpload_Console"); - - if (!console) { - documentForm = document.createElement("form"); - document.getElementsByTagName("body")[0].appendChild(documentForm); - - console = document.createElement("textarea"); - console.id = "SWFUpload_Console"; - console.style.fontFamily = "monospace"; - console.setAttribute("wrap", "off"); - console.wrap = "off"; - console.style.overflow = "auto"; - console.style.width = "700px"; - console.style.height = "350px"; - console.style.margin = "5px"; - documentForm.appendChild(console); - } - - console.value += message + "\n"; - - console.scrollTop = console.scrollHeight - console.clientHeight; - } catch (ex) { - alert("Exception: " + ex.name + " Message: " + ex.message); - } -}; +/** + * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com + * + * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/ + * + * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilz�n and Mammon Media and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + */ + + +/* ******************* */ +/* Constructor & Init */ +/* ******************* */ +var SWFUpload; + +if (SWFUpload == undefined) { + SWFUpload = function (settings) { + this.initSWFUpload(settings); + }; +} + +SWFUpload.prototype.initSWFUpload = function (settings) { + try { + this.customSettings = {}; // A container where developers can place their own settings associated with this instance. + this.settings = settings; + this.eventQueue = []; + this.movieName = "SWFUpload_" + SWFUpload.movieCount++; + this.movieElement = null; + + + // Setup global control tracking + SWFUpload.instances[this.movieName] = this; + + // Load the settings. Load the Flash movie. + this.initSettings(); + this.loadFlash(); + this.displayDebugInfo(); + } catch (ex) { + delete SWFUpload.instances[this.movieName]; + throw ex; + } +}; + +/* *************** */ +/* Static Members */ +/* *************** */ +SWFUpload.instances = {}; +SWFUpload.movieCount = 0; +SWFUpload.version = "2.2.0 2009-03-25"; +SWFUpload.QUEUE_ERROR = { + QUEUE_LIMIT_EXCEEDED : -100, + FILE_EXCEEDS_SIZE_LIMIT : -110, + ZERO_BYTE_FILE : -120, + INVALID_FILETYPE : -130 +}; +SWFUpload.UPLOAD_ERROR = { + HTTP_ERROR : -200, + MISSING_UPLOAD_URL : -210, + IO_ERROR : -220, + SECURITY_ERROR : -230, + UPLOAD_LIMIT_EXCEEDED : -240, + UPLOAD_FAILED : -250, + SPECIFIED_FILE_ID_NOT_FOUND : -260, + FILE_VALIDATION_FAILED : -270, + FILE_CANCELLED : -280, + UPLOAD_STOPPED : -290 +}; +SWFUpload.FILE_STATUS = { + QUEUED : -1, + IN_PROGRESS : -2, + ERROR : -3, + COMPLETE : -4, + CANCELLED : -5 +}; +SWFUpload.BUTTON_ACTION = { + SELECT_FILE : -100, + SELECT_FILES : -110, + START_UPLOAD : -120 +}; +SWFUpload.CURSOR = { + ARROW : -1, + HAND : -2 +}; +SWFUpload.WINDOW_MODE = { + WINDOW : "window", + TRANSPARENT : "transparent", + OPAQUE : "opaque" +}; + +// Private: takes a URL, determines if it is relative and converts to an absolute URL +// using the current site. Only processes the URL if it can, otherwise returns the URL untouched +SWFUpload.completeURL = function(url) { + if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) { + return url; + } + + var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : ""); + + var indexSlash = window.location.pathname.lastIndexOf("/"); + if (indexSlash <= 0) { + path = "/"; + } else { + path = window.location.pathname.substr(0, indexSlash) + "/"; + } + + return /*currentURL +*/ path + url; + +}; + + +/* ******************** */ +/* Instance Members */ +/* ******************** */ + +// Private: initSettings ensures that all the +// settings are set, getting a default value if one was not assigned. +SWFUpload.prototype.initSettings = function () { + this.ensureDefault = function (settingName, defaultValue) { + this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName]; + }; + + // Upload backend settings + this.ensureDefault("upload_url", ""); + this.ensureDefault("preserve_relative_urls", false); + this.ensureDefault("file_post_name", "Filedata"); + this.ensureDefault("post_params", {}); + this.ensureDefault("use_query_string", false); + this.ensureDefault("requeue_on_error", false); + this.ensureDefault("http_success", []); + this.ensureDefault("assume_success_timeout", 0); + + // File Settings + this.ensureDefault("file_types", "*.*"); + this.ensureDefault("file_types_description", "All Files"); + this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited" + this.ensureDefault("file_upload_limit", 0); + this.ensureDefault("file_queue_limit", 0); + + // Flash Settings + this.ensureDefault("flash_url", "swfupload.swf"); + this.ensureDefault("prevent_swf_caching", true); + + // Button Settings + this.ensureDefault("button_image_url", ""); + this.ensureDefault("button_width", 1); + this.ensureDefault("button_height", 1); + this.ensureDefault("button_text", ""); + this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;"); + this.ensureDefault("button_text_top_padding", 0); + this.ensureDefault("button_text_left_padding", 0); + this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES); + this.ensureDefault("button_disabled", false); + this.ensureDefault("button_placeholder_id", ""); + this.ensureDefault("button_placeholder", null); + this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW); + this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW); + + // Debug Settings + this.ensureDefault("debug", false); + this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API + + // Event Handlers + this.settings.return_upload_start_handler = this.returnUploadStart; + this.ensureDefault("swfupload_loaded_handler", null); + this.ensureDefault("file_dialog_start_handler", null); + this.ensureDefault("file_queued_handler", null); + this.ensureDefault("file_queue_error_handler", null); + this.ensureDefault("file_dialog_complete_handler", null); + + this.ensureDefault("upload_start_handler", null); + this.ensureDefault("upload_progress_handler", null); + this.ensureDefault("upload_error_handler", null); + this.ensureDefault("upload_success_handler", null); + this.ensureDefault("upload_complete_handler", null); + + this.ensureDefault("debug_handler", this.debugMessage); + + this.ensureDefault("custom_settings", {}); + + // Other settings + this.customSettings = this.settings.custom_settings; + + // Update the flash url if needed + if (!!this.settings.prevent_swf_caching) { + this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime(); + } + + if (!this.settings.preserve_relative_urls) { + //this.settings.flash_url = SWFUpload.completeURL(this.settings.flash_url); // Don't need to do this one since flash doesn't look at it + this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url); + this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url); + } + + delete this.ensureDefault; +}; + +// Private: loadFlash replaces the button_placeholder element with the flash movie. +SWFUpload.prototype.loadFlash = function () { + var targetElement, tempParent; + + // Make sure an element with the ID we are going to use doesn't already exist + if (document.getElementById(this.movieName) !== null) { + throw "ID " + this.movieName + " is already in use. The Flash Object could not be added"; + } + + // Get the element where we will be placing the flash movie + targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder; + + if (targetElement == undefined) { + throw "Could not find the placeholder element: " + this.settings.button_placeholder_id; + } + + // Append the container and load the flash + tempParent = document.createElement("div"); + tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers) + targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement); + + // Fix IE Flash/Form bug + if (window[this.movieName] == undefined) { + window[this.movieName] = this.getMovieElement(); + } + +}; + +// Private: getFlashHTML generates the object tag needed to embed the flash in to the document +SWFUpload.prototype.getFlashHTML = function () { + // Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay + return ['', + '', + '', + '', + '', + '', + '', + ''].join(""); +}; + +// Private: getFlashVars builds the parameter string that will be passed +// to flash in the flashvars param. +SWFUpload.prototype.getFlashVars = function () { + // Build a string from the post param object + var paramString = this.buildParamString(); + var httpSuccessString = this.settings.http_success.join(","); + + // Build the parameter string + return ["movieName=", encodeURIComponent(this.movieName), + "&uploadURL=", encodeURIComponent(this.settings.upload_url), + "&useQueryString=", encodeURIComponent(this.settings.use_query_string), + "&requeueOnError=", encodeURIComponent(this.settings.requeue_on_error), + "&httpSuccess=", encodeURIComponent(httpSuccessString), + "&assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout), + "&params=", encodeURIComponent(paramString), + "&filePostName=", encodeURIComponent(this.settings.file_post_name), + "&fileTypes=", encodeURIComponent(this.settings.file_types), + "&fileTypesDescription=", encodeURIComponent(this.settings.file_types_description), + "&fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit), + "&fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit), + "&fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit), + "&debugEnabled=", encodeURIComponent(this.settings.debug_enabled), + "&buttonImageURL=", encodeURIComponent(this.settings.button_image_url), + "&buttonWidth=", encodeURIComponent(this.settings.button_width), + "&buttonHeight=", encodeURIComponent(this.settings.button_height), + "&buttonText=", encodeURIComponent(this.settings.button_text), + "&buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding), + "&buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding), + "&buttonTextStyle=", encodeURIComponent(this.settings.button_text_style), + "&buttonAction=", encodeURIComponent(this.settings.button_action), + "&buttonDisabled=", encodeURIComponent(this.settings.button_disabled), + "&buttonCursor=", encodeURIComponent(this.settings.button_cursor) + ].join(""); +}; + +// Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload +// The element is cached after the first lookup +SWFUpload.prototype.getMovieElement = function () { + if (this.movieElement == undefined) { + this.movieElement = document.getElementById(this.movieName); + } + + if (this.movieElement === null) { + throw "Could not find Flash element"; + } + + return this.movieElement; +}; + +// Private: buildParamString takes the name/value pairs in the post_params setting object +// and joins them up in to a string formatted "name=value&name=value" +SWFUpload.prototype.buildParamString = function () { + var postParams = this.settings.post_params; + var paramStringPairs = []; + + if (typeof(postParams) === "object") { + for (var name in postParams) { + if (postParams.hasOwnProperty(name)) { + paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString())); + } + } + } + + return paramStringPairs.join("&"); +}; + +// Public: Used to remove a SWFUpload instance from the page. This method strives to remove +// all references to the SWF, and other objects so memory is properly freed. +// Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state. +// Credits: Major improvements provided by steffen +SWFUpload.prototype.destroy = function () { + try { + // Make sure Flash is done before we try to remove it + this.cancelUpload(null, false); + + + // Remove the SWFUpload DOM nodes + var movieElement = null; + movieElement = this.getMovieElement(); + + if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE + // Loop through all the movie's properties and remove all function references (DOM/JS IE 6/7 memory leak workaround) + for (var i in movieElement) { + try { + if (typeof(movieElement[i]) === "function") { + movieElement[i] = null; + } + } catch (ex1) {} + } + + // Remove the Movie Element from the page + try { + movieElement.parentNode.removeChild(movieElement); + } catch (ex) {} + } + + // Remove IE form fix reference + window[this.movieName] = null; + + // Destroy other references + SWFUpload.instances[this.movieName] = null; + delete SWFUpload.instances[this.movieName]; + + this.movieElement = null; + this.settings = null; + this.customSettings = null; + this.eventQueue = null; + this.movieName = null; + + + return true; + } catch (ex2) { + return false; + } +}; + + +// Public: displayDebugInfo prints out settings and configuration +// information about this SWFUpload instance. +// This function (and any references to it) can be deleted when placing +// SWFUpload in production. +SWFUpload.prototype.displayDebugInfo = function () { + this.debug( + [ + "---SWFUpload Instance Info---\n", + "Version: ", SWFUpload.version, "\n", + "Movie Name: ", this.movieName, "\n", + "Settings:\n", + "\t", "upload_url: ", this.settings.upload_url, "\n", + "\t", "flash_url: ", this.settings.flash_url, "\n", + "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n", + "\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n", + "\t", "http_success: ", this.settings.http_success.join(", "), "\n", + "\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n", + "\t", "file_post_name: ", this.settings.file_post_name, "\n", + "\t", "post_params: ", this.settings.post_params.toString(), "\n", + "\t", "file_types: ", this.settings.file_types, "\n", + "\t", "file_types_description: ", this.settings.file_types_description, "\n", + "\t", "file_size_limit: ", this.settings.file_size_limit, "\n", + "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n", + "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n", + "\t", "debug: ", this.settings.debug.toString(), "\n", + + "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n", + + "\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n", + "\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n", + "\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n", + "\t", "button_width: ", this.settings.button_width.toString(), "\n", + "\t", "button_height: ", this.settings.button_height.toString(), "\n", + "\t", "button_text: ", this.settings.button_text.toString(), "\n", + "\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n", + "\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n", + "\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n", + "\t", "button_action: ", this.settings.button_action.toString(), "\n", + "\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n", + + "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n", + "Event Handlers:\n", + "\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n", + "\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n", + "\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n", + "\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n", + "\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n", + "\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n", + "\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n", + "\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n", + "\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n", + "\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n" + ].join("") + ); +}; + +/* Note: addSetting and getSetting are no longer used by SWFUpload but are included + the maintain v2 API compatibility +*/ +// Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used. +SWFUpload.prototype.addSetting = function (name, value, default_value) { + if (value == undefined) { + return (this.settings[name] = default_value); + } else { + return (this.settings[name] = value); + } +}; + +// Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found. +SWFUpload.prototype.getSetting = function (name) { + if (this.settings[name] != undefined) { + return this.settings[name]; + } + + return ""; +}; + + + +// Private: callFlash handles function calls made to the Flash element. +// Calls are made with a setTimeout for some functions to work around +// bugs in the ExternalInterface library. +SWFUpload.prototype.callFlash = function (functionName, argumentArray) { + argumentArray = argumentArray || []; + + var movieElement = this.getMovieElement(); + var returnValue, returnString; + + // Flash's method if calling ExternalInterface methods (code adapted from MooTools). + try { + returnString = movieElement.CallFunction('' + __flash__argumentsToXML(argumentArray, 0) + ''); + returnValue = eval(returnString); + } catch (ex) { + throw "Call to " + functionName + " failed"; + } + + // Unescape file post param values + if (returnValue != undefined && typeof returnValue.post === "object") { + returnValue = this.unescapeFilePostParams(returnValue); + } + + return returnValue; +}; + +/* ***************************** + -- Flash control methods -- + Your UI should use these + to operate SWFUpload + ***************************** */ + +// WARNING: this function does not work in Flash Player 10 +// Public: selectFile causes a File Selection Dialog window to appear. This +// dialog only allows 1 file to be selected. +SWFUpload.prototype.selectFile = function () { + this.callFlash("SelectFile"); +}; + +// WARNING: this function does not work in Flash Player 10 +// Public: selectFiles causes a File Selection Dialog window to appear/ This +// dialog allows the user to select any number of files +// Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names. +// If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around +// for this bug. +SWFUpload.prototype.selectFiles = function () { + this.callFlash("SelectFiles"); +}; + + +// Public: startUpload starts uploading the first file in the queue unless +// the optional parameter 'fileID' specifies the ID +SWFUpload.prototype.startUpload = function (fileID) { + this.callFlash("StartUpload", [fileID]); +}; + +// Public: cancelUpload cancels any queued file. The fileID parameter may be the file ID or index. +// If you do not specify a fileID the current uploading file or first file in the queue is cancelled. +// If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter. +SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) { + if (triggerErrorEvent !== false) { + triggerErrorEvent = true; + } + this.callFlash("CancelUpload", [fileID, triggerErrorEvent]); +}; + +// Public: stopUpload stops the current upload and requeues the file at the beginning of the queue. +// If nothing is currently uploading then nothing happens. +SWFUpload.prototype.stopUpload = function () { + this.callFlash("StopUpload"); +}; + +/* ************************ + * Settings methods + * These methods change the SWFUpload settings. + * SWFUpload settings should not be changed directly on the settings object + * since many of the settings need to be passed to Flash in order to take + * effect. + * *********************** */ + +// Public: getStats gets the file statistics object. +SWFUpload.prototype.getStats = function () { + return this.callFlash("GetStats"); +}; + +// Public: setStats changes the SWFUpload statistics. You shouldn't need to +// change the statistics but you can. Changing the statistics does not +// affect SWFUpload accept for the successful_uploads count which is used +// by the upload_limit setting to determine how many files the user may upload. +SWFUpload.prototype.setStats = function (statsObject) { + this.callFlash("SetStats", [statsObject]); +}; + +// Public: getFile retrieves a File object by ID or Index. If the file is +// not found then 'null' is returned. +SWFUpload.prototype.getFile = function (fileID) { + if (typeof(fileID) === "number") { + return this.callFlash("GetFileByIndex", [fileID]); + } else { + return this.callFlash("GetFile", [fileID]); + } +}; + +// Public: addFileParam sets a name/value pair that will be posted with the +// file specified by the Files ID. If the name already exists then the +// exiting value will be overwritten. +SWFUpload.prototype.addFileParam = function (fileID, name, value) { + return this.callFlash("AddFileParam", [fileID, name, value]); +}; + +// Public: removeFileParam removes a previously set (by addFileParam) name/value +// pair from the specified file. +SWFUpload.prototype.removeFileParam = function (fileID, name) { + this.callFlash("RemoveFileParam", [fileID, name]); +}; + +// Public: setUploadUrl changes the upload_url setting. +SWFUpload.prototype.setUploadURL = function (url) { + this.settings.upload_url = url.toString(); + this.callFlash("SetUploadURL", [url]); +}; + +// Public: setPostParams changes the post_params setting +SWFUpload.prototype.setPostParams = function (paramsObject) { + this.settings.post_params = paramsObject; + this.callFlash("SetPostParams", [paramsObject]); +}; + +// Public: addPostParam adds post name/value pair. Each name can have only one value. +SWFUpload.prototype.addPostParam = function (name, value) { + this.settings.post_params[name] = value; + this.callFlash("SetPostParams", [this.settings.post_params]); +}; + +// Public: removePostParam deletes post name/value pair. +SWFUpload.prototype.removePostParam = function (name) { + delete this.settings.post_params[name]; + this.callFlash("SetPostParams", [this.settings.post_params]); +}; + +// Public: setFileTypes changes the file_types setting and the file_types_description setting +SWFUpload.prototype.setFileTypes = function (types, description) { + this.settings.file_types = types; + this.settings.file_types_description = description; + this.callFlash("SetFileTypes", [types, description]); +}; + +// Public: setFileSizeLimit changes the file_size_limit setting +SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) { + this.settings.file_size_limit = fileSizeLimit; + this.callFlash("SetFileSizeLimit", [fileSizeLimit]); +}; + +// Public: setFileUploadLimit changes the file_upload_limit setting +SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) { + this.settings.file_upload_limit = fileUploadLimit; + this.callFlash("SetFileUploadLimit", [fileUploadLimit]); +}; + +// Public: setFileQueueLimit changes the file_queue_limit setting +SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) { + this.settings.file_queue_limit = fileQueueLimit; + this.callFlash("SetFileQueueLimit", [fileQueueLimit]); +}; + +// Public: setFilePostName changes the file_post_name setting +SWFUpload.prototype.setFilePostName = function (filePostName) { + this.settings.file_post_name = filePostName; + this.callFlash("SetFilePostName", [filePostName]); +}; + +// Public: setUseQueryString changes the use_query_string setting +SWFUpload.prototype.setUseQueryString = function (useQueryString) { + this.settings.use_query_string = useQueryString; + this.callFlash("SetUseQueryString", [useQueryString]); +}; + +// Public: setRequeueOnError changes the requeue_on_error setting +SWFUpload.prototype.setRequeueOnError = function (requeueOnError) { + this.settings.requeue_on_error = requeueOnError; + this.callFlash("SetRequeueOnError", [requeueOnError]); +}; + +// Public: setHTTPSuccess changes the http_success setting +SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) { + if (typeof http_status_codes === "string") { + http_status_codes = http_status_codes.replace(" ", "").split(","); + } + + this.settings.http_success = http_status_codes; + this.callFlash("SetHTTPSuccess", [http_status_codes]); +}; + +// Public: setHTTPSuccess changes the http_success setting +SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) { + this.settings.assume_success_timeout = timeout_seconds; + this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]); +}; + +// Public: setDebugEnabled changes the debug_enabled setting +SWFUpload.prototype.setDebugEnabled = function (debugEnabled) { + this.settings.debug_enabled = debugEnabled; + this.callFlash("SetDebugEnabled", [debugEnabled]); +}; + +// Public: setButtonImageURL loads a button image sprite +SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) { + if (buttonImageURL == undefined) { + buttonImageURL = ""; + } + + this.settings.button_image_url = buttonImageURL; + this.callFlash("SetButtonImageURL", [buttonImageURL]); +}; + +// Public: setButtonDimensions resizes the Flash Movie and button +SWFUpload.prototype.setButtonDimensions = function (width, height) { + this.settings.button_width = width; + this.settings.button_height = height; + + var movie = this.getMovieElement(); + if (movie != undefined) { + movie.style.width = width + "px"; + movie.style.height = height + "px"; + } + + this.callFlash("SetButtonDimensions", [width, height]); +}; +// Public: setButtonText Changes the text overlaid on the button +SWFUpload.prototype.setButtonText = function (html) { + this.settings.button_text = html; + this.callFlash("SetButtonText", [html]); +}; +// Public: setButtonTextPadding changes the top and left padding of the text overlay +SWFUpload.prototype.setButtonTextPadding = function (left, top) { + this.settings.button_text_top_padding = top; + this.settings.button_text_left_padding = left; + this.callFlash("SetButtonTextPadding", [left, top]); +}; + +// Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button +SWFUpload.prototype.setButtonTextStyle = function (css) { + this.settings.button_text_style = css; + this.callFlash("SetButtonTextStyle", [css]); +}; +// Public: setButtonDisabled disables/enables the button +SWFUpload.prototype.setButtonDisabled = function (isDisabled) { + this.settings.button_disabled = isDisabled; + this.callFlash("SetButtonDisabled", [isDisabled]); +}; +// Public: setButtonAction sets the action that occurs when the button is clicked +SWFUpload.prototype.setButtonAction = function (buttonAction) { + this.settings.button_action = buttonAction; + this.callFlash("SetButtonAction", [buttonAction]); +}; + +// Public: setButtonCursor changes the mouse cursor displayed when hovering over the button +SWFUpload.prototype.setButtonCursor = function (cursor) { + this.settings.button_cursor = cursor; + this.callFlash("SetButtonCursor", [cursor]); +}; + +/* ******************************* + Flash Event Interfaces + These functions are used by Flash to trigger the various + events. + + All these functions a Private. + + Because the ExternalInterface library is buggy the event calls + are added to a queue and the queue then executed by a setTimeout. + This ensures that events are executed in a determinate order and that + the ExternalInterface bugs are avoided. +******************************* */ + +SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) { + // Warning: Don't call this.debug inside here or you'll create an infinite loop + + if (argumentArray == undefined) { + argumentArray = []; + } else if (!(argumentArray instanceof Array)) { + argumentArray = [argumentArray]; + } + + var self = this; + if (typeof this.settings[handlerName] === "function") { + // Queue the event + this.eventQueue.push(function () { + this.settings[handlerName].apply(this, argumentArray); + }); + + // Execute the next queued event + setTimeout(function () { + self.executeNextEvent(); + }, 0); + + } else if (this.settings[handlerName] !== null) { + throw "Event handler " + handlerName + " is unknown or is not a function"; + } +}; + +// Private: Causes the next event in the queue to be executed. Since events are queued using a setTimeout +// we must queue them in order to garentee that they are executed in order. +SWFUpload.prototype.executeNextEvent = function () { + // Warning: Don't call this.debug inside here or you'll create an infinite loop + + var f = this.eventQueue ? this.eventQueue.shift() : null; + if (typeof(f) === "function") { + f.apply(this); + } +}; + +// Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have +// properties that contain characters that are not valid for JavaScript identifiers. To work around this +// the Flash Component escapes the parameter names and we must unescape again before passing them along. +SWFUpload.prototype.unescapeFilePostParams = function (file) { + var reg = /[$]([0-9a-f]{4})/i; + var unescapedPost = {}; + var uk; + + if (file != undefined) { + for (var k in file.post) { + if (file.post.hasOwnProperty(k)) { + uk = k; + var match; + while ((match = reg.exec(uk)) !== null) { + uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16))); + } + unescapedPost[uk] = file.post[k]; + } + } + + file.post = unescapedPost; + } + + return file; +}; + +// Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working) +SWFUpload.prototype.testExternalInterface = function () { + try { + return this.callFlash("TestExternalInterface"); + } catch (ex) { + return false; + } +}; + +// Private: This event is called by Flash when it has finished loading. Don't modify this. +// Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded. +SWFUpload.prototype.flashReady = function () { + // Check that the movie element is loaded correctly with its ExternalInterface methods defined + var movieElement = this.getMovieElement(); + + if (!movieElement) { + this.debug("Flash called back ready but the flash movie can't be found."); + return; + } + + this.cleanUp(movieElement); + + this.queueEvent("swfupload_loaded_handler"); +}; + +// Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE. +// This function is called by Flash each time the ExternalInterface functions are created. +SWFUpload.prototype.cleanUp = function (movieElement) { + // Pro-actively unhook all the Flash functions + try { + if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE + this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)"); + for (var key in movieElement) { + try { + if (typeof(movieElement[key]) === "function") { + movieElement[key] = null; + } + } catch (ex) { + } + } + } + } catch (ex1) { + + } + + // Fix Flashes own cleanup code so if the SWFMovie was removed from the page + // it doesn't display errors. + window["__flash__removeCallback"] = function (instance, name) { + try { + if (instance) { + instance[name] = null; + } + } catch (flashEx) { + + } + }; + +}; + + +/* This is a chance to do something before the browse window opens */ +SWFUpload.prototype.fileDialogStart = function () { + this.queueEvent("file_dialog_start_handler"); +}; + + +/* Called when a file is successfully added to the queue. */ +SWFUpload.prototype.fileQueued = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("file_queued_handler", file); +}; + + +/* Handle errors that occur when an attempt to queue a file fails. */ +SWFUpload.prototype.fileQueueError = function (file, errorCode, message) { + file = this.unescapeFilePostParams(file); + this.queueEvent("file_queue_error_handler", [file, errorCode, message]); +}; + +/* Called after the file dialog has closed and the selected files have been queued. + You could call startUpload here if you want the queued files to begin uploading immediately. */ +SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) { + this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]); +}; + +SWFUpload.prototype.uploadStart = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("return_upload_start_handler", file); +}; + +SWFUpload.prototype.returnUploadStart = function (file) { + var returnValue; + if (typeof this.settings.upload_start_handler === "function") { + file = this.unescapeFilePostParams(file); + returnValue = this.settings.upload_start_handler.call(this, file); + } else if (this.settings.upload_start_handler != undefined) { + throw "upload_start_handler must be a function"; + } + + // Convert undefined to true so if nothing is returned from the upload_start_handler it is + // interpretted as 'true'. + if (returnValue === undefined) { + returnValue = true; + } + + returnValue = !!returnValue; + + this.callFlash("ReturnUploadStart", [returnValue]); +}; + + + +SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]); +}; + +SWFUpload.prototype.uploadError = function (file, errorCode, message) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_error_handler", [file, errorCode, message]); +}; + +SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_success_handler", [file, serverData, responseReceived]); +}; + +SWFUpload.prototype.uploadComplete = function (file) { + file = this.unescapeFilePostParams(file); + this.queueEvent("upload_complete_handler", file); +}; + +/* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the + internal debug console. You can override this event and have messages written where you want. */ +SWFUpload.prototype.debug = function (message) { + this.queueEvent("debug_handler", message); +}; + + +/* ********************************** + Debug Console + The debug console is a self contained, in page location + for debug message to be sent. The Debug Console adds + itself to the body if necessary. + + The console is automatically scrolled as messages appear. + + If you are using your own debug handler or when you deploy to production and + have debug disabled you can remove these functions to reduce the file size + and complexity. +********************************** */ + +// Private: debugMessage is the default debug_handler. If you want to print debug messages +// call the debug() function. When overriding the function your own function should +// check to see if the debug setting is true before outputting debug information. +SWFUpload.prototype.debugMessage = function (message) { + if (this.settings.debug) { + var exceptionMessage, exceptionValues = []; + + // Check for an exception object and print it nicely + if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") { + for (var key in message) { + if (message.hasOwnProperty(key)) { + exceptionValues.push(key + ": " + message[key]); + } + } + exceptionMessage = exceptionValues.join("\n") || ""; + exceptionValues = exceptionMessage.split("\n"); + exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: "); + SWFUpload.Console.writeLine(exceptionMessage); + } else { + SWFUpload.Console.writeLine(message); + } + } +}; + +SWFUpload.Console = {}; +SWFUpload.Console.writeLine = function (message) { + var console, documentForm; + + try { + console = document.getElementById("SWFUpload_Console"); + + if (!console) { + documentForm = document.createElement("form"); + document.getElementsByTagName("body")[0].appendChild(documentForm); + + console = document.createElement("textarea"); + console.id = "SWFUpload_Console"; + console.style.fontFamily = "monospace"; + console.setAttribute("wrap", "off"); + console.wrap = "off"; + console.style.overflow = "auto"; + console.style.width = "700px"; + console.style.height = "350px"; + console.style.margin = "5px"; + documentForm.appendChild(console); + } + + console.value += message + "\n"; + + console.scrollTop = console.scrollHeight - console.clientHeight; + } catch (ex) { + alert("Exception: " + ex.name + " Message: " + ex.message); + } +}; diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/js/swfupload/swfupload.queue.js --- a/src/ldt/ldt/static/ldt/js/swfupload/swfupload.queue.js Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/js/swfupload/swfupload.queue.js Mon May 16 20:00:36 2011 +0200 @@ -1,98 +1,98 @@ -/* - Queue Plug-in - - Features: - *Adds a cancelQueue() method for cancelling the entire queue. - *All queued files are uploaded when startUpload() is called. - *If false is returned from uploadComplete then the queue upload is stopped. - If false is not returned (strict comparison) then the queue upload is continued. - *Adds a QueueComplete event that is fired when all the queued files have finished uploading. - Set the event handler with the queue_complete_handler setting. - - */ - -var SWFUpload; -if (typeof(SWFUpload) === "function") { - SWFUpload.queue = {}; - - SWFUpload.prototype.initSettings = (function (oldInitSettings) { - return function () { - if (typeof(oldInitSettings) === "function") { - oldInitSettings.call(this); - } - - this.queueSettings = {}; - - this.queueSettings.queue_cancelled_flag = false; - this.queueSettings.queue_upload_count = 0; - - this.queueSettings.user_upload_complete_handler = this.settings.upload_complete_handler; - this.queueSettings.user_upload_start_handler = this.settings.upload_start_handler; - this.settings.upload_complete_handler = SWFUpload.queue.uploadCompleteHandler; - this.settings.upload_start_handler = SWFUpload.queue.uploadStartHandler; - - this.settings.queue_complete_handler = this.settings.queue_complete_handler || null; - }; - })(SWFUpload.prototype.initSettings); - - SWFUpload.prototype.startUpload = function (fileID) { - this.queueSettings.queue_cancelled_flag = false; - this.callFlash("StartUpload", [fileID]); - }; - - SWFUpload.prototype.cancelQueue = function () { - this.queueSettings.queue_cancelled_flag = true; - this.stopUpload(); - - var stats = this.getStats(); - while (stats.files_queued > 0) { - this.cancelUpload(); - stats = this.getStats(); - } - }; - - SWFUpload.queue.uploadStartHandler = function (file) { - var returnValue; - if (typeof(this.queueSettings.user_upload_start_handler) === "function") { - returnValue = this.queueSettings.user_upload_start_handler.call(this, file); - } - - // To prevent upload a real "FALSE" value must be returned, otherwise default to a real "TRUE" value. - returnValue = (returnValue === false) ? false : true; - - this.queueSettings.queue_cancelled_flag = !returnValue; - - return returnValue; - }; - - SWFUpload.queue.uploadCompleteHandler = function (file) { - var user_upload_complete_handler = this.queueSettings.user_upload_complete_handler; - var continueUpload; - - if (file.filestatus === SWFUpload.FILE_STATUS.COMPLETE) { - this.queueSettings.queue_upload_count++; - } - - if (typeof(user_upload_complete_handler) === "function") { - continueUpload = (user_upload_complete_handler.call(this, file) === false) ? false : true; - } else if (file.filestatus === SWFUpload.FILE_STATUS.QUEUED) { - // If the file was stopped and re-queued don't restart the upload - continueUpload = false; - } else { - continueUpload = true; - } - - if (continueUpload) { - var stats = this.getStats(); - if (stats.files_queued > 0 && this.queueSettings.queue_cancelled_flag === false) { - this.startUpload(); - } else if (this.queueSettings.queue_cancelled_flag === false) { - this.queueEvent("queue_complete_handler", [this.queueSettings.queue_upload_count]); - this.queueSettings.queue_upload_count = 0; - } else { - this.queueSettings.queue_cancelled_flag = false; - this.queueSettings.queue_upload_count = 0; - } - } - }; +/* + Queue Plug-in + + Features: + *Adds a cancelQueue() method for cancelling the entire queue. + *All queued files are uploaded when startUpload() is called. + *If false is returned from uploadComplete then the queue upload is stopped. + If false is not returned (strict comparison) then the queue upload is continued. + *Adds a QueueComplete event that is fired when all the queued files have finished uploading. + Set the event handler with the queue_complete_handler setting. + + */ + +var SWFUpload; +if (typeof(SWFUpload) === "function") { + SWFUpload.queue = {}; + + SWFUpload.prototype.initSettings = (function (oldInitSettings) { + return function () { + if (typeof(oldInitSettings) === "function") { + oldInitSettings.call(this); + } + + this.queueSettings = {}; + + this.queueSettings.queue_cancelled_flag = false; + this.queueSettings.queue_upload_count = 0; + + this.queueSettings.user_upload_complete_handler = this.settings.upload_complete_handler; + this.queueSettings.user_upload_start_handler = this.settings.upload_start_handler; + this.settings.upload_complete_handler = SWFUpload.queue.uploadCompleteHandler; + this.settings.upload_start_handler = SWFUpload.queue.uploadStartHandler; + + this.settings.queue_complete_handler = this.settings.queue_complete_handler || null; + }; + })(SWFUpload.prototype.initSettings); + + SWFUpload.prototype.startUpload = function (fileID) { + this.queueSettings.queue_cancelled_flag = false; + this.callFlash("StartUpload", [fileID]); + }; + + SWFUpload.prototype.cancelQueue = function () { + this.queueSettings.queue_cancelled_flag = true; + this.stopUpload(); + + var stats = this.getStats(); + while (stats.files_queued > 0) { + this.cancelUpload(); + stats = this.getStats(); + } + }; + + SWFUpload.queue.uploadStartHandler = function (file) { + var returnValue; + if (typeof(this.queueSettings.user_upload_start_handler) === "function") { + returnValue = this.queueSettings.user_upload_start_handler.call(this, file); + } + + // To prevent upload a real "FALSE" value must be returned, otherwise default to a real "TRUE" value. + returnValue = (returnValue === false) ? false : true; + + this.queueSettings.queue_cancelled_flag = !returnValue; + + return returnValue; + }; + + SWFUpload.queue.uploadCompleteHandler = function (file) { + var user_upload_complete_handler = this.queueSettings.user_upload_complete_handler; + var continueUpload; + + if (file.filestatus === SWFUpload.FILE_STATUS.COMPLETE) { + this.queueSettings.queue_upload_count++; + } + + if (typeof(user_upload_complete_handler) === "function") { + continueUpload = (user_upload_complete_handler.call(this, file) === false) ? false : true; + } else if (file.filestatus === SWFUpload.FILE_STATUS.QUEUED) { + // If the file was stopped and re-queued don't restart the upload + continueUpload = false; + } else { + continueUpload = true; + } + + if (continueUpload) { + var stats = this.getStats(); + if (stats.files_queued > 0 && this.queueSettings.queue_cancelled_flag === false) { + this.startUpload(); + } else if (this.queueSettings.queue_cancelled_flag === false) { + this.queueEvent("queue_complete_handler", [this.queueSettings.queue_upload_count]); + this.queueSettings.queue_upload_count = 0; + } else { + this.queueSettings.queue_cancelled_flag = false; + this.queueSettings.queue_upload_count = 0; + } + } + }; } \ No newline at end of file diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/js/swfupload/swfupload.speed.js --- a/src/ldt/ldt/static/ldt/js/swfupload/swfupload.speed.js Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/js/swfupload/swfupload.speed.js Mon May 16 20:00:36 2011 +0200 @@ -1,342 +1,342 @@ -/* - Speed Plug-in - - Features: - *Adds several properties to the 'file' object indicated upload speed, time left, upload time, etc. - - currentSpeed -- String indicating the upload speed, bytes per second - - averageSpeed -- Overall average upload speed, bytes per second - - movingAverageSpeed -- Speed over averaged over the last several measurements, bytes per second - - timeRemaining -- Estimated remaining upload time in seconds - - timeElapsed -- Number of seconds passed for this upload - - percentUploaded -- Percentage of the file uploaded (0 to 100) - - sizeUploaded -- Formatted size uploaded so far, bytes - - *Adds setting 'moving_average_history_size' for defining the window size used to calculate the moving average speed. - - *Adds several Formatting functions for formatting that values provided on the file object. - - SWFUpload.speed.formatBPS(bps) -- outputs string formatted in the best units (Gbps, Mbps, Kbps, bps) - - SWFUpload.speed.formatTime(seconds) -- outputs string formatted in the best units (x Hr y M z S) - - SWFUpload.speed.formatSize(bytes) -- outputs string formatted in the best units (w GB x MB y KB z B ) - - SWFUpload.speed.formatPercent(percent) -- outputs string formatted with a percent sign (x.xx %) - - SWFUpload.speed.formatUnits(baseNumber, divisionArray, unitLabelArray, fractionalBoolean) - - Formats a number using the division array to determine how to apply the labels in the Label Array - - factionalBoolean indicates whether the number should be returned as a single fractional number with a unit (speed) - or as several numbers labeled with units (time) - */ - -var SWFUpload; -if (typeof(SWFUpload) === "function") { - SWFUpload.speed = {}; - - SWFUpload.prototype.initSettings = (function (oldInitSettings) { - return function () { - if (typeof(oldInitSettings) === "function") { - oldInitSettings.call(this); - } - - this.ensureDefault = function (settingName, defaultValue) { - this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName]; - }; - - // List used to keep the speed stats for the files we are tracking - this.fileSpeedStats = {}; - this.speedSettings = {}; - - this.ensureDefault("moving_average_history_size", "10"); - - this.speedSettings.user_file_queued_handler = this.settings.file_queued_handler; - this.speedSettings.user_file_queue_error_handler = this.settings.file_queue_error_handler; - this.speedSettings.user_upload_start_handler = this.settings.upload_start_handler; - this.speedSettings.user_upload_error_handler = this.settings.upload_error_handler; - this.speedSettings.user_upload_progress_handler = this.settings.upload_progress_handler; - this.speedSettings.user_upload_success_handler = this.settings.upload_success_handler; - this.speedSettings.user_upload_complete_handler = this.settings.upload_complete_handler; - - this.settings.file_queued_handler = SWFUpload.speed.fileQueuedHandler; - this.settings.file_queue_error_handler = SWFUpload.speed.fileQueueErrorHandler; - this.settings.upload_start_handler = SWFUpload.speed.uploadStartHandler; - this.settings.upload_error_handler = SWFUpload.speed.uploadErrorHandler; - this.settings.upload_progress_handler = SWFUpload.speed.uploadProgressHandler; - this.settings.upload_success_handler = SWFUpload.speed.uploadSuccessHandler; - this.settings.upload_complete_handler = SWFUpload.speed.uploadCompleteHandler; - - delete this.ensureDefault; - }; - })(SWFUpload.prototype.initSettings); - - - SWFUpload.speed.fileQueuedHandler = function (file) { - if (typeof this.speedSettings.user_file_queued_handler === "function") { - file = SWFUpload.speed.extendFile(file); - - return this.speedSettings.user_file_queued_handler.call(this, file); - } - }; - - SWFUpload.speed.fileQueueErrorHandler = function (file, errorCode, message) { - if (typeof this.speedSettings.user_file_queue_error_handler === "function") { - file = SWFUpload.speed.extendFile(file); - - return this.speedSettings.user_file_queue_error_handler.call(this, file, errorCode, message); - } - }; - - SWFUpload.speed.uploadStartHandler = function (file) { - if (typeof this.speedSettings.user_upload_start_handler === "function") { - file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); - return this.speedSettings.user_upload_start_handler.call(this, file); - } - }; - - SWFUpload.speed.uploadErrorHandler = function (file, errorCode, message) { - file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); - SWFUpload.speed.removeTracking(file, this.fileSpeedStats); - - if (typeof this.speedSettings.user_upload_error_handler === "function") { - return this.speedSettings.user_upload_error_handler.call(this, file, errorCode, message); - } - }; - SWFUpload.speed.uploadProgressHandler = function (file, bytesComplete, bytesTotal) { - this.updateTracking(file, bytesComplete); - file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); - - if (typeof this.speedSettings.user_upload_progress_handler === "function") { - return this.speedSettings.user_upload_progress_handler.call(this, file, bytesComplete, bytesTotal); - } - }; - - SWFUpload.speed.uploadSuccessHandler = function (file, serverData) { - if (typeof this.speedSettings.user_upload_success_handler === "function") { - file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); - return this.speedSettings.user_upload_success_handler.call(this, file, serverData); - } - }; - SWFUpload.speed.uploadCompleteHandler = function (file) { - file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); - SWFUpload.speed.removeTracking(file, this.fileSpeedStats); - - if (typeof this.speedSettings.user_upload_complete_handler === "function") { - return this.speedSettings.user_upload_complete_handler.call(this, file); - } - }; - - // Private: extends the file object with the speed plugin values - SWFUpload.speed.extendFile = function (file, trackingList) { - var tracking; - - if (trackingList) { - tracking = trackingList[file.id]; - } - - if (tracking) { - file.currentSpeed = tracking.currentSpeed; - file.averageSpeed = tracking.averageSpeed; - file.movingAverageSpeed = tracking.movingAverageSpeed; - file.timeRemaining = tracking.timeRemaining; - file.timeElapsed = tracking.timeElapsed; - file.percentUploaded = tracking.percentUploaded; - file.sizeUploaded = tracking.bytesUploaded; - - } else { - file.currentSpeed = 0; - file.averageSpeed = 0; - file.movingAverageSpeed = 0; - file.timeRemaining = 0; - file.timeElapsed = 0; - file.percentUploaded = 0; - file.sizeUploaded = 0; - } - - return file; - }; - - // Private: Updates the speed tracking object, or creates it if necessary - SWFUpload.prototype.updateTracking = function (file, bytesUploaded) { - var tracking = this.fileSpeedStats[file.id]; - if (!tracking) { - this.fileSpeedStats[file.id] = tracking = {}; - } - - // Sanity check inputs - bytesUploaded = bytesUploaded || tracking.bytesUploaded || 0; - if (bytesUploaded < 0) { - bytesUploaded = 0; - } - if (bytesUploaded > file.size) { - bytesUploaded = file.size; - } - - var tickTime = (new Date()).getTime(); - if (!tracking.startTime) { - tracking.startTime = (new Date()).getTime(); - tracking.lastTime = tracking.startTime; - tracking.currentSpeed = 0; - tracking.averageSpeed = 0; - tracking.movingAverageSpeed = 0; - tracking.movingAverageHistory = []; - tracking.timeRemaining = 0; - tracking.timeElapsed = 0; - tracking.percentUploaded = bytesUploaded / file.size; - tracking.bytesUploaded = bytesUploaded; - } else if (tracking.startTime > tickTime) { - this.debug("When backwards in time"); - } else { - // Get time and deltas - var now = (new Date()).getTime(); - var lastTime = tracking.lastTime; - var deltaTime = now - lastTime; - var deltaBytes = bytesUploaded - tracking.bytesUploaded; - - if (deltaBytes === 0 || deltaTime === 0) { - return tracking; - } - - // Update tracking object - tracking.lastTime = now; - tracking.bytesUploaded = bytesUploaded; - - // Calculate speeds - tracking.currentSpeed = (deltaBytes * 8 ) / (deltaTime / 1000); - tracking.averageSpeed = (tracking.bytesUploaded * 8) / ((now - tracking.startTime) / 1000); - - // Calculate moving average - tracking.movingAverageHistory.push(tracking.currentSpeed); - if (tracking.movingAverageHistory.length > this.settings.moving_average_history_size) { - tracking.movingAverageHistory.shift(); - } - - tracking.movingAverageSpeed = SWFUpload.speed.calculateMovingAverage(tracking.movingAverageHistory); - - // Update times - tracking.timeRemaining = (file.size - tracking.bytesUploaded) * 8 / tracking.movingAverageSpeed; - tracking.timeElapsed = (now - tracking.startTime) / 1000; - - // Update percent - tracking.percentUploaded = (tracking.bytesUploaded / file.size * 100); - } - - return tracking; - }; - SWFUpload.speed.removeTracking = function (file, trackingList) { - try { - trackingList[file.id] = null; - delete trackingList[file.id]; - } catch (ex) { - } - }; - - SWFUpload.speed.formatUnits = function (baseNumber, unitDivisors, unitLabels, singleFractional) { - var i, unit, unitDivisor, unitLabel; - - if (baseNumber === 0) { - return "0 " + unitLabels[unitLabels.length - 1]; - } - - if (singleFractional) { - unit = baseNumber; - unitLabel = unitLabels.length >= unitDivisors.length ? unitLabels[unitDivisors.length - 1] : ""; - for (i = 0; i < unitDivisors.length; i++) { - if (baseNumber >= unitDivisors[i]) { - unit = (baseNumber / unitDivisors[i]).toFixed(2); - unitLabel = unitLabels.length >= i ? " " + unitLabels[i] : ""; - break; - } - } - - return unit + unitLabel; - } else { - var formattedStrings = []; - var remainder = baseNumber; - - for (i = 0; i < unitDivisors.length; i++) { - unitDivisor = unitDivisors[i]; - unitLabel = unitLabels.length > i ? " " + unitLabels[i] : ""; - - unit = remainder / unitDivisor; - if (i < unitDivisors.length -1) { - unit = Math.floor(unit); - } else { - unit = unit.toFixed(2); - } - if (unit > 0) { - remainder = remainder % unitDivisor; - - formattedStrings.push(unit + unitLabel); - } - } - - return formattedStrings.join(" "); - } - }; - - SWFUpload.speed.formatBPS = function (baseNumber) { - var bpsUnits = [1073741824, 1048576, 1024, 1], bpsUnitLabels = ["Gbps", "Mbps", "Kbps", "bps"]; - return SWFUpload.speed.formatUnits(baseNumber, bpsUnits, bpsUnitLabels, true); - - }; - SWFUpload.speed.formatTime = function (baseNumber) { - var timeUnits = [86400, 3600, 60, 1], timeUnitLabels = ["d", "h", "m", "s"]; - return SWFUpload.speed.formatUnits(baseNumber, timeUnits, timeUnitLabels, false); - - }; - SWFUpload.speed.formatBytes = function (baseNumber) { - var sizeUnits = [1073741824, 1048576, 1024, 1], sizeUnitLabels = ["GB", "MB", "KB", "bytes"]; - return SWFUpload.speed.formatUnits(baseNumber, sizeUnits, sizeUnitLabels, true); - - }; - SWFUpload.speed.formatPercent = function (baseNumber) { - return baseNumber.toFixed(2) + " %"; - }; - - SWFUpload.speed.calculateMovingAverage = function (history) { - var vals = [], size, sum = 0.0, mean = 0.0, varianceTemp = 0.0, variance = 0.0, standardDev = 0.0; - var i; - var mSum = 0, mCount = 0; - - size = history.length; - - // Check for sufficient data - if (size >= 8) { - // Clone the array and Calculate sum of the values - for (i = 0; i < size; i++) { - vals[i] = history[i]; - sum += vals[i]; - } - - mean = sum / size; - - // Calculate variance for the set - for (i = 0; i < size; i++) { - varianceTemp += Math.pow((vals[i] - mean), 2); - } - - variance = varianceTemp / size; - standardDev = Math.sqrt(variance); - - //Standardize the Data - for (i = 0; i < size; i++) { - vals[i] = (vals[i] - mean) / standardDev; - } - - // Calculate the average excluding outliers - var deviationRange = 2.0; - for (i = 0; i < size; i++) { - - if (vals[i] <= deviationRange && vals[i] >= -deviationRange) { - mCount++; - mSum += history[i]; - } - } - - } else { - // Calculate the average (not enough data points to remove outliers) - mCount = size; - for (i = 0; i < size; i++) { - mSum += history[i]; - } - } - - return mSum / mCount; - }; - +/* + Speed Plug-in + + Features: + *Adds several properties to the 'file' object indicated upload speed, time left, upload time, etc. + - currentSpeed -- String indicating the upload speed, bytes per second + - averageSpeed -- Overall average upload speed, bytes per second + - movingAverageSpeed -- Speed over averaged over the last several measurements, bytes per second + - timeRemaining -- Estimated remaining upload time in seconds + - timeElapsed -- Number of seconds passed for this upload + - percentUploaded -- Percentage of the file uploaded (0 to 100) + - sizeUploaded -- Formatted size uploaded so far, bytes + + *Adds setting 'moving_average_history_size' for defining the window size used to calculate the moving average speed. + + *Adds several Formatting functions for formatting that values provided on the file object. + - SWFUpload.speed.formatBPS(bps) -- outputs string formatted in the best units (Gbps, Mbps, Kbps, bps) + - SWFUpload.speed.formatTime(seconds) -- outputs string formatted in the best units (x Hr y M z S) + - SWFUpload.speed.formatSize(bytes) -- outputs string formatted in the best units (w GB x MB y KB z B ) + - SWFUpload.speed.formatPercent(percent) -- outputs string formatted with a percent sign (x.xx %) + - SWFUpload.speed.formatUnits(baseNumber, divisionArray, unitLabelArray, fractionalBoolean) + - Formats a number using the division array to determine how to apply the labels in the Label Array + - factionalBoolean indicates whether the number should be returned as a single fractional number with a unit (speed) + or as several numbers labeled with units (time) + */ + +var SWFUpload; +if (typeof(SWFUpload) === "function") { + SWFUpload.speed = {}; + + SWFUpload.prototype.initSettings = (function (oldInitSettings) { + return function () { + if (typeof(oldInitSettings) === "function") { + oldInitSettings.call(this); + } + + this.ensureDefault = function (settingName, defaultValue) { + this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName]; + }; + + // List used to keep the speed stats for the files we are tracking + this.fileSpeedStats = {}; + this.speedSettings = {}; + + this.ensureDefault("moving_average_history_size", "10"); + + this.speedSettings.user_file_queued_handler = this.settings.file_queued_handler; + this.speedSettings.user_file_queue_error_handler = this.settings.file_queue_error_handler; + this.speedSettings.user_upload_start_handler = this.settings.upload_start_handler; + this.speedSettings.user_upload_error_handler = this.settings.upload_error_handler; + this.speedSettings.user_upload_progress_handler = this.settings.upload_progress_handler; + this.speedSettings.user_upload_success_handler = this.settings.upload_success_handler; + this.speedSettings.user_upload_complete_handler = this.settings.upload_complete_handler; + + this.settings.file_queued_handler = SWFUpload.speed.fileQueuedHandler; + this.settings.file_queue_error_handler = SWFUpload.speed.fileQueueErrorHandler; + this.settings.upload_start_handler = SWFUpload.speed.uploadStartHandler; + this.settings.upload_error_handler = SWFUpload.speed.uploadErrorHandler; + this.settings.upload_progress_handler = SWFUpload.speed.uploadProgressHandler; + this.settings.upload_success_handler = SWFUpload.speed.uploadSuccessHandler; + this.settings.upload_complete_handler = SWFUpload.speed.uploadCompleteHandler; + + delete this.ensureDefault; + }; + })(SWFUpload.prototype.initSettings); + + + SWFUpload.speed.fileQueuedHandler = function (file) { + if (typeof this.speedSettings.user_file_queued_handler === "function") { + file = SWFUpload.speed.extendFile(file); + + return this.speedSettings.user_file_queued_handler.call(this, file); + } + }; + + SWFUpload.speed.fileQueueErrorHandler = function (file, errorCode, message) { + if (typeof this.speedSettings.user_file_queue_error_handler === "function") { + file = SWFUpload.speed.extendFile(file); + + return this.speedSettings.user_file_queue_error_handler.call(this, file, errorCode, message); + } + }; + + SWFUpload.speed.uploadStartHandler = function (file) { + if (typeof this.speedSettings.user_upload_start_handler === "function") { + file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); + return this.speedSettings.user_upload_start_handler.call(this, file); + } + }; + + SWFUpload.speed.uploadErrorHandler = function (file, errorCode, message) { + file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); + SWFUpload.speed.removeTracking(file, this.fileSpeedStats); + + if (typeof this.speedSettings.user_upload_error_handler === "function") { + return this.speedSettings.user_upload_error_handler.call(this, file, errorCode, message); + } + }; + SWFUpload.speed.uploadProgressHandler = function (file, bytesComplete, bytesTotal) { + this.updateTracking(file, bytesComplete); + file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); + + if (typeof this.speedSettings.user_upload_progress_handler === "function") { + return this.speedSettings.user_upload_progress_handler.call(this, file, bytesComplete, bytesTotal); + } + }; + + SWFUpload.speed.uploadSuccessHandler = function (file, serverData) { + if (typeof this.speedSettings.user_upload_success_handler === "function") { + file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); + return this.speedSettings.user_upload_success_handler.call(this, file, serverData); + } + }; + SWFUpload.speed.uploadCompleteHandler = function (file) { + file = SWFUpload.speed.extendFile(file, this.fileSpeedStats); + SWFUpload.speed.removeTracking(file, this.fileSpeedStats); + + if (typeof this.speedSettings.user_upload_complete_handler === "function") { + return this.speedSettings.user_upload_complete_handler.call(this, file); + } + }; + + // Private: extends the file object with the speed plugin values + SWFUpload.speed.extendFile = function (file, trackingList) { + var tracking; + + if (trackingList) { + tracking = trackingList[file.id]; + } + + if (tracking) { + file.currentSpeed = tracking.currentSpeed; + file.averageSpeed = tracking.averageSpeed; + file.movingAverageSpeed = tracking.movingAverageSpeed; + file.timeRemaining = tracking.timeRemaining; + file.timeElapsed = tracking.timeElapsed; + file.percentUploaded = tracking.percentUploaded; + file.sizeUploaded = tracking.bytesUploaded; + + } else { + file.currentSpeed = 0; + file.averageSpeed = 0; + file.movingAverageSpeed = 0; + file.timeRemaining = 0; + file.timeElapsed = 0; + file.percentUploaded = 0; + file.sizeUploaded = 0; + } + + return file; + }; + + // Private: Updates the speed tracking object, or creates it if necessary + SWFUpload.prototype.updateTracking = function (file, bytesUploaded) { + var tracking = this.fileSpeedStats[file.id]; + if (!tracking) { + this.fileSpeedStats[file.id] = tracking = {}; + } + + // Sanity check inputs + bytesUploaded = bytesUploaded || tracking.bytesUploaded || 0; + if (bytesUploaded < 0) { + bytesUploaded = 0; + } + if (bytesUploaded > file.size) { + bytesUploaded = file.size; + } + + var tickTime = (new Date()).getTime(); + if (!tracking.startTime) { + tracking.startTime = (new Date()).getTime(); + tracking.lastTime = tracking.startTime; + tracking.currentSpeed = 0; + tracking.averageSpeed = 0; + tracking.movingAverageSpeed = 0; + tracking.movingAverageHistory = []; + tracking.timeRemaining = 0; + tracking.timeElapsed = 0; + tracking.percentUploaded = bytesUploaded / file.size; + tracking.bytesUploaded = bytesUploaded; + } else if (tracking.startTime > tickTime) { + this.debug("When backwards in time"); + } else { + // Get time and deltas + var now = (new Date()).getTime(); + var lastTime = tracking.lastTime; + var deltaTime = now - lastTime; + var deltaBytes = bytesUploaded - tracking.bytesUploaded; + + if (deltaBytes === 0 || deltaTime === 0) { + return tracking; + } + + // Update tracking object + tracking.lastTime = now; + tracking.bytesUploaded = bytesUploaded; + + // Calculate speeds + tracking.currentSpeed = (deltaBytes * 8 ) / (deltaTime / 1000); + tracking.averageSpeed = (tracking.bytesUploaded * 8) / ((now - tracking.startTime) / 1000); + + // Calculate moving average + tracking.movingAverageHistory.push(tracking.currentSpeed); + if (tracking.movingAverageHistory.length > this.settings.moving_average_history_size) { + tracking.movingAverageHistory.shift(); + } + + tracking.movingAverageSpeed = SWFUpload.speed.calculateMovingAverage(tracking.movingAverageHistory); + + // Update times + tracking.timeRemaining = (file.size - tracking.bytesUploaded) * 8 / tracking.movingAverageSpeed; + tracking.timeElapsed = (now - tracking.startTime) / 1000; + + // Update percent + tracking.percentUploaded = (tracking.bytesUploaded / file.size * 100); + } + + return tracking; + }; + SWFUpload.speed.removeTracking = function (file, trackingList) { + try { + trackingList[file.id] = null; + delete trackingList[file.id]; + } catch (ex) { + } + }; + + SWFUpload.speed.formatUnits = function (baseNumber, unitDivisors, unitLabels, singleFractional) { + var i, unit, unitDivisor, unitLabel; + + if (baseNumber === 0) { + return "0 " + unitLabels[unitLabels.length - 1]; + } + + if (singleFractional) { + unit = baseNumber; + unitLabel = unitLabels.length >= unitDivisors.length ? unitLabels[unitDivisors.length - 1] : ""; + for (i = 0; i < unitDivisors.length; i++) { + if (baseNumber >= unitDivisors[i]) { + unit = (baseNumber / unitDivisors[i]).toFixed(2); + unitLabel = unitLabels.length >= i ? " " + unitLabels[i] : ""; + break; + } + } + + return unit + unitLabel; + } else { + var formattedStrings = []; + var remainder = baseNumber; + + for (i = 0; i < unitDivisors.length; i++) { + unitDivisor = unitDivisors[i]; + unitLabel = unitLabels.length > i ? " " + unitLabels[i] : ""; + + unit = remainder / unitDivisor; + if (i < unitDivisors.length -1) { + unit = Math.floor(unit); + } else { + unit = unit.toFixed(2); + } + if (unit > 0) { + remainder = remainder % unitDivisor; + + formattedStrings.push(unit + unitLabel); + } + } + + return formattedStrings.join(" "); + } + }; + + SWFUpload.speed.formatBPS = function (baseNumber) { + var bpsUnits = [1073741824, 1048576, 1024, 1], bpsUnitLabels = ["Gbps", "Mbps", "Kbps", "bps"]; + return SWFUpload.speed.formatUnits(baseNumber, bpsUnits, bpsUnitLabels, true); + + }; + SWFUpload.speed.formatTime = function (baseNumber) { + var timeUnits = [86400, 3600, 60, 1], timeUnitLabels = ["d", "h", "m", "s"]; + return SWFUpload.speed.formatUnits(baseNumber, timeUnits, timeUnitLabels, false); + + }; + SWFUpload.speed.formatBytes = function (baseNumber) { + var sizeUnits = [1073741824, 1048576, 1024, 1], sizeUnitLabels = ["GB", "MB", "KB", "bytes"]; + return SWFUpload.speed.formatUnits(baseNumber, sizeUnits, sizeUnitLabels, true); + + }; + SWFUpload.speed.formatPercent = function (baseNumber) { + return baseNumber.toFixed(2) + " %"; + }; + + SWFUpload.speed.calculateMovingAverage = function (history) { + var vals = [], size, sum = 0.0, mean = 0.0, varianceTemp = 0.0, variance = 0.0, standardDev = 0.0; + var i; + var mSum = 0, mCount = 0; + + size = history.length; + + // Check for sufficient data + if (size >= 8) { + // Clone the array and Calculate sum of the values + for (i = 0; i < size; i++) { + vals[i] = history[i]; + sum += vals[i]; + } + + mean = sum / size; + + // Calculate variance for the set + for (i = 0; i < size; i++) { + varianceTemp += Math.pow((vals[i] - mean), 2); + } + + variance = varianceTemp / size; + standardDev = Math.sqrt(variance); + + //Standardize the Data + for (i = 0; i < size; i++) { + vals[i] = (vals[i] - mean) / standardDev; + } + + // Calculate the average excluding outliers + var deviationRange = 2.0; + for (i = 0; i < size; i++) { + + if (vals[i] <= deviationRange && vals[i] >= -deviationRange) { + mCount++; + mSum += history[i]; + } + } + + } else { + // Calculate the average (not enough data points to remove outliers) + mCount = size; + for (i = 0; i < size; i++) { + mSum += history[i]; + } + } + + return mSum / mCount; + }; + } \ No newline at end of file diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/static/ldt/js/swfupload/swfupload.swfobject.js --- a/src/ldt/ldt/static/ldt/js/swfupload/swfupload.swfobject.js Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/static/ldt/js/swfupload/swfupload.swfobject.js Mon May 16 20:00:36 2011 +0200 @@ -1,111 +1,111 @@ -/* - SWFUpload.SWFObject Plugin - - Summary: - This plugin uses SWFObject to embed SWFUpload dynamically in the page. SWFObject provides accurate Flash Player detection and DOM Ready loading. - This plugin replaces the Graceful Degradation plugin. - - Features: - * swfupload_load_failed_hander event - * swfupload_pre_load_handler event - * minimum_flash_version setting (default: "9.0.28") - * SWFUpload.onload event for early loading - - Usage: - Provide handlers and settings as needed. When using the SWFUpload.SWFObject plugin you should initialize SWFUploading - in SWFUpload.onload rather than in window.onload. When initialized this way SWFUpload can load earlier preventing the UI flicker - that was seen using the Graceful Degradation plugin. - - - - Notes: - You must provide set minimum_flash_version setting to "8" if you are using SWFUpload for Flash Player 8. - The swfuploadLoadFailed event is only fired if the minimum version of Flash Player is not met. Other issues such as missing SWF files, browser bugs - or corrupt Flash Player installations will not trigger this event. - The swfuploadPreLoad event is fired as soon as the minimum version of Flash Player is found. It does not wait for SWFUpload to load and can - be used to prepare the SWFUploadUI and hide alternate content. - swfobject's onDomReady event is cross-browser safe but will default to the window.onload event when DOMReady is not supported by the browser. - Early DOM Loading is supported in major modern browsers but cannot be guaranteed for every browser ever made. -*/ - - -/* SWFObject v2.1 - Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis - This software is released under the MIT License -*/ -var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write(" + + Notes: + You must provide set minimum_flash_version setting to "8" if you are using SWFUpload for Flash Player 8. + The swfuploadLoadFailed event is only fired if the minimum version of Flash Player is not met. Other issues such as missing SWF files, browser bugs + or corrupt Flash Player installations will not trigger this event. + The swfuploadPreLoad event is fired as soon as the minimum version of Flash Player is found. It does not wait for SWFUpload to load and can + be used to prepare the SWFUploadUI and hide alternate content. + swfobject's onDomReady event is cross-browser safe but will default to the window.onload event when DOMReady is not supported by the browser. + Early DOM Loading is supported in major modern browsers but cannot be guaranteed for every browser ever made. +*/ + + +/* SWFObject v2.1 + Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis + This software is released under the MIT License +*/ +var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write(" - {% endif %} - {% block extra_body %} - {% endblock %} - - {% block main_content %} - {% endblock %} - - {% block content %} - {% endblock %} - - - + +{% block html_declare %} + +{% endblock %} + + + {% if user.is_authenticated %}Hello {{ user }}{% else %}Please login{% endif %} + + {% block extra_head %} + {% endblock %} + + + +

social-auth

+ {% if FACEBOOK_APP_ID %} +
+ + {% endif %} + {% block extra_body %} + {% endblock %} + + {% block main_content %} + {% endblock %} + + {% block content %} + {% endblock %} + + + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/templates/socialauth/createprofile.html --- a/src/ldt/ldt/templates/socialauth/createprofile.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/templates/socialauth/createprofile.html Mon May 16 20:00:36 2011 +0200 @@ -1,13 +1,13 @@ -{% extends 'socialauth/socialauth_base.html' %} - -{% block content %} - -
{% csrf_token %} - - {{ create_form }} -
- - -
- +{% extends 'socialauth/socialauth_base.html' %} + +{% block content %} + +
{% csrf_token %} + + {{ create_form }} +
+ + +
+ {% endblock %} \ No newline at end of file diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/text/annotindexer.py --- a/src/ldt/ldt/text/annotindexer.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/text/annotindexer.py Mon May 16 20:00:36 2011 +0200 @@ -1,41 +1,41 @@ -import lucene - - -class AnnotIndexer(object): - - def __init__(self, annotList, writer): - self.__annotList = annotList - self.__writer = writer - - - def index_all(self): - for annot in self.__annotList: - self.index_annotation(annot) - - - def index_annotation(self, annotation): - - doc = lucene.Document() - - doc.add(lucene.Field("annotation_id", annotation.external_id, lucene.Field.Store.YES, lucene.Field.Index.NOT_ANALYZED)) - - annottags = annotation.get_tag_list() - tags = "" - - if annottags is None or len(annottags) == 0: - tags = "" - else: - for tag in annottags: - tags += tag + ";" - - doc.add(lucene.Field("type_doc", "text-annotation", lucene.Field.Store.NO, lucene.Field.Index.NOT_ANALYZED)) - doc.add(lucene.Field("tags", tags, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) - doc.add(lucene.Field("title", annotation.title, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) - doc.add(lucene.Field("abstract", annotation.description, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) - doc.add(lucene.Field("text", annotation.text, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) - doc.add(lucene.Field("all", " ".join([tags, annotation.title, annotation.description, annotation.text]), lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) - - self.__writer.addDocument(doc) - - self.__writer.close() - +import lucene + + +class AnnotIndexer(object): + + def __init__(self, annotList, writer): + self.__annotList = annotList + self.__writer = writer + + + def index_all(self): + for annot in self.__annotList: + self.index_annotation(annot) + + + def index_annotation(self, annotation): + + doc = lucene.Document() + + doc.add(lucene.Field("annotation_id", annotation.external_id, lucene.Field.Store.YES, lucene.Field.Index.NOT_ANALYZED)) + + annottags = annotation.get_tag_list() + tags = "" + + if annottags is None or len(annottags) == 0: + tags = "" + else: + for tag in annottags: + tags += tag + ";" + + doc.add(lucene.Field("type_doc", "text-annotation", lucene.Field.Store.NO, lucene.Field.Index.NOT_ANALYZED)) + doc.add(lucene.Field("tags", tags, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) + doc.add(lucene.Field("title", annotation.title, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) + doc.add(lucene.Field("abstract", annotation.description, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) + doc.add(lucene.Field("text", annotation.text, lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) + doc.add(lucene.Field("all", " ".join([tags, annotation.title, annotation.description, annotation.text]), lucene.Field.Store.NO, lucene.Field.Index.ANALYZED)) + + self.__writer.addDocument(doc) + + self.__writer.close() + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/text/models.py --- a/src/ldt/ldt/text/models.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/text/models.py Mon May 16 20:00:36 2011 +0200 @@ -1,148 +1,154 @@ -from annotindexer import AnnotIndexer -from django.db import models -from django.utils.translation import ugettext_lazy as _ -from tagging.models import Tag -from utils import generate_uuid -import ldt.indexation -import lucene -import lxml -import tagging.fields -#from django.core.management.validation import max_length - -def Property(func): - return property(**func()) - - -class Annotation(models.Model): - external_id = models.CharField(max_length=1024, null=False, unique=True, default=generate_uuid, verbose_name=_('annotation.external_id')) - uri = models.CharField(max_length=1024, verbose_name=_('annotation.uri')) - tags_field = tagging.fields.TagField(max_length=2048, null=True, blank=True, verbose_name=_('annotation.tags')) - title = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('annotation.title')) - description = models.TextField(null=True, blank=True, verbose_name=_('annotation.description')) - text = models.TextField(null=True, blank=True, verbose_name=_('annotation.text')) - color = models.CharField(max_length=1024, verbose_name=_('annotation.color')) - creator = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('creator.title')) - contributor = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('contributor.title')) - creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('annotation.creation_date')) - update_date = models.DateTimeField(auto_now=True, verbose_name=_('annotation.update_date')) - - @Property - def tags(): #@NoSelf - - def fget(self): - return ",".join(self.tag_list) - - def fset(self, value): - values = None - if isinstance(value, (list, tuple)): - values = list(value) - elif value is not None: - values = [v.lower().strip() for v in unicode(value).split(",")] - - if values is not None: - self.tags_field = ",".join(values) + "," - else: - self.tags_field = None - - return locals() - - @Property - def tag_list(): #@NoSelf - def fget(self): - return [t.name for t in Tag.objects.get_for_object(self)] - - return locals() - - - def get_tag_list(self): - tags = [] - if self.tags: - tags_list = unicode(self.tags) - for t in tags_list.split(","): - tags.append(t.strip()) - return tags - #return self.tags - - - def __unicode__(self): - return unicode(self.external_id) + u": " + unicode(self.title) - - def serialize(self, root_element=None): - - if root_element is not None: - iri = root_element - else : - iri = lxml.etree.Element('iri') - doc = lxml.etree.ElementTree(iri) - - - textannotation = lxml.etree.SubElement(iri, 'text-annotation') - id = lxml.etree.SubElement(textannotation, 'id') - id.text = self.external_id - uri = lxml.etree.SubElement(textannotation, 'uri') - uri.text = self.uri - - if self.tags: - tags = lxml.etree.SubElement(textannotation, 'tags') - for t in self.get_tag_list(): - tag = lxml.etree.SubElement(tags, 'tag') - tag.text = t - - content = lxml.etree.SubElement(textannotation, 'content') - color = lxml.etree.SubElement(content, 'color') - color.text = self.color - description = lxml.etree.SubElement(content, 'description') - description.text = self.description - title = lxml.etree.SubElement(content, 'title') - title.text = self.title - text = lxml.etree.SubElement(content, 'text') - text.text = self.text - - meta = lxml.etree.SubElement(textannotation, 'meta') - contributor = lxml.etree.SubElement(meta, "contributor") - contributor.text = self.contributor - creator = lxml.etree.SubElement(meta, "creator") - creator.text = self.creator - creationdate = lxml.etree.SubElement(meta, "created") - creationdate.text = str(self.creation_date) - updatedate = lxml.etree.SubElement(meta, "modified") - updatedate.text = str(self.update_date) - - if root_element is not None: - return root_element - else: - return doc - - - @staticmethod - def create_annotation(external_id, uri=None, tags=None, title=None, description=None, text=None, color=None, creator=None, contributor=None, creation_date=None, update_date=None): - annotation = Annotation(external_id=external_id, uri=uri, tags=tags, title=title, description=description, text=text, color=color, creator=creator, contributor=contributor, creation_date=creation_date, update_date=update_date) - annotation.save() - annotation.index_annot() - - return annotation - - - def delete(self): - super(Annotation, self).delete() - lucene.getVMEnv().attachCurrentThread() - writer = ldt.indexation.get_writer() - writer.deleteDocuments(lucene.Term("external_id", self.external_id)) - writer.close() - - def index_annot(self): - lucene.getVMEnv().attachCurrentThread() - writer = ldt.indexation.get_writer() - annotl = [self, ] - indexer = AnnotIndexer(annotl, writer) - indexer.index_all() - writer.close() - - def update_index(self): - lucene.getVMEnv().attachCurrentThread() - writer = ldt.indexation.get_writer() - writer.deleteDocuments(lucene.Term("external_id", self.external_id)) - writer.close() - self.index_annot() - - +from annotindexer import AnnotIndexer +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from tagging.models import Tag +from utils import generate_uuid +import ldt.indexation +import lucene +import lxml +import tagging.fields +#from django.core.management.validation import max_length + +def Property(func): + return property(**func()) + + +class Annotation(models.Model): + external_id = models.CharField(max_length=1024, null=False, unique=True, default=generate_uuid, verbose_name=_('annotation.external_id')) + uri = models.CharField(max_length=1024, verbose_name=_('annotation.uri')) + tags_field = tagging.fields.TagField(max_length=2048, null=True, blank=True, verbose_name=_('annotation.tags')) + title = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('annotation.title')) + description = models.TextField(null=True, blank=True, verbose_name=_('annotation.description')) + text = models.TextField(null=True, blank=True, verbose_name=_('annotation.text')) + color = models.CharField(max_length=1024, verbose_name=_('annotation.color')) + creator = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('creator.title')) + contributor = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('contributor.title')) + creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('annotation.creation_date')) + update_date = models.DateTimeField(auto_now=True, verbose_name=_('annotation.update_date')) + + @Property + def tags(): #@NoSelf + + def fget(self): + return ",".join(self.tag_list) + + def fset(self, value): + values = None + if isinstance(value, (list, tuple)): + values = list(value) + elif value is not None: + values = [v.lower().strip() for v in unicode(value).split(",")] + + if values is not None: + self.tags_field = ",".join(values) + "," + else: + self.tags_field = None + + return locals() + + @Property + def tag_list(): #@NoSelf + def fget(self): + return [t.name for t in Tag.objects.get_for_object(self)] + + return locals() + + + def get_tag_list(self): + tags = [] + if self.tags: + tags_list = unicode(self.tags) + for t in tags_list.split(","): + tags.append(t.strip()) + return tags + #return self.tags + + + def __unicode__(self): + return unicode(self.external_id) + u": " + unicode(self.title) + + def serialize(self, root_element=None): + + if root_element is not None: + iri = root_element + else : + iri = lxml.etree.Element('iri') + doc = lxml.etree.ElementTree(iri) + + + textannotation = lxml.etree.SubElement(iri, 'text-annotation') + id = lxml.etree.SubElement(textannotation, 'id') + id.text = self.external_id + uri = lxml.etree.SubElement(textannotation, 'uri') + uri.text = self.uri + + if self.tags: + tags = lxml.etree.SubElement(textannotation, 'tags') + for t in self.get_tag_list(): + tag = lxml.etree.SubElement(tags, 'tag') + tag.text = t + + content = lxml.etree.SubElement(textannotation, 'content') + color = lxml.etree.SubElement(content, 'color') + color.text = self.color + description = lxml.etree.SubElement(content, 'description') + description.text = self.description + title = lxml.etree.SubElement(content, 'title') + title.text = self.title + text = lxml.etree.SubElement(content, 'text') + text.text = self.text + + meta = lxml.etree.SubElement(textannotation, 'meta') + contributor = lxml.etree.SubElement(meta, "contributor") + contributor.text = self.contributor + creator = lxml.etree.SubElement(meta, "creator") + creator.text = self.creator + creationdate = lxml.etree.SubElement(meta, "created") + creationdate.text = str(self.creation_date) + updatedate = lxml.etree.SubElement(meta, "modified") + updatedate.text = str(self.update_date) + + if root_element is not None: + return root_element + else: + return doc + + + @staticmethod + def create_annotation(external_id, uri=None, tags=None, title=None, description=None, text=None, color=None, creator=None, contributor=None, creation_date=None, update_date=None): + annotation = Annotation(external_id=external_id, uri=uri, tags=tags, title=title, description=description, text=text, color=color, creator=creator, contributor=contributor, creation_date=creation_date, update_date=update_date) + annotation.save() + annotation.index_annot() + + return annotation + + + def delete(self): + super(Annotation, self).delete() + lucene.getVMEnv().attachCurrentThread() + writer = ldt.indexation.get_writer() + try: + writer.deleteDocuments(lucene.Term("external_id", self.external_id)) + finally: + writer.close() + + def index_annot(self): + lucene.getVMEnv().attachCurrentThread() + writer = ldt.indexation.get_writer() + try: + annotl = [self, ] + indexer = AnnotIndexer(annotl, writer) + indexer.index_all() + finally: + writer.close() + + def update_index(self): + lucene.getVMEnv().attachCurrentThread() + writer = ldt.indexation.get_writer() + try: + writer.deleteDocuments(lucene.Term("external_id", self.external_id)) + finally: + writer.close() + self.index_annot() + + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/text/urls.py --- a/src/ldt/ldt/text/urls.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/text/urls.py Mon May 16 20:00:36 2011 +0200 @@ -1,13 +1,13 @@ -from django.conf.urls.defaults import patterns, url - -# Uncomment the next two lines to enable the admin: -# from django.contrib import admin -# admin.autodiscover() - -urlpatterns = patterns('ldt.text', - url(r'^create/$', 'views.create_annotation'), - url(r'^filter/$', 'views.filter_annotation'), - url(r'^get/(?P.*)$', 'views.get_annotation'), - url(r'^delete/(?P.*)$', 'views.delete_annotation'), - url(r'^update/(?P.*)$', 'views.update_annotation'), -) +from django.conf.urls.defaults import patterns, url + +# Uncomment the next two lines to enable the admin: +# from django.contrib import admin +# admin.autodiscover() + +urlpatterns = patterns('ldt.text', + url(r'^create/$', 'views.create_annotation'), + url(r'^filter/$', 'views.filter_annotation'), + url(r'^get/(?P.*)$', 'views.get_annotation'), + url(r'^delete/(?P.*)$', 'views.delete_annotation'), + url(r'^update/(?P.*)$', 'views.update_annotation'), +) diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/text/views.py --- a/src/ldt/ldt/text/views.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/text/views.py Mon May 16 20:00:36 2011 +0200 @@ -1,199 +1,199 @@ -from django.db import IntegrityError -from django.db.models import Q -from django.http import HttpResponse, Http404 -from django.views.decorators.csrf import csrf_exempt -from ldt.text.models import Annotation -from ldt.text.utils import TextSearch, generate_uuid -from oauth_provider.decorators import oauth_required -from urllib2 import urlparse -import lxml - - -## Filters the annotation depending on the request parameters -## Returns an xml containing the resulting annotations -def filter_annotation(request, uri=None, filter=None, limit=None, creator=None): - query = Q() - - if request.GET.get('uri'): - query &= Q(uri=request.GET.get('uri')) - if request.GET.get('creator'): - query &= Q(creator=request.GET.get('creator')) - - annotlist = Annotation.objects.filter(query) - - if request.GET.get('filter') and len(request.GET.get('filter')) > 0: - search = TextSearch() - res = search.query("text", request.GET.get('filter')) - for r in res: - annotlist.append(r) - - if request.GET.get('limit'): - nb = request.GET.get('limit')[0] - offset = request.GET.get('limit')[2] - annotlist = annotlist[offset:] - annotlist = annotlist[:nb] - - #create xml - iri = lxml.etree.Element('iri') - doc = lxml.etree.ElementTree(iri) - - for annot in annotlist: - annot.serialize(iri) - - return HttpResponse(lxml.etree.tostring(doc, pretty_print=True), mimetype="text/xml;charset=utf-8") - - -## Creates an annotation from a urlencoded xml content -## Returns an xml-structured annotation -@oauth_required -@csrf_exempt -def create_annotation(request): - cont = request.POST["content"] - doc = lxml.etree.fromstring(cont) - - id_nodes = doc.xpath("/iri/text-annotation/id/text()") - if id_nodes: - id = unicode(id_nodes[0]) - else: - id = generate_uuid() - - uri = unicode(doc.xpath("/iri/text-annotation/uri/text()")[0]) - - ltags = list(set([unicode(tag.text).lower().strip() for tag in doc.xpath("/iri/text-annotation/tags/tag")])) - tags = ",".join(ltags) - if len(ltags) == 1: - tags += "," - - - title_nodes = doc.xpath("/iri/text-annotation/content/title/text()") - if title_nodes: - title = unicode(title_nodes[0]) - else: - title = None - desc_nodes = doc.xpath("/iri/text-annotation/content/description/text()") - if desc_nodes: - desc = unicode(desc_nodes[0]) - else: - desc = None - text_nodes = doc.xpath("/iri/text-annotation/content/text/text()") - if text_nodes: - text = unicode(text_nodes[0]) - else: - text = None - color_nodes = doc.xpath("/iri/text-annotation/content/color/text()") - if color_nodes: - color = unicode(color_nodes[0]) - else: - color = None - - creator_nodes = doc.xpath("/iri/text-annotation/meta/creator/text()") - if creator_nodes: - creator = unicode(creator_nodes[0]) - else: - creator = None - contributor_nodes = doc.xpath("/iri/text-annotation/meta/contributor/text()") - if contributor_nodes: - contributor = unicode(contributor_nodes[0]) - else: - contributor = None - - try: - annotation = Annotation.create_annotation(external_id=id, uri=uri, tags=tags, title=title, description=desc, text=text, color=color, creator=creator, contributor=contributor) - annotation.save() - return HttpResponse(lxml.etree.tostring(annotation.serialize(), pretty_print=True), mimetype="text/xml;charset=utf-8") - except IntegrityError: - return HttpResponse(status=409) - - - -## Gets an annotation from its id -## Returns the xml-structured annotation -def get_annotation(request, id): - try: - annot = Annotation.objects.get(external_id=id) - except Annotation.DoesNotExist: - raise Http404 - - doc = annot.serialize() - - return HttpResponse(lxml.etree.tostring(doc, pretty_print=True), mimetype="text/xml;charset=utf-8") - - -## Deletes an annotation (from its id) -## Returns an empty xml-structured annotation -@oauth_required -@csrf_exempt -def delete_annotation(request, id): - try: - annot = Annotation.objects.get(external_id=id) - annot.delete() - except Annotation.DoesNotExist: - raise Http404 - - return HttpResponse("") - - -## Updates the content of an annotation -## Returns the xml-structured updated annotation -@oauth_required -@csrf_exempt -def update_annotation(request, id): - - put_data = {} - if request.GET != {}: - put_data = request.GET.copy() - elif request.raw_post_data is not None: - for k, v in urlparse.parse_qs(request.raw_post_data).iteritems(): - if len(v) > 1: - for item in v: - put_data[k] = item - else: - put_data[k] = v[0] - - try: - annot = Annotation.objects.get(external_id=id) - except Annotation.DoesNotExist: - raise Http404 - - cont = put_data['content'] - doc = lxml.etree.fromstring(cont) - - uri = doc.xpath("/iri/text-annotation/uri/text()") - if uri != [] and annot.uri != uri[0]: - annot.uri = unicode(uri[0]) - - tags_nodes = doc.xpath("/iri/text-annotation/tags") - - if len(tags_nodes) > 0: - tags = list(set([unicode(tag.text).lower().strip() for tag in doc.xpath("/iri/text-annotation/tags/tag")])) - tags_str = ",".join(tags) - if len(tags) == 1: - tags_str += "," - annot.tags = tags_str - - title = doc.xpath("/iri/text-annotation/content/title/text()") - if title and annot.title != title[0]: - annot.title = unicode(title[0]) - desc = doc.xpath("/iri/text-annotation/content/description/text()") - if desc and annot.description != desc[0]: - annot.description = unicode(desc[0]) - text = doc.xpath("/iri/text-annotation/content/text/text()") - if text and annot.text != text[0]: - annot.text = unicode(text[0]) - color = doc.xpath("/iri/text-annotation/content/color/text()") - if color and annot.color != color[0]: - annot.color = unicode(color[0]) - - contributor = doc.xpath("/iri/text-annotation/meta/contributor/text()") - if contributor and annot.contributor != contributor[0]: - annot.contributor = unicode(contributor[0]) - update_date = doc.xpath("/iri/text-annotation/meta/modified/text()") - if update_date and annot.update_date != update_date[0]: - annot.update_date = unicode(update_date[0]) - - annot.save() - annot.update_index() - - return HttpResponse(lxml.etree.tostring(annot.serialize(), pretty_print=True), mimetype="text/xml;charset=utf-8") - - +from django.db import IntegrityError +from django.db.models import Q +from django.http import HttpResponse, Http404 +from django.views.decorators.csrf import csrf_exempt +from ldt.text.models import Annotation +from ldt.text.utils import TextSearch, generate_uuid +from oauth_provider.decorators import oauth_required +from urllib2 import urlparse +import lxml + + +## Filters the annotation depending on the request parameters +## Returns an xml containing the resulting annotations +def filter_annotation(request, uri=None, filter=None, limit=None, creator=None): + query = Q() + + if request.GET.get('uri'): + query &= Q(uri=request.GET.get('uri')) + if request.GET.get('creator'): + query &= Q(creator=request.GET.get('creator')) + + annotlist = Annotation.objects.filter(query) + + if request.GET.get('filter') and len(request.GET.get('filter')) > 0: + search = TextSearch() + res = search.query("text", request.GET.get('filter')) + for r in res: + annotlist.append(r) + + if request.GET.get('limit'): + nb = request.GET.get('limit')[0] + offset = request.GET.get('limit')[2] + annotlist = annotlist[offset:] + annotlist = annotlist[:nb] + + #create xml + iri = lxml.etree.Element('iri') + doc = lxml.etree.ElementTree(iri) + + for annot in annotlist: + annot.serialize(iri) + + return HttpResponse(lxml.etree.tostring(doc, pretty_print=True), mimetype="text/xml;charset=utf-8") + + +## Creates an annotation from a urlencoded xml content +## Returns an xml-structured annotation +@oauth_required +@csrf_exempt +def create_annotation(request): + cont = request.POST["content"] + doc = lxml.etree.fromstring(cont) + + id_nodes = doc.xpath("/iri/text-annotation/id/text()") + if id_nodes: + id = unicode(id_nodes[0]) + else: + id = generate_uuid() + + uri = unicode(doc.xpath("/iri/text-annotation/uri/text()")[0]) + + ltags = list(set([unicode(tag.text).lower().strip() for tag in doc.xpath("/iri/text-annotation/tags/tag")])) + tags = ",".join(ltags) + if len(ltags) == 1: + tags += "," + + + title_nodes = doc.xpath("/iri/text-annotation/content/title/text()") + if title_nodes: + title = unicode(title_nodes[0]) + else: + title = None + desc_nodes = doc.xpath("/iri/text-annotation/content/description/text()") + if desc_nodes: + desc = unicode(desc_nodes[0]) + else: + desc = None + text_nodes = doc.xpath("/iri/text-annotation/content/text/text()") + if text_nodes: + text = unicode(text_nodes[0]) + else: + text = None + color_nodes = doc.xpath("/iri/text-annotation/content/color/text()") + if color_nodes: + color = unicode(color_nodes[0]) + else: + color = None + + creator_nodes = doc.xpath("/iri/text-annotation/meta/creator/text()") + if creator_nodes: + creator = unicode(creator_nodes[0]) + else: + creator = None + contributor_nodes = doc.xpath("/iri/text-annotation/meta/contributor/text()") + if contributor_nodes: + contributor = unicode(contributor_nodes[0]) + else: + contributor = None + + try: + annotation = Annotation.create_annotation(external_id=id, uri=uri, tags=tags, title=title, description=desc, text=text, color=color, creator=creator, contributor=contributor) + annotation.save() + return HttpResponse(lxml.etree.tostring(annotation.serialize(), pretty_print=True), mimetype="text/xml;charset=utf-8") + except IntegrityError: + return HttpResponse(status=409) + + + +## Gets an annotation from its id +## Returns the xml-structured annotation +def get_annotation(request, id): + try: + annot = Annotation.objects.get(external_id=id) + except Annotation.DoesNotExist: + raise Http404 + + doc = annot.serialize() + + return HttpResponse(lxml.etree.tostring(doc, pretty_print=True), mimetype="text/xml;charset=utf-8") + + +## Deletes an annotation (from its id) +## Returns an empty xml-structured annotation +@oauth_required +@csrf_exempt +def delete_annotation(request, id): + try: + annot = Annotation.objects.get(external_id=id) + annot.delete() + except Annotation.DoesNotExist: + raise Http404 + + return HttpResponse("") + + +## Updates the content of an annotation +## Returns the xml-structured updated annotation +@oauth_required +@csrf_exempt +def update_annotation(request, id): + + put_data = {} + if request.GET != {}: + put_data = request.GET.copy() + elif request.raw_post_data is not None: + for k, v in urlparse.parse_qs(request.raw_post_data).iteritems(): + if len(v) > 1: + for item in v: + put_data[k] = item + else: + put_data[k] = v[0] + + try: + annot = Annotation.objects.get(external_id=id) + except Annotation.DoesNotExist: + raise Http404 + + cont = put_data['content'] + doc = lxml.etree.fromstring(cont) + + uri = doc.xpath("/iri/text-annotation/uri/text()") + if uri != [] and annot.uri != uri[0]: + annot.uri = unicode(uri[0]) + + tags_nodes = doc.xpath("/iri/text-annotation/tags") + + if len(tags_nodes) > 0: + tags = list(set([unicode(tag.text).lower().strip() for tag in doc.xpath("/iri/text-annotation/tags/tag")])) + tags_str = ",".join(tags) + if len(tags) == 1: + tags_str += "," + annot.tags = tags_str + + title = doc.xpath("/iri/text-annotation/content/title/text()") + if title and annot.title != title[0]: + annot.title = unicode(title[0]) + desc = doc.xpath("/iri/text-annotation/content/description/text()") + if desc and annot.description != desc[0]: + annot.description = unicode(desc[0]) + text = doc.xpath("/iri/text-annotation/content/text/text()") + if text and annot.text != text[0]: + annot.text = unicode(text[0]) + color = doc.xpath("/iri/text-annotation/content/color/text()") + if color and annot.color != color[0]: + annot.color = unicode(color[0]) + + contributor = doc.xpath("/iri/text-annotation/meta/contributor/text()") + if contributor and annot.contributor != contributor[0]: + annot.contributor = unicode(contributor[0]) + update_date = doc.xpath("/iri/text-annotation/meta/modified/text()") + if update_date and annot.update_date != update_date[0]: + annot.update_date = unicode(update_date[0]) + + annot.save() + annot.update_index() + + return HttpResponse(lxml.etree.tostring(annot.serialize(), pretty_print=True), mimetype="text/xml;charset=utf-8") + + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/admin.py --- a/src/ldt/ldt/user/admin.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/admin.py Mon May 16 20:00:36 2011 +0200 @@ -1,40 +1,40 @@ -from copy import deepcopy #@UnresolvedImport -from django.contrib import admin -from django.contrib.auth.admin import UserAdmin -from django.utils.translation import ugettext as _ -from forms import ldtForm, IriGroupForm -from models import ldt, IriGroup - -class ldtAdmin(UserAdmin): - list_display = ('username', 'email', 'first_name', 'last_name') - - fieldsets = [ - (None, {'fields': ('username', ('password1', 'password2'))}), - (_('User details'), {'fields': (('first_name', 'last_name'), 'email')}), - (_('Groups'), {'fields': ('groups',)}), - (_('Permissions'), {'fields': ('is_staff', 'user_permissions')}), - ] - form = ldtForm - model = ldt - filter_horizontal = ('user_permissions',) - - def get_fieldsets(self, request, obj=None): - fieldsets = deepcopy(self.fieldsets) - if not '/add' in request.path: - fieldsets[0] = (None, {'fields': ('username',)}) - fieldsets.append((_('Password'), {'fields': ('password1', 'password2'), 'classes': ('collapse',)})) - return fieldsets - - def add_view(self, request): - return super(UserAdmin, self).add_view(request) - -admin.site.unregister(ldt) -admin.site.register(ldt, ldtAdmin) - -class IriGroupAdmin(admin.ModelAdmin): - form = IriGroupForm - model = IriGroup - filter_horizontal = ('permissions',) - -admin.site.unregister(IriGroup) -admin.site.register(IriGroup, IriGroupAdmin) +from copy import deepcopy #@UnresolvedImport +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from django.utils.translation import ugettext as _ +from forms import ldtForm, IriGroupForm +from models import ldt, IriGroup + +class ldtAdmin(UserAdmin): + list_display = ('username', 'email', 'first_name', 'last_name') + + fieldsets = [ + (None, {'fields': ('username', ('password1', 'password2'))}), + (_('User details'), {'fields': (('first_name', 'last_name'), 'email')}), + (_('Groups'), {'fields': ('groups',)}), + (_('Permissions'), {'fields': ('is_staff', 'user_permissions')}), + ] + form = ldtForm + model = ldt + filter_horizontal = ('user_permissions',) + + def get_fieldsets(self, request, obj=None): + fieldsets = deepcopy(self.fieldsets) + if not '/add' in request.path: + fieldsets[0] = (None, {'fields': ('username',)}) + fieldsets.append((_('Password'), {'fields': ('password1', 'password2'), 'classes': ('collapse',)})) + return fieldsets + + def add_view(self, request): + return super(UserAdmin, self).add_view(request) + +admin.site.unregister(ldt) +admin.site.register(ldt, ldtAdmin) + +class IriGroupAdmin(admin.ModelAdmin): + form = IriGroupForm + model = IriGroup + filter_horizontal = ('permissions',) + +admin.site.unregister(IriGroup) +admin.site.register(IriGroup, IriGroupAdmin) diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/forms.py --- a/src/ldt/ldt/user/forms.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/forms.py Mon May 16 20:00:36 2011 +0200 @@ -1,98 +1,98 @@ -from django import forms -from django.contrib.auth.forms import UserCreationForm -from django.contrib.auth.models import Permission -from django.forms.util import ErrorList -from django.utils.translation import gettext as _ -from ldt.management import get_content_type_list -from models import ldt, IriGroup - - -class ldtForm(UserCreationForm): - - class Meta: - model = ldt - - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, - initial=None, error_class=ErrorList, label_suffix=':', - empty_permitted=False, instance=None): - - if instance: - initial = initial or {} - - super(ldtForm, self).__init__(data, files, auto_id, prefix, - initial, error_class, label_suffix, empty_permitted, instance) - - # filtre les permissions necessaires - content_type_list = get_content_type_list() - self.fields['user_permissions'].queryset = Permission.objects.filter(content_type__in=content_type_list) - - if instance: - self.fields['password1'].required = False - self.fields['password1'].label = _('New password') - self.fields['password2'].required = False - self.fields['password2'].label = _('New password confirmation') - - self._password_change = True - - def clean_username(self): - if self.instance: - return self.cleaned_data['username'] - return super(ldtForm, self).clean_username() - - def clean_password2(self): - if self.instance and self.cleaned_data['password1'] == '' and self.cleaned_data['password2'] == '': - self._password_change = False - return u'' - return super(ldtForm, self).clean_password2() - - - def save(self, commit=True): - Super = self._password_change and ldtForm or UserCreationForm - user = super(Super, self).save(commit=False) - # if user.pk != None: - # self.save_m2m() - - if commit: - user.save() - - return user - -class IriGroupForm(forms.ModelForm): - class meta: - model = IriGroup - - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, - initial=None, error_class=ErrorList, label_suffix=':', - empty_permitted=False, instance=None): - if instance: - initial = initial or {} - - super(IriGroupForm, self).__init__(data, files, auto_id, prefix, - initial, error_class, label_suffix, empty_permitted, instance) - - # filtre les permissions necessaires - content_type_list = get_content_type_list() - self.fields['permissions'].queryset = Permission.objects.filter(content_type__in=content_type_list) - -class EmailChangeForm(forms.Form): - email1 = forms.EmailField(label=_("E-mail"), max_length=75) - email2 = forms.EmailField(label=_("E-mail"), max_length=75) - - def __init__(self, user=None, *args, **kwargs): - self.user = user - super(EmailChangeForm, self).__init__(*args, **kwargs) - - def clean_email2(self): - email1 = self.cleaned_data.get('email1') - email2 = self.cleaned_data.get('email2') - if email1 and email2: - if email1 != email2: - raise forms.ValidationError(_("The two emails didn't match.")) - return email2 - - - def save(self): - self.user.email = self.cleaned_data['email1'] - self.user.save() - return self.user - +from django import forms +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.models import Permission +from django.forms.util import ErrorList +from django.utils.translation import gettext as _ +from ldt.management import get_content_type_list +from models import ldt, IriGroup + + +class ldtForm(UserCreationForm): + + class Meta: + model = ldt + + def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, + initial=None, error_class=ErrorList, label_suffix=':', + empty_permitted=False, instance=None): + + if instance: + initial = initial or {} + + super(ldtForm, self).__init__(data, files, auto_id, prefix, + initial, error_class, label_suffix, empty_permitted, instance) + + # filtre les permissions necessaires + content_type_list = get_content_type_list() + self.fields['user_permissions'].queryset = Permission.objects.filter(content_type__in=content_type_list) + + if instance: + self.fields['password1'].required = False + self.fields['password1'].label = _('New password') + self.fields['password2'].required = False + self.fields['password2'].label = _('New password confirmation') + + self._password_change = True + + def clean_username(self): + if self.instance: + return self.cleaned_data['username'] + return super(ldtForm, self).clean_username() + + def clean_password2(self): + if self.instance and self.cleaned_data['password1'] == '' and self.cleaned_data['password2'] == '': + self._password_change = False + return u'' + return super(ldtForm, self).clean_password2() + + + def save(self, commit=True): + Super = self._password_change and ldtForm or UserCreationForm + user = super(Super, self).save(commit=False) + # if user.pk != None: + # self.save_m2m() + + if commit: + user.save() + + return user + +class IriGroupForm(forms.ModelForm): + class meta: + model = IriGroup + + def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, + initial=None, error_class=ErrorList, label_suffix=':', + empty_permitted=False, instance=None): + if instance: + initial = initial or {} + + super(IriGroupForm, self).__init__(data, files, auto_id, prefix, + initial, error_class, label_suffix, empty_permitted, instance) + + # filtre les permissions necessaires + content_type_list = get_content_type_list() + self.fields['permissions'].queryset = Permission.objects.filter(content_type__in=content_type_list) + +class EmailChangeForm(forms.Form): + email1 = forms.EmailField(label=_("E-mail"), max_length=75) + email2 = forms.EmailField(label=_("E-mail"), max_length=75) + + def __init__(self, user=None, *args, **kwargs): + self.user = user + super(EmailChangeForm, self).__init__(*args, **kwargs) + + def clean_email2(self): + email1 = self.cleaned_data.get('email1') + email2 = self.cleaned_data.get('email2') + if email1 and email2: + if email1 != email2: + raise forms.ValidationError(_("The two emails didn't match.")) + return email2 + + + def save(self): + self.user.email = self.cleaned_data['email1'] + self.user.save() + return self.user + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/models.py --- a/src/ldt/ldt/user/models.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/models.py Mon May 16 20:00:36 2011 +0200 @@ -1,41 +1,41 @@ -from django.contrib import admin -from django.contrib.auth.models import User, Group, UserManager -from django.db import models -import datetime - - -class IriGroup(Group): - description = models.TextField(null=True, blank=True) - - def __unicode__(self): - return self.name - - -class ldt(User): - irigroups = models.ManyToManyField(IriGroup, blank=True) - - class Meta: - verbose_name = 'iri user' - verbose_name_plural = 'iri users' - - def __unicode__(self): - return self.username - - -class ldtManager(UserManager): - def create_user(self, username, email, password=None): - "Creates and saves a User with the given username, e-mail and password." - now = datetime.datetime.now() - user = ldt(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, now) - if password: - user.set_password(password) - else: - user.set_unusable_password() - user.save() - return user - -User.objects = ldtManager() -User.objects.contribute_to_class(User, "objects") - -admin.site.register(ldt) -admin.site.register(IriGroup) +from django.contrib import admin +from django.contrib.auth.models import User, Group, UserManager +from django.db import models +import datetime + + +class IriGroup(Group): + description = models.TextField(null=True, blank=True) + + def __unicode__(self): + return self.name + + +class ldt(User): + irigroups = models.ManyToManyField(IriGroup, blank=True) + + class Meta: + verbose_name = 'iri user' + verbose_name_plural = 'iri users' + + def __unicode__(self): + return self.username + + +class ldtManager(UserManager): + def create_user(self, username, email, password=None): + "Creates and saves a User with the given username, e-mail and password." + now = datetime.datetime.now() + user = ldt(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, now) + if password: + user.set_password(password) + else: + user.set_unusable_password() + user.save() + return user + +User.objects = ldtManager() +User.objects.contribute_to_class(User, "objects") + +admin.site.register(ldt) +admin.site.register(IriGroup) diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/templates/ldt/user/change_email.html --- a/src/ldt/ldt/user/templates/ldt/user/change_email.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/templates/ldt/user/change_email.html Mon May 16 20:00:36 2011 +0200 @@ -1,51 +1,51 @@ -{% extends "ldt/user/user_base.html" %} -{# form of email address's change #} -{% load i18n %} -{% block breadcrumb %} -
  • -
  • {% trans "Profiles" %}
  • -
  • {% trans "Modification de l'adresse émail" %}
  • -{% endblock %} - -{% block content_title %}{% trans "Modification de l'adresse émail" %}{% endblock %} -{% block js_declaration %}{{ block.super }} - -{% endblock %} -{% block css_import %} -{{ block.super }} - -{% endblock %} - -{% block iricontent %} -

    {% trans "Please enter your new e-mail twice so we can verify you typed it in correctly." %}

    -
    -{% csrf_token %} - - - - - - - - - - - - -
    - - - - {{form.email1.errors}}
    - - - - {{form.email1.errors}}
    -
    -{% endblock%} +{% extends "ldt/user/user_base.html" %} +{# form of email address's change #} +{% load i18n %} +{% block breadcrumb %} +
  • +
  • {% trans "Profiles" %}
  • +
  • {% trans "Modification de l'adresse émail" %}
  • +{% endblock %} + +{% block content_title %}{% trans "Modification de l'adresse émail" %}{% endblock %} +{% block js_declaration %}{{ block.super }} + +{% endblock %} +{% block css_import %} +{{ block.super }} + +{% endblock %} + +{% block iricontent %} +

    {% trans "Please enter your new e-mail twice so we can verify you typed it in correctly." %}

    +
    +{% csrf_token %} + + + + + + + + + + + + +
    + + + + {{form.email1.errors}}
    + + + + {{form.email1.errors}}
    +
    +{% endblock%} diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/templates/ldt/user/change_email_done.html --- a/src/ldt/ldt/user/templates/ldt/user/change_email_done.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/templates/ldt/user/change_email_done.html Mon May 16 20:00:36 2011 +0200 @@ -1,14 +1,14 @@ -{% extends "ldt/user/user_base.html" %} -{# if email is changed successfully, retrun this page #} -{% load i18n %} -{% block breadcrumb %} -
  • -
  • {% trans "Profiles" %}
  • -
  • {% trans "email change" %}
  • -{% endblock %} - -{% block content_title %}{% trans "email change" %}{% endblock %} -{% block iricontent %} -

    {% trans "email changed" %}

    -{% trans "back to profile" %} -{% endblock %} +{% extends "ldt/user/user_base.html" %} +{# if email is changed successfully, retrun this page #} +{% load i18n %} +{% block breadcrumb %} +
  • +
  • {% trans "Profiles" %}
  • +
  • {% trans "email change" %}
  • +{% endblock %} + +{% block content_title %}{% trans "email change" %}{% endblock %} +{% block iricontent %} +

    {% trans "email changed" %}

    +{% trans "back to profile" %} +{% endblock %} diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/templates/ldt/user/home.html --- a/src/ldt/ldt/user/templates/ldt/user/home.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/templates/ldt/user/home.html Mon May 16 20:00:36 2011 +0200 @@ -1,14 +1,14 @@ -{% extends "ldt/ldt_base.html" %} -{% load i18n %} - -{% block title %}Home{% endblock %} - -{% block content_base %} - -

    Welcome

    -
  • {% trans "Se connecter" %}
  • -
  • {% trans "Créer un compte" %}
  • -
  • {% trans "récupérer mot de passe" %}
  • - -{% endblock %} - +{% extends "ldt/ldt_base.html" %} +{% load i18n %} + +{% block title %}Home{% endblock %} + +{% block content_base %} + +

    Welcome

    +
  • {% trans "Se connecter" %}
  • +
  • {% trans "Créer un compte" %}
  • +
  • {% trans "récupérer mot de passe" %}
  • + +{% endblock %} + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/templates/ldt/user/login_form.html --- a/src/ldt/ldt/user/templates/ldt/user/login_form.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/templates/ldt/user/login_form.html Mon May 16 20:00:36 2011 +0200 @@ -1,75 +1,75 @@ -{% load i18n %} -{# print user's state and form of login #} -{% block js_import %} -{{block.super}} - - -{% endblock %} -{% block css_import %} -{{block.super}} -{% endblock %} -
    -
    +{% load i18n %} +{# print user's state and form of login #} +{% block js_import %} +{{block.super}} + + +{% endblock %} +{% block css_import %} +{{block.super}} +{% endblock %} +
    +
    diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/templates/ldt/user/space.html --- a/src/ldt/ldt/user/templates/ldt/user/space.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/templates/ldt/user/space.html Mon May 16 20:00:36 2011 +0200 @@ -1,19 +1,19 @@ -{% extends "ldt/user/user_base.html" %} -{# user's space (edit page or project lignes de temps) #} -{% load i18n %} -{% block breadcrumb %} -
  • -
  • {% trans "Space" %}
  • -{% endblock %} - -{% block content_title %}{% trans "Space" %}{% endblock %} -{% block iricontent%} - -{% endblock %} +{% extends "ldt/user/user_base.html" %} +{# user's space (edit page or project lignes de temps) #} +{% load i18n %} +{% block breadcrumb %} +
  • +
  • {% trans "Space" %}
  • +{% endblock %} + +{% block content_title %}{% trans "Space" %}{% endblock %} +{% block iricontent%} + +{% endblock %} diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/templates/registration/activation_complete.html --- a/src/ldt/ldt/user/templates/registration/activation_complete.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/templates/registration/activation_complete.html Mon May 16 20:00:36 2011 +0200 @@ -1,8 +1,8 @@ -{% extends "registration/base.html" %} -{% load i18n %} - -{% block content_title %}{% trans 'Sign up successfully' %}{% endblock %} -{% block iricontent %} -

    {% trans "activation completed" %}

    - -{% endblock%} +{% extends "registration/base.html" %} +{% load i18n %} + +{% block content_title %}{% trans 'Sign up successfully' %}{% endblock %} +{% block iricontent %} +

    {% trans "activation completed" %}

    + +{% endblock%} diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/templates/registration/registration_complete.html --- a/src/ldt/ldt/user/templates/registration/registration_complete.html Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/templates/registration/registration_complete.html Mon May 16 20:00:36 2011 +0200 @@ -1,12 +1,12 @@ -{% extends "registration/base.html" %} -{% load i18n %} - -{% block breadcrumb %} -
  • -
  • {% trans 'Sign up' %}
  • -{% endblock %} -{% block content_title %}{% trans 'Sign up successfully' %}{% endblock %} -{% block iricontent %} -

    {% trans "We've e-mailed you instructions for activate your account to the e-mail address you submitted. You should be receiving it shortly." %}

    - +{% extends "registration/base.html" %} +{% load i18n %} + +{% block breadcrumb %} +
  • +
  • {% trans 'Sign up' %}
  • +{% endblock %} +{% block content_title %}{% trans 'Sign up successfully' %}{% endblock %} +{% block iricontent %} +

    {% trans "We've e-mailed you instructions for activate your account to the e-mail address you submitted. You should be receiving it shortly." %}

    + {% endblock%} \ No newline at end of file diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/templatetags/logintag.py --- a/src/ldt/ldt/user/templatetags/logintag.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/templatetags/logintag.py Mon May 16 20:00:36 2011 +0200 @@ -1,8 +1,8 @@ -from django import template - -register = template.Library() - -def loginAjax(user, reload=None): - return {'user': user, 'reload': reload} - -register.inclusion_tag('ldt/user/login_form.html')(loginAjax) +from django import template + +register = template.Library() + +def loginAjax(user, reload=None): + return {'user': user, 'reload': reload} + +register.inclusion_tag('ldt/user/login_form.html')(loginAjax) diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/tests.py --- a/src/ldt/ldt/user/tests.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/tests.py Mon May 16 20:00:36 2011 +0200 @@ -1,23 +1,23 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" - -from django.test import TestCase - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.failUnlessEqual(1 + 1, 2) - -__test__ = {"doctest": """ -Another way to test that 1 + 1 is equal to 2. - ->>> 1 + 1 == 2 -True -"""} - +""" +This file demonstrates two different styles of tests (one doctest and one +unittest). These will both pass when you run "manage.py test". + +Replace these with more appropriate tests for your application. +""" + +from django.test import TestCase + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.failUnlessEqual(1 + 1, 2) + +__test__ = {"doctest": """ +Another way to test that 1 + 1 is equal to 2. + +>>> 1 + 1 == 2 +True +"""} + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/urls.py --- a/src/ldt/ldt/user/urls.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/urls.py Mon May 16 20:00:36 2011 +0200 @@ -1,19 +1,19 @@ -from django.conf.urls.defaults import patterns, url - -urlpatterns = patterns('', - url(r'^loginAjax/$', 'ldt.user.views.loginAjax'), - url(r'^profile/', 'ldt.user.views.profile'), - url(r'^logout/', 'ldt.user.views.logout_view'), - url(r'^space/$', 'ldt.user.views.space'), - url(r'^emailchange/$', 'ldt.user.views.change_email'), - url(r'^emailchange/done/$', 'ldt.user.views.change_email_done'), -# url(r'^space/ldt/$', 'ldt.ldt_utils.views.list_ldt'), -# url(r'^space/ldt/indexproject/(?P.*)$', 'ldt.ldt_utils.views.indexProject'), -# url(r'^space/ldt/init/(?P.*)/(?P.*)$', 'ldt.ldt_utils.views.init'), -# url(r'^space/ldt/project/(?P.*)$', 'ldt.ldt_utils.views.ldtProject'), -# url(r'^space/ldt/create/$', 'ldt.ldt_utils.views.create_ldt_view'), -# url(r'^space/ldt/created_done/$', 'ldt.ldt_utils.views.created_ldt'), -# url(r'^space/ldt/save/$', 'ldt.ldt_utils.views.save_ldtProject'), -# url(r'^space/ldt/publish/(?P.*)$', 'ldt.ldt_utils.views.publish'), -# url(r'^space/ldt/unpublish/(?P.*)$', 'ldt.ldt_utils.views.unpublish'), -) +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('', + url(r'^loginAjax/$', 'ldt.user.views.loginAjax'), + url(r'^profile/', 'ldt.user.views.profile'), + url(r'^logout/', 'ldt.user.views.logout_view'), + url(r'^space/$', 'ldt.user.views.space'), + url(r'^emailchange/$', 'ldt.user.views.change_email'), + url(r'^emailchange/done/$', 'ldt.user.views.change_email_done'), +# url(r'^space/ldt/$', 'ldt.ldt_utils.views.list_ldt'), +# url(r'^space/ldt/indexproject/(?P.*)$', 'ldt.ldt_utils.views.indexProject'), +# url(r'^space/ldt/init/(?P.*)/(?P.*)$', 'ldt.ldt_utils.views.init'), +# url(r'^space/ldt/project/(?P.*)$', 'ldt.ldt_utils.views.ldtProject'), +# url(r'^space/ldt/create/$', 'ldt.ldt_utils.views.create_ldt_view'), +# url(r'^space/ldt/created_done/$', 'ldt.ldt_utils.views.created_ldt'), +# url(r'^space/ldt/save/$', 'ldt.ldt_utils.views.save_ldtProject'), +# url(r'^space/ldt/publish/(?P.*)$', 'ldt.ldt_utils.views.publish'), +# url(r'^space/ldt/unpublish/(?P.*)$', 'ldt.ldt_utils.views.unpublish'), +) diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/user/views.py --- a/src/ldt/ldt/user/views.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/user/views.py Mon May 16 20:00:36 2011 +0200 @@ -1,74 +1,74 @@ -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth.decorators import login_required -from django.core.urlresolvers import reverse -from django.http import HttpResponse, HttpResponseRedirect -from django.shortcuts import render_to_response -from django.template import RequestContext, loader -from django.utils import simplejson -from django.utils.translation import ugettext as _ -from forms import EmailChangeForm -from ldt.management import test_cms, test_ldt -# from django.contrib.sites.models import Site, RequestSite - - -def home(request): - return render_to_response('ldt/user/home.html', context_instance=RequestContext(request)) - -@login_required -def profile(request): - return render_to_response('ldt/user/profile.html', context_instance=RequestContext(request)) - -@login_required -def space(request, page_id=None, slug=None): - cms = test_cms() - ldt = test_ldt() - context = { - 'cms': cms, - 'ldt': ldt - } - return render_to_response('ldt/user/space.html', context, context_instance=RequestContext(request)) - - - -def logout_view(request): - logout(request) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) - #return HttpResponseRedirect(settings.LOGOUT_URL) - - -def loginAjax(request, loginstate_template_name='ldt/user/login_form.html'): - if request.method == "POST": - username = request.POST["username"] - password = request.POST["password"] - user = authenticate(username=username, password=password) - error_message = _(u"Sorry, that's not a valid username or password.") - if user is not None: - if user.is_active: - login(request, user) - context = RequestContext(request, { 'username': user.username, }) - template = loader.get_template(loginstate_template_name) - html = template.render(context) - return HttpResponse(simplejson.dumps({'message': u'successful', 'username': user.username, 'html': html, 'reload': request.POST["reload"], })) - else: - return HttpResponse(simplejson.dumps({'message': error_message, })) - else: - return HttpResponse(simplejson.dumps({'message': error_message, })) - return render_to_response('ldt/user/login_ajax.html', context_instance=RequestContext(request)) - -@login_required -def change_email(request, post_change_redirect=None): - if post_change_redirect is None: - post_change_redirect = reverse('ldt.user.views.change_email_done') - if request.method == "POST": - form = EmailChangeForm(request.user, request.POST) - if form.is_valid(): - form.save() - return HttpResponseRedirect(post_change_redirect) - else: - form = EmailChangeForm(request.user) - return render_to_response('ldt/user/change_email.html', {'form': form, }, context_instance=RequestContext(request)) - -@login_required -def change_email_done(request, template_name='ldt/user/change_email_done.html'): - return render_to_response(template_name, context_instance=RequestContext(request)) - +from django.contrib.auth import authenticate, login, logout +from django.contrib.auth.decorators import login_required +from django.core.urlresolvers import reverse +from django.http import HttpResponse, HttpResponseRedirect +from django.shortcuts import render_to_response +from django.template import RequestContext, loader +from django.utils import simplejson +from django.utils.translation import ugettext as _ +from forms import EmailChangeForm +from ldt.management import test_cms, test_ldt +# from django.contrib.sites.models import Site, RequestSite + + +def home(request): + return render_to_response('ldt/user/home.html', context_instance=RequestContext(request)) + +@login_required +def profile(request): + return render_to_response('ldt/user/profile.html', context_instance=RequestContext(request)) + +@login_required +def space(request, page_id=None, slug=None): + cms = test_cms() + ldt = test_ldt() + context = { + 'cms': cms, + 'ldt': ldt + } + return render_to_response('ldt/user/space.html', context, context_instance=RequestContext(request)) + + + +def logout_view(request): + logout(request) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + #return HttpResponseRedirect(settings.LOGOUT_URL) + + +def loginAjax(request, loginstate_template_name='ldt/user/login_form.html'): + if request.method == "POST": + username = request.POST["username"] + password = request.POST["password"] + user = authenticate(username=username, password=password) + error_message = _(u"Sorry, that's not a valid username or password.") + if user is not None: + if user.is_active: + login(request, user) + context = RequestContext(request, { 'username': user.username, }) + template = loader.get_template(loginstate_template_name) + html = template.render(context) + return HttpResponse(simplejson.dumps({'message': u'successful', 'username': user.username, 'html': html, 'reload': request.POST["reload"], })) + else: + return HttpResponse(simplejson.dumps({'message': error_message, })) + else: + return HttpResponse(simplejson.dumps({'message': error_message, })) + return render_to_response('ldt/user/login_ajax.html', context_instance=RequestContext(request)) + +@login_required +def change_email(request, post_change_redirect=None): + if post_change_redirect is None: + post_change_redirect = reverse('ldt.user.views.change_email_done') + if request.method == "POST": + form = EmailChangeForm(request.user, request.POST) + if form.is_valid(): + form.save() + return HttpResponseRedirect(post_change_redirect) + else: + form = EmailChangeForm(request.user) + return render_to_response('ldt/user/change_email.html', {'form': form, }, context_instance=RequestContext(request)) + +@login_required +def change_email_done(request, template_name='ldt/user/change_email_done.html'): + return render_to_response(template_name, context_instance=RequestContext(request)) + diff -r 06b1221142ac -r 4535dafa6007 src/ldt/ldt/utils/__init__.py --- a/src/ldt/ldt/utils/__init__.py Mon May 16 17:43:34 2011 +0200 +++ b/src/ldt/ldt/utils/__init__.py Mon May 16 20:00:36 2011 +0200 @@ -1,4 +1,4 @@ - -def Property(func): - return property(**func()) - + +def Property(func): + return property(**func()) +