forked from mirrors/bookwyrm
Author class view
This commit is contained in:
parent
56e3e98bc1
commit
4dea22bef6
7 changed files with 301 additions and 64 deletions
|
@ -27,7 +27,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form class="block" name="edit-author" action="/edit-author/{{ author.id }}" method="post">
|
||||
<form class="block" name="edit-author" action="{{ author.local_path }}/edit" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="last_edited_by" value="{{ request.user.id }}">
|
||||
|
||||
|
|
|
@ -96,12 +96,13 @@ urlpatterns = [
|
|||
re_path(r'^resolve-book/?$', views.resolve_book),
|
||||
re_path(r'^switch-edition/?$', views.switch_edition),
|
||||
|
||||
re_path(r'^author/(?P<author_id>[\w\-]+)/edit/?$', vviews.edit_author_page),
|
||||
# author
|
||||
re_path(r'^author/(?P<author_id>\d+)(.json)?/?$', views.Author.as_view()),
|
||||
re_path(r'^author/(?P<author_id>\d+)/edit/?$', views.EditAuthor.as_view()),
|
||||
|
||||
re_path(r'^tag/?$', actions.tag),
|
||||
re_path(r'^untag/?$', actions.untag),
|
||||
|
||||
re_path(r'^author/(?P<author_id>[\w\-]+)(.json)?/?$', vviews.author_page),
|
||||
re_path(r'^tag/(?P<tag_id>.+)\.json/?$', vviews.tag_page),
|
||||
re_path(r'^tag/(?P<tag_id>.+)/?$', vviews.tag_page),
|
||||
re_path(r'^%s/shelf/(?P<shelf_identifier>[\w-]+)(.json)?/?$' % \
|
||||
|
@ -111,8 +112,6 @@ urlpatterns = [
|
|||
|
||||
re_path(r'^search/?$', vviews.search),
|
||||
|
||||
re_path(r'^edit-author/(?P<author_id>\d+)/?$', actions.edit_author),
|
||||
|
||||
re_path(r'^edit-readthrough/?$', actions.edit_readthrough),
|
||||
re_path(r'^delete-readthrough/?$', actions.delete_readthrough),
|
||||
re_path(r'^create-readthrough/?$', actions.create_readthrough),
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
import dateutil.parser
|
||||
from dateutil.parser import ParserError
|
||||
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponseBadRequest, HttpResponseNotFound
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils import timezone
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
|
@ -13,27 +12,6 @@ from bookwyrm import forms, models, outgoing
|
|||
from bookwyrm.broadcast import broadcast
|
||||
from bookwyrm.vviews import get_user_from_username, get_edition
|
||||
|
||||
@login_required
|
||||
@permission_required('bookwyrm.edit_book', raise_exception=True)
|
||||
@require_POST
|
||||
def edit_author(request, author_id):
|
||||
''' edit a author cool '''
|
||||
author = get_object_or_404(models.Author, id=author_id)
|
||||
|
||||
form = forms.AuthorForm(request.POST, request.FILES, instance=author)
|
||||
if not form.is_valid():
|
||||
data = {
|
||||
'title': 'Edit Author',
|
||||
'author': author,
|
||||
'form': form
|
||||
}
|
||||
return TemplateResponse(request, 'edit_author.html', data)
|
||||
author = form.save()
|
||||
|
||||
broadcast(request.user, author.to_update_activity(request.user))
|
||||
return redirect('/author/%s' % author.id)
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def create_shelf(request):
|
||||
|
|
|
@ -11,3 +11,4 @@ from .status import Status, Replies, CreateStatus, DeleteStatus
|
|||
from .interaction import Favorite, Unfavorite, Boost, Unboost
|
||||
from .books import Book, EditBook, Editions
|
||||
from .books import upload_cover, add_description, switch_edition, resolve_book
|
||||
from .author import Author, EditAuthor
|
||||
|
|
66
bookwyrm/views/author.py
Normal file
66
bookwyrm/views/author.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
''' the good people stuff! the authors! '''
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
|
||||
from bookwyrm import forms, models
|
||||
from bookwyrm.activitypub import ActivitypubResponse
|
||||
from bookwyrm.broadcast import broadcast
|
||||
from .helpers import is_api_request
|
||||
|
||||
|
||||
# pylint: disable= no-self-use
|
||||
class Author(View):
|
||||
''' this person wrote a book '''
|
||||
def get(self, request, author_id):
|
||||
''' landing page for an author '''
|
||||
author = get_object_or_404(models.Author, id=author_id)
|
||||
|
||||
if is_api_request(request):
|
||||
return ActivitypubResponse(author.to_activity())
|
||||
|
||||
books = models.Work.objects.filter(
|
||||
Q(authors=author) | Q(editions__authors=author)).distinct()
|
||||
data = {
|
||||
'title': author.name,
|
||||
'author': author,
|
||||
'books': [b.get_default_edition() for b in books],
|
||||
}
|
||||
return TemplateResponse(request, 'author.html', data)
|
||||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(
|
||||
permission_required('bookwyrm.edit_book', raise_exception=True),
|
||||
name='dispatch')
|
||||
class EditAuthor(View):
|
||||
''' edit author info '''
|
||||
def get(self, request, author_id):
|
||||
''' info about a book '''
|
||||
author = get_object_or_404(models.Author, id=author_id)
|
||||
data = {
|
||||
'title': 'Edit Author',
|
||||
'author': author,
|
||||
'form': forms.AuthorForm(instance=author)
|
||||
}
|
||||
return TemplateResponse(request, 'edit_author.html', data)
|
||||
|
||||
def post(self, request, author_id):
|
||||
''' edit a author cool '''
|
||||
author = get_object_or_404(models.Author, id=author_id)
|
||||
|
||||
form = forms.AuthorForm(request.POST, request.FILES, instance=author)
|
||||
if not form.is_valid():
|
||||
data = {
|
||||
'title': 'Edit Author',
|
||||
'author': author,
|
||||
'form': form
|
||||
}
|
||||
return TemplateResponse(request, 'edit_author.html', data)
|
||||
author = form.save()
|
||||
|
||||
broadcast(request.user, author.to_update_activity(request.user))
|
||||
return redirect('/author/%s' % author.id)
|
228
bookwyrm/views/books.py
Normal file
228
bookwyrm/views/books.py
Normal file
|
@ -0,0 +1,228 @@
|
|||
''' the good stuff! the books! '''
|
||||
from django.core.paginator import Paginator
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.db import transaction
|
||||
from django.db.models import Avg, Q
|
||||
from django.http import HttpResponseNotFound
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
from bookwyrm import forms, models
|
||||
from bookwyrm.activitypub import ActivitypubResponse
|
||||
from bookwyrm.broadcast import broadcast
|
||||
from bookwyrm.connectors import connector_manager
|
||||
from bookwyrm.settings import PAGE_LENGTH
|
||||
from .helpers import is_api_request, get_activity_feed, get_edition
|
||||
|
||||
|
||||
# pylint: disable= no-self-use
|
||||
class Book(View):
|
||||
''' a book! this is the stuff '''
|
||||
def get(self, request, book_id):
|
||||
''' info about a book '''
|
||||
try:
|
||||
page = int(request.GET.get('page', 1))
|
||||
except ValueError:
|
||||
page = 1
|
||||
|
||||
try:
|
||||
book = models.Book.objects.select_subclasses().get(id=book_id)
|
||||
except models.Book.DoesNotExist:
|
||||
return HttpResponseNotFound()
|
||||
|
||||
if is_api_request(request):
|
||||
return ActivitypubResponse(book.to_activity())
|
||||
|
||||
if isinstance(book, models.Work):
|
||||
book = book.get_default_edition()
|
||||
if not book:
|
||||
return HttpResponseNotFound()
|
||||
|
||||
work = book.parent_work
|
||||
if not work:
|
||||
return HttpResponseNotFound()
|
||||
|
||||
reviews = models.Review.objects.filter(
|
||||
book__in=work.editions.all(),
|
||||
)
|
||||
# all reviews for the book
|
||||
reviews = get_activity_feed(
|
||||
request.user,
|
||||
['public', 'unlisted', 'followers', 'direct'],
|
||||
queryset=reviews
|
||||
)
|
||||
|
||||
# the reviews to show
|
||||
paginated = Paginator(reviews.exclude(
|
||||
Q(content__isnull=True) | Q(content='')
|
||||
), PAGE_LENGTH)
|
||||
reviews_page = paginated.page(page)
|
||||
|
||||
user_tags = readthroughs = user_shelves = other_edition_shelves = []
|
||||
if request.user.is_authenticated:
|
||||
user_tags = models.UserTag.objects.filter(
|
||||
book=book, user=request.user
|
||||
).values_list('tag__identifier', flat=True)
|
||||
|
||||
readthroughs = models.ReadThrough.objects.filter(
|
||||
user=request.user,
|
||||
book=book,
|
||||
).order_by('start_date')
|
||||
|
||||
user_shelves = models.ShelfBook.objects.filter(
|
||||
added_by=request.user, book=book
|
||||
)
|
||||
|
||||
other_edition_shelves = models.ShelfBook.objects.filter(
|
||||
~Q(book=book),
|
||||
added_by=request.user,
|
||||
book__parent_work=book.parent_work,
|
||||
)
|
||||
|
||||
data = {
|
||||
'title': book.title,
|
||||
'book': book,
|
||||
'reviews': reviews_page,
|
||||
'review_count': reviews.count(),
|
||||
'ratings': reviews.filter(Q(content__isnull=True) | Q(content='')),
|
||||
'rating': reviews.aggregate(Avg('rating'))['rating__avg'],
|
||||
'tags': models.UserTag.objects.filter(book=book),
|
||||
'user_tags': user_tags,
|
||||
'user_shelves': user_shelves,
|
||||
'other_edition_shelves': other_edition_shelves,
|
||||
'readthroughs': readthroughs,
|
||||
'path': '/book/%s' % book_id,
|
||||
}
|
||||
return TemplateResponse(request, 'book.html', data)
|
||||
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
@method_decorator(
|
||||
permission_required('bookwyrm.edit_book', raise_exception=True),
|
||||
name='dispatch')
|
||||
class EditBook(View):
|
||||
''' edit a book '''
|
||||
def get(self, request, book_id):
|
||||
''' info about a book '''
|
||||
book = get_edition(book_id)
|
||||
if not book.description:
|
||||
book.description = book.parent_work.description
|
||||
data = {
|
||||
'title': 'Edit Book',
|
||||
'book': book,
|
||||
'form': forms.EditionForm(instance=book)
|
||||
}
|
||||
return TemplateResponse(request, 'edit_book.html', data)
|
||||
|
||||
def post(self, request, book_id):
|
||||
''' edit a book cool '''
|
||||
book = get_object_or_404(models.Edition, id=book_id)
|
||||
|
||||
form = forms.EditionForm(request.POST, request.FILES, instance=book)
|
||||
if not form.is_valid():
|
||||
data = {
|
||||
'title': 'Edit Book',
|
||||
'book': book,
|
||||
'form': form
|
||||
}
|
||||
return TemplateResponse(request, 'edit_book.html', data)
|
||||
book = form.save()
|
||||
|
||||
broadcast(request.user, book.to_update_activity(request.user))
|
||||
return redirect('/book/%s' % book.id)
|
||||
|
||||
|
||||
class Editions(View):
|
||||
''' list of editions '''
|
||||
def get(self, request, book_id):
|
||||
''' list of editions of a book '''
|
||||
work = get_object_or_404(models.Work, id=book_id)
|
||||
|
||||
if is_api_request(request):
|
||||
return ActivitypubResponse(work.to_edition_list(**request.GET))
|
||||
|
||||
data = {
|
||||
'title': 'Editions of %s' % work.title,
|
||||
'editions': work.editions.order_by('-edition_rank').all(),
|
||||
'work': work,
|
||||
}
|
||||
return TemplateResponse(request, 'editions.html', data)
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def upload_cover(request, book_id):
|
||||
''' upload a new cover '''
|
||||
book = get_object_or_404(models.Edition, id=book_id)
|
||||
|
||||
form = forms.CoverForm(request.POST, request.FILES, instance=book)
|
||||
if not form.is_valid():
|
||||
return redirect('/book/%d' % book.id)
|
||||
|
||||
book.cover = form.files['cover']
|
||||
book.save()
|
||||
|
||||
broadcast(request.user, book.to_update_activity(request.user))
|
||||
return redirect('/book/%s' % book.id)
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
@permission_required('bookwyrm.edit_book', raise_exception=True)
|
||||
def add_description(request, book_id):
|
||||
''' upload a new cover '''
|
||||
if not request.method == 'POST':
|
||||
return redirect('/')
|
||||
|
||||
book = get_object_or_404(models.Edition, id=book_id)
|
||||
|
||||
description = request.POST.get('description')
|
||||
|
||||
book.description = description
|
||||
book.save()
|
||||
|
||||
broadcast(request.user, book.to_update_activity(request.user))
|
||||
return redirect('/book/%s' % book.id)
|
||||
|
||||
|
||||
@require_POST
|
||||
def resolve_book(request):
|
||||
''' figure out the local path to a book from a remote_id '''
|
||||
remote_id = request.POST.get('remote_id')
|
||||
connector = connector_manager.get_or_create_connector(remote_id)
|
||||
book = connector.get_or_create_book(remote_id)
|
||||
|
||||
return redirect('/book/%d' % book.id)
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
@transaction.atomic
|
||||
def switch_edition(request):
|
||||
''' switch your copy of a book to a different edition '''
|
||||
edition_id = request.POST.get('edition')
|
||||
new_edition = get_object_or_404(models.Edition, id=edition_id)
|
||||
shelfbooks = models.ShelfBook.objects.filter(
|
||||
book__parent_work=new_edition.parent_work,
|
||||
shelf__user=request.user
|
||||
)
|
||||
for shelfbook in shelfbooks.all():
|
||||
broadcast(request.user, shelfbook.to_remove_activity(request.user))
|
||||
|
||||
shelfbook.book = new_edition
|
||||
shelfbook.save()
|
||||
|
||||
broadcast(request.user, shelfbook.to_add_activity(request.user))
|
||||
|
||||
readthroughs = models.ReadThrough.objects.filter(
|
||||
book__parent_work=new_edition.parent_work,
|
||||
user=request.user
|
||||
)
|
||||
for readthrough in readthroughs.all():
|
||||
readthrough.book = new_edition
|
||||
readthrough.save()
|
||||
|
||||
return redirect('/book/%d' % new_edition.id)
|
|
@ -1,18 +1,15 @@
|
|||
''' views for pages you can go to in the application '''
|
||||
import re
|
||||
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.contrib.postgres.search import TrigramSimilarity
|
||||
from django.db.models import Q
|
||||
from django.db.models.functions import Greatest
|
||||
from django.http import HttpResponseNotFound, JsonResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.template.response import TemplateResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.decorators.http import require_GET
|
||||
|
||||
from bookwyrm import outgoing
|
||||
from bookwyrm import forms, models
|
||||
from bookwyrm import models
|
||||
from bookwyrm.activitypub import ActivitypubResponse
|
||||
from bookwyrm.connectors import connector_manager
|
||||
from bookwyrm.utils import regex
|
||||
|
@ -90,38 +87,6 @@ def search(request):
|
|||
return TemplateResponse(request, 'search_results.html', data)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required('bookwyrm.edit_book', raise_exception=True)
|
||||
@require_GET
|
||||
def edit_author_page(request, author_id):
|
||||
''' info about a book '''
|
||||
author = get_object_or_404(models.Author, id=author_id)
|
||||
data = {
|
||||
'title': 'Edit Author',
|
||||
'author': author,
|
||||
'form': forms.AuthorForm(instance=author)
|
||||
}
|
||||
return TemplateResponse(request, 'edit_author.html', data)
|
||||
|
||||
|
||||
@require_GET
|
||||
def author_page(request, author_id):
|
||||
''' landing page for an author '''
|
||||
author = get_object_or_404(models.Author, id=author_id)
|
||||
|
||||
if is_api_request(request):
|
||||
return ActivitypubResponse(author.to_activity())
|
||||
|
||||
books = models.Work.objects.filter(
|
||||
Q(authors=author) | Q(editions__authors=author)).distinct()
|
||||
data = {
|
||||
'title': author.name,
|
||||
'author': author,
|
||||
'books': [b.get_default_edition() for b in books],
|
||||
}
|
||||
return TemplateResponse(request, 'author.html', data)
|
||||
|
||||
|
||||
@require_GET
|
||||
def tag_page(request, tag_id):
|
||||
''' books related to a tag '''
|
||||
|
|
Loading…
Reference in a new issue