2021-03-08 16:49:10 +00:00
|
|
|
""" non-interactive pages """
|
2021-01-29 18:25:31 +00:00
|
|
|
from django.contrib.auth.decorators import login_required
|
|
|
|
from django.core.paginator import Paginator
|
2021-03-27 15:15:39 +00:00
|
|
|
from django.db.models import Q
|
2021-04-30 16:33:36 +00:00
|
|
|
from django.http import HttpResponseNotFound, Http404
|
2021-01-29 18:25:31 +00:00
|
|
|
from django.template.response import TemplateResponse
|
|
|
|
from django.utils import timezone
|
|
|
|
from django.utils.decorators import method_decorator
|
|
|
|
from django.views import View
|
|
|
|
|
2021-03-23 01:39:16 +00:00
|
|
|
from bookwyrm import activitystreams, forms, models
|
2021-01-29 18:25:31 +00:00
|
|
|
from bookwyrm.activitypub import ActivitypubResponse
|
2021-03-23 01:39:16 +00:00
|
|
|
from bookwyrm.settings import PAGE_LENGTH, STREAMS
|
2021-04-06 15:31:18 +00:00
|
|
|
from bookwyrm.suggested_users import suggested_users
|
|
|
|
from .helpers import get_user_from_username, privacy_filter
|
2021-04-11 16:26:12 +00:00
|
|
|
from .helpers import is_api_request, is_bookwyrm_request
|
2021-01-29 18:25:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
# pylint: disable= no-self-use
|
2021-03-08 16:49:10 +00:00
|
|
|
@method_decorator(login_required, name="dispatch")
|
2021-01-29 18:25:31 +00:00
|
|
|
class Feed(View):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""activity stream"""
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2021-01-29 18:25:31 +00:00
|
|
|
def get(self, request, tab):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""user's homepage with activity feed"""
|
2021-08-05 00:53:44 +00:00
|
|
|
tab = [s for s in STREAMS if s["key"] == tab]
|
|
|
|
tab = tab[0] or STREAMS[0]
|
2021-03-22 21:11:23 +00:00
|
|
|
|
2021-08-05 00:53:44 +00:00
|
|
|
activities = activitystreams.streams[tab["key"]].get_activity_stream(request.user)
|
2021-01-29 18:25:31 +00:00
|
|
|
paginated = Paginator(activities, PAGE_LENGTH)
|
|
|
|
|
2021-04-06 15:31:18 +00:00
|
|
|
suggestions = suggested_users.get_suggestions(request.user)
|
2021-03-26 17:32:42 +00:00
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
data = {
|
|
|
|
**feed_page_data(request.user),
|
|
|
|
**{
|
|
|
|
"user": request.user,
|
2021-04-19 22:01:20 +00:00
|
|
|
"activities": paginated.get_page(request.GET.get("page")),
|
2021-04-06 15:31:18 +00:00
|
|
|
"suggested_users": suggestions,
|
2021-03-08 16:49:10 +00:00
|
|
|
"tab": tab,
|
2021-08-05 00:53:44 +00:00
|
|
|
"streams": STREAMS,
|
2021-03-08 16:49:10 +00:00
|
|
|
"goal_form": forms.GoalForm(),
|
2021-08-05 00:53:44 +00:00
|
|
|
"path": "/%s" % tab["key"],
|
2021-03-08 16:49:10 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
return TemplateResponse(request, "feed/feed.html", data)
|
2021-01-29 18:25:31 +00:00
|
|
|
|
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
@method_decorator(login_required, name="dispatch")
|
2021-01-29 18:25:31 +00:00
|
|
|
class DirectMessage(View):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""dm view"""
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2021-01-29 19:44:04 +00:00
|
|
|
def get(self, request, username=None):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""like a feed but for dms only"""
|
2021-03-23 02:17:46 +00:00
|
|
|
# remove fancy subclasses of status, keep just good ol' notes
|
|
|
|
queryset = models.Status.objects.filter(
|
|
|
|
review__isnull=True,
|
|
|
|
comment__isnull=True,
|
|
|
|
quotation__isnull=True,
|
|
|
|
generatednote__isnull=True,
|
|
|
|
)
|
2021-01-29 19:44:04 +00:00
|
|
|
|
|
|
|
user = None
|
|
|
|
if username:
|
|
|
|
try:
|
2021-02-23 20:41:37 +00:00
|
|
|
user = get_user_from_username(request.user, username)
|
2021-04-30 16:33:36 +00:00
|
|
|
except Http404:
|
2021-01-29 19:44:04 +00:00
|
|
|
pass
|
|
|
|
if user:
|
|
|
|
queryset = queryset.filter(Q(user=user) | Q(mention_users=user))
|
|
|
|
|
2021-03-29 20:51:06 +00:00
|
|
|
activities = privacy_filter(
|
|
|
|
request.user, queryset, privacy_levels=["direct"]
|
2021-03-29 21:20:51 +00:00
|
|
|
).order_by("-published_date")
|
2021-01-29 19:44:04 +00:00
|
|
|
|
2021-01-29 18:25:31 +00:00
|
|
|
paginated = Paginator(activities, PAGE_LENGTH)
|
2021-03-08 16:49:10 +00:00
|
|
|
data = {
|
|
|
|
**feed_page_data(request.user),
|
|
|
|
**{
|
|
|
|
"user": request.user,
|
|
|
|
"partner": user,
|
2021-04-19 22:01:20 +00:00
|
|
|
"activities": paginated.get_page(request.GET.get("page")),
|
2021-03-08 16:49:10 +00:00
|
|
|
"path": "/direct-messages",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return TemplateResponse(request, "feed/direct_messages.html", data)
|
2021-01-29 18:25:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Status(View):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""get posting"""
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2021-01-29 18:25:31 +00:00
|
|
|
def get(self, request, username, status_id):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""display a particular status (and replies, etc)"""
|
2021-01-29 18:25:31 +00:00
|
|
|
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(
|
2021-03-08 16:49:10 +00:00
|
|
|
id=status_id, deleted=False
|
|
|
|
)
|
2021-04-30 16:33:36 +00:00
|
|
|
except (ValueError, models.Status.DoesNotExist):
|
2021-01-29 18:25:31 +00:00
|
|
|
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
|
2021-04-11 16:26:12 +00:00
|
|
|
if not status.visible_to_user(request.user):
|
2021-01-29 18:25:31 +00:00
|
|
|
return HttpResponseNotFound()
|
|
|
|
|
|
|
|
if is_api_request(request):
|
|
|
|
return ActivitypubResponse(
|
2021-03-08 16:49:10 +00:00
|
|
|
status.to_activity(pure=not is_bookwyrm_request(request))
|
|
|
|
)
|
|
|
|
|
|
|
|
data = {
|
|
|
|
**feed_page_data(request.user),
|
|
|
|
**{
|
|
|
|
"status": status,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return TemplateResponse(request, "feed/status.html", data)
|
2021-01-29 18:25:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Replies(View):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""replies page (a json view of status)"""
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2021-01-29 18:25:31 +00:00
|
|
|
def get(self, request, username, status_id):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""ordered collection of replies to a status"""
|
2021-01-29 18:25:31 +00:00
|
|
|
# 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):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""info we need for every feed page"""
|
2021-01-29 18:25:31 +00:00
|
|
|
if not user.is_authenticated:
|
|
|
|
return {}
|
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
goal = models.AnnualGoal.objects.filter(user=user, year=timezone.now().year).first()
|
2021-01-29 18:25:31 +00:00
|
|
|
return {
|
2021-03-08 16:49:10 +00:00
|
|
|
"suggested_books": get_suggested_books(user),
|
|
|
|
"goal": goal,
|
|
|
|
"goal_form": forms.GoalForm(),
|
2021-01-29 18:25:31 +00:00
|
|
|
}
|
|
|
|
|
2021-03-08 16:49:10 +00:00
|
|
|
|
2021-01-29 18:25:31 +00:00
|
|
|
def get_suggested_books(user, max_books=5):
|
2021-04-26 16:15:42 +00:00
|
|
|
"""helper to get a user's recent books"""
|
2021-01-29 18:25:31 +00:00
|
|
|
book_count = 0
|
2021-03-08 16:49:10 +00:00
|
|
|
preset_shelves = [("reading", max_books), ("read", 2), ("to-read", max_books)]
|
2021-01-29 18:25:31 +00:00
|
|
|
suggested_books = []
|
|
|
|
for (preset, shelf_max) in preset_shelves:
|
2021-03-08 16:49:10 +00:00
|
|
|
limit = (
|
|
|
|
shelf_max
|
|
|
|
if shelf_max < (max_books - book_count)
|
|
|
|
else max_books - book_count
|
|
|
|
)
|
2021-01-29 18:25:31 +00:00
|
|
|
shelf = user.shelf_set.get(identifier=preset)
|
2021-05-23 00:33:10 +00:00
|
|
|
if not shelf.books.exists():
|
2021-01-29 18:25:31 +00:00
|
|
|
continue
|
2021-05-23 00:33:10 +00:00
|
|
|
|
2021-01-29 18:25:31 +00:00
|
|
|
shelf_preview = {
|
2021-03-08 16:49:10 +00:00
|
|
|
"name": shelf.name,
|
|
|
|
"identifier": shelf.identifier,
|
2021-05-23 00:33:10 +00:00
|
|
|
"books": shelf.books.order_by("shelfbook").prefetch_related("authors")[
|
|
|
|
:limit
|
|
|
|
],
|
2021-01-29 18:25:31 +00:00
|
|
|
}
|
|
|
|
suggested_books.append(shelf_preview)
|
2021-03-08 16:49:10 +00:00
|
|
|
book_count += len(shelf_preview["books"])
|
2021-01-29 18:25:31 +00:00
|
|
|
return suggested_books
|