implemented ebook versions

It turned out that ebookfile handling needed revamping with the
addition of ebook versions; so this change turned out to be rather big.
pull/1/head
eric 2016-08-24 15:41:29 -04:00
parent 651f45f624
commit 7ad0d7f494
18 changed files with 357 additions and 197 deletions

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0004_auto_20160808_1548'),
]
operations = [
migrations.AddField(
model_name='ebookfile',
name='ebook',
field=models.ForeignKey(related_name='ebook_files', to='core.Ebook', null=True),
),
]

View File

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
def add_ebooks_to_ebfs(apps, schema_editor):
EbookFile = apps.get_model('core', 'EbookFile')
Ebook = apps.get_model('core', 'Ebook')
for ebf in EbookFile.objects.all():
for ebook in Ebook.objects.filter(edition=ebf.edition, format=ebf.format).exclude(provider='Unglue.it'):
ebf.ebook = ebook
ebf.save()
for ebook in Ebook.objects.filter(url=ebf.file.url):
ebf.ebook = ebook
ebf.save()
if not ebf.ebook:
if ebf.edition.work.campaigns.filter(type=3):
ebf.ebook = Ebook.objects.create(
edition=ebf.edition,
active=False,
url=ebf.file.url,
provider='Unglue.it',
format=ebf.format,
rights=ebf.edition.work.campaigns.order_by('-created')[0].license
)
ebf.save()
elif ebf.edition.work.campaigns.filter(type=2):
pass
else:
print 'ebf {} is dangling'.format(ebf.id)
def noop(apps, schema_editor):
pass
dependencies = [
('core', '0005_ebookfile_ebook'),
]
operations = [
migrations.RunPython(add_ebooks_to_ebfs, reverse_code=noop, hints={'core': 'EbookFile'}),
]

View File

@ -78,6 +78,7 @@ from .bibmodels import (
EbookFile, EbookFile,
Edition, Edition,
EditionNote, EditionNote,
good_providers,
Identifier, Identifier,
path_for_file, path_for_file,
Publisher, Publisher,
@ -675,7 +676,11 @@ class Campaign(models.Model):
self.activated = datetime.today() self.activated = datetime.today()
if self.type == THANKS: if self.type == THANKS:
# make ebooks from ebookfiles # make ebooks from ebookfiles
self.work.make_ebooks_from_ebfs() if self.use_add_ask:
self.add_ask_to_ebfs()
else:
self.revert_asks()
self.work.remove_old_ebooks()
self.save() self.save()
action = CampaignAction(campaign=self, type='activated', comment=self.get_type_display()) action = CampaignAction(campaign=self, type='activated', comment=self.get_type_display())
ungluers = self.work.wished_by() ungluers = self.work.wished_by()
@ -934,82 +939,112 @@ class Campaign(models.Model):
def latest_ending(cls): def latest_ending(cls):
return timedelta(days=int(settings.UNGLUEIT_LONGEST_DEADLINE)) + now() return timedelta(days=int(settings.UNGLUEIT_LONGEST_DEADLINE)) + now()
def make_mobi(self): def make_mobis(self):
for ebf in self.work.ebookfiles().filter(format='epub').order_by('-created'): # make archive files for ebooks, make mobi files for epubs
if ebf.active: versions = set()
new_mobi_ebf = EbookFile.objects.create(edition=ebf.edition, format='mobi', asking=ebf.asking) for ebook in self.work.ebooks().filter(provider__in=good_providers, format='mobi'):
new_mobi_ebf.file.save(path_for_file('ebf', None), ContentFile(mobi.convert_to_mobi(ebf.file.url))) versions.add(ebook.version_label)
new_mobi_ebf.save() for ebook in self.work.ebooks_all().exclude(provider='Unglue.it').filter(provider__in=good_providers, format='epub'):
self.work.make_ebooks_from_ebfs() if not ebook.version_label in versions:
return True # now make the mobi file
return False ebf = ebook.get_archive_ebf()
ebf.make_mobi()
def add_ask_to_ebfs(self, position=0): def add_ask_to_ebfs(self, position=0):
if not self.use_add_ask or self.type != THANKS: if not self.use_add_ask or self.type != THANKS:
return return
pdf_to_do = pdf_edition = None format_versions = []
epub_to_do = epub_edition = None to_dos = []
new_ebfs = {} for ebf in self.work.ebookfiles().filter(asking=False, ebook__provider='Unglue.it').order_by('-created'):
for ebf in self.work.ebookfiles().filter(asking=False).order_by('-created'): format_version = '{}_{}'.format(ebf.ebook.format, ebf.ebook.version_label)
if ebf.format == 'pdf' and not pdf_to_do: if ebf.format in ('pdf', 'epub') and not format_version in format_versions:
ebf.file.open() ebf.file.open()
pdf_to_do = ebf.file.read() to_dos.append({'content': ebf.file.read(), 'ebook': ebf.ebook})
pdf_edition = ebf.edition format_versions.append(format_version)
elif ebf.format == 'epub' and not epub_to_do: for ebook in self.work.ebooks_all().exclude(provider='Unglue.it').filter(provider__in=good_providers):
ebf.file.open() format_version = '{}_{}'.format(ebook.format, ebook.version_label)
epub_to_do = ebf.file.read() if ebook.format in ('pdf', 'epub') and not format_version in format_versions:
epub_edition = ebf.edition to_dos.append({'content': ebook.get_archive().read(), 'ebook': ebook})
for ebook in self.work.ebooks_all().exclude(provider='Unglue.it'): format_versions.append(format_version)
if ebook.format == 'pdf' and not pdf_to_do: new_ebfs = []
r = requests.get(ebook.url) for to_do in to_dos:
pdf_to_do = r.content edition = to_do['ebook'].edition
pdf_edition = ebook.edition version = to_do['ebook'].version
elif ebook.format == 'epub' and not epub_to_do: if to_do['ebook'].format == 'pdf':
r = requests.get(ebook.url) try:
epub_to_do = r.content added = ask_pdf({'campaign':self, 'work':self.work, 'site':Site.objects.get_current()})
epub_edition = ebook.edition new_file = SpooledTemporaryFile()
if pdf_to_do: old_file = SpooledTemporaryFile()
try: old_file.write(to_do['content'])
added = ask_pdf({'campaign':self, 'work':self.work, 'site':Site.objects.get_current()}) if position == 0:
new_file = SpooledTemporaryFile() pdf_append(added, old_file, new_file)
old_file = SpooledTemporaryFile() else:
old_file.write(pdf_to_do) pdf_append(old_file, added, new_file)
if position == 0: new_file.seek(0)
pdf_append(added, old_file, new_file) new_pdf_ebf = EbookFile.objects.create(edition=edition, format='pdf', asking=True)
else: new_pdf_ebf.version = version
pdf_append(old_file, added, new_file) new_pdf_ebf.file.save(path_for_file('ebf', None), ContentFile(new_file.read()))
new_file.seek(0) new_pdf_ebf.save()
new_pdf_ebf = EbookFile.objects.create(edition=pdf_edition, format='pdf', asking=True) new_ebfs.append(new_pdf_ebf)
new_pdf_ebf.file.save(path_for_file('ebf', None), ContentFile(new_file.read())) except Exception as e:
new_pdf_ebf.save() logger.error("error appending pdf ask %s" % (e))
new_ebfs['pdf'] = new_pdf_ebf elif to_do['ebook'].format == 'epub':
except Exception as e: try:
logger.error("error appending pdf ask %s" % (e)) old_file = SpooledTemporaryFile()
if epub_to_do: old_file.write(to_do['content'])
try: new_file = ask_epub(old_file, {'campaign':self, 'work':self.work, 'site':Site.objects.get_current()})
old_file = SpooledTemporaryFile() new_file.seek(0)
old_file.write(epub_to_do) new_epub_ebf = EbookFile.objects.create(edition=edition, format='epub', asking=True)
new_file = ask_epub(old_file, {'campaign':self, 'work':self.work, 'site':Site.objects.get_current()}) new_epub_ebf.file.save(path_for_file(new_epub_ebf, None), ContentFile(new_file.read()))
new_file.seek(0) new_epub_ebf.save()
new_epub_ebf = EbookFile.objects.create(edition=epub_edition, format='epub', asking=True) new_epub_ebf.version = version
new_epub_ebf.file.save(path_for_file(new_epub_ebf, None), ContentFile(new_file.read())) new_ebfs.append(new_epub_ebf)
new_epub_ebf.save()
new_ebfs['epub'] = new_epub_ebf # now make the mobi file
# now make the mobi file new_mobi_ebf = EbookFile.objects.create(edition=edition, format='mobi', asking=True)
new_mobi_ebf = EbookFile.objects.create(edition=epub_edition, format='mobi', asking=True) new_mobi_ebf.file.save(path_for_file('ebf', None), ContentFile(mobi.convert_to_mobi(new_epub_ebf.file.url)))
new_mobi_ebf.file.save(path_for_file('ebf', None), ContentFile(mobi.convert_to_mobi(new_epub_ebf.file.url))) new_mobi_ebf.save()
new_mobi_ebf.save() new_mobi_ebf.version = version
new_ebfs['mobi'] = new_mobi_ebf new_ebfs.append(new_mobi_ebf)
except Exception as e: except Exception as e:
logger.error("error making epub ask or mobi %s" % (e)) logger.error("error making epub ask or mobi %s" % (e))
for key in new_ebfs.keys(): for ebf in new_ebfs:
for old_ebf in self.work.ebookfiles().filter(asking=True, format=key).exclude(pk=new_ebfs[key].pk): ebook = Ebook.objects.create(
obsolete = Ebook.objects.filter(url=old_ebf.file.url) edition=ebf.edition,
for eb in obsolete: format=ebf.format,
eb.deactivate() rights=self.license,
old_ebf.file.delete() provider="Unglue.it",
old_ebf.delete() url=ebf.file.url,
self.work.make_ebooks_from_ebfs(add_ask=True) version=ebf.version
)
ebf.ebook = ebook
ebf.save()
new_ebf_pks = [ebf.pk for ebf in new_ebfs]
for old_ebf in self.work.ebookfiles().filter(asking=True).exclude(pk__in=new_ebf_pks):
obsolete = Ebook.objects.filter(url=old_ebf.file.url)
old_ebf.ebook.deactivate()
old_ebf.file.delete()
old_ebf.delete()
for non_asking in self.work.ebookfiles().filter(asking=False, ebook__active=True):
non_asking.ebook.deactivate()
def revert_asks(self):
# there should be a deactivated non-asking ebook for every asking ebook
if self.type != THANKS: # just to make sure that ebf's can be unglued by mistake
return
format_versions = []
for ebf in EbookFile.objects.filter(edition__work=self.work).exclude(file='').exclude(ebook=None).order_by('-created'):
format_version = '{}_{}'.format(ebf.format, ebf.ebook.version_label)
if ebf.asking:
ebf.ebook.deactivate()
elif format_version in format_versions:
# this ebook file has the wrong "asking"
ebf.ebook.deactivate()
else:
ebf.ebook.activate()
format_versions.append(format_version)
def make_unglued_ebf(self, format, watermarked): def make_unglued_ebf(self, format, watermarked):
r = urllib2.urlopen(watermarked.download_link(format)) r = urllib2.urlopen(watermarked.download_link(format))
@ -1023,6 +1058,7 @@ class Campaign(models.Model):
rights=self.license, rights=self.license,
provider="Unglue.it", provider="Unglue.it",
url=settings.BASE_URL_SECURE + reverse('download_campaign', args=[self.work.id, format]), url=settings.BASE_URL_SECURE + reverse('download_campaign', args=[self.work.id, format]),
version='unglued',
) )
old_ebooks = Ebook.objects.exclude(pk=ebook.pk).filter( old_ebooks = Ebook.objects.exclude(pk=ebook.pk).filter(
edition=self.work.preferred_edition, edition=self.work.preferred_edition,

View File

@ -25,8 +25,10 @@ from regluit.marc.models import MARCRecord as NewMARC
from regluit.utils.localdatetime import now from regluit.utils.localdatetime import now
from regluit.questionnaire.models import Landing from regluit.questionnaire.models import Landing
from regluit.core import mobi
import regluit.core.cc as cc import regluit.core.cc as cc
from regluit.core.epub import test_epub from regluit.core.epub import test_epub
from regluit.core.parameters import ( from regluit.core.parameters import (
AGE_LEVEL_CHOICES, AGE_LEVEL_CHOICES,
BORROWED, BORROWED,
@ -41,6 +43,7 @@ from regluit.core.parameters import (
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
good_providers = ('Internet Archive', 'Unglue.it', 'Github', 'OAPEN Library')
class Identifier(models.Model): class Identifier(models.Model):
@ -360,7 +363,15 @@ class Work(models.Model):
def pdffiles(self): def pdffiles(self):
return EbookFile.objects.filter(edition__work=self, format='pdf').exclude(file='').order_by('-created') return EbookFile.objects.filter(edition__work=self, format='pdf').exclude(file='').order_by('-created')
def versions(self):
version_labels = ['']
for ebook in self.ebooks():
if not ebook.version_label in version_labels:
version_labels.append(ebook.version_label)
version_labels.remove('')
return version_labels
def formats(self): def formats(self):
fmts = [] fmts = []
for fmt in ['pdf', 'epub', 'mobi', 'html']: for fmt in ['pdf', 'epub', 'mobi', 'html']:
@ -369,48 +380,20 @@ class Work(models.Model):
break break
return fmts return fmts
def make_ebooks_from_ebfs(self, add_ask=True):
# either the ebf has been uploaded or a created (perhaps an ask was added or mobi generated)
if self.last_campaign().type != THANKS: # just to make sure that ebf's can be unglued by mistake
return
ebfs = EbookFile.objects.filter(edition__work=self).exclude(file='').order_by('-created')
done_formats = []
for ebf in ebfs:
previous_ebooks = Ebook.objects.filter(url=ebf.file.url,)
try:
previous_ebook = previous_ebooks[0]
for eb in previous_ebooks[1:]: #housekeeping
eb.deactivate()
except IndexError:
previous_ebook = None
if ebf.format not in done_formats:
if ebf.asking == add_ask or ebf.format == 'mobi':
if previous_ebook:
previous_ebook.activate()
else:
ebook = Ebook.objects.get_or_create(
edition=ebf.edition,
format=ebf.format,
rights=self.last_campaign().license,
provider="Unglue.it",
url=ebf.file.url,
)
done_formats.append(ebf.format)
elif previous_ebook:
previous_ebook.deactivate()
elif previous_ebook:
previous_ebook.deactivate()
return
def remove_old_ebooks(self): def remove_old_ebooks(self):
# this method is triggered after an file upload or new ebook saved
old = Ebook.objects.filter(edition__work=self, active=True).order_by('-created') old = Ebook.objects.filter(edition__work=self, active=True).order_by('-created')
done_formats = []
# keep most recent ebook for each format and version label
done_format_versions = []
for eb in old: for eb in old:
if eb.format in done_formats: format_version = '{}_{}'.format(eb.format, eb.version_label)
if format_version in done_format_versions:
eb.deactivate() eb.deactivate()
else: else:
done_formats.append(eb.format) done_format_versions.append(format_version)
# check for failed uploads.
null_files = EbookFile.objects.filter(edition__work=self, file='') null_files = EbookFile.objects.filter(edition__work=self, file='')
for ebf in null_files: for ebf in null_files:
ebf.file.delete() ebf.file.delete()
@ -1005,7 +988,8 @@ class EbookFile(models.Model):
edition = models.ForeignKey('Edition', related_name='ebook_files') edition = models.ForeignKey('Edition', related_name='ebook_files')
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
asking = models.BooleanField(default=False) asking = models.BooleanField(default=False)
ebook = models.ForeignKey('Ebook', related_name='ebook_files', null=True)
version = None
def check_file(self): def check_file(self):
if self.format == 'epub': if self.format == 'epub':
return test_epub(self.file) return test_epub(self.file)
@ -1018,6 +1002,24 @@ class EbookFile(models.Model):
except: except:
return False return False
def make_mobi(self):
if not self.format == 'epub':
return False
new_mobi_ebf = EbookFile.objects.create(edition=self.edition, format='mobi', asking=self.asking)
new_mobi_ebf.file.save(path_for_file('ebf', None), ContentFile(mobi.convert_to_mobi(self.file.url)))
new_mobi_ebf.save()
if self.ebook:
new_ebook = Ebook.objects.create(
edition=self.edition,
format='mobi',
url=new_mobi_ebf.file.url,
rights=self.ebook.rights,
version=self.ebook.version,
)
new_mobi_ebf.ebook = new_ebook
new_mobi_ebf.save()
return True
send_to_kindle_limit = 7492232 send_to_kindle_limit = 7492232
class Ebook(models.Model): class Ebook(models.Model):
@ -1041,49 +1043,63 @@ class Ebook(models.Model):
else: else:
return False return False
def get_archive(self): # returns an archived file def get_archive(self): # returns an open file
if self.edition.ebook_files.filter(format=self.format).count() == 0: ebf = self.get_archive_ebf()
if self.provider is not 'Unglue.it': if not ebf:
try: return None
r = urllib2.urlopen(self.url) try:
try: ebf.file.open()
self.filesize = int(r.info().getheaders("Content-Length")[0]) except ValueError:
if self.save: logger.error(u'couldn\'t open EbookFile {}'.format(ebf.id))
self.filesize = self.filesize if self.filesize < 2147483647 else 2147483647 # largest safe positive integer return None
self.save() except IOError:
ebf = EbookFile.objects.create(edition=self.edition, format=self.format) logger.error(u'EbookFile {} does not exist'.format(ebf.id))
ebf.file.save(path_for_file(ebf, None), ContentFile(r.read())) return None
ebf.file.close() return ebf.file
ebf.save()
ebf.file.open() def get_archive_ebf(self): # returns an ebf
return ebf.file if not self.ebook_files.filter(asking=False):
except IndexError: if not self.provider in good_providers:
# response has no Content-Length header probably a bad link return None
logging.error('Bad link error: {}'.format(self.url))
except IOError:
logger.error(u'could not open {}'.format(self.url))
else:
# this shouldn't happen, except in testing perhaps
logger.error(u'couldn\'t find ebookfile for {}'.format(self.url))
# try the url instead
f = urllib.urlopen(self.url)
return f
else:
ebf = self.edition.ebook_files.filter(format=self.format).order_by('-created')[0]
try: try:
ebf.file.open() r = urllib2.urlopen(self.url)
except ValueError: try:
logger.error(u'couldn\'t open EbookFile {}'.format(ebf.id)) self.filesize = int(r.info().getheaders("Content-Length")[0])
return None if self.save:
self.filesize = self.filesize if self.filesize < 2147483647 else 2147483647 # largest safe positive integer
self.save()
ebf = EbookFile.objects.create(edition=self.edition, ebook=self, format=self.format)
ebf.file.save(path_for_file(ebf, None), ContentFile(r.read()))
ebf.file.close()
ebf.save()
return ebf
except IndexError:
# response has no Content-Length header probably a bad link
logging.error('Bad link error: {}'.format(self.url))
except IOError: except IOError:
logger.error(u'EbookFile {} does not exist'.format(ebf.id)) logger.error(u'could not open {}'.format(self.url))
return None else:
return ebf.file ebf = self.ebook_files.filter(asking=False).order_by('-created')[0]
return ebf
def set_provider(self): def set_provider(self):
self.provider = Ebook.infer_provider(self.url) self.provider = Ebook.infer_provider(self.url)
return self.provider return self.provider
@property
def version_label(self):
if self.version is None:
return ''
version_match = re.search(r'(.*)\.(\d+)$',self.version)
return version_match.group(1) if version_match else self.version
@property
def version_iter(self):
if self.version is None:
return 0
version_match = re.search(r'(.*)\.(\d+)$',self.version)
return int(version_match.group(2)) if version_match else 0
@property @property
def rights_badge(self): def rights_badge(self):
if self.rights is None: if self.rights is None:

View File

@ -134,12 +134,13 @@ def process_ebfs(campaign):
if campaign.use_add_ask: if campaign.use_add_ask:
campaign.add_ask_to_ebfs() campaign.add_ask_to_ebfs()
else: else:
campaign.work.make_ebooks_from_ebfs(add_ask=False) campaign.revert_asks()
campaign.work.remove_old_ebooks() campaign.make_mobis()
@task @task
def make_mobi(campaign): def make_mobi(ebookfile):
return campaign.make_mobi() return ebookfile.make_mobi()
@task @task
def refresh_acqs(): def refresh_acqs():

View File

@ -1011,6 +1011,11 @@ class EbookFileTests(TestCase):
dj_file = DjangoFile(temp_file) dj_file = DjangoFile(temp_file)
ebf = EbookFile( format='pdf', edition=e, file=dj_file) ebf = EbookFile( format='pdf', edition=e, file=dj_file)
ebf.save() ebf.save()
eb = Ebook( format='pdf', edition=e, url=ebf.file.url, provider='Unglue.it')
eb.save()
ebf.ebook = eb
ebf.save()
temp_file.close() temp_file.close()
finally: finally:
@ -1018,7 +1023,7 @@ class EbookFileTests(TestCase):
os.remove(temp.name) os.remove(temp.name)
#test the ask-appender #test the ask-appender
c.add_ask_to_ebfs() c.add_ask_to_ebfs()
asking_pdf = c.work.ebookfiles().filter(asking = True)[0].file.url asking_pdf = c.work.ebookfiles().filter(asking=True)[0].file.url
assert test_pdf(asking_pdf) assert test_pdf(asking_pdf)
#Now do the same with epub #Now do the same with epub
@ -1034,16 +1039,25 @@ class EbookFileTests(TestCase):
dj_file = DjangoFile(temp_file) dj_file = DjangoFile(temp_file)
ebf = EbookFile( format='epub', edition=e, file=dj_file) ebf = EbookFile( format='epub', edition=e, file=dj_file)
ebf.save() ebf.save()
eb = Ebook( format='epub', edition=e, url=ebf.file.url, provider='Unglue.it')
eb.save()
ebf.ebook = eb
ebf.save()
temp_file.close() temp_file.close()
ebf.make_mobi()
finally: finally:
# make sure we get rid of temp file # make sure we get rid of temp file
os.remove(temp.name) os.remove(temp.name)
#test the ask-appender #test the ask-appender
c.add_ask_to_ebfs() c.add_ask_to_ebfs()
self.assertTrue( c.work.ebookfiles().filter(asking = True, format='epub').count >0) self.assertTrue( c.work.ebookfiles().filter(asking = True, format='epub').count() > 0)
self.assertTrue( c.work.ebookfiles().filter(asking = True, format='mobi').count >0) self.assertTrue( c.work.ebookfiles().filter(asking = True, format='mobi').count() > 0)
self.assertTrue( c.work.ebookfiles().filter(asking = True, ebook__active=True).count() > 0)
self.assertTrue( c.work.ebookfiles().filter(asking = False, ebook__active=True).count() == 0)
#test the unasker
c.revert_asks()
self.assertTrue( c.work.ebookfiles().filter(asking = True, ebook__active=True).count() == 0)
self.assertTrue( c.work.ebookfiles().filter(asking = False, ebook__active=True).count() > 0)
class MobigenTests(TestCase): class MobigenTests(TestCase):
def test_convert_to_mobi(self): def test_convert_to_mobi(self):

View File

@ -4,7 +4,7 @@ from StringIO import StringIO
from regluit.core.facets import BaseFacet from regluit.core.facets import BaseFacet
from regluit.core.models import Work from regluit.core.models import Work, good_providers
from regluit.api.onix import onix_feed from regluit.api.onix import onix_feed
from .models import Target from .models import Target
@ -45,7 +45,7 @@ def get_target_facet(target, start=datetime(1900,1,1), new=False):
editions__ebooks__created__gt = start, editions__ebooks__created__gt = start,
identifiers__type="isbn", identifiers__type="isbn",
editions__ebooks__format__in = formats, editions__ebooks__format__in = formats,
editions__ebooks__provider__in = ('Internet Archive', 'Unglue.it', 'Github', 'OAPEN Library'), editions__ebooks__provider__in = good_providers,
).distinct().order_by('-featured') ).distinct().order_by('-featured')
model_filters = {"Ebook": format_filter, "Edition": edition_format_filter} model_filters = {"Ebook": format_filter, "Edition": edition_format_filter}

View File

@ -261,7 +261,8 @@ class EditionForm(forms.ModelForm):
} }
class EbookFileForm(forms.ModelForm): class EbookFileForm(forms.ModelForm):
file = forms.FileField(max_length=16777216) version = forms.CharField(max_length=512, required=False)
file = forms.FileField(max_length=16777216)
def __init__(self, campaign_type=BUY2UNGLUE, *args, **kwargs): def __init__(self, campaign_type=BUY2UNGLUE, *args, **kwargs):
super(EbookFileForm, self).__init__(*args, **kwargs) super(EbookFileForm, self).__init__(*args, **kwargs)
@ -305,7 +306,7 @@ class EbookFileForm(forms.ModelForm):
class Meta: class Meta:
model = EbookFile model = EbookFile
widgets = { 'edition': forms.HiddenInput} widgets = { 'edition': forms.HiddenInput}
exclude = { 'created', 'asking' } exclude = { 'created', 'asking', 'ebook' }
class EbookForm(forms.ModelForm): class EbookForm(forms.ModelForm):
class Meta: class Meta:

View File

@ -149,7 +149,7 @@ $j(document).ready(function() {
<a href="{% url 'download_ebook' ebook.id %}"> <a href="{% url 'download_ebook' ebook.id %}">
<img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a> <img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a>
<a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }}" title="{{ ebook.format }}" /></a> <a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }}" title="{{ ebook.format }}" /></a>
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> <a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %}
{% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %} {% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %}
@ -168,7 +168,7 @@ $j(document).ready(function() {
<a href="{% url 'download_ebook' ebook.id %}"> <a href="{% url 'download_ebook' ebook.id %}">
<img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a> <img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a>
<a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }} at {{ebook.provider}}" title="{{ ebook.format }} at {{ebook.provider}}" /></a> <a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }} at {{ebook.provider}}" title="{{ ebook.format }} at {{ebook.provider}}" /></a>
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }} at {{ ebook.provider }}</a> <a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }} {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %} at {{ ebook.provider }}</a>
{% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %} {% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %}
{% if not forloop.last %}<br /><br />{% endif %} {% if not forloop.last %}<br /><br />{% endif %}

View File

@ -19,8 +19,8 @@
{% if edition.note %} {% if edition.note %}
{{ edition.note }}.<br /> {{ edition.note }}.<br />
{% endif %} {% endif %}
{% if edition.ebooks.all %} {% if edition.downloads.count %}
{{ edition.ebooks.all.count }} ebooks<br /> {{ edition.downloads.count }} ebooks<br />
{% endif %} {% endif %}
{% if edition.publisher %} {% if edition.publisher %}
Publisher: <a href="{% url 'bypubname_list' edition.publisher_name.id %}">{{edition.publisher}}</a><br /> Publisher: <a href="{% url 'bypubname_list' edition.publisher_name.id %}">{{edition.publisher}}</a><br />

View File

@ -7,21 +7,32 @@
<h2>eBooks for this Edition</h2> <h2>eBooks for this Edition</h2>
{% for ebook in edition.ebooks.all %} {% for ebook in edition.ebooks.all %}
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> {{ebook.rights}} at {{ebook.provider}}. Downloaded {{ ebook.download_count }} times.<br /> <a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> {{ebook.rights}} at {{ebook.provider}}.
{% if ebook.version %} {{ ebook.version }}. {% endif %}
Downloaded {{ ebook.download_count }} times since {{ ebook.created }}<br />
{% endfor %} {% endfor %}
{% endif %} {% endif %}
<h2>Add an eBook for this Edition:</h2> <h2>Add an eBook for this Edition:</h2>
<span>If you know that this edition is available as a public domain or Creative Commons ebook, you can enter the link here and "unglue" it. Right now, we're only accepting URLs that point to Internet Archive, Wikisources, Wikibooks, Hathitrust, Project Gutenberg, raw files at Github, or Google Books.</span> <span>If you know that this edition is available as a public domain or Creative Commons ebook, you can enter the link here and "unglue" it. Right now, we're only accepting URLs that point to Internet Archive, Wikisources, Wikibooks, Hathitrust, Project Gutenberg, OApen, raw files at Github, or Google Books.</span>
<form method="POST" action="#add_ebook"> <form method="POST" action="#add_ebook">
{% csrf_token %}{{ edition.ebook_form.edition.errors }}{{ edition.ebook_form.edition }}{{ edition.ebook_form.user.errors }}{{ edition.ebook_form.user }}{{ edition.ebook_form.provider.errors }}{{ edition.ebook_form.provider }} {% csrf_token %}{{ edition.ebook_form.edition.errors }}{{ edition.ebook_form.edition }}{{ edition.ebook_form.user.errors }}{{ edition.ebook_form.user }}{{ edition.ebook_form.provider.errors }}{{ edition.ebook_form.provider }}
{{ edition.ebook_form.url.errors }}<span>URL: {{ edition.ebook_form.url }}</span><br /> {{ edition.ebook_form.url.errors }}<span>URL: {{ edition.ebook_form.url }}</span><br />
{{ edition.ebook_form.format.errors }}<span>File Format: {{ edition.ebook_form.format }}</span>&nbsp;&nbsp;&nbsp; {{ edition.ebook_form.format.errors }}<span>File Format: {{ edition.ebook_form.format }}</span>&nbsp;&nbsp;&nbsp;
{{ edition.ebook_form.rights.errors }}<span>License: {{ edition.ebook_form.rights }}</span><br /> {{ edition.ebook_form.rights.errors }}<span>License: {{ edition.ebook_form.rights }}</span><br />
{{ edition.ebook_form.version.errors }}<span>Version: {{ edition.ebook_form.version }} </span><br />
<input type="submit" name="add_ebook" value="add ebook" /> <input type="submit" name="add_ebook" value="add ebook" />
</form> </form>
<h3>Note on versions</h4>
<p>
Unglue.it's version strings have two components, a label and a iteration.
The iteration is denoted by a dot and a number at the end of version string, and is assumed to be 0 if not given explicitly.
Unglue.it will show the user just the label and will suppress display of all but the highest iteration for a given label.
so if the ebooks have versions "", ".1", "1.0.0", "1.0.2", "Open Access" and "Open Access.1", Unglue.it will display 3 ebooks labelled "", "1.0" and "Open Access".
If you want ebooks from two editions with the same format to display, give them different version labels.
</p>
</div> </div>
{% else %} {% else %}
<div> Adding ebook links is disabled for this work.</div> <div> Adding ebook links is disabled for this work.</div>

View File

@ -20,12 +20,20 @@
<b>LibraryThing ID</b>: {{ edition.librarything_id }}<br /> <b>LibraryThing ID</b>: {{ edition.librarything_id }}<br />
</div> </div>
{% if edition.ebooks.all.0 %}
<h2>Active eBooks for this Work</h2>
{% for ebook in edition.work.ebooks %}
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> {{ebook.rights}} at {{ebook.provider}}.
{% if ebook.version %} {{ ebook.version }}. {% endif %}
Downloaded {{ ebook.download_count }} times since {{ ebook.created }}<br />
{% endfor %}
{% endif %}
{% if edition.ebook_files.all %} {% if edition.ebook_files.all %}
<h2> Ebook Files for this Edition</h2> <h2> Ebook Files for this Edition</h2>
<ul> <ul>
{% for ebook_file in edition.ebook_files.all %} {% for ebook_file in edition.ebook_files.all %}
{% if ebook_file.file %} {% if ebook_file.file %}
<li>{% if ebook_file.active %}<span class="yikes">ACTIVE</span> {% endif %}<a href="{{ebook_file.file.url}}">{{ebook_file.file}}</a> created {{ebook_file.created}} {% if ebook_file.asking %}(This file has had the campaign 'ask' added.){% endif %}</li> <li>{% if ebook_file.active %}<span class="yikes">ACTIVE</span> {% elif ebook_file.ebook.active %} MIRROR {% endif %}<a href="{{ebook_file.file.url}}">{{ebook_file.file}}</a> created {{ebook_file.created}} {% if ebook_file.asking %}(This file has had the campaign 'ask' added.){% endif %}</li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
@ -66,15 +74,27 @@
For ePUB files, use the <a href=https://code.google.com/p/epubcheck/">epubcheck</a> tool to make sure everything will work properly.</p> For ePUB files, use the <a href=https://code.google.com/p/epubcheck/">epubcheck</a> tool to make sure everything will work properly.</p>
<form method="POST" action="#" enctype="multipart/form-data"> <form method="POST" action="#" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{form.as_p}} {{form.edition.errors}}{{form.edition}}
<p>{{form.format.errors}}Format: {{form.format}}</p>
{% if edition.work.versions %}
<p>There are named versions for this ebook. Specify the version you want to replace.<br /> {{form.version.errors}}Version: <select id="version">
<option value="{{ version }}" >---</option>
{% for version in edition.work.versions %}
<option value="{{ version }}" >{{ version }}</option>
{% endfor %}
</select></p>
{% else %}
<input type="hidden" value="" id="version" name="version"/>
{% endif %}
<p>{{form.file.errors}}Upload File: {{form.file}}</p>
<input type="submit" id="submit_file" value="submit ebook file"> <input type="submit" id="submit_file" value="submit ebook file">
</form> </form>
{% if edition.work %}
<h2>More Edition Management</h2> <h2>More Edition Management</h2>
<div><a href="{% url 'new_edition' edition.work.id edition.id %}">Edit this edition</a></div> <div><a href="{% url 'new_edition' edition.work.id edition.id %}">Edit this edition</a></div>
{% if edition.work.last_campaign %} {% if edition.work.last_campaign %}
<div><a href="{% url 'manage_campaign' edition.work.last_campaign.id %}">Manage this campaign</a></div> <div><a href="{% url 'manage_campaign' edition.work.last_campaign.id %}">Manage this campaign</a></div>
{% endif %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -136,14 +136,13 @@ Please fix the following before launching your campaign:
<div class="edition_form" id="edition_{{edition.id}}"> <div class="edition_form" id="edition_{{edition.id}}">
<p> Edition {{ edition.id }}: <input type="radio" {% ifequal edition.id form.edition.value %}checked="checked" {% endifequal %}id="id_edition_{{forloop.counter}}" value="{{edition.id}}" name="edition" /><label for="id_edition_{{forloop.counter}}"> Prefer this edition </label> <p> Edition {{ edition.id }}: <input type="radio" {% ifequal edition.id form.edition.value %}checked="checked" {% endifequal %}id="id_edition_{{forloop.counter}}" value="{{edition.id}}" name="edition" /><label for="id_edition_{{forloop.counter}}"> Prefer this edition </label>
<ul style="text-indent:1em"> <ul style="text-indent:1em">
<li style="text-indent:2.5em">There are {{ edition.downloads.all.count }} downloadable ebook for this edition</li>
<li style="text-indent:2.5em"><a href="{% url 'new_edition' edition.work.id edition.id %}"> Edit </a> this edition</li> <li style="text-indent:2.5em"><a href="{% url 'new_edition' edition.work.id edition.id %}"> Edit </a> this edition</li>
{% ifnotequal campaign.type 1 %} {% ifnotequal campaign.type 1 %}
{% if campaign.rh.can_sell %} {% if campaign.rh.can_sell %}
{% if edition.ebook_files.all.0 %} {% if edition.ebook_files.all.0 %}
<li style="text-indent:2.5em">You have uploaded ebook files for this edition. <a href="{% url 'edition_uploads' edition.id %}"> Upload another</a></li> <li style="text-indent:2.5em">You have uploaded ebook files for this edition. You can <a href="{% url 'edition_uploads' edition.id %}"> manage its ebooks or upload another</a></li>
{% else %} {% else %}
<li style="text-indent:2.5em">You can <a href="{% url 'edition_uploads' edition.id %}"> Load a file</a> for this edition.</li> <li style="text-indent:2.5em">You can <a href="{% url 'edition_uploads' edition.id %}"> Manage ebooks</a> for this edition.</li>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endifnotequal %} {% endifnotequal %}
@ -156,11 +155,11 @@ Please fix the following before launching your campaign:
<p>If you don't see an edition that matches what you want to release, you can <a href="{% url 'rh_edition' work.id '' %}">create a new edition</a>.</p> <p>If you don't see an edition that matches what you want to release, you can <a href="{% url 'rh_edition' work.id '' %}">create a new edition</a>.</p>
{% if campaign.work.ebookfiles.0 %} {% if campaign.work.ebookfiles.0 %}
<h3>Uploaded Files</h3> <h3>All ebook files for this book</h3>
{% endif %} {% endif %}
{% if campaign.work.epubfiles.0 %} {% if campaign.work.epubfiles.0 %}
{% for ebf in campaign.work.epubfiles %} {% for ebf in campaign.work.epubfiles %}
<p>{% if ebf.active %}<span class="yikes">ACTIVE</span> {% endif %}EPUB file: <a href="{{ebf.file.url}}">{{ebf.file}}</a> <br />created {{ebf.created}} for edition <a href="#edition_{{ebf.edition.id}}">{{ebf.edition.id}}</a> {% if ebf.asking %}(This file has had the campaign 'ask' added.){% endif %}<br />{% if ebf.active %}{% ifequal action 'mademobi' %}<span class="yikes">A MOBI file is being generated. </span> (Takes a minute or two.) {% else %}You can <a href="{% url 'makemobi' campaign.id %}">generate a MOBI file.</a> {% endifequal %}{% endif %}</p> <p>{% if ebf.active %}<span class="yikes">ACTIVE</span> {% elif ebf.ebook.active %} MIRROR {% endif %}EPUB file: <a href="{{ebf.file.url}}">{{ebf.file}}</a> <br />created {{ebf.created}} for edition <a href="#edition_{{ebf.edition.id}}">{{ebf.edition.id}}</a> {% if ebf.asking %}(This file has had the campaign 'ask' added.){% endif %}<br />{% if ebf.active %}{% ifequal action 'mademobi' %}<span class="yikes">A MOBI file is being generated. </span> (Takes a minute or two.) {% else %}You can <a href="{% url 'makemobi' campaign.id ebf.id %}">generate a MOBI file.</a> {% endifequal %}{% endif %}</p>
{% endfor %} {% endfor %}
{% if campaign.work.test_acqs.0 %} {% if campaign.work.test_acqs.0 %}
<ul> <ul>

