diff --git a/data/interfaces/bookstrap/index.html b/data/interfaces/bookstrap/index.html
index f346c117..41d7809f 100644
--- a/data/interfaces/bookstrap/index.html
+++ b/data/interfaces/bookstrap/index.html
@@ -308,12 +308,12 @@
}
},
callback: function (result) {
- if (result) { document.getElementById("mark_authors").submit(); }
+ if (result) { submitFormAjax(); }
}
});
return false;
}
- else { document.getElementById("mark_authors").submit(); }
+ else { submitFormAjax(); }
}
function bookinfo(bookid) {
@@ -339,5 +339,78 @@
});
};
+ function submitFormAjax() {
+ var form = document.getElementById("mark_authors");
+ var formData = new FormData(form);
+
+ // Show loading modal
+ bootbox.dialog({
+ message: '
Processing...
',
+ size: 'small',
+ backdrop: false
+ });
+
+ // Convert FormData to URLSearchParams for the AJAX call
+ var params = new URLSearchParams();
+ var formDataEntries = formData.entries();
+ for (var pair of formDataEntries) {
+ params.append(pair[0], pair[1]);
+ }
+
+ // Make AJAX call to the new endpoint
+ fetch('mark_authors_ajax', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ body: params
+ })
+ .then(response => response.json())
+ .then(data => {
+ // Close loading modal
+ bootbox.hideAll();
+
+ // Show result modal
+ var message = 'Summary:
' + data.summary + '
';
+ if (data.passed > 0 || data.failed > 0) {
+ message += '';
+ message += '
Successful: ' + data.passed + '
';
+ if (data.failed > 0) {
+ message += '
Failed: ' + data.failed + '
';
+ }
+ message += '
';
+ }
+ bootbox.dialog({
+ title: 'Mark Authors Complete',
+ message: message,
+ buttons: {
+ ok: {
+ label: 'OK',
+ className: 'btn-primary',
+ callback: function() {
+ window.location.reload();
+ }
+ }
+ }
+ });
+ })
+ .catch(error => {
+ // Close loading modal
+ bootbox.hideAll();
+
+ // Show error modal
+ bootbox.dialog({
+ title: 'Error',
+ message: 'An error occurred: ' + error.message + '
',
+ buttons: {
+ primary: {
+ label: "Close",
+ className: 'btn-primary',
+ callback: function(result){ window.location.reload('series'); }
+ },
+ }
+ });
+ });
+ }
%def>
diff --git a/lazylibrarian/webServe.py b/lazylibrarian/webServe.py
index 27003a24..71de1e4b 100644
--- a/lazylibrarian/webServe.py
+++ b/lazylibrarian/webServe.py
@@ -448,7 +448,7 @@ class WebInterface:
title = 'Inactive Authors'
else:
title = 'Ignored Authors'
- return serve_template(templatename="index.html", title=title)
+ return serve_template(templatename="index.html", title=title, redirect=title.lower())
@cherrypy.expose
def home(self):
@@ -512,7 +512,7 @@ class WebInterface:
typelist=get_list(CONFIG['EBOOK_TYPE']), themelist=themelist)
finally:
db.close()
- return serve_template(templatename="index.html", title=title)
+ return serve_template(templatename="index.html", title='Authors', redirect='authors')
# noinspection PyUnusedLocal
@cherrypy.expose
@@ -2116,13 +2116,14 @@ class WebInterface:
# AUTHOR ############################################################
@cherrypy.expose
- def mark_authors(self, action=None, redirect=None, **args):
+ @cherrypy.tools.json_out()
+ def mark_authors_ajax(self, action=None, **args):
self.check_permitted(lazylibrarian.perm_status)
logger = logging.getLogger(__name__)
for arg in ['author_table_length', 'ignored']:
args.pop(arg, None)
- if not self.valid_source(redirect):
- redirect = "authors"
+ passed = 0
+ failed = 0
if action:
db = database.DBConnection()
try:
@@ -2130,9 +2131,11 @@ class WebInterface:
check = db.match("SELECT AuthorName from authors WHERE AuthorID=?", (authorid,))
if not check:
logger.warning(f'Unable to set Status to "{action}" for "{authorid}"')
+ failed += 1
elif action in ["Active", "Wanted", "Paused", "Ignored"]:
db.upsert("authors", {'Status': action}, {'AuthorID': authorid})
logger.info(f'Status set to "{action}" for "{check["AuthorName"]}"')
+ passed += 1
elif action == "Delete":
logger.info(f"Deleting author and books: {check['AuthorName']}")
books = db.select("SELECT BookFile from books WHERE AuthorID=? AND BookFile is not null",
@@ -2147,9 +2150,11 @@ class WebInterface:
logger.warning(f'rmtree failed on {book["BookFile"]}, {type(e).__name__} {str(e)}')
db.action('DELETE from authors WHERE AuthorID=?', (authorid,))
+ passed += 1
elif action == "Remove":
logger.info(f"Removing author: {check['AuthorName']}")
db.action('DELETE from authors WHERE AuthorID=?', (authorid,))
+ passed += 1
elif action == 'Subscribe':
cookie = cherrypy.request.cookie
if cookie and 'll_uid' in list(cookie.keys()):
@@ -2158,10 +2163,12 @@ class WebInterface:
(userid, 'author', authorid))
if res:
logger.debug(f"User {userid} is already subscribed to {authorid}")
+ failed += 1
else:
db.action('INSERT into subscribers (UserID, Type, WantID) VALUES (?, ?, ?)',
(userid, 'author', authorid))
logger.debug(f"Subscribe {userid} to author {authorid}")
+ passed += 1
elif action == 'Unsubscribe':
cookie = cherrypy.request.cookie
if cookie and 'll_uid' in list(cookie.keys()):
@@ -2173,12 +2180,29 @@ class WebInterface:
db.action('DELETE from subscribers WHERE UserID=? and Type=? and WantID=?',
(userid, 'ebook', iss['bookid']))
logger.debug(f"Unsubscribe {userid} author {authorid}")
+ passed += 1
finally:
db.close()
- raise cherrypy.HTTPRedirect(redirect)
+ # Return JSON response instead of redirect
+ total = passed + failed
+ summary = f"Mark Authors '{action}' completed."
+ if total > 0:
+ summary += f" {passed} successful"
+ if failed > 0:
+ summary += f", {failed} failed"
+ summary += f" out of {total} total items."
+ else:
+ summary += " No items were processed."
+ return {
+ 'success': True,
+ 'action': action,
+ 'passed': passed,
+ 'failed': failed,
+ 'total': total,
+ 'summary': summary
+ }
- # noinspection PyGlobalUndefined
@cherrypy.expose
def author_page(self, authorid, book_lang=None, library='eBook', ignored=False, book_filter=''):
global lastauthor
@@ -5395,6 +5419,7 @@ class WebInterface:
# noinspection PyBroadException
@cherrypy.expose
+ @cherrypy.tools.json_out()
def magazine_update(self, **kwargs):
cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"
self.check_permitted(lazylibrarian.perm_edit)