Merge branch 'master' into successful_works_in_inglued_tab

pull/1/head
Andromeda Yelton 2012-12-31 13:47:17 -05:00
commit bf6cfb7cb2
20 changed files with 256 additions and 25 deletions

View File

@ -2,9 +2,25 @@ from selectable.base import ModelLookup
from selectable.registry import registry from selectable.registry import registry
from django.contrib.auth.models import User from django.contrib.auth.models import User
from regluit.core.models import Work
class OwnerLookup(ModelLookup): class OwnerLookup(ModelLookup):
model = User model = User
search_fields = ('username__icontains',) search_fields = ('username__icontains',)
registry.register(OwnerLookup) class WorkLookup(ModelLookup):
model = Work
search_fields = ('title__istartswith',)
filters = {'language': 'en', }
def get_item_label(self,item):
return "%s (%s)"%(item.title,item.id)
def get_query(self, request, term):
results = super(WorkLookup, self).get_query(request, term)
language = request.GET.get('language', 'en')
results = results.filter(language=language)
return results
registry.register(OwnerLookup)
registry.register(WorkLookup)

View File

@ -249,15 +249,15 @@ class BookLoaderTests(TestCase):
#ebook_epub = edition.ebooks.all()[0] #ebook_epub = edition.ebooks.all()[0]
ebook_epub = edition.ebooks.filter(format='epub')[0] ebook_epub = edition.ebooks.filter(format='epub')[0]
self.assertEqual(ebook_epub.format, 'epub') self.assertEqual(ebook_epub.format, 'epub')
#self.assertEqual(ebook_epub.url, 'http://books.google.com/books/download/The_Latin_language.epub?id=U3FXAAAAYAAJ&ie=ISO-8859-1&output=epub&source=gbs_api') #self.assertEqual(ebook_epub.url, 'http://books.google.com/books/download/The_Latin_language.epub?id=N1RfAAAAMAAJ&ie=ISO-8859-1&output=epub&source=gbs_api')
self.assertEqual(parse_qs(urlparse(ebook_epub.url).query).get("id"), ['U3FXAAAAYAAJ']) self.assertEqual(parse_qs(urlparse(ebook_epub.url).query).get("id"), ['N1RfAAAAMAAJ'])
self.assertEqual(parse_qs(urlparse(ebook_epub.url).query).get("output"), ['epub']) self.assertEqual(parse_qs(urlparse(ebook_epub.url).query).get("output"), ['epub'])
self.assertEqual(ebook_epub.provider, 'Google Books') self.assertEqual(ebook_epub.provider, 'Google Books')
self.assertEqual(ebook_epub.set_provider(), 'Google Books') self.assertEqual(ebook_epub.set_provider(), 'Google Books')
ebook_pdf = edition.ebooks.filter(format='pdf')[0] ebook_pdf = edition.ebooks.filter(format='pdf')[0]
self.assertEqual(ebook_pdf.format, 'pdf') self.assertEqual(ebook_pdf.format, 'pdf')
#self.assertEqual(ebook_pdf.url, 'http://books.google.com/books/download/The_Latin_language.pdf?id=U3FXAAAAYAAJ&ie=ISO-8859-1&output=pdf&sig=ACfU3U2yLt3nmTncB8ozxOWUc4iHKUznCA&source=gbs_api') #self.assertEqual(ebook_pdf.url, 'http://books.google.com/books/download/The_Latin_language.pdf?id=N1RfAAAAMAAJ&ie=ISO-8859-1&output=pdf&sig=ACfU3U2yLt3nmTncB8ozxOWUc4iHKUznCA&source=gbs_api')
self.assertEqual(parse_qs(urlparse(ebook_pdf.url).query).get("id"), ['U3FXAAAAYAAJ']) self.assertEqual(parse_qs(urlparse(ebook_pdf.url).query).get("id"), ['N1RfAAAAMAAJ'])
self.assertEqual(parse_qs(urlparse(ebook_pdf.url).query).get("output"), ['pdf']) self.assertEqual(parse_qs(urlparse(ebook_pdf.url).query).get("output"), ['pdf'])
self.assertEqual(ebook_pdf.provider, 'Google Books') self.assertEqual(ebook_pdf.provider, 'Google Books')
self.assertEqual(edition.public_domain, True) self.assertEqual(edition.public_domain, True)

View File

@ -13,8 +13,8 @@ from decimal import Decimal as D
from selectable.forms import AutoCompleteSelectMultipleWidget,AutoCompleteSelectMultipleField from selectable.forms import AutoCompleteSelectMultipleWidget,AutoCompleteSelectMultipleField
from selectable.forms import AutoCompleteSelectWidget,AutoCompleteSelectField from selectable.forms import AutoCompleteSelectWidget,AutoCompleteSelectField
from regluit.core.models import UserProfile, RightsHolder, Claim, Campaign, Premium, Ebook, Edition, PledgeExtra from regluit.core.models import UserProfile, RightsHolder, Claim, Campaign, Premium, Ebook, Edition, PledgeExtra, Work
from regluit.core.lookups import OwnerLookup from regluit.core.lookups import OwnerLookup, WorkLookup
from regluit.utils.localdatetime import now from regluit.utils.localdatetime import now
@ -208,6 +208,36 @@ def getTransferCreditForm(maximum, data=None, *args, **kwargs ):
) )
return TransferCreditForm( data=data ) return TransferCreditForm( data=data )
class WorkForm(forms.Form):
other_work = forms.ModelChoiceField(queryset=Work.objects.all(),
widget=forms.HiddenInput(),
required=True,
error_messages={'required': 'Missing work to merge with.'},
)
work=None
def clean_other_work(self):
if self.cleaned_data["other_work"].id== self.work.id:
raise forms.ValidationError(_("You can't merge a work into itself"))
return self.cleaned_data["other_work"]
def __init__(self, work=None, *args, **kwargs):
super(WorkForm, self).__init__(*args, **kwargs)
self.work=work
class OtherWorkForm(WorkForm):
other_work = AutoCompleteSelectField(
WorkLookup,
label='Other Work',
widget=AutoCompleteSelectWidget(WorkLookup),
required=True,
error_messages={'required': 'Missing work to merge with.'},
)
def __init__(self, *args, **kwargs):
super(OtherWorkForm, self).__init__(*args, **kwargs)
self.fields['other_work'].widget.update_query_parameters({'language':self.work.language})
class EditManagersForm(forms.ModelForm): class EditManagersForm(forms.ModelForm):
managers = AutoCompleteSelectMultipleField( managers = AutoCompleteSelectMultipleField(

View File

@ -0,0 +1,28 @@
{% extends "basedocumentation.html" %}
{% block doccontent %}
<h1>Smashwords + Unglue.it</h1>
<p>Are you a Smashwords author? Do you want to unglue your book? You can! Here's how:</p>
<ul>
<li>Make sure your book meets Smashwords' <a href="http://www.smashwords.com/distribution">standards for inclusion</a> in their Premium Catalog. Consult the <a href="http://www.smashwords.com/books/view/52">Smashwords Style Guide</a> for details.</li>
<li>Contact <a href="mailto:rights@gluejar.com">rights@gluejar.com</a> about signing a Platform Services Agreement with Unglue.it, and follow the instructions on the <a href="/rightsholders/">rights holder tools page</a> to claim your book, develop a publicity strategy, and start a campaign.</li>
</ul>
<h2>Why Unglue Your Book?</h2>
<p>As a self-published author, you know that innovative marketing and distribution are critical.</p>
<p>Ungluing campaigns guarantee you income when campaigns succeed, without risk to you if they don't. Whether campaigns succeed or fail, they're a tool for you to reach out to, discover, interact with, and increase your audience while raising the profile of your work. Successful campaigns mean wider distribution of your book -- our <a href="https://unglue.it/work/81834/">first unglued ebook</a> reached #3 most-downloaded in Amazon's Kindle eBooks > Nonfiction > Social Sciences category. Your unglued book, in turn, becomes an ambassador for the rest of your work.</p>
<p>Rest assured that, when you unglue a book, you retain the copyright. You can choose whichever <a href="http://creativecommons.org/licenses/">Creative Commons license</a> serves your interests best, whether that's inviting your fans to remix your work or sharing it widely while reserving certain rights. You're still welcome to sell your book under the terms of your Smashwords agreement, and to separately license other editions. Ungluing isn't instead of your book's other opportunities -- it's in addition to them.</p>
<h2>The Fine Print</h2>
<p><I>Don't the <a href="http://www.smashwords.com/about/tos">Smashwords Terms of Service</a> say that authors can't distribute Meatgrinder files through other channels without special permission?</i></p>
<p>Yes. You have that permission, courtesy of an agreement between Smashwords and Unglue.it.</p>
<p><I>Where can I learn more about Unglue.it's terms?</I></p>
<p>Please see our <a href="{% url terms %}">Terms of Service</a> and our <a href="{% url faq %}">FAQ</a>.</p>
{% endblock %}

View File

@ -4,6 +4,10 @@
<h2>Admin Users Only</h2> <h2>Admin Users Only</h2>
<p>This function is only available to Unglue.it administration.</p> <p>This function is only available to Unglue.it administration or authorized campaign managers.</p>
<p>If you believe you should have been able to do something here, please make sure you're logged in.</p>
<p>Campaign managers can create new editions of works that are already in the Unglue.it system, but only Unglue.it staff can create editions for works not in the system. If you're a campaign manager trying to add your work to the database, please send us the ISBN-13, publisher, year of publication, and a cover image, and we'll set that up for you.</p>
{% endblock %} {% endblock %}

View File

@ -22,7 +22,7 @@
{% block base_js %} {% block base_js %}
<script type="text/javascript" src="{{ jquery_home }}"></script> <script type="text/javascript" src="{{ jquery_home }}"></script>
{% endblock %} {% endblock %}
<script type="text/javascript" src="/static/js/hijax.js?v=1"></script> <script type="text/javascript" src="/static/js/hijax.js?v=2"></script>
{% block extra_js %} {% block extra_js %}
{% endblock %} {% endblock %}
<script type="text/javascript" src="/static/js/watermark_init.js"></script> <script type="text/javascript" src="/static/js/watermark_init.js"></script>
@ -139,7 +139,7 @@
{% block news %} {% block news %}
<div class="launch_top"> <div class="launch_top">
We unglued <a href="/work/81834/">one book</a>. Amazon <a href="http://blog.unglue.it/2012/08/09/open-thread-amazon-forces-unglue-it-to-suspend-crowdfunding-for-creative-commons-ebooks/">shut us down</a>. Now we're back. Help us unglue <a href="https://unglue.it/campaigns/ending">four more books</a>! <br /> We've unglued our <a href="/work/113782/">second</a> and <a href="/work/76348/">third</a> books. Help us <a href="https://unglue.it/campaigns/ending">unglue even more</a>! <br />
</div> </div>
{% endblock %} {% endblock %}

View File

@ -562,9 +562,13 @@ Need more ideas? We're happy to work with rights holders personally to craft a
<dd>The campaign ends. Supporters' credit cards are not charged, so you are not paid, and not obligated to release an unglued ebook.<br /><br /> <dd>The campaign ends. Supporters' credit cards are not charged, so you are not paid, and not obligated to release an unglued ebook.<br /><br />
If you're concerned a campaign may not reach its goal you have several options. You can lower the target price to a level more likely to succeed. Or you are welcome to run a second campaign at a later time, perhaps with a different goal, duration, and publicity strategy. We'd be happy to consult with you about this.</dd> If you're concerned a campaign may not reach its goal you have several options. You can lower the target price to a level more likely to succeed. Or you are welcome to run a second campaign at a later time, perhaps with a different goal, duration, and publicity strategy. We'd be happy to consult with you about this.</dd>
<dt>Is there a minimum funding goal?</dt>
<dd>Yes, the minimum funding goal is $500.</dd>
<dt>What fees does Unglue.it charge?</dt> <dt>What fees does Unglue.it charge?</dt>
<dd>When a campaign succeeds, Unglue.it will deduct a 6% commission on the funds raised. Our payment processor also charges a small fee on each transaction, plus (where relevant) currency conversion costs. If you do not have a suitable ePub version of your book available, you will also need to cover ebook conversion costs; please price this into your goal for a campaign. Details are spelled out in the Platform Services Agreement that rights holders must sign before launching an Unglue.it campaign.</dd> <dd>When a campaign succeeds, Unglue.it will deduct a 6% commission (or $60, whichever is greater) on the funds raised. Our payment processor also charges a small fee on each transaction, plus (where relevant) currency conversion costs. If you do not have a suitable ePub version of your book available, you will also need to cover ebook conversion costs; please price this into your goal for a campaign. Details are spelled out in the Platform Services Agreement that rights holders must sign before launching an Unglue.it campaign.</dd>
<dt>Does it cost money to start a campaign on Unglue.it?</dt> <dt>Does it cost money to start a campaign on Unglue.it?</dt>

View File

@ -0,0 +1,35 @@
{% extends "basedocumentation.html" %}
{% block extra_extra_head %}
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/ui-lightness/jquery-ui.css" type="text/css" media="screen">
{{ form.media.css }}
<script type="text/javascript" src="{{ jquery_home }}"></script>
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>
{{ form.media.js }}
{% endblock %}
{% block doccontent %}
{% if merge_complete %}
<h2>Merge {{ old_work_id }} into {{ work.id }} Complete</h2>
{% include 'workbox.html' %}
{% else %}
<h2>Merge Works</h2>
<form method="POST" action="#">
{% csrf_token %}
{{ form.as_p }}
<h3>Merge this work...</h3>
{% if other_work %}
{% with other_work as work%}
{% include 'workbox.html' %}
{% endwith %}
{% endif %}
<h3>... into the current work</h3>
{% include 'workbox.html' %}
{% if other_work %}
<input type="submit" name="confirm_merge_works" value="Confirm Merge" id="submit" />
{% else %}
<input type="submit" name="merge_works" value="Preview Merge Works" id="submit" />
{% endif %}
</form>
{% endif %}
{% endblock %}

View File

@ -92,5 +92,20 @@
</dd> </dd>
</dl> </dl>
<h2>Pledges</h2>
<dl>
<dt>How much has been pledged to Unglue.it?</dt>
<p>Excludes pledges canceled, failed, or otherwise uncollectable.</p>
<dd>
<ul class="terms">
<li>{{ transactions.today.count }} pledges have been made today totaling ${% if transactions.today.sum %}{{ transactions.today.sum }}{% else %}0{% endif %}.
<li>{{ transactions.yesterday.count }} pledges were made yesterday totaling ${% if transactions.yesterday.sum %}{{ transactions.yesterday.sum }}{% else %}0{% endif %}.
<li>{{ transactions.days7.count }} pledges have been made in the past 7 days totaling ${% if transactions.days7.sum %}{{ transactions.days7.sum }}{% else %}0{% endif %}.
<li>{{ transactions.month.count }} pledges have been made in the past month totaling ${% if transactions.month.sum %}{{ transactions.month.sum }}{% else %}0{% endif %}.
<li>{{ transactions.count }} pledges have been made altogether totaling ${{ transactions.sum }}.
</li>
</ul>
</dd>
</dl>
{% endblock %} {% endblock %}

View File

@ -9,4 +9,4 @@ If necessary to provide you with any premiums you requested, {{ campaign.rightsh
Thank you for your support. Thank you for your support.
{{ campaign.rightsholder }} (rights holder for {{ campaign.work.title }} and the Unglue.it team {{ campaign.rightsholder }} (rights holder for {{ campaign.work.title }}) and the Unglue.it team

View File

@ -15,9 +15,9 @@
<div class="jsmodule rounded clearfix"> <div class="jsmodule rounded clearfix">
<div class="jsmod-content"> <div class="jsmod-content">
<div><h2>Error: Card authorization for a pledge transaction</h2> <div><h2>Error: Card authorization</h2>
<div> <div>
<p>Unglue.it would like to process your pledge, but there's been some problem processing your credit card (<b>{{exception.message}}</b>). Please <a href="{{ request.get_full_path }}">try again</a>, or contact <a href="mailto:support@gluejar.com?subject={{ request.get_full_path|urlencode }}">unglue.it support</a>. <p>Unglue.it would like to accept your credit card, but we encountered the following problem: <b>{{exception.message}}</b>. Please <a href="{{ request.get_full_path }}">try again</a>, or contact <a href="mailto:support@gluejar.com?subject={{ request.get_full_path|urlencode }}">unglue.it support</a>.
</p> </p>
</div> </div>
</div> </div>

View File

@ -115,7 +115,7 @@ The Company's mission is to make copyrighted literary works freely and readily a
<p>Rights Holders who have executed a Platform Services Agreement may claim works and may initiate and conduct Campaigns as described in the Rights Holder Tools page at <a href="https://unglue.it/rightsholders/">https://unglue.it/rightsholders/</a>.</p> <p>Rights Holders who have executed a Platform Services Agreement may claim works and may initiate and conduct Campaigns as described in the Rights Holder Tools page at <a href="https://unglue.it/rightsholders/">https://unglue.it/rightsholders/</a>.</p>
<p>There is no charge for Rights Holders to launch and fund a Campaign using the Service. However, the Company will withhold a “Sales Commission” of 6% of gross aggregate Contributions upon the completion of a successful Campaign. The Rights Holder is responsible for providing a Standard Ebook File at their own expense, as described in a Platform Services Agreement. </p> <p>There is no charge for Rights Holders to launch and fund a Campaign using the Service. However, the Company will withhold a “Sales Commission” of 6% of gross aggregate Contributions (or $60, whichever is greater) upon the completion of a successful Campaign. The Rights Holder is responsible for providing a Standard Ebook File at their own expense, as described in a Platform Services Agreement. </p>
<p>The Rights Holder hereby authorizes the Company to use the Service to display and market the Subject Work, to collect Contributions or cause Contributions to be collected from Supporters on behalf of the Rights Holder, and to retain, reserve and/or distribute the Contributions to the Rights Holder, to the Company, to Designated Vendors (as defined below) or otherwise pursuant to the terms of this Agreement. </p> <p>The Rights Holder hereby authorizes the Company to use the Service to display and market the Subject Work, to collect Contributions or cause Contributions to be collected from Supporters on behalf of the Rights Holder, and to retain, reserve and/or distribute the Contributions to the Rights Holder, to the Company, to Designated Vendors (as defined below) or otherwise pursuant to the terms of this Agreement. </p>

View File

@ -321,6 +321,9 @@ $j(document).ready(function(){
{% endif %} {% endif %}
<p>If you'd like to contact us regarding rights for this work, please email <a href="mailto:rights@gluejar.com">rights@gluejar.com</a>.</p> <p>If you'd like to contact us regarding rights for this work, please email <a href="mailto:rights@gluejar.com">rights@gluejar.com</a>.</p>
{% if user.is_staff %}<h4>Related Works</h4>
<a href="{% url merge work_id %}">Merge other works into this one</a><br />
{% endif %}
{% if work.subjects.all.count > 0 %} {% if work.subjects.all.count > 0 %}
<h4>Subjects</h4> <h4>Subjects</h4>

View File

@ -0,0 +1,16 @@
<div class="workbox">
<a href="{% url work work.id %}">{{ work.title }}</a> # {{work.id }}<br />
Language: {{ work.language }}<br />
Editions: <ol>
{% for edition in work.editions.all %}
<li>
<div class="editionbox">{{ edition.title }}, published by {{edition.publisher}} in {{ edition.publication_date }} with authors
{% for author in edition.authors.all %}
{{author}},
{% endfor %}
</div>
</li>
{% endfor %}
</ol>
</div>

View File

@ -10,7 +10,7 @@ from regluit.core.feeds import SupporterWishlistFeed
from regluit.core.models import Campaign from regluit.core.models import Campaign
from regluit.frontend.views import GoodreadsDisplayView, LibraryThingView, PledgeView, PledgeCompleteView, PledgeCancelView, PledgeRechargeView, FAQView from regluit.frontend.views import GoodreadsDisplayView, LibraryThingView, PledgeView, PledgeCompleteView, PledgeCancelView, PledgeRechargeView, FAQView
from regluit.frontend.views import CampaignListView, WorkListView, UngluedListView, InfoPageView, InfoLangView, DonationView, FundPledgeView from regluit.frontend.views import CampaignListView, WorkListView, UngluedListView, InfoPageView, InfoLangView, DonationView, FundPledgeView
from regluit.frontend.views import NonprofitCampaign, DonationCredit, PledgeModifiedView, ManageAccount from regluit.frontend.views import NonprofitCampaign, DonationCredit, PledgeModifiedView, ManageAccount, MergeView
urlpatterns = patterns( urlpatterns = patterns(
"regluit.frontend.views", "regluit.frontend.views",
@ -49,6 +49,7 @@ urlpatterns = patterns(
url(r"^work/(?P<work_id>\d+)/lockss/$", "lockss", name="lockss"), url(r"^work/(?P<work_id>\d+)/lockss/$", "lockss", name="lockss"),
url(r"^lockss/(?P<year>\d+)/$", "lockss_manifest", name="lockss_manifest"), url(r"^lockss/(?P<year>\d+)/$", "lockss_manifest", name="lockss_manifest"),
url(r"^work/(?P<work_id>\d+)/download/$", "download", name="download"), url(r"^work/(?P<work_id>\d+)/download/$", "download", name="download"),
url(r"^work/(?P<work_id>\d+)/merge/$", login_required(MergeView.as_view()), name="merge"),
url(r"^work/\d+/acks/images/(?P<file_name>[\w\.]*)$", "static_redirect_view",{'dir': 'images'}), url(r"^work/\d+/acks/images/(?P<file_name>[\w\.]*)$", "static_redirect_view",{'dir': 'images'}),
url(r"^work/(?P<work_id>\d+)/librarything/$", "work_librarything", name="work_librarything"), url(r"^work/(?P<work_id>\d+)/librarything/$", "work_librarything", name="work_librarything"),
url(r"^work/(?P<work_id>\d+)/goodreads/$", "work_goodreads", name="work_goodreads"), url(r"^work/(?P<work_id>\d+)/goodreads/$", "work_goodreads", name="work_goodreads"),

View File

@ -44,11 +44,12 @@ from regluit.core import models, bookloader, librarything
from regluit.core import userlists from regluit.core import userlists
from regluit.core.search import gluejar_search from regluit.core.search import gluejar_search
from regluit.core.goodreads import GoodreadsClient from regluit.core.goodreads import GoodreadsClient
from regluit.core.bookloader import merge_works
from regluit.frontend.forms import UserData, UserEmail, ProfileForm, CampaignPledgeForm, GoodreadsShelfLoadingForm from regluit.frontend.forms import UserData, UserEmail, ProfileForm, CampaignPledgeForm, GoodreadsShelfLoadingForm
from regluit.frontend.forms import RightsHolderForm, UserClaimForm, LibraryThingForm, OpenCampaignForm from regluit.frontend.forms import RightsHolderForm, UserClaimForm, LibraryThingForm, OpenCampaignForm
from regluit.frontend.forms import getManageCampaignForm, DonateForm, CampaignAdminForm, EmailShareForm, FeedbackForm from regluit.frontend.forms import getManageCampaignForm, DonateForm, CampaignAdminForm, EmailShareForm, FeedbackForm
from regluit.frontend.forms import EbookForm, CustomPremiumForm, EditManagersForm, EditionForm, PledgeCancelForm from regluit.frontend.forms import EbookForm, CustomPremiumForm, EditManagersForm, EditionForm, PledgeCancelForm
from regluit.frontend.forms import getTransferCreditForm, CCForm, CloneCampaignForm, PlainCCForm from regluit.frontend.forms import getTransferCreditForm, CCForm, CloneCampaignForm, PlainCCForm, WorkForm, OtherWorkForm
from regluit.payment.manager import PaymentManager from regluit.payment.manager import PaymentManager
from regluit.payment.models import Transaction, Account from regluit.payment.models import Transaction, Account
from regluit.payment import baseprocessor from regluit.payment import baseprocessor
@ -568,6 +569,46 @@ class CampaignListView(FilterableListView):
context['facet'] =self.kwargs['facet'] context['facet'] =self.kwargs['facet']
return context return context
class MergeView(FormView):
template_name="merge.html"
work=None
def dispatch(self, request, *args, **kwargs):
if not request.user.is_staff:
return render(request, "admins_only.html")
else:
return super(MergeView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(MergeView, self).get_context_data(**kwargs)
context['work']=self.work
return context
def get_form_class(self):
if self.request.method == 'POST' and self.request.POST.has_key('confirm_merge_works'):
return WorkForm
else:
return OtherWorkForm
def get_form_kwargs(self):
self.work = get_object_or_404(models.Work, id=self.kwargs["work_id"])
form_kwargs= {'work':self.work}
if self.request.method == 'POST':
form_kwargs.update({'data':self.request.POST})
return form_kwargs
def form_valid(self, form):
other_work=form.cleaned_data['other_work']
context=self.get_context_data()
if self.request.POST.has_key('confirm_merge_works'):
context['old_work_id']=other_work.id
merge_works(self.work,other_work,self.request.user)
context['merge_complete']=True
else:
context['form']=WorkForm(initial={'other_work':other_work})
context['other_work']=other_work
return render(self.request, self.template_name, context)
class DonationView(TemplateView): class DonationView(TemplateView):
template_name = "donation.html" template_name = "donation.html"
@ -1597,11 +1638,26 @@ class InfoPageView(TemplateView):
wishlists.yesterday = wishlists.filter(created__range = (date_today()-timedelta(days=1), date_today())) wishlists.yesterday = wishlists.filter(created__range = (date_today()-timedelta(days=1), date_today()))
else: else:
wishlists.yesterday = wishlists.month.filter(created__day = date_today().day-1) wishlists.yesterday = wishlists.month.filter(created__day = date_today().day-1)
transactions = Transaction.objects.filter(status__in = [TRANSACTION_STATUS_ACTIVE, TRANSACTION_STATUS_COMPLETE])
transactions.sum = transactions.aggregate(Sum('amount'))['amount__sum']
transactions.today = transactions.filter(date_created__range = (date_today(), now()))
transactions.today.sum = transactions.today.aggregate(Sum('amount'))['amount__sum']
transactions.days7 = transactions.filter(date_created__range = (date_today()-timedelta(days=7), now()))
transactions.days7.sum = transactions.days7.aggregate(Sum('amount'))['amount__sum']
transactions.year = transactions.filter(date_created__year = date_today().year)
transactions.year.sum = transactions.year.aggregate(Sum('amount'))['amount__sum']
transactions.month = transactions.filter(date_created__month = date_today().month)
transactions.month.sum = transactions.month.aggregate(Sum('amount'))['amount__sum']
transactions.yesterday = transactions.filter(date_created__range = (date_today()-timedelta(days=1), date_today()))
transactions.yesterday.sum = transactions.yesterday.aggregate(Sum('amount'))['amount__sum']
return { return {
'users': users, 'users': users,
'works': works, 'works': works,
'ebooks': ebooks, 'ebooks': ebooks,
'wishlists': wishlists, 'wishlists': wishlists,
'transactions': transactions,
} }
class InfoLangView(TemplateView): class InfoLangView(TemplateView):

View File

@ -478,7 +478,6 @@ class StripeErrorTest(TestCase):
self.assertEqual(e.code, "missing") self.assertEqual(e.code, "missing")
self.assertEqual(e.message, "Cannot charge a customer that has no active card") self.assertEqual(e.message, "Cannot charge a customer that has no active card")
class PledgeScenarioTest(TestCase): class PledgeScenarioTest(TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
@ -658,6 +657,14 @@ class Processor(baseprocessor.Processor):
transaction.error = e.message transaction.error = e.message
transaction.save() transaction.save()
# fire off the fact that transaction failed -- should actually do so only if not a transient error
# if card_declined or expired card, ask user to update account
if e.code in ('card_declined', 'expired_card'):
transaction_failed.send(sender=self, transaction=transaction)
# otherwise, report exception to us
else:
logger.exception("transaction id {0}, exception: {1}".format(transaction.id, e.message))
raise StripelibError(e.message, e) raise StripelibError(e.message, e)
else: else:
@ -667,6 +674,11 @@ class Processor(baseprocessor.Processor):
transaction.pay_key = charge.id transaction.pay_key = charge.id
transaction.date_payment = now() transaction.date_payment = now()
transaction.save() transaction.save()
# fire signal for sucessful transaction
transaction_charged.send(sender=self, transaction=transaction)
else: else:
# nothing to charge # nothing to charge
raise StripeLibError("No customer id available to charge for transaction {0}".format(transaction.id), None) raise StripeLibError("No customer id available to charge for transaction {0}".format(transaction.id), None)
@ -751,7 +763,9 @@ class Processor(baseprocessor.Processor):
pass pass
elif resource == 'charge': elif resource == 'charge':
# we need to handle: succeeded, failed, refunded, disputed # we need to handle: succeeded, failed, refunded, disputed
if action == 'succeeded': if action == 'succeeded':
# TO DO: delete this logic since we don't do anything but look up transaction.
logger.info("charge.succeeded webhook for {0}".format(ev_object.get("id"))) logger.info("charge.succeeded webhook for {0}".format(ev_object.get("id")))
# try to parse description of object to pull related transaction if any # try to parse description of object to pull related transaction if any
# wrapping this in a try statement because it possible that we have a charge.succeeded outside context of unglue.it # wrapping this in a try statement because it possible that we have a charge.succeeded outside context of unglue.it
@ -764,12 +778,11 @@ class Processor(baseprocessor.Processor):
logger.info("ev_object.id == transaction.pay_key: {0}".format(ev_object.id)) logger.info("ev_object.id == transaction.pay_key: {0}".format(ev_object.id))
else: else:
logger.warning("ev_object.id {0} <> transaction.pay_key {1}".format(ev_object.id, transaction.pay_key)) logger.warning("ev_object.id {0} <> transaction.pay_key {1}".format(ev_object.id, transaction.pay_key))
# now -- should fire off transaction_charged here -- if so we need to move it from ?
transaction_charged.send(sender=self, transaction=transaction)
except Exception, e: except Exception, e:
logger.warning(e) logger.warning(e)
elif action == 'failed': elif action == 'failed':
# TO DO: delete this logic since we don't do anything but look up transaction.
logger.info("charge.failed webhook for {0}".format(ev_object.get("id"))) logger.info("charge.failed webhook for {0}".format(ev_object.get("id")))
try: try:
charge_meta = json.loads(ev_object["description"]) charge_meta = json.loads(ev_object["description"])
@ -780,8 +793,7 @@ class Processor(baseprocessor.Processor):
logger.info("ev_object.id == transaction.pay_key: {0}".format(ev_object.id)) logger.info("ev_object.id == transaction.pay_key: {0}".format(ev_object.id))
else: else:
logger.warning("ev_object.id {0} <> transaction.pay_key {1}".format(ev_object.id, transaction.pay_key)) logger.warning("ev_object.id {0} <> transaction.pay_key {1}".format(ev_object.id, transaction.pay_key))
# now -- should fire off transaction_charged here -- if so we need to move it from ?
transaction_failed.send(sender=self, transaction=transaction)
except Exception, e: except Exception, e:
logger.warning(e) logger.warning(e)
elif action == 'refunded': elif action == 'refunded':

View File

@ -233,7 +233,7 @@ GOODREADS_API_KEY = ""
GOODREADS_API_SECRET = "" GOODREADS_API_SECRET = ""
# unglue.it parameters # unglue.it parameters
UNGLUEIT_MINIMUM_TARGET = '1000' # in US Dollars UNGLUEIT_MINIMUM_TARGET = '500' # in US Dollars
UNGLUEIT_LONGEST_DEADLINE = '180' # number of days allowed for a campaign UNGLUEIT_LONGEST_DEADLINE = '180' # number of days allowed for a campaign
UNGLUEIT_RECOMMENDED_USERNAME = 'unglueit' UNGLUEIT_RECOMMENDED_USERNAME = 'unglueit'

View File

@ -12,6 +12,11 @@ $j(document).ready(function() {
var windowWidth = $j(document).width(); var windowWidth = $j(document).width();
var marginWidth = (windowWidth - hijaxWidth)/2; var marginWidth = (windowWidth - hijaxWidth)/2;
$j('#about_expandable').css({'margin-left': marginWidth}); $j('#about_expandable').css({'margin-left': marginWidth});
// position div vertically relative to top of viewport, to ensure visibility
// regardless of where on the page the user clicked to activate it
var marginTop = window.pageYOffset;
$j('#about_expandable').css({'margin-top': marginTop});
}); });
if ($j(this).attr("href").substr(-9,8) == "download") { if ($j(this).attr("href").substr(-9,8) == "download") {

6
static/js/loader-gif.js Normal file
View File

@ -0,0 +1,6 @@
var $j = jQuery.noConflict();
$j().ready(function() {
$j(".loader-gif").click(function(event) {
$j(this).addClass("show-loading");
});
});