View File

@ -431,7 +431,7 @@
This work has been downloaded {{ work.download_count }} times via unglue.it ebook links. This work has been downloaded {{ work.download_count }} times via unglue.it ebook links.
<ol> <ol>
{% for ebook in work.ebooks.all %} {% for ebook in work.ebooks.all %}
<li>{{ ebook.download_count }} - {{ ebook.format }} ({{ ebook.rights }}) at {{ ebook.provider }}</li> <li>{{ ebook.download_count }} - {{ ebook.format }} {% if ebook.version %} {{ ebook.version }} {% endif %}({{ ebook.rights }}) at {{ ebook.provider }}. </li>
{% endfor %} {% endfor %}
</ol> </ol>
</div> </div>

View File

@ -27,7 +27,7 @@ urlpatterns = [
url(r"^rightsholders/$", views.rh_tools, name="rightsholders"), url(r"^rightsholders/$", views.rh_tools, name="rightsholders"),
url(r"^rightsholders/campaign/(?P<id>\d+)/$", views.manage_campaign, name="manage_campaign"), url(r"^rightsholders/campaign/(?P<id>\d+)/$", views.manage_campaign, name="manage_campaign"),
url(r"^rightsholders/campaign/(?P<id>\d+)/results/$", views.manage_campaign, {'action': 'results'}, name="campaign_results"), url(r"^rightsholders/campaign/(?P<id>\d+)/results/$", views.manage_campaign, {'action': 'results'}, name="campaign_results"),
url(r"^rightsholders/campaign/(?P<id>\d+)/makemobi/$", views.manage_campaign, {'action': 'makemobi'}, name="makemobi"), url(r"^rightsholders/campaign/(?P<id>\d+)/(?P<ebf>\d+)/makemobi/$", views.manage_campaign, {'action': 'makemobi'}, name="makemobi"),
url(r"^rightsholders/campaign/(?P<id>\d+)/mademobi/$", views.manage_campaign, {'action': 'mademobi'}, name="mademobi"), url(r"^rightsholders/campaign/(?P<id>\d+)/mademobi/$", views.manage_campaign, {'action': 'mademobi'}, name="mademobi"),
url(r"^rightsholders/edition/(?P<work_id>\d*)/(?P<edition_id>\d*)$", views.new_edition, {'by': 'rh'}, name="rh_edition"), url(r"^rightsholders/edition/(?P<work_id>\d*)/(?P<edition_id>\d*)$", views.new_edition, {'by': 'rh'}, name="rh_edition"),
url(r"^rightsholders/edition/(?P<edition_id>\d*)/upload/$", views.edition_uploads, name="edition_uploads"), url(r"^rightsholders/edition/(?P<edition_id>\d*)/upload/$", views.edition_uploads, name="edition_uploads"),

View File

@ -428,9 +428,8 @@ def edition_uploads(request, edition_id):
except models.Edition.DoesNotExist: except models.Edition.DoesNotExist:
raise Http404 raise Http404
campaign_type = edition.work.last_campaign().type campaign_type = edition.work.last_campaign().type
if not request.user.is_staff : if not user_can_edit_work(request.user, edition.work):
if not request.user in edition.work.last_campaign().managers.all(): return render(request, "admins_only.html")
return render(request, "admins_only.html")
if request.method == 'POST' : if request.method == 'POST' :
form = EbookFileForm(data=request.POST, files=request.FILES, campaign_type=campaign_type) form = EbookFileForm(data=request.POST, files=request.FILES, campaign_type=campaign_type)
if form.is_valid() : if form.is_valid() :
@ -462,6 +461,19 @@ def edition_uploads(request, edition_id):
form.instance.delete() form.instance.delete()
else: else:
tasks.process_ebfs.delay(edition.work.last_campaign()) tasks.process_ebfs.delay(edition.work.last_campaign())
if form.instance.id:
new_ebook = models.Ebook.objects.create(
edition=edition,
format=form.instance.format,
url=form.instance.file.url,
rights=edition.work.last_campaign().license,
version=form.cleaned_data['version'],
active=False,
provider="Unglue.it",
)
form.instance.ebook = new_ebook
form.instance.save()
else: else:
context['upload_error'] = form.errors context['upload_error'] = form.errors
form = EbookFileForm(initial={'edition':edition, 'format':'epub'}, campaign_type=campaign_type) form = EbookFileForm(initial={'edition':edition, 'format':'epub'}, campaign_type=campaign_type)
@ -654,19 +666,10 @@ def manage_ebooks(request, edition_id, by=None):
work = edition.work work = edition.work
else: else:
raise Http404 raise Http404
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 # if the work and edition are set, we save the edition and set the work
alert = '' alert = ''
admin = False admin = user_can_edit_work(request.user, work)
if request.user.is_staff :
admin = True
elif work and work.last_campaign():
if request.user in work.last_campaign().managers.all():
admin = True
elif work == None and request.user.rights_holder.count():
admin = True
if request.method == 'POST' : if request.method == 'POST' :
edition.new_authors = zip(request.POST.getlist('new_author'), request.POST.getlist('new_author_relation')) edition.new_authors = zip(request.POST.getlist('new_author'), request.POST.getlist('new_author_relation'))
edition.new_subjects = request.POST.getlist('new_subject') edition.new_subjects = request.POST.getlist('new_subject')
@ -680,6 +683,7 @@ def manage_ebooks(request, edition_id, by=None):
edition.ebook_form = EbookForm(data = request.POST, prefix = 'ebook_%d'%edition.id) edition.ebook_form = EbookForm(data = request.POST, prefix = 'ebook_%d'%edition.id)
if edition.ebook_form.is_valid(): if edition.ebook_form.is_valid():
edition.ebook_form.save() edition.ebook_form.save()
edition.work.remove_old_ebooks()
alert = 'Thanks for adding an ebook to unglue.it!' alert = 'Thanks for adding an ebook to unglue.it!'
else: else:
alert = 'your submitted ebook had errors' alert = 'your submitted ebook had errors'
@ -700,7 +704,7 @@ def campaign_results(request, campaign):
}) })
def manage_campaign(request, id, action='manage'): def manage_campaign(request, id, ebf=None, action='manage'):
campaign = get_object_or_404(models.Campaign, id=id) campaign = get_object_or_404(models.Campaign, id=id)
campaign.not_manager = False campaign.not_manager = False
campaign.problems = [] campaign.problems = []
@ -782,7 +786,8 @@ def manage_campaign(request, id, action='manage'):
activetab = '#2' activetab = '#2'
else: else:
if action == 'makemobi': if action == 'makemobi':
tasks.make_mobi.delay(campaign) ebookfile = get_object_or_404(models.EbookFile, id=ebf)
tasks.make_mobi.delay(ebookfile)
return HttpResponseRedirect(reverse('mademobi', args=[campaign.id])) return HttpResponseRedirect(reverse('mademobi', args=[campaign.id]))
elif action == 'mademobi': elif action == 'mademobi':
alerts.append('A MOBI file is being generated') alerts.append('A MOBI file is being generated')

File diff suppressed because one or more lines are too long

View File

@ -63,10 +63,6 @@
width: 660px !important; width: 660px !important;
} }
a {
color:#3d4e53;
}
#js-search { #js-search {
margin: 0 15px 0 15px !important; margin: 0 15px 0 15px !important;
} }