From defbd5044563111666d916674519c49b6e304a5e Mon Sep 17 00:00:00 2001 From: Krzysztof Klimonda Date: Sun, 14 Apr 2013 15:51:39 +0200 Subject: [PATCH 1/4] Don't load Pins "in background" when lightbox is active. Remove the scroll event handler when lightbox is active, so pins are not loaded in background breaking the page layout. --- pinry/static/js/lightbox.js | 10 ++++++++++ pinry/static/js/pinry.js | 14 +++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) 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); } }); From 7db42bb0753456781f8d8ffccff59e0636755699 Mon Sep 17 00:00:00 2001 From: Krzysztof Klimonda Date: Tue, 16 Apr 2013 00:30:43 +0200 Subject: [PATCH 2/4] Generate thumbnails when image is being saved Too lax unique constraints for Thumbnail coped with "on demand" thumbnail generation may leave database in inconsistent state where two thumbnail for the same size are saved. We should be able to prevent that from happening by generating all thumbnails when we save the image. Should fix #24, but I can't figure out a way to actually test it. --- pinry/core/api.py | 2 +- pinry/core/models.py | 13 ++++++++++--- pinry/core/tests/helpers.py | 8 ++++++++ pinry/core/views.py | 4 ++++ 4 files changed, 23 insertions(+), 4 deletions(-) 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 From a704cb7297f3d53611fcfd32b08daa7a799a6ff6 Mon Sep 17 00:00:00 2001 From: Krzysztof Klimonda Date: Tue, 16 Apr 2013 02:23:49 +0200 Subject: [PATCH 3/4] Pin factory-boy dependency on 1.3.x branch Factory Boy 2.0 have removed the "extracted_key" keyword argument from post_generation() hook. Until we can update tests to work with 2.0 make dependency on 1.3.x branch. In turn, the update got stalled by a bug in Factory Boy (https://github.com/rbarrois/factory_boy/issues/53). --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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..fd176b3 100644 --- a/setup.py +++ b/setup.py @@ -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", From d8f67caed0e9b15b883fe7e4c6f03dbfb3aeedb7 Mon Sep 17 00:00:00 2001 From: Krzysztof Klimonda Date: Tue, 16 Apr 2013 13:52:43 +0200 Subject: [PATCH 4/4] Update version to 1.1.0 in preparation for the release --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fd176b3..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, "