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
df91ca50
Commit
df91ca50
authored
Apr 09, 2021
by
cbartondock
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://github.com/janeczku/calibre-web
parents
eb599373
2d73f541
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
61 additions
and
31 deletions
+61
-31
admin.py
cps/admin.py
+29
-8
config_sql.py
cps/config_sql.py
+1
-1
db.py
cps/db.py
+2
-2
editbooks.py
cps/editbooks.py
+2
-2
gdriveutils.py
cps/gdriveutils.py
+1
-1
main.js
cps/static/js/main.js
+3
-1
table.js
cps/static/js/table.js
+11
-6
user_table.html
cps/templates/user_table.html
+6
-5
ub.py
cps/ub.py
+1
-1
web.py
cps/web.py
+5
-4
No files found.
cps/admin.py
View file @
df91ca50
...
...
@@ -37,7 +37,7 @@ from flask_babel import gettext as _
from
sqlalchemy
import
and_
from
sqlalchemy.orm.attributes
import
flag_modified
from
sqlalchemy.exc
import
IntegrityError
,
OperationalError
,
InvalidRequestError
from
sqlalchemy.sql.expression
import
func
,
or_
from
sqlalchemy.sql.expression
import
func
,
or_
,
text
from
.
import
constants
,
logger
,
helper
,
services
from
.cli
import
filepicker
...
...
@@ -244,6 +244,13 @@ def list_users():
off
=
request
.
args
.
get
(
"offset"
)
or
0
limit
=
request
.
args
.
get
(
"limit"
)
or
10
search
=
request
.
args
.
get
(
"search"
)
sort
=
request
.
args
.
get
(
"sort"
)
order
=
request
.
args
.
get
(
"order"
)
if
sort
and
order
:
order
=
text
(
sort
+
" "
+
order
)
else
:
order
=
ub
.
User
.
name
.
desc
()
all_user
=
ub
.
session
.
query
(
ub
.
User
)
if
not
config
.
config_anonbrowse
:
all_user
=
all_user
.
filter
(
ub
.
User
.
role
.
op
(
'&'
)(
constants
.
ROLE_ANONYMOUS
)
!=
constants
.
ROLE_ANONYMOUS
)
...
...
@@ -252,10 +259,10 @@ def list_users():
users
=
all_user
.
filter
(
or_
(
func
.
lower
(
ub
.
User
.
name
)
.
ilike
(
"
%
"
+
search
+
"
%
"
),
func
.
lower
(
ub
.
User
.
kindle_mail
)
.
ilike
(
"
%
"
+
search
+
"
%
"
),
func
.
lower
(
ub
.
User
.
email
)
.
ilike
(
"
%
"
+
search
+
"
%
"
)))
\
.
offset
(
off
)
.
limit
(
limit
)
.
all
()
.
o
rder_by
(
order
)
.
o
ffset
(
off
)
.
limit
(
limit
)
.
all
()
filtered_count
=
len
(
users
)
else
:
users
=
all_user
.
offset
(
off
)
.
limit
(
limit
)
.
all
()
users
=
all_user
.
o
rder_by
(
order
)
.
o
ffset
(
off
)
.
limit
(
limit
)
.
all
()
filtered_count
=
total_count
for
user
in
users
:
...
...
@@ -335,6 +342,9 @@ def edit_list_user(param):
elif
param
==
'kindle_mail'
:
user
.
kindle_mail
=
valid_email
(
vals
[
'value'
])
if
vals
[
'value'
]
else
""
elif
param
==
'role'
:
if
user
.
name
==
"Guest"
and
int
(
vals
[
'field_index'
])
in
\
[
constants
.
ROLE_ADMIN
,
constants
.
ROLE_PASSWD
,
constants
.
ROLE_EDIT_SHELFS
]:
raise
Exception
(
_
(
"Guest can't have this role"
))
if
vals
[
'value'
]
==
'true'
:
user
.
role
|=
int
(
vals
[
'field_index'
])
else
:
...
...
@@ -345,6 +355,8 @@ def edit_list_user(param):
return
_
(
u"No admin user remaining, can't remove admin role"
,
nick
=
user
.
name
),
400
user
.
role
&=
~
int
(
vals
[
'field_index'
])
elif
param
==
'sidebar_view'
:
if
user
.
name
==
"Guest"
and
int
(
vals
[
'field_index'
])
==
constants
.
SIDEBAR_READ_AND_UNREAD
:
raise
Exception
(
_
(
"Guest can't have this view"
))
if
vals
[
'value'
]
==
'true'
:
user
.
sidebar_view
|=
int
(
vals
[
'field_index'
])
else
:
...
...
@@ -358,6 +370,8 @@ def edit_list_user(param):
elif
param
==
'denied_column_value'
:
user
.
denied_column_value
=
vals
[
'value'
]
elif
param
==
'locale'
:
if
user
.
name
==
"Guest"
:
raise
Exception
(
_
(
"Guest's Locale is determined automatically and can't be set"
))
user
.
locale
=
vals
[
'value'
]
elif
param
==
'default_language'
:
user
.
default_language
=
vals
[
'value'
]
...
...
@@ -1185,10 +1199,14 @@ def _handle_edit_user(to_save, content, languages, translations, kobo_support):
if
to_save
.
get
(
"delete"
):
if
ub
.
session
.
query
(
ub
.
User
)
.
filter
(
ub
.
User
.
role
.
op
(
'&'
)(
constants
.
ROLE_ADMIN
)
==
constants
.
ROLE_ADMIN
,
ub
.
User
.
id
!=
content
.
id
)
.
count
():
ub
.
session
.
query
(
ub
.
User
)
.
filter
(
ub
.
User
.
id
==
content
.
id
)
.
delete
()
ub
.
session_commit
()
flash
(
_
(
u"User '
%(nick)
s' deleted"
,
nick
=
content
.
name
),
category
=
"success"
)
return
redirect
(
url_for
(
'admin.admin'
))
if
content
.
name
!=
"Guest"
:
ub
.
session
.
query
(
ub
.
User
)
.
filter
(
ub
.
User
.
id
==
content
.
id
)
.
delete
()
ub
.
session_commit
()
flash
(
_
(
u"User '
%(nick)
s' deleted"
,
nick
=
content
.
name
),
category
=
"success"
)
return
redirect
(
url_for
(
'admin.admin'
))
else
:
flash
(
_
(
u"Can't delete Guest User"
),
category
=
"error"
)
return
redirect
(
url_for
(
'admin.admin'
))
else
:
flash
(
_
(
u"No admin user remaining, can't delete user"
,
nick
=
content
.
name
),
category
=
"error"
)
return
redirect
(
url_for
(
'admin.admin'
))
...
...
@@ -1255,6 +1273,7 @@ def _handle_edit_user(to_save, content, languages, translations, kobo_support):
except
OperationalError
:
ub
.
session
.
rollback
()
flash
(
_
(
u"Settings DB is not Writeable"
),
category
=
"error"
)
return
""
@
admi
.
route
(
"/admin/user/new"
,
methods
=
[
"GET"
,
"POST"
])
...
...
@@ -1350,7 +1369,9 @@ def edit_user(user_id):
kobo_support
=
feature_support
[
'kobo'
]
and
config
.
config_kobo_sync
if
request
.
method
==
"POST"
:
to_save
=
request
.
form
.
to_dict
()
_handle_edit_user
(
to_save
,
content
,
languages
,
translations
,
kobo_support
)
resp
=
_handle_edit_user
(
to_save
,
content
,
languages
,
translations
,
kobo_support
)
if
resp
:
return
resp
return
render_title_template
(
"user_edit.html"
,
translations
=
translations
,
languages
=
languages
,
...
...
cps/config_sql.py
View file @
df91ca50
...
...
@@ -24,7 +24,7 @@ import sys
from
sqlalchemy
import
exc
,
Column
,
String
,
Integer
,
SmallInteger
,
Boolean
,
BLOB
,
JSON
from
sqlalchemy.exc
import
OperationalError
try
:
# Compability with sqlalchemy 2.0
# Compa
ti
bility with sqlalchemy 2.0
from
sqlalchemy.orm
import
declarative_base
except
ImportError
:
from
sqlalchemy.ext.declarative
import
declarative_base
...
...
cps/db.py
View file @
df91ca50
...
...
@@ -33,7 +33,7 @@ from sqlalchemy.orm.collections import InstrumentedList
from
sqlalchemy.ext.declarative
import
DeclarativeMeta
from
sqlalchemy.exc
import
OperationalError
try
:
# Compability with sqlalchemy 2.0
# Compa
ti
bility with sqlalchemy 2.0
from
sqlalchemy.orm
import
declarative_base
except
ImportError
:
from
sqlalchemy.ext.declarative
import
declarative_base
...
...
@@ -393,7 +393,7 @@ class AlchemyEncoder(json.JSONEncoder):
if
isinstance
(
o
.
__class__
,
DeclarativeMeta
):
# an SQLAlchemy class
fields
=
{}
for
field
in
[
x
for
x
in
dir
(
o
)
if
not
x
.
startswith
(
'_'
)
and
x
!=
'metadata'
]:
for
field
in
[
x
for
x
in
dir
(
o
)
if
not
x
.
startswith
(
'_'
)
and
x
!=
'metadata'
and
x
!=
"password"
]:
if
field
==
'books'
:
continue
data
=
o
.
__getattribute__
(
field
)
...
...
cps/editbooks.py
View file @
df91ca50
...
...
@@ -238,14 +238,14 @@ def modify_identifiers(input_identifiers, db_identifiers, db_session):
@
editbook
.
route
(
"/ajax/delete/<int:book_id>"
)
@
login_required
def
delete_book_from_details
(
book_id
):
return
Response
(
delete_book
(
book_id
,
""
,
True
),
mimetype
=
'application/json'
)
return
Response
(
delete_book
(
book_id
,
""
,
True
),
mimetype
=
'application/json'
)
@
editbook
.
route
(
"/delete/<int:book_id>"
,
defaults
=
{
'book_format'
:
""
})
@
editbook
.
route
(
"/delete/<int:book_id>/<string:book_format>"
)
@
login_required
def
delete_book_ajax
(
book_id
,
book_format
):
return
delete_book
(
book_id
,
book_format
,
False
)
return
delete_book
(
book_id
,
book_format
,
False
)
def
delete_whole_book
(
book_id
,
book
):
...
...
cps/gdriveutils.py
View file @
df91ca50
...
...
@@ -29,7 +29,7 @@ from sqlalchemy import Column, UniqueConstraint
from
sqlalchemy
import
String
,
Integer
from
sqlalchemy.orm
import
sessionmaker
,
scoped_session
try
:
# Compability with sqlalchemy 2.0
# Compa
ti
bility with sqlalchemy 2.0
from
sqlalchemy.orm
import
declarative_base
except
ImportError
:
from
sqlalchemy.ext.declarative
import
declarative_base
...
...
cps/static/js/main.js
View file @
df91ca50
...
...
@@ -142,10 +142,11 @@ $("#delete_confirm").click(function() {
//get data-id attribute of the clicked element
var
deleteId
=
$
(
this
).
data
(
"delete-id"
);
var
bookFormat
=
$
(
this
).
data
(
"delete-format"
);
var
ajaxResponse
=
$
(
this
).
data
(
"ajax"
);
if
(
bookFormat
)
{
window
.
location
.
href
=
getPath
()
+
"/delete/"
+
deleteId
+
"/"
+
bookFormat
;
}
else
{
if
(
$
(
this
).
data
(
"delete-format"
)
)
{
if
(
ajaxResponse
)
{
path
=
getPath
()
+
"/ajax/delete/"
+
deleteId
;
$
.
ajax
({
method
:
"get"
,
...
...
@@ -187,6 +188,7 @@ $("#deleteModal").on("show.bs.modal", function(e) {
}
$
(
e
.
currentTarget
).
find
(
"#delete_confirm"
).
data
(
"delete-id"
,
bookId
);
$
(
e
.
currentTarget
).
find
(
"#delete_confirm"
).
data
(
"delete-format"
,
bookfomat
);
$
(
e
.
currentTarget
).
find
(
"#delete_confirm"
).
data
(
"ajax"
,
$
(
e
.
relatedTarget
).
data
(
"ajax"
));
});
...
...
cps/static/js/table.js
View file @
df91ca50
...
...
@@ -459,8 +459,8 @@ $(function() {
$
(
"input[data-name='admin_role'][data-pk='"
+
guest
.
data
(
"pk"
)
+
"']"
).
prop
(
"disabled"
,
true
);
$
(
"input[data-name='passwd_role'][data-pk='"
+
guest
.
data
(
"pk"
)
+
"']"
).
prop
(
"disabled"
,
true
);
$
(
"input[data-name='edit_shelf_role'][data-pk='"
+
guest
.
data
(
"pk"
)
+
"']"
).
prop
(
"disabled"
,
true
);
// ToDo: Disable delete
$
(
"input[data-name='sidebar_read_and_unread'][data-pk='"
+
guest
.
data
(
"pk"
)
+
"']"
).
prop
(
"disabled"
,
true
);
$
(
".user-remove[data-pk='"
+
guest
.
data
(
"pk"
)
+
"']"
).
prop
(
"disabled"
,
true
);
},
// eslint-disable-next-line no-unused-vars
...
...
@@ -603,7 +603,7 @@ function EbookActions (value, row) {
/* Function for deleting books */
function
UserActions
(
value
,
row
)
{
return
[
"<div class=
\"
user-remove
\"
data-target=
\"
#GeneralDeleteModal
\"
title=
\"
Remove
\"
>"
,
"<div class=
\"
user-remove
\"
data-
pk=
\"
"
+
row
.
id
+
"
\"
data-
target=
\"
#GeneralDeleteModal
\"
title=
\"
Remove
\"
>"
,
"<i class=
\"
glyphicon glyphicon-trash
\"
></i>"
,
"</div>"
].
join
(
""
);
...
...
@@ -618,14 +618,14 @@ function responseHandler(res) {
}
function
singleUserFormatter
(
value
,
row
)
{
return
'<a class="btn btn-default" href="/admin/user/'
+
row
.
id
+
'">'
+
this
.
buttontext
+
'</a>'
return
'<a class="btn btn-default" href="
'
+
window
.
location
.
pathname
+
'/../..
/admin/user/'
+
row
.
id
+
'">'
+
this
.
buttontext
+
'</a>'
}
function
checkboxFormatter
(
value
,
row
,
index
){
if
(
value
&
this
.
column
)
return
'<input type="checkbox" class="chk" data-pk="'
+
row
.
id
+
'" data-name="'
+
this
.
name
+
'" checked onchange="checkboxChange(this, '
+
row
.
id
+
',
\'
'
+
this
.
field
+
'
\'
, '
+
this
.
column
+
')">'
;
return
'<input type="checkbox" class="chk" data-pk="'
+
row
.
id
+
'" data-name="'
+
this
.
field
+
'" checked onchange="checkboxChange(this, '
+
row
.
id
+
',
\'
'
+
this
.
name
+
'
\'
, '
+
this
.
column
+
')">'
;
else
return
'<input type="checkbox" class="chk" data-pk="'
+
row
.
id
+
'" data-name="'
+
this
.
name
+
'" onchange="checkboxChange(this, '
+
row
.
id
+
',
\'
'
+
this
.
field
+
'
\'
, '
+
this
.
column
+
')">'
;
return
'<input type="checkbox" class="chk" data-pk="'
+
row
.
id
+
'" data-name="'
+
this
.
field
+
'" onchange="checkboxChange(this, '
+
row
.
id
+
',
\'
'
+
this
.
name
+
'
\'
, '
+
this
.
column
+
')">'
;
}
function
checkboxChange
(
checkbox
,
userId
,
field
,
field_index
)
{
...
...
@@ -732,6 +732,11 @@ function user_handle (userId) {
});
}
function
checkboxSorter
(
a
,
b
,
c
,
d
)
{
return
a
-
b
}
function
test
(){
console
.
log
(
"hello"
);
}
cps/templates/user_table.html
View file @
df91ca50
...
...
@@ -111,15 +111,16 @@
{{ user_table_row('allowed_column_value', _("Edit Allowed Column Values"), _("Allowed Column Values"), false, true, 2) }}
{{ user_table_row('denied_column_value', _("Edit Denied Column Values"), _("Denied Columns Values"), false, true, 3) }}
{{ user_checkbox_row("role", "admin_role", _('Admin'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "download_role",_('Upload'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "upload_role", _('Download'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "edit_role", _('Edit'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "passwd_role", _('Change Password'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "
edit_shelf_role", _('Edit Public Shelfs
'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "d
elete_role", _('Delete
'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "
upload_role",_('Upload
'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "d
ownload_role", _('Download
'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "viewer_role", _('View'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "edit_role", _('Edit'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "delete_role", _('Delete'), visiblility, all_roles)}}
{{ user_checkbox_row("role", "edit_shelf_role", _('Edit Public Shelfs'), visiblility, all_roles)}}
{{ user_checkbox_row("sidebar_view", "detail_random", _('Show Random Books in Detail View'), visiblility, sidebar_settings)}}
{{ user_checkbox_row("sidebar_view", "sidebar_language", _('Show language selection'), visiblility, sidebar_settings)}}
{{ user_checkbox_row("sidebar_view", "sidebar_read_and_unread", _('Show read/unread selection'), visiblility, sidebar_settings)}}
{{ user_checkbox_row("sidebar_view", "sidebar_series", _('Show series selection'), visiblility, sidebar_settings)}}
{{ user_checkbox_row("sidebar_view", "sidebar_category", _('Show category selection'), visiblility, sidebar_settings)}}
{{ user_checkbox_row("sidebar_view", "sidebar_random", _('Show random books'), visiblility, sidebar_settings)}}
...
...
cps/ub.py
View file @
df91ca50
...
...
@@ -44,7 +44,7 @@ from sqlalchemy import String, Integer, SmallInteger, Boolean, DateTime, Float,
from
sqlalchemy.orm.attributes
import
flag_modified
from
sqlalchemy.sql.expression
import
func
try
:
# Compability with sqlalchemy 2.0
# Compa
ti
bility with sqlalchemy 2.0
from
sqlalchemy.orm
import
declarative_base
except
ImportError
:
from
sqlalchemy.ext.declarative
import
declarative_base
...
...
cps/web.py
View file @
df91ca50
...
...
@@ -755,11 +755,12 @@ def books_table():
def
list_books
():
off
=
request
.
args
.
get
(
"offset"
)
or
0
limit
=
request
.
args
.
get
(
"limit"
)
or
config
.
config_books_per_page
# sort = request.args.get("sort")
if
request
.
args
.
get
(
"order"
)
==
'desc'
:
order
=
[
db
.
Books
.
timestamp
.
desc
()]
sort
=
request
.
args
.
get
(
"sort"
)
order
=
request
.
args
.
get
(
"order"
)
if
sort
and
order
:
order
=
[
text
(
sort
+
" "
+
order
)]
else
:
order
=
[
db
.
Books
.
timestamp
.
a
sc
()]
order
=
[
db
.
Books
.
timestamp
.
de
sc
()]
search
=
request
.
args
.
get
(
"search"
)
total_count
=
calibre_db
.
session
.
query
(
db
.
Books
)
.
count
()
if
search
:
...
...
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