Merge pull request #635 from Gluejar/versions-relations-ednotes
Versions relations ednotes [merge into master not dj18]pull/1/head
commit
599ac8dc69
14
api/onix.py
14
api/onix.py
|
@ -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")
|
||||
|
|
51
api/opds.py
51
api/opds.py
|
@ -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=''
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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'}),
|
||||
]
|
|
@ -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),
|
||||
),
|
||||
]
|
|
@ -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'}),
|
||||
]
|
|
@ -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),
|
||||
),
|
||||
]
|
2449
core/models.py
2449
core/models.py
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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')
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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',
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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>
|
||||
{{ 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>
|
||||
{{ 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>
|
|
@ -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 %}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"),
|
||||
|
|
1496
frontend/views.py
1496
frontend/views.py
File diff suppressed because it is too large
Load Diff
13
marc/load.py
13
marc/load.py
|
@ -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(
|
||||
|
|
|
@ -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
|
@ -63,10 +63,6 @@
|
|||
width: 660px !important;
|
||||
}
|
||||
|
||||
a {
|
||||
color:#3d4e53;
|
||||
}
|
||||
|
||||
#js-search {
|
||||
margin: 0 15px 0 15px !important;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue