Merge pull request #2247 from bookwyrm-social/followers-following-views

Merges follower/following views
This commit is contained in:
Mouse Reeve 2022-08-02 11:59:06 -07:00 committed by GitHub
commit 3270d0a7d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 101 additions and 98 deletions

View file

@ -4,7 +4,7 @@
{% load utilities %}
{% block primary_link %}{% spaceless %}
{% url 'user-followers' request.user.localname %}
{% url 'user-relationships' request.user.localname 'followers' %}
{% endspaceless %}{% endblock %}
{% block icon %}

View file

@ -4,7 +4,7 @@
{% load utilities %}
{% block primary_link %}{% spaceless %}
{% url 'user-followers' request.user.localname %}
{% url 'user-relationships' request.user.localname 'followers' %}
{% endspaceless %}{% endblock %}
{% block icon %}

View file

@ -6,11 +6,11 @@
{% with user|username as username %}
<nav class="tabs">
<ul>
{% url 'user-followers' user|username as url %}
{% url 'user-relationships' user|username 'followers' as url %}
<li{% if url == request.path or url == request.path|add:'/' %} class="is-active"{% endif %}>
<a href="{{ url }}">{% trans "Followers" %}</a>
</li>
{% url 'user-following' user|username as url %}
{% url 'user-relationships' user|username 'following' as url %}
<li{% if url == request.path or url == request.path|add:'/' %} class="is-active"{% endif %}>
<a href="{{ url }}">{% trans "Following" %}</a>
</li>

View file

@ -23,8 +23,14 @@
<p>
{% if request.user.id == user.id or admin_mode %}
<a href="{% url 'user-followers' user|username %}">{% blocktrans count counter=user.followers.count %}{{ counter }} follower{% plural %}{{ counter }} followers{% endblocktrans %}</a>,
<a href="{% url 'user-following' user|username %}">{% blocktrans with counter=user.following.count %}{{ counter }} following{% endblocktrans %}</a>
<a href="{% url 'user-relationships' user|username 'followers' %}">{% blocktrans trimmed count counter=user.followers.count %}
{{ counter }} follower
{% plural %}
{{ counter }} followers
{% endblocktrans %}</a>,
<a href="{% url 'user-relationships' user|username 'following' %}">{% blocktrans trimmed with counter=user.following.count %}
{{ counter }} following
{% endblocktrans %}</a>
{% elif request.user.is_authenticated %}
@ -34,7 +40,7 @@
{% endif %}
{% else %}
{% mutuals_count user as mutuals %}
<a href="{% url 'user-followers' user|username %}">
<a href="{% url 'user-relationships' user|username 'followers' %}">
{% if mutuals %}
{% blocktrans with mutuals_display=mutuals|intcomma count counter=mutuals %}{{ mutuals_display }} follower you follow{% plural %}{{ mutuals_display }} followers you follow{% endblocktrans %}
{% elif request.user in user.following.all %}

View file

@ -116,30 +116,38 @@ class UserViews(TestCase):
def test_followers_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Followers.as_view()
view = views.Relationships.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "mouse")
result = view(request, "mouse", "followers")
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.user.is_api_request") as is_api:
def test_followers_page_ap(self):
"""JSON response"""
view = views.Relationships.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.relationships.is_api_request") as is_api:
is_api.return_value = True
result = view(request, "mouse")
result = view(request, "mouse", "followers")
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_followers_page_anonymous(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Followers.as_view()
view = views.Relationships.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "mouse")
result = view(request, "mouse", "followers")
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
@ -148,55 +156,63 @@ class UserViews(TestCase):
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
def test_followers_page_blocked(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Followers.as_view()
view = views.Relationships.as_view()
request = self.factory.get("")
request.user = self.local_user
self.rat.blocks.add(self.local_user)
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
with self.assertRaises(Http404):
view(request, "rat")
view(request, "rat", "followers")
def test_following_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Following.as_view()
view = views.Relationships.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "mouse")
result = view(request, "mouse", "following")
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.user.is_api_request") as is_api:
def test_following_page_json(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Relationships.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.relationships.is_api_request") as is_api:
is_api.return_value = True
result = view(request, "mouse")
result = view(request, "mouse", "following")
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_following_page_anonymous(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Following.as_view()
view = views.Relationships.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "mouse")
result = view(request, "mouse", "following")
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_following_page_blocked(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Following.as_view()
view = views.Relationships.as_view()
request = self.factory.get("")
request.user = self.local_user
self.rat.blocks.add(self.local_user)
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
with self.assertRaises(Http404):
view(request, "rat")
view(request, "rat", "following")
def test_hide_suggestions(self):
"""update suggestions settings"""

View file

@ -376,14 +376,9 @@ urlpatterns = [
re_path(rf"^@(?P<username>{regex.USERNAME})$", views.user_redirect),
re_path(rf"{USER_PATH}/rss/?$", views.rss_feed.RssFeed(), name="user-rss"),
re_path(
rf"{USER_PATH}/followers(.json)?/?$",
views.Followers.as_view(),
name="user-followers",
),
re_path(
rf"{USER_PATH}/following(.json)?/?$",
views.Following.as_view(),
name="user-following",
rf"{USER_PATH}/(?P<direction>(followers|following))(.json)?/?$",
views.Relationships.as_view(),
name="user-relationships",
),
re_path(r"^hide-suggestions/?$", views.hide_suggestions, name="hide-suggestions"),
# groups

View file

@ -127,14 +127,8 @@ from .setup import InstanceConfig, CreateAdmin
from .status import CreateStatus, EditStatus, DeleteStatus, update_progress
from .status import edit_readthrough
from .updates import get_notification_count, get_unread_status_string
from .user import (
User,
Followers,
Following,
hide_suggestions,
user_redirect,
toggle_guided_tour,
)
from .user import User, hide_suggestions, user_redirect, toggle_guided_tour
from .relationships import Relationships
from .wellknown import *
from .annual_summary import (
AnnualSummary,

View file

@ -0,0 +1,50 @@
""" Following and followers lists """
from django.core.exceptions import PermissionDenied
from django.core.paginator import Paginator
from django.db.models import Q, Count
from django.template.response import TemplateResponse
from django.views import View
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.settings import PAGE_LENGTH
from .helpers import get_user_from_username, is_api_request
# pylint: disable=no-self-use
class Relationships(View):
"""list of followers/following view"""
def get(self, request, username, direction):
"""list of followers"""
user = get_user_from_username(request.user, username)
if is_api_request(request):
if direction == "followers":
return ActivitypubResponse(user.to_followers_activity(**request.GET))
return ActivitypubResponse(user.to_following_activity(**request.GET))
if user.hide_follows and user != request.user:
raise PermissionDenied()
annotation_queryset = (
user.followers if direction == "followers" else user.following
)
follows = annotate_if_follows(request.user, annotation_queryset)
paginated = Paginator(follows.all(), PAGE_LENGTH)
data = {
"user": user,
"is_self": request.user.id == user.id,
"follow_list": paginated.get_page(request.GET.get("page")),
}
return TemplateResponse(request, f"user/relationships/{direction}.html", data)
def annotate_if_follows(user, queryset):
"""Sort a list of users by if you follow them"""
if not user.is_authenticated:
return queryset.order_by("-created_date")
return queryset.annotate(
request_user_follows=Count("followers", filter=Q(followers=user))
).order_by("-request_user_follows", "-created_date")

View file

@ -1,8 +1,6 @@
""" non-interactive pages """
""" The user profile """
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.core.paginator import Paginator
from django.db.models import Q, Count
from django.http import Http404
from django.shortcuts import redirect
from django.template.response import TemplateResponse
@ -102,62 +100,6 @@ class User(View):
return TemplateResponse(request, "user/user.html", data)
class Followers(View):
"""list of followers view"""
def get(self, request, username):
"""list of followers"""
user = get_user_from_username(request.user, username)
if is_api_request(request):
return ActivitypubResponse(user.to_followers_activity(**request.GET))
if user.hide_follows and user != request.user:
raise PermissionDenied()
followers = annotate_if_follows(request.user, user.followers)
paginated = Paginator(followers.all(), PAGE_LENGTH)
data = {
"user": user,
"is_self": request.user.id == user.id,
"follow_list": paginated.get_page(request.GET.get("page")),
}
return TemplateResponse(request, "user/relationships/followers.html", data)
class Following(View):
"""list of following view"""
def get(self, request, username):
"""list of followers"""
user = get_user_from_username(request.user, username)
if is_api_request(request):
return ActivitypubResponse(user.to_following_activity(**request.GET))
if user.hide_follows and user != request.user:
raise PermissionDenied()
following = annotate_if_follows(request.user, user.following)
paginated = Paginator(following.all(), PAGE_LENGTH)
data = {
"user": user,
"is_self": request.user.id == user.id,
"follow_list": paginated.get_page(request.GET.get("page")),
}
return TemplateResponse(request, "user/relationships/following.html", data)
def annotate_if_follows(user, queryset):
"""Sort a list of users by if you follow them"""
if not user.is_authenticated:
return queryset.order_by("-created_date")
return queryset.annotate(
request_user_follows=Count("followers", filter=Q(followers=user))
).order_by("-request_user_follows", "-created_date")
@require_POST
@login_required
def hide_suggestions(request):