Source code for shoop.admin.modules.media.views

# -*- coding: utf-8 -*-
# This file is part of Shoop.
#
# Copyright (c) 2012-2016, Shoop Ltd. All rights reserved.
#
# This source code is licensed under the AGPLv3 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals

import json

from django.core.exceptions import ObjectDoesNotExist
from django.db import IntegrityError
from django.http.response import JsonResponse
from django.utils.encoding import force_text
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy as _l
from django.views.generic import TemplateView
from filer.models import File, Folder
from filer.models.imagemodels import Image
from mptt.utils import get_cached_trees

from shoop.admin.modules.media.utils import delete_folder
from shoop.utils.excs import Problem
from shoop.utils.filer import filer_file_from_upload, filer_image_from_upload


def _filer_file_to_json_dict(file):
    """
    :type file: filer.models.File
    :rtype: dict
    """
    try:
        thumbnail = file.easy_thumbnails_thumbnailer.get_thumbnail({
            'size': (128, 128),
            'crop': True,
            'upscale': True,
            'subject_location': file.subject_location
        })
    except Exception:
        thumbnail = None
    return {
        "id": file.id,
        "name": file.label,
        "size": file.size,
        "url": file.url,
        "thumbnail": (thumbnail.url if thumbnail else None),
        "date": file.uploaded_at.isoformat()
    }


def _filer_folder_to_json_dict(folder, children=None):
    """
    :type file: filer.models.Folder
    :rtype: dict
    """
    if folder and children is None:
        # This allows us to pass `None` as a pseudo root folder
        children = folder.get_children()
    return {
        "id": folder.pk if folder else 0,
        "name": folder.name if folder else _("Root"),
        "children": [_filer_folder_to_json_dict(child) for child in children]
    }


[docs]def get_folder_name(folder): return (folder.name if folder else _("Root"))
[docs]class MediaBrowserView(TemplateView): """ A view for browsing media. Most of this is just a JSON API that the Javascript (`static_src/media/browser`) uses. """ template_name = "shoop/admin/media/browser.jinja" title = _l(u"Browse Media")
[docs] def get_context_data(self, **kwargs): context = super(MediaBrowserView, self).get_context_data(**kwargs) context["browser_config"] = { "filter": self.filter } return context
[docs] def get(self, request, *args, **kwargs): self.filter = request.REQUEST.get("filter") action = request.REQUEST.get("action") handler = getattr(self, "handle_get_%s" % action, None) if handler: return handler(request.REQUEST) return super(MediaBrowserView, self).get(request, *args, **kwargs)
[docs] def post(self, request, *args, **kwargs): if request.REQUEST.get("action") == "upload": return self.handle_upload() # Instead of normal POST variables, the Mithril `m.request()` # method passes data as a JSON payload (which is a good idea, # as it allows shedding the legacy of form data), so we need # to parse that. data = json.loads(request.body.decode("utf-8")) action = data.get("action") handler = getattr(self, "handle_post_%s" % action, None) if handler: try: return handler(data) except ObjectDoesNotExist as odne: return JsonResponse({"error": force_text(odne)}) except Problem as prob: return JsonResponse({"error": force_text(prob)}) else: return JsonResponse({"error": "unknown action %s" % action})
[docs] def handle_get_folders(self, data): root_folders = get_cached_trees(Folder._tree_manager.all()) return JsonResponse({"rootFolder": _filer_folder_to_json_dict(None, root_folders)})
[docs] def handle_post_new_folder(self, data): parent_id = int(data.get("parent", 0)) if parent_id > 0: parent = Folder.objects.get(pk=parent_id) else: parent = None name = data["name"] folder = Folder.objects.create(name=name) if parent: folder.move_to(parent, "last-child") folder.save() return JsonResponse({"success": True, "folder": _filer_folder_to_json_dict(folder, ())})
[docs] def handle_get_folder(self, data): try: folder_id = int(data.get("id", 0)) if folder_id: folder = Folder.objects.get(pk=folder_id) subfolders = folder.get_children() files = folder.files else: folder = None subfolders = Folder.objects.filter(parent=None) files = File.objects.filter(folder=None) except ObjectDoesNotExist: return JsonResponse({ "folder": None, "error": "Folder does not exist" }) if self.filter == "images": files = files.instance_of(Image) return JsonResponse({"folder": { "id": folder.id if folder else 0, "name": get_folder_name(folder), "files": [_filer_file_to_json_dict(file) for file in files], "folders": [ # Explicitly pass empty list of children to avoid recursion _filer_folder_to_json_dict(subfolder, children=()) for subfolder in subfolders.order_by("name") ] }})
[docs] def handle_upload(self): request = self.request try: folder_id = int(request.REQUEST.get("folder_id", 0)) if folder_id != 0: folder = Folder.objects.get(pk=folder_id) else: folder = None # Root folder upload. How bold! except Exception as exc: return JsonResponse({"error": "Invalid folder: %s" % force_text(exc)}) try: upload_file = request.FILES["file"] if upload_file.content_type.startswith("image/"): filer_file = filer_image_from_upload(request, path=folder, upload_data=upload_file) else: filer_file = filer_file_from_upload(request, path=folder, upload_data=upload_file) except Exception as exc: return JsonResponse({"error": force_text(exc)}) return JsonResponse({ "file": _filer_file_to_json_dict(filer_file), "message": _("%(file)s uploaded to %(folder)s") % { "file": filer_file.label, "folder": get_folder_name(folder) } })
[docs] def handle_post_rename_folder(self, data): folder = Folder.objects.get(pk=data["id"]) folder.name = data["name"] folder.save(update_fields=("name",)) return JsonResponse({"success": True, "message": _("Folder renamed.")})
[docs] def handle_post_delete_folder(self, data): folder = Folder.objects.get(pk=data["id"]) new_selected_folder_id = folder.parent_id message = delete_folder(folder) return JsonResponse({"success": True, "message": message, "newFolderId": new_selected_folder_id})
[docs] def handle_post_rename_file(self, data): file = File.objects.get(pk=data["id"]) file.name = data["name"] file.save(update_fields=("name",)) return JsonResponse({"success": True, "message": _("File renamed.")})
[docs] def handle_post_delete_file(self, data): file = File.objects.get(pk=data["id"]) try: file.delete() except IntegrityError as ie: raise Problem(str(ie)) return JsonResponse({"success": True, "message": _("File deleted.")})
[docs] def handle_post_move_file(self, data): file = File.objects.get(pk=data["file_id"]) folder_id = int(data["folder_id"]) if folder_id: folder = Folder.objects.get(pk=data["folder_id"]) else: folder = None old_folder = file.folder file.folder = folder file.save(update_fields=("folder",)) return JsonResponse({ "success": True, "message": _("%(file)s moved from %(old)s to %(new)s.") % { "file": file, "old": get_folder_name(old_folder), "new": get_folder_name(folder) } })