Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep track of progress through books over time #354

Merged
merged 43 commits into from Jan 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
3beebe4
Add initial draft of progress update
cincodenada Nov 17, 2020
7ffc311
Add display and form for existing pages_read
cincodenada Nov 17, 2020
13229ea
Add progress updates as their own table
cincodenada Nov 17, 2020
00b8608
Make ProgressUpdate attached to a readthrough
cincodenada Nov 17, 2020
f524f0c
Add basic view logic for testing
cincodenada Nov 17, 2020
c9b2b4e
Add migration for ProgressUpdate
cincodenada Nov 17, 2020
ff7d87b
Make progress updates toggle-able
cincodenada Nov 19, 2020
a579ea5
Add initial inline progress update
cincodenada Nov 20, 2020
f57d9ee
Rework to use bulma better
cincodenada Nov 21, 2020
e7c0368
PR feedback
cincodenada Nov 26, 2020
090cf2a
Make inline progress form actually work
cincodenada Nov 26, 2020
64fb88c
ProgressUpdate doesn't need its own date field
cincodenada Nov 26, 2020
692aa08
Remove unneeded class, wrap line
cincodenada Nov 26, 2020
97e49c4
Undo stray css edit
cincodenada Nov 26, 2020
85026b8
Merge branch 'main' into progress_update
cincodenada Nov 27, 2020
3b0b8f1
Merge migration branches
cincodenada Nov 28, 2020
5f2ac6d
Rename fr_* to bw_*
cincodenada Nov 28, 2020
3cb2827
Merge branch 'main' into progress_update
cincodenada Nov 28, 2020
f86140c
Move -x down to eliminate pointless noise
cincodenada Nov 28, 2020
6455cc7
Add initial tests and some fixes
cincodenada Nov 28, 2020
9ed7d23
Test updating a progress
cincodenada Nov 28, 2020
500f052
Add option for progress percentage
cincodenada Nov 28, 2020
a951f20
Add a couple forgotten files
cincodenada Nov 28, 2020
7fadbee
Merge branch 'main' into progress_update
cincodenada Nov 28, 2020
4814788
Merge branch 'main' into progress_update
cincodenada Jan 14, 2021
1e13997
Create an actual user, add missing file
cincodenada Jan 14, 2021
da8d8cd
Add deletion of progress updates
cincodenada Jan 17, 2021
2d15713
Fix inline form
cincodenada Jan 17, 2021
a4796cf
Make the switching work, wows
cincodenada Jan 17, 2021
6e05dfd
Revert "Make the switching work, wows"
cincodenada Jan 17, 2021
ef05ac1
Small fixes to old form
cincodenada Jan 17, 2021
a4519d5
Merge branch 'main' into progress_update
cincodenada Jan 17, 2021
49893f4
Merge fixes
cincodenada Jan 17, 2021
0af4863
Update merge migration
cincodenada Jan 17, 2021
1ea8ea0
Temp commit to make test run verbose, to see what's happening
cincodenada Jan 18, 2021
29140be
Merge branch 'main' into progress_update
cincodenada Jan 19, 2021
79e284e
Just scootch the migration merge up
cincodenada Jan 19, 2021
60b4282
Mock the AP publishing to stop hanging tests
cincodenada Jan 19, 2021
32346cf
Cascade-delete progress updates
cincodenada Jan 20, 2021
edba55f
Flatten and rework sidebar update
cincodenada Jan 20, 2021
070fa04
Add validators and more tests
cincodenada Jan 20, 2021
85edee4
Merge branch 'main' into progress_update
cincodenada Jan 20, 2021
57607c3
Regenerate merge migration
cincodenada Jan 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/django-tests.yml
Expand Up @@ -65,4 +65,4 @@ jobs:
EMAIL_HOST_PASSWORD: ""
EMAIL_USE_TLS: true
run: |
python manage.py test
python manage.py test -v 3
31 changes: 31 additions & 0 deletions bookwyrm/migrations/0012_progressupdate.py
@@ -0,0 +1,31 @@
# Generated by Django 3.0.7 on 2020-11-17 07:36

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('bookwyrm', '0011_auto_20201113_1727'),
]

operations = [
migrations.CreateModel(
name='ProgressUpdate',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_date', models.DateTimeField(auto_now_add=True)),
('updated_date', models.DateTimeField(auto_now=True)),
('remote_id', models.CharField(max_length=255, null=True)),
('progress', models.IntegerField()),
('mode', models.CharField(choices=[('PG', 'page'), ('PCT', 'percent')], default='PG', max_length=3)),
('readthrough', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='bookwyrm.ReadThrough')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
]
14 changes: 14 additions & 0 deletions bookwyrm/migrations/0014_merge_20201128_0007.py
@@ -0,0 +1,14 @@
# Generated by Django 3.0.7 on 2020-11-28 00:07

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('bookwyrm', '0013_book_origin_id'),
('bookwyrm', '0012_progressupdate'),
]

operations = [
]
23 changes: 23 additions & 0 deletions bookwyrm/migrations/0015_auto_20201128_0734.py
@@ -0,0 +1,23 @@
# Generated by Django 3.0.7 on 2020-11-28 07:34

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('bookwyrm', '0014_merge_20201128_0007'),
]

operations = [
migrations.RenameField(
model_name='readthrough',
old_name='pages_read',
new_name='progress',
),
migrations.AddField(
model_name='readthrough',
name='progress_mode',
field=models.CharField(choices=[('PG', 'page'), ('PCT', 'percent')], default='PG', max_length=3),
),
]
14 changes: 14 additions & 0 deletions bookwyrm/migrations/0039_merge_20210120_0753.py
@@ -0,0 +1,14 @@
# Generated by Django 3.0.7 on 2021-01-20 07:53

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('bookwyrm', '0038_auto_20210119_1534'),
('bookwyrm', '0015_auto_20201128_0734'),
]

operations = [
]
2 changes: 1 addition & 1 deletion bookwyrm/models/__init__.py
Expand Up @@ -13,7 +13,7 @@
from .attachment import Image
from .favorite import Favorite
from .notification import Notification
from .readthrough import ReadThrough
from .readthrough import ReadThrough, ProgressUpdate, ProgressMode

from .tag import Tag, UserTag

Expand Down
4 changes: 4 additions & 0 deletions bookwyrm/models/book.py
Expand Up @@ -72,6 +72,10 @@ def author_text(self):
''' format a list of authors '''
return ', '.join(a.name for a in self.authors.all())

@property
def latest_readthrough(self):
return self.readthrough_set.order_by('-updated_date').first()

@property
def edition_info(self):
''' properties of this edition, as a string '''
Expand Down
36 changes: 34 additions & 2 deletions bookwyrm/models/readthrough.py
@@ -1,17 +1,26 @@
''' progress in a book '''
from django.db import models
from django.utils import timezone
from django.core import validators

from .base_model import BookWyrmModel

class ProgressMode(models.TextChoices):
PAGE = 'PG', 'page'
PERCENT = 'PCT', 'percent'

class ReadThrough(BookWyrmModel):
''' Store progress through a book in the database. '''
''' Store a read through a book in the database. '''
user = models.ForeignKey('User', on_delete=models.PROTECT)
book = models.ForeignKey('Edition', on_delete=models.PROTECT)
pages_read = models.IntegerField(
progress = models.IntegerField(
validators=[validators.MinValueValidator(0)],
null=True,
blank=True)
progress_mode = models.CharField(
max_length=3,
choices=ProgressMode.choices,
default=ProgressMode.PAGE)
start_date = models.DateTimeField(
blank=True,
null=True)
Expand All @@ -24,3 +33,26 @@ def save(self, *args, **kwargs):
self.user.last_active_date = timezone.now()
self.user.save()
super().save(*args, **kwargs)

def create_update(self):
if self.progress:
return self.progressupdate_set.create(
user=self.user,
progress=self.progress,
mode=self.progress_mode)

class ProgressUpdate(BookWyrmModel):
''' Store progress through a book in the database. '''
user = models.ForeignKey('User', on_delete=models.PROTECT)
readthrough = models.ForeignKey('ReadThrough', on_delete=models.CASCADE)
progress = models.IntegerField(validators=[validators.MinValueValidator(0)])
mode = models.CharField(
max_length=3,
choices=ProgressMode.choices,
default=ProgressMode.PAGE)

def save(self, *args, **kwargs):
''' update user active time '''
self.user.last_active_date = timezone.now()
self.user.save()
super().save(*args, **kwargs)
4 changes: 4 additions & 0 deletions bookwyrm/templates/feed.html
Expand Up @@ -48,6 +48,10 @@ <h2 class="title is-5">Your books</h2>
</div>
<div class="card-content">
{% include 'snippets/shelve_button.html' with book=book %}
{% active_shelf book as active_shelf %}
{% if active_shelf.shelf.identifier == 'reading' and book.latest_readthrough %}
{% include 'snippets/progress_update.html' with readthrough=book.latest_readthrough %}
{% endif %}
{% include 'snippets/create_status.html' with book=book %}
</div>
</div>
Expand Down
7 changes: 3 additions & 4 deletions bookwyrm/templates/snippets/components/modal.html
Expand Up @@ -7,11 +7,10 @@ <h2 class="modal-card-title">
</h2>
{% include 'snippets/toggle/toggle_button.html' with label="close" class="delete" nonbutton=True %}
</header>

{% block modal-form-open %}{% endblock %}

{% block modal-body %}{% endblock %}

<section class="modal-card-body">
{% block modal-body %}{% endblock %}
</section>
<footer class="modal-card-foot">
{% block modal-footer %}{% endblock %}
</footer>
Expand Down
6 changes: 5 additions & 1 deletion bookwyrm/templates/snippets/delete_readthrough_modal.html
@@ -1,6 +1,10 @@
{% extends 'snippets/components/modal.html' %}
{% block modal-title %}Delete these read dates?{% endblock %}

{% block modal-body %}
{% if readthrough.progress_updates|length > 0 %}
You are deleting this readthrough and its {{ readthrough.progress_updates|length }} associated progress updates.
{% endif %}
{% endblock %}
{% block modal-footer %}
<form name="delete-readthrough-{{ readthrough.id }}" action="/delete-readthrough" method="POST">
{% csrf_token %}
Expand Down
27 changes: 27 additions & 0 deletions bookwyrm/templates/snippets/progress_update.html
@@ -0,0 +1,27 @@
<form class="field is-grouped is-small" action="/edit-readthrough" method="POST">
{% csrf_token %}
<input type="hidden" name="id" value="{{ readthrough.id }}"/>
<label class="label is-align-self-center mb-0 pr-2" for="progress">Currently at</label>
<div class="control">
<div class="field has-addons">
<div class="control">
<input
aria-label="{% if readthrough.progress_mode == 'PG' %}Current page{% else %}Percent read{% endif %}"
class="input is-small" type="number"
name="progress" size="3" value="{{ readthrough.progress|default:'' }}">
</div>
<div class="control">
<a class="button is-small is-static">
{% if readthrough.progress_mode == 'PG' %}
pages
{% else %}
%
{% endif %}
</a>
</div>
</div>
</div>
<div class="control">
<button class="button is-small px-2" type="submit">Save</button>
</div>
</form>
39 changes: 39 additions & 0 deletions bookwyrm/templates/snippets/readthrough.html
Expand Up @@ -13,6 +13,15 @@
<dt>Finished reading:</dt>
<dd>{{ readthrough.finish_date | naturalday }}</dd>
</div>
{% elif readthrough.progress %}
<div class="is-flex">
<dt>Progress:</dt>
{% if readthrough.progress_mode == 'PG' %}
<dd>on page {{ readthrough.progress }} of {{ book.pages }}</dd>
{% else %}
<dd>{{ readthrough.progress }}%</dd>
{% endif %}
</div>
{% endif %}
</dl>
<div class="field has-addons">
Expand All @@ -23,6 +32,36 @@
{% include 'snippets/toggle/toggle_button.html' with class="is-small" text="Delete these read dates" icon="x" controls_text="delete-readthrough" controls_uid=readthrough.id focus="modal-title-delete-readthrough" %}
</div>
</div>
{% if show_progress %}
Progress Updates:
<ul>
{% if readthrough.finish_date %}
<li>{{ readthrough.start_date | naturalday }}: finished</li>
{% endif %}
{% for progress_update in readthrough.progress_updates %}
<li>
<form name="delete-update" action="/delete-progressupdate" method="POST">
{% csrf_token %}
{{ progress_update.created_date | naturalday }}:
{% if progress_update.mode == 'PG' %}
page {{ progress_update.progress }} of {{ book.pages }}
{% else %}
{{ progress_update.progress }}%
{% endif %}
<input type="hidden" name="id" value="{{ progress_update.id }}"/>
<button type="submit" class="button is-small" for="delete-progressupdate-{{ progress_update.id }}" role="button" tabindex="0">
<span class="icon icon-x">
<span class="is-sr-only">Delete this progress update</span>
</span>
</button>
</form>
</li>
{% endfor %}
<li>{{ readthrough.start_date | naturalday }}: started</li>
</ul>
{% elif readthrough.progress_updates|length %}
<a href="?showprogress">Show {{ readthrough.progress_updates|length }} Progress Updates</a>
{% endif %}
</div>
</div>

Expand Down
25 changes: 25 additions & 0 deletions bookwyrm/templates/snippets/readthrough_form.html
Expand Up @@ -7,6 +7,31 @@
<input type="date" name="start_date" class="input" id="id_start_date-{{ readthrough.id }}" value="{{ readthrough.start_date | date:"Y-m-d" }}">
</label>
</div>
{# Only show progress for editing existing readthroughs #}
{% if readthrough.id and not readthrough.finish_date %}
<div class="columns">
<div class="column">
<div class="field">
<label class="label">
Progress
<input type="number" name="progress" class="input" id="id_progress-{{ readthrough.id }}" value="{{ readthrough.progress }}">
</label>
</div>
</div>
<div class="column">
<div class="control mt-5">
<label class="radio">
<input type="radio" name="progress_mode" id="id_progress_mode-{{ readthrough.id }}" value="PG" {% if readthrough.progress_mode == 'PG' %}checked{% endif %}>
pages
</label>
<label class="radio">
<input type="radio" name="progress_mode" id="id_progress_mode-{{ readthrough.id }}" value="PCT" {% if readthrough.progress_mode == 'PCT' %}checked{% endif %}>
percent
</label>
</div>
</div>
</div>
{% endif %}
<div class="field">
<label class="label">
Finished reading
Expand Down
1 change: 1 addition & 0 deletions bookwyrm/tests/actions/__init__.py
@@ -0,0 +1 @@
from . import *