Merge remote-tracking branch 'origin/back' into Develop

This commit is contained in:
Ozzie Isaacs 2024-02-26 18:07:57 +01:00
commit 4fbd064b85
10 changed files with 43 additions and 32 deletions

View File

@ -60,6 +60,7 @@ from .tasks.upload import TaskUpload
from .render_template import render_title_template
from .usermanagement import login_required_if_no_ano
from .kobo_sync_status import change_archived_books
from .redirect import get_redirect_location
editbook = Blueprint('edit-book', __name__)
@ -96,7 +97,7 @@ def delete_book_from_details(book_id):
@editbook.route("/delete/<int:book_id>/<string:book_format>", methods=["POST"])
@login_required
def delete_book_ajax(book_id, book_format):
return delete_book_from_table(book_id, book_format, False)
return delete_book_from_table(book_id, book_format, False, request.form.to_dict().get('location', ""))
@editbook.route("/admin/book/<int:book_id>", methods=['GET'])
@ -823,7 +824,7 @@ def delete_whole_book(book_id, book):
calibre_db.session.query(db.Books).filter(db.Books.id == book_id).delete()
def render_delete_book_result(book_format, json_response, warning, book_id):
def render_delete_book_result(book_format, json_response, warning, book_id, location=""):
if book_format:
if json_response:
return json.dumps([warning, {"location": url_for("edit-book.show_edit_book", book_id=book_id),
@ -835,16 +836,16 @@ def render_delete_book_result(book_format, json_response, warning, book_id):
return redirect(url_for('edit-book.show_edit_book', book_id=book_id))
else:
if json_response:
return json.dumps([warning, {"location": url_for('web.index'),
return json.dumps([warning, {"location": get_redirect_location(location, "web.index"),
"type": "success",
"format": book_format,
"message": _('Book Successfully Deleted')}])
else:
flash(_('Book Successfully Deleted'), category="success")
return redirect(url_for('web.index'))
return redirect(get_redirect_location(location, "web.index"))
def delete_book_from_table(book_id, book_format, json_response):
def delete_book_from_table(book_id, book_format, json_response, location=""):
warning = {}
if current_user.role_delete_books():
book = calibre_db.get_book(book_id)
@ -891,7 +892,7 @@ def delete_book_from_table(book_id, book_format, json_response):
else:
# book not found
log.error('Book with id "%s" could not be deleted: not found', book_id)
return render_delete_book_result(book_format, json_response, warning, book_id)
return render_delete_book_result(book_format, json_response, warning, book_id, location)
message = _("You are missing permissions to delete books")
if json_response:
return json.dumps({"location": url_for("edit-book.show_edit_book", book_id=book_id),

View File

@ -692,15 +692,15 @@ def valid_password(check_password):
if config.config_password_policy:
verify = ""
if config.config_password_min_length > 0:
verify += "^(?=.{" + str(config.config_password_min_length) + ",}$)"
verify += r"^(?=.{" + str(config.config_password_min_length) + ",}$)"
if config.config_password_number:
verify += "(?=.*?\d)"
verify += r"(?=.*?\d)"
if config.config_password_lower:
verify += "(?=.*?[a-z])"
verify += r"(?=.*?[a-z])"
if config.config_password_upper:
verify += "(?=.*?[A-Z])"
verify += r"(?=.*?[A-Z])"
if config.config_password_special:
verify += "(?=.*?[^A-Za-z\s0-9])"
verify += r"(?=.*?[^A-Za-z\s0-9])"
match = re.match(verify, check_password)
if not match:
raise Exception(_("Password doesn't comply with password validation rules"))
@ -1039,7 +1039,7 @@ def check_calibre(calibre_location):
binaries_available = [os.path.isfile(binary_path) for binary_path in supported_binary_paths]
binaries_executable = [os.access(binary_path, os.X_OK) for binary_path in supported_binary_paths]
if all(binaries_available) and all(binaries_executable):
values = [process_wait([binary_path, "--version"], pattern='\(calibre (.*)\)')
values = [process_wait([binary_path, "--version"], pattern=r'\(calibre (.*)\)')
for binary_path in supported_binary_paths]
if all(values):
version = values[0].group(1)

View File

@ -44,9 +44,9 @@ def remove_prefix(text, prefix):
return ""
def redirect_back(endpoint, **values):
target = request.form.get('next', None) or url_for(endpoint, **values)
def get_redirect_location(next, endpoint, **values):
target = next or url_for(endpoint, **values)
adapter = current_app.url_map.bind(urlparse(request.host_url).netloc)
if not len(adapter.allowed_methods(remove_prefix(target, request.environ.get('HTTP_X_SCRIPT_NAME',"")))):
target = url_for(endpoint, **values)
return redirect(target)
return target

View File

@ -20,7 +20,7 @@ function getPath() {
return jsFileLocation.substr(0, jsFileLocation.search("/static/js/libs/jquery.min.js")); // the js folder path
}
function postButton(event, action){
function postButton(event, action, location=""){
event.preventDefault();
var newForm = jQuery('<form>', {
"action": action,
@ -30,7 +30,14 @@ function postButton(event, action){
'name': 'csrf_token',
'value': $("input[name=\'csrf_token\']").val(),
'type': 'hidden'
})).appendTo('body')
if(location !== "") {
newForm.append(jQuery('<input>', {
'name': 'location',
'value': location,
'type': 'hidden'
})).appendTo('body');
}
newForm.submit();
}
@ -212,17 +219,20 @@ $("#delete_confirm").click(function(event) {
$( ".navbar" ).after( '<div class="row-fluid text-center" >' +
'<div id="flash_'+item.type+'" class="alert alert-'+item.type+'">'+item.message+'</div>' +
'</div>');
}
});
$("#books-table").bootstrapTable("refresh");
}
});
} else {
postButton(event, getPath() + "/delete/" + deleteId);
var loc = sessionStorage.getItem("back");
if (!loc) {
loc = $(this).data("back");
}
sessionStorage.removeItem("back");
postButton(event, getPath() + "/delete/" + deleteId, location=loc);
}
}
});
//triggered when modal is about to be shown
@ -541,6 +551,7 @@ $(function() {
$.get(e.relatedTarget.href).done(function(content) {
$modalBody.html(content);
preFilters.remove(useCache);
$("#back").remove();
});
})
.on("hidden.bs.modal", function() {

View File

@ -32,7 +32,7 @@
</div>
<div class="row display-flex">
{% for entry in entries %}
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book session">
<div class="cover">
<a href="{{ url_for('web.show_book', book_id=entry.Books.id) }}" {% if simple==false %}data-toggle="modal" data-target="#bookDetailsModal" data-remote="false"{% endif %}>
<span class="img" title="{{entry.Books.title}}">
@ -99,7 +99,7 @@
<h3>{{_("More by")}} {{ author.name.replace('|',',') }}</h3>
<div class="row">
{% for entry in other_books %}
<div class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="col-sm-3 col-lg-2 col-xs-6 book session">
<div class="cover">
<a href="https://www.goodreads.com/book/show/{{ entry.gid['#text'] }}" target="_blank" rel="noopener">
<img title="{{entry.title}}" src="{{ entry.image_url }}" />

5
cps/templates/detail.html Executable file → Normal file
View File

@ -333,18 +333,18 @@
{% endif %}
{% if current_user.role_edit() %}
<div class="btn-toolbar" role="toolbar">
<div class="col-sm-12">
<div class="btn-group" role="group" aria-label="Edit/Delete book">
<a href="{{ url_for('edit-book.show_edit_book', book_id=entry.id) }}"
class="btn btn-sm btn-primary" id="edit_book" role="button"><span
class="glyphicon glyphicon-edit"></span> {{ _('Edit Metadata') }}</a>
</div>
<div class="btn btn-default" data-back="{{ url_for('web.index') }}" id="back">{{_('Cancel')}}</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
@ -367,4 +367,3 @@
</script>
{% endblock %}

View File

@ -6,7 +6,7 @@
<h2 class="random-books">{{_('Discover (Random Books)')}}</h2>
<div class="row display-flex">
{% for entry in random %}
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books_rand">
<div class="col-sm-3 col-lg-2 col-xs-6 book session" id="books_rand">
<div class="cover">
<a href="{{ url_for('web.show_book', book_id=entry.Books.id) }}" {% if simple==false %}data-toggle="modal" data-target="#bookDetailsModal" data-remote="false"{% endif %}>
<span class="img" title="{{ entry.Books.title }}">
@ -89,7 +89,7 @@
<div class="row display-flex">
{% if entries[0] %}
{% for entry in entries %}
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books">
<div class="col-sm-3 col-lg-2 col-xs-6 book session" id="books">
<div class="cover">
<a href="{{ url_for('web.show_book', book_id=entry.Books.id) }}" {% if simple==false %}data-toggle="modal" data-target="#bookDetailsModal" data-remote="false"{% endif %}>
<span class="img" title="{{ entry.Books.title }}">

View File

@ -41,7 +41,7 @@
<div class="row display-flex">
{% for entry in entries %}
<div class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="col-sm-3 col-lg-2 col-xs-6 book session">
<div class="cover">
{% if entry.Books.has_cover is defined %}
<a href="{{ url_for('web.show_book', book_id=entry.Books.id) }}" {% if simple==false %}data-toggle="modal" data-target="#bookDetailsModal" data-remote="false"{% endif %}>

View File

@ -31,7 +31,7 @@
{% endif %}
<div class="row display-flex">
{% for entry in entries %}
<div class="col-sm-3 col-lg-2 col-xs-6 book">
<div class="col-sm-3 col-lg-2 col-xs-6 book session">
<div class="cover">
<a href="{{ url_for('web.show_book', book_id=entry.Books.id) }}" {% if simple==false %}data-toggle="modal" data-target="#bookDetailsModal" data-remote="false"{% endif %}>
<span class="img" title="{{entry.Books.title}}" >

View File

@ -50,7 +50,7 @@ from .helper import check_valid_domain, check_email, check_username, \
send_registration_mail, check_send_to_ereader, check_read_formats, tags_filters, reset_password, valid_email, \
edit_book_read_status, valid_password
from .pagination import Pagination
from .redirect import redirect_back
from .redirect import get_redirect_location
from .babel import get_available_locale
from .usermanagement import login_required_if_no_ano
from .kobo_sync_status import remove_synced_book
@ -1342,7 +1342,7 @@ def handle_login_user(user, remember, message, category):
ub.store_user_session()
flash(message, category=category)
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
return redirect_back("web.index")
return redirect(get_redirect_location(request.form.get('next', None), "web.index"))
def render_login(username="", password=""):