first version of embed and auth. plan to implement rbac
--- a/web/franceculture/settings.py Thu Sep 23 18:39:40 2010 +0200
+++ b/web/franceculture/settings.py Wed Sep 29 10:10:07 2010 +0200
@@ -144,5 +144,5 @@
LOGIN_REDIRECT_URL = BASE_URL + 'franceculture'
GLOBAL_LOG_LEVEL = LOG_LEVEL
-GLOBAL_LOG_HANDLERS = [logging.FileHandler(LOG_FILE)]
+GLOBAL_LOG_HANDLERS = [{'handler':logging.FileHandler(LOG_FILE), 'format':"%(asctime)s - %(levelname)s : %(message)s"}]
--- a/web/franceculture/templates/franceculture/partial/embed.html Thu Sep 23 18:39:40 2010 +0200
+++ b/web/franceculture/templates/franceculture/partial/embed.html Wed Sep 29 10:10:07 2010 +0200
@@ -1,5 +1,6 @@
+{% load i18n %}
<div style="height: 80px"> </div>
-<div id="{{ player_id }}">
+<div id="{{ player_id }}_embed" class="iri_player_embed">
</div>
<script type="text/javascript">
var config = {
@@ -11,7 +12,7 @@
width:650,
height:1,
mode:'radio',
- container:'{{ player_id }}',
+ container:'{{ player_id }}_embed',
debug:false,
css:'{{WEB_URL}}{{MEDIA_URL}}css/LdtPlayer.css'},
player:{
@@ -19,4 +20,18 @@
src:'{{WEB_URL}}{{MEDIA_URL}}swf/player.swf'}
};
__IriSP.init(config);
-</script>
\ No newline at end of file
+</script>
+<div id="{{ player_id }}_seo" style="display: none;">
+ <ul>
+ {% for annotation in annotations %}
+ <li><span class="title">{{annotation.title}}</span><span class="desc">{{annotation.desc}}</span><span class="tags">{{annotation.tags}}</span><span class="uri">{% if annotation.uri %}<a href="{{annotation.uri}}">{{annotation.uri}}</a>{% endif %}</span></li>
+ {% endfor %}
+ </ul>
+</div>
+<div id="{{ player_id }}_link_list">
+ <ul>
+ {% for annotation in annotations %}
+ <li><span class="title">{{annotation.title}}</span>: <span class="uri">{% if annotation.uri %}<a href="{{annotation.uri}}">{{annotation.uri}}</a>{% endif %}</span></li>
+ {% endfor %}
+ </ul>
+</div>
\ No newline at end of file
--- a/web/franceculture/urls.py Thu Sep 23 18:39:40 2010 +0200
+++ b/web/franceculture/urls.py Wed Sep 29 10:10:07 2010 +0200
@@ -23,7 +23,7 @@
(r'^accounts/', include('registration.backends.simple.urls')),
url(r'^/?$', "franceculture.views.workspace", name="root-view"),
- url(r'^filterprojects/(?P<filter>\w*)/(?P<is_owner>true|false)/(?P<status>\d)$', "franceculture.views.projectsfilter", ),
- url(r'^filtercontents/(?P<filter>\w*)/$', "franceculture.views.contentsfilter", ),
+ url(r'^filterprojects/_(?P<filter>[\w\%\_\-\+]*?)/(?P<is_owner>true|false)/(?P<status>\d)$', "franceculture.views.projectsfilter", ),
+ url(r'^filtercontents/_(?P<filter>[\w\%\_\-\+]*?)/$', "franceculture.views.contentsfilter", ),
(r'^embedpopup/?$', "franceculture.views.popup_embed"),
)
--- a/web/franceculture/views.py Thu Sep 23 18:39:40 2010 +0200
+++ b/web/franceculture/views.py Wed Sep 29 10:10:07 2010 +0200
@@ -5,8 +5,11 @@
from django.template.loader import render_to_string
from ldt.ldt_utils.models import Content, Project, Owner
from ldt.ldt_utils.utils import boolean_convert
-from django.http import HttpResponseServerError
+from django.http import HttpResponseServerError, HttpResponseForbidden
from django.db.models import Q
+import logging
+import lxml.etree
+import ldt.auth
@login_required
@@ -30,7 +33,7 @@
is_owner = boolean_convert(is_owner)
status = int(status)
query = Q()
-
+
if is_owner:
owner = None
try:
@@ -42,7 +45,9 @@
if status > 0:
query &= Q(state=status)
- if filter and filter != "_":
+ if filter:
+ if len(filter) > 0 and filter[0] == '_':
+ filter = filter[1:]
query &= Q(title__icontains=filter)
project_list = Project.objects.filter(query)
@@ -54,8 +59,10 @@
@login_required
def contentsfilter(request, filter):
- if filter == "_":
- filter = ""
+
+ if filter and len(filter) > 0 and filter[0] == '_':
+ filter = filter[1:]
+
if filter:
content_list = Content.objects.filter(title__icontains=filter)
else:
@@ -71,11 +78,58 @@
json_url = request.GET.get("json_url")
player_id = request.GET.get("player_id")
+ ldt_id = request.GET.get("ldt_id")
- embed_rendered = escape(render_to_string('franceculture/partial/embed.html', {'json_url':json_url,'player_id':player_id}, context_instance=RequestContext(request)))
+ project = Project.objects.get(ldt_id=ldt_id);
+
+ if not ldt.auth.checkAccess(request.user, project):
+ return HttpResponseForbidden(_("You can not access this project"))
+
+
+ doc = lxml.etree.fromstring(project.ldt)
+
+ annotations = []
+
+ for contentnode in doc.xpath("/iri/annotations/content"):
+ iri_id = contentnode.get("id")
+ content = Content.objects.get(iri_id=iri_id)
+
+ for annotationnode in contentnode.xpath("ensemble/decoupage/elements/element"):
+
+ tags = annotationnode.get('tags')
+ tags_list = []
+ tags_list.extend(annotationnode.xpath("tags/tag/text()"))
+ if tags:
+ tags_list.append(tags)
+ tags = ",".join(tags_list)
+
+ begin = annotationnode.get('begin')
+ if begin is None:
+ begin = 0
+ else:
+ begin = int(begin)
+
+ uri = None
+ if content.media_obj.external_publication_url:
+ uri = "%s#%d" % (content.media_obj.external_publication_url, begin)
+
+ annotations.append({
+ 'begin': begin,
+ 'duration':annotationnode.get('dur'),
+ 'title':u"".join(annotationnode.xpath("title/text()")),
+ 'desc':u"".join(annotationnode.xpath("abstract/text()")),
+ 'tags': tags,
+ 'id':u"".join(annotationnode.get('id')),
+ 'uri':uri
+ })
+
+
+ embed_rendered = escape(render_to_string('franceculture/partial/embed.html', {'json_url':json_url,'player_id':player_id, 'annotations':annotations}, context_instance=RequestContext(request)))
return render_to_response("franceculture/embed_popup.html",
{'json_url':json_url,'player_id':player_id, 'player_embed_rendered':embed_rendered},
context_instance=RequestContext(request))
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/ldt/auth/__init__.py Wed Sep 29 10:10:07 2010 +0200
@@ -0,0 +1,7 @@
+
+def checkAccess(user, obj):
+ check_meth = getattr(obj, 'checkAccess', False)
+ if check_meth:
+ return check_meth(user)
+ else:
+ return False
\ No newline at end of file
--- a/web/ldt/ldt_utils/models.py Thu Sep 23 18:39:40 2010 +0200
+++ b/web/ldt/ldt_utils/models.py Wed Sep 29 10:10:07 2010 +0200
@@ -21,9 +21,9 @@
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, null=True, blank=True, verbose_name=_('content.external_permalink'))
- external_publication_url = models.URLField(max_length=1024, null=True, blank=True, verbose_name=_('content.external_publication_url'))
- external_src_url = models.URLField(max_length=1024, null=True, blank=True, verbose_name=_('content.external_publication_url'))
+ 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=False, null=True, blank=True, verbose_name=_('media.external_publication_url'))
+ external_src_url = models.URLField(max_length=1024, verify_exists=False, 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'))
@@ -45,7 +45,7 @@
'mp3': lambda s: "%s:%s" %("mp3",res_src[:-4]),
'mp4': lambda s: "%s:%s" %("mp4",res_src[:-4]),
'f4v': lambda s: "%s:%s" %("mp4",res_src[:-4]),
- }.get(extension, lambda s:s)(res_src)
+ }.get(extension, lambda s:s)(res_src.lower())
return res_src
return locals()
@@ -80,6 +80,9 @@
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:
@@ -246,6 +249,10 @@
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)
@@ -284,6 +291,12 @@
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):
--- a/web/ldt/ldt_utils/views.py Thu Sep 23 18:39:40 2010 +0200
+++ b/web/ldt/ldt_utils/views.py Wed Sep 29 10:10:07 2010 +0200
@@ -1,5 +1,5 @@
import django.core.urlresolvers
-from django.http import HttpResponse, HttpResponseRedirect
+from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from django.core.urlresolvers import reverse
@@ -28,6 +28,9 @@
import urllib2
from urllib2 import urlparse
from jogging import logging
+import ldt.utils.path
+import ldt.auth as ldt_auth
+from django.utils.translation import ugettext as _
@@ -203,7 +206,7 @@
def project_json_id(request, id):
project = get_object_or_404(Project,ldt_id=id)
-
+
return project_json(request, project)
@@ -216,7 +219,10 @@
def project_json(request, project):
-
+
+ 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"
@@ -401,6 +407,7 @@
media = None
elif media_input_type == "link":
media = content_form.cleaned_data["media_obj"]
+ created = False
elif media_input_type == "url" or media_input_type == "upload" or media_input_type == "create":
# copy file
#complet src
@@ -419,12 +426,18 @@
source_file = request.FILES['media-media_file']
source_filename = source_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 = source_filename+"(%d)" % (i)
+ base_source_filename = "%s.%d.%s" % (base_basename_filename,i,extension)
destination_filepath = os.path.join(settings.STREAM_PATH, base_source_filename)
i += 1
@@ -455,10 +468,13 @@
if not cleaned_data['videopath']:
cleaned_data['videopath'] = settings.STREAM_URL
media, created = Media.objects.get_or_create(src=cleaned_data['src'], defaults=cleaned_data)
- if 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))
- media.save()
+ 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))
+ media.save()
#except Exception as inst:
# logging.debug("write_content_base : POST error when saving media:" + str(inst))
# form_status = "error"
--- a/web/ldt/locale/en/LC_MESSAGES/django.po Thu Sep 23 18:39:40 2010 +0200
+++ b/web/ldt/locale/en/LC_MESSAGES/django.po Wed Sep 29 10:10:07 2010 +0200
@@ -84,7 +84,7 @@
#: ldt_utils/models.py:31
#, fuzzy
msgid "media.duration"
-msgstr "duration"
+msgstr "duration (ms)"
#: ldt_utils/models.py:32
msgid "media.creator"
@@ -135,7 +135,7 @@
#: ldt_utils/models.py:58
msgid "content.duration"
-msgstr "duration"
+msgstr "duration (ms)"
#: ldt_utils/models.py:209
msgid "created by"
--- a/web/ldt/locale/fr/LC_MESSAGES/django.po Thu Sep 23 18:39:40 2010 +0200
+++ b/web/ldt/locale/fr/LC_MESSAGES/django.po Wed Sep 29 10:10:07 2010 +0200
@@ -82,7 +82,7 @@
#: ldt_utils/models.py:31
msgid "media.duration"
-msgstr "Durée du contenu"
+msgstr "Durée du contenu (ms)"
#: ldt_utils/models.py:32
msgid "media.creator"
@@ -132,7 +132,7 @@
#: ldt_utils/models.py:58
msgid "content.duration"
-msgstr "Durée"
+msgstr "Durée (ms)"
#: ldt_utils/models.py:209
msgid "created by"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/ldt/utils/path.py Wed Sep 29 10:10:07 2010 +0200
@@ -0,0 +1,14 @@
+"""
+Some small file related utilities
+"""
+
+import unicodedata
+import string
+
+validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits)
+
+
+def sanitize_filename(filename):
+ cleanedFilename = unicodedata.normalize('NFKD', filename).encode('ASCII', 'ignore').lower()
+ return ''.join(c for c in cleanedFilename if c in validFilenameChars).replace(' ','_')
+
\ No newline at end of file
--- a/web/static/js/projectscontents.js Thu Sep 23 18:39:40 2010 +0200
+++ b/web/static/js/projectscontents.js Wed Sep 29 10:10:07 2010 +0200
@@ -68,6 +68,7 @@
var link = $(e.target);
var json_url = link.attr("href");
var player_id = link.attr("id");
+ var ldt_id = player_id.substring(15);
/*$.nyroModalSettings({
ajax: { data: ({ json_url:json_url, player_id:player_id }) }
});*/
@@ -79,7 +80,7 @@
width:750,
bgColor: 'rgb(239, 239, 239)',
padding: 5,
- url: embed_url+'?json_url='+escape(json_url)+'&player_id='+escape(player_id),
+ url: embed_url+'?json_url='+escape(json_url)+'&player_id='+escape(player_id)+'&ldt_id='+escape(ldt_id),
});
return false;
});
@@ -133,11 +134,8 @@
target.attr('timer',setTimeout(function() {
target.next(".searchajaxloader").show();
target.nextAll(".searchclear").hide();
- var realVal = target.realVal();
- if(realVal.length == 0) {
- realVal = "_";
- }
- url = url.replace('__FILTER__',escape(realVal));
+ var filterVal = "_" + escape(target.realVal());
+ url = url.replace('__FILTER__',filterVal);
$(container_selector).load(url, null, function() {
target.next(".searchajaxloader").hide();
if(target.realVal().length > 0) {
Binary file web/static/swf/ldt/LignesDeTempsFlex.swf has changed