This commit is contained in:
cbartondock 2021-04-08 20:25:02 -04:00
commit df91ca500f
10 changed files with 61 additions and 31 deletions

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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"));
}); });

View File

@ -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");
} }

View File

@ -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)}}

View File

@ -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

View File

@ -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: