Commit 0992bafe authored by Ozzie Isaacs's avatar Ozzie Isaacs

Bulk User management

parent c810c527
...@@ -35,6 +35,7 @@ from flask import Blueprint, flash, redirect, url_for, abort, request, make_resp ...@@ -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_login import login_required, current_user, logout_user, confirm_login
from flask_babel import gettext as _ from flask_babel import gettext as _
from sqlalchemy import and_ from sqlalchemy import and_
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_
...@@ -225,11 +226,12 @@ def edit_user_table(): ...@@ -225,11 +226,12 @@ def edit_user_table():
return render_title_template("user_table.html", return render_title_template("user_table.html",
users=allUser.all(), users=allUser.all(),
visiblility=visibility, visiblility=visibility,
all_roles = constants.ALL_ROLES, all_roles=constants.ALL_ROLES,
sidebar_settings=constants.sidebar_settings,
title=_(u"Edit Users"), title=_(u"Edit Users"),
page="usertable") page="usertable")
@admi.route("/axjax/listusers") @admi.route("/ajax/listusers")
@login_required @login_required
@admin_required @admin_required
def list_users(): def list_users():
...@@ -242,8 +244,11 @@ 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) all_user = all_user.filter(ub.User.role.op('&')(constants.ROLE_ANONYMOUS) != constants.ROLE_ANONYMOUS)
total_count = all_user.count() total_count = all_user.count()
if search: if search:
users = all_user.filter().offset(off).limit(limit).all() users = all_user.filter(or_(func.lower(ub.User.nickname).ilike("%" + search + "%"),
filtered_count = users.length() 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: else:
users = all_user.offset(off).limit(limit).all() users = all_user.offset(off).limit(limit).all()
filtered_count = total_count filtered_count = total_count
...@@ -255,6 +260,14 @@ def list_users(): ...@@ -255,6 +260,14 @@ def list_users():
response.headers["Content-Type"] = "application/json; charset=utf-8" response.headers["Content-Type"] = "application/json; charset=utf-8"
return response 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/<param>", methods=['POST']) @admi.route("/axjax/editlistusers/<param>", methods=['POST'])
@login_required @login_required
...@@ -285,6 +298,24 @@ def edit_list_user(param): ...@@ -285,6 +298,24 @@ def edit_list_user(param):
return "" 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"]) @admi.route("/admin/viewconfig", methods=["POST"])
@login_required @login_required
@admin_required @admin_required
......
...@@ -88,6 +88,26 @@ SIDEBAR_ARCHIVED = 1 << 15 ...@@ -88,6 +88,26 @@ SIDEBAR_ARCHIVED = 1 << 15
SIDEBAR_DOWNLOAD = 1 << 16 SIDEBAR_DOWNLOAD = 1 << 16
SIDEBAR_LIST = 1 << 17 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_ROLES = sum(r for r in ALL_ROLES.values()) & ~ROLE_ANONYMOUS
ADMIN_USER_SIDEBAR = (SIDEBAR_LIST << 1) - 1 ADMIN_USER_SIDEBAR = (SIDEBAR_LIST << 1) - 1
......
...@@ -116,7 +116,7 @@ $(function() { ...@@ -116,7 +116,7 @@ $(function() {
search: true, search: true,
showColumns: true, showColumns: true,
searchAlign: "left", searchAlign: "left",
showSearchButton : false, showSearchButton : true,
searchOnEnterKey: true, searchOnEnterKey: true,
checkboxHeader: false, checkboxHeader: false,
maintainMetaData: true, maintainMetaData: true,
...@@ -377,15 +377,24 @@ $(function() { ...@@ -377,15 +377,24 @@ $(function() {
search: true, search: true,
showColumns: true, showColumns: true,
searchAlign: "left", searchAlign: "left",
showSearchButton : false, showSearchButton : true,
searchOnEnterKey: true, searchOnEnterKey: true,
checkboxHeader: false, checkboxHeader: true,
maintainMetaData: true, maintainMetaData: true,
responseHandler: responseHandler, responseHandler: responseHandler,
columns: user_column, columns: user_column,
formatNoMatches: function () { formatNoMatches: function () {
return ""; 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 // eslint-disable-next-line no-unused-vars
/*onEditableSave: function (field, row, oldvalue, $el) { /*onEditableSave: function (field, row, oldvalue, $el) {
if (field === "title" || field === "authors") { if (field === "title" || field === "authors") {
...@@ -411,22 +420,47 @@ $(function() { ...@@ -411,22 +420,47 @@ $(function() {
var hidden = $("#user-table").bootstrapTable("getHiddenColumns"); var hidden = $("#user-table").bootstrapTable("getHiddenColumns");
var st = ""; var st = "";
visible.forEach(function(item) { visible.forEach(function(item) {
st += "\"" + item.field + "\":\"" + "true" + "\","; st += "\"" + item.name + "\":\"" + "true" + "\",";
}); });
hidden.forEach(function(item) { hidden.forEach(function(item) {
st += "\"" + item.field + "\":\"" + "false" + "\","; st += "\"" + item.name + "\":\"" + "false" + "\",";
}); });
st = st.slice(0, -1); st = st.slice(0, -1);
/*$.ajax({ $.ajax({
method:"post", method:"post",
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
dataType: "json", dataType: "json",
url: window.location.pathname + "/../../ajax/table_settings", url: window.location.pathname + "/../../ajax/user_table_settings",
data: "{" + st + "}", 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", /*$("#user-table").on("check.bs.table check-all.bs.table uncheck.bs.table uncheck-all.bs.table",
function (e, rowsAfter, rowsBefore) { function (e, rowsAfter, rowsBefore) {
...@@ -474,7 +508,7 @@ function EbookActions (value, row) { ...@@ -474,7 +508,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-toggle=\"modal\" data-target=\"#GeneralDeleteModal\" data-ajax=\"1\" data-delete-id=\"" + row.id + "\" title=\"Remove\">", "<div class=\"user-remove\" data-target=\"#GeneralDeleteModal\" title=\"Remove\">",
"<i class=\"glyphicon glyphicon-trash\"></i>", "<i class=\"glyphicon glyphicon-trash\"></i>",
"</div>" "</div>"
].join(""); ].join("");
...@@ -507,3 +541,8 @@ function checkboxChange(checkbox, index){ ...@@ -507,3 +541,8 @@ function checkboxChange(checkbox, index){
reinit: false reinit: false
}); });
} }
function checkboxHeader(element) {
console.log("hallo");
}
{% extends "layout.html" %} {% extends "layout.html" %}
{% macro user_table_row(parameter, edit_text, show_text, validate) -%} {% macro user_table_row(parameter, edit_text, show_text, validate) -%}
<th data-field="{{ parameter }}" id="{{ parameter }}" data-sortable="true" <th data-field="{{ parameter }}" id="{{ parameter }}" data-sortable="true"
data-visible = "{{visiblility.get(parameter)}}" data-name="{{ parameter }}"
data-visible="{{visiblility.get(parameter)}}"
data-editable-type="text" data-editable-type="text"
data-editable-url="{{ url_for('admin.edit_list_user', param=parameter)}}" data-editable-url="{{ url_for('admin.edit_list_user', param=parameter)}}"
data-editable-title="{{ edit_text }}" data-editable-title="{{ edit_text }}"
...@@ -16,28 +17,44 @@ ...@@ -16,28 +17,44 @@
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<h2 class="{{page}}">{{_(title)}}</h2> <h2 class="{{page}}">{{_(title)}}</h2>
<table>
</table>
<table id="user-table" class="table table-no-bordered table-striped" <table id="user-table" class="table table-no-bordered table-striped"
data-url="{{url_for('admin.list_users')}}"> data-url="{{url_for('admin.list_users')}}">
<thead> <thead>
<tr> <tr>
<th data-buttontext="{{_('Edit User')}}" data-formatter="singleUserFormatter"></th> <th data-name="edit" data-buttontext="{{_('Edit User')}}" data-visible="{{visiblility.get('edit')}}" data-formatter="singleUserFormatter">{{_('Edit')}}</th>
<th data-field="state" data-checkbox="true" data-sortable="true"></th> <th data-name="state" data-field="state" data-checkbox="true" data-visible="{{visiblility.get('state')}}" data-sortable="true"></th>
<th data-field="id" id="id" data-visible="false" data-switchable="false"></th> <th data-name="id" data-field="id" id="id" data-visible="false" data-switchable="false"></th>
{{ user_table_row('nickname', _('Enter Username'), _('Username'), true) }} {{ user_table_row('nickname', _('Enter Username'), _('Username'), true) }}
{{ user_table_row('email', _('Enter E-mail Address'), _('E-mail Address'), 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('kindle_mail', _('Enter Kindle E-mail Address'), _('Kindle E-mail'), true) }}
<th data-field="role" data-column="{{all_roles.admin_role}}" data-formatter="checkboxFormatter">{{_('Admin')}}</th> <th data-name="admin_role" data-field="role" data-visible="{{visiblility.get('admin_role')}}" data-column="{{all_roles.admin_role}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chkhead" onchange="checkboxHeader(this)"><br>{{_('Admin')}}</th>
<th data-field="role" data-column="{{all_roles.download_role}}" data-formatter="checkboxFormatter">{{_('Upload')}}</th> <th data-name="download_role" data-field="role" data-visible="{{visiblility.get('download_role')}}" data-column="{{all_roles.download_role}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chkhead" onchange="checkboxHeader(this)"><br>{{_('Upload')}}</th>
<th data-field="role" data-column="{{all_roles.upload_role}}" data-formatter="checkboxFormatter">{{_('Download')}}</th> <th data-name="upload_role" data-field="role" data-visible="{{visiblility.get('upload_role')}}" data-column="{{all_roles.upload_role}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chkhead" onchange="checkboxHeader(this)"><br>{{_('Download')}}</th>
<th data-field="role" data-column="{{all_roles.edit_role}}" data-formatter="checkboxFormatter">{{_('Edit')}}</th> <th data-name="edit_role" data-field="role" data-visible="{{visiblility.get('edit_role')}}" data-column="{{all_roles.edit_role}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chkhead" onchange="checkboxHeader(this)"><br>{{_('Edit')}}</th>
<th data-field="role" data-column="{{all_roles.passwd_role}}" data-formatter="checkboxFormatter">{{_('Change Password')}}</th> <th data-name="passwd_role" data-field="role" data-visible="{{visiblility.get('passwd_role')}}" data-column="{{all_roles.passwd_role}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chkhead" onchange="checkboxHeader(this)"><br>{{_('Change Password')}}</th>
<th data-field="role" data-column="{{all_roles.edit_shelf_role}}" data-formatter="checkboxFormatter">{{_('Edit Public Shelfs')}}</th> <th data-name="edit_shelf_role" data-field="role" data-visible="{{visiblility.get('edit_shelf_role')}}" data-column="{{all_roles.edit_shelf_role}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chkhead" onchange="checkboxHeader(this)"><br>{{_('Edit Public Shelfs')}}</th>
<th data-field="role" data-column="{{all_roles.delete_role}}" data-formatter="checkboxFormatter">{{_('Delete')}}</th> <th data-name="delete_role" data-field="role" data-visible="{{visiblility.get('delete_role')}}" data-column="{{all_roles.delete_role}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chkhead" onchange="checkboxHeader(this)"><br>{{_('Delete')}}</th>
<th data-field="role" data-column="{{all_roles.viewer_role}}" data-formatter="checkboxFormatter">{{_('View')}}</th> <th data-name="viewer_role" data-field="role" data-visible="{{visiblility.get('viewer_role')}}" data-column="{{all_roles.viewer_role}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chkhead" onchange="checkboxHeader(this)"><br>{{_('View')}}</th>
{{ user_table_row('denied_tags', _("Enter Users's Locale"), _("Users's Locale"), 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_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('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) }} {{ user_table_row('denied_column_value', _("Enter Users's Locale"), _("Users's Locale"), true) }}
<th data-name="detail_random" data-field="sidebar_view" data-visible="{{visiblility.get('detail_random')}}" data-column="{{sidebar_settings.detail_random}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show Random Books in Detail View')}}</th>
<th data-name="sidebar_language" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_language')}}" data-column="{{sidebar_settings.sidebar_language}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show language selection')}}</th>
<th data-name="sidebar_series" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_series')}}" data-column="{{sidebar_settings.sidebar_series}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show series selection')}}</th>
<th data-name="sidebar_category" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_category')}}" data-column="{{sidebar_settings.sidebar_category}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{ _('Show category selection')}}</th>
<th data-name="sidebar_random" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_random')}}" data-column="{{sidebar_settings.sidebar_random}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{ _('Show random books')}}</th>
<th data-name="sidebar_author" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_author')}}" data-column="{{sidebar_settings.sidebar_author}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show author selection')}}</th>
<th data-name="sidebar_best_rated" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_best_rated')}}" data-column="{{sidebar_settings.sidebar_best_rated}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show Top Rated Books')}}</th>
<th data-name="sidebar_read_and_unread" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_read_and_unread')}}" data-column="{{sidebar_settings.sidebar_read_and_unread}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show random books')}}</th>
<th data-name="sidebar_publisher" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_publisher')}}" data-column="{{sidebar_settings.sidebar_publisher}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show publisher selection')}}</th>
<th data-name="sidebar_rating" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_rating')}}" data-column="{{sidebar_settings.sidebar_rating}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show ratings selection')}}</th>
<th data-name="sidebar_format" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_format')}}" data-column="{{sidebar_settings.sidebar_format}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show file formats selection')}}</th>
<th data-name="sidebar_archived" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_archived')}}" data-column="{{sidebar_settings.sidebar_archived}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show archived books')}}</th>
<th data-name="sidebar_download" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_download')}}" data-column="{{sidebar_settings.sidebar_download}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show Downloaded Books')}}</th>
<th data-name="sidebar_list" data-field="sidebar_view" data-visible="{{visiblility.get('sidebar_list')}}" data-column="{{sidebar_settings.sidebar_list}}" data-formatter="checkboxFormatter"><input type="checkbox" class="chk" ><br>{{_('Show Books List')}}</th>
<th data-align="right" data-formatter="UserActions" data-switchable="false">{{_('Delete User')}}</th> <th data-align="right" data-formatter="UserActions" data-switchable="false">{{_('Delete User')}}</th>
</tr> </tr>
</thead> </thead>
......
This diff is collapsed.
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