diff --git a/pinry/core/api.py b/pinry/core/api.py index c516538..56a4b21 100644 --- a/pinry/core/api.py +++ b/pinry/core/api.py @@ -59,7 +59,7 @@ class UserResource(ModelResource): def filter_generator_for(size): def wrapped_func(bundle, **kwargs): - return Thumbnail.objects.get_or_create_at_size(bundle.obj.pk, size, **kwargs) + return bundle.obj.get_by_size(size) return wrapped_func diff --git a/pinry/core/models.py b/pinry/core/models.py index 9b6f85f..68d39cc 100644 --- a/pinry/core/models.py +++ b/pinry/core/models.py @@ -1,10 +1,11 @@ import requests from cStringIO import StringIO +from django.conf import settings from django.core.files.uploadedfile import InMemoryUploadedFile -from django.db import models +from django.db import models, transaction -from django_images.models import Image as BaseImage +from django_images.models import Image as BaseImage, Thumbnail from taggit.managers import TaggableManager from ..users.models import User @@ -19,7 +20,13 @@ class ImageManager(models.Manager): buf.write(response.content) obj = InMemoryUploadedFile(buf, 'image', file_name, None, buf.tell(), None) - return Image.objects.create(image=obj) + # create the image and its thumbnails in one transaction, removing + # a chance of getting Database into a inconsistent state when we + # try to create thumbnails one by one later + image = self.create(image=obj) + for size in settings.IMAGE_SIZES.keys(): + Thumbnail.objects.get_or_create_at_size(image.pk, size) + return image class Image(BaseImage): diff --git a/pinry/core/tests/helpers.py b/pinry/core/tests/helpers.py index ce4e6fd..67435ef 100644 --- a/pinry/core/tests/helpers.py +++ b/pinry/core/tests/helpers.py @@ -3,6 +3,7 @@ from django.contrib.auth.models import Permission from django.core.files.images import ImageFile from django.db.models.query import QuerySet from django.test import TestCase +from django_images.models import Thumbnail import factory from taggit.models import Tag @@ -33,8 +34,15 @@ class TagFactory(factory.Factory): class ImageFactory(factory.Factory): + FACTORY_FOR = Image + image = factory.LazyAttribute(lambda a: ImageFile(open(TEST_IMAGE_PATH, 'rb'))) + @factory.post_generation() + def create_thumbnails(self, create, extracted, **kwargs): + for size in settings.IMAGE_SIZES.keys(): + Thumbnail.objects.get_or_create_at_size(self.pk, size) + class PinFactory(factory.Factory): submitter = factory.SubFactory(UserFactory) diff --git a/pinry/core/views.py b/pinry/core/views.py index 5b57c4b..8192705 100644 --- a/pinry/core/views.py +++ b/pinry/core/views.py @@ -1,9 +1,11 @@ from django.http import HttpResponseRedirect +from django.conf import settings from django.core.urlresolvers import reverse from django.views.generic import CreateView from django_images.models import Image from braces.views import JSONResponseMixin, LoginRequiredMixin +from django_images.models import Thumbnail from .forms import ImageForm @@ -20,6 +22,8 @@ class CreateImage(JSONResponseMixin, LoginRequiredMixin, CreateView): def form_valid(self, form): image = form.save() + for size in settings.IMAGE_SIZES.keys(): + Thumbnail.objects.get_or_create_at_size(image.pk, size) return self.render_json_response({ 'success': { 'id': image.id diff --git a/pinry/static/js/lightbox.js b/pinry/static/js/lightbox.js index ca2465e..2d8f849 100644 --- a/pinry/static/js/lightbox.js +++ b/pinry/static/js/lightbox.js @@ -22,12 +22,22 @@ $(window).load(function() { 'margin-top': -$('body').data('scroll-level') }); $(window).scrollTop(0); + /* disable the global pin-loading scroll handler so we don't + load pins when scrolling a selected image */ + $(window).off('scroll'); } else { $('#pins').css({ 'position': 'static', 'margin-top': 0 }); $(window).scrollTop($('body').data('scroll-level')); + /* enable the pin-loading scroll handler unless we've already + loaded all pins from the server (in which case an element + with id 'the-end' exists */ + var theEnd = document.getElementById('the-end'); + if (!theEnd) { + $(window).scroll(scrollHandler); + } } } // End Helper Functions diff --git a/pinry/static/js/pinry.js b/pinry/static/js/pinry.js index 5068a04..3e08d14 100644 --- a/pinry/static/js/pinry.js +++ b/pinry/static/js/pinry.js @@ -91,6 +91,14 @@ $(window).load(function() { blockContainer.css('height', colHeights.sort().slice(-1)[0]); } + /** + * On scroll load more pins from the server + */ + window.scrollHandler = function() { + var windowPosition = $(window).scrollTop() + $(window).height(); + var bottom = $(document).height() - 100; + if(windowPosition > bottom) loadPins(); + } /** * Load our pins using the pins template into our UI, be sure to define a @@ -138,11 +146,7 @@ $(window).load(function() { $('body').append(theEnd); } } else { - $(window).scroll(function() { - var windowPosition = $(window).scrollTop() + $(window).height(); - var bottom = $(document).height() - 100; - if(windowPosition > bottom) loadPins(); - }); + $(window).scroll(scrollHandler); } }); diff --git a/requirements.txt b/requirements.txt index a11fa5e..17a13ea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ South django-tastypie==0.9.12 django-braces mock -factory-boy +factory-boy>=1.3,<2.0 django_compressor requests http://github.com/kklimonda/django-images/tarball/master#egg=django-images diff --git a/setup.py b/setup.py index fe958e4..6eeed23 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ install_requires = [ setup( name="pinry", - version="1.0.0", + version="1.1.0", author="Pinry contributors", author_email="devs@getpinry.com", description=("A tiling image board system for people who want to save, " @@ -38,7 +38,7 @@ setup( packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]), long_description=read('README.md'), dependency_links=dependency_links, - tests_require=['mock', 'factory-boy'], + tests_require=['mock', 'factory-boy>=1.3,<2.0'], install_requires=install_requires, classifiers=[ "Development Status :: 4 - Beta",