Merge pull request #692 from mouse-reeve/create-book

Create book
This commit is contained in:
Mouse Reeve
2021-03-12 10:26:15 -08:00
committed by GitHub
8 changed files with 336 additions and 44 deletions

View File

@ -2,7 +2,7 @@
from .authentication import Login, Register, Logout
from .author import Author, EditAuthor
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 .error import not_found_page, server_error_page
from .federation import Federation

View File

@ -1,6 +1,7 @@
""" the good stuff! the books! """
from django.core.paginator import Paginator
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.models import Avg, Q
from django.http import HttpResponseNotFound
@ -106,23 +107,126 @@ class Book(View):
class EditBook(View):
""" edit a book """
def get(self, request, book_id):
def get(self, request, book_id=None):
""" info about a book """
book = get_edition(book_id)
if not book.description:
book.description = book.parent_work.description
book = None
if book_id:
book = get_edition(book_id)
if not book.description:
book.description = book.parent_work.description
data = {"book": book, "form": forms.EditionForm(instance=book)}
return TemplateResponse(request, "edit_book.html", data)
def post(self, request, book_id):
def post(self, request, book_id=None):
""" 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)
data = {"book": book, "form": form}
if not form.is_valid():
data = {"book": book, "form": form}
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()
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)