From 0992bafe308249aad9ef56f5005f11c59ccf9512 Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Sat, 13 Feb 2021 13:17:02 +0100 Subject: [PATCH] Bulk User management --- cps/admin.py | 39 ++++++- cps/constants.py | 20 ++++ cps/static/js/table.js | 57 ++++++++-- cps/templates/user_table.html | 41 ++++--- test/Calibre-Web TestSummary_Linux.html | 138 ++++++++++++++++-------- 5 files changed, 226 insertions(+), 69 deletions(-) diff --git a/cps/admin.py b/cps/admin.py index aa608ef5..30b268cb 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -35,6 +35,7 @@ from flask import Blueprint, flash, redirect, url_for, abort, request, make_resp from flask_login import login_required, current_user, logout_user, confirm_login 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_ @@ -225,11 +226,12 @@ def edit_user_table(): return render_title_template("user_table.html", users=allUser.all(), visiblility=visibility, - all_roles = constants.ALL_ROLES, + all_roles=constants.ALL_ROLES, + sidebar_settings=constants.sidebar_settings, title=_(u"Edit Users"), page="usertable") -@admi.route("/axjax/listusers") +@admi.route("/ajax/listusers") @login_required @admin_required def list_users(): @@ -242,8 +244,11 @@ def list_users(): all_user = all_user.filter(ub.User.role.op('&')(constants.ROLE_ANONYMOUS) != constants.ROLE_ANONYMOUS) total_count = all_user.count() if search: - users = all_user.filter().offset(off).limit(limit).all() - filtered_count = users.length() + users = all_user.filter(or_(func.lower(ub.User.nickname).ilike("%" + search + "%"), + func.lower(ub.User.kindle_mail).ilike("%" + search + "%"), + func.lower(ub.User.email).ilike("%" + search + "%")))\ + .offset(off).limit(limit).all() + filtered_count = len(users) else: users = all_user.offset(off).limit(limit).all() filtered_count = total_count @@ -255,6 +260,14 @@ def list_users(): response.headers["Content-Type"] = "application/json; charset=utf-8" return response +@admi.route("/ajax/deleteuser") +@login_required +@admin_required +def delete_user(): + # ToDo User delete check also not last one + pass + return + @admi.route("/axjax/editlistusers/", methods=['POST']) @login_required @@ -285,6 +298,24 @@ def edit_list_user(param): return "" +@admi.route("/ajax/user_table_settings", methods=['POST']) +@login_required +@admin_required +def update_table_settings(): + # ToDo: Save table settings + current_user.view_settings['useredit'] = json.loads(request.data) + try: + try: + flag_modified(current_user, "view_settings") + except AttributeError: + pass + ub.session.commit() + except (InvalidRequestError, OperationalError): + log.error("Invalid request received: %r ", request, ) + return "Invalid request", 400 + return "" + + @admi.route("/admin/viewconfig", methods=["POST"]) @login_required @admin_required diff --git a/cps/constants.py b/cps/constants.py index 613d17ac..1712da3f 100644 --- a/cps/constants.py +++ b/cps/constants.py @@ -88,6 +88,26 @@ SIDEBAR_ARCHIVED = 1 << 15 SIDEBAR_DOWNLOAD = 1 << 16 SIDEBAR_LIST = 1 << 17 +sidebar_settings = { + "detail_random": DETAIL_RANDOM, + "sidebar_language": SIDEBAR_LANGUAGE, + "sidebar_series": SIDEBAR_SERIES, + "sidebar_category": SIDEBAR_CATEGORY, + "sidebar_random": SIDEBAR_RANDOM, + "sidebar_author": SIDEBAR_AUTHOR, + "sidebar_best_rated": SIDEBAR_BEST_RATED, + "sidebar_read_and_unread": SIDEBAR_READ_AND_UNREAD, + "sidebar_recent": SIDEBAR_RECENT, + "sidebar_sorted": SIDEBAR_SORTED, + "sidebar_publisher": SIDEBAR_PUBLISHER, + "sidebar_rating": SIDEBAR_RATING, + "sidebar_format": SIDEBAR_FORMAT, + "sidebar_archived": SIDEBAR_ARCHIVED, + "sidebar_download": SIDEBAR_DOWNLOAD, + "sidebar_list": SIDEBAR_LIST, + } + + ADMIN_USER_ROLES = sum(r for r in ALL_ROLES.values()) & ~ROLE_ANONYMOUS ADMIN_USER_SIDEBAR = (SIDEBAR_LIST << 1) - 1 diff --git a/cps/static/js/table.js b/cps/static/js/table.js index 0695ee92..b857fc95 100644 --- a/cps/static/js/table.js +++ b/cps/static/js/table.js @@ -116,7 +116,7 @@ $(function() { search: true, showColumns: true, searchAlign: "left", - showSearchButton : false, + showSearchButton : true, searchOnEnterKey: true, checkboxHeader: false, maintainMetaData: true, @@ -377,15 +377,24 @@ $(function() { search: true, showColumns: true, searchAlign: "left", - showSearchButton : false, + showSearchButton : true, searchOnEnterKey: true, - checkboxHeader: false, + checkboxHeader: true, maintainMetaData: true, responseHandler: responseHandler, columns: user_column, formatNoMatches: function () { return ""; }, + onPostBody () { + // var elements = ; + // Remove all checkboxes from Headers for showing the texts in the column selector + $('.columns [data-field]').each(function(){ + var elText = $(this).next().text(); + $(this).next().empty(); + $(this).next().text(elText); + }); + }, // eslint-disable-next-line no-unused-vars /*onEditableSave: function (field, row, oldvalue, $el) { if (field === "title" || field === "authors") { @@ -411,22 +420,47 @@ $(function() { var hidden = $("#user-table").bootstrapTable("getHiddenColumns"); var st = ""; visible.forEach(function(item) { - st += "\"" + item.field + "\":\"" + "true" + "\","; + st += "\"" + item.name + "\":\"" + "true" + "\","; }); hidden.forEach(function(item) { - st += "\"" + item.field + "\":\"" + "false" + "\","; + st += "\"" + item.name + "\":\"" + "false" + "\","; }); st = st.slice(0, -1); - /*$.ajax({ + $.ajax({ method:"post", contentType: "application/json; charset=utf-8", dataType: "json", - url: window.location.pathname + "/../../ajax/table_settings", + url: window.location.pathname + "/../../ajax/user_table_settings", data: "{" + st + "}", - });*/ + }); }, }); + function user_handle (userId) { + $.ajax({ + method:"post", + url: window.location.pathname + "/../../ajax/deleteuser", + data: {"userid":userId} + }); + $.ajax({ + method:"get", + url: window.location.pathname + "/../../ajax/listusers", + async: true, + timeout: 900, + success:function(data) { + $("#user-table").bootstrapTable("load", data); + } + }); + + + } + + + $("#user-table").on("click-cell.bs.table", function (field, value, row, $element) { + if (value === "denied_column_value") { + ConfirmDialog("btndeluser", $element.id, user_handle); + } + }); /*$("#user-table").on("check.bs.table check-all.bs.table uncheck.bs.table uncheck-all.bs.table", function (e, rowsAfter, rowsBefore) { @@ -474,7 +508,7 @@ function EbookActions (value, row) { /* Function for deleting books */ function UserActions (value, row) { return [ - "
", + "
", "", "
" ].join(""); @@ -507,3 +541,8 @@ function checkboxChange(checkbox, index){ reinit: false }); } + + +function checkboxHeader(element) { + console.log("hallo"); +} diff --git a/cps/templates/user_table.html b/cps/templates/user_table.html index 043b3339..3c6d4ed5 100644 --- a/cps/templates/user_table.html +++ b/cps/templates/user_table.html @@ -1,7 +1,8 @@ {% extends "layout.html" %} {% macro user_table_row(parameter, edit_text, show_text, validate) -%} {{_(title)}} + +
- - - + + + {{ user_table_row('nickname', _('Enter Username'), _('Username'), true) }} {{ user_table_row('email', _('Enter E-mail Address'), _('E-mail Address'), true) }} {{ user_table_row('kindle_mail', _('Enter Kindle E-mail Address'), _('Kindle E-mail'), true) }} - - - - - - - - + + + + + + + + {{ user_table_row('denied_tags', _("Enter Users's Locale"), _("Users's Locale"), true) }} {{ user_table_row('allowed_tags', _("Enter Users's Locale"), _("Users's Locale"), true) }} {{ user_table_row('allowed_column_value', _("Enter Users's Locale"), _("Users's Locale"), true) }} {{ user_table_row('denied_column_value', _("Enter Users's Locale"), _("Users's Locale"), true) }} + + + + + + + + + + + + + + diff --git a/test/Calibre-Web TestSummary_Linux.html b/test/Calibre-Web TestSummary_Linux.html index 702a2668..c18e6bad 100644 --- a/test/Calibre-Web TestSummary_Linux.html +++ b/test/Calibre-Web TestSummary_Linux.html @@ -37,14 +37,14 @@
-

Start Time: 2021-02-08 20:40:55

+

Start Time: 2021-02-09 20:40:28

-

Stop Time: 2021-02-08 23:09:33

+

Stop Time: 2021-02-09 23:08:52

@@ -1595,12 +1595,12 @@ - + - + + - + - + @@ -2376,11 +2356,11 @@ IndexError: list index out of range - + - - + + + - + @@ -2594,12 +2594,12 @@ IndexError: list index out of range - + - - - + + + + - + @@ -2688,11 +2708,41 @@ IndexError: list index out of range - + - + @@ -3399,8 +3449,8 @@ IndexError: list index out of range - - + + @@ -3430,7 +3480,7 @@ IndexError: list index out of range - + @@ -3766,7 +3816,7 @@ IndexError: list index out of range
{{_('Edit')}}{{_('Admin')}}{{_('Upload')}}{{_('Download')}}{{_('Edit')}}{{_('Change Password')}}{{_('Edit Public Shelfs')}}{{_('Delete')}}{{_('View')}}
{{_('Admin')}}

{{_('Upload')}}

{{_('Download')}}

{{_('Edit')}}

{{_('Change Password')}}

{{_('Edit Public Shelfs')}}

{{_('Delete')}}

{{_('View')}}

{{_('Show Random Books in Detail View')}}

{{_('Show language selection')}}

{{_('Show series selection')}}

{{ _('Show category selection')}}

{{ _('Show random books')}}

{{_('Show author selection')}}

{{_('Show Top Rated Books')}}

{{_('Show random books')}}

{{_('Show publisher selection')}}

{{_('Show ratings selection')}}

{{_('Show file formats selection')}}

{{_('Show archived books')}}

{{_('Show Downloaded Books')}}

{{_('Show Books List')}}
{{_('Delete User')}}
TestKoboSync 9890 01 0 Detail @@ -1609,31 +1609,11 @@ -
TestKoboSync - test_book_download
-
- ERROR -
- - - -
PASS
TestRegister 88071 0 0 @@ -2453,11 +2433,31 @@ IndexError: list index out of range -
TestRegister - test_user_change_password
PASS +
+ FAIL +
+ + + +
TestUpdater 8700511 1 Detail @@ -2653,11 +2653,31 @@ IndexError: list index out of range -
TestUpdater - test_perform_update_stable_errors
PASS +
+ FAIL +
+ + + +
TestUpdater - test_reconnect_database
PASS +
+ ERROR +
+ + + +
Total 29929102892 1 7  
PlatformLinux 5.8.0-41-generic #46~20.04.1-Ubuntu SMP Mon Jan 18 17:52:23 UTC 2021 x86_64 x86_64Linux 5.8.0-43-generic #49~20.04.1-Ubuntu SMP Fri Feb 5 09:57:56 UTC 2021 x86_64 x86_64 Basic