Merge pull request #1845 from bookwyrm-social/organizing-templatetags

Organizing templatetags
This commit is contained in:
Mouse Reeve 2022-01-18 14:51:13 -08:00 committed by GitHub
commit db715cce2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 630 additions and 375 deletions

View file

@ -2,7 +2,7 @@
{% load humanize %} {% load humanize %}
{% load i18n %} {% load i18n %}
{% load utilities %} {% load utilities %}
{% load bookwyrm_tags %} {% load landing_page_tags %}
{% load cache %} {% load cache %}
{% block title %} {% block title %}

View file

@ -1,6 +1,6 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load book_display_tags %}
{% load humanize %} {% load humanize %}
{% load utilities %} {% load utilities %}
{% load static %} {% load static %}

View file

@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load book_display_tags %}
{% load utilities %} {% load utilities %}
{% get_book_file_links book as links %} {% get_book_file_links book as links %}

View file

@ -1,4 +1,4 @@
{% load bookwyrm_tags %} {% load rating_tags %}
{% load i18n %} {% load i18n %}
{% load utilities %} {% load utilities %}
{% load status_display %} {% load status_display %}

View file

@ -1,4 +1,4 @@
{% load bookwyrm_tags %} {% load landing_page_tags %}
{% load utilities %} {% load utilities %}
{% load i18n %} {% load i18n %}
{% load status_display %} {% load status_display %}

View file

@ -1,6 +1,6 @@
{% extends 'feed/layout.html' %} {% extends 'feed/layout.html' %}
{% load feed_page_tags %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %}
{% block opengraph_images %} {% block opengraph_images %}

View file

@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load feed_page_tags %}
{% suggested_books as suggested_books %} {% suggested_books as suggested_books %}
<section class="block"> <section class="block">

View file

@ -1,7 +1,6 @@
{% extends 'groups/layout.html' %} {% extends 'groups/layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load group_tags %}
{% load bookwyrm_group_tags %}
{% load markdown %} {% load markdown %}
{% block panel %} {% block panel %}

View file

@ -1,6 +1,6 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_group_tags %} {% load group_tags %}
{% block title %}{{ group.name }}{% endblock %} {% block title %}{{ group.name }}{% endblock %}

View file

@ -1,8 +1,7 @@
{% load i18n %} {% load i18n %}
{% load utilities %} {% load utilities %}
{% load humanize %} {% load humanize %}
{% load bookwyrm_tags %} {% load group_tags %}
{% load bookwyrm_group_tags %}
<h2 class="title is-5">Group Members</h2> <h2 class="title is-5">Group Members</h2>
{% if group.user == request.user %} {% if group.user == request.user %}

View file

@ -1,7 +1,7 @@
{% extends 'landing/layout.html' %} {% extends 'landing/layout.html' %}
{% load i18n %} {% load i18n %}
{% load cache %} {% load cache %}
{% load bookwyrm_tags %} {% load landing_page_tags %}
{% block panel %} {% block panel %}

View file

@ -1,4 +1,5 @@
{% load bookwyrm_tags %} {% load book_display_tags %}
{% load rating_tags %}
{% load markdown %} {% load markdown %}
{% load i18n %} {% load i18n %}

View file

@ -1,4 +1,4 @@
{% load bookwyrm_tags %} {% load rating_tags %}
{% load i18n %} {% load i18n %}
{% if book %} {% if book %}

View file

@ -1,7 +1,8 @@
{% extends 'embed-layout.html' %} {% extends 'embed-layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load book_display_tags %}
{% load bookwyrm_group_tags %} {% load rating_tags %}
{% load group_tags %}
{% load markdown %} {% load markdown %}
{% block title %}{% blocktrans with list_name=list.name owner=list.user.display_name %}{{ list_name }}, a list by {{owner}}{% endblocktrans %}{% endblock title %} {% block title %}{% blocktrans with list_name=list.name owner=list.user.display_name %}{{ list_name }}, a list by {{owner}}{% endblocktrans %}{% endblock title %}

View file

@ -1,7 +1,8 @@
{% extends 'lists/layout.html' %} {% extends 'lists/layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load rating_tags %}
{% load bookwyrm_group_tags %} {% load book_display_tags %}
{% load group_tags %}
{% load markdown %} {% load markdown %}
{% block breadcrumbs %} {% block breadcrumbs %}

View file

@ -1,4 +1,4 @@
{% load bookwyrm_tags %} {% load notification_page_tags %}
{% related_status notification as related_status %} {% related_status notification as related_status %}
<div class="notification {% if notification.id in unread %}has-background-primary{% endif %}"> <div class="notification {% if notification.id in unread %}has-background-primary{% endif %}">
<div class="columns is-mobile {% if notification.id in unread %}has-text-white{% else %}has-text-grey{% endif %}"> <div class="columns is-mobile {% if notification.id in unread %}has-text-white{% else %}has-text-grey{% endif %}">

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load bookwyrm_tags %} {% load shelf_tags %}
{% load utilities %} {% load utilities %}
{% load humanize %} {% load humanize %}
{% load i18n %} {% load i18n %}

View file

@ -1,5 +1,6 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_group_tags %} {% load group_tags %}
{% if request.user == user or not request.user == group.user or not request.user.is_authenticated %} {% if request.user == user or not request.user == group.user or not request.user.is_authenticated %}
{% elif user in request.user.blocks.all %} {% elif user in request.user.blocks.all %}
{% include 'snippets/block_button.html' with blocks=True %} {% include 'snippets/block_button.html' with blocks=True %}

View file

@ -1,5 +1,5 @@
{% extends "snippets/create_status/layout.html" %} {% extends "snippets/create_status/layout.html" %}
{% load bookwyrm_tags %} {% load shelf_tags %}
{% load i18n %} {% load i18n %}
{% load utilities %} {% load utilities %}
{% load status_display %} {% load status_display %}

View file

@ -1,4 +1,3 @@
{% load bookwyrm_tags %}
{% load i18n %} {% load i18n %}
{% load utilities %} {% load utilities %}
{% load status_display %} {% load status_display %}

View file

@ -1,5 +1,4 @@
{% extends "snippets/create_status/layout.html" %} {% extends "snippets/create_status/layout.html" %}
{% load bookwyrm_tags %}
{% load utilities %} {% load utilities %}
{% load status_display %} {% load status_display %}
{% load i18n %} {% load i18n %}

View file

@ -1,5 +1,4 @@
{% extends "snippets/create_status/layout.html" %} {% extends "snippets/create_status/layout.html" %}
{% load bookwyrm_tags %}
{% load utilities %} {% load utilities %}
{% load status_display %} {% load status_display %}
{% load i18n %} {% load i18n %}

View file

@ -1,5 +1,6 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_group_tags %} {% load group_tags %}
{% if group|is_invited:request.user %} {% if group|is_invited:request.user %}
<div class="field is-grouped"> <div class="field is-grouped">
<form action="/accept-group-invitation/" method="POST"> <form action="/accept-group-invitation/" method="POST">

View file

@ -1,5 +1,6 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load rating_tags %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<span class="is-sr-only">{% trans "Leave a rating" %}</span> <span class="is-sr-only">{% trans "Leave a rating" %}</span>
<div class="block"> <div class="block">

View file

@ -1,5 +1,6 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_group_tags %} {% load group_tags %}
{% if request.user == user or not request.user == group.user or not request.user.is_authenticated %} {% if request.user == user or not request.user == group.user or not request.user.is_authenticated %}
{% else %} {% else %}
{% if user in request.user.blocks.all %} {% if user in request.user.blocks.all %}

View file

@ -1,7 +1,7 @@
{% extends 'components/dropdown.html' %} {% extends 'components/dropdown.html' %}
{% load i18n %} {% load shelf_tags %}
{% load bookwyrm_tags %}
{% load utilities %} {% load utilities %}
{% load i18n %}
{% block dropdown-trigger %} {% block dropdown-trigger %}
<span>{% trans "Move book" %}</span> <span>{% trans "Move book" %}</span>

View file

@ -1,5 +1,5 @@
{% load bookwyrm_tags %}
{% load utilities %} {% load utilities %}
{% load shelf_tags %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}

View file

@ -1,5 +1,5 @@
{% load bookwyrm_tags %}
{% load utilities %} {% load utilities %}
{% load shelf_tags %}
{% load i18n %} {% load i18n %}
{% with next_shelf_identifier=active_shelf.shelf.identifier|next_shelf %} {% with next_shelf_identifier=active_shelf.shelf.identifier|next_shelf %}

View file

