Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
D
douban-api-proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
captainwong
douban-api-proxy
Commits
e404da41
Commit
e404da41
authored
Jan 24, 2020
by
Michael Shavit
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for book 'deletion' (i.e archiving) from a Kobo device.
parent
cd9bb56d
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
50 additions
and
4 deletions
+50
-4
kobo.py
cps/kobo.py
+39
-4
ub.py
cps/ub.py
+11
-0
No files found.
cps/kobo.py
View file @
e404da41
...
@@ -21,6 +21,7 @@ import sys
...
@@ -21,6 +21,7 @@ import sys
import
uuid
import
uuid
from
datetime
import
datetime
from
datetime
import
datetime
from
time
import
gmtime
,
strftime
from
time
import
gmtime
,
strftime
try
:
try
:
from
urllib
import
unquote
from
urllib
import
unquote
except
ImportError
:
except
ImportError
:
...
@@ -35,12 +36,12 @@ from flask import (
...
@@ -35,12 +36,12 @@ from flask import (
url_for
,
url_for
,
redirect
,
redirect
,
)
)
from
flask_login
import
login_required
from
flask_login
import
login_required
,
current_user
from
werkzeug.datastructures
import
Headers
from
werkzeug.datastructures
import
Headers
from
sqlalchemy
import
func
from
sqlalchemy
import
func
import
requests
import
requests
from
.
import
config
,
logger
,
kobo_auth
,
db
,
helper
from
.
import
config
,
logger
,
kobo_auth
,
db
,
helper
,
ub
from
.services
import
SyncToken
as
SyncToken
from
.services
import
SyncToken
as
SyncToken
from
.web
import
download_required
from
.web
import
download_required
...
@@ -53,6 +54,7 @@ kobo_auth.register_url_value_preprocessor(kobo)
...
@@ -53,6 +54,7 @@ kobo_auth.register_url_value_preprocessor(kobo)
log
=
logger
.
create
()
log
=
logger
.
create
()
def
get_store_url_for_current_request
():
def
get_store_url_for_current_request
():
# Programmatically modify the current url to point to the official Kobo store
# Programmatically modify the current url to point to the official Kobo store
base
,
sep
,
request_path_with_auth_token
=
request
.
full_path
.
rpartition
(
"/kobo/"
)
base
,
sep
,
request_path_with_auth_token
=
request
.
full_path
.
rpartition
(
"/kobo/"
)
...
@@ -114,6 +116,14 @@ def HandleSyncRequest():
...
@@ -114,6 +116,14 @@ def HandleSyncRequest():
# in case of external changes (e.g: adding a book through Calibre).
# in case of external changes (e.g: adding a book through Calibre).
db
.
reconnect_db
(
config
)
db
.
reconnect_db
(
config
)
archived_books
=
(
ub
.
session
.
query
(
ub
.
ArchivedBook
)
.
filter
(
ub
.
ArchivedBook
.
user_id
==
int
(
current_user
.
id
))
.
filter
(
ub
.
ArchivedBook
.
is_archived
==
True
)
.
all
()
)
archived_book_ids
=
[
archived_book
.
book_id
for
archived_book
in
archived_books
]
# sqlite gives unexpected results when performing the last_modified comparison without the datetime cast.
# sqlite gives unexpected results when performing the last_modified comparison without the datetime cast.
# It looks like it's treating the db.Books.last_modified field as a string and may fail
# It looks like it's treating the db.Books.last_modified field as a string and may fail
# the comparison because of the +00:00 suffix.
# the comparison because of the +00:00 suffix.
...
@@ -122,6 +132,7 @@ def HandleSyncRequest():
...
@@ -122,6 +132,7 @@ def HandleSyncRequest():
.
join
(
db
.
Data
)
.
join
(
db
.
Data
)
.
filter
(
func
.
datetime
(
db
.
Books
.
last_modified
)
!=
sync_token
.
books_last_modified
)
.
filter
(
func
.
datetime
(
db
.
Books
.
last_modified
)
!=
sync_token
.
books_last_modified
)
.
filter
(
db
.
Data
.
format
.
in_
(
KOBO_FORMATS
))
.
filter
(
db
.
Data
.
format
.
in_
(
KOBO_FORMATS
))
.
filter
(
db
.
Books
.
id
.
notin_
(
archived_book_ids
))
.
all
()
.
all
()
)
)
for
book
in
changed_entries
:
for
book
in
changed_entries
:
...
@@ -342,13 +353,37 @@ def TopLevelEndpoint():
...
@@ -342,13 +353,37 @@ def TopLevelEndpoint():
return
make_response
(
jsonify
({}))
return
make_response
(
jsonify
({}))
@
kobo
.
route
(
"/v1/library/<book_uuid>"
,
methods
=
[
"DELETE"
])
@
login_required
def
HandleBookDeletionRequest
(
book_uuid
):
log
.
info
(
"Kobo book deletion request received for book
%
s"
%
book_uuid
)
book
=
db
.
session
.
query
(
db
.
Books
)
.
filter
(
db
.
Books
.
uuid
==
book_uuid
)
.
first
()
if
not
book
:
log
.
info
(
u"Book
%
s not found in database"
,
book_uuid
)
return
redirect_or_proxy_request
()
book_id
=
book
.
id
archived_book
=
(
ub
.
session
.
query
(
ub
.
ArchivedBook
)
.
filter
(
ub
.
ArchivedBook
.
book_id
==
book_id
)
.
first
()
)
if
not
archived_book
:
archived_book
=
ub
.
ArchivedBook
(
user_id
=
current_user
.
id
,
book_id
=
book_id
)
archived_book
.
book_id
=
book_id
archived_book
.
is_archived
=
True
ub
.
session
.
merge
(
archived_book
)
ub
.
session
.
commit
()
return
(
""
,
204
)
# TODO: Implement the following routes
# TODO: Implement the following routes
@
kobo
.
route
(
"/v1/library/<dummy>"
,
methods
=
[
"DELETE"
,
"GET"
])
@
kobo
.
route
(
"/v1/library/<book_uuid>/state"
,
methods
=
[
"PUT"
])
@
kobo
.
route
(
"/v1/library/<book_uuid>/state"
,
methods
=
[
"PUT"
])
@
kobo
.
route
(
"/v1/library/tags"
,
methods
=
[
"POST"
])
@
kobo
.
route
(
"/v1/library/tags"
,
methods
=
[
"POST"
])
@
kobo
.
route
(
"/v1/library/tags/<shelf_name>"
,
methods
=
[
"POST"
])
@
kobo
.
route
(
"/v1/library/tags/<shelf_name>"
,
methods
=
[
"POST"
])
@
kobo
.
route
(
"/v1/library/tags/<tag_id>"
,
methods
=
[
"DELETE"
])
@
kobo
.
route
(
"/v1/library/tags/<tag_id>"
,
methods
=
[
"DELETE"
])
def
HandleUnimplementedRequest
(
dummy
=
None
,
book_uuid
=
None
,
shelf_name
=
None
,
tag_id
=
None
):
def
HandleUnimplementedRequest
(
book_uuid
=
None
,
shelf_name
=
None
,
tag_id
=
None
):
return
redirect_or_proxy_request
()
return
redirect_or_proxy_request
()
...
...
cps/ub.py
View file @
e404da41
...
@@ -300,6 +300,15 @@ class Bookmark(Base):
...
@@ -300,6 +300,15 @@ class Bookmark(Base):
format
=
Column
(
String
(
collation
=
'NOCASE'
))
format
=
Column
(
String
(
collation
=
'NOCASE'
))
bookmark_key
=
Column
(
String
)
bookmark_key
=
Column
(
String
)
# Baseclass representing books that are archived on the user's Kobo device.
class
ArchivedBook
(
Base
):
__tablename__
=
'archived_book'
id
=
Column
(
Integer
,
primary_key
=
True
)
user_id
=
Column
(
Integer
,
ForeignKey
(
'user.id'
))
book_id
=
Column
(
Integer
)
is_archived
=
Column
(
Boolean
,
unique
=
False
)
# Baseclass representing Downloads from calibre-web in app.db
# Baseclass representing Downloads from calibre-web in app.db
class
Downloads
(
Base
):
class
Downloads
(
Base
):
...
@@ -353,6 +362,8 @@ def migrate_Database(session):
...
@@ -353,6 +362,8 @@ def migrate_Database(session):
ReadBook
.
__table__
.
create
(
bind
=
engine
)
ReadBook
.
__table__
.
create
(
bind
=
engine
)
if
not
engine
.
dialect
.
has_table
(
engine
.
connect
(),
"bookmark"
):
if
not
engine
.
dialect
.
has_table
(
engine
.
connect
(),
"bookmark"
):
Bookmark
.
__table__
.
create
(
bind
=
engine
)
Bookmark
.
__table__
.
create
(
bind
=
engine
)
if
not
engine
.
dialect
.
has_table
(
engine
.
connect
(),
"archived_book"
):
ArchivedBook
.
__table__
.
create
(
bind
=
engine
)
if
not
engine
.
dialect
.
has_table
(
engine
.
connect
(),
"registration"
):
if
not
engine
.
dialect
.
has_table
(
engine
.
connect
(),
"registration"
):
ReadBook
.
__table__
.
create
(
bind
=
engine
)
ReadBook
.
__table__
.
create
(
bind
=
engine
)
conn
=
engine
.
connect
()
conn
=
engine
.
connect
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment