bookwyrm-mastodon/bookwyrm/vviews.py

200 lines
6.1 KiB
Python
Raw Normal View History

2020-02-22 17:02:03 -05:00
''' views for pages you can go to in the application '''
2020-05-04 00:13:43 -04:00
import re
2020-10-01 15:59:38 -04:00
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
2021-01-12 13:19:58 -05:00
from django.shortcuts import get_object_or_404
2020-01-25 18:25:19 -05:00
from django.template.response import TemplateResponse
2020-03-13 20:57:36 -04:00
from django.views.decorators.csrf import csrf_exempt
2020-11-28 11:22:25 -05:00
from django.views.decorators.http import require_GET
2020-01-25 01:32:41 -05:00
from bookwyrm import outgoing
2021-01-02 11:14:28 -05:00
from bookwyrm import forms, models
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.connectors import connector_manager
2020-11-01 13:42:48 -05:00
from bookwyrm.utils import regex
2020-01-28 14:45:27 -05:00
2021-01-02 11:14:28 -05:00
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):
2021-01-02 11:38:27 -05:00
book = book.get_default_edition()
2021-01-02 11:14:28 -05:00
return book
2020-02-22 17:02:03 -05:00
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
2020-02-22 17:02:03 -05:00
try:
return models.User.objects.get(localname=username)
2020-02-22 17:02:03 -05:00
except models.User.DoesNotExist:
return models.User.objects.get(username=username)
2020-02-22 17:02:03 -05:00
2020-03-13 20:57:36 -04:00
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(
request, 'error.html', {'title': 'Oops!'}, status=500)
def not_found_page(request, _):
''' 404s '''
return TemplateResponse(
request, 'notfound.html', {'title': 'Not found'}, status=404)
2020-11-28 11:22:25 -05:00
@require_GET
2020-05-04 00:13:43 -04:00
def search(request):
''' that search bar up top '''
query = request.GET.get('q')
min_confidence = request.GET.get('min_confidence', 0.1)
2020-05-04 13:15:41 -04:00
if is_api_request(request):
# only return local book results via json so we don't cause a cascade
book_results = connector_manager.local_search(
query, min_confidence=min_confidence)
2020-12-30 14:37:26 -05:00
return JsonResponse([r.json() for r in book_results], safe=False)
2020-05-04 00:13:43 -04:00
# use webfinger for mastodon style account@domain.com username
2021-01-06 19:01:13 -05:00
if re.match(r'\B%s' % regex.full_username, query):
outgoing.handle_remote_webfinger(query)
# do a local user search
user_results = models.User.objects.annotate(
similarity=Greatest(
TrigramSimilarity('username', query),
TrigramSimilarity('localname', query),
)
).filter(
similarity__gt=0.5,
).order_by('-similarity')[:10]
book_results = connector_manager.search(
query, min_confidence=min_confidence)
data = {
2020-11-02 17:25:16 -05:00
'title': 'Search Results',
'book_results': book_results,
'user_results': user_results,
'query': query,
}
return TemplateResponse(request, 'search_results.html', data)
2020-05-04 00:13:43 -04:00
@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)
2020-11-28 11:22:25 -05:00
@require_GET
2020-05-03 20:53:14 -04:00
def author_page(request, author_id):
2020-02-11 01:32:03 -05:00
''' landing page for an author '''
author = get_object_or_404(models.Author, id=author_id)
2020-02-11 01:32:03 -05:00
if is_api_request(request):
return ActivitypubResponse(author.to_activity())
books = models.Work.objects.filter(
Q(authors=author) | Q(editions__authors=author)).distinct()
2020-02-11 01:32:03 -05:00
data = {
2020-11-02 17:25:16 -05:00
'title': author.name,
2020-02-11 01:32:03 -05:00
'author': author,
2020-11-28 20:41:57 -05:00
'books': [b.get_default_edition() for b in books],
2020-02-11 01:32:03 -05:00
}
return TemplateResponse(request, 'author.html', data)
2020-11-28 11:22:25 -05:00
@require_GET
2020-02-21 12:10:27 -05:00
def tag_page(request, tag_id):
''' books related to a tag '''
2020-02-21 12:15:20 -05:00
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()
2020-02-21 12:10:27 -05:00
data = {
2020-11-02 17:25:16 -05:00
'title': tag_obj.name,
2020-02-21 12:10:27 -05:00
'books': books,
2020-02-21 12:15:20 -05:00
'tag': tag_obj,
2020-02-21 12:10:27 -05:00
}
return TemplateResponse(request, 'tag.html', data)
@csrf_exempt
2020-11-28 11:22:25 -05:00
@require_GET
def user_shelves_page(request, username):
''' list of followers '''
return shelf_page(request, username, None)
2020-11-28 11:22:25 -05:00
@require_GET
2020-02-21 19:03:05 -05:00
def shelf_page(request, username, shelf_identifier):
''' display a shelf '''
try:
user = get_user_from_username(username)
except models.User.DoesNotExist:
return HttpResponseNotFound()
2020-11-10 17:52:04 -05:00
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')
2020-03-27 22:52:05 -04:00
if is_api_request(request):
return ActivitypubResponse(shelf.to_activity(**request.GET))
2020-03-27 22:52:05 -04:00
2020-12-30 19:07:29 -05:00
books = models.ShelfBook.objects.filter(
added_by=user, shelf=shelf
).order_by('-updated_date').all()
2020-11-10 17:07:12 -05:00
data = {
2020-12-19 21:54:56 -05:00
'title': '%s\'s %s shelf' % (user.display_name, shelf.name),
2020-11-10 17:07:12 -05:00
'user': user,
'is_self': is_self,
'shelves': shelves.all(),
2020-11-10 17:52:04 -05:00
'shelf': shelf,
2020-12-30 19:07:29 -05:00
'books': [b.book for b in books],
2020-11-10 17:07:12 -05:00
}
return TemplateResponse(request, 'shelf.html', data)