Merge pull request #246 from Gluejar/b2u_ungluify

B2u ungluify
pull/1/head
Raymond Yee 2013-11-15 15:59:05 -08:00
commit 2959b68549
15 changed files with 202 additions and 60 deletions

View File

@ -58,6 +58,17 @@ class BooXtream(object):
files= {'epubfile': ('%012x.epub' % random.randrange(16**12),epubfile)}
else:
files={}
if settings.LOCAL_TEST:
# fake it, so you can test other functions without hitting booxtream
boox = Boox.objects.create(
download_link_epub='https://github.com/eshellman/42_ebook/blob/master/download/42.epub?raw=true',
download_link_mobi='https://github.com/eshellman/42_ebook/blob/master/download/42.mobi?raw=true',
referenceid= kwargs.get('referenceid'),
downloads_remaining= kwargs.get('downloadlimit'),
expirydays=kwargs.get('expirydays'),
)
return boox
resp = self.postrequest(url, data=kwargs, files=files)
doc = ElementTree.fromstring(resp.content)

View File

@ -17,3 +17,11 @@ class Boox(models.Model):
def expired(self):
return self.created+timedelta(days=self.expirydays) < datetime.now()
def download_link(self, format):
if format == 'epub':
return self.download_link_epub
elif format == 'mobi':
return self.download_link_mobi
else:
return None

View File

@ -14,4 +14,15 @@ def personalize(epub_file, acq):
output.addmetadata('rights','%s after %s'%(acq.work.last_campaign().license_url,acq.work.last_campaign().cc_date))
output.close()
#output.writetodisk('testfile2.epub')
return output
def ungluify(epub_file, campaign):
output = EPUB(epub_file, "a")
context={'campaign':campaign}
part = StringIO(unicode(render_to_string('epub/cc_license.xhtml', context)))
output.addpart(part, "cc_license.xhtml", "application/xhtml+xml", 1) #after title, we hope
output.addmetadata('rights', campaign.license_url)
output.close()
#output.writetodisk('testfile3.epub')
return output

View File

@ -7,6 +7,7 @@ import hashlib
import re
import random
import urllib
import urllib2
from ckeditor.fields import RichTextField
from datetime import timedelta, datetime
@ -21,6 +22,7 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.core.files.base import ContentFile
from django.db import models
from django.db.models import F, Q, get_model
from django.db.models.signals import post_save
@ -31,7 +33,7 @@ regluit imports
'''
import regluit
import regluit.core.isbn
from regluit.core.epub import personalize
from regluit.core.epub import personalize, ungluify
from regluit.core.signals import (
successful_campaign,
@ -336,7 +338,7 @@ class Acq(models.Model):
return self.watermarked
def _hash(self):
return hashlib.md5('1c1a56974ef08edc%s:%s:%s'%(self.user.id,self.work.id,self.created)).hexdigest()
return hashlib.md5('%s:%s:%s:%s'%(settings.TWITTER_CONSUMER_SECRET,self.user.id,self.work.id,self.created)).hexdigest()
def expire_in(self, delta):
self.expires = now() + delta
@ -513,46 +515,61 @@ class Campaign(models.Model):
def update_status(self, ignore_deadline_for_success=False, send_notice=False, process_transactions=False):
"""Updates the campaign's status. returns true if updated.
for REWARDS:
Computes UNSUCCESSFUL only after the deadline has passed
Computes SUCCESSFUL only after the deadline has passed if ignore_deadline_for_success is TRUE -- otherwise looks just at amount of pledges accumulated
by default, send_notice is False so that we have to explicitly send specify delivery of successful_campaign notice
for BUY2UNGLUE:
Sets SUCCESSFUL when cc_date is in the past.
if process_transactions is True, also execute or cancel associated transactions
"""
if not self.status=='ACTIVE':
return False
elif (ignore_deadline_for_success or self.deadline < now()) and self.current_total >= self.target:
self.status = 'SUCCESSFUL'
self.save()
action = CampaignAction(campaign=self, type='succeeded', comment = self.current_total)
action.save()
elif self.type==REWARDS:
if (ignore_deadline_for_success or self.deadline < now()) and self.current_total >= self.target:
self.status = 'SUCCESSFUL'
self.save()
action = CampaignAction(campaign=self, type='succeeded', comment = self.current_total)
action.save()
if process_transactions:
p = PaymentManager()
results = p.execute_campaign(self)
if process_transactions:
p = PaymentManager()
results = p.execute_campaign(self)
if send_notice:
successful_campaign.send(sender=None,campaign=self)
if send_notice:
successful_campaign.send(sender=None,campaign=self)
# should be more sophisticated in whether to return True -- look at all the transactions?
return True
elif self.deadline < now() and self.current_total < self.target:
self.status = 'UNSUCCESSFUL'
self.save()
action = CampaignAction(campaign=self, type='failed', comment = self.current_total)
action.save()
# should be more sophisticated in whether to return True -- look at all the transactions?
return True
elif self.deadline < now() and self.current_total < self.target:
self.status = 'UNSUCCESSFUL'
self.save()
action = CampaignAction(campaign=self, type='failed', comment = self.current_total)
action.save()
if process_transactions:
p = PaymentManager()
results = p.cancel_campaign(self)
if process_transactions:
p = PaymentManager()
results = p.cancel_campaign(self)
if send_notice:
regluit.core.signals.unsuccessful_campaign.send(sender=None,campaign=self)
# should be more sophisticated in whether to return True -- look at all the transactions?
return True
else:
return False
if send_notice:
regluit.core.signals.unsuccessful_campaign.send(sender=None,campaign=self)
# should be more sophisticated in whether to return True -- look at all the transactions?
return True
elif self.type==BUY2UNGLUE:
if self.cc_date < date_today():
self.status = 'SUCCESSFUL'
self.save()
action = CampaignAction(campaign=self, type='succeeded', comment = self.current_total)
action.save()
self.watermark_success()
if send_notice:
successful_campaign.send(sender=None,campaign=self)
# should be more sophisticated in whether to return True -- look at all the transactions?
return True
return False
_current_total = None
@property
@ -820,6 +837,14 @@ class Campaign(models.Model):
return ''
return ''
def percent_of_goal(self):
if(self.status == 'SUCCESSFUL' or self.status == 'ACTIVE'):
if self.type == BUY2UNGLUE:
percent = int(100 - 100*self.left/self.target)
else:
percent = int(self.current_total/self.target*100)
return percent
@property
def countdown(self):
from math import ceil
@ -840,6 +865,45 @@ class Campaign(models.Model):
@classmethod
def latest_ending(cls):
return (timedelta(days=int(settings.UNGLUEIT_LONGEST_DEADLINE)) + now())
def make_unglued_ebf(self, format, watermarked):
ebf=EbookFile.objects.create(edition=self.work.preferred_edition, format=format)
r=urllib2.urlopen(watermarked.download_link(format))
ebf.file.save(path_for_file(ebf,None),ContentFile(r.read()))
ebf.file.close()
ebf.save()
ebook=Ebook.objects.create(
edition=self.work.preferred_edition,
format=format,
rights=self.license,
provider="Unglue.it",
url= settings.BASE_URL_SECURE + reverse('download_campaign',args=[self.work.id,format]),
)
return ebook.pk
def watermark_success(self):
if self.status == 'SUCCESSFUL' and self.type == BUY2UNGLUE:
params={
'customeremailaddress': self.license,
'customername': 'The Public',
'languagecode':'1033',
'expirydays': 1,
'downloadlimit': 7,
'exlibris':0,
'chapterfooter':0,
'disclaimer':0,
'referenceid': '%s:%s:%s' % (self.work.id, self.id, self.license),
'kf8mobi': True,
'epub': True,
}
ungluified = ungluify(self.work.ebookfiles()[0].file, self)
ungluified.filename.seek(0)
watermarked = watermarker.platform(epubfile= ungluified.filename, **params)
self.make_unglued_ebf('epub', watermarked)
self.make_unglued_ebf('mobi', watermarked)
return True
return False
class Identifier(models.Model):
# olib, ltwk, goog, gdrd, thng, isbn, oclc, olwk, olib, gute, glue
@ -1023,15 +1087,8 @@ class Work(models.Model):
return status
def percent_of_goal(self):
percent = 0
campaign = self.last_campaign()
if campaign is not None:
if(campaign.status == 'SUCCESSFUL' or campaign.status == 'ACTIVE'):
if campaign.type == BUY2UNGLUE:
percent = int(100 - 100*campaign.left/campaign.target)
else:
percent = int(campaign.current_total/campaign.target*100)
return percent
return 0 if campaign is None else campaign.percent_of_goal()
def ebooks(self):
return Ebook.objects.filter(edition__work=self).order_by('-created')
@ -1395,7 +1452,8 @@ FORMAT_CHOICES = (('pdf','PDF'),( 'epub','EPUB'), ('html','HTML'), ('text','TEXT
def path_for_file(instance, filename):
version = EbookFile.objects.filter(edition = instance.edition, format = instance.format).count()
fn = "ebf/%s.%d.%s"%(instance.edition.pk,version,instance.format)
hash = hashlib.md5('%s.%s.%d'%(settings.TWITTER_CONSUMER_SECRET, instance.edition.pk, version)).hexdigest()
fn = "ebf/%s.%s"%(hash,instance.format)
return fn
class EbookFile(models.Model):

View File

@ -30,7 +30,7 @@ from social_auth.backends.facebook import FacebookBackend
regluit imports
"""
from regluit.payment.signals import transaction_charged, transaction_failed, pledge_modified, pledge_created
from regluit.utils.localdatetime import now
from regluit.utils.localdatetime import now, date_today
from regluit.core.parameters import REWARDS, BUY2UNGLUE, LIBRARY, RESERVE
from regluit.libraryauth.models import Library, LibraryUser
@ -183,6 +183,7 @@ unsuccessful_campaign.connect(notify_unsuccessful_campaign)
def handle_transaction_charged(sender,transaction=None, **kwargs):
if transaction==None:
return
transaction._current_total = None
if transaction.campaign.type is REWARDS:
notification.send([transaction.user], "pledge_charged", {'transaction':transaction}, True)
else:
@ -203,6 +204,8 @@ def handle_transaction_charged(sender,transaction=None, **kwargs):
notification.send([transaction.user], "purchase_complete", {'transaction':transaction}, True)
from regluit.core.tasks import watermark_acq
watermark_acq.delay(new_acq)
if transaction.campaign.cc_date < date_today() :
transaction.campaign.update_status(send_notice=True)
from regluit.core.tasks import emit_notifications
emit_notifications.delay()

View File

@ -823,6 +823,7 @@ class MailingListTests(TestCase):
self.user = User.objects.create_user('chimp_test', 'eric@gluejar.com', 'chimp_test')
self.assertTrue(self.user.profile.on_ml)
@override_settings(LOCAL_TEST=True)
class EbookFileTests(TestCase):
def test_ebookfile(self):
@ -832,8 +833,15 @@ class EbookFileTests(TestCase):
w = Work.objects.create(title="Work 1")
e = Edition.objects.create(title=w.title,work=w)
u = User.objects.create_user('test', 'test@example.org', 'testpass')
c = Campaign.objects.create(work=w, type = parameters.BUY2UNGLUE, cc_date_initial= datetime(2020,1,1),target=1000, deadline=datetime(2020,1,1))
rh = RightsHolder.objects.create(owner = u, rights_holder_name = 'rights holder name')
cl = Claim.objects.create(rights_holder = rh, work = w, user = u, status = 'active')
c = Campaign.objects.create(work = w,
type = parameters.BUY2UNGLUE,
cc_date_initial = datetime(2020,1,1),
target = 1000,
deadline = datetime(2020,1,1),
license = 'CC BY',
)
# download the test epub into a temp file
temp = NamedTemporaryFile(delete=False)
test_file_content = requests.get(settings.BOOXTREAM_TEST_EPUB_URL).content
@ -862,10 +870,16 @@ class EbookFileTests(TestCase):
self.assertIsNot(acq.nonce, None)
url= acq.get_watermarked().download_link_epub
self.assertRegexpMatches(url,'download.booxtream.com/')
print url
self.assertRegexpMatches(url,'github.com/eshellman/42_ebook/blob/master/download/42')
c.activate()
#flip the campaign to success
c.cc_date_initial= datetime(2012,1,1)
c.update_status()
self.assertEqual( c.work.ebooks().count(),2 )
from .signals import handle_transaction_charged
@override_settings(LOCAL_TEST=True)
class LibTests(TestCase):
class transaction:

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>License Information</title>
</head>
<body>
<div class="booksection">
<p class="copyk">
<p>&#x00A0;</p>
<p class="copyk">After {{ campaign.cc_date }}, this book is be released under a {{ campaign.license }} license at which time the any previous restricted license terms shall be replaced and superseded by the terms of the applicable Creative Commons license <a href="{{ campaign.license_url }}">{{ acq.work.last_campaign.license_url }}</a></p>
<p class="copy"></p>
</div>
</body>
</html>

View File

@ -1,12 +1,13 @@
{% if pledged %}You pledged toward{% else %}Hooray! You wished for{% endif %} it, and now the campaign
for {{ campaign.work.title}} (https://{{current_site.domain}}{% url work campaign.work.id %}) has succeeded.
{% if pledged %}You pledged toward it{% else %}You put it on your list{% endif %}, and now the campaign for {{ campaign.work.title}} (https://{{current_site.domain}}{% url work campaign.work.id %}) has succeeded.
{% ifequal campaign.type 1 %}
You will notified when an Unglued ebook edition is available, within 90 days.
{% if pledged %}
If necessary to provide you with any premiums you requested, {{ campaign.rightsholder }} will be contacting you.
{% endif%}
{% endif %}
{% else %}
Get your free copy now!
{% endifequal %}
Thank you for your support.
{{ campaign.rightsholder }} (rights holder for {{ campaign.work.title }}) and the Unglue.it team

View File

@ -5,10 +5,15 @@
{% endblock %}
{% block comments_graphical %}
Hooray! We're going to give <a href="{% url work campaign.work.id %}">{{ campaign.work.title }}</a> to the world!
The campaign to unglue <a href="{% url work campaign.work.id %}">{{ campaign.work.title }}</a> has succeeded!
{% endblock %}
{% block comments_textual %}
A book on your wishlist, {{ campaign.work.title }}, has met its goal price of {{ campaign.target }}, thanks to the support of ungluers like you. Unglue.it and the book's rights holder, {{ campaign.rightsholder }}, will be converting it to an unglued ebook edition and making it available for all the world to enjoy. If you've asked us to in your <a href="/notification/settings/">notification settings</a>, we'll tell you when the unglued ebook is ready.<br /><br />
{% ifequal campaign.type 1 %}
A book on your ungluing list, {{ campaign.work.title }}, has met its goal price of {{ campaign.target }}, thanks to the support of ungluers like you. Unglue.it and the book's rights holder, {{ campaign.rightsholder }}, will be converting it to an unglued ebook edition and making it available for all the world to enjoy. We'll let you know you when the unglued ebook is ready.<br /><br />
{% else %}
A book on your ungluing list, {{ campaign.work.title }}, has met its revenue target, thanks to the support of ungluers like you. The book is now unglued - available for all the world to enjoy. <br /><br />
{% endifequal %}
Thank you again!
{% endblock %}

View File

@ -1,8 +1,8 @@
{% if work.last_campaign_status == 'SUCCESSFUL' %}
Great news! {{ work.title }}, which you have supported on Unglue.it, is now available for download as an Unglued Ebook.
{{ work.title }}, which is on your ungluing list, is now available for download as an Unglued Ebook.
{% else %}
Good News! {{ work.title }}, which is on your wishlist, is available for download as a {{ work.ebooks.0.get_rights_display }} ebook.
{{ work.title }}, which is on your ungluing list, is available for download as a {{ work.ebooks.0.get_rights_display }} ebook.
{% if work.ebooks.0.user %}
We'd like to thank Ungluer {{work.ebooks.0.user}} for adding the link(s).

View File

@ -12,11 +12,11 @@
{% block comments_textual %}
{% if work.last_campaign_status == 'SUCCESSFUL' %}
<p>
Great News! <a href="{% url work work.id %}">{{ work.title }}</a> which you have supported is now available for download as an Unglued Ebook.
Great News! <a href="{% url work work.id %}">{{ work.title }}</a> which is on your ungluing list is now available for download as an Unglued Ebook.
</p>
{% else %}
<p>
Good News! <a href="{% url work work.id %}">{{ work.title }}</a> which is on your wishlist is available for download as a {{ work.ebooks.0.get_rights_display }} ebook.
Good News! <a href="{% url work work.id %}">{{ work.title }}</a> which is on your ungluing list is available for download as a {{ work.ebooks.0.get_rights_display }} ebook.
</p>
{% if work.ebooks.0.user %}
<p>

View File

@ -49,11 +49,9 @@
{% endif %}
{% else %}
{% if request.user == work.user_with_rights %}
{% ifequal work.last_campaign.status 'SUCCESSFUL' %}
<div class="launch_top pale">Congratulations, {{ request.user.username }}; you successfully unglued this work! What are your plans for publicity and distribution? We're happy to brainstorm with you about next steps.</div>
{% else %}
{% ifnotequal work.last_campaign.status 'SUCCESSFUL' %}
<div class="launch_top pale">Hi, {{ request.user.username }}. Since you're a rights holder for this work, you can <a href="{% url rightsholders %}">launch a campaign</a>.</div>
{% endifequal %}
{% endifnotequal %}
{% endif %}
{% endif %}
{% endif %}
@ -159,7 +157,7 @@
{% endif %}
</div>
<div class="campaign-status-info">
<span>${{ work.last_campaign.current_total|floatformat:0|intcomma }}</span> pledged
<span>${{ work.last_campaign.current_total|floatformat:0|intcomma }}</span> raised
</div>
<div class="campaign-status-info">
<span>${{ work.last_campaign.target|floatformat:0|intcomma }}</span> goal

View File

@ -85,6 +85,7 @@ urlpatterns = patterns(
url(r"^work/(?P<work_id>\d+)/lockss/$", "lockss", name="lockss"),
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+)/unglued/(?P<format>\w+)/$", "download_campaign", name="download_campaign"),
url(r"^work/(?P<work_id>\d+)/borrow/$", "borrow", name="borrow"),
url(r"^work/(?P<work_id>\d+)/reserve/$", "reserve", name="reserve"),
url(r"^work/(?P<work_id>\d+)/merge/$", login_required(MergeView.as_view()), name="merge"),

View File

@ -2673,6 +2673,20 @@ def download_purchased(request, work_id):
HttpResponseRedirect('/accounts/login/download/')
return download(request, work_id)
def download_campaign(request, work_id, format):
work = safe_get_work(work_id)
campaign = work.last_campaign()
if campaign is None or (campaign.status != 'SUCCESSFUL'):
raise Http404
if campaign.type is BUY2UNGLUE:
ebfs= models.EbookFile.objects.filter(edition__work=campaign.work, format=format).exclude(file='').order_by('-created')
logger.info(ebfs.count())
for ebf in ebfs:
logger.info(ebf.file.url)
return HttpResponseRedirect(ebf.file.url)
raise Http404
def download_acq(request, nonce, format):
acq = get_object_or_404(models.Acq,nonce=nonce)
if acq.on_reserve:

View File

@ -7,6 +7,7 @@ from regluit.payment.parameters import PAYMENT_HOST_PAYPAL, PAYMENT_HOST_AMAZON
PROJECT_DIR = dirname(dirname(realpath(__file__)))
LANGUAGE_CODE = 'en-us'
LOCAL_TEST = False
WISHED_LANGS = ('en','fr','es','de','el','pt','it','ru','cs','ja','zh','nl','ut','ar','la','id','ca','fa','sv','sl','ko','tr')