from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import redirect, get_object_or_404
from django.utils.decorators import method_decorator
from django.views.decorators.cache import never_cache
from django.views.generic.base import View, TemplateResponseMixin
from guardian.shortcuts import assign
from ldt.ldt_utils.models import Project, Content
from ldt.ldt_utils.views.content import write_content_base, delete_content
from ldt.ldt_utils.utils import generate_uuid, copy_ldt
from ldt.security.permissionchecker import check_object_perm_for_user
from metadatacomposer.forms import ImageUploadModelForm
from metadatacomposer.models import Image
from sorl.thumbnail import get_thumbnail
import os
import datetime
import logging #@UnresolvedImport
logger = logging.getLogger(__name__)
class MetadataComposerContextView(View):
branding = "iri"
def get_context_dict(self, request):
context = {}
context["branding"] = self.branding
context["top_header_css"] = "metadatacomposer/%s/composer_header_css.html" % self.branding
context["top_header_partial"] = "metadatacomposer/%s/composer_header.html" % self.branding
context["player_css"] = "metadatacomposer/%s/composer_player_css.html" % self.branding
context["player_about"] = "metadatacomposer/%s/composer_player_about.html" % self.branding
return context
class MetadataComposerHome(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_home.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerHome, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
projects = Project.safe_objects.filter(owner=request.user).exclude(title__startswith='front').order_by('-modification_date')[:6]
images = Image.objects.order_by('-modification_date')[:6]
contents = Content.safe_objects.order_by('-update_date')[:6]
context = self.get_context_dict(request)
context.update({"projects":projects, "images": images, "contents": contents})
return self.render_to_response(context)
class MetadataComposerProjectList(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_project_list.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerProjectList, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
page = request.GET.get("page") or 1
projects = Project.safe_objects.prefetch_related("contents").exclude(title__startswith='front').order_by('-modification_date').filter(owner=request.user)
nb = getattr(settings, 'METADATACOMPOSER_ELEMENTS_PER_PAGE', 9)
if page=="x":
nb = projects.count()
paginator = Paginator(projects, nb)
try:
results = paginator.page(page)
except (EmptyPage, InvalidPage):
results = paginator.page(paginator.num_pages)
context = self.get_context_dict(request)
context.update({"results":results})
return self.render_to_response(context)
class MetadataComposerResourceList(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_resource_list.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerResourceList, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
# We get the first page of images
image_results = get_images(1)
# We get the first contents page and theirs projects
content_results = get_contents_and_projects(1, request.user)
context = self.get_context_dict(request)
context.update({"image_results":image_results, "content_results":content_results})
return self.render_to_response(context)
class MetadataComposerImagePagination(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
if self.template_name and self.template_name!="":
return self.template_name
else:
return "partial/resource_image_list.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerImagePagination, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
page = request.GET.get("page") or 1
mode = request.GET.get("mode") or "resource"
# Get current contents page and theirs projects
image_results = get_images(page)
if mode=="library":
self.template_name = "partial/library_image_list.html"
context = self.get_context_dict(request)
context.update({"image_results":image_results})
return self.render_to_response(context)
class MetadataComposerContentPagination(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
if self.template_name and self.template_name!="":
return self.template_name
else:
return "partial/resource_content_list.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerContentPagination, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
page = request.GET.get("page") or 1
mode = request.GET.get("mode") or "resource"
select_media = False
create_empty_project = False
if mode=="library":
self.template_name = "partial/library_content_list.html"
select_media = True
elif mode=="create":
self.template_name = "partial/library_content_list.html"
create_empty_project = True
# Get current contents page and theirs projects
content_results = get_contents_and_projects(page, request.user, select_media, create_empty_project)
context = self.get_context_dict(request)
context.update({"content_results":content_results, "mode":mode})
return self.render_to_response(context)
def get_images(page):
# We get the current's page images
images = Image.objects.order_by('-modification_date')
nb = getattr(settings, 'METADATACOMPOSER_ELEMENTS_PER_PAGE', 8)
if page=="x":
nb = images.count()
paginator = Paginator(images, nb)
try:
results = paginator.page(page)
except (EmptyPage, InvalidPage):
results = paginator.page(paginator.num_pages)
return results
def get_contents_and_projects(page, user, select_media=False, create_empty_project=False):
# We get the current's page contents
# prefetch_related("project_set") is unfortunately useless because we have to filter the project queryset later
if select_media:
contents = Content.safe_objects.select_related("media_obj").order_by('-update_date')
else:
contents = Content.safe_objects.order_by('-update_date')
nb = getattr(settings, 'METADATACOMPOSER_ELEMENTS_PER_PAGE', 8)
if page=="x":
nb = contents.count()
paginator = Paginator(contents, nb)
try:
results = paginator.page(page)
except (EmptyPage, InvalidPage):
results = paginator.page(paginator.num_pages)
# We add the user's projects for each content
results_object_list = []
for content in results.object_list:
# We filter the content's projects with the user's ones
if select_media:
if not content.videopath and content.videopath!="":
content.url = content.videopath.rstrip('/') + "/" + content.src
else:
content.url = content.src
elif create_empty_project:
content.url = "create_project_for_me"
projects = content.project_set.all().filter(owner=user)
results_object_list.append({"content":content, "projects":projects})
results.object_list = results_object_list
return results
class MetadataComposerModalContent(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_modal_content.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerModalContent, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", iri_id=None, **kwargs):
self.branding = branding
# Generate fake id to validate ContentForm
if not iri_id:
iri_id = generate_uuid()
content = None
else:
content = Content.safe_objects.select_related("media_obj").get(iri_id=iri_id)
context = self.get_context_dict(request)
context.update({"iri_id":iri_id, "content":content})
return self.render_to_response(context)
def post(self, request, branding="iri", iri_id=None, **kwargs):
self.branding = branding
# We create the media
content_form, media_form, picture_form, form_status, _, current_front_project, e, traceback = write_content_base(request, iri_id)
# And test creation
if (content_form == False and media_form == False and picture_form == False and form_status == False and current_front_project == False):
#message=_("An error occurred - Please try again or contact webmaster")
#title = _("Error")
raise e, None, traceback
return redirect(request.META['HTTP_REFERER'])
class MetadataComposerModalContentLibrary(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_modal_content_library.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerModalContentLibrary, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
mode = request.GET.get("mode") or None
select_media = True
create_empty_project = False
if mode=="create":
select_media = False
create_empty_project = True
context = self.get_context_dict(request)
context.update({"content_results":get_contents_and_projects(1, request.user, select_media, create_empty_project), "mode":mode})
return self.render_to_response(context)
class MetadataComposerModalImage(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_modal_image.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerModalImage, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
image_pk = request.GET.get("image") or None
# Add form
if image_pk:
form = ImageUploadModelForm(instance=Image.objects.get(pk=image_pk))
else:
form = ImageUploadModelForm()
context = self.get_context_dict(request)
context.update({"form":form, "image_pk":image_pk})
return self.render_to_response(context)
def post(self, request, branding="iri", **kwargs):
self.branding = branding
# Check form
if 'image_pk' in request.POST:
form = ImageUploadModelForm(request.POST, request.FILES, instance=Image.objects.get(pk=request.POST['image_pk']))
else:
form = ImageUploadModelForm(request.POST, request.FILES)
if form.is_valid():
# If an image id was in the form, we update the existing image
form.save()
return redirect(request.META['HTTP_REFERER'])
else:
context = self.get_context_dict(request)
context.update({"form":form})
return redirect("composer_modal_image", branding=branding)
class MetadataComposerModalImageLibrary(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_modal_image_library.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerModalImageLibrary, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
context = self.get_context_dict(request)
context.update({"image_results":get_images(1)})
return self.render_to_response(context)
class MetadataComposerRemoveImage(View):
@method_decorator(login_required)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
image_pk = request.GET.get("image") or None
if image_pk:
image = get_object_or_404(Image, pk=image_pk)
image.delete()
return redirect(request.META['HTTP_REFERER'])
class MetadataComposerRemoveContent(View):
@method_decorator(login_required)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
delete_content(request)
return redirect(request.META['HTTP_REFERER'])
class MetadataComposerRemoveProject(View):
@method_decorator(login_required)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
ldt_id = request.GET.get("ldt_id") or None
if ldt_id:
proj = get_object_or_404(Project, ldt_id=ldt_id)
if check_object_perm_for_user(proj, "change_project", request.user):
proj.delete()
return redirect(request.META['HTTP_REFERER'])
class MetadataComposerImage(View):
def get(self, request, branding="iri", image_pk=None, **kwargs):
self.branding = branding
image_data = None
if image_pk:
image = get_object_or_404(Image, pk=image_pk)
width = request.GET.get("width") or None
height = request.GET.get("height") or None
maxwidth = request.GET.get("maxwidth") or None
maxheight = request.GET.get("maxheight") or None
image_file = None
image_data = None
# Check w and h
if width:
try:
width = str(int(width))
except:
return HttpResponseBadRequest("width parameter must be integer.")
if height:
try:
height = str(int(height))
except:
return HttpResponseBadRequest("height parameter must be integer.")
if maxwidth:
try:
maxwidth = int(maxwidth)
except:
return HttpResponseBadRequest("maxwidth parameter must be integer.")
if maxheight:
try:
maxheight = int(maxheight)
except:
return HttpResponseBadRequest("maxheight parameter must be integer.")
if (maxwidth and not maxheight) or (not maxwidth and maxheight):
return HttpResponseBadRequest("maxwidth AND maxheight parameters must be set.")
if not width and not height and not maxwidth and not maxheight:
# No w and no h parameter : raw file 200px width
image_file = get_thumbnail(os.path.join(settings.MEDIA_ROOT, image.image_file.path), '200', crop='center', format='PNG', quality=99)
#image_data = open(os.path.join(settings.MEDIA_ROOT, image.image_file.path), "rb").read()
elif width and not height:
# W and no h parameter : thumbnail with fixed width
image_file = get_thumbnail(os.path.join(settings.MEDIA_ROOT, image.image_file.path), width, crop='center', format='PNG', quality=99)
elif not width and height:
# H and no w parameter : thumbnail with fixed height
image_file = get_thumbnail(os.path.join(settings.MEDIA_ROOT, image.image_file.path), 'x'+height, crop='center', format='PNG', quality=99)
elif width and height:
# H and no w parameter : thumbnail with fixed height
image_file = get_thumbnail(os.path.join(settings.MEDIA_ROOT, image.image_file.path), width+'x'+height, crop='center', format='PNG', quality=99)
elif maxwidth and maxheight:
# We compare wanted format with image's format and we resize W or H
if (float(image.image_file.width)/float(image.image_file.height)) > (float(maxwidth)/float(maxheight)):
# Image ratio > wanted ratio, we resize with fixed width
image_file = get_thumbnail(os.path.join(settings.MEDIA_ROOT, image.image_file.path), str(maxwidth), crop='center', format='PNG', quality=99)
else:
# Image ratio < wanted ratio, we resize with fixed height
image_file = get_thumbnail(os.path.join(settings.MEDIA_ROOT, image.image_file.path), 'x'+str(maxheight), crop='center', format='PNG', quality=99)
# We display directly the image file or, if asked, the <img> html tag
imgtag = request.GET.get("imgtag") or None
if imgtag:
imgtag = {'true': True, 'false': False, "0": False, "1": True}.get(imgtag.lower())
if imgtag:
return HttpResponse('<img src="' + image_file.url + '" />')
else:
if image_file:
image_data = image_file.read()
return HttpResponse(image_data, mimetype="image/png")
class MetadataComposerPlayer(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_player.html"
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerPlayer, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", ldt_id=None, **kwargs):
self.branding = branding
if not ldt_id:
return HttpResponseBadRequest("ldt_id parameter must be set.")
context = self.get_context_dict(request)
context.update({"ldt_id": ldt_id})
return self.render_to_response(context)
class MetadataComposerPreviewPlayer(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_preview_player.html"
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerPreviewPlayer, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", ldt_id=None, **kwargs):
self.branding = branding
if not ldt_id:
return HttpResponseBadRequest("ldt_id parameter must be set.")
context = self.get_context_dict(request)
context.update({"ldt_id": ldt_id})
return self.render_to_response(context)
class MetadataComposerEdit(TemplateResponseMixin, MetadataComposerContextView):
def get_template_names(self):
return "metadatacomposer_edit.html"
@method_decorator(login_required)
@method_decorator(never_cache)
def dispatch(self, *args, **kwargs):
return super(MetadataComposerEdit, self).dispatch(*args, **kwargs)
def get(self, request, branding="iri", ldt_id=None, **kwargs):
self.branding = branding
project = None
if not ldt_id:
return HttpResponseBadRequest("ldt_id parameter must be set.")
else:
project = get_object_or_404(Project.safe_objects, ldt_id=ldt_id)
if project:
if not check_object_perm_for_user(project, "change_project", request.user):
return HttpResponseBadRequest("Current user has no right to edit this project.")
context = self.get_context_dict(request)
context.update({"ldt_id": ldt_id, "project":project})
return self.render_to_response(context)
class MetadataComposerNewProject(View):
@method_decorator(login_required)
def get(self, request, branding="iri", iri_id=None, **kwargs):
self.branding = branding
# Get content and creator user
content = get_object_or_404(Content.safe_objects, iri_id=iri_id)
contents = [ content, ]
u = request.user
# Create project
project = Project.create_project(title="Project on " + content.title + " " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),
user=u, contents=contents,
description='',
set_icon=False)
# Set project state to "published" and save
assign('view_project', u, project)
assign('change_project', u, project)
project.publish()
# Since the project is published by default, we assign permission for the everyone group
#assign('ldt_utils.view_project', Group.objects.get(name=settings.PUBLIC_GROUP_NAME), project)
#assign('view_project', Group.objects.get(name=settings.PUBLIC_GROUP_NAME), project)
# Redirect to project edition in composer interface
return redirect('composer_edit', branding=branding, ldt_id=project.ldt_id)
class MetadataComposerDuplicateProject(View):
@method_decorator(login_required)
def get(self, request, branding="iri", **kwargs):
self.branding = branding
ldt_id = request.GET.get("ldt_id") or None
if ldt_id:
proj = get_object_or_404(Project, ldt_id=ldt_id)
u = request.user
# Create project
newproj = Project.create_project(title="Copy of " + proj.title,
user=u, contents=proj.contents.all(),
description=proj.description,
set_icon=False)
# Copy project (copies xml/ldt data and updates the xml with the good new ldt_id)
newproj = copy_ldt(proj, newproj, u)
# Save ldt content and set project state to "published" and save
newproj.state = 2
newproj.save()
assign('view_project', u, newproj)
assign('change_project', u, newproj)
# Since the project is published by default, we assign permission for the everyone group
assign('ldt_utils.view_project', Group.objects.get(name=settings.PUBLIC_GROUP_NAME), newproj)
return redirect("composer_project_list", branding=branding)