Merge branch 'relaunch' of github.com:Gluejar/regluit into relaunch

pull/1/head
Andromeda Yelton 2012-09-28 10:40:56 -04:00
commit 839a864149
6 changed files with 133 additions and 40 deletions

View File

@ -210,6 +210,47 @@ class Campaign(models.Model):
except: except:
return u"Campaign %s (no associated work)" % self.name return u"Campaign %s (no associated work)" % self.name
def clone(self):
"""use a previous UNSUCCESSFUL campaign's data as the basis for a new campaign"""
if self.clonable():
old_managers= self.managers.all()
# copy custom premiums
new_premiums= self.premiums.filter(type='CU')
# setting pk to None will insert new copy http://stackoverflow.com/a/4736172/7782
self.pk = None
self.status = 'INITIALIZED'
# set deadline far in future -- presumably RH will set deadline to proper value before campaign launched
self.deadline = date_today() + timedelta(days=int(settings.UNGLUEIT_LONGEST_DEADLINE))
# allow created, activated dates to be autoset by db
self.created = None
self.name = 'copy of %s' % self.name
self.activated = None
self.update_left()
self.save()
self.managers=old_managers
# clone associated premiums
for premium in new_premiums:
premium.pk=None
premium.created = None
premium.campaign = self
premium.save()
return self
else:
return None
def clonable(self):
"""campaign clonable if it's UNSUCCESSFUL and is the last campaign associated with a Work"""
if self.status == 'UNSUCCESSFUL' and self.work.last_campaign().id==self.id:
return True
else:
return False
@property @property
def launchable(self): def launchable(self):
may_launch=True may_launch=True
@ -341,7 +382,9 @@ class Campaign(models.Model):
@property @property
def supporters_count(self): def supporters_count(self):
# avoid transmitting the whole list if you don't need to; let the db do the count. # avoid transmitting the whole list if you don't need to; let the db do the count.
return self.transactions().filter(status=TRANSACTION_STATUS_ACTIVE).values_list('user', flat=True).distinct().count() active = self.transactions().filter(status=TRANSACTION_STATUS_ACTIVE).values_list('user', flat=True).distinct().count()
complete = self.transactions().filter(status=TRANSACTION_STATUS_COMPLETE).values_list('user', flat=True).distinct().count()
return active+complete
def transaction_to_recharge(self, user): def transaction_to_recharge(self, user):
"""given a user, return the transaction to be recharged if there is one -- None otherwise""" """given a user, return the transaction to be recharged if there is one -- None otherwise"""

View File

@ -14,7 +14,7 @@ from django.contrib.sites.models import Site
from django.http import Http404 from django.http import Http404
from regluit.payment.models import Transaction from regluit.payment.models import Transaction
from regluit.core.models import Campaign, Work, UnglueitError, Edition, RightsHolder, Claim, Key, Ebook from regluit.core.models import Campaign, Work, UnglueitError, Edition, RightsHolder, Claim, Key, Ebook, Premium
from regluit.core import bookloader, models, search, goodreads, librarything from regluit.core import bookloader, models, search, goodreads, librarything
from regluit.core import isbn from regluit.core import isbn
from regluit.payment.parameters import PAYMENT_TYPE_AUTHORIZATION from regluit.payment.parameters import PAYMENT_TYPE_AUTHORIZATION
@ -388,6 +388,8 @@ class CampaignTests(TestCase):
w = Work() w = Work()
w.save() w.save()
w2 = Work()
w2.save()
# INITIALIZED # INITIALIZED
c1 = Campaign(target=D('1000.00'),deadline=datetime(2013,1,1),work=w) c1 = Campaign(target=D('1000.00'),deadline=datetime(2013,1,1),work=w)
c1.save() c1.save()
@ -402,6 +404,8 @@ class CampaignTests(TestCase):
rh.save() rh.save()
cl = Claim(rights_holder = rh, work = w, user = u, status = 'active') cl = Claim(rights_holder = rh, work = w, user = u, status = 'active')
cl.save() cl.save()
cl2 = Claim(rights_holder = rh, work = w2, user = u, status = 'active')
cl2.save()
c2.activate() c2.activate()
self.assertEqual(c2.status, 'ACTIVE') self.assertEqual(c2.status, 'ACTIVE')
# SUSPENDED # SUSPENDED
@ -414,7 +418,7 @@ class CampaignTests(TestCase):
# should not let me suspend a campaign that hasn't been initialized # should not let me suspend a campaign that hasn't been initialized
self.assertRaises(UnglueitError, c1.suspend, "for testing") self.assertRaises(UnglueitError, c1.suspend, "for testing")
# UNSUCCESSFUL # UNSUCCESSFUL
c3 = Campaign(target=D('1000.00'),deadline=now() - timedelta(days=1),work=w) c3 = Campaign(target=D('1000.00'),deadline=now() - timedelta(days=1),work=w2)
c3.save() c3.save()
c3.activate() c3.activate()
self.assertEqual(c3.status, 'ACTIVE') self.assertEqual(c3.status, 'ACTIVE')
@ -422,6 +426,17 @@ class CampaignTests(TestCase):
self.assertTrue(c3.update_status()) self.assertTrue(c3.update_status())
self.assertEqual(c3.status, 'UNSUCCESSFUL') self.assertEqual(c3.status, 'UNSUCCESSFUL')
# premiums
pr1= Premium(type='CU', campaign=c3, amount=10, description='botsnack', limit=1)
pr1.save()
self.assertEqual(pr1.premium_remaining,1)
#cloning (note we changed c3 to w2 to make it clonable)
c7= c3.clone()
self.assertEqual(c7.status, 'INITIALIZED')
self.assertEqual(c7.premiums.all()[0].description , 'botsnack')
# SUCCESSFUL # SUCCESSFUL
c4 = Campaign(target=D('1000.00'),deadline=now() - timedelta(days=1),work=w) c4 = Campaign(target=D('1000.00'),deadline=now() - timedelta(days=1),work=w)
c4.save() c4.save()

View File

