add breadcrumbs to fileupload,
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Thu, 7 Mar 2013 12:11:39 +0000 (13:11 +0100)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Thu, 7 Mar 2013 12:11:39 +0000 (13:11 +0100)
basic support for browsing directories,
minor fixes.

12 files changed:
apps/apiclient/urls.py
apps/catalogue/urls.py
apps/catalogue/views.py
apps/cover/urls.py
apps/fileupload/forms.py
apps/fileupload/static/fileupload/css/bootstrap.min.css
apps/fileupload/static/fileupload/css/style.css
apps/fileupload/templates/fileupload/picture_form.html
apps/fileupload/urls.py
apps/fileupload/views.py
apps/wiki/urls.py
redakcja/urls.py

index 87d9997..55cc466 100755 (executable)
@@ -1,4 +1,4 @@
-from django.conf.urls.defaults import *
+from django.conf.urls import patterns, url
 
 urlpatterns = patterns('apiclient.views',
     url(r'^oauth/$', 'oauth', name='apiclient_oauth'),
 
 urlpatterns = patterns('apiclient.views',
     url(r'^oauth/$', 'oauth', name='apiclient_oauth'),
index feebb3e..e72b88d 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8
 # -*- coding: utf-8
-from django.conf.urls.defaults import *
+from django.conf.urls import patterns, url
 from django.contrib.auth.decorators import permission_required
 from django.views.generic import RedirectView
 from catalogue.feeds import PublishTrackFeed
 from django.contrib.auth.decorators import permission_required
 from django.views.generic import RedirectView
 from catalogue.feeds import PublishTrackFeed
index a397830..e09940d 100644 (file)
@@ -479,6 +479,12 @@ class GalleryView(UploadView):
     def get_object(self, request, slug):
         return get_object_or_404(Book, slug=slug)
 
     def get_object(self, request, slug):
         return get_object_or_404(Book, slug=slug)
 
+    def breadcrumbs(self):
+        return [
+            (_('books'), reverse('catalogue_document_list')),
+            (self.object.title, self.object.get_absolute_url()),
+            (_('scan gallery'),),
+        ]
+
     def get_directory(self):
         return "%s%s/" % (settings.IMAGE_DIR, self.object.gallery)
     def get_directory(self):
         return "%s%s/" % (settings.IMAGE_DIR, self.object.gallery)
-
index 2337d47..f1a48d3 100644 (file)
@@ -3,7 +3,7 @@
 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
 
 
 urlpatterns = patterns('cover.views',
 
 
 urlpatterns = patterns('cover.views',
index b29d318..f5e1069 100644 (file)
@@ -1,4 +1,4 @@
 from django import forms
 
 class UploadForm(forms.Form):
 from django import forms
 
 class UploadForm(forms.Form):
-    file  = forms.FileField()
+    files = forms.FileField()
index 4bb154d..9999524 100644 (file)
@@ -19,8 +19,6 @@ textarea{overflow:auto;vertical-align:top;}
 .clearfix:after{clear:both;}
 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}
 .input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}
 .clearfix:after{clear:both;}
 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}
 .input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}
-a{color:#0088cc;text-decoration:none;}
-a:hover{color:#005580;text-decoration:underline;}
 .row{margin-left:-20px;*zoom:1;}
 .row:before,.row:after{display:table;content:"";}
 .row:after{clear:both;}
 .row{margin-left:-20px;*zoom:1;}
 .row:before,.row:after{display:table;content:"";}
 .row:after{clear:both;}
index 3c9bfff..e45d81d 100644 (file)
@@ -1,3 +1,10 @@
 .preview img {
     max-height: 50px;
 }
 .preview img {
     max-height: 50px;
 }
+
+.delete button[data-type=""] {
+    display: none;
+}
+.delete button[data-type=""] + input {
+    display: none;
+}
index 52ac3cc..ce23179 100644 (file)
 
 {% block content %}
 
 
 {% block content %}
 
-<h1>{% trans "Gallery for:" %} <a href="{{ view.object.get_absolute_url }}">{{ view.object }}</a></h1>
-
+<h1>
+{% trans "Browse:" %}
+{% for crumb in view.breadcrumbs %}
+    {% if crumb.1 %}
+        <a href="{{ crumb.1 }}">{{ crumb.0 }}</a>
+    {% else %}
+        {{ crumb.0 }}
+    {% endif %}
+    {% if not forloop.last %}/{% endif %}
+{% endfor %}
+</h1>
 
 
     <form id="fileupload" method="post" action="." enctype="multipart/form-data">{% csrf_token %}
 
 
     <form id="fileupload" method="post" action="." enctype="multipart/form-data">{% csrf_token %}
@@ -24,7 +33,7 @@
                 <span class="btn btn-success fileinput-button">
                     <i class="icon-plus icon-white"></i>
                     <span>{% trans "Add files..." %}</span>
                 <span class="btn btn-success fileinput-button">
                     <i class="icon-plus icon-white"></i>
                     <span>{% trans "Add files..." %}</span>
-                    <input type="file" multiple="" name="files[]">
+                    <input type="file" multiple="" name="files">
                 </span>
                 <button class="btn btn-primary start" type="submit">
                     <i class="icon-upload icon-white"></i>
                 </span>
                 <button class="btn btn-primary start" type="submit">
                     <i class="icon-upload icon-white"></i>
index 290a4cf..cd4f46c 100644 (file)
@@ -1,7 +1,7 @@
-from django.conf.urls.defaults import *
+from django.conf.urls import patterns, url
 from fileupload.views import UploadView
 
 urlpatterns = patterns('',
 from fileupload.views import UploadView
 
 urlpatterns = patterns('',
-    (r'^(?P<path>.+)$', UploadView.as_view(), {}, 'upload'),
+    url(r'^(?P<path>(?:.*/)?)$', UploadView.as_view(), name='fileupload'),
 )
 
 )
 
index 217a78b..9425515 100644 (file)
@@ -1,9 +1,27 @@
 import json
 import os
 import json
 import os
-from .forms import UploadForm
-from django.views.generic import FormView, View
-from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
+from urllib import quote
 from django.conf import settings
 from django.conf import settings
+from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
+from django.utils.decorators import method_decorator
+from django.views.decorators.vary import vary_on_headers
+from django.views.generic import FormView, View
+from .forms import UploadForm
+
+
+# Use sorl.thumbnail if available.
+try:
+    from sorl.thumbnail import default
+except ImportError:
+    def thumbnail(relpath):
+        return settings.MEDIA_URL + relpath
+else:
+    def thumbnail(relpath):
+        try:
+            return default.backend.get_thumbnail(relpath, "x50").url
+        except IOError:
+            # That's not an image. No thumb.
+            return None
 
 
 class JSONResponse(HttpResponse):
 
 
 class JSONResponse(HttpResponse):
@@ -12,11 +30,50 @@ class JSONResponse(HttpResponse):
         content = json.dumps(obj)
         super(JSONResponse, self).__init__(content, mimetype, *args, **kwargs)
 
         content = json.dumps(obj)
         super(JSONResponse, self).__init__(content, mimetype, *args, **kwargs)
 
+
 class UploadView(FormView):
     template_name = "fileupload/picture_form.html"
     form_class = UploadForm
 
 class UploadView(FormView):
     template_name = "fileupload/picture_form.html"
     form_class = UploadForm
 
+    def get_object(self, request, *args, **kwargs):
+        """Get any data for later use."""
+        return None
+
+    def get_directory(self):
+        """Directory relative to MEDIA_ROOT. Must end with a slash."""
+        return self.kwargs['path']
+
+    def breadcrumbs(self):
+        """List of tuples (name, url) or just (name,) for breadcrumbs.
+
+        Probably only the last item (representing currently browsed dir)
+        should lack url.
+
+        """
+        directory = self.get_directory()
+        now_path = os.path.dirname(self.request.get_full_path())
+        directory = os.path.dirname(directory)
+        if directory:
+            crumbs = [
+                (os.path.basename(directory),)
+            ]
+            directory = os.path.dirname(directory)
+            now_path = (os.path.dirname(now_path))
+            while directory:
+                crumbs.insert(0, (os.path.basename(directory), now_path+'/'))
+                directory = os.path.dirname(directory)
+                now_path = os.path.dirname(now_path)
+            crumbs.insert(0, ('media', now_path))
+        else:
+            crumbs = [('media',)]
+        return crumbs
+
     def get_safe_path(self, filename=""):
     def get_safe_path(self, filename=""):
+        """Finds absolute filesystem path of the browsed dir of file.
+        
+        Makes sure it's inside MEDIA_ROOT.
+        
+        """
         path = os.path.abspath(os.path.join(
                 settings.MEDIA_ROOT,
                 self.get_directory(),
         path = os.path.abspath(os.path.join(
                 settings.MEDIA_ROOT,
                 self.get_directory(),
@@ -28,9 +85,11 @@ class UploadView(FormView):
                 raise Http404
         return path
 
                 raise Http404
         return path
 
-    def get_url(self, filename=""):
-        return settings.MEDIA_URL + self.get_directory() + filename
+    def get_url(self, filename):
+        """Finds URL of a file in browsed dir."""
+        return settings.MEDIA_URL + self.get_directory() + quote(filename.encode('utf-8'))
 
 
+    @method_decorator(vary_on_headers('Accept'))
     def dispatch(self, request, *args, **kwargs):
         self.object = self.get_object(request, *args, **kwargs)
         return super(UploadView, self).dispatch(request, *args, **kwargs)
     def dispatch(self, request, *args, **kwargs):
         self.object = self.get_object(request, *args, **kwargs)
         return super(UploadView, self).dispatch(request, *args, **kwargs)
@@ -38,37 +97,50 @@ class UploadView(FormView):
     def get(self, request, *args, **kwargs):
         if request.is_ajax():
             files = []
     def get(self, request, *args, **kwargs):
         if request.is_ajax():
             files = []
-            
             path = self.get_safe_path()
             if os.path.isdir(path):
                 for f in os.listdir(path):
             path = self.get_safe_path()
             if os.path.isdir(path):
                 for f in os.listdir(path):
-                    files.append({
+                    file_info = {
                         "name": f,
                         "name": f,
-                        "url": self.get_url(f),
-                        'thumbnail_url': self.get_url(f), # FIXME: thumb!
-                        'delete_url': "%s?file=%s" % (request.get_full_path(), f), # FIXME: encode
-                        'delete_type': "DELETE"
-                    })
+                    }
+                    if os.path.isdir(os.path.join(path, f)):
+                        file_info.update({
+                            "url": "%s%s/" % (request.get_full_path(), f),
+                        })
+                    else:
+                        file_info.update({
+                            "url": self.get_url(f),
+                            'thumbnail_url': thumbnail(self.get_directory() + f),
+                            'delete_url': "%s?file=%s" % (
+                                request.get_full_path(),
+                                quote(f.encode('utf-8'))),
+                            'delete_type': "DELETE"
+                        })
+                        thumbnail_url = thumbnail(self.get_directory() + f),
+                    files.append(file_info)
             return JSONResponse(files)
         else:
             return super(UploadView, self).get(request, *args, **kwargs)
 
     def form_valid(self, form):
             return JSONResponse(files)
         else:
             return super(UploadView, self).get(request, *args, **kwargs)
 
     def form_valid(self, form):
-        f = self.request.FILES.get('file')
+        flist = self.request.FILES.getlist('files')
         path = self.get_safe_path()
         path = self.get_safe_path()
-        
         if not os.path.isdir(path):
             os.makedirs(path)
         if not os.path.isdir(path):
             os.makedirs(path)
-        with open(self.get_safe_path(f.name), 'w') as destination:
-            for chunk in f.chunks():
-                destination.write(chunk)
-        data = [{
-            'name': f.name, 
-            'url': self.get_url(f.name),
-            'thumbnail_url': self.get_url(f.name), # FIXME: thumb!
-            'delete_url': "%s?file=%s" % (self.request.get_full_path(), f.name), # FIXME: encode
-            'delete_type': "DELETE"
-        }]
+        data = []
+        for f in flist:
+            with open(self.get_safe_path(f.name), 'w') as destination:
+                for chunk in f.chunks():
+                    destination.write(chunk)
+            data.append({
+                'name': f.name, 
+                'url': self.get_url(f.name),
+                'thumbnail_url': thumbnail(self.get_directory() + f.name),
+                        'delete_url': "%s?file=%s" % (
+                            request.get_full_path(),
+                            quote(f.name.encode('utf-8'))),
+                'delete_type': "DELETE"
+            })
         response = JSONResponse(data)
         response['Content-Disposition'] = 'inline; filename=files.json'
         return response
         response = JSONResponse(data)
         response['Content-Disposition'] = 'inline; filename=files.json'
         return response
index 211bb3a..0c73aed 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8
 # -*- coding: utf-8
-from django.conf.urls.defaults import *
+from django.conf.urls import patterns, url
 
 
 urlpatterns = patterns('wiki.views',
 
 
 urlpatterns = patterns('wiki.views',
index d25312d..17fa1bb 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
 # -*- coding: utf-8 -*-
 
-from django.conf.urls.defaults import *
+from django.conf.urls import include, patterns, url
 from django.contrib import admin
 from django.conf import settings
 from django.conf.urls.static import static
 from django.contrib import admin
 from django.conf import settings
 from django.conf.urls.static import static