Add to and edit lists

This commit is contained in:
Mouse Reeve 2021-01-31 10:34:25 -08:00
parent 4883231347
commit acd922970a
8 changed files with 149 additions and 60 deletions

View file

@ -0,0 +1,45 @@
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="id_name">Name:</label>
{{ list_form.name }}
</div>
<div class="field">
<label class="label" for="id_description">Description:</label>
{{ list_form.description }}
</div>
</div>
<div class="column">
<fieldset class="field">
<legend class="label">List curation:</legend>
<label class="field">
<input type="radio" name="curation" value="closed"{% if not list or list.curation == 'closed' %} checked{% endif %}> Closed
<p class="help mb-2">Only you can add and remove books to this list</p>
</label>
<label class="field">
<input type="radio" name="curation" value="curated"{% if list.curation == 'curated' %} checked{% endif %}> Curated
<p class="help mb-2">Anyone can suggest books, subject to your approval</p>
</label>
<label class="field">
<input type="radio" name="curation" value="open"{% if list.curation == 'open' %} checked{% endif %}> Open
<p class="help mb-2">Anyone can add books to this list, but only you can remove them</p>
</label>
</fieldset>
</div>
</div>
<div class="field has-addons">
<div class="control">
{% include 'snippets/privacy_select.html' with current=list.privacy %}
</div>
<div class="control">
<button type="submit" class="button is-primary">Save</button>
{% include 'snippets/toggle/close_button.html' with controls_text='create-list' text="Cancel" %}
</div>
</div>

View file

@ -1,28 +1,66 @@
{% extends 'layout.html' %}
{% load bookwyrm_tags %}
{% block content %}
<header class="columns content">
<div class="column">
<h1 class="title">{{ list.name }} <span class="subtitle">{% include 'snippets/privacy-icons.html' with item=list %}</span></h1>
<p class="subtitle help">Created by {% include 'snippets/username.html' with user=list.user %}</p>
{% include 'snippets/trimmed_text.html' with full=list.description %}
</div>
{% if request.user == list.user %}
<div class="column is-narrow">
{% include 'snippets/toggle/open_button.html' with text="Edit list" icon="pencil" controls_text="edit-list" %}
{% include 'snippets/toggle/open_button.html' with text="Edit list" icon="pencil" controls_text="create-list" %}
</div>
{% endif %}
</header>
<form name="create-list" method="post" action="{% url 'list' list.id %}" class="box hidden" id="create-list">
<h3 class="title">Edit list</h3>
{% include 'lists/form.html' %}
</form>
<div class="columns content">
<section class="column">
<h2>Books</h2>
<section class="column is-three-quarters">
{% if not list.books.exists %}
<p>This list is currently empty</p>
{% else %}
{% for book in list.books.all %}
{{ book }}
<ol>
{% for item in list.listitem_set.all %}
<li class="block">
<div class="card">
<header class="card-header">
<a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=item.book size="medium" %}</a>
<div class="card-header-title is-flex-direction-column is-align-items-self-start">
<span>{% include 'snippets/book_titleby.html' with book=item.book %}</span>
{% include 'snippets/stars.html' with rating=item.book|rating:request.user %}
{% include 'snippets/shelve_button.html' with book=item.book %}
</div>
</header>
{% if item.note %}
<div class="card-content">
{% include 'snippets/trimmed_text.html' with full=item.note %}
</div>
{% endif %}
<div class="card-footer has-background-white-bis">
<div class="card-footer-item">
<p>Added by {% include 'snippets/username.html' with user=item.added_by %}</p>
</div>
<form name="add-book" method="post" action="{% url 'list-add-book' list.id %}" class="card-footer-item">
{% csrf_token %}
<input type="hidden" name="book" value="{{ book.id }}">
<button type="submit" class="button is-small is-danger">Remove</button>
</form>
</div>
</div>
</li>
{% endfor %}
</ol>
{% endif %}
</section>
{% if not list.curation == 'closed' or request.user == list.user %}
<section class="column is-one-quarter">
<h2>Add Books</h2>
{% for book in suggested_books %}
@ -34,11 +72,13 @@
<p>{% include 'snippets/book_titleby.html' with book=book %}</p>
<form name="add-book" method="post" action="{% url 'list-add-book' list.id %}">
{% csrf_token %}
<input type="hidden" name="book" value="{{ book.id }}">
<button type="submit" class="button is-small is-link">Add</button>
</form>
</div>
</div>
{% endfor %}
</section>
{% endif %}
</div>
{% endblock %}

View file

@ -18,50 +18,7 @@
<form name="create-list" method="post" action="{% url 'lists' %}" class="box hidden" id="create-list">
<h3 class="title">Create list</h3>
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="id_name">Name:</label>
{{ list_form.name }}
</div>
<div class="field">
<label class="label" for="id_description">Description:</label>
{{ list_form.description }}
</div>
</div>
<div class="column">
<fieldset class="field">
<legend class="label">List curation:</legend>
<label class="field">
<input type="radio" name="curation" value="closed" checked> Closed
<p class="help mb-2">Only you can add and remove books to this list</p>
</label>
<label class="field">
<input type="radio" name="curation" value="curated"> Curated
<p class="help mb-2">Anyone can suggest books, subject to your approval</p>
</label>
<label class="field">
<input type="radio" name="curation" value="open"> Open
<p class="help mb-2">Anyone can add books to this list, but only you can remove them</p>
</label>
</fieldset>
</div>
</div>
<div class="field has-addons">
<div class="control">
{% include 'snippets/privacy_select.html' %}
</div>
<div class="control">
<button type="submit" class="button is-primary">Save</button>
{% include 'snippets/toggle/close_button.html' with controls_text='create-list' text="Cancel" %}
</div>
</div>
{% include 'lists/form.html' %}
</form>
{% if request.user.list_set.exists %}

View file

@ -13,7 +13,7 @@
<label class="is-sr-only" for="rating-no-rating-{{ book.id }}">No rating</label>
<input class="is-sr-only" type="radio" name="rating" value="" id="rating-no-rating-{{ book.id }}" checked>
{% for i in '12345'|make_list %}
<input class="is-sr-only" id="rating-book{{book.id}}-star-{{ forloop.counter }}" type="radio" name="rating" value="{{ forloop.counter }}" {% if book|rating:user == forloop.counter %}checked{% endif %}>
<input class="is-sr-only" id="rating-book{{book.id}}-star-{{ forloop.counter }}" type="radio" name="rating" value="{{ forloop.counter }}" {% if book|user_rating:user == forloop.counter %}checked{% endif %}>
<label class="icon icon-star-empty" for="rating-book{{book.id}}-star-{{ forloop.counter }}">
<span class="is-sr-only">{{ forloop.counter }} star{{ forloop.counter | pluralize }}</span>
</label>

View file

@ -1,8 +1,7 @@
<div class="stars">
<p class="stars">
<span class="is-sr-only">{% if rating %}{{ rating|floatformat }} star{{ rating|floatformat | pluralize }}{% else %}No rating{% endif %}</span>
{% for i in '12345'|make_list %}
<span class="icon icon-star-{% if rating >= forloop.counter %}full{% elif rating|floatformat:0 >= forloop.counter|floatformat:0 %}half{% else %}empty{% endif %}">
<span class="icon icon-star-{% if rating >= forloop.counter %}full{% elif rating|floatformat:0 >= forloop.counter|floatformat:0 %}half{% else %}empty{% endif %}" aria-hidden="true">
</span>
{% endfor %}
</div>
</p>

View file

@ -4,9 +4,10 @@ from datetime import datetime
from dateutil.relativedelta import relativedelta
from django import template
from django.db.models import Avg
from django.utils import timezone
from bookwyrm import models
from bookwyrm import models, views
from bookwyrm.views.status import to_markdown
@ -20,6 +21,17 @@ def dict_key(d, k):
@register.filter(name='rating')
def get_rating(book, user):
''' get the overall rating of a book '''
queryset = views.helpers.get_activity_feed(
user,
['public', 'followers', 'unlisted', 'direct'],
queryset=models.Review.objects.filter(book=book),
)
return queryset.aggregate(Avg('rating'))['rating__avg']
@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,

View file

@ -91,7 +91,7 @@ urlpatterns = [
re_path(r'^list/(?P<list_id>\d+)(.json)?/?$',
views.List.as_view(), name='list'),
re_path(r'^list/(?P<list_id>\d+)/add/?$',
views.List.as_view(), name='list-add-book'),
views.list.add_book, name='list-add-book'),
# preferences
re_path(r'^preferences/profile/?$', views.EditUser.as_view()),

View file

@ -1,11 +1,12 @@
''' book list views'''
from django.contrib.auth.decorators import login_required
from django.db.models import Q
from django.http import HttpResponseNotFound
from django.http import HttpResponseNotFound, HttpResponseBadRequest
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.http import require_POST
from bookwyrm import forms, models
from bookwyrm.activitypub import ActivitypubResponse
@ -35,7 +36,6 @@ class Lists(View):
''' create a book_list '''
form = forms.ListForm(request.POST)
if not form.is_valid():
print(form.errors)
return redirect('lists')
book_list = form.save()
return redirect(book_list.local_path)
@ -52,14 +52,15 @@ class List(View):
if is_api_request(request):
return ActivitypubResponse(book_list.to_activity())
suggestions = request.user.shelfbook_set.all().filter(
~Q(book__in=book_list.books)
suggestions = request.user.shelfbook_set.filter(
~Q(book__in=book_list.books.all())
)
data = {
'title': '%s | Lists' % book_list.name,
'list': book_list,
'suggested_books': [s.book for s in suggestions[:5]],
'list_form': forms.ListForm(instance=book_list),
}
return TemplateResponse(request, 'lists/list.html', data)
@ -69,4 +70,39 @@ class List(View):
def post(self, request, list_id):
''' edit a book_list '''
book_list = get_object_or_404(models.List, id=list_id)
form = forms.ListForm(request.POST, instance=book_list)
if not form.is_valid():
return redirect('list', book_list.id)
book_list = form.save()
return redirect(book_list.local_path)
@require_POST
def add_book(request, list_id):
''' put a book on a list '''
book_list = get_object_or_404(models.List, id=list_id)
if not object_visible_to_user(request.user, book_list):
return HttpResponseNotFound()
book = get_object_or_404(models.Edition, id=request.POST.get('book'))
# do you have permission to add to the list?
if request.user == book_list.user or book_list.curation == 'open':
# go ahead and add it
models.ListItem.objects.create(
book=book,
book_list=book_list,
added_by=request.user,
)
elif book_list.curation == 'curated':
# make a pending entry
models.ListItem.objects.create(
approved=False,
book=book,
book_list=book_list,
added_by=request.user,
)
else:
# you can't add to this list, what were you THINKING
return HttpResponseBadRequest()
return redirect('list', list_id)