Adds tag class views

This commit is contained in:
Mouse Reeve 2021-01-13 10:24:24 -08:00
parent 99abb2631e
commit 20e280e676
7 changed files with 183 additions and 110 deletions

View file

@ -48,8 +48,6 @@ class ViewActions(TestCase):
self.factory = RequestFactory() self.factory = RequestFactory()
def test_edit_shelf_privacy(self): def test_edit_shelf_privacy(self):
''' set name or privacy on shelf ''' ''' set name or privacy on shelf '''
shelf = self.local_user.shelf_set.get(identifier='to-read') shelf = self.local_user.shelf_set.get(identifier='to-read')
@ -168,43 +166,3 @@ class ViewActions(TestCase):
self.assertEqual(readthrough.finish_date.day, 7) self.assertEqual(readthrough.finish_date.day, 7)
self.assertEqual(readthrough.book, self.book) self.assertEqual(readthrough.book, self.book)
self.assertEqual(readthrough.user, self.local_user) self.assertEqual(readthrough.user, self.local_user)
def test_tag(self):
''' add a tag to a book '''
request = self.factory.post(
'', {
'name': 'A Tag!?',
'book': self.book.id,
})
request.user = self.local_user
with patch('bookwyrm.broadcast.broadcast_task.delay'):
actions.tag(request)
tag = models.Tag.objects.get()
user_tag = models.UserTag.objects.get()
self.assertEqual(tag.name, 'A Tag!?')
self.assertEqual(tag.identifier, 'A+Tag%21%3F')
self.assertEqual(user_tag.user, self.local_user)
self.assertEqual(user_tag.book, self.book)
def test_untag(self):
''' remove a tag from a book '''
tag = models.Tag.objects.create(name='A Tag!?')
models.UserTag.objects.create(
user=self.local_user, book=self.book, tag=tag)
request = self.factory.post(
'', {
'user': self.local_user.id,
'book': self.book.id,
'name': tag.name,
})
request.user = self.local_user
with patch('bookwyrm.broadcast.broadcast_task.delay'):
actions.untag(request)
self.assertTrue(models.Tag.objects.filter(name='A Tag!?').exists())
self.assertFalse(models.UserTag.objects.exists())

View file

@ -0,0 +1,99 @@
''' test for app action functionality '''
from unittest.mock import patch
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
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 TagViews(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.group = Group.objects.create(name='editor')
self.group.permissions.add(
Permission.objects.create(
name='edit_book',
codename='edit_book',
content_type=ContentType.objects.get_for_model(models.User)).id
)
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
)
def test_tag_page(self):
''' there are so many views, this just makes sure it LOADS '''
view = views.Tag.as_view()
tag = models.Tag.objects.create(name='hi there')
models.UserTag.objects.create(
tag=tag, user=self.local_user, book=self.book)
request = self.factory.get('')
with patch('bookwyrm.views.tag.is_api_request') as is_api:
is_api.return_value = False
result = view(request, tag.identifier)
self.assertIsInstance(result, TemplateResponse)
self.assertEqual(result.template_name, 'tag.html')
self.assertEqual(result.status_code, 200)
request = self.factory.get('')
with patch('bookwyrm.views.tag.is_api_request') as is_api:
is_api.return_value = True
result = view(request, tag.identifier)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_tag(self):
''' add a tag to a book '''
view = views.AddTag.as_view()
request = self.factory.post(
'', {
'name': 'A Tag!?',
'book': self.book.id,
})
request.user = self.local_user
with patch('bookwyrm.broadcast.broadcast_task.delay'):
view(request)
tag = models.Tag.objects.get()
user_tag = models.UserTag.objects.get()
self.assertEqual(tag.name, 'A Tag!?')
self.assertEqual(tag.identifier, 'A+Tag%21%3F')
self.assertEqual(user_tag.user, self.local_user)
self.assertEqual(user_tag.book, self.book)
def test_untag(self):
''' remove a tag from a book '''
view = views.RemoveTag.as_view()
tag = models.Tag.objects.create(name='A Tag!?')
models.UserTag.objects.create(
user=self.local_user, book=self.book, tag=tag)
request = self.factory.post(
'', {
'user': self.local_user.id,
'book': self.book.id,
'name': tag.name,
})
request.user = self.local_user
with patch('bookwyrm.broadcast.broadcast_task.delay'):
view(request)
self.assertTrue(models.Tag.objects.filter(name='A Tag!?').exists())
self.assertFalse(models.UserTag.objects.exists())

View file

@ -100,11 +100,12 @@ urlpatterns = [
re_path(r'^author/(?P<author_id>\d+)(.json)?/?$', views.Author.as_view()), 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'^author/(?P<author_id>\d+)/edit/?$', views.EditAuthor.as_view()),
re_path(r'^tag/?$', actions.tag), # tags
re_path(r'^untag/?$', actions.untag), re_path(r'^tag/(?P<tag_id>.+)\.json/?$', views.Tag.as_view()),
re_path(r'^tag/(?P<tag_id>.+)/?$', views.Tag.as_view()),
re_path(r'^tag/?$', views.AddTag.as_view()),
re_path(r'^untag/?$', views.RemoveTag.as_view()),
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)?/?$' % \ re_path(r'^%s/shelf/(?P<shelf_identifier>[\w-]+)(.json)?/?$' % \
user_path, vviews.shelf_page), user_path, vviews.shelf_page),
re_path(r'^%s/shelf/(?P<shelf_identifier>[\w-]+)(.json)?/?$' % \ re_path(r'^%s/shelf/(?P<shelf_identifier>[\w-]+)(.json)?/?$' % \

View file

@ -9,7 +9,6 @@ from django.utils import timezone
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from bookwyrm import forms, models, outgoing from bookwyrm import forms, models, outgoing
from bookwyrm.broadcast import broadcast
from bookwyrm.vviews import get_user_from_username, get_edition from bookwyrm.vviews import get_user_from_username, get_edition
@login_required @login_required
@ -215,47 +214,6 @@ def create_readthrough(request):
return redirect(request.headers.get('Referer', '/')) return redirect(request.headers.get('Referer', '/'))
@login_required
@require_POST
def tag(request):
''' tag a book '''
# I'm not using a form here because sometimes "name" is sent as a hidden
# field which doesn't validate
name = request.POST.get('name')
book_id = request.POST.get('book')
book = get_object_or_404(models.Edition, id=book_id)
tag_obj, created = models.Tag.objects.get_or_create(
name=name,
)
user_tag, _ = models.UserTag.objects.get_or_create(
user=request.user,
book=book,
tag=tag_obj,
)
if created:
broadcast(request.user, user_tag.to_add_activity(request.user))
return redirect('/book/%s' % book_id)
@login_required
@require_POST
def untag(request):
''' untag a book '''
name = request.POST.get('name')
tag_obj = get_object_or_404(models.Tag, name=name)
book_id = request.POST.get('book')
book = get_object_or_404(models.Edition, id=book_id)
user_tag = get_object_or_404(
models.UserTag, tag=tag_obj, book=book, user=request.user)
tag_activity = user_tag.to_remove_activity(request.user)
user_tag.delete()
broadcast(request.user, tag_activity)
return redirect('/book/%s' % book_id)
@login_required @login_required
@require_POST @require_POST
def follow(request): def follow(request):

View file

@ -12,3 +12,4 @@ from .interaction import Favorite, Unfavorite, Boost, Unboost
from .books import Book, EditBook, Editions from .books import Book, EditBook, Editions
from .books import upload_cover, add_description, switch_edition, resolve_book from .books import upload_cover, add_description, switch_edition, resolve_book
from .author import Author, EditAuthor from .author import Author, EditAuthor
from .tag import Tag, AddTag, RemoveTag

78
bookwyrm/views/tag.py Normal file
View file

@ -0,0 +1,78 @@
''' tagging views'''
from django.contrib.auth.decorators import login_required
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 bookwyrm import models
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.broadcast import broadcast
from .helpers import is_api_request
# pylint: disable= no-self-use
class Tag(View):
''' tag page '''
def get(self, request, tag_id):
''' see books related to a tag '''
tag_obj = models.Tag.objects.filter(identifier=tag_id).first()
if not tag_obj:
return HttpResponseNotFound()
if is_api_request(request):
return ActivitypubResponse(tag_obj.to_activity(**request.GET))
books = models.Edition.objects.filter(
usertag__tag__identifier=tag_id
).distinct()
data = {
'title': tag_obj.name,
'books': books,
'tag': tag_obj,
}
return TemplateResponse(request, 'tag.html', data)
@method_decorator(login_required, name='dispatch')
class AddTag(View):
''' add a tag to a book '''
def post(self, request):
''' tag a book '''
# I'm not using a form here because sometimes "name" is sent as a hidden
# field which doesn't validate
name = request.POST.get('name')
book_id = request.POST.get('book')
book = get_object_or_404(models.Edition, id=book_id)
tag_obj, created = models.Tag.objects.get_or_create(
name=name,
)
user_tag, _ = models.UserTag.objects.get_or_create(
user=request.user,
book=book,
tag=tag_obj,
)
if created:
broadcast(request.user, user_tag.to_add_activity(request.user))
return redirect('/book/%s' % book_id)
@method_decorator(login_required, name='dispatch')
class RemoveTag(View):
''' remove a user's tag from a book '''
def post(self, request):
''' untag a book '''
name = request.POST.get('name')
tag_obj = get_object_or_404(models.Tag, name=name)
book_id = request.POST.get('book')
book = get_object_or_404(models.Edition, id=book_id)
user_tag = get_object_or_404(
models.UserTag, tag=tag_obj, book=book, user=request.user)
tag_activity = user_tag.to_remove_activity(request.user)
user_tag.delete()
broadcast(request.user, tag_activity)
return redirect('/book/%s' % book_id)

View file

@ -22,7 +22,6 @@ def get_edition(book_id):
return book return book
def get_user_from_username(username): def get_user_from_username(username):
''' helper function to resolve a localname or a username to a user ''' ''' helper function to resolve a localname or a username to a user '''
# raises DoesNotExist if user is now found # raises DoesNotExist if user is now found
@ -87,27 +86,6 @@ def search(request):
return TemplateResponse(request, 'search_results.html', data) return TemplateResponse(request, 'search_results.html', data)
@require_GET
def tag_page(request, tag_id):
''' books related to a tag '''
tag_obj = models.Tag.objects.filter(identifier=tag_id).first()
if not tag_obj:
return HttpResponseNotFound()
if is_api_request(request):
return ActivitypubResponse(tag_obj.to_activity(**request.GET))
books = models.Edition.objects.filter(
usertag__tag__identifier=tag_id
).distinct()
data = {
'title': tag_obj.name,
'books': books,
'tag': tag_obj,
}
return TemplateResponse(request, 'tag.html', data)
@csrf_exempt @csrf_exempt
@require_GET @require_GET
def user_shelves_page(request, username): def user_shelves_page(request, username):