mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-12-15 04:36:34 +00:00
Merge pull request #382 from mouse-reeve/switch-edition
Adds shelf info to book page
This commit is contained in:
commit
ef92e562fd
14 changed files with 252 additions and 112 deletions
19
bookwyrm/migrations/0017_auto_20201212_0059.py
Normal file
19
bookwyrm/migrations/0017_auto_20201212_0059.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.0.7 on 2020-12-12 00:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('bookwyrm', '0016_auto_20201211_2026'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='readthrough',
|
||||||
|
name='book',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='bookwyrm.Edition'),
|
||||||
|
),
|
||||||
|
]
|
14
bookwyrm/migrations/0023_merge_20201216_0112.py
Normal file
14
bookwyrm/migrations/0023_merge_20201216_0112.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Django 3.0.7 on 2020-12-16 01:12
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('bookwyrm', '0017_auto_20201212_0059'),
|
||||||
|
('bookwyrm', '0022_auto_20201212_1744'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
14
bookwyrm/migrations/0024_merge_20201216_1721.py
Normal file
14
bookwyrm/migrations/0024_merge_20201216_1721.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Django 3.0.7 on 2020-12-16 17:21
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('bookwyrm', '0023_auto_20201214_0511'),
|
||||||
|
('bookwyrm', '0023_merge_20201216_0112'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
|
@ -240,7 +240,7 @@ class Boost(Status):
|
||||||
class ReadThrough(BookWyrmModel):
|
class ReadThrough(BookWyrmModel):
|
||||||
''' Store progress through a book in the database. '''
|
''' Store progress through a book in the database. '''
|
||||||
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
||||||
book = models.ForeignKey('Book', on_delete=models.PROTECT)
|
book = models.ForeignKey('Edition', on_delete=models.PROTECT)
|
||||||
pages_read = models.IntegerField(
|
pages_read = models.IntegerField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True)
|
blank=True)
|
||||||
|
|
|
@ -91,88 +91,27 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% for readthrough in readthroughs %}
|
{# user's relationship to the book #}
|
||||||
<div class="content block">
|
|
||||||
<input class="toggle-control" type="radio" name="show-edit-readthrough" id="show-readthrough-{{ readthrough.id }}" checked>
|
|
||||||
<div class="toggle-content hidden">
|
|
||||||
<dl>
|
|
||||||
{% if readthrough.start_date %}
|
|
||||||
<dt>Started reading:</dt>
|
|
||||||
<dd>{{ readthrough.start_date | naturalday }}</dd>
|
|
||||||
{% endif %}
|
|
||||||
{% if readthrough.finish_date %}
|
|
||||||
<dt>Finished reading:</dt>
|
|
||||||
<dd>{{ readthrough.finish_date | naturalday }}</dd>
|
|
||||||
{% endif %}
|
|
||||||
</dl>
|
|
||||||
<div class="field is-grouped">
|
|
||||||
<label class="button is-small" for="edit-readthrough-{{ readthrough.id }}" role="button" tabindex="0">
|
|
||||||
<span class="icon icon-pencil">
|
|
||||||
<span class="is-sr-only">Edit read-through dates</span>
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<label class="button is-small" for="delete-readthrough-{{ readthrough.id }}" role="button" tabindex="0">
|
|
||||||
<span class="icon icon-x">
|
|
||||||
<span class="is-sr-only">Delete this read-through</span>
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="block">
|
|
||||||
<input class="toggle-control" type="radio" name="show-edit-readthrough" id="edit-readthrough-{{ readthrough.id }}">
|
|
||||||
<div class="toggle-content hidden">
|
|
||||||
<div class="box">
|
|
||||||
<form name="edit-readthrough" action="/edit-readthrough" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="id" value="{{ readthrough.id }}">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">
|
|
||||||
Started reading
|
|
||||||
<input type="date" name="start_date" class="input" id="id_start_date-{{ readthrough.id }}" value="{{ readthrough.start_date | date:"Y-m-d" }}">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">
|
|
||||||
Finished reading
|
|
||||||
<input type="date" name="finish_date" class="input" id="id_finish_date-{{ readthrough.id }}" value="{{ readthrough.finish_date | date:"Y-m-d" }}">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="field is-grouped">
|
|
||||||
<button class="button is-primary" type="submit">Save</button>
|
|
||||||
<label class="button" for="show-readthrough-{{ readthrough.id }}" role="button" tabindex="0">Cancel</label>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input class="toggle-control" type="checkbox" name="delete-readthrough-{{ readthrough.id }}" id="delete-readthrough-{{ readthrough.id }}">
|
{% for shelf in user_shelves %}
|
||||||
<div class="modal toggle-content hidden">
|
<p>
|
||||||
<div class="modal-background"></div>
|
This edition is on your <a href="/user/{{ user.localname }}/shelves/{{ shelf.shelf.identifier }}">{{ shelf.shelf.name }}</a> shelf.
|
||||||
<div class="modal-card">
|
{% include 'snippets/shelf_selector.html' with current=shelf.shelf %}
|
||||||
<header class="modal-card-head">
|
</p>
|
||||||
<p class="modal-card-title">Delete this read-though?</p>
|
|
||||||
<label class="delete" for="delete-readthrough-{{ readthrough.id }}" aria-label="close"></label>
|
|
||||||
</header>
|
|
||||||
<footer class="modal-card-foot">
|
|
||||||
<form name="delete-readthrough-{{ readthrough.id }}" action="/delete-readthrough" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="id" value="{{ readthrough.id }}">
|
|
||||||
<button class="button is-danger is-light" type="submit">
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
<label for="delete-readthrough-{{ readthrough.id }}" class="button" role="button" tabindex="0">Cancel</button>
|
|
||||||
</form>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
<label class="modal-close is-large" for="delete-readthrough-{{ readthrough.id }}" aria-label="close"></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for shelf in other_edition_shelves %}
|
||||||
|
<p>
|
||||||
|
A <a href="/book/{{ shelf.book.id }}">different edition</a> of this book is on your <a href="/user/{{ user.localname }}/shelves/{{ shelf.shelf.identifier }}">{{ shelf.shelf.name }}</a> shelf.
|
||||||
|
{% include 'snippets/switch_edition_button.html' with edition=book %}
|
||||||
|
</p>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for readthrough in readthroughs %}
|
||||||
|
{% include 'snippets/readthrough.html' with readthrough=readthrough %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<div class="box">
|
<div class="box">
|
||||||
{% include 'snippets/create_status.html' with book=book hide_cover=True %}
|
{% include 'snippets/create_status.html' with book=book hide_cover=True %}
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
<div class="columns">
|
<div class="columns is-multiline">
|
||||||
{% for book in books %}
|
{% for book in books %}
|
||||||
{% if forloop.counter0|divisibleby:"4" %}
|
|
||||||
</div>
|
|
||||||
<div class="columns">
|
|
||||||
{% endif %}
|
|
||||||
<div class="column is-narrow">
|
<div class="column is-narrow">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<a href="/book/{{ book.id }}">
|
<a href="/book/{{ book.id }}">
|
||||||
{% include 'snippets/book_cover.html' with book=book %}
|
{% include 'snippets/book_cover.html' with book=book %}
|
||||||
</a>
|
</a>
|
||||||
{% include 'snippets/rate_action.html' with user=request.user book=book %}
|
{% include 'snippets/shelve_button.html' with book=book switch_mode=True %}
|
||||||
{% include 'snippets/shelve_button.html' with book=book %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
80
bookwyrm/templates/snippets/readthrough.html
Normal file
80
bookwyrm/templates/snippets/readthrough.html
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
{% load humanize %}
|
||||||
|
<div class="content block">
|
||||||
|
<input class="toggle-control" type="radio" name="show-edit-readthrough" id="show-readthrough-{{ readthrough.id }}" checked>
|
||||||
|
<div class="toggle-content hidden">
|
||||||
|
<dl>
|
||||||
|
{% if readthrough.start_date %}
|
||||||
|
<dt>Started reading:</dt>
|
||||||
|
<dd>{{ readthrough.start_date | naturalday }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
{% if readthrough.finish_date %}
|
||||||
|
<dt>Finished reading:</dt>
|
||||||
|
<dd>{{ readthrough.finish_date | naturalday }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<label class="button is-small" for="edit-readthrough-{{ readthrough.id }}" role="button" tabindex="0">
|
||||||
|
<span class="icon icon-pencil">
|
||||||
|
<span class="is-sr-only">Edit read-through dates</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label class="button is-small" for="delete-readthrough-{{ readthrough.id }}" role="button" tabindex="0">
|
||||||
|
<span class="icon icon-x">
|
||||||
|
<span class="is-sr-only">Delete this read-through</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="block">
|
||||||
|
<input class="toggle-control" type="radio" name="show-edit-readthrough" id="edit-readthrough-{{ readthrough.id }}">
|
||||||
|
<div class="toggle-content hidden">
|
||||||
|
<div class="box">
|
||||||
|
<form name="edit-readthrough" action="/edit-readthrough" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="id" value="{{ readthrough.id }}">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">
|
||||||
|
Started reading
|
||||||
|
<input type="date" name="start_date" class="input" id="id_start_date-{{ readthrough.id }}" value="{{ readthrough.start_date | date:"Y-m-d" }}">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">
|
||||||
|
Finished reading
|
||||||
|
<input type="date" name="finish_date" class="input" id="id_finish_date-{{ readthrough.id }}" value="{{ readthrough.finish_date | date:"Y-m-d" }}">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<button class="button is-primary" type="submit">Save</button>
|
||||||
|
<label class="button" for="show-readthrough-{{ readthrough.id }}" role="button" tabindex="0">Cancel</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input class="toggle-control" type="checkbox" name="delete-readthrough-{{ readthrough.id }}" id="delete-readthrough-{{ readthrough.id }}">
|
||||||
|
<div class="modal toggle-content hidden">
|
||||||
|
<div class="modal-background"></div>
|
||||||
|
<div class="modal-card">
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<p class="modal-card-title">Delete this read-though?</p>
|
||||||
|
<label class="delete" for="delete-readthrough-{{ readthrough.id }}" aria-label="close"></label>
|
||||||
|
</header>
|
||||||
|
<footer class="modal-card-foot">
|
||||||
|
<form name="delete-readthrough-{{ readthrough.id }}" action="/delete-readthrough" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="id" value="{{ readthrough.id }}">
|
||||||
|
<button class="button is-danger is-light" type="submit">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
<label for="delete-readthrough-{{ readthrough.id }}" class="button" role="button" tabindex="0">Cancel</button>
|
||||||
|
</form>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
<label class="modal-close is-large" for="delete-readthrough-{{ readthrough.id }}" aria-label="close"></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -4,24 +4,28 @@
|
||||||
{% with book.id|uuid as uuid %}
|
{% with book.id|uuid as uuid %}
|
||||||
{% active_shelf book as active_shelf %}
|
{% active_shelf book as active_shelf %}
|
||||||
<div class="field is-grouped">
|
<div class="field is-grouped">
|
||||||
{% if active_shelf.identifier == 'read' %}
|
{% if switch_mode and active_shelf.book != book %}
|
||||||
|
{% include 'snippets/switch_edition_button.html' with edition=book size='is-small' %}
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{% if active_shelf.shelf.identifier == 'read' %}
|
||||||
<button class="button is-small" disabled>
|
<button class="button is-small" disabled>
|
||||||
<span>Read</span> <span class="icon icon-check"></span>
|
<span>Read</span> <span class="icon icon-check"></span>
|
||||||
</button>
|
</button>
|
||||||
{% elif active_shelf.identifier == 'reading' %}
|
{% elif active_shelf.shelf.identifier == 'reading' %}
|
||||||
<label class="button is-small" for="finish-reading-{{ uuid }}" role="button" tabindex="0">
|
<label class="button is-small" for="finish-reading-{{ uuid }}" role="button" tabindex="0">
|
||||||
I'm done!
|
I'm done!
|
||||||
</label>
|
</label>
|
||||||
{% include 'snippets/finish_reading_modal.html' %}
|
{% include 'snippets/finish_reading_modal.html' with book=active_shelf.book %}
|
||||||
{% elif active_shelf.identifier == 'to-read' %}
|
{% elif active_shelf.shelf.identifier == 'to-read' %}
|
||||||
<label class="button is-small" for="start-reading-{{ uuid }}" role="button" tabindex="0">
|
<label class="button is-small" for="start-reading-{{ uuid }}" role="button" tabindex="0">
|
||||||
Start reading
|
Start reading
|
||||||
</label>
|
</label>
|
||||||
{% include 'snippets/start_reading_modal.html' %}
|
{% include 'snippets/start_reading_modal.html' with book=active_shelf.book %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<form name="shelve" action="/shelve/" method="post">
|
<form name="shelve" action="/shelve/" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="book" value="{{ book.id }}">
|
<input type="hidden" name="book" value="{{ active_shelf.book.id }}">
|
||||||
<input type="hidden" name="shelf" value="to-read">
|
<input type="hidden" name="shelf" value="to-read">
|
||||||
<button class="button is-small" type="submit">Want to read</button>
|
<button class="button is-small" type="submit">Want to read</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -40,17 +44,17 @@
|
||||||
<ul class="dropdown-content">
|
<ul class="dropdown-content">
|
||||||
{% for shelf in request.user.shelf_set.all %}
|
{% for shelf in request.user.shelf_set.all %}
|
||||||
<li role="menuitem">
|
<li role="menuitem">
|
||||||
{% if shelf.identifier == 'to-read' %}
|
{% if active_shelf.shelf.identifier == 'to-read' and shelf.identifier == 'reading' %}
|
||||||
<div class="dropdown-item pt-0 pb-0">
|
<div class="dropdown-item pt-0 pb-0">
|
||||||
<label class="button is-small" for="start-reading-{{ uuid }}" role="button" tabindex="0">
|
<label class="button is-small" for="start-reading-{{ uuid }}" role="button" tabindex="0">
|
||||||
Start reading
|
Start reading
|
||||||
</label>
|
</label>
|
||||||
{% include 'snippets/start_reading_modal.html' %}
|
{% include 'snippets/start_reading_modal.html' with book=active_shelf.book %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<form class="dropdown-item pt-0 pb-0" name="shelve" action="/shelve/" method="post">
|
<form class="dropdown-item pt-0 pb-0" name="shelve" action="/shelve/" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="book" value="{{ book.id }}">
|
<input type="hidden" name="book" value="{{ active_shelf.book.id }}">
|
||||||
<button class="button is-small" name="shelf" type="submit" value="{{ shelf.identifier }}" {% if shelf in book.shelf_set.all %} disabled {% endif %}>
|
<button class="button is-small" name="shelf" type="submit" value="{{ shelf.identifier }}" {% if shelf in book.shelf_set.all %} disabled {% endif %}>
|
||||||
<span>{{ shelf.name }}</span>
|
<span>{{ shelf.name }}</span>
|
||||||
{% if shelf in book.shelf_set.all %}<span class="icon icon-check"></span>{% endif %}
|
{% if shelf in book.shelf_set.all %}<span class="icon icon-check"></span>{% endif %}
|
||||||
|
@ -62,6 +66,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
5
bookwyrm/templates/snippets/switch_edition_button.html
Normal file
5
bookwyrm/templates/snippets/switch_edition_button.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<form name="switch-edition" action="/switch-edition" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="edition" value="{{ edition.id }}">
|
||||||
|
<button class="button {{ size }}">Switch to this edition</button>
|
||||||
|
</form>
|
|
@ -132,9 +132,10 @@ def time_since(date):
|
||||||
delta = now - date
|
delta = now - date
|
||||||
|
|
||||||
if date < (now - relativedelta(weeks=1)):
|
if date < (now - relativedelta(weeks=1)):
|
||||||
|
formatter = '%b %-d'
|
||||||
if date.year != now.year:
|
if date.year != now.year:
|
||||||
return date.strftime('%b %-d %Y')
|
formatter += ' %Y'
|
||||||
return date.strftime('%b %-d')
|
return date.strftime(formatter)
|
||||||
delta = relativedelta(now, date)
|
delta = relativedelta(now, date)
|
||||||
if delta.days:
|
if delta.days:
|
||||||
return '%dd' % delta.days
|
return '%dd' % delta.days
|
||||||
|
@ -150,9 +151,9 @@ def active_shelf(context, book):
|
||||||
''' check what shelf a user has a book on, if any '''
|
''' check what shelf a user has a book on, if any '''
|
||||||
shelf = models.ShelfBook.objects.filter(
|
shelf = models.ShelfBook.objects.filter(
|
||||||
shelf__user=context['request'].user,
|
shelf__user=context['request'].user,
|
||||||
book=book
|
book__in=book.parent_work.editions.all()
|
||||||
).first()
|
).first()
|
||||||
return shelf.shelf if shelf else None
|
return shelf if shelf else {'book': book}
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=False)
|
@register.simple_tag(takes_context=False)
|
||||||
|
|
|
@ -237,3 +237,28 @@ class ViewActions(TestCase):
|
||||||
resp = actions.password_reset(request)
|
resp = actions.password_reset(request)
|
||||||
self.assertEqual(resp.template_name, 'password_reset.html')
|
self.assertEqual(resp.template_name, 'password_reset.html')
|
||||||
self.assertTrue(models.PasswordReset.objects.exists())
|
self.assertTrue(models.PasswordReset.objects.exists())
|
||||||
|
|
||||||
|
def test_switch_edition(self):
|
||||||
|
''' updates user's relationships to a book '''
|
||||||
|
work = models.Work.objects.create(title='test work')
|
||||||
|
edition1 = models.Edition.objects.create(
|
||||||
|
title='first ed', parent_work=work)
|
||||||
|
edition2 = models.Edition.objects.create(
|
||||||
|
title='second ed', parent_work=work)
|
||||||
|
shelf = models.Shelf.objects.create(
|
||||||
|
name='Test Shelf', user=self.local_user)
|
||||||
|
shelf.books.add(edition1)
|
||||||
|
models.ReadThrough.objects.create(
|
||||||
|
user=self.local_user, book=edition1)
|
||||||
|
|
||||||
|
self.assertEqual(models.ShelfBook.objects.get().book, edition1)
|
||||||
|
self.assertEqual(models.ReadThrough.objects.get().book, edition1)
|
||||||
|
request = self.factory.post('', {
|
||||||
|
'edition': edition2.id
|
||||||
|
})
|
||||||
|
request.user = self.local_user
|
||||||
|
with patch('bookwyrm.broadcast.broadcast_task.delay'):
|
||||||
|
actions.switch_edition(request)
|
||||||
|
|
||||||
|
self.assertEqual(models.ShelfBook.objects.get().book, edition2)
|
||||||
|
self.assertEqual(models.ReadThrough.objects.get().book, edition2)
|
||||||
|
|
|
@ -98,15 +98,16 @@ urlpatterns = [
|
||||||
|
|
||||||
re_path(r'^edit-profile/?$', actions.edit_profile),
|
re_path(r'^edit-profile/?$', actions.edit_profile),
|
||||||
|
|
||||||
re_path(r'^import-data/?', actions.import_data),
|
re_path(r'^import-data/?$', actions.import_data),
|
||||||
re_path(r'^retry-import/?', actions.retry_import),
|
re_path(r'^retry-import/?$', actions.retry_import),
|
||||||
re_path(r'^resolve-book/?', actions.resolve_book),
|
re_path(r'^resolve-book/?$', actions.resolve_book),
|
||||||
re_path(r'^edit-book/(?P<book_id>\d+)/?', actions.edit_book),
|
re_path(r'^edit-book/(?P<book_id>\d+)/?$', actions.edit_book),
|
||||||
re_path(r'^upload-cover/(?P<book_id>\d+)/?', actions.upload_cover),
|
re_path(r'^upload-cover/(?P<book_id>\d+)/?$', actions.upload_cover),
|
||||||
re_path(r'^add-description/(?P<book_id>\d+)/?', actions.add_description),
|
re_path(r'^add-description/(?P<book_id>\d+)/?$', actions.add_description),
|
||||||
|
|
||||||
re_path(r'^edit-readthrough/?', actions.edit_readthrough),
|
re_path(r'^switch-edition/?$', actions.switch_edition),
|
||||||
re_path(r'^delete-readthrough/?', actions.delete_readthrough),
|
re_path(r'^edit-readthrough/?$', actions.edit_readthrough),
|
||||||
|
re_path(r'^delete-readthrough/?$', actions.delete_readthrough),
|
||||||
|
|
||||||
re_path(r'^rate/?$', actions.rate),
|
re_path(r'^rate/?$', actions.rate),
|
||||||
re_path(r'^review/?$', actions.review),
|
re_path(r'^review/?$', actions.review),
|
||||||
|
|
|
@ -10,6 +10,7 @@ from django.contrib.auth import authenticate, login, logout
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
|
from django.db import transaction
|
||||||
from django.http import HttpResponseBadRequest, HttpResponseNotFound
|
from django.http import HttpResponseBadRequest, HttpResponseNotFound
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
@ -17,6 +18,7 @@ from django.utils import timezone
|
||||||
from django.views.decorators.http import require_GET, require_POST
|
from django.views.decorators.http import require_GET, require_POST
|
||||||
|
|
||||||
from bookwyrm import books_manager
|
from bookwyrm import books_manager
|
||||||
|
from bookwyrm.broadcast import broadcast
|
||||||
from bookwyrm import forms, models, outgoing
|
from bookwyrm import forms, models, outgoing
|
||||||
from bookwyrm import goodreads_import
|
from bookwyrm import goodreads_import
|
||||||
from bookwyrm.emailing import password_reset_email
|
from bookwyrm.emailing import password_reset_email
|
||||||
|
@ -246,6 +248,36 @@ def edit_book(request, book_id):
|
||||||
return redirect('/book/%s' % book.id)
|
return redirect('/book/%s' % book.id)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@require_POST
|
||||||
|
@transaction.atomic
|
||||||
|
def switch_edition(request):
|
||||||
|
''' switch your copy of a book to a different edition '''
|
||||||
|
edition_id = request.POST.get('edition')
|
||||||
|
new_edition = get_object_or_404(models.Edition, id=edition_id)
|
||||||
|
shelfbooks = models.ShelfBook.objects.filter(
|
||||||
|
book__parent_work=new_edition.parent_work,
|
||||||
|
shelf__user=request.user
|
||||||
|
)
|
||||||
|
for shelfbook in shelfbooks.all():
|
||||||
|
broadcast(request.user, shelfbook.to_remove_activity(request.user))
|
||||||
|
|
||||||
|
shelfbook.book = new_edition
|
||||||
|
shelfbook.save()
|
||||||
|
|
||||||
|
broadcast(request.user, shelfbook.to_add_activity(request.user))
|
||||||
|
|
||||||
|
readthroughs = models.ReadThrough.objects.filter(
|
||||||
|
book__parent_work=new_edition.parent_work,
|
||||||
|
user=request.user
|
||||||
|
)
|
||||||
|
for readthrough in readthroughs.all():
|
||||||
|
readthrough.book = new_edition
|
||||||
|
readthrough.save()
|
||||||
|
|
||||||
|
return redirect('/book/%d' % new_edition.id)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@require_POST
|
@require_POST
|
||||||
def upload_cover(request, book_id):
|
def upload_cover(request, book_id):
|
||||||
|
|
|
@ -594,8 +594,7 @@ def book_page(request, book_id):
|
||||||
prev_page = '/book/%s/?page=%d' % \
|
prev_page = '/book/%s/?page=%d' % \
|
||||||
(book_id, reviews_page.previous_page_number())
|
(book_id, reviews_page.previous_page_number())
|
||||||
|
|
||||||
user_tags = []
|
user_tags = readthroughs = user_shelves = other_edition_shelves = []
|
||||||
readthroughs = []
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
user_tags = models.UserTag.objects.filter(
|
user_tags = models.UserTag.objects.filter(
|
||||||
book=book, user=request.user
|
book=book, user=request.user
|
||||||
|
@ -606,6 +605,16 @@ def book_page(request, book_id):
|
||||||
book=book,
|
book=book,
|
||||||
).order_by('start_date')
|
).order_by('start_date')
|
||||||
|
|
||||||
|
user_shelves = models.ShelfBook.objects.filter(
|
||||||
|
added_by=request.user, book=book
|
||||||
|
)
|
||||||
|
|
||||||
|
other_edition_shelves = models.ShelfBook.objects.filter(
|
||||||
|
~Q(book=book),
|
||||||
|
added_by=request.user,
|
||||||
|
book__parent_work=book.parent_work,
|
||||||
|
)
|
||||||
|
|
||||||
rating = reviews.aggregate(Avg('rating'))
|
rating = reviews.aggregate(Avg('rating'))
|
||||||
tags = models.UserTag.objects.filter(
|
tags = models.UserTag.objects.filter(
|
||||||
book=book,
|
book=book,
|
||||||
|
@ -619,6 +628,8 @@ def book_page(request, book_id):
|
||||||
'rating': rating['rating__avg'],
|
'rating': rating['rating__avg'],
|
||||||
'tags': tags,
|
'tags': tags,
|
||||||
'user_tags': user_tags,
|
'user_tags': user_tags,
|
||||||
|
'user_shelves': user_shelves,
|
||||||
|
'other_edition_shelves': other_edition_shelves,
|
||||||
'readthroughs': readthroughs,
|
'readthroughs': readthroughs,
|
||||||
'path': '/book/%s' % book_id,
|
'path': '/book/%s' % book_id,
|
||||||
'info_fields': [
|
'info_fields': [
|
||||||
|
@ -662,10 +673,9 @@ def editions_page(request, book_id):
|
||||||
encoder=ActivityEncoder
|
encoder=ActivityEncoder
|
||||||
)
|
)
|
||||||
|
|
||||||
editions = models.Edition.objects.filter(parent_work=work).all()
|
|
||||||
data = {
|
data = {
|
||||||
'title': 'Editions of %s' % work.title,
|
'title': 'Editions of %s' % work.title,
|
||||||
'editions': editions,
|
'editions': work.editions.all(),
|
||||||
'work': work,
|
'work': work,
|
||||||
}
|
}
|
||||||
return TemplateResponse(request, 'editions.html', data)
|
return TemplateResponse(request, 'editions.html', data)
|
||||||
|
|
Loading…
Reference in a new issue