Merge pull request #635 from Gluejar/versions-relations-ednotes

Versions relations ednotes [merge into master not dj18]
pull/1/head
Raymond Yee 2016-09-30 11:08:53 -07:00 committed by GitHub
commit 599ac8dc69
36 changed files with 4259 additions and 3484 deletions

View File

@ -1,5 +1,6 @@
import datetime
import pytz
import re
from lxml import etree
from regluit.core import models
from regluit.core.cc import ccinfo
@ -134,6 +135,19 @@ def product(edition, facet=None):
subj_node.append(text_node("SubjectSchemeIdentifier", "20"))
subj_node.append(text_node("SubjectHeadingText", subject.name))
# audience range composite
if work.age_level:
range_match = re.search(r'(\d?\d?)-(\d?\d?)', work.age_level)
if range_match:
audience_range_node = etree.SubElement(descriptive_node, "AudienceRange")
audience_range_node.append(text_node("AudienceRangeQualifier", "17")) #Interest age, years
if range_match.group(1):
audience_range_node.append(text_node("AudienceRangePrecision", "03")) #from
audience_range_node.append(text_node("AudienceRangeValue", range_match.group(1)))
if range_match.group(2):
audience_range_node.append(text_node("AudienceRangePrecision", "04")) #from
audience_range_node.append(text_node("AudienceRangeValue", range_match.group(2)))
# Collateral Detail Block
coll_node = etree.SubElement(product_node, "CollateralDetail")
desc_node = etree.SubElement(coll_node, "TextContent")

View File

@ -84,25 +84,29 @@ def work_node(work, facet=None):
node.append(text_node('updated', work.first_ebook().created.isoformat()))
# links for all ebooks
ebooks=facet.filter_model("Ebook",work.ebooks()) if facet else work.ebooks()
ebooks = facet.filter_model("Ebook",work.ebooks()) if facet else work.ebooks()
versions = set()
for ebook in ebooks:
link_node = etree.Element("link")
if not ebook.version_label in versions:
versions.add(ebook.version_label)
link_node = etree.Element("link")
# ebook.download_url is an absolute URL with the protocol, domain, and path baked in
link_rel = "http://opds-spec.org/acquisition/open-access"
link_node.attrib.update({"href":add_query_component(ebook.download_url, "feed=opds"),
"rel":link_rel,
"{http://purl.org/dc/terms/}rights": str(ebook.rights)})
if ebook.is_direct():
link_node.attrib["type"] = FORMAT_TO_MIMETYPE.get(ebook.format, "")
else:
""" indirect acquisition, i.e. google books """
link_node.attrib["type"] = "text/html"
indirect = etree.Element("{http://opds-spec.org/}indirectAcquisition",)
indirect.attrib["type"] = FORMAT_TO_MIMETYPE.get(ebook.format, "")
link_node.append(indirect)
node.append(link_node)
# ebook.download_url is an absolute URL with the protocol, domain, and path baked in
link_rel = "http://opds-spec.org/acquisition/open-access"
link_node.attrib.update({"href":add_query_component(ebook.download_url, "feed=opds"),
"rel":link_rel,
"{http://purl.org/dc/terms/}rights": str(ebook.rights)})
if ebook.is_direct():
link_node.attrib["type"] = FORMAT_TO_MIMETYPE.get(ebook.format, "")
else:
""" indirect acquisition, i.e. google books """
link_node.attrib["type"] = "text/html"
indirect = etree.Element("{http://opds-spec.org/}indirectAcquisition",)
indirect.attrib["type"] = FORMAT_TO_MIMETYPE.get(ebook.format, "")
link_node.append(indirect)
if ebook.version_label:
link_node.attrib.update({"{http://schema.org/}version": ebook.version_label})
node.append(link_node)
# get the cover -- assume jpg?
@ -163,6 +167,16 @@ def work_node(work, facet=None):
# caused by control chars in subject.name
logger.warning('Deleting subject: %s' % subject.name)
subject.delete()
# age level
# <category term="15-18" scheme="http://schema.org/typicalAgeRange" label="Teen - Grade 10-12, Age 15-18"/>
if work.age_level:
category_node = etree.Element("category")
category_node.attrib["scheme"] = 'http://schema.org/typicalAgeRange'
category_node.attrib["term"] = work.age_level
category_node.attrib["label"] = work.get_age_level_display()
node.append(category_node)
# rating
rating_node = etree.Element("{http://schema.org/}Rating")
@ -227,6 +241,9 @@ def opds_feed_for_work(work_id):
works=models.Work.objects.filter(id=work_id)
except models.Work.DoesNotExist:
works=models.Work.objects.none()
except ValueError:
# not a valid work_id
works=models.Work.objects.none()
self.works=works
self.title='Unglue.it work #%s' % work_id
self.feed_path=''

View File

@ -74,7 +74,8 @@ class WorkAdmin(ModelAdmin):
ordering = ('title',)
list_display = ('title', 'created')
date_hierarchy = 'created'
fields = ('title', 'description', 'language', 'featured')
fields = ('title', 'description', 'language', 'featured', 'publication_range',
'age_level', 'openlibrary_lookup')
class AuthorAdmin(ModelAdmin):
search_fields = ('name',)
@ -105,9 +106,9 @@ class EditionAdminForm(forms.ModelForm):
)
publisher_name = AutoCompleteSelectField(
PublisherNameLookup,
label='Name',
label='Publisher Name',
widget=AutoCompleteSelectWidget(PublisherNameLookup),
required=True,
required=False,
)
class Meta(object):
model = models.Edition
@ -174,24 +175,76 @@ class CeleryTaskAdmin(ModelAdmin):
class PressAdmin(ModelAdmin):
list_display = ('title', 'source', 'date')
ordering = ('-date',)
class WorkRelationAdminForm(forms.ModelForm):
to_work = AutoCompleteSelectField(
WorkLookup,
label='To Work',
widget=AutoCompleteSelectWidget(WorkLookup),
required=True,
)
from_work = AutoCompleteSelectField(
WorkLookup,
label='From Work',
widget=AutoCompleteSelectWidget(WorkLookup),
required=True,
)
class Meta(object):
model = models.WorkRelation
exclude = ()
class WorkRelationAdmin(ModelAdmin):
form = WorkRelationAdminForm
list_display = ('to_work', 'relation', 'from_work')
class IdentifierAdminForm(forms.ModelForm):
work = AutoCompleteSelectField(
WorkLookup,
label='Work',
widget=AutoCompleteSelectWidget(WorkLookup, attrs={'size':60}),
required=False,
)
edition = AutoCompleteSelectField(
EditionLookup,
label='Edition',
widget=AutoCompleteSelectWidget(EditionLookup, attrs={'size':60}),
required=True,
)
class Meta(object):
model = models.Identifier
exclude = ()
class IdentifierAdmin(ModelAdmin):
form = IdentifierAdminForm
list_display = ('type', 'value')
search_fields = ('type', 'value')
class OfferAdmin(ModelAdmin):
list_display = ('work', 'license', 'price', 'active')
search_fields = ('work__title',)
readonly_fields = ('work',)
admin_site.register(models.Acq, AcqAdmin)
admin_site.register(models.Work, WorkAdmin)
admin_site.register(models.Claim, ClaimAdmin)
admin_site.register(models.RightsHolder, RightsHolderAdmin)
admin_site.register(models.Premium, PremiumAdmin)
admin_site.register(models.Campaign, CampaignAdmin)
admin_site.register(models.Author, AuthorAdmin)
admin_site.register(models.Badge, ModelAdmin)
admin_site.register(models.Campaign, CampaignAdmin)
admin_site.register(models.CeleryTask, CeleryTaskAdmin)
admin_site.register(models.Claim, ClaimAdmin)
admin_site.register(models.Ebook, EbookAdmin)
admin_site.register(models.Edition, EditionAdmin)
admin_site.register(models.Gift, GiftAdmin)
admin_site.register(models.Identifier, IdentifierAdmin)
admin_site.register(models.Offer, OfferAdmin)
admin_site.register(models.Premium, PremiumAdmin)
admin_site.register(models.Press, PressAdmin)
admin_site.register(models.Publisher, PublisherAdmin)
admin_site.register(models.PublisherName, PublisherNameAdmin)
admin_site.register(models.Subject, SubjectAdmin)
admin_site.register(models.Edition, EditionAdmin)
admin_site.register(models.Ebook, EbookAdmin)
admin_site.register(models.Wishlist, WishlistAdmin)
admin_site.register(models.UserProfile, UserProfileAdmin)
admin_site.register(models.CeleryTask, CeleryTaskAdmin)
admin_site.register(models.Press, PressAdmin)
admin_site.register(models.Gift, GiftAdmin)
admin_site.register(models.Relation, RelationAdmin)
admin_site.register(models.RightsHolder, RightsHolderAdmin)
admin_site.register(models.Subject, SubjectAdmin)
admin_site.register(models.UserProfile, UserProfileAdmin)
admin_site.register(models.Wishlist, WishlistAdmin)
admin_site.register(models.Work, WorkAdmin)
admin_site.register(models.WorkRelation, WorkRelationAdmin)

View File

@ -449,6 +449,7 @@ def add_related(isbn):
for w in works_to_merge:
logger.debug("merge_works path 2 %s %s", lang_edition.work.id, w.id )
merge_works(lang_edition.work, w)
models.WorkRelation.objects.get_or_create(to_work=lang_edition.work, from_work=work, relation='translation')
return new_editions
@ -901,8 +902,8 @@ def load_from_yaml(yaml_url, test_mode=False):
rights = cc.match_license(metadata.rights),
format = ebook_format,
edition = edition,
# version = metadata._version
)
ebook.set_version(metadata._version)
return work.id

View File

@ -106,7 +106,7 @@ def description(license):
else:
return ''
class ccinfo():
class ccinfo(object):
def __init__(self, license):
value=license_value(license)
self.license=value if value else license

View File

@ -3,7 +3,7 @@ from selectable.registry import registry
from django.contrib.auth.models import User
from django.db.models import Count
from regluit.core.models import Work, PublisherName, Edition, Subject
from regluit.core.models import Work, PublisherName, Edition, Subject, EditionNote
class OwnerLookup(ModelLookup):
model = User
@ -54,8 +54,17 @@ class SubjectLookup(ModelLookup):
def get_query(self, request, term):
return super(SubjectLookup, self).get_query( request, term).annotate(Count('works')).order_by('-works__count')
class EditionNoteLookup(ModelLookup):
model = EditionNote
search_fields = ('note__icontains',)
def create_item(self, value):
new_note, created = EditionNote.objects.get_or_create(note=value)
new_note.save()
return new_note
registry.register(OwnerLookup)
registry.register(WorkLookup)
registry.register(PublisherNameLookup)
registry.register(EditionLookup)
registry.register(SubjectLookup)
registry.register(SubjectLookup)
registry.register(EditionNoteLookup)

View File

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0002_auto_20160722_1716'),
]
operations = [
migrations.CreateModel(
name='EditionNote',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('note', models.CharField(max_length=64, unique=True, null=True, blank=True)),
],
),
migrations.CreateModel(
name='WorkRelation',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('relation', models.CharField(max_length=15, choices=[(b'translation', b'translation'), (b'revision', b'revision'), (b'sequel', b'sequel'), (b'compilation', b'compilation')])),
],
),
migrations.AddField(
model_name='ebook',
name='version',
field=models.CharField(max_length=255, null=True),
),
migrations.AddField(
model_name='work',
name='age_level',
field=models.CharField(default=b'', max_length=5, choices=[(b'', b'No Rating'), (b'5-6', b"Children's - Kindergarten, Age 5-6"), (b'6-7', b"Children's - Grade 1-2, Age 6-7"), (b'7-8', b"Children's - Grade 2-3, Age 7-8"), (b'8-9', b"Children's - Grade 3-4, Age 8-9"), (b'9-11', b"Children's - Grade 4-6, Age 9-11"), (b'12-14', b'Teen - Grade 7-9, Age 12-14'), (b'15-18', b'Teen - Grade 10-12, Age 15-18'), (b'18-', b'Adult/Advanced Reader')]),
),
migrations.AddField(
model_name='workrelation',
name='from_work',
field=models.ForeignKey(related_name='works_related_from', to='core.Work'),
),
migrations.AddField(
model_name='workrelation',
name='to_work',
field=models.ForeignKey(related_name='works_related_to', to='core.Work'),
),
migrations.AddField(
model_name='edition',
name='note',
field=models.ForeignKey(to='core.EditionNote', null=True),
),
migrations.AddField(
model_name='work',
name='related',
field=models.ManyToManyField(related_name='reverse_related', null=True, through='core.WorkRelation', to='core.Work'),
),
]

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models, transaction
from django.db.utils import IntegrityError
class Migration(migrations.Migration):
def url_to_doi(apps, schema_editor):
Indentifier = apps.get_model('core', 'Identifier')
for doi in Indentifier.objects.filter(type='http', value__icontains='dx.doi.org'):
if doi.value.startswith('http://dx.doi.org/10.'):
doi.value = doi.value[18:]
elif doi.value.startswith('https://dx.doi.org/10.'):
doi.value = doi.value[19:]
else:
continue
doi.type = 'doi'
try:
with transaction.atomic():
doi.save()
except IntegrityError:
continue
def doi_to_url(apps, schema_editor):
Indentifier = apps.get_model('core', 'Identifier')
for doi in Indentifier.objects.filter(type='doi'):
doi.value = 'https://dx.doi.org/{}'.format(doi.value)
doi.type = 'http'
try:
with transaction.atomic():
doi.save()
except IntegrityError:
continue
dependencies = [
('core', '0003_auto_20160816_1645'),
]
operations = [
migrations.RunPython(url_to_doi, reverse_code=doi_to_url, hints={'core': 'Identifier'}),
]

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,53 @@
# -*- 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):
"""
Now that EbookFile has ebook foreign key, this migration populates that key
"""
EbookFile = apps.get_model('core', 'EbookFile')
Ebook = apps.get_model('core', 'Ebook')
for ebf in EbookFile.objects.all():
# Connect each ebf (ebookfile) based on common edition (excluding the unglue.it provider) or URL.
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 the ebookfile is still not connected to an ebook...
if not ebf.ebook:
# and the edition is associated with a THANKS campaign
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()
# Buy to unglue campaign
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

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0006_auto_20160818_1809'),
]
operations = [
migrations.RemoveField(
model_name='ebook',
name='version',
),
migrations.AddField(
model_name='ebook',
name='version_iter',
field=models.PositiveIntegerField(default=0),
),
migrations.AddField(
model_name='ebook',
name='version_label',
field=models.CharField(default=b'', max_length=255, blank=True),
),
migrations.AlterField(
model_name='edition',
name='note',
field=models.ForeignKey(blank=True, to='core.EditionNote', null=True),
),
migrations.AlterField(
model_name='edition',
name='publisher_name',
field=models.ForeignKey(related_name='editions', blank=True, to='core.PublisherName', null=True),
),
migrations.AlterField(
model_name='userprofile',
name='badges',
field=models.ManyToManyField(related_name='holders', to='core.Badge', blank=True),
),
migrations.AlterField(
model_name='userprofile',
name='facebook_id',
field=models.BigIntegerField(null=True, blank=True),
),
migrations.AlterField(
model_name='work',
name='age_level',
field=models.CharField(default=b'', max_length=5, blank=True, choices=[(b'', b'No Rating'), (b'5-6', b"Children's - Kindergarten, Age 5-6"), (b'6-7', b"Children's - Grade 1-2, Age 6-7"), (b'7-8', b"Children's - Grade 2-3, Age 7-8"), (b'8-9', b"Children's - Grade 3-4, Age 8-9"), (b'9-11', b"Children's - Grade 4-6, Age 9-11"), (b'12-14', b'Teen - Grade 7-9, Age 12-14'), (b'15-18', b'Teen - Grade 10-12, Age 15-18'), (b'18-', b'Adult/Advanced Reader')]),
),
migrations.AlterField(
model_name='work',
name='openlibrary_lookup',
field=models.DateTimeField(null=True, blank=True),
),
migrations.AlterField(
model_name='work',
name='publication_range',
field=models.CharField(max_length=50, null=True, blank=True),
),
]

File diff suppressed because it is too large Load Diff

1391
core/models/__init__.py Executable file

File diff suppressed because it is too large Load Diff

1191
core/models/bibmodels.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,30 @@
(REWARDS, BUY2UNGLUE, THANKS) = (1, 2, 3)
(INDIVIDUAL, LIBRARY, BORROWED, RESERVE, THANKED) = (1, 2, 3, 4, 5)
TESTING = 0
OFFER_CHOICES = ((INDIVIDUAL,'Individual license'),(LIBRARY,'Library License'))
ACQ_CHOICES = ((INDIVIDUAL,'Individual license'),(LIBRARY,'Library License'),(BORROWED,'Borrowed from Library'), (TESTING,'Just for Testing'), (RESERVE,'On Reserve'),(THANKED,'Already Thanked'),)
AGE_LEVEL_CHOICES = (
('', 'No Rating'),
('5-6', 'Children\'s - Kindergarten, Age 5-6'),
('6-7', 'Children\'s - Grade 1-2, Age 6-7'),
('7-8', 'Children\'s - Grade 2-3, Age 7-8'),
('8-9', 'Children\'s - Grade 3-4, Age 8-9'),
('9-11', 'Children\'s - Grade 4-6, Age 9-11'),
('12-14', 'Teen - Grade 7-9, Age 12-14'),
('15-18', 'Teen - Grade 10-12, Age 15-18'),
('18-', 'Adult/Advanced Reader')
)
TEXT_RELATION_CHOICES = (
('translation', 'translation'),
('revision', 'revision'),
('sequel', 'sequel'),
('compilation', 'compilation')
)

View File

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

View File

@ -192,6 +192,16 @@ class BookLoaderTests(TestCase):
self.assertTrue(models.Edition.objects.count() > 15)
self.assertEqual(models.Work.objects.filter(language=lang).count(), 1)
self.assertTrue(edition.work.editions.count() > 9)
self.assertTrue(edition.work.reverse_related.count() > 0)
# is edition.work found among the from_work of all the to_work of edition.work?
back_point = True
to_works = [wr.to_work for wr in edition.work.works_related_from.all()]
for to_work in to_works:
if edition.work.id not in [wr1.from_work.id for wr1 in to_work.works_related_to.all()]:
back_point = False
break
self.assertTrue(back_point)
def test_populate_edition(self):
@ -1009,6 +1019,11 @@ class EbookFileTests(TestCase):
dj_file = DjangoFile(temp_file)
ebf = EbookFile( format='pdf', edition=e, file=dj_file)
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()
finally:
@ -1016,7 +1031,7 @@ class EbookFileTests(TestCase):
os.remove(temp.name)
#test the ask-appender
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)
#Now do the same with epub
@ -1032,16 +1047,25 @@ class EbookFileTests(TestCase):
dj_file = DjangoFile(temp_file)
ebf = EbookFile( format='epub', edition=e, file=dj_file)
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()
ebf.make_mobi()
finally:
# make sure we get rid of temp file
os.remove(temp.name)
#test the ask-appender
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='mobi').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, 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):
def test_convert_to_mobi(self):

View File

@ -7,6 +7,9 @@
# ssh ubuntu@please.unglueit.com "/opt/regluit/deploy/update-regluit"
cd /opt/regluit
find . -name "*.pyc" -delete
find . -type d -empty -delete
sudo -u ubuntu /usr/bin/git pull
source ENV/bin/activate
pip install --upgrade -r requirements_versioned.pip

View File

@ -1,6 +1,9 @@
#!/bin/bash
cd /opt/regluit
find . -name "*.pyc" -delete
find . -type d -empty -delete
sudo -u ubuntu /usr/bin/git pull origin production
source ENV/bin/activate
pip install --upgrade -r requirements_versioned.pip

View File

@ -7,6 +7,9 @@
# ssh ubuntu@please.unglueit.com "/opt/regluit/deploy/update-regluit"
cd /opt/regluit
find . -name "*.pyc" -delete
find . -type d -empty -delete
sudo -u ubuntu /usr/bin/git pull
source ENV/bin/activate
#pip install -r requirements.pip

View File

@ -4,7 +4,7 @@ from StringIO import StringIO
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 .models import Target
@ -45,7 +45,7 @@ def get_target_facet(target, start=datetime(1900,1,1), new=False):
editions__ebooks__created__gt = start,
identifiers__type="isbn",
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')
model_filters = {"Ebook": format_filter, "Edition": edition_format_filter}

View File

@ -1,22 +1,17 @@
"""
external library imports
"""
#external library imports
import logging
import re
import zipfile
from datetime import timedelta, datetime, date
from datetime import timedelta, date
from decimal import Decimal as D
"""
django imports
"""
#django imports
from django import forms
from django.conf import settings
from django.conf.global_settings import LANGUAGES
from django.contrib.auth.models import User
from django.core.validators import validate_email
from django.db import models
from django.forms.widgets import RadioSelect
from django.forms.extras.widgets import SelectDateWidget
from django.utils.translation import ugettext_lazy as _
@ -32,10 +27,8 @@ from selectable.forms import (
from PyPDF2 import PdfFileReader
#regluit imports
"""
regluit imports
"""
from regluit.core.models import (
UserProfile,
RightsHolder,
@ -51,23 +44,28 @@ from regluit.core.models import (
Work,
Press,
Libpref,
Subject,
TWITTER,
FACEBOOK,
GRAVATAR,
UNGLUEITAR
)
from regluit.libraryauth.models import Library
from regluit.core.parameters import LIBRARY, REWARDS, BUY2UNGLUE, THANKS
from regluit.core.parameters import (
LIBRARY,
REWARDS,
BUY2UNGLUE,
THANKS,
AGE_LEVEL_CHOICES,
TEXT_RELATION_CHOICES,
)
from regluit.core.lookups import (
OwnerLookup,
WorkLookup,
PublisherNameLookup,
EditionLookup,
SubjectLookup,
EditionNoteLookup,
)
from regluit.utils.localdatetime import now
from regluit.utils.fields import EpubFileField, ISBNField
from regluit.utils.fields import ISBNField
from regluit.mobi import Mobi
from regluit.pyepub import EPUB
from regluit.bisac.models import BisacHeading
@ -90,15 +88,15 @@ class SurveyForm(forms.Form):
label = forms.CharField(max_length=64, required=True)
survey = forms.ModelChoiceField(Questionnaire.objects.all(), widget=RadioSelect(), empty_label=None, required = True,)
isbn = ISBNField(
label=_("ISBN"),
max_length=17,
label=_("ISBN"),
max_length=17,
required = False,
help_text = _("13 digits, no dash."),
error_messages = {
'invalid': _("This must be a valid ISBN-13."),
}
)
def clean_isbn(self):
isbn = self.cleaned_data['isbn']
if not isbn:
@ -115,24 +113,36 @@ class EditionForm(forms.ModelForm):
add_author = forms.CharField(max_length=500, required=False)
add_author_relation = forms.ChoiceField(choices=CREATOR_RELATIONS, initial=('aut', 'Author'))
add_subject = AutoCompleteSelectField(
SubjectLookup,
widget=AutoCompleteSelectWidget(SubjectLookup,allow_new=True),
label='Keyword',
required =False
SubjectLookup,
widget=AutoCompleteSelectWidget(SubjectLookup, allow_new=True),
label='Keyword',
required=False,
)
add_related_work = AutoCompleteSelectField(
WorkLookup,
widget=AutoCompleteSelectWidget(WorkLookup, allow_new=False, attrs={'size': 40}),
label='Related Work',
required=False,
)
add_work_relation = forms.ChoiceField(
choices=TEXT_RELATION_CHOICES,
initial=('translation', 'translation'),
required=False,
)
bisac = forms.ModelChoiceField( bisac_headings, required=False )
publisher_name = AutoCompleteSelectField(
PublisherNameLookup,
label='Publisher Name',
widget=AutoCompleteSelectWidget(PublisherNameLookup,allow_new=True),
required=False,
allow_new=True,
)
PublisherNameLookup,
label='Publisher Name',
widget=AutoCompleteSelectWidget(PublisherNameLookup,allow_new=True),
required=False,
allow_new=True,
)
isbn = ISBNField(
label=_("ISBN"),
max_length=17,
label=_("ISBN"),
max_length=17,
required = False,
help_text = _("13 digits, no dash."),
error_messages = {
@ -140,8 +150,8 @@ class EditionForm(forms.ModelForm):
}
)
goog = forms.RegexField(
label=_("Google Books ID"),
max_length=12,
label=_("Google Books ID"),
max_length=12,
regex=r'^([a-zA-Z0-9\-_]{12}|delete)$',
required = False,
help_text = _("12 alphanumeric characters, dash or underscore, case sensitive."),
@ -150,8 +160,8 @@ class EditionForm(forms.ModelForm):
}
)
gdrd = forms.RegexField(
label=_("GoodReads ID"),
max_length=8,
label=_("GoodReads ID"),
max_length=8,
regex=r'^(\d+|delete)$',
required = False,
help_text = _("1-8 digits."),
@ -160,8 +170,8 @@ class EditionForm(forms.ModelForm):
}
)
thng = forms.RegexField(
label=_("LibraryThing ID"),
max_length=8,
label=_("LibraryThing ID"),
max_length=8,
regex=r'(^\d+|delete)$',
required = False,
help_text = _("1-8 digits."),
@ -170,7 +180,7 @@ class EditionForm(forms.ModelForm):
}
)
oclc = forms.RegexField(
label=_("OCLCnum"),
label=_("OCLCnum"),
regex=r'^(\d\d\d\d\d\d\d\d\d*|delete)$',
required = False,
help_text = _("8 or more digits."),
@ -182,132 +192,191 @@ class EditionForm(forms.ModelForm):
label=_("HTTP URL"),
# https://mathiasbynens.be/demo/url-regex
regex=re.compile(r"(https?|ftp)://(-\.)?([^\s/?\.#]+\.?)+(/[^\s]*)?$",
flags=re.IGNORECASE|re.S ),
flags=re.IGNORECASE|re.S ),
required = False,
help_text = _("no spaces of funny stuff."),
error_messages = {
'invalid': _("This value must be a valid http(s) URL."),
}
)
doi = forms.RegexField(
label=_("DOI"),
regex=r'^(https?://dx\.doi\.org/)?(10.\d\d\d\d/\w+|delete)$',
required = False,
help_text = _("starts with '10.' or 'http://dx.doi.org'"),
error_messages = {
'invalid': _("This value must be a valid DOI."),
}
)
language = forms.ChoiceField(choices=LANGUAGES)
age_level = forms.ChoiceField(choices=AGE_LEVEL_CHOICES, required=False)
description = forms.CharField( required=False, widget=CKEditorWidget())
coverfile = forms.ImageField(required=False)
note = AutoCompleteSelectField(
EditionNoteLookup,
widget=AutoCompleteSelectWidget(EditionNoteLookup, allow_new=True),
label='Edition Note',
required=False,
allow_new=True,
)
def __init__(self, *args, **kwargs):
super(EditionForm, self).__init__(*args, **kwargs)
self.relators = []
if self.instance:
for relator in self.instance.relators.all():
select = forms.Select(choices=CREATOR_RELATIONS).render('change_relator_%s' % relator.id , relator.relation.code )
self.relators.append({'relator':relator,'select':select})
self.relators.append({'relator':relator, 'select':select})
def clean_doi(self):
doi = self.cleaned_data["doi"]
if doi:
if doi.startswith("https"):
return doi[19:]
elif doi.startswith("http"):
return doi[18:]
return doi
def clean(self):
has_isbn = self.cleaned_data.get("isbn", False) not in nulls
has_oclc = self.cleaned_data.get("oclc", False) not in nulls
has_goog = self.cleaned_data.get("goog", False) not in nulls
has_http = self.cleaned_data.get("http", False) not in nulls
if not has_isbn and not has_oclc and not has_goog and not has_http:
raise forms.ValidationError(_("There must be either an ISBN or an OCLC number."))
has_doi = self.cleaned_data.get("doi", False) not in nulls
try:
has_id = self.instance.work.identifiers.all().count() > 0
except AttributeError:
has_id = False
if not has_id and not has_isbn and not has_oclc and not has_goog and not has_http and not has_doi:
raise forms.ValidationError(_("There must be either an ISBN, a DOI, a URL or an OCLC number."))
return self.cleaned_data
class Meta:
model = Edition
exclude = ('created', 'work')
widgets = {
widgets = {
'title': forms.TextInput(attrs={'size': 40}),
'add_author': forms.TextInput(attrs={'size': 30}),
'add_subject': forms.TextInput(attrs={'size': 30}),
'unglued': forms.CheckboxInput(),
'cover_image': forms.TextInput(attrs={'size': 60}),
}
def test_file(the_file):
if the_file and the_file.name:
if format == 'epub':
try:
book = EPUB(the_file.file)
except Exception as e:
raise forms.ValidationError(_('Are you sure this is an EPUB file?: %s' % e) )
elif format == 'mobi':
try:
book = Mobi(the_file.file)
book.parse()
except Exception as e:
raise forms.ValidationError(_('Are you sure this is a MOBI file?: %s' % e) )
elif format == 'pdf':
try:
doc = PdfFileReader(the_file.file)
except Exception, e:
raise forms.ValidationError(_('%s is not a valid PDF file' % the_file.name) )
class EbookFileForm(forms.ModelForm):
file = forms.FileField(max_length=16777216)
file = forms.FileField(max_length=16777216)
version_label = forms.CharField(max_length=512, required=False)
new_version_label = forms.CharField(required=False)
def __init__(self, campaign_type=BUY2UNGLUE, *args, **kwargs):
super(EbookFileForm, self).__init__(*args, **kwargs)
self.campaign_type = campaign_type
if campaign_type == BUY2UNGLUE:
self.fields['format'].widget=forms.HiddenInput()
self.fields['format'].widget = forms.HiddenInput()
if campaign_type == THANKS:
self.fields['format'].widget=forms.Select(choices=(('pdf','PDF'),( 'epub','EPUB'), ('mobi','MOBI')))
self.fields['format'].widget = forms.Select(
choices = (('pdf', 'PDF'), ('epub', 'EPUB'), ('mobi', 'MOBI'))
)
def clean_version_label(self):
new_label = self.data.get('new_version_label','')
return new_label if new_label else self.cleaned_data['version_label']
def clean_format(self):
if self.campaign_type is BUY2UNGLUE:
return 'epub'
else:
logger.info("EbookFileForm "+self.cleaned_data.get('format',''))
return self.cleaned_data.get('format','')
def clean(self):
format = self.cleaned_data['format']
the_file = self.cleaned_data.get('file',None)
if the_file and the_file.name:
if format == 'epub':
try:
book = EPUB(the_file.file)
except Exception as e:
raise forms.ValidationError(_('Are you sure this is an EPUB file?: %s' % e) )
elif format == 'mobi':
try:
book = Mobi(the_file.file)
book.parse()
except Exception as e:
raise forms.ValidationError(_('Are you sure this is a MOBI file?: %s' % e) )
elif format == 'pdf':
try:
doc = PdfFileReader(the_file.file)
except Exception, e:
raise forms.ValidationError(_('%s is not a valid PDF file' % the_file.name) )
the_file = self.cleaned_data.get('file', None)
test_file(the_file)
return self.cleaned_data
class Meta:
model = EbookFile
widgets = { 'edition': forms.HiddenInput}
exclude = { 'created', 'asking' }
exclude = { 'created', 'asking', 'ebook' }
class EbookForm(forms.ModelForm):
file = forms.FileField(max_length=16777216, required=False)
url = forms.CharField(required=False, widget=forms.TextInput(attrs={'size' : 60},))
version_label = forms.CharField(required=False)
new_version_label = forms.CharField(required=False)
class Meta:
model = Ebook
exclude =( 'created', 'download_count', 'active', 'filesize')
widgets = {
'edition': forms.HiddenInput,
'user': forms.HiddenInput,
'provider': forms.HiddenInput,
'url': forms.TextInput(attrs={'size' : 60}),
exclude = ('created', 'download_count', 'active', 'filesize', 'version_iter')
widgets = {
'edition': forms.HiddenInput,
'user': forms.HiddenInput,
'provider': forms.HiddenInput,
}
def clean_version_label(self):
new_label = self.data.get('new_version_label','')
return new_label if new_label else self.cleaned_data['version_label']
def clean_provider(self):
new_provider= Ebook.infer_provider(self.data[self.prefix + '-url'])
new_provider = Ebook.infer_provider(self.cleaned_data['url'])
if not new_provider:
raise forms.ValidationError(_("At this time, ebook URLs must point at Internet Archive, Wikisources, Wikibooks, Hathitrust, Project Gutenberg, raw files at Github, or Google Books."))
return new_provider
def clean_url(self):
url = self.data[self.prefix + '-url']
url = self.cleaned_data['url']
try:
Ebook.objects.get(url=url)
except Ebook.DoesNotExist:
return url
raise forms.ValidationError(_("There's already an ebook with that url."))
def clean(self):
format = self.cleaned_data['format']
the_file = self.cleaned_data.get('file', None)
url = self.cleaned_data.get('url', None)
test_file(the_file)
if not the_file and not url:
raise forms.ValidationError(_("Either a link or a file is required."))
if the_file and url:
self.cleaned_data['url'] = ''
return self.cleaned_data
def UserClaimForm ( user_instance, *args, **kwargs ):
class ClaimForm(forms.ModelForm):
i_agree=forms.BooleanField(error_messages={'required': 'You must agree to the Terms in order to claim a work.'})
rights_holder=forms.ModelChoiceField(queryset=user_instance.rights_holder.all(), empty_label=None)
i_agree = forms.BooleanField(error_messages={'required': 'You must agree to the Terms in order to claim a work.'})
rights_holder = forms.ModelChoiceField(queryset=user_instance.rights_holder.all(), empty_label=None)
class Meta:
model = Claim
exclude = ('status',)
widgets = {
'user': forms.HiddenInput,
'work': forms.HiddenInput,
widgets = {
'user': forms.HiddenInput,
'work': forms.HiddenInput,
}
def __init__(self):
super(ClaimForm, self).__init__(*args, **kwargs)
return ClaimForm()
class RightsHolderForm(forms.ModelForm):
owner = AutoCompleteSelectField(
OwnerLookup,
@ -317,7 +386,7 @@ class RightsHolderForm(forms.ModelForm):
error_messages={'required': 'Please ensure the owner is a valid Unglue.it account.'},
)
email = forms.EmailField(
label=_("notification email address for rights holder"),
label=_("notification email address for rights holder"),
max_length=100,
error_messages={'required': 'Please enter an email address for the rights holder.'},
)
@ -333,12 +402,12 @@ class RightsHolderForm(forms.ModelForm):
return rights_holder_name
raise forms.ValidationError(_("Another rights holder with that name already exists."))
class ProfileForm(forms.ModelForm):
clear_facebook=forms.BooleanField(required=False)
clear_twitter=forms.BooleanField(required=False)
clear_goodreads=forms.BooleanField(required=False)
clear_facebook = forms.BooleanField(required=False)
clear_twitter = forms.BooleanField(required=False)
clear_goodreads = forms.BooleanField(required=False)
class Meta:
model = UserProfile
fields = 'tagline', 'librarything_id', 'home_url', 'clear_facebook', 'clear_twitter', 'clear_goodreads', 'avatar_source'
@ -361,10 +430,10 @@ class ProfileForm(forms.ModelForm):
def clean(self):
# check that if a social net is cleared, we're not using it a avatar source
if self.cleaned_data.get("clear_facebook", False) and self.cleaned_data.get("avatar_source", None)==FACEBOOK:
self.cleaned_data["avatar_source"]==UNGLUEITAR
if self.cleaned_data.get("clear_twitter", False) and self.cleaned_data.get("avatar_source", None)==TWITTER:
self.cleaned_data["avatar_source"]==UNGLUEITAR
if self.cleaned_data.get("clear_facebook", False) and self.cleaned_data.get("avatar_source", None) == FACEBOOK:
self.cleaned_data["avatar_source"] == UNGLUEITAR
if self.cleaned_data.get("clear_twitter", False) and self.cleaned_data.get("avatar_source", None) == TWITTER:
self.cleaned_data["avatar_source"] == UNGLUEITAR
return self.cleaned_data
class CloneCampaignForm(forms.Form):
@ -395,30 +464,33 @@ def getTransferCreditForm(maximum, data=None, *args, **kwargs ):
)
amount = forms.IntegerField(
required=True,
min_value=1,
min_value=1,
max_value=maximum,
label="Transfer Amount",
error_messages={'min_value': 'Transfer amount must be positive', 'max_value': 'You only have %(limit_value)s available for transfer'},
error_messages={
'min_value': 'Transfer amount must be positive',
'max_value': 'You only have %(limit_value)s available for transfer'
},
)
return TransferCreditForm( data=data )
class WorkForm(forms.Form):
other_work = forms.ModelChoiceField(queryset=Work.objects.all(),
widget=forms.HiddenInput(),
required=True,
other_work = forms.ModelChoiceField(queryset=Work.objects.all(),
widget=forms.HiddenInput(),
required=True,
error_messages={'required': 'Missing work to merge with.'},
)
work=None
work = None
def clean_other_work(self):
if self.cleaned_data["other_work"].id== self.work.id:
if self.cleaned_data["other_work"].id == self.work.id:
raise forms.ValidationError(_("You can't merge a work into itself"))
return self.cleaned_data["other_work"]
def __init__(self, work=None, *args, **kwargs):
super(WorkForm, self).__init__(*args, **kwargs)
self.work=work
self.work = work
class OtherWorkForm(WorkForm):
other_work = AutoCompleteSelectField(
@ -427,12 +499,12 @@ class OtherWorkForm(WorkForm):
widget=AutoCompleteSelectWidget(WorkLookup),
required=True,
error_messages={'required': 'Missing work to merge with.'},
)
)
def __init__(self, *args, **kwargs):
super(OtherWorkForm, self).__init__(*args, **kwargs)
self.fields['other_work'].widget.update_query_parameters({'language':self.work.language})
class EditManagersForm(forms.ModelForm):
managers = AutoCompleteSelectMultipleField(
OwnerLookup,
@ -451,7 +523,7 @@ class CustomPremiumForm(forms.ModelForm):
class Meta:
model = Premium
fields = 'campaign', 'amount', 'description', 'type', 'limit'
widgets = {
widgets = {
'description': forms.Textarea(attrs={'cols': 80, 'rows': 4}),
'campaign': forms.HiddenInput,
'type': forms.HiddenInput(attrs={'value':'XX'}),
@ -459,21 +531,24 @@ class CustomPremiumForm(forms.ModelForm):
}
def clean_type(self):
return 'CU'
class OfferForm(forms.ModelForm):
class Meta:
model = Offer
fields = 'work', 'price', 'license'
widgets = {
widgets = {
'work': forms.HiddenInput,
'license': forms.HiddenInput,
}
date_selector=range(date.today().year, settings.MAX_CC_DATE.year+1)
date_selector = range(date.today().year, settings.MAX_CC_DATE.year+1)
class CCDateForm(object):
target = forms.DecimalField( min_value= D(settings.UNGLUEIT_MINIMUM_TARGET), error_messages={'required': 'Please specify a Revenue Target.'} )
target = forms.DecimalField(
min_value= D(settings.UNGLUEIT_MINIMUM_TARGET),
error_messages={'required': 'Please specify a Revenue Target.'}
)
minimum_target = settings.UNGLUEIT_MINIMUM_TARGET
maximum_target = settings.UNGLUEIT_MAXIMUM_TARGET
max_cc_date = settings.MAX_CC_DATE
@ -490,26 +565,26 @@ class CCDateForm(object):
new_cc_date_initial = self.cleaned_data['cc_date_initial']
if new_cc_date_initial.date() > settings.MAX_CC_DATE:
raise forms.ValidationError('The initial Ungluing Date cannot be after %s'%settings.MAX_CC_DATE)
elif new_cc_date_initial - now() < timedelta(days=0):
elif new_cc_date_initial - now() < timedelta(days=0):
raise forms.ValidationError('The initial Ungluing date must be in the future!')
return new_cc_date_initial
class DateCalculatorForm(CCDateForm, forms.ModelForm):
revenue = forms.DecimalField()
cc_date_initial = forms.DateTimeField(
widget = SelectDateWidget(years=date_selector)
widget = SelectDateWidget(years=date_selector)
)
class Meta:
model = Campaign
fields = 'target', 'cc_date_initial', 'revenue',
def getManageCampaignForm ( instance, data=None, initial=None, *args, **kwargs ):
def get_queryset():
work=instance.work
work = instance.work
return Edition.objects.filter(work = work)
class ManageCampaignForm(CCDateForm,forms.ModelForm):
class ManageCampaignForm(CCDateForm, forms.ModelForm):
target = forms.DecimalField( required= (instance.type in {REWARDS, BUY2UNGLUE}))
deadline = forms.DateTimeField(
required = (instance.type==REWARDS),
@ -520,91 +595,102 @@ def getManageCampaignForm ( instance, data=None, initial=None, *args, **kwargs )
widget = SelectDateWidget(years=date_selector) if instance.status=='INITIALIZED' else forms.HiddenInput
)
paypal_receiver = forms.EmailField(
label=_("contact email address for this campaign"),
max_length=100,
label=_("contact email address for this campaign"),
max_length=100,
error_messages={'required': 'You must enter the email we should contact you at for this campaign.'},
)
edition = forms.ModelChoiceField(get_queryset(), widget=RadioSelect(),empty_label='no edition selected',required = False,)
publisher = forms.ModelChoiceField(instance.work.publishers(), empty_label='no publisher selected', required = False,)
edition = forms.ModelChoiceField(
get_queryset(),
widget=RadioSelect(),
empty_label='no edition selected',
required=False,
)
publisher = forms.ModelChoiceField(
instance.work.publishers(),
empty_label='no publisher selected',
required=False,
)
work_description = forms.CharField( required=False , widget=CKEditorWidget())
class Meta:
model = Campaign
fields = 'description', 'details', 'license', 'target', 'deadline', 'paypal_receiver', 'edition', 'email', 'publisher', 'cc_date_initial', "do_watermark", "use_add_ask",
fields = ('description', 'details', 'license', 'target', 'deadline', 'paypal_receiver',
'edition', 'email', 'publisher', 'cc_date_initial', "do_watermark", "use_add_ask",
)
widgets = { 'deadline': SelectDateWidget }
def clean_target(self):
if self.instance.type == THANKS:
return None
new_target = super(ManageCampaignForm,self).clean_target()
new_target = super(ManageCampaignForm, self).clean_target()
if self.instance:
if self.instance.status == 'ACTIVE' and self.instance.target < new_target:
raise forms.ValidationError(_('The fundraising target for an ACTIVE campaign cannot be increased.'))
return new_target
def clean_cc_date_initial(self):
if self.instance.type in {REWARDS,THANKS} :
if self.instance.type in {REWARDS, THANKS} :
return None
if self.instance:
if self.instance.status != 'INITIALIZED':
# can't change this once launched
return self.instance.cc_date_initial
return super(ManageCampaignForm,self).clean_cc_date_initial()
return super(ManageCampaignForm, self).clean_cc_date_initial()
def clean_deadline(self):
if self.instance.type in {BUY2UNGLUE, THANKS} :
return None
new_deadline_date = self.cleaned_data['deadline']
new_deadline= new_deadline_date + timedelta(hours=23,minutes=59)
new_deadline = new_deadline_date + timedelta(hours=23, minutes=59)
if self.instance:
if self.instance.status == 'ACTIVE':
return self.instance.deadline
if new_deadline_date - now() > timedelta(days=int(settings.UNGLUEIT_LONGEST_DEADLINE)):
raise forms.ValidationError(_('The chosen closing date is more than %s days from now' % settings.UNGLUEIT_LONGEST_DEADLINE))
elif new_deadline - now() < timedelta(days=0):
elif new_deadline - now() < timedelta(days=0):
raise forms.ValidationError(_('The chosen closing date is in the past'))
return new_deadline
def clean_license(self):
new_license = self.cleaned_data['license']
if self.instance:
if self.instance.status == 'ACTIVE' and self.instance.license != new_license:
# should only allow change to a less restrictive license
if self.instance.license == 'CC BY-ND' and new_license in ['CC BY-NC-ND','CC BY-NC-SA','CC BY-NC']:
if self.instance.license == 'CC BY-ND' and new_license in ['CC BY-NC-ND', 'CC BY-NC-SA', 'CC BY-NC']:
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
elif self.instance.license == 'CC BY' and new_license != 'CC0':
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
elif self.instance.license == 'CC BY-NC' and new_license in ['CC BY-NC-ND','CC BY-NC-SA','CC BY-SA','CC BY-ND']:
elif self.instance.license == 'CC BY-NC' and new_license in ['CC BY-NC-ND', 'CC BY-NC-SA', 'CC BY-SA', 'CC BY-ND']:
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
elif self.instance.license == 'CC BY-ND' and new_license in ['CC BY-NC-ND','CC BY-NC-SA','CC BY-SA','CC BY-NC']:
elif self.instance.license == 'CC BY-ND' and new_license in ['CC BY-NC-ND', 'CC BY-NC-SA', 'CC BY-SA', 'CC BY-NC']:
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
elif self.instance.license == 'CC BY-SA' and new_license in ['CC BY-NC-ND','CC BY-NC-SA','CC BY-ND','CC BY-NC']:
elif self.instance.license == 'CC BY-SA' and new_license in ['CC BY-NC-ND', 'CC BY-NC-SA', 'CC BY-ND', 'CC BY-NC']:
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
elif self.instance.license == 'CC BY-NC-SA' and new_license in ['CC BY-NC-ND','CC BY-ND']:
elif self.instance.license == 'CC BY-NC-SA' and new_license in ['CC BY-NC-ND', 'CC BY-ND']:
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
elif self.instance.license == 'CC0' :
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
elif self.instance.license in ['GDFL' , 'LAL']:
elif self.instance.license in ['GDFL', 'LAL']:
raise forms.ValidationError(_('Once you start a campaign with GDFL or LAL, you can\'t use any other license.'))
return new_license
if initial and not initial.get('edition', None) and not instance.edition:
initial['edition']= instance.work.editions.all()[0]
return ManageCampaignForm(instance = instance, data=data, initial=initial)
initial['edition'] = instance.work.editions.all()[0]
return ManageCampaignForm(instance=instance, data=data, initial=initial)
class CampaignPurchaseForm(forms.Form):
anonymous = forms.BooleanField(required=False, label=_("Make this purchase anonymous, please"))
offer_id = forms.IntegerField(required=False)
offer=None
offer = None
library_id = forms.IntegerField(required=False)
library = None
copies = forms.IntegerField(required=False,min_value=1)
copies = forms.IntegerField(required=False, min_value=1)
give_to = forms.EmailField(required = False)
give_message = forms.CharField(required = False, max_length=512, )
def clean_offer_id(self):
offer_id = self.cleaned_data['offer_id']
try:
self.offer= Offer.objects.get(id=offer_id)
self.offer = Offer.objects.get(id=offer_id)
except Offer.DoesNotExist:
raise forms.ValidationError(_("Sorry, that offer is not valid."))
@ -615,23 +701,23 @@ class CampaignPurchaseForm(forms.Form):
self.library = Library.objects.get(id=library_id)
except Library.DoesNotExist:
raise forms.ValidationError(_("Sorry, that Library is not valid."))
def clean_copies(self):
copies = self.cleaned_data.get('copies',1)
copies = self.cleaned_data.get('copies', 1)
return copies if copies else 1
def clean_anonymous(self):
if self.data.get('give', False):
return True
else:
return self.cleaned_data['anonymous']
def clean(self):
if self.offer.license == LIBRARY:
if not self.library:
raise forms.ValidationError(_("No library specified." ))
if self.data.get('give', False):
if not self.cleaned_data.get('give_to',None):
if not self.cleaned_data.get('give_to', None):
raise forms.ValidationError(_("Gift recipient email is needed." ))
else:
if 'give_to' in self._errors:
@ -639,28 +725,31 @@ class CampaignPurchaseForm(forms.Form):
return self.cleaned_data
def amount(self):
return self.offer.price * self.cleaned_data.get('copies',1) if self.offer else None
return self.offer.price * self.cleaned_data.get('copies', 1) if self.offer else None
@property
def trans_extra(self):
pe = PledgeExtra( anonymous=self.cleaned_data['anonymous'],
offer = self.offer )
if self.library:
pe.extra['library_id']=self.library.id
pe.extra['copies']=self.cleaned_data.get('copies',1)
pe.extra['library_id'] = self.library.id
pe.extra['copies'] = self.cleaned_data.get('copies', 1)
if self.data.get('give', False):
pe.extra['give_to']=self.cleaned_data['give_to']
pe.extra['give_message']=self.cleaned_data['give_message']
pe.extra['give_to'] = self.cleaned_data['give_to']
pe.extra['give_message'] = self.cleaned_data['give_message']
return pe
class CampaignThanksForm(forms.Form):
anonymous = forms.BooleanField(required=False, label=_("Make this contribution anonymous, please"))
anonymous = forms.BooleanField(
required=False,
label=_("Make this contribution anonymous, please")
)
preapproval_amount = forms.DecimalField(
required = True,
min_value=D('1.00'),
max_value=D('2000.00'),
decimal_places=2,
max_value=D('2000.00'),
decimal_places=2,
label="Pledge Amount",
)
@property
@ -672,43 +761,47 @@ class CampaignPledgeForm(forms.Form):
preapproval_amount = forms.DecimalField(
required = False,
min_value=D('1.00'),
max_value=D('2000.00'),
decimal_places=2,
max_value=D('2000.00'),
decimal_places=2,
label="Pledge Amount",
)
def amount(self):
return self.cleaned_data["preapproval_amount"] if self.cleaned_data else None
anonymous = forms.BooleanField(required=False, label=_("Make this pledge anonymous, please"))
ack_name = forms.CharField(required=False, max_length=64, label=_("What name should we display?"))
ack_name = forms.CharField(
required=False,
max_length=64,
label=_("What name should we display?")
)
ack_dedication = forms.CharField(required=False, max_length=140, label=_("Your dedication:"))
premium_id = forms.IntegerField(required=False)
premium=None
premium = None
@property
def trans_extra(self):
return PledgeExtra( anonymous=self.cleaned_data['anonymous'],
ack_name=self.cleaned_data['ack_name'],
ack_dedication=self.cleaned_data['ack_dedication'],
premium=self.premium)
def clean_preapproval_amount(self):
preapproval_amount = self.cleaned_data['preapproval_amount']
if preapproval_amount is None:
raise forms.ValidationError(_("Please enter a pledge amount."))
return preapproval_amount
def clean_premium_id(self):
premium_id = self.cleaned_data['premium_id']
try:
self.premium= Premium.objects.get(id=premium_id)
if self.premium.limit>0:
if self.premium.limit<=self.premium.premium_count:
self.premium = Premium.objects.get(id=premium_id)
if self.premium.limit > 0:
if self.premium.limit <= self.premium.premium_count:
raise forms.ValidationError(_("Sorry, that premium is fully subscribed."))
except Premium.DoesNotExist:
raise forms.ValidationError(_("Sorry, that premium is not valid."))
def clean(self):
# check on whether the preapproval amount is < amount for premium tier. If so, put an error message
preapproval_amount = self.cleaned_data.get("preapproval_amount")
@ -716,7 +809,7 @@ class CampaignPledgeForm(forms.Form):
# preapproval_amount failed validation, that error is the relevant one
return self.cleaned_data
elif self.premium is None:
raise forms.ValidationError(_("Please select a premium." ))
raise forms.ValidationError(_("Please select a premium." ))
elif preapproval_amount < self.premium.amount:
logger.info("raising form validating error")
raise forms.ValidationError(_("Sorry, you must pledge at least $%s to select that premium." % (self.premium.amount)))
@ -727,11 +820,11 @@ class TokenCCMixin(forms.Form):
class BaseCCMixin(forms.Form):
work_id = forms.IntegerField(required=False, widget=forms.HiddenInput())
preapproval_amount= forms.DecimalField(
preapproval_amount = forms.DecimalField(
required=False,
min_value=D('1.00'),
max_value=D('100000.00'),
decimal_places=2,
min_value=D('1.00'),
max_value=D('100000.00'),
decimal_places=2,
label="Amount",
)
class UserCCMixin(forms.Form):
@ -751,7 +844,7 @@ class CCForm(UserCCMixin, BaseCCForm):
class AccountCCForm( BaseCCMixin, UserCCMixin, forms.Form):
pass
class GoodreadsShelfLoadingForm(forms.Form):
goodreads_shelf_name_number = forms.CharField(widget=forms.Select(choices=(
('all','all'),
@ -767,40 +860,60 @@ class PledgeCancelForm(forms.Form):
class CampaignAdminForm(forms.Form):
campaign_id = forms.IntegerField()
class EmailShareForm(forms.Form):
recipient = forms.EmailField(error_messages={'required': 'Please specify a recipient.'})
subject = forms.CharField(max_length=100, error_messages={'required': 'Please specify a subject.'})
message = forms.CharField(widget=forms.Textarea(), error_messages={'required': 'Please include a message.'})
message = forms.CharField(
widget=forms.Textarea(),
error_messages={'required': 'Please include a message.'}
)
# allows us to return user to original page by passing it as hidden form input
# we can't rely on POST or GET since the emailshare view handles both
# and may iterate several times as it catches user errors, losing URL info
next = forms.CharField(widget=forms.HiddenInput())
class FeedbackForm(forms.Form):
sender = forms.EmailField(widget=forms.TextInput(attrs={'size':50}), label="Your email", error_messages={'required': 'Please specify your email address.'})
subject = forms.CharField(max_length=500, widget=forms.TextInput(attrs={'size':50}), error_messages={'required': 'Please specify a subject.'})
message = forms.CharField(widget=forms.Textarea(), error_messages={'required': 'Please specify a message.'})
sender = forms.EmailField(
widget=forms.TextInput(attrs={'size':50}),
label="Your email",
error_messages={'required': 'Please specify your email address.'}
)
subject = forms.CharField(
max_length=500,
widget=forms.TextInput(attrs={'size':50}),
error_messages={'required': 'Please specify a subject.'}
)
message = forms.CharField(
widget=forms.Textarea(),
error_messages={'required': 'Please specify a message.'}
)
page = forms.CharField(widget=forms.HiddenInput())
notarobot = forms.IntegerField(label="Please prove you're not a robot", error_messages={'required': "You must do the sum to prove you're not a robot."})
notarobot = forms.IntegerField(
label="Please prove you're not a robot",
error_messages={'required': "You must do the sum to prove you're not a robot."}
)
answer = forms.IntegerField(widget=forms.HiddenInput())
num1 = forms.IntegerField(widget=forms.HiddenInput())
num2 = forms.IntegerField(widget=forms.HiddenInput())
def clean(self):
cleaned_data = self.cleaned_data
notarobot = str(cleaned_data.get("notarobot"))
answer = str(cleaned_data.get("answer"))
if notarobot != answer:
raise forms.ValidationError(_("Whoops, try that sum again."))
return cleaned_data
class MsgForm(forms.Form):
msg = forms.CharField(widget=forms.Textarea(), error_messages={'required': 'Please specify a message.'})
msg = forms.CharField(
widget=forms.Textarea(),
error_messages={'required': 'Please specify a message.'}
)
def full_clean(self):
super(MsgForm,self).full_clean()
super(MsgForm, self).full_clean()
if self.data.has_key("supporter"):
try:
self.cleaned_data['supporter'] = User.objects.get(id=self.data["supporter"])
@ -815,20 +928,20 @@ class MsgForm(forms.Form):
raise ValidationError("Work does not exist")
else:
raise ValidationError("Work is not specified")
class PressForm(forms.ModelForm):
class Meta:
model = Press
exclude = ()
widgets = {
widgets = {
'date': SelectDateWidget(years=range(2010,2025)),
}
class KindleEmailForm(forms.Form):
kindle_email = forms.EmailField()
class LibModeForm(forms.ModelForm):
class Meta:
model = Libpref
@ -836,7 +949,11 @@ class LibModeForm(forms.ModelForm):
class RegiftForm(forms.Form):
give_to = forms.EmailField(label="email address of recipient")
give_message = forms.CharField( max_length=512, label="your gift message", initial="Here's an ebook from unglue.it, I hope you like it! - me")
give_message = forms.CharField(
max_length=512,
label="your gift message",
initial="Here's an ebook from unglue.it, I hope you like it! - me",
)
class SubjectSelectForm(forms.Form):
add_kw = AutoCompleteSelectField(
@ -855,4 +972,4 @@ class MapSubjectForm(forms.Form):
widget=AutoCompleteSelectWidget(SubjectLookup,allow_new=False),
label='Target Subject',
)

View File

@ -149,7 +149,7 @@ $j(document).ready(function() {
<a href="{% url 'download_ebook' ebook.id %}">
<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 %}">{{ 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 %}
@ -168,7 +168,7 @@ $j(document).ready(function() {
<a href="{% url 'download_ebook' ebook.id %}">
<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 %}">{{ 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 not forloop.last %}<br /><br />{% endif %}

View File

@ -16,6 +16,12 @@
{% endfor %}
<br />
{% endif %}
{% if edition.note %}
{{ edition.note }}.<br />
{% endif %}
{% if edition.downloads.count %}
{{ edition.downloads.count }} ebooks<br />
{% endif %}
{% if edition.publisher %}
Publisher: <a href="{% url 'bypubname_list' edition.publisher_name.id %}">{{edition.publisher}}</a><br />
{% endif %}
@ -28,6 +34,9 @@
{% if edition.oclc %}
OCLC: <a href="http://www.worldcat.org/oclc/{{ edition.oclc }}">{{ edition.oclc }}</a><br />
{% endif %}
{% if edition.doi %}
DOI: <a href="https://dx.doi.org/{{ edition.doi }}">{{ edition.doi }}</a><br />
{% endif %}
{% if edition.http_id %}
web: <a href="{{ edition.http_id }}">{{ edition.http_id }}</a><br />
{% endif %}

View File

@ -1,31 +1,48 @@
<div class="clearfix">
{% if edition.ebook_form %}
{% if show_ebook_form %}
<div id="add_ebook">
{% if ebook_form and show_ebook_form %}
<div id="add_ebook">
{% if alert %}<div class="yikes">{{alert}}</div>{% endif %}
{% if edition.ebooks.all.0 %}
<h2>eBooks for this Edition</h2>
{% 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 />
{% endfor %}
{% endif %}
<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>
<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 }}
{{ 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.rights.errors }}<span>License: {{ edition.ebook_form.rights }}</span><br />
<input type="submit" name="add_ebook" value="add ebook" />
</form>
</div>
{% else %}
<div> Adding ebook links is disabled for this work.</div>
{% endif %}
{% if edition.ebooks.all.0 %}
<h2>eBooks for this Edition</h2>
{% for ebook in edition.ebooks.all %}
{% if ebook.active %}
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> {{ebook.rights}} at {{ebook.provider}}.
{% if ebook.version_label %} {{ ebook.version_label }} (v{{ ebook.version_iter }}). {% endif %}
Downloaded {{ ebook.download_count }} times since {{ ebook.created }}<br />
{% endif %}
{% endfor %}
{% endif %}
<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, OApen, raw files at Github, or Google Books.</span>
<form method="POST" action="#add_ebook" enctype="multipart/form-data">
{% csrf_token %}
{{ ebook_form.edition.errors }}{{ ebook_form.edition }}{{ ebook_form.user.errors }}{{ ebook_form.user }}{{ ebook_form.provider.errors }}{{ ebook_form.provider }}
<br />
{{ ebook_form.url.errors }}<span>Add a Link URL: {{ ebook_form.url }}</span><br />
or...<br />
{{ ebook_form.file.errors }}<span>Upload an ebook file: {{ ebook_form.file }}</span><br /><br />
{{ ebook_form.format.errors }}<span>File Format: {{ ebook_form.format }}</span>&nbsp;&nbsp;&nbsp;
{{ ebook_form.rights.errors }}<span>License: {{ ebook_form.rights }}</span><br /><br />
<span>Version Label (optional): {% if edition.work.versions %}
<select id='version_label'>
<option value=""> (no label) </option>
{% for vers in edition.work.versions %}<option value="{{ vers }}" >{{ vers }}</option>{% endfor %}
</select> or add a new version label:
{% endif %}
{{ ebook_form.new_version_label.errors }} {{ ebook_form.new_version_label }} </span> <br />
<br /><input type="submit" name="add_ebook" value="add link/upload ebook" />
</form>
<h3>Note on versions</h4>
<p>
If you want ebooks from two editions with the same format and provider to display, give them different version labels.
</p>
</div>
{% else %}
<div> Adding ebook links is disabled for this work.</div>
{% endif %}
</div>

View File

@ -20,12 +20,20 @@
<b>LibraryThing ID</b>: {{ edition.librarything_id }}<br />
</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_label %} {{ ebook.version_label }}. {% endif %} v{{ ebook.version_iter }}
Downloaded {{ ebook.download_count }} times since {{ ebook.created }}<br />
{% endfor %}
{% endif %}
{% if edition.ebook_files.all %}
<h2> Ebook Files for this Edition</h2>
<ul>
{% for ebook_file in edition.ebook_files.all %}
{% 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 %}
{% endfor %}
</ul>
@ -66,15 +74,28 @@
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">
{% csrf_token %}
{{form.as_p}}
{{form.edition.errors}}{{form.edition}}
<p>{{form.format.errors}}Format: {{form.format}}</p>
<h3>Note on versions</h4>
<p>
If you want ebooks from two editions with the same format and provider to display, give them different version labels.
</p>
<span>Version Label (optional): {% if edition.work.versions %}
<select id='version_label'>
<option value=""> (no label) </option>
{% for vers in edition.work.versions %}<option value="{{ vers }}" >{{ vers }}</option>{% endfor %}
</select> or add a new version label:
{% endif %}
{{ form.new_version_label.errors }} {{ form.new_version_label }} </span> <br />
<p>{{form.file.errors}}Upload File: {{form.file}}</p>
<input type="submit" id="submit_file" value="submit ebook file">
</form>
{% if edition.work %}
<h2>More Edition Management</h2>
<div><a href="{% url 'new_edition' edition.work.id edition.id %}">Edit this edition</a></div>
{% if edition.work.last_campaign %}
<div><a href="{% url 'manage_campaign' edition.work.last_campaign.id %}">Manage this campaign</a></div>
{% endif %}
{% endif %}
{% endblock %}

View File

@ -136,14 +136,13 @@ Please fix the following before launching your campaign:
<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>
<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>
{% ifnotequal campaign.type 1 %}
{% if campaign.rh.can_sell %}
{% 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 %}
<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 %}
{% 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>
{% if campaign.work.ebookfiles.0 %}
<h3>Uploaded Files</h3>
<h3>All ebook files for this book</h3>
{% endif %}
{% if campaign.work.epubfiles.0 %}
{% 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 %}
{% if campaign.work.test_acqs.0 %}
<ul>

View File

@ -6,7 +6,27 @@
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>
<script type="text/javascript">
onload = function(){
var urlInput = document.getElementById('id_url');
var formatInput = document.getElementById('id_format');
urlInput.oninput = function(){
if(urlInput.value.endsWith('.pdf')){
formatInput.value = 'pdf'
}
else if(urlInput.value.endsWith('.epub')){
formatInput.value = 'epub'
}
else if(urlInput.value.endsWith('.mobi')){
formatInput.value = 'mobi'
}
else if(urlInput.value.endsWith('.html')){
formatInput.value = 'html'
};
};
};
</script>
{% endblock %}
{% block doccontent %}

View File

@ -93,11 +93,12 @@ ul.fancytree-container {
<h2>Create New Edition</h2>
{% endif %}
<p>Title and ISBN 13 are required; the rest is optional, though a cover image is strongly recommended.</p>
<p>Title and ISBN 13 (or DOI, OCLCNum or URL) are required; the rest is optional, though a cover image is strongly recommended.</p>
<form id="editform" enctype="multipart/form-data" method="POST" action="#">
{% csrf_token %}
{{ form.work }}
{{ form.non_field_errors }}
<!--{{ form.errors }}-->
<div>
<p><b>Title</b>: {{ form.title.errors }}{{ form.title }}</p>
<p><b>Publisher Name</b> : {{ form.publisher_name.errors }}{{ form.publisher_name }}<br />(If you change this, click another form element before submitting)</p>
@ -122,6 +123,25 @@ ul.fancytree-container {
<input type="submit" name="add_author_submit" value="Add Author" id="submit_author"></p>
<p><b>Language</b>: {{ form.language.errors }}{{ form.language }}</p>
{% if edition.pk %}
<p><b>Add a Related Work</b>: {{ form.add_work_relation.errors }}{{ form.add_work_relation }} of {{ form.add_related_work.errors }}{{ form.add_related_work }}</p>
<ul>{% for work_rel in edition.work.works_related_to.all %}
<li>
This work is a {{ work_rel.relation }} of <a href="{% url 'work' work_rel.from_work.id %}">{{ work_rel.from_work }}</a>.
<input type="submit" name="delete_work_rel_{{ work_rel.id }}" value="x" class="deletebutton" title="delete work relation">
</li>
{% endfor %}
{% for work_rel in edition.work.works_related_from.all %}
<li>
<a href="{% url 'work' work_rel.to_work.id %}">{{ work_rel.to_work }}</a> is a {{ work_rel.relation }} of this work.
<input type="submit" name="delete_work_rel_{{ work_rel.id }}" value="x" class="deletebutton" title="delete work relation">
</li>
{% endfor %}</ul>
{% endif %}
<p><b>Age Level</b>: {{ form.age_level.errors }}{{ form.age_level }}</p>
<p><b>Edition Note</b>: {{ form.note.errors }}{{ form.note }}</p>
<h4> Identifiers </h4>
{% if id_msg %} <span class="errorlist">{{ id_msg }} </span>{% endif %}
<p> Enter 'delete' to remove the identifier. </p>
@ -130,9 +150,8 @@ ul.fancytree-container {
<p><b>Google Books ID</b>: {{ form.goog.errors }}{{ form.goog }}</p>
<p><b>GoodReads ID</b>: {{ form.gdrd.errors }}{{ form.gdrd }}</p>
<p><b>LibraryThing ID</b>: {{ form.thng.errors }}{{ form.thng }}</p>
{% if request.user.is_staff %}
<p><b>HTTP ID</b>: {{ form.http.errors }}{{ form.http }}</p>
{% endif %}
<p><b>DOI</b>: {{ form.doi.errors }}{{ form.doi }}</p>
<p><b>HTTP(S) ID</b>: {{ form.http.errors }}{{ form.http }}</p>
<p><b>Description</b>: <br />
{{ form.description.errors }}{{ form.description }}<br />
(<i>{% if work.last_campaign %}
@ -175,7 +194,7 @@ ul.fancytree-container {
[ no cover specified for this edition ]<br />
{% endif %}
{{ form.cover_image.errors }}{{ form.cover_image }}{{ form.cover_image.help_text }}
(<i>Enter a URL for an image, ideally 120px wide. </i>)<br />
(<i>Enter a URL for an image, at least 300 px wide. The image will be scaled to the proportions of a 6x9 cover. </i>)<br />
OR...<br />
{{ form.coverfile.errors }}{{ form.coverfile }}{{ form.coverfile.help_text }}

View File

@ -102,6 +102,8 @@
<span itemprop="publisher"><a href="{% url 'bypubname_list' work.last_campaign.publisher.name.id %}">{{ work.last_campaign.publisher }}</a></span>
{% endif %}
<span itemprop="datePublished">{{ work.publication_date }}</span>
<meta itemprop="inLanguage" content="work.language" />
<meta itemprop="typicalAgeRange" content="work.age_range" />
</h3>
</div>
</div>
@ -276,6 +278,18 @@
{{ work.last_campaign.description|safe }}
{% endif %}
</div>
<div>
{% for work_rel in work.works_related_to.all %}
<p>
This work is a {{ work_rel.relation }} of <a href="{% url 'work' work_rel.from_work.id %}">{{ work_rel.from_work }}</a>.
</p>
{% endfor %}
{% for work_rel in work.works_related_from.all %}
<p>
<a href="{% url 'work' work_rel.to_work.id %}">{{ work_rel.to_work }}</a> is a {{ work_rel.relation }} of this work.
</p>
{% endfor %}
</div>
</div>
</div>
<div id="tabs-2" class="tabs {% if activetab == '2' %}active{% endif %}">
@ -417,7 +431,7 @@
This work has been downloaded {{ work.download_count }} times via unglue.it ebook links.
<ol>
{% 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_label %} ({{ ebook.version_label }}) {% endif %}({{ ebook.rights }}) at {{ ebook.provider }}. </li>
{% endfor %}
</ol>
</div>

View File

@ -27,7 +27,7 @@ urlpatterns = [
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+)/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/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"),

File diff suppressed because it is too large Load Diff

View File

@ -89,6 +89,17 @@ def stub(edition):
)
record.add_ordered_field(field245)
#edition statement
if edition.note:
field250 = pymarc.Field(
tag='250',
indicators = [' ', ' '],
subfields = [
'a', unicode(edition.note),
]
)
record.add_ordered_field(field250)
# publisher, date
if edition.publisher:
field260 = pymarc.Field(
@ -101,7 +112,7 @@ def stub(edition):
if edition.publication_date:
field260.add_subfield('c', unicode(edition.publication_date))
record.add_ordered_field(field260)
if edition.description:
#add 520 field (description)
field520 = pymarc.Field(

View File

@ -56,6 +56,7 @@ class AbstractEdition:
publisher = ''
title = ''
publication_date = ''
note = ''
# the edition should be able to report ebook downloads, with should have format and url attributes
def downloads(self):

File diff suppressed because one or more lines are too long

View File

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