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
Hide 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,6 +74,41 @@ def _cover_processing(tmp_file_name, img, extension):
return
tmp_cover_name
def
_extract_Cover_from_archive
(
original_file_extension
,
tmp_file_name
,
rarExecutable
):
cover_data
=
None
if
original_file_extension
.
upper
()
==
'.CBZ'
:
cf
=
zipfile
.
ZipFile
(
tmp_file_name
)
for
name
in
cf
.
namelist
():
ext
=
os
.
path
.
splitext
(
name
)
if
len
(
ext
)
>
1
:
extension
=
ext
[
1
]
.
lower
()
if
extension
in
COVER_EXTENSIONS
:
cover_data
=
cf
.
read
(
name
)
break
elif
original_file_extension
.
upper
()
==
'.CBT'
:
cf
=
tarfile
.
TarFile
(
tmp_file_name
)
for
name
in
cf
.
getnames
():
ext
=
os
.
path
.
splitext
(
name
)
if
len
(
ext
)
>
1
:
extension
=
ext
[
1
]
.
lower
()
if
extension
in
COVER_EXTENSIONS
:
cover_data
=
cf
.
extractfile
(
name
)
.
read
()
break
elif
original_file_extension
.
upper
()
==
'.CBR'
and
use_rarfile
:
try
:
rarfile
.
UNRAR_TOOL
=
rarExecutable
cf
=
rarfile
.
RarFile
(
tmp_file_name
)
for
name
in
cf
.
getnames
():
ext
=
os
.
path
.
splitext
(
name
)
if
len
(
ext
)
>
1
:
extension
=
ext
[
1
]
.
lower
()
if
extension
in
COVER_EXTENSIONS
:
cover_data
=
cf
.
read
(
name
)
break
except
Exception
as
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
...
...
@@ -87,37 +122,7 @@ def _extractCover(tmp_file_name, original_file_extension, rarExecutable):
cover_data
=
archive
.
getPage
(
index
)
break
else
:
if
original_file_extension
.
upper
()
==
'.CBZ'
:
cf
=
zipfile
.
ZipFile
(
tmp_file_name
)
for
name
in
cf
.
namelist
():
ext
=
os
.
path
.
splitext
(
name
)
if
len
(
ext
)
>
1
:
extension
=
ext
[
1
]
.
lower
()
if
extension
in
COVER_EXTENSIONS
:
cover_data
=
cf
.
read
(
name
)
break
elif
original_file_extension
.
upper
()
==
'.CBT'
:
cf
=
tarfile
.
TarFile
(
tmp_file_name
)
for
name
in
cf
.
getnames
():
ext
=
os
.
path
.
splitext
(
name
)
if
len
(
ext
)
>
1
:
extension
=
ext
[
1
]
.
lower
()
if
extension
in
COVER_EXTENSIONS
:
cover_data
=
cf
.
extractfile
(
name
)
.
read
()
break
elif
original_file_extension
.
upper
()
==
'.CBR'
and
use_rarfile
:
try
:
rarfile
.
UNRAR_TOOL
=
rarExecutable
cf
=
rarfile
.
RarFile
(
tmp_file_name
)
for
name
in
cf
.
getnames
():
ext
=
os
.
path
.
splitext
(
name
)
if
len
(
ext
)
>
1
:
extension
=
ext
[
1
]
.
lower
()
if
extension
in
COVER_EXTENSIONS
:
cover_data
=
cf
.
read
(
name
)
break
except
Exception
as
e
:
log
.
debug
(
'Rarfile failed with error:
%
s'
,
e
)
cover_data
=
_extract_Cover_from_archive
(
original_file_extension
,
tmp_file_name
,
rarExecutable
)
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
file_path
=
tmp_file_path
,
extension
=
original_file_extension
,
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
),
description
=
loadedMetadata
.
comments
or
""
,
tags
=
""
,
...
...
cps/config_sql.py
View file @
1e40ffd1
...
...
@@ -146,15 +146,16 @@ class _ConfigSQL(object):
self
.
load
()
change
=
False
if
self
.
config_converterpath
==
None
:
if
self
.
config_converterpath
==
None
:
# pylint: disable=access-member-before-definition
change
=
True
self
.
config_converterpath
=
autodetect_calibre_binary
()
if
self
.
config_kepubifypath
==
None
:
if
self
.
config_kepubifypath
==
None
:
# pylint: disable=access-member-before-definition
change
=
True
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
self
.
config_rarfile_location
=
autodetect_unrar_binary
()
if
change
:
...
...
@@ -181,7 +182,8 @@ class _ConfigSQL(object):
return
None
return
self
.
config_keyfile
def
get_config_ipaddress
(
self
):
@
staticmethod
def
get_config_ipaddress
():
return
cli
.
ipadress
or
""
def
_has_role
(
self
,
role_flag
):
...
...
@@ -299,6 +301,7 @@ class _ConfigSQL(object):
have_metadata_db
=
os
.
path
.
isfile
(
db_file
)
self
.
db_configured
=
have_metadata_db
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
)
if
logfile
!=
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
DEFAULT_MAIL_SERVER
=
"mail.example.org"
DEFAULT_PASSWORD
=
"admin123"
DEFAULT_PASSWORD
=
"admin123"
# nosec # noqa
DEFAULT_PORT
=
8083
env_CALIBRE_PORT
=
os
.
environ
.
get
(
"CALIBRE_PORT"
,
DEFAULT_PORT
)
try
:
...
...
cps/db.py
View file @
1e40ffd1
...
...
@@ -156,10 +156,8 @@ class Identifiers(Base):
return
u"https://portal.issn.org/resource/ISSN/{0}"
.
format
(
self
.
val
)
elif
format_type
==
"isfdb"
:
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
:
return
u"
"
return
u"
{0}"
.
format
(
self
.
val
)
class
Comments
(
Base
):
...
...
@@ -386,14 +384,14 @@ class Custom_Columns(Base):
class
AlchemyEncoder
(
json
.
JSONEncoder
):
def
default
(
self
,
o
bj
):
if
isinstance
(
o
bj
.
__class__
,
DeclarativeMeta
):
def
default
(
self
,
o
):
if
isinstance
(
o
.
__class__
,
DeclarativeMeta
):
# an SQLAlchemy class
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'
:
continue
data
=
o
bj
.
__getattribute__
(
field
)
data
=
o
.
__getattribute__
(
field
)
try
:
if
isinstance
(
data
,
str
):
data
=
data
.
replace
(
"'"
,
"
\'
"
)
...
...
@@ -413,12 +411,12 @@ class AlchemyEncoder(json.JSONEncoder):
else
:
json
.
dumps
(
data
)
fields
[
field
]
=
data
except
:
except
Exception
:
fields
[
field
]
=
""
# a json-encodable dict
return
fields
return
json
.
JSONEncoder
.
default
(
self
,
o
bj
)
return
json
.
JSONEncoder
.
default
(
self
,
o
)
class
CalibreDB
():
...
...
@@ -565,8 +563,8 @@ class CalibreDB():
def
get_book_by_uuid
(
self
,
book_uuid
):
return
self
.
session
.
query
(
Books
)
.
filter
(
Books
.
uuid
==
book_uuid
)
.
first
()
def
get_book_format
(
self
,
book_id
,
format
):
return
self
.
session
.
query
(
Data
)
.
filter
(
Data
.
book
==
book_id
)
.
filter
(
Data
.
format
==
format
)
.
first
()
def
get_book_format
(
self
,
book_id
,
f
ile_f
ormat
):
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
def
common_filters
(
self
,
allow_show_archived
=
False
):
...
...
@@ -744,7 +742,7 @@ class CalibreDB():
if
old_session
:
try
:
old_session
.
close
()
except
:
except
Exception
:
pass
if
old_session
.
bind
:
try
:
...
...
cps/gdrive.py
View file @
1e40ffd1
...
...
@@ -47,7 +47,7 @@ except ImportError as err:
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"
)
...
...
cps/helper.py
View file @
1e40ffd1
...
...
@@ -134,63 +134,71 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False):
taskMessage
=
_
(
u"Registration e-mail for user:
%(name)
s"
,
name
=
user_name
),
text
=
txt
))
return
def
check_send_to_kindle_without_converter
(
entry
):
bookformats
=
list
()
# no converter - only for mobi and pdf formats
for
ele
in
iter
(
entry
.
data
):
if
ele
.
uncompressed_size
<
config
.
mail_size
:
if
'MOBI'
in
ele
.
format
:
bookformats
.
append
({
'format'
:
'Mobi'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Mobi'
)})
if
'PDF'
in
ele
.
format
:
bookformats
.
append
({
'format'
:
'Pdf'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Pdf'
)})
if
'AZW'
in
ele
.
format
:
bookformats
.
append
({
'format'
:
'Azw'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Azw'
)})
return
bookformats
def
check_send_to_kindle_with_converter
(
entry
):
bookformats
=
list
()
formats
=
list
()
for
ele
in
iter
(
entry
.
data
):
if
ele
.
uncompressed_size
<
config
.
mail_size
:
formats
.
append
(
ele
.
format
)
if
'MOBI'
in
formats
:
bookformats
.
append
({
'format'
:
'Mobi'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Mobi'
)})
if
'AZW'
in
formats
:
bookformats
.
append
({
'format'
:
'Azw'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Azw'
)})
if
'PDF'
in
formats
:
bookformats
.
append
({
'format'
:
'Pdf'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Pdf'
)})
if
'EPUB'
in
formats
and
'MOBI'
not
in
formats
:
bookformats
.
append
({
'format'
:
'Mobi'
,
'convert'
:
1
,
'text'
:
_
(
'Convert
%(orig)
s to
%(format)
s and send to Kindle'
,
orig
=
'Epub'
,
format
=
'Mobi'
)})
if
'AZW3'
in
formats
and
not
'MOBI'
in
formats
:
bookformats
.
append
({
'format'
:
'Mobi'
,
'convert'
:
2
,
'text'
:
_
(
'Convert
%(orig)
s to
%(format)
s and send to Kindle'
,
orig
=
'Azw3'
,
format
=
'Mobi'
)})
return
bookformats
def
check_send_to_kindle
(
entry
):
"""
returns all available book formats for sending to Kindle
"""
if
len
(
entry
.
data
):
bookformats
=
list
()
if
not
config
.
config_converterpath
:
# no converter - only for mobi and pdf formats
for
ele
in
iter
(
entry
.
data
):
if
ele
.
uncompressed_size
<
config
.
mail_size
:
if
'MOBI'
in
ele
.
format
:
bookformats
.
append
({
'format'
:
'Mobi'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Mobi'
)})
if
'PDF'
in
ele
.
format
:
bookformats
.
append
({
'format'
:
'Pdf'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Pdf'
)})
if
'AZW'
in
ele
.
format
:
bookformats
.
append
({
'format'
:
'Azw'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Azw'
)})
book_formats
=
check_send_to_kindle_with_converter
(
entry
)
else
:
formats
=
list
()
for
ele
in
iter
(
entry
.
data
):
if
ele
.
uncompressed_size
<
config
.
mail_size
:
formats
.
append
(
ele
.
format
)
if
'MOBI'
in
formats
:
bookformats
.
append
({
'format'
:
'Mobi'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Mobi'
)})
if
'AZW'
in
formats
:
bookformats
.
append
({
'format'
:
'Azw'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Azw'
)})
if
'PDF'
in
formats
:
bookformats
.
append
({
'format'
:
'Pdf'
,
'convert'
:
0
,
'text'
:
_
(
'Send
%(format)
s to Kindle'
,
format
=
'Pdf'
)})
if
config
.
config_converterpath
:
if
'EPUB'
in
formats
and
'MOBI'
not
in
formats
:
bookformats
.
append
({
'format'
:
'Mobi'
,
'convert'
:
1
,
'text'
:
_
(
'Convert
%(orig)
s to
%(format)
s and send to Kindle'
,
orig
=
'Epub'
,
format
=
'Mobi'
)})
if
'AZW3'
in
formats
and
not
'MOBI'
in
formats
:
bookformats
.
append
({
'format'
:
'Mobi'
,
'convert'
:
2
,
'text'
:
_
(
'Convert
%(orig)
s to
%(format)
s and send to Kindle'
,
orig
=
'Azw3'
,
format
=
'Mobi'
)})
return
bookformats
book_formats
=
check_send_to_kindle_with_converter
(
entry
)
return
book_formats
else
:
log
.
error
(
u'Cannot find book entry
%
d'
,
entry
.
id
)
return
None
...
...
@@ -742,7 +750,7 @@ def format_runtime(runtime):
# helper function to apply localize status information in tasklist entries
def
render_task_status
(
tasklist
):
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
():
ret
=
{}
if
task
.
start_time
:
...
...
cps/isoLanguages.py
View file @
1e40ffd1
...
...
@@ -71,7 +71,7 @@ def get_valid_language_codes(locale, language_names, remainder=None):
languages
=
list
()
if
""
in
language_names
:
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
:
languages
.
append
(
k
)
language_names
.
remove
(
k
)
...
...
cps/kobo.py
View file @
1e40ffd1
...
...
@@ -42,8 +42,7 @@ from flask import (
from
flask_login
import
current_user
from
werkzeug.datastructures
import
Headers
from
sqlalchemy
import
func
from
sqlalchemy.sql.expression
import
and_
,
or_
from
sqlalchemy.orm
import
load_only
from
sqlalchemy.sql.expression
import
and_
from
sqlalchemy.exc
import
StatementError
import
requests
...
...
@@ -893,17 +892,6 @@ def HandleProductsRequest(dummy=None):
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
():
# 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.
...
...
@@ -947,7 +935,7 @@ def HandleInitRequest():
store_response_json
=
store_response
.
json
()
if
"Resources"
in
store_response_json
:
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."
)
if
not
kobo_resources
:
kobo_resources
=
NATIVE_KOBO_RESOURCES
()
...
...
cps/oauth.py
View file @
1e40ffd1
This diff is collapsed.
Click to expand it.
cps/oauth_bb.py
View file @
1e40ffd1
...
...
@@ -35,7 +35,10 @@ from sqlalchemy.orm.exc import NoResultFound
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
=
{}
...
...
cps/server.py
View file @
1e40ffd1
...
...
@@ -137,8 +137,8 @@ class WebServer(object):
return
sock
,
_readable_listen_address
(
*
address
)
def
_get_args_for_reloading
(
self
):
@
staticmethod
def
_get_args_for_reloading
():
"""Determine how the script was executed, and return the args needed
to execute it again in a new process.
Code from https://github.com/pyload/pyload. Author GammaC0de, voulter
...
...
cps/services/SyncToken.py
View file @
1e40ffd1
...
...
@@ -64,7 +64,7 @@ class SyncToken:
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"
LAST_MODIFIED_ADDED_VERSION
=
"1-1-0"
MIN_VERSION
=
"1-0-0"
...
...
@@ -91,7 +91,7 @@ class SyncToken:
def
__init__
(
self
,
raw_kobo_store_token
=
""
,
raw_kobo_store_token
=
""
,
# nosec
books_last_created
=
datetime
.
min
,
books_last_modified
=
datetime
.
min
,
archive_last_modified
=
datetime
.
min
,
...
...
@@ -110,7 +110,7 @@ class SyncToken:
@
staticmethod
def
from_headers
(
headers
):
sync_token_header
=
headers
.
get
(
SyncToken
.
SYNC_TOKEN_HEADER
,
""
)
if
sync_token_header
==
""
:
if
sync_token_header
==
""
:
# nosec
return
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
{
display
:
none
;
body
.serieslist.grid-view
div
.container-fluid
>
div
>
div
.col-sm-10
::before
{
display
:
none
;
}
.cover
.badge
{
position
:
absolute
;
top
:
0
;
left
:
0
;
color
:
#fff
;
background-color
:
#cc7b19
;
border-radius
:
0
;
padding
:
0
8px
;
box-shadow
:
0
0
4px
rgba
(
0
,
0
,
0
,
.6
);
line-height
:
24px
;
.cover
.badge
{
position
:
absolute
;
top
:
0
;
left
:
0
;
color
:
#fff
;
background-color
:
#cc7b19
;
border-radius
:
0
;
padding
:
0
8px
;
box-shadow
:
0
0
4px
rgba
(
0
,
0
,
0
,
0.6
);
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
{
padding
:
0
0px
;
line-height
:
15px
;
.cover
.read
{
padding
:
0
0
;
line-height
:
15px
;
}
cps/static/css/kthoom.css
View file @
1e40ffd1
...
...
@@ -33,7 +33,6 @@ body {
position
:
relative
;
cursor
:
pointer
;
padding
:
4px
;
transition
:
all
0.2s
ease
;
}
...
...
@@ -45,7 +44,7 @@ body {
#sidebar
a
.active
,
#sidebar
a
.active
img
+
span
{
background-color
:
#45
B29D
;
background-color
:
#45
b29d
;
}
#sidebar
li
img
{
...
...
@@ -99,7 +98,7 @@ body {
background-color
:
#ccc
;
}
#progress
.bar-read
{
#progress
.bar-read
{
color
:
#fff
;
background-color
:
#45b29d
;
}
...
...
cps/static/css/listen.css
View file @
1e40ffd1
...
...
@@ -66,19 +66,12 @@ body {
right
:
40px
;
}
xmp
,
pre
,
plaintext
{
pre
{
display
:
block
;
font-family
:
-moz-fixed
;
white-space
:
pre
;
margin
:
1em
0
;
}
pre
{
white-space
:
pre-wrap
;
word-wrap
:
break-word
;
font-family
:
-moz-fixed
;
font-family
:
-moz-fixed
,
sans-serif
;
column-count
:
2
;
-webkit-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>')
// Get rid of leading white space
recentlyAdded
=
$
(
"#nav_new a:contains('Recently')"
).
text
().
trim
();
$
(
"#nav_new a:contains('Recently')"
).
contents
().
filter
(
function
()
{
return
this
.
nodeType
==
3
return
this
.
nodeType
==
=
3
}).
each
(
function
()
{
this
.
textContent
=
this
.
textContent
.
replace
(
" Recently Added"
,
recentlyAdded
);
});
...
...
cps/static/js/edit_books.js
View file @
1e40ffd1
/**
* Created by SpeedProg on 05.04.2015.
*/
/* global Bloodhound, language, Modernizr, tinymce */
/* global Bloodhound, language, Modernizr, tinymce
, getPath
*/
if
(
$
(
"#description"
).
length
)
{
tinymce
.
init
({
...
...
@@ -250,14 +250,14 @@ promisePublishers.done(function() {
});
$
(
"#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
;
}
var
form
=
$
(
"form"
).
serialize
();
$
.
getJSON
(
getPath
()
+
"/get_matching_tags"
,
form
,
function
(
data
)
{
$
(
".tags_click"
).
each
(
function
()
{
if
(
$
.
inArray
(
parseInt
(
$
(
this
).
val
(),
10
),
data
.
tags
)
===
-
1
)
{
if
(
!
$
(
this
).
prop
(
"selected"
))
{
if
(
!
$
(
this
).
prop
(
"selected"
))
{
$
(
this
).
prop
(
"disabled"
,
true
);
}
}
else
{
...
...
@@ -265,10 +265,10 @@ $("#search").on("change input.typeahead:selected", function(event) {
}
});
$
(
"#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"
);
$
(
'#exclude_tag'
).
selectpicker
(
"refresh"
);
$
(
"#include_tag"
).
selectpicker
(
"refresh"
);
$
(
"#exclude_tag"
).
selectpicker
(
"refresh"
);
});
});
...
...
cps/static/js/filter_grid.js
View file @
1e40ffd1
...
...
@@ -36,7 +36,6 @@ $("#desc").click(function() {
sortBy
:
"name"
,
sortAscending
:
true
});
return
;
});
$
(
"#asc"
).
click
(
function
()
{
...
...
@@ -52,19 +51,20 @@ $("#asc").click(function() {
sortBy
:
"name"
,
sortAscending
:
false
});
return
;
});
$
(
"#all"
).
click
(
function
()
{
// go through all elements and make them visible
$list
.
isotope
({
filter
:
function
()
{
return
true
;
}
})
}
});
});
$
(
".char"
).
click
(
function
()
{
var
character
=
this
.
innerText
;
$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() {
// Find count of middle element
var
count
=
$
(
".row:visible"
).
length
;
if
(
count
>
20
)
{
middle
=
parseInt
(
count
/
2
)
+
(
count
%
2
);
middle
=
parseInt
(
count
/
2
,
10
)
+
(
count
%
2
);
//var middle = parseInt(count / 2) + (count % 2);
// search for the middle of all visible elements
...
...
@@ -135,7 +135,7 @@ $("#asc").click(function() {
// Find count of middle element
var
count
=
$
(
".row:visible"
).
length
;
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);
// search for the middle of all visible elements
...
...
cps/static/js/get_meta.js
View file @
1e40ffd1
...
...
@@ -138,8 +138,8 @@ $(function () {
seriesTitle
=
result
.
series
.
title
;
}
var
dateFomers
=
result
.
pubdate
.
split
(
"-"
);
var
publishedYear
=
parseInt
(
dateFomers
[
0
]);
var
publishedMonth
=
parseInt
(
dateFomers
[
1
]);
var
publishedYear
=
parseInt
(
dateFomers
[
0
]
,
10
);
var
publishedMonth
=
parseInt
(
dateFomers
[
1
]
,
10
);
var
publishedDate
=
new
Date
(
publishedYear
,
publishedMonth
-
1
,
1
);
publishedDate
=
formatDate
(
publishedDate
);
...
...
@@ -194,8 +194,8 @@ $(function () {
}
else
{
dateFomers
=
result
.
date_added
.
split
(
"-"
);
}
var
publishedYear
=
parseInt
(
dateFomers
[
0
]);
var
publishedMonth
=
parseInt
(
dateFomers
[
1
]);
var
publishedYear
=
parseInt
(
dateFomers
[
0
]
,
10
);
var
publishedMonth
=
parseInt
(
dateFomers
[
1
]
,
10
);
var
publishedDate
=
new
Date
(
publishedYear
,
publishedMonth
-
1
,
1
);
publishedDate
=
formatDate
(
publishedDate
);
...
...
cps/static/js/main.js
View file @
1e40ffd1
...
...
@@ -38,10 +38,10 @@ $(document).on("change", "input[type=\"checkbox\"][data-control]", function () {
$
(
document
).
on
(
"change"
,
"select[data-control]"
,
function
()
{
var
$this
=
$
(
this
);
var
name
=
$this
.
data
(
"control"
);
var
showOrHide
=
parseInt
(
$this
.
val
());
var
showOrHide
=
parseInt
(
$this
.
val
()
,
10
);
// var showOrHideLast = $("#" + name + " option:last").val()
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
)
{
$
(
"[data-related^="
+
name
+
"][data-related*=-"
+
element
+
"]"
).
show
();
}
else
{
...
...
@@ -55,7 +55,7 @@ $(document).on("change", "select[data-control]", function() {
$
(
document
).
on
(
"change"
,
"select[data-controlall]"
,
function
()
{
var
$this
=
$
(
this
);
var
name
=
$this
.
data
(
"controlall"
);
var
showOrHide
=
parseInt
(
$this
.
val
());
var
showOrHide
=
parseInt
(
$this
.
val
()
,
10
);
if
(
showOrHide
)
{
$
(
"[data-related="
+
name
+
"]"
).
show
();
}
else
{
...
...
@@ -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 dataValue= e.data('value'); // target.data('value');
$confirm
.
modal
(
'show'
);
...
...
@@ -481,7 +481,7 @@ $(function() {
});
$
(
"#config_delete_kobo_token"
).
click
(
function
()
{
C
onfirmDialog
(
c
onfirmDialog
(
$
(
this
).
attr
(
'id'
),
$
(
this
).
data
(
'value'
),
function
(
value
)
{
...
...
@@ -509,7 +509,7 @@ $(function() {
});
$
(
"#btndeluser"
).
click
(
function
()
{
C
onfirmDialog
(
c
onfirmDialog
(
$
(
this
).
attr
(
'id'
),
$
(
this
).
data
(
'value'
),
function
(
value
){
...
...
@@ -527,7 +527,7 @@ $(function() {
});
$
(
"#delete_shelf"
).
click
(
function
()
{
C
onfirmDialog
(
c
onfirmDialog
(
$
(
this
).
attr
(
'id'
),
$
(
this
).
data
(
'value'
),
function
(
value
){
...
...
cps/static/js/table.js
View file @
1e40ffd1
...
...
@@ -16,6 +16,7 @@
*/
/* exported TableActions, RestrictionActions, EbookActions, responseHandler */
/* global getPath, confirmDialog */
var
selections
=
[];
...
...
@@ -209,7 +210,7 @@ $(function() {
striped
:
false
});
function
domain
_h
andle
(
domainId
)
{
function
domain
H
andle
(
domainId
)
{
$
.
ajax
({
method
:
"post"
,
url
:
window
.
location
.
pathname
+
"/../../ajax/deletedomain"
,
...
...
@@ -236,12 +237,12 @@ $(function() {
}
$
(
"#domain-allow-table"
).
on
(
"click-cell.bs.table"
,
function
(
field
,
value
,
row
,
$element
)
{
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
)
{
if
(
value
===
2
)
{
ConfirmDialog
(
"btndeletedomain"
,
$element
.
id
,
domain_h
andle
);
confirmDialog
(
"btndeletedomain"
,
$element
.
id
,
domainH
andle
);
}
});
...
...
@@ -255,12 +256,12 @@ $(function() {
$
(
"#h3"
).
addClass
(
"hidden"
);
$
(
"#h4"
).
addClass
(
"hidden"
);
});
function
startTable
(
type
,
user
_i
d
)
{
function
startTable
(
type
,
user
I
d
)
{
$
(
"#restrict-elements-table"
).
bootstrapTable
({
formatNoMatches
:
function
()
{
return
""
;
},
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
I
d
,
rowStyle
:
function
(
row
)
{
// console.log('Reihe :' + row + " Index :" + index);
if
(
row
.
id
.
charAt
(
0
)
===
"a"
)
{
...
...
@@ -274,13 +275,13 @@ $(function() {
$
.
ajax
({
type
:
"Post"
,
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
,
timeout
:
900
,
success
:
function
()
{
$
.
ajax
({
method
:
"get"
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
I
d
,
async
:
true
,
timeout
:
900
,
success
:
function
(
data
)
{
...
...
@@ -296,7 +297,7 @@ $(function() {
$
(
"#restrict-elements-table"
).
removeClass
(
"table-hover"
);
$
(
"#restrict-elements-table"
).
on
(
"editable-save.bs.table"
,
function
(
e
,
field
,
row
)
{
$
.
ajax
({
url
:
getPath
()
+
"/ajax/editrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/editrestriction/"
+
type
+
"/"
+
user
I
d
,
type
:
"Post"
,
data
:
row
});
...
...
@@ -304,13 +305,13 @@ $(function() {
$
(
"[id^=submit_]"
).
click
(
function
()
{
$
(
this
)[
0
].
blur
();
$
.
ajax
({
url
:
getPath
()
+
"/ajax/addrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/addrestriction/"
+
type
+
"/"
+
user
I
d
,
type
:
"Post"
,
data
:
$
(
this
).
closest
(
"form"
).
serialize
()
+
"&"
+
$
(
this
)[
0
].
name
+
"="
,
success
:
function
()
{
$
.
ajax
({
method
:
"get"
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
_i
d
,
url
:
getPath
()
+
"/ajax/listrestriction/"
+
type
+
"/"
+
user
I
d
,
async
:
true
,
timeout
:
900
,
success
:
function
(
data
)
{
...
...
@@ -332,12 +333,12 @@ $(function() {
$
(
"#h1"
).
removeClass
(
"hidden"
);
});
$
(
"#get_user_column_values"
).
on
(
"click"
,
function
()
{
startTable
(
3
,
$
(
this
).
data
(
'id'
));
startTable
(
3
,
$
(
this
).
data
(
"id"
));
$
(
"#h4"
).
removeClass
(
"hidden"
);
});
$
(
"#get_user_tags"
).
on
(
"click"
,
function
()
{
startTable
(
2
,
$
(
this
).
data
(
'id'
));
startTable
(
2
,
$
(
this
).
data
(
"id"
));
$
(
this
)[
0
].
blur
();
$
(
"#h3"
).
removeClass
(
"hidden"
);
});
...
...
cps/tasks/upload.py
View file @
1e40ffd1
...
...
@@ -12,7 +12,6 @@ class TaskUpload(CalibreTask):
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"""
pass
@
property
def
name
(
self
):
...
...
cps/ub.py
View file @
1e40ffd1
...
...
@@ -138,15 +138,15 @@ class UserBase:
mct
=
self
.
allowed_column_value
or
""
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
):
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
):
self
.
view_settings
[
page
]
=
dict
()
self
.
view_settings
[
page
][
prop
erty
]
=
value
self
.
view_settings
[
page
][
prop
]
=
value
try
:
flag_modified
(
self
,
"view_settings"
)
except
AttributeError
:
...
...
@@ -437,11 +437,8 @@ class RemoteAuthToken(Base):
return
'<Token
%
r>'
%
self
.
id
# 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 during migration of database
def
add_missing_tables
(
engine
,
session
):
if
not
engine
.
dialect
.
has_table
(
engine
.
connect
(),
"book_read_link"
):
ReadBook
.
__table__
.
create
(
bind
=
engine
)
if
not
engine
.
dialect
.
has_table
(
engine
.
connect
(),
"bookmark"
):
...
...
@@ -459,6 +456,10 @@ def migrate_Database(session):
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"insert into registration (domain, allow) values('
%
.
%
',1)"
)
session
.
commit
()
# migrate all settings missing in registration table
def
migrate_registration_table
(
engine
,
session
):
try
:
session
.
query
(
exists
()
.
where
(
Registration
.
allow
))
.
scalar
()
session
.
commit
()
...
...
@@ -468,27 +469,29 @@ def migrate_Database(session):
conn
.
execute
(
"update registration set 'allow' = 1"
)
session
.
commit
()
try
:
session
.
query
(
exists
()
.
where
(
RemoteAuthToken
.
token_type
))
.
scalar
()
session
.
commit
()
except
exc
.
OperationalError
:
# Database is not compatible, some columns are missing
with
engine
.
connect
()
as
conn
:
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
()
# Handle table exists, but no content
cnt
=
session
.
query
(
Registration
)
.
count
()
if
not
cnt
:
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"insert into registration (domain, allow) values('
%
.
%
',1)"
)
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
:
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"
)
conn
.
execute
(
"UPDATE user SET password='' where nickname = 'Guest' and password !=''"
)
session
.
commit
()
test
=
session
.
query
(
ReadBook
)
.
filter
(
ReadBook
.
last_modified
==
None
)
.
all
()
for
book
in
test
:
book
.
last_modified
=
datetime
.
datetime
.
utcnow
()
session
.
commit
()
except
exc
.
OperationalError
:
print
(
'Settings database is not writeable. Exiting...'
)
sys
.
exit
(
2
)
def
migrate_shelfs
(
engine
,
session
):
try
:
session
.
query
(
exists
()
.
where
(
Shelf
.
uuid
))
.
scalar
()
except
exc
.
OperationalError
:
...
...
@@ -504,22 +507,51 @@ def migrate_Database(session):
for
book_shelf
in
session
.
query
(
BookShelf
)
.
all
():
book_shelf
.
date_added
=
datetime
.
datetime
.
now
()
session
.
commit
()
try
:
# Handle table exists, but no content
cnt
=
session
.
query
(
Registration
)
.
count
()
if
not
cnt
:
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"insert into registration (domain, allow) values('
%
.
%
',1)"
)
session
.
commit
()
except
exc
.
OperationalError
:
# Database is not writeable
print
(
'Settings database is not writeable. Exiting...'
)
sys
.
exit
(
2
)
try
:
session
.
query
(
exists
()
.
where
(
BookShelf
.
order
))
.
scalar
()
except
exc
.
OperationalError
:
# Database is not compatible, some columns are missing
with
engine
.
connect
()
as
conn
:
conn
.
execute
(
"ALTER TABLE book_shelf_link ADD column 'order' INTEGER DEFAULT 1"
)
session
.
commit
()
def
migrate_readBook
(
engine
,
session
):
try
:
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
with
engine
.
connect
()
as
conn
:
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
()
# 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
:
create
=
False
session
.
query
(
exists
()
.
where
(
User
.
sidebar_view
))
.
scalar
()
...
...
@@ -578,8 +610,7 @@ def migrate_Database(session):
"locale VARCHAR(2),"
"sidebar_view INTEGER,"
"default_language VARCHAR(3),"
# "series_view VARCHAR(10),"
"view_settings VARCHAR,"
"view_settings VARCHAR,"
"UNIQUE (nickname),"
"UNIQUE (email))"
)
conn
.
execute
(
"INSERT INTO user_id(id, nickname, email, role, password, kindle_mail,locale,"
...
...
@@ -590,15 +621,7 @@ def migrate_Database(session):
conn
.
execute
(
"DROP TABLE user"
)
conn
.
execute
(
"ALTER TABLE user_id RENAME TO user"
)
session
.
commit
()
# 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
)
migrate_guest_password
(
engine
,
session
)
def
clean_database
(
session
):
...
...
cps/updater.py
View file @
1e40ffd1
...
...
@@ -267,7 +267,8 @@ class Updater(threading.Thread):
log
.
debug
(
"Could not remove:
%
s"
,
item_path
)
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
):
return
os
.
sep
+
os
.
path
.
relpath
(
sys
.
prefix
,
constants
.
BASE_DIR
)
else
:
...
...
cps/usermanagement.py
View file @
1e40ffd1
...
...
@@ -72,7 +72,7 @@ def load_user_from_request(request):
def
load_user_from_auth_header
(
header_val
):
if
header_val
.
startswith
(
'Basic '
):
header_val
=
header_val
.
replace
(
'Basic '
,
''
,
1
)
basic_username
=
basic_password
=
''
basic_username
=
basic_password
=
''
# nosec
try
:
header_val
=
base64
.
b64decode
(
header_val
)
.
decode
(
'utf-8'
)
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