Repository: django-cms/django-filer

Issue:
remember last openened folder in file picker
especially with deeply nested folder structures it is annoying to select many files. remember the last opened folder.



Discussion:
+1


Resolving patch:
diff --git a/filer/admin/folderadmin.py b/filer/admin/folderadmin.py
--- a/filer/admin/folderadmin.py
+++ b/filer/admin/folderadmin.py
@@ -1,18 +1,17 @@
 #-*- coding: utf-8 -*-
 from django import forms
 from django import template
-from django.contrib import admin
 from django.contrib.admin import helpers
 from django.contrib.admin.util import quote, unquote, capfirst
 from django.template.defaultfilters import urlencode
 from filer.admin.patched.admin_utils import get_deleted_objects
 from django.core.exceptions import PermissionDenied
-from django.core.paginator import Paginator, InvalidPage, EmptyPage
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 from django.core.urlresolvers import reverse
 from django.db import router
 from django.db.models import Q
-from django.http import HttpResponseRedirect, Http404, HttpResponse
-from django.shortcuts import render_to_response
+from django.http import HttpResponseRedirect, HttpResponse
+from django.shortcuts import render_to_response, get_object_or_404
 from django.template import RequestContext
 from django.utils.encoding import force_unicode
 from django.utils.html import escape
@@ -163,8 +162,15 @@ def get_urls(self):
         url_patterns = patterns('',
             # we override the default list view with our own directory listing
             # of the root directories
-            url(r'^$', self.admin_site.admin_view(self.directory_listing),
+            url(r'^$',
+                self.admin_site.admin_view(self.directory_listing),
                 name='filer-directory_listing-root'),
+
+            url(r'^last/$',
+                self.admin_site.admin_view(self.directory_listing),
+                {'viewtype': 'last'},
+                name='filer-directory_listing-last'),
+
             url(r'^(?P<folder_id>\d+)/list/$',
                 self.admin_site.admin_view(self.directory_listing),
                 name='filer-directory_listing'),
@@ -175,10 +181,12 @@ def get_urls(self):
             url(r'^make_folder/$',
                 self.admin_site.admin_view(views.make_folder),
                 name='filer-directory_listing-make_root_folder'),
+
             url(r'^images_with_missing_data/$',
                 self.admin_site.admin_view(self.directory_listing),
                 {'viewtype': 'images_with_missing_data'},
                 name='filer-directory_listing-images_with_missing_data'),
+
             url(r'^unfiled_images/$',
                 self.admin_site.admin_view(self.directory_listing),
                 {'viewtype': 'unfiled_images'},
@@ -194,13 +202,21 @@ def directory_listing(self, request, folder_id=None, viewtype=None):
             folder = ImagesWithMissingData()
         elif viewtype == 'unfiled_images':
             folder = UnfiledImages()
+        elif viewtype == 'last':
+            last_folder_id = request.session.get('filer_last_folder_id')
+            try:
+                Folder.objects.get(id=last_folder_id)
+            except Folder.DoesNotExist:
+                url = reverse('admin:filer-directory_listing-root')
+            else:
+                url = reverse('admin:filer-directory_listing', kwargs={'folder_id': last_folder_id})
+                url = "%s%s%s" % (url, popup_param(request), selectfolder_param(request,"&"))
+            return HttpResponseRedirect(url)
         elif folder_id == None:
             folder = FolderRoot()
         else:
-            try:
-                folder = Folder.objects.get(id=folder_id)
-            except Folder.DoesNotExist:
-                raise Http404
+            folder = get_object_or_404(Folder, id=folder_id)
+        request.session['filer_last_folder_id'] = folder_id
 
         # Check actions to see if any are available on this changelist
         actions = self.get_actions(request)
@@ -295,12 +311,6 @@ def filter_file(qs, terms=[]):
         items = folder_children + folder_files
         paginator = Paginator(items, FILER_PAGINATE_BY)
 
-        # Make sure page request is an int. If not, deliver first page.
-        try:
-            page = int(request.GET.get('page', '1'))
-        except ValueError:
-            page = 1
-
         # Are we moving to clipboard?
         if request.method == 'POST' and '_save' not in request.POST:
             for f in folder_files:
@@ -347,8 +357,10 @@ def filter_file(qs, terms=[]):
 
         # If page request (9999) is out of range, deliver last page of results.
         try:
-            paginated_items = paginator.page(page)
-        except (EmptyPage, InvalidPage):
+            paginated_items = paginator.page(request.GET.get('page', 1))
+        except PageNotAnInteger:
+            paginated_items = paginator.page(1)
+        except EmptyPage:
             paginated_items = paginator.page(paginator.num_pages)
         return render_to_response(
             'admin/filer/folder/directory_listing.html',
diff --git a/filer/fields/file.py b/filer/fields/file.py
--- a/filer/fields/file.py
+++ b/filer/fields/file.py
@@ -39,7 +39,7 @@ def render(self, name, value, attrs=None):
                 if filer_settings.FILER_DEBUG:
                     raise e
         if not related_url:
-            related_url = reverse('admin:filer-directory_listing-root')
+            related_url = reverse('admin:filer-directory_listing-last')
         params = self.url_parameters()
         if params:
             lookup_url = '?' + '&amp;'.join(
diff --git a/filer/fields/folder.py b/filer/fields/folder.py
--- a/filer/fields/folder.py
+++ b/filer/fields/folder.py
@@ -35,7 +35,7 @@ def render(self, name, value, attrs=None):
             except Exception:
                 pass
         if not related_url:
-            related_url = reverse('admin:filer-directory_listing-root')
+            related_url = reverse('admin:filer-directory_listing-last')
         params = self.url_parameters()
         params['select_folder'] = 1
         if params:


Test patch:
diff --git a/filer/tests/admin.py b/filer/tests/admin.py
--- a/filer/tests/admin.py
+++ b/filer/tests/admin.py
@@ -19,8 +19,10 @@ class FilerFolderAdminUrlsTests(TestCase):
     def setUp(self):
         self.superuser = create_superuser()
         self.client.login(username='admin', password='secret')
+
     def tearDown(self):
         self.client.logout()
+
     def test_filer_app_index_get(self):
         response = self.client.get(reverse('admin:app_list', args=('filer',)))
         self.assertEqual(response.status_code, 200)
@@ -41,6 +43,20 @@ def test_filer_make_root_folder_post(self):
         #TODO: not sure why the status code is 200
         self.assertEqual(response.status_code, 200)
 
+    def test_filer_remember_last_opened_directory(self):
+        folder = Folder.objects.create(name='remember me please')
+
+        get_last_folder = lambda: self.client.get(reverse('admin:filer-directory_listing-last'), follow=True)
+
+        self.client.get(reverse('admin:filer-directory_listing', kwargs={'folder_id': folder.id}))
+        self.assertEqual(int(self.client.session['filer_last_folder_id']), folder.id)
+
+        self.assertEqual(get_last_folder().context['folder'], folder)
+
+        # let's test fallback
+        folder.delete()
+        self.assertTrue(isinstance(get_last_folder().context['folder'], FolderRoot))
+
     def test_filer_directory_listing_root_empty_get(self):
         response = self.client.post(reverse('admin:filer-directory_listing-root'))
         self.assertEqual(response.status_code, 200)
@@ -330,4 +346,4 @@ def test_render_add_view(self):
         Really stupid and simple test to see if the add Permission view can be rendered
         """
         response = self.client.get(reverse('admin:filer_folderpermission_add'))
-        self.assertEqual(response.status_code, 200)
\ No newline at end of file
+        self.assertEqual(response.status_code, 200)