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
|
|
|
|
from django.views import View
|
|
|
|
|
|
|
|
from bookwyrm import forms, models
|
|
|
|
from bookwyrm.activitypub import ActivitypubResponse
|
|
|
|
from bookwyrm.settings import PAGE_LENGTH
|
|
|
|
from .helpers import get_activity_feed
|
|
|
|
from .helpers import 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':
|
|
|
|
activities = get_activity_feed(
|
|
|
|
request.user, ['public', 'unlisted', 'followers'],
|
|
|
|
following_only=True)
|
|
|
|
elif tab == 'local':
|
|
|
|
activities = get_activity_feed(
|
|
|
|
request.user, ['public', 'followers'], local_only=True)
|
|
|
|
else:
|
|
|
|
activities = get_activity_feed(
|
|
|
|
request.user, ['public', 'followers'])
|
|
|
|
paginated = Paginator(activities, PAGE_LENGTH)
|
|
|
|
|
|
|
|
data = {**feed_page_data(request.user), **{
|
|
|
|
'title': 'Updates Feed',
|
|
|
|
'user': request.user,
|
|
|
|
'activities': paginated.page(page),
|
|
|
|
'tab': tab,
|
|
|
|
'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(
|
|
|
|
request.user, 'direct', queryset=queryset)
|
|
|
|
|
2021-01-29 18:25:31 +00:00
|
|
|
paginated = Paginator(activities, PAGE_LENGTH)
|
|
|
|
activity_page = paginated.page(page)
|
|
|
|
data = {**feed_page_data(request.user), **{
|
|
|
|
'title': 'Direct Messages',
|
|
|
|
'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:
|
2021-02-23 21:12:50 +00:00
|
|
|
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), **{
|
|
|
|
'title': 'Status by %s' % user.username,
|
|
|
|
'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,
|
|
|
|
'books': [s.book for s in shelf_books]
|
|
|
|
}
|
|
|
|
suggested_books.append(shelf_preview)
|
|
|
|
book_count += len(shelf_preview['books'])
|
|
|
|
return suggested_books
|