Commit df91ca50 authored by cbartondock's avatar cbartondock

Merge branch 'master' of https://github.com/janeczku/calibre-web

parents eb599373 2d73f541
...@@ -37,7 +37,7 @@ from flask_babel import gettext as _ ...@@ -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(): ...@@ -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(): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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():
ub.session.query(ub.User).filter(ub.User.id == content.id).delete() if content.name != "Guest":
ub.session_commit() ub.session.query(ub.User).filter(ub.User.id == content.id).delete()
flash(_(u"User '%(nick)s' deleted", nick=content.name), category="success") ub.session_commit()
return redirect(url_for('admin.admin')) 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: 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): ...@@ -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): ...@@ -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 ...@@ -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 ...@@ -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): ...@@ -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)
......
...@@ -238,14 +238,14 @@ def modify_identifiers(input_identifiers, db_identifiers, db_session): ...@@ -238,14 +238,14 @@ def modify_identifiers(input_identifiers, db_identifiers, db_session):
@editbook.route("/ajax/delete/<int:book_id>") @editbook.route("/ajax/delete/<int:book_id>")
@login_required @login_required
def delete_book_from_details(book_id): 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>", defaults={'book_format': ""})
@editbook.route("/delete/<int:book_id>/<string:book_format>") @editbook.route("/delete/<int:book_id>/<string:book_format>")
@login_required @login_required
def delete_book_ajax(book_id, book_format): 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): def delete_whole_book(book_id, book):
......
...@@ -29,7 +29,7 @@ from sqlalchemy import Column, UniqueConstraint ...@@ -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() { ...@@ -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) { ...@@ -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() { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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 @@ ...@@ -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, ...@@ -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(): ...@@ -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:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment