Merge pull request #384 from mouse-reeve/cleanup

Cleans up template tags
This commit is contained in:
Mouse Reeve 2020-12-12 20:07:44 -08:00 committed by GitHub
commit d4f8f2e276
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 288 additions and 60 deletions

View file

@ -1,7 +1,7 @@
''' customize the info available in context for rendering templates '''
from bookwyrm import models
def site_settings(request):
def site_settings(request):# pylint: disable=unused-argument
''' include the custom info about the site '''
return {
'site': models.SiteSettings.objects.get()

View file

@ -30,7 +30,7 @@ class CustomForm(ModelForm):
visible.field.widget.attrs['rows'] = None
visible.field.widget.attrs['class'] = css_classes[input_type]
# pylint: disable=missing-class-docstring
class LoginForm(CustomForm):
class Meta:
model = models.User
@ -131,6 +131,7 @@ class ImportForm(forms.Form):
class ExpiryWidget(widgets.Select):
def value_from_datadict(self, data, files, name):
''' human-readable exiration time buckets '''
selected_string = super().value_from_datadict(data, files, name)
if selected_string == 'day':

View file

@ -53,7 +53,7 @@ def import_data(job_id):
for item in job.items.all():
try:
item.resolve()
except Exception as e:
except Exception as e:# pylint: disable=broad-except
logger.exception(e)
item.fail_reason = 'Error loading book'
item.save()

View file

@ -17,9 +17,6 @@ from bookwyrm.signatures import Signature
@csrf_exempt
def inbox(request, username):
''' incoming activitypub events '''
# TODO: should do some kind of checking if the user accepts
# this action from the sender probably? idk
# but this will just throw a 404 if the user doesn't exist
try:
models.User.objects.get(localname=username)
except models.User.DoesNotExist:

View file

@ -16,7 +16,8 @@ class Author(ActivitypubMixin, BookWyrmModel):
max_length=255, blank=True, null=True, deduplication_field=True)
sync = models.BooleanField(default=True)
last_sync_date = models.DateTimeField(default=timezone.now)
wikipedia_link = fields.CharField(max_length=255, blank=True, null=True, deduplication_field=True)
wikipedia_link = fields.CharField(
max_length=255, blank=True, null=True, deduplication_field=True)
# idk probably other keys would be useful here?
born = fields.DateTimeField(blank=True, null=True)
died = fields.DateTimeField(blank=True, null=True)

View file

@ -44,6 +44,7 @@ class BookWyrmModel(models.Model):
@receiver(models.signals.post_save)
#pylint: disable=unused-argument
def execute_after_save(sender, instance, created, *args, **kwargs):
''' set the remote_id after save (when the id is available) '''
if not created or not hasattr(instance, 'get_remote_id'):

View file

@ -6,7 +6,6 @@ from django.db import models
from django.utils import timezone
from bookwyrm import books_manager
from bookwyrm.connectors import ConnectorException
from bookwyrm.models import ReadThrough, User, Book
from bookwyrm.utils.fields import JSONField
from .base_model import PrivacyLevels

View file

@ -37,7 +37,7 @@ class UserRelationship(ActivitypubMixin, BookWyrmModel):
activity_serializer = activitypub.Follow
def get_remote_id(self, status=None):
def get_remote_id(self, status=None):# pylint: disable=arguments-differ
''' use shelf identifier in remote_id '''
status = status or 'follows'
base_path = self.user_subject.remote_id

View file

@ -1,7 +1,7 @@
''' Handle user activity '''
from django.utils import timezone
from bookwyrm import activitypub, books_manager, models
from bookwyrm import models
from bookwyrm.sanitize_html import InputHtmlParser

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% block content %}
<div class="block">
<h1 class="title">{{ author.name }}</h1>

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% load humanize %}
{% block content %}

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% block content %}
<div class="block">
<h1 class="title">Editions of <a href="/book/{{ work.id }}">"{{ work.title }}"</a></h1>

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% block content %}
<div class="columns">

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% block content %}
<div class="block">
<h1 class="title">

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% block content %}
<div class="block">
<h1 class="title">

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% load humanize %}
{% block content %}
<div class="block">

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<!DOCTYPE html>
<html lang="en">
<head>

View file

@ -1,6 +1,6 @@
{% extends 'layout.html' %}
{% load humanize %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% block content %}
<div class="block">
<h1 class="title">Notifications</h1>

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% block content %}
<div class="columns">

View file

@ -1,3 +1,3 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<img class="avatar image {% if large %}is-96x96{% else %}is-32x32{% endif %}" src="{% if user.avatar %}/images/{{ user.avatar }}{% else %}/static/images/default_avi.jpg{% endif %}" alt="avatar for {{ user|username }}">

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<div class="cover-container is-{{ size }}">
{% if book.cover %}
<img class="book-cover" src="/images/{{ book.cover }}" alt="{% include 'snippets/cover_alt.html' with book=book %}">

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<div class="columns">
<div class="column is-narrow">
<div>

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
{% with status.id|uuid as uuid %}
<form name="boost" action="/boost/{{ status.id }}" method="post" onsubmit="return interact(event)" class="boost-{{ status.id }}-{{ uuid }} {% if request.user|boosted:status %}hidden{% endif %}" data-id="boost-{{ status.id }}-{{ uuid }}">
{% csrf_token %}

View file

@ -1,2 +1,2 @@
{% load fr_display %}
{% load bookwyrm_tags %}
'{{ book.title }}' Cover ({{ book|edition_info }})

View file

@ -1,5 +1,5 @@
{% load humanize %}
{% load fr_display %}
{% load bookwyrm_tags %}
<div class="tabs is-boxed">
<ul role="tablist">

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
{% with status.id|uuid as uuid %}
<form name="favorite" action="/favorite/{{ status.id }}" method="POST" onsubmit="return interact(event)" class="fav-{{ status.id }}-{{ uuid }} {% if request.user|liked:status %}hidden{% endif %}" data-id="fav-{{ status.id }}-{{ uuid }}">
{% csrf_token %}

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<div>
<input class="toggle-control" type="checkbox" name="finish-reading-{{ uuid }}" id="finish-reading-{{ uuid }}">
<div class="modal toggle-content hidden">

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
{% if request.user|follow_request_exists:user %}
<form action="/accept-follow-request/" method="POST">
{% csrf_token %}

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<div class="select">
{% with 0|uuid as uuid %}
{% if not no_label %}

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<span class="is-sr-only">Leave a rating</span>
<div class="field is-grouped stars rate-stars">
{% for i in '12345'|make_list %}

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
{% with activity.id|uuid as uuid %}
<form class="is-flex-grow-1" name="reply" action="/reply" method="post" onsubmit="return reply(event)">
<div class="columns">

View file

@ -1,5 +1,5 @@
{% load humanize %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% if shelf.books.all|length > 0 %}
<table class="table is-striped is-fullwidth">

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
{% if request.user.is_authenticated %}
{% with book.id|uuid as uuid %}

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
{% if not status.deleted %}
{% if status.status_type == 'Boost' %}
{% include 'snippets/avatar.html' with user=status.user %}

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
{% load humanize %}
{% if not status.deleted %}

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<div class="block">
{% if status.status_type == 'Review' %}
<h3>

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
{% include 'snippets/avatar.html' with user=status.user %}
{% include 'snippets/username.html' with user=status.user %}

View file

@ -1,4 +1,4 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<div class="block">
{% with depth=depth|add:1 %}

View file

@ -1,8 +1,8 @@
{% load fr_display %}
{% load bookwyrm_tags %}
{% with 0|uuid as uuid %}
{% if full %}
{% with full|text_overflow as trimmed %}
{% with full|truncatewords_html:60 as trimmed %}
{% if trimmed != full %}
<div>
<input type="radio" name="show-hide-{{ uuid }}" id="show-{{ uuid }}" class="toggle-control" checked>

View file

@ -1,5 +1,5 @@
{% load humanize %}
{% load fr_display %}
{% load bookwyrm_tags %}
<div class="block">
<div class="columns">
<div class="column is-narrow">

View file

@ -1,2 +1,2 @@
{% load fr_display %}
{% load bookwyrm_tags %}
<a href="/user/{{ user | username }}" class="user">{% if user.name %}{{ user.name }}{% else %}{{ user | username }}{% endif %}</a>{% if possessive %}'s{% endif %}{% if show_full and user.name or show_full and user.localname %} ({{ user.username }}){% endif %}

View file

@ -1,5 +1,5 @@
{% extends 'layout.html' %}
{% load fr_display %}
{% load bookwyrm_tags %}
{% block content %}
<div class="block">

View file

@ -13,7 +13,7 @@ register = template.Library()
@register.filter(name='dict_key')
def dict_key(d, k):
'''Returns the given key from a dictionary.'''
''' Returns the given key from a dictionary. '''
return d.get(k) or 0
@ -116,20 +116,6 @@ 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='text_overflow')
def text_overflow(text):
''' dont' let book descriptions run for ages '''
if not text:
return ''
char_max = 400
if text and len(text) < char_max:
return text
trimmed = text[:char_max]
# go back to the last space
trimmed = ' '.join(trimmed.split(' ')[:-1])
return trimmed + '...'
@register.filter(name='uuid')
def get_uuid(identifier):
@ -146,6 +132,8 @@ def time_since(date):
delta = now - date
if date < (now - relativedelta(weeks=1)):
if date.year != now.year:
return date.strftime('%b %-d %Y')
return date.strftime('%b %-d')
delta = relativedelta(now, date)
if delta.days:
@ -160,7 +148,6 @@ def time_since(date):
@register.simple_tag(takes_context=True)
def active_shelf(context, book):
''' check what shelf a user has a book on, if any '''
#TODO: books can be on multiple shelves, handle that better
shelf = models.ShelfBook.objects.filter(
shelf__user=context['request'].user,
book=book

View file

@ -0,0 +1,242 @@
''' style fixes and lookups for templates '''
import re
from unittest.mock import patch
from dateutil.parser import parse
from dateutil.relativedelta import relativedelta
from django.test import TestCase
from django.utils import timezone
from bookwyrm import models
from bookwyrm.templatetags import bookwyrm_tags
class TemplateTags(TestCase):
''' lotta different things here '''
def setUp(self):
''' create some filler objects '''
self.user = models.User.objects.create_user(
'mouse', 'mouse@mouse.mouse', 'mouseword', local=True)
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_dict_key(self):
''' just getting a value out of a dict '''
test_dict = {'a': 1, 'b': 3}
self.assertEqual(
bookwyrm_tags.dict_key(test_dict, 'a'), 1)
self.assertEqual(
bookwyrm_tags.dict_key(test_dict, 'c'), 0)
def test_get_rating(self):
''' get a user's most recent rating of a book '''
models.Review.objects.create(
user=self.user, book=self.book, rating=3)
self.assertEqual(
bookwyrm_tags.get_rating(self.book, self.user), 3)
def test_get_rating_doesnt_exist(self):
''' there is no rating available '''
self.assertEqual(
bookwyrm_tags.get_rating(self.book, self.user), 0)
def test_get_user_identifer_local(self):
''' fall back to the simplest uid available '''
self.assertNotEqual(self.user.username, self.user.localname)
self.assertEqual(
bookwyrm_tags.get_user_identifier(self.user), 'mouse')
def test_get_user_identifer_remote(self):
''' for a remote user, should be their full username '''
self.assertEqual(
bookwyrm_tags.get_user_identifier(self.remote_user),
'rat@example.com')
def test_get_notification_count(self):
''' just countin' '''
self.assertEqual(bookwyrm_tags.get_notification_count(self.user), 0)
models.Notification.objects.create(
user=self.user, notification_type='FOLLOW')
models.Notification.objects.create(
user=self.user, notification_type='FOLLOW')
models.Notification.objects.create(
user=self.remote_user, notification_type='FOLLOW')
self.assertEqual(bookwyrm_tags.get_notification_count(self.user), 2)
def test_get_replies(self):
''' direct replies to a status '''
parent = models.Review.objects.create(
user=self.user, book=self.book)
first_child = models.Status.objects.create(
reply_parent=parent, user=self.user)
second_child = models.Status.objects.create(
reply_parent=parent, user=self.user)
third_child = models.Status.objects.create(
reply_parent=parent, user=self.user, deleted=True)
replies = bookwyrm_tags.get_replies(parent)
self.assertEqual(len(replies), 2)
self.assertTrue(first_child in replies)
self.assertTrue(second_child in replies)
self.assertFalse(third_child in replies)
def test_get_parent(self):
''' get the reply parent of a status '''
parent = models.Review.objects.create(
user=self.user, book=self.book)
child = models.Status.objects.create(
reply_parent=parent, user=self.user)
result = bookwyrm_tags.get_parent(child)
self.assertEqual(result, parent)
self.assertIsInstance(result, models.Review)
def test_get_user_liked(self):
''' did a user like a status '''
status = models.Review.objects.create(
user=self.remote_user, book=self.book)
self.assertFalse(bookwyrm_tags.get_user_liked(self.user, status))
models.Favorite.objects.create(
user=self.user,
status=status
)
self.assertTrue(bookwyrm_tags.get_user_liked(self.user, status))
def test_get_user_boosted(self):
''' did a user boost a status '''
status = models.Review.objects.create(
user=self.remote_user, book=self.book)
self.assertFalse(bookwyrm_tags.get_user_boosted(self.user, status))
models.Boost.objects.create(
user=self.user,
boosted_status=status
)
self.assertTrue(bookwyrm_tags.get_user_boosted(self.user, status))
def test_follow_request_exists(self):
''' does a user want to follow '''
self.assertFalse(
bookwyrm_tags.follow_request_exists(self.user, self.remote_user))
models.UserFollowRequest.objects.create(
user_subject=self.user,
user_object=self.remote_user)
self.assertFalse(
bookwyrm_tags.follow_request_exists(self.user, self.remote_user))
self.assertTrue(
bookwyrm_tags.follow_request_exists(self.remote_user, self.user))
def test_get_boosted(self):
''' load a boosted status '''
status = models.Review.objects.create(
user=self.remote_user, book=self.book)
boost = models.Boost.objects.create(
user=self.user,
boosted_status=status
)
boosted = bookwyrm_tags.get_boosted(boost)
self.assertIsInstance(boosted, models.Review)
self.assertEqual(boosted, status)
def test_get_edition_info(self):
''' text slug about an edition '''
self.assertEqual(
bookwyrm_tags.get_edition_info(self.book), '')
self.book.physical_format = 'worm'
self.book.save()
self.assertEqual(
bookwyrm_tags.get_edition_info(self.book), 'worm')
self.book.languages = ['English']
self.book.save()
self.assertEqual(
bookwyrm_tags.get_edition_info(self.book), 'worm')
self.book.languages = ['Glorbish', 'English']
self.book.save()
self.assertEqual(
bookwyrm_tags.get_edition_info(self.book),
'worm, Glorbish language')
self.book.published_date = timezone.make_aware(parse('2020'))
self.book.save()
self.assertEqual(
bookwyrm_tags.get_edition_info(self.book),
'worm, Glorbish language, 2020')
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_uuid(self):
''' uuid functionality '''
uuid = bookwyrm_tags.get_uuid('hi')
self.assertTrue(re.match(r'hi[A-Za-z0-9\-]', uuid))
def test_time_since(self):
''' ultraconcise timestamps '''
self.assertEqual(bookwyrm_tags.time_since('bleh'), '')
now = timezone.now()
self.assertEqual(bookwyrm_tags.time_since(now), '0s')
seconds_ago = now - relativedelta(seconds=4)
self.assertEqual(bookwyrm_tags.time_since(seconds_ago), '4s')
minutes_ago = now - relativedelta(minutes=8)
self.assertEqual(bookwyrm_tags.time_since(minutes_ago), '8m')
hours_ago = now - relativedelta(hours=9)
self.assertEqual(bookwyrm_tags.time_since(hours_ago), '9h')
days_ago = now - relativedelta(days=3)
self.assertEqual(bookwyrm_tags.time_since(days_ago), '3d')
# I am not going to figure out how to mock dates tonight.
months_ago = now - relativedelta(months=5)
self.assertTrue(re.match(
r'[A-Z][a-z]{2} \d?\d',
bookwyrm_tags.time_since(months_ago)
))
years_ago = now - relativedelta(years=10)
self.assertTrue(re.match(
r'[A-Z][a-z]{2} \d?\d \d{4}',
bookwyrm_tags.time_since(years_ago)
))