Merge with c28d4dc49a50141899cfd5adfbefe7ab69f4e565
authorverrierj
Fri, 06 Jan 2012 10:09:16 +0100
changeset 335 07448cec6e8a
parent 334 b4b11979cd4a (current diff)
parent 332 c28d4dc49a50 (diff)
child 336 24eea54ed5f9
Merge with c28d4dc49a50141899cfd5adfbefe7ab69f4e565
--- a/src/ldt/ldt/api/ldt/handlers.py	Thu Jan 05 17:33:44 2012 +0100
+++ b/src/ldt/ldt/api/ldt/handlers.py	Fri Jan 06 10:09:16 2012 +0100
@@ -19,7 +19,7 @@
     @require_extended
     def update(self, request, project_id):
         """
-        This method is called when a PUT request is sent to http://<plateform_location>/api/ldt/projects/<project_id>.format. 
+        This method is called when a PUT request is sent to http://<plateform_location>/api/ldt/projects/<project_id>.<format>. 
             <project_id> is the ldt_id field of the project. If <projet_id> does not match any project on the platform, a 410 ("Gone")
             error will be returned.
             <format> is the format of the data sent back by the server. It can be 'json', 'yaml', 'xml' or 'pickle'.
@@ -45,10 +45,76 @@
         A platform is reachable at http://localhost/. It contains a project with ID a0593b58-f258-11df-80e1-00145ea4a2be. This project has
         a content milosforman_amadeus, which has a cutting Salieri inside the view "View at the last recording". The following JSON file exists in the current directory :
     
+        Example of ajax call with 2 differents annotations :
+        $('#mon_ajax').click(function(e) {
+            var url = "{% url project_api project_id='c8448f21-272d-11e1-876b-c8bcc896c290.' emitter_format='json' %}";
+            
+            var monjson = '{\
+                    "annotations": [\
+                        {\
+                            "type": "c_07BA1284-5F24-71A8-1EE2-423EED999B8A",\
+                            "type_title": "New cutting name if necessary",\
+                            "media": "briandepalma_scarfacedepalma",\
+                            "begin": 1600000,\
+                            "end": 2100000,\
+                            "content": {\
+                                "data": "new scar annot"\
+                            },\
+                            "tags": [ "json","dude" ]\
+                        }\
+                    ],\
+                    "meta": {\
+                        "creator": "John Doe",\
+                        "created": "2011-09-10T09:12:58"\
+                    }\
+                }';
+            var monjson2 = '{\
+                    "annotations": [\
+                        {\
+                            "type": "c_07BA1284-5F24-71A8-1EE2-423EED999B8A",\
+                            "type_title": "New cutting name if necessary",\
+                            "media": "briandepalma_scarfacedepalma",\
+                            "begin": 2400000,\
+                            "end": 3000000,\
+                            "content": {\
+                                "data": "ntm iam 2"\
+                            },\
+                            "tags": [ "jak" ]\
+                        }\
+                    ],\
+                    "meta": {\
+                        "creator": "John Doe",\
+                        "created": "2011-09-10T09:12:58"\
+                    }\
+                }';
+            
+            $.ajax({
+                url: url,
+                type: 'PUT',
+                contentType: 'application/json',
+                data: monjson,
+                // bug with jquery >= 1.5, "json" adds a callback so we don't specify dataType
+                //dataType: 'json',
+                success: function(json, textStatus, XMLHttpRequest) {
+                    alert("success = " + json);
+                },
+                error: function(jqXHR, textStatus, errorThrown) {
+                    alert("ERROR = " + jqXHR.responseText + ", " + errorThrown);
+                }
+            });
+        });
+        
+        If we send a PUT request with curl :    
+        $curl -X PUT http://localhost/api/ldt/projects/a0593b58-f258-11df-80e1-00145ea4a2be.json -d @example.JSON -H  "content-type:application/json"
+        A new cutting titled "New cutting name" will be created with the first annotation inside, and the annotation "Annotation about Salieri"
+        will be added to the Salieri cutting. The returned file is :
+        
         {
             "annotations": [
                 {
-                    "type": "New cutting name",
+                    "id": "6d8baf01-ffb1-11e0-810c-001485352c9a",
+                    "type": "id_annot_type",
+                    "type_title": "New cutting name",
                     "media": "milosforman_amadeus",
                     "begin": 50000,
                     "end": 900000,
@@ -58,44 +124,9 @@
                     "tags": [ "json" ]
                 },
                 {
-                    "type": "Salieri",
-                    "media": "milosforman_amadeus",
-                    "begin": 700000,
-                    "end": 1200000,
-                    "content": {
-                        "data": "Annotation about Salieri"
-                    },
-                    "tags": [ "xml", "test", "blop" ]
-                }
-            ],
-            
-            "meta": {
-                "creator": "John Doe",
-                "created": "2011-09-10T09:12:58"
-            }
-        }
-            
-        If we send a PUT request with curl :    
-        $curl -X PUT http://localhost/api/ldt/projects/a0593b58-f258-11df-80e1-00145ea4a2be.json -d @example.JSON -H  "content-type:application/json"
-        A new cutting titled "New cutting name" will be created with the first annotation inside, and the annotation "Annotation about Salieri"
-        will be added to the Salieri cutting. The returned file is :
-        
-        {
-            "annotations": [
-                {
-                    "id": "6d8baf01-ffb1-11e0-810c-001485352c9a",
-                    "type": "New cutting name",
-                    "media": "milosforman_amadeus",
-                    "begin": 50000,
-                    "end": 900000,
-                    "content": {
-                        "data": "new annotation"
-                    },
-                    "tags": [ "json" ]
-                },
-                {
-                    "id": "6d8baf00-ffb1-11e0-8097-001485352c9a",
-                    "type": "Salieri",
+                    "id": "6d8baf00-ffb1-11e0-8097-001485352c9b",
+                    "type": "another_id_annot_type",
+                    "type_title": "Salieri",
                     "media": "milosforman_amadeus",
                     "begin": 700000,
                     "end": 1200000,
@@ -112,16 +143,17 @@
             }
         }
         
-        """    
-        
-        if request.content_type == 'application/json':
+        """
+        #return rc.ALL_OK
+        #assert False, " TIBO str(request.data) = " + str(request.data)
+        if request.content_type.lower().find("application/json") > -1 :
             try:
                 project = Project.objects.get(ldt_id=project_id)
             except Project.DoesNotExist:
-                return rc.NOT_HERE 
+                return rc.NOT_HERE
         
             adder = LdtAnnotation(project)
-            logging.debug("request json " + repr(request.data))       
+            logging.debug("request json " + repr(request.data))
 
             meta = request.data['meta']
             author = meta['creator']
@@ -131,9 +163,10 @@
             for a in new_annotations:
                 dur = str(a['end'] - a['begin'])
                 begin = str(a['begin'])
-                new_id = adder.add(a['media'], a['type'], a['content']['data'], '', a['tags'], begin, dur, author, date)
+                new_id = adder.add(a['media'], a['type'], a['type_title'], a['content']['data'], '', a['tags'], begin, dur, author, date)
                 if not new_id:
                     return rc.BAD_REQUEST
+                adder.save()
                 a['id'] = new_id
             
             return request.data
@@ -141,12 +174,12 @@
         else:
             logging.debug("request " + repr(request))
             data = request.data
-            ldt_str = data["ldt"] 
+            ldt_str = data["ldt"]
             
             logging.debug("request data" + repr(ldt_str))
             
             if not ldt_str:
-                return rc.ALL_OK
+                return rc.BAD_REQUEST
             
             project = Project.objects.get(ldt_id=project_id)
             
--- a/src/ldt/ldt/api/ldt/urls.py	Thu Jan 05 17:33:44 2012 +0100
+++ b/src/ldt/ldt/api/ldt/urls.py	Fri Jan 06 10:09:16 2012 +0100
@@ -5,5 +5,5 @@
 project_handler = Resource(ProjectHandler, None)
 
 urlpatterns = patterns('',
-    url(r'projects/(?P<project_id>[^/.]+)\.?(?P<emitter_format>.*)$', project_handler),
+    url(r'projects/(?P<project_id>[^/.]+)\.?(?P<emitter_format>.*)$', project_handler, name='project_api'),
 )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/api/middleware/pistonput.py	Fri Jan 06 10:09:16 2012 +0100
@@ -0,0 +1,18 @@
+"""
+This middleware changes the request header content type because 
+piston does not like 'charset=UTF-8" in PUT request
+"""
+
+from django.conf import settings
+
+class PistonPutMiddleware(object):
+
+    def process_request(self, request):
+        if request.method in ('PUT') and not 'boundary=' in request.META['CONTENT_TYPE']:
+            request.META['CONTENT_TYPE'] = [c.strip() for c in request.META['CONTENT_TYPE'].split(";") ][0]
+        return None
+#        if request.method == 'PUT' and request.META.has_key('CONTENT_TYPE') :
+#            if request.META['CONTENT_TYPE'] == 'application/x-www-form-urlencoded; charset=UTF-8':
+#                request.META['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
+#            if request.META['CONTENT_TYPE'] == 'application/json; charset=UTF-8':
+#                request.META['CONTENT_TYPE'] = 'application/json'
\ No newline at end of file
--- a/src/ldt/ldt/ldt_utils/utils.py	Thu Jan 05 17:33:44 2012 +0100
+++ b/src/ldt/ldt/ldt_utils/utils.py	Fri Jan 06 10:09:16 2012 +0100
@@ -152,6 +152,7 @@
         elementfile = lxml.etree.SubElement(elementInit, 'file')
             
         elementfile.set('src', settings.WEB_URL + django.core.urlresolvers.reverse(method, args=url))
+        elementfile.set('src', django.core.urlresolvers.reverse(method, args=url))
         if(search):
             elementfile.set("segsel", settings.WEB_URL + django.core.urlresolvers.reverse(search, args=url))
 
@@ -168,78 +169,89 @@
         self.parser = lxml.etree.XMLParser(remove_blank_text=True)
         self.ldtdoc = lxml.etree.parse(StringIO(project.ldt.encode("utf-8")), self.parser)
         self.to_add = True
-    
-    def add(self, media, cutting, title, text, tags_list, begin, dur, author, date, view="View at the last recording", color="16776960"):
+    #   add( a['media'], a['type'],  a['type_title, a[data], '', a['tags'], begin, dur, author, date)
+    def add(self, media, cutting_id, cutting_title, title, text, tags_list, begin, dur, author, date, view_id=None, color="16776960"):
         """
         Add an annotation to a project. begin and dur must be strings. Default color is yellow.
         """
                 
+        # We check if the project references the media.
         path_media = self.ldtdoc.xpath('/iri/medias/media[@id="%s"]' % media)
-
         if len(path_media) == 0:
             self.to_add = False
             return False
-                                
+        
+        # We get the content node
         path_annotations = self.ldtdoc.xpath('/iri/annotations')[0]
         path_content = path_annotations.xpath('content[@id="%s"]' % media)
-                
+        # If the content node does not exist, we create it
         if len(path_content) == 0:
             path_content = lxml.etree.SubElement(path_annotations, 'content')
             path_content.set('id', media)
             path_content = [path_content]
-                
-        path_ensemble = path_content[0].xpath('ensemble[decoupage[title="%s"]]' % cutting)
+        
+        # We generate the cutting id if necessary
+        if cutting_id is None or cutting_id=="" :
+            cutting_id = 'c_' + generate_uuid()
+        
+        # We get the ensemble node
+        path_ensemble = path_content[0].xpath('ensemble[decoupage[@id="%s"]]' % cutting_id)
         if len(path_ensemble) == 0:
-            path_ensemble = path_content[0].xpath('ensemble')
-                
-        if len(path_ensemble) == 0:
+            # If the ensemble node does not exist, we create it
             path_ensemble = lxml.etree.SubElement(path_content[0], 'ensemble')
             path_ensemble.set('id', 'g_' + generate_uuid())
             path_ensemble.set('title', _('Personal cutting'))
             path_ensemble.set('author', 'undefined')
-            path_ensemble = [path_ensemble]                
- 
+            path_ensemble = [path_ensemble]
+        #else:
+        #    path_ensemble = path_content[0].xpath('ensemble')
+        
+            
+        # We get the elements node in the good decoupage node
         ensemble_id = path_ensemble[0].get('id')
-        decoupage_elements = path_ensemble[0].xpath('decoupage[title="%s"]/elements' % cutting)
+        decoupage_elements = path_ensemble[0].xpath('decoupage[@id="%s"]/elements' % cutting_id)
         if len(decoupage_elements) == 0:
+            # If the decoupage node does not exist, we create it and its elements node 
             decoupage = lxml.etree.SubElement(path_ensemble[0], 'decoupage')
-            cutting_id = 'c_' + generate_uuid()
+            #cutting_id = "c_" + generate_uuid()
             decoupage.set('id', cutting_id)
             decoupage.set('author', author)
             decoupage_title = lxml.etree.SubElement(decoupage, 'title')
-            decoupage_title.text = cutting
+            decoupage_title.text = cutting_title
             lxml.etree.SubElement(decoupage, 'abstract')
             decoupage_elements = lxml.etree.SubElement(decoupage, 'elements')
             decoupage_elements = [decoupage_elements]
-        else:
-            cutting_id = path_ensemble[0].xpath('decoupage[title="%s"]' % cutting)[0].get('id')     
-        
-        path_view = self.ldtdoc.xpath('/iri/displays/display[@title="%s"]' % view)
-        if len(path_view) == 0:
-            path_view = self.ldtdoc.xpath('/iri/displays/display[@title="Init view"]')
+        #else:
+        #    cutting_id = path_ensemble[0].xpath('decoupage[title="%s"]' % cutting_title)[0].get('id')     
         
-        if len(path_view) != 0:        
-            content_display = path_view[0].xpath('content[@id="%s"]' % media)
-            if len(content_display) == 0:
-                content_display = lxml.etree.SubElement(path_view[0], 'content')
-                content_display.set('id', media)
-                content_display = [content_display]
-            
-            dec = lxml.etree.SubElement(content_display[0], 'decoupage')
-            dec.set('idens', ensemble_id)
-            dec.set('id', cutting_id)
-            dec.set('tagsSelect', '')                           
-                
+        # We add the cutting to the view
+        if view_id is not None and view_id!="" :
+            path_view = self.ldtdoc.xpath('/iri/displays/display[@id="%s"]' % view_id)
+            if len(path_view) == 0:
+                path_view = self.ldtdoc.xpath('/iri/displays/display[@title="Init view"]')
+            else :
+                content_display = path_view[0].xpath('content[@id="%s"]' % media)
+                if len(content_display) == 0:
+                    content_display = lxml.etree.SubElement(path_view[0], 'content')
+                    content_display.set('id', media)
+                    content_display = [content_display]
+                # We add the decoupage node to the content node
+                dec = lxml.etree.SubElement(content_display[0], 'decoupage')
+                dec.set('idens', ensemble_id)
+                dec.set('id', cutting_id)
+                dec.set('tagsSelect', '')
+        
+        # We add the annotation/element node
         element = lxml.etree.SubElement(decoupage_elements[0], 'element')
-        id_annotation = generate_uuid()
-        element.set('id', 's_' + id_annotation)
+        id_annotation = 's_' + generate_uuid()
+        element.set('id', id_annotation)
         element.set('begin', begin)
         element.set('dur', dur)
         element.set('author', author)
         element.set('date', date)
         element.set('color', color)
         abstract = lxml.etree.SubElement(element, 'abstract')
-        abstract.text = text 
+        abstract.text = text
         title_node = lxml.etree.SubElement(element, 'title')
         title_node.text = title
         audio = lxml.etree.SubElement(element, 'audio')
@@ -249,12 +261,13 @@
         for tag in tags_list:
             tag_node = lxml.etree.SubElement(tags, 'tag')
             tag_node.text = tag
-            
+        
         return id_annotation
     
     def save(self):
         if self.to_add:
             self.project.ldt = lxml.etree.tostring(self.ldtdoc, pretty_print=True)
+            #assert False, " TIBO SAVE " + self.project.ldt
             self.project.save()
     
     def __del__(self):
--- a/src/ldt/ldt/ldt_utils/views/workspace.py	Thu Jan 05 17:33:44 2012 +0100
+++ b/src/ldt/ldt/ldt_utils/views/workspace.py	Fri Jan 06 10:09:16 2012 +0100
@@ -2,7 +2,7 @@
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.models import Group
 from django.core.cache import cache
-from django.core.urlresolvers import reverse
+from django.core.urlresolvers import reverse#, resolve
 from django.core.paginator import Paginator, InvalidPage, EmptyPage
 from django.http import (HttpResponseRedirect, HttpResponseForbidden )
 from ldt.indexation import get_results_with_context, highlight_documents
@@ -36,10 +36,19 @@
 
     is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
     
+    # Resolve a URL
+    #project_api_view, project_api_args, project_api_kwargs = resolve('/api/ldt/projects/c8448f21-272d-11e1-876b-c8bcc896c290.json')
+    #match = resolve('/api/ldt/projects/c8448f21-272d-11e1-876b-c8bcc896c290.json')
+    
+    # Print the URL pattern that matches the URL
+    #print match.url_name
+    
     # render list
     return render_to_response("ldt/ldt_utils/workspace.html",
                               {'contents': content_list, 'projects': project_list,
-                               'is_gecko': is_gecko},
+                               'is_gecko': is_gecko, #'project_api_url':"match.url_name",
+                               #'project_api_view':match.url_name,'project_api_args':"project_api_args",'project_api_kwargs':"project_api_kwargs"
+                               },
                               context_instance=RequestContext(request))
 
 @login_required
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ldt/ldt/ldt_utils/views_old.py	Fri Jan 06 10:09:16 2012 +0100
@@ -0,0 +1,1383 @@
+from django.conf import settings
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import User, Group
+from django.core.cache import cache
+from django.core.urlresolvers import reverse
+from django.core.paginator import Paginator, InvalidPage, EmptyPage
+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 ldt.indexation import get_results_with_context, highlight_documents
+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, GroupAddForm)
+from guardian.shortcuts import remove_perm, get_objects_for_group, get_objects_for_user
+from ldt.ldt_utils.models import Content
+from ldt.ldt_utils.utils import boolean_convert, LdtUtils, LdtSearch
+from ldt.security.utils import (assign_perm_to_obj, set_forbidden_stream, 
+    add_change_attr, get_userlist, get_userlist_model, get_userlist_group)
+from ldt.security.cache import get_cached_checker, cached_assign
+from lxml.html import fragment_fromstring
+from models import Media, Project
+from projectserializer import ProjectSerializer
+from urllib2 import urlparse
+from operator import itemgetter
+from itertools import groupby
+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
+import subprocess
+import re
+import datetime
+
+
+@login_required
+def workspace(request):
+    
+    # list of contents
+    content_list = add_change_attr(request.user, Content.safe_objects.all()) #@UndefinedVariable
+    
+    # get list of projects owned by the current user
+    project_list = add_change_attr(request.user, Project.safe_objects.filter(owner=request.user)) #@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))
+
+@login_required
+def groups(request): 
+
+    # get list of all published projects
+    group_list = request.user.groups.exclude(name=settings.PUBLIC_GROUP_NAME)
+    
+    group_list = sorted(group_list.all(), key=lambda group: group.name.lower())    
+    group_list = add_change_attr(request.user, group_list)
+
+    can_add_group = True if request.user.user_permissions.filter(codename='add_group') else False
+    is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
+    # render list
+    return render_to_response("ldt/ldt_utils/groups.html",
+                              {'groups': group_list,
+                               'is_gecko': is_gecko,
+                               'can_add_group': can_add_group},
+                              context_instance=RequestContext(request))
+
+
+@login_required
+def published_project(request): 
+
+    # get list of all published projects
+    project_list = Project.safe_objects.filter(state=2) #@UndefinedVariable
+    # Search form
+    form = SearchForm()
+
+    is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
+    
+    # render list
+    return render_to_response("ldt/ldt_utils/published_projects.html",
+                              {'projects': project_list, 'form': form,
+                               '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.safe_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.check_access(request.user, project):
+        return HttpResponseForbidden(_("You can not access this project"))
+
+    ps = ProjectSerializer(project, from_contents=False, from_display=True)
+    annotations = ps.get_annotations(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 projects_filter(request, filter, is_owner=False, status=0, id_group=0):
+    is_owner = boolean_convert(is_owner)
+    status = int(status)
+    id_group = int(id_group)
+    query = Q()
+
+    if is_owner:
+        owner = None
+        try:
+            owner = request.user
+        except:
+            return HttpResponseServerError("<h1>User not found</h1>")
+        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)
+    
+    is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
+    show_username = True
+    
+    if id_group > 0:    # Search inside a group
+        grp = Group.objects.get(id=id_group)
+        project_list = get_objects_for_group(grp, 'ldt_utils.view_project').filter(query)
+    elif id_group == -1:# Search inside projects shared with a specific user
+        project_list = get_objects_for_user(request.user, 'ldt_utils.view_project', use_groups=False).exclude(owner=request.user)
+    else:
+        project_list = Project.safe_objects.filter(query)
+        show_username = False
+
+    project_list = add_change_attr(request.user, project_list)
+    
+    if status == 2:
+        url_templ = "ldt/ldt_utils/partial/publishedprojectslist.html"
+    else:
+        url_templ = "ldt/ldt_utils/partial/projectslist.html"
+        
+    return render_to_response(url_templ,
+                              {'projects': project_list, 'show_username':show_username,
+                               'is_gecko': is_gecko, 'group_id':id_group},
+                              context_instance=RequestContext(request))
+
+def share_filter(request, filter, use_groups=False):
+    use_groups = boolean_convert(use_groups)
+    if not filter or len(filter) == 0:
+        raise AttributeError("filter should be a string")
+    
+    filter = filter[1:]    
+    resp = get_userlist(request.user, filter=filter)
+            
+    if use_groups:
+        groups = Group.objects.filter(name__icontains=filter).exclude(name=settings.PUBLIC_GROUP_NAME)[0:20]
+
+        for g in groups:
+            resp.append({'name': g.name, 'id': g.id, 'type': 'group'})
+    
+    resp = sorted(resp, key=lambda elem: elem['name'].lower())
+    
+    return render_to_response("ldt/ldt_utils/partial/sharewith.html", {'elem_list' : resp}, context_instance=RequestContext(request))
+    
+@login_required
+def contents_filter(request, filter): 
+    if filter and len(filter) > 0 and filter[0] == '_':
+        filter = filter[1:]
+
+    if filter:
+        content_list = Content.safe_objects.filter(title__icontains=filter) #@UndefinedVariable
+    else:
+        content_list = Content.safe_objects.all() #@UndefinedVariable
+        
+    content_list = add_change_attr(request.user, content_list)
+    
+    return render_to_response("ldt/ldt_utils/partial/contentslist.html",
+                              {'contents': content_list},
+                              context_instance=RequestContext(request))
+
+@login_required
+def groups_filter(request, filter):
+    if filter and len(filter) > 0 and filter[0] == '_':
+        filter = filter[1:]
+
+    if filter:
+        group_list = request.user.groups.filter(name__icontains=filter)
+        search_active = True 
+    else:
+        group_list = request.user.groups.all()
+        search_active = False
+        
+    group_list = group_list.exclude(name=settings.PUBLIC_GROUP_NAME)
+    group_list = sorted(group_list.all(), key=lambda group: group.name.lower())
+    group_list = add_change_attr(request.user, group_list)
+    
+    
+    return render_to_response("ldt/ldt_utils/partial/groupslist.html",
+                              {'groups': group_list, 'search_active': search_active},
+                              context_instance=RequestContext(request))
+    
+
+def search_form(request): 
+    form = SearchForm()
+    return render_to_response('ldt/ldt_utils/search_form.html', {'form': form} , context_instance=RequestContext(request))
+
+
+@login_required
+def search_index(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]
+        
+        if request.POST.has_key("ldt_pres"):
+            url = settings.WEB_URL + django.core.urlresolvers.reverse("ldt.ldt_utils.views.search_init", args=[field, queryStr])
+            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': url}, context_instance=RequestContext(request))
+        else:
+            results = get_results_with_context(field, search)     
+            complete_results = []
+            proj_list = Project.safe_objects.all()
+            results.sort(key=lambda k: k['iri_id'])
+            for iri_id, item in groupby(results, itemgetter('iri_id')):                
+                try: 
+                    content = Content.objects.get(iri_id=iri_id)
+                except Content.DoesNotExist:
+                    continue
+                segments = list(item)
+                to_delete = []
+                for s in segments:
+                    if not s['project_id']:
+                        s['project_id'] = '_'
+                    else:
+                        project = proj_list.filter(ldt_id=s['project_id'])
+                        if len(project) == 0:
+                            to_delete.append(s)
+                            
+                for e in to_delete:
+                    segments.remove(e)
+                    
+                if not segments:
+                    continue 
+                
+                score = sum([seg['score'] for seg in segments])
+                desc = content.description if content.description else ''
+                complete_results.append({'list' : segments, 'score' : score, 'content_title' : content.title, 'content_id' : content.iri_id, 'content_description' : desc })
+            
+            complete_results.sort(key=lambda k: k['score'])
+                                
+            cache.set('complete_results_%s' % request.user.username, complete_results)
+            cache.set('search_%s' % request.user.username, search)
+            cache.set('field_%s' % request.user.username, field)
+
+            paginator = Paginator (complete_results, settings.LDT_RESULTS_PER_PAGE)
+            page = 1
+            
+            try:
+                results = paginator.page(page)
+            except (EmptyPage, InvalidPage):
+                results = paginator.page(paginator.num_pages)
+                
+            results.object_list = highlight_documents(results.object_list, search, field)
+            
+            return render_to_response('ldt/ldt_utils/search_results.html', {'results': results, 'nb_results' : paginator.count, 'search' : search, '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/'}, context_instance=RequestContext(request))   
+        
+    else:
+        return HttpResponseRedirect(reverse('ldt.ldt_utils.views.published_project'))
+        
+
+def search_listing(request):
+    if not cache.get('complete_results_%s' % request.user.username):
+        return HttpResponseRedirect(reverse('ldt.ldt_utils.views.published_project'))
+     
+    complete_results = cache.get('complete_results_%s' % request.user.username)
+    search = cache.get('search_%s' % request.user.username)
+    field = cache.get('field_%s' % request.user.username)
+    paginator = Paginator(complete_results, settings.LDT_RESULTS_PER_PAGE)
+    language_code = request.LANGUAGE_CODE[:2]
+
+    try:
+        page = int(request.GET.get('page', '1'))
+    except ValueError:
+        page = 1
+
+    try:
+        results = paginator.page(page)
+    except (EmptyPage, InvalidPage):
+        results = paginator.page(paginator.num_pages)
+    
+    results.object_list = highlight_documents(results.object_list, search, field)
+
+    return render_to_response('ldt/ldt_utils/search_results.html', {'results': results, 'nb_results' : paginator.count, 'search' : search, '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/'}, context_instance=RequestContext(request))   
+  
+def search_index_get(request, field, query):
+    
+    language_code = request.LANGUAGE_CODE[:2]
+    
+    url = settings.WEB_URL + django.core.urlresolvers.reverse("ldt.ldt_utils.views.search_init", 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 search_init(request, field, query):
+    
+    ldtgen = LdtUtils()
+    
+    doc = ldtgen.generate_init([field, query], 'ldt.ldt_utils.views.search_ldt', 'ldt.ldt_utils.views.search_segments')
+    
+    resp = HttpResponse(mimetype="text/xml;charset=utf-8")
+    resp.write(lxml.etree.tostring(doc, pretty_print=True, encoding="utf-8")) 
+    return resp
+
+def search_ldt(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 = {}
+        projIds = {}
+        
+        for result in searcher.query(field, queryStr):
+            ids[result["iri_id"]] = ""
+            projIds[result["project_id"]] = ""
+
+        id_list = ids.keys()
+        projId_list = projIds.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
+        projectList = Project.safe_objects.filter(ldt_id__in=projId_list)    
+          
+    ldtgen = LdtUtils()
+    #            generate_ldt(contentList, title=u"", author=u"IRI Web", web_url=u"", startSegment=None, projects=None):
+    doc = ldtgen.generate_ldt(contentList, title=u"Recherche : " + queryStr, projects=projectList)
+    doc = set_forbidden_stream(doc, request.user)   
+    doc.write(resp, pretty_print=True)
+    
+    return resp
+
+
+def search_segments(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.safe_objects.all() #@UndefinedVariable
+    try:
+        owner = request.user #@UndefinedVariable
+    except:
+        return HttpResponseRedirect(settings.LOGIN_URL)
+    ldtProjects = Project.safe_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.safe_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):
+    groups = request.user.groups.exclude(name=settings.PUBLIC_GROUP_NAME)
+    redirect_to = ''
+    if request.method == "POST" :
+        form = LdtAddForm(request.POST)
+        form_status = "none"
+        contents = Content.safe_objects.all()
+           
+        if form.is_valid():              
+                     
+            user = request.user            
+            project = Project.create_project(title=form.cleaned_data['title'], user=user, 
+                                             contents=form.cleaned_data['contents'],
+                                             description=form.cleaned_data['description'])
+  
+            if form.cleaned_data["share"]:
+                assign_perm_to_obj(project, form.cleaned_data["read_list"], form.cleaned_data["write_list"], user)
+            form_status = "saved"
+            is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
+            if is_gecko :
+                redirect_to = reverse('index_project_full', args=[project.ldt_id])
+            else:
+                return HttpResponseRedirect(reverse('index_project', args=[project.ldt_id]))   
+     
+    else:
+        form = LdtAddForm()
+        contents = Content.safe_objects.all()             
+        form_status = "none"    
+    
+    return render_to_response('ldt/ldt_utils/create_ldt.html', {'contents': contents, 'form': form, 'form_status':form_status,
+                                                                'redirect_to': redirect_to, 'create_project_action':reverse(create_ldt_view), 'language_code' : settings.LANGUAGE_CODE[2:],
+                                                                'elem_list': get_userlist(request.user)}, 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):
+    url_str = settings.WEB_URL + reverse("ldt.ldt_utils.views.init_segment", args=[project_id, content_id, ensemble_id, cutting_id, segment_id])
+    post_url = ""
+    language_code = request.LANGUAGE_CODE[:2]
+    readonly = 'true'
+    template_path = 'ldt/ldt_utils/init_ldt.html'
+    
+    return render_to_response(template_path, {'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_str, 'posturl': post_url, 'id': id, 'readonly': readonly}, context_instance=RequestContext(request))
+    
+def init_segment(request, project_id, content_id, ensemble_id, cutting_id, segment_id):
+
+    if project_id != u"_":
+        get_object_or_404(Project.safe_objects, ldt_id=project_id)
+    
+    ldtgen = LdtUtils()
+    doc = ldtgen.generate_init([project_id, content_id, ensemble_id, cutting_id, segment_id], 'ldt.ldt_utils.views.ldt_segment', 'ldt.ldt_utils.views.highlight_segment')
+    
+    return HttpResponse(lxml.etree.tostring(lxml.etree.ElementTree(doc), pretty_print=True), mimetype="text/xml;charset=utf-8")
+
+def highlight_segment(request, project_id, content_id, ensemble_id, cutting_id, segment_id):
+    if project_id != u"_":
+        get_object_or_404(Project.safe_objects, ldt_id=project_id)
+    
+    iri = lxml.etree.Element('iri')
+    doc = lxml.etree.ElementTree(iri)    
+
+    seg = lxml.etree.SubElement(iri, 'seg')
+    seg.set('idctt', content_id)
+    seg.set('idens', ensemble_id)
+    seg.set('iddec', cutting_id)
+    seg.set('idseg', segment_id)
+    seg.set('idvue', "")
+    seg.set('crit', "")
+  
+    return HttpResponse(lxml.etree.tostring(doc, pretty_print=True), mimetype="text/xml;charset=utf-8") 
+
+
+def ldt_segment(request, project_id, content_id, ensemble_id, cutting_id, segment_id): 
+
+    resp = HttpResponse(mimetype="text/xml")
+    resp['Cache-Control'] = 'no-cache, must-revalidate'
+    resp['Pragma'] = 'no-cache'
+    
+    if project_id and project_id != "_" :
+        project = Project.safe_objects.get(ldt_id=project_id) #@UndefinedVariable
+        ldtdoc = lxml.etree.fromstring(project.ldt.encode("utf-8"))
+        ldtdoc = set_forbidden_stream(ldtdoc, request.user)
+        displays_node = ldtdoc.find("displays")
+        if not displays_node:
+            displays_node = lxml.etree.SubElement(ldtdoc, u"displays")        
+        res = displays_node.xpath("display")
+        if len(res) > 0:
+            display_node = res[0]
+        else:
+            display_node = lxml.etree.SubElement(displays_node, u"display", attrib={u'id':u'0', u'title': u'generated', u'idsel':unicode(content_id), u'tc':u'0'})
+        
+        res = display_node.xpath("content[@id='%s']/decoupage[(@id='%s') and (@idens='%s')]" % (content_id, cutting_id, ensemble_id))
+        if len(res) == 0:
+            #create node
+            res = display_node.xpath("content[@id='%s']" % (content_id))
+            if len(res) == 0:
+                content_node = lxml.etree.SubElement(display_node, u"content")
+            else:
+                content_node = res[0]
+            lxml.etree.SubElement(content_node, u"decoupage", attrib={u'id':unicode(cutting_id), u'idens':unicode(ensemble_id)})
+        active_segment_node = displays_node.find(u"activeSegment")
+        if not active_segment_node:
+            active_segment_node = lxml.etree.SubElement(displays_node, u"activeSegment")
+        id_node = active_segment_node.find(u"id")
+        if id_node:
+            active_segment_node.remove(id_node)
+        lxml.etree.SubElement(active_segment_node, u"id", attrib={u"idctt":unicode(content_id), u"idens": unicode(ensemble_id), "idcut":unicode(cutting_id), u"idseg":unicode(segment_id)})
+                                    
+        resp.write(lxml.etree.tostring(ldtdoc, xml_declaration=True, encoding='utf-8', pretty_print=True))
+    else:
+        # generate ldt from 
+        ldtgen = LdtUtils()
+        content_list = Content.safe_objects.filter(iri_id=content_id)
+        if request.user and request.user.username:
+            username = request.user.username
+        else:
+            username = "webuser"
+        
+        start_segment = {
+            'idcontent': content_id,
+            'idgroup' : ensemble_id,
+            'idcutting' : cutting_id,
+            'idsegment' : segment_id
+        }        
+        
+        doc = ldtgen.generate_ldt(content_list, "segment : ", author=username, startSegment=start_segment)
+        doc = set_forbidden_stream(doc, request.user)
+        doc.write(resp, pretty_print=('DEBUG' in dir(settings) and settings.DEBUG))
+        
+    return resp
+        
+   
+@login_required    
+def index_project(request, id, full=False): 
+
+    urlStr = settings.WEB_URL + reverse("space_ldt_init", args=['ldt_project', id])
+    posturl = settings.WEB_URL + reverse("ldt.ldt_utils.views.save_ldt_project")
+    language_code = request.LANGUAGE_CODE[:2]
+    
+    try:
+        ldt = Project.safe_objects.get(ldt_id=id)
+    except Project.DoesNotExist:
+        return HttpResponseRedirect(reverse("ldt.ldt_utils.views.workspace"))
+    
+    if ldt.state == 2 or not request.user.has_perm('change_project', ldt): #published
+        readonly = 'true'
+    else:
+        readonly = 'false'
+       
+    if full:
+        template_path = 'ldt/ldt_utils/init_ldt_full.html'
+    else:
+        template_path = 'ldt/ldt_utils/init_ldt.html'
+  
+    return render_to_response(template_path, {'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.generate_init([url], 'ldt.ldt_utils.views.' + method, None)    
+
+    library = doc.xpath('/iri/files/library')[0]
+    for c in Content.safe_objects.all():
+        elem = lxml.etree.SubElement(library, 'file')
+        elem.set('src', c.iri_url())
+        elem.set('video', c.videopath)
+        elem.set('title', c.title)
+        elem.set('author', '')
+        elem.set('category', '')
+        elem.set('pict', '')
+        elem.set('img', '')
+
+    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 ldt_project(request, id): 
+    resp = HttpResponse(mimetype="text/xml")
+    resp['Cache-Control'] = 'no-cache, must-revalidate'
+    resp['Pragma'] = 'no-cache'
+    
+    project = Project.safe_objects.get(ldt_id=id) #@UndefinedVariable
+    
+    doc = lxml.etree.fromstring(project.ldt)
+    doc = set_forbidden_stream(doc, request.user)
+    resp.write(lxml.etree.tostring(doc, pretty_print=True, xml_declaration=True, encoding="utf-8")) 
+
+    return resp
+
+
+def project_json_id(request, id): 
+    
+    project = get_object_or_404(Project.safe_objects, ldt_id=id)
+
+    return project_json(request, project, False)
+
+
+def project_json_externalid(request, id): 
+        
+    res_proj = get_list_or_404(Project.safe_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): # Not checked
+    
+    if not ldt_auth.check_access(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.safe_objects.get(ldt_id=ldt_id); #@UndefinedVariable
+    
+    if not ldt_auth.check_access(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.get_annotations(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"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
+    resp.write(u"<!DOCTYPE rdf:RDF PUBLIC \"-//DUBLIN CORE//DCMES DTD 2002/07/31//EN\" \"http://dublincore.org/documents/2002/07/31/dcmes-xml/dcmes-xml-dtd.dtd\">\n")
+    
+    resp.write(lxml.etree.tostring(rdf_root, xml_declaration=False, encoding="utf-8", pretty_print=True))
+
+    return resp
+
+def save_ldt_project(request):
+    if request.method == "POST":
+        ldt = request.POST['ldt']
+        id = request.POST['id']
+        ldtproject = Project.safe_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.safe_objects, ldt_id=id)
+    ldt.publish()
+    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.safe_objects, ldt_id=id)
+    ldt.unpublish()
+    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.safe_objects.filter(iri_id=url) #@UndefinedVariable
+
+    ldtgen = LdtUtils()
+    doc = ldtgen.generate_ldt(contentList, title=contentList[0].title, startSegment=startSegment)
+    doc = set_forbidden_stream(doc, request.user)
+    doc.write(resp, pretty_print=True)
+
+    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.safe_objects, iri_id=iri_id)
+    contents = [ content, ]
+    groups = request.user.groups.exclude(name=settings.PUBLIC_GROUP_NAME)
+    redirect_to = ''
+    form_status = "none"
+    
+    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, description=form.cleaned_data['description'])
+            form_status = "saved" 
+
+            if form.cleaned_data["share"]:
+                assign_perm_to_obj(project, form.cleaned_data["read_list"], form.cleaned_data["write_list"], user)
+
+            # Modal window is not used with firefox
+            is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
+            if is_gecko :
+                redirect_to = reverse('index_project_full', args=[project.ldt_id])
+            else:
+                return HttpResponseRedirect(reverse('index_project', args=[project.ldt_id]))
+    else:
+        form = AddProjectForm()
+           
+    return render_to_response('ldt/ldt_utils/create_ldt.html', {'form':form, 'form_status': form_status, 'contents':contents,'groups' : groups,
+                                                                'redirect_to': redirect_to, 'elem_list': get_userlist(request.user), 'create_project_action':reverse("ldt.ldt_utils.views.create_project", args=[iri_id])}, context_instance=RequestContext(request))
+
+@login_required
+def update_project(request, ldt_id):
+    project = get_object_or_404(Project.safe_objects, ldt_id=ldt_id)
+    contents = project.contents.all()
+    groups = request.user.groups.exclude(name=settings.PUBLIC_GROUP_NAME)
+    member_list, admin_list = get_userlist_model(project, request.user)
+    
+    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 = 'none' 
+            form = AddProjectForm(request.POST)
+            
+            if form.is_valid():          
+                if project.title != form.cleaned_data['title'] or project.description != form.cleaned_data['description']:
+                    project.title = form.cleaned_data['title']
+                    project.description = form.cleaned_data['description']
+                    ldt = lxml.etree.fromstring(project.ldt.encode("utf-8"))
+                    res = ldt.xpath("/iri/project")
+                    res[0].set("title", project.title)
+                    res[0].set("abstract", project.description)
+                    project.ldt = lxml.etree.tostring(ldt, pretty_print=True)
+                    project.save()                    
+                    
+                if form.cleaned_data["share"]:
+                    assign_perm_to_obj(project, form.cleaned_data["read_list"], form.cleaned_data["write_list"], request.user)
+                form_status = "saved"
+    else:
+        form = AddProjectForm({'title':unicode(project.title), 'description':unicode(project.get_description())})
+        
+        form_status = 'none'
+       
+    return render_to_response('ldt/ldt_utils/create_ldt.html', {'form':form, 'form_status':form_status, 'groups': groups, 'elem_list': get_userlist(request.user), 
+                                                                'ldt_id': ldt_id, 'contents':contents, 'member_list': member_list, 'admin_list': admin_list,
+                                                                '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, group_id=0): 
+    
+    project = get_object_or_404(Project.safe_objects, ldt_id=ldt_id)
+    if request.method == "POST" :
+        form = CopyProjectForm(request.POST)
+        
+        if form.is_valid():
+            user = request.user
+            group_id = form.cleaned_data['group']
+            group = Group.objects.get(id=group_id) if group_id and group_id > 0 else None
+            project = project.copy_project(title=form.cleaned_data['title'], user=user, group=group)
+            is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
+            if is_gecko:
+                return HttpResponseRedirect(reverse('index_project_full', args=[project.ldt_id]))
+            else:
+                return HttpResponseRedirect(reverse('index_project', args=[project.ldt_id]))
+    else:
+        form = CopyProjectForm()
+    # 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/copy_ldt.html', {'form':form, 'project':project, 'group_id':group_id, 'target_parent':target_parent}, context_instance=RequestContext(request))
+
+
+def write_content_base(request, iri_id=None): 
+
+    if iri_id:        
+        instance_content = Content.safe_objects.get(iri_id=iri_id) #@UndefinedVariable
+        instance_media = instance_content.media_obj
+        logging.debug("write_content_base : valid form: for instance : media -> " + repr(instance_media) + " content : for instance : " + repr(instance_content)) #@UndefinedVariable
+    else:
+        logging.debug("No iri_id") #@UndefinedVariable
+        instance_content = None
+        instance_media = None
+    
+    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_instance_val['read_list'] = request.POST.getlist('read_list')
+        content_instance_val['write_list'] = request.POST.getlist('write_list')
+        content_instance_val['share'] = request.POST.get('share', False)
+
+        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.safe_objects.get_or_create(src=cleaned_data['src'], defaults=cleaned_data) #@UndefinedVariable
+                    cached_assign('view_media', request.user, media)
+                else:
+                    media = None
+                    
+
+            if media and not created:
+                for attribute in ('external_id', 'external_permalink', 'external_publication_url', 'external_src_url', 'media_creation_date', 'videopath', 'duration', 'description', 'title'):
+                    setattr(media, attribute, cleaned_data.get(attribute))
+                mimetype = cleaned_data.get('mimetype_field', None)
+                if not mimetype:
+                    mimetype = mimetypes.guess_type(media.src)
+                media.mimetype_field = mimetype
+                cached_assign('view_media', request.user, media)
+                cached_assign('change_media', request.user, media)
+                media.save()
+            
+            if form_status != "error": 
+                content_defaults = {}
+                content_defaults.update(content_form.cleaned_data)
+                content_defaults['media_obj'] = media
+                               
+                for key in ["media_input_type", "groups", "is_public", "read_list", "write_list", "share" ]:
+                    del content_defaults[key]
+                     
+                content, created = Content.safe_objects.get_or_create(iri_id=content_form.cleaned_data['iri_id'], defaults=content_defaults) #@UndefinedVariable
+                if not created:
+                    content.save() # Check if user is allowed to change object before assigning permissions.
+                cached_assign('change_content', request.user, content)
+                cached_assign('view_content', request.user, content)
+                everyone = Group.objects.get(name=settings.PUBLIC_GROUP_NAME)
+                if content_form.cleaned_data['is_public']:
+                    cached_assign('view_content', everyone, content)
+                    if media:
+                        cached_assign('view_media', everyone, media)
+                elif content_form.cleaned_data["share"]:
+                    remove_perm('view_content', everyone, content)
+                    assign_perm_to_obj(content, content_form.cleaned_data['read_list'], content_form.cleaned_data['write_list'], request.user)
+                    if media:
+                        assign_perm_to_obj(media, content_form.cleaned_data['read_list'], content_form.cleaned_data['write_list'], request.user)
+                if not created:
+                    for attribute in ('iriurl', 'title', 'description', 'duration', 'content_creation_date', 'tags', 'media_obj'):
+                        setattr(content, attribute, content_defaults[attribute])
+                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"}
+        if instance_content:
+            initial['is_public'] = instance_content.is_public
+        
+        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) 
+    groups = request.user.groups.exclude(name=settings.PUBLIC_GROUP_NAME)
+    member_list = admin_list = []
+    
+    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:
+            member_list, admin_list = get_userlist_model(Content.objects.get(iri_id=iri_id), request.user)
+        
+    if iri_id:
+        create_content_action = reverse('ldt.ldt_utils.views.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    
+    content_form.fields["media_obj"].queryset = Media.safe_objects.all()
+    
+    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,
+                                                                    'elem_list': get_userlist(request.user), 'member_list': member_list, 'admin_list': admin_list,  'iri_id': iri_id, 'session_key':session_key, 'cookie_name':cookie_name}, context_instance=RequestContext(request))
+
+@login_required
+def prepare_delete_content(request, iri_id=None): 
+    errors = []
+    titles = []
+    if not iri_id:
+        iri_id = request.REQUEST.get("iri_id", None)
+        
+    if iri_id:
+        for content in Content.safe_objects.filter(iri_id=iri_id): 
+            titles.append(unicode(content.title))
+            projects = content.project_set.all()
+            projects_nb = len(projects)
+            if projects_nb > 0:
+                project_titles = map(lambda p: unicode(p.title), projects)
+                errors.append(ungettext("Content '%(title)s' is referenced by this project : %(project_titles)s. Please delete it beforehand.", "Content '%(title)s' is referenced by %(count)d projects: %(project_titles)s. Please delete them beforehand.", projects_nb) % {'title':unicode(content.title), 'count':projects_nb, 'project_titles': ",".join(project_titles)})
+ 
+    return errors, titles
+
+
+@login_required
+def delete_content(request, iri_id=None):
+    if not iri_id:
+        iri_id = request.REQUEST.get("iri_id", None)
+        
+    if iri_id:
+        Content.safe_objects.get(iri_id=iri_id).delete()
+
+
+def upload(request):
+    if request.method == 'POST':
+        for field_name in request.FILES:
+            # We get the file name
+            source_file = request.FILES[field_name]
+            source_filename = source_file.name
+            # We sanitize the file name : no space, only lower case.
+            source_filename = ldt_utils_path.sanitize_filename(source_filename)
+            # We create the session temp folder if necessary
+            if not os.path.exists(os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME])):
+                os.makedirs(os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME]))
+            destination_filepath = os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", source_filename)
+            # We delete the existing file if necessary
+            if os.path.exists(destination_filepath):
+                os.remove(destination_filepath)
+            
+            destination_file = open(destination_filepath, "wb")
+            
+            for chunk in source_file.chunks():
+                destination_file.write(chunk)
+            destination_file.close()
+            
+        # indicate that everything is OK for SWFUpload
+        return HttpResponse("ok", mimetype="text/plain")
+    else:
+        return HttpResponse("notok", mimetype="text/plain")
+
+def remove_temp_file(request):
+    # The filename arrives with a GET var.
+    file_path = os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", ldt_utils_path.sanitize_filename(request.GET["filename"]))
+    if os.path.exists(file_path):
+        os.remove(file_path)
+    return HttpResponse("remove ok", mimetype="text/plain")
+
+def get_duration(request):
+    try:
+        # The filename arrives with a GET var.
+        file_path = os.path.join(settings.STREAM_PATH, "tmp/" + request.COOKIES[settings.SESSION_COOKIE_NAME] + "/", ldt_utils_path.sanitize_filename(request.GET["filename"]))
+        if hasattr(settings, 'FFMPEG_PATH') and os.path.exists(file_path):
+            output = str(subprocess.Popen([settings.FFMPEG_PATH, "-i", file_path], stderr=subprocess.PIPE).communicate()[1])
+            m = re.search("Duration:\s*?([\d.:]+)", output, re.M)
+            dur_arr = m.group(1).split(":")
+            td = datetime.timedelta(hours=int(dur_arr[0]), minutes=int(dur_arr[1]), seconds=float(dur_arr[2]))
+            str_duration = str((td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / 10 ** 3)
+            return HttpResponse(str_duration, mimetype="text/plain")
+        else:
+            return HttpResponse("", mimetype="text/plain")
+    except Exception as inst:
+        return HttpResponse(str(inst), mimetype="text/plain")
+
+
+@login_required
+def get_group_projects(request):
+
+    # Get group, user and project_list
+    grp_id = request.POST["id_group"]
+    if grp_id == "-1":
+        project_list = get_objects_for_user(request.user, 'ldt_utils.view_project', use_groups=False).exclude(owner=request.user)
+    else:
+        grp = Group.objects.get(id=grp_id)
+        everyone = Group.objects.get(name=settings.PUBLIC_GROUP_NAME)
+        project_list = get_objects_for_group(grp, 'ldt_utils.view_project') | get_objects_for_group(everyone, 'ldt_utils.view_project').filter(owner__in=[grp])
+    
+    project_list = add_change_attr(request.user, project_list)
+    
+    is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
+
+    return render_to_response("ldt/ldt_utils/partial/projectslist.html",
+                              {'projects': project_list, 'show_username':True,
+                               'is_gecko': is_gecko, 'group_id': grp_id},
+                              context_instance=RequestContext(request))
+
+@login_required
+def create_group(request):
+    if not request.user.user_permissions.filter(codename='add_group'):
+        return HttpResponseServerError('<h1>User %s can not create a group.</h1>' % request.user.username)
+
+    form_status = ''
+    
+    if request.method == 'POST':
+        form = GroupAddForm(request.POST)
+        
+        if form.is_valid():         
+            name = form.cleaned_data['name']
+            members_list = form.cleaned_data['read_list']
+            admin_list = form.cleaned_data['write_list']          
+            
+            group = Group.objects.create(name=name)
+            group.save()
+            cached_assign('is_owner_group', request.user, group)
+            cached_assign('change_group', request.user, group)
+            request.user.groups.add(group)             
+
+            for elem in members_list:
+                if hasattr(elem, 'username'):
+                    elem.groups.add(group)
+                    if elem in admin_list:
+                        cached_assign('change_group', elem, group)
+                        
+            form_status = 'saved'
+            
+    else:
+        form = GroupAddForm()
+        
+    return render_to_response("ldt/ldt_utils/create_group.html", {'group_edition': True, 'form' : form, 'form_status' : form_status, 'elem_list' : get_userlist(request.user)}, context_instance=RequestContext(request))
+
+@login_required
+def update_group(request, group_id):
+    group = get_object_or_404(Group, id=group_id)
+    checker = get_cached_checker(request.user)
+    
+    if not checker.has_perm('change_group', group):
+        form_status = 'none'
+        return render_to_response("ldt/ldt_utils/create_group.html", {'form_status' : form_status}, context_instance=RequestContext(request))
+
+    form_status = ''
+    is_owner_group = checker.has_perm('is_owner_group', group)     
+            
+    if request.method == "POST":
+        form = GroupAddForm(request.POST, instance=group)
+        submit_action = request.REQUEST.get("submit_button", False)
+        
+        if submit_action == 'delete':
+            if is_owner_group:
+                group.delete()
+                form_status = 'deleted'
+        else:   
+            if form.is_valid():
+                name = form.cleaned_data['name']
+                new_member_list = form.cleaned_data['read_list']
+                old_member_list = group.user_set.exclude(id=request.user.id)
+                admin_list = form.cleaned_data['write_list']
+                group.name = name
+
+                for user in new_member_list:
+                    if not hasattr(user, 'username'):
+                        raise AttributeError('new_member_list should only contain users')
+                    if user != request.user:                      
+                        group.user_set.add(user)
+                        if is_owner_group:
+                            if user in admin_list:
+                                cached_assign('change_group', user, group)
+                            else:
+                                remove_perm('change_group', user, group)
+                                
+                for user in old_member_list:
+                    if user not in new_member_list:
+                        group.user_set.remove(user)
+                        remove_perm('change_group', user, group)
+                                        
+                group.save()
+                form_status = 'saved'                   
+    else:
+        form = GroupAddForm(initial={'name':unicode(group.name)})    
+
+    if form_status != 'deleted':
+        member_list, admin_list = get_userlist_group(group, request.user)
+    else:    
+        member_list = admin_list = []
+        
+    return render_to_response("ldt/ldt_utils/create_group.html", {'group_id' : group_id, 'form' : form, 'form_status' : form_status, 'group_edition': True,
+                                                                  'elem_list' : get_userlist(request.user), 'member_list': member_list, 'admin_list': admin_list,
+                                                                  'is_owner_group': is_owner_group}, context_instance=RequestContext(request))
--- a/src/ldt/ldt/settings.py	Thu Jan 05 17:33:44 2012 +0100
+++ b/src/ldt/ldt/settings.py	Fri Jan 06 10:09:16 2012 +0100
@@ -47,6 +47,7 @@
     'django.contrib.messages.middleware.MessageMiddleware',
     'django_openid_consumer.middleware.OpenIDMiddleware',
     'ldt.ldt_utils.middleware.userprofile.LanguageMiddleware',
+    'ldt.api.middleware.pistonput.PistonPutMiddleware',
 )
 
 
@@ -92,4 +93,3 @@
 DEFAULT_PROJECT_ICON = "thumbnails/projects/project_default_icon.png"
 DEFAULT_USER_ICON = "thumbnails/users/user_default_icon.png"
 DEFAULT_GROUP_ICON = "thumbnails/groups/group_default_icon.png"
-
--- a/web/ldtplatform/settings.py	Thu Jan 05 17:33:44 2012 +0100
+++ b/web/ldtplatform/settings.py	Fri Jan 06 10:09:16 2012 +0100
@@ -91,6 +91,7 @@
     'django_openid_consumer.middleware.OpenIDMiddleware',
     'ldt.ldt_utils.middleware.userprofile.LanguageMiddleware',
     'ldt.security.middleware.SecurityMiddleware',
+    'ldt.api.middleware.pistonput.PistonPutMiddleware',
 )
 
 TEMPLATE_CONTEXT_PROCESSORS = (