2011-12-05 05:56:24 +00:00
import re
import sys
import json
2011-10-20 03:31:16 +00:00
import logging
2012-03-13 20:57:42 +00:00
import urllib
2012-03-07 19:42:16 +00:00
from datetime import timedelta
from regluit . utils . localdatetime import now , date_today
2012-01-09 20:53:09 +00:00
from random import randint
2011-12-05 05:56:24 +00:00
from re import sub
2011-12-19 06:33:13 +00:00
from itertools import islice
from decimal import Decimal as D
2011-12-23 01:34:24 +00:00
from xml . etree import ElementTree as ET
2011-12-19 06:33:13 +00:00
import requests
import oauth2 as oauth
2011-11-30 02:02:51 +00:00
from django import forms
2011-10-20 03:31:16 +00:00
from django . conf import settings
2011-09-12 05:53:54 +00:00
from django . contrib . auth . models import User
2011-09-27 09:27:15 +00:00
from django . core . urlresolvers import reverse
2011-10-23 18:40:06 +00:00
from django . core . exceptions import ObjectDoesNotExist
2012-01-02 14:39:11 +00:00
from django . contrib import messages
2012-02-23 20:40:45 +00:00
from django . contrib . auth . decorators import login_required
2012-02-03 15:22:53 +00:00
from django . contrib . comments import Comment
2012-05-12 15:12:27 +00:00
from django . contrib . sites . models import Site
2012-02-23 20:40:45 +00:00
from django . db . models import Q , Count , Sum
2011-11-01 00:26:05 +00:00
from django . forms import Select
2011-11-17 19:35:29 +00:00
from django . forms . models import modelformset_factory
2012-02-11 20:14:31 +00:00
from django . http import HttpResponseRedirect , Http404
2012-02-02 14:03:24 +00:00
from django . http import HttpResponse , HttpResponseNotFound
2012-04-25 02:20:10 +00:00
from django . template . loader import render_to_string
2011-09-29 06:23:50 +00:00
from django . views . decorators . csrf import csrf_exempt
from django . views . decorators . http import require_POST
2011-10-12 17:47:48 +00:00
from django . views . generic . edit import FormView
2011-12-01 18:17:33 +00:00
from django . views . generic . list import ListView
2011-10-25 01:29:01 +00:00
from django . views . generic . base import TemplateView
2011-09-29 01:36:47 +00:00
from django . shortcuts import render , render_to_response , get_object_or_404
2012-03-01 13:53:55 +00:00
from django . utils . http import urlencode
2011-11-22 05:28:06 +00:00
from django . utils . translation import ugettext_lazy as _
2011-10-20 03:31:16 +00:00
from regluit . core import tasks
2012-05-11 19:53:46 +00:00
from regluit . core . tasks import send_mail_task , emit_notifications
2011-11-16 18:20:10 +00:00
from regluit . core import models , bookloader , librarything
2011-11-14 20:16:12 +00:00
from regluit . core import userlists
2011-09-29 06:23:50 +00:00
from regluit . core . search import gluejar_search
2011-10-25 01:29:01 +00:00
from regluit . core . goodreads import GoodreadsClient
2012-04-25 02:20:10 +00:00
from regluit . frontend . forms import UserData , UserEmail , ProfileForm , CampaignPledgeForm , GoodreadsShelfLoadingForm
2011-11-23 16:06:48 +00:00
from regluit . frontend . forms import RightsHolderForm , UserClaimForm , LibraryThingForm , OpenCampaignForm
2012-05-01 14:56:19 +00:00
from regluit . frontend . forms import getManageCampaignForm , DonateForm , CampaignAdminForm , EmailShareForm , FeedbackForm
2012-05-21 14:56:18 +00:00
from regluit . frontend . forms import EbookForm , CustomPremiumForm , EditManagersForm , EditionForm , PledgeCancelForm
2011-10-13 21:13:37 +00:00
from regluit . payment . manager import PaymentManager
2012-01-10 23:26:04 +00:00
from regluit . payment . models import Transaction
from regluit . payment . parameters import TARGET_TYPE_CAMPAIGN , TARGET_TYPE_DONATION , PAYMENT_TYPE_AUTHORIZATION
2012-05-04 14:30:05 +00:00
from regluit . payment . parameters import TRANSACTION_STATUS_ACTIVE , TRANSACTION_STATUS_COMPLETE , TRANSACTION_STATUS_CANCELED , TRANSACTION_STATUS_ERROR , TRANSACTION_STATUS_FAILED , TRANSACTION_STATUS_INCOMPLETE
2012-04-25 17:55:30 +00:00
from regluit . payment . paypal import Preapproval
2011-10-25 01:29:01 +00:00
from regluit . core import goodreads
2011-11-01 16:50:05 +00:00
from tastypie . models import ApiKey
2011-12-19 06:33:13 +00:00
from regluit . payment . models import Transaction
2012-05-11 21:14:49 +00:00
from notification import models as notification
2011-12-19 06:33:13 +00:00
2011-10-25 01:29:01 +00:00
2011-10-12 17:47:48 +00:00
logger = logging . getLogger ( __name__ )
2011-10-03 16:36:04 +00:00
2012-07-07 22:13:05 +00:00
def static_redirect_view ( request , file_name , dir = " " ) :
return HttpResponseRedirect ( ' /static/ ' + dir + " / " + file_name )
2012-03-08 14:36:59 +00:00
def slideshow ( max ) :
ending = models . Campaign . objects . filter ( status = ' ACTIVE ' ) . order_by ( ' deadline ' )
count = ending . count ( )
j = 0
2012-06-13 12:41:23 +00:00
worklist = [ ]
if max > count :
# add all the works with active campaigns
for campaign in ending :
worklist . append ( campaign . work )
# then fill out the rest of the list with popular but inactive works
remainder = max - count
remainder_works = models . Work . objects . exclude ( campaigns__status = ' ACTIVE ' ) . order_by ( ' -num_wishes ' ) [ : remainder ]
worklist . extend ( remainder_works )
2012-03-08 14:36:59 +00:00
else :
2012-06-13 12:41:23 +00:00
# if the active campaign list has more works than we can fit
# in our slideshow, it's the only source we need to draw from
while j < max :
worklist . append ( ending [ j ] . work )
j + = 1
2012-03-23 15:15:37 +00:00
2012-03-08 14:36:59 +00:00
return worklist
2011-10-13 16:23:57 +00:00
2012-03-13 20:57:42 +00:00
def next ( request ) :
2012-03-23 15:15:37 +00:00
if request . COOKIES . has_key ( ' next ' ) :
2012-05-15 18:18:17 +00:00
response = HttpResponseRedirect ( urllib . unquote ( urllib . unquote ( request . COOKIES [ ' next ' ] ) ) )
2012-03-23 15:15:37 +00:00
response . delete_cookie ( ' next ' )
return response
else :
return HttpResponseRedirect ( ' / ' )
2012-08-24 19:14:32 +00:00
def safe_get_work ( work_id ) :
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
return work
2012-03-13 20:57:42 +00:00
2012-05-24 19:29:45 +00:00
def home ( request , landing = False ) :
if request . user . is_authenticated ( ) and landing == False :
2011-09-27 09:27:15 +00:00
return HttpResponseRedirect ( reverse ( ' supporter ' ,
args = [ request . user . username ] ) )
2012-01-15 23:03:54 +00:00
2012-03-08 14:36:59 +00:00
worklist = slideshow ( 12 )
works = worklist [ : 6 ]
works2 = worklist [ 6 : 12 ]
2011-12-09 00:12:26 +00:00
events = models . Wishes . objects . order_by ( ' -created ' ) [ 0 : 2 ]
return render ( request , ' home.html ' , { ' suppress_search_box ' : True , ' works ' : works , ' works2 ' : works2 , ' events ' : events } )
2011-09-12 03:44:21 +00:00
2011-11-02 19:40:43 +00:00
def stub ( request ) :
2011-11-09 17:24:26 +00:00
path = request . path [ 6 : ] # get rid of /stub/
return render ( request , ' stub.html ' , { ' path ' : path } )
2011-11-06 21:46:46 +00:00
2012-07-07 22:13:05 +00:00
def acks ( request , work ) :
return render ( request , ' front_matter.html ' , { ' campaign ' : work . last_campaign ( ) } )
2011-11-06 23:54:48 +00:00
def work ( request , work_id , action = ' display ' ) :
2012-08-24 19:14:32 +00:00
work = safe_get_work ( work_id )
2012-07-07 22:13:05 +00:00
if action == " acks " :
return acks ( request , work )
2012-08-24 19:14:32 +00:00
2012-02-28 22:28:33 +00:00
if request . method == ' POST ' and not request . user . is_anonymous ( ) :
activetab = ' 4 '
else :
alert = ' '
try :
activetab = request . GET [ ' tab ' ]
if activetab not in [ ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' ] :
activetab = ' 1 ' ;
except :
activetab = ' 1 ' ;
2012-08-24 19:14:32 +00:00
context = { }
2011-11-06 22:44:50 +00:00
campaign = work . last_campaign ( )
2012-05-01 14:56:19 +00:00
if campaign and campaign . edition :
editions = [ campaign . edition ]
else :
editions = work . editions . all ( ) . order_by ( ' -publication_date ' )
2012-01-09 17:44:35 +00:00
try :
2012-01-31 15:07:52 +00:00
pledged = campaign . transactions ( ) . filter ( user = request . user , status = " ACTIVE " )
2012-01-09 17:44:35 +00:00
except :
2012-01-31 15:07:52 +00:00
pledged = None
2012-05-01 17:49:23 +00:00
countdown = " "
2012-08-24 19:14:32 +00:00
try :
assert not ( work . last_campaign_status ( ) == ' ACTIVE ' and work . first_ebook ( ) )
except :
2012-08-27 20:38:35 +00:00
logger . warning ( " Campaign running for %s when ebooks are already available: why? " % work . title )
2012-08-24 19:14:32 +00:00
2012-05-13 19:33:54 +00:00
if work . last_campaign_status ( ) == ' ACTIVE ' :
2012-06-15 15:06:38 +00:00
from math import ceil
2012-05-01 17:49:23 +00:00
time_remaining = campaign . deadline - now ( )
2012-06-15 15:06:38 +00:00
'''
we want to round up on all of these ; if it ' s the 3rd and the
campaign ends the 8 th , users expect to see 5 days remaining ,
not 4 ( as an artifact of 4 days 11 hours or whatever )
time_remaining . whatever is an int , so just adding 1 will do
that for us ( except in the case where . days exists and both other
fields are 0 , which is unlikely enough I ' m not defending against it)
'''
2012-05-01 17:49:23 +00:00
if time_remaining . days :
2012-06-15 15:06:38 +00:00
countdown = " in %s days " % str ( time_remaining . days + 1 )
2012-05-01 17:49:23 +00:00
elif time_remaining . seconds > 3600 :
2012-06-15 15:06:38 +00:00
countdown = " in %s hours " % str ( time_remaining . seconds / 3600 + 1 )
2012-05-01 17:49:23 +00:00
elif time_remaining . seconds > 60 :
2012-06-15 15:06:38 +00:00
countdown = " in %s minutes " % str ( time_remaining . seconds / 60 + 1 )
2012-05-01 17:49:23 +00:00
else :
countdown = " right now "
2012-08-24 19:14:32 +00:00
2012-05-14 02:13:45 +00:00
if action == ' preview ' :
work . last_campaign_status = ' ACTIVE '
2012-05-11 18:13:09 +00:00
2011-12-31 18:48:54 +00:00
try :
2012-01-17 04:28:34 +00:00
pubdate = work . publication_date [ : 4 ]
2011-12-31 18:48:54 +00:00
except IndexError :
pubdate = ' unknown '
2012-08-24 19:14:32 +00:00
2011-11-26 22:09:33 +00:00
if not request . user . is_anonymous ( ) :
2012-03-23 01:24:12 +00:00
claimform = UserClaimForm ( request . user , data = { ' claim-work ' : work . pk , ' claim-user ' : request . user . id } , prefix = ' claim ' )
2012-02-28 22:28:33 +00:00
for edition in editions :
2012-04-27 21:14:57 +00:00
edition . hide_details = 1
if request . method == ' POST ' and not request . user . is_anonymous ( ) :
if request . POST . has_key ( ' ebook_ %d -edition ' % edition . id ) :
edition . ebook_form = EbookForm ( data = request . POST , prefix = ' ebook_ %d ' % edition . id )
if edition . ebook_form . is_valid ( ) :
edition . ebook_form . save ( )
alert = ' Thanks for adding an ebook to unglue.it! '
else :
edition . hide_details = 0
alert = ' your submitted ebook had errors '
else :
#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 )
2011-11-26 22:09:33 +00:00
else :
claimform = None
2012-08-24 19:14:32 +00:00
2011-11-06 22:44:50 +00:00
if campaign :
2012-03-21 21:53:33 +00:00
# pull up premiums explicitly tied to the campaign or generic premiums
2012-03-26 22:46:34 +00:00
premiums = campaign . effective_premiums ( )
2011-11-07 20:39:02 +00:00
else :
premiums = None
2011-11-21 15:51:50 +00:00
2012-02-11 19:15:06 +00:00
wishers = work . num_wishes
2011-11-22 19:28:27 +00:00
base_url = request . build_absolute_uri ( " / " ) [ : - 1 ]
2012-04-03 13:56:41 +00:00
active_claims = work . claim . all ( ) . filter ( status = ' active ' )
if active_claims . count ( ) == 1 :
2012-04-03 19:50:02 +00:00
claimstatus = ' one_active '
rights_holder_name = active_claims [ 0 ] . rights_holder . rights_holder_name
2012-04-03 13:56:41 +00:00
else :
rights_holder_name = None
2012-04-03 19:50:02 +00:00
pending_claims = work . claim . all ( ) . filter ( status = ' pending ' )
pending_claims_count = pending_claims . count ( )
if pending_claims_count > 1 :
claimstatus = ' disputed '
elif pending_claims_count == 1 :
claimstatus = ' one_pending '
rights_holder_name = pending_claims [ 0 ] . rights_holder . rights_holder_name
else :
claimstatus = ' open '
2012-02-01 20:57:03 +00:00
2012-03-23 15:09:51 +00:00
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 ,
2012-04-03 13:56:41 +00:00
' pledged ' : pledged ,
2012-03-23 15:09:51 +00:00
' activetab ' : activetab ,
2012-04-03 13:56:41 +00:00
' alert ' : alert ,
' claimstatus ' : claimstatus ,
' rights_holder_name ' : rights_holder_name ,
2012-08-27 20:48:07 +00:00
' countdown ' : countdown ,
2012-03-23 15:09:51 +00:00
} )
2011-11-21 03:23:51 +00:00
2012-05-14 05:07:02 +00:00
def new_edition ( request , work_id , edition_id , by = None ) :
2012-05-11 18:13:09 +00:00
if not request . user . is_authenticated ( ) :
return render ( request , " admins_only.html " )
# if the work and edition are set, we save the edition and set the work
language = ' en '
description = ' '
title = ' '
if work_id :
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
language = work . language
description = work . description
title = work . title
else :
work = None
2012-05-14 05:07:02 +00:00
if not request . user . is_staff :
if by == ' rh ' and work is not None :
if not request . user in work . last_campaign ( ) . managers . all ( ) :
return render ( request , " admins_only.html " )
else :
return render ( request , " admins_only.html " )
2012-05-11 18:13:09 +00:00
if edition_id :
try :
edition = models . Edition . objects . get ( id = edition_id )
except models . Work . DoesNotExist :
raise Http404
if work :
edition . work = work
language = edition . work . language
description = edition . work . description
else :
edition = models . Edition ( )
if work :
edition . work = work
if request . method == ' POST ' :
edition . new_author_names = request . POST . getlist ( ' new_author ' )
edition . new_subjects = request . POST . getlist ( ' new_subject ' )
if request . POST . has_key ( ' add_author_submit ' ) :
new_author_name = request . POST [ ' add_author ' ] . strip ( )
try :
author = models . Author . objects . get ( name = new_author_name )
except models . Author . DoesNotExist :
author = models . Author . objects . create ( name = new_author_name )
edition . new_author_names . append ( new_author_name )
form = EditionForm ( instance = edition , data = request . POST )
elif request . POST . has_key ( ' add_subject_submit ' ) :
new_subject = request . POST [ ' add_subject ' ] . strip ( )
try :
author = models . Subject . objects . get ( name = new_subject )
except models . Subject . DoesNotExist :
author = models . Subject . objects . create ( name = new_subject )
edition . new_subjects . append ( new_subject )
form = EditionForm ( instance = edition , data = request . POST )
else :
form = EditionForm ( instance = edition , data = request . POST )
if form . is_valid ( ) :
form . save ( )
if not work :
work = models . Work ( title = form . cleaned_data [ ' title ' ] , language = form . cleaned_data [ ' language ' ] , description = form . cleaned_data [ ' description ' ] )
work . save ( )
edition . work = work
edition . save ( )
else :
work . description = form . cleaned_data [ ' description ' ]
work . title = form . cleaned_data [ ' title ' ]
work . save ( )
models . Identifier . get_or_add ( type = ' isbn ' , value = form . cleaned_data [ ' isbn_13 ' ] , edition = edition , work = work )
for author_name in edition . new_author_names :
try :
author = models . Author . objects . get ( name = author_name )
except models . Author . DoesNotExist :
author = models . Author . objects . create ( name = author_name )
author . editions . add ( edition )
for subject_name in edition . new_subjects :
try :
subject = models . Subject . objects . get ( name = subject_name )
except models . Subject . DoesNotExist :
subject = models . Subject . objects . create ( name = subject_name )
subject . works . add ( work )
work_url = reverse ( ' work ' , kwargs = { ' work_id ' : edition . work . id } )
return HttpResponseRedirect ( work_url )
else :
form = EditionForm ( instance = edition , initial = {
' language ' : language ,
' isbn_13 ' : edition . isbn_13 ,
' description ' : description ,
' title ' : title
} )
return render ( request , ' new_edition.html ' , {
' form ' : form , ' edition ' : edition
} )
2011-11-21 03:23:51 +00:00
def manage_campaign ( request , id ) :
campaign = get_object_or_404 ( models . Campaign , id = id )
2011-11-26 02:23:37 +00:00
campaign . not_manager = False
campaign . problems = [ ]
2012-07-10 19:58:19 +00:00
if ( not request . user . is_authenticated ) or ( not request . user in campaign . managers . all ( ) and not request . user . is_staff ) :
2011-11-22 05:28:06 +00:00
campaign . not_manager = True
return render ( request , ' manage_campaign.html ' , { ' campaign ' : campaign } )
2012-05-04 13:56:41 +00:00
alerts = [ ]
activetab = ' #1 '
2012-03-26 19:31:41 +00:00
if request . method == ' POST ' :
if request . POST . has_key ( ' add_premium ' ) :
postcopy = request . POST . copy ( )
postcopy [ ' type ' ] = ' CU '
new_premium_form = CustomPremiumForm ( data = postcopy )
if new_premium_form . is_valid ( ) :
new_premium_form . save ( )
alerts . append ( _ ( ' New premium has been added ' ) )
new_premium_form = CustomPremiumForm ( data = { ' campaign ' : campaign } )
else :
alerts . append ( _ ( ' New premium has not been added ' ) )
2012-05-01 14:56:19 +00:00
form = getManageCampaignForm ( instance = campaign )
2012-05-04 13:56:41 +00:00
activetab = ' #2 '
elif request . POST . has_key ( ' save ' ) or request . POST . has_key ( ' launch ' ) :
2012-05-01 14:56:19 +00:00
form = getManageCampaignForm ( instance = campaign , data = request . POST )
2012-03-26 19:31:41 +00:00
if form . is_valid ( ) :
form . save ( )
2012-06-22 03:10:50 +00:00
campaign . update_left ( )
2012-03-26 19:31:41 +00:00
alerts . append ( _ ( ' Campaign data has been saved ' ) )
2012-05-04 13:56:41 +00:00
activetab = ' #2 '
2011-11-26 02:23:37 +00:00
else :
2012-03-26 19:31:41 +00:00
alerts . append ( _ ( ' Campaign data has NOT been saved ' ) )
if ' launch ' in request . POST . keys ( ) :
2012-05-04 13:56:41 +00:00
activetab = ' #3 '
2012-06-13 12:41:23 +00:00
if ( campaign . launchable and form . is_valid ( ) ) :
2012-03-26 19:31:41 +00:00
campaign . activate ( )
alerts . append ( _ ( ' Campaign has been launched ' ) )
else :
alerts . append ( _ ( ' Campaign has NOT been launched ' ) )
new_premium_form = CustomPremiumForm ( data = { ' campaign ' : campaign } )
elif request . POST . has_key ( ' inactivate ' ) :
2012-05-04 13:56:41 +00:00
activetab = ' #2 '
2012-03-26 19:31:41 +00:00
if request . POST . has_key ( ' premium_id ' ) :
2012-05-08 14:51:04 +00:00
premiums_to_stop = request . POST . getlist ( ' premium_id ' )
2012-03-26 19:31:41 +00:00
for premium_to_stop in premiums_to_stop :
selected_premium = models . Premium . objects . get ( id = premium_to_stop )
if selected_premium . type == ' CU ' :
selected_premium . type = ' XX '
selected_premium . save ( )
alerts . append ( _ ( ' Premium %s has been inactivated ' % premium_to_stop ) )
2012-05-01 14:56:19 +00:00
form = getManageCampaignForm ( instance = campaign )
2012-03-26 19:31:41 +00:00
new_premium_form = CustomPremiumForm ( data = { ' campaign ' : campaign } )
2011-11-22 05:28:06 +00:00
else :
2012-05-01 14:56:19 +00:00
form = getManageCampaignForm ( instance = campaign )
2012-03-26 19:31:41 +00:00
new_premium_form = CustomPremiumForm ( data = { ' campaign ' : campaign } )
2012-05-04 13:56:41 +00:00
work = campaign . work
try :
pubdate = work . publication_date [ : 4 ]
except IndexError :
pubdate = ' unknown '
2012-03-26 19:31:41 +00:00
return render ( request , ' manage_campaign.html ' , {
' campaign ' : campaign ,
' form ' : form ,
' problems ' : campaign . problems ,
' alerts ' : alerts ,
2012-03-26 22:46:34 +00:00
' premiums ' : campaign . effective_premiums ( ) ,
2012-03-26 19:31:41 +00:00
' premium_form ' : new_premium_form ,
2012-05-04 13:56:41 +00:00
' pubdate ' : pubdate ,
' work ' : work ,
' activetab ' : activetab ,
2012-03-26 19:31:41 +00:00
} )
2011-11-15 16:27:32 +00:00
2011-11-22 01:12:13 +00:00
def googlebooks ( request , googlebooks_id ) :
try :
2012-01-09 18:55:22 +00:00
edition = models . Identifier . objects . get ( type = ' goog ' , value = googlebooks_id ) . edition
except models . Identifier . DoesNotExist :
2012-01-31 15:08:43 +00:00
try :
edition = bookloader . add_by_googlebooks_id ( googlebooks_id )
if edition . new :
# add related editions asynchronously
2012-02-16 18:19:36 +00:00
tasks . populate_edition . delay ( edition . isbn_13 )
2012-01-31 15:08:43 +00:00
except bookloader . LookupFailure :
logger . warning ( " failed to load googlebooks_id %s " % googlebooks_id )
return HttpResponseNotFound ( " failed looking up googlebooks id %s " % googlebooks_id )
2011-11-22 01:12:13 +00:00
if not edition :
return HttpResponseNotFound ( " invalid googlebooks id " )
work_url = reverse ( ' work ' , kwargs = { ' work_id ' : edition . work . id } )
return HttpResponseRedirect ( work_url )
2011-10-20 03:31:16 +00:00
2011-11-15 02:13:39 +00:00
def subjects ( request ) :
order = request . GET . get ( ' order ' )
subjects = models . Subject . objects . all ( )
2011-12-19 06:33:13 +00:00
subjects = subjects . annotate ( Count ( ' works ' ) )
2011-11-15 02:13:39 +00:00
if request . GET . get ( ' order ' ) == ' count ' :
2011-12-19 06:33:13 +00:00
subjects = subjects . order_by ( ' -works__count ' )
2011-11-15 02:13:39 +00:00
else :
subjects = subjects . order_by ( ' name ' )
2011-10-20 03:31:16 +00:00
2011-11-15 02:13:39 +00:00
return render ( request , ' subjects.html ' , { ' subjects ' : subjects } )
2011-11-07 21:01:08 +00:00
2012-07-21 20:26:16 +00:00
class FilterableListView ( ListView ) :
def get_queryset ( self ) :
if self . request . GET . has_key ( ' pub_lang ' ) :
if self . model is models . Campaign :
return self . get_queryset_all ( ) . filter ( work__language = self . request . GET [ ' pub_lang ' ] )
else :
return self . get_queryset_all ( ) . filter ( language = self . request . GET [ ' pub_lang ' ] )
else :
return self . get_queryset_all ( )
def get_context_data ( self , * * kwargs ) :
context = super ( FilterableListView , self ) . get_context_data ( * * kwargs )
if self . request . GET . has_key ( ' pub_lang ' ) :
context [ ' pub_lang ' ] = self . request . GET [ ' pub_lang ' ]
else :
context [ ' pub_lang ' ] = ' '
context [ ' show_langs ' ] = True
context [ ' WISHED_LANGS ' ] = settings . WISHED_LANGS
return context
2011-12-03 00:29:23 +00:00
recommended_user = User . objects . filter ( username = settings . UNGLUEIT_RECOMMENDED_USERNAME )
2012-07-21 20:26:16 +00:00
class WorkListView ( FilterableListView ) :
2011-12-03 00:29:23 +00:00
template_name = " work_list.html "
context_object_name = " work_list "
2012-07-21 20:26:16 +00:00
def get_queryset_all ( self ) :
2011-12-03 00:29:23 +00:00
facet = self . kwargs [ ' facet ' ]
if ( facet == ' popular ' ) :
2012-02-11 19:15:06 +00:00
return models . Work . objects . order_by ( ' -num_wishes ' , ' id ' )
2011-12-03 00:29:23 +00:00
elif ( facet == ' recommended ' ) :
2012-03-12 20:40:21 +00:00
return models . Work . objects . filter ( wishlists__user = recommended_user ) . order_by ( ' -num_wishes ' )
2012-01-31 22:56:34 +00:00
elif ( facet == ' new ' ) :
2012-02-11 19:15:06 +00:00
return models . Work . objects . filter ( num_wishes__gt = 0 ) . order_by ( ' -created ' , ' -num_wishes ' , ' id ' )
2011-12-03 00:29:23 +00:00
else :
2012-02-01 17:43:46 +00:00
return models . Work . objects . all ( ) . order_by ( ' -created ' , ' id ' )
2012-07-21 20:26:16 +00:00
2011-12-03 00:29:23 +00:00
def get_context_data ( self , * * kwargs ) :
context = super ( WorkListView , self ) . get_context_data ( * * kwargs )
2011-12-03 03:31:39 +00:00
qs = self . get_queryset ( )
context [ ' ungluers ' ] = userlists . work_list_users ( qs , 5 )
2012-05-08 18:28:06 +00:00
context [ ' facet ' ] = self . kwargs [ ' facet ' ]
2012-06-01 17:15:50 +00:00
context [ ' works_unglued ' ] = qs . filter ( editions__ebooks__isnull = False ) . distinct ( ) [ : 20 ]
context [ ' works_active ' ] = qs . exclude ( editions__ebooks__isnull = False ) . filter ( Q ( campaigns__status = ' ACTIVE ' ) | Q ( campaigns__status = ' SUCCESSFUL ' ) ) . distinct ( ) [ : 20 ]
context [ ' works_wished ' ] = qs . exclude ( editions__ebooks__isnull = False ) . exclude ( campaigns__status = ' ACTIVE ' ) . exclude ( campaigns__status = ' SUCCESSFUL ' ) . distinct ( ) [ : 20 ]
2012-02-29 18:15:38 +00:00
2012-03-02 14:40:10 +00:00
context [ ' activetab ' ] = " #3 "
2012-02-29 18:15:38 +00:00
counts = { }
counts [ ' unglued ' ] = context [ ' works_unglued ' ] . count ( )
counts [ ' unglueing ' ] = context [ ' works_active ' ] . count ( )
counts [ ' wished ' ] = context [ ' works_wished ' ] . count ( )
context [ ' counts ' ] = counts
2012-05-08 18:28:06 +00:00
2011-12-03 00:29:23 +00:00
return context
2012-01-15 21:48:26 +00:00
2012-07-21 20:26:16 +00:00
class UngluedListView ( FilterableListView ) :
2012-01-15 21:48:26 +00:00
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
2012-07-21 20:26:16 +00:00
def get_queryset_all ( self ) :
2012-01-15 21:48:26 +00:00
facet = self . kwargs [ ' facet ' ]
if ( facet == ' popular ' ) :
2012-02-29 19:20:50 +00:00
return models . Work . objects . filter ( editions__ebooks__isnull = False ) . distinct ( ) . order_by ( ' -num_wishes ' )
2012-01-15 21:48:26 +00:00
else :
2012-01-20 23:35:37 +00:00
#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 ' )
2012-01-15 21:48:26 +00:00
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 ' ]
2012-03-02 14:40:10 +00:00
context [ ' activetab ' ] = " #1 "
2012-01-15 21:48:26 +00:00
return context
2011-12-03 00:29:23 +00:00
2012-07-21 20:26:16 +00:00
class CampaignListView ( FilterableListView ) :
2011-12-01 18:17:33 +00:00
template_name = " campaign_list.html "
context_object_name = " campaign_list "
model = models . Campaign
2012-07-21 20:26:16 +00:00
def get_queryset_all ( self ) :
2011-12-01 18:17:33 +00:00
facet = self . kwargs [ ' facet ' ]
if ( facet == ' newest ' ) :
2011-12-06 21:37:03 +00:00
return models . Campaign . objects . filter ( status = ' ACTIVE ' ) . order_by ( ' -activated ' )
2011-12-01 22:32:53 +00:00
elif ( facet == ' pledged ' ) :
2011-12-06 21:37:03 +00:00
return models . Campaign . objects . filter ( status = ' ACTIVE ' ) . annotate ( total_pledge = Sum ( ' transaction__amount ' ) ) . order_by ( ' -total_pledge ' )
2011-12-01 22:32:53 +00:00
elif ( facet == ' pledges ' ) :
2011-12-06 21:37:03 +00:00
return models . Campaign . objects . filter ( status = ' ACTIVE ' ) . annotate ( pledges = Count ( ' transaction ' ) ) . order_by ( ' -pledges ' )
2011-12-01 18:17:33 +00:00
elif ( facet == ' almost ' ) :
2011-12-06 21:37:03 +00:00
return models . Campaign . objects . filter ( status = ' ACTIVE ' ) . all ( ) # STUB: will need to make db changes to make this work
2011-12-01 18:17:33 +00:00
elif ( facet == ' ending ' ) :
2011-12-06 21:37:03 +00:00
return models . Campaign . objects . filter ( status = ' ACTIVE ' ) . order_by ( ' deadline ' )
2011-12-01 18:17:33 +00:00
else :
return models . Campaign . objects . all ( )
2011-12-03 03:53:39 +00:00
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
2011-12-01 18:17:33 +00:00
2011-11-28 23:39:06 +00:00
class PledgeView ( FormView ) :
template_name = " pledge.html "
form_class = CampaignPledgeForm
embedded = False
2012-03-15 21:54:38 +00:00
def get ( self , request , * args , * * kwargs ) :
2012-03-19 23:32:37 +00:00
# change the default behavior from https://code.djangoproject.com/browser/django/tags/releases/1.3.1/django/views/generic/edit.py#L129
2012-03-15 21:54:38 +00:00
# don't automatically bind the data to the form on GET, only on POST
# compare with https://code.djangoproject.com/browser/django/tags/releases/1.3.1/django/views/generic/edit.py#L34
form_class = self . get_form_class ( )
form = form_class ( )
2012-05-13 19:18:48 +00:00
context_data = self . get_context_data ( form = form )
# if there is already an active campaign pledge for user, redirect to the pledge modify page
if context_data . get ( ' redirect_to_modify_pledge ' ) :
work = context_data [ ' work ' ]
return HttpResponseRedirect ( reverse ( ' pledge_modify ' , args = [ work . id ] ) )
else :
return self . render_to_response ( context_data )
2012-03-15 21:54:38 +00:00
2011-11-28 23:39:06 +00:00
def get_context_data ( self , * * kwargs ) :
2012-05-13 19:18:48 +00:00
""" set up the pledge page """
# the following should be true since PledgeModifyView.as_view is wrapped in login_required
assert self . request . user . is_authenticated ( )
user = self . request . user
2011-11-28 23:39:06 +00:00
context = super ( PledgeView , self ) . get_context_data ( * * kwargs )
work = get_object_or_404 ( models . Work , id = self . kwargs [ " work_id " ] )
campaign = work . last_campaign ( )
2011-11-30 02:02:51 +00:00
2012-06-21 17:16:51 +00:00
# if there is no campaign or if campaign is not active, we should raise an error
if campaign is None or campaign . status != ' ACTIVE ' :
raise Http404
premiums = campaign . effective_premiums ( )
2011-11-30 02:02:51 +00:00
premium_id = self . request . REQUEST . get ( ' premium_id ' , None )
preapproval_amount = self . request . REQUEST . get ( ' preapproval_amount ' , None )
2011-11-28 23:39:06 +00:00
2011-11-30 02:02:51 +00:00
if premium_id is not None and preapproval_amount is None :
2011-11-28 23:39:06 +00:00
try :
preapproval_amount = D ( models . Premium . objects . get ( id = premium_id ) . amount )
except :
preapproval_amount = None
2012-03-15 21:54:38 +00:00
2011-11-30 02:02:51 +00:00
data = { ' preapproval_amount ' : preapproval_amount , ' premium_id ' : premium_id }
2011-11-28 23:39:06 +00:00
2012-03-15 21:54:38 +00:00
form_class = self . get_form_class ( )
# no validation errors, please, when we're only doing a GET
# to avoid validation errors, don't bind the form
if preapproval_amount is not None :
form = form_class ( data )
else :
form = form_class ( )
2012-05-01 13:56:19 +00:00
try :
pubdate = work . publication_date [ : 4 ]
except IndexError :
pubdate = ' unknown '
2012-05-25 22:44:28 +00:00
context . update ( {
' redirect_to_modify_pledge ' : False ,
' work ' : work , ' campaign ' : campaign ,
' premiums ' : premiums , ' form ' : form ,
' premium_id ' : premium_id ,
' faqmenu ' : ' pledge ' ,
' pubdate ' : pubdate ,
' payment_processor ' : settings . PAYMENT_PROCESSOR ,
} )
2012-05-13 19:18:48 +00:00
# check whether the user already has an ACTIVE transaction for the given campaign.
# if so, we should redirect the user to modify pledge page
# BUGBUG: but what about Completed Transactions?
transactions = campaign . transactions ( ) . filter ( user = user , status = TRANSACTION_STATUS_ACTIVE )
if transactions . count ( ) > 0 :
context . update ( { ' redirect_to_modify_pledge ' : True } )
else :
context . update ( { ' redirect_to_modify_pledge ' : False } )
2011-11-30 02:02:51 +00:00
2011-11-28 23:39:06 +00:00
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 " ]
2012-03-21 21:53:33 +00:00
# right now, if there is a non-zero pledge amount, go with that. otherwise, do the pre_approval
2011-11-28 23:39:06 +00:00
campaign = models . Work . objects . get ( id = int ( work_id ) ) . last_campaign ( )
2012-03-21 21:53:33 +00:00
premium_id = form . cleaned_data [ " premium_id " ]
# confirm that the premium_id is a valid one for the campaign in question
try :
premium = models . Premium . objects . get ( id = premium_id )
if not ( premium . campaign is None or premium . campaign == campaign ) :
premium = None
except models . Premium . DoesNotExist , e :
premium = None
2011-11-28 23:39:06 +00:00
p = PaymentManager ( embedded = self . embedded )
2012-01-04 17:03:50 +00:00
# PledgeView is wrapped in login_required -- so in theory, user should never be None -- but I'll keep this logic here for now.
2011-11-28 23:39:06 +00:00
if self . request . user . is_authenticated ( ) :
user = self . request . user
else :
user = None
if not self . embedded :
2012-01-11 01:15:39 +00:00
return_url = None
2012-05-18 23:59:48 +00:00
nevermind_url = None
2012-01-10 20:16:04 +00:00
2011-12-19 23:34:30 +00:00
# the recipients of this authorization is not specified here but rather by the PaymentManager.
2011-12-20 19:56:01 +00:00
# set the expiry date based on the campaign deadline
2012-03-07 19:42:16 +00:00
expiry = campaign . deadline + timedelta ( days = settings . PREAPPROVAL_PERIOD_AFTER_CAMPAIGN )
2012-05-14 17:15:40 +00:00
paymentReason = " Unglue.it Pledge for {0} " . format ( campaign . name )
2011-12-20 19:56:01 +00:00
t , url = p . authorize ( ' USD ' , TARGET_TYPE_CAMPAIGN , preapproval_amount , expiry = expiry , campaign = campaign , list = None , user = user ,
2012-05-18 23:59:48 +00:00
return_url = return_url , nevermind_url = nevermind_url , anonymous = anonymous , premium = premium ,
2012-05-14 17:15:40 +00:00
paymentReason = paymentReason )
2011-12-19 23:34:30 +00:00
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 } ]
2011-11-28 23:39:06 +00:00
2012-01-11 01:15:39 +00:00
return_url = None
2012-05-18 23:59:48 +00:00
nevermind_url = None
2012-01-10 20:16:04 +00:00
2011-11-28 23:39:06 +00:00
t , url = p . pledge ( ' USD ' , TARGET_TYPE_CAMPAIGN , receiver_list , campaign = campaign , list = None , user = user ,
2012-05-18 23:59:48 +00:00
return_url = return_url , nevermind_url = nevermind_url , anonymous = anonymous , premium = premium )
2011-11-28 23:39:06 +00:00
if url :
2012-07-18 18:09:48 +00:00
logger . info ( " PledgeView url: " + url )
2011-11-28 23:39:06 +00:00
return HttpResponseRedirect ( url )
else :
2012-07-18 18:09:48 +00:00
logger . error ( " Attempt to produce transaction id {0} failed " . format ( t . id ) )
return HttpResponse ( " Our attempt to enable your transaction failed. We have logged this error. " )
2012-01-09 17:36:03 +00:00
2012-03-19 23:32:37 +00:00
class PledgeModifyView ( FormView ) :
"""
A view to handle request to change an existing pledge
2012-07-10 20:36:32 +00:00
"""
2012-04-19 14:50:40 +00:00
template_name = " pledge.html "
2012-03-19 23:32:37 +00:00
form_class = CampaignPledgeForm
embedded = False
def get_context_data ( self , * * kwargs ) :
context = super ( PledgeModifyView , self ) . get_context_data ( * * kwargs )
# the following should be true since PledgeModifyView.as_view is wrapped in login_required
assert self . request . user . is_authenticated ( )
user = self . request . user
work = get_object_or_404 ( models . Work , id = self . kwargs [ " work_id " ] )
try :
campaign = work . last_campaign ( )
premiums = campaign . effective_premiums ( )
# which combination of campaign and transaction status required?
# Campaign must be ACTIVE
assert campaign . status == ' ACTIVE '
2012-04-25 20:10:53 +00:00
2012-04-25 17:55:30 +00:00
transactions = campaign . transactions ( ) . filter ( user = user , status = TRANSACTION_STATUS_ACTIVE )
2012-03-19 23:32:37 +00:00
assert transactions . count ( ) == 1
transaction = transactions [ 0 ]
2012-04-25 17:55:30 +00:00
assert transaction . type == PAYMENT_TYPE_AUTHORIZATION and transaction . status == TRANSACTION_STATUS_ACTIVE
2012-03-19 23:32:37 +00:00
except Exception , e :
raise e
# what stuff do we need to pull out to populate form?
# preapproval_amount, premium_id (which we don't have stored yet)
2012-03-21 21:53:33 +00:00
if transaction . premium is not None :
premium_id = transaction . premium . id
2012-05-13 14:49:23 +00:00
premium_description = transaction . premium . description
2012-03-21 21:53:33 +00:00
else :
premium_id = None
2012-05-13 14:49:23 +00:00
premium_description = None
2012-03-21 21:53:33 +00:00
2012-03-19 23:32:37 +00:00
# is there a Transaction for an ACTIVE campaign for this
# should make sure Transaction is modifiable.
preapproval_amount = transaction . amount
data = { ' preapproval_amount ' : preapproval_amount , ' premium_id ' : premium_id }
2012-03-22 19:09:13 +00:00
# initialize form with the current state of the transaction if the current values empty
form = kwargs [ ' form ' ]
2012-03-19 23:32:37 +00:00
2012-03-22 19:09:13 +00:00
if not ( form . is_bound ) :
form_class = self . get_form_class ( )
form = form_class ( initial = data )
2012-03-19 23:32:37 +00:00
2012-05-25 22:18:29 +00:00
context . update ( {
' work ' : work ,
' campaign ' : campaign ,
' premiums ' : premiums ,
' form ' : form ,
' preapproval_amount ' : preapproval_amount ,
' premium_id ' : premium_id ,
' premium_description ' : premium_description ,
' faqmenu ' : ' modify ' ,
' tid ' : transaction . id ,
' payment_processor ' : settings . PAYMENT_PROCESSOR ,
} )
2012-03-19 23:32:37 +00:00
return context
2012-03-22 19:09:13 +00:00
def form_invalid ( self , form ) :
logger . info ( " form.non_field_errors: {0} " . format ( form . non_field_errors ( ) ) )
response = self . render_to_response ( self . get_context_data ( form = form ) )
return response
2012-03-19 23:32:37 +00:00
def form_valid ( self , form ) :
# What are the situations we need to deal with?
# 2 main situations: if the new amount is less than max_amount, no need to go out to PayPal again
# if new amount is greater than max_amount...need to go out and get new approval.
# to start with, we can use the standard pledge_complete, pledge_cancel machinery
# might have to modify the pledge_complete, pledge_cancel because the messages are going to be
# different because we're modifying a pledge rather than a new one.
work_id = self . kwargs [ " work_id " ]
preapproval_amount = form . cleaned_data [ " preapproval_amount " ]
anonymous = form . cleaned_data [ " anonymous " ]
assert self . request . user . is_authenticated ( )
user = self . request . user
# 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 ( )
assert campaign . status == ' ACTIVE '
2012-03-21 21:53:33 +00:00
premium_id = form . cleaned_data [ " premium_id " ]
# confirm that the premium_id is a valid one for the campaign in question
try :
premium = models . Premium . objects . get ( id = premium_id )
if not ( premium . campaign is None or premium . campaign == campaign ) :
premium = None
except models . Premium . DoesNotExist , e :
premium = None
2012-04-25 17:55:30 +00:00
transactions = campaign . transactions ( ) . filter ( user = user , status = TRANSACTION_STATUS_ACTIVE )
2012-03-19 23:32:37 +00:00
assert transactions . count ( ) == 1
transaction = transactions [ 0 ]
2012-04-25 17:55:30 +00:00
assert transaction . type == PAYMENT_TYPE_AUTHORIZATION and transaction . status == TRANSACTION_STATUS_ACTIVE
2012-03-19 23:32:37 +00:00
p = PaymentManager ( embedded = self . embedded )
2012-05-14 17:15:40 +00:00
paymentReason = " Unglue.it Pledge for {0} " . format ( campaign . name )
status , url = p . modify_transaction ( transaction = transaction , amount = preapproval_amount , premium = premium ,
paymentReason = paymentReason )
2012-03-19 23:32:37 +00:00
logger . info ( " status: {0} , url: {1} " . format ( status , url ) )
if status and url is not None :
logger . info ( " PledgeModifyView paypal: " + url )
return HttpResponseRedirect ( url )
elif status and url is None :
2012-03-20 18:21:06 +00:00
# let's use the pledge_complete template for now and maybe look into customizing it.
return HttpResponseRedirect ( " {0} ?tid= {1} " . format ( reverse ( ' pledge_complete ' ) , transaction . id ) )
2012-03-19 23:32:37 +00:00
else :
2012-05-29 12:54:57 +00:00
return HttpResponse ( " No modification made " )
2012-03-19 23:32:37 +00:00
2012-07-10 20:36:32 +00:00
class PledgeRechargeView ( TemplateView ) :
"""
a view to allow for recharge of a transaction for failed transactions or ones with errors
"""
template_name = " pledge_recharge.html "
def get_context_data ( self , * * kwargs ) :
2012-07-12 02:51:36 +00:00
context = super ( PledgeRechargeView , self ) . get_context_data ( * * kwargs )
2012-07-10 20:36:32 +00:00
# the following should be true since PledgeModifyView.as_view is wrapped in login_required
assert self . request . user . is_authenticated ( )
user = self . request . user
work = get_object_or_404 ( models . Work , id = self . kwargs [ " work_id " ] )
2012-07-13 17:17:51 +00:00
campaign = work . last_campaign ( )
if campaign is None :
return Http404
transaction = campaign . transaction_to_recharge ( user )
# calculate a URL to do a preapproval -- in the future, we may want to do a straight up payment
2012-07-13 22:55:41 +00:00
return_url = None
nevermind_url = None
2012-07-10 20:36:32 +00:00
2012-07-13 22:55:41 +00:00
if transaction is not 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 )
paymentReason = " Unglue.it Recharge for {0} " . format ( campaign . name )
p = PaymentManager ( embedded = False )
t , url = p . authorize ( ' USD ' , TARGET_TYPE_CAMPAIGN , transaction . amount , expiry = expiry , campaign = campaign , list = None , user = user ,
return_url = return_url , nevermind_url = nevermind_url , anonymous = transaction . anonymous , premium = transaction . premium ,
paymentReason = paymentReason )
logger . info ( " Recharge url: {0} " . format ( url ) )
else :
url = None
2012-07-10 20:36:32 +00:00
context . update ( {
' work ' : work ,
2012-07-13 17:17:51 +00:00
' transaction ' : transaction ,
2012-07-13 22:55:41 +00:00
' payment_processor ' : transaction . host if transaction is not None else None ,
' recharge_url ' : url
2012-07-10 20:36:32 +00:00
} )
return context
2012-01-09 17:36:03 +00:00
class PledgeCompleteView ( TemplateView ) :
2012-01-11 01:15:39 +00:00
""" A callback for PayPal to tell unglue.it that a payment transaction has completed successfully.
Possible things to implement :
2012-03-19 23:32:37 +00:00
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 )
2012-01-11 01:15:39 +00:00
"""
2012-01-09 17:36:03 +00:00
template_name = " pledge_complete.html "
2012-01-10 20:16:04 +00:00
def get_context_data ( self ) :
2012-01-09 17:36:03 +00:00
# pick up all get and post parameters and display
2012-01-10 20:16:04 +00:00
context = super ( PledgeCompleteView , self ) . get_context_data ( )
2012-01-09 17:36:03 +00:00
output = " pledge complete "
output + = self . request . method + " \n " + str ( self . request . REQUEST . items ( ) )
context [ " output " ] = output
2012-01-11 01:15:39 +00:00
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
2012-03-19 18:46:41 +00:00
else :
# should be 403 -- but let's try 404 for now -- 403 exception coming in Django 1.4
raise Http404
2012-01-11 01:15:39 +00:00
except Exception , e :
2012-03-19 18:46:41 +00:00
raise Http404
2012-01-11 01:15:39 +00:00
# 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)
2012-01-09 17:36:03 +00:00
2012-01-11 01:15:39 +00:00
if transaction . type == PAYMENT_TYPE_AUTHORIZATION :
correct_transaction_type = True
else :
correct_transaction_type = False
2012-03-16 20:03:38 +00:00
# add the work corresponding to the Transaction on the user's wishlist if it's not already on the wishlist
if user is not None and correct_user and correct_transaction_type and ( campaign is not None ) and ( work is not None ) :
# ok to overwrite Wishes.source?
user . wishlist . add_work ( work , ' pledging ' )
2012-03-26 19:26:47 +00:00
2012-05-01 17:49:23 +00:00
worklist = slideshow ( 8 )
works = worklist [ : 4 ]
works2 = worklist [ 4 : 8 ]
2012-03-26 19:26:47 +00:00
2012-01-11 01:15:39 +00:00
context [ " transaction " ] = transaction
context [ " correct_user " ] = correct_user
context [ " correct_transaction_type " ] = correct_transaction_type
context [ " work " ] = work
context [ " campaign " ] = campaign
2012-02-21 14:24:23 +00:00
context [ " faqmenu " ] = " complete "
2012-03-26 19:26:47 +00:00
context [ " works " ] = works
2012-05-13 02:42:09 +00:00
context [ " works2 " ] = works2
2012-05-14 20:56:36 +00:00
context [ " site " ] = Site . objects . get_current ( )
2012-01-11 01:15:39 +00:00
return context
2012-01-09 17:36:03 +00:00
2012-05-21 14:56:18 +00:00
class PledgeCancelView ( FormView ) :
""" A view for allowing a user to cancel the active transaction for specified campaign """
2012-01-09 17:36:03 +00:00
template_name = " pledge_cancel.html "
2012-05-21 14:56:18 +00:00
form_class = PledgeCancelForm
2012-01-09 17:36:03 +00:00
2012-05-21 14:56:18 +00:00
def get_context_data ( self , * * kwargs ) :
context = super ( PledgeCancelView , self ) . get_context_data ( * * kwargs )
2012-05-18 23:59:48 +00:00
2012-05-23 14:22:48 +00:00
# initialize error to be None
context [ " error " ] = None
2012-05-18 23:59:48 +00:00
2012-05-21 14:56:18 +00:00
# the following should be true since PledgeCancelView.as_view is wrapped in login_required
2012-05-23 14:22:48 +00:00
if self . request . user . is_authenticated ( ) :
user = self . request . user
else :
2012-05-25 01:47:50 +00:00
context [ " error " ] = " You are not logged in. "
2012-05-23 14:22:48 +00:00
return context
2012-05-18 23:59:48 +00:00
2012-05-21 14:56:18 +00:00
campaign = get_object_or_404 ( models . Campaign , id = self . kwargs [ " campaign_id " ] )
2012-05-23 14:22:48 +00:00
if campaign . status != ' ACTIVE ' :
context [ " error " ] = " {0} is not an active campaign " . format ( campaign )
return context
2012-05-21 14:56:18 +00:00
work = campaign . work
transactions = campaign . transactions ( ) . filter ( user = user , status = TRANSACTION_STATUS_ACTIVE )
2012-05-23 14:22:48 +00:00
if transactions . count ( ) < 1 :
2012-05-25 01:47:50 +00:00
context [ " error " ] = " You don ' t have an active transaction for this campaign. "
2012-05-23 14:22:48 +00:00
return context
elif transactions . count ( ) > 1 :
2012-05-25 01:47:50 +00:00
logger . error ( " User {0} has {1} active transactions for campaign id {2} " . format ( user , transactions . count ( ) , campaign . id ) )
2012-05-23 14:22:48 +00:00
context [ " error " ] = " You have {0} active transactions for this campaign " . format ( transactions . count ( ) )
return context
2012-05-21 14:56:18 +00:00
transaction = transactions [ 0 ]
2012-05-23 14:22:48 +00:00
if transaction . type != PAYMENT_TYPE_AUTHORIZATION :
2012-05-25 01:47:50 +00:00
logger . error ( " Transaction id {0} transaction type, which should be {1} , is actually {2} " . format ( transaction . id , PAYMENT_TYPE_AUTHORIZATION , transaction . type ) )
2012-05-23 14:22:48 +00:00
context [ " error " ] = " Your transaction type, which should be {0} , is actually {1} " . format ( PAYMENT_TYPE_AUTHORIZATION , transaction . type )
return context
# we've located the transaction, work, and campaign referenced in the view
2012-05-18 23:59:48 +00:00
context [ " transaction " ] = transaction
context [ " work " ] = work
context [ " campaign " ] = campaign
context [ " faqmenu " ] = " cancel "
return context
2012-05-23 14:22:48 +00:00
def form_valid ( self , form ) :
# check that user does, in fact, have an active transaction for specified campaign
logger . info ( " arrived at pledge_cancel form_valid " )
# pull campaign_id from form, not from URI as we do from GET
campaign_id = self . request . REQUEST . get ( ' campaign_id ' )
2012-05-25 01:47:50 +00:00
# this following logic should be extraneous.
if self . request . user . is_authenticated ( ) :
user = self . request . user
else :
return HttpResponse ( " You need to be logged in. " )
2012-05-23 14:22:48 +00:00
try :
2012-05-23 16:12:21 +00:00
# look up the specified campaign and attempt to pull up the appropriate transaction
# i.e., the transaction actually belongs to user, that the transaction is active
2012-05-23 14:22:48 +00:00
campaign = get_object_or_404 ( models . Campaign , id = self . kwargs [ " campaign_id " ] , status = ' ACTIVE ' )
transaction = campaign . transaction_set . get ( user = user , status = TRANSACTION_STATUS_ACTIVE ,
type = PAYMENT_TYPE_AUTHORIZATION )
2012-05-23 16:12:21 +00:00
# attempt to cancel the transaction and redirect to the Work page if cancel is successful
2012-05-23 14:22:48 +00:00
# here's a place that would be nice to use https://docs.djangoproject.com/en/dev/ref/contrib/messages/
2012-05-23 16:12:21 +00:00
# to display the success or failure of the cancel operation as a popup in the context of the work page
2012-05-23 14:22:48 +00:00
p = PaymentManager ( )
result = p . cancel_transaction ( transaction )
2012-05-25 01:47:50 +00:00
# put a notification here for pledge cancellation?
2012-05-23 16:12:21 +00:00
if result :
# Now if we redirect the user to the Work page and the IPN hasn't arrived, the status of the
# transaction might be out of date. Let's try an explicit polling of the transaction result before redirecting
# We might want to remove this in a production system
if settings . DEBUG :
update_status = p . update_preapproval ( transaction )
2012-06-15 20:14:26 +00:00
# send a notice out that the transaction has been canceled -- leverage the pledge_modify notice for now
# BUGBUG: should have a pledge cancel notice actually since I think it's different
from regluit . payment . signals import pledge_modified
pledge_modified . send ( sender = self , transaction = transaction , up_or_down = " canceled " )
logger . info ( " pledge_modified notice for cancellation: sender {0} , transaction {1} " . format ( self , transaction ) )
2012-05-23 16:12:21 +00:00
return HttpResponseRedirect ( reverse ( ' work ' , kwargs = { ' work_id ' : campaign . work . id } ) )
else :
2012-05-25 01:47:50 +00:00
logger . error ( " Attempt to cancel transaction id {0} failed " . format ( transaction . id ) )
return HttpResponse ( " Our attempt to cancel your transaction failed. We have logged this error. " )
except Exception , e :
logger . error ( " Exception from attempt to cancel pledge for campaign id {0} for username {1} : {2} " . format ( campaign_id , user . username , e ) )
return HttpResponse ( " Sorry, something went wrong in canceling your campaign pledge. We have logged this error. " )
2012-05-23 14:22:48 +00:00
2012-05-18 23:59:48 +00:00
class PledgeNeverMindView ( TemplateView ) :
""" A callback for PayPal to tell unglue.it that a payment transaction has been canceled by the user """
template_name = " pledge_nevermind.html "
def get_context_data ( self ) :
context = super ( PledgeNeverMindView , 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 )
2012-01-10 23:26:04 +00:00
2012-01-11 01:15:39 +00:00
# work and campaign in question
try :
campaign = transaction . campaign
work = campaign . work
except Exception , e :
campaign = None
work = None
2012-01-10 23:26:04 +00:00
# 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 :
2012-01-11 01:15:39 +00:00
correct_transaction_type = True
2012-01-10 23:26:04 +00:00
else :
2012-01-11 01:15:39 +00:00
correct_transaction_type = False
2012-01-10 23:26:04 +00:00
# status?
2012-01-11 01:15:39 +00:00
2012-01-10 23:26:04 +00:00
# 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
2012-01-11 01:15:39 +00:00
context [ " work " ] = work
context [ " campaign " ] = campaign
2012-02-21 14:24:23 +00:00
context [ " faqmenu " ] = " cancel "
2012-01-10 23:26:04 +00:00
2012-01-09 17:36:03 +00:00
return context
2011-11-28 23:39:06 +00:00
2011-12-03 00:37:27 +00:00
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
2011-11-07 21:01:08 +00:00
2011-12-03 00:37:27 +00:00
# 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 )
2011-11-16 05:22:22 +00:00
def claim ( request ) :
if request . method == ' GET ' :
data = request . GET
else :
data = request . POST
2012-03-23 01:24:12 +00:00
form = UserClaimForm ( request . user , data = data , prefix = ' claim ' )
2011-11-16 05:22:22 +00:00
if form . is_valid ( ) :
2011-11-23 16:06:48 +00:00
# make sure we're not creating a duplicate claim
2012-03-23 01:24:12 +00:00
if not models . Claim . objects . filter ( work = data [ ' claim-work ' ] , rights_holder = data [ ' claim-rights_holder ' ] , status = ' pending ' ) . count ( ) :
2011-11-16 05:22:22 +00:00
form . save ( )
2012-03-23 01:24:12 +00:00
return HttpResponseRedirect ( reverse ( ' work ' , kwargs = { ' work_id ' : data [ ' claim-work ' ] } ) )
2011-11-16 05:22:22 +00:00
else :
2012-03-23 01:24:12 +00:00
work = models . Work . objects . get ( id = data [ ' claim-work ' ] )
rights_holder = models . RightsHolder . objects . get ( id = data [ ' claim-rights_holder ' ] )
2012-04-05 20:55:10 +00:00
active_claims = work . claim . exclude ( status = ' release ' )
context = { ' form ' : form , ' work ' : work , ' rights_holder ' : rights_holder , ' active_claims ' : active_claims }
2011-11-16 05:22:22 +00:00
return render ( request , " claim.html " , context )
2011-11-20 02:12:18 +00:00
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 :
2012-04-07 18:12:54 +00:00
if claim . status == ' active ' :
claim . campaigns = claim . work . campaigns . all ( )
else :
claim . campaigns = [ ]
2011-11-20 02:12:18 +00:00
claim . can_open_new = True
for campaign in claim . campaigns :
2011-11-22 05:28:06 +00:00
if campaign . status in [ ' ACTIVE ' , ' INITIALIZED ' ] :
claim . can_open_new = False
2012-04-03 19:50:02 +00:00
if request . method == ' POST ' and request . POST . has_key ( ' edit_managers_ %s ' % campaign . id ) :
campaign . edit_managers_form = EditManagersForm ( instance = campaign , data = request . POST , prefix = campaign . id )
if campaign . edit_managers_form . is_valid ( ) :
campaign . edit_managers_form . save ( )
2012-04-07 18:12:54 +00:00
campaign . edit_managers_form = EditManagersForm ( instance = campaign , prefix = campaign . id )
2012-04-03 19:50:02 +00:00
else :
campaign . edit_managers_form = EditManagersForm ( instance = campaign , prefix = campaign . id )
2011-11-20 02:12:18 +00:00
if claim . status == ' active ' and claim . can_open_new :
2012-04-05 21:53:00 +00:00
if request . method == ' POST ' and request . POST . has_key ( ' work ' ) and int ( request . POST [ ' work ' ] ) == claim . work . id :
2011-11-20 02:12:18 +00:00
claim . campaign_form = OpenCampaignForm ( request . POST )
if claim . campaign_form . is_valid ( ) :
2011-11-29 04:37:17 +00:00
new_campaign = claim . campaign_form . save ( commit = False )
2012-03-07 19:42:16 +00:00
new_campaign . deadline = date_today ( ) + timedelta ( days = int ( settings . UNGLUEIT_LONGEST_DEADLINE ) )
2011-11-29 04:37:17 +00:00
new_campaign . target = D ( settings . UNGLUEIT_MINIMUM_TARGET )
new_campaign . save ( )
claim . campaign_form . save_m2m ( )
2011-11-20 02:12:18 +00:00
claim . can_open_new = False
else :
2012-05-07 21:32:45 +00:00
claim . campaign_form = OpenCampaignForm ( data = { ' work ' : claim . work , ' name ' : claim . work . title , ' userid ' : request . user . id , ' managers_1 ' : request . user . id } )
2011-11-20 02:12:18 +00:00
else :
claim . can_open_new = False
return render ( request , " rh_tools.html " , { ' claims ' : claims , } )
2011-11-15 04:28:55 +00:00
def rh_admin ( request ) :
2011-11-19 00:50:47 +00:00
if not request . user . is_authenticated ( ) :
return render ( request , " admins_only.html " )
2011-11-21 20:08:15 +00:00
if not request . user . is_staff :
2011-11-15 04:28:55 +00:00
return render ( request , " admins_only.html " )
2011-11-17 19:35:29 +00:00
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 ' )
2011-11-15 04:28:55 +00:00
if request . method == ' POST ' :
2011-11-17 19:35:29 +00:00
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 ( )
2012-04-07 19:31:11 +00:00
form = RightsHolderForm ( )
2011-11-17 19:35:29 +00:00
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 ( )
2011-11-20 02:12:18 +00:00
pending_formset = PendingFormSet ( queryset = pending_data )
2011-11-15 04:28:55 +00:00
else :
form = RightsHolderForm ( )
2011-11-17 19:35:29 +00:00
pending_formset = PendingFormSet ( queryset = pending_data )
2011-11-15 04:28:55 +00:00
rights_holders = models . RightsHolder . objects . all ( )
2011-11-17 19:35:29 +00:00
2011-11-16 19:45:37 +00:00
context = {
' request ' : request ,
' rights_holders ' : rights_holders ,
' form ' : form ,
2011-11-17 19:35:29 +00:00
' pending ' : zip ( pending_data , pending_formset ) ,
' pending_formset ' : pending_formset ,
' active_data ' : active_data ,
2011-11-16 19:45:37 +00:00
}
2011-11-15 04:28:55 +00:00
return render ( request , " rights_holders.html " , context )
2011-12-20 22:42:06 +00:00
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 = { }
2011-12-21 22:32:08 +00:00
def campaigns_types ( ) :
# pull out Campaigns with Transactions that are ACTIVE -- and hence can be executed
# Campaign.objects.filter(transaction__status='ACTIVE')
2012-04-25 17:55:30 +00:00
campaigns_with_active_transactions = models . Campaign . objects . filter ( transaction__status = TRANSACTION_STATUS_ACTIVE )
2011-12-21 22:32:08 +00:00
# pull out Campaigns with Transactions that are INCOMPLETE
2012-04-25 17:55:30 +00:00
campaigns_with_incomplete_transactions = models . Campaign . objects . filter ( transaction__status = TRANSACTION_STATUS_INCOMPLETE )
2011-12-21 22:32:08 +00:00
# show all Campaigns with Transactions that are COMPLETED
2012-05-04 14:30:05 +00:00
campaigns_with_completed_transactions = models . Campaign . objects . filter ( transaction__status = TRANSACTION_STATUS_COMPLETE )
2011-12-21 22:32:08 +00:00
# show Campaigns with Transactions that are CANCELED
2012-04-25 20:10:53 +00:00
campaigns_with_canceled_transactions = models . Campaign . objects . filter ( transaction__status = TRANSACTION_STATUS_CANCELED )
2011-12-21 22:32:08 +00:00
2012-04-25 20:10:53 +00:00
return ( campaigns_with_active_transactions , campaigns_with_incomplete_transactions , campaigns_with_completed_transactions , campaigns_with_canceled_transactions )
2011-12-21 22:32:08 +00:00
2011-12-20 22:42:06 +00:00
form = CampaignAdminForm ( )
2011-12-21 22:32:08 +00:00
pm = PaymentManager ( )
check_status_results = None
command_status = None
2011-12-20 22:42:06 +00:00
if request . method == ' GET ' :
2011-12-21 22:32:08 +00:00
pass
2011-12-20 22:42:06 +00:00
elif request . method == ' POST ' :
2011-12-21 22:32:08 +00:00
if ' campaign_checkstatus ' in request . POST . keys ( ) :
# campaign_checkstatus
try :
2011-12-23 01:34:24 +00:00
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 " )
2011-12-21 22:32:08 +00:00
except Exception , e :
check_status_results = e
2011-12-23 14:59:07 +00:00
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 ) )
2011-12-21 22:32:08 +00:00
elif ' finish_campaigns ' in request . POST . keys ( ) :
2011-12-23 14:59:07 +00:00
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 ) )
2011-12-21 22:32:08 +00:00
elif ' cancel_campaigns ' in request . POST . keys ( ) :
2011-12-23 14:59:07 +00:00
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 ) )
2011-12-21 01:36:27 +00:00
2011-12-21 22:32:08 +00:00
( campaigns_with_active_transactions , campaigns_with_incomplete_transactions , campaigns_with_completed_transactions ,
campaigns_with_canceled_transactions ) = campaigns_types ( )
2011-12-20 22:42:06 +00:00
context . update ( {
' form ' : form ,
2011-12-21 01:36:27 +00:00
' check_status_results ' : check_status_results ,
' campaigns_with_active_transactions ' : campaigns_with_active_transactions ,
' campaigns_with_incomplete_transactions ' : campaigns_with_incomplete_transactions ,
2011-12-21 22:32:08 +00:00
' campaigns_with_completed_transactions ' : campaigns_with_completed_transactions ,
' campaigns_with_canceled_transactions ' : campaigns_with_canceled_transactions ,
' command_status ' : command_status
2011-12-20 22:42:06 +00:00
} )
2011-12-21 22:32:08 +00:00
2011-12-20 22:42:06 +00:00
return render ( request , " campaign_admin.html " , context )
2011-11-15 04:28:55 +00:00
2011-11-03 20:28:53 +00:00
def supporter ( request , supporter_username , template_name ) :
2011-10-19 07:13:29 +00:00
supporter = get_object_or_404 ( User , username = supporter_username )
wishlist = supporter . wishlist
2012-03-07 18:23:34 +00:00
works = [ ]
works2 = [ ]
works_unglued = [ ]
works_active = [ ]
works_wished = [ ]
2012-02-22 03:00:23 +00:00
2012-03-07 18:23:34 +00:00
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 ( )
2012-02-22 03:00:23 +00:00
2012-03-08 14:36:59 +00:00
else :
2012-03-07 18:23:34 +00:00
backed = 0
backing = 0
wished = 0
2012-03-08 14:36:59 +00:00
worklist = slideshow ( 8 )
works = worklist [ : 4 ]
works2 = worklist [ 4 : 8 ]
2012-03-28 13:08:05 +00:00
2012-05-11 18:13:09 +00:00
# default to showing the Active tab if there are active campaigns, else show Wishlist
2012-03-28 13:08:05 +00:00
if backing > 0 :
2012-05-11 18:13:09 +00:00
activetab = " #2 "
2012-03-28 13:08:05 +00:00
else :
2012-05-11 18:13:09 +00:00
activetab = " #3 "
2012-02-23 20:40:45 +00:00
2011-10-19 07:13:29 +00:00
date = supporter . date_joined . strftime ( " % B %d , % Y " )
2012-02-23 20:40:45 +00:00
2011-10-23 18:40:06 +00:00
# following block to support profile admin form in supporter page
2011-10-19 07:13:29 +00:00
if request . user . is_authenticated ( ) and request . user . username == supporter_username :
2011-11-17 00:47:29 +00:00
2011-11-09 17:24:26 +00:00
try :
profile_obj = request . user . get_profile ( )
except ObjectDoesNotExist :
profile_obj = models . UserProfile ( )
profile_obj . user = request . user
2011-11-17 00:47:29 +00:00
2011-10-19 07:13:29 +00:00
if request . method == ' POST ' :
2011-10-23 18:40:06 +00:00
profile_form = ProfileForm ( data = request . POST , instance = profile_obj )
2011-10-19 07:13:29 +00:00
if profile_form . is_valid ( ) :
2012-01-24 17:36:45 +00:00
if profile_form . cleaned_data [ ' clear_facebook ' ] or profile_form . cleaned_data [ ' clear_twitter ' ] or profile_form . cleaned_data [ ' clear_goodreads ' ] :
2011-11-14 18:23:14 +00:00
if profile_form . cleaned_data [ ' clear_facebook ' ] :
profile_obj . facebook_id = 0
if profile_form . cleaned_data [ ' clear_twitter ' ] :
profile_obj . twitter_id = " "
2012-01-24 17:36:45 +00:00
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
2011-11-14 18:23:14 +00:00
profile_obj . save ( )
2011-10-19 07:13:29 +00:00
profile_form . save ( )
2011-11-17 00:47:29 +00:00
2011-10-19 07:13:29 +00:00
else :
2011-11-09 17:24:26 +00:00
profile_form = ProfileForm ( instance = profile_obj )
2011-11-17 00:47:29 +00:00
if request . user . profile . goodreads_user_id is not None :
2012-01-24 17:36:45 +00:00
goodreads_id = request . user . profile . goodreads_user_id
2011-11-17 00:47:29 +00:00
else :
2012-01-24 17:36:45 +00:00
goodreads_id = None
2011-11-17 00:47:29 +00:00
if request . user . profile . librarything_id is not None :
librarything_id = request . user . profile . librarything_id
else :
librarything_id = None
2011-10-19 16:55:48 +00:00
else :
profile_form = ' '
2012-01-24 17:36:45 +00:00
goodreads_id = None
2011-11-17 00:47:29 +00:00
librarything_id = None
2011-10-19 07:13:29 +00:00
context = {
2011-10-14 14:18:38 +00:00
" supporter " : supporter ,
" wishlist " : wishlist ,
2012-02-22 03:00:23 +00:00
" works_unglued " : works_unglued ,
" works_active " : works_active ,
" works_wished " : works_wished ,
2012-03-07 18:23:34 +00:00
" works " : works ,
" works2 " : works2 ,
2011-10-14 14:18:38 +00:00
" backed " : backed ,
" backing " : backing ,
" wished " : wished ,
" date " : date ,
2011-10-19 07:13:29 +00:00
" profile_form " : profile_form ,
2011-11-16 20:45:33 +00:00
" ungluers " : userlists . other_users ( supporter , 5 ) ,
2011-11-17 00:47:29 +00:00
" goodreads_auth_url " : reverse ( ' goodreads_auth ' ) ,
2012-01-24 17:36:45 +00:00
" goodreads_id " : goodreads_id ,
2012-02-23 20:40:45 +00:00
" librarything_id " : librarything_id ,
2012-03-28 13:08:05 +00:00
" activetab " : activetab
2011-10-19 07:13:29 +00:00
}
2011-11-03 20:28:53 +00:00
return render ( request , template_name , context )
2011-10-03 16:36:04 +00:00
def edit_user ( request ) :
if not request . user . is_authenticated ( ) :
2012-04-25 02:20:10 +00:00
return HttpResponseRedirect ( reverse ( ' auth_login ' ) )
form = UserData ( )
2012-05-26 21:30:12 +00:00
emailform = UserEmail ( )
2011-10-03 16:36:04 +00:00
if request . method == ' POST ' :
2012-04-25 02:20:10 +00:00
if ' change_username ' in request . POST . keys ( ) :
2012-05-26 21:30:12 +00:00
form = UserData ( request . POST )
form . oldusername = request . user . username
2012-04-25 02:20:10 +00:00
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
elif ' change_email ' in request . POST . keys ( ) :
emailform = UserEmail ( request . POST )
2012-05-26 21:28:57 +00:00
emailform . oldemail = request . user . email
2012-04-25 02:20:10 +00:00
if emailform . is_valid ( ) :
request . user . email = emailform . cleaned_data [ ' email ' ]
request . user . save ( )
send_mail_task . delay (
' unglue.it email changed ' ,
2012-05-26 21:28:57 +00:00
render_to_string ( ' registration/email_changed.txt ' , { ' oldemail ' : emailform . oldemail , ' request ' : request } ) ,
2012-04-25 02:20:10 +00:00
None ,
2012-05-26 21:28:57 +00:00
[ request . user . email , emailform . oldemail ]
2012-04-25 02:20:10 +00:00
)
return HttpResponseRedirect ( reverse ( ' home ' ) ) # Redirect after POST
return render ( request , ' registration/user_change_form.html ' , { ' form ' : form , ' emailform ' : emailform } )
2011-10-03 16:36:04 +00:00
2011-09-29 01:36:47 +00:00
def search ( request ) :
2011-09-29 01:54:50 +00:00
q = request . GET . get ( ' q ' , None )
2012-02-05 00:06:53 +00:00
page = int ( request . GET . get ( ' page ' , 1 ) )
results = gluejar_search ( q , user_ip = request . META [ ' REMOTE_ADDR ' ] , page = page )
2011-09-29 06:23:50 +00:00
2011-10-10 22:08:53 +00:00
# flag search result as on wishlist as appropriate
2011-09-30 01:01:28 +00:00
if not request . user . is_anonymous ( ) :
2011-11-14 20:40:33 +00:00
ungluers = userlists . other_users ( request . user , 5 )
else :
2011-11-15 16:47:47 +00:00
ungluers = userlists . other_users ( None , 5 )
2012-02-05 00:06:53 +00:00
2012-01-03 00:07:12 +00:00
works = [ ]
2011-11-15 16:27:32 +00:00
for result in results :
2012-01-31 15:07:52 +00:00
try :
work = models . Identifier . objects . get ( type = ' goog ' , value = result [ ' googlebooks_id ' ] ) . work
works . append ( work )
except models . Identifier . DoesNotExist :
works . append ( result )
2011-09-29 01:54:50 +00:00
context = {
" q " : q ,
2012-01-03 00:07:12 +00:00
" results " : works ,
2011-11-14 20:40:33 +00:00
" ungluers " : ungluers
2011-09-29 01:54:50 +00:00
}
return render ( request , ' search.html ' , context )
2011-09-29 06:23:50 +00:00
2011-09-29 11:44:03 +00:00
# TODO: perhaps this functionality belongs in the API?
2011-09-29 06:23:50 +00:00
@require_POST
@login_required
2011-10-10 16:57:10 +00:00
@csrf_exempt
2011-09-29 06:23:50 +00:00
def wishlist ( request ) :
2011-10-10 16:57:10 +00:00
googlebooks_id = request . POST . get ( ' googlebooks_id ' , None )
2011-09-29 11:44:03 +00:00
remove_work_id = request . POST . get ( ' remove_work_id ' , None )
2011-12-28 02:39:40 +00:00
add_work_id = request . POST . get ( ' add_work_id ' , None )
2012-01-31 23:15:03 +00:00
2011-10-10 16:57:10 +00:00
if googlebooks_id :
2012-01-31 19:54:48 +00:00
try :
edition = bookloader . add_by_googlebooks_id ( googlebooks_id )
if edition . new :
# add related editions asynchronously
2012-02-16 18:19:36 +00:00
tasks . populate_edition . delay ( edition . isbn_13 )
2012-01-31 19:54:48 +00:00
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 ) )
2011-09-29 11:44:03 +00:00
# TODO: redirect to work page, when it exists
return HttpResponseRedirect ( ' / ' )
elif remove_work_id :
2012-03-09 21:05:01 +00:00
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
2011-12-08 23:22:05 +00:00
request . user . wishlist . remove_work ( work )
2011-09-29 16:42:19 +00:00
# TODO: where to redirect?
2011-09-29 11:44:03 +00:00
return HttpResponseRedirect ( ' / ' )
2011-12-28 02:39:40 +00:00
elif add_work_id :
2011-12-31 18:49:23 +00:00
# if adding from work page, we have may work.id, not googlebooks_id
2012-03-09 21:05:01 +00:00
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
2011-12-31 18:49:23 +00:00
request . user . wishlist . add_work ( work , ' user ' )
2011-12-28 02:39:40 +00:00
return HttpResponseRedirect ( ' / ' )
2011-10-14 02:16:28 +00:00
2012-03-08 03:06:30 +00:00
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
2012-03-07 19:42:16 +00:00
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 )
2012-03-13 20:54:30 +00:00
users . yesterday = users . filter ( date_joined__range = ( date_today ( ) - timedelta ( days = 1 ) , date_today ( ) ) )
2012-03-13 03:34:10 +00:00
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 = ' ' )
2012-03-08 03:06:30 +00:00
works = models . Work . objects
2012-03-07 19:42:16 +00:00
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 )
2012-03-13 20:54:30 +00:00
works . yesterday = works . filter ( created__range = ( date_today ( ) - timedelta ( days = 1 ) , date_today ( ) ) )
2012-03-08 03:06:30 +00:00
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
2012-03-07 19:42:16 +00:00
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 )
2012-03-13 20:54:30 +00:00
ebooks . yesterday = ebooks . filter ( created__range = ( date_today ( ) - timedelta ( days = 1 ) , date_today ( ) ) )
2012-03-08 03:06:30 +00:00
wishlists = models . Wishlist . objects . exclude ( wishes__isnull = True )
2012-03-07 19:42:16 +00:00
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 )
2012-03-13 03:34:10 +00:00
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 )
2012-03-08 03:06:30 +00:00
return {
' users ' : users ,
' works ' : works ,
' ebooks ' : ebooks ,
' wishlists ' : wishlists ,
}
2012-07-20 18:29:04 +00:00
class InfoLangView ( TemplateView ) :
def get_template_names ( self , * * kwargs ) :
if self . kwargs [ ' template_name ' ] :
return ( self . kwargs [ ' template_name ' ] )
else :
return ( ' languages.html ' )
def get_context_data ( self , * * kwargs ) :
languages = models . Work . objects . filter ( num_wishes__gte = 1 ) . values ( ' language ' ) . annotate ( lang_count = Count ( ' language ' ) ) . order_by ( ' -lang_count ' )
return {
' wished_languages ' : languages ,
}
2012-03-08 03:06:30 +00:00
2012-01-03 21:17:04 +00:00
class FAQView ( TemplateView ) :
2012-01-31 15:07:52 +00:00
template_name = " faq.html "
def get_context_data ( self , * * kwargs ) :
location = self . kwargs [ " location " ]
sublocation = self . kwargs [ " sublocation " ]
return { ' location ' : location , ' sublocation ' : sublocation }
2011-10-25 01:29:01 +00:00
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 )
2011-10-29 22:40:00 +00:00
user = self . request . user
2011-11-01 16:50:05 +00:00
if user . is_authenticated ( ) :
api_key = ApiKey . objects . filter ( user = user ) [ 0 ] . key
context [ ' api_key ' ] = api_key
2011-10-25 01:29:01 +00:00
2011-10-29 22:40:00 +00:00
if user . profile . goodreads_user_id is None :
2011-10-25 01:29:01 +00:00
# calculate the Goodreads authorization URL
( context [ " goodreads_auth_url " ] , request_token ) = gr_client . begin_authorization ( self . request . build_absolute_uri ( reverse ( ' goodreads_cb ' ) ) )
2011-10-29 22:40:00 +00:00
logger . info ( " goodreads_auth_url: %s " % ( context [ " goodreads_auth_url " ] ) )
2011-10-25 01:29:01 +00:00
# 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 ' ]
2011-10-29 22:40:00 +00:00
else :
2011-11-01 00:26:05 +00:00
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
2011-11-10 23:14:33 +00:00
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 " ] ]
2011-11-15 20:51:38 +00:00
gr_shelf_load_form . fields [ ' goodreads_shelf_name_number ' ] . widget = Select ( choices = tuple ( choices ) )
2011-10-25 01:29:01 +00:00
2011-11-01 00:26:05 +00:00
context [ " gr_shelf_load_form " ] = gr_shelf_load_form
2011-11-10 23:14:33 +00:00
# also load any CeleryTasks associated with the user
context [ " celerytasks " ] = models . CeleryTask . objects . filter ( user = user )
2011-10-25 01:29:01 +00:00
return context
2011-10-29 22:40:00 +00:00
2011-11-16 22:16:57 +00:00
@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 )
2011-10-29 22:40:00 +00:00
@login_required
2011-10-25 01:29:01 +00:00
def goodreads_cb ( request ) :
2011-10-29 22:40:00 +00:00
""" handle callback from Goodreads """
2011-10-25 01:29:01 +00:00
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 )
2011-10-29 22:40:00 +00:00
# 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 " ]
2011-10-25 01:29:01 +00:00
# let's get the userid, username
user = gr_client . auth_user ( )
2011-10-29 22:40:00 +00:00
profile . goodreads_user_id = user [ " userid " ]
profile . goodreads_user_name = user [ " name " ]
profile . goodreads_user_link = user [ " link " ]
profile . save ( ) # is this needed?
2011-10-25 01:29:01 +00:00
# redirect to the Goodreads display page -- should observe some next later
2011-11-16 20:45:33 +00:00
return HttpResponseRedirect ( reverse ( ' home ' ) )
2011-11-01 00:26:05 +00:00
@require_POST
@login_required
@csrf_exempt
def goodreads_flush_assoc ( request ) :
2011-10-29 22:40:00 +00:00
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 ( )
2011-11-10 15:36:17 +00:00
logger . info ( ' Goodreads association flushed for user %s ' , user )
2011-11-01 00:26:05 +00:00
return HttpResponseRedirect ( reverse ( ' goodreads_display ' ) )
2011-10-25 01:29:01 +00:00
2011-11-01 00:26:05 +00:00
@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
2011-11-15 20:51:38 +00:00
goodreads_shelf_name_number = request . POST . get ( ' goodreads_shelf_name_number ' , ' all:0 ' )
2011-11-01 00:26:05 +00:00
user = request . user
try :
2011-11-10 23:14:33 +00:00
# parse out shelf name and expected number of books
2011-11-15 20:51:38 +00:00
( shelf_name , expected_number_of_books ) = re . match ( r ' ^(.*):( \ d+)$ ' , goodreads_shelf_name_number ) . groups ( )
2011-11-10 23:14:33 +00:00
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 )
2012-02-16 18:19:36 +00:00
task_id = load_task . delay ( user . id , shelf_name , expected_number_of_books = expected_number_of_books )
2011-11-10 23:14:33 +00:00
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 ( )
2011-12-26 17:53:28 +00:00
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> " )
2011-11-01 00:26:05 +00:00
except Exception , e :
return HttpResponse ( " Error in loading shelf: %s " % ( e ) )
2011-11-10 15:36:17 +00:00
logger . info ( " Error in loading shelf for user %s : %s " , user , e )
2011-11-01 00:26:05 +00:00
2011-11-17 00:47:29 +00:00
2012-01-24 17:36:45 +00:00
@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 " )
2011-11-17 00:47:29 +00:00
@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
2011-11-17 15:40:40 +00:00
logger . info ( ' Adding task to load librarything %s to user %s ' , lt_username , user )
2011-11-17 00:47:29 +00:00
load_task_name = " load_librarything_into_wishlist "
load_task = getattr ( tasks , load_task_name )
2012-02-16 18:19:36 +00:00
task_id = load_task . delay ( user . id , lt_username , None )
2011-11-17 00:47:29 +00:00
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 ( )
2011-12-31 18:49:23 +00:00
2011-12-26 17:53:28 +00:00
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> " )
2011-11-17 00:47:29 +00:00
except Exception , e :
return HttpResponse ( " Error in loading LibraryThing library: %s " % ( e ) )
logger . info ( " Error in loading LibraryThing for user %s : %s " , user , e )
2011-11-01 00:26:05 +00:00
@require_POST
@login_required
2011-11-01 17:41:39 +00:00
@csrf_exempt
2011-11-01 00:26:05 +00:00
def clear_wishlist ( request ) :
2011-11-01 17:41:39 +00:00
try :
request . user . wishlist . works . clear ( )
2011-11-10 15:36:17 +00:00
logger . info ( " Wishlist for user %s cleared " , request . user )
2011-11-01 17:41:39 +00:00
return HttpResponse ( ' wishlist cleared ' )
except Exception , e :
return HttpResponse ( " Error in clearing wishlist: %s " % ( e ) )
2011-11-10 15:36:17 +00:00
logger . info ( " Error in clearing wishlist for user %s : %s " , request . user , e )
2011-11-01 21:24:18 +00:00
2011-11-16 18:20:10 +00:00
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 } )
2011-11-17 15:40:40 +00:00
# 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
2011-11-16 18:20:10 +00:00
return context
def form_valid ( self , form ) :
return super ( LibraryThingView , self ) . form_valid ( form )
2011-11-10 23:14:33 +00:00
@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 )
2011-11-06 21:46:46 +00:00
2011-11-10 01:31:31 +00:00
def celery_test ( request ) :
return HttpResponse ( " celery_test " )
2011-12-05 05:56:24 +00:00
# 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 )
2011-12-20 04:26:55 +00:00
isbn = work . first_isbn_13 ( )
2011-12-05 05:56:24 +00:00
if work . librarything_id :
url = work . librarything_url
elif isbn :
# TODO: do the redirect here and capture the work id?
2011-12-20 04:26:55 +00:00
url = " http://www.librarything.com/isbn/ %s " % isbn
2011-12-05 05:56:24 +00:00
else :
term = work . title + " " + work . author ( )
2012-03-01 13:53:55 +00:00
q = urlencode ( { ' searchtpe ' : ' work ' , ' term ' : term } )
2011-12-05 05:56:24 +00:00
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 )
2012-01-17 21:50:19 +00:00
isbns = [ " ISBN: " + i . value for i in work . identifiers . filter ( type = ' isbn ' ) ]
2011-12-06 14:53:53 +00:00
url = None
2011-12-05 05:56:24 +00:00
if work . openlibrary_id :
url = work . openlibrary_url
elif len ( isbns ) > 0 :
isbns = " , " . join ( isbns )
2011-12-06 14:53:53 +00:00
u = ' http://openlibrary.org/api/books?bibkeys= %s &jscmd=data&format=json ' % isbns
2012-03-10 16:03:58 +00:00
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 )
2011-12-06 14:53:53 +00:00
# fall back to doing a search on openlibrary
if not url :
2012-03-01 13:53:55 +00:00
q = urlencode ( { ' q ' : work . title + " " + work . author ( ) } )
2011-12-05 05:56:24 +00:00
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 )
2011-12-20 04:26:55 +00:00
isbn = work . first_isbn_13 ( )
2011-12-05 05:56:24 +00:00
if work . goodreads_id :
url = work . goodreads_url
elif isbn :
2011-12-20 04:26:55 +00:00
url = " http://www.goodreads.com/book/isbn/ %s " % isbn
2011-12-05 05:56:24 +00:00
else :
2012-03-01 13:53:55 +00:00
q = urlencode ( { ' query ' : work . title + " " + work . author ( ) } )
2011-12-05 05:56:24 +00:00
url = " http://www.goodreads.com/search? " + q
return HttpResponseRedirect ( url )
2011-12-29 01:43:52 +00:00
2012-01-02 14:39:11 +00:00
@login_required
2012-05-14 02:59:07 +00:00
def emailshare ( request , action ) :
2011-12-31 18:49:23 +00:00
if request . method == ' POST ' :
form = EmailShareForm ( request . POST )
if form . is_valid ( ) :
subject = form . cleaned_data [ ' subject ' ]
message = form . cleaned_data [ ' message ' ]
2012-05-13 20:38:58 +00:00
sender = ' %s via Unglue.it < %s > ' % ( request . user . username , request . user . email )
2011-12-31 18:49:23 +00:00
recipient = form . cleaned_data [ ' recipient ' ]
2012-04-25 02:20:10 +00:00
send_mail_task . delay ( subject , message , sender , [ recipient ] )
2011-12-31 18:49:23 +00:00
try :
next = form . cleaned_data [ ' next ' ]
except :
next = ' '
return HttpResponseRedirect ( next )
else :
2012-05-12 15:12:27 +00:00
2011-12-31 18:49:23 +00:00
try :
next = request . GET [ ' next ' ]
2012-05-14 02:59:07 +00:00
work_id = next . split ( ' / ' ) [ - 2 ]
work_id = int ( work_id )
work = models . Work . objects . get ( pk = work_id )
if action == ' pledge ' :
2012-05-12 15:12:27 +00:00
message = render_to_string ( ' emails/i_just_pledged.txt ' , { ' request ' : request , ' work ' : work , ' site ' : Site . objects . get_current ( ) } )
subject = " Help me unglue " + work . title
2012-03-12 17:18:11 +00:00
else :
2012-04-25 02:17:30 +00:00
try :
2012-05-12 15:12:27 +00:00
status = work . last_campaign ( ) . status
2012-04-25 02:17:30 +00:00
except :
status = None
2012-03-26 19:26:47 +00:00
2012-04-25 02:17:30 +00:00
# customize the call to action depending on campaign status
if status == ' ACTIVE ' :
2012-05-12 15:12:27 +00:00
message = render_to_string ( ' emails/pledge_this.txt ' , { ' request ' : request , ' work ' : work , ' site ' : Site . objects . get_current ( ) } )
2012-04-25 02:17:30 +00:00
else :
2012-05-12 15:12:27 +00:00
message = render_to_string ( ' emails/wish_this.txt ' , { ' request ' : request , ' work ' : work , ' site ' : Site . objects . get_current ( ) } )
2012-05-08 20:15:23 +00:00
subject = ' Come see one of my favorite books on Unglue.it '
2012-04-25 17:45:18 +00:00
2012-05-12 15:12:27 +00:00
form = EmailShareForm ( initial = { ' next ' : next , ' subject ' : subject , ' message ' : message } )
2011-12-31 18:49:23 +00:00
except :
next = ' '
2012-05-12 15:12:27 +00:00
form = EmailShareForm ( initial = { ' next ' : next , ' subject ' : ' Come join me on Unglue.it ' , ' message ' : render_to_string ( ' emails/join_me.txt ' , { ' request ' : request , ' site ' : Site . objects . get_current ( ) } ) } )
2011-12-29 01:43:52 +00:00
2011-12-31 18:49:23 +00:00
return render ( request , " emailshare.html " , { ' form ' : form } )
2012-01-09 20:53:09 +00:00
def feedback ( request ) :
num1 = randint ( 0 , 10 )
num2 = randint ( 0 , 10 )
sum = num1 + num2
2012-01-31 15:07:52 +00:00
2012-01-09 20:53:09 +00:00
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 ' ]
2012-01-25 19:55:03 +00:00
useragent = request . META [ ' HTTP_USER_AGENT ' ]
2012-01-16 00:02:50 +00:00
if request . user . is_anonymous ( ) :
2012-01-31 15:07:52 +00:00
ungluer = " (not logged in) "
2012-01-16 00:02:50 +00:00
else :
2012-01-31 15:07:52 +00:00
ungluer = request . user . username
2012-01-25 19:55:03 +00:00
message = " <<<This feedback is about " + page + " . Original user message follows \n from " + sender + " , ungluer name " + ungluer + " \n with user agent " + useragent + " \n >>> \n " + message
2012-04-25 02:20:10 +00:00
send_mail_task . delay ( subject , message , sender , [ recipient ] )
2012-01-09 20:53:09 +00:00
return render ( request , " thanks.html " , { " page " : page } )
else :
2012-01-31 15:07:52 +00:00
num1 = request . POST [ ' num1 ' ]
num2 = request . POST [ ' num2 ' ]
2012-01-09 20:53:09 +00:00
else :
2012-01-31 15:07:52 +00:00
if request . user . is_authenticated ( ) :
sender = request . user . email ;
else :
sender = ' '
try :
page = request . GET [ ' page ' ]
except :
page = ' / '
2012-01-09 20:53:09 +00:00
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 } )
2012-01-09 21:13:49 +00:00
2012-02-03 15:22:53 +00:00
def comment ( request ) :
2012-02-23 20:40:45 +00:00
latest_comments = Comment . objects . all ( ) . order_by ( ' -submit_date ' ) [ : 20 ]
2012-02-05 00:06:53 +00:00
return render ( request , " comments.html " , { ' latest_comments ' : latest_comments } )
2012-04-04 16:15:18 +00:00
def campaign_archive_js ( request ) :
""" proxy for mailchimp js """
response = HttpResponse ( )
r = requests . get ( settings . CAMPAIGN_ARCHIVE_JS )
response . status_code = r . status_code
response . content = r . content
response [ " Content-Type " ] = " text/javascript "
return response
2012-08-15 13:40:37 +00:00
def lockss ( request , work_id ) :
2012-08-24 19:14:32 +00:00
work = safe_get_work ( work_id )
2012-08-27 20:48:07 +00:00
try :
ebook = work . ebooks ( ) . filter ( unglued = True ) [ 0 ]
except :
ebook = None
2012-08-15 13:40:37 +00:00
authors = list ( models . Author . objects . filter ( editions__work = work ) . all ( ) )
2012-08-24 19:14:32 +00:00
return render ( request , " lockss.html " , { ' work ' : work , ' ebook ' : ebook , ' authors ' : authors } )
def download ( request , work_id ) :
context = { }
work = safe_get_work ( work_id )
context . update ( { ' work ' : work } )
unglued_ebook = work . ebooks ( ) . filter ( unglued = True )
other_ebooks = work . ebooks ( ) . filter ( unglued = False )
try :
ungluedcount = unglued_ebook . count ( )
assert ( ungluedcount == 1 or ungluedcount == 0 )
except :
2012-08-27 20:38:35 +00:00
logger . warning ( " There is more than one unglued edition for %s " % work . title )
2012-08-24 19:14:32 +00:00
try :
unglued_ebook = unglued_ebook [ 0 ]
except :
pass
context . update ( {
' unglued_ebook ' : unglued_ebook ,
' other_ebooks ' : other_ebooks
} )
return render ( request , " download.html " , context )
2012-08-27 19:35:29 +00:00
def about ( request , facet ) :
template = " about_ " + facet + " .html "
return render ( request , template )