@ -164,6 +164,9 @@ class UserData(forms.Form):
return username return username
raise forms.ValidationError(_("Your username is already "+username)) raise forms.ValidationError(_("Your username is already "+username))
class CloneCampaignForm(forms.Form):
campaign_id = forms.IntegerField(required = True, widget = forms.HiddenInput)
class OpenCampaignForm(forms.ModelForm): class OpenCampaignForm(forms.ModelForm):
managers = AutoCompleteSelectMultipleField( managers = AutoCompleteSelectMultipleField(
OwnerLookup, OwnerLookup,

View File

@ -208,8 +208,9 @@ Please fix the following before launching your campaign:
{{ form.deadline.errors }}<span style="display: none">{{ form.deadline }}</span> {{ form.deadline.errors }}<span style="display: none">{{ form.deadline }}</span>
{% endifnotequal %} {% endifnotequal %}
<h3>Email address</h3> <h3>e-mail contact address</h3>
<p>Enter the email address we should contact you at for issues relating to managing this campaign.</p> <p>Enter the email address where notifications about this campaign should be sent. If your campaign succeeds, this email needs to work if you want to get paid!</p>
<p>{{ form.paypal_receiver.errors }}{{ form.paypal_receiver }}</p> <p>{{ form.paypal_receiver.errors }}{{ form.paypal_receiver }}</p>

View File

@ -20,21 +20,33 @@
Any questions not covered here? Please email us at <a href="mailto:rights@gluejar.com">rights@gluejar.com</a>. Any questions not covered here? Please email us at <a href="mailto:rights@gluejar.com">rights@gluejar.com</a>.
</div></div> </div></div>
{% if request.user.campaigns.all %} {% if campaigns %}
<h2>Campaigns You Manage</h2> <h2>Campaigns You Manage</h2>
<dl> <dl>
{% for campaign in request.user.campaigns.all %} {% for campaign in campaigns %}
<dt>Work: <a href="{% url work work_id=campaign.work.id %}">{{campaign.work.title }}</a></dt> <dt>Work: <a href="{% url work work_id=campaign.work.id %}">{{campaign.work.title }}</a></dt>
<dd> <dd>
<div class="work_campaigns clearfix"> <div class="work_campaigns clearfix">
<div class="campaign_info"> <div class="campaign_info">
Campaign: {{ campaign.name }}<br /> Campaign: {{ campaign.name }}<br />
Campaign status: {{ campaign.status }} <br /> Campaign status: {{ campaign.status }} <br />
Created: {{ campaign.created }} Created: {{ campaign.created }}<br />
${{ campaign.current_total }} pledged of ${{ campaign.target }}, {{ campaign.supporters_count }} supporters
</div> </div>
{% if campaign.status = 'ACTIVE' or campaign.status = 'INITIALIZED' %}
<div> <div>
<a href="{% url manage_campaign campaign.id %}" class="manage">Manage This Campaign</a> <a href="{% url manage_campaign campaign.id %}" class="manage">Manage This Campaign</a>
</div> </div>
{% endif %}
{% if campaign.clone_form %}
<div>
<form method="POST" action="#">
{% csrf_token %}
{{ campaign.clone_form }}{{ campaign.clone_form.errors }}
<input type="submit" name="clone" value="Clone this Campaign">
</form>
</div>
{% endif %}
</div> </div>
</dd> </dd>
{% endfor %} {% endfor %}
@ -51,7 +63,7 @@ Any questions not covered here? Please email us at <a href="mailto:rights@gluej
<br />Date of Claim : {{ claim.created }} <br />Date of Claim : {{ claim.created }}
<br />Status of Claim: {{ claim.get_status_display }} <br />Status of Claim: {{ claim.get_status_display }}
{% if claim.can_open_new %} {% if claim.can_open_new %}
<h3>Open a campaign for this work</h3> <h3>Open a blank campaign for this work</h3>
<form method="POST" action="#"> <form method="POST" action="#">
{% csrf_token %} {% csrf_token %}
<p>Name the Campaign: {{ claim.campaign_form.name }}{{ claim.campaign_form.name.errors }}</p> <p>Name the Campaign: {{ claim.campaign_form.name }}{{ claim.campaign_form.name.errors }}</p>
@ -67,6 +79,7 @@ Any questions not covered here? Please email us at <a href="mailto:rights@gluej
<h3>Campaigns for this work</h3> <h3>Campaigns for this work</h3>
{% for campaign in claim.campaigns %} {% for campaign in claim.campaigns %}
<div class="work_campaigns clearfix"> <div class="work_campaigns clearfix">
{% if campaign.status = 'ACTIVE' or campaign.status = 'INITIALIZED' %}
<div class="campaign_info"> <div class="campaign_info">
Name: Your campaign, "{{ campaign.name }}", is {{ campaign.status }}<br /> Name: Your campaign, "{{ campaign.name }}", is {{ campaign.status }}<br />
Created: {{ campaign.created }}<br /> Created: {{ campaign.created }}<br />
@ -81,6 +94,15 @@ Any questions not covered here? Please email us at <a href="mailto:rights@gluej
<a href="{% url manage_campaign campaign.id %}" class="manage">Manage This Campaign</a> <a href="{% url manage_campaign campaign.id %}" class="manage">Manage This Campaign</a>
</div> </div>
{% endif %} {% endif %}
{% else %}
<div class="campaign_info">
Name: Your campaign, "{{ campaign.name }}", is {{ campaign.status }}<br />
Created: {{ campaign.created }}<br />
Manager(s): {% for user in campaign.managers.all %} <a href="{% url supporter user.username %}">{{ user.username }} </a> {% endfor %}
<br />
${{ campaign.current_total }} pledged of ${{ campaign.target }}, {{ campaign.supporters_count }} supporters
</div>
{% endif %}
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
@ -138,20 +160,19 @@ Any questions not covered here? Please email us at <a href="mailto:rights@gluej
</li> </li>
</ol> </ol>
<h2>Rightsholder social media tools</h2>
Needs to be written. What would you find helpful in a social media toolkit? <a href="/feedback">Send us feedback.</a>
<h2>Rewards</h2> <h2>Rewards</h2>
<p>Campaigns have rewards as a way to thank supporters. unglue.it includes a standard set of rewards in all campaigns. You are encouraged to add additional sweeteners to motivate people to contribute.</p> <p>Campaigns can have rewards as a way to motivate and thank supporters. You are strongly encouraged to add rewards - they are given special prominence on the campaign page.</p>
<p>Here are the standard rewards:</p> <p>What should you add as rewards? Anything you think you can reasonably deliver that will get supporters excited about the book. For example: other books, whether electronic or physical; artwork or multimedia relating to the book, its author, or its themes; in-person or online chats with the author; memorabilia.</p>
<h2>Acknowledgements</h2>
<p>Here are the standard acknowledgements. These automatically combine with your rewards. For example, if you offer a $30 reward, ungluers who pledge $30 will receive the $25 acknowledgement as well.</p>
<ul class="terms"> <ul class="terms">
<li><em>Any level ($1 minimum)</em> &#8212; The unglued ebook delivered to your inbox</li> <li><em>Any amount</em> &#8212; The unglued ebook</li>
<li><em>$25</em> &#8212; Your username under "supporters" in the acknowledgements section</li> <li><em>$25 and above</em> &#8212; Their name in the acknowledgements section under "supporters"</li>
<li><em>$50</em> &#8212; Your name &amp; profile link under "benefactors"</li> <li><em>$50 and above</em> &#8212; Their name &amp; profile link under "benefactors"</li>
<li><em>$100</em> &#8212; Your name, profile link, &amp; profile tagline under "bibliophiles"</li> <li><em>$100 and above</em> &#8212; Their name, profile link, &amp; a dedication under "bibliophiles"</li>
</ul> </ul>
<h2>More Questions</h2> <h2>More Questions</h2>

View File

@ -48,7 +48,7 @@ from regluit.frontend.forms import UserData, UserEmail, ProfileForm, CampaignPle
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 from regluit.frontend.forms import getTransferCreditForm, CCForm, CloneCampaignForm
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.parameters import TRANSACTION_STATUS_ACTIVE, TRANSACTION_STATUS_COMPLETE, TRANSACTION_STATUS_CANCELED, TRANSACTION_STATUS_ERROR, TRANSACTION_STATUS_FAILED, TRANSACTION_STATUS_INCOMPLETE, TRANSACTION_STATUS_NONE, TRANSACTION_STATUS_MODIFIED from regluit.payment.parameters import TRANSACTION_STATUS_ACTIVE, TRANSACTION_STATUS_COMPLETE, TRANSACTION_STATUS_CANCELED, TRANSACTION_STATUS_ERROR, TRANSACTION_STATUS_FAILED, TRANSACTION_STATUS_INCOMPLETE, TRANSACTION_STATUS_NONE, TRANSACTION_STATUS_MODIFIED
@ -1154,7 +1154,7 @@ def rh_tools(request):
claim.campaigns = claim.work.campaigns.all() claim.campaigns = claim.work.campaigns.all()
else: else:
claim.campaigns = [] claim.campaigns = []
claim.can_open_new=True claim.can_open_new=False if claim.work.last_campaign_status in ['ACTIVE','INITIALIZED'] else True
for campaign in claim.campaigns: for campaign in claim.campaigns:
if campaign.status in ['ACTIVE','INITIALIZED']: if campaign.status in ['ACTIVE','INITIALIZED']:
claim.can_open_new=False claim.can_open_new=False
@ -1179,7 +1179,17 @@ def rh_tools(request):
claim.campaign_form = OpenCampaignForm(data={'work': claim.work, 'name': claim.work.title, 'userid': request.user.id, 'managers_1': request.user.id}) claim.campaign_form = OpenCampaignForm(data={'work': claim.work, 'name': claim.work.title, 'userid': request.user.id, 'managers_1': request.user.id})
else: else:
claim.can_open_new=False claim.can_open_new=False
return render(request, "rh_tools.html", {'claims': claims ,}) campaigns = request.user.campaigns.all()
new_campaign = None
for campaign in campaigns:
if campaign.clonable():
if request.method == 'POST' and request.POST.has_key('c%s-campaign_id'% campaign.id):
clone_form= CloneCampaignForm(data=request.POST, prefix = 'c%s' % campaign.id)
if clone_form.is_valid():
campaign.clone()
else:
campaign.clone_form= CloneCampaignForm(initial={'campaign_id':campaign.id}, prefix = 'c%s' % campaign.id)
return render(request, "rh_tools.html", {'claims': claims ,'campaigns': campaigns})
def rh_admin(request): def rh_admin(request):
if not request.user.is_authenticated() : if not request.user.is_authenticated() :