diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index 52d10aa6..4e5206f6 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -58,6 +58,9 @@ class ReadingViews(TestCase): "post-status": True, "privacy": "followers", "start_date": "2020-01-05", + "book": self.book.id, + "mention_books": self.book.id, + "user": self.local_user.id, }, ) request.user = self.local_user @@ -77,6 +80,45 @@ class ReadingViews(TestCase): self.assertEqual(readthrough.user, self.local_user) self.assertEqual(readthrough.book, self.book) + def test_start_reading_with_comment(self, *_): + """begin a book""" + shelf = self.local_user.shelf_set.get(identifier=models.Shelf.READING) + self.assertFalse(shelf.books.exists()) + self.assertFalse(models.Status.objects.exists()) + + request = self.factory.post( + "", + { + "post-status": True, + "privacy": "followers", + "start_date": "2020-01-05", + "content": "hello hello", + "book": self.book.id, + "mention_books": self.book.id, + "user": self.local_user.id, + "reading_status": "reading", + }, + ) + request.user = self.local_user + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + views.ReadingStatus.as_view()(request, "start", self.book.id) + + self.assertEqual(shelf.books.get(), self.book) + + status = models.Comment.objects.get() + self.assertEqual(status.user, self.local_user) + self.assertEqual(status.book, self.book) + self.assertFalse(status.mention_books.exists()) + self.assertEqual(status.privacy, "followers") + self.assertEqual(status.content, "

hello hello

") + self.assertEqual(status.reading_status, "reading") + + readthrough = models.ReadThrough.objects.get() + self.assertIsNotNone(readthrough.start_date) + self.assertIsNone(readthrough.finish_date) + self.assertEqual(readthrough.user, self.local_user) + self.assertEqual(readthrough.book, self.book) + @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") def test_start_reading_reshelve(self, *_): @@ -203,3 +245,42 @@ class ReadingViews(TestCase): self.assertEqual(readthrough.finish_date.day, 7) self.assertEqual(readthrough.book, self.book) self.assertEqual(readthrough.user, self.local_user) + + def test_update_progress_comment(self, *_): + """update progress with commentary""" + readthrough = models.ReadThrough.objects.create( + user=self.local_user, start_date=timezone.now(), book=self.book + ) + request = self.factory.post( + "", + { + "post-status": True, + "privacy": "followers", + "start_date": "2020-01-05", + "content": "hello hello", + "book": self.book.id, + "mention_books": self.book.id, + "user": self.local_user.id, + "id": readthrough.id, + "progress": 23, + "progress_mode": "PCT", + }, + ) + request.user = self.local_user + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + views.update_progress(request, self.book.id) + + status = models.Comment.objects.get() + self.assertEqual(status.user, self.local_user) + self.assertEqual(status.book, self.book) + self.assertFalse(status.mention_books.exists()) + self.assertEqual(status.privacy, "followers") + self.assertEqual(status.content, "

hello hello

") + self.assertIsNone(status.reading_status) + self.assertEqual(status.progress, 23) + self.assertEqual(status.progress_mode, "PCT") + + self.assertIsNotNone(readthrough.start_date) + self.assertIsNone(readthrough.finish_date) + self.assertEqual(readthrough.user, self.local_user) + self.assertEqual(readthrough.book, self.book) diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 4209d4a9..63c5c768 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -51,8 +51,7 @@ from .list import save_list, unsave_list, delete_list from .login import Login, Logout from .notifications import Notifications from .outbox import Outbox -from .reading import edit_readthrough, create_readthrough -from .reading import delete_readthrough, delete_progressupdate +from .reading import create_readthrough, delete_readthrough, delete_progressupdate from .reading import ReadingStatus from .register import Register, ConfirmEmail, ConfirmEmailCode, resend_link from .rss_feed import RssFeed @@ -62,6 +61,7 @@ from .shelf import Shelf from .shelf import create_shelf, delete_shelf from .shelf import shelve, unshelve from .status import CreateStatus, DeleteStatus, DeleteAndRedraft, update_progress +from .status import edit_readthrough from .updates import get_notification_count, get_unread_status_count from .user import User, Followers, Following, hide_suggestions from .wellknown import * diff --git a/bookwyrm/views/helpers.py b/bookwyrm/views/helpers.py index fc5493f5..bd31fbbc 100644 --- a/bookwyrm/views/helpers.py +++ b/bookwyrm/views/helpers.py @@ -1,5 +1,10 @@ """ helper functions used in various views """ import re +from datetime import datetime +import dateutil.parser +import dateutil.tz +from dateutil.parser import ParserError + from requests import HTTPError from django.core.exceptions import FieldError from django.db.models import Q @@ -180,3 +185,15 @@ def get_landing_books(): .order_by("-review__published_date")[:6] ) ) + + +def load_date_in_user_tz_as_utc(date_str: str, user: models.User) -> datetime: + """ensures that data is stored consistently in the UTC timezone""" + if not date_str: + return None + user_tz = dateutil.tz.gettz(user.preferred_timezone) + date = dateutil.parser.parse(date_str, ignoretz=True) + try: + return date.replace(tzinfo=user_tz).astimezone(dateutil.tz.UTC) + except ParserError: + return None diff --git a/bookwyrm/views/reading.py b/bookwyrm/views/reading.py index 012f151a..54427ffb 100644 --- a/bookwyrm/views/reading.py +++ b/bookwyrm/views/reading.py @@ -1,9 +1,4 @@ """ the good stuff! the books! """ -from datetime import datetime -import dateutil.parser -import dateutil.tz -from dateutil.parser import ParserError - from django.contrib.auth.decorators import login_required from django.db import transaction from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound @@ -13,8 +8,10 @@ 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 import models +from .status import CreateStatus from .helpers import get_edition, handle_reading_status, is_api_request +from .helpers import load_date_in_user_tz_as_utc @method_decorator(login_required, name="dispatch") @@ -88,15 +85,9 @@ class ReadingStatus(View): if request.POST.get("post-status"): # is it a comment? if request.POST.get("content"): - form = forms.CommentForm(request.POST) - if form.is_valid(): - form.save() - else: - # uh oh - raise Exception(form.errors) - else: - privacy = request.POST.get("privacy") - handle_reading_status(request.user, desired_shelf, book, privacy) + return CreateStatus.as_view()(request, "comment") + privacy = request.POST.get("privacy") + handle_reading_status(request.user, desired_shelf, book, privacy) if is_api_request(request): return HttpResponse() @@ -133,45 +124,6 @@ def update_readthrough_on_shelve( active_readthrough.save() -@login_required -@require_POST -def edit_readthrough(request): - """can't use the form because the dates are too finnicky""" - readthrough = get_object_or_404(models.ReadThrough, id=request.POST.get("id")) - readthrough.raise_not_editable(request.user) - - readthrough.start_date = load_date_in_user_tz_as_utc( - request.POST.get("start_date"), request.user - ) - readthrough.finish_date = load_date_in_user_tz_as_utc( - request.POST.get("finish_date"), request.user - ) - - progress = request.POST.get("progress") - try: - progress = int(progress) - readthrough.progress = progress - except (ValueError, TypeError): - pass - - progress_mode = request.POST.get("progress_mode") - try: - progress_mode = models.ProgressMode(progress_mode) - readthrough.progress_mode = progress_mode - except ValueError: - pass - - readthrough.save() - - # record the progress update individually - # use default now for date field - readthrough.create_update() - - if is_api_request(request): - return HttpResponse() - return redirect(request.headers.get("Referer", "/")) - - @login_required @require_POST def delete_readthrough(request): @@ -204,18 +156,6 @@ def create_readthrough(request): return redirect("book", book.id) -def load_date_in_user_tz_as_utc(date_str: str, user: models.User) -> datetime: - """ensures that data is stored consistently in the UTC timezone""" - if not date_str: - return None - user_tz = dateutil.tz.gettz(user.preferred_timezone) - date = dateutil.parser.parse(date_str, ignoretz=True) - try: - return date.replace(tzinfo=user_tz).astimezone(dateutil.tz.UTC) - except ParserError: - return None - - @login_required @require_POST def delete_progressupdate(request): diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index 58d31aaa..32ce109d 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -18,7 +18,7 @@ from bookwyrm.sanitize_html import InputHtmlParser from bookwyrm.settings import DOMAIN from bookwyrm.utils import regex from .helpers import handle_remote_webfinger, is_api_request -from .reading import edit_readthrough +from .helpers import load_date_in_user_tz_as_utc # pylint: disable= no-self-use @@ -145,6 +145,45 @@ def update_progress(request, book_id): # pylint: disable=unused-argument return edit_readthrough(request) +@login_required +@require_POST +def edit_readthrough(request): + """can't use the form because the dates are too finnicky""" + readthrough = get_object_or_404(models.ReadThrough, id=request.POST.get("id")) + readthrough.raise_not_editable(request.user) + + readthrough.start_date = load_date_in_user_tz_as_utc( + request.POST.get("start_date"), request.user + ) + readthrough.finish_date = load_date_in_user_tz_as_utc( + request.POST.get("finish_date"), request.user + ) + + progress = request.POST.get("progress") + try: + progress = int(progress) + readthrough.progress = progress + except (ValueError, TypeError): + pass + + progress_mode = request.POST.get("progress_mode") + try: + progress_mode = models.ProgressMode(progress_mode) + readthrough.progress_mode = progress_mode + except ValueError: + pass + + readthrough.save() + + # record the progress update individually + # use default now for date field + readthrough.create_update() + + if is_api_request(request): + return HttpResponse() + return redirect(request.headers.get("Referer", "/")) + + def find_mentions(content): """detect @mentions in raw status content""" if not content: