Merge pull request #164 from Gluejar/manage_book_data

Manage book data
pull/1/head
thatandromeda 2013-04-24 11:31:07 -07:00
commit babeb9e4aa
9 changed files with 158 additions and 23 deletions

View File

@ -487,6 +487,20 @@ def merge_works(w1, w2, user=None):
ww.save()
w2.delete()
def detach_edition(e):
"""will detach edition from its work, creating a new stub work. if remerge=true, will see if there's another work to attach to
"""
logger.info("splitting edition %s from %s", e, e.work)
w = models.Work(title=e.title, language = e.work.language)
w.save()
for identifier in e.identifiers.all():
identifier.work = w
identifier.save()
e.work = w
e.save()
def despam_description(description):
""" a lot of descriptions from openlibrary have free-book promotion text; this removes some of it."""

View File

@ -16,7 +16,7 @@ from selectable.forms import AutoCompleteSelectWidget,AutoCompleteSelectField
from regluit.core.models import UserProfile, RightsHolder, Claim, Campaign, Premium, Ebook, Edition, PledgeExtra, Work, Press
from regluit.core.models import TWITTER, FACEBOOK, GRAVATAR
from regluit.core.lookups import OwnerLookup, WorkLookup
from regluit.core.lookups import OwnerLookup, WorkLookup, PublisherNameLookup
from regluit.utils.localdatetime import now
@ -27,10 +27,17 @@ logger = logging.getLogger(__name__)
class EditionForm(forms.ModelForm):
add_author = forms.CharField(max_length=500, required=False)
add_subject = forms.CharField(max_length=200, required=False)
isbn_13 = forms.RegexField(
publisher_name = AutoCompleteSelectField(
PublisherNameLookup,
label='Publisher Name',
widget=AutoCompleteSelectWidget(PublisherNameLookup),
required=False,
)
isbn = forms.RegexField(
label=_("ISBN"),
max_length=13,
regex=r'^97[89]\d\d\d\d\d\d\d\d\d\d$',
regex=r'^(97[89]\d\d\d\d\d\d\d\d\d\d|delete)$',
required = True,
help_text = _("13 digits, no dash."),
error_messages = {
@ -38,9 +45,39 @@ class EditionForm(forms.ModelForm):
'required': _("Yes, we need an ISBN."),
}
)
oclcnum = forms.RegexField(
goog = forms.RegexField(
label=_("Google Books ID"),
max_length=12,
regex=r'^([a-zA-Z0-9\-_]{12}|delete)$',
required = False,
help_text = _("12 alphanumeric characters, dash or underscore, case sensitive."),
error_messages = {
'invalid': _("This value must be 12 alphanumeric characters, dash or underscore."),
}
)
gdrd = forms.RegexField(
label=_("GoodReads ID"),
max_length=8,
regex=r'^(\d+|delete)$',
required = False,
help_text = _("1-8 digits."),
error_messages = {
'invalid': _("This value must be 1-8 digits."),
}
)
thng = forms.RegexField(
label=_("LibraryThing ID"),
max_length=8,
regex=r'(^\d+|delete)$',
required = False,
help_text = _("1-8 digits."),
error_messages = {
'invalid': _("This value must be 1-8 digits."),
}
)
oclc = forms.RegexField(
label=_("OCLCnum"),
regex=r'^\d\d\d\d\d\d\d\d\d*$',
regex=r'^(\d\d\d\d\d\d\d\d\d*|delete)$',
required = False,
help_text = _("8 or more digits."),
error_messages = {
@ -237,7 +274,7 @@ class WorkForm(forms.Form):
class OtherWorkForm(WorkForm):
other_work = AutoCompleteSelectField(
WorkLookup,
label='Other Work',
label='Other Work (title)',
widget=AutoCompleteSelectWidget(WorkLookup),
required=True,
error_messages={'required': 'Missing work to merge with.'},

View File

@ -8,9 +8,12 @@
{% endblock %}
{% block doccontent %}
<h2>{{ work.title }}</h2>
{% if merge_complete %}
<h2>Merge {{ old_work_id }} into {{ work.id }} Complete</h2>
<h2>Merge {{ old_work_id }} into <a href="{% url work work.id %}">{{ work.id }}</a> Complete</h2>
{% include 'workbox.html' %}
<div><a href="?again">Merge more</a><br /><br /></div>
{% else %}
<h2>Merge Works</h2>
<form method="POST" action="#">
@ -31,4 +34,9 @@
{% endif %}
</form>
{% endif %}
<h2>More Edition Management</h2>
<div><a href="{% url split work.id %}">Remove editions from this work</a><br /><br /></div>
<div><a href="{% url new_edition work.id '' %}">Create a new edition for this work</a><br /><br /></div>
{% endblock %}

View File

@ -4,6 +4,7 @@
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/ui-lightness/jquery-ui.css" type="text/css" media="screen">
{{ form.media.css }}
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>
{{ form.media.js }}
{% endblock %}
@ -20,6 +21,7 @@
{{ form.work }}
<div>
<p><b>Title</b>: {{ form.title.errors }}{{ form.title }}</p>
<p><b>Publisher</b>: {{ form.publisher_name.errors }}{{ form.publisher_name }}</p>
<p>
<b>Authors</b>:
@ -43,9 +45,14 @@
<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>ISBN-13</b>: {{ form.isbn_13.errors }}{{ form.isbn_13 }}</p>
<p><b>OCLC Number</b>: {{ form.oclcnum.errors }}{{ form.oclcnum }}</p>
<h4> Identifiers </h4>
{% if id_msg %} <span class="errorlist">{{ id_msg }} </span>{% endif %}
<p> Enter 'delete' to remove the identifier. </p>
<p><b>ISBN-13</b>: {{ form.isbn.errors }}{{ form.isbn }}</p>
<p><b>OCLC Number</b>: {{ form.oclc.errors }}{{ form.oclc }}</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>LibraryThing ID</b>: {{ form.thng.errors }}{{ form.thng }}</p>
<p><b>Description</b>: <br />
{{ form.description.errors }}{{ form.description }}<br />
@ -81,6 +88,11 @@
</div>
<input type="submit" name="create_new_edition" value="{% if edition.pk %}Save Edits{% else %}Create Edition{% endif %}" id="submit">
</form>
{% if edition.work %}
<h2>More Edition Management</h2>
<div><a href="{% url merge edition.work.id %}">Merge other works into this one</a></div>
<div><a href="{% url split edition.work.id %}">Remove editions from this work</a><br /><br /></div>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends "basedocumentation.html" %}
{% block doccontent %}
<h2 class="book-name"><a href="{% url work work.id %}">{{ work.title }}</a></h2>
<h2>Split Editions</h2>
<form method="POST" action="#">
{% csrf_token %}
{{ formset.management_form }}
<dl>
{% for form in formset %}
<dt class="editionbox">
{{ form.instance.title }}, published by {{form.instance.publisher}} in {{ form.instance.publication_date }}
</dt>
<dd>with authors
{% for author in form.instance.authors.all %}
{{author}},
{% endfor %}
<br />
ISBN: {{ form.instance.isbn_13 }}
<br />
{{ form.id }}Split this Edition: {{form.DELETE.0}}
</dd>
{% endfor %}
</dl>
<input type="submit" value="Split Editions" name="submit" />
</form>
<h2>More Edition Management</h2>
<div><a href="{% url merge work.id %}">Merge other works into this one</a></div>
<div><a href="{% url new_edition work.id '' %}">Create a new edition for this work</a><br /><br /></div>
{% endblock %}

View File

@ -320,7 +320,8 @@
{% endif %}
{% if user.is_staff %}
<h4>Related Works</h4>
<a href="{% url merge work_id %}">Merge other works into this one</a><br />
<div><a href="{% url merge work_id %}">Merge other works into this one</a></div>
<div><a href="{% url split work_id %}">Remove editions from this work</a><br /><br /></div>
{% endif %}
{% if work.subjects.all.count > 0 %}
<h4>Subjects</h4>

View File

@ -57,6 +57,7 @@ urlpatterns = patterns(
url(r"^lockss/(?P<year>\d+)/$", "lockss_manifest", name="lockss_manifest"),
url(r"^work/(?P<work_id>\d+)/download/$", "download", name="download"),
url(r"^work/(?P<work_id>\d+)/merge/$", login_required(MergeView.as_view()), name="merge"),
url(r"^work/(?P<work_id>\d+)/split/$", "split_work", name="split"),
url(r"^work/\d+/acks/images/(?P<file_name>[\w\.]*)$", "static_redirect_view",{'dir': 'images'}),
url(r"^work/(?P<work_id>\d+)/librarything/$", "work_librarything", name="work_librarything"),
url(r"^work/(?P<work_id>\d+)/goodreads/$", "work_goodreads", name="work_goodreads"),

View File

@ -35,6 +35,7 @@ from django.core.urlresolvers import reverse
from django.db.models import Q, Count, Sum
from django.forms import Select
from django.forms.models import modelformset_factory
from django.forms.models import inlineformset_factory
from django.http import HttpResponseRedirect, Http404
from django.http import HttpResponse, HttpResponseNotFound
from django.shortcuts import render, render_to_response, get_object_or_404
@ -54,7 +55,7 @@ from regluit.core import tasks
from regluit.core import models, bookloader, librarything
from regluit.core import userlists
from regluit.core import goodreads
from regluit.core.bookloader import merge_works
from regluit.core.bookloader import merge_works, detach_edition
from regluit.core.goodreads import GoodreadsClient
from regluit.core.search import gluejar_search
from regluit.core.signals import supporter_message
@ -407,12 +408,20 @@ def new_edition(request, work_id, edition_id, by=None):
work.title=form.cleaned_data['title']
work.save()
# note: this is very powerful. it can steal an isbn from another edition/work, and it will wipe the changed isbn from the db
models.Identifier.set(type='isbn', value=form.cleaned_data['isbn_13'], edition=edition, work=work)
if form.cleaned_data['oclcnum']:
# note: this is very powerful.(same comment as for isbn) use with care!
models.Identifier.set(type='oclc', value=form.cleaned_data['oclcnum'], edition=edition, work=work)
id_msg=""
for id_type in ('isbn', 'oclc', 'goog', 'thng', 'gdrd'):
id_val = form.cleaned_data[id_type]
if id_val=='delete':
edition.identifiers.filter(type=id_type).delete()
elif id_val:
existing= models.Identifier.objects.filter(type=id_type, value=form.cleaned_data[id_type])
if existing.count() and existing[0].edition != edition:
return render(request, 'new_edition.html', {
'form': form, 'edition': edition,
'id_msg': "%s = %s already exists"%( id_type, id_val ),
})
else:
models.Identifier.set(type=id_type, value=id_val, edition=edition, work=work)
for author_name in edition.new_author_names:
try:
author= models.Author.objects.get(name=author_name)
@ -430,14 +439,18 @@ def new_edition(request, work_id, edition_id, by=None):
else:
form = EditionForm(instance=edition, initial={
'language':language,
'isbn_13':edition.isbn_13,
'oclcnum':edition.oclc,
'publisher_name':edition.publisher_name,
'isbn':edition.isbn_13,
'oclc':edition.oclc,
'description':description,
'title': title
'title': title,
'goog': edition.googlebooks_id,
'gdrd': edition.goodreads_id,
'thng': edition.librarything_id,
})
return render(request, 'new_edition.html', {
'form': form, 'edition': edition
'form': form, 'edition': edition,
})
@ -719,6 +732,22 @@ class CampaignListView(FilterableListView):
context['facet'] =self.kwargs['facet']
return context
@login_required
def split_work(request,work_id):
if not request.user.is_staff:
return render(request, "admins_only.html")
work = get_object_or_404(models.Work, id=work_id)
EditionFormSet = inlineformset_factory(models.Work, models.Edition, fields=(), extra=0 )
if request.method == "POST":
formset = EditionFormSet(data=request.POST, instance=work)
if formset.is_valid():
for form in formset.deleted_forms:
detach_edition(form.instance)
formset = EditionFormSet(instance=work)
return render(request, "split.html", { "work":work, "formset": formset,})
class MergeView(FormView):
template_name="merge.html"
work=None

View File

@ -26,7 +26,7 @@ django-nose-selenium==0.7.3
#django-notification==0.2
git+git://github.com/aladagemre/django-notification.git@2927346f4c513a217ac8ad076e494dd1adbf70e1
django-registration==0.8
django-selectable==0.5.2
django-selectable==0.7.0
django-smtp-ssl==1.0
django-social-auth==0.7.20
django-storages==1.1.6