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
0955c6d6
Commit
0955c6d6
authored
Jan 26, 2020
by
Ozzieisaacs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update Kobo
parent
cd9bb56d
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
213 additions
and
31 deletions
+213
-31
kobo.py
cps/kobo.py
+191
-29
reverseproxy.py
cps/reverseproxy.py
+7
-0
server.py
cps/server.py
+1
-1
config_edit.html
cps/templates/config_edit.html
+12
-0
ub.py
cps/ub.py
+2
-1
No files found.
cps/kobo.py
View file @
0955c6d6
...
@@ -31,7 +31,7 @@ from flask import (
...
@@ -31,7 +31,7 @@ from flask import (
request
,
request
,
make_response
,
make_response
,
jsonify
,
jsonify
,
json
,
current_app
,
url_for
,
url_for
,
redirect
,
redirect
,
)
)
...
@@ -44,7 +44,7 @@ from . import config, logger, kobo_auth, db, helper
...
@@ -44,7 +44,7 @@ from . import config, logger, kobo_auth, db, helper
from
.services
import
SyncToken
as
SyncToken
from
.services
import
SyncToken
as
SyncToken
from
.web
import
download_required
from
.web
import
download_required
KOBO_FORMATS
=
{
"KEPUB"
:
[
"KEPUB"
],
"EPUB"
:
[
"
EPUB"
,
"EPUB3
"
]}
KOBO_FORMATS
=
{
"KEPUB"
:
[
"KEPUB"
],
"EPUB"
:
[
"
KEPUB
"
]}
KOBO_STOREAPI_URL
=
"https://storeapi.kobo.com"
KOBO_STOREAPI_URL
=
"https://storeapi.kobo.com"
kobo
=
Blueprint
(
"kobo"
,
__name__
,
url_prefix
=
"/kobo/<auth_token>"
)
kobo
=
Blueprint
(
"kobo"
,
__name__
,
url_prefix
=
"/kobo/<auth_token>"
)
...
@@ -74,6 +74,7 @@ def redirect_or_proxy_request():
...
@@ -74,6 +74,7 @@ def redirect_or_proxy_request():
if
request
.
method
==
"GET"
:
if
request
.
method
==
"GET"
:
return
redirect
(
get_store_url_for_current_request
(),
307
)
return
redirect
(
get_store_url_for_current_request
(),
307
)
if
request
.
method
==
"DELETE"
:
if
request
.
method
==
"DELETE"
:
log
.
info
(
'Delete Book'
)
return
make_response
(
jsonify
({}))
return
make_response
(
jsonify
({}))
else
:
else
:
# The Kobo device turns other request types into GET requests on redirects, so we instead proxy to the Kobo store ourselves.
# The Kobo device turns other request types into GET requests on redirects, so we instead proxy to the Kobo store ourselves.
...
@@ -124,6 +125,7 @@ def HandleSyncRequest():
...
@@ -124,6 +125,7 @@ def HandleSyncRequest():
.
filter
(
db
.
Data
.
format
.
in_
(
KOBO_FORMATS
))
.
filter
(
db
.
Data
.
format
.
in_
(
KOBO_FORMATS
))
.
all
()
.
all
()
)
)
for
book
in
changed_entries
:
for
book
in
changed_entries
:
entitlement
=
{
entitlement
=
{
"BookEntitlement"
:
create_book_entitlement
(
book
),
"BookEntitlement"
:
create_book_entitlement
(
book
),
...
@@ -144,30 +146,29 @@ def HandleSyncRequest():
...
@@ -144,30 +146,29 @@ def HandleSyncRequest():
sync_token
.
books_last_modified
=
new_books_last_modified
sync_token
.
books_last_modified
=
new_books_last_modified
# Missing feature: Detect server-side book deletions.
# Missing feature: Detect server-side book deletions.
return
generate_sync_response
(
request
,
sync_token
,
entitlements
)
return
generate_sync_response
(
request
,
sync_token
,
entitlements
)
def
generate_sync_response
(
request
,
sync_token
,
entitlements
):
def
generate_sync_response
(
request
,
sync_token
,
entitlements
):
# We first merge in sync results from the official Kobo store.
# We first merge in sync results from the official Kobo store.
outgoing_headers
=
Headers
(
request
.
headers
)
#
outgoing_headers = Headers(request.headers)
outgoing_headers
.
remove
(
"Host"
)
#
outgoing_headers.remove("Host")
sync_token
.
set_kobo_store_header
(
outgoing_headers
)
#
sync_token.set_kobo_store_header(outgoing_headers)
store_response
=
requests
.
request
(
#
store_response = requests.request(
method
=
request
.
method
,
#
method=request.method,
url
=
get_store_url_for_current_request
(),
#
url=get_store_url_for_current_request(),
headers
=
outgoing_headers
,
#
headers=outgoing_headers,
data
=
request
.
get_data
(),
#
data=request.get_data(),
)
#
)
store_entitlements
=
store_response
.
json
()
#
store_entitlements = store_response.json()
entitlements
+=
store_entitlements
#
entitlements += store_entitlements
sync_token
.
merge_from_store_response
(
store_response
)
#
sync_token.merge_from_store_response(store_response)
response
=
make_response
(
jsonify
(
entitlements
))
response
=
make_response
(
jsonify
(
entitlements
))
# sync_token.to_headers(request.headers)
sync_token
.
to_headers
(
response
.
headers
)
#
sync_token.to_headers(response.headers)
try
:
'''
try:
# These headers could probably use some more investigation.
# These headers could probably use some more investigation.
response.headers["x-kobo-sync"] = store_response.headers["x-kobo-sync"]
response.headers["x-kobo-sync"] = store_response.headers["x-kobo-sync"]
response.headers["x-kobo-sync-mode"] = store_response.headers[
response.headers["x-kobo-sync-mode"] = store_response.headers[
...
@@ -177,7 +178,7 @@ def generate_sync_response(request, sync_token, entitlements):
...
@@ -177,7 +178,7 @@ def generate_sync_response(request, sync_token, entitlements):
"x-kobo-recent-reads"
"x-kobo-recent-reads"
]
]
except KeyError:
except KeyError:
pass
pass
'''
return
response
return
response
...
@@ -197,12 +198,22 @@ def HandleMetadataRequest(book_uuid):
...
@@ -197,12 +198,22 @@ def HandleMetadataRequest(book_uuid):
def
get_download_url_for_book
(
book
,
book_format
):
def
get_download_url_for_book
(
book
,
book_format
):
return
url_for
(
if
not
current_app
.
wsgi_app
.
is_proxied
:
"web.download_link"
,
log
.
debug
(
'Received unproxied request, changed request port to server port'
)
book_id
=
book
.
id
,
return
"{url_scheme}://{url_base}:{url_port}/download/{book_id}/{book_format}"
.
format
(
book_format
=
book_format
.
lower
(),
url_scheme
=
request
.
environ
[
'wsgi.url_scheme'
],
_external
=
True
,
url_base
=
request
.
environ
[
'SERVER_NAME'
],
)
url_port
=
config
.
config_port
,
book_id
=
book
.
id
,
book_format
=
book_format
.
lower
()
)
else
:
return
url_for
(
"web.download_link"
,
book_id
=
book
.
id
,
book_format
=
book_format
.
lower
(),
_external
=
True
,
)
def
create_book_entitlement
(
book
):
def
create_book_entitlement
(
book
):
...
@@ -255,11 +266,11 @@ def get_series(book):
...
@@ -255,11 +266,11 @@ def get_series(book):
def
get_metadata
(
book
):
def
get_metadata
(
book
):
download_urls
=
[]
download_urls
=
[]
for
book_data
in
book
.
data
:
for
book_data
in
book
.
data
:
if
book_data
.
format
not
in
KOBO_FORMATS
:
if
book_data
.
format
not
in
KOBO_FORMATS
:
continue
continue
for
kobo_format
in
KOBO_FORMATS
[
book_data
.
format
]:
for
kobo_format
in
KOBO_FORMATS
[
book_data
.
format
]:
# log.debug('Id: %s, Format: %s' % (book.id, kobo_format))
download_urls
.
append
(
download_urls
.
append
(
{
{
"Format"
:
kobo_format
,
"Format"
:
kobo_format
,
...
@@ -349,17 +360,29 @@ def TopLevelEndpoint():
...
@@ -349,17 +360,29 @@ def TopLevelEndpoint():
@
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
(
dummy
=
None
,
book_uuid
=
None
,
shelf_name
=
None
,
tag_id
=
None
):
log
.
debug
(
"Alternative Request received:"
)
return
redirect_or_proxy_request
()
return
redirect_or_proxy_request
()
# TODO: Implement the following routes
@
kobo
.
route
(
"/v1/user/loyalty/<dummy>"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/user/profile"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/user/wishlist"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/user/recommendations"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/analytics/<dummy>"
,
methods
=
[
"GET"
,
"POST"
])
def
HandleUserRequest
(
dummy
=
None
):
log
.
debug
(
"Unimplemented Request received:
%
s"
,
request
.
base_url
)
return
make_response
(
jsonify
({}))
# return redirect_or_proxy_request()
@
kobo
.
app_errorhandler
(
404
)
@
kobo
.
app_errorhandler
(
404
)
def
handle_404
(
err
):
def
handle_404
(
err
):
# This handler acts as a catch-all for endpoints that we don't have an interest in
# This handler acts as a catch-all for endpoints that we don't have an interest in
# implementing (e.g: v1/analytics/gettests, v1/user/recommendations, etc)
# implementing (e.g: v1/analytics/gettests, v1/user/recommendations, etc)
log
.
debug
(
"Unknown Request received:
%
s"
,
request
.
base_url
)
return
redirect_or_proxy_request
()
return
redirect_or_proxy_request
()
@
kobo
.
route
(
"/v1/initialization"
)
'''
@kobo.route("/v1/initialization")
@login_required
@login_required
def HandleInitRequest():
def HandleInitRequest():
outgoing_headers = Headers(request.headers)
outgoing_headers = Headers(request.headers)
...
@@ -374,7 +397,6 @@ def HandleInitRequest():
...
@@ -374,7 +397,6 @@ def HandleInitRequest():
store_response_json = store_response.json()
store_response_json = store_response.json()
if "Resources" in store_response_json:
if "Resources" in store_response_json:
kobo_resources = store_response_json["Resources"]
kobo_resources = store_response_json["Resources"]
calibre_web_url = url_for("web.index", _external=True).strip("/")
calibre_web_url = url_for("web.index", _external=True).strip("/")
kobo_resources["image_host"] = calibre_web_url
kobo_resources["image_host"] = calibre_web_url
kobo_resources["image_url_quality_template"] = unquote(url_for("kobo.HandleCoverImageRequest", _external=True,
kobo_resources["image_url_quality_template"] = unquote(url_for("kobo.HandleCoverImageRequest", _external=True,
...
@@ -385,3 +407,143 @@ def HandleInitRequest():
...
@@ -385,3 +407,143 @@ def HandleInitRequest():
book_uuid="{ImageId}"))
book_uuid="{ImageId}"))
return make_response(store_response_json, store_response.status_code)
return make_response(store_response_json, store_response.status_code)
'''
@
kobo
.
route
(
"/v1/initialization"
)
def
HandleInitRequest
():
resources
=
NATIVE_KOBO_RESOURCES
(
calibre_web_url
=
url_for
(
"web.index"
,
_external
=
True
)
.
strip
(
"/"
)
)
response
=
make_response
(
jsonify
({
"Resources"
:
resources
}))
response
.
headers
[
"x-kobo-apitoken"
]
=
"e30="
return
response
def
NATIVE_KOBO_RESOURCES
(
calibre_web_url
):
return
{
"account_page"
:
"https://secure.kobobooks.com/profile"
,
"account_page_rakuten"
:
"https://my.rakuten.co.jp/"
,
"add_entitlement"
:
"https://storeapi.kobo.com/v1/library/{RevisionIds}"
,
"affiliaterequest"
:
"https://storeapi.kobo.com/v1/affiliate"
,
"audiobook_subscription_orange_deal_inclusion_url"
:
"https://authorize.kobo.com/inclusion"
,
"authorproduct_recommendations"
:
"https://storeapi.kobo.com/v1/products/books/authors/recommendations"
,
"autocomplete"
:
"https://storeapi.kobo.com/v1/products/autocomplete"
,
"blackstone_header"
:
{
"key"
:
"x-amz-request-payer"
,
"value"
:
"requester"
},
"book"
:
"https://storeapi.kobo.com/v1/products/books/{ProductId}"
,
"book_detail_page"
:
"https://store.kobobooks.com/{culture}/ebook/{slug}"
,
"book_detail_page_rakuten"
:
"http://books.rakuten.co.jp/rk/{crossrevisionid}"
,
"book_landing_page"
:
"https://store.kobobooks.com/ebooks"
,
"book_subscription"
:
"https://storeapi.kobo.com/v1/products/books/subscriptions"
,
"categories"
:
"https://storeapi.kobo.com/v1/categories"
,
"categories_page"
:
"https://store.kobobooks.com/ebooks/categories"
,
"category"
:
"https://storeapi.kobo.com/v1/categories/{CategoryId}"
,
"category_featured_lists"
:
"https://storeapi.kobo.com/v1/categories/{CategoryId}/featured"
,
"category_products"
:
"https://storeapi.kobo.com/v1/categories/{CategoryId}/products"
,
"checkout_borrowed_book"
:
"https://storeapi.kobo.com/v1/library/borrow"
,
"configuration_data"
:
"https://storeapi.kobo.com/v1/configuration"
,
"content_access_book"
:
"https://storeapi.kobo.com/v1/products/books/{ProductId}/access"
,
"customer_care_live_chat"
:
"https://v2.zopim.com/widget/livechat.html?key=Y6gwUmnu4OATxN3Tli4Av9bYN319BTdO"
,
"daily_deal"
:
"https://storeapi.kobo.com/v1/products/dailydeal"
,
"deals"
:
"https://storeapi.kobo.com/v1/deals"
,
"delete_entitlement"
:
"https://storeapi.kobo.com/v1/library/{Ids}"
,
"delete_tag"
:
"https://storeapi.kobo.com/v1/library/tags/{TagId}"
,
"delete_tag_items"
:
"https://storeapi.kobo.com/v1/library/tags/{TagId}/items/delete"
,
"device_auth"
:
"https://storeapi.kobo.com/v1/auth/device"
,
"device_refresh"
:
"https://storeapi.kobo.com/v1/auth/refresh"
,
"dictionary_host"
:
"https://kbdownload1-a.akamaihd.net"
,
"discovery_host"
:
"https://discovery.kobobooks.com"
,
"eula_page"
:
"https://www.kobo.com/termsofuse?style=onestore"
,
"exchange_auth"
:
"https://storeapi.kobo.com/v1/auth/exchange"
,
"external_book"
:
"https://storeapi.kobo.com/v1/products/books/external/{Ids}"
,
"facebook_sso_page"
:
"https://authorize.kobo.com/signin/provider/Facebook/login?returnUrl=http://store.kobobooks.com/"
,
"featured_list"
:
"https://storeapi.kobo.com/v1/products/featured/{FeaturedListId}"
,
"featured_lists"
:
"https://storeapi.kobo.com/v1/products/featured"
,
"free_books_page"
:
{
"EN"
:
"https://www.kobo.com/{region}/{language}/p/free-ebooks"
,
"FR"
:
"https://www.kobo.com/{region}/{language}/p/livres-gratuits"
,
"IT"
:
"https://www.kobo.com/{region}/{language}/p/libri-gratuiti"
,
"NL"
:
"https://www.kobo.com/{region}/{language}/List/bekijk-het-overzicht-van-gratis-ebooks/QpkkVWnUw8sxmgjSlCbJRg"
,
"PT"
:
"https://www.kobo.com/{region}/{language}/p/livros-gratis"
,
},
"fte_feedback"
:
"https://storeapi.kobo.com/v1/products/ftefeedback"
,
"get_tests_request"
:
"https://storeapi.kobo.com/v1/analytics/gettests"
,
"giftcard_epd_redeem_url"
:
"https://www.kobo.com/{storefront}/{language}/redeem-ereader"
,
"giftcard_redeem_url"
:
"https://www.kobo.com/{storefront}/{language}/redeem"
,
"help_page"
:
"http://www.kobo.com/help"
,
"image_host"
:
calibre_web_url
,
"image_url_quality_template"
:
calibre_web_url
+
"/{ImageId}/{Width}/{Height}/{Quality}/{IsGreyscale}/image.jpg"
,
"image_url_template"
:
calibre_web_url
+
"/{ImageId}/{Width}/{Height}/false/image.jpg"
,
"kobo_audiobooks_enabled"
:
"False"
,
"kobo_audiobooks_orange_deal_enabled"
:
"False"
,
"kobo_audiobooks_subscriptions_enabled"
:
"False"
,
"kobo_nativeborrow_enabled"
:
"True"
,
"kobo_onestorelibrary_enabled"
:
"False"
,
"kobo_redeem_enabled"
:
"True"
,
"kobo_shelfie_enabled"
:
"False"
,
"kobo_subscriptions_enabled"
:
"False"
,
"kobo_superpoints_enabled"
:
"False"
,
"kobo_wishlist_enabled"
:
"True"
,
"library_book"
:
"https://storeapi.kobo.com/v1/user/library/books/{LibraryItemId}"
,
"library_items"
:
"https://storeapi.kobo.com/v1/user/library"
,
"library_metadata"
:
"https://storeapi.kobo.com/v1/library/{Ids}/metadata"
,
"library_prices"
:
"https://storeapi.kobo.com/v1/user/library/previews/prices"
,
"library_stack"
:
"https://storeapi.kobo.com/v1/user/library/stacks/{LibraryItemId}"
,
"library_sync"
:
"https://storeapi.kobo.com/v1/library/sync"
,
"love_dashboard_page"
:
"https://store.kobobooks.com/{culture}/kobosuperpoints"
,
"love_points_redemption_page"
:
"https://store.kobobooks.com/{culture}/KoboSuperPointsRedemption?productId={ProductId}"
,
"magazine_landing_page"
:
"https://store.kobobooks.com/emagazines"
,
"notifications_registration_issue"
:
"https://storeapi.kobo.com/v1/notifications/registration"
,
"oauth_host"
:
"https://oauth.kobo.com"
,
"overdrive_account"
:
"https://auth.overdrive.com/account"
,
"overdrive_library"
:
"https://{libraryKey}.auth.overdrive.com/library"
,
"overdrive_library_finder_host"
:
"https://libraryfinder.api.overdrive.com"
,
"overdrive_thunder_host"
:
"https://thunder.api.overdrive.com"
,
"password_retrieval_page"
:
"https://www.kobobooks.com/passwordretrieval.html"
,
"post_analytics_event"
:
"https://storeapi.kobo.com/v1/analytics/event"
,
"privacy_page"
:
"https://www.kobo.com/privacypolicy?style=onestore"
,
"product_nextread"
:
"https://storeapi.kobo.com/v1/products/{ProductIds}/nextread"
,
"product_prices"
:
"https://storeapi.kobo.com/v1/products/{ProductIds}/prices"
,
"product_recommendations"
:
"https://storeapi.kobo.com/v1/products/{ProductId}/recommendations"
,
"product_reviews"
:
"https://storeapi.kobo.com/v1/products/{ProductIds}/reviews"
,
"products"
:
"https://storeapi.kobo.com/v1/products"
,
"provider_external_sign_in_page"
:
"https://authorize.kobo.com/ExternalSignIn/{providerName}?returnUrl=http://store.kobobooks.com/"
,
"purchase_buy"
:
"https://www.kobo.com/checkout/createpurchase/"
,
"purchase_buy_templated"
:
"https://www.kobo.com/{culture}/checkout/createpurchase/{ProductId}"
,
"quickbuy_checkout"
:
"https://storeapi.kobo.com/v1/store/quickbuy/{PurchaseId}/checkout"
,
"quickbuy_create"
:
"https://storeapi.kobo.com/v1/store/quickbuy/purchase"
,
"rating"
:
"https://storeapi.kobo.com/v1/products/{ProductId}/rating/{Rating}"
,
"reading_state"
:
"https://storeapi.kobo.com/v1/library/{Ids}/state"
,
"redeem_interstitial_page"
:
"https://store.kobobooks.com"
,
"registration_page"
:
"https://authorize.kobo.com/signup?returnUrl=http://store.kobobooks.com/"
,
"related_items"
:
"https://storeapi.kobo.com/v1/products/{Id}/related"
,
"remaining_book_series"
:
"https://storeapi.kobo.com/v1/products/books/series/{SeriesId}"
,
"rename_tag"
:
"https://storeapi.kobo.com/v1/library/tags/{TagId}"
,
"review"
:
"https://storeapi.kobo.com/v1/products/reviews/{ReviewId}"
,
"review_sentiment"
:
"https://storeapi.kobo.com/v1/products/reviews/{ReviewId}/sentiment/{Sentiment}"
,
"shelfie_recommendations"
:
"https://storeapi.kobo.com/v1/user/recommendations/shelfie"
,
"sign_in_page"
:
"https://authorize.kobo.com/signin?returnUrl=http://store.kobobooks.com/"
,
"social_authorization_host"
:
"https://social.kobobooks.com:8443"
,
"social_host"
:
"https://social.kobobooks.com"
,
"stacks_host_productId"
:
"https://store.kobobooks.com/collections/byproductid/"
,
"store_home"
:
"www.kobo.com/{region}/{language}"
,
"store_host"
:
"store.kobobooks.com"
,
"store_newreleases"
:
"https://store.kobobooks.com/{culture}/List/new-releases/961XUjtsU0qxkFItWOutGA"
,
"store_search"
:
"https://store.kobobooks.com/{culture}/Search?Query={query}"
,
"store_top50"
:
"https://store.kobobooks.com/{culture}/ebooks/Top"
,
"tag_items"
:
"https://storeapi.kobo.com/v1/library/tags/{TagId}/Items"
,
"tags"
:
"https://storeapi.kobo.com/v1/library/tags"
,
"taste_profile"
:
"https://storeapi.kobo.com/v1/products/tasteprofile"
,
"update_accessibility_to_preview"
:
"https://storeapi.kobo.com/v1/library/{EntitlementIds}/preview"
,
"use_one_store"
:
"False"
,
"user_loyalty_benefits"
:
"https://storeapi.kobo.com/v1/user/loyalty/benefits"
,
"user_platform"
:
"https://storeapi.kobo.com/v1/user/platform"
,
"user_profile"
:
"https://storeapi.kobo.com/v1/user/profile"
,
"user_ratings"
:
"https://storeapi.kobo.com/v1/user/ratings"
,
"user_recommendations"
:
"https://storeapi.kobo.com/v1/user/recommendations"
,
"user_reviews"
:
"https://storeapi.kobo.com/v1/user/reviews"
,
"user_wishlist"
:
"https://storeapi.kobo.com/v1/user/wishlist"
,
"userguide_host"
:
"https://kbdownload1-a.akamaihd.net"
,
"wishlist_page"
:
"https://store.kobobooks.com/{region}/{language}/account/wishlist"
,
}
cps/reverseproxy.py
View file @
0955c6d6
...
@@ -60,10 +60,13 @@ class ReverseProxied(object):
...
@@ -60,10 +60,13 @@ class ReverseProxied(object):
def
__init__
(
self
,
application
):
def
__init__
(
self
,
application
):
self
.
app
=
application
self
.
app
=
application
self
.
proxied
=
False
def
__call__
(
self
,
environ
,
start_response
):
def
__call__
(
self
,
environ
,
start_response
):
self
.
proxied
=
False
script_name
=
environ
.
get
(
'HTTP_X_SCRIPT_NAME'
,
''
)
script_name
=
environ
.
get
(
'HTTP_X_SCRIPT_NAME'
,
''
)
if
script_name
:
if
script_name
:
self
.
proxied
=
True
environ
[
'SCRIPT_NAME'
]
=
script_name
environ
[
'SCRIPT_NAME'
]
=
script_name
path_info
=
environ
.
get
(
'PATH_INFO'
,
''
)
path_info
=
environ
.
get
(
'PATH_INFO'
,
''
)
if
path_info
and
path_info
.
startswith
(
script_name
):
if
path_info
and
path_info
.
startswith
(
script_name
):
...
@@ -76,3 +79,7 @@ class ReverseProxied(object):
...
@@ -76,3 +79,7 @@ class ReverseProxied(object):
if
servr
:
if
servr
:
environ
[
'HTTP_HOST'
]
=
servr
environ
[
'HTTP_HOST'
]
=
servr
return
self
.
app
(
environ
,
start_response
)
return
self
.
app
(
environ
,
start_response
)
@
property
def
is_proxied
(
self
):
return
self
.
proxied
cps/server.py
View file @
0955c6d6
...
@@ -24,7 +24,7 @@ import signal
...
@@ -24,7 +24,7 @@ import signal
import
socket
import
socket
try
:
try
:
from
gevent.pywsgi
import
WSGIServer
from
gevent.py
l
wsgi
import
WSGIServer
from
gevent.pool
import
Pool
from
gevent.pool
import
Pool
from
gevent
import
__version__
as
_version
from
gevent
import
__version__
as
_version
VERSION
=
'Gevent '
+
_version
VERSION
=
'Gevent '
+
_version
...
...
cps/templates/config_edit.html
View file @
0955c6d6
...
@@ -169,6 +169,18 @@
...
@@ -169,6 +169,18 @@
<input
type=
"checkbox"
id=
"config_remote_login"
name=
"config_remote_login"
{%
if
config
.
config_remote_login
%}
checked
{%
endif
%}
>
<input
type=
"checkbox"
id=
"config_remote_login"
name=
"config_remote_login"
{%
if
config
.
config_remote_login
%}
checked
{%
endif
%}
>
<label
for=
"config_remote_login"
>
{{_('Enable remote login ("magic link")')}}
</label>
<label
for=
"config_remote_login"
>
{{_('Enable remote login ("magic link")')}}
</label>
</div>
</div>
{% if feature_support['kobo'] %}
<div
class=
"form-group"
>
<input
type=
"checkbox"
id=
"config_kobo_sync"
name=
"config_kobo_sync"
data-control=
"kobo-settings"
{%
if
config
.
config_kobo_sync
%}
checked
{%
endif
%}
>
<label
for=
"config_kobo_sync"
>
{{_('Enable Kobo sync')}}
</label>
</div>
<div
data-related=
"kobo-settings"
>
<div
class=
"form-group"
>
<input
type=
"checkbox"
id=
"config_kobo_proxy"
name=
"config_kobo_proxy"
{%
if
config
.
config_kobo_proxy
%}
checked
{%
endif
%}
>
<label
for=
"config_kobo_proxy"
>
{{_('Proxy unknown requests to Kobo Store')}}
</label>
</div>
</div>
{% endif %}
{% if feature_support['goodreads'] %}
{% if feature_support['goodreads'] %}
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<input
type=
"checkbox"
id=
"config_use_goodreads"
name=
"config_use_goodreads"
data-control=
"goodreads-settings"
{%
if
config
.
config_use_goodreads
%}
checked
{%
endif
%}
>
<input
type=
"checkbox"
id=
"config_use_goodreads"
name=
"config_use_goodreads"
data-control=
"goodreads-settings"
{%
if
config
.
config_use_goodreads
%}
checked
{%
endif
%}
>
...
...
cps/ub.py
View file @
0955c6d6
...
@@ -464,7 +464,8 @@ def migrate_Database(session):
...
@@ -464,7 +464,8 @@ def migrate_Database(session):
def
clean_database
(
session
):
def
clean_database
(
session
):
# Remove expired remote login tokens
# Remove expired remote login tokens
now
=
datetime
.
datetime
.
now
()
now
=
datetime
.
datetime
.
now
()
session
.
query
(
RemoteAuthToken
)
.
filter
(
now
>
RemoteAuthToken
.
expiration
)
.
delete
()
session
.
query
(
RemoteAuthToken
)
.
filter
(
now
>
RemoteAuthToken
.
expiration
)
.
\
filter
(
RemoteAuthToken
.
token_type
!=
1
)
.
delete
()
session
.
commit
()
session
.
commit
()
...
...
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