From 53f05dbb6d822a9597c5edca0e7091dc63bec5c3 Mon Sep 17 00:00:00 2001 From: Krzysztof Klimonda Date: Sun, 3 Mar 2013 04:47:34 -0800 Subject: [PATCH] A general project refactor Removed pins django app, and moved code to the core. Moved user related code out of core to the users app. --- pinry/core/api.py | 4 +-- pinry/core/auth/backends.py | 4 +-- pinry/core/forms.py | 44 +++++++------------------- pinry/core/models.py | 43 ++++++++++++++++++++----- pinry/core/tests.py | 4 +-- pinry/core/urls.py | 20 ++++++------ pinry/core/views.py | 56 +++++++++++---------------------- pinry/fixtures/test_resources.json | 1 + pinry/pins/__init__.py | 0 pinry/pins/fixtures/test_resources.json | 1 - pinry/pins/forms.py | 19 ----------- pinry/pins/models.py | 39 ----------------------- pinry/pins/tests.py | 37 ---------------------- pinry/pins/urls.py | 15 --------- pinry/pins/utils.py | 56 --------------------------------- pinry/pins/views.py | 30 ------------------ pinry/settings/__init__.py | 2 +- pinry/templates/base.html | 8 ++--- pinry/templates/user/login.html | 2 +- pinry/templates/user/register.html | 2 +- pinry/urls.py | 4 +-- pinry/users/__init__.py | 1 + pinry/users/forms.py | 38 ++++++++++++++++++++++ pinry/users/models.py | 12 +++++++ pinry/users/urls.py | 10 ++++++ pinry/users/views.py | 44 ++++++++++++++++++++++++++ 26 files changed, 197 insertions(+), 299 deletions(-) create mode 100644 pinry/fixtures/test_resources.json delete mode 100644 pinry/pins/__init__.py delete mode 100644 pinry/pins/fixtures/test_resources.json delete mode 100644 pinry/pins/forms.py delete mode 100644 pinry/pins/models.py delete mode 100644 pinry/pins/tests.py delete mode 100644 pinry/pins/urls.py delete mode 100644 pinry/pins/utils.py delete mode 100644 pinry/pins/views.py create mode 100644 pinry/users/__init__.py create mode 100644 pinry/users/forms.py create mode 100644 pinry/users/models.py create mode 100644 pinry/users/urls.py create mode 100644 pinry/users/views.py diff --git a/pinry/core/api.py b/pinry/core/api.py index 259951b..e9fe5da 100644 --- a/pinry/core/api.py +++ b/pinry/core/api.py @@ -4,8 +4,8 @@ from tastypie.exceptions import Unauthorized from tastypie.resources import ModelResource from django_images.models import Thumbnail -from pinry.core.models import User -from pinry.pins.models import Image, Pin +from .models import Pin, Image +from ..users.models import User class PinryAuthorization(DjangoAuthorization): diff --git a/pinry/core/auth/backends.py b/pinry/core/auth/backends.py index 149defc..f4c95c1 100644 --- a/pinry/core/auth/backends.py +++ b/pinry/core/auth/backends.py @@ -1,7 +1,7 @@ from django.core.validators import email_re -from pinry.core.models import User -from pinry.pins.models import Pin +from pinry.core.models import Pin +from pinry.users.models import User class CombinedAuthBackend(object): diff --git a/pinry/core/forms.py b/pinry/core/forms.py index 6fe0770..7c080b7 100644 --- a/pinry/core/forms.py +++ b/pinry/core/forms.py @@ -1,38 +1,18 @@ from django import forms -from django.utils.translation import ugettext, ugettext_lazy as _ -from django.contrib.auth.models import User +from django_images.models import Image -class UserCreationForm(forms.ModelForm): - """ - A form that creates a user, with no privileges, from the given username, - email, and password. - """ - error_messages = { - 'duplicate_username': _("A user with that username already exists."), - } - username = forms.RegexField(label=_("Username"), max_length=30, - regex=r'^[\w-]+$') - password = forms.CharField(label=_("Password"), - widget=forms.PasswordInput) - class Meta: - model = User - fields = ("username", "email") +FIELD_NAME_MAPPING = { + 'image': 'qqfile', +} + - def clean_username(self): - # Since User.username is unique, this check is redundant, - # but it sets a nicer error message than the ORM. See #13147. - username = self.cleaned_data["username"] - try: - User._default_manager.get(username=username) - except User.DoesNotExist: - return username - raise forms.ValidationError(self.error_messages['duplicate_username']) +class ImageForm(forms.ModelForm): + def add_prefix(self, field_name): + field_name = FIELD_NAME_MAPPING.get(field_name, field_name) + return super(ImageForm, self).add_prefix(field_name) - def save(self, commit=True): - user = super(UserCreationForm, self).save(commit=False) - user.set_password(self.cleaned_data["password"]) - if commit: - user.save() - return user + class Meta: + model = Image + fields = ('image',) \ No newline at end of file diff --git a/pinry/core/models.py b/pinry/core/models.py index 0557b7e..cc14090 100644 --- a/pinry/core/models.py +++ b/pinry/core/models.py @@ -1,10 +1,39 @@ -import hashlib -from django.contrib.auth.models import User as BaseUser +import urllib2 +from cStringIO import StringIO -class User(BaseUser): - @property - def gravatar(self): - return hashlib.md5(self.email).hexdigest() +from django.core.files.uploadedfile import InMemoryUploadedFile +from django.db import models + +from django_images.models import Image as BaseImage +from taggit.managers import TaggableManager + +from ..users.models import User + + +class ImageManager(models.Manager): + # FIXME: Move this into an asynchronous task + def create_for_url(self, url): + file_name = url.split("/")[-1] + buf = StringIO() + buf.write(urllib2.urlopen(url).read()) + obj = InMemoryUploadedFile(buf, 'image', file_name, None, buf.tell(), None) + return Image.objects.create(image=obj) + + +class Image(BaseImage): + objects = ImageManager() class Meta: - proxy = True \ No newline at end of file + proxy = True + + +class Pin(models.Model): + submitter = models.ForeignKey(User) + url = models.TextField(blank=True, null=True) + description = models.TextField(blank=True, null=True) + image = models.ForeignKey(Image, related_name='pin') + published = models.DateTimeField(auto_now_add=True) + tags = TaggableManager() + + def __unicode__(self): + return self.url \ No newline at end of file diff --git a/pinry/core/tests.py b/pinry/core/tests.py index e13b819..08241a0 100644 --- a/pinry/core/tests.py +++ b/pinry/core/tests.py @@ -4,11 +4,11 @@ from django.conf import settings from django.test.client import Client from django_images.models import Thumbnail - from taggit.models import Tag from tastypie.test import ResourceTestCase -from ..pins.models import User, Pin, Image +from .models import Pin, Image +from ..users.models import User def filter_generator_for(size): diff --git a/pinry/core/urls.py b/pinry/core/urls.py index a9eb392..a17743a 100644 --- a/pinry/core/urls.py +++ b/pinry/core/urls.py @@ -1,9 +1,10 @@ from django.conf.urls import patterns, include, url +from django.views.generic import TemplateView from tastypie.api import Api from .api import ImageResource, ThumbnailResource, PinResource, UserResource -from .views import CreateUser +from .views import CreateImage v1_api = Api(api_name='v1') @@ -14,17 +15,14 @@ v1_api.register(UserResource()) urlpatterns = patterns('', -) - - -urlpatterns = patterns('', url(r'^api/', include(v1_api.urls, namespace='api')), - url(r'^$', 'pinry.core.views.home', name='home'), - + url(r'^pin-form/$', TemplateView.as_view(template_name='core/pin_form.html'), + name='pin-form'), + url(r'^create-image/$', CreateImage.as_view(), name='create-image'), + url(r'^tag/(?P(\w|-)+)/$', TemplateView.as_view(template_name='core/pins.html'), + name='tag-pins'), url(r'^private/$', 'pinry.core.views.private', name='private'), - url(r'^login/$', 'django.contrib.auth.views.login', - {'template_name': 'user/login.html'}, name='login'), - url(r'^logout/$', 'pinry.core.views.logout_user', name='logout'), - url(r'^register/$', CreateUser.as_view(), name='register'), + url(r'^$', TemplateView.as_view(template_name='core/pins.html'), + name='recent-pins'), ) diff --git a/pinry/core/views.py b/pinry/core/views.py index 2f74804..722f96e 100644 --- a/pinry/core/views.py +++ b/pinry/core/views.py @@ -1,53 +1,35 @@ -from django.contrib.auth.models import Permission from django.template.response import TemplateResponse from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse -from django.contrib.auth.decorators import login_required -from django.contrib.auth import logout, authenticate, login -from django.contrib import messages -from django.conf import settings -from django.utils.functional import lazy from django.views.generic import CreateView +from django_images.models import Image -from .forms import UserCreationForm -from .models import User +from braces.views import JSONResponseMixin, LoginRequiredMixin - -reverse_lazy = lambda name=None, *args : lazy(reverse, str)(name, args=args) - - -def home(request): - return HttpResponseRedirect(reverse('pins:recent-pins')) +from .forms import ImageForm def private(request): return TemplateResponse(request, 'user/private.html', None) -class CreateUser(CreateView): - template_name = 'user/register.html' - model = User - form_class = UserCreationForm - success_url = reverse_lazy('pins:recent-pins') +class CreateImage(JSONResponseMixin, LoginRequiredMixin, CreateView): + template_name = None # JavaScript-only view + model = Image + form_class = ImageForm def get(self, request, *args, **kwargs): - if not settings.ALLOW_NEW_REGISTRATIONS: - messages.error(request, "The admin of this service is not allowing new registrations.") - return HttpResponseRedirect(reverse('pins:recent-pins')) - return super(CreateUser, self).get(request, *args, **kwargs) + if not request.is_ajax(): + return HttpResponseRedirect(reverse('core:recent-pins')) + super(CreateImage, self).get(request, *args, **kwargs) def form_valid(self, form): - redirect = super(CreateUser, self).form_valid(form) - permissions = Permission.objects.filter(codename__in=['add_pin', 'add_image']) - user = authenticate(username=form.cleaned_data['username'], - password=form.cleaned_data['password']) - user.user_permissions = permissions - login(self.request, user) - return redirect - - -@login_required -def logout_user(request): - logout(request) - messages.success(request, 'You have successfully logged out.') - return HttpResponseRedirect(reverse('core:home')) + image = form.save() + return self.render_json_response({ + 'success': { + 'id': image.id + } + }) + + def form_invalid(self, form): + return self.render_json_response({'error': form.errors}) \ No newline at end of file diff --git a/pinry/fixtures/test_resources.json b/pinry/fixtures/test_resources.json new file mode 100644 index 0000000..dec7a69 --- /dev/null +++ b/pinry/fixtures/test_resources.json @@ -0,0 +1 @@ +[{"pk": 1, "model": "auth.permission", "fields": {"codename": "add_permission", "name": "Can add permission", "content_type": 1}}, {"pk": 2, "model": "auth.permission", "fields": {"codename": "change_permission", "name": "Can change permission", "content_type": 1}}, {"pk": 3, "model": "auth.permission", "fields": {"codename": "delete_permission", "name": "Can delete permission", "content_type": 1}}, {"pk": 4, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 2}}, {"pk": 5, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 2}}, {"pk": 6, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 2}}, {"pk": 7, "model": "auth.permission", "fields": {"codename": "add_user", "name": "Can add user", "content_type": 3}}, {"pk": 8, "model": "auth.permission", "fields": {"codename": "change_user", "name": "Can change user", "content_type": 3}}, {"pk": 9, "model": "auth.permission", "fields": {"codename": "delete_user", "name": "Can delete user", "content_type": 3}}, {"pk": 10, "model": "auth.permission", "fields": {"codename": "add_contenttype", "name": "Can add content type", "content_type": 4}}, {"pk": 11, "model": "auth.permission", "fields": {"codename": "change_contenttype", "name": "Can change content type", "content_type": 4}}, {"pk": 12, "model": "auth.permission", "fields": {"codename": "delete_contenttype", "name": "Can delete content type", "content_type": 4}}, {"pk": 13, "model": "auth.permission", "fields": {"codename": "add_session", "name": "Can add session", "content_type": 5}}, {"pk": 14, "model": "auth.permission", "fields": {"codename": "change_session", "name": "Can change session", "content_type": 5}}, {"pk": 15, "model": "auth.permission", "fields": {"codename": "delete_session", "name": "Can delete session", "content_type": 5}}, {"pk": 16, "model": "auth.permission", "fields": {"codename": "add_migrationhistory", "name": "Can add migration history", "content_type": 6}}, {"pk": 17, "model": "auth.permission", "fields": {"codename": "change_migrationhistory", "name": "Can change migration history", "content_type": 6}}, {"pk": 18, "model": "auth.permission", "fields": {"codename": "delete_migrationhistory", "name": "Can delete migration history", "content_type": 6}}, {"pk": 19, "model": "auth.permission", "fields": {"codename": "add_tag", "name": "Can add Tag", "content_type": 7}}, {"pk": 20, "model": "auth.permission", "fields": {"codename": "change_tag", "name": "Can change Tag", "content_type": 7}}, {"pk": 21, "model": "auth.permission", "fields": {"codename": "delete_tag", "name": "Can delete Tag", "content_type": 7}}, {"pk": 22, "model": "auth.permission", "fields": {"codename": "add_taggeditem", "name": "Can add Tagged Item", "content_type": 8}}, {"pk": 23, "model": "auth.permission", "fields": {"codename": "change_taggeditem", "name": "Can change Tagged Item", "content_type": 8}}, {"pk": 24, "model": "auth.permission", "fields": {"codename": "delete_taggeditem", "name": "Can delete Tagged Item", "content_type": 8}}, {"pk": 25, "model": "auth.permission", "fields": {"codename": "add_image", "name": "Can add image", "content_type": 9}}, {"pk": 26, "model": "auth.permission", "fields": {"codename": "change_image", "name": "Can change image", "content_type": 9}}, {"pk": 27, "model": "auth.permission", "fields": {"codename": "delete_image", "name": "Can delete image", "content_type": 9}}, {"pk": 28, "model": "auth.permission", "fields": {"codename": "add_thumbnail", "name": "Can add thumbnail", "content_type": 10}}, {"pk": 29, "model": "auth.permission", "fields": {"codename": "change_thumbnail", "name": "Can change thumbnail", "content_type": 10}}, {"pk": 30, "model": "auth.permission", "fields": {"codename": "delete_thumbnail", "name": "Can delete thumbnail", "content_type": 10}}, {"pk": 31, "model": "auth.permission", "fields": {"codename": "add_pin", "name": "Can add pin", "content_type": 12}}, {"pk": 32, "model": "auth.permission", "fields": {"codename": "change_pin", "name": "Can change pin", "content_type": 12}}, {"pk": 33, "model": "auth.permission", "fields": {"codename": "delete_pin", "name": "Can delete pin", "content_type": 12}}, {"pk": 1, "model": "auth.user", "fields": {"username": "jdoe", "first_name": "", "last_name": "", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2013-02-25T18:07:05.308Z", "groups": [], "user_permissions": [31], "password": "pbkdf2_sha256$10000$fWo1asHpXTeD$zDtszDL5fU2JZQd2goXayWCWl/EZbL8CZ+COg4Xqi04=", "email": "jdoe@example.com", "date_joined": "2013-02-25T18:07:05.308Z"}}, {"pk": 1, "model": "django_images.image", "fields": {"width": 300, "image": "screenshot.png", "height": 300}}, {"pk": 2, "model": "django_images.image", "fields": {"width": 500, "image": "screenshot.png", "height": 500}}, {"pk": 1, "model": "pins.pin", "fields": {"submitter": 1, "url": "https://si0.twimg.com/profile_images/70370524/cc_white.png", "image": 1, "description": "Creative Commons Logo", "published": "2013-02-25T18:08:31.308Z"}}, {"pk": 2, "model": "pins.pin", "fields": {"submitter": 1, "url": "https://si0.twimg.com/profile_images/70370524/cc_white.png", "image": 2, "description": "Creative Commons logo downloaded from DeviantArt", "published": "2013-02-25T18:08:54.612Z"}}, {"pk": 1, "model": "taggit.tag", "fields": {"name": "creative-commons", "slug": "creative-commons"}}, {"pk": 2, "model": "taggit.tag", "fields": {"name": "deviantart", "slug": "deviantart"}}, {"pk": 1, "model": "taggit.taggeditem", "fields": {"tag": 1, "content_type": 12, "object_id": 1}}, {"pk": 2, "model": "taggit.taggeditem", "fields": {"tag": 1, "content_type": 12, "object_id": 2}}, {"pk": 3, "model": "taggit.taggeditem", "fields": {"tag": 2, "content_type": 12, "object_id": 2}}] diff --git a/pinry/pins/__init__.py b/pinry/pins/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pinry/pins/fixtures/test_resources.json b/pinry/pins/fixtures/test_resources.json deleted file mode 100644 index dec7a69..0000000 --- a/pinry/pins/fixtures/test_resources.json +++ /dev/null @@ -1 +0,0 @@ -[{"pk": 1, "model": "auth.permission", "fields": {"codename": "add_permission", "name": "Can add permission", "content_type": 1}}, {"pk": 2, "model": "auth.permission", "fields": {"codename": "change_permission", "name": "Can change permission", "content_type": 1}}, {"pk": 3, "model": "auth.permission", "fields": {"codename": "delete_permission", "name": "Can delete permission", "content_type": 1}}, {"pk": 4, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 2}}, {"pk": 5, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 2}}, {"pk": 6, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 2}}, {"pk": 7, "model": "auth.permission", "fields": {"codename": "add_user", "name": "Can add user", "content_type": 3}}, {"pk": 8, "model": "auth.permission", "fields": {"codename": "change_user", "name": "Can change user", "content_type": 3}}, {"pk": 9, "model": "auth.permission", "fields": {"codename": "delete_user", "name": "Can delete user", "content_type": 3}}, {"pk": 10, "model": "auth.permission", "fields": {"codename": "add_contenttype", "name": "Can add content type", "content_type": 4}}, {"pk": 11, "model": "auth.permission", "fields": {"codename": "change_contenttype", "name": "Can change content type", "content_type": 4}}, {"pk": 12, "model": "auth.permission", "fields": {"codename": "delete_contenttype", "name": "Can delete content type", "content_type": 4}}, {"pk": 13, "model": "auth.permission", "fields": {"codename": "add_session", "name": "Can add session", "content_type": 5}}, {"pk": 14, "model": "auth.permission", "fields": {"codename": "change_session", "name": "Can change session", "content_type": 5}}, {"pk": 15, "model": "auth.permission", "fields": {"codename": "delete_session", "name": "Can delete session", "content_type": 5}}, {"pk": 16, "model": "auth.permission", "fields": {"codename": "add_migrationhistory", "name": "Can add migration history", "content_type": 6}}, {"pk": 17, "model": "auth.permission", "fields": {"codename": "change_migrationhistory", "name": "Can change migration history", "content_type": 6}}, {"pk": 18, "model": "auth.permission", "fields": {"codename": "delete_migrationhistory", "name": "Can delete migration history", "content_type": 6}}, {"pk": 19, "model": "auth.permission", "fields": {"codename": "add_tag", "name": "Can add Tag", "content_type": 7}}, {"pk": 20, "model": "auth.permission", "fields": {"codename": "change_tag", "name": "Can change Tag", "content_type": 7}}, {"pk": 21, "model": "auth.permission", "fields": {"codename": "delete_tag", "name": "Can delete Tag", "content_type": 7}}, {"pk": 22, "model": "auth.permission", "fields": {"codename": "add_taggeditem", "name": "Can add Tagged Item", "content_type": 8}}, {"pk": 23, "model": "auth.permission", "fields": {"codename": "change_taggeditem", "name": "Can change Tagged Item", "content_type": 8}}, {"pk": 24, "model": "auth.permission", "fields": {"codename": "delete_taggeditem", "name": "Can delete Tagged Item", "content_type": 8}}, {"pk": 25, "model": "auth.permission", "fields": {"codename": "add_image", "name": "Can add image", "content_type": 9}}, {"pk": 26, "model": "auth.permission", "fields": {"codename": "change_image", "name": "Can change image", "content_type": 9}}, {"pk": 27, "model": "auth.permission", "fields": {"codename": "delete_image", "name": "Can delete image", "content_type": 9}}, {"pk": 28, "model": "auth.permission", "fields": {"codename": "add_thumbnail", "name": "Can add thumbnail", "content_type": 10}}, {"pk": 29, "model": "auth.permission", "fields": {"codename": "change_thumbnail", "name": "Can change thumbnail", "content_type": 10}}, {"pk": 30, "model": "auth.permission", "fields": {"codename": "delete_thumbnail", "name": "Can delete thumbnail", "content_type": 10}}, {"pk": 31, "model": "auth.permission", "fields": {"codename": "add_pin", "name": "Can add pin", "content_type": 12}}, {"pk": 32, "model": "auth.permission", "fields": {"codename": "change_pin", "name": "Can change pin", "content_type": 12}}, {"pk": 33, "model": "auth.permission", "fields": {"codename": "delete_pin", "name": "Can delete pin", "content_type": 12}}, {"pk": 1, "model": "auth.user", "fields": {"username": "jdoe", "first_name": "", "last_name": "", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2013-02-25T18:07:05.308Z", "groups": [], "user_permissions": [31], "password": "pbkdf2_sha256$10000$fWo1asHpXTeD$zDtszDL5fU2JZQd2goXayWCWl/EZbL8CZ+COg4Xqi04=", "email": "jdoe@example.com", "date_joined": "2013-02-25T18:07:05.308Z"}}, {"pk": 1, "model": "django_images.image", "fields": {"width": 300, "image": "screenshot.png", "height": 300}}, {"pk": 2, "model": "django_images.image", "fields": {"width": 500, "image": "screenshot.png", "height": 500}}, {"pk": 1, "model": "pins.pin", "fields": {"submitter": 1, "url": "https://si0.twimg.com/profile_images/70370524/cc_white.png", "image": 1, "description": "Creative Commons Logo", "published": "2013-02-25T18:08:31.308Z"}}, {"pk": 2, "model": "pins.pin", "fields": {"submitter": 1, "url": "https://si0.twimg.com/profile_images/70370524/cc_white.png", "image": 2, "description": "Creative Commons logo downloaded from DeviantArt", "published": "2013-02-25T18:08:54.612Z"}}, {"pk": 1, "model": "taggit.tag", "fields": {"name": "creative-commons", "slug": "creative-commons"}}, {"pk": 2, "model": "taggit.tag", "fields": {"name": "deviantart", "slug": "deviantart"}}, {"pk": 1, "model": "taggit.taggeditem", "fields": {"tag": 1, "content_type": 12, "object_id": 1}}, {"pk": 2, "model": "taggit.taggeditem", "fields": {"tag": 1, "content_type": 12, "object_id": 2}}, {"pk": 3, "model": "taggit.taggeditem", "fields": {"tag": 2, "content_type": 12, "object_id": 2}}] diff --git a/pinry/pins/forms.py b/pinry/pins/forms.py deleted file mode 100644 index bf0b3ed..0000000 --- a/pinry/pins/forms.py +++ /dev/null @@ -1,19 +0,0 @@ -from django import forms - -from django_images.models import Image - - -FIELD_NAME_MAPPING = { - 'image': 'qqfile', -} - - -class ImageForm(forms.ModelForm): - - def add_prefix(self, field_name): - field_name = FIELD_NAME_MAPPING.get(field_name, field_name) - return super(ImageForm, self).add_prefix(field_name) - - class Meta: - model = Image - fields = ('image',) diff --git a/pinry/pins/models.py b/pinry/pins/models.py deleted file mode 100644 index 422943a..0000000 --- a/pinry/pins/models.py +++ /dev/null @@ -1,39 +0,0 @@ -import urllib2 -from cStringIO import StringIO - -from django.core.files.uploadedfile import InMemoryUploadedFile -from django.db import models - -from django_images.models import Image as BaseImage -from taggit.managers import TaggableManager - -from ..core.models import User - - -class ImageManager(models.Manager): - # FIXME: Move this into an asynchronous task - def create_for_url(self, url): - file_name = url.split("/")[-1] - buf = StringIO() - buf.write(urllib2.urlopen(url).read()) - obj = InMemoryUploadedFile(buf, 'image', file_name, None, buf.tell(), None) - return Image.objects.create(image=obj) - - -class Image(BaseImage): - objects = ImageManager() - - class Meta: - proxy = True - - -class Pin(models.Model): - submitter = models.ForeignKey(User) - url = models.TextField(blank=True, null=True) - description = models.TextField(blank=True, null=True) - image = models.ForeignKey(Image, related_name='pin') - published = models.DateTimeField(auto_now_add=True) - tags = TaggableManager() - - def __unicode__(self): - return self.url diff --git a/pinry/pins/tests.py b/pinry/pins/tests.py deleted file mode 100644 index 69faeeb..0000000 --- a/pinry/pins/tests.py +++ /dev/null @@ -1,37 +0,0 @@ -from django.core.urlresolvers import reverse -from django.test import TestCase - -from pinry.core.models import User - - -class CreateImageTest(TestCase): - fixtures = ['test_resources.json'] - - def setUp(self): - self.client.login(username='jdoe', password='password') - - def test_form_post_unauthenticated(self): - post_data = { - 'image': 'foobar.jpg' - } - self.client.logout() - response = self.client.post(reverse('pins:new-pin'), data=post_data) - expected_url = '{login_url}?next={next_url}'.format(**{ - 'login_url': reverse('core:login'), - 'next_url': reverse('pins:new-pin') - }) - self.assertRedirects(response, expected_url=expected_url) - - def test_form_post_browser(self): - post_data = { - 'image': 'foobar.jpg' - } - response = self.client.post(reverse('pins:new-pin'), data=post_data) - self.assertEqual(response.status_code, 200) - - def test_form_post_ajax(self): - post_data = { - 'image': 'foobar.jpg' - } - response = self.client.post(reverse('pins:new-pin'), data=post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) \ No newline at end of file diff --git a/pinry/pins/urls.py b/pinry/pins/urls.py deleted file mode 100644 index 6e94fa7..0000000 --- a/pinry/pins/urls.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.conf.urls import patterns, url -from django.views.generic import TemplateView - -from .views import CreateImage - - -urlpatterns = patterns('pinry.pins.views', - url(r'^pin-form/$', TemplateView.as_view(template_name='core/pin_form.html'), - name='pin-form'), - url(r'^create-image/$', CreateImage.as_view(), name='create-image'), - url(r'^tag/(?P(\w|-)+)/$', TemplateView.as_view(template_name='core/pins.html'), - name='tag-pins'), - url(r'^$', TemplateView.as_view(template_name='core/pins.html'), - name='recent-pins'), -) diff --git a/pinry/pins/utils.py b/pinry/pins/utils.py deleted file mode 100644 index fe0138a..0000000 --- a/pinry/pins/utils.py +++ /dev/null @@ -1,56 +0,0 @@ -import PIL -import mimetypes - -mimetypes.init() - - -# this neat function is based on django-images and easy-thumbnails -def scale_and_crop(image, size, crop=False, upscale=False, quality=None): - # Open image and store format/metadata. - image.open() - im = PIL.Image.open(image) - im_format, im_info = im.format, im.info - if quality: - im_info['quality'] = quality - - # Force PIL to load image data. - im.load() - - source_x, source_y = [float(v) for v in im.size] - target_x, target_y = [float(v) for v in size] - - if crop or not target_x or not target_y: - scale = max(target_x / source_x, target_y / source_y) - else: - scale = min(target_x / source_x, target_y / source_y) - - # Handle one-dimensional targets. - if not target_x: - target_x = source_x * scale - elif not target_y: - target_y = source_y * scale - - if scale < 1.0 or (scale > 1.0 and upscale): - im = im.resize((int(source_x * scale), int(source_y * scale)), - resample=PIL.Image.ANTIALIAS) - - if crop: - # Use integer values now. - source_x, source_y = im.size - # Difference between new image size and requested size. - diff_x = int(source_x - min(source_x, target_x)) - diff_y = int(source_y - min(source_y, target_y)) - if diff_x or diff_y: - # Center cropping (default). - halfdiff_x, halfdiff_y = diff_x // 2, diff_y // 2 - box = [halfdiff_x, halfdiff_y, - min(source_x, int(target_x) + halfdiff_x), - min(source_y, int(target_y) + halfdiff_y)] - # Finally, crop the image! - im = im.crop(box) - - # Close image and replace format/metadata, as PIL blows this away. - im.format, im.info = im_format, im_info - image.close() - return im - diff --git a/pinry/pins/views.py b/pinry/pins/views.py deleted file mode 100644 index ee586de..0000000 --- a/pinry/pins/views.py +++ /dev/null @@ -1,30 +0,0 @@ -from django.core.urlresolvers import reverse -from django.http import HttpResponseRedirect -from django.views.generic import CreateView - -from braces.views import LoginRequiredMixin, JSONResponseMixin -from django_images.models import Image - -from .forms import ImageForm - - -class CreateImage(JSONResponseMixin, LoginRequiredMixin, CreateView): - template_name = None # JavaScript-only view - model = Image - form_class = ImageForm - - def get(self, request, *args, **kwargs): - if not request.is_ajax(): - return HttpResponseRedirect(reverse('pins:recent-pins')) - super(CreateImage, self).get(request, *args, **kwargs) - - def form_valid(self, form): - image = form.save() - return self.render_json_response({ - 'success': { - 'id': image.id - } - }) - - def form_invalid(self, form): - return self.render_json_response({'error': form.errors}) diff --git a/pinry/settings/__init__.py b/pinry/settings/__init__.py index 91cf68a..439e1ae 100644 --- a/pinry/settings/__init__.py +++ b/pinry/settings/__init__.py @@ -85,7 +85,7 @@ INSTALLED_APPS = ( 'taggit', 'django_images', 'pinry.core', - 'pinry.pins', + 'pinry.users', ) IMAGE_SIZES = { diff --git a/pinry/templates/base.html b/pinry/templates/base.html index f564825..a9d9b97 100644 --- a/pinry/templates/base.html +++ b/pinry/templates/base.html @@ -44,15 +44,15 @@