1447 lines
61 KiB
Python
Executable File
1447 lines
61 KiB
Python
Executable File
import re
|
|
import sys
|
|
import json
|
|
import logging
|
|
from datetime import timedelta
|
|
from regluit.utils.localdatetime import now, date_today
|
|
|
|
from random import randint
|
|
from re import sub
|
|
from itertools import islice
|
|
from decimal import Decimal as D
|
|
from xml.etree import ElementTree as ET
|
|
|
|
import requests
|
|
import oauth2 as oauth
|
|
from django import forms
|
|
from django.conf import settings
|
|
from django.contrib.auth.models import User
|
|
from django.core.urlresolvers import reverse
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
from django.core.mail import send_mail
|
|
from django.contrib import messages
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.contrib.comments import Comment
|
|
from django.db.models import Q, Count, Sum
|
|
from django.forms import Select
|
|
from django.forms.models import modelformset_factory
|
|
from django.http import HttpResponseRedirect, Http404
|
|
from django.http import HttpResponse, HttpResponseNotFound
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
from django.views.decorators.http import require_POST
|
|
from django.views.generic.edit import FormView
|
|
from django.views.generic.list import ListView
|
|
from django.views.generic.base import TemplateView
|
|
from django.shortcuts import render, render_to_response, get_object_or_404
|
|
from django.utils.http import urlencode
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from regluit.core import tasks
|
|
from regluit.core import models, bookloader, librarything
|
|
from regluit.core import userlists
|
|
from regluit.core.search import gluejar_search
|
|
from regluit.core.goodreads import GoodreadsClient
|
|
from regluit.frontend.forms import UserData, ProfileForm, CampaignPledgeForm, GoodreadsShelfLoadingForm
|
|
from regluit.frontend.forms import RightsHolderForm, UserClaimForm, LibraryThingForm, OpenCampaignForm
|
|
from regluit.frontend.forms import ManageCampaignForm, DonateForm, CampaignAdminForm, EmailShareForm, FeedbackForm
|
|
from regluit.frontend.forms import EbookForm
|
|
from regluit.payment.manager import PaymentManager
|
|
from regluit.payment.models import Transaction
|
|
from regluit.payment.parameters import TARGET_TYPE_CAMPAIGN, TARGET_TYPE_DONATION, PAYMENT_TYPE_AUTHORIZATION
|
|
from regluit.payment.paypal import Preapproval, IPN_PAY_STATUS_NONE, IPN_PAY_STATUS_ACTIVE, IPN_PAY_STATUS_INCOMPLETE, IPN_PAY_STATUS_COMPLETED, IPN_PAY_STATUS_CANCELED, IPN_TYPE_PREAPPROVAL
|
|
from regluit.core import goodreads
|
|
from tastypie.models import ApiKey
|
|
from regluit.payment.models import Transaction
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def slideshow(max):
|
|
ending = models.Campaign.objects.filter(status='ACTIVE').order_by('deadline')
|
|
count = ending.count()
|
|
is_preview = settings.IS_PREVIEW
|
|
i = 0
|
|
j = 0
|
|
|
|
if is_preview:
|
|
# on the preview site there are no active campaigns, so we should show most-wished books instead
|
|
worklist = models.Work.objects.order_by('-num_wishes')[:max]
|
|
else:
|
|
worklist = []
|
|
while i<max and count>0:
|
|
worklist.append(ending[j].work)
|
|
i += 1
|
|
j += 1
|
|
if j == count:
|
|
j = 0
|
|
|
|
return worklist
|
|
|
|
def home(request):
|
|
if request.user.is_authenticated():
|
|
return HttpResponseRedirect(reverse('supporter',
|
|
args=[request.user.username]))
|
|
|
|
worklist = slideshow(12)
|
|
works = worklist[:6]
|
|
works2 = worklist[6:12]
|
|
|
|
events = models.Wishes.objects.order_by('-created')[0:2]
|
|
return render(request, 'home.html', {'suppress_search_box': True, 'works': works, 'works2': works2, 'events': events})
|
|
|
|
def stub(request):
|
|
path = request.path[6:] # get rid of /stub/
|
|
return render(request,'stub.html', {'path': path})
|
|
|
|
def work(request, work_id, action='display'):
|
|
try:
|
|
work = models.Work.objects.get(id = work_id)
|
|
except models.Work.DoesNotExist:
|
|
try:
|
|
work = models.WasWork.objects.get(was = work_id).work
|
|
except models.WasWork.DoesNotExist:
|
|
raise Http404
|
|
|
|
if request.method == 'POST' and not request.user.is_anonymous():
|
|
activetab = '4'
|
|
ebook_form= EbookForm( data = request.POST)
|
|
if ebook_form.is_valid():
|
|
ebook_form.save()
|
|
alert = 'Thanks for adding an ebook to unglue.it!'
|
|
else:
|
|
alert = ebook_form.errors
|
|
else:
|
|
alert=''
|
|
try:
|
|
activetab = request.GET['tab']
|
|
if activetab not in ['1', '2', '3', '4']:
|
|
activetab = '1';
|
|
except:
|
|
activetab = '1';
|
|
editions = work.editions.all().order_by('-publication_date')
|
|
campaign = work.last_campaign()
|
|
try:
|
|
pledged = campaign.transactions().filter(user=request.user, status="ACTIVE")
|
|
except:
|
|
pledged = None
|
|
try:
|
|
pubdate = work.publication_date[:4]
|
|
except IndexError:
|
|
pubdate = 'unknown'
|
|
if not request.user.is_anonymous():
|
|
claimform = UserClaimForm( request.user, data={'work':work.pk, 'user': request.user.id}, prefix = 'claim')
|
|
for edition in editions:
|
|
#edition.ebook_form = EbookForm( data = {'user':request.user.id, 'edition':edition.pk })
|
|
edition.ebook_form = EbookForm( instance= models.Ebook(user = request.user, edition = edition, provider = 'x' ), prefix = 'ebook_%d'%edition.id)
|
|
else:
|
|
claimform = None
|
|
if campaign:
|
|
q = Q(campaign=campaign) | Q(campaign__isnull=True)
|
|
premiums = models.Premium.objects.filter(q)
|
|
else:
|
|
premiums = None
|
|
|
|
wishers = work.num_wishes
|
|
base_url = request.build_absolute_uri("/")[:-1]
|
|
|
|
|
|
#may want to deprecate the following
|
|
if action == 'setup_campaign':
|
|
return render(request, 'setup_campaign.html', {'work': work})
|
|
else:
|
|
return render(request, 'work.html', {
|
|
'work': work,
|
|
'premiums': premiums,
|
|
'ungluers': userlists.supporting_users(work, 5),
|
|
'claimform': claimform,
|
|
'wishers': wishers,
|
|
'base_url': base_url,
|
|
'editions': editions,
|
|
'pubdate': pubdate,
|
|
'pledged':pledged,
|
|
'activetab': activetab,
|
|
'alert':alert
|
|
})
|
|
|
|
def manage_campaign(request, id):
|
|
campaign = get_object_or_404(models.Campaign, id=id)
|
|
campaign.not_manager=False
|
|
campaign.problems=[]
|
|
if (not request.user.is_authenticated) or (not request.user in campaign.managers.all()):
|
|
campaign.not_manager=True
|
|
return render(request, 'manage_campaign.html', {'campaign': campaign})
|
|
alerts = []
|
|
if request.method == 'POST':
|
|
form= ManageCampaignForm(instance=campaign, data=request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
alerts.append(_('Campaign data has been saved'))
|
|
else:
|
|
alerts.append(_('Campaign data has NOT been saved'))
|
|
if 'launch' in request.POST.keys():
|
|
if campaign.launchable :
|
|
campaign.activate()
|
|
alerts.append(_('Campaign has been launched'))
|
|
else:
|
|
alerts.append(_('Campaign has NOT been launched'))
|
|
else:
|
|
form= ManageCampaignForm(instance=campaign)
|
|
return render(request, 'manage_campaign.html', {'campaign': campaign, 'form':form, 'problems': campaign.problems, 'alerts': alerts})
|
|
|
|
def googlebooks(request, googlebooks_id):
|
|
try:
|
|
edition = models.Identifier.objects.get(type='goog',value=googlebooks_id).edition
|
|
except models.Identifier.DoesNotExist:
|
|
try:
|
|
edition = bookloader.add_by_googlebooks_id(googlebooks_id)
|
|
if edition.new:
|
|
# add related editions asynchronously
|
|
tasks.populate_edition.delay(edition.isbn_13)
|
|
except bookloader.LookupFailure:
|
|
logger.warning("failed to load googlebooks_id %s" % googlebooks_id)
|
|
return HttpResponseNotFound("failed looking up googlebooks id %s" % googlebooks_id)
|
|
if not edition:
|
|
return HttpResponseNotFound("invalid googlebooks id")
|
|
work_url = reverse('work', kwargs={'work_id': edition.work.id})
|
|
return HttpResponseRedirect(work_url)
|
|
|
|
def subjects(request):
|
|
order = request.GET.get('order')
|
|
subjects = models.Subject.objects.all()
|
|
subjects = subjects.annotate(Count('works'))
|
|
|
|
if request.GET.get('order') == 'count':
|
|
subjects = subjects.order_by('-works__count')
|
|
else:
|
|
subjects = subjects.order_by('name')
|
|
|
|
return render(request, 'subjects.html', {'subjects': subjects})
|
|
|
|
|
|
recommended_user = User.objects.filter( username=settings.UNGLUEIT_RECOMMENDED_USERNAME)
|
|
|
|
class WorkListView(ListView):
|
|
template_name = "work_list.html"
|
|
context_object_name = "work_list"
|
|
|
|
def get_queryset(self):
|
|
facet = self.kwargs['facet']
|
|
if (facet == 'popular'):
|
|
return models.Work.objects.order_by('-num_wishes', 'id')
|
|
elif (facet == 'recommended'):
|
|
return models.Work.objects.filter(wishlists__user=recommended_user).order_by('-num_wishes')
|
|
elif (facet == 'new'):
|
|
return models.Work.objects.filter(num_wishes__gt=0).order_by('-created', '-num_wishes' ,'id')
|
|
else:
|
|
return models.Work.objects.all().order_by('-created', 'id')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(WorkListView, self).get_context_data(**kwargs)
|
|
qs=self.get_queryset()
|
|
context['ungluers'] = userlists.work_list_users(qs,5)
|
|
context['facet'] =self.kwargs['facet']
|
|
context['works_unglued'] = qs.filter(editions__ebooks__isnull=False).distinct()
|
|
context['works_active'] = qs.exclude(editions__ebooks__isnull=False).filter(Q(campaigns__status='ACTIVE') | Q(campaigns__status='SUCCESSFUL')).distinct()
|
|
context['works_wished'] = qs.exclude(editions__ebooks__isnull=False).exclude(campaigns__status='ACTIVE').exclude(campaigns__status='SUCCESSFUL').distinct()
|
|
|
|
context['activetab'] = "#3"
|
|
|
|
counts={}
|
|
counts['unglued'] = context['works_unglued'].count()
|
|
counts['unglueing'] = context['works_active'].count()
|
|
counts['wished'] = context['works_wished'].count()
|
|
context['counts'] = counts
|
|
return context
|
|
|
|
class UngluedListView(ListView):
|
|
template_name = "unglued_list.html"
|
|
context_object_name = "work_list"
|
|
|
|
def work_set_counts(self,work_set):
|
|
counts={}
|
|
counts['unglued'] = work_set.annotate(ebook_count=Count('editions__ebooks')).filter(ebook_count__gt=0).count()
|
|
return counts
|
|
|
|
def get_queryset(self):
|
|
facet = self.kwargs['facet']
|
|
if (facet == 'popular'):
|
|
return models.Work.objects.filter(editions__ebooks__isnull=False).distinct().order_by('-num_wishes')
|
|
else:
|
|
#return models.Work.objects.annotate(ebook_count=Count('editions__ebooks')).filter(ebook_count__gt=0).order_by('-created')
|
|
return models.Work.objects.filter(editions__ebooks__isnull=False).distinct().order_by('-created')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(UngluedListView, self).get_context_data(**kwargs)
|
|
qs=self.get_queryset()
|
|
context['counts'] = self.work_set_counts(qs)
|
|
context['ungluers'] = userlists.work_list_users(qs,5)
|
|
context['facet'] =self.kwargs['facet']
|
|
context['activetab'] = "#1"
|
|
return context
|
|
|
|
|
|
class CampaignListView(ListView):
|
|
template_name = "campaign_list.html"
|
|
context_object_name = "campaign_list"
|
|
model = models.Campaign
|
|
|
|
def get_queryset(self):
|
|
facet = self.kwargs['facet']
|
|
if (facet == 'newest'):
|
|
return models.Campaign.objects.filter(status='ACTIVE').order_by('-activated')
|
|
elif (facet == 'pledged'):
|
|
return models.Campaign.objects.filter(status='ACTIVE').annotate(total_pledge=Sum('transaction__amount')).order_by('-total_pledge')
|
|
elif (facet == 'pledges'):
|
|
return models.Campaign.objects.filter(status='ACTIVE').annotate(pledges=Count('transaction')).order_by('-pledges')
|
|
elif (facet == 'almost'):
|
|
return models.Campaign.objects.filter(status='ACTIVE').all() # STUB: will need to make db changes to make this work
|
|
elif (facet == 'ending'):
|
|
return models.Campaign.objects.filter(status='ACTIVE').order_by('deadline')
|
|
else:
|
|
return models.Campaign.objects.all()
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(CampaignListView, self).get_context_data(**kwargs)
|
|
qs=self.get_queryset()
|
|
context['ungluers'] = userlists.campaign_list_users(qs,5)
|
|
context['facet'] =self.kwargs['facet']
|
|
return context
|
|
|
|
class PledgeView(FormView):
|
|
template_name="pledge.html"
|
|
form_class = CampaignPledgeForm
|
|
embedded = False
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(PledgeView, self).get_context_data(**kwargs)
|
|
|
|
work = get_object_or_404(models.Work, id=self.kwargs["work_id"])
|
|
|
|
campaign = work.last_campaign()
|
|
|
|
if campaign:
|
|
premiums = campaign.effective_premiums()
|
|
|
|
premium_id = self.request.REQUEST.get('premium_id', None)
|
|
preapproval_amount = self.request.REQUEST.get('preapproval_amount', None)
|
|
|
|
if premium_id is not None and preapproval_amount is None:
|
|
try:
|
|
preapproval_amount = D(models.Premium.objects.get(id=premium_id).amount)
|
|
except:
|
|
preapproval_amount = None
|
|
|
|
logger.info("preapproval_amount, premium_id: %s %s ", preapproval_amount, premium_id)
|
|
data = {'preapproval_amount':preapproval_amount, 'premium_id':premium_id}
|
|
|
|
form = CampaignPledgeForm(data)
|
|
|
|
context.update({'work':work,'campaign':campaign, 'premiums':premiums, 'form':form, 'premium_id':premium_id, 'faqmenu': 'pledge'})
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
work_id = self.kwargs["work_id"]
|
|
preapproval_amount = form.cleaned_data["preapproval_amount"]
|
|
anonymous = form.cleaned_data["anonymous"]
|
|
|
|
# right now, if there is a non-zero pledge amount, go with that. otherwise, do the pre_approval
|
|
campaign = models.Work.objects.get(id=int(work_id)).last_campaign()
|
|
|
|
p = PaymentManager(embedded=self.embedded)
|
|
|
|
# PledgeView is wrapped in login_required -- so in theory, user should never be None -- but I'll keep this logic here for now.
|
|
if self.request.user.is_authenticated():
|
|
user = self.request.user
|
|
else:
|
|
user = None
|
|
|
|
if not self.embedded:
|
|
|
|
return_url = None
|
|
cancel_url = None
|
|
|
|
# the recipients of this authorization is not specified here but rather by the PaymentManager.
|
|
# set the expiry date based on the campaign deadline
|
|
expiry = campaign.deadline + timedelta( days=settings.PREAPPROVAL_PERIOD_AFTER_CAMPAIGN )
|
|
t, url = p.authorize('USD', TARGET_TYPE_CAMPAIGN, preapproval_amount, expiry=expiry, campaign=campaign, list=None, user=user,
|
|
return_url=return_url, cancel_url=cancel_url, anonymous=anonymous)
|
|
else: # embedded view -- which we're not actively using right now.
|
|
# embedded view triggerws instant payment: send to the partnering RH
|
|
receiver_list = [{'email':settings.PAYPAL_NONPROFIT_PARTNER_EMAIL, 'amount':preapproval_amount}]
|
|
|
|
return_url = None
|
|
cancel_url = None
|
|
|
|
t, url = p.pledge('USD', TARGET_TYPE_CAMPAIGN, receiver_list, campaign=campaign, list=None, user=user,
|
|
return_url=return_url, cancel_url=cancel_url, anonymous=anonymous)
|
|
|
|
if url:
|
|
logger.info("PledgeView paypal: " + url)
|
|
print >> sys.stderr, "CampaignFormView paypal: ", url
|
|
return HttpResponseRedirect(url)
|
|
else:
|
|
response = t.reference
|
|
logger.info("PledgeView paypal: Error " + str(t.reference))
|
|
return HttpResponse(response)
|
|
|
|
class PledgeCompleteView(TemplateView):
|
|
"""A callback for PayPal to tell unglue.it that a payment transaction has completed successfully.
|
|
|
|
Possible things to implement:
|
|
|
|
after pledging, supporter receives email including thanks, work pledged, amount, expiry date, any next steps they should expect; others?
|
|
study other confirmation emails for their contents
|
|
after pledging, supporters are returned to a thank-you screen
|
|
should have prominent "thank you" or "congratulations" message
|
|
should have prominent share options
|
|
should suggest other works for supporters to explore (on what basis?)
|
|
link to work page? or to page on which supporter entered the process? (if the latter, how does that work with widgets?)
|
|
should note that a confirmation email has been sent to $email from $sender
|
|
should briefly note next steps (e.g. if this campaign succeeds you will be emailed on date X)
|
|
|
|
"""
|
|
|
|
template_name="pledge_complete.html"
|
|
|
|
def get_context_data(self):
|
|
# pick up all get and post parameters and display
|
|
context = super(PledgeCompleteView, self).get_context_data()
|
|
|
|
output = "pledge complete"
|
|
output += self.request.method + "\n" + str(self.request.REQUEST.items())
|
|
context["output"] = output
|
|
|
|
if self.request.user.is_authenticated():
|
|
user = self.request.user
|
|
else:
|
|
user = None
|
|
|
|
# pull out the transaction id and try to get the corresponding Transaction
|
|
transaction_id = self.request.REQUEST.get("tid")
|
|
transaction = Transaction.objects.get(id=transaction_id)
|
|
|
|
# work and campaign in question
|
|
try:
|
|
campaign = transaction.campaign
|
|
work = campaign.work
|
|
except Exception, e:
|
|
campaign = None
|
|
work = None
|
|
|
|
# we need to check whether the user tied to the transaction is indeed the authenticated user.
|
|
|
|
correct_user = False
|
|
try:
|
|
if user.id == transaction.user.id:
|
|
correct_user = True
|
|
except Exception, e:
|
|
pass
|
|
|
|
# check that the user had not already approved the transaction
|
|
# do we need to first run PreapprovalDetails to check on the status
|
|
|
|
# is it of type=PAYMENT_TYPE_AUTHORIZATION and status is NONE or ACTIVE (but approved is false)
|
|
|
|
if transaction.type == PAYMENT_TYPE_AUTHORIZATION:
|
|
correct_transaction_type = True
|
|
else:
|
|
correct_transaction_type = False
|
|
|
|
context["transaction"] = transaction
|
|
context["correct_user"] = correct_user
|
|
context["correct_transaction_type"] = correct_transaction_type
|
|
context["work"] = work
|
|
context["campaign"] = campaign
|
|
context["faqmenu"] = "complete"
|
|
|
|
return context
|
|
|
|
|
|
class PledgeCancelView(TemplateView):
|
|
"""A callback for PayPal to tell unglue.it that a payment transaction has been canceled by the user"""
|
|
template_name="pledge_cancel.html"
|
|
|
|
def get_context_data(self):
|
|
context = super(PledgeCancelView, self).get_context_data()
|
|
|
|
if self.request.user.is_authenticated():
|
|
user = self.request.user
|
|
else:
|
|
user = None
|
|
|
|
# pull out the transaction id and try to get the corresponding Transaction
|
|
transaction_id = self.request.REQUEST.get("tid")
|
|
transaction = Transaction.objects.get(id=transaction_id)
|
|
|
|
# work and campaign in question
|
|
try:
|
|
campaign = transaction.campaign
|
|
work = campaign.work
|
|
except Exception, e:
|
|
campaign = None
|
|
work = None
|
|
|
|
# we need to check whether the user tied to the transaction is indeed the authenticated user.
|
|
|
|
correct_user = False
|
|
try:
|
|
if user.id == transaction.user.id:
|
|
correct_user = True
|
|
except Exception, e:
|
|
pass
|
|
|
|
# check that the user had not already approved the transaction
|
|
# do we need to first run PreapprovalDetails to check on the status
|
|
|
|
# is it of type=PAYMENT_TYPE_AUTHORIZATION and status is NONE or ACTIVE (but approved is false)
|
|
|
|
if transaction.type == PAYMENT_TYPE_AUTHORIZATION:
|
|
correct_transaction_type = True
|
|
else:
|
|
correct_transaction_type = False
|
|
|
|
# status?
|
|
|
|
# give the user an opportunity to approved the transaction again
|
|
# provide a URL to click on.
|
|
# https://www.sandbox.paypal.com/?cmd=_ap-preapproval&preapprovalkey=PA-6JV656290V840615H
|
|
try_again_url = '%s?cmd=_ap-preapproval&preapprovalkey=%s' % (settings.PAYPAL_PAYMENT_HOST, transaction.preapproval_key)
|
|
|
|
context["transaction"] = transaction
|
|
context["correct_user"] = correct_user
|
|
context["correct_transaction_type"] = correct_transaction_type
|
|
context["try_again_url"] = try_again_url
|
|
context["work"] = work
|
|
context["campaign"] = campaign
|
|
context["faqmenu"] = "cancel"
|
|
|
|
return context
|
|
|
|
|
|
class DonateView(FormView):
|
|
template_name="donate.html"
|
|
form_class = DonateForm
|
|
embedded = False
|
|
|
|
#def get_context_data(self, **kwargs):
|
|
# context = super(DonateView, self).get_context_data(**kwargs)
|
|
#
|
|
# form = CampaignPledgeForm(data)
|
|
#
|
|
# context.update({'work':work,'campaign':campaign, 'premiums':premiums, 'form':form, 'premium_id':premium_id})
|
|
# return context
|
|
|
|
def form_valid(self, form):
|
|
donation_amount = form.cleaned_data["donation_amount"]
|
|
anonymous = form.cleaned_data["anonymous"]
|
|
|
|
# right now, if there is a non-zero pledge amount, go with that. otherwise, do the pre_approval
|
|
campaign = None
|
|
|
|
p = PaymentManager(embedded=self.embedded)
|
|
|
|
# we should force login at this point -- or if no account, account creation, login, and return to this spot
|
|
if self.request.user.is_authenticated():
|
|
user = self.request.user
|
|
else:
|
|
user = None
|
|
|
|
# instant payment: send to the partnering RH
|
|
receiver_list = [{'email':settings.PAYPAL_NONPROFIT_PARTNER_EMAIL, 'amount':donation_amount}]
|
|
|
|
#redirect the page back to campaign page on success
|
|
return_url = self.request.build_absolute_uri(reverse('donate'))
|
|
|
|
t, url = p.pledge('USD', TARGET_TYPE_DONATION, receiver_list, campaign=campaign, list=None, user=user,
|
|
return_url=return_url, anonymous=anonymous)
|
|
|
|
if url:
|
|
return HttpResponseRedirect(url)
|
|
else:
|
|
response = t.reference
|
|
logger.info("PledgeView paypal: Error " + str(t.reference))
|
|
return HttpResponse(response)
|
|
|
|
|
|
def claim(request):
|
|
if request.method == 'GET':
|
|
data = request.GET
|
|
else:
|
|
data = request.POST
|
|
form = UserClaimForm(request.user, data=data)
|
|
if form.is_valid():
|
|
# make sure we're not creating a duplicate claim
|
|
if not models.Claim.objects.filter(work=data['work'], rights_holder=data['rights_holder'], status='pending').count():
|
|
form.save()
|
|
return HttpResponseRedirect(reverse('work', kwargs={'work_id': data['work']}))
|
|
else:
|
|
work = models.Work.objects.get(id=data['work'])
|
|
rights_holder = models.RightsHolder.objects.get(id=data['rights_holder'])
|
|
context = {'form': form, 'work': work, 'rights_holder':rights_holder }
|
|
return render(request, "claim.html", context)
|
|
|
|
def rh_tools(request):
|
|
if not request.user.is_authenticated() :
|
|
return render(request, "rh_tools.html")
|
|
claims = request.user.claim.filter(user=request.user)
|
|
campaign_form = "xxx"
|
|
if not claims:
|
|
return render(request, "rh_tools.html")
|
|
for claim in claims:
|
|
claim.campaigns= claim.work.campaigns.all()
|
|
claim.can_open_new=True
|
|
for campaign in claim.campaigns:
|
|
if campaign.status in ['ACTIVE','INITIALIZED']:
|
|
claim.can_open_new=False
|
|
if claim.status == 'active' and claim.can_open_new:
|
|
if request.method == 'POST' and int(request.POST['work']) == claim.work.id :
|
|
claim.campaign_form = OpenCampaignForm(request.POST)
|
|
if claim.campaign_form.is_valid():
|
|
new_campaign = claim.campaign_form.save(commit=False)
|
|
new_campaign.deadline = date_today() + timedelta(days=int(settings.UNGLUEIT_LONGEST_DEADLINE))
|
|
new_campaign.target = D(settings.UNGLUEIT_MINIMUM_TARGET)
|
|
new_campaign.save()
|
|
claim.campaign_form.save_m2m()
|
|
claim.can_open_new=False
|
|
else:
|
|
claim.campaign_form = OpenCampaignForm(data={'work': claim.work, 'name': claim.work.title, 'userid': request.user.id})
|
|
else:
|
|
claim.can_open_new=False
|
|
return render(request, "rh_tools.html", {'claims': claims ,})
|
|
|
|
def rh_admin(request):
|
|
if not request.user.is_authenticated() :
|
|
return render(request, "admins_only.html")
|
|
if not request.user.is_staff :
|
|
return render(request, "admins_only.html")
|
|
PendingFormSet = modelformset_factory(models.Claim, fields=['status'], extra=0)
|
|
pending_data = models.Claim.objects.filter(status = 'pending')
|
|
active_data = models.Claim.objects.filter(status = 'active')
|
|
if request.method == 'POST':
|
|
if 'create_rights_holder' in request.POST.keys():
|
|
form = RightsHolderForm(data=request.POST)
|
|
pending_formset = PendingFormSet (queryset=pending_data)
|
|
if form.is_valid():
|
|
form.save()
|
|
if 'set_claim_status' in request.POST.keys():
|
|
pending_formset = PendingFormSet (request.POST, request.FILES, queryset=pending_data)
|
|
form = RightsHolderForm()
|
|
if pending_formset.is_valid():
|
|
pending_formset.save()
|
|
pending_formset = PendingFormSet(queryset=pending_data)
|
|
else:
|
|
form = RightsHolderForm()
|
|
pending_formset = PendingFormSet(queryset=pending_data)
|
|
rights_holders = models.RightsHolder.objects.all()
|
|
|
|
context = {
|
|
'request': request,
|
|
'rights_holders': rights_holders,
|
|
'form': form,
|
|
'pending': zip(pending_data,pending_formset),
|
|
'pending_formset': pending_formset,
|
|
'active_data': active_data,
|
|
}
|
|
return render(request, "rights_holders.html", context)
|
|
|
|
def campaign_admin(request):
|
|
if not request.user.is_authenticated() :
|
|
return render(request, "admins_only.html")
|
|
if not request.user.is_staff :
|
|
return render(request, "admins_only.html")
|
|
|
|
context = {}
|
|
|
|
def campaigns_types():
|
|
# pull out Campaigns with Transactions that are ACTIVE -- and hence can be executed
|
|
# Campaign.objects.filter(transaction__status='ACTIVE')
|
|
|
|
campaigns_with_active_transactions = models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_ACTIVE)
|
|
|
|
# pull out Campaigns with Transactions that are INCOMPLETE
|
|
|
|
campaigns_with_incomplete_transactions = models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_INCOMPLETE)
|
|
|
|
# show all Campaigns with Transactions that are COMPLETED
|
|
|
|
campaigns_with_completed_transactions = models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_COMPLETED)
|
|
|
|
# show Campaigns with Transactions that are CANCELED
|
|
|
|
campaigns_with_canceled_transactions = models.Campaign.objects.filter(transaction__status=IPN_PAY_STATUS_CANCELED)
|
|
|
|
return (campaigns_with_active_transactions, campaigns_with_incomplete_transactions, campaigns_with_completed_transactions,
|
|
campaigns_with_canceled_transactions)
|
|
|
|
form = CampaignAdminForm()
|
|
pm = PaymentManager()
|
|
check_status_results = None
|
|
command_status = None
|
|
|
|
if request.method == 'GET':
|
|
pass
|
|
elif request.method == 'POST':
|
|
if 'campaign_checkstatus' in request.POST.keys():
|
|
# campaign_checkstatus
|
|
try:
|
|
status = pm.checkStatus()
|
|
check_status_results = ""
|
|
# parse the output to display chat transaction statuses have been updated
|
|
if len(status["preapprovals"]):
|
|
for t in status["preapprovals"]:
|
|
check_status_results += "<p>Preapproval key: %s updated</p>" % (t["key"])
|
|
else:
|
|
check_status_results += "<p>No preapprovals needed updating</p>"
|
|
if len(status["payments"]):
|
|
for t in status["payments"]:
|
|
info = ", ".join(["%s:%s" % (k,v) for (k,v) in t.items()])
|
|
check_status_results += "<p>Payment updated: %s </p>" % (info)
|
|
|
|
else:
|
|
check_status_results += "<p>No payments needed updating</p>"
|
|
command_status = _("Transactions updated based on PaymentDetails and PreapprovalDetails")
|
|
except Exception, e:
|
|
check_status_results = e
|
|
elif 'execute_campaigns' in request.POST.keys():
|
|
c_id = request.POST.get('active_campaign', None)
|
|
if c_id is not None:
|
|
try:
|
|
campaign = models.Campaign.objects.get(id=c_id)
|
|
results = pm.execute_campaign(campaign)
|
|
command_status = str(results)
|
|
except Exception, e:
|
|
command_status = "Error in executing transactions for campaign %s " % (str(e))
|
|
elif 'finish_campaigns' in request.POST.keys():
|
|
c_id = request.POST.get('incomplete_campaign', None)
|
|
if c_id is not None:
|
|
try:
|
|
campaign = models.Campaign.objects.get(id=c_id)
|
|
results = pm.finish_campaign(campaign)
|
|
command_status = str(results)
|
|
except Exception, e:
|
|
command_status = "Error in finishing transactions for campaign %s " % (str(e))
|
|
|
|
elif 'cancel_campaigns' in request.POST.keys():
|
|
c_id = request.POST.get('active_campaign', None)
|
|
if c_id is not None:
|
|
try:
|
|
campaign = models.Campaign.objects.get(id=c_id)
|
|
results = pm.cancel_campaign(campaign)
|
|
command_status = str(results)
|
|
except Exception, e:
|
|
command_status = "Error in canceling transactions for campaign %s " % (str(e))
|
|
|
|
(campaigns_with_active_transactions, campaigns_with_incomplete_transactions, campaigns_with_completed_transactions,
|
|
campaigns_with_canceled_transactions) = campaigns_types()
|
|
|
|
context.update({
|
|
'form': form,
|
|
'check_status_results':check_status_results,
|
|
'campaigns_with_active_transactions': campaigns_with_active_transactions,
|
|
'campaigns_with_incomplete_transactions': campaigns_with_incomplete_transactions,
|
|
'campaigns_with_completed_transactions': campaigns_with_completed_transactions,
|
|
'campaigns_with_canceled_transactions': campaigns_with_canceled_transactions,
|
|
'command_status': command_status
|
|
})
|
|
|
|
return render(request, "campaign_admin.html", context)
|
|
|
|
def supporter(request, supporter_username, template_name):
|
|
supporter = get_object_or_404(User, username=supporter_username)
|
|
wishlist = supporter.wishlist
|
|
works = []
|
|
works2 = []
|
|
works_unglued = []
|
|
works_active = []
|
|
works_wished = []
|
|
is_preview = settings.IS_PREVIEW
|
|
|
|
if (wishlist.works.all()):
|
|
# querysets for tabs
|
|
# unglued tab is anything with an existing ebook
|
|
## .order_by() may clash with .distinct() and this should be fixed
|
|
works_unglued = wishlist.works.all().filter(editions__ebooks__isnull=False).distinct().order_by('-num_wishes')
|
|
|
|
# take the set complement of the unglued tab and filter it for active works to get middle tab
|
|
result = wishlist.works.all().exclude(pk__in=works_unglued.values_list('pk', flat=True))
|
|
works_active = result.filter(Q(campaigns__status='ACTIVE') | Q(campaigns__status='SUCCESSFUL')).order_by('-campaigns__status', 'campaigns__deadline').distinct()
|
|
|
|
# everything else goes in tab 3
|
|
works_wished = result.exclude(pk__in=works_active.values_list('pk', flat=True)).order_by('-num_wishes')
|
|
|
|
# badge counts
|
|
backed = works_unglued.count()
|
|
backing = works_active.count()
|
|
wished = works_wished.count()
|
|
|
|
else:
|
|
backed = 0
|
|
backing = 0
|
|
wished = 0
|
|
|
|
worklist = slideshow(8)
|
|
works = worklist[:4]
|
|
works2 = worklist[4:8]
|
|
|
|
date = supporter.date_joined.strftime("%B %d, %Y")
|
|
|
|
# following block to support profile admin form in supporter page
|
|
if request.user.is_authenticated() and request.user.username == supporter_username:
|
|
|
|
try:
|
|
profile_obj=request.user.get_profile()
|
|
except ObjectDoesNotExist:
|
|
profile_obj= models.UserProfile()
|
|
profile_obj.user=request.user
|
|
|
|
if request.method == 'POST':
|
|
profile_form = ProfileForm(data=request.POST,instance=profile_obj)
|
|
if profile_form.is_valid():
|
|
if profile_form.cleaned_data['clear_facebook'] or profile_form.cleaned_data['clear_twitter'] or profile_form.cleaned_data['clear_goodreads'] :
|
|
if profile_form.cleaned_data['clear_facebook']:
|
|
profile_obj.facebook_id=0
|
|
if profile_form.cleaned_data['clear_twitter']:
|
|
profile_obj.twitter_id=""
|
|
if profile_form.cleaned_data['clear_goodreads']:
|
|
profile_obj.goodreads_user_id = None
|
|
profile_obj.goodreads_user_name = None
|
|
profile_obj.goodreads_user_link = None
|
|
profile_obj.goodreads_auth_token = None
|
|
profile_obj.goodreads_auth_secret = None
|
|
|
|
profile_obj.save()
|
|
profile_form.save()
|
|
|
|
else:
|
|
profile_form= ProfileForm(instance=profile_obj)
|
|
|
|
if request.user.profile.goodreads_user_id is not None:
|
|
goodreads_id = request.user.profile.goodreads_user_id
|
|
else:
|
|
goodreads_id = None
|
|
|
|
if request.user.profile.librarything_id is not None:
|
|
librarything_id = request.user.profile.librarything_id
|
|
else:
|
|
librarything_id = None
|
|
else:
|
|
profile_form = ''
|
|
goodreads_id = None
|
|
librarything_id = None
|
|
|
|
context = {
|
|
"supporter": supporter,
|
|
"wishlist": wishlist,
|
|
"works_unglued": works_unglued,
|
|
"works_active": works_active,
|
|
"works_wished": works_wished,
|
|
"works": works,
|
|
"works2": works2,
|
|
"is_preview": is_preview,
|
|
"backed": backed,
|
|
"backing": backing,
|
|
"wished": wished,
|
|
"date": date,
|
|
"profile_form": profile_form,
|
|
"ungluers": userlists.other_users(supporter, 5 ),
|
|
"goodreads_auth_url": reverse('goodreads_auth'),
|
|
"goodreads_id": goodreads_id,
|
|
"librarything_id": librarything_id,
|
|
"activetab": "#3"
|
|
}
|
|
|
|
return render(request, template_name, context)
|
|
|
|
def edit_user(request):
|
|
form=UserData()
|
|
if not request.user.is_authenticated():
|
|
return HttpResponseRedirect(reverse('auth_login'))
|
|
oldusername=request.user.username
|
|
if request.method == 'POST':
|
|
# surely there's a better way to add data to the POST data?
|
|
postcopy=request.POST.copy()
|
|
postcopy['oldusername']=oldusername
|
|
form = UserData(postcopy)
|
|
if form.is_valid(): # All validation rules pass, go and change the username
|
|
request.user.username=form.cleaned_data['username']
|
|
request.user.save()
|
|
return HttpResponseRedirect(reverse('home')) # Redirect after POST
|
|
return render(request,'registration/user_change_form.html', {'form': form},)
|
|
|
|
|
|
def search(request):
|
|
q = request.GET.get('q', None)
|
|
page = int(request.GET.get('page', 1))
|
|
results = gluejar_search(q, user_ip=request.META['REMOTE_ADDR'], page=page)
|
|
|
|
# flag search result as on wishlist as appropriate
|
|
if not request.user.is_anonymous():
|
|
ungluers = userlists.other_users(request.user, 5)
|
|
else:
|
|
ungluers = userlists.other_users(None, 5)
|
|
|
|
works=[]
|
|
for result in results:
|
|
try:
|
|
work = models.Identifier.objects.get(type='goog',value=result['googlebooks_id']).work
|
|
works.append(work)
|
|
except models.Identifier.DoesNotExist:
|
|
works.append(result)
|
|
context = {
|
|
"q": q,
|
|
"results": works,
|
|
"ungluers": ungluers
|
|
}
|
|
return render(request, 'search.html', context)
|
|
|
|
# TODO: perhaps this functionality belongs in the API?
|
|
@require_POST
|
|
@login_required
|
|
@csrf_exempt
|
|
def wishlist(request):
|
|
googlebooks_id = request.POST.get('googlebooks_id', None)
|
|
remove_work_id = request.POST.get('remove_work_id', None)
|
|
add_work_id = request.POST.get('add_work_id', None)
|
|
|
|
if googlebooks_id:
|
|
try:
|
|
edition = bookloader.add_by_googlebooks_id(googlebooks_id)
|
|
if edition.new:
|
|
# add related editions asynchronously
|
|
tasks.populate_edition.delay(edition.isbn_13)
|
|
request.user.wishlist.add_work(edition.work,'user')
|
|
except bookloader.LookupFailure:
|
|
logger.warning("failed to load googlebooks_id %s" % googlebooks_id)
|
|
except Exception, e:
|
|
logger.warning("Error in wishlist adding %s" % (e))
|
|
# TODO: redirect to work page, when it exists
|
|
return HttpResponseRedirect('/')
|
|
elif remove_work_id:
|
|
try:
|
|
work = models.Work.objects.get(id=int(remove_work_id))
|
|
except models.Work.DoesNotExist:
|
|
try:
|
|
work = models.WasWork.objects.get(was = work_id).work
|
|
except models.WasWork.DoesNotExist:
|
|
raise Http404
|
|
request.user.wishlist.remove_work(work)
|
|
# TODO: where to redirect?
|
|
return HttpResponseRedirect('/')
|
|
elif add_work_id:
|
|
# if adding from work page, we have may work.id, not googlebooks_id
|
|
try:
|
|
work = models.Work.objects.get(pk=add_work_id)
|
|
except models.Work.DoesNotExist:
|
|
try:
|
|
work = models.WasWork.objects.get(was = work_id).work
|
|
except models.WasWork.DoesNotExist:
|
|
raise Http404
|
|
|
|
request.user.wishlist.add_work(work,'user')
|
|
return HttpResponseRedirect('/')
|
|
|
|
class CampaignFormView(FormView):
|
|
template_name="campaign_detail.html"
|
|
form_class = CampaignPledgeForm
|
|
embedded = False
|
|
|
|
def get_context_data(self, **kwargs):
|
|
pk = self.kwargs["pk"]
|
|
campaign = models.Campaign.objects.get(id=int(pk))
|
|
context = super(CampaignFormView, self).get_context_data(**kwargs)
|
|
base_url = self.request.build_absolute_uri("/")[:-1]
|
|
context.update({
|
|
'embedded': self.embedded,
|
|
'campaign': campaign,
|
|
'base_url':base_url
|
|
})
|
|
|
|
return context
|
|
|
|
def form_valid(self,form):
|
|
pk = self.kwargs["pk"]
|
|
preapproval_amount = form.cleaned_data["preapproval_amount"]
|
|
anonymous = form.cleaned_data["anonymous"]
|
|
|
|
# right now, if there is a non-zero pledge amount, go with that. otherwise, do the pre_approval
|
|
campaign = models.Campaign.objects.get(id=int(pk))
|
|
|
|
p = PaymentManager(embedded=self.embedded)
|
|
|
|
# we should force login at this point -- or if no account, account creation, login, and return to this spot
|
|
if self.request.user.is_authenticated():
|
|
user = self.request.user
|
|
else:
|
|
user = None
|
|
|
|
# calculate the work corresponding to the campaign id
|
|
work_id = campaign.work.id
|
|
|
|
# set the expiry date based on the campaign deadline
|
|
expiry = campaign.deadline + timedelta( days=settings.PREAPPROVAL_PERIOD_AFTER_CAMPAIGN )
|
|
|
|
if not self.embedded:
|
|
|
|
return_url = self.request.build_absolute_uri(reverse('work',kwargs={'work_id': str(work_id)}))
|
|
t, url = p.authorize('USD', TARGET_TYPE_CAMPAIGN, preapproval_amount, expiry=expiry, campaign=campaign, list=None, user=user,
|
|
return_url=return_url, anonymous=anonymous)
|
|
else:
|
|
# instant payment: send to the partnering RH
|
|
# right now, all money going to Gluejar.
|
|
receiver_list = [{'email':settings.PAYPAL_GLUEJAR_EMAIL, 'amount':preapproval_amount}]
|
|
|
|
#redirect the page back to campaign page on success
|
|
return_url = self.request.build_absolute_uri(reverse('campaign_by_id',kwargs={'pk': str(pk)}))
|
|
t, url = p.pledge('USD', TARGET_TYPE_CAMPAIGN, receiver_list, campaign=campaign, list=None, user=user,
|
|
return_url=return_url, anonymous=anonymous)
|
|
|
|
if url:
|
|
logger.info("CampaignFormView paypal: " + url)
|
|
print >> sys.stderr, "CampaignFormView paypal: ", url
|
|
return HttpResponseRedirect(url)
|
|
else:
|
|
response = t.reference
|
|
logger.info("CampaignFormView paypal: Error " + str(t.reference))
|
|
return HttpResponse(response)
|
|
|
|
class InfoPageView(TemplateView):
|
|
|
|
def get_template_names(self, **kwargs):
|
|
if self.kwargs['template_name']:
|
|
return (self.kwargs['template_name'])
|
|
else:
|
|
return ('metrics.html')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
users = User.objects
|
|
users.today = users.filter(date_joined__range = (date_today(), now()))
|
|
users.days7 = users.filter(date_joined__range = (date_today()-timedelta(days=7), now()))
|
|
users.year = users.filter(date_joined__year = date_today().year)
|
|
users.month = users.year.filter(date_joined__month = date_today().month)
|
|
users.yesterday = users.filter(date_joined__range = (date_today()-timedelta(days=1), date_today()))
|
|
users.gr = users.filter(profile__goodreads_user_id__isnull = False)
|
|
users.lt = users.exclude(profile__librarything_id = '')
|
|
users.fb = users.filter(profile__facebook_id__isnull = False)
|
|
users.tw = users.exclude(profile__twitter_id = '')
|
|
works = models.Work.objects
|
|
works.today = works.filter(created__range = (date_today(), now()))
|
|
works.days7 = works.filter(created__range = (date_today()-timedelta(days=7), now()))
|
|
works.year = works.filter(created__year = date_today().year)
|
|
works.month = works.year.filter(created__month = date_today().month)
|
|
works.yesterday = works.filter(created__range = (date_today()-timedelta(days=1), date_today()))
|
|
works.wishedby2 = works.filter(num_wishes__gte = 2)
|
|
works.wishedby20 = works.filter(num_wishes__gte = 20)
|
|
works.wishedby5 = works.filter(num_wishes__gte = 5)
|
|
works.wishedby50 = works.filter(num_wishes__gte = 50)
|
|
works.wishedby10 = works.filter(num_wishes__gte = 10)
|
|
works.wishedby100 = works.filter(num_wishes__gte = 100)
|
|
ebooks = models.Ebook.objects
|
|
ebooks.today = ebooks.filter(created__range = (date_today(), now()))
|
|
ebooks.days7 = ebooks.filter(created__range = (date_today()-timedelta(days=7), now()))
|
|
ebooks.year = ebooks.filter(created__year = date_today().year)
|
|
ebooks.month = ebooks.year.filter(created__month = date_today().month)
|
|
ebooks.yesterday = ebooks.filter(created__range = (date_today()-timedelta(days=1), date_today()))
|
|
wishlists= models.Wishlist.objects.exclude(wishes__isnull=True)
|
|
wishlists.today = wishlists.filter(created__range = (date_today(), now()))
|
|
wishlists.days7 = wishlists.filter(created__range = (date_today()-timedelta(days=7), now()))
|
|
wishlists.year = wishlists.filter(created__year = date_today().year)
|
|
wishlists.month = wishlists.year.filter(created__month = date_today().month)
|
|
if date_today().day==1:
|
|
wishlists.yesterday = wishlists.filter(created__range = (date_today()-timedelta(days=1), date_today()))
|
|
else:
|
|
wishlists.yesterday = wishlists.month.filter(created__day = date_today().day-1)
|
|
return {
|
|
'users': users,
|
|
'works': works,
|
|
'ebooks': ebooks,
|
|
'wishlists': wishlists,
|
|
}
|
|
|
|
|
|
class FAQView(TemplateView):
|
|
template_name = "faq.html"
|
|
def get_context_data(self, **kwargs):
|
|
location = self.kwargs["location"]
|
|
sublocation = self.kwargs["sublocation"]
|
|
return {'location': location, 'sublocation': sublocation}
|
|
|
|
class GoodreadsDisplayView(TemplateView):
|
|
template_name = "goodreads_display.html"
|
|
def get_context_data(self, **kwargs):
|
|
context = super(GoodreadsDisplayView, self).get_context_data(**kwargs)
|
|
session = self.request.session
|
|
gr_client = GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
|
|
|
|
user = self.request.user
|
|
if user.is_authenticated():
|
|
api_key = ApiKey.objects.filter(user=user)[0].key
|
|
context['api_key'] = api_key
|
|
|
|
if user.profile.goodreads_user_id is None:
|
|
# calculate the Goodreads authorization URL
|
|
(context["goodreads_auth_url"], request_token) = gr_client.begin_authorization(self.request.build_absolute_uri(reverse('goodreads_cb')))
|
|
logger.info("goodreads_auth_url: %s" %(context["goodreads_auth_url"]))
|
|
# store request token in session so that we can redeem it for auth_token if authorization works
|
|
session['goodreads_request_token'] = request_token['oauth_token']
|
|
session['goodreads_request_secret'] = request_token['oauth_token_secret']
|
|
else:
|
|
gr_shelves = gr_client.shelves_list(user_id=user.profile.goodreads_user_id)
|
|
context["shelves_info"] = gr_shelves
|
|
gr_shelf_load_form = GoodreadsShelfLoadingForm()
|
|
# load the shelves into the form
|
|
choices = [('all:%d' % (gr_shelves["total_book_count"]),'all (%d)' % (gr_shelves["total_book_count"]))] + \
|
|
[("%s:%d" % (s["name"], s["book_count"]) ,"%s (%d)" % (s["name"],s["book_count"])) for s in gr_shelves["user_shelves"]]
|
|
gr_shelf_load_form.fields['goodreads_shelf_name_number'].widget = Select(choices=tuple(choices))
|
|
|
|
context["gr_shelf_load_form"] = gr_shelf_load_form
|
|
|
|
# also load any CeleryTasks associated with the user
|
|
context["celerytasks"] = models.CeleryTask.objects.filter(user=user)
|
|
|
|
return context
|
|
|
|
@login_required
|
|
def goodreads_auth(request):
|
|
|
|
# calculate the Goodreads authorization URL
|
|
gr_client = GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
|
|
(goodreads_auth_url, request_token) = gr_client.begin_authorization(request.build_absolute_uri(reverse('goodreads_cb')))
|
|
logger.info("goodreads_auth_url: %s" %(goodreads_auth_url))
|
|
# store request token in session so that we can redeem it for auth_token if authorization works
|
|
request.session['goodreads_request_token'] = request_token['oauth_token']
|
|
request.session['goodreads_request_secret'] = request_token['oauth_token_secret']
|
|
|
|
return HttpResponseRedirect(goodreads_auth_url)
|
|
|
|
@login_required
|
|
def goodreads_cb(request):
|
|
"""handle callback from Goodreads"""
|
|
|
|
session = request.session
|
|
authorized_flag = request.GET['authorize'] # is it '1'?
|
|
request_oauth_token = request.GET['oauth_token']
|
|
|
|
if authorized_flag == '1':
|
|
request_token = {'oauth_token': session.get('goodreads_request_token'),
|
|
'oauth_token_secret': session.get('goodreads_request_secret')}
|
|
gr_client = GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
|
|
|
|
access_token = gr_client.complete_authorization(request_token)
|
|
|
|
# store the access token in the user profile
|
|
profile = request.user.profile
|
|
profile.goodreads_auth_token = access_token["oauth_token"]
|
|
profile.goodreads_auth_secret = access_token["oauth_token_secret"]
|
|
|
|
# let's get the userid, username
|
|
user = gr_client.auth_user()
|
|
|
|
profile.goodreads_user_id = user["userid"]
|
|
profile.goodreads_user_name = user["name"]
|
|
profile.goodreads_user_link = user["link"]
|
|
|
|
profile.save() # is this needed?
|
|
|
|
# redirect to the Goodreads display page -- should observe some next later
|
|
return HttpResponseRedirect(reverse('home'))
|
|
|
|
@require_POST
|
|
@login_required
|
|
@csrf_exempt
|
|
def goodreads_flush_assoc(request):
|
|
user = request.user
|
|
if user.is_authenticated():
|
|
profile = user.profile
|
|
profile.goodreads_user_id = None
|
|
profile.goodreads_user_name = None
|
|
profile.goodreads_user_link = None
|
|
profile.goodreads_auth_token = None
|
|
profile.goodreads_auth_secret = None
|
|
profile.save()
|
|
logger.info('Goodreads association flushed for user %s', user)
|
|
return HttpResponseRedirect(reverse('goodreads_display'))
|
|
|
|
@require_POST
|
|
@login_required
|
|
@csrf_exempt
|
|
def goodreads_load_shelf(request):
|
|
"""
|
|
a view to allow user load goodreads shelf into her wishlist
|
|
"""
|
|
# Should be moved to the API
|
|
goodreads_shelf_name_number = request.POST.get('goodreads_shelf_name_number', 'all:0')
|
|
user = request.user
|
|
try:
|
|
# parse out shelf name and expected number of books
|
|
(shelf_name, expected_number_of_books) = re.match(r'^(.*):(\d+)$', goodreads_shelf_name_number).groups()
|
|
expected_number_of_books = int(expected_number_of_books)
|
|
logger.info('Adding task to load shelf %s to user %s with %d books', shelf_name, user, expected_number_of_books)
|
|
load_task_name = "load_goodreads_shelf_into_wishlist"
|
|
load_task = getattr(tasks, load_task_name)
|
|
task_id = load_task.delay(user.id, shelf_name, expected_number_of_books=expected_number_of_books)
|
|
|
|
ct = models.CeleryTask()
|
|
ct.task_id = task_id
|
|
ct.function_name = load_task_name
|
|
ct.user = user
|
|
ct.description = "Loading Goodread shelf %s to user %s with %s books" % (shelf_name, user, expected_number_of_books)
|
|
ct.save()
|
|
|
|
return HttpResponse("<span style='margin: auto 10px auto 36px;vertical-align: middle;display: inline-block;'>We're on it! <a href='JavaScript:window.location.reload()'>Reload the page</a> to see the books we've snagged so far.</span>")
|
|
except Exception,e:
|
|
return HttpResponse("Error in loading shelf: %s " % (e))
|
|
logger.info("Error in loading shelf for user %s: %s ", user, e)
|
|
|
|
|
|
@login_required
|
|
def goodreads_calc_shelves(request):
|
|
|
|
# we should move towards calculating this only if needed (perhaps with Ajax), caching previous results, etc to speed up
|
|
# performance
|
|
|
|
if request.user.profile.goodreads_user_id is not None:
|
|
gr_client = GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
|
|
goodreads_shelves = gr_client.shelves_list(user_id=request.user.profile.goodreads_user_id)
|
|
#goodreads_shelf_load_form = GoodreadsShelfLoadingForm()
|
|
## load the shelves into the form
|
|
#choices = [('all:%d' % (goodreads_shelves["total_book_count"]),'all (%d)' % (goodreads_shelves["total_book_count"]))] + \
|
|
# [("%s:%d" % (s["name"], s["book_count"]) ,"%s (%d)" % (s["name"],s["book_count"])) for s in goodreads_shelves["user_shelves"]]
|
|
#goodreads_shelf_load_form.fields['goodreads_shelf_name_number'].widget = Select(choices=tuple(choices))
|
|
else:
|
|
goodreads_shelf_load_form = None
|
|
|
|
return HttpResponse(json.dumps(goodreads_shelves), content_type="application/json")
|
|
|
|
|
|
@require_POST
|
|
@login_required
|
|
@csrf_exempt
|
|
def librarything_load(request):
|
|
"""
|
|
a view to allow user load librarything library into her wishlist
|
|
"""
|
|
# Should be moved to the API
|
|
user = request.user
|
|
|
|
|
|
try:
|
|
# figure out expected_number_of_books later
|
|
|
|
lt_username = request.user.profile.librarything_id
|
|
logger.info('Adding task to load librarything %s to user %s', lt_username, user )
|
|
load_task_name = "load_librarything_into_wishlist"
|
|
load_task = getattr(tasks, load_task_name)
|
|
task_id = load_task.delay(user.id, lt_username, None)
|
|
|
|
ct = models.CeleryTask()
|
|
ct.task_id = task_id
|
|
ct.function_name = load_task_name
|
|
ct.user = user
|
|
ct.description = "Loading LibraryThing collection of %s to user %s." % (lt_username, user)
|
|
ct.save()
|
|
|
|
return HttpResponse("<span style='margin: auto 10px auto 36px;vertical-align: middle;display: inline-block;'>We're on it! <a href='JavaScript:window.location.reload()'>Reload the page</a> to see the books we've snagged so far.</span>")
|
|
except Exception,e:
|
|
return HttpResponse("Error in loading LibraryThing library: %s " % (e))
|
|
logger.info("Error in loading LibraryThing for user %s: %s ", user, e)
|
|
|
|
@require_POST
|
|
@login_required
|
|
@csrf_exempt
|
|
def clear_wishlist(request):
|
|
try:
|
|
request.user.wishlist.works.clear()
|
|
logger.info("Wishlist for user %s cleared", request.user)
|
|
return HttpResponse('wishlist cleared')
|
|
except Exception, e:
|
|
return HttpResponse("Error in clearing wishlist: %s " % (e))
|
|
logger.info("Error in clearing wishlist for user %s: %s ", request.user, e)
|
|
|
|
|
|
class LibraryThingView(FormView):
|
|
template_name="librarything.html"
|
|
form_class = LibraryThingForm
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(LibraryThingView, self).get_context_data(**kwargs)
|
|
form = kwargs['form']
|
|
# get the books for the lt_username in the form
|
|
lt_username=self.request.GET.get("lt_username",None)
|
|
if lt_username is not None:
|
|
lt = librarything.LibraryThing(username=lt_username)
|
|
context.update({'books':list(lt.parse_user_catalog(view_style=5))})
|
|
else:
|
|
context.update({'books':None})
|
|
|
|
# try picking up the LibraryThing api key -- and set to None if not available. Not being used for
|
|
# anything crucial at this moment, so a None is ok here
|
|
try:
|
|
context.update({'lt_api_key':settings.LIBRARYTHING_API_KEY})
|
|
except:
|
|
pass
|
|
|
|
return context
|
|
|
|
def form_valid(self,form):
|
|
return super(LibraryThingView, self).form_valid(form)
|
|
|
|
@require_POST
|
|
@login_required
|
|
@csrf_exempt
|
|
def clear_celery_tasks(request):
|
|
try:
|
|
request.user.tasks.clear()
|
|
logger.info("Celery tasks for user %s cleared", request.user)
|
|
return HttpResponse('Celery Tasks List cleared')
|
|
except Exception, e:
|
|
return HttpResponse("Error in clearing Celery Tasks: %s " % (e))
|
|
logger.info("Error in clearing Celery Tasks for user %s: %s ", request.user, e)
|
|
|
|
def celery_test(request):
|
|
return HttpResponse("celery_test")
|
|
|
|
# routing views that try to redirect to the works page on a 3rd party site
|
|
#
|
|
# TODO: need to queue up a task to look up IDs if we have to fallback to
|
|
# routing based on ISBN or search
|
|
|
|
def work_librarything(request, work_id):
|
|
work = get_object_or_404(models.Work, id=work_id)
|
|
isbn = work.first_isbn_13()
|
|
if work.librarything_id:
|
|
url = work.librarything_url
|
|
elif isbn:
|
|
# TODO: do the redirect here and capture the work id?
|
|
url = "http://www.librarything.com/isbn/%s" % isbn
|
|
else:
|
|
term = work.title + " " + work.author()
|
|
q = urlencode({'searchtpe': 'work', 'term': term})
|
|
url = "http://www.librarything.com/search.php?" + q
|
|
return HttpResponseRedirect(url)
|
|
|
|
def work_openlibrary(request, work_id):
|
|
work = get_object_or_404(models.Work, id=work_id)
|
|
isbns = ["ISBN:" + i.value for i in work.identifiers.filter(type='isbn')]
|
|
url = None
|
|
|
|
if work.openlibrary_id:
|
|
url = work.openlibrary_url
|
|
elif len(isbns) > 0:
|
|
isbns = ",".join(isbns)
|
|
u = 'http://openlibrary.org/api/books?bibkeys=%s&jscmd=data&format=json' % isbns
|
|
try:
|
|
j = json.loads(requests.get(u).content)
|
|
# as long as there were some matches get the first one and route to it
|
|
if len(j.keys()) > 0:
|
|
first = j.keys()[0]
|
|
url = "http://openlibrary.org" + j[first]['key']
|
|
except ValueError:
|
|
# fail at openlibrary
|
|
logger.warning("failed to get OpenLibrary json at %s" % u)
|
|
# fall back to doing a search on openlibrary
|
|
if not url:
|
|
q = urlencode({'q': work.title + " " + work.author()})
|
|
url = "http://openlibrary.org/search?" + q
|
|
return HttpResponseRedirect(url)
|
|
|
|
def work_goodreads(request, work_id):
|
|
work = get_object_or_404(models.Work, id=work_id)
|
|
isbn = work.first_isbn_13()
|
|
if work.goodreads_id:
|
|
url = work.goodreads_url
|
|
elif isbn:
|
|
url = "http://www.goodreads.com/book/isbn/%s" % isbn
|
|
else:
|
|
q = urlencode({'query': work.title + " " + work.author()})
|
|
url = "http://www.goodreads.com/search?" + q
|
|
return HttpResponseRedirect(url)
|
|
|
|
@login_required
|
|
def emailshare(request):
|
|
if request.method == 'POST':
|
|
form=EmailShareForm(request.POST)
|
|
if form.is_valid():
|
|
subject = form.cleaned_data['subject']
|
|
message = form.cleaned_data['message']
|
|
sender = form.cleaned_data['sender']
|
|
recipient = form.cleaned_data['recipient']
|
|
send_mail(subject, message, sender, [recipient])
|
|
try:
|
|
next = form.cleaned_data['next']
|
|
except:
|
|
next = ''
|
|
return HttpResponseRedirect(next)
|
|
|
|
else:
|
|
try:
|
|
next = request.GET['next']
|
|
work_id = next.split('/')[-2]
|
|
work_id = int(work_id)
|
|
book = models.Work.objects.get(pk=work_id)
|
|
title = book.title
|
|
# if title requires unicode let's ignore it for now
|
|
try:
|
|
title = ', '+str(title)+', '
|
|
except:
|
|
title = ' '
|
|
try:
|
|
status = book.last_campaign().status
|
|
except:
|
|
status = None
|
|
|
|
# customize the call to action depending on campaign status
|
|
if status == 'ACTIVE':
|
|
message = 'Help me unglue one of my favorite books'+title+'on Unglue.It: '+next+'. If enough of us pledge to unglue this book, the creator will be paid and the ebook will become free to everyone on earth.'
|
|
else:
|
|
message = 'Help me unglue one of my favorite books'+title+'on Unglue.It: '+next+'. If enough of us wishlist this book, Unglue.It may start a campaign to pay the creator and make the ebook free to everyone on earth.'
|
|
form = EmailShareForm(initial={'next':next, 'subject': 'Come see one of my favorite books on Unglue.It', 'message': message})
|
|
except:
|
|
next = ''
|
|
sender = ''
|
|
form = EmailShareForm(initial={'next':next, 'subject': 'Come join me on Unglue.It', 'message':"I'm ungluing books on Unglue.It. Together we're paying creators and making ebooks free to everyone on earth. Join me! http://unglue.it"})
|
|
|
|
return render(request, "emailshare.html", {'form':form})
|
|
|
|
def feedback(request):
|
|
num1 = randint(0,10)
|
|
num2 = randint(0,10)
|
|
sum = num1 + num2
|
|
|
|
if request.method == 'POST':
|
|
form=FeedbackForm(request.POST)
|
|
if form.is_valid():
|
|
subject = form.cleaned_data['subject']
|
|
message = form.cleaned_data['message']
|
|
sender = form.cleaned_data['sender']
|
|
recipient = 'support@gluejar.com'
|
|
page = form.cleaned_data['page']
|
|
useragent = request.META['HTTP_USER_AGENT']
|
|
if request.user.is_anonymous():
|
|
ungluer = "(not logged in)"
|
|
else:
|
|
ungluer = request.user.username
|
|
message = "<<<This feedback is about "+page+". Original user message follows\nfrom "+sender+", ungluer name "+ungluer+"\nwith user agent "+useragent+"\n>>>\n"+message
|
|
send_mail(subject, message, sender, [recipient])
|
|
|
|
return render(request, "thanks.html", {"page":page})
|
|
|
|
else:
|
|
num1 = request.POST['num1']
|
|
num2 = request.POST['num2']
|
|
|
|
else:
|
|
if request.user.is_authenticated():
|
|
sender=request.user.email;
|
|
else:
|
|
sender=''
|
|
try:
|
|
page = request.GET['page']
|
|
except:
|
|
page='/'
|
|
form = FeedbackForm(initial={"sender":sender, "subject": "Feedback on page "+page, "page":page, "num1":num1, "num2":num2, "answer":sum})
|
|
|
|
return render(request, "feedback.html", {'form':form, 'num1':num1, 'num2':num2})
|
|
|
|
def comment(request):
|
|
latest_comments = Comment.objects.all().order_by('-submit_date')[:20]
|
|
return render(request, "comments.html", {'latest_comments': latest_comments})
|