mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2025-01-03 05:48:44 +00:00
Adds shelf views
This commit is contained in:
parent
20e280e676
commit
beeeaaaf39
8 changed files with 414 additions and 214 deletions
|
@ -115,49 +115,6 @@ def handle_reject(follow_request):
|
|||
broadcast(to_follow, activity, privacy='direct', direct_recipients=[user])
|
||||
|
||||
|
||||
def handle_shelve(user, book, shelf):
|
||||
''' a local user is getting a book put on their shelf '''
|
||||
# update the database
|
||||
shelve = models.ShelfBook(book=book, shelf=shelf, added_by=user)
|
||||
shelve.save()
|
||||
|
||||
broadcast(user, shelve.to_add_activity(user))
|
||||
|
||||
|
||||
def handle_unshelve(user, book, shelf):
|
||||
''' a local user is getting a book put on their shelf '''
|
||||
# update the database
|
||||
row = models.ShelfBook.objects.get(book=book, shelf=shelf)
|
||||
activity = row.to_remove_activity(user)
|
||||
row.delete()
|
||||
|
||||
broadcast(user, activity)
|
||||
|
||||
|
||||
def handle_reading_status(user, shelf, book, privacy):
|
||||
''' post about a user reading a book '''
|
||||
# tell the world about this cool thing that happened
|
||||
try:
|
||||
message = {
|
||||
'to-read': 'wants to read',
|
||||
'reading': 'started reading',
|
||||
'read': 'finished reading'
|
||||
}[shelf.identifier]
|
||||
except KeyError:
|
||||
# it's a non-standard shelf, don't worry about it
|
||||
return
|
||||
|
||||
status = create_generated_note(
|
||||
user,
|
||||
message,
|
||||
mention_books=[book],
|
||||
privacy=privacy
|
||||
)
|
||||
status.save()
|
||||
|
||||
broadcast(user, status.to_create_activity(user))
|
||||
|
||||
|
||||
def handle_imported_book(user, item, include_reviews, privacy):
|
||||
''' process a goodreads csv and then post about it '''
|
||||
if isinstance(item.book, models.Work):
|
||||
|
|
192
bookwyrm/tests/views/test_shelf.py
Normal file
192
bookwyrm/tests/views/test_shelf.py
Normal file
|
@ -0,0 +1,192 @@
|
|||
''' test for app action functionality '''
|
||||
from unittest.mock import patch
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
|
||||
from bookwyrm import models, views
|
||||
from bookwyrm.activitypub import ActivitypubResponse
|
||||
|
||||
|
||||
class ShelfViews(TestCase):
|
||||
''' tag views'''
|
||||
def setUp(self):
|
||||
''' we need basic test data and mocks '''
|
||||
self.factory = RequestFactory()
|
||||
self.local_user = models.User.objects.create_user(
|
||||
'mouse@local.com', 'mouse@mouse.com', 'mouseword',
|
||||
local=True, localname='mouse',
|
||||
remote_id='https://example.com/users/mouse',
|
||||
)
|
||||
self.work = models.Work.objects.create(title='Test Work')
|
||||
self.book = models.Edition.objects.create(
|
||||
title='Example Edition',
|
||||
remote_id='https://example.com/book/1',
|
||||
parent_work=self.work
|
||||
)
|
||||
self.shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf',
|
||||
identifier='test-shelf',
|
||||
user=self.local_user
|
||||
)
|
||||
|
||||
|
||||
def test_shelf_page(self):
|
||||
''' there are so many views, this just makes sure it LOADS '''
|
||||
view = views.Shelf.as_view()
|
||||
shelf = self.local_user.shelf_set.first()
|
||||
request = self.factory.get('')
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.shelf.is_api_request') as is_api:
|
||||
is_api.return_value = False
|
||||
result = view(request, self.local_user.username, shelf.identifier)
|
||||
self.assertIsInstance(result, TemplateResponse)
|
||||
self.assertEqual(result.template_name, 'shelf.html')
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
with patch('bookwyrm.views.shelf.is_api_request') as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(
|
||||
request, self.local_user.username, shelf.identifier)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
request = self.factory.get('/?page=1')
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.views.shelf.is_api_request') as is_api:
|
||||
is_api.return_value = True
|
||||
result = view(
|
||||
request, self.local_user.username, shelf.identifier)
|
||||
self.assertIsInstance(result, ActivitypubResponse)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
||||
|
||||
def test_edit_shelf_privacy(self):
|
||||
''' set name or privacy on shelf '''
|
||||
view = views.Shelf.as_view()
|
||||
shelf = self.local_user.shelf_set.get(identifier='to-read')
|
||||
self.assertEqual(shelf.privacy, 'public')
|
||||
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'privacy': 'unlisted',
|
||||
'user': self.local_user.id,
|
||||
'name': 'To Read',
|
||||
})
|
||||
request.user = self.local_user
|
||||
view(request, self.local_user.username, shelf.id)
|
||||
shelf.refresh_from_db()
|
||||
|
||||
self.assertEqual(shelf.privacy, 'unlisted')
|
||||
|
||||
|
||||
def test_edit_shelf_name(self):
|
||||
''' change the name of an editable shelf '''
|
||||
view = views.Shelf.as_view()
|
||||
shelf = models.Shelf.objects.create(
|
||||
name='Test Shelf', user=self.local_user)
|
||||
self.assertEqual(shelf.privacy, 'public')
|
||||
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'privacy': 'public',
|
||||
'user': self.local_user.id,
|
||||
'name': 'cool name'
|
||||
})
|
||||
request.user = self.local_user
|
||||
view(request, request.user.username, shelf.id)
|
||||
shelf.refresh_from_db()
|
||||
|
||||
self.assertEqual(shelf.name, 'cool name')
|
||||
self.assertEqual(shelf.identifier, 'testshelf-%d' % shelf.id)
|
||||
|
||||
|
||||
def test_edit_shelf_name_not_editable(self):
|
||||
''' can't change the name of an non-editable shelf '''
|
||||
view = views.Shelf.as_view()
|
||||
shelf = self.local_user.shelf_set.get(identifier='to-read')
|
||||
self.assertEqual(shelf.privacy, 'public')
|
||||
|
||||
request = self.factory.post(
|
||||
'', {
|
||||
'privacy': 'public',
|
||||
'user': self.local_user.id,
|
||||
'name': 'cool name'
|
||||
})
|
||||
request.user = self.local_user
|
||||
view(request, request.user.username, shelf.id)
|
||||
|
||||
self.assertEqual(shelf.name, 'To Read')
|
||||
|
||||
|
||||
def test_handle_shelve(self):
|
||||
''' shelve a book '''
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': self.shelf.identifier
|
||||
})
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.broadcast.broadcast_task.delay'):
|
||||
views.shelve(request)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(self.shelf.books.get(), self.book)
|
||||
|
||||
|
||||
def test_handle_shelve_to_read(self):
|
||||
''' special behavior for the to-read shelf '''
|
||||
shelf = models.Shelf.objects.get(identifier='to-read')
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': shelf.identifier
|
||||
})
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.broadcast.broadcast_task.delay'):
|
||||
views.shelve(request)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
|
||||
def test_handle_shelve_reading(self):
|
||||
''' special behavior for the reading shelf '''
|
||||
shelf = models.Shelf.objects.get(identifier='reading')
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': shelf.identifier
|
||||
})
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.broadcast.broadcast_task.delay'):
|
||||
views.shelve(request)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
|
||||
def test_handle_shelve_read(self):
|
||||
''' special behavior for the read shelf '''
|
||||
shelf = models.Shelf.objects.get(identifier='read')
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': shelf.identifier
|
||||
})
|
||||
request.user = self.local_user
|
||||
|
||||
with patch('bookwyrm.broadcast.broadcast_task.delay'):
|
||||
views.shelve(request)
|
||||
# make sure the book is on the shelf
|
||||
self.assertEqual(shelf.books.get(), self.book)
|
||||
|
||||
|
||||
def test_handle_unshelve(self):
|
||||
''' remove a book from a shelf '''
|
||||
self.shelf.books.add(self.book)
|
||||
self.shelf.save()
|
||||
self.assertEqual(self.shelf.books.count(), 1)
|
||||
request = self.factory.post('', {
|
||||
'book': self.book.id,
|
||||
'shelf': self.shelf.id
|
||||
})
|
||||
request.user = self.local_user
|
||||
with patch('bookwyrm.broadcast.broadcast_task.delay'):
|
||||
views.unshelve(request)
|
||||
self.assertEqual(self.shelf.books.count(), 0)
|
|
@ -68,7 +68,7 @@ urlpatterns = [
|
|||
# users
|
||||
re_path(r'%s/?$' % user_path, views.User.as_view()),
|
||||
re_path(r'%s\.json$' % user_path, views.User.as_view()),
|
||||
re_path(r'%s/shelves/?$' % user_path, vviews.user_shelves_page),
|
||||
re_path(r'%s/shelves/?$' % user_path, views.user_shelves_page),
|
||||
re_path(r'%s/followers(.json)?/?$' % user_path, views.Followers.as_view()),
|
||||
re_path(r'%s/following(.json)?/?$' % user_path, views.Following.as_view()),
|
||||
re_path(r'^edit-profile/?$', views.EditUser.as_view()),
|
||||
|
@ -106,10 +106,15 @@ urlpatterns = [
|
|||
re_path(r'^tag/?$', views.AddTag.as_view()),
|
||||
re_path(r'^untag/?$', views.RemoveTag.as_view()),
|
||||
|
||||
# shelf
|
||||
re_path(r'^%s/shelf/(?P<shelf_identifier>[\w-]+)(.json)?/?$' % \
|
||||
user_path, vviews.shelf_page),
|
||||
user_path, views.Shelf.as_view()),
|
||||
re_path(r'^%s/shelf/(?P<shelf_identifier>[\w-]+)(.json)?/?$' % \
|
||||
local_user_path, vviews.shelf_page),
|
||||
local_user_path, views.Shelf.as_view()),
|
||||
re_path(r'^create-shelf/?$', views.create_shelf),
|
||||
re_path(r'^delete-shelf/(?P<shelf_id>\d+)?$', views.delete_shelf),
|
||||
re_path(r'^shelve/?$', views.shelve),
|
||||
re_path(r'^unshelve/?$', views.unshelve),
|
||||
|
||||
re_path(r'^search/?$', vviews.search),
|
||||
|
||||
|
@ -117,11 +122,6 @@ urlpatterns = [
|
|||
re_path(r'^delete-readthrough/?$', actions.delete_readthrough),
|
||||
re_path(r'^create-readthrough/?$', actions.create_readthrough),
|
||||
|
||||
re_path(r'^create-shelf/?$', actions.create_shelf),
|
||||
re_path(r'^edit-shelf/(?P<shelf_id>\d+)?$', actions.edit_shelf),
|
||||
re_path(r'^delete-shelf/(?P<shelf_id>\d+)?$', actions.delete_shelf),
|
||||
re_path(r'^shelve/?$', actions.shelve),
|
||||
re_path(r'^unshelve/?$', actions.unshelve),
|
||||
re_path(r'^start-reading/(?P<book_id>\d+)/?$', actions.start_reading),
|
||||
re_path(r'^finish-reading/(?P<book_id>\d+)/?$', actions.finish_reading),
|
||||
|
||||
|
|
|
@ -8,95 +8,22 @@ from django.shortcuts import get_object_or_404, redirect
|
|||
from django.utils import timezone
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
from bookwyrm import forms, models, outgoing
|
||||
from bookwyrm.vviews import get_user_from_username, get_edition
|
||||
from bookwyrm import models, outgoing
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def create_shelf(request):
|
||||
''' user generated shelves '''
|
||||
form = forms.ShelfForm(request.POST)
|
||||
if not form.is_valid():
|
||||
return redirect(request.headers.get('Referer', '/'))
|
||||
def get_edition(book_id):
|
||||
''' look up a book in the db and return an edition '''
|
||||
book = models.Book.objects.select_subclasses().get(id=book_id)
|
||||
if isinstance(book, models.Work):
|
||||
book = book.get_default_edition()
|
||||
return book
|
||||
|
||||
shelf = form.save()
|
||||
return redirect('/user/%s/shelf/%s' % \
|
||||
(request.user.localname, shelf.identifier))
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def edit_shelf(request, shelf_id):
|
||||
''' user generated shelves '''
|
||||
shelf = get_object_or_404(models.Shelf, id=shelf_id)
|
||||
if request.user != shelf.user:
|
||||
return HttpResponseBadRequest()
|
||||
if not shelf.editable and request.POST.get('name') != shelf.name:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
form = forms.ShelfForm(request.POST, instance=shelf)
|
||||
if not form.is_valid():
|
||||
return redirect(shelf.local_path)
|
||||
shelf = form.save()
|
||||
return redirect(shelf.local_path)
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def delete_shelf(request, shelf_id):
|
||||
''' user generated shelves '''
|
||||
shelf = get_object_or_404(models.Shelf, id=shelf_id)
|
||||
if request.user != shelf.user or not shelf.editable:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
shelf.delete()
|
||||
return redirect('/user/%s/shelves' % request.user.localname)
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def shelve(request):
|
||||
''' put a on a user's shelf '''
|
||||
book = get_edition(request.POST['book'])
|
||||
|
||||
desired_shelf = models.Shelf.objects.filter(
|
||||
identifier=request.POST['shelf'],
|
||||
user=request.user
|
||||
).first()
|
||||
|
||||
if request.POST.get('reshelve', True):
|
||||
try:
|
||||
current_shelf = models.Shelf.objects.get(
|
||||
user=request.user,
|
||||
edition=book
|
||||
)
|
||||
outgoing.handle_unshelve(request.user, book, current_shelf)
|
||||
except models.Shelf.DoesNotExist:
|
||||
# this just means it isn't currently on the user's shelves
|
||||
pass
|
||||
outgoing.handle_shelve(request.user, book, desired_shelf)
|
||||
|
||||
# post about "want to read" shelves
|
||||
if desired_shelf.identifier == 'to-read':
|
||||
outgoing.handle_reading_status(
|
||||
request.user,
|
||||
desired_shelf,
|
||||
book,
|
||||
privacy=desired_shelf.privacy
|
||||
)
|
||||
|
||||
return redirect('/')
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def unshelve(request):
|
||||
''' put a on a user's shelf '''
|
||||
book = models.Edition.objects.get(id=request.POST['book'])
|
||||
current_shelf = models.Shelf.objects.get(id=request.POST['shelf'])
|
||||
|
||||
outgoing.handle_unshelve(request.user, book, current_shelf)
|
||||
return redirect(request.headers.get('Referer', '/'))
|
||||
def get_user_from_username(username):
|
||||
''' helper function to resolve a localname or a username to a user '''
|
||||
# raises DoesNotExist if user is now found
|
||||
try:
|
||||
return models.User.objects.get(localname=username)
|
||||
except models.User.DoesNotExist:
|
||||
return models.User.objects.get(username=username)
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
|
@ -13,3 +13,6 @@ from .books import Book, EditBook, Editions
|
|||
from .books import upload_cover, add_description, switch_edition, resolve_book
|
||||
from .author import Author, EditAuthor
|
||||
from .tag import Tag, AddTag, RemoveTag
|
||||
from .shelf import Shelf
|
||||
from .shelf import user_shelves_page, create_shelf, delete_shelf
|
||||
from .shelf import shelve, unshelve
|
||||
|
|
|
@ -4,7 +4,9 @@ from requests import HTTPError
|
|||
from django.db.models import Q
|
||||
|
||||
from bookwyrm import activitypub, models
|
||||
from bookwyrm.broadcast import broadcast
|
||||
from bookwyrm.connectors import ConnectorException, get_data
|
||||
from bookwyrm.status import create_generated_note
|
||||
from bookwyrm.utils import regex
|
||||
|
||||
|
||||
|
@ -147,3 +149,25 @@ def get_edition(book_id):
|
|||
return book
|
||||
|
||||
|
||||
def handle_reading_status(user, shelf, book, privacy):
|
||||
''' post about a user reading a book '''
|
||||
# tell the world about this cool thing that happened
|
||||
try:
|
||||
message = {
|
||||
'to-read': 'wants to read',
|
||||
'reading': 'started reading',
|
||||
'read': 'finished reading'
|
||||
}[shelf.identifier]
|
||||
except KeyError:
|
||||
# it's a non-standard shelf, don't worry about it
|
||||
return
|
||||
|
||||
status = create_generated_note(
|
||||
user,
|
||||
message,
|
||||
mention_books=[book],
|
||||
privacy=privacy
|
||||
)
|
||||
status.save()
|
||||
|
||||
broadcast(user, status.to_create_activity(user))
|
||||
|
|
172
bookwyrm/views/shelf.py
Normal file
172
bookwyrm/views/shelf.py
Normal file
|
@ -0,0 +1,172 @@
|
|||
''' shelf views'''
|
||||
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.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 .helpers import is_api_request, get_edition, get_user_from_username
|
||||
from .helpers import handle_reading_status
|
||||
|
||||
|
||||
# pylint: disable= no-self-use
|
||||
class Shelf(View):
|
||||
''' shelf page '''
|
||||
def get(self, request, username, shelf_identifier):
|
||||
''' display a shelf '''
|
||||
try:
|
||||
user = get_user_from_username(username)
|
||||
except models.User.DoesNotExist:
|
||||
return HttpResponseNotFound()
|
||||
|
||||
if shelf_identifier:
|
||||
shelf = user.shelf_set.get(identifier=shelf_identifier)
|
||||
else:
|
||||
shelf = user.shelf_set.first()
|
||||
|
||||
is_self = request.user == user
|
||||
|
||||
shelves = user.shelf_set
|
||||
if not is_self:
|
||||
follower = user.followers.filter(id=request.user.id).exists()
|
||||
# make sure the user has permission to view the shelf
|
||||
if shelf.privacy == 'direct' or \
|
||||
(shelf.privacy == 'followers' and not follower):
|
||||
return HttpResponseNotFound()
|
||||
|
||||
# only show other shelves that should be visible
|
||||
if follower:
|
||||
shelves = shelves.filter(privacy__in=['public', 'followers'])
|
||||
else:
|
||||
shelves = shelves.filter(privacy='public')
|
||||
|
||||
|
||||
if is_api_request(request):
|
||||
return ActivitypubResponse(shelf.to_activity(**request.GET))
|
||||
|
||||
books = models.ShelfBook.objects.filter(
|
||||
added_by=user, shelf=shelf
|
||||
).order_by('-updated_date').all()
|
||||
|
||||
data = {
|
||||
'title': '%s\'s %s shelf' % (user.display_name, shelf.name),
|
||||
'user': user,
|
||||
'is_self': is_self,
|
||||
'shelves': shelves.all(),
|
||||
'shelf': shelf,
|
||||
'books': [b.book for b in books],
|
||||
}
|
||||
|
||||
return TemplateResponse(request, 'shelf.html', data)
|
||||
|
||||
@method_decorator(login_required, name='dispatch')
|
||||
def post(self, request, username, shelf_id):
|
||||
''' user generated shelves '''
|
||||
if not request.user.username == username:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
shelf = get_object_or_404(models.Shelf, id=shelf_id)
|
||||
if request.user != shelf.user:
|
||||
return HttpResponseBadRequest()
|
||||
if not shelf.editable and request.POST.get('name') != shelf.name:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
form = forms.ShelfForm(request.POST, instance=shelf)
|
||||
if not form.is_valid():
|
||||
return redirect(shelf.local_path)
|
||||
shelf = form.save()
|
||||
return redirect(shelf.local_path)
|
||||
|
||||
|
||||
def user_shelves_page(request, username):
|
||||
''' default shelf '''
|
||||
return Shelf.as_view()(request, username, None)
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def create_shelf(request):
|
||||
''' user generated shelves '''
|
||||
form = forms.ShelfForm(request.POST)
|
||||
if not form.is_valid():
|
||||
return redirect(request.headers.get('Referer', '/'))
|
||||
|
||||
shelf = form.save()
|
||||
return redirect('/user/%s/shelf/%s' % \
|
||||
(request.user.localname, shelf.identifier))
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def delete_shelf(request, shelf_id):
|
||||
''' user generated shelves '''
|
||||
shelf = get_object_or_404(models.Shelf, id=shelf_id)
|
||||
if request.user != shelf.user or not shelf.editable:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
shelf.delete()
|
||||
return redirect('/user/%s/shelves' % request.user.localname)
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def shelve(request):
|
||||
''' put a on a user's shelf '''
|
||||
book = get_edition(request.POST.get('book'))
|
||||
|
||||
desired_shelf = models.Shelf.objects.filter(
|
||||
identifier=request.POST.get('shelf'),
|
||||
user=request.user
|
||||
).first()
|
||||
|
||||
if request.POST.get('reshelve', True):
|
||||
try:
|
||||
current_shelf = models.Shelf.objects.get(
|
||||
user=request.user,
|
||||
edition=book
|
||||
)
|
||||
handle_unshelve(request.user, book, current_shelf)
|
||||
except models.Shelf.DoesNotExist:
|
||||
# this just means it isn't currently on the user's shelves
|
||||
pass
|
||||
shelfbook = models.ShelfBook(
|
||||
book=book, shelf=desired_shelf, added_by=request.user)
|
||||
shelfbook.save()
|
||||
|
||||
broadcast(request.user, shelfbook.to_add_activity(request.user))
|
||||
|
||||
# post about "want to read" shelves
|
||||
if desired_shelf.identifier == 'to-read':
|
||||
handle_reading_status(
|
||||
request.user,
|
||||
desired_shelf,
|
||||
book,
|
||||
privacy=desired_shelf.privacy
|
||||
)
|
||||
|
||||
return redirect('/')
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def unshelve(request):
|
||||
''' put a on a user's shelf '''
|
||||
book = models.Edition.objects.get(id=request.POST['book'])
|
||||
current_shelf = models.Shelf.objects.get(id=request.POST['shelf'])
|
||||
|
||||
handle_unshelve(request.user, book, current_shelf)
|
||||
return redirect(request.headers.get('Referer', '/'))
|
||||
|
||||
|
||||
def handle_unshelve(user, book, shelf):
|
||||
''' unshelve a book '''
|
||||
row = models.ShelfBook.objects.get(book=book, shelf=shelf)
|
||||
activity = row.to_remove_activity(user)
|
||||
row.delete()
|
||||
|
||||
broadcast(user, activity)
|
|
@ -3,40 +3,21 @@ import re
|
|||
|
||||
from django.contrib.postgres.search import TrigramSimilarity
|
||||
from django.db.models.functions import Greatest
|
||||
from django.http import HttpResponseNotFound, JsonResponse
|
||||
from django.http import JsonResponse
|
||||
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 models
|
||||
from bookwyrm.activitypub import ActivitypubResponse
|
||||
from bookwyrm.connectors import connector_manager
|
||||
from bookwyrm.utils import regex
|
||||
|
||||
def get_edition(book_id):
|
||||
''' look up a book in the db and return an edition '''
|
||||
book = models.Book.objects.select_subclasses().get(id=book_id)
|
||||
if isinstance(book, models.Work):
|
||||
book = book.get_default_edition()
|
||||
return book
|
||||
|
||||
|
||||
def get_user_from_username(username):
|
||||
''' helper function to resolve a localname or a username to a user '''
|
||||
# raises DoesNotExist if user is now found
|
||||
try:
|
||||
return models.User.objects.get(localname=username)
|
||||
except models.User.DoesNotExist:
|
||||
return models.User.objects.get(username=username)
|
||||
|
||||
|
||||
def is_api_request(request):
|
||||
''' check whether a request is asking for html or data '''
|
||||
return 'json' in request.headers.get('Accept') or \
|
||||
request.path[-5:] == '.json'
|
||||
|
||||
|
||||
def server_error_page(request):
|
||||
''' 500 errors '''
|
||||
return TemplateResponse(
|
||||
|
@ -84,59 +65,3 @@ def search(request):
|
|||
'query': query,
|
||||
}
|
||||
return TemplateResponse(request, 'search_results.html', data)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@require_GET
|
||||
def user_shelves_page(request, username):
|
||||
''' list of followers '''
|
||||
return shelf_page(request, username, None)
|
||||
|
||||
|
||||
@require_GET
|
||||
def shelf_page(request, username, shelf_identifier):
|
||||
''' display a shelf '''
|
||||
try:
|
||||
user = get_user_from_username(username)
|
||||
except models.User.DoesNotExist:
|
||||
return HttpResponseNotFound()
|
||||
|
||||
if shelf_identifier:
|
||||
shelf = user.shelf_set.get(identifier=shelf_identifier)
|
||||
else:
|
||||
shelf = user.shelf_set.first()
|
||||
|
||||
is_self = request.user == user
|
||||
|
||||
shelves = user.shelf_set
|
||||
if not is_self:
|
||||
follower = user.followers.filter(id=request.user.id).exists()
|
||||
# make sure the user has permission to view the shelf
|
||||
if shelf.privacy == 'direct' or \
|
||||
(shelf.privacy == 'followers' and not follower):
|
||||
return HttpResponseNotFound()
|
||||
|
||||
# only show other shelves that should be visible
|
||||
if follower:
|
||||
shelves = shelves.filter(privacy__in=['public', 'followers'])
|
||||
else:
|
||||
shelves = shelves.filter(privacy='public')
|
||||
|
||||
|
||||
if is_api_request(request):
|
||||
return ActivitypubResponse(shelf.to_activity(**request.GET))
|
||||
|
||||
books = models.ShelfBook.objects.filter(
|
||||
added_by=user, shelf=shelf
|
||||
).order_by('-updated_date').all()
|
||||
|
||||
data = {
|
||||
'title': '%s\'s %s shelf' % (user.display_name, shelf.name),
|
||||
'user': user,
|
||||
'is_self': is_self,
|
||||
'shelves': shelves.all(),
|
||||
'shelf': shelf,
|
||||
'books': [b.book for b in books],
|
||||
}
|
||||
|
||||
return TemplateResponse(request, 'shelf.html', data)
|
||||
|
|
Loading…
Reference in a new issue