moviewyrm/bookwyrm/views/feed.py

175 lines
5.8 KiB
Python
Raw Normal View History

2021-01-29 18:25:31 +00:00
''' non-interactive pages '''
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
2021-01-29 19:44:04 +00:00
from django.db.models import Q
2021-01-29 18:25:31 +00:00
from django.http import HttpResponseNotFound
from django.template.response import TemplateResponse
from django.utils import timezone
from django.utils.decorators import method_decorator
2021-03-02 17:59:15 +00:00
from django.utils.translation import gettext as _
2021-01-29 18:25:31 +00:00
from django.views import View
from bookwyrm import forms, models
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.settings import PAGE_LENGTH
2021-02-24 19:59:21 +00:00
from .helpers import get_activity_feed, get_user_from_username
2021-02-23 19:34:15 +00:00
from .helpers import is_api_request, is_bookwyrm_request, object_visible_to_user
2021-01-29 18:25:31 +00:00
# pylint: disable= no-self-use
@method_decorator(login_required, name='dispatch')
class Feed(View):
''' activity stream '''
def get(self, request, tab):
''' user's homepage with activity feed '''
try:
page = int(request.GET.get('page', 1))
except ValueError:
page = 1
if tab == 'home':
2021-02-24 19:59:21 +00:00
activities = get_activity_feed(
2021-02-24 20:06:00 +00:00
request.user, following_only=True)
2021-03-02 17:59:15 +00:00
tab_title = _('Home')
2021-01-29 18:25:31 +00:00
elif tab == 'local':
activities = get_activity_feed(
2021-02-24 19:35:19 +00:00
request.user, privacy=['public', 'followers'], local_only=True)
2021-03-02 17:59:15 +00:00
tab_title = _('Local')
2021-01-29 18:25:31 +00:00
else:
activities = get_activity_feed(
2021-02-24 19:35:19 +00:00
request.user, privacy=['public', 'followers'])
2021-03-02 17:59:15 +00:00
tab_title = _('Federated')
2021-01-29 18:25:31 +00:00
paginated = Paginator(activities, PAGE_LENGTH)
data = {**feed_page_data(request.user), **{
'user': request.user,
'activities': paginated.page(page),
'tab': tab,
2021-03-02 17:59:15 +00:00
'tab_title': tab_title,
2021-01-29 18:25:31 +00:00
'goal_form': forms.GoalForm(),
2021-01-29 19:14:18 +00:00
'path': '/%s' % tab,
2021-01-29 18:25:31 +00:00
}}
return TemplateResponse(request, 'feed/feed.html', data)
@method_decorator(login_required, name='dispatch')
class DirectMessage(View):
''' dm view '''
2021-01-29 19:44:04 +00:00
def get(self, request, username=None):
2021-01-29 18:25:31 +00:00
''' like a feed but for dms only '''
try:
page = int(request.GET.get('page', 1))
except ValueError:
page = 1
2021-01-29 19:44:04 +00:00
queryset = models.Status.objects
user = None
if username:
try:
2021-02-23 20:41:37 +00:00
user = get_user_from_username(request.user, username)
2021-01-29 19:44:04 +00:00
except models.User.DoesNotExist:
pass
if user:
queryset = queryset.filter(Q(user=user) | Q(mention_users=user))
activities = get_activity_feed(
2021-02-24 19:35:19 +00:00
request.user, privacy=['direct'], queryset=queryset)
2021-01-29 19:44:04 +00:00
2021-01-29 18:25:31 +00:00
paginated = Paginator(activities, PAGE_LENGTH)
activity_page = paginated.page(page)
data = {**feed_page_data(request.user), **{
'user': request.user,
2021-01-29 19:44:04 +00:00
'partner': user,
2021-01-29 18:25:31 +00:00
'activities': activity_page,
2021-01-29 19:14:18 +00:00
'path': '/direct-messages',
2021-01-29 18:25:31 +00:00
}}
return TemplateResponse(request, 'feed/direct_messages.html', data)
class Status(View):
''' get posting '''
def get(self, request, username, status_id):
''' display a particular status (and replies, etc) '''
try:
user = get_user_from_username(request.user, username)
2021-01-29 18:25:31 +00:00
status = models.Status.objects.select_subclasses().get(
id=status_id, deleted=False)
except ValueError:
return HttpResponseNotFound()
# the url should have the poster's username in it
if user != status.user:
return HttpResponseNotFound()
# make sure the user is authorized to see the status
if not object_visible_to_user(request.user, status):
return HttpResponseNotFound()
if is_api_request(request):
return ActivitypubResponse(
2021-02-23 19:34:15 +00:00
status.to_activity(pure=not is_bookwyrm_request(request)))
2021-01-29 18:25:31 +00:00
data = {**feed_page_data(request.user), **{
'status': status,
}}
return TemplateResponse(request, 'feed/status.html', data)
class Replies(View):
''' replies page (a json view of status) '''
def get(self, request, username, status_id):
''' ordered collection of replies to a status '''
# the html view is the same as Status
if not is_api_request(request):
status_view = Status.as_view()
return status_view(request, username, status_id)
# the json view is different than Status
status = models.Status.objects.get(id=status_id)
if status.user.localname != username:
return HttpResponseNotFound()
return ActivitypubResponse(status.to_replies(**request.GET))
def feed_page_data(user):
''' info we need for every feed page '''
if not user.is_authenticated:
return {}
goal = models.AnnualGoal.objects.filter(
user=user, year=timezone.now().year
).first()
return {
'suggested_books': get_suggested_books(user),
'goal': goal,
'goal_form': forms.GoalForm(),
}
def get_suggested_books(user, max_books=5):
''' helper to get a user's recent books '''
book_count = 0
preset_shelves = [
('reading', max_books), ('read', 2), ('to-read', max_books)
]
suggested_books = []
for (preset, shelf_max) in preset_shelves:
limit = shelf_max if shelf_max < (max_books - book_count) \
else max_books - book_count
shelf = user.shelf_set.get(identifier=preset)
shelf_books = shelf.shelfbook_set.order_by(
'-updated_date'
).all()[:limit]
if not shelf_books:
continue
shelf_preview = {
'name': shelf.name,
2021-03-02 18:32:46 +00:00
'identifier': shelf.identifier,
2021-01-29 18:25:31 +00:00
'books': [s.book for s in shelf_books]
}
suggested_books.append(shelf_preview)
book_count += len(shelf_preview['books'])
return suggested_books