Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2021-02-03 16:45:44 -08:00
commit a0b0edbc3e
13 changed files with 157 additions and 76 deletions

View file

@ -0,0 +1,34 @@
''' PROCEED WITH CAUTION: this permanently deletes book data '''
from django.core.management.base import BaseCommand
from django.db.models import Count, Q
from bookwyrm import models
def remove_editions():
''' combine duplicate editions and update related models '''
# not in use
filters = {'%s__isnull' % r.name: True \
for r in models.Edition._meta.related_objects}
# no cover, no identifying fields
filters['cover'] = ''
null_fields = {'%s__isnull' % f: True for f in \
['isbn_10', 'isbn_13', 'oclc_number']}
editions = models.Edition.objects.filter(
Q(languages=[]) | Q(languages__contains=['English']),
**filters, **null_fields
).annotate(Count('parent_work__editions')).filter(
# mustn't be the only edition for the work
parent_work__editions__count__gt=1
)
print(editions.count())
editions.delete()
class Command(BaseCommand):
''' dedplucate allllll the book data models '''
help = 'merges duplicate book data'
# pylint: disable=no-self-use,unused-argument
def handle(self, *args, **options):
''' run deudplications '''
remove_editions()

View file

@ -0,0 +1,13 @@
<section class="card hidden {{ class }}" id="{{ controls_text }}{% if controls_uid %}-{{ controls_uid }}{% endif %}">
<header class="card-header has-background-white-ter">
<h2 class="card-header-title" tabindex="0" id="{{ controls_text }}{% if controls_uid %}-{{ controls_uid }}{% endif %}-header">
{% block header %}{% endblock %}
</h2>
<span class="card-header-icon">
{% include 'snippets/toggle/toggle_button.html' with label="Close" class="delete" nonbutton=True controls_text=controls_text %}
</span>
</header>
<section class="card-content content">
{% block form %}{% endblock %}
</section>
</section>

View file

@ -0,0 +1,11 @@
{% extends 'components/inline_form.html' %}
{% block header %}
Create List
{% endblock %}
{% block form %}
<form name="create-list" method="post" action="{% url 'lists' %}">
{% include 'lists/form.html' %}
</form>
{% endblock %}

View file

@ -0,0 +1,11 @@
{% extends 'components/inline_form.html' %}
{% block header %}
Edit List
{% endblock %}
{% block form %}
<form name="edit-list" method="post" action="{% url 'list' list.id %}">
{% include 'lists/form.html' %}
</form>
{% endblock %}

View file

@ -9,8 +9,8 @@
</h4> </h4>
</header> </header>
<div class="card-image is-flex"> <div class="card-image is-flex">
{% for book in list.books.all|slice:5 %} {% for book in list.listitem_set.all|slice:5 %}
{% include 'snippets/book_cover.html' with book=book size="small" %} {% include 'snippets/book_cover.html' with book=book.book size="small" %}
{% endfor %} {% endfor %}
</div> </div>
<div class="card-content is-flex-grow-0"> <div class="card-content is-flex-grow-0">

View file

@ -15,15 +15,9 @@
{% endif %} {% endif %}
</header> </header>
<form name="edit-list" method="post" action="{% url 'list' list.id %}" class="box hidden" id="edit-list"> <div class="block">
<header class="columns"> {% include 'lists/edit_form.html' with controls_text="edit-list" %}
<h3 class="title column" tabindex="0" id="edit-list-header">Edit list</h3> </div>
<div class="column is-narrow">
{% include 'snippets/toggle/toggle_button.html' with controls_text="edit-list" label="close" class="delete" nonbutton=True %}
</div>
</header>
{% include 'lists/form.html' %}
</form>
{% block panel %}{% endblock %} {% block panel %}{% endblock %}

View file

@ -5,26 +5,20 @@
<h1 class="title">Lists</h1> <h1 class="title">Lists</h1>
</header> </header>
{% if request.user.is_authenticated and not lists.has_previous %} {% if request.user.is_authenticated and not lists.has_previous %}
<section class="block content"> <header class="block columns">
<header class="columns"> <div class="column">
<div class="column"> <h2 class="title">Your lists</h2>
<h2 class="title">Your lists</h2> </div>
</div> <div class="column is-narrow">
<div class="column is-narrow"> {% include 'snippets/toggle/open_button.html' with controls_text="create-list" icon="plus" text="Create new list" focus="create-list-header" %}
{% include 'snippets/toggle/open_button.html' with controls_text="create-list" icon="plus" text="Create new list" focus="create-list-header" %} </div>
</div> </header>
</header>
<form name="create-list" method="post" action="{% url 'lists' %}" class="box hidden" id="create-list"> <div class="block">
<header class="columns"> {% include 'lists/create_form.html' with controls_text="create-list" %}
<h3 class="title column" tabindex="0" id="create-list-header">Create list</h3> </div>
<div class="column is-narrow">
{% include 'snippets/toggle/toggle_button.html' with controls_text="create-list" label="Close" class="delete" nonbutton=True %}
</div>
</header>
{% include 'lists/form.html' %}
</form>
<div class="block content">
{% if request.user.list_set.exists %} {% if request.user.list_set.exists %}
{% include 'lists/list_items.html' with lists=request.user.list_set.all|slice:4 %} {% include 'lists/list_items.html' with lists=request.user.list_set.all|slice:4 %}
{% endif %} {% endif %}
@ -39,9 +33,7 @@
{% if lists %} {% if lists %}
<section class="block content"> <section class="block content">
<h2 class="title">Recent Lists</h2> <h2 class="title">Recent Lists</h2>
{% if request.user.list_set.exists %}
{% include 'lists/list_items.html' with lists=lists %} {% include 'lists/list_items.html' with lists=lists %}
{% endif %}
</section> </section>
<div> <div>
{% include 'snippets/pagination.html' with page=lists path=path %} {% include 'snippets/pagination.html' with page=lists path=path %}

View file

@ -0,0 +1,26 @@
{% extends 'components/inline_form.html' %}
{% block header %}
Create New Shelf
{% endblock %}
{% block form %}
<form name="create-shelf" action="{% url 'shelf-create' %}" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<div class="field">
<label class="label" for="id_name_create">Name:</label>
<input type="text" name="name" maxlength="100" class="input" required="true" id="id_name_create">
</div>
<div class="field has-addons">
<div class="control">
{% include 'snippets/privacy_select.html' %}
</div>
<div class="control">
<button class="button is-primary" type="submit">Create shelf</button>
</div>
</div>
</form>
{% endblock %}

View file

@ -0,0 +1,31 @@
{% extends 'components/inline_form.html' %}
{% block header %}
Edit Shelf
{% endblock %}
{% block form %}
<form name="edit-shelf" action="{{ shelf.local_path }}" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
{% if shelf.editable %}
<div class="field">
<label class="label" for="id_name">Name:</label>
<input type="text" name="name" maxlength="100" class="input" required="true" value="{{ shelf.name }}" id="id_name">
</div>
{% else %}
<input type="hidden" name="name" required="true" value="{{ shelf.name }}">
{% endif %}
<div class="field has-addons">
<div class="control">
{% include 'snippets/privacy_select.html' with current=shelf.privacy %}
</div>
<div class="control">
<button class="button is-primary" type="submit">Update shelf</button>
</div>
</div>
</form>
{% endblock %}

View file

@ -29,30 +29,13 @@
{% if is_self %} {% if is_self %}
<div class="column is-narrow"> <div class="column is-narrow">
{% include 'snippets/toggle/open_button.html' with text="Create shelf" icon="plus" class="is-clickable" controls_text="create-shelf-form" %} {% include 'snippets/toggle/open_button.html' with text="Create shelf" icon="plus" controls_text="create-shelf-form" focus="create-shelf-form-header" %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="hidden box mb-5" id="create-shelf-form"> <div class="block">
<h2 class="title is-4">Create new shelf</h2> {% include 'user/create_shelf_form.html' with controls_text='create-shelf-form' %}
<form name="create-shelf" action="/create-shelf/" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<div class="field">
<label class="label" for="id_name_create">Name:</label>
<input type="text" name="name" maxlength="100" class="input" required="true" id="id_name_create">
</div>
<label class="label">
<p>Shelf privacy:</p>
{% include 'snippets/privacy_select.html' with no_label=True %}
</label>
<div class="field is-grouped">
<button class="button is-primary" type="submit">Create shelf</button>
{% include 'snippets/toggle/close_button.html' with text="Cancel" controls_text="create-shelf-form" %}
</div>
</form>
</div> </div>
<div class="block columns"> <div class="block columns">
@ -66,34 +49,13 @@
</div> </div>
{% if is_self %} {% if is_self %}
<div class="column is-narrow"> <div class="column is-narrow">
{% include 'snippets/toggle/open_button.html' with text="Edit shelf" icon="pencil" class="is-clickable" controls_text="edit-shelf-form" %} {% include 'snippets/toggle/open_button.html' with text="Edit shelf" icon="pencil" controls_text="edit-shelf-form" focus="edit-shelf-form-header" %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="hidden box mb-5" id="edit-shelf-form"> <div class="block">
<h2 class="title is-4">Edit shelf</h2> {% include 'user/edit_shelf_form.html' with controls_text="edit-shelf-form" %}
<form name="create-shelf" action="{{ shelf.local_path }}" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
{% if shelf.editable %}
<div class="field">
<label class="label" for="id_name">Name:</label>
<input type="text" name="name" maxlength="100" class="input" required="true" value="{{ shelf.name }}" id="id_name">
</div>
{% else %}
<input type="hidden" name="name" required="true" value="{{ shelf.name }}">
{% endif %}
<label class="label">
<p>Shelf privacy:</p>
{% include 'snippets/privacy_select.html' with no_label=True current=shelf.privacy %}
</label>
<div class="field is-grouped">
<button class="button is-primary" type="submit">Update shelf</button>
{% include 'snippets/toggle/close_button.html' with text="Cancel" controls_text="edit-shelf-form" %}
</div>
</form>
</div> </div>
<div class="block"> <div class="block">

View file

@ -192,9 +192,15 @@ class Openlibrary(TestCase):
self.assertEqual(edition['key'], '/books/OL9788823M') self.assertEqual(edition['key'], '/books/OL9788823M')
@responses.activate
def test_create_edition_from_data(self): def test_create_edition_from_data(self):
''' okay but can it actually create an edition with proper metadata ''' ''' okay but can it actually create an edition with proper metadata '''
work = models.Work.objects.create(title='Hello') work = models.Work.objects.create(title='Hello')
responses.add(
responses.GET,
'https://openlibrary.org/authors/OL382982A',
json={'hi': 'there'},
status=200)
result = self.connector.create_edition_from_data( result = self.connector.create_edition_from_data(
work, self.edition_data) work, self.edition_data)
self.assertEqual(result.parent_work, work) self.assertEqual(result.parent_work, work)

View file

@ -150,7 +150,7 @@ urlpatterns = [
user_path, views.Shelf.as_view(), name='shelf'), user_path, views.Shelf.as_view(), name='shelf'),
re_path(r'^%s/shelf/(?P<shelf_identifier>[\w-]+)(.json)?/?$' % \ re_path(r'^%s/shelf/(?P<shelf_identifier>[\w-]+)(.json)?/?$' % \
local_user_path, views.Shelf.as_view()), local_user_path, views.Shelf.as_view()),
re_path(r'^create-shelf/?$', views.create_shelf), re_path(r'^create-shelf/?$', views.create_shelf, name='shelf-create'),
re_path(r'^delete-shelf/(?P<shelf_id>\d+)?$', views.delete_shelf), re_path(r'^delete-shelf/(?P<shelf_id>\d+)?$', views.delete_shelf),
re_path(r'^shelve/?$', views.shelve), re_path(r'^shelve/?$', views.shelve),
re_path(r'^unshelve/?$', views.unshelve), re_path(r'^unshelve/?$', views.unshelve),

View file

@ -29,6 +29,7 @@ class Lists(View):
user = request.user if request.user.is_authenticated else None user = request.user if request.user.is_authenticated else None
lists = models.List.objects.filter( lists = models.List.objects.filter(
~Q(user=user), ~Q(user=user),
books__isnull=False,
).all() ).all()
lists = privacy_filter(request.user, lists, ['public', 'followers']) lists = privacy_filter(request.user, lists, ['public', 'followers'])