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
1e40ffd1
Commit
1e40ffd1
authored
Mar 16, 2021
by
cbartondock
Browse files
Options
Browse Files
Download
Plain Diff
merge changes
parents
83474da7
53ee0aae
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
1135 additions
and
959 deletions
+1135
-959
admin.py
cps/admin.py
+119
-87
comic.py
cps/comic.py
+38
-32
config_sql.py
cps/config_sql.py
+7
-4
constants.py
cps/constants.py
+1
-1
db.py
cps/db.py
+10
-12
gdrive.py
cps/gdrive.py
+1
-1
helper.py
cps/helper.py
+56
-48
isoLanguages.py
cps/isoLanguages.py
+1
-1
kobo.py
cps/kobo.py
+2
-14
oauth.py
cps/oauth.py
+125
-129
oauth_bb.py
cps/oauth_bb.py
+4
-1
server.py
cps/server.py
+2
-2
SyncToken.py
cps/services/SyncToken.py
+3
-3
caliBlur_override.css
cps/static/css/caliBlur_override.css
+19
-17
kthoom.css
cps/static/css/kthoom.css
+2
-3
listen.css
cps/static/css/listen.css
+2
-9
main.css
cps/static/css/main.css
+206
-222
style.css
cps/static/css/style.css
+143
-82
caliBlur.js
cps/static/js/caliBlur.js
+1
-1
edit_books.js
cps/static/js/edit_books.js
+6
-6
filter_grid.js
cps/static/js/filter_grid.js
+5
-5
filter_list.js
cps/static/js/filter_list.js
+2
-2
get_meta.js
cps/static/js/get_meta.js
+4
-4
main.js
cps/static/js/main.js
+7
-7
table.js
cps/static/js/table.js
+13
-12
upload.py
cps/tasks/upload.py
+0
-1
ub.py
cps/ub.py
+71
-48
updater.py
cps/updater.py
+2
-1
usermanagement.py
cps/usermanagement.py
+1
-1
web.py
cps/web.py
+282
-203
No files found.
cps/admin.py
View file @
1e40ffd1
This diff is collapsed.
Click to expand it.
cps/comic.py
View file @
1e40ffd1
...
@@ -74,19 +74,8 @@ def _cover_processing(tmp_file_name, img, extension):
...
@@ -74,19 +74,8 @@ def _cover_processing(tmp_file_name, img, extension):
return
tmp_cover_name
return
tmp_cover_name
def
_extract_Cover_from_archive
(
original_file_extension
,
tmp_file_name
,
rarExecutable
):
def
_extractCover
(
tmp_file_name
,
original_file_extension
,
rarExecutable
):
cover_data
=
None
cover_data
=
extension
=
None
if
use_comic_meta
:
archive
=
ComicArchive
(
tmp_file_name
,
rar_exe_path
=
rarExecutable
)
for
index
,
name
in
enumerate
(
archive
.
getPageNameList
()):
ext
=
os
.
path
.
splitext
(
name
)
if
len
(
ext
)
>
1
:
extension
=
ext
[
1
]
.
lower
()
if
extension
in
COVER_EXTENSIONS
:
cover_data
=
archive
.
getPage
(
index
)
break
else
:
if
original_file_extension
.
upper
()
==
'.CBZ'
:
if
original_file_extension
.
upper
()
==
'.CBZ'
:
cf
=
zipfile
.
ZipFile
(
tmp_file_name
)
cf
=
zipfile
.
ZipFile
(
tmp_file_name
)
for
name
in
cf
.
namelist
():
for
name
in
cf
.
namelist
():
...
@@ -118,6 +107,22 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
...
@@ -118,6 +107,22 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
break
break
except
Exception
as
e
:
except
Exception
as
e
:
log
.
debug
(
'Rarfile failed with error:
%
s'
,
e
)
log
.
debug
(
'Rarfile failed with error:
%
s'
,
e
)
return
cover_data
def
_extractCover
(
tmp_file_name
,
original_file_extension
,
rarExecutable
):
cover_data
=
extension
=
None
if
use_comic_meta
:
archive
=
ComicArchive
(
tmp_file_name
,
rar_exe_path
=
rarExecutable
)
for
index
,
name
in
enumerate
(
archive
.
getPageNameList
()):
ext
=
os
.
path
.
splitext
(
name
)
if
len
(
ext
)
>
1
:
extension
=
ext
[
1
]
.
lower
()
if
extension
in
COVER_EXTENSIONS
:
cover_data
=
archive
.
getPage
(
index
)
break
else
:
cover_data
=
_extract_Cover_from_archive
(
original_file_extension
,
tmp_file_name
,
rarExecutable
)
return
_cover_processing
(
tmp_file_name
,
cover_data
,
extension
)
return
_cover_processing
(
tmp_file_name
,
cover_data
,
extension
)
...
@@ -142,7 +147,8 @@ def get_comic_info(tmp_file_path, original_file_name, original_file_extension, r
...
@@ -142,7 +147,8 @@ def get_comic_info(tmp_file_path, original_file_name, original_file_extension, r
file_path
=
tmp_file_path
,
file_path
=
tmp_file_path
,
extension
=
original_file_extension
,
extension
=
original_file_extension
,
title
=
loadedMetadata
.
title
or
original_file_name
,
title
=
loadedMetadata
.
title
or
original_file_name
,
author
=
" & "
.
join
([
credit
[
"person"
]
for
credit
in
loadedMetadata
.
credits
if
credit
[
"role"
]
==
"Writer"
])
or
u'Unknown'
,
author
=
" & "
.
join
([
credit
[
"person"
]
for
credit
in
loadedMetadata
.
credits
if
credit
[
"role"
]
==
"Writer"
])
or
u'Unknown'
,
cover
=
_extractCover
(
tmp_file_path
,
original_file_extension
,
rarExecutable
),
cover
=
_extractCover
(
tmp_file_path
,
original_file_extension
,
rarExecutable
),
description
=
loadedMetadata
.
comments
or
""
,
description
=
loadedMetadata
.
comments
or
""
,
tags
=
""
,
tags
=
""
,
...
...
cps/config_sql.py
View file @
1e40ffd1
...
@@ -146,15 +146,16 @@ class _ConfigSQL(object):
...
@@ -146,15 +146,16 @@ class _ConfigSQL(object):
self
.
load
()
self
.
load
()
change
=
False
change
=
False
if
self
.
config_converterpath
==
None
:
if
self
.
config_converterpath
==
None
:
# pylint: disable=access-member-before-definition
change
=
True
change
=
True
self
.
config_converterpath
=
autodetect_calibre_binary
()
self
.
config_converterpath
=
autodetect_calibre_binary
()
if
self
.
config_kepubifypath
==
None
:
if
self
.
config_kepubifypath
==
None
:
# pylint: disable=access-member-before-definition
change
=
True
change
=
True
self
.
config_kepubifypath
=
autodetect_kepubify_binary
()
self
.
config_kepubifypath
=
autodetect_kepubify_binary
()
if
self
.
config_rarfile_location
==
None
:
if
self
.
config_rarfile_location
==
None
:
# pylint: disable=access-member-before-definition
change
=
True
change
=
True
self
.
config_rarfile_location
=
autodetect_unrar_binary
()
self
.
config_rarfile_location
=
autodetect_unrar_binary
()
if
change
:
if
change
:
...
@@ -181,7 +182,8 @@ class _ConfigSQL(object):
...
@@ -181,7 +182,8 @@ class _ConfigSQL(object):
return
None
return
None
return
self
.
config_keyfile
return
self
.
config_keyfile
def
get_config_ipaddress
(
self
):
@
staticmethod
def
get_config_ipaddress
():
return
cli
.
ipadress
or
""
return
cli
.
ipadress
or
""
def
_has_role
(
self
,
role_flag
):
def
_has_role
(
self
,
role_flag
):
...
@@ -299,6 +301,7 @@ class _ConfigSQL(object):
...
@@ -299,6 +301,7 @@ class _ConfigSQL(object):
have_metadata_db
=
os
.
path
.
isfile
(
db_file
)
have_metadata_db
=
os
.
path
.
isfile
(
db_file
)
self
.
db_configured
=
have_metadata_db
self
.
db_configured
=
have_metadata_db
constants
.
EXTENSIONS_UPLOAD
=
[
x
.
lstrip
()
.
rstrip
()
.
lower
()
for
x
in
self
.
config_upload_formats
.
split
(
','
)]
constants
.
EXTENSIONS_UPLOAD
=
[
x
.
lstrip
()
.
rstrip
()
.
lower
()
for
x
in
self
.
config_upload_formats
.
split
(
','
)]
# pylint: disable=access-member-before-definition
logfile
=
logger
.
setup
(
self
.
config_logfile
,
self
.
config_log_level
)
logfile
=
logger
.
setup
(
self
.
config_logfile
,
self
.
config_log_level
)
if
logfile
!=
self
.
config_logfile
:
if
logfile
!=
self
.
config_logfile
:
log
.
warning
(
"Log path
%
s not valid, falling back to default"
,
self
.
config_logfile
)
log
.
warning
(
"Log path
%
s not valid, falling back to default"
,
self
.
config_logfile
)
...
...
cps/constants.py
View file @
1e40ffd1
...
@@ -104,7 +104,7 @@ LDAP_AUTH_SIMPLE = 0
...
@@ -104,7 +104,7 @@ LDAP_AUTH_SIMPLE = 0
DEFAULT_MAIL_SERVER
=
"mail.example.org"
DEFAULT_MAIL_SERVER
=
"mail.example.org"
DEFAULT_PASSWORD
=
"admin123"
DEFAULT_PASSWORD
=
"admin123"
# nosec # noqa
DEFAULT_PORT
=
8083
DEFAULT_PORT
=
8083
env_CALIBRE_PORT
=
os
.
environ
.
get
(
"CALIBRE_PORT"
,
DEFAULT_PORT
)
env_CALIBRE_PORT
=
os
.
environ
.
get
(
"CALIBRE_PORT"
,
DEFAULT_PORT
)
try
:
try
:
...
...
cps/db.py
View file @
1e40ffd1
...
@@ -156,10 +156,8 @@ class Identifiers(Base):
...
@@ -156,10 +156,8 @@ class Identifiers(Base):
return
u"https://portal.issn.org/resource/ISSN/{0}"
.
format
(
self
.
val
)
return
u"https://portal.issn.org/resource/ISSN/{0}"
.
format
(
self
.
val
)
elif
format_type
==
"isfdb"
:
elif
format_type
==
"isfdb"
:
return
u"http://www.isfdb.org/cgi-bin/pl.cgi?{0}"
.
format
(
self
.
val
)
return
u"http://www.isfdb.org/cgi-bin/pl.cgi?{0}"
.
format
(
self
.
val
)
elif
format_type
==
"url"
:
return
u"{0}"
.
format
(
self
.
val
)
else
:
else
:
return
u"
"
return
u"
{0}"
.
format
(
self
.
val
)
class
Comments
(
Base
):
class
Comments
(
Base
):
...
@@ -386,14 +384,14 @@ class Custom_Columns(Base):
...
@@ -386,14 +384,14 @@ class Custom_Columns(Base):
class
AlchemyEncoder
(
json
.
JSONEncoder
):
class
AlchemyEncoder
(
json
.
JSONEncoder
):
def
default
(
self
,
o
bj
):
def
default
(
self
,
o
):
if
isinstance
(
o
bj
.
__class__
,
DeclarativeMeta
):
if
isinstance
(
o
.
__class__
,
DeclarativeMeta
):
# an SQLAlchemy class
# an SQLAlchemy class
fields
=
{}
fields
=
{}
for
field
in
[
x
for
x
in
dir
(
o
bj
)
if
not
x
.
startswith
(
'_'
)
and
x
!=
'metadata'
]:
for
field
in
[
x
for
x
in
dir
(
o
)
if
not
x
.
startswith
(
'_'
)
and
x
!=
'metadata'
]:
if
field
==
'books'
:
if
field
==
'books'
:
continue
continue
data
=
o
bj
.
__getattribute__
(
field
)
data
=
o
.
__getattribute__
(
field
)
try
:
try
:
if
isinstance
(
data
,
str
):
if
isinstance
(
data
,
str
):
data
=
data
.
replace
(
"'"
,
"
\'
"
)
data
=
data
.
replace
(
"'"
,
"
\'
"
)
...
@@ -413,12 +411,12 @@ class AlchemyEncoder(json.JSONEncoder):
...
@@ -413,12 +411,12 @@ class AlchemyEncoder(json.JSONEncoder):
else
:
else
:
json
.
dumps
(
data
)
json
.
dumps
(
data
)
fields
[
field
]
=
data
fields
[
field
]
=
data
except
:
except
Exception
:
fields
[
field
]
=
""
fields
[
field
]
=
""
# a json-encodable dict
# a json-encodable dict
return
fields
return
fields
return
json
.
JSONEncoder
.
default
(
self
,
o
bj
)
return
json
.
JSONEncoder
.
default
(
self
,
o
)
class
CalibreDB
():
class
CalibreDB
():
...
@@ -565,8 +563,8 @@ class CalibreDB():
...
@@ -565,8 +563,8 @@ class CalibreDB():
def
get_book_by_uuid
(
self
,
book_uuid
):
def
get_book_by_uuid
(
self
,
book_uuid
):
return
self
.
session
.
query
(
Books
)
.
filter
(
Books
.
uuid
==
book_uuid
)
.
first
()
return
self
.
session
.
query
(
Books
)
.
filter
(
Books
.
uuid
==
book_uuid
)
.
first
()
def
get_book_format
(
self
,
book_id
,
format
):
def
get_book_format
(
self
,
book_id
,
f
ile_f
ormat
):
return
self
.
session
.
query
(
Data
)
.
filter
(
Data
.
book
==
book_id
)
.
filter
(
Data
.
format
==
format
)
.
first
()
return
self
.
session
.
query
(
Data
)
.
filter
(
Data
.
book
==
book_id
)
.
filter
(
Data
.
format
==
f
ile_f
ormat
)
.
first
()
# Language and content filters for displaying in the UI
# Language and content filters for displaying in the UI
def
common_filters
(
self
,
allow_show_archived
=
False
):
def
common_filters
(
self
,
allow_show_archived
=
False
):
...
@@ -744,7 +742,7 @@ class CalibreDB():
...
@@ -744,7 +742,7 @@ class CalibreDB():
if
old_session
:
if
old_session
:
try
:
try
:
old_session
.
close
()
old_session
.
close
()
except
:
except
Exception
:
pass
pass
if
old_session
.
bind
:
if
old_session
.
bind
:
try
:
try
:
...
...
cps/gdrive.py
View file @
1e40ffd1
...
@@ -47,7 +47,7 @@ except ImportError as err:
...
@@ -47,7 +47,7 @@ except ImportError as err:
current_milli_time
=
lambda
:
int
(
round
(
time
()
*
1000
))
current_milli_time
=
lambda
:
int
(
round
(
time
()
*
1000
))
gdrive_watch_callback_token
=
'target=calibreweb-watch_files'
gdrive_watch_callback_token
=
'target=calibreweb-watch_files'
#nosec
@
gdrive
.
route
(
"/authenticate"
)
@
gdrive
.
route
(
"/authenticate"
)
...
...
cps/helper.py
View file @
1e40ffd1
...
@@ -134,17 +134,11 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False):
...
@@ -134,17 +134,11 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False):
taskMessage
=
_
(
u"Registration e-mail for user:
%(name)
s"
,
name
=
user_name
),
taskMessage
=
_
(
u"Registration e-mail for user:
%(name)
s"
,
name
=
user_name
),
text
=
txt
text
=
txt
))
))
return
return
def
check_send_to_kindle
(
entry
):
def
check_send_to_kindle_without_converter
(
entry
):
"""
returns all available book formats for sending to Kindle
"""
if
len
(
entry
.
data
):
bookformats
=
list
()
bookformats
=
list
()
if
not
config
.
config_converterpath
:
# no converter - only for mobi and pdf formats
# no converter - only for mobi and pdf formats
for
ele
in
iter
(
entry
.
data
):
for
ele
in
iter
(
entry
.
data
):
if
ele
.
uncompressed_size
<
config
.
mail_size
:
if
ele
.
uncompressed_size
<
config
.
mail_size
:
...
@@ -160,7 +154,10 @@ def check_send_to_kindle(entry):
...
@@ -160,7 +154,10 @@ def check_send_to_kindle(entry):
bookformats
.
append
({
'format'
:
'Azw'
,
bookformats
.
append
({
'format'
:
'Azw'
,
'convert'
:
0
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Azw'
)})
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Azw'
)})
else
:
return
bookformats
def
check_send_to_kindle_with_converter
(
entry
):
bookformats
=
list
()
formats
=
list
()
formats
=
list
()
for
ele
in
iter
(
entry
.
data
):
for
ele
in
iter
(
entry
.
data
):
if
ele
.
uncompressed_size
<
config
.
mail_size
:
if
ele
.
uncompressed_size
<
config
.
mail_size
:
...
@@ -177,10 +174,9 @@ def check_send_to_kindle(entry):
...
@@ -177,10 +174,9 @@ def check_send_to_kindle(entry):
bookformats
.
append
({
'format'
:
'Pdf'
,
bookformats
.
append
({
'format'
:
'Pdf'
,
'convert'
:
0
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Pdf'
)})
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Pdf'
)})
if
config
.
config_converterpath
:
if
'EPUB'
in
formats
and
'MOBI'
not
in
formats
:
if
'EPUB'
in
formats
and
'MOBI'
not
in
formats
:
bookformats
.
append
({
'format'
:
'Mobi'
,
bookformats
.
append
({
'format'
:
'Mobi'
,
'convert'
:
1
,
'convert'
:
1
,
'text'
:
_
(
'Convert
%(orig)
s to
%(format)
s and send to Kindle'
,
'text'
:
_
(
'Convert
%(orig)
s to
%(format)
s and send to Kindle'
,
orig
=
'Epub'
,
orig
=
'Epub'
,
format
=
'Mobi'
)})
format
=
'Mobi'
)})
...
@@ -191,6 +187,18 @@ def check_send_to_kindle(entry):
...
@@ -191,6 +187,18 @@ def check_send_to_kindle(entry):
orig
=
'Azw3'
,
orig
=
'Azw3'
,
format
=
'Mobi'
)})
format
=
'Mobi'
)})
return
bookformats
return
bookformats
def
check_send_to_kindle
(
entry
):
"""
returns all available book formats for sending to Kindle
"""
if
len
(
entry
.
data
):
if
not
config
.
config_converterpath
:
book_formats
=
check_send_to_kindle_with_converter
(
entry
)
else
:
book_formats
=
check_send_to_kindle_with_converter
(
entry
)
return
book_formats
else
:
else
:
log
.
error
(
u'Cannot find book entry
%
d'
,
entry
.
id
)
log
.
error
(
u'Cannot find book entry
%
d'
,
entry
.
id
)
return
None
return
None
...
@@ -742,7 +750,7 @@ def format_runtime(runtime):
...
@@ -742,7 +750,7 @@ def format_runtime(runtime):
# helper function to apply localize status information in tasklist entries
# helper function to apply localize status information in tasklist entries
def
render_task_status
(
tasklist
):
def
render_task_status
(
tasklist
):
renderedtasklist
=
list
()
renderedtasklist
=
list
()
for
num
,
user
,
added
,
task
in
tasklist
:
for
__
,
user
,
added
,
task
in
tasklist
:
if
user
==
current_user
.
nickname
or
current_user
.
role_admin
():
if
user
==
current_user
.
nickname
or
current_user
.
role_admin
():
ret
=
{}
ret
=
{}
if
task
.
start_time
:
if
task
.
start_time
:
...
...
cps/isoLanguages.py
View file @
1e40ffd1
...
@@ -71,7 +71,7 @@ def get_valid_language_codes(locale, language_names, remainder=None):
...
@@ -71,7 +71,7 @@ def get_valid_language_codes(locale, language_names, remainder=None):
languages
=
list
()
languages
=
list
()
if
""
in
language_names
:
if
""
in
language_names
:
language_names
.
remove
(
""
)
language_names
.
remove
(
""
)
for
k
,
v
in
get_language_names
(
locale
)
.
items
():
for
k
,
__
in
get_language_names
(
locale
)
.
items
():
if
k
in
language_names
:
if
k
in
language_names
:
languages
.
append
(
k
)
languages
.
append
(
k
)
language_names
.
remove
(
k
)
language_names
.
remove
(
k
)
...
...
cps/kobo.py
View file @
1e40ffd1
...
@@ -42,8 +42,7 @@ from flask import (
...
@@ -42,8 +42,7 @@ from flask import (
from
flask_login
import
current_user
from
flask_login
import
current_user
from
werkzeug.datastructures
import
Headers
from
werkzeug.datastructures
import
Headers
from
sqlalchemy
import
func
from
sqlalchemy
import
func
from
sqlalchemy.sql.expression
import
and_
,
or_
from
sqlalchemy.sql.expression
import
and_
from
sqlalchemy.orm
import
load_only
from
sqlalchemy.exc
import
StatementError
from
sqlalchemy.exc
import
StatementError
import
requests
import
requests
...
@@ -893,17 +892,6 @@ def HandleProductsRequest(dummy=None):
...
@@ -893,17 +892,6 @@ def HandleProductsRequest(dummy=None):
return
redirect_or_proxy_request
()
return
redirect_or_proxy_request
()
'''@kobo.errorhandler(404)
def handle_404(err):
# 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)
if err:
print('404')
return jsonify(error=str(err)), 404
log.debug("Unknown Request received:
%
s, method:
%
s, data:
%
s", request.base_url, request.method, request.data)
return redirect_or_proxy_request()'''
def
make_calibre_web_auth_response
():
def
make_calibre_web_auth_response
():
# As described in kobo_auth.py, CalibreWeb doesn't make use practical use of this auth/device API call for
# As described in kobo_auth.py, CalibreWeb doesn't make use practical use of this auth/device API call for
# authentation (nor for authorization). We return a dummy response just to keep the device happy.
# authentation (nor for authorization). We return a dummy response just to keep the device happy.
...
@@ -947,7 +935,7 @@ def HandleInitRequest():
...
@@ -947,7 +935,7 @@ 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"
]
except
:
except
Exception
:
log
.
error
(
"Failed to receive or parse response from Kobo's init endpoint. Falling back to un-proxied mode."
)
log
.
error
(
"Failed to receive or parse response from Kobo's init endpoint. Falling back to un-proxied mode."
)
if
not
kobo_resources
:
if
not
kobo_resources
:
kobo_resources
=
NATIVE_KOBO_RESOURCES
()
kobo_resources
=
NATIVE_KOBO_RESOURCES
()
...
...
cps/oauth.py
View file @
1e40ffd1
...
@@ -19,7 +19,6 @@
...
@@ -19,7 +19,6 @@
from
__future__
import
division
,
print_function
,
unicode_literals
from
__future__
import
division
,
print_function
,
unicode_literals
from
flask
import
session
from
flask
import
session
try
:
try
:
from
flask_dance.consumer.backend.sqla
import
SQLAlchemyBackend
,
first
,
_get_real_user
from
flask_dance.consumer.backend.sqla
import
SQLAlchemyBackend
,
first
,
_get_real_user
from
sqlalchemy.orm.exc
import
NoResultFound
from
sqlalchemy.orm.exc
import
NoResultFound
...
@@ -34,8 +33,8 @@ except ImportError:
...
@@ -34,8 +33,8 @@ except ImportError:
except
ImportError
:
except
ImportError
:
pass
pass
try
:
class
OAuthBackend
(
SQLAlchemyBackend
):
class
OAuthBackend
(
SQLAlchemyBackend
):
"""
"""
Stores and retrieves OAuth tokens using a relational database through
Stores and retrieves OAuth tokens using a relational database through
the `SQLAlchemy`_ ORM.
the `SQLAlchemy`_ ORM.
...
@@ -162,6 +161,3 @@ try:
...
@@ -162,6 +161,3 @@ try:
self
.
cache
.
delete
(
self
.
make_cache_key
(
self
.
cache
.
delete
(
self
.
make_cache_key
(
blueprint
=
blueprint
,
user
=
user
,
user_id
=
user_id
,
blueprint
=
blueprint
,
user
=
user
,
user_id
=
user_id
,
))
))
except
Exception
:
pass
cps/oauth_bb.py
View file @
1e40ffd1
...
@@ -35,7 +35,10 @@ from sqlalchemy.orm.exc import NoResultFound
...
@@ -35,7 +35,10 @@ from sqlalchemy.orm.exc import NoResultFound
from
.
import
constants
,
logger
,
config
,
app
,
ub
from
.
import
constants
,
logger
,
config
,
app
,
ub
from
.oauth
import
OAuthBackend
,
backend_resultcode
try
:
from
.oauth
import
OAuthBackend
,
backend_resultcode
except
NameError
:
pass
oauth_check
=
{}
oauth_check
=
{}
...
...
cps/server.py
View file @
1e40ffd1
...
@@ -137,8 +137,8 @@ class WebServer(object):
...
@@ -137,8 +137,8 @@ class WebServer(object):
return
sock
,
_readable_listen_address
(
*
address
)
return
sock
,
_readable_listen_address
(
*
address
)
@
staticmethod
def
_get_args_for_reloading
(
self
):
def
_get_args_for_reloading
():
"""Determine how the script was executed, and return the args needed
"""Determine how the script was executed, and return the args needed
to execute it again in a new process.
to execute it again in a new process.
Code from https://github.com/pyload/pyload. Author GammaC0de, voulter
Code from https://github.com/pyload/pyload. Author GammaC0de, voulter
...
...
cps/services/SyncToken.py
View file @
1e40ffd1
...
@@ -64,7 +64,7 @@ class SyncToken:
...
@@ -64,7 +64,7 @@ class SyncToken:
books_last_modified: Datetime representing the last modified book that the device knows about.
books_last_modified: Datetime representing the last modified book that the device knows about.
"""
"""
SYNC_TOKEN_HEADER
=
"x-kobo-synctoken"
SYNC_TOKEN_HEADER
=
"x-kobo-synctoken"
# nosec
VERSION
=
"1-1-0"
VERSION
=
"1-1-0"
LAST_MODIFIED_ADDED_VERSION
=
"1-1-0"
LAST_MODIFIED_ADDED_VERSION
=
"1-1-0"
MIN_VERSION
=
"1-0-0"
MIN_VERSION
=
"1-0-0"
...
@@ -91,7 +91,7 @@ class SyncToken:
...
@@ -91,7 +91,7 @@ class SyncToken:
def
__init__
(
def
__init__
(
self
,
self
,
raw_kobo_store_token
=
""
,
raw_kobo_store_token
=
""
,
# nosec
books_last_created
=
datetime
.
min
,
books_last_created
=
datetime
.
min
,
books_last_modified
=
datetime
.
min
,
books_last_modified
=
datetime
.
min
,
archive_last_modified
=
datetime
.
min
,
archive_last_modified
=
datetime
.
min
,
...
@@ -110,7 +110,7 @@ class SyncToken:
...
@@ -110,7 +110,7 @@ class SyncToken:
@
staticmethod
@
staticmethod
def
from_headers
(
headers
):
def
from_headers
(
headers
):
sync_token_header
=
headers
.
get
(
SyncToken
.
SYNC_TOKEN_HEADER
,
""
)
sync_token_header
=
headers
.
get
(
SyncToken
.
SYNC_TOKEN_HEADER
,
""
)
if
sync_token_header
==
""
:
if
sync_token_header
==
""
:
# nosec
return
SyncToken
()
return
SyncToken
()
# On the first sync from a Kobo device, we may receive the SyncToken
# On the first sync from a Kobo device, we may receive the SyncToken
...
...
cps/static/css/caliBlur_override.css
View file @
1e40ffd1
body
.serieslist.grid-view
div
.container-fluid
>
div
>
div
.col-sm-10
:before
{
body
.serieslist.grid-view
div
.container-fluid
>
div
>
div
.col-sm-10
::before
{
display
:
none
;
display
:
none
;
}
}
.cover
.badge
{
.cover
.badge
{
position
:
absolute
;
position
:
absolute
;
top
:
0
;
top
:
0
;
left
:
0
;
left
:
0
;
...
@@ -9,14 +10,15 @@ body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{
...
@@ -9,14 +10,15 @@ body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{
background-color
:
#cc7b19
;
background-color
:
#cc7b19
;
border-radius
:
0
;
border-radius
:
0
;
padding
:
0
8px
;
padding
:
0
8px
;
box-shadow
:
0
0
4px
rgba
(
0
,
0
,
0
,
.6
);
box-shadow
:
0
0
4px
rgba
(
0
,
0
,
0
,
0
.6
);
line-height
:
24px
;
line-height
:
24px
;
}
}
.cover
{
box-shadow
:
0
0
4px
rgba
(
0
,
0
,
0
,
.6
);
.cover
{
box-shadow
:
0
0
4px
rgba
(
0
,
0
,
0
,
0.6
);
}
}
.cover
.read
{
.cover
.read
{
padding
:
0
0px
;
padding
:
0
0
;
line-height
:
15px
;
line-height
:
15px
;
}
}
cps/static/css/kthoom.css
View file @
1e40ffd1
...
@@ -33,7 +33,6 @@ body {
...
@@ -33,7 +33,6 @@ body {
position
:
relative
;
position
:
relative
;
cursor
:
pointer
;
cursor
:
pointer
;
padding
:
4px
;
padding
:
4px
;
transition
:
all
0.2s
ease
;
transition
:
all
0.2s
ease
;
}
}
...
@@ -45,7 +44,7 @@ body {
...
@@ -45,7 +44,7 @@ body {
#sidebar
a
.active
,
#sidebar
a
.active
,
#sidebar
a
.active
img
+
span
{
#sidebar
a
.active
img
+
span
{
background-color
:
#45
B29D
;
background-color
:
#45
b29d
;
}
}
#sidebar
li
img
{
#sidebar
li
img
{
...
...
cps/static/css/listen.css
View file @
1e40ffd1
...
@@ -66,19 +66,12 @@ body {
...
@@ -66,19 +66,12 @@ body {
right
:
40px
;
right
:
40px
;
}
}
xmp
,
pre
{
pre
,
plaintext
{
display
:
block
;
display
:
block
;
font-family
:
-moz-fixed
;
white-space
:
pre
;
margin
:
1em
0
;
margin
:
1em
0
;
}
pre
{
white-space
:
pre-wrap
;
white-space
:
pre-wrap
;
word-wrap
:
break-word
;
word-wrap
:
break-word
;
font-family
:
-moz-fixed
;
font-family
:
-moz-fixed
,
sans-serif
;
column-count
:
2
;
column-count
:
2
;
-webkit-columns
:
2
;
-webkit-columns
:
2
;
-moz-columns
:
2
;
-moz-columns
:
2
;
...
...
cps/static/css/main.css
View file @
1e40ffd1
This diff is collapsed.
Click to expand it.
cps/static/css/style.css
View file @
1e40ffd1
This diff is collapsed.
Click to expand it.
cps/static/js/caliBlur.js
View file @
1e40ffd1
...
@@ -710,7 +710,7 @@ $(".navbar-collapse.collapse.in").before('<div class="sidebar-backdrop"></div>')
...
@@ -710,7 +710,7 @@ $(".navbar-collapse.collapse.in").before('<div class="sidebar-backdrop"></div>')
// Get rid of leading white space
// Get rid of leading white space
recentlyAdded
=
$
(
"#nav_new a:contains('Recently')"
).
text
().
trim
();
recentlyAdded
=
$
(
"#nav_new a:contains('Recently')"
).
text
().
trim
();
$
(
"#nav_new a:contains('Recently')"
).
contents
().
filter
(
function
()
{
$
(
"#nav_new a:contains('Recently')"
).
contents
().
filter
(
function
()
{
return
this
.
nodeType
==
3
return
this
.
nodeType
==
=
3
}).
each
(
function
()
{
}).
each
(
function
()
{
this
.
textContent
=
this
.
textContent
.
replace
(
" Recently Added"
,
recentlyAdded
);
this
.
textContent
=
this
.
textContent
.
replace
(
" Recently Added"
,
recentlyAdded
);
});
});
...
...
cps/static/js/edit_books.js
View file @
1e40ffd1
/**
/**
* Created by SpeedProg on 05.04.2015.
* Created by SpeedProg on 05.04.2015.
*/
*/
/* global Bloodhound, language, Modernizr, tinymce */
/* global Bloodhound, language, Modernizr, tinymce
, getPath
*/
if
(
$
(
"#description"
).
length
)
{
if
(
$
(
"#description"
).
length
)
{
tinymce
.
init
({
tinymce
.
init
({
...
@@ -250,14 +250,14 @@ promisePublishers.done(function() {
...
@@ -250,14 +250,14 @@ promisePublishers.done(function() {
});
});
$
(
"#search"
).
on
(
"change input.typeahead:selected"
,
function
(
event
)
{
$
(
"#search"
).
on
(
"change input.typeahead:selected"
,
function
(
event
)
{
if
(
event
.
target
.
type
==
"search"
&&
event
.
target
.
tagName
==
"INPUT"
)
{
if
(
event
.
target
.
type
==
=
"search"
&&
event
.
target
.
tagName
=
==
"INPUT"
)
{
return
;
return
;
}
}
var
form
=
$
(
"form"
).
serialize
();
var
form
=
$
(
"form"
).
serialize
();
$
.
getJSON
(
getPath
()
+
"/get_matching_tags"
,
form
,
function
(
data
)
{
$
.
getJSON
(
getPath
()
+
"/get_matching_tags"
,
form
,
function
(
data
)
{
$
(
".tags_click"
).
each
(
function
()
{
$
(
".tags_click"
).
each
(
function
()
{
if
(
$
.
inArray
(
parseInt
(
$
(
this
).
val
(),
10
),
data
.
tags
)
===
-
1
)
{
if
(
$
.
inArray
(
parseInt
(
$
(
this
).
val
(),
10
),
data
.
tags
)
===
-
1
)
{
if
(
!
$
(
this
).
prop
(
"selected"
))
{
if
(
!
$
(
this
).
prop
(
"selected"
))
{
$
(
this
).
prop
(
"disabled"
,
true
);
$
(
this
).
prop
(
"disabled"
,
true
);
}
}
}
else
{
}
else
{
...
@@ -265,10 +265,10 @@ $("#search").on("change input.typeahead:selected", function(event) {
...
@@ -265,10 +265,10 @@ $("#search").on("change input.typeahead:selected", function(event) {
}
}
});
});
$
(
"#include_tag option:selected"
).
each
(
function
()
{
$
(
"#include_tag option:selected"
).
each
(
function
()
{
$
(
"#exclude_tag"
).
find
(
"[value="
+
$
(
this
).
val
()
+
"]"
).
prop
(
"disabled"
,
true
);
$
(
"#exclude_tag"
).
find
(
"[value="
+
$
(
this
).
val
()
+
"]"
).
prop
(
"disabled"
,
true
);
});
});
$
(
'#include_tag'
).
selectpicker
(
"refresh"
);
$
(
"#include_tag"
).
selectpicker
(
"refresh"
);
$
(
'#exclude_tag'
).
selectpicker
(
"refresh"
);
$
(
"#exclude_tag"
).
selectpicker
(
"refresh"
);
});
});
});
});
...
...
cps/static/js/filter_grid.js
View file @
1e40ffd1
...
@@ -36,7 +36,6 @@ $("#desc").click(function() {
...
@@ -36,7 +36,6 @@ $("#desc").click(function() {
sortBy
:
"name"
,
sortBy
:
"name"
,
sortAscending
:
true
sortAscending
:
true
});
});
return
;
});
});
$
(
"#asc"
).
click
(
function
()
{
$
(
"#asc"
).
click
(
function
()
{
...
@@ -52,19 +51,20 @@ $("#asc").click(function() {
...
@@ -52,19 +51,20 @@ $("#asc").click(function() {
sortBy
:
"name"
,
sortBy
:
"name"
,
sortAscending
:
false
sortAscending
:
false
});
});
return
;
});
});
$
(
"#all"
).
click
(
function
()
{
$
(
"#all"
).
click
(
function
()
{
// go through all elements and make them visible
// go through all elements and make them visible
$list
.
isotope
({
filter
:
function
()
{
$list
.
isotope
({
filter
:
function
()
{
return
true
;
return
true
;
}
})
}
});
});
});
$
(
".char"
).
click
(
function
()
{
$
(
".char"
).
click
(
function
()
{
var
character
=
this
.
innerText
;
var
character
=
this
.
innerText
;
$list
.
isotope
({
filter
:
function
()
{
$list
.
isotope
({
filter
:
function
()
{
return
this
.
attributes
[
"data-id"
].
value
.
charAt
(
0
).
toUpperCase
()
==
character
;
return
this
.
attributes
[
"data-id"
].
value
.
charAt
(
0
).
toUpperCase
()
===
character
;
}
})
}
});
});
});
cps/static/js/filter_list.js
View file @
1e40ffd1
...
@@ -88,7 +88,7 @@ $("#desc").click(function() {
...
@@ -88,7 +88,7 @@ $("#desc").click(function() {
// Find count of middle element
// Find count of middle element
var
count
=
$
(
".row:visible"
).
length
;
var
count
=
$
(
".row:visible"
).
length
;
if
(
count
>
20
)
{
if
(
count
>
20
)
{
middle
=
parseInt
(
count
/
2
)
+
(
count
%
2
);
middle
=
parseInt
(
count
/
2
,
10
)
+
(
count
%
2
);
//var middle = parseInt(count / 2) + (count % 2);
//var middle = parseInt(count / 2) + (count % 2);
// search for the middle of all visible elements
// search for the middle of all visible elements
...
@@ -135,7 +135,7 @@ $("#asc").click(function() {
...
@@ -135,7 +135,7 @@ $("#asc").click(function() {
// Find count of middle element
// Find count of middle element
var
count
=
$
(
".row:visible"
).
length
;
var
count
=
$
(
".row:visible"
).
length
;
if
(
count
>
20
)
{
if
(
count
>
20
)
{
var
middle
=
parseInt
(
count
/
2
)
+
(
count
%
2
);
var
middle
=
parseInt
(
count
/
2
,
10
)
+
(
count
%
2
);
//var middle = parseInt(count / 2) + (count % 2);
//var middle = parseInt(count / 2) + (count % 2);
// search for the middle of all visible elements
// search for the middle of all visible elements
...
...
cps/static/js/get_meta.js
View file @
1e40ffd1
...
@@ -138,8 +138,8 @@ $(function () {
...
@@ -138,8 +138,8 @@ $(function () {
seriesTitle
=
result
.
series
.
title
;
seriesTitle
=
result
.
series
.
title
;
}
}
var
dateFomers
=
result
.
pubdate
.
split
(
"-"
);
var
dateFomers
=
result
.
pubdate
.
split
(
"-"
);
var
publishedYear
=
parseInt
(
dateFomers
[
0
]);
var
publishedYear
=
parseInt
(
dateFomers
[
0
]
,
10
);
var
publishedMonth
=
parseInt
(
dateFomers
[
1
]);
var
publishedMonth
=
parseInt
(
dateFomers
[
1
]
,
10
);
var
publishedDate
=
new
Date
(
publishedYear
,
publishedMonth
-
1
,
1
);
var
publishedDate
=
new
Date
(
publishedYear
,
publishedMonth
-
1
,
1
);
publishedDate
=
formatDate
(
publishedDate
);
publishedDate
=
formatDate
(
publishedDate
);
...
@@ -194,8 +194,8 @@ $(function () {
...
@@ -194,8 +194,8 @@ $(function () {
}
else
{
}
else
{
dateFomers
=
result
.
date_added
.
split
(
"-"
);
dateFomers
=
result
.
date_added
.
split
(
"-"
);
}
}
var
publishedYear
=
parseInt
(
dateFomers
[
0
]);
var
publishedYear
=
parseInt
(
dateFomers
[
0
]
,
10
);
var
publishedMonth
=
parseInt
(
dateFomers
[
1
]);
var
publishedMonth
=
parseInt
(
dateFomers
[
1
]
,
10
);
var
publishedDate
=
new
Date
(
publishedYear
,
publishedMonth
-
1
,
1
);
var
publishedDate
=
new
Date
(
publishedYear
,
publishedMonth
-
1
,
1
);
publishedDate
=
formatDate
(
publishedDate
);
publishedDate
=
formatDate
(
publishedDate
);
...
...
cps/static/js/main.js
View file @
1e40ffd1
...
@@ -38,10 +38,10 @@ $(document).on("change", "input[type=\"checkbox\"][data-control]", function () {
...
@@ -38,10 +38,10 @@ $(document).on("change", "input[type=\"checkbox\"][data-control]", function () {
$
(
document
).
on
(
"change"
,
"select[data-control]"
,
function
()
{
$
(
document
).
on
(
"change"
,
"select[data-control]"
,
function
()
{
var
$this
=
$
(
this
);
var
$this
=
$
(
this
);
var
name
=
$this
.
data
(
"control"
);
var
name
=
$this
.
data
(
"control"
);
var
showOrHide
=
parseInt
(
$this
.
val
());
var
showOrHide
=
parseInt
(
$this
.
val
()
,
10
);
// var showOrHideLast = $("#" + name + " option:last").val()
// var showOrHideLast = $("#" + name + " option:last").val()
for
(
var
i
=
0
;
i
<
$
(
this
)[
0
].
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
$
(
this
)[
0
].
length
;
i
++
)
{
var
element
=
parseInt
(
$
(
this
)[
0
][
i
].
value
);
var
element
=
parseInt
(
$
(
this
)[
0
][
i
].
value
,
10
);
if
(
element
===
showOrHide
)
{
if
(
element
===
showOrHide
)
{
$
(
"[data-related^="
+
name
+
"][data-related*=-"
+
element
+
"]"
).
show
();
$
(
"[data-related^="
+
name
+
"][data-related*=-"
+
element
+
"]"
).
show
();
}
else
{
}
else
{
...
@@ -55,7 +55,7 @@ $(document).on("change", "select[data-control]", function() {
...
@@ -55,7 +55,7 @@ $(document).on("change", "select[data-control]", function() {
$
(
document
).
on
(
"change"
,
"select[data-controlall]"
,
function
()
{
$
(
document
).
on
(
"change"
,
"select[data-controlall]"
,
function
()
{
var
$this
=
$
(
this
);
var
$this
=
$
(
this
);
var
name
=
$this
.
data
(
"controlall"
);
var
name
=
$this
.
data
(
"controlall"
);
var
showOrHide
=
parseInt
(
$this
.
val
());
var
showOrHide
=
parseInt
(
$this
.
val
()
,
10
);
if
(
showOrHide
)
{
if
(
showOrHide
)
{
$
(
"[data-related="
+
name
+
"]"
).
show
();
$
(
"[data-related="
+
name
+
"]"
).
show
();
}
else
{
}
else
{
...
@@ -114,7 +114,7 @@ $(document).ready(function() {
...
@@ -114,7 +114,7 @@ $(document).ready(function() {
}
}
});
});
function
C
onfirmDialog
(
id
,
dataValue
,
yesFn
,
noFn
)
{
function
c
onfirmDialog
(
id
,
dataValue
,
yesFn
,
noFn
)
{
var
$confirm
=
$
(
"#GeneralDeleteModal"
);
var
$confirm
=
$
(
"#GeneralDeleteModal"
);
// var dataValue= e.data('value'); // target.data('value');
// var dataValue= e.data('value'); // target.data('value');
$confirm
.
modal
(
'show'
);
$confirm
.
modal
(
'show'
);
...
@@ -481,7 +481,7 @@ $(function() {
...
@@ -481,7 +481,7 @@ $(function() {
});
});
$
(
"#config_delete_kobo_token"
).
click
(
function
()
{
$
(
"#config_delete_kobo_token"
).
click
(
function
()
{
C
onfirmDialog
(
c
onfirmDialog
(
$
(
this
).
attr
(
'id'
),
$
(
this
).
attr
(
'id'
),
$
(
this
).
data
(
'value'
),
$
(
this
).
data
(
'value'
),
function
(
value
)
{
function
(
value
)
{
...
@@ -509,7 +509,7 @@ $(function() {
...
@@ -509,7 +509,7 @@ $(function() {
});
});
$
(
"#btndeluser"
).
click
(
function
()
{
$
(
"#btndeluser"
).
click
(
function
()
{
C
onfirmDialog
(
c
onfirmDialog
(
$
(
this
).
attr
(
'id'
),
$
(
this
).
attr
(
'id'
),
$
(
this
).
data
(
'value'
),
$
(
this
).
data
(
'value'
),
function
(
value
){
function
(
value
){
...
@@ -527,7 +527,7 @@ $(function() {
...
@@ -527,7 +527,7 @@ $(function() {
});
});
$
(
"#delete_shelf"
).
click
(
function
()
{
$
(
"#delete_shelf"
).
click
(
function
()
{
C
onfirmDialog
(
c
onfirmDialog
(
$
(
this
).
attr
(
'id'
),
$
(
this
).
attr
(
'id'
),
$
(
this
).
data
(
'value'
),
$
(
this
).
data
(
'value'
),
function
(
value
){
function
(
value
){
...
...
cps/static/js/table.js
View file @
1e40ffd1
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
*/
*/
/* exported TableActions, RestrictionActions, EbookActions, responseHandler */
/* exported TableActions, RestrictionActions, EbookActions, responseHandler */
/* global getPath, confirmDialog */
var
selections
=
[];
var
selections
=
[];
...
@@ -209,7 +210,7 @@ $(function() {
...
@@ -209,7 +210,7 @@ $(function() {
striped
:
false
striped
:
false
});
});
function
domain
_h
andle
(
domainId
)
{
function
domain
H
andle
(
domainId
)
{
$
.
ajax
({
$
.
ajax
({
method
:
"post"
,
method
:
"post"
,
url
:
window
.
location
.
pathname
+
"/../../ajax/deletedomain"
,
url
:
window
.
location
.
pathname
+
"/../../ajax/deletedomain"
,
...
@@ -236,12 +237,12 @@ $(function() {
...
@@ -236,12 +237,12 @@ $(function() {
}
}
$
(
"#domain-allow-table"
).
on
(
"click-cell.bs.table"
,
function
(
field
,
value
,
row
,
$element
)
{
$
(
"#domain-allow-table"
).
on
(
"click-cell.bs.table"
,
function
(
field
,
value
,
row
,
$element
)
{
if
(
value
===
2
)
{
if
(
value
===
2
)
{
ConfirmDialog
(
"btndeletedomain"
,
$element
.
id
,
domain_h
andle
);
confirmDialog
(
"btndeletedomain"
,
$element
.
id
,
domainH
andle
);
}
}
});
});
$
(
"#domain-deny-table"
).
on
(
"click-cell.bs.table"
,
function
(
field
,
value
,
row
,
$element
)
{
$
(
"#domain-deny-table"
).
on
(
"click-cell.bs.table"
,
function
(
field
,
value
,
row
,
$element
)
{
if
(
value
===
2
)
{
if
(
value
===
2
)
{
ConfirmDialog
(
"btndeletedomain"
,
$element
.
id
,
domain_h
andle
);
confirmDialog
(
"btndeletedomain"
,
$element
.
id
,
domainH
andle
);
}
}
});
});
...
@@ -255,12 +256,12 @@ $(function() {
...
@@ -255,12 +256,12 @@ $(function() {
$
(
"#h3"
).
addClass
(
"hidden"
);
$
(
"#h3"
).
addClass
(
"hidden"
);
$
(
"#h4"
).
addClass
(
"hidden"
);
$
(
"#h4"
).
addClass
(
"hidden"
);
});
});
function
startTable
(
type
,
user
_i
d
)
{
function
startTable
(
type
,
user
I
d
)
{
$
(
"#restrict-elements-table"
).
bootstrapTable
({
$
(
"#restrict-elements-table"
).
bootstrapTable
({
formatNoMatches
:
function
()
{
formatNoMatches
:
function
()
{
return
""
;
return
""
;
},
},
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
I
d
,
rowStyle
:
function
(
row
)
{
rowStyle
:
function
(
row
)
{
// console.log('Reihe :' + row + " Index :" + index);
// console.log('Reihe :' + row + " Index :" + index);
if
(
row
.
id
.
charAt
(
0
)
===
"a"
)
{
if
(
row
.
id
.
charAt
(
0
)
===
"a"
)
{
...
@@ -274,13 +275,13 @@ $(function() {
...
@@ -274,13 +275,13 @@ $(function() {
$
.
ajax
({
$
.
ajax
({
type
:
"Post"
,
type
:
"Post"
,
data
:
"id="
+
row
.
id
+
"&type="
+
row
.
type
+
"&Element="
+
encodeURIComponent
(
row
.
Element
),
data
:
"id="
+
row
.
id
+
"&type="
+
row
.
type
+
"&Element="
+
encodeURIComponent
(
row
.
Element
),
url
:
getPath
()
+
"/ajax/deleterestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/deleterestriction/"
+
type
+
"/"
+
user
I
d
,
async
:
true
,
async
:
true
,
timeout
:
900
,
timeout
:
900
,
success
:
function
()
{
success
:
function
()
{
$
.
ajax
({
$
.
ajax
({
method
:
"get"
,
method
:
"get"
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
I
d
,
async
:
true
,
async
:
true
,
timeout
:
900
,
timeout
:
900
,
success
:
function
(
data
)
{
success
:
function
(
data
)
{
...
@@ -296,7 +297,7 @@ $(function() {
...
@@ -296,7 +297,7 @@ $(function() {
$
(
"#restrict-elements-table"
).
removeClass
(
"table-hover"
);
$
(
"#restrict-elements-table"
).
removeClass
(
"table-hover"
);
$
(
"#restrict-elements-table"
).
on
(
"editable-save.bs.table"
,
function
(
e
,
field
,
row
)
{
$
(
"#restrict-elements-table"
).
on
(
"editable-save.bs.table"
,
function
(
e
,
field
,
row
)
{
$
.
ajax
({
$
.
ajax
({
url
:
getPath
()
+
"/ajax/editrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/editrestriction/"
+
type
+
"/"
+
user
I
d
,
type
:
"Post"
,
type
:
"Post"
,
data
:
row
data
:
row
});
});
...
@@ -304,13 +305,13 @@ $(function() {
...
@@ -304,13 +305,13 @@ $(function() {
$
(
"[id^=submit_]"
).
click
(
function
()
{
$
(
"[id^=submit_]"
).
click
(
function
()
{
$
(
this
)[
0
].
blur
();
$
(
this
)[
0
].
blur
();
$
.
ajax
({
$
.
ajax
({
url
:
getPath
()
+
"/ajax/addrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/addrestriction/"
+
type
+
"/"
+
user
I
d
,
type
:
"Post"
,
type
:
"Post"
,
data
:
$
(
this
).
closest
(
"form"
).
serialize
()
+
"&"
+
$
(
this
)[
0
].
name
+
"="
,
data
:
$
(
this
).
closest
(
"form"
).
serialize
()
+
"&"
+
$
(
this
)[
0
].
name
+
"="
,
success
:
function
()
{
success
:
function
()
{
$
.
ajax
({
$
.
ajax
({
method
:
"get"
,
method
:
"get"
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
I
d
,
async
:
true
,
async
:
true
,
timeout
:
900
,
timeout
:
900
,
success
:
function
(
data
)
{
success
:
function
(
data
)
{
...
@@ -332,12 +333,12 @@ $(function() {
...
@@ -332,12 +333,12 @@ $(function() {
$
(
"#h1"
).
removeClass
(
"hidden"
);
$
(
"#h1"
).
removeClass
(
"hidden"
);
});
});
$
(
"#get_user_column_values"
).
on
(
"click"
,
function
()
{
$
(
"#get_user_column_values"
).
on
(
"click"
,
function
()
{
startTable
(
3
,
$
(
this
).
data
(
'id'
));
startTable
(
3
,
$
(
this
).
data
(
"id"
));
$
(
"#h4"
).
removeClass
(
"hidden"
);
$
(
"#h4"
).
removeClass
(
"hidden"
);
});
});
$
(
"#get_user_tags"
).
on
(
"click"
,
function
()
{
$
(
"#get_user_tags"
).
on
(
"click"
,
function
()
{
startTable
(
2
,
$
(
this
).
data
(
'id'
));
startTable
(
2
,
$
(
this
).
data
(
"id"
));
$
(
this
)[
0
].
blur
();
$
(
this
)[
0
].
blur
();
$
(
"#h3"
).
removeClass
(
"hidden"
);
$
(
"#h3"
).
removeClass
(
"hidden"
);
});
});
...
...
cps/tasks/upload.py
View file @
1e40ffd1
...
@@ -12,7 +12,6 @@ class TaskUpload(CalibreTask):
...
@@ -12,7 +12,6 @@ class TaskUpload(CalibreTask):
def
run
(
self
,
worker_thread
):
def
run
(
self
,
worker_thread
):
"""Upload task doesn't have anything to do, it's simply a way to add information to the task list"""
"""Upload task doesn't have anything to do, it's simply a way to add information to the task list"""
pass
@
property
@
property
def
name
(
self
):
def
name
(
self
):
...
...
cps/ub.py
View file @
1e40ffd1
...
@@ -138,15 +138,15 @@ class UserBase:
...
@@ -138,15 +138,15 @@ class UserBase:
mct
=
self
.
allowed_column_value
or
""
mct
=
self
.
allowed_column_value
or
""
return
[
t
.
strip
()
for
t
in
mct
.
split
(
","
)]
return
[
t
.
strip
()
for
t
in
mct
.
split
(
","
)]
def
get_view_property
(
self
,
page
,
prop
erty
):
def
get_view_property
(
self
,
page
,
prop
):
if
not
self
.
view_settings
.
get
(
page
):
if
not
self
.
view_settings
.
get
(
page
):
return
None
return
None
return
self
.
view_settings
[
page
]
.
get
(
prop
erty
)
return
self
.
view_settings
[
page
]
.
get
(
prop
)
def
set_view_property
(
self
,
page
,
prop
erty
,
value
):
def
set_view_property
(
self
,
page
,
prop
,
value
):
if
not
self
.
view_settings
.
get
(
page
):
if
not
self
.
view_settings
.
get
(
page
):
self
.
view_settings
[
page
]
=
dict
()
self
.
view_settings
[
page
]
=
dict
()
self
.
view_settings
[
page
][
prop
erty
]
=
value
self
.
view_settings
[
page
][
prop
]
=
value
try
:
try
:
flag_modified
(
self
,
"view_settings"
)
flag_modified
(
self
,
"view_settings"
)
except
AttributeError
:
except
AttributeError
:
...
@@ -437,11 +437,8 @@ class RemoteAuthToken(Base):
...
@@ -437,11 +437,8 @@ class RemoteAuthToken(Base):
return
'<Token
%
r>'
%
self
.
id
return
'<Token
%
r>'
%
self
.
id
# Migrate database to current version, has to be updated after every database change. Currently migration from
# Add missing tables during migration of database
# everywhere to current should work. Migration is done by checking if relevant columns are existing, and than adding
def
add_missing_tables
(
engine
,
session
):
# rows with SQL commands
def
migrate_Database
(
session
):
engine
=
session
.
bind
if
not
engine
.
dialect
.
has_table
(
engine
.
connect
(),
"book_read_link"
):
if
not
engine
.
dialect
.
has_table
(
engine
.
connect
(),
"book_read_link"
):
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"
):
...
@@ -459,6 +456,10 @@ def migrate_Database(session):
...
@@ -459,6 +456,10 @@ def migrate_Database(session):
with
engine
.
connect
()
as
conn
:
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"insert into registration (domain, allow) values('
%
.
%
',1)"
)
conn
.
execute
(
"insert into registration (domain, allow) values('
%
.
%
',1)"
)
session
.
commit
()
session
.
commit
()
# migrate all settings missing in registration table
def
migrate_registration_table
(
engine
,
session
):
try
:
try
:
session
.
query
(
exists
()
.
where
(
Registration
.
allow
))
.
scalar
()
session
.
query
(
exists
()
.
where
(
Registration
.
allow
))
.
scalar
()
session
.
commit
()
session
.
commit
()
...
@@ -468,27 +469,29 @@ def migrate_Database(session):
...
@@ -468,27 +469,29 @@ def migrate_Database(session):
conn
.
execute
(
"update registration set 'allow' = 1"
)
conn
.
execute
(
"update registration set 'allow' = 1"
)
session
.
commit
()
session
.
commit
()
try
:
try
:
session
.
query
(
exists
()
.
where
(
RemoteAuthToken
.
token_type
))
.
scalar
()
# Handle table exists, but no content
session
.
commi
t
()
cnt
=
session
.
query
(
Registration
)
.
coun
t
()
except
exc
.
OperationalError
:
# Database is not compatible, some columns are missing
if
not
cnt
:
with
engine
.
connect
()
as
conn
:
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"ALTER TABLE remote_auth_token ADD column 'token_type' INTEGER DEFAULT 0"
)
conn
.
execute
(
"insert into registration (domain, allow) values('
%
.
%
',1)"
)
conn
.
execute
(
"update remote_auth_token set 'token_type' = 0"
)
session
.
commit
()
session
.
commit
()
except
exc
.
OperationalError
:
# Database is not writeable
print
(
'Settings database is not writeable. Exiting...'
)
sys
.
exit
(
2
)
# Remove login capability of user Guest
def
migrate_guest_password
(
engine
,
session
):
try
:
try
:
session
.
query
(
exists
()
.
where
(
ReadBook
.
read_status
))
.
scalar
()
except
exc
.
OperationalError
:
with
engine
.
connect
()
as
conn
:
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"ALTER TABLE book_read_link ADD column 'read_status' INTEGER DEFAULT 0"
)
conn
.
execute
(
"UPDATE user SET password='' where nickname = 'Guest' and password !=''"
)
conn
.
execute
(
"UPDATE book_read_link SET 'read_status' = 1 WHERE is_read"
)
conn
.
execute
(
"ALTER TABLE book_read_link ADD column 'last_modified' DATETIME"
)
conn
.
execute
(
"ALTER TABLE book_read_link ADD column 'last_time_started_reading' DATETIME"
)
conn
.
execute
(
"ALTER TABLE book_read_link ADD column 'times_started_reading' INTEGER DEFAULT 0"
)
session
.
commit
()
test
=
session
.
query
(
ReadBook
)
.
filter
(
ReadBook
.
last_modified
==
None
)
.
all
()
for
book
in
test
:
book
.
last_modified
=
datetime
.
datetime
.
utcnow
()
session
.
commit
()
session
.
commit
()
except
exc
.
OperationalError
:
print
(
'Settings database is not writeable. Exiting...'
)
sys
.
exit
(
2
)
def
migrate_shelfs
(
engine
,
session
):
try
:
try
:
session
.
query
(
exists
()
.
where
(
Shelf
.
uuid
))
.
scalar
()
session
.
query
(
exists
()
.
where
(
Shelf
.
uuid
))
.
scalar
()
except
exc
.
OperationalError
:
except
exc
.
OperationalError
:
...
@@ -505,21 +508,50 @@ def migrate_Database(session):
...
@@ -505,21 +508,50 @@ def migrate_Database(session):
book_shelf
.
date_added
=
datetime
.
datetime
.
now
()
book_shelf
.
date_added
=
datetime
.
datetime
.
now
()
session
.
commit
()
session
.
commit
()
try
:
try
:
# Handle table exists, but no content
session
.
query
(
exists
()
.
where
(
BookShelf
.
order
))
.
scalar
()
cnt
=
session
.
query
(
Registration
)
.
count
()
except
exc
.
OperationalError
:
# Database is not compatible, some columns are missing
if
not
cnt
:
with
engine
.
connect
()
as
conn
:
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"insert into registration (domain, allow) values('
%
.
%
',1)
"
)
conn
.
execute
(
"ALTER TABLE book_shelf_link ADD column 'order' INTEGER DEFAULT 1
"
)
session
.
commit
()
session
.
commit
()
except
exc
.
OperationalError
:
# Database is not writeable
print
(
'Settings database is not writeable. Exiting...'
)
sys
.
exit
(
2
)
def
migrate_readBook
(
engine
,
session
):
try
:
try
:
session
.
query
(
exists
()
.
where
(
BookShelf
.
order
))
.
scalar
()
session
.
query
(
exists
()
.
where
(
ReadBook
.
read_status
))
.
scalar
()
except
exc
.
OperationalError
:
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"ALTER TABLE book_read_link ADD column 'read_status' INTEGER DEFAULT 0"
)
conn
.
execute
(
"UPDATE book_read_link SET 'read_status' = 1 WHERE is_read"
)
conn
.
execute
(
"ALTER TABLE book_read_link ADD column 'last_modified' DATETIME"
)
conn
.
execute
(
"ALTER TABLE book_read_link ADD column 'last_time_started_reading' DATETIME"
)
conn
.
execute
(
"ALTER TABLE book_read_link ADD column 'times_started_reading' INTEGER DEFAULT 0"
)
session
.
commit
()
test
=
session
.
query
(
ReadBook
)
.
filter
(
ReadBook
.
last_modified
==
None
)
.
all
()
for
book
in
test
:
book
.
last_modified
=
datetime
.
datetime
.
utcnow
()
session
.
commit
()
def
migrate_remoteAuthToken
(
engine
,
session
):
try
:
session
.
query
(
exists
()
.
where
(
RemoteAuthToken
.
token_type
))
.
scalar
()
session
.
commit
()
except
exc
.
OperationalError
:
# Database is not compatible, some columns are missing
except
exc
.
OperationalError
:
# Database is not compatible, some columns are missing
with
engine
.
connect
()
as
conn
:
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"ALTER TABLE book_shelf_link ADD column 'order' INTEGER DEFAULT 1"
)
conn
.
execute
(
"ALTER TABLE remote_auth_token ADD column 'token_type' INTEGER DEFAULT 0"
)
conn
.
execute
(
"update remote_auth_token set 'token_type' = 0"
)
session
.
commit
()
session
.
commit
()
# Migrate database to current version, has to be updated after every database change. Currently migration from
# everywhere to current should work. Migration is done by checking if relevant columns are existing, and than adding
# rows with SQL commands
def
migrate_Database
(
session
):
engine
=
session
.
bind
add_missing_tables
(
engine
,
session
)
migrate_registration_table
(
engine
,
session
)
migrate_readBook
(
engine
,
session
)
migrate_remoteAuthToken
(
engine
,
session
)
migrate_shelfs
(
engine
,
session
)
try
:
try
:
create
=
False
create
=
False
session
.
query
(
exists
()
.
where
(
User
.
sidebar_view
))
.
scalar
()
session
.
query
(
exists
()
.
where
(
User
.
sidebar_view
))
.
scalar
()
...
@@ -578,7 +610,6 @@ def migrate_Database(session):
...
@@ -578,7 +610,6 @@ def migrate_Database(session):
"locale VARCHAR(2),"
"locale VARCHAR(2),"
"sidebar_view INTEGER,"
"sidebar_view INTEGER,"
"default_language VARCHAR(3),"
"default_language VARCHAR(3),"
# "series_view VARCHAR(10),"
"view_settings VARCHAR,"
"view_settings VARCHAR,"
"UNIQUE (nickname),"
"UNIQUE (nickname),"
"UNIQUE (email))"
)
"UNIQUE (email))"
)
...
@@ -590,15 +621,7 @@ def migrate_Database(session):
...
@@ -590,15 +621,7 @@ def migrate_Database(session):
conn
.
execute
(
"DROP TABLE user"
)
conn
.
execute
(
"DROP TABLE user"
)
conn
.
execute
(
"ALTER TABLE user_id RENAME TO user"
)
conn
.
execute
(
"ALTER TABLE user_id RENAME TO user"
)
session
.
commit
()
session
.
commit
()
migrate_guest_password
(
engine
,
session
)
# Remove login capability of user Guest
try
:
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"UPDATE user SET password='' where nickname = 'Guest' and password !=''"
)
session
.
commit
()
except
exc
.
OperationalError
:
print
(
'Settings database is not writeable. Exiting...'
)
sys
.
exit
(
2
)
def
clean_database
(
session
):
def
clean_database
(
session
):
...
...
cps/updater.py
View file @
1e40ffd1
...
@@ -267,7 +267,8 @@ class Updater(threading.Thread):
...
@@ -267,7 +267,8 @@ class Updater(threading.Thread):
log
.
debug
(
"Could not remove:
%
s"
,
item_path
)
log
.
debug
(
"Could not remove:
%
s"
,
item_path
)
shutil
.
rmtree
(
source
,
ignore_errors
=
True
)
shutil
.
rmtree
(
source
,
ignore_errors
=
True
)
def
is_venv
(
self
):
@
staticmethod
def
is_venv
():
if
(
hasattr
(
sys
,
'real_prefix'
))
or
(
hasattr
(
sys
,
'base_prefix'
)
and
sys
.
base_prefix
!=
sys
.
prefix
):
if
(
hasattr
(
sys
,
'real_prefix'
))
or
(
hasattr
(
sys
,
'base_prefix'
)
and
sys
.
base_prefix
!=
sys
.
prefix
):
return
os
.
sep
+
os
.
path
.
relpath
(
sys
.
prefix
,
constants
.
BASE_DIR
)
return
os
.
sep
+
os
.
path
.
relpath
(
sys
.
prefix
,
constants
.
BASE_DIR
)
else
:
else
:
...
...
cps/usermanagement.py
View file @
1e40ffd1
...
@@ -72,7 +72,7 @@ def load_user_from_request(request):
...
@@ -72,7 +72,7 @@ def load_user_from_request(request):
def
load_user_from_auth_header
(
header_val
):
def
load_user_from_auth_header
(
header_val
):
if
header_val
.
startswith
(
'Basic '
):
if
header_val
.
startswith
(
'Basic '
):
header_val
=
header_val
.
replace
(
'Basic '
,
''
,
1
)
header_val
=
header_val
.
replace
(
'Basic '
,
''
,
1
)
basic_username
=
basic_password
=
''
basic_username
=
basic_password
=
''
# nosec
try
:
try
:
header_val
=
base64
.
b64decode
(
header_val
)
.
decode
(
'utf-8'
)
header_val
=
base64
.
b64decode
(
header_val
)
.
decode
(
'utf-8'
)
basic_username
=
header_val
.
split
(
':'
)[
0
]
basic_username
=
header_val
.
split
(
':'
)[
0
]
...
...
cps/web.py
View file @
1e40ffd1
This diff is collapsed.
Click to expand it.
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