mirror of
https://github.com/janeczku/calibre-web
synced 2025-10-26 21:07:40 +00:00
Improved error handling on mass edit list
This commit is contained in:
124
cps/editbooks.py
124
cps/editbooks.py
@@ -215,7 +215,7 @@ def table_get_custom_enum(c_id):
|
|||||||
@edit_required
|
@edit_required
|
||||||
def edit_list_book(param):
|
def edit_list_book(param):
|
||||||
vals = request.get_json()
|
vals = request.get_json()
|
||||||
return edit_book_param(param, vals)
|
return jsonify(edit_book_param(param, vals))
|
||||||
|
|
||||||
@editbook.route("/ajax/editselectedbooks", methods=['POST'])
|
@editbook.route("/ajax/editselectedbooks", methods=['POST'])
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
@@ -239,34 +239,56 @@ def edit_selected_books():
|
|||||||
"checkA": d.get('checkA'),
|
"checkA": d.get('checkA'),
|
||||||
"checkT": d.get('checkT'),
|
"checkT": d.get('checkT'),
|
||||||
}
|
}
|
||||||
|
res = list()
|
||||||
if title:
|
if title:
|
||||||
vals['value'] = title
|
vals['value'] = title
|
||||||
res_title = edit_book_param('title', vals)
|
out = edit_book_param('title', vals, True)
|
||||||
|
if out[0].get('success') != True:
|
||||||
|
res.extend(out)
|
||||||
if title_sort:
|
if title_sort:
|
||||||
vals['value'] = title_sort
|
vals['value'] = title_sort
|
||||||
res1_tit_sort = edit_book_param('sort', vals)
|
out = edit_book_param('sort', vals, True)
|
||||||
|
if out[0].get('success') != True:
|
||||||
|
res.extend(out)
|
||||||
if author_sort:
|
if author_sort:
|
||||||
vals['value'] = author_sort
|
vals['value'] = author_sort
|
||||||
res_author_sort = edit_book_param('author_sort', vals)
|
out = edit_book_param('author_sort', vals, True)
|
||||||
|
if out[0].get('success') != True:
|
||||||
|
res.extend(out)
|
||||||
if authors:
|
if authors:
|
||||||
vals['value'] = authors
|
vals['value'] = authors
|
||||||
res_author = edit_book_param('authors', vals)
|
out = edit_book_param('authors', vals, True)
|
||||||
|
if out[0].get('success') != True:
|
||||||
|
res.extend(out)
|
||||||
if categories:
|
if categories:
|
||||||
vals['value'] = categories
|
vals['value'] = categories
|
||||||
res_cat = edit_book_param('tags', vals)
|
out = edit_book_param('tags', vals, True)
|
||||||
|
if out[0].get('success') != True:
|
||||||
|
res.extend(out)
|
||||||
if series:
|
if series:
|
||||||
vals['value'] = series
|
vals['value'] = series
|
||||||
res_series = edit_book_param('series', vals)
|
out = edit_book_param('series', vals, True)
|
||||||
|
if out[0].get('success') != True:
|
||||||
|
res.extend(out)
|
||||||
if languages:
|
if languages:
|
||||||
vals['value'] = languages
|
vals['value'] = languages
|
||||||
res_lang = edit_book_param('languages', vals)
|
out = edit_book_param('languages', vals, True)
|
||||||
|
if out[0].get('success') != True:
|
||||||
|
res.extend(out)
|
||||||
if publishers:
|
if publishers:
|
||||||
vals['value'] = publishers
|
vals['value'] = publishers
|
||||||
res_pup = edit_book_param('publishers', vals)
|
out = edit_book_param('publishers', vals, True)
|
||||||
|
if out[0].get('success') != True:
|
||||||
|
res.extend(out)
|
||||||
if comments:
|
if comments:
|
||||||
vals['value'] = comments
|
vals['value'] = comments
|
||||||
res_comments = edit_book_param('comments', vals)
|
out = edit_book_param('comments', vals, True)
|
||||||
return json.dumps({'success': True})
|
if out[0].get('success') != True:
|
||||||
|
res.extend(out)
|
||||||
|
if len(res) == 0:
|
||||||
|
return jsonify([{'success': True, "msg": _("Changes successfully applied")}])
|
||||||
|
else:
|
||||||
|
return jsonify(res)
|
||||||
|
|
||||||
# Separated from /editbooks so that /editselectedbooks can also use this
|
# Separated from /editbooks so that /editselectedbooks can also use this
|
||||||
#
|
#
|
||||||
@@ -281,70 +303,87 @@ def edit_selected_books():
|
|||||||
#
|
#
|
||||||
@login_required_if_no_ano
|
@login_required_if_no_ano
|
||||||
@edit_required
|
@edit_required
|
||||||
def edit_book_param(param, vals):
|
def edit_book_param(param, vals, multi=False):
|
||||||
elements = vals.get('pk',[])
|
elements = vals.get('pk',[])
|
||||||
if vals.get('value', None) is None:
|
if vals.get('value', None) is None:
|
||||||
return jsonify(success=False, msg=_("Value is missing on request"))
|
return {'success':False, 'msg':_("Value is missing on request")}
|
||||||
if not elements :
|
if not elements :
|
||||||
return jsonify(success=False, msg=_("Oops! Selected book is unavailable. File does not exist or is not accessible"))
|
return {"success":False, "msg":_("Oops! Selected book is unavailable. File does not exist or is not accessible")}
|
||||||
ret = {}
|
ret = {}
|
||||||
|
out = list()
|
||||||
for elem in elements:
|
for elem in elements:
|
||||||
book = calibre_db.get_book(elem)
|
book = calibre_db.get_book(elem)
|
||||||
if not book:
|
if not book:
|
||||||
ret = jsonify(success=False, msg=_("Oops! Selected book is unavailable. File does not exist or is not accessible"))
|
ret = {"success": False,
|
||||||
|
"msg": _("Oops! Selected book is unavailable. File does not exist or is not accessible")}
|
||||||
|
if multi:
|
||||||
|
out.append(ret)
|
||||||
continue
|
continue
|
||||||
calibre_db.create_functions(config)
|
calibre_db.create_functions(config)
|
||||||
sort_param = ""
|
sort_param = ""
|
||||||
try:
|
try:
|
||||||
if param == 'series_index':
|
if param == 'series_index':
|
||||||
edit_book_series_index(vals['value'], book)
|
edit_book_series_index(vals['value'], book)
|
||||||
ret = jsonify(success=True, newValue=book.series_index)
|
ret = {"success":True,
|
||||||
|
"newValue":book.series_index}
|
||||||
elif param == 'tags':
|
elif param == 'tags':
|
||||||
edit_book_tags(vals['value'], book)
|
edit_book_tags(vals['value'], book)
|
||||||
ret = jsonify(success=True, newValue=', '.join([tag.name for tag in book.tags]))
|
ret = {"success":True,
|
||||||
|
"newValue":', '.join([tag.name for tag in book.tags])}
|
||||||
elif param == 'series':
|
elif param == 'series':
|
||||||
edit_book_series(vals['value'], book)
|
edit_book_series(vals['value'], book)
|
||||||
ret = jsonify(success=True, newValue=', '.join([serie.name for serie in book.series]))
|
ret = {"success":True,
|
||||||
|
"newValue":', '.join([serie.name for serie in book.series])}
|
||||||
elif param == 'publishers':
|
elif param == 'publishers':
|
||||||
edit_book_publisher(vals['value'], book)
|
edit_book_publisher(vals['value'], book)
|
||||||
ret = jsonify(success=True,
|
ret = {"success":True,
|
||||||
newValue=', '.join([publisher.name for publisher in book.publishers]))
|
"newValue":', '.join([publisher.name for publisher in book.publishers])}
|
||||||
elif param == 'languages':
|
elif param == 'languages':
|
||||||
invalid = list()
|
invalid = list()
|
||||||
edit_book_languages(vals['value'], book, invalid=invalid)
|
edit_book_languages(vals['value'], book, invalid=invalid)
|
||||||
if invalid:
|
if invalid:
|
||||||
ret = jsonify(success=False, msg='Invalid languages in request: {}'.format(','.join(invalid)))
|
ret = {"success": False, "msg": 'Invalid languages in request: {}'.format(','.join(invalid))}
|
||||||
|
if multi:
|
||||||
|
out.append(ret)
|
||||||
else:
|
else:
|
||||||
lang_names = list()
|
lang_names = list()
|
||||||
for lang in book.languages:
|
for lang in book.languages:
|
||||||
lang_names.append(isoLanguages.get_language_name(get_locale(), lang.lang_code))
|
lang_names.append(isoLanguages.get_language_name(get_locale(), lang.lang_code))
|
||||||
ret = jsonify(success=True, newValue=', '.join(lang_names))
|
ret = {"success":True,
|
||||||
|
"newValue":', '.join(lang_names)}
|
||||||
elif param == 'author_sort':
|
elif param == 'author_sort':
|
||||||
book.author_sort = vals['value']
|
book.author_sort = vals['value']
|
||||||
ret = jsonify(success=True, newValue=book.author_sort)
|
ret = {"success":True,
|
||||||
|
"newValue":book.author_sort}
|
||||||
elif param == 'title':
|
elif param == 'title':
|
||||||
sort_param = book.sort
|
sort_param = book.sort
|
||||||
if handle_title_on_edit(book, vals.get('value', "")):
|
if handle_title_on_edit(book, vals.get('value', "")):
|
||||||
rename_error = helper.update_dir_structure(book.id, config.get_book_path())
|
rename_error = helper.update_dir_structure(book.id, config.get_book_path())
|
||||||
if not rename_error:
|
if not rename_error:
|
||||||
ret = jsonify(success=True, newValue=book.title)
|
ret = {"success":True,
|
||||||
|
"newValue":book.title}
|
||||||
else:
|
else:
|
||||||
ret = jsonify(success=False, msg=rename_error)
|
ret = {"success":False, "msg":rename_error}
|
||||||
|
if multi:
|
||||||
|
out.append(ret)
|
||||||
elif param == 'sort':
|
elif param == 'sort':
|
||||||
book.sort = vals['value']
|
book.sort = vals['value']
|
||||||
ret = jsonify(success=True, newValue=book.sort)
|
ret = {"success":True,
|
||||||
|
"newValue":book.sort}
|
||||||
elif param == 'comments':
|
elif param == 'comments':
|
||||||
edit_book_comments(vals['value'], book)
|
edit_book_comments(vals['value'], book)
|
||||||
ret = jsonify(success=True, newValue=book.comments[0].text)
|
ret = {"success":True,
|
||||||
|
"newValue":book.comments[0].text}
|
||||||
elif param == 'authors':
|
elif param == 'authors':
|
||||||
input_authors, __ = handle_author_on_edit(book, vals['value'], vals.get('checkA', None) == True)
|
input_authors, __ = handle_author_on_edit(book, vals['value'], vals.get('checkA', None) == True)
|
||||||
rename_error = helper.update_dir_structure(book.id, config.get_book_path(), input_authors[0])
|
rename_error = helper.update_dir_structure(book.id, config.get_book_path(), input_authors[0])
|
||||||
if not rename_error:
|
if not rename_error:
|
||||||
ret = jsonify(
|
ret = {"success":True,
|
||||||
success=True,
|
"newValue":' & '.join([author.replace('|', ',') for author in input_authors])}
|
||||||
newValue=' & '.join([author.replace('|', ',') for author in input_authors]))
|
|
||||||
else:
|
else:
|
||||||
ret = jsonify(success=False, msg=rename_error)
|
ret = {"success":False, "msg":rename_error}
|
||||||
|
if multi:
|
||||||
|
out.append(ret)
|
||||||
elif param == 'is_archived':
|
elif param == 'is_archived':
|
||||||
is_archived = change_archived_books(book.id, vals['value'] == "True",
|
is_archived = change_archived_books(book.id, vals['value'] == "True",
|
||||||
message="Book {} archive bit set to: {}".format(book.id,
|
message="Book {} archive bit set to: {}".format(book.id,
|
||||||
@@ -355,7 +394,11 @@ def edit_book_param(param, vals):
|
|||||||
elif param == 'read_status':
|
elif param == 'read_status':
|
||||||
error = helper.edit_book_read_status(book.id, vals['value'] == "True")
|
error = helper.edit_book_read_status(book.id, vals['value'] == "True")
|
||||||
if error:
|
if error:
|
||||||
return error, 400
|
if multi:
|
||||||
|
out.append({"success":False, "msg":error})
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
return error, 400
|
||||||
continue
|
continue
|
||||||
elif param.startswith("custom_column_"):
|
elif param.startswith("custom_column_"):
|
||||||
new_val = dict()
|
new_val = dict()
|
||||||
@@ -365,8 +408,11 @@ def edit_book_param(param, vals):
|
|||||||
if vals['value'] in ["True", "False"]:
|
if vals['value'] in ["True", "False"]:
|
||||||
ret = {}
|
ret = {}
|
||||||
else:
|
else:
|
||||||
ret = jsonify(success=True, newValue=vals['value'])
|
ret = {"success":True, "newValue":vals['value']}
|
||||||
else:
|
else:
|
||||||
|
if multi:
|
||||||
|
out.append({"success":False, "msg":_("Parameter not found")})
|
||||||
|
continue
|
||||||
return _("Parameter not found"), 400
|
return _("Parameter not found"), 400
|
||||||
book.last_modified = datetime.now(timezone.utc)
|
book.last_modified = datetime.now(timezone.utc)
|
||||||
|
|
||||||
@@ -378,8 +424,16 @@ def edit_book_param(param, vals):
|
|||||||
except (OperationalError, IntegrityError, StaleDataError, AttributeError) as e:
|
except (OperationalError, IntegrityError, StaleDataError, AttributeError) as e:
|
||||||
calibre_db.session.rollback()
|
calibre_db.session.rollback()
|
||||||
log.error_or_exception("Database error: {}".format(e))
|
log.error_or_exception("Database error: {}".format(e))
|
||||||
ret = jsonify(success=False, msg='Database error: {}'.format(e.orig if hasattr(e, "orig") else e))
|
ret = {"success":False, "msg":'Database error: {}'.format(e.orig if hasattr(e, "orig") else e)}
|
||||||
return ret
|
if multi:
|
||||||
|
out.append(ret)
|
||||||
|
if multi:
|
||||||
|
if len(out) > 0:
|
||||||
|
return out
|
||||||
|
else:
|
||||||
|
return [ret]
|
||||||
|
else:
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@editbook.route("/ajax/sort_value/<field>/<int:bookid>")
|
@editbook.route("/ajax/sort_value/<field>/<int:bookid>")
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ def rename_all_files_on_change(one_book, new_path, old_path, all_new_name, gdriv
|
|||||||
os.makedirs(new_path)
|
os.makedirs(new_path)
|
||||||
shutil.move(os.path.join(old_path, file_format.name + '.' + file_format.format.lower()),
|
shutil.move(os.path.join(old_path, file_format.name + '.' + file_format.format.lower()),
|
||||||
os.path.join(new_path, all_new_name + '.' + file_format.format.lower()))
|
os.path.join(new_path, all_new_name + '.' + file_format.format.lower()))
|
||||||
except PermissionError as ex:
|
except (PermissionError, FileNotFoundError) as ex:
|
||||||
log.error("Moving book-id %s folder %s failed: %s", one_book.id, new_path, ex)
|
log.error("Moving book-id %s folder %s failed: %s", one_book.id, new_path, ex)
|
||||||
return _("Moving book path of Book %(book_id)s to: '%(src)s' failed with error: %(error)s",
|
return _("Moving book path of Book %(book_id)s to: '%(src)s' failed with error: %(error)s",
|
||||||
book_id=one_book.id, src=new_path, error=str(ex))
|
book_id=one_book.id, src=new_path, error=str(ex))
|
||||||
@@ -475,10 +475,11 @@ def update_dir_structure_file(book_id, calibre_path, original_filepath, new_auth
|
|||||||
all_new_name = get_valid_filename(local_book.title, chars=42) + ' - ' \
|
all_new_name = get_valid_filename(local_book.title, chars=42) + ' - ' \
|
||||||
+ get_valid_filename(new_author, chars=42)
|
+ get_valid_filename(new_author, chars=42)
|
||||||
# Book folder already moved, only files need to be renamed
|
# Book folder already moved, only files need to be renamed
|
||||||
error |= rename_all_files_on_change(local_book, new_path, new_path, all_new_name)
|
renameerror = rename_all_files_on_change(local_book, new_path, new_path, all_new_name)
|
||||||
|
|
||||||
if error:
|
|
||||||
return error
|
if error or renameerror:
|
||||||
|
return error or renameerror
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -558,7 +559,7 @@ def move_files_on_change(calibre_path, new_author_dir, new_titledir, localbook,
|
|||||||
log.error("Deleting authorpath for book %s failed: %s", localbook.id, ex)
|
log.error("Deleting authorpath for book %s failed: %s", localbook.id, ex)
|
||||||
# change location in database to new author/title path
|
# change location in database to new author/title path
|
||||||
localbook.path = os.path.join(new_author_dir, new_titledir).replace('\\', '/')
|
localbook.path = os.path.join(new_author_dir, new_titledir).replace('\\', '/')
|
||||||
except OSError as ex:
|
except (OSError, FileNotFoundError) as ex:
|
||||||
log.error_or_exception("Rename title from {} to {} failed with error: {}".format(path, new_path, ex))
|
log.error_or_exception("Rename title from {} to {} failed with error: {}".format(path, new_path, ex))
|
||||||
return _("Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
|
return _("Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
|
||||||
src=path, dest=new_path, error=str(ex))
|
src=path, dest=new_path, error=str(ex))
|
||||||
|
|||||||
@@ -220,7 +220,8 @@ $(function() {
|
|||||||
"comments": $("#comments_input").val().toString(),
|
"comments": $("#comments_input").val().toString(),
|
||||||
"checkA": $('#autoupdate_authorsort').prop('checked').toString()
|
"checkA": $('#autoupdate_authorsort').prop('checked').toString()
|
||||||
}),
|
}),
|
||||||
success: function success(booTitles) {
|
success: function success(data) {
|
||||||
|
let result = "";
|
||||||
$("#books-table").bootstrapTable("refresh");
|
$("#books-table").bootstrapTable("refresh");
|
||||||
$("#books-table").bootstrapTable("uncheckAll");
|
$("#books-table").bootstrapTable("uncheckAll");
|
||||||
|
|
||||||
@@ -234,7 +235,23 @@ $(function() {
|
|||||||
$("#publishers_input").val("");
|
$("#publishers_input").val("");
|
||||||
$("#comments_input").val("");
|
$("#comments_input").val("");
|
||||||
|
|
||||||
handleListServerResponse;
|
$("#flash_success").remove();
|
||||||
|
$("#flash_danger").remove();
|
||||||
|
|
||||||
|
if (!jQuery.isEmptyObject(data)) {
|
||||||
|
data.forEach(function(item) {
|
||||||
|
if (item.success === true) {
|
||||||
|
result = "success";
|
||||||
|
} else {
|
||||||
|
result = "danger";
|
||||||
|
}
|
||||||
|
$(".navbar").after('<div class="row-fluid text-center">' +
|
||||||
|
'<div id="flash_' + result + '" class="alert alert-' + result + '">' + item.msg + '</div>' +
|
||||||
|
'</div>');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$(".table.table-striped").bootstrapTable("refresh");
|
||||||
|
// handleListServerResponse(data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user