forked from mirrors/bookwyrm
commit
f220290a2b
8 changed files with 336 additions and 44 deletions
|
@ -143,7 +143,7 @@ class EditionForm(CustomForm):
|
||||||
"created_date",
|
"created_date",
|
||||||
"updated_date",
|
"updated_date",
|
||||||
"edition_rank",
|
"edition_rank",
|
||||||
"authors", # TODO
|
"authors",
|
||||||
"parent_work",
|
"parent_work",
|
||||||
"shelves",
|
"shelves",
|
||||||
"subjects", # TODO
|
"subjects", # TODO
|
||||||
|
|
|
@ -2,18 +2,24 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load humanize %}
|
{% load humanize %}
|
||||||
|
|
||||||
{% block title %}{% trans "Edit Book" %}{% endblock %}
|
{% block title %}{% if book %}{% blocktrans with book_title=book.title %}Edit "{{ book_title }}"{% endblocktrans %}{% else %}{% trans "Add Book" %}{% endif %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<header class="block">
|
<header class="block">
|
||||||
<h1 class="title level-left">
|
<h1 class="title level-left">
|
||||||
Edit "{{ book.title }}"
|
{% if book %}
|
||||||
|
{% blocktrans with book_title=book.title %}Edit "{{ book_title }}"{% endblocktrans %}
|
||||||
|
{% else %}
|
||||||
|
{% trans "Add Book" %}
|
||||||
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
|
{% if book %}
|
||||||
<div>
|
<div>
|
||||||
<p>{% trans "Added:" %} {{ book.created_date | naturaltime }}</p>
|
<p>{% trans "Added:" %} {{ book.created_date | naturaltime }}</p>
|
||||||
<p>{% trans "Updated:" %} {{ book.updated_date | naturaltime }}</p>
|
<p>{% trans "Updated:" %} {{ book.updated_date | naturaltime }}</p>
|
||||||
<p>{% trans "Last edited by:" %} <a href="{{ book.last_edited_by.remote_id }}">{{ book.last_edited_by.display_name }}</a></p>
|
<p>{% trans "Last edited by:" %} <a href="{{ book.last_edited_by.remote_id }}">{{ book.last_edited_by.display_name }}</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{% if form.non_field_errors %}
|
{% if form.non_field_errors %}
|
||||||
|
@ -22,40 +28,111 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form class="block" name="edit-book" action="{{ book.local_path }}/edit" method="post" enctype="multipart/form-data">
|
{% if book %}
|
||||||
|
<form class="block" name="edit-book" action="{{ book.local_path }}/{% if confirm_mode %}confirm{% else %}edit{% endif %}" method="post" enctype="multipart/form-data">
|
||||||
|
{% else %}
|
||||||
|
<form class="block" name="create-book" action="/create-book{% if confirm_mode %}/confirm{% endif %}" method="post" enctype="multipart/form-data">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
{% if confirm_mode %}
|
||||||
|
<div class="box">
|
||||||
|
<h2 class="title is-4">{% trans "Confirm Book Info" %}</h2>
|
||||||
|
<div class="columns">
|
||||||
|
{% if author_matches %}
|
||||||
|
<div class="column is-half">
|
||||||
|
{% for author in author_matches %}
|
||||||
|
<fieldset class="mb-4">
|
||||||
|
<legend class="title is-5 mb-1">{% blocktrans with name=author.name %}Is "{{ name }}" an existing author?{% endblocktrans %}</legend>
|
||||||
|
{% with forloop.counter as counter %}
|
||||||
|
{% for match in author.matches %}
|
||||||
|
<label><input type="radio" name="author_match-{{ counter }}" value="{{ match.id }}" required> {{ match.name }}</label>
|
||||||
|
<p class="help">
|
||||||
|
<a href="{{ author.local_path }}" target="_blank">{% blocktrans with book_title=match.book_set.first.title %}Author of <em>{{ book_title }}</em>{% endblocktrans %}</a>
|
||||||
|
</p>
|
||||||
|
{% endfor %}
|
||||||
|
<label><input type="radio" name="author_match-{{ counter }}" value="0" required> {% trans "This is a new author" %}</label>
|
||||||
|
{% endwith %}
|
||||||
|
</fieldset>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p class="column is-half">{% blocktrans with name=add_author %}Creating a new author: {{ name }}{% endblocktrans %}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not book %}
|
||||||
|
<div class="column is-half">
|
||||||
|
<fieldset>
|
||||||
|
<legend class="title is-5 mb-1">{% trans "Is this an edition of an existing work?" %}</legend>
|
||||||
|
{% for match in book_matches %}
|
||||||
|
<label class="label"><input type="radio" name="parent_work" value="{{ match.parent_work.id }}"> {{ match.parent_work.title }}</label>
|
||||||
|
{% endfor %}
|
||||||
|
<label><input type="radio" name="parent_work" value="0" required> {% trans "This is a new work" %}</label>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="button is-primary" type="submit">{% trans "Confirm" %}</button>
|
||||||
|
<a href="#" class="button" data-back>
|
||||||
|
<span>{% trans "Back" %}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="block">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<input type="hidden" name="last_edited_by" value="{{ request.user.id }}">
|
<input type="hidden" name="last_edited_by" value="{{ request.user.id }}">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<h2 class="title is-4">{% trans "Metadata" %}</h2>
|
<section class="block">
|
||||||
<p class="fields is-grouped"><label class="label" for="id_title">{% trans "Title:" %}</label> {{ form.title }} </p>
|
<h2 class="title is-4">{% trans "Metadata" %}</h2>
|
||||||
{% for error in form.title.errors %}
|
<p class="fields is-grouped"><label class="label" for="id_title">{% trans "Title:" %}</label> {{ form.title }} </p>
|
||||||
<p class="help is-danger">{{ error | escape }}</p>
|
{% for error in form.title.errors %}
|
||||||
{% endfor %}
|
<p class="help is-danger">{{ error | escape }}</p>
|
||||||
<p class="fields is-grouped"><label class="label" for="id_subtitle">{% trans "Subtitle:" %}</label> {{ form.subtitle }} </p>
|
{% endfor %}
|
||||||
{% for error in form.subtitle.errors %}
|
<p class="fields is-grouped"><label class="label" for="id_subtitle">{% trans "Subtitle:" %}</label> {{ form.subtitle }} </p>
|
||||||
<p class="help is-danger">{{ error | escape }}</p>
|
{% for error in form.subtitle.errors %}
|
||||||
{% endfor %}
|
<p class="help is-danger">{{ error | escape }}</p>
|
||||||
<p class="fields is-grouped"><label class="label" for="id_description">{% trans "Description:" %}</label> {{ form.description }} </p>
|
{% endfor %}
|
||||||
{% for error in form.description.errors %}
|
<p class="fields is-grouped"><label class="label" for="id_description">{% trans "Description:" %}</label> {{ form.description }} </p>
|
||||||
<p class="help is-danger">{{ error | escape }}</p>
|
{% for error in form.description.errors %}
|
||||||
{% endfor %}
|
<p class="help is-danger">{{ error | escape }}</p>
|
||||||
<p class="fields is-grouped"><label class="label" for="id_series">{% trans "Series:" %}</label> {{ form.series }} </p>
|
{% endfor %}
|
||||||
{% for error in form.series.errors %}
|
<p class="fields is-grouped"><label class="label" for="id_series">{% trans "Series:" %}</label> {{ form.series }} </p>
|
||||||
<p class="help is-danger">{{ error | escape }}</p>
|
{% for error in form.series.errors %}
|
||||||
{% endfor %}
|
<p class="help is-danger">{{ error | escape }}</p>
|
||||||
<p class="fields is-grouped"><label class="label" for="id_series_number">{% trans "Series number:" %}</label> {{ form.series_number }} </p>
|
{% endfor %}
|
||||||
{% for error in form.series_number.errors %}
|
<p class="fields is-grouped"><label class="label" for="id_series_number">{% trans "Series number:" %}</label> {{ form.series_number }} </p>
|
||||||
<p class="help is-danger">{{ error | escape }}</p>
|
{% for error in form.series_number.errors %}
|
||||||
{% endfor %}
|
<p class="help is-danger">{{ error | escape }}</p>
|
||||||
<p class="fields is-grouped"><label class="label" for="id_first_published_date">{% trans "First published date:" %}</label> {{ form.first_published_date }} </p>
|
{% endfor %}
|
||||||
{% for error in form.first_published_date.errors %}
|
<p class="fields is-grouped"><label class="label" for="id_first_published_date">{% trans "First published date:" %}</label> {{ form.first_published_date }} </p>
|
||||||
<p class="help is-danger">{{ error | escape }}</p>
|
{% for error in form.first_published_date.errors %}
|
||||||
{% endfor %}
|
<p class="help is-danger">{{ error | escape }}</p>
|
||||||
<p class="fields is-grouped"><label class="label" for="id_published_date">{% trans "Published date:" %}</label> {{ form.published_date }} </p>
|
{% endfor %}
|
||||||
{% for error in form.published_date.errors %}
|
<p class="fields is-grouped"><label class="label" for="id_published_date">{% trans "Published date:" %}</label> {{ form.published_date }} </p>
|
||||||
<p class="help is-danger">{{ error | escape }}</p>
|
{% for error in form.published_date.errors %}
|
||||||
{% endfor %}
|
<p class="help is-danger">{{ error | escape }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="block">
|
||||||
|
<h2 class="title is-4">{% trans "Authors" %}</h2>
|
||||||
|
{% if book.authors.exists %}
|
||||||
|
<fieldset>
|
||||||
|
{% for author in book.authors.all %}
|
||||||
|
<label class="label mb-2">
|
||||||
|
<input type="checkbox" name="remove_authors" value="{{ author.id }}" {% if author.id|stringformat:"i" in remove_authors %}checked{% endif %}>
|
||||||
|
{% blocktrans with name=author.name path=author.local_path %}Remove <a href="{{ path }}">{{ name }}</a>{% endblocktrans %}
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</fieldset>
|
||||||
|
{% endif %}
|
||||||
|
<label class="label" for="id_add_author">{% trans "Add Authors:" %}</label>
|
||||||
|
<p class="help">Separate multiple author names with commas.</p>
|
||||||
|
<input class="input" type="text" name="add_author" id="id_add_author" placeholder="{% trans 'John Doe, Jane Smith' %}" value="{{ add_author }}" {% if confirm_mode %}readonly{% endif %}>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="column">
|
<div class="column">
|
||||||
|
@ -116,10 +193,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if not confirm_mode %}
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<button class="button is-primary" type="submit">{% trans "Save" %}</button>
|
<button class="button is-primary" type="submit">{% trans "Save" %}</button>
|
||||||
<a class="button" href="/book/{{ book.id }}">{% trans "Cancel" %}</a>
|
<a class="button" href="/book/{{ book.id }}">{% trans "Cancel" %}</a>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -68,6 +68,10 @@
|
||||||
{% include 'snippets/toggle/close_button.html' with text=button_text small=True controls_text="more-results" %}
|
{% include 'snippets/toggle/close_button.html' with text=button_text small=True controls_text="more-results" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="block">
|
||||||
|
<a href="/create-book">Manually add book</a>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
|
|
|
@ -84,6 +84,108 @@ class BookViews(TestCase):
|
||||||
self.book.refresh_from_db()
|
self.book.refresh_from_db()
|
||||||
self.assertEqual(self.book.title, "New Title")
|
self.assertEqual(self.book.title, "New Title")
|
||||||
|
|
||||||
|
def test_edit_book_add_author(self):
|
||||||
|
""" lets a user edit a book with new authors """
|
||||||
|
view = views.EditBook.as_view()
|
||||||
|
self.local_user.groups.add(self.group)
|
||||||
|
form = forms.EditionForm(instance=self.book)
|
||||||
|
form.data["title"] = "New Title"
|
||||||
|
form.data["last_edited_by"] = self.local_user.id
|
||||||
|
form.data["add_author"] = "Sappho"
|
||||||
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
|
result = view(request, self.book.id)
|
||||||
|
result.render()
|
||||||
|
|
||||||
|
# the changes haven't been saved yet
|
||||||
|
self.book.refresh_from_db()
|
||||||
|
self.assertEqual(self.book.title, "Example Edition")
|
||||||
|
|
||||||
|
def test_edit_book_add_new_author_confirm(self):
|
||||||
|
""" lets a user edit a book confirmed with new authors """
|
||||||
|
view = views.ConfirmEditBook.as_view()
|
||||||
|
self.local_user.groups.add(self.group)
|
||||||
|
form = forms.EditionForm(instance=self.book)
|
||||||
|
form.data["title"] = "New Title"
|
||||||
|
form.data["last_edited_by"] = self.local_user.id
|
||||||
|
form.data["add_author"] = "Sappho"
|
||||||
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
|
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||||
|
view(request, self.book.id)
|
||||||
|
|
||||||
|
self.book.refresh_from_db()
|
||||||
|
self.assertEqual(self.book.title, "New Title")
|
||||||
|
self.assertEqual(self.book.authors.first().name, "Sappho")
|
||||||
|
|
||||||
|
def test_edit_book_remove_author(self):
|
||||||
|
""" remove an author from a book """
|
||||||
|
author = models.Author.objects.create(name="Sappho")
|
||||||
|
self.book.authors.add(author)
|
||||||
|
form = forms.EditionForm(instance=self.book)
|
||||||
|
view = views.EditBook.as_view()
|
||||||
|
self.local_user.groups.add(self.group)
|
||||||
|
form = forms.EditionForm(instance=self.book)
|
||||||
|
form.data["title"] = "New Title"
|
||||||
|
form.data["last_edited_by"] = self.local_user.id
|
||||||
|
form.data["remove_authors"] = [author.id]
|
||||||
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
|
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
|
||||||
|
view(request, self.book.id)
|
||||||
|
self.book.refresh_from_db()
|
||||||
|
self.assertEqual(self.book.title, "New Title")
|
||||||
|
self.assertFalse(self.book.authors.exists())
|
||||||
|
|
||||||
|
def test_create_book(self):
|
||||||
|
""" create an entirely new book and work """
|
||||||
|
view = views.ConfirmEditBook.as_view()
|
||||||
|
self.local_user.groups.add(self.group)
|
||||||
|
form = forms.EditionForm()
|
||||||
|
form.data["title"] = "New Title"
|
||||||
|
form.data["last_edited_by"] = self.local_user.id
|
||||||
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
|
view(request)
|
||||||
|
book = models.Edition.objects.get(title="New Title")
|
||||||
|
self.assertEqual(book.parent_work.title, "New Title")
|
||||||
|
|
||||||
|
def test_create_book_existing_work(self):
|
||||||
|
""" create an entirely new book and work """
|
||||||
|
view = views.ConfirmEditBook.as_view()
|
||||||
|
self.local_user.groups.add(self.group)
|
||||||
|
form = forms.EditionForm()
|
||||||
|
form.data["title"] = "New Title"
|
||||||
|
form.data["parent_work"] = self.work.id
|
||||||
|
form.data["last_edited_by"] = self.local_user.id
|
||||||
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
|
view(request)
|
||||||
|
book = models.Edition.objects.get(title="New Title")
|
||||||
|
self.assertEqual(book.parent_work, self.work)
|
||||||
|
|
||||||
|
def test_create_book_with_author(self):
|
||||||
|
""" create an entirely new book and work """
|
||||||
|
view = views.ConfirmEditBook.as_view()
|
||||||
|
self.local_user.groups.add(self.group)
|
||||||
|
form = forms.EditionForm()
|
||||||
|
form.data["title"] = "New Title"
|
||||||
|
form.data["add_author"] = "Sappho"
|
||||||
|
form.data["last_edited_by"] = self.local_user.id
|
||||||
|
request = self.factory.post("", form.data)
|
||||||
|
request.user = self.local_user
|
||||||
|
|
||||||
|
view(request)
|
||||||
|
book = models.Edition.objects.get(title="New Title")
|
||||||
|
self.assertEqual(book.parent_work.title, "New Title")
|
||||||
|
self.assertEqual(book.authors.first().name, "Sappho")
|
||||||
|
self.assertEqual(book.authors.first(), book.parent_work.authors.first())
|
||||||
|
|
||||||
def test_switch_edition(self):
|
def test_switch_edition(self):
|
||||||
""" updates user's relationships to a book """
|
""" updates user's relationships to a book """
|
||||||
work = models.Work.objects.create(title="test work")
|
work = models.Work.objects.create(title="test work")
|
||||||
|
|
|
@ -127,6 +127,9 @@ urlpatterns = [
|
||||||
# books
|
# books
|
||||||
re_path(r"%s(.json)?/?$" % book_path, views.Book.as_view()),
|
re_path(r"%s(.json)?/?$" % book_path, views.Book.as_view()),
|
||||||
re_path(r"%s/edit/?$" % book_path, views.EditBook.as_view()),
|
re_path(r"%s/edit/?$" % book_path, views.EditBook.as_view()),
|
||||||
|
re_path(r"%s/confirm/?$" % book_path, views.ConfirmEditBook.as_view()),
|
||||||
|
re_path(r"^create-book/?$", views.EditBook.as_view()),
|
||||||
|
re_path(r"^create-book/confirm?$", views.ConfirmEditBook.as_view()),
|
||||||
re_path(r"%s/editions(.json)?/?$" % book_path, views.Editions.as_view()),
|
re_path(r"%s/editions(.json)?/?$" % book_path, views.Editions.as_view()),
|
||||||
re_path(r"^upload-cover/(?P<book_id>\d+)/?$", views.upload_cover),
|
re_path(r"^upload-cover/(?P<book_id>\d+)/?$", views.upload_cover),
|
||||||
re_path(r"^add-description/(?P<book_id>\d+)/?$", views.add_description),
|
re_path(r"^add-description/(?P<book_id>\d+)/?$", views.add_description),
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from .authentication import Login, Register, Logout
|
from .authentication import Login, Register, Logout
|
||||||
from .author import Author, EditAuthor
|
from .author import Author, EditAuthor
|
||||||
from .block import Block, unblock
|
from .block import Block, unblock
|
||||||
from .books import Book, EditBook, Editions
|
from .books import Book, EditBook, ConfirmEditBook, Editions
|
||||||
from .books import upload_cover, add_description, switch_edition, resolve_book
|
from .books import upload_cover, add_description, switch_edition, resolve_book
|
||||||
from .error import not_found_page, server_error_page
|
from .error import not_found_page, server_error_page
|
||||||
from .federation import Federation
|
from .federation import Federation
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
""" the good stuff! the books! """
|
""" the good stuff! the books! """
|
||||||
from django.core.paginator import Paginator
|
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
|
from django.contrib.postgres.search import SearchRank, SearchVector
|
||||||
|
from django.core.paginator import Paginator
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import Avg, Q
|
from django.db.models import Avg, Q
|
||||||
from django.http import HttpResponseNotFound
|
from django.http import HttpResponseNotFound
|
||||||
|
@ -106,23 +107,126 @@ class Book(View):
|
||||||
class EditBook(View):
|
class EditBook(View):
|
||||||
""" edit a book """
|
""" edit a book """
|
||||||
|
|
||||||
def get(self, request, book_id):
|
def get(self, request, book_id=None):
|
||||||
""" info about a book """
|
""" info about a book """
|
||||||
book = get_edition(book_id)
|
book = None
|
||||||
if not book.description:
|
if book_id:
|
||||||
book.description = book.parent_work.description
|
book = get_edition(book_id)
|
||||||
|
if not book.description:
|
||||||
|
book.description = book.parent_work.description
|
||||||
data = {"book": book, "form": forms.EditionForm(instance=book)}
|
data = {"book": book, "form": forms.EditionForm(instance=book)}
|
||||||
return TemplateResponse(request, "edit_book.html", data)
|
return TemplateResponse(request, "edit_book.html", data)
|
||||||
|
|
||||||
def post(self, request, book_id):
|
def post(self, request, book_id=None):
|
||||||
""" edit a book cool """
|
""" edit a book cool """
|
||||||
book = get_object_or_404(models.Edition, id=book_id)
|
# returns None if no match is found
|
||||||
|
book = models.Edition.objects.filter(id=book_id).first()
|
||||||
form = forms.EditionForm(request.POST, request.FILES, instance=book)
|
form = forms.EditionForm(request.POST, request.FILES, instance=book)
|
||||||
|
|
||||||
|
data = {"book": book, "form": form}
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
data = {"book": book, "form": form}
|
|
||||||
return TemplateResponse(request, "edit_book.html", data)
|
return TemplateResponse(request, "edit_book.html", data)
|
||||||
|
|
||||||
|
add_author = request.POST.get("add_author")
|
||||||
|
# we're adding an author through a free text field
|
||||||
|
if add_author:
|
||||||
|
data["add_author"] = add_author
|
||||||
|
data["author_matches"] = []
|
||||||
|
for author in add_author.split(","):
|
||||||
|
if not author:
|
||||||
|
continue
|
||||||
|
# check for existing authors
|
||||||
|
vector = SearchVector("name", weight="A") + SearchVector(
|
||||||
|
"aliases", weight="B"
|
||||||
|
)
|
||||||
|
|
||||||
|
data["author_matches"].append(
|
||||||
|
{
|
||||||
|
"name": author.strip(),
|
||||||
|
"matches": (
|
||||||
|
models.Author.objects.annotate(search=vector)
|
||||||
|
.annotate(rank=SearchRank(vector, add_author))
|
||||||
|
.filter(rank__gt=0.4)
|
||||||
|
.order_by("-rank")[:5]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# we're creating a new book
|
||||||
|
if not book:
|
||||||
|
# check if this is an edition of an existing work
|
||||||
|
author_text = book.author_text if book else add_author
|
||||||
|
data["book_matches"] = connector_manager.local_search(
|
||||||
|
"%s %s" % (form.cleaned_data.get("title"), author_text),
|
||||||
|
min_confidence=0.5,
|
||||||
|
raw=True,
|
||||||
|
)[:5]
|
||||||
|
|
||||||
|
# either of the above cases requires additional confirmation
|
||||||
|
if add_author or not book:
|
||||||
|
# creting a book or adding an author to a book needs another step
|
||||||
|
data["confirm_mode"] = True
|
||||||
|
# this isn't preserved because it isn't part of the form obj
|
||||||
|
data["remove_authors"] = request.POST.getlist("remove_authors")
|
||||||
|
return TemplateResponse(request, "edit_book.html", data)
|
||||||
|
|
||||||
|
remove_authors = request.POST.getlist("remove_authors")
|
||||||
|
for author_id in remove_authors:
|
||||||
|
book.authors.remove(author_id)
|
||||||
|
|
||||||
book = form.save()
|
book = form.save()
|
||||||
|
return redirect("/book/%s" % book.id)
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(login_required, name="dispatch")
|
||||||
|
@method_decorator(
|
||||||
|
permission_required("bookwyrm.edit_book", raise_exception=True), name="dispatch"
|
||||||
|
)
|
||||||
|
class ConfirmEditBook(View):
|
||||||
|
""" confirm edits to a book """
|
||||||
|
|
||||||
|
def post(self, request, book_id=None):
|
||||||
|
""" edit a book cool """
|
||||||
|
# returns None if no match is found
|
||||||
|
book = models.Edition.objects.filter(id=book_id).first()
|
||||||
|
form = forms.EditionForm(request.POST, request.FILES, instance=book)
|
||||||
|
|
||||||
|
data = {"book": book, "form": form}
|
||||||
|
if not form.is_valid():
|
||||||
|
return TemplateResponse(request, "edit_book.html", data)
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
# save book
|
||||||
|
book = form.save()
|
||||||
|
|
||||||
|
# get or create author as needed
|
||||||
|
if request.POST.get("add_author"):
|
||||||
|
for (i, author) in enumerate(request.POST.get("add_author").split(",")):
|
||||||
|
if not author:
|
||||||
|
continue
|
||||||
|
match = request.POST.get("author_match-%d" % i)
|
||||||
|
if match and match != "0":
|
||||||
|
author = get_object_or_404(
|
||||||
|
models.Author, id=request.POST["author_match-%d" % i]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
author = models.Author.objects.create(name=author.strip())
|
||||||
|
book.authors.add(author)
|
||||||
|
|
||||||
|
# create work, if needed
|
||||||
|
if not book_id:
|
||||||
|
work_match = request.POST.get("parent_work")
|
||||||
|
if work_match and work_match != "0":
|
||||||
|
work = get_object_or_404(models.Work, id=work_match)
|
||||||
|
else:
|
||||||
|
work = models.Work.objects.create(title=form.cleaned_data["title"])
|
||||||
|
work.authors.set(book.authors.all())
|
||||||
|
book.parent_work = work
|
||||||
|
# we don't tell the world when creating a book
|
||||||
|
book.save(broadcast=False)
|
||||||
|
|
||||||
|
for author_id in request.POST.getlist("remove_authors"):
|
||||||
|
book.authors.remove(author_id)
|
||||||
|
|
||||||
return redirect("/book/%s" % book.id)
|
return redirect("/book/%s" % book.id)
|
||||||
|
|
||||||
|
|
2
bw-dev
2
bw-dev
|
@ -36,7 +36,7 @@ function initdb {
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeitblack {
|
function makeitblack {
|
||||||
runweb black celerywyrm bookwyrm
|
docker-compose run --rm web black celerywyrm bookwyrm
|
||||||
}
|
}
|
||||||
|
|
||||||
CMD=$1
|
CMD=$1
|
||||||
|
|
Loading…
Reference in a new issue