diff --git a/reader/forms.py b/reader/forms.py index b20e692afe84da92032b55a04ddff1be3d91c10f..b2f833ae53e36437324b7098fba173db9c4b7f1b 100644 --- a/reader/forms.py +++ b/reader/forms.py @@ -10,7 +10,7 @@ from django.core.exceptions import ValidationError from django.db.models.fields.files import FieldFile from api_koreader.xpointer_cfi_utils import validate_epub -from reader.models import Book +from reader.models import Book, UserBook class FileTypeValidator: @@ -68,3 +68,9 @@ class BookForm(forms.ModelForm): if not self.request.user.has_perm("reader.book_create_loanable"): self.fields["loanable"].disabled = True self.fields["loanable_copies"].disabled = True + + +class UserBookProgressForm(forms.ModelForm): + class Meta: + model = UserBook + fields = ["percentage_read", "last_progress_device", "last_progress_cfi"] diff --git a/reader/urls.py b/reader/urls.py index fe79163a827b3d2c599e3c509d740d5140b4090f..3994eec433dddebfb645c1e0856507b07a1261a1 100644 --- a/reader/urls.py +++ b/reader/urls.py @@ -9,4 +9,5 @@ urlpatterns = [ path("books/<int:book_id>", views.view_book, name='view_book'), path("books/<int:book_id>/to_library", views.add_to_library, name='add_to_library'), path("books/<int:book_id>/read", views.read_book, name='read_book'), + path("books/<int:book_id>/progress", views.update_progress, name='update_progress'), ] \ No newline at end of file diff --git a/reader/views.py b/reader/views.py index 6a1139b2b7b07db69439d8983899be71ae543656..0307ac852a729753247759d4d7cc3829396ebbb7 100644 --- a/reader/views.py +++ b/reader/views.py @@ -1,9 +1,12 @@ +import re + from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied +from django.http import JsonResponse from django.shortcuts import render, redirect, get_object_or_404 from django.views.decorators.http import require_POST -from reader.forms import BookForm +from reader.forms import BookForm, UserBookProgressForm from reader.models import Book, UserBook @@ -139,15 +142,66 @@ def read_book(request, book_id): if not user_can_access_book(request, book): raise PermissionDenied userbook = get_object_or_404(UserBook, book=book, user=request.user) + pagenumber = None + cfi_ref = None # Check file type match book.file_type: case "pdf": reader_template = "reader/book_read/pdf_viewer.html" + try: + # Try to parse page number + pagenumber = int(userbook.last_progress_cfi) + except ValueError: + pass + except TypeError: + pass case "epub": reader_template = "reader/book_read/epub_viewer.html" + # Try to parse CFI + rgx = re.compile(r"epubcfi\((.*)\)") + m = rgx.match(userbook.last_progress_cfi) + if m: + cfi_ref = userbook.last_progress_cfi case _: reader_template = "reader/book_read/invalid_filetype.html" return render(request, reader_template, { "book": book, - "userbook": userbook - }) \ No newline at end of file + "userbook": userbook, + "pagenumber": pagenumber, + "cfi_ref": cfi_ref + }) + + +@require_POST +@login_required(login_url='login') +def update_progress(request, book_id): + book = get_object_or_404(Book, id=book_id) + if not user_can_access_book(request, book): + raise PermissionDenied + userbook = get_object_or_404(UserBook, book=book, user=request.user) + form = UserBookProgressForm(data=request.POST, instance=userbook) + if form.is_valid(): + valid_for_filetype = False + if book.file_type == "pdf": + # Check page number is valid + try: + int(form.cleaned_data["last_progress_cfi"]) + valid_for_filetype = True # If no exception, it's valid + except ValueError: + pass + except TypeError: + pass + elif book.file_type == "epub": + # Check CFI is valid + rgx = re.compile(r"epubcfi\((.*)\)") + m = rgx.match(form.cleaned_data["last_progress_cfi"]) + if m: + valid_for_filetype = True + + if valid_for_filetype: + form.save() + return JsonResponse({"success": True}) + else: + return JsonResponse({"error": "Invalid progress for file type"}, status=400) + else: + return JsonResponse({"error": form.errors}, status=400) \ No newline at end of file