Merge branch 'master' of https://github.com/janeczku/calibre-web
This commit is contained in:
commit
df91ca500f
29
cps/admin.py
29
cps/admin.py
|
@ -37,7 +37,7 @@ from flask_babel import gettext as _
|
||||||
from sqlalchemy import and_
|
from sqlalchemy import and_
|
||||||
from sqlalchemy.orm.attributes import flag_modified
|
from sqlalchemy.orm.attributes import flag_modified
|
||||||
from sqlalchemy.exc import IntegrityError, OperationalError, InvalidRequestError
|
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 . import constants, logger, helper, services
|
||||||
from .cli import filepicker
|
from .cli import filepicker
|
||||||
|
@ -244,6 +244,13 @@ def list_users():
|
||||||
off = request.args.get("offset") or 0
|
off = request.args.get("offset") or 0
|
||||||
limit = request.args.get("limit") or 10
|
limit = request.args.get("limit") or 10
|
||||||
search = request.args.get("search")
|
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)
|
all_user = ub.session.query(ub.User)
|
||||||
if not config.config_anonbrowse:
|
if not config.config_anonbrowse:
|
||||||
all_user = all_user.filter(ub.User.role.op('&')(constants.ROLE_ANONYMOUS) != constants.ROLE_ANONYMOUS)
|
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 + "%"),
|
users = all_user.filter(or_(func.lower(ub.User.name).ilike("%" + search + "%"),
|
||||||
func.lower(ub.User.kindle_mail).ilike("%" + search + "%"),
|
func.lower(ub.User.kindle_mail).ilike("%" + search + "%"),
|
||||||
func.lower(ub.User.email).ilike("%" + search + "%")))\
|
func.lower(ub.User.email).ilike("%" + search + "%")))\
|
||||||
.offset(off).limit(limit).all()
|
.order_by(order).offset(off).limit(limit).all()
|
||||||
filtered_count = len(users)
|
filtered_count = len(users)
|
||||||
else:
|
else:
|
||||||
users = all_user.offset(off).limit(limit).all()
|
users = all_user.order_by(order).offset(off).limit(limit).all()
|
||||||
filtered_count = total_count
|
filtered_count = total_count
|
||||||
|
|
||||||
for user in users:
|
for user in users:
|
||||||
|
@ -335,6 +342,9 @@ def edit_list_user(param):
|
||||||
elif param == 'kindle_mail':
|
elif param == 'kindle_mail':
|
||||||
user.kindle_mail = valid_email(vals['value']) if vals['value'] else ""
|
user.kindle_mail = valid_email(vals['value']) if vals['value'] else ""
|
||||||
elif param == 'role':
|
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':
|
if vals['value'] == 'true':
|
||||||
user.role |= int(vals['field_index'])
|
user.role |= int(vals['field_index'])
|
||||||
else:
|
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
|
return _(u"No admin user remaining, can't remove admin role", nick=user.name), 400
|
||||||
user.role &= ~int(vals['field_index'])
|
user.role &= ~int(vals['field_index'])
|
||||||
elif param == 'sidebar_view':
|
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':
|
if vals['value'] == 'true':
|
||||||
user.sidebar_view |= int(vals['field_index'])
|
user.sidebar_view |= int(vals['field_index'])
|
||||||
else:
|
else:
|
||||||
|
@ -358,6 +370,8 @@ def edit_list_user(param):
|
||||||
elif param == 'denied_column_value':
|
elif param == 'denied_column_value':
|
||||||
user.denied_column_value = vals['value']
|
user.denied_column_value = vals['value']
|
||||||
elif param == 'locale':
|
elif param == 'locale':
|
||||||
|
if user.name == "Guest":
|
||||||
|
raise Exception(_("Guest's Locale is determined automatically and can't be set"))
|
||||||
user.locale = vals['value']
|
user.locale = vals['value']
|
||||||
elif param == 'default_language':
|
elif param == 'default_language':
|
||||||
user.default_language = vals['value']
|
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 to_save.get("delete"):
|
||||||
if ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN,
|
if ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN,
|
||||||
ub.User.id != content.id).count():
|
ub.User.id != content.id).count():
|
||||||
|
if content.name != "Guest":
|
||||||
ub.session.query(ub.User).filter(ub.User.id == content.id).delete()
|
ub.session.query(ub.User).filter(ub.User.id == content.id).delete()
|
||||||
ub.session_commit()
|
ub.session_commit()
|
||||||
flash(_(u"User '%(nick)s' deleted", nick=content.name), category="success")
|
flash(_(u"User '%(nick)s' deleted", nick=content.name), category="success")
|
||||||
return redirect(url_for('admin.admin'))
|
return redirect(url_for('admin.admin'))
|
||||||
|
else:
|
||||||
|
flash(_(u"Can't delete Guest User"), category="error")
|
||||||
|
return redirect(url_for('admin.admin'))
|
||||||
else:
|
else:
|
||||||
flash(_(u"No admin user remaining, can't delete user", nick=content.name), category="error")
|
flash(_(u"No admin user remaining, can't delete user", nick=content.name), category="error")
|
||||||
return redirect(url_for('admin.admin'))
|
return redirect(url_for('admin.admin'))
|
||||||
|
@ -1255,6 +1273,7 @@ def _handle_edit_user(to_save, content, languages, translations, kobo_support):
|
||||||
except OperationalError:
|
except OperationalError:
|
||||||
ub.session.rollback()
|
ub.session.rollback()
|
||||||
flash(_(u"Settings DB is not Writeable"), category="error")
|
flash(_(u"Settings DB is not Writeable"), category="error")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@admi.route("/admin/user/new", methods=["GET", "POST"])
|
@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
|
kobo_support = feature_support['kobo'] and config.config_kobo_sync
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
to_save = request.form.to_dict()
|
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",
|
return render_title_template("user_edit.html",
|
||||||
translations=translations,
|
translations=translations,
|
||||||
languages=languages,
|
languages=languages,
|
||||||
|
|
|
@ -24,7 +24,7 @@ import sys
|
||||||
from sqlalchemy import exc, Column, String, Integer, SmallInteger, Boolean, BLOB, JSON
|
from sqlalchemy import exc, Column, String, Integer, SmallInteger, Boolean, BLOB, JSON
|
||||||
from sqlalchemy.exc import OperationalError
|
from sqlalchemy.exc import OperationalError
|
||||||
try:
|
try:
|
||||||
# Compability with sqlalchemy 2.0
|
# Compatibility with sqlalchemy 2.0
|
||||||
from sqlalchemy.orm import declarative_base
|
from sqlalchemy.orm import declarative_base
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
|
@ -33,7 +33,7 @@ from sqlalchemy.orm.collections import InstrumentedList
|
||||||
from sqlalchemy.ext.declarative import DeclarativeMeta
|
from sqlalchemy.ext.declarative import DeclarativeMeta
|
||||||
from sqlalchemy.exc import OperationalError
|
from sqlalchemy.exc import OperationalError
|
||||||
try:
|
try:
|
||||||
# Compability with sqlalchemy 2.0
|
# Compatibility with sqlalchemy 2.0
|
||||||
from sqlalchemy.orm import declarative_base
|
from sqlalchemy.orm import declarative_base
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
@ -393,7 +393,7 @@ class AlchemyEncoder(json.JSONEncoder):
|
||||||
if isinstance(o.__class__, DeclarativeMeta):
|
if isinstance(o.__class__, DeclarativeMeta):
|
||||||
# an SQLAlchemy class
|
# an SQLAlchemy class
|
||||||
fields = {}
|
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':
|
if field == 'books':
|
||||||
continue
|
continue
|
||||||
data = o.__getattribute__(field)
|
data = o.__getattribute__(field)
|
||||||
|
|
|
@ -29,7 +29,7 @@ from sqlalchemy import Column, UniqueConstraint
|
||||||
from sqlalchemy import String, Integer
|
from sqlalchemy import String, Integer
|
||||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||||
try:
|
try:
|
||||||
# Compability with sqlalchemy 2.0
|
# Compatibility with sqlalchemy 2.0
|
||||||
from sqlalchemy.orm import declarative_base
|
from sqlalchemy.orm import declarative_base
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
|
@ -142,10 +142,11 @@ $("#delete_confirm").click(function() {
|
||||||
//get data-id attribute of the clicked element
|
//get data-id attribute of the clicked element
|
||||||
var deleteId = $(this).data("delete-id");
|
var deleteId = $(this).data("delete-id");
|
||||||
var bookFormat = $(this).data("delete-format");
|
var bookFormat = $(this).data("delete-format");
|
||||||
|
var ajaxResponse = $(this).data("ajax");
|
||||||
if (bookFormat) {
|
if (bookFormat) {
|
||||||
window.location.href = getPath() + "/delete/" + deleteId + "/" + bookFormat;
|
window.location.href = getPath() + "/delete/" + deleteId + "/" + bookFormat;
|
||||||
} else {
|
} else {
|
||||||
if ($(this).data("delete-format")) {
|
if (ajaxResponse) {
|
||||||
path = getPath() + "/ajax/delete/" + deleteId;
|
path = getPath() + "/ajax/delete/" + deleteId;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
method:"get",
|
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-id", bookId);
|
||||||
$(e.currentTarget).find("#delete_confirm").data("delete-format", bookfomat);
|
$(e.currentTarget).find("#delete_confirm").data("delete-format", bookfomat);
|
||||||
|
$(e.currentTarget).find("#delete_confirm").data("ajax", $(e.relatedTarget).data("ajax"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -459,8 +459,8 @@ $(function() {
|
||||||
$("input[data-name='admin_role'][data-pk='"+guest.data("pk")+"']").prop("disabled", true);
|
$("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='passwd_role'][data-pk='"+guest.data("pk")+"']").prop("disabled", true);
|
||||||
$("input[data-name='edit_shelf_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
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
@ -603,7 +603,7 @@ function EbookActions (value, row) {
|
||||||
/* Function for deleting books */
|
/* Function for deleting books */
|
||||||
function UserActions (value, row) {
|
function UserActions (value, row) {
|
||||||
return [
|
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>",
|
"<i class=\"glyphicon glyphicon-trash\"></i>",
|
||||||
"</div>"
|
"</div>"
|
||||||
].join("");
|
].join("");
|
||||||
|
@ -618,14 +618,14 @@ function responseHandler(res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function singleUserFormatter(value, row) {
|
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){
|
function checkboxFormatter(value, row, index){
|
||||||
if(value & this.column)
|
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
|
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) {
|
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(){
|
function test(){
|
||||||
console.log("hello");
|
console.log("hello");
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,15 +111,16 @@
|
||||||
{{ user_table_row('allowed_column_value', _("Edit Allowed Column Values"), _("Allowed Column Values"), false, true, 2) }}
|
{{ 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_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", "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", "passwd_role", _('Change Password'), visiblility, all_roles)}}
|
||||||
{{ user_checkbox_row("role", "edit_shelf_role", _('Edit Public Shelfs'), visiblility, all_roles)}}
|
{{ user_checkbox_row("role", "upload_role",_('Upload'), visiblility, all_roles)}}
|
||||||
{{ user_checkbox_row("role", "delete_role", _('Delete'), visiblility, all_roles)}}
|
{{ user_checkbox_row("role", "download_role", _('Download'), visiblility, all_roles)}}
|
||||||
{{ user_checkbox_row("role", "viewer_role", _('View'), 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", "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_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_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_category", _('Show category selection'), visiblility, sidebar_settings)}}
|
||||||
{{ user_checkbox_row("sidebar_view", "sidebar_random", _('Show random books'), visiblility, sidebar_settings)}}
|
{{ user_checkbox_row("sidebar_view", "sidebar_random", _('Show random books'), visiblility, sidebar_settings)}}
|
||||||
|
|
|
@ -44,7 +44,7 @@ from sqlalchemy import String, Integer, SmallInteger, Boolean, DateTime, Float,
|
||||||
from sqlalchemy.orm.attributes import flag_modified
|
from sqlalchemy.orm.attributes import flag_modified
|
||||||
from sqlalchemy.sql.expression import func
|
from sqlalchemy.sql.expression import func
|
||||||
try:
|
try:
|
||||||
# Compability with sqlalchemy 2.0
|
# Compatibility with sqlalchemy 2.0
|
||||||
from sqlalchemy.orm import declarative_base
|
from sqlalchemy.orm import declarative_base
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
|
@ -755,11 +755,12 @@ def books_table():
|
||||||
def list_books():
|
def list_books():
|
||||||
off = request.args.get("offset") or 0
|
off = request.args.get("offset") or 0
|
||||||
limit = request.args.get("limit") or config.config_books_per_page
|
limit = request.args.get("limit") or config.config_books_per_page
|
||||||
# sort = request.args.get("sort")
|
sort = request.args.get("sort")
|
||||||
if request.args.get("order") == 'desc':
|
order = request.args.get("order")
|
||||||
order = [db.Books.timestamp.desc()]
|
if sort and order:
|
||||||
|
order = [text(sort + " " + order)]
|
||||||
else:
|
else:
|
||||||
order = [db.Books.timestamp.asc()]
|
order = [db.Books.timestamp.desc()]
|
||||||
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:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user