diff --git a/cps/kobo.py b/cps/kobo.py index 6e284d9a..87e2d340 100644 --- a/cps/kobo.py +++ b/cps/kobo.py @@ -39,10 +39,10 @@ from flask import ( redirect, abort ) -from flask_login import login_required, current_user +from flask_login import current_user, login_required from werkzeug.datastructures import Headers from sqlalchemy import func -from sqlalchemy.sql.expression import or_ +from sqlalchemy.sql.expression import and_, or_ import requests from . import config, logger, kobo_auth, db, helper, ub @@ -152,7 +152,7 @@ def HandleSyncRequest(): # (Ideally we would use a join for this logic, however cross-database joins don't look trivial in SqlAlchemy.) recently_restored_or_archived_books = [] archived_book_ids = {} - new_archived_last_modified = datetime.min + new_archived_last_modified = datetime.datetime.min for archived_book in archived_books: if archived_book.last_modified > sync_token.archive_last_modified: recently_restored_or_archived_books.append(archived_book.book_id) @@ -213,6 +213,7 @@ def HandleSyncRequest(): sync_token.books_last_created = new_books_last_created sync_token.books_last_modified = new_books_last_modified sync_token.archive_last_modified = new_archived_last_modified + sync_token.reading_state_last_modified = new_reading_state_last_modified if config.config_kobo_proxy: return generate_sync_response(request, sync_token, sync_results) @@ -288,7 +289,7 @@ def create_book_entitlement(book, archived): "IsRemoved": archived, "IsHiddenFromArchive": False, "IsLocked": False, - "LastModified": book.last_modified, + "LastModified": convert_to_kobo_timestamp_string(book.last_modified), "OriginCategory": "Imported", "RevisionId": book_uuid, "Status": "Active", @@ -568,7 +569,7 @@ def HandleBookDeletionRequest(book_uuid): if not archived_book: archived_book = ub.ArchivedBook(user_id=current_user.id, book_id=book_id) archived_book.is_archived = True - archived_book.last_modified = datetime.utcnow() + archived_book.last_modified = datetime.datetime.utcnow() ub.session.merge(archived_book) ub.session.commit() @@ -577,12 +578,12 @@ def HandleBookDeletionRequest(book_uuid): # TODO: Implement the following routes -@kobo.route("/v1/library//state", methods=["PUT"]) +@kobo.route("/v1/library/", methods=["DELETE", "GET"]) @kobo.route("/v1/library/tags", methods=["POST"]) @kobo.route("/v1/library/tags/", methods=["POST"]) @kobo.route("/v1/library/tags/", methods=["DELETE"]) -def HandleUnimplementedRequest(book_uuid=None, shelf_name=None, tag_id=None): - log.debug("Alternative Request received:") +def HandleUnimplementedRequest(dummy=None, book_uuid=None, shelf_name=None, tag_id=None): + log.debug("Unimplemented Library Request received: %s", request.base_url) return redirect_or_proxy_request() diff --git a/cps/services/SyncToken.py b/cps/services/SyncToken.py index 15f788f2..9804fdb3 100644 --- a/cps/services/SyncToken.py +++ b/cps/services/SyncToken.py @@ -77,6 +77,7 @@ class SyncToken(): "books_last_modified": {"type": "string"}, "books_last_created": {"type": "string"}, "archive_last_modified": {"type": "string"}, + "reading_state_last_modified": {"type": "string"}, }, } @@ -86,11 +87,14 @@ class SyncToken(): books_last_created=datetime.min, books_last_modified=datetime.min, archive_last_modified=datetime.min, + reading_state_last_modified=datetime.min, ): self.raw_kobo_store_token = raw_kobo_store_token self.books_last_created = books_last_created self.books_last_modified = books_last_modified self.archive_last_modified = archive_last_modified + self.reading_state_last_modified = reading_state_last_modified + @staticmethod def from_headers(headers): @@ -123,6 +127,7 @@ class SyncToken(): books_last_modified = get_datetime_from_json(data_json, "books_last_modified") books_last_created = get_datetime_from_json(data_json, "books_last_created") archive_last_modified = get_datetime_from_json(data_json, "archive_last_modified") + reading_state_last_modified = get_datetime_from_json(data_json, "reading_state_last_modified") except TypeError: log.error("SyncToken timestamps don't parse to a datetime.") return SyncToken(raw_kobo_store_token=raw_kobo_store_token) @@ -131,7 +136,8 @@ class SyncToken(): raw_kobo_store_token=raw_kobo_store_token, books_last_created=books_last_created, books_last_modified=books_last_modified, - archive_last_modified=archive_last_modified + archive_last_modified=archive_last_modified, + reading_state_last_modified=reading_state_last_modified ) def set_kobo_store_header(self, store_headers): @@ -152,7 +158,8 @@ class SyncToken(): "raw_kobo_store_token": self.raw_kobo_store_token, "books_last_modified": to_epoch_timestamp(self.books_last_modified), "books_last_created": to_epoch_timestamp(self.books_last_created), - "archive_last_modified": to_epoch_timestamp(self.archive_last_modified) + "archive_last_modified": to_epoch_timestamp(self.archive_last_modified), + "reading_state_last_modified": to_epoch_timestamp(self.reading_state_last_modified) }, } return b64encode_json(token)