Merge branch 'master' into prettier_acks
Conflicts: frontend/templates/front_matter.htmlpull/1/head
commit
658783306c
|
@ -462,8 +462,7 @@ class Campaign(models.Model):
|
|||
it's easier to return transactions than ungluers
|
||||
"""
|
||||
p = PaymentManager()
|
||||
ungluers={"all":[],"supporters":[], "patrons":[], "bibliophiles":[]}
|
||||
anons = 0
|
||||
ungluers={"all":[],"supporters":[], "anon_supporters": 0, "patrons":[], "anon_patrons": 0, "bibliophiles":[]}
|
||||
if self.status == "ACTIVE":
|
||||
translist = p.query_campaign(self, summary=False, pledged=True, authorized=True)
|
||||
elif self.status == "SUCCESSFUL":
|
||||
|
@ -472,14 +471,18 @@ class Campaign(models.Model):
|
|||
translist = []
|
||||
for transaction in translist:
|
||||
ungluers['all'].append(transaction.user)
|
||||
if transaction.anonymous:
|
||||
anons += 1
|
||||
if transaction.amount >= Premium.TIERS["bibliophile"]:
|
||||
ungluers['bibliophiles'].append(transaction)
|
||||
elif transaction.amount >= Premium.TIERS["patron"]:
|
||||
ungluers['patrons'].append(transaction)
|
||||
if transaction.anonymous:
|
||||
ungluers['anon_patrons'] += 1
|
||||
else:
|
||||
ungluers['patrons'].append(transaction)
|
||||
elif transaction.amount >= Premium.TIERS["supporter"]:
|
||||
ungluers['supporters'].append(transaction)
|
||||
if transaction.anonymous:
|
||||
ungluers['anon_supporters'] += 1
|
||||
else:
|
||||
ungluers['supporters'].append(transaction)
|
||||
|
||||
return ungluers
|
||||
|
||||
|
|
|
@ -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 %}
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
<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 %}
|
|
@ -22,7 +22,7 @@
|
|||
{% block base_js %}
|
||||
<script type="text/javascript" src="{{ jquery_home }}"></script>
|
||||
{% 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 %}
|
||||
{% endblock %}
|
||||
<script type="text/javascript" src="/static/js/watermark_init.js"></script>
|
||||
|
@ -139,7 +139,7 @@
|
|||
|
||||
{% block news %}
|
||||
<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 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">five more books</a>! <br />
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -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 />
|
||||
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>
|
||||
|
||||
<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>
|
||||
|
||||
|
|
|
@ -1,7 +1,30 @@
|
|||
{% extends "basedocumentation.html" %}
|
||||
{% block title %}Ungluers supporting the {{ campaign }}{% endblock %}
|
||||
{% block extra_extra_head %}
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/vanilla.css" class="day" title="day" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/vanilla.css" class="day" title="day" />
|
||||
<style>
|
||||
.ackbox {
|
||||
float: left;
|
||||
min-width: 33%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
dt {
|
||||
margin-left: auto;
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
p {
|
||||
text-indent: 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block doccontent %}
|
||||
<!-- trim here -->
|
||||
|
@ -25,31 +48,53 @@
|
|||
Unglued ebooks are made possible through the Unglue.it website by contributions from {{ transactions.all|length }} readers like you.</p>
|
||||
{% if transactions.supporters %}
|
||||
<h2>Supporters of this edition:</h2>
|
||||
<p>
|
||||
{% for transaction in transactions.supporters %}
|
||||
{{ transaction.ack_name }}<br />
|
||||
<div class="ackbox">
|
||||
{{ transaction.ack_name }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% if transactions.anon_supporters %}
|
||||
<div class="ackbox">
|
||||
Anonymous ({{ transactions.anon_supporters }})
|
||||
</div>
|
||||
{% endif %}
|
||||
<br />
|
||||
{% endif %}
|
||||
{% if transactions.patrons %}
|
||||
<h2>Benefactors of this edition:</h2>
|
||||
{% for transaction in transactions.patrons %}
|
||||
<a href="{{ transaction.ack_link }}">{{ transaction.ack_name }}</a><br />
|
||||
<div class="ackbox">
|
||||
{% if transaction.ack_link %}
|
||||
<a href="{{ transaction.ack_link }}">{{ transaction.ack_name }}</a>
|
||||
{% else %}
|
||||
{{ transaction.ack_name }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if transactions.anon_supporters %}
|
||||
<div class="ackbox">
|
||||
Anonymous ({{ transactions.anon_patrons }})
|
||||
</div>
|
||||
{% endif %}
|
||||
<br />
|
||||
{% endif %}
|
||||
{% if transactions.bibliophiles %}
|
||||
<h2>Bibliophiles of this edition:</h2>
|
||||
<dl>
|
||||
{% for transaction in transactions.bibliophiles %}
|
||||
<dt class="nomargin"><a href="{{ transaction.ack_link }}">{{ transaction.ack_name }}</a></dt>
|
||||
<dd class="margin">{{ transaction.ack_dedication }}</dd>
|
||||
{% if not transaction.anonymous %}
|
||||
<dt>{% if transaction.ack_link %}<a href="{{transaction.ack_link}}">{{ transaction.ack_name }}</a>{% else %}{{ transaction.ack_name }}{% endif %}</dt>
|
||||
{% else %}
|
||||
<dt>Anonymous</dt>
|
||||
{% endif %}
|
||||
<dd>{{ transaction.ack_dedication }}</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<hr>
|
||||
<p>
|
||||
You can say thank you by supporting the ungluing of more books at <a href="https://unglue.it/">https://unglue.it/</a> .
|
||||
You can say thank you by supporting the ungluing of more books at <a href="https://unglue.it/">https://unglue.it/</a> .
|
||||
</p>
|
||||
</section>
|
||||
<!-- trim here -->
|
||||
|
|
|
@ -92,5 +92,20 @@
|
|||
</dd>
|
||||
</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 %}
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<div class="jsmodule rounded clearfix">
|
||||
<div class="jsmod-content">
|
||||
|
||||
<div><h2>Error: Card authorization for a pledge transaction</h2>
|
||||
<div><h2>Error: Card authorization</h2>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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>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>
|
||||
|
||||
|
|
|
@ -1595,11 +1595,26 @@ class InfoPageView(TemplateView):
|
|||
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)
|
||||
|
||||
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 {
|
||||
'users': users,
|
||||
'works': works,
|
||||
'ebooks': ebooks,
|
||||
'wishlists': wishlists,
|
||||
'transactions': transactions,
|
||||
}
|
||||
|
||||
class InfoLangView(TemplateView):
|
||||
|
|
|
@ -105,7 +105,7 @@ class Transaction(models.Model):
|
|||
|
||||
@property
|
||||
def ack_link(self):
|
||||
return 'https://unglue.it/supporter/%s'%urllib.urlencode(self.user.username) if not self.anonymous else ''
|
||||
return 'https://unglue.it/supporter/%s' % urllib.quote(self.user.username) if not self.anonymous else ''
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.secret:
|
||||
|
|
|
@ -478,7 +478,6 @@ class StripeErrorTest(TestCase):
|
|||
self.assertEqual(e.code, "missing")
|
||||
self.assertEqual(e.message, "Cannot charge a customer that has no active card")
|
||||
|
||||
|
||||
class PledgeScenarioTest(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
@ -658,6 +657,14 @@ class Processor(baseprocessor.Processor):
|
|||
transaction.error = e.message
|
||||
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)
|
||||
|
||||
else:
|
||||
|
@ -667,6 +674,11 @@ class Processor(baseprocessor.Processor):
|
|||
transaction.pay_key = charge.id
|
||||
transaction.date_payment = now()
|
||||
transaction.save()
|
||||
|
||||
# fire signal for sucessful transaction
|
||||
transaction_charged.send(sender=self, transaction=transaction)
|
||||
|
||||
|
||||
else:
|
||||
# nothing to charge
|
||||
raise StripeLibError("No customer id available to charge for transaction {0}".format(transaction.id), None)
|
||||
|
@ -751,7 +763,9 @@ class Processor(baseprocessor.Processor):
|
|||
pass
|
||||
elif resource == 'charge':
|
||||
# we need to handle: succeeded, failed, refunded, disputed
|
||||
|
||||
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")))
|
||||
# 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
|
||||
|
@ -764,12 +778,11 @@ class Processor(baseprocessor.Processor):
|
|||
logger.info("ev_object.id == transaction.pay_key: {0}".format(ev_object.id))
|
||||
else:
|
||||
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:
|
||||
logger.warning(e)
|
||||
logger.warning(e)
|
||||
|
||||
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")))
|
||||
try:
|
||||
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))
|
||||
else:
|
||||
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:
|
||||
logger.warning(e)
|
||||
elif action == 'refunded':
|
||||
|
|
|
@ -233,7 +233,7 @@ GOODREADS_API_KEY = ""
|
|||
GOODREADS_API_SECRET = ""
|
||||
|
||||
# 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_RECOMMENDED_USERNAME = 'unglueit'
|
||||
|
||||
|
|
|
@ -223,12 +223,11 @@ sub {
|
|||
div.picture-right {
|
||||
float: right ;
|
||||
margin-bottom: 1em;
|
||||
margin-left: 1em;"}
|
||||
margin-left: 1em; }
|
||||
|
||||
.aut {
|
||||
text-align: center ;
|
||||
font-style: italic; }
|
||||
|
||||
.agate-info {
|
||||
font-size: 80%; }
|
||||
|
||||
font-size: 80%; }
|
|
@ -22,7 +22,7 @@ $j(document).ready(function() {
|
|||
$j('#feedback').css({"opacity": "0.07"});
|
||||
$j('#js-page-wrap').css({"opacity": "0.07"});
|
||||
$j('#footer').css({"opacity": "0.07"});
|
||||
$j('#about_expandable').css({'position': 'absolute'});
|
||||
$j('#about_expandable').css({'position': 'fixed'});
|
||||
$j('#about_expandable').fadeTo("slow", 1);
|
||||
|
||||
// if we're on a supporter page, personalize our about box
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
var $j = jQuery.noConflict();
|
||||
$j().ready(function() {
|
||||
$j(".loader-gif").click(function(event) {
|
||||
$j(this).addClass("show-loading");
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue