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 datetime
|
||||||
import pytz
|
import pytz
|
||||||
|
import re
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from regluit.core import models
|
from regluit.core import models
|
||||||
from regluit.core.cc import ccinfo
|
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("SubjectSchemeIdentifier", "20"))
|
||||||
subj_node.append(text_node("SubjectHeadingText", subject.name))
|
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
|
# Collateral Detail Block
|
||||||
coll_node = etree.SubElement(product_node, "CollateralDetail")
|
coll_node = etree.SubElement(product_node, "CollateralDetail")
|
||||||
desc_node = etree.SubElement(coll_node, "TextContent")
|
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()))
|
node.append(text_node('updated', work.first_ebook().created.isoformat()))
|
||||||
|
|
||||||
# links for all ebooks
|
# 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:
|
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
|
# 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_rel = "http://opds-spec.org/acquisition/open-access"
|
||||||
link_node.attrib.update({"href":add_query_component(ebook.download_url, "feed=opds"),
|
link_node.attrib.update({"href":add_query_component(ebook.download_url, "feed=opds"),
|
||||||
"rel":link_rel,
|
"rel":link_rel,
|
||||||
"{http://purl.org/dc/terms/}rights": str(ebook.rights)})
|
"{http://purl.org/dc/terms/}rights": str(ebook.rights)})
|
||||||
if ebook.is_direct():
|
if ebook.is_direct():
|
||||||
link_node.attrib["type"] = FORMAT_TO_MIMETYPE.get(ebook.format, "")
|
link_node.attrib["type"] = FORMAT_TO_MIMETYPE.get(ebook.format, "")
|
||||||
else:
|
else:
|
||||||
""" indirect acquisition, i.e. google books """
|
""" indirect acquisition, i.e. google books """
|
||||||
link_node.attrib["type"] = "text/html"
|
link_node.attrib["type"] = "text/html"
|
||||||
indirect = etree.Element("{http://opds-spec.org/}indirectAcquisition",)
|
indirect = etree.Element("{http://opds-spec.org/}indirectAcquisition",)
|
||||||
indirect.attrib["type"] = FORMAT_TO_MIMETYPE.get(ebook.format, "")
|
indirect.attrib["type"] = FORMAT_TO_MIMETYPE.get(ebook.format, "")
|
||||||
link_node.append(indirect)
|
link_node.append(indirect)
|
||||||
|
if ebook.version_label:
|
||||||
node.append(link_node)
|
link_node.attrib.update({"{http://schema.org/}version": ebook.version_label})
|
||||||
|
node.append(link_node)
|
||||||
|
|
||||||
# get the cover -- assume jpg?
|
# get the cover -- assume jpg?
|
||||||
|
|
||||||
|
@ -163,6 +167,16 @@ def work_node(work, facet=None):
|
||||||
# caused by control chars in subject.name
|
# caused by control chars in subject.name
|
||||||
logger.warning('Deleting subject: %s' % subject.name)
|
logger.warning('Deleting subject: %s' % subject.name)
|
||||||
subject.delete()
|
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
|
||||||
rating_node = etree.Element("{http://schema.org/}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)
|
works=models.Work.objects.filter(id=work_id)
|
||||||
except models.Work.DoesNotExist:
|
except models.Work.DoesNotExist:
|
||||||
works=models.Work.objects.none()
|
works=models.Work.objects.none()
|
||||||
|
except ValueError:
|
||||||
|
# not a valid work_id
|
||||||
|
works=models.Work.objects.none()
|
||||||
self.works=works
|
self.works=works
|
||||||
self.title='Unglue.it work #%s' % work_id
|
self.title='Unglue.it work #%s' % work_id
|
||||||
self.feed_path=''
|
self.feed_path=''
|
||||||
|
|
|
@ -74,7 +74,8 @@ class WorkAdmin(ModelAdmin):
|
||||||
ordering = ('title',)
|
ordering = ('title',)
|
||||||
list_display = ('title', 'created')
|
list_display = ('title', 'created')
|
||||||
date_hierarchy = 'created'
|
date_hierarchy = 'created'
|
||||||
fields = ('title', 'description', 'language', 'featured')
|
fields = ('title', 'description', 'language', 'featured', 'publication_range',
|
||||||
|
'age_level', 'openlibrary_lookup')
|
||||||
|
|
||||||
class AuthorAdmin(ModelAdmin):
|
class AuthorAdmin(ModelAdmin):
|
||||||
search_fields = ('name',)
|
search_fields = ('name',)
|
||||||
|
@ -105,9 +106,9 @@ class EditionAdminForm(forms.ModelForm):
|
||||||
)
|
)
|
||||||
publisher_name = AutoCompleteSelectField(
|
publisher_name = AutoCompleteSelectField(
|
||||||
PublisherNameLookup,
|
PublisherNameLookup,
|
||||||
label='Name',
|
label='Publisher Name',
|
||||||
widget=AutoCompleteSelectWidget(PublisherNameLookup),
|
widget=AutoCompleteSelectWidget(PublisherNameLookup),
|
||||||
required=True,
|
required=False,
|
||||||
)
|
)
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
model = models.Edition
|
model = models.Edition
|
||||||
|
@ -174,24 +175,76 @@ class CeleryTaskAdmin(ModelAdmin):
|
||||||
class PressAdmin(ModelAdmin):
|
class PressAdmin(ModelAdmin):
|
||||||
list_display = ('title', 'source', 'date')
|
list_display = ('title', 'source', 'date')
|
||||||
ordering = ('-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.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.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.Publisher, PublisherAdmin)
|
||||||
admin_site.register(models.PublisherName, PublisherNameAdmin)
|
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.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:
|
for w in works_to_merge:
|
||||||
logger.debug("merge_works path 2 %s %s", lang_edition.work.id, w.id )
|
logger.debug("merge_works path 2 %s %s", lang_edition.work.id, w.id )
|
||||||
merge_works(lang_edition.work, w)
|
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
|
return new_editions
|
||||||
|
|
||||||
|
@ -901,8 +902,8 @@ def load_from_yaml(yaml_url, test_mode=False):
|
||||||
rights = cc.match_license(metadata.rights),
|
rights = cc.match_license(metadata.rights),
|
||||||
format = ebook_format,
|
format = ebook_format,
|
||||||
edition = edition,
|
edition = edition,
|
||||||
# version = metadata._version
|
|
||||||
)
|
)
|
||||||
|
ebook.set_version(metadata._version)
|
||||||
|
|
||||||
return work.id
|
return work.id
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ def description(license):
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
class ccinfo():
|
class ccinfo(object):
|
||||||
def __init__(self, license):
|
def __init__(self, license):
|
||||||
value=license_value(license)
|
value=license_value(license)
|
||||||
self.license=value if value else 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.contrib.auth.models import User
|
||||||
from django.db.models import Count
|
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):
|
class OwnerLookup(ModelLookup):
|
||||||
model = User
|
model = User
|
||||||
|
@ -54,8 +54,17 @@ class SubjectLookup(ModelLookup):
|
||||||
def get_query(self, request, term):
|
def get_query(self, request, term):
|
||||||
return super(SubjectLookup, self).get_query( request, term).annotate(Count('works')).order_by('-works__count')
|
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(OwnerLookup)
|
||||||
registry.register(WorkLookup)
|
registry.register(WorkLookup)
|
||||||
registry.register(PublisherNameLookup)
|
registry.register(PublisherNameLookup)
|
||||||
registry.register(EditionLookup)
|
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)
|
(REWARDS, BUY2UNGLUE, THANKS) = (1, 2, 3)
|
||||||
(INDIVIDUAL, LIBRARY, BORROWED, RESERVE, THANKED) = (1, 2, 3, 4, 5)
|
(INDIVIDUAL, LIBRARY, BORROWED, RESERVE, THANKED) = (1, 2, 3, 4, 5)
|
||||||
TESTING = 0
|
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:
|
if campaign.use_add_ask:
|
||||||
campaign.add_ask_to_ebfs()
|
campaign.add_ask_to_ebfs()
|
||||||
else:
|
else:
|
||||||
campaign.work.make_ebooks_from_ebfs(add_ask=False)
|
campaign.revert_asks()
|
||||||
campaign.work.remove_old_ebooks()
|
campaign.make_mobis()
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def make_mobi(campaign):
|
def make_mobi(ebookfile):
|
||||||
return campaign.make_mobi()
|
return ebookfile.make_mobi()
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def refresh_acqs():
|
def refresh_acqs():
|
||||||
|
|
|
@ -192,6 +192,16 @@ class BookLoaderTests(TestCase):
|
||||||
self.assertTrue(models.Edition.objects.count() > 15)
|
self.assertTrue(models.Edition.objects.count() > 15)
|
||||||
self.assertEqual(models.Work.objects.filter(language=lang).count(), 1)
|
self.assertEqual(models.Work.objects.filter(language=lang).count(), 1)
|
||||||
self.assertTrue(edition.work.editions.count() > 9)
|
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):
|
def test_populate_edition(self):
|
||||||
|
@ -1009,6 +1019,11 @@ class EbookFileTests(TestCase):
|
||||||
dj_file = DjangoFile(temp_file)
|
dj_file = DjangoFile(temp_file)
|
||||||
ebf = EbookFile( format='pdf', edition=e, file=dj_file)
|
ebf = EbookFile( format='pdf', edition=e, file=dj_file)
|
||||||
ebf.save()
|
ebf.save()
|
||||||
|
eb = Ebook( format='pdf', edition=e, url=ebf.file.url, provider='Unglue.it')
|
||||||
|
eb.save()
|
||||||
|
ebf.ebook = eb
|
||||||
|
ebf.save()
|
||||||
|
|
||||||
|
|
||||||
temp_file.close()
|
temp_file.close()
|
||||||
finally:
|
finally:
|
||||||
|
@ -1016,7 +1031,7 @@ class EbookFileTests(TestCase):
|
||||||
os.remove(temp.name)
|
os.remove(temp.name)
|
||||||
#test the ask-appender
|
#test the ask-appender
|
||||||
c.add_ask_to_ebfs()
|
c.add_ask_to_ebfs()
|
||||||
asking_pdf = c.work.ebookfiles().filter(asking = True)[0].file.url
|
asking_pdf = c.work.ebookfiles().filter(asking=True)[0].file.url
|
||||||
assert test_pdf(asking_pdf)
|
assert test_pdf(asking_pdf)
|
||||||
|
|
||||||
#Now do the same with epub
|
#Now do the same with epub
|
||||||
|
@ -1032,16 +1047,25 @@ class EbookFileTests(TestCase):
|
||||||
dj_file = DjangoFile(temp_file)
|
dj_file = DjangoFile(temp_file)
|
||||||
ebf = EbookFile( format='epub', edition=e, file=dj_file)
|
ebf = EbookFile( format='epub', edition=e, file=dj_file)
|
||||||
ebf.save()
|
ebf.save()
|
||||||
|
eb = Ebook( format='epub', edition=e, url=ebf.file.url, provider='Unglue.it')
|
||||||
|
eb.save()
|
||||||
|
ebf.ebook = eb
|
||||||
|
ebf.save()
|
||||||
temp_file.close()
|
temp_file.close()
|
||||||
|
ebf.make_mobi()
|
||||||
finally:
|
finally:
|
||||||
# make sure we get rid of temp file
|
# make sure we get rid of temp file
|
||||||
os.remove(temp.name)
|
os.remove(temp.name)
|
||||||
#test the ask-appender
|
#test the ask-appender
|
||||||
c.add_ask_to_ebfs()
|
c.add_ask_to_ebfs()
|
||||||
self.assertTrue( c.work.ebookfiles().filter(asking = True, format='epub').count >0)
|
self.assertTrue( c.work.ebookfiles().filter(asking = True, format='epub').count() > 0)
|
||||||
self.assertTrue( c.work.ebookfiles().filter(asking = True, format='mobi').count >0)
|
self.assertTrue( c.work.ebookfiles().filter(asking = True, format='mobi').count() > 0)
|
||||||
|
self.assertTrue( c.work.ebookfiles().filter(asking = True, ebook__active=True).count() > 0)
|
||||||
|
self.assertTrue( c.work.ebookfiles().filter(asking = False, ebook__active=True).count() == 0)
|
||||||
|
#test the unasker
|
||||||
|
c.revert_asks()
|
||||||
|
self.assertTrue( c.work.ebookfiles().filter(asking = True, ebook__active=True).count() == 0)
|
||||||
|
self.assertTrue( c.work.ebookfiles().filter(asking = False, ebook__active=True).count() > 0)
|
||||||
|
|
||||||
class MobigenTests(TestCase):
|
class MobigenTests(TestCase):
|
||||||
def test_convert_to_mobi(self):
|
def test_convert_to_mobi(self):
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
# ssh ubuntu@please.unglueit.com "/opt/regluit/deploy/update-regluit"
|
# ssh ubuntu@please.unglueit.com "/opt/regluit/deploy/update-regluit"
|
||||||
|
|
||||||
cd /opt/regluit
|
cd /opt/regluit
|
||||||
|
find . -name "*.pyc" -delete
|
||||||
|
find . -type d -empty -delete
|
||||||
|
|
||||||
sudo -u ubuntu /usr/bin/git pull
|
sudo -u ubuntu /usr/bin/git pull
|
||||||
source ENV/bin/activate
|
source ENV/bin/activate
|
||||||
pip install --upgrade -r requirements_versioned.pip
|
pip install --upgrade -r requirements_versioned.pip
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
cd /opt/regluit
|
cd /opt/regluit
|
||||||
|
find . -name "*.pyc" -delete
|
||||||
|
find . -type d -empty -delete
|
||||||
|
|
||||||
sudo -u ubuntu /usr/bin/git pull origin production
|
sudo -u ubuntu /usr/bin/git pull origin production
|
||||||
source ENV/bin/activate
|
source ENV/bin/activate
|
||||||
pip install --upgrade -r requirements_versioned.pip
|
pip install --upgrade -r requirements_versioned.pip
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
# ssh ubuntu@please.unglueit.com "/opt/regluit/deploy/update-regluit"
|
# ssh ubuntu@please.unglueit.com "/opt/regluit/deploy/update-regluit"
|
||||||
|
|
||||||
cd /opt/regluit
|
cd /opt/regluit
|
||||||
|
find . -name "*.pyc" -delete
|
||||||
|
find . -type d -empty -delete
|
||||||
|
|
||||||
sudo -u ubuntu /usr/bin/git pull
|
sudo -u ubuntu /usr/bin/git pull
|
||||||
source ENV/bin/activate
|
source ENV/bin/activate
|
||||||
#pip install -r requirements.pip
|
#pip install -r requirements.pip
|
||||||
|
|
|
@ -4,7 +4,7 @@ from StringIO import StringIO
|
||||||
|
|
||||||
|
|
||||||
from regluit.core.facets import BaseFacet
|
from regluit.core.facets import BaseFacet
|
||||||
from regluit.core.models import Work
|
from regluit.core.models import Work, good_providers
|
||||||
from regluit.api.onix import onix_feed
|
from regluit.api.onix import onix_feed
|
||||||
|
|
||||||
from .models import Target
|
from .models import Target
|
||||||
|
@ -45,7 +45,7 @@ def get_target_facet(target, start=datetime(1900,1,1), new=False):
|
||||||
editions__ebooks__created__gt = start,
|
editions__ebooks__created__gt = start,
|
||||||
identifiers__type="isbn",
|
identifiers__type="isbn",
|
||||||
editions__ebooks__format__in = formats,
|
editions__ebooks__format__in = formats,
|
||||||
editions__ebooks__provider__in = ('Internet Archive', 'Unglue.it', 'Github', 'OAPEN Library'),
|
editions__ebooks__provider__in = good_providers,
|
||||||
).distinct().order_by('-featured')
|
).distinct().order_by('-featured')
|
||||||
|
|
||||||
model_filters = {"Ebook": format_filter, "Edition": edition_format_filter}
|
model_filters = {"Ebook": format_filter, "Edition": edition_format_filter}
|
||||||
|
|
|
@ -1,22 +1,17 @@
|
||||||
"""
|
#external library imports
|
||||||
external library imports
|
|
||||||
"""
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import zipfile
|
|
||||||
|
|
||||||
from datetime import timedelta, datetime, date
|
from datetime import timedelta, date
|
||||||
from decimal import Decimal as D
|
from decimal import Decimal as D
|
||||||
|
|
||||||
"""
|
#django imports
|
||||||
django imports
|
|
||||||
"""
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.global_settings import LANGUAGES
|
from django.conf.global_settings import LANGUAGES
|
||||||
from django.contrib.auth.models import User
|
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.widgets import RadioSelect
|
||||||
from django.forms.extras.widgets import SelectDateWidget
|
from django.forms.extras.widgets import SelectDateWidget
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -32,10 +27,8 @@ from selectable.forms import (
|
||||||
|
|
||||||
from PyPDF2 import PdfFileReader
|
from PyPDF2 import PdfFileReader
|
||||||
|
|
||||||
|
#regluit imports
|
||||||
|
|
||||||
"""
|
|
||||||
regluit imports
|
|
||||||
"""
|
|
||||||
from regluit.core.models import (
|
from regluit.core.models import (
|
||||||
UserProfile,
|
UserProfile,
|
||||||
RightsHolder,
|
RightsHolder,
|
||||||
|
@ -51,23 +44,28 @@ from regluit.core.models import (
|
||||||
Work,
|
Work,
|
||||||
Press,
|
Press,
|
||||||
Libpref,
|
Libpref,
|
||||||
Subject,
|
|
||||||
TWITTER,
|
TWITTER,
|
||||||
FACEBOOK,
|
FACEBOOK,
|
||||||
GRAVATAR,
|
|
||||||
UNGLUEITAR
|
UNGLUEITAR
|
||||||
)
|
)
|
||||||
from regluit.libraryauth.models import Library
|
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 (
|
from regluit.core.lookups import (
|
||||||
OwnerLookup,
|
OwnerLookup,
|
||||||
WorkLookup,
|
WorkLookup,
|
||||||
PublisherNameLookup,
|
PublisherNameLookup,
|
||||||
EditionLookup,
|
|
||||||
SubjectLookup,
|
SubjectLookup,
|
||||||
|
EditionNoteLookup,
|
||||||
)
|
)
|
||||||
from regluit.utils.localdatetime import now
|
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.mobi import Mobi
|
||||||
from regluit.pyepub import EPUB
|
from regluit.pyepub import EPUB
|
||||||
from regluit.bisac.models import BisacHeading
|
from regluit.bisac.models import BisacHeading
|
||||||
|
@ -90,15 +88,15 @@ class SurveyForm(forms.Form):
|
||||||
label = forms.CharField(max_length=64, required=True)
|
label = forms.CharField(max_length=64, required=True)
|
||||||
survey = forms.ModelChoiceField(Questionnaire.objects.all(), widget=RadioSelect(), empty_label=None, required = True,)
|
survey = forms.ModelChoiceField(Questionnaire.objects.all(), widget=RadioSelect(), empty_label=None, required = True,)
|
||||||
isbn = ISBNField(
|
isbn = ISBNField(
|
||||||
label=_("ISBN"),
|
label=_("ISBN"),
|
||||||
max_length=17,
|
max_length=17,
|
||||||
required = False,
|
required = False,
|
||||||
help_text = _("13 digits, no dash."),
|
help_text = _("13 digits, no dash."),
|
||||||
error_messages = {
|
error_messages = {
|
||||||
'invalid': _("This must be a valid ISBN-13."),
|
'invalid': _("This must be a valid ISBN-13."),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def clean_isbn(self):
|
def clean_isbn(self):
|
||||||
isbn = self.cleaned_data['isbn']
|
isbn = self.cleaned_data['isbn']
|
||||||
if not isbn:
|
if not isbn:
|
||||||
|
@ -115,24 +113,36 @@ class EditionForm(forms.ModelForm):
|
||||||
add_author = forms.CharField(max_length=500, required=False)
|
add_author = forms.CharField(max_length=500, required=False)
|
||||||
add_author_relation = forms.ChoiceField(choices=CREATOR_RELATIONS, initial=('aut', 'Author'))
|
add_author_relation = forms.ChoiceField(choices=CREATOR_RELATIONS, initial=('aut', 'Author'))
|
||||||
add_subject = AutoCompleteSelectField(
|
add_subject = AutoCompleteSelectField(
|
||||||
SubjectLookup,
|
SubjectLookup,
|
||||||
widget=AutoCompleteSelectWidget(SubjectLookup,allow_new=True),
|
widget=AutoCompleteSelectWidget(SubjectLookup, allow_new=True),
|
||||||
label='Keyword',
|
label='Keyword',
|
||||||
required =False
|
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 )
|
bisac = forms.ModelChoiceField( bisac_headings, required=False )
|
||||||
|
|
||||||
publisher_name = AutoCompleteSelectField(
|
publisher_name = AutoCompleteSelectField(
|
||||||
PublisherNameLookup,
|
PublisherNameLookup,
|
||||||
label='Publisher Name',
|
label='Publisher Name',
|
||||||
widget=AutoCompleteSelectWidget(PublisherNameLookup,allow_new=True),
|
widget=AutoCompleteSelectWidget(PublisherNameLookup,allow_new=True),
|
||||||
required=False,
|
required=False,
|
||||||
allow_new=True,
|
allow_new=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
isbn = ISBNField(
|
isbn = ISBNField(
|
||||||
label=_("ISBN"),
|
label=_("ISBN"),
|
||||||
max_length=17,
|
max_length=17,
|
||||||
required = False,
|
required = False,
|
||||||
help_text = _("13 digits, no dash."),
|
help_text = _("13 digits, no dash."),
|
||||||
error_messages = {
|
error_messages = {
|
||||||
|
@ -140,8 +150,8 @@ class EditionForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
goog = forms.RegexField(
|
goog = forms.RegexField(
|
||||||
label=_("Google Books ID"),
|
label=_("Google Books ID"),
|
||||||
max_length=12,
|
max_length=12,
|
||||||
regex=r'^([a-zA-Z0-9\-_]{12}|delete)$',
|
regex=r'^([a-zA-Z0-9\-_]{12}|delete)$',
|
||||||
required = False,
|
required = False,
|
||||||
help_text = _("12 alphanumeric characters, dash or underscore, case sensitive."),
|
help_text = _("12 alphanumeric characters, dash or underscore, case sensitive."),
|
||||||
|
@ -150,8 +160,8 @@ class EditionForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
gdrd = forms.RegexField(
|
gdrd = forms.RegexField(
|
||||||
label=_("GoodReads ID"),
|
label=_("GoodReads ID"),
|
||||||
max_length=8,
|
max_length=8,
|
||||||
regex=r'^(\d+|delete)$',
|
regex=r'^(\d+|delete)$',
|
||||||
required = False,
|
required = False,
|
||||||
help_text = _("1-8 digits."),
|
help_text = _("1-8 digits."),
|
||||||
|
@ -160,8 +170,8 @@ class EditionForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
thng = forms.RegexField(
|
thng = forms.RegexField(
|
||||||
label=_("LibraryThing ID"),
|
label=_("LibraryThing ID"),
|
||||||
max_length=8,
|
max_length=8,
|
||||||
regex=r'(^\d+|delete)$',
|
regex=r'(^\d+|delete)$',
|
||||||
required = False,
|
required = False,
|
||||||
help_text = _("1-8 digits."),
|
help_text = _("1-8 digits."),
|
||||||
|
@ -170,7 +180,7 @@ class EditionForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
oclc = forms.RegexField(
|
oclc = forms.RegexField(
|
||||||
label=_("OCLCnum"),
|
label=_("OCLCnum"),
|
||||||
regex=r'^(\d\d\d\d\d\d\d\d\d*|delete)$',
|
regex=r'^(\d\d\d\d\d\d\d\d\d*|delete)$',
|
||||||
required = False,
|
required = False,
|
||||||
help_text = _("8 or more digits."),
|
help_text = _("8 or more digits."),
|
||||||
|
@ -182,132 +192,191 @@ class EditionForm(forms.ModelForm):
|
||||||
label=_("HTTP URL"),
|
label=_("HTTP URL"),
|
||||||
# https://mathiasbynens.be/demo/url-regex
|
# https://mathiasbynens.be/demo/url-regex
|
||||||
regex=re.compile(r"(https?|ftp)://(-\.)?([^\s/?\.#]+\.?)+(/[^\s]*)?$",
|
regex=re.compile(r"(https?|ftp)://(-\.)?([^\s/?\.#]+\.?)+(/[^\s]*)?$",
|
||||||
flags=re.IGNORECASE|re.S ),
|
flags=re.IGNORECASE|re.S ),
|
||||||
required = False,
|
required = False,
|
||||||
help_text = _("no spaces of funny stuff."),
|
help_text = _("no spaces of funny stuff."),
|
||||||
error_messages = {
|
error_messages = {
|
||||||
'invalid': _("This value must be a valid http(s) URL."),
|
'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)
|
language = forms.ChoiceField(choices=LANGUAGES)
|
||||||
|
age_level = forms.ChoiceField(choices=AGE_LEVEL_CHOICES, required=False)
|
||||||
description = forms.CharField( required=False, widget=CKEditorWidget())
|
description = forms.CharField( required=False, widget=CKEditorWidget())
|
||||||
coverfile = forms.ImageField(required=False)
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(EditionForm, self).__init__(*args, **kwargs)
|
super(EditionForm, self).__init__(*args, **kwargs)
|
||||||
self.relators = []
|
self.relators = []
|
||||||
if self.instance:
|
if self.instance:
|
||||||
for relator in self.instance.relators.all():
|
for relator in self.instance.relators.all():
|
||||||
select = forms.Select(choices=CREATOR_RELATIONS).render('change_relator_%s' % relator.id , relator.relation.code )
|
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):
|
def clean(self):
|
||||||
has_isbn = self.cleaned_data.get("isbn", False) not in nulls
|
has_isbn = self.cleaned_data.get("isbn", False) not in nulls
|
||||||
has_oclc = self.cleaned_data.get("oclc", 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_goog = self.cleaned_data.get("goog", False) not in nulls
|
||||||
has_http = self.cleaned_data.get("http", 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:
|
has_doi = self.cleaned_data.get("doi", False) not in nulls
|
||||||
raise forms.ValidationError(_("There must be either an ISBN or an OCLC number."))
|
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
|
return self.cleaned_data
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Edition
|
model = Edition
|
||||||
exclude = ('created', 'work')
|
exclude = ('created', 'work')
|
||||||
widgets = {
|
widgets = {
|
||||||
'title': forms.TextInput(attrs={'size': 40}),
|
'title': forms.TextInput(attrs={'size': 40}),
|
||||||
'add_author': forms.TextInput(attrs={'size': 30}),
|
'add_author': forms.TextInput(attrs={'size': 30}),
|
||||||
'add_subject': forms.TextInput(attrs={'size': 30}),
|
'add_subject': forms.TextInput(attrs={'size': 30}),
|
||||||
'unglued': forms.CheckboxInput(),
|
'unglued': forms.CheckboxInput(),
|
||||||
'cover_image': forms.TextInput(attrs={'size': 60}),
|
'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):
|
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):
|
def __init__(self, campaign_type=BUY2UNGLUE, *args, **kwargs):
|
||||||
super(EbookFileForm, self).__init__(*args, **kwargs)
|
super(EbookFileForm, self).__init__(*args, **kwargs)
|
||||||
self.campaign_type = campaign_type
|
self.campaign_type = campaign_type
|
||||||
if campaign_type == BUY2UNGLUE:
|
if campaign_type == BUY2UNGLUE:
|
||||||
self.fields['format'].widget=forms.HiddenInput()
|
self.fields['format'].widget = forms.HiddenInput()
|
||||||
if campaign_type == THANKS:
|
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):
|
def clean_format(self):
|
||||||
if self.campaign_type is BUY2UNGLUE:
|
if self.campaign_type is BUY2UNGLUE:
|
||||||
return 'epub'
|
return 'epub'
|
||||||
else:
|
else:
|
||||||
logger.info("EbookFileForm "+self.cleaned_data.get('format',''))
|
logger.info("EbookFileForm "+self.cleaned_data.get('format',''))
|
||||||
return self.cleaned_data.get('format','')
|
return self.cleaned_data.get('format','')
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
format = self.cleaned_data['format']
|
format = self.cleaned_data['format']
|
||||||
the_file = self.cleaned_data.get('file',None)
|
the_file = self.cleaned_data.get('file', None)
|
||||||
if the_file and the_file.name:
|
test_file(the_file)
|
||||||
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) )
|
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = EbookFile
|
model = EbookFile
|
||||||
widgets = { 'edition': forms.HiddenInput}
|
widgets = { 'edition': forms.HiddenInput}
|
||||||
exclude = { 'created', 'asking' }
|
exclude = { 'created', 'asking', 'ebook' }
|
||||||
|
|
||||||
class EbookForm(forms.ModelForm):
|
class EbookForm(forms.ModelForm):
|
||||||
|
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:
|
class Meta:
|
||||||
model = Ebook
|
model = Ebook
|
||||||
exclude =( 'created', 'download_count', 'active', 'filesize')
|
exclude = ('created', 'download_count', 'active', 'filesize', 'version_iter')
|
||||||
widgets = {
|
widgets = {
|
||||||
'edition': forms.HiddenInput,
|
'edition': forms.HiddenInput,
|
||||||
'user': forms.HiddenInput,
|
'user': forms.HiddenInput,
|
||||||
'provider': forms.HiddenInput,
|
'provider': forms.HiddenInput,
|
||||||
'url': forms.TextInput(attrs={'size' : 60}),
|
|
||||||
}
|
}
|
||||||
|
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):
|
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:
|
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."))
|
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
|
return new_provider
|
||||||
|
|
||||||
def clean_url(self):
|
def clean_url(self):
|
||||||
url = self.data[self.prefix + '-url']
|
url = self.cleaned_data['url']
|
||||||
try:
|
try:
|
||||||
Ebook.objects.get(url=url)
|
Ebook.objects.get(url=url)
|
||||||
except Ebook.DoesNotExist:
|
except Ebook.DoesNotExist:
|
||||||
return url
|
return url
|
||||||
raise forms.ValidationError(_("There's already an ebook with that 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 ):
|
def UserClaimForm ( user_instance, *args, **kwargs ):
|
||||||
class ClaimForm(forms.ModelForm):
|
class ClaimForm(forms.ModelForm):
|
||||||
i_agree=forms.BooleanField(error_messages={'required': 'You must agree to the Terms in order to claim a work.'})
|
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)
|
rights_holder = forms.ModelChoiceField(queryset=user_instance.rights_holder.all(), empty_label=None)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Claim
|
model = Claim
|
||||||
exclude = ('status',)
|
exclude = ('status',)
|
||||||
widgets = {
|
widgets = {
|
||||||
'user': forms.HiddenInput,
|
'user': forms.HiddenInput,
|
||||||
'work': forms.HiddenInput,
|
'work': forms.HiddenInput,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(ClaimForm, self).__init__(*args, **kwargs)
|
super(ClaimForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
return ClaimForm()
|
return ClaimForm()
|
||||||
|
|
||||||
class RightsHolderForm(forms.ModelForm):
|
class RightsHolderForm(forms.ModelForm):
|
||||||
owner = AutoCompleteSelectField(
|
owner = AutoCompleteSelectField(
|
||||||
OwnerLookup,
|
OwnerLookup,
|
||||||
|
@ -317,7 +386,7 @@ class RightsHolderForm(forms.ModelForm):
|
||||||
error_messages={'required': 'Please ensure the owner is a valid Unglue.it account.'},
|
error_messages={'required': 'Please ensure the owner is a valid Unglue.it account.'},
|
||||||
)
|
)
|
||||||
email = forms.EmailField(
|
email = forms.EmailField(
|
||||||
label=_("notification email address for rights holder"),
|
label=_("notification email address for rights holder"),
|
||||||
max_length=100,
|
max_length=100,
|
||||||
error_messages={'required': 'Please enter an email address for the rights holder.'},
|
error_messages={'required': 'Please enter an email address for the rights holder.'},
|
||||||
)
|
)
|
||||||
|
@ -333,12 +402,12 @@ class RightsHolderForm(forms.ModelForm):
|
||||||
return rights_holder_name
|
return rights_holder_name
|
||||||
raise forms.ValidationError(_("Another rights holder with that name already exists."))
|
raise forms.ValidationError(_("Another rights holder with that name already exists."))
|
||||||
|
|
||||||
|
|
||||||
class ProfileForm(forms.ModelForm):
|
class ProfileForm(forms.ModelForm):
|
||||||
clear_facebook=forms.BooleanField(required=False)
|
clear_facebook = forms.BooleanField(required=False)
|
||||||
clear_twitter=forms.BooleanField(required=False)
|
clear_twitter = forms.BooleanField(required=False)
|
||||||
clear_goodreads=forms.BooleanField(required=False)
|
clear_goodreads = forms.BooleanField(required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = UserProfile
|
model = UserProfile
|
||||||
fields = 'tagline', 'librarything_id', 'home_url', 'clear_facebook', 'clear_twitter', 'clear_goodreads', 'avatar_source'
|
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):
|
def clean(self):
|
||||||
# check that if a social net is cleared, we're not using it a avatar source
|
# 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:
|
if self.cleaned_data.get("clear_facebook", False) and self.cleaned_data.get("avatar_source", None) == FACEBOOK:
|
||||||
self.cleaned_data["avatar_source"]==UNGLUEITAR
|
self.cleaned_data["avatar_source"] == UNGLUEITAR
|
||||||
if self.cleaned_data.get("clear_twitter", False) and self.cleaned_data.get("avatar_source", None)==TWITTER:
|
if self.cleaned_data.get("clear_twitter", False) and self.cleaned_data.get("avatar_source", None) == TWITTER:
|
||||||
self.cleaned_data["avatar_source"]==UNGLUEITAR
|
self.cleaned_data["avatar_source"] == UNGLUEITAR
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
class CloneCampaignForm(forms.Form):
|
class CloneCampaignForm(forms.Form):
|
||||||
|
@ -395,30 +464,33 @@ def getTransferCreditForm(maximum, data=None, *args, **kwargs ):
|
||||||
)
|
)
|
||||||
amount = forms.IntegerField(
|
amount = forms.IntegerField(
|
||||||
required=True,
|
required=True,
|
||||||
min_value=1,
|
min_value=1,
|
||||||
max_value=maximum,
|
max_value=maximum,
|
||||||
label="Transfer Amount",
|
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 )
|
return TransferCreditForm( data=data )
|
||||||
|
|
||||||
|
|
||||||
class WorkForm(forms.Form):
|
class WorkForm(forms.Form):
|
||||||
other_work = forms.ModelChoiceField(queryset=Work.objects.all(),
|
other_work = forms.ModelChoiceField(queryset=Work.objects.all(),
|
||||||
widget=forms.HiddenInput(),
|
widget=forms.HiddenInput(),
|
||||||
required=True,
|
required=True,
|
||||||
error_messages={'required': 'Missing work to merge with.'},
|
error_messages={'required': 'Missing work to merge with.'},
|
||||||
)
|
)
|
||||||
work=None
|
work = None
|
||||||
|
|
||||||
def clean_other_work(self):
|
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"))
|
raise forms.ValidationError(_("You can't merge a work into itself"))
|
||||||
return self.cleaned_data["other_work"]
|
return self.cleaned_data["other_work"]
|
||||||
|
|
||||||
def __init__(self, work=None, *args, **kwargs):
|
def __init__(self, work=None, *args, **kwargs):
|
||||||
super(WorkForm, self).__init__(*args, **kwargs)
|
super(WorkForm, self).__init__(*args, **kwargs)
|
||||||
self.work=work
|
self.work = work
|
||||||
|
|
||||||
class OtherWorkForm(WorkForm):
|
class OtherWorkForm(WorkForm):
|
||||||
other_work = AutoCompleteSelectField(
|
other_work = AutoCompleteSelectField(
|
||||||
|
@ -427,12 +499,12 @@ class OtherWorkForm(WorkForm):
|
||||||
widget=AutoCompleteSelectWidget(WorkLookup),
|
widget=AutoCompleteSelectWidget(WorkLookup),
|
||||||
required=True,
|
required=True,
|
||||||
error_messages={'required': 'Missing work to merge with.'},
|
error_messages={'required': 'Missing work to merge with.'},
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(OtherWorkForm, self).__init__(*args, **kwargs)
|
super(OtherWorkForm, self).__init__(*args, **kwargs)
|
||||||
self.fields['other_work'].widget.update_query_parameters({'language':self.work.language})
|
self.fields['other_work'].widget.update_query_parameters({'language':self.work.language})
|
||||||
|
|
||||||
class EditManagersForm(forms.ModelForm):
|
class EditManagersForm(forms.ModelForm):
|
||||||
managers = AutoCompleteSelectMultipleField(
|
managers = AutoCompleteSelectMultipleField(
|
||||||
OwnerLookup,
|
OwnerLookup,
|
||||||
|
@ -451,7 +523,7 @@ class CustomPremiumForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Premium
|
model = Premium
|
||||||
fields = 'campaign', 'amount', 'description', 'type', 'limit'
|
fields = 'campaign', 'amount', 'description', 'type', 'limit'
|
||||||
widgets = {
|
widgets = {
|
||||||
'description': forms.Textarea(attrs={'cols': 80, 'rows': 4}),
|
'description': forms.Textarea(attrs={'cols': 80, 'rows': 4}),
|
||||||
'campaign': forms.HiddenInput,
|
'campaign': forms.HiddenInput,
|
||||||
'type': forms.HiddenInput(attrs={'value':'XX'}),
|
'type': forms.HiddenInput(attrs={'value':'XX'}),
|
||||||
|
@ -459,21 +531,24 @@ class CustomPremiumForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
def clean_type(self):
|
def clean_type(self):
|
||||||
return 'CU'
|
return 'CU'
|
||||||
|
|
||||||
class OfferForm(forms.ModelForm):
|
class OfferForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Offer
|
model = Offer
|
||||||
fields = 'work', 'price', 'license'
|
fields = 'work', 'price', 'license'
|
||||||
widgets = {
|
widgets = {
|
||||||
'work': forms.HiddenInput,
|
'work': forms.HiddenInput,
|
||||||
'license': 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):
|
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
|
minimum_target = settings.UNGLUEIT_MINIMUM_TARGET
|
||||||
maximum_target = settings.UNGLUEIT_MAXIMUM_TARGET
|
maximum_target = settings.UNGLUEIT_MAXIMUM_TARGET
|
||||||
max_cc_date = settings.MAX_CC_DATE
|
max_cc_date = settings.MAX_CC_DATE
|
||||||
|
@ -490,26 +565,26 @@ class CCDateForm(object):
|
||||||
new_cc_date_initial = self.cleaned_data['cc_date_initial']
|
new_cc_date_initial = self.cleaned_data['cc_date_initial']
|
||||||
if new_cc_date_initial.date() > settings.MAX_CC_DATE:
|
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)
|
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!')
|
raise forms.ValidationError('The initial Ungluing date must be in the future!')
|
||||||
return new_cc_date_initial
|
return new_cc_date_initial
|
||||||
|
|
||||||
class DateCalculatorForm(CCDateForm, forms.ModelForm):
|
class DateCalculatorForm(CCDateForm, forms.ModelForm):
|
||||||
revenue = forms.DecimalField()
|
revenue = forms.DecimalField()
|
||||||
cc_date_initial = forms.DateTimeField(
|
cc_date_initial = forms.DateTimeField(
|
||||||
widget = SelectDateWidget(years=date_selector)
|
widget = SelectDateWidget(years=date_selector)
|
||||||
)
|
)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Campaign
|
model = Campaign
|
||||||
fields = 'target', 'cc_date_initial', 'revenue',
|
fields = 'target', 'cc_date_initial', 'revenue',
|
||||||
|
|
||||||
def getManageCampaignForm ( instance, data=None, initial=None, *args, **kwargs ):
|
def getManageCampaignForm ( instance, data=None, initial=None, *args, **kwargs ):
|
||||||
|
|
||||||
def get_queryset():
|
def get_queryset():
|
||||||
work=instance.work
|
work = instance.work
|
||||||
return Edition.objects.filter(work = 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}))
|
target = forms.DecimalField( required= (instance.type in {REWARDS, BUY2UNGLUE}))
|
||||||
deadline = forms.DateTimeField(
|
deadline = forms.DateTimeField(
|
||||||
required = (instance.type==REWARDS),
|
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
|
widget = SelectDateWidget(years=date_selector) if instance.status=='INITIALIZED' else forms.HiddenInput
|
||||||
)
|
)
|
||||||
paypal_receiver = forms.EmailField(
|
paypal_receiver = forms.EmailField(
|
||||||
label=_("contact email address for this campaign"),
|
label=_("contact email address for this campaign"),
|
||||||
max_length=100,
|
max_length=100,
|
||||||
error_messages={'required': 'You must enter the email we should contact you at for this campaign.'},
|
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,)
|
edition = forms.ModelChoiceField(
|
||||||
publisher = forms.ModelChoiceField(instance.work.publishers(), empty_label='no publisher selected', required = False,)
|
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())
|
work_description = forms.CharField( required=False , widget=CKEditorWidget())
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Campaign
|
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 }
|
widgets = { 'deadline': SelectDateWidget }
|
||||||
|
|
||||||
def clean_target(self):
|
def clean_target(self):
|
||||||
if self.instance.type == THANKS:
|
if self.instance.type == THANKS:
|
||||||
return None
|
return None
|
||||||
new_target = super(ManageCampaignForm,self).clean_target()
|
new_target = super(ManageCampaignForm, self).clean_target()
|
||||||
if self.instance:
|
if self.instance:
|
||||||
if self.instance.status == 'ACTIVE' and self.instance.target < new_target:
|
if self.instance.status == 'ACTIVE' and self.instance.target < new_target:
|
||||||
raise forms.ValidationError(_('The fundraising target for an ACTIVE campaign cannot be increased.'))
|
raise forms.ValidationError(_('The fundraising target for an ACTIVE campaign cannot be increased.'))
|
||||||
return new_target
|
return new_target
|
||||||
|
|
||||||
def clean_cc_date_initial(self):
|
def clean_cc_date_initial(self):
|
||||||
if self.instance.type in {REWARDS,THANKS} :
|
if self.instance.type in {REWARDS, THANKS} :
|
||||||
return None
|
return None
|
||||||
if self.instance:
|
if self.instance:
|
||||||
if self.instance.status != 'INITIALIZED':
|
if self.instance.status != 'INITIALIZED':
|
||||||
# can't change this once launched
|
# can't change this once launched
|
||||||
return self.instance.cc_date_initial
|
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):
|
def clean_deadline(self):
|
||||||
if self.instance.type in {BUY2UNGLUE, THANKS} :
|
if self.instance.type in {BUY2UNGLUE, THANKS} :
|
||||||
return None
|
return None
|
||||||
new_deadline_date = self.cleaned_data['deadline']
|
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:
|
||||||
if self.instance.status == 'ACTIVE':
|
if self.instance.status == 'ACTIVE':
|
||||||
return self.instance.deadline
|
return self.instance.deadline
|
||||||
if new_deadline_date - now() > timedelta(days=int(settings.UNGLUEIT_LONGEST_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))
|
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'))
|
raise forms.ValidationError(_('The chosen closing date is in the past'))
|
||||||
return new_deadline
|
return new_deadline
|
||||||
|
|
||||||
def clean_license(self):
|
def clean_license(self):
|
||||||
new_license = self.cleaned_data['license']
|
new_license = self.cleaned_data['license']
|
||||||
if self.instance:
|
if self.instance:
|
||||||
if self.instance.status == 'ACTIVE' and self.instance.license != new_license:
|
if self.instance.status == 'ACTIVE' and self.instance.license != new_license:
|
||||||
# should only allow change to a less restrictive 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.'))
|
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
|
||||||
elif self.instance.license == 'CC BY' and new_license != 'CC0':
|
elif self.instance.license == 'CC BY' and new_license != 'CC0':
|
||||||
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
|
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.'))
|
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.'))
|
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.'))
|
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.'))
|
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
|
||||||
elif self.instance.license == 'CC0' :
|
elif self.instance.license == 'CC0' :
|
||||||
raise forms.ValidationError(_('The proposed license for an ACTIVE campaign may not add restrictions.'))
|
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.'))
|
raise forms.ValidationError(_('Once you start a campaign with GDFL or LAL, you can\'t use any other license.'))
|
||||||
return new_license
|
return new_license
|
||||||
if initial and not initial.get('edition', None) and not instance.edition:
|
if initial and not initial.get('edition', None) and not instance.edition:
|
||||||
initial['edition']= instance.work.editions.all()[0]
|
initial['edition'] = instance.work.editions.all()[0]
|
||||||
return ManageCampaignForm(instance = instance, data=data, initial=initial)
|
return ManageCampaignForm(instance=instance, data=data, initial=initial)
|
||||||
|
|
||||||
class CampaignPurchaseForm(forms.Form):
|
class CampaignPurchaseForm(forms.Form):
|
||||||
anonymous = forms.BooleanField(required=False, label=_("Make this purchase anonymous, please"))
|
anonymous = forms.BooleanField(required=False, label=_("Make this purchase anonymous, please"))
|
||||||
offer_id = forms.IntegerField(required=False)
|
offer_id = forms.IntegerField(required=False)
|
||||||
offer=None
|
offer = None
|
||||||
library_id = forms.IntegerField(required=False)
|
library_id = forms.IntegerField(required=False)
|
||||||
library = None
|
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_to = forms.EmailField(required = False)
|
||||||
give_message = forms.CharField(required = False, max_length=512, )
|
give_message = forms.CharField(required = False, max_length=512, )
|
||||||
|
|
||||||
def clean_offer_id(self):
|
def clean_offer_id(self):
|
||||||
offer_id = self.cleaned_data['offer_id']
|
offer_id = self.cleaned_data['offer_id']
|
||||||
try:
|
try:
|
||||||
self.offer= Offer.objects.get(id=offer_id)
|
self.offer = Offer.objects.get(id=offer_id)
|
||||||
except Offer.DoesNotExist:
|
except Offer.DoesNotExist:
|
||||||
raise forms.ValidationError(_("Sorry, that offer is not valid."))
|
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)
|
self.library = Library.objects.get(id=library_id)
|
||||||
except Library.DoesNotExist:
|
except Library.DoesNotExist:
|
||||||
raise forms.ValidationError(_("Sorry, that Library is not valid."))
|
raise forms.ValidationError(_("Sorry, that Library is not valid."))
|
||||||
|
|
||||||
def clean_copies(self):
|
def clean_copies(self):
|
||||||
copies = self.cleaned_data.get('copies',1)
|
copies = self.cleaned_data.get('copies', 1)
|
||||||
return copies if copies else 1
|
return copies if copies else 1
|
||||||
|
|
||||||
def clean_anonymous(self):
|
def clean_anonymous(self):
|
||||||
if self.data.get('give', False):
|
if self.data.get('give', False):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return self.cleaned_data['anonymous']
|
return self.cleaned_data['anonymous']
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if self.offer.license == LIBRARY:
|
if self.offer.license == LIBRARY:
|
||||||
if not self.library:
|
if not self.library:
|
||||||
raise forms.ValidationError(_("No library specified." ))
|
raise forms.ValidationError(_("No library specified." ))
|
||||||
if self.data.get('give', False):
|
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." ))
|
raise forms.ValidationError(_("Gift recipient email is needed." ))
|
||||||
else:
|
else:
|
||||||
if 'give_to' in self._errors:
|
if 'give_to' in self._errors:
|
||||||
|
@ -639,28 +725,31 @@ class CampaignPurchaseForm(forms.Form):
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
def amount(self):
|
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
|
@property
|
||||||
def trans_extra(self):
|
def trans_extra(self):
|
||||||
pe = PledgeExtra( anonymous=self.cleaned_data['anonymous'],
|
pe = PledgeExtra( anonymous=self.cleaned_data['anonymous'],
|
||||||
offer = self.offer )
|
offer = self.offer )
|
||||||
if self.library:
|
if self.library:
|
||||||
pe.extra['library_id']=self.library.id
|
pe.extra['library_id'] = self.library.id
|
||||||
pe.extra['copies']=self.cleaned_data.get('copies',1)
|
pe.extra['copies'] = self.cleaned_data.get('copies', 1)
|
||||||
if self.data.get('give', False):
|
if self.data.get('give', False):
|
||||||
pe.extra['give_to']=self.cleaned_data['give_to']
|
pe.extra['give_to'] = self.cleaned_data['give_to']
|
||||||
pe.extra['give_message']=self.cleaned_data['give_message']
|
pe.extra['give_message'] = self.cleaned_data['give_message']
|
||||||
return pe
|
return pe
|
||||||
|
|
||||||
class CampaignThanksForm(forms.Form):
|
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(
|
preapproval_amount = forms.DecimalField(
|
||||||
required = True,
|
required = True,
|
||||||
min_value=D('1.00'),
|
min_value=D('1.00'),
|
||||||
max_value=D('2000.00'),
|
max_value=D('2000.00'),
|
||||||
decimal_places=2,
|
decimal_places=2,
|
||||||
label="Pledge Amount",
|
label="Pledge Amount",
|
||||||
)
|
)
|
||||||
@property
|
@property
|
||||||
|
@ -672,43 +761,47 @@ class CampaignPledgeForm(forms.Form):
|
||||||
preapproval_amount = forms.DecimalField(
|
preapproval_amount = forms.DecimalField(
|
||||||
required = False,
|
required = False,
|
||||||
min_value=D('1.00'),
|
min_value=D('1.00'),
|
||||||
max_value=D('2000.00'),
|
max_value=D('2000.00'),
|
||||||
decimal_places=2,
|
decimal_places=2,
|
||||||
label="Pledge Amount",
|
label="Pledge Amount",
|
||||||
)
|
)
|
||||||
def amount(self):
|
def amount(self):
|
||||||
return self.cleaned_data["preapproval_amount"] if self.cleaned_data else None
|
return self.cleaned_data["preapproval_amount"] if self.cleaned_data else None
|
||||||
|
|
||||||
anonymous = forms.BooleanField(required=False, label=_("Make this pledge anonymous, please"))
|
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:"))
|
ack_dedication = forms.CharField(required=False, max_length=140, label=_("Your dedication:"))
|
||||||
|
|
||||||
premium_id = forms.IntegerField(required=False)
|
premium_id = forms.IntegerField(required=False)
|
||||||
premium=None
|
premium = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def trans_extra(self):
|
def trans_extra(self):
|
||||||
return PledgeExtra( anonymous=self.cleaned_data['anonymous'],
|
return PledgeExtra( anonymous=self.cleaned_data['anonymous'],
|
||||||
ack_name=self.cleaned_data['ack_name'],
|
ack_name=self.cleaned_data['ack_name'],
|
||||||
ack_dedication=self.cleaned_data['ack_dedication'],
|
ack_dedication=self.cleaned_data['ack_dedication'],
|
||||||
premium=self.premium)
|
premium=self.premium)
|
||||||
|
|
||||||
def clean_preapproval_amount(self):
|
def clean_preapproval_amount(self):
|
||||||
preapproval_amount = self.cleaned_data['preapproval_amount']
|
preapproval_amount = self.cleaned_data['preapproval_amount']
|
||||||
if preapproval_amount is None:
|
if preapproval_amount is None:
|
||||||
raise forms.ValidationError(_("Please enter a pledge amount."))
|
raise forms.ValidationError(_("Please enter a pledge amount."))
|
||||||
return preapproval_amount
|
return preapproval_amount
|
||||||
|
|
||||||
def clean_premium_id(self):
|
def clean_premium_id(self):
|
||||||
premium_id = self.cleaned_data['premium_id']
|
premium_id = self.cleaned_data['premium_id']
|
||||||
try:
|
try:
|
||||||
self.premium= Premium.objects.get(id=premium_id)
|
self.premium = Premium.objects.get(id=premium_id)
|
||||||
if self.premium.limit>0:
|
if self.premium.limit > 0:
|
||||||
if self.premium.limit<=self.premium.premium_count:
|
if self.premium.limit <= self.premium.premium_count:
|
||||||
raise forms.ValidationError(_("Sorry, that premium is fully subscribed."))
|
raise forms.ValidationError(_("Sorry, that premium is fully subscribed."))
|
||||||
except Premium.DoesNotExist:
|
except Premium.DoesNotExist:
|
||||||
raise forms.ValidationError(_("Sorry, that premium is not valid."))
|
raise forms.ValidationError(_("Sorry, that premium is not valid."))
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
# check on whether the preapproval amount is < amount for premium tier. If so, put an error message
|
# 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")
|
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
|
# preapproval_amount failed validation, that error is the relevant one
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
elif self.premium is None:
|
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:
|
elif preapproval_amount < self.premium.amount:
|
||||||
logger.info("raising form validating error")
|
logger.info("raising form validating error")
|
||||||
raise forms.ValidationError(_("Sorry, you must pledge at least $%s to select that premium." % (self.premium.amount)))
|
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):
|
class BaseCCMixin(forms.Form):
|
||||||
work_id = forms.IntegerField(required=False, widget=forms.HiddenInput())
|
work_id = forms.IntegerField(required=False, widget=forms.HiddenInput())
|
||||||
preapproval_amount= forms.DecimalField(
|
preapproval_amount = forms.DecimalField(
|
||||||
required=False,
|
required=False,
|
||||||
min_value=D('1.00'),
|
min_value=D('1.00'),
|
||||||
max_value=D('100000.00'),
|
max_value=D('100000.00'),
|
||||||
decimal_places=2,
|
decimal_places=2,
|
||||||
label="Amount",
|
label="Amount",
|
||||||
)
|
)
|
||||||
class UserCCMixin(forms.Form):
|
class UserCCMixin(forms.Form):
|
||||||
|
@ -751,7 +844,7 @@ class CCForm(UserCCMixin, BaseCCForm):
|
||||||
|
|
||||||
class AccountCCForm( BaseCCMixin, UserCCMixin, forms.Form):
|
class AccountCCForm( BaseCCMixin, UserCCMixin, forms.Form):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class GoodreadsShelfLoadingForm(forms.Form):
|
class GoodreadsShelfLoadingForm(forms.Form):
|
||||||
goodreads_shelf_name_number = forms.CharField(widget=forms.Select(choices=(
|
goodreads_shelf_name_number = forms.CharField(widget=forms.Select(choices=(
|
||||||
('all','all'),
|
('all','all'),
|
||||||
|
@ -767,40 +860,60 @@ class PledgeCancelForm(forms.Form):
|
||||||
|
|
||||||
class CampaignAdminForm(forms.Form):
|
class CampaignAdminForm(forms.Form):
|
||||||
campaign_id = forms.IntegerField()
|
campaign_id = forms.IntegerField()
|
||||||
|
|
||||||
class EmailShareForm(forms.Form):
|
class EmailShareForm(forms.Form):
|
||||||
recipient = forms.EmailField(error_messages={'required': 'Please specify a recipient.'})
|
recipient = forms.EmailField(error_messages={'required': 'Please specify a recipient.'})
|
||||||
subject = forms.CharField(max_length=100, error_messages={'required': 'Please specify a subject.'})
|
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
|
# 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
|
# 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
|
# and may iterate several times as it catches user errors, losing URL info
|
||||||
next = forms.CharField(widget=forms.HiddenInput())
|
next = forms.CharField(widget=forms.HiddenInput())
|
||||||
|
|
||||||
class FeedbackForm(forms.Form):
|
class FeedbackForm(forms.Form):
|
||||||
sender = forms.EmailField(widget=forms.TextInput(attrs={'size':50}), label="Your email", error_messages={'required': 'Please specify your email address.'})
|
sender = forms.EmailField(
|
||||||
subject = forms.CharField(max_length=500, widget=forms.TextInput(attrs={'size':50}), error_messages={'required': 'Please specify a subject.'})
|
widget=forms.TextInput(attrs={'size':50}),
|
||||||
message = forms.CharField(widget=forms.Textarea(), error_messages={'required': 'Please specify a message.'})
|
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())
|
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())
|
answer = forms.IntegerField(widget=forms.HiddenInput())
|
||||||
num1 = forms.IntegerField(widget=forms.HiddenInput())
|
num1 = forms.IntegerField(widget=forms.HiddenInput())
|
||||||
num2 = forms.IntegerField(widget=forms.HiddenInput())
|
num2 = forms.IntegerField(widget=forms.HiddenInput())
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = self.cleaned_data
|
cleaned_data = self.cleaned_data
|
||||||
notarobot = str(cleaned_data.get("notarobot"))
|
notarobot = str(cleaned_data.get("notarobot"))
|
||||||
answer = str(cleaned_data.get("answer"))
|
answer = str(cleaned_data.get("answer"))
|
||||||
if notarobot != answer:
|
if notarobot != answer:
|
||||||
raise forms.ValidationError(_("Whoops, try that sum again."))
|
raise forms.ValidationError(_("Whoops, try that sum again."))
|
||||||
|
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
class MsgForm(forms.Form):
|
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):
|
def full_clean(self):
|
||||||
super(MsgForm,self).full_clean()
|
super(MsgForm, self).full_clean()
|
||||||
if self.data.has_key("supporter"):
|
if self.data.has_key("supporter"):
|
||||||
try:
|
try:
|
||||||
self.cleaned_data['supporter'] = User.objects.get(id=self.data["supporter"])
|
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")
|
raise ValidationError("Work does not exist")
|
||||||
else:
|
else:
|
||||||
raise ValidationError("Work is not specified")
|
raise ValidationError("Work is not specified")
|
||||||
|
|
||||||
class PressForm(forms.ModelForm):
|
class PressForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Press
|
model = Press
|
||||||
exclude = ()
|
exclude = ()
|
||||||
|
|
||||||
widgets = {
|
widgets = {
|
||||||
'date': SelectDateWidget(years=range(2010,2025)),
|
'date': SelectDateWidget(years=range(2010,2025)),
|
||||||
}
|
}
|
||||||
|
|
||||||
class KindleEmailForm(forms.Form):
|
class KindleEmailForm(forms.Form):
|
||||||
kindle_email = forms.EmailField()
|
kindle_email = forms.EmailField()
|
||||||
|
|
||||||
|
|
||||||
class LibModeForm(forms.ModelForm):
|
class LibModeForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Libpref
|
model = Libpref
|
||||||
|
@ -836,7 +949,11 @@ class LibModeForm(forms.ModelForm):
|
||||||
|
|
||||||
class RegiftForm(forms.Form):
|
class RegiftForm(forms.Form):
|
||||||
give_to = forms.EmailField(label="email address of recipient")
|
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):
|
class SubjectSelectForm(forms.Form):
|
||||||
add_kw = AutoCompleteSelectField(
|
add_kw = AutoCompleteSelectField(
|
||||||
|
@ -855,4 +972,4 @@ class MapSubjectForm(forms.Form):
|
||||||
widget=AutoCompleteSelectWidget(SubjectLookup,allow_new=False),
|
widget=AutoCompleteSelectWidget(SubjectLookup,allow_new=False),
|
||||||
label='Target Subject',
|
label='Target Subject',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ $j(document).ready(function() {
|
||||||
<a href="{% url 'download_ebook' ebook.id %}">
|
<a href="{% url 'download_ebook' ebook.id %}">
|
||||||
<img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a>
|
<img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a>
|
||||||
<a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }}" title="{{ ebook.format }}" /></a>
|
<a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }}" title="{{ ebook.format }}" /></a>
|
||||||
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a>
|
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %}
|
||||||
{% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %}
|
{% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ $j(document).ready(function() {
|
||||||
<a href="{% url 'download_ebook' ebook.id %}">
|
<a href="{% url 'download_ebook' ebook.id %}">
|
||||||
<img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a>
|
<img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a>
|
||||||
<a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }} at {{ebook.provider}}" title="{{ ebook.format }} at {{ebook.provider}}" /></a>
|
<a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }} at {{ebook.provider}}" title="{{ ebook.format }} at {{ebook.provider}}" /></a>
|
||||||
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }} at {{ ebook.provider }}</a>
|
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }} {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %} at {{ ebook.provider }}</a>
|
||||||
{% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %}
|
{% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %}
|
||||||
|
|
||||||
{% if not forloop.last %}<br /><br />{% endif %}
|
{% if not forloop.last %}<br /><br />{% endif %}
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<br />
|
<br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if edition.note %}
|
||||||
|
{{ edition.note }}.<br />
|
||||||
|
{% endif %}
|
||||||
|
{% if edition.downloads.count %}
|
||||||
|
{{ edition.downloads.count }} ebooks<br />
|
||||||
|
{% endif %}
|
||||||
{% if edition.publisher %}
|
{% if edition.publisher %}
|
||||||
Publisher: <a href="{% url 'bypubname_list' edition.publisher_name.id %}">{{edition.publisher}}</a><br />
|
Publisher: <a href="{% url 'bypubname_list' edition.publisher_name.id %}">{{edition.publisher}}</a><br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -28,6 +34,9 @@
|
||||||
{% if edition.oclc %}
|
{% if edition.oclc %}
|
||||||
OCLC: <a href="http://www.worldcat.org/oclc/{{ edition.oclc }}">{{ edition.oclc }}</a><br />
|
OCLC: <a href="http://www.worldcat.org/oclc/{{ edition.oclc }}">{{ edition.oclc }}</a><br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if edition.doi %}
|
||||||
|
DOI: <a href="https://dx.doi.org/{{ edition.doi }}">{{ edition.doi }}</a><br />
|
||||||
|
{% endif %}
|
||||||
{% if edition.http_id %}
|
{% if edition.http_id %}
|
||||||
web: <a href="{{ edition.http_id }}">{{ edition.http_id }}</a><br />
|
web: <a href="{{ edition.http_id }}">{{ edition.http_id }}</a><br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,31 +1,48 @@
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
{% if edition.ebook_form %}
|
{% if ebook_form and show_ebook_form %}
|
||||||
{% if show_ebook_form %}
|
<div id="add_ebook">
|
||||||
<div id="add_ebook">
|
|
||||||
{% if alert %}<div class="yikes">{{alert}}</div>{% endif %}
|
{% if alert %}<div class="yikes">{{alert}}</div>{% endif %}
|
||||||
{% if edition.ebooks.all.0 %}
|
{% if edition.ebooks.all.0 %}
|
||||||
<h2>eBooks for this Edition</h2>
|
<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 %}
|
|
||||||
|
|
||||||
|
{% 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 %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
|
@ -20,12 +20,20 @@
|
||||||
<b>LibraryThing ID</b>: {{ edition.librarything_id }}<br />
|
<b>LibraryThing ID</b>: {{ edition.librarything_id }}<br />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
{% if edition.ebooks.all.0 %}
|
||||||
|
<h2>Active eBooks for this Work</h2>
|
||||||
|
{% for ebook in edition.work.ebooks %}
|
||||||
|
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> {{ebook.rights}} at {{ebook.provider}}.
|
||||||
|
{% if ebook.version_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 %}
|
{% if edition.ebook_files.all %}
|
||||||
<h2> Ebook Files for this Edition</h2>
|
<h2> Ebook Files for this Edition</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{% for ebook_file in edition.ebook_files.all %}
|
{% for ebook_file in edition.ebook_files.all %}
|
||||||
{% if ebook_file.file %}
|
{% if ebook_file.file %}
|
||||||
<li>{% if ebook_file.active %}<span class="yikes">ACTIVE</span> {% endif %}<a href="{{ebook_file.file.url}}">{{ebook_file.file}}</a> created {{ebook_file.created}} {% if ebook_file.asking %}(This file has had the campaign 'ask' added.){% endif %}</li>
|
<li>{% if ebook_file.active %}<span class="yikes">ACTIVE</span> {% elif ebook_file.ebook.active %} MIRROR {% endif %}<a href="{{ebook_file.file.url}}">{{ebook_file.file}}</a> created {{ebook_file.created}} {% if ebook_file.asking %}(This file has had the campaign 'ask' added.){% endif %}</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -66,15 +74,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>
|
For ePUB files, use the <a href=https://code.google.com/p/epubcheck/">epubcheck</a> tool to make sure everything will work properly.</p>
|
||||||
<form method="POST" action="#" enctype="multipart/form-data">
|
<form method="POST" action="#" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{form.as_p}}
|
{{form.edition.errors}}{{form.edition}}
|
||||||
|
<p>{{form.format.errors}}Format: {{form.format}}</p>
|
||||||
|
<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">
|
<input type="submit" id="submit_file" value="submit ebook file">
|
||||||
</form>
|
</form>
|
||||||
{% if edition.work %}
|
|
||||||
<h2>More Edition Management</h2>
|
<h2>More Edition Management</h2>
|
||||||
|
|
||||||
<div><a href="{% url 'new_edition' edition.work.id edition.id %}">Edit this edition</a></div>
|
<div><a href="{% url 'new_edition' edition.work.id edition.id %}">Edit this edition</a></div>
|
||||||
{% if edition.work.last_campaign %}
|
{% if edition.work.last_campaign %}
|
||||||
<div><a href="{% url 'manage_campaign' edition.work.last_campaign.id %}">Manage this campaign</a></div>
|
<div><a href="{% url 'manage_campaign' edition.work.last_campaign.id %}">Manage this campaign</a></div>
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -136,14 +136,13 @@ Please fix the following before launching your campaign:
|
||||||
<div class="edition_form" id="edition_{{edition.id}}">
|
<div class="edition_form" id="edition_{{edition.id}}">
|
||||||
<p> Edition {{ edition.id }}: <input type="radio" {% ifequal edition.id form.edition.value %}checked="checked" {% endifequal %}id="id_edition_{{forloop.counter}}" value="{{edition.id}}" name="edition" /><label for="id_edition_{{forloop.counter}}"> Prefer this edition </label>
|
<p> Edition {{ edition.id }}: <input type="radio" {% ifequal edition.id form.edition.value %}checked="checked" {% endifequal %}id="id_edition_{{forloop.counter}}" value="{{edition.id}}" name="edition" /><label for="id_edition_{{forloop.counter}}"> Prefer this edition </label>
|
||||||
<ul style="text-indent:1em">
|
<ul style="text-indent:1em">
|
||||||
<li style="text-indent:2.5em">There are {{ edition.downloads.all.count }} downloadable ebook for this edition</li>
|
|
||||||
<li style="text-indent:2.5em"><a href="{% url 'new_edition' edition.work.id edition.id %}"> Edit </a> this edition</li>
|
<li style="text-indent:2.5em"><a href="{% url 'new_edition' edition.work.id edition.id %}"> Edit </a> this edition</li>
|
||||||
{% ifnotequal campaign.type 1 %}
|
{% ifnotequal campaign.type 1 %}
|
||||||
{% if campaign.rh.can_sell %}
|
{% if campaign.rh.can_sell %}
|
||||||
{% if edition.ebook_files.all.0 %}
|
{% if edition.ebook_files.all.0 %}
|
||||||
<li style="text-indent:2.5em">You have uploaded ebook files for this edition. <a href="{% url 'edition_uploads' edition.id %}"> Upload another</a></li>
|
<li style="text-indent:2.5em">You have uploaded ebook files for this edition. You can <a href="{% url 'edition_uploads' edition.id %}"> manage its ebooks or upload another</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li style="text-indent:2.5em">You can <a href="{% url 'edition_uploads' edition.id %}"> Load a file</a> for this edition.</li>
|
<li style="text-indent:2.5em">You can <a href="{% url 'edition_uploads' edition.id %}"> Manage ebooks</a> for this edition.</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endifnotequal %}
|
{% endifnotequal %}
|
||||||
|
@ -156,11 +155,11 @@ Please fix the following before launching your campaign:
|
||||||
|
|
||||||
<p>If you don't see an edition that matches what you want to release, you can <a href="{% url 'rh_edition' work.id '' %}">create a new edition</a>.</p>
|
<p>If you don't see an edition that matches what you want to release, you can <a href="{% url 'rh_edition' work.id '' %}">create a new edition</a>.</p>
|
||||||
{% if campaign.work.ebookfiles.0 %}
|
{% if campaign.work.ebookfiles.0 %}
|
||||||
<h3>Uploaded Files</h3>
|
<h3>All ebook files for this book</h3>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if campaign.work.epubfiles.0 %}
|
{% if campaign.work.epubfiles.0 %}
|
||||||
{% for ebf in campaign.work.epubfiles %}
|
{% for ebf in campaign.work.epubfiles %}
|
||||||
<p>{% if ebf.active %}<span class="yikes">ACTIVE</span> {% endif %}EPUB file: <a href="{{ebf.file.url}}">{{ebf.file}}</a> <br />created {{ebf.created}} for edition <a href="#edition_{{ebf.edition.id}}">{{ebf.edition.id}}</a> {% if ebf.asking %}(This file has had the campaign 'ask' added.){% endif %}<br />{% if ebf.active %}{% ifequal action 'mademobi' %}<span class="yikes">A MOBI file is being generated. </span> (Takes a minute or two.) {% else %}You can <a href="{% url 'makemobi' campaign.id %}">generate a MOBI file.</a> {% endifequal %}{% endif %}</p>
|
<p>{% if ebf.active %}<span class="yikes">ACTIVE</span> {% elif ebf.ebook.active %} MIRROR {% endif %}EPUB file: <a href="{{ebf.file.url}}">{{ebf.file}}</a> <br />created {{ebf.created}} for edition <a href="#edition_{{ebf.edition.id}}">{{ebf.edition.id}}</a> {% if ebf.asking %}(This file has had the campaign 'ask' added.){% endif %}<br />{% if ebf.active %}{% ifequal action 'mademobi' %}<span class="yikes">A MOBI file is being generated. </span> (Takes a minute or two.) {% else %}You can <a href="{% url 'makemobi' campaign.id ebf.id %}">generate a MOBI file.</a> {% endifequal %}{% endif %}</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if campaign.work.test_acqs.0 %}
|
{% if campaign.work.test_acqs.0 %}
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
@ -6,7 +6,27 @@
|
||||||
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
|
<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" 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 %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block doccontent %}
|
{% block doccontent %}
|
||||||
|
|
|
@ -93,11 +93,12 @@ ul.fancytree-container {
|
||||||
<h2>Create New Edition</h2>
|
<h2>Create New Edition</h2>
|
||||||
{% endif %}
|
{% 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="#">
|
<form id="editform" enctype="multipart/form-data" method="POST" action="#">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.work }}
|
{{ form.work }}
|
||||||
{{ form.non_field_errors }}
|
{{ form.non_field_errors }}
|
||||||
|
<!--{{ form.errors }}-->
|
||||||
<div>
|
<div>
|
||||||
<p><b>Title</b>: {{ form.title.errors }}{{ form.title }}</p>
|
<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>
|
<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>
|
<input type="submit" name="add_author_submit" value="Add Author" id="submit_author"></p>
|
||||||
|
|
||||||
<p><b>Language</b>: {{ form.language.errors }}{{ form.language }}</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>
|
<h4> Identifiers </h4>
|
||||||
{% if id_msg %} <span class="errorlist">{{ id_msg }} </span>{% endif %}
|
{% if id_msg %} <span class="errorlist">{{ id_msg }} </span>{% endif %}
|
||||||
<p> Enter 'delete' to remove the identifier. </p>
|
<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>Google Books ID</b>: {{ form.goog.errors }}{{ form.goog }}</p>
|
||||||
<p><b>GoodReads ID</b>: {{ form.gdrd.errors }}{{ form.gdrd }}</p>
|
<p><b>GoodReads ID</b>: {{ form.gdrd.errors }}{{ form.gdrd }}</p>
|
||||||
<p><b>LibraryThing ID</b>: {{ form.thng.errors }}{{ form.thng }}</p>
|
<p><b>LibraryThing ID</b>: {{ form.thng.errors }}{{ form.thng }}</p>
|
||||||
{% if request.user.is_staff %}
|
<p><b>DOI</b>: {{ form.doi.errors }}{{ form.doi }}</p>
|
||||||
<p><b>HTTP ID</b>: {{ form.http.errors }}{{ form.http }}</p>
|
<p><b>HTTP(S) ID</b>: {{ form.http.errors }}{{ form.http }}</p>
|
||||||
{% endif %}
|
|
||||||
<p><b>Description</b>: <br />
|
<p><b>Description</b>: <br />
|
||||||
{{ form.description.errors }}{{ form.description }}<br />
|
{{ form.description.errors }}{{ form.description }}<br />
|
||||||
(<i>{% if work.last_campaign %}
|
(<i>{% if work.last_campaign %}
|
||||||
|
@ -175,7 +194,7 @@ ul.fancytree-container {
|
||||||
[ no cover specified for this edition ]<br />
|
[ no cover specified for this edition ]<br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ form.cover_image.errors }}{{ form.cover_image }}{{ form.cover_image.help_text }}
|
{{ 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 />
|
OR...<br />
|
||||||
|
|
||||||
{{ form.coverfile.errors }}{{ form.coverfile }}{{ form.coverfile.help_text }}
|
{{ 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>
|
<span itemprop="publisher"><a href="{% url 'bypubname_list' work.last_campaign.publisher.name.id %}">{{ work.last_campaign.publisher }}</a></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span itemprop="datePublished">{{ work.publication_date }}</span>
|
<span itemprop="datePublished">{{ work.publication_date }}</span>
|
||||||
|
<meta itemprop="inLanguage" content="work.language" />
|
||||||
|
<meta itemprop="typicalAgeRange" content="work.age_range" />
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -276,6 +278,18 @@
|
||||||
{{ work.last_campaign.description|safe }}
|
{{ work.last_campaign.description|safe }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
<div id="tabs-2" class="tabs {% if activetab == '2' %}active{% endif %}">
|
<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.
|
This work has been downloaded {{ work.download_count }} times via unglue.it ebook links.
|
||||||
<ol>
|
<ol>
|
||||||
{% for ebook in work.ebooks.all %}
|
{% for ebook in work.ebooks.all %}
|
||||||
<li>{{ ebook.download_count }} - {{ ebook.format }} ({{ ebook.rights }}) at {{ ebook.provider }}</li>
|
<li>{{ ebook.download_count }} - {{ ebook.format }} {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %}({{ ebook.rights }}) at {{ ebook.provider }}. </li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -27,7 +27,7 @@ urlpatterns = [
|
||||||
url(r"^rightsholders/$", views.rh_tools, name="rightsholders"),
|
url(r"^rightsholders/$", views.rh_tools, name="rightsholders"),
|
||||||
url(r"^rightsholders/campaign/(?P<id>\d+)/$", views.manage_campaign, name="manage_campaign"),
|
url(r"^rightsholders/campaign/(?P<id>\d+)/$", views.manage_campaign, name="manage_campaign"),
|
||||||
url(r"^rightsholders/campaign/(?P<id>\d+)/results/$", views.manage_campaign, {'action': 'results'}, name="campaign_results"),
|
url(r"^rightsholders/campaign/(?P<id>\d+)/results/$", views.manage_campaign, {'action': 'results'}, name="campaign_results"),
|
||||||
url(r"^rightsholders/campaign/(?P<id>\d+)/makemobi/$", views.manage_campaign, {'action': 'makemobi'}, name="makemobi"),
|
url(r"^rightsholders/campaign/(?P<id>\d+)/(?P<ebf>\d+)/makemobi/$", views.manage_campaign, {'action': 'makemobi'}, name="makemobi"),
|
||||||
url(r"^rightsholders/campaign/(?P<id>\d+)/mademobi/$", views.manage_campaign, {'action': 'mademobi'}, name="mademobi"),
|
url(r"^rightsholders/campaign/(?P<id>\d+)/mademobi/$", views.manage_campaign, {'action': 'mademobi'}, name="mademobi"),
|
||||||
url(r"^rightsholders/edition/(?P<work_id>\d*)/(?P<edition_id>\d*)$", views.new_edition, {'by': 'rh'}, name="rh_edition"),
|
url(r"^rightsholders/edition/(?P<work_id>\d*)/(?P<edition_id>\d*)$", views.new_edition, {'by': 'rh'}, name="rh_edition"),
|
||||||
url(r"^rightsholders/edition/(?P<edition_id>\d*)/upload/$", views.edition_uploads, name="edition_uploads"),
|
url(r"^rightsholders/edition/(?P<edition_id>\d*)/upload/$", views.edition_uploads, name="edition_uploads"),
|
||||||
|
|
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)
|
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
|
# publisher, date
|
||||||
if edition.publisher:
|
if edition.publisher:
|
||||||
field260 = pymarc.Field(
|
field260 = pymarc.Field(
|
||||||
|
@ -101,7 +112,7 @@ def stub(edition):
|
||||||
if edition.publication_date:
|
if edition.publication_date:
|
||||||
field260.add_subfield('c', unicode(edition.publication_date))
|
field260.add_subfield('c', unicode(edition.publication_date))
|
||||||
record.add_ordered_field(field260)
|
record.add_ordered_field(field260)
|
||||||
|
|
||||||
if edition.description:
|
if edition.description:
|
||||||
#add 520 field (description)
|
#add 520 field (description)
|
||||||
field520 = pymarc.Field(
|
field520 = pymarc.Field(
|
||||||
|
|
|
@ -56,6 +56,7 @@ class AbstractEdition:
|
||||||
publisher = ''
|
publisher = ''
|
||||||
title = ''
|
title = ''
|
||||||
publication_date = ''
|
publication_date = ''
|
||||||
|
note = ''
|
||||||
|
|
||||||
# the edition should be able to report ebook downloads, with should have format and url attributes
|
# the edition should be able to report ebook downloads, with should have format and url attributes
|
||||||
def downloads(self):
|
def downloads(self):
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -63,10 +63,6 @@
|
||||||
width: 660px !important;
|
width: 660px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
color:#3d4e53;
|
|
||||||
}
|
|
||||||
|
|
||||||
#js-search {
|
#js-search {
|
||||||
margin: 0 15px 0 15px !important;
|
margin: 0 15px 0 15px !important;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue