added celery async task for add_related that gets exercised when a book is added to a wishlist. includes new settings for the djkombu celery backend

pull/1/head
Ed Summers 2011-10-19 23:31:16 -04:00
parent a6e8d115db
commit 0c1411f2e8
10 changed files with 57 additions and 16 deletions

View File

@ -18,6 +18,7 @@ def add_by_isbn(isbn, work=None, add_related=True):
is optional, and if not supplied the edition will be associated with is optional, and if not supplied the edition will be associated with
a stub work. a stub work.
""" """
logger.info("adding book for %s", isbn)
# save a lookup to google if we already have this isbn # save a lookup to google if we already have this isbn
has_isbn = Q(isbn_10=isbn) | Q(isbn_13=isbn) has_isbn = Q(isbn_10=isbn) | Q(isbn_13=isbn)
for edition in models.Edition.objects.filter(has_isbn): for edition in models.Edition.objects.filter(has_isbn):
@ -49,6 +50,7 @@ def add_by_googlebooks_id(googlebooks_id, work=None):
if not created: if not created:
return e return e
logger.info("loading metadata from google for %s", googlebooks_id)
url = "https://www.googleapis.com/books/v1/volumes/%s" % googlebooks_id url = "https://www.googleapis.com/books/v1/volumes/%s" % googlebooks_id
d = _get_json(url)['volumeInfo'] d = _get_json(url)['volumeInfo']
@ -89,6 +91,7 @@ def add_related(isbn):
The initial seed ISBN will be added if it's not already there. The initial seed ISBN will be added if it's not already there.
""" """
# make sure the seed edition is there # make sure the seed edition is there
logger.info("adding related editions for %s", isbn)
edition = add_by_isbn(isbn) edition = add_by_isbn(isbn)
# this is the work everything will hang off # this is the work everything will hang off
@ -104,6 +107,7 @@ def thingisbn(isbn):
"""given an ISBN return a list of related edition ISBNs, according to """given an ISBN return a list of related edition ISBNs, according to
Library Thing. Library Thing.
""" """
logger.info("looking up %s at ThingISBN" % isbn)
url = "http://www.librarything.com/api/thingISBN/%s" % isbn url = "http://www.librarything.com/api/thingISBN/%s" % isbn
xml = requests.get(url, headers={"User-Agent": settings.USER_AGENT}).content xml = requests.get(url, headers={"User-Agent": settings.USER_AGENT}).content
doc = ElementTree.fromstring(xml) doc = ElementTree.fromstring(xml)
@ -113,6 +117,7 @@ def thingisbn(isbn):
def merge_works(w1, w2): def merge_works(w1, w2):
"""will merge the second work (w2) into the first (w1) """will merge the second work (w2) into the first (w1)
""" """
logger.info("merging work %s into %s", w1, w2)
for edition in w2.editions.all(): for edition in w2.editions.all():
edition.work = w1 edition.work = w1
edition.save() edition.save()

View File

@ -102,9 +102,7 @@ class Work(models.Model):
openlibrary_id = models.CharField(max_length=50, null=True) openlibrary_id = models.CharField(max_length=50, null=True)
def cover_image_small(self): def cover_image_small(self):
server_id = random.randint(0, 9) return self.editions.all()[0].cover_image_small()
gb_id = self.editions.all()[0].googlebooks_id
return "http://bks%i.books.google.com/books?id=%s&printsec=frontcover&img=1&zoom=5" % (server_id, gb_id)
def __unicode__(self): def __unicode__(self):
return self.title return self.title
@ -143,6 +141,14 @@ class Edition(models.Model):
def __unicode__(self): def __unicode__(self):
return "%s (%s)" % (self.title, self.isbn_13) return "%s (%s)" % (self.title, self.isbn_13)
def cover_image_small(self):
server_id = random.randint(0, 9)
return "http://bks%i.books.google.com/books?id=%s&printsec=frontcover&img=1&zoom=5" % (server_id, self.googlebooks_id)
def cover_image_thumbnail(self):
server_id = random.randint(0, 9)
return "http://bks%s.books.google.com/books?id=%s&printsec=frontcover&img=1&zoom=1" % (server_id, self.googlebooks_id)
@classmethod @classmethod
def get_by_isbn(klass, isbn): def get_by_isbn(klass, isbn):
for e in Edition.objects.filter(Q(isbn_10=isbn) | Q(isbn_13=isbn)): for e in Edition.objects.filter(Q(isbn_10=isbn) | Q(isbn_13=isbn)):

View File

@ -4,5 +4,6 @@ import os
import django.core.handlers.wsgi import django.core.handlers.wsgi
os.environ['CELERY_LOADER'] = 'django'
os.environ['DJANGO_SETTINGS_MODULE'] = 'regluit.settings.prod' os.environ['DJANGO_SETTINGS_MODULE'] = 'regluit.settings.prod'
application = django.core.handlers.wsgi.WSGIHandler() application = django.core.handlers.wsgi.WSGIHandler()

View File

@ -233,7 +233,7 @@ how do I integrate the your wishlist thing with the tabs thing?
</div> </div>
<div class="book-name"> <div class="book-name">
<span> <span>
{{ work.title }} <a href="{% url work work.id %}">{{ work.title }}</a>
</span> </span>
</div> </div>
{% ifequal supporter request.user %} {% ifequal supporter request.user %}

View File

@ -9,6 +9,7 @@ from regluit.frontend.views import CampaignFormView
urlpatterns = patterns( urlpatterns = patterns(
"regluit.frontend.views", "regluit.frontend.views",
url(r"^$", "home", name="home"), url(r"^$", "home", name="home"),
url(r"work/(?P<work_id>.+)/$", "work", name="work"),
url(r"^supporter/(?P<supporter_username>.+)/$", "supporter", name="supporter"), url(r"^supporter/(?P<supporter_username>.+)/$", "supporter", name="supporter"),
url(r"^search/$", "search", name="search"), url(r"^search/$", "search", name="search"),
url(r"^privacy/$", TemplateView.as_view(template_name="privacy.html"), url(r"^privacy/$", TemplateView.as_view(template_name="privacy.html"),

View File

@ -1,31 +1,25 @@
from django.template import RequestContext import logging
from decimal import Decimal as D
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
# from django.contrib.auth.forms import UserChangeForm
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.http import HttpResponse from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from django.views.generic import ListView, DetailView
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.shortcuts import render, render_to_response, get_object_or_404 from django.shortcuts import render, render_to_response, get_object_or_404
from django.conf import settings from regluit.core import tasks
from regluit.core import models, bookloader from regluit.core import models, bookloader
from regluit.core.search import gluejar_search from regluit.core.search import gluejar_search
from regluit.frontend.forms import UserData, ProfileForm
from regluit.frontend.forms import UserData,ProfileForm
from regluit.frontend.forms import CampaignPledgeForm from regluit.frontend.forms import CampaignPledgeForm
from regluit.payment.manager import PaymentManager from regluit.payment.manager import PaymentManager
from regluit.payment.parameters import TARGET_TYPE_CAMPAIGN from regluit.payment.parameters import TARGET_TYPE_CAMPAIGN
from decimal import Decimal as D
import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
from regluit.payment.models import Transaction from regluit.payment.models import Transaction
@ -36,6 +30,10 @@ def home(request):
args=[request.user.username])) args=[request.user.username]))
return render(request, 'home.html', {'suppress_search_box': True}) return render(request, 'home.html', {'suppress_search_box': True})
def work(request, work_id):
work = get_object_or_404(models.Work, id=work_id)
return render(request, 'work.html', {'work': work})
def supporter(request, supporter_username): def supporter(request, supporter_username):
supporter = get_object_or_404(User, username=supporter_username) supporter = get_object_or_404(User, username=supporter_username)
wishlist = supporter.wishlist wishlist = supporter.wishlist
@ -137,6 +135,8 @@ def wishlist(request):
remove_work_id = request.POST.get('remove_work_id', None) remove_work_id = request.POST.get('remove_work_id', None)
if googlebooks_id: if googlebooks_id:
edition = bookloader.add_by_googlebooks_id(googlebooks_id) edition = bookloader.add_by_googlebooks_id(googlebooks_id)
# add related editions asynchronously
tasks.add_related.delay(edition.isbn_10)
request.user.wishlist.works.add(edition.work) request.user.wishlist.works.add(edition.work)
# TODO: redirect to work page, when it exists # TODO: redirect to work page, when it exists
return HttpResponseRedirect('/') return HttpResponseRedirect('/')
@ -158,6 +158,7 @@ class CampaignFormView(FormView):
'campaign': campaign 'campaign': campaign
}) })
return context return context
def form_valid(self,form): def form_valid(self,form):
pk = self.kwargs["pk"] pk = self.kwargs["pk"]
pledge_amount = form.cleaned_data["pledge_amount"] pledge_amount = form.cleaned_data["pledge_amount"]

View File

@ -9,3 +9,4 @@ selenium
django-nose-selenium django-nose-selenium
nose nose
django-profiles django-profiles
django-kombu

View File

@ -107,6 +107,7 @@ INSTALLED_APPS = (
'registration', 'registration',
'social_auth', 'social_auth',
'tastypie', 'tastypie',
'djcelery',
) )
# A sample logging configuration. The only tangible logging # A sample logging configuration. The only tangible logging
@ -182,3 +183,6 @@ USER_AGENT = "unglue.it.bot v0.0.1 <http://unglue.it>"
SOUTH_TESTS_MIGRATE = True SOUTH_TESTS_MIGRATE = True
AUTH_PROFILE_MODULE = "core.userprofile" AUTH_PROFILE_MODULE = "core.userprofile"
import djcelery
djcelery.setup_loader()

View File

@ -79,3 +79,7 @@ PAYPAL_TEST_RH_EMAIL = "rh1_1317336251_biz@gluejar.com"
PAYPAL_TEST_NONPROFIT_PARTNER_EMAIL = "" PAYPAL_TEST_NONPROFIT_PARTNER_EMAIL = ""
BASE_URL = 'http://0.0.0.0/' BASE_URL = 'http://0.0.0.0/'
# use database as queuing service in development
BROKER_TRANSPORT = "djkombu.transport.DatabaseTransport"
INSTALLED_APPS += ("djkombu",)

View File

@ -697,3 +697,21 @@ span.bounce-search {
border-bottom: 3px solid; border-bottom: 3px solid;
cursor: pointer; cursor: pointer;
} }
/* work page */
ul.edition-list {
list-style: none;
}
ul.edition-list li {
clear: both;
padding: 10px;
height: 80px;
border-bottom: thin gray solid;
}
li.edition img.cover {
vertical-align: top;
}
li.edition span.publisher {
font-weight: bold;
}