@ -1,5 +1,5 @@
{% load bookwyrm_tags %}
{% load utilities %} {% load utilities %}
{% load shelf_tags %}
{% load i18n %} {% load i18n %}
{% with next_shelf_identifier=active_shelf.shelf.identifier|next_shelf %} {% with next_shelf_identifier=active_shelf.shelf.identifier|next_shelf %}

View file

@ -1,4 +1,5 @@
{% load bookwyrm_tags %} {% load book_display_tags %}
{% load rating_tags %}
{% load markdown %} {% load markdown %}
{% load i18n %} {% load i18n %}
{% load static %} {% load static %}

View file

@ -1,6 +1,6 @@
{% spaceless %} {% spaceless %}
{% load bookwyrm_tags %} {% load book_display_tags %}
{% load markdown %} {% load markdown %}
{% load i18n %} {% load i18n %}
{% load cache %} {% load cache %}

View file

@ -4,7 +4,7 @@
{% load utilities %} {% load utilities %}
{% load markdown %} {% load markdown %}
{% load layout %} {% load layout %}
{% load bookwyrm_group_tags %} {% load group_tags %}
{% block title %}{{ user.display_name }}{% endblock %} {% block title %}{{ user.display_name }}{% endblock %}

View file

@ -1,7 +1,7 @@
{% load i18n %} {% load i18n %}
{% load humanize %} {% load humanize %}
{% load utilities %} {% load utilities %}
{% load bookwyrm_tags %} {% load user_page_tags %}
<div class="media block"> <div class="media block">
<div class="media-left"> <div class="media-left">

View file

@ -0,0 +1,17 @@
""" template filters """
from django import template
register = template.Library()
@register.filter(name="book_description")
def get_book_description(book):
"""use the work's text if the book doesn't have it"""
return book.description or book.parent_work.description
@register.simple_tag(takes_context=False)
def get_book_file_links(book):
"""links for a book"""
return book.file_links.filter(domain__status="approved")

View file

@ -1,226 +0,0 @@
""" template filters """
from django import template
from django.db.models import Avg, StdDev, Count, F, Q
from bookwyrm import models
from bookwyrm.utils import cache
from bookwyrm.views.feed import get_suggested_books
register = template.Library()
@register.filter(name="rating")
def get_rating(book, user):
"""get the overall rating of a book"""
return cache.get_or_set(
f"book-rating-{book.parent_work.id}-{user.id}",
lambda u, b: models.Review.privacy_filter(u)
.filter(book__parent_work__editions=b)
.aggregate(Avg("rating"))["rating__avg"]
or 0,
user,
book,
timeout=15552000,
)
@register.filter(name="user_rating")
def get_user_rating(book, user):
"""get a user's rating of a book"""
rating = (
models.Review.objects.filter(
user=user,
book=book,
rating__isnull=False,
deleted=False,
)
.order_by("-published_date")
.first()
)
if rating:
return rating.rating
return 0
@register.filter(name="is_book_on_shelf")
def get_is_book_on_shelf(book, shelf):
"""is a book on a shelf"""
return cache.get_or_set(
f"book-on-shelf-{book.id}-{shelf.id}",
lambda b, s: s.books.filter(id=b.id).exists(),
book,
shelf,
timeout=15552000,
)
@register.filter(name="book_description")
def get_book_description(book):
"""use the work's text if the book doesn't have it"""
return book.description or book.parent_work.description
@register.filter(name="next_shelf")
def get_next_shelf(current_shelf):
"""shelf you'd use to update reading progress"""
if current_shelf == "to-read":
return "reading"
if current_shelf == "reading":
return "read"
if current_shelf == "read":
return "complete"
return "to-read"
@register.filter(name="load_subclass")
def load_subclass(status):
"""sometimes you didn't select_subclass"""
if hasattr(status, "quotation"):
return status.quotation
if hasattr(status, "review"):
return status.review
if hasattr(status, "comment"):
return status.comment
if hasattr(status, "generatednote"):
return status.generatednote
return status
@register.simple_tag(takes_context=False)
def get_book_superlatives():
"""get book stats for the about page"""
total_ratings = models.Review.objects.filter(local=True, deleted=False).count()
data = {}
data["top_rated"] = (
models.Work.objects.annotate(
rating=Avg(
"editions__review__rating",
filter=Q(editions__review__local=True, editions__review__deleted=False),
),
rating_count=Count(
"editions__review",
filter=Q(editions__review__local=True, editions__review__deleted=False),
),
)
.annotate(weighted=F("rating") * F("rating_count") / total_ratings)
.filter(rating__gt=4, weighted__gt=0)
.order_by("-weighted")
.first()
)
data["controversial"] = (
models.Work.objects.annotate(
deviation=StdDev(
"editions__review__rating",
filter=Q(editions__review__local=True, editions__review__deleted=False),
),
rating_count=Count(
"editions__review",
filter=Q(editions__review__local=True, editions__review__deleted=False),
),
)
.annotate(weighted=F("deviation") * F("rating_count") / total_ratings)
.filter(weighted__gt=0)
.order_by("-weighted")
.first()
)
data["wanted"] = (
models.Work.objects.annotate(
shelf_count=Count(
"editions__shelves", filter=Q(editions__shelves__identifier="to-read")
)
)
.order_by("-shelf_count")
.first()
)
return data
@register.simple_tag(takes_context=False)
def related_status(notification):
"""for notifications"""
if not notification.related_status:
return None
return load_subclass(notification.related_status)
@register.simple_tag(takes_context=True)
def active_shelf(context, book):
"""check what shelf a user has a book on, if any"""
user = context["request"].user
return (
cache.get_or_set(
f"active_shelf-{user.id}-{book.id}",
lambda u, b: (
models.ShelfBook.objects.filter(
shelf__user=u,
book__parent_work__editions=b,
).first()
or False
),
user,
book,
timeout=15552000,
)
or {"book": book}
)
@register.simple_tag(takes_context=False)
def latest_read_through(book, user):
"""the most recent read activity"""
return cache.get_or_set(
f"latest_read_through-{user.id}-{book.id}",
lambda u, b: (
models.ReadThrough.objects.filter(user=u, book=b, is_active=True)
.order_by("-start_date")
.first()
or False
),
user,
book,
timeout=15552000,
)
@register.simple_tag(takes_context=False)
def get_landing_books():
"""list of books for the landing page"""
return list(
set(
models.Edition.objects.filter(
review__published_date__isnull=False,
review__deleted=False,
review__user__local=True,
review__privacy__in=["public", "unlisted"],
)
.exclude(cover__exact="")
.distinct()
.order_by("-review__published_date")[:6]
)
)
@register.simple_tag(takes_context=True)
def mutuals_count(context, user):
"""how many users that you follow, follow them"""
viewer = context["request"].user
if not viewer.is_authenticated:
return None
return user.followers.filter(followers=viewer).count()
@register.simple_tag(takes_context=True)
def suggested_books(context):
"""get books for suggested books panel"""
# this happens here instead of in the view so that the template snippet can
# be cached in the template
return get_suggested_books(context["request"].user)
@register.simple_tag(takes_context=False)
def get_book_file_links(book):
"""links for a book"""
return book.file_links.filter(domain__status="approved")

View file

@ -0,0 +1,28 @@
""" tags used on the feed pages """
from django import template
from bookwyrm.views.feed import get_suggested_books
register = template.Library()
@register.filter(name="load_subclass")
def load_subclass(status):
"""sometimes you didn't select_subclass"""
if hasattr(status, "quotation"):
return status.quotation
if hasattr(status, "review"):
return status.review
if hasattr(status, "comment"):
return status.comment
if hasattr(status, "generatednote"):
return status.generatednote
return status
@register.simple_tag(takes_context=True)
def suggested_books(context):
"""get books for suggested books panel"""
# this happens here instead of in the view so that the template snippet can
# be cached in the template
return get_suggested_books(context["request"].user)

View file

@ -0,0 +1,76 @@
""" template filters """
from django import template
from django.db.models import Avg, StdDev, Count, F, Q
from bookwyrm import models
register = template.Library()
@register.simple_tag(takes_context=False)
def get_book_superlatives():
"""get book stats for the about page"""
total_ratings = models.Review.objects.filter(local=True, deleted=False).count()
data = {}
data["top_rated"] = (
models.Work.objects.annotate(
rating=Avg(
"editions__review__rating",
filter=Q(editions__review__local=True, editions__review__deleted=False),
),
rating_count=Count(
"editions__review",
filter=Q(editions__review__local=True, editions__review__deleted=False),
),
)
.annotate(weighted=F("rating") * F("rating_count") / total_ratings)
.filter(rating__gt=4, weighted__gt=0)
.order_by("-weighted")
.first()
)
data["controversial"] = (
models.Work.objects.annotate(
deviation=StdDev(
"editions__review__rating",
filter=Q(editions__review__local=True, editions__review__deleted=False),
),
rating_count=Count(
"editions__review",
filter=Q(editions__review__local=True, editions__review__deleted=False),
),
)
.annotate(weighted=F("deviation") * F("rating_count") / total_ratings)
.filter(weighted__gt=0)
.order_by("-weighted")
.first()
)
data["wanted"] = (
models.Work.objects.annotate(
shelf_count=Count(
"editions__shelves", filter=Q(editions__shelves__identifier="to-read")
)
)
.order_by("-shelf_count")
.first()
)
return data
@register.simple_tag(takes_context=False)
def get_landing_books():
"""list of books for the landing page"""
return list(
set(
models.Edition.objects.filter(
review__published_date__isnull=False,
review__deleted=False,
review__user__local=True,
review__privacy__in=["public", "unlisted"],
)
.exclude(cover__exact="")
.distinct()
.order_by("-review__published_date")[:6]
)
)

View file

@ -0,0 +1,14 @@
""" tags used on the feed pages """
from django import template
from bookwyrm.templatetags.feed_page_tags import load_subclass
register = template.Library()
@register.simple_tag(takes_context=False)
def related_status(notification):
"""for notifications"""
if not notification.related_status:
return None
return load_subclass(notification.related_status)

View file

@ -0,0 +1,42 @@
""" template filters """
from django import template
from django.db.models import Avg
from bookwyrm import models
from bookwyrm.utils import cache
register = template.Library()
@register.filter(name="rating")
def get_rating(book, user):
"""get the overall rating of a book"""
return cache.get_or_set(
f"book-rating-{book.parent_work.id}-{user.id}",
lambda u, b: models.Review.privacy_filter(u)
.filter(book__parent_work__editions=b, rating__gt=0)
.aggregate(Avg("rating"))["rating__avg"]
or 0,
user,
book,
timeout=15552000,
)
@register.filter(name="user_rating")
def get_user_rating(book, user):
"""get a user's rating of a book"""
rating = (
models.Review.objects.filter(
user=user,
book=book,
rating__isnull=False,
deleted=False,
)
.order_by("-published_date")
.first()
)
if rating:
return rating.rating
return 0

View file

@ -0,0 +1,71 @@
""" Filters and tags related to shelving books """
from django import template
from bookwyrm import models
from bookwyrm.utils import cache
register = template.Library()
@register.filter(name="is_book_on_shelf")
def get_is_book_on_shelf(book, shelf):
"""is a book on a shelf"""
return cache.get_or_set(
f"book-on-shelf-{book.id}-{shelf.id}",
lambda b, s: s.books.filter(id=b.id).exists(),
book,
shelf,
timeout=15552000,
)
@register.filter(name="next_shelf")
def get_next_shelf(current_shelf):
"""shelf you'd use to update reading progress"""
if current_shelf == "to-read":
return "reading"
if current_shelf == "reading":
return "read"
if current_shelf == "read":
return "complete"
return "to-read"
@register.simple_tag(takes_context=True)
def active_shelf(context, book):
"""check what shelf a user has a book on, if any"""
user = context["request"].user
return (
cache.get_or_set(
f"active_shelf-{user.id}-{book.id}",
lambda u, b: (
models.ShelfBook.objects.filter(
shelf__user=u,
book__parent_work__editions=b,
).first()
or False
),
user,
book,
timeout=15552000,
)
or {"book": book}
)
@register.simple_tag(takes_context=False)
def latest_read_through(book, user):
"""the most recent read activity"""
return cache.get_or_set(
f"latest_read_through-{user.id}-{book.id}",
lambda u, b: (
models.ReadThrough.objects.filter(user=u, book=b, is_active=True)
.order_by("-start_date")
.first()
or False
),
user,
book,
timeout=15552000,
)

View file

@ -0,0 +1,14 @@
""" template filters """
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def mutuals_count(context, user):
"""how many users that you follow, follow them"""
viewer = context["request"].user
if not viewer.is_authenticated:
return None
return user.followers.filter(followers=viewer).count()

View file

@ -0,0 +1,62 @@
""" style fixes and lookups for templates """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import models
from bookwyrm.templatetags import book_display_tags
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
class BookDisplayTags(TestCase):
"""lotta different things here"""
def setUp(self):
"""create some filler objects"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
self.user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
)
self.book = models.Edition.objects.create(title="Test Book")
def test_get_book_description(self, *_):
"""grab it from the edition or the parent"""
work = models.Work.objects.create(title="Test Work")
self.book.parent_work = work
self.book.save()
self.assertIsNone(book_display_tags.get_book_description(self.book))
work.description = "hi"
work.save()
self.assertEqual(book_display_tags.get_book_description(self.book), "hi")
self.book.description = "hello"
self.book.save()
self.assertEqual(book_display_tags.get_book_description(self.book), "hello")
def test_get_book_file_links(self, *_):
"""load approved links"""
link = models.FileLink.objects.create(
book=self.book,
url="https://web.site/hello",
)
links = book_display_tags.get_book_file_links(self.book)
# the link is pending
self.assertFalse(links.exists())
domain = link.domain
domain.status = "approved"
domain.save()
links = book_display_tags.get_book_file_links(self.book)
self.assertTrue(links.exists())
self.assertEqual(links[0], link)

View file

@ -1,101 +0,0 @@
""" style fixes and lookups for templates """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import models
from bookwyrm.templatetags import bookwyrm_tags
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
class BookWyrmTags(TestCase):
"""lotta different things here"""
def setUp(self):
"""create some filler objects"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
self.user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.rat",
"ratword",
remote_id="http://example.com/rat",
local=False,
)
self.book = models.Edition.objects.create(title="Test Book")
def test_get_user_rating(self, *_):
"""get a user's most recent rating of a book"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"):
models.Review.objects.create(user=self.user, book=self.book, rating=3)
self.assertEqual(bookwyrm_tags.get_user_rating(self.book, self.user), 3)
def test_get_user_rating_doesnt_exist(self, *_):
"""there is no rating available"""
self.assertEqual(bookwyrm_tags.get_user_rating(self.book, self.user), 0)
def test_get_book_description(self, *_):
"""grab it from the edition or the parent"""
work = models.Work.objects.create(title="Test Work")
self.book.parent_work = work
self.book.save()
self.assertIsNone(bookwyrm_tags.get_book_description(self.book))
work.description = "hi"
work.save()
self.assertEqual(bookwyrm_tags.get_book_description(self.book), "hi")
self.book.description = "hello"
self.book.save()
self.assertEqual(bookwyrm_tags.get_book_description(self.book), "hello")
def test_get_next_shelf(self, *_):
"""self progress helper"""
self.assertEqual(bookwyrm_tags.get_next_shelf("to-read"), "reading")
self.assertEqual(bookwyrm_tags.get_next_shelf("reading"), "read")
self.assertEqual(bookwyrm_tags.get_next_shelf("read"), "complete")
self.assertEqual(bookwyrm_tags.get_next_shelf("blooooga"), "to-read")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
def test_load_subclass(self, *_):
"""get a status' real type"""
review = models.Review.objects.create(user=self.user, book=self.book, rating=3)
status = models.Status.objects.get(id=review.id)
self.assertIsInstance(status, models.Status)
self.assertIsInstance(bookwyrm_tags.load_subclass(status), models.Review)
quote = models.Quotation.objects.create(
user=self.user, book=self.book, content="hi"
)
status = models.Status.objects.get(id=quote.id)
self.assertIsInstance(status, models.Status)
self.assertIsInstance(bookwyrm_tags.load_subclass(status), models.Quotation)
comment = models.Comment.objects.create(
user=self.user, book=self.book, content="hi"
)
status = models.Status.objects.get(id=comment.id)
self.assertIsInstance(status, models.Status)
self.assertIsInstance(bookwyrm_tags.load_subclass(status), models.Comment)
def test_related_status(self, *_):
"""gets the subclass model for a notification status"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"):
status = models.Status.objects.create(content="hi", user=self.user)
notification = models.Notification.objects.create(
user=self.user, notification_type="MENTION", related_status=status
)
result = bookwyrm_tags.related_status(notification)
self.assertIsInstance(result, models.Status)

View file

@ -0,0 +1,49 @@
""" style fixes and lookups for templates """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import models
from bookwyrm.templatetags import feed_page_tags
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
class FeedPageTags(TestCase):
"""lotta different things here"""
def setUp(self):
"""create some filler objects"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
self.user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
)
self.book = models.Edition.objects.create(title="Test Book")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
def test_load_subclass(self, *_):
"""get a status' real type"""
review = models.Review.objects.create(user=self.user, book=self.book, rating=3)
status = models.Status.objects.get(id=review.id)
self.assertIsInstance(status, models.Status)
self.assertIsInstance(feed_page_tags.load_subclass(status), models.Review)
quote = models.Quotation.objects.create(
user=self.user, book=self.book, content="hi"
)
status = models.Status.objects.get(id=quote.id)
self.assertIsInstance(status, models.Status)
self.assertIsInstance(feed_page_tags.load_subclass(status), models.Quotation)
comment = models.Comment.objects.create(
user=self.user, book=self.book, content="hi"
)
status = models.Status.objects.get(id=comment.id)
self.assertIsInstance(status, models.Status)
self.assertIsInstance(feed_page_tags.load_subclass(status), models.Comment)

View file

@ -0,0 +1,37 @@
""" style fixes and lookups for templates """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import models
from bookwyrm.templatetags import notification_page_tags
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
class NotificationPageTags(TestCase):
"""lotta different things here"""
def setUp(self):
"""create some filler objects"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
self.user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
)
def test_related_status(self, *_):
"""gets the subclass model for a notification status"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"):
status = models.Status.objects.create(content="hi", user=self.user)
notification = models.Notification.objects.create(
user=self.user, notification_type="MENTION", related_status=status
)
result = notification_page_tags.related_status(notification)
self.assertIsInstance(result, models.Status)

View file

@ -0,0 +1,80 @@
""" Gettings book ratings """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import models
from bookwyrm.templatetags import rating_tags
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
class RatingTags(TestCase):
"""lotta different things here"""
def setUp(self):
"""create some filler objects"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.rat",
"ratword",
remote_id="http://example.com/rat",
local=False,
)
work = models.Work.objects.create(title="Work title")
self.book = models.Edition.objects.create(
title="Test Book",
parent_work=work,
)
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
def test_get_rating(self, *_):
"""privacy filtered rating"""
# follows-only: not included
models.ReviewRating.objects.create(
user=self.remote_user,
rating=5,
book=self.book,
privacy="followers",
)
self.assertEqual(rating_tags.get_rating(self.book, self.local_user), 0)
# public: included
models.ReviewRating.objects.create(
user=self.remote_user,
rating=5,
book=self.book,
privacy="public",
)
self.assertEqual(rating_tags.get_rating(self.book, self.local_user), 5)
# rating unset: not included
models.Review.objects.create(
name="blah",
user=self.local_user,
rating=0,
book=self.book,
privacy="public",
)
self.assertEqual(rating_tags.get_rating(self.book, self.local_user), 5)
def test_get_user_rating(self, *_):
"""get a user's most recent rating of a book"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"):
models.Review.objects.create(user=self.local_user, book=self.book, rating=3)
self.assertEqual(rating_tags.get_user_rating(self.book, self.local_user), 3)
def test_get_user_rating_doesnt_exist(self, *_):
"""there is no rating available"""
self.assertEqual(rating_tags.get_user_rating(self.book, self.local_user), 0)

View file

@ -0,0 +1,70 @@
""" style fixes and lookups for templates """
from unittest.mock import patch
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models
from bookwyrm.templatetags import shelf_tags
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
class ShelfTags(TestCase):
"""lotta different things here"""
def setUp(self):
"""create some filler objects"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.rat",
"ratword",
remote_id="http://example.com/rat",
local=False,
)
self.book = models.Edition.objects.create(
title="Test Book",
parent_work=models.Work.objects.create(title="Test work"),
)
def test_get_is_book_on_shelf(self, *_):
"""check if a book is on a shelf"""
shelf = self.local_user.shelf_set.first()
self.assertFalse(shelf_tags.get_is_book_on_shelf(self.book, shelf))
models.ShelfBook.objects.create(
shelf=shelf, book=self.book, user=self.local_user
)
self.assertTrue(shelf_tags.get_is_book_on_shelf(self.book, shelf))
def test_get_next_shelf(self, *_):
"""self progress helper"""
self.assertEqual(shelf_tags.get_next_shelf("to-read"), "reading")
self.assertEqual(shelf_tags.get_next_shelf("reading"), "read")
self.assertEqual(shelf_tags.get_next_shelf("read"), "complete")
self.assertEqual(shelf_tags.get_next_shelf("blooooga"), "to-read")
def test_active_shelf(self, *_):
"""get the shelf a book is on"""
shelf = self.local_user.shelf_set.first()
request = self.factory.get("")
request.user = self.local_user
context = {"request": request}
self.assertIsInstance(shelf_tags.active_shelf(context, self.book), dict)
models.ShelfBook.objects.create(
shelf=shelf, book=self.book, user=self.local_user
)
self.assertEqual(shelf_tags.active_shelf(context, self.book).shelf, shelf)

View file

@ -1,4 +1,5 @@
""" style fixes and lookups for templates """ """ style fixes and lookups for templates """
from datetime import datetime
from unittest.mock import patch from unittest.mock import patch
from django.test import TestCase from django.test import TestCase
@ -35,6 +36,12 @@ class StatusDisplayTags(TestCase):
) )
self.book = models.Edition.objects.create(title="Test Book") self.book = models.Edition.objects.create(title="Test Book")
def test_get_mentions(self, *_):
"""list of people mentioned"""
status = models.Status.objects.create(content="hi", user=self.remote_user)
result = status_display.get_mentions(status, self.user)
self.assertEqual(result, "@rat@example.com ")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")
def test_get_replies(self, *_): def test_get_replies(self, *_):
"""direct replies to a status""" """direct replies to a status"""
@ -83,8 +90,16 @@ class StatusDisplayTags(TestCase):
self.assertIsInstance(boosted, models.Review) self.assertIsInstance(boosted, models.Review)
self.assertEqual(boosted, status) self.assertEqual(boosted, status)
def test_get_mentions(self, *_): def test_get_published_date(self, *_):
"""list of people mentioned""" """date formatting"""
status = models.Status.objects.create(content="hi", user=self.remote_user) date = datetime(2020, 1, 1, 0, 0, tzinfo=timezone.utc)
result = status_display.get_mentions(status, self.user) with patch("django.utils.timezone.now") as timezone_mock:
self.assertEqual(result, "@rat@example.com ") timezone_mock.return_value = datetime(2022, 1, 1, 0, 0, tzinfo=timezone.utc)
result = status_display.get_published_date(date)
self.assertEqual(result, "Jan. 1, 2020")
date = datetime(2022, 1, 1, 0, 0, tzinfo=timezone.utc)
with patch("django.utils.timezone.now") as timezone_mock:
timezone_mock.return_value = datetime(2022, 1, 8, 0, 0, tzinfo=timezone.utc)
result = status_display.get_published_date(date)
self.assertEqual(result, "Jan 1")

View file

@ -35,6 +35,15 @@ class UtilitiesTags(TestCase):
) )
self.book = models.Edition.objects.create(title="Test Book") self.book = models.Edition.objects.create(title="Test Book")
def test_get_uuid(self, *_):
"""uuid functionality"""
uuid = utilities.get_uuid("hi")
self.assertTrue(re.match(r"hi[A-Za-z0-9\-]", uuid))
def test_join(self, *_):
"""concats things with underscores"""
self.assertEqual(utilities.join("hi", 5, "blah", 0.75), "hi_5_blah_0.75")
def test_get_user_identifer_local(self, *_): def test_get_user_identifer_local(self, *_):
"""fall back to the simplest uid available""" """fall back to the simplest uid available"""
self.assertNotEqual(self.user.username, self.user.localname) self.assertNotEqual(self.user.username, self.user.localname)
@ -46,11 +55,6 @@ class UtilitiesTags(TestCase):
utilities.get_user_identifier(self.remote_user), "rat@example.com" utilities.get_user_identifier(self.remote_user), "rat@example.com"
) )
def test_get_uuid(self, *_):
"""uuid functionality"""
uuid = utilities.get_uuid("hi")
self.assertTrue(re.match(r"hi[A-Za-z0-9\-]", uuid))
def test_get_title(self, *_): def test_get_title(self, *_):
"""the title of a book""" """the title of a book"""
self.assertEqual(utilities.get_title(None), "") self.assertEqual(utilities.get_title(None), "")