Commits

Mikhail Korobov committed be7996e

AlbumSite is refactored according to changes in PluggableSite. It is now possible to attach AlbumSite to objects with non-trivial urls. No documentation yet.

  • Participants
  • Parent commits a155a11

Comments (0)

Files changed (3)

File photo_albums/test_utils.py

     
 '''
 
-from django.core.urlresolvers import reverse
+from django.core.urlresolvers import reverse, NoReverseMatch
 from generic_utils.test_helpers import ViewTest
 from generic_images.models import AttachedImage
 
     album_for_id = None
     " object id (or slug) for which album is attached to "
     
+    album_for_kwargs = None
+    "object url resolver kwargs (for more complex object urls)"    
+    
     non_existing_object_id = 0
     
+    non_existing_object_kwargs = None
+    
     image2_in_album_id = None    
     " "
     
         permission checks
     """
     
-    non_existing_image_id = 0            
+    non_existing_image_id = 0
+    
+    def __init__(self, *args, **kwargs):
+        if (self.album_for_id is not None) and (self.album_for_kwargs is not None):
+            raise ValueError('Ambiguity between album_for_id and '
+                             'album_for_kwargs. Please remove one of these parameters.')
+            
+        if self.non_existing_object_kwargs is None: 
+            self.non_existing_object_kwargs = {'object_id':self.non_existing_object_id}
+            
+        super(AlbumTest, self).__init__(*args, **kwargs)
+        
+        
     
     def check(self, view, status, kwargs=None):
         if not kwargs:
             kwargs = {}
         if view not in self.excluded_views:            
-            if not 'object_id' in kwargs:
-                kwargs['object_id'] = self.album_for_id
             name = '%s:%s' % (self.album_site.instance_name, view,)
+            if self.album_for_id is not None:                
+                if not 'object_id' in kwargs:
+                    kwargs['object_id'] = self.album_for_id
+            else:
+                if kwargs != self.non_existing_object_kwargs:
+                    kwargs.update(self.album_for_kwargs)
             return self.check_url(name, status, kwargs=kwargs, current_app=self.album_site.app_name)                
                 
     def test_public_views(self):
         self.check('show_album', 200)
-        self.check('show_album', 404, kwargs={'object_id':self.non_existing_object_id})
+        
+        try:
+            self.check('show_album', 404, kwargs=self.non_existing_object_kwargs)
+        except NoReverseMatch: # non_existing_object_kwargs is needed but not specified, 
+            pass               # don't want to force all developers to add this just for one small test
 
         self.check('show_image', 200, kwargs={'image_id': self.image_in_album_id})
         self.check('show_image', 404, kwargs={'image_id': self.image_in_other_album_id})

File photo_albums/urls.py

     :func:`~photo_albums.views.upload_zip` view. 
         
     '''        
-                    
-    def __init__(self, instance_name, queryset, app_name='album', 
-                 object_regex = r'\d+', lookup_field = 'pk',                 
-                 extra_context=None, template_object_name = 'object',
+    def __init__(self, 
+                 instance_name, 
+                 app_name = 'album',
+                 queryset = None,
+                 object_regex = None,
+                 lookup_field = None,
+                 extra_context=None, 
+                 template_object_name = 'object',
                  has_edit_permission = lambda request, obj: True,
-                 context_processors=None,
+                 context_processors = None, 
+                 object_getter = None,
                  edit_form_class = ImageEditForm,
                  upload_form_class = AttachedImageForm,
                  upload_formset_class = PhotoFormSet,
-                 upload_zip_form_class = UploadZipAlbumForm):
+                 upload_zip_form_class = UploadZipAlbumForm
+                ):
+                            
         self.edit_form_class = edit_form_class
         self.upload_form_class = upload_form_class
         self.upload_formset_class = upload_formset_class
         self.upload_zip_form_class = upload_zip_form_class
             
-        super(PhotoAlbumSite, self).__init__(instance_name, queryset, app_name, 
-                                             object_regex, lookup_field,                                             
+        super(PhotoAlbumSite, self).__init__(instance_name, app_name, queryset,
+                                             object_regex, lookup_field,
                                              extra_context, template_object_name,
-                                             has_edit_permission, context_processors)
+                                             has_edit_permission, context_processors, 
+                                             object_getter)
                 
     def patterns(self):
         return patterns('photo_albums.views',
                             name = 'show_album',
                         ),
                         url(
-                            self.make_regex(r'/edit'),
+                            self.make_regex(r'/edit/'),
                             'edit_album', 
                             {'album_site': self},
                             name = 'edit_album',
                             name = 'show_image',
                         ),
                         url(
-                            self.make_regex(r'/(?P<image_id>\d+)/edit'),
+                            self.make_regex(r'/(?P<image_id>\d+)/edit/'),
                             'edit_image',
                             {'album_site': self},
                             name = 'edit_image',
                         ),
                         url(
-                            self.make_regex(r'/(?P<image_id>\d+)/delete'),
+                            self.make_regex(r'/(?P<image_id>\d+)/delete/'),
                             'delete_image',
                             {'album_site': self},
                             name = 'delete_image',
                         ),
                         url(
-                            self.make_regex(r'/(?P<image_id>\d+)/set-as-main'),
+                            self.make_regex(r'/(?P<image_id>\d+)/set-as-main/'),
                             'set_as_main_image',
                             {'album_site': self},
                             name = 'set_as_main_image',
                         ),
                         url(
-                            self.make_regex(r'/(?P<image_id>\d+)/clear-main'),
+                            self.make_regex(r'/(?P<image_id>\d+)/clear-main/'),
                             'clear_main_image',
                             {'album_site': self},
                             name = 'clear_main_image',

File photo_albums/views.py

 Views used by PhotoAlbumSite. 
 '''
 
-from django.conf import settings
 from django.core.urlresolvers import reverse
 from django.http import HttpResponseRedirect, Http404
 from django.shortcuts import render_to_response, get_object_or_404
 from django.template import RequestContext
-from django.contrib.auth import authenticate, login, logout
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.models import User
-from django.views.generic.create_update import create_object, delete_object, update_object
+from django.views.generic.create_update import delete_object
 from django.utils import simplejson
 from django.core.paginator import Paginator
-from django.contrib.contenttypes.models import ContentType
 
 from annoying.decorators import ajax_request
 from annoying.utils import HttpResponseReload
 
-from photo_albums.forms import PhotoFormSet, UploadZipAlbumForm
-from generic_images.forms import AttachedImageForm
 from generic_images.models import AttachedImage
 from generic_utils import get_template_search_list
+from generic_utils.app_utils import get_site_decorator
 
+# decorator for AlbumSite views
+album_site_method = get_site_decorator('album_site')
 
+# a couple of functions to make templates rendering easier
 def _get_template_names(object, template_name):
     return get_template_search_list('albums', object, template_name)
-     
 
-def show_album(request, object_id, album_site, template_name='show_album.html'):
+def _render(template, obj, context):    
+    template_variants = _get_template_names(obj, template) 
+    return render_to_response(template_variants, context_instance=context)
+            
+
+#==============================================================================
+
+@album_site_method(template_name='show_album.html')
+def show_album(request, obj, album_site, context, template_name):
     ''' Show album for object using show_album.html template '''
-        
-    object, context = album_site.get_object_and_context(object_id)
+                
+    images = AttachedImage.objects.for_model(obj)
+    context.update({'images': images})    
     
-    images = AttachedImage.objects.for_model(object)
-    context.update({'images': images})
-    
-    return render_to_response(_get_template_names(object, template_name), 
-                              context,
-                              context_instance=RequestContext(request, processors=album_site.context_processors),
-                              )
+    return _render(template_name, obj, context)
+
     
 
 @login_required
-def edit_album(request, object_id, album_site, template_name='edit_album.html'):
+@album_site_method(template_name='edit_album.html')
+def edit_album(request, obj, album_site, context, template_name):
     ''' Show album for object using edit_album.html template, with permission checks. '''
     
-    object, context = album_site.get_object_and_context(object_id)
-    album_site.check_permissions(request, object)
+    album_site.check_permissions(request, obj)
     
-    images = AttachedImage.objects.for_model(object)
+    images = AttachedImage.objects.for_model(obj)
     context.update({'images': images})
-        
-    return render_to_response(_get_template_names(object, template_name), 
-                              context,
-                              context_instance=RequestContext(request, processors=album_site.context_processors),
-                              )
+    
+    return _render(template_name, obj, context)
     
     
 @login_required
-def upload_main_image(request, object_id, album_site):    
+@album_site_method()
+def upload_main_image(request, obj, album_site, context):    
     ''' Upload 1 image and make it main image in gallery '''
     
-    object, context = album_site.get_object_and_context(object_id)
-    album_site.check_permissions(request, object)
-    
-    success_url = album_site.reverse('show_album', args=[object_id])
+    album_site.check_permissions(request, obj)    
+    success_url = '../' #album_site.reverse('show_album', args=[object_id])
     
     if request.method == 'POST':
         form = album_site.upload_form_class(request.POST, request.FILES)
         if form.is_valid():
-            photo = form.save(commit=False)
+            photo = form.save(commit=False)     #TODO: move logic to form
             photo.user = request.user
-            photo.content_object = object
+            photo.content_object = obj
             photo.is_main = True
             photo.save()
             return HttpResponseRedirect(success_url) # Redirect after POST
         form = album_site.upload_form_class()        
 
     context.update({'form': form})
+    
+    return _render('upload_main_image.html', obj, context)
 
-    return render_to_response(
-                                _get_template_names(object, 'upload_main_image.html'),
-                                context,
-                                context_instance=RequestContext(request, processors=album_site.context_processors),
-                             )
 
 @login_required
-def upload_zip(request, object_id, album_site):
+@album_site_method()
+def upload_zip(request, obj, album_site, context):
     ''' Upload zip archive with images, extract them, check if they are correct 
         and attach to object. Redirect to ``show_album`` view on success.
-    '''
-    
-    obj, context = album_site.get_object_and_context(object_id)
+    '''    
     album_site.check_permissions(request, obj)
     
     form_class = album_site.upload_zip_form_class    
         form = form_class(request.user, obj, request.POST, request.FILES)
         if form.is_valid():
             form.process_zip_file()
-            success_url = album_site.reverse('show_album', args=[object_id])
+            success_url = '../' #album_site.reverse('show_album', args=[object_id])
             return HttpResponseRedirect(success_url)        
     else:
         form = form_class(request.user, obj)
         
     context.update({'form': form})
-        
-    return render_to_response(
-                                _get_template_names(obj, 'upload_zip.html'),
-                                context,
-                                context_instance=RequestContext(request, processors=album_site.context_processors),
-                             )
+    
+    return _render('upload_zip.html', obj, context)        
 
 @login_required
-def upload_images(request, object_id, album_site):    
+@album_site_method()
+def upload_images(request, obj, album_site, context):
     ''' Upload several images at once '''
     
-    object, context = album_site.get_object_and_context(object_id)
-    album_site.check_permissions(request, object)
+    album_site.check_permissions(request, obj)
     
-    success_url = album_site.reverse('show_album', args=[object_id])
+    success_url = '../' # album_site.reverse('show_album', args=[object_id])
+    FormsetCls = album_site.upload_formset_class
     
     if request.method == 'POST':
-        formset = album_site.upload_formset_class(request.POST, request.FILES, queryset = AttachedImage.objects.none())
+        formset = FormsetCls(request.POST, 
+                             request.FILES, 
+                             queryset = AttachedImage.objects.none())
         if formset.is_valid():
             instances = formset.save(commit=False)
             for photo in instances:
                 photo.user = request.user
-                photo.content_object = object
+                photo.content_object = obj
                 photo.save()
             return HttpResponseRedirect(success_url) # Redirect after POST
     else:
-        formset = album_site.upload_formset_class(queryset = AttachedImage.objects.none())        
+        formset = FormsetCls(queryset = AttachedImage.objects.none())        
 
     context.update({'formset': formset})
     
-    return render_to_response(_get_template_names(object, 'upload_images.html'), 
-                              context, 
-                              context_instance=RequestContext(request, processors=album_site.context_processors))
+    return _render('upload_images.html', obj, context)
 
 
-
-def _one_image_context(image_id, object):
-    album = AttachedImage.objects.for_model(object) 
+def _one_image_context(image_id, obj):
+    album = AttachedImage.objects.for_model(obj) 
     image = get_object_or_404(album, id=image_id)    
 
     next_id = getattr(image.next(), 'id', None)
     return {'image': image, 'prev': prev_id, 'next': next_id}
 
 
-def show_image(request, object_id, image_id, album_site):
-    '''  Show one image '''
-    
-    object, context = album_site.get_object_and_context(object_id)        
-    context.update(_one_image_context(image_id, object))
-
-    return render_to_response(_get_template_names(object, 'show_image.html'), context, 
-                              context_instance=RequestContext(request, processors=album_site.context_processors))
+@album_site_method(image_id=None)
+def show_image(request, obj, album_site, context, image_id):
+    '''  Show one image '''    
+    context.update(_one_image_context(image_id, obj))    
+    return _render('show_image.html', obj, context)
 
 
 @login_required
-def edit_image(request, object_id, image_id, album_site): 
+@album_site_method(image_id=None)
+def edit_image(request, obj, album_site, context, image_id):
     ''' Show one image. Checks permissions and provides edit form. '''   
     
-    object, context = album_site.get_object_and_context(object_id)
-    album_site.check_permissions(request, object)
-
-    context.update(_one_image_context(image_id, object))
-
+    album_site.check_permissions(request, obj)
+    context.update(_one_image_context(image_id, obj))
+    
+    FormCls = album_site.edit_form_class
+    
     if request.method == 'POST':
-        form = album_site.edit_form_class(request.POST, request.FILES, instance = context['image'])
+        form = FormCls(request.POST, request.FILES, instance = context['image'])
         if form.is_valid():
             form.save()
             return HttpResponseReload(request) # Redirect after POST
     else:
-        form = album_site.edit_form_class(instance = context['image'])
+        form = FormCls(instance = context['image'])
         
     context.update({'form': form})
-    
-    return render_to_response(_get_template_names(object, 'edit_image.html'), context, 
-                              context_instance=RequestContext(request, processors=album_site.context_processors))
-    
+
+    return _render('edit_image.html', obj, context)
+
 
 @login_required
-def delete_image(request, object_id, image_id, album_site):
+@album_site_method(image_id=None)
+def delete_image(request, obj, album_site, context, image_id):
     ''' Delete image if request method is POST, displays 
         ``confirm_delete.html`` template otherwise 
     '''
-    object, context = album_site.get_object_and_context(object_id)
-    album_site.check_permissions(request, object)
+    album_site.check_permissions(request, obj)
     
-    image = get_object_or_404(AttachedImage.objects.for_model(object), id=image_id)
-    next_url = album_site.reverse('show_album', args=[object_id])
+    image = get_object_or_404(AttachedImage.objects.for_model(obj), id=image_id)
+    next_url = '../../' #album_site.reverse('show_album', args=[object_id])
+    
+    plain_context = {}
+    for d in context:
+        plain_context.update(d)        
     
     return delete_object(request, 
                          model=AttachedImage, 
                          post_delete_redirect = next_url, 
                          object_id = image_id,
-                         extra_context = context, 
+                         extra_context = plain_context, 
                          context_processors=album_site.context_processors,
-                         template_name = _get_template_names(object, 'confirm_delete.html')[1])
-
+                         template_name = _get_template_names(obj, 'confirm_delete.html')[1])
 
     
 @login_required
-def set_as_main_image(request, object_id, image_id, album_site):
+@album_site_method(image_id=None)
+def set_as_main_image(request, obj, album_site, context, image_id):
     ''' Mark image as main and redirect to ``show_image`` view '''
-    object, context = album_site.get_object_and_context(object_id)
-    album_site.check_permissions(request, object)
+    album_site.check_permissions(request, obj)
     
-    image = get_object_or_404(AttachedImage.objects.for_model(object), id=image_id)
+    image = get_object_or_404(AttachedImage.objects.for_model(obj), id=image_id)
     image.is_main = True
     image.save()
     
-    next_url = album_site.reverse('show_image', args=[object_id, image_id])    
-    return HttpResponseRedirect(next_url)
+    return HttpResponseRedirect('../')
 
     
 @login_required
-def clear_main_image(request, object_id, image_id, album_site):
+@album_site_method(image_id=None)
+def clear_main_image(request, obj, album_site, context, image_id):
     ''' Mark image as not main and redirect to ``show_image`` view '''
-    object, context = album_site.get_object_and_context(object_id)
-    album_site.check_permissions(request, object)
+    album_site.check_permissions(request, obj)
 
-    image = AttachedImage.objects.get_main_for(object)
+    image = AttachedImage.objects.get_main_for(obj)
     if image:
         image.is_main = False
         image.save()
         
-    next_url = album_site.reverse('show_image', args=[object_id, image_id])    
-    return HttpResponseRedirect(next_url)
+    return HttpResponseRedirect('../')
 
 
 @login_required
 @ajax_request
-def set_image_order(request, object_id, album_site):
+@album_site_method()
+def set_image_order(request, obj, album_site, context):
     ''' Ajax view that can be used to implement image reorder
     functionality. Accepts json data in form:: 
     
             
     and assigns passed order to images with passed id's, with permission checks. 
     '''
-    object, context = album_site.get_object_and_context(object_id)
-    album_site.check_permissions(request, object)
+    album_site.check_permissions(request, obj)
     
     if request.is_ajax():        
         data_str = request.POST.get('items','')
             order = item['order']
             try:
                 #check that image belongs to proper object
-                image = AttachedImage.objects.for_model(object).get(id=image_id)
+                image = AttachedImage.objects.for_model(obj).get(id=image_id)
                 image.order = order
                 image.save()
             except AttachedImage.DoesNotExist: