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
725fc658
Commit
725fc658
authored
Mar 14, 2021
by
Ozzie Isaacs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Some code cosmetics
parent
e4e27662
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
460 additions
and
410 deletions
+460
-410
comic.py
cps/comic.py
+38
-32
config_sql.py
cps/config_sql.py
+7
-4
constants.py
cps/constants.py
+1
-1
helper.py
cps/helper.py
+56
-48
isoLanguages.py
cps/isoLanguages.py
+1
-1
oauth.py
cps/oauth.py
+125
-129
oauth_bb.py
cps/oauth_bb.py
+4
-1
server.py
cps/server.py
+1
-1
SyncToken.py
cps/services/SyncToken.py
+3
-3
caliBlur_override.css
cps/static/css/caliBlur_override.css
+18
-16
kthoom.css
cps/static/css/kthoom.css
+2
-3
main.css
cps/static/css/main.css
+0
-2
style.css
cps/static/css/style.css
+57
-36
caliBlur.js
cps/static/js/caliBlur.js
+1
-1
filter_list.js
cps/static/js/filter_list.js
+2
-2
main.js
cps/static/js/main.js
+2
-2
table.js
cps/static/js/table.js
+1
-0
upload.py
cps/tasks/upload.py
+0
-1
ub.py
cps/ub.py
+71
-48
usermanagement.py
cps/usermanagement.py
+1
-1
web.py
cps/web.py
+69
-78
No files found.
cps/comic.py
View file @
725fc658
...
@@ -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 @
725fc658
...
@@ -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 @
725fc658
...
@@ -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/helper.py
View file @
725fc658
...
@@ -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 @
725fc658
...
@@ -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/oauth.py
View file @
725fc658
...
@@ -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 @
725fc658
...
@@ -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 @
725fc658
...
@@ -137,7 +137,7 @@ class WebServer(object):
...
@@ -137,7 +137,7 @@ 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
(
self
):
"""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.
...
...
cps/services/SyncToken.py
View file @
725fc658
...
@@ -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 @
725fc658
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
;
...
@@ -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
,
.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
,
.6
);
}
}
.cover
.read
{
.cover
.read
{
padding
:
0
0px
;
padding
:
0px
0px
;
line-height
:
15px
;
line-height
:
15px
;
}
}
cps/static/css/kthoom.css
View file @
725fc658
...
@@ -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/main.css
View file @
725fc658
...
@@ -490,7 +490,6 @@ input:-moz-placeholder { color: #454545; }
...
@@ -490,7 +490,6 @@ input:-moz-placeholder { color: #454545; }
position
:
fixed
;
position
:
fixed
;
top
:
50%
;
top
:
50%
;
left
:
50%
;
left
:
50%
;
//
width
:
50%
;
width
:
630px
;
width
:
630px
;
height
:
auto
;
height
:
auto
;
z-index
:
2000
;
z-index
:
2000
;
...
@@ -593,7 +592,6 @@ input:-moz-placeholder { color: #454545; }
...
@@ -593,7 +592,6 @@ input:-moz-placeholder { color: #454545; }
}
}
.md-content
>
.closer
{
.md-content
>
.closer
{
//
font-size
:
18px
;
position
:
absolute
;
position
:
absolute
;
right
:
0
;
right
:
0
;
top
:
0
;
top
:
0
;
...
...
cps/static/css/style.css
View file @
725fc658
.tooltip.bottom
.tooltip-inner
{
.tooltip.bottom
.tooltip-inner
{
font-size
:
13px
;
font-size
:
13px
;
font-family
:
Open
Sans
Semibold
,
Helvetica
Neue
,
Helvetica
,
Arial
,
sans-serif
;
font-family
:
Open
Sans
Semibold
,
Helvetica
Neue
,
Helvetica
,
Arial
,
sans-serif
;
-webkit-font-smoothing
:
antialiased
;
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
-moz-osx-font-smoothing
:
grayscale
;
padding
:
3px
10px
;
padding
:
3px
10px
;
...
@@ -48,10 +48,10 @@ body {
...
@@ -48,10 +48,10 @@ body {
body
h2
{
body
h2
{
font-weight
:
normal
;
font-weight
:
normal
;
color
:
#444
;
color
:
#444
;
}
}
a
,
.danger
,
.book-remove
,
.editable-empty
,
.editable-empty
:hover
{
color
:
#45b29d
;
}
a
,
.danger
,
.book-remove
,
.editable-empty
,
.editable-empty
:hover
{
color
:
#45b29d
;
}
.book-remove
:hover
{
color
:
#23527c
;
}
.book-remove
:hover
{
color
:
#23527c
;
}
...
@@ -119,7 +119,7 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
...
@@ -119,7 +119,7 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
max-height
:
100%
;
max-height
:
100%
;
}
}
.container-fluid
.discover
{
margin-bottom
:
50px
;
}
.container-fluid
.discover
{
margin-bottom
:
50px
;
}
.container-fluid
.new-books
{
border-top
:
1px
solid
#ccc
;
}
.container-fluid
.new-books
{
border-top
:
1px
solid
#ccc
;
}
.container-fluid
.new-books
h2
{
margin
:
50px
0
0
0
;
}
.container-fluid
.new-books
h2
{
margin
:
50px
0
0
0
;
}
.container-fluid
.book
{
.container-fluid
.book
{
...
@@ -174,9 +174,10 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
...
@@ -174,9 +174,10 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
.container-fluid
.book
.meta
.rating
{
margin-top
:
5px
;
}
.container-fluid
.book
.meta
.rating
{
margin-top
:
5px
;
}
.rating
.glyphicon-star-empty
{
color
:
#444
;
}
.rating
.glyphicon-star-empty
{
color
:
#444
;
}
.rating
.glyphicon-star.good
{
color
:
#444
;
}
.rating
.glyphicon-star.good
{
color
:
#444
;
}
.rating-clear
.glyphicon-remove
{
color
:
#333
}
.rating-clear
.glyphicon-remove
{
color
:
#333
;
}
.container-fluid
.author
.author-hidden
,
.container-fluid
.author
.author-hidden-divider
{
display
:
none
;
}
.container-fluid
.author
.author-hidden
,
.container-fluid
.author
.author-hidden-divider
{
display
:
none
;
}
.navbar-brand
{
.navbar-brand
{
font-family
:
'Grand Hotel'
,
cursive
;
font-family
:
'Grand Hotel'
,
cursive
;
...
@@ -190,7 +191,7 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
...
@@ -190,7 +191,7 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
border-top
:
1px
solid
#ccc
;
border-top
:
1px
solid
#ccc
;
}
}
.more-stuff
>
li
{
margin-bottom
:
10px
;
}
.more-stuff
>
li
{
margin-bottom
:
10px
;
}
.navbar-collapse.in
.navbar-nav
{
margin
:
0
;
}
.navbar-collapse.in
.navbar-nav
{
margin
:
0
;
}
span
.glyphicon.glyphicon-tags
{
span
.glyphicon.glyphicon-tags
{
...
@@ -211,8 +212,8 @@ span.glyphicon.glyphicon-tags {
...
@@ -211,8 +212,8 @@ span.glyphicon.glyphicon-tags {
box-shadow
:
0
5px
8px
-6px
#777
;
box-shadow
:
0
5px
8px
-6px
#777
;
}
}
.navbar-default
.navbar-toggle
.icon-bar
{
background-color
:
#000
;
}
.navbar-default
.navbar-toggle
.icon-bar
{
background-color
:
#000
;
}
.navbar-default
.navbar-toggle
{
border-color
:
#000
;
}
.navbar-default
.navbar-toggle
{
border-color
:
#000
;
}
.cover
{
margin-bottom
:
10px
;
}
.cover
{
margin-bottom
:
10px
;
}
.cover
.badge
{
.cover
.badge
{
...
@@ -231,14 +232,14 @@ span.glyphicon.glyphicon-tags {
...
@@ -231,14 +232,14 @@ span.glyphicon.glyphicon-tags {
display
:
inline-block
;
display
:
inline-block
;
padding
:
2px
;
padding
:
2px
;
}
}
.cover-height
{
max-height
:
100px
;}
.cover-height
{
max-height
:
100px
;
}
.col-sm-2
a
.cover-small
{
.col-sm-2
a
.cover-small
{
margin
:
5px
;
margin
:
5px
;
max-height
:
200px
;
max-height
:
200px
;
}
}
.btn-file
{
position
:
relative
;
overflow
:
hidden
;
}
.btn-file
{
position
:
relative
;
overflow
:
hidden
;
}
.btn-file
input
[
type
=
file
]
{
.btn-file
input
[
type
=
file
]
{
position
:
absolute
;
position
:
absolute
;
...
@@ -256,22 +257,42 @@ span.glyphicon.glyphicon-tags {
...
@@ -256,22 +257,42 @@ span.glyphicon.glyphicon-tags {
display
:
block
;
display
:
block
;
}
}
.btn-toolbar
.btn
,
.discover
.btn
{
margin-bottom
:
5px
;
}
.btn-toolbar
.btn
,
.button-link
{
color
:
#fff
;
}
.discover
.btn
{
margin-bottom
:
5px
;
}
.btn-primary
:hover
,
.btn-primary
:focus
,
.btn-primary
:active
,
.btn-primary.active
,
.open
.dropdown-toggle.btn-primary
{
background-color
:
#1C5484
;
}
.button-link
{
color
:
#fff
;
}
.btn-primary.disabled
,
.btn-primary
[
disabled
],
fieldset
[
disabled
]
.btn-primary
,
.btn-primary.disabled
:hover
,
.btn-primary
[
disabled
]
:hover
,
fieldset
[
disabled
]
.btn-primary
:hover
,
.btn-primary.disabled
:focus
,
.btn-primary
[
disabled
]
:focus
,
fieldset
[
disabled
]
.btn-primary
:focus
,
.btn-primary.disabled
:active
,
.btn-primary
[
disabled
]
:active
,
fieldset
[
disabled
]
.btn-primary
:active
,
.btn-primary.disabled.active
,
.btn-primary
[
disabled
]
.active
,
fieldset
[
disabled
]
.btn-primary.active
{
background-color
:
#89B9E2
;
}
.btn-toolbar
>
.btn
+
.btn
,
.btn-toolbar
>
.btn-group
+
.btn
,
.btn-toolbar
>
.btn
+
.btn-group
,
.btn-toolbar
>
.btn-group
+
.btn-group
{
margin-left
:
0
;
}
.btn-primary
:hover
,
.panel-body
{
background-color
:
#f5f5f5
;
}
.btn-primary
:focus
,
.spinner
{
margin
:
0
41%
;
}
.btn-primary
:active
,
.spinner2
{
margin
:
0
41%
;
}
.btn-primary.active
,
.open
.dropdown-toggle.btn-primary
{
background-color
:
#1c5484
;
}
.btn-primary.disabled
,
.btn-primary
[
disabled
],
fieldset
[
disabled
]
.btn-primary
,
.btn-primary.disabled
:hover
,
.btn-primary
[
disabled
]
:hover
,
fieldset
[
disabled
]
.btn-primary
:hover
,
.btn-primary.disabled
:focus
,
.btn-primary
[
disabled
]
:focus
,
fieldset
[
disabled
]
.btn-primary
:focus
,
.btn-primary.disabled
:active
,
.btn-primary
[
disabled
]
:active
,
fieldset
[
disabled
]
.btn-primary
:active
,
.btn-primary.disabled.active
,
.btn-primary
[
disabled
]
.active
,
fieldset
[
disabled
]
.btn-primary.active
{
background-color
:
#89B9E2
;
}
.btn-toolbar
>
.btn
+
.btn
,
.btn-toolbar
>
.btn-group
+
.btn
,
.btn-toolbar
>
.btn
+
.btn-group
,
.btn-toolbar
>
.btn-group
+
.btn-group
{
margin-left
:
0
;
}
.panel-body
{
background-color
:
#f5f5f5
;
}
.spinner
{
margin
:
0
41%
;
}
.spinner2
{
margin
:
0
41%
;
}
.intend-form
{
margin-left
:
20px
;
}
.intend-form
{
margin-left
:
20px
;
}
table
.bg-dark-danger
{
background-color
:
#d9534f
;
color
:
#fff
;
}
table
.bg-dark-danger
{
background-color
:
#d9534f
;
color
:
#fff
;
}
table
.bg-dark-danger
a
{
color
:
#fff
;
}
table
.bg-dark-danger
a
{
color
:
#fff
;
}
table
.bg-dark-danger
:hover
{
background-color
:
#c9302c
;
}
table
.bg-dark-danger
:hover
{
background-color
:
#c9302c
;
}
table
.bg-primary
:hover
{
background-color
:
#1C
5484
;
}
table
.bg-primary
:hover
{
background-color
:
#1c
5484
;
}
table
.bg-primary
a
{
color
:
#fff
;
}
table
.bg-primary
a
{
color
:
#fff
;
}
.block-label
{
display
:
block
;
}
.block-label
{
display
:
block
;
}
.fake-input
{
position
:
absolute
;
pointer-events
:
none
;
top
:
0
;
}
.fake-input
{
position
:
absolute
;
pointer-events
:
none
;
top
:
0
;
}
input
.pill
{
position
:
absolute
;
opacity
:
0
;
}
input
.pill
{
position
:
absolute
;
opacity
:
0
;
}
...
...
cps/static/js/caliBlur.js
View file @
725fc658
...
@@ -677,7 +677,7 @@ $(".navbar-collapse.collapse.in").before('<div class="sidebar-backdrop"></div>')
...
@@ -677,7 +677,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/filter_list.js
View file @
725fc658
...
@@ -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/main.js
View file @
725fc658
...
@@ -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
{
...
...
cps/static/js/table.js
View file @
725fc658
...
@@ -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
=
[];
...
...
cps/tasks/upload.py
View file @
725fc658
...
@@ -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 @
725fc658
...
@@ -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/usermanagement.py
View file @
725fc658
...
@@ -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 @
725fc658
...
@@ -216,7 +216,7 @@ def update_view():
...
@@ -216,7 +216,7 @@ def update_view():
for
param
in
to_save
[
element
]:
for
param
in
to_save
[
element
]:
current_user
.
set_view_property
(
element
,
param
,
to_save
[
element
][
param
])
current_user
.
set_view_property
(
element
,
param
,
to_save
[
element
][
param
])
except
Exception
as
e
:
except
Exception
as
e
:
log
.
error
(
"Could not save view_settings:
%
r
%
r: e"
,
request
,
to_save
,
e
)
log
.
error
(
"Could not save view_settings:
%
r
%
r:
%
e"
,
request
,
to_save
,
e
)
return
"Invalid request"
,
400
return
"Invalid request"
,
400
return
"1"
,
200
return
"1"
,
200
...
@@ -340,7 +340,7 @@ def get_matching_tags():
...
@@ -340,7 +340,7 @@ def get_matching_tags():
return
json_dumps
return
json_dumps
def
render_books_list
(
data
,
sort
,
book_id
,
page
):
def
get_sort_function
(
sort
,
data
):
order
=
[
db
.
Books
.
timestamp
.
desc
()]
order
=
[
db
.
Books
.
timestamp
.
desc
()]
if
sort
==
'stored'
:
if
sort
==
'stored'
:
sort
=
current_user
.
get_view_property
(
data
,
'stored'
)
sort
=
current_user
.
get_view_property
(
data
,
'stored'
)
...
@@ -366,6 +366,11 @@ def render_books_list(data, sort, book_id, page):
...
@@ -366,6 +366,11 @@ def render_books_list(data, sort, book_id, page):
order
=
[
db
.
Books
.
series_index
.
asc
()]
order
=
[
db
.
Books
.
series_index
.
asc
()]
if
sort
==
'seriesdesc'
:
if
sort
==
'seriesdesc'
:
order
=
[
db
.
Books
.
series_index
.
desc
()]
order
=
[
db
.
Books
.
series_index
.
desc
()]
return
order
def
render_books_list
(
data
,
sort
,
book_id
,
page
):
order
=
get_sort_function
(
sort
,
data
)
if
data
==
"rated"
:
if
data
==
"rated"
:
if
current_user
.
check_visibility
(
constants
.
SIDEBAR_BEST_RATED
):
if
current_user
.
check_visibility
(
constants
.
SIDEBAR_BEST_RATED
):
...
@@ -453,18 +458,11 @@ def render_hot_books(page):
...
@@ -453,18 +458,11 @@ def render_hot_books(page):
def
render_downloaded_books
(
page
,
order
):
def
render_downloaded_books
(
page
,
order
):
if
current_user
.
check_visibility
(
constants
.
SIDEBAR_DOWNLOAD
):
if
current_user
.
check_visibility
(
constants
.
SIDEBAR_DOWNLOAD
):
# order = order or []
if
current_user
.
show_detail_random
():
if
current_user
.
show_detail_random
():
random
=
calibre_db
.
session
.
query
(
db
.
Books
)
.
filter
(
calibre_db
.
common_filters
())
\
random
=
calibre_db
.
session
.
query
(
db
.
Books
)
.
filter
(
calibre_db
.
common_filters
())
\
.
order_by
(
func
.
random
())
.
limit
(
config
.
config_random_books
)
.
order_by
(
func
.
random
())
.
limit
(
config
.
config_random_books
)
else
:
else
:
random
=
false
()
random
=
false
()
# off = int(int(config.config_books_per_page) * (page - 1))
'''entries, random, pagination = calibre_db.fill_indexpage(page, 0,
db.Books,
db_filter,
order,
ub.ReadBook, db.Books.id==ub.ReadBook.book_id)'''
entries
,
__
,
pagination
=
calibre_db
.
fill_indexpage
(
page
,
entries
,
__
,
pagination
=
calibre_db
.
fill_indexpage
(
page
,
0
,
0
,
...
@@ -748,7 +746,7 @@ def list_books():
...
@@ -748,7 +746,7 @@ def list_books():
search
=
request
.
args
.
get
(
"search"
)
search
=
request
.
args
.
get
(
"search"
)
total_count
=
calibre_db
.
session
.
query
(
db
.
Books
)
.
count
()
total_count
=
calibre_db
.
session
.
query
(
db
.
Books
)
.
count
()
if
search
:
if
search
:
entries
,
filtered_count
,
pagination
=
calibre_db
.
get_search_results
(
search
,
off
,
order
,
limit
)
entries
,
filtered_count
,
__
=
calibre_db
.
get_search_results
(
search
,
off
,
order
,
limit
)
else
:
else
:
entries
,
__
,
__
=
calibre_db
.
fill_indexpage
((
int
(
off
)
/
(
int
(
limit
))
+
1
),
limit
,
db
.
Books
,
True
,
order
)
entries
,
__
,
__
=
calibre_db
.
fill_indexpage
((
int
(
off
)
/
(
int
(
limit
))
+
1
),
limit
,
db
.
Books
,
True
,
order
)
filtered_count
=
total_count
filtered_count
=
total_count
...
@@ -1411,30 +1409,7 @@ def logout():
...
@@ -1411,30 +1409,7 @@ def logout():
# ################################### Users own configuration #########################################################
# ################################### Users own configuration #########################################################
def
change_profile
(
kobo_support
,
local_oauth_check
,
oauth_status
,
translations
,
languages
):
@
web
.
route
(
"/me"
,
methods
=
[
"GET"
,
"POST"
])
@
login_required
def
profile
():
# downloads = list()
languages
=
calibre_db
.
speaking_language
()
translations
=
babel
.
list_translations
()
+
[
LC
(
'en'
)]
kobo_support
=
feature_support
[
'kobo'
]
and
config
.
config_kobo_sync
if
feature_support
[
'oauth'
]
and
config
.
config_login_type
==
2
:
oauth_status
=
get_oauth_status
()
local_oauth_check
=
oauth_check
else
:
oauth_status
=
None
local_oauth_check
=
{}
'''entries, __, pagination = calibre_db.fill_indexpage(page,
0,
db.Books,
ub.Downloads.user_id == int(current_user.id), # True,
[],
ub.Downloads, db.Books.id == ub.Downloads.book_id)'''
if
request
.
method
==
"POST"
:
to_save
=
request
.
form
.
to_dict
()
to_save
=
request
.
form
.
to_dict
()
current_user
.
random_books
=
0
current_user
.
random_books
=
0
if
current_user
.
role_passwd
()
or
current_user
.
role_admin
():
if
current_user
.
role_passwd
()
or
current_user
.
role_admin
():
...
@@ -1495,6 +1470,22 @@ def profile():
...
@@ -1495,6 +1470,22 @@ def profile():
log
.
error
(
"Database error:
%
s"
,
e
)
log
.
error
(
"Database error:
%
s"
,
e
)
flash
(
_
(
u"Database error:
%(error)
s."
,
error
=
e
),
category
=
"error"
)
flash
(
_
(
u"Database error:
%(error)
s."
,
error
=
e
),
category
=
"error"
)
@
web
.
route
(
"/me"
,
methods
=
[
"GET"
,
"POST"
])
@
login_required
def
profile
():
languages
=
calibre_db
.
speaking_language
()
translations
=
babel
.
list_translations
()
+
[
LC
(
'en'
)]
kobo_support
=
feature_support
[
'kobo'
]
and
config
.
config_kobo_sync
if
feature_support
[
'oauth'
]
and
config
.
config_login_type
==
2
:
oauth_status
=
get_oauth_status
()
local_oauth_check
=
oauth_check
else
:
oauth_status
=
None
local_oauth_check
=
{}
if
request
.
method
==
"POST"
:
change_profile
(
kobo_support
,
local_oauth_check
,
oauth_status
,
translations
,
languages
)
return
render_title_template
(
"user_edit.html"
,
return
render_title_template
(
"user_edit.html"
,
translations
=
translations
,
translations
=
translations
,
profile
=
1
,
profile
=
1
,
...
...
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