@ -31,7 +31,7 @@ from functools import wraps
try :
try :
from lxml . html . clean import clean_html
from lxml . html . clean import clean_html
except ImportError :
except ImportError :
pass
clean_html = None
from flask import Blueprint , request , flash , redirect , url_for , abort , Markup , Response
from flask import Blueprint , request , flash , redirect , url_for , abort , Markup , Response
from flask_babel import gettext as _
from flask_babel import gettext as _
@ -48,7 +48,7 @@ from .usermanagement import login_required_if_no_ano
from . kobo_sync_status import change_archived_books
from . kobo_sync_status import change_archived_books
editb ook = Blueprint ( ' edit book' , __name__ )
EditB ook = Blueprint ( ' edit - book' , __name__ )
log = logger . create ( )
log = logger . create ( )
@ -61,6 +61,7 @@ def upload_required(f):
return inner
return inner
def edit_required ( f ) :
def edit_required ( f ) :
@wraps ( f )
@wraps ( f )
def inner ( * args , * * kwargs ) :
def inner ( * args , * * kwargs ) :
@ -70,6 +71,7 @@ def edit_required(f):
return inner
return inner
def search_objects_remove ( db_book_object , db_type , input_elements ) :
def search_objects_remove ( db_book_object , db_type , input_elements ) :
del_elements = [ ]
del_elements = [ ]
for c_elements in db_book_object :
for c_elements in db_book_object :
@ -119,6 +121,7 @@ def remove_objects(db_book_object, db_session, del_elements):
db_session . delete ( del_element )
db_session . delete ( del_element )
return changed
return changed
def add_objects ( db_book_object , db_object , db_session , db_type , add_elements ) :
def add_objects ( db_book_object , db_object , db_session , db_type , add_elements ) :
changed = False
changed = False
if db_type == ' languages ' :
if db_type == ' languages ' :
@ -128,7 +131,7 @@ def add_objects(db_book_object, db_object, db_session, db_type, add_elements):
else :
else :
db_filter = db_object . name
db_filter = db_object . name
for add_element in add_elements :
for add_element in add_elements :
# check if a element with that name exists
# check if a n element with that name exists
db_element = db_session . query ( db_object ) . filter ( db_filter == add_element ) . first ( )
db_element = db_session . query ( db_object ) . filter ( db_filter == add_element ) . first ( )
# if no element is found add it
# if no element is found add it
if db_type == ' author ' :
if db_type == ' author ' :
@ -147,7 +150,6 @@ def add_objects(db_book_object, db_object, db_session, db_type, add_elements):
db_book_object . append ( new_element )
db_book_object . append ( new_element )
else :
else :
db_element = create_objects_for_addition ( db_element , add_element , db_type )
db_element = create_objects_for_addition ( db_element , add_element , db_type )
changed = True
# add element to book
# add element to book
changed = True
changed = True
db_book_object . append ( db_element )
db_book_object . append ( db_element )
@ -178,7 +180,7 @@ def create_objects_for_addition(db_element, add_element, db_type):
return db_element
return db_element
# Modifies different Database objects, first check if elements if elements have to be deleted,
# Modifies different Database objects, first check if elements have to be deleted,
# because they are no longer used, than check if elements have to be added to database
# because they are no longer used, than check if elements have to be added to database
def modify_database_object ( input_elements , db_book_object , db_object , db_session , db_type ) :
def modify_database_object ( input_elements , db_book_object , db_object , db_session , db_type ) :
# passing input_elements not as a list may lead to undesired results
# passing input_elements not as a list may lead to undesired results
@ -224,14 +226,15 @@ def modify_identifiers(input_identifiers, db_identifiers, db_session):
changed = True
changed = True
return changed , error
return changed , error
@editbook.route ( " /ajax/delete/<int:book_id> " , methods = [ " POST " ] )
@EditBook.route ( " /ajax/delete/<int:book_id> " , methods = [ " POST " ] )
@login_required
@login_required
def delete_book_from_details ( book_id ) :
def delete_book_from_details ( book_id ) :
return Response ( delete_book_from_table ( book_id , " " , True ) , mimetype = ' application/json ' )
return Response ( delete_book_from_table ( book_id , " " , True ) , mimetype = ' application/json ' )
@ editb ook.route( " /delete/<int:book_id> " , defaults = { ' book_format ' : " " } , methods = [ " POST " ] )
@ EditB ook.route( " /delete/<int:book_id> " , defaults = { ' book_format ' : " " } , methods = [ " POST " ] )
@ editb ook.route( " /delete/<int:book_id>/<string:book_format> " , methods = [ " POST " ] )
@ EditB ook.route( " /delete/<int:book_id>/<string:book_format> " , methods = [ " POST " ] )
@login_required
@login_required
def delete_book_ajax ( book_id , book_format ) :
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 )
@ -252,8 +255,8 @@ def delete_whole_book(book_id, book):
modify_database_object ( [ u ' ' ] , book . languages , db . Languages , calibre_db . session , ' languages ' )
modify_database_object ( [ u ' ' ] , book . languages , db . Languages , calibre_db . session , ' languages ' )
modify_database_object ( [ u ' ' ] , book . publishers , db . Publishers , calibre_db . session , ' publishers ' )
modify_database_object ( [ u ' ' ] , book . publishers , db . Publishers , calibre_db . session , ' publishers ' )
cc = calibre_db . session . query ( db . Custom _ Columns) . \
cc = calibre_db . session . query ( db . Custom Columns) . \
filter ( db . Custom _ Columns. datatype . notin_ ( db . cc_exceptions ) ) . all ( )
filter ( db . Custom Columns. datatype . notin_ ( db . cc_exceptions ) ) . all ( )
for c in cc :
for c in cc :
cc_string = " custom_column_ " + str ( c . id )
cc_string = " custom_column_ " + str ( c . id )
if not c . is_multiple :
if not c . is_multiple :
@ -283,18 +286,18 @@ def delete_whole_book(book_id, book):
calibre_db . session . query ( db . Books ) . filter ( db . Books . id == book_id ) . delete ( )
calibre_db . session . query ( db . Books ) . filter ( db . Books . id == book_id ) . delete ( )
def render_delete_book_result ( book_format , json R esponse, warning , book_id ) :
def render_delete_book_result ( book_format , json _r esponse, warning , book_id ) :
if book_format :
if book_format :
if json R esponse:
if json _r esponse:
return json . dumps ( [ warning , { " location " : url_for ( " edit book.edit_book" , book_id = book_id ) ,
return json . dumps ( [ warning , { " location " : url_for ( " edit - book.edit_book" , book_id = book_id ) ,
" type " : " success " ,
" type " : " success " ,
" format " : book_format ,
" format " : book_format ,
" message " : _ ( ' Book Format Successfully Deleted ' ) } ] )
" message " : _ ( ' Book Format Successfully Deleted ' ) } ] )
else :
else :
flash ( _ ( ' Book Format Successfully Deleted ' ) , category = " success " )
flash ( _ ( ' Book Format Successfully Deleted ' ) , category = " success " )
return redirect ( url_for ( ' edit book.edit_book' , book_id = book_id ) )
return redirect ( url_for ( ' edit - book.edit_book' , book_id = book_id ) )
else :
else :
if json R esponse:
if json _r esponse:
return json . dumps ( [ warning , { " location " : url_for ( ' web.index ' ) ,
return json . dumps ( [ warning , { " location " : url_for ( ' web.index ' ) ,
" type " : " success " ,
" type " : " success " ,
" format " : book_format ,
" format " : book_format ,
@ -304,7 +307,7 @@ def render_delete_book_result(book_format, jsonResponse, warning, book_id):
return redirect ( url_for ( ' web.index ' ) )
return redirect ( url_for ( ' web.index ' ) )
def delete_book_from_table ( book_id , book_format , json R esponse) :
def delete_book_from_table ( book_id , book_format , json _r esponse) :
warning = { }
warning = { }
if current_user . role_delete_books ( ) :
if current_user . role_delete_books ( ) :
book = calibre_db . get_book ( book_id )
book = calibre_db . get_book ( book_id )
@ -312,17 +315,17 @@ def delete_book_from_table(book_id, book_format, jsonResponse):
try :
try :
result , error = helper . delete_book ( book , config . config_calibre_dir , book_format = book_format . upper ( ) )
result , error = helper . delete_book ( book , config . config_calibre_dir , book_format = book_format . upper ( ) )
if not result :
if not result :
if json R esponse:
if json _r esponse:
return json . dumps ( [ { " location " : url_for ( " edit book.edit_book" , book_id = book_id ) ,
return json . dumps ( [ { " location " : url_for ( " edit - book.edit_book" , book_id = book_id ) ,
" type " : " danger " ,
" type " : " danger " ,
" format " : " " ,
" format " : " " ,
" message " : error } ] )
" message " : error } ] )
else :
else :
flash ( error , category = " error " )
flash ( error , category = " error " )
return redirect ( url_for ( ' edit book.edit_book' , book_id = book_id ) )
return redirect ( url_for ( ' edit - book.edit_book' , book_id = book_id ) )
if error :
if error :
if json R esponse:
if json _r esponse:
warning = { " location " : url_for ( " edit book.edit_book" , book_id = book_id ) ,
warning = { " location " : url_for ( " edit - book.edit_book" , book_id = book_id ) ,
" type " : " warning " ,
" type " : " warning " ,
" format " : " " ,
" format " : " " ,
" message " : error }
" message " : error }
@ -337,37 +340,38 @@ def delete_book_from_table(book_id, book_format, jsonResponse):
kobo_sync_status . remove_synced_book ( book . id , True )
kobo_sync_status . remove_synced_book ( book . id , True )
calibre_db . session . commit ( )
calibre_db . session . commit ( )
except Exception as ex :
except Exception as ex :
log . debug _or_exception( ex )
log . error _or_exception( ex )
calibre_db . session . rollback ( )
calibre_db . session . rollback ( )
if json R esponse:
if json _r esponse:
return json . dumps ( [ { " location " : url_for ( " edit book.edit_book" , book_id = book_id ) ,
return json . dumps ( [ { " location " : url_for ( " edit - book.edit_book" , book_id = book_id ) ,
" type " : " danger " ,
" type " : " danger " ,
" format " : " " ,
" format " : " " ,
" message " : ex } ] )
" message " : ex } ] )
else :
else :
flash ( str ( ex ) , category = " error " )
flash ( str ( ex ) , category = " error " )
return redirect ( url_for ( ' edit book.edit_book' , book_id = book_id ) )
return redirect ( url_for ( ' edit - book.edit_book' , book_id = book_id ) )
else :
else :
# book not found
# book not found
log . error ( ' Book with id " %s " could not be deleted: not found ' , book_id )
log . error ( ' Book with id " %s " could not be deleted: not found ' , book_id )
return render_delete_book_result ( book_format , json R esponse, warning , book_id )
return render_delete_book_result ( book_format , json _r esponse, warning , book_id )
message = _ ( " You are missing permissions to delete books " )
message = _ ( " You are missing permissions to delete books " )
if json R esponse:
if json _r esponse:
return json . dumps ( { " location " : url_for ( " edit book.edit_book" , book_id = book_id ) ,
return json . dumps ( { " location " : url_for ( " edit - book.edit_book" , book_id = book_id ) ,
" type " : " danger " ,
" type " : " danger " ,
" format " : " " ,
" format " : " " ,
" message " : message } )
" message " : message } )
else :
else :
flash ( message , category = " error " )
flash ( message , category = " error " )
return redirect ( url_for ( ' edit book.edit_book' , book_id = book_id ) )
return redirect ( url_for ( ' edit - book.edit_book' , book_id = book_id ) )
def render_edit_book ( book_id ) :
def render_edit_book ( book_id ) :
cc = calibre_db . session . query ( db . Custom _ Columns) . filter ( db . Custom _ Columns. datatype . notin_ ( db . cc_exceptions ) ) . all ( )
cc = calibre_db . session . query ( db . Custom Columns) . filter ( db . Custom Columns. datatype . notin_ ( db . cc_exceptions ) ) . all ( )
book = calibre_db . get_filtered_book ( book_id , allow_show_archived = True )
book = calibre_db . get_filtered_book ( book_id , allow_show_archived = True )
if not book :
if not book :
flash ( _ ( u " Oops! Selected book title is unavailable. File does not exist or is not accessible " ) , category = " error " )
flash ( _ ( u " Oops! Selected book title is unavailable. File does not exist or is not accessible " ) ,
category = " error " )
return redirect ( url_for ( " web.index " ) )
return redirect ( url_for ( " web.index " ) )
for lang in book . languages :
for lang in book . languages :
@ -430,6 +434,7 @@ def edit_book_ratings(to_save, book):
changed = True
changed = True
return changed
return changed
def edit_book_tags ( tags , book ) :
def edit_book_tags ( tags , book ) :
input_tags = tags . split ( ' , ' )
input_tags = tags . split ( ' , ' )
input_tags = list ( map ( lambda it : it . strip ( ) , input_tags ) )
input_tags = list ( map ( lambda it : it . strip ( ) , input_tags ) )
@ -446,48 +451,48 @@ def edit_book_series(series, book):
def edit_book_series_index ( series_index , book ) :
def edit_book_series_index ( series_index , book ) :
# Add default series_index to book
# Add default series_index to book
modif _date = False
modif y _date = False
series_index = series_index or ' 1 '
series_index = series_index or ' 1 '
if not series_index . replace ( ' . ' , ' ' , 1 ) . isdigit ( ) :
if not series_index . replace ( ' . ' , ' ' , 1 ) . isdigit ( ) :
flash ( _ ( " %(seriesindex)s is not a valid number, skipping " , seriesindex = series_index ) , category = " warning " )
flash ( _ ( " %(seriesindex)s is not a valid number, skipping " , seriesindex = series_index ) , category = " warning " )
return False
return False
if str ( book . series_index ) != series_index :
if str ( book . series_index ) != series_index :
book . series_index = series_index
book . series_index = series_index
modif _date = True
modif y _date = True
return modif _date
return modif y _date
# Handle book comments/description
# Handle book comments/description
def edit_book_comments ( comments , book ) :
def edit_book_comments ( comments , book ) :
modif _date = False
modif y _date = False
if comments :
if comments :
comments = clean_html ( comments )
comments = clean_html ( comments )
if len ( book . comments ) :
if len ( book . comments ) :
if book . comments [ 0 ] . text != comments :
if book . comments [ 0 ] . text != comments :
book . comments [ 0 ] . text = comments
book . comments [ 0 ] . text = comments
modif _date = True
modif y _date = True
else :
else :
if comments :
if comments :
book . comments . append ( db . Comments ( tex t= comments , book = book . id ) )
book . comments . append ( db . Comments ( commen t= comments , book = book . id ) )
modif _date = True
modif y _date = True
return modif _date
return modif y _date
def edit_book_languages ( languages , book , upload = False , invalid = None ) :
def edit_book_languages ( languages , book , upload _mode = False , invalid = None ) :
input_languages = languages . split ( ' , ' )
input_languages = languages . split ( ' , ' )
unknown_languages = [ ]
unknown_languages = [ ]
if not upload :
if not upload _mode :
input_l = isoLanguages . get_language_codes ( get_locale ( ) , input_languages , unknown_languages )
input_l = isoLanguages . get_language_codes ( get_locale ( ) , input_languages , unknown_languages )
else :
else :
input_l = isoLanguages . get_valid_language_codes ( get_locale ( ) , input_languages , unknown_languages )
input_l = isoLanguages . get_valid_language_codes ( get_locale ( ) , input_languages , unknown_languages )
for l in unknown_languages :
for l ang in unknown_languages :
log . error ( " ' %s ' is not a valid language " , l )
log . error ( " ' %s ' is not a valid language " , l ang )
if isinstance ( invalid , list ) :
if isinstance ( invalid , list ) :
invalid . append ( l )
invalid . append ( l ang )
else :
else :
raise ValueError ( _ ( u " ' %(langname)s ' is not a valid language " , langname = l ) )
raise ValueError ( _ ( u " ' %(langname)s ' is not a valid language " , langname = l ang ) )
# ToDo: Not working correct
# ToDo: Not working correct
if upload and len ( input_l ) == 1 :
if upload _mode and len ( input_l ) == 1 :
# If the language of the file is excluded from the users view, it's not imported, to allow the user to view
# If the language of the file is excluded from the users view, it's not imported, to allow the user to view
# the book it's language is set to the filter language
# the book it's language is set to the filter language
if input_l [ 0 ] != current_user . filter_language ( ) and current_user . filter_language ( ) != " all " :
if input_l [ 0 ] != current_user . filter_language ( ) and current_user . filter_language ( ) != " all " :
@ -571,17 +576,20 @@ def edit_cc_data_string(book, c, to_save, cc_db_value, cc_string):
getattr ( book , cc_string ) . append ( new_cc )
getattr ( book , cc_string ) . append ( new_cc )
return changed , to_save
return changed , to_save
def edit_single_cc_data ( book_id , book , column_id , to_save ) :
def edit_single_cc_data ( book_id , book , column_id , to_save ) :
cc = ( calibre_db . session . query ( db . Custom _ Columns)
cc = ( calibre_db . session . query ( db . Custom Columns)
. filter ( db . Custom _ Columns. datatype . notin_ ( db . cc_exceptions ) )
. filter ( db . Custom Columns. datatype . notin_ ( db . cc_exceptions ) )
. filter ( db . Custom _ Columns. id == column_id )
. filter ( db . Custom Columns. id == column_id )
. all ( ) )
. all ( ) )
return edit_cc_data ( book_id , book , to_save , cc )
return edit_cc_data ( book_id , book , to_save , cc )
def edit_all_cc_data ( book_id , book , to_save ) :
def edit_all_cc_data ( book_id , book , to_save ) :
cc = calibre_db . session . query ( db . Custom _ Columns) . filter ( db . Custom _ Columns. datatype . notin_ ( db . cc_exceptions ) ) . all ( )
cc = calibre_db . session . query ( db . Custom Columns) . filter ( db . Custom Columns. datatype . notin_ ( db . cc_exceptions ) ) . all ( )
return edit_cc_data ( book_id , book , to_save , cc )
return edit_cc_data ( book_id , book , to_save , cc )
def edit_cc_data ( book_id , book , to_save , cc ) :
def edit_cc_data ( book_id , book , to_save , cc ) :
changed = False
changed = False
for c in cc :
for c in cc :
@ -614,10 +622,11 @@ def edit_cc_data(book_id, book, to_save, cc):
' custom ' )
' custom ' )
return changed
return changed
def upload_single_file ( request , book , book_id ) :
def upload_single_file ( file_request , book , book_id ) :
# Check and handle Uploaded file
# Check and handle Uploaded file
if ' btn-upload-format ' in request. files :
if ' btn-upload-format ' in file_ request. files :
requested_file = request. files [ ' btn-upload-format ' ]
requested_file = file_ request. files [ ' btn-upload-format ' ]
# check for empty request
# check for empty request
if requested_file . filename != ' ' :
if requested_file . filename != ' ' :
if not current_user . role_upload ( ) :
if not current_user . role_upload ( ) :
@ -663,23 +672,23 @@ def upload_single_file(request, book, book_id):
calibre_db . update_title_sort ( config )
calibre_db . update_title_sort ( config )
except ( OperationalError , IntegrityError ) as e :
except ( OperationalError , IntegrityError ) as e :
calibre_db . session . rollback ( )
calibre_db . session . rollback ( )
log . error ( ' Database error: %s ' , e )
log . error _or_exception( " Database error: {} " . format ( e ) )
flash ( _ ( u " Database error: %(error)s . " , error = e ) , category = " error " )
flash ( _ ( u " Database error: %(error)s . " , error = e . orig ) , category = " error " )
return redirect ( url_for ( ' web.show_book ' , book_id = book . id ) )
return redirect ( url_for ( ' web.show_book ' , book_id = book . id ) )
# Queue uploader info
# Queue uploader info
link = ' <a href= " {} " > {} </a> ' . format ( url_for ( ' web.show_book ' , book_id = book . id ) , escape ( book . title ) )
link = ' <a href= " {} " > {} </a> ' . format ( url_for ( ' web.show_book ' , book_id = book . id ) , escape ( book . title ) )
upload Text= _ ( u " File format %(ext)s added to %(book)s " , ext = file_ext . upper ( ) , book = link )
upload _text = _ ( u " File format %(ext)s added to %(book)s " , ext = file_ext . upper ( ) , book = link )
WorkerThread . add ( current_user . name , TaskUpload ( upload T ext, escape ( book . title ) ) )
WorkerThread . add ( current_user . name , TaskUpload ( upload _t ext, escape ( book . title ) ) )
return uploader . process (
return uploader . process (
saved_filename , * os . path . splitext ( requested_file . filename ) ,
saved_filename , * os . path . splitext ( requested_file . filename ) ,
rarExecutable = config . config_rarfile_location )
rarExecutable = config . config_rarfile_location )
def upload_cover ( request, book ) :
def upload_cover ( cover_ request, book ) :
if ' btn-upload-cover ' in request. files :
if ' btn-upload-cover ' in cover_ request. files :
requested_file = request. files [ ' btn-upload-cover ' ]
requested_file = cover_ request. files [ ' btn-upload-cover ' ]
# check for empty request
# check for empty request
if requested_file . filename != ' ' :
if requested_file . filename != ' ' :
if not current_user . role_upload ( ) :
if not current_user . role_upload ( ) :
@ -707,8 +716,8 @@ def handle_title_on_edit(book, book_title):
def handle_author_on_edit ( book , author_name , update_stored = True ) :
def handle_author_on_edit ( book , author_name , update_stored = True ) :
# handle author(s)
# handle author(s)
# renamed = False
input_authors , renamed = prepare_authors ( author_name )
input_authors = author_name . split ( ' & ' )
''' input_authors = author_name.split( ' & ' )
input_authors = list ( map ( lambda it : it . strip ( ) . replace ( ' , ' , ' | ' ) , input_authors ) )
input_authors = list ( map ( lambda it : it . strip ( ) . replace ( ' , ' , ' | ' ) , input_authors ) )
# Remove duplicates in authors list
# Remove duplicates in authors list
input_authors = helper . uniq ( input_authors )
input_authors = helper . uniq ( input_authors )
@ -726,7 +735,7 @@ def handle_author_on_edit(book, author_name, update_stored=True):
sorted_renamed_author = helper . get_sorted_author ( renamed_author . name )
sorted_renamed_author = helper . get_sorted_author ( renamed_author . name )
sorted_old_author = helper . get_sorted_author ( in_aut )
sorted_old_author = helper . get_sorted_author ( in_aut )
for one_book in all_books :
for one_book in all_books :
one_book . author_sort = one_book . author_sort . replace ( sorted_renamed_author , sorted_old_author )
one_book . author_sort = one_book . author_sort . replace ( sorted_renamed_author , sorted_old_author ) '''
change = modify_database_object ( input_authors , book . authors , db . Authors , calibre_db . session , ' author ' )
change = modify_database_object ( input_authors , book . authors , db . Authors , calibre_db . session , ' author ' )
@ -747,17 +756,17 @@ def handle_author_on_edit(book, author_name, update_stored=True):
return input_authors , change , renamed
return input_authors , change , renamed
@ editb ook.route( " /admin/book/<int:book_id> " , methods = [ ' GET ' , ' POST ' ] )
@ EditB ook.route( " /admin/book/<int:book_id> " , methods = [ ' GET ' , ' POST ' ] )
@login_required_if_no_ano
@login_required_if_no_ano
@edit_required
@edit_required
def edit_book ( book_id ) :
def edit_book ( book_id ) :
modif _date = False
modif y _date = False
# create the function for sorting...
# create the function for sorting...
try :
try :
calibre_db . update_title_sort ( config )
calibre_db . update_title_sort ( config )
except sqliteOperationalError as e :
except sqliteOperationalError as e :
log . debug _or_exception( e )
log . error _or_exception( e )
calibre_db . session . rollback ( )
calibre_db . session . rollback ( )
# Show form
# Show form
@ -768,13 +777,14 @@ def edit_book(book_id):
# Book not found
# Book not found
if not book :
if not book :
flash ( _ ( u " Oops! Selected book title is unavailable. File does not exist or is not accessible " ) , category = " error " )
flash ( _ ( u " Oops! Selected book title is unavailable. File does not exist or is not accessible " ) ,
category = " error " )
return redirect ( url_for ( " web.index " ) )
return redirect ( url_for ( " web.index " ) )
meta = upload_single_file ( request , book , book_id )
meta = upload_single_file ( request , book , book_id )
if upload_cover ( request , book ) is True :
if upload_cover ( request , book ) is True :
book . has_cover = 1
book . has_cover = 1
modif _date = True
modif y _date = True
try :
try :
to_save = request . form . to_dict ( )
to_save = request . form . to_dict ( )
merge_metadata ( to_save , meta )
merge_metadata ( to_save , meta )
@ -787,12 +797,12 @@ def edit_book(book_id):
input_authors , authorchange , renamed = handle_author_on_edit ( book , to_save [ " author_name " ] )
input_authors , authorchange , renamed = handle_author_on_edit ( book , to_save [ " author_name " ] )
if authorchange or title_change :
if authorchange or title_change :
edited_books_id = book . id
edited_books_id = book . id
modif _date = True
modif y _date = True
if config . config_use_google_drive :
if config . config_use_google_drive :
gdriveutils . updateGdriveCalibreFromLocal ( )
gdriveutils . updateGdriveCalibreFromLocal ( )
error = False
error = " "
if edited_books_id :
if edited_books_id :
error = helper . update_dir_structure ( edited_books_id , config . config_calibre_dir , input_authors [ 0 ] ,
error = helper . update_dir_structure ( edited_books_id , config . config_calibre_dir , input_authors [ 0 ] ,
renamed_author = renamed )
renamed_author = renamed )
@ -809,33 +819,33 @@ def edit_book(book_id):
result , error = helper . save_cover_from_url ( to_save [ " cover_url " ] , book . path )
result , error = helper . save_cover_from_url ( to_save [ " cover_url " ] , book . path )
if result is True :
if result is True :
book . has_cover = 1
book . has_cover = 1
modif _date = True
modif y _date = True
helper . clear_cover_thumbnail_cache ( book . id )
helper . clear_cover_thumbnail_cache ( book . id )
else :
else :
flash ( error , category = " error " )
flash ( error , category = " error " )
# Add default series_index to book
# Add default series_index to book
modif _date | = edit_book_series_index ( to_save [ " series_index " ] , book )
modif y _date | = edit_book_series_index ( to_save [ " series_index " ] , book )
# Handle book comments/description
# Handle book comments/description
modif _date | = edit_book_comments ( Markup ( to_save [ ' description ' ] ) . unescape ( ) , book )
modif y _date | = edit_book_comments ( Markup ( to_save [ ' description ' ] ) . unescape ( ) , book )
# Handle identifiers
# Handle identifiers
input_identifiers = identifier_list ( to_save , book )
input_identifiers = identifier_list ( to_save , book )
modification , warning = modify_identifiers ( input_identifiers , book . identifiers , calibre_db . session )
modification , warning = modify_identifiers ( input_identifiers , book . identifiers , calibre_db . session )
if warning :
if warning :
flash ( _ ( " Identifiers are not Case Sensitive, Overwriting Old Identifier " ) , category = " warning " )
flash ( _ ( " Identifiers are not Case Sensitive, Overwriting Old Identifier " ) , category = " warning " )
modif _date | = modification
modif y _date | = modification
# Handle book tags
# Handle book tags
modif _date | = edit_book_tags ( to_save [ ' tags ' ] , book )
modif y _date | = edit_book_tags ( to_save [ ' tags ' ] , book )
# Handle book series
# Handle book series
modif _date | = edit_book_series ( to_save [ " series " ] , book )
modif y _date | = edit_book_series ( to_save [ " series " ] , book )
# handle book publisher
# handle book publisher
modif _date | = edit_book_publisher ( to_save [ ' publisher ' ] , book )
modif y _date | = edit_book_publisher ( to_save [ ' publisher ' ] , book )
# handle book languages
# handle book languages
modif _date | = edit_book_languages ( to_save [ ' languages ' ] , book )
modif y _date | = edit_book_languages ( to_save [ ' languages ' ] , book )
# handle book ratings
# handle book ratings
modif _date | = edit_book_ratings ( to_save , book )
modif y _date | = edit_book_ratings ( to_save , book )
# handle cc data
# handle cc data
modif _date | = edit_all_cc_data ( book_id , book , to_save )
modif y _date | = edit_all_cc_data ( book_id , book , to_save )
if to_save [ " pubdate " ] :
if to_save [ " pubdate " ] :
try :
try :
@ -845,7 +855,7 @@ def edit_book(book_id):
else :
else :
book . pubdate = db . Books . DEFAULT_PUBDATE
book . pubdate = db . Books . DEFAULT_PUBDATE
if modif _date:
if modif y _date:
book . last_modified = datetime . utcnow ( )
book . last_modified = datetime . utcnow ( )
kobo_sync_status . remove_synced_book ( edited_books_id , all = True )
kobo_sync_status . remove_synced_book ( edited_books_id , all = True )
@ -866,8 +876,13 @@ def edit_book(book_id):
calibre_db . session . rollback ( )
calibre_db . session . rollback ( )
flash ( str ( e ) , category = " error " )
flash ( str ( e ) , category = " error " )
return redirect ( url_for ( ' web.show_book ' , book_id = book . id ) )
return redirect ( url_for ( ' web.show_book ' , book_id = book . id ) )
except ( OperationalError , IntegrityError ) as e :
log . error_or_exception ( " Database error: {} " . format ( e ) )
calibre_db . session . rollback ( )
flash ( _ ( u " Database error: %(error)s . " , error = e . orig ) , category = " error " )
return redirect ( url_for ( ' web.show_book ' , book_id = book . id ) )
except Exception as ex :
except Exception as ex :
log . debug_or_exception ( ex )
log . error _or_exception( ex )
calibre_db . session . rollback ( )
calibre_db . session . rollback ( )
flash ( _ ( " Error editing book, please check logfile for details " ) , category = " error " )
flash ( _ ( " Error editing book, please check logfile for details " ) , category = " error " )
return redirect ( url_for ( ' web.show_book ' , book_id = book . id ) )
return redirect ( url_for ( ' web.show_book ' , book_id = book . id ) )
@ -902,14 +917,7 @@ def identifier_list(to_save, book):
return result
return result
def prepare_authors_on_upload ( title , authr ) :
def prepare_authors ( authr ) :
if title != _ ( u ' Unknown ' ) and authr != _ ( u ' Unknown ' ) :
entry = calibre_db . check_exists_book ( authr , title )
if entry :
log . info ( " Uploaded book probably exists in library " )
flash ( _ ( u " Uploaded book probably exists in the library, consider to change before upload new: " )
+ Markup ( render_title_template ( ' book_exists_flash.html ' , entry = entry ) ) , category = " warning " )
# handle authors
# handle authors
input_authors = authr . split ( ' & ' )
input_authors = authr . split ( ' & ' )
# handle_authors(input_authors)
# handle_authors(input_authors)
@ -932,6 +940,18 @@ def prepare_authors_on_upload(title, authr):
sorted_old_author = helper . get_sorted_author ( in_aut )
sorted_old_author = helper . get_sorted_author ( in_aut )
for one_book in all_books :
for one_book in all_books :
one_book . author_sort = one_book . author_sort . replace ( sorted_renamed_author , sorted_old_author )
one_book . author_sort = one_book . author_sort . replace ( sorted_renamed_author , sorted_old_author )
return input_authors , renamed
def prepare_authors_on_upload ( title , authr ) :
if title != _ ( u ' Unknown ' ) and authr != _ ( u ' Unknown ' ) :
entry = calibre_db . check_exists_book ( authr , title )
if entry :
log . info ( " Uploaded book probably exists in library " )
flash ( _ ( u " Uploaded book probably exists in the library, consider to change before upload new: " )
+ Markup ( render_title_template ( ' book_exists_flash.html ' , entry = entry ) ) , category = " warning " )
input_authors , renamed = prepare_authors ( authr )
sort_authors_list = list ( )
sort_authors_list = list ( )
db_author = None
db_author = None
@ -952,7 +972,7 @@ def prepare_authors_on_upload(title, authr):
return sort_authors , input_authors , db_author , renamed
return sort_authors , input_authors , db_author , renamed
def create_book_on_upload ( modif _date, meta ) :
def create_book_on_upload ( modif y _date, meta ) :
title = meta . title
title = meta . title
authr = meta . author
authr = meta . author
sort_authors , input_authors , db_author , renamed_authors = prepare_authors_on_upload ( title , authr )
sort_authors , input_authors , db_author , renamed_authors = prepare_authors_on_upload ( title , authr )
@ -960,34 +980,34 @@ def create_book_on_upload(modif_date, meta):
title_dir = helper . get_valid_filename ( title , chars = 96 )
title_dir = helper . get_valid_filename ( title , chars = 96 )
author_dir = helper . get_valid_filename ( db_author . name , chars = 96 )
author_dir = helper . get_valid_filename ( db_author . name , chars = 96 )
# combine path and normalize path from w indows systems
# combine path and normalize path from W indows systems
path = os . path . join ( author_dir , title_dir ) . replace ( ' \\ ' , ' / ' )
path = os . path . join ( author_dir , title_dir ) . replace ( ' \\ ' , ' / ' )
# Calibre adds books with utc as timezone
# Calibre adds books with utc as timezone
db_book = db . Books ( title , " " , sort_authors , datetime . utcnow ( ) , datetime ( 101 , 1 , 1 ) ,
db_book = db . Books ( title , " " , sort_authors , datetime . utcnow ( ) , datetime ( 101 , 1 , 1 ) ,
' 1 ' , datetime . utcnow ( ) , path , meta . cover , db_author , [ ] , " " )
' 1 ' , datetime . utcnow ( ) , path , meta . cover , db_author , [ ] , " " )
modif _date | = modify_database_object ( input_authors , db_book . authors , db . Authors , calibre_db . session ,
modif y _date | = modify_database_object ( input_authors , db_book . authors , db . Authors , calibre_db . session ,
' author ' )
' author ' )
# Add series_index to book
# Add series_index to book
modif _date | = edit_book_series_index ( meta . series_id , db_book )
modif y _date | = edit_book_series_index ( meta . series_id , db_book )
# add languages
# add languages
invalid = [ ]
invalid = [ ]
modif _date | = edit_book_languages ( meta . languages , db_book , upload = True , invalid = invalid )
modif y _date | = edit_book_languages ( meta . languages , db_book , upload _mode = True , invalid = invalid )
if invalid :
if invalid :
for l in invalid :
for l ang in invalid :
flash ( _ ( u " ' %(langname)s ' is not a valid language " , langname = l ) , category = " warning " )
flash ( _ ( u " ' %(langname)s ' is not a valid language " , langname = l ang ) , category = " warning " )
# handle tags
# handle tags
modif _date | = edit_book_tags ( meta . tags , db_book )
modif y _date | = edit_book_tags ( meta . tags , db_book )
# handle publisher
# handle publisher
modif _date | = edit_book_publisher ( meta . publisher , db_book )
modif y _date | = edit_book_publisher ( meta . publisher , db_book )
# handle series
# handle series
modif _date | = edit_book_series ( meta . series , db_book )
modif y _date | = edit_book_series ( meta . series , db_book )
# Add file to book
# Add file to book
file_size = os . path . getsize ( meta . file_path )
file_size = os . path . getsize ( meta . file_path )
@ -999,6 +1019,7 @@ def create_book_on_upload(modif_date, meta):
calibre_db . session . flush ( )
calibre_db . session . flush ( )
return db_book , input_authors , title_dir , renamed_authors
return db_book , input_authors , title_dir , renamed_authors
def file_handling_on_upload ( requested_file ) :
def file_handling_on_upload ( requested_file ) :
# check if file extension is correct
# check if file extension is correct
if ' . ' in requested_file . filename :
if ' . ' in requested_file . filename :
@ -1042,7 +1063,7 @@ def move_coverfile(meta, db_book):
category = " error " )
category = " error " )
@ editb ook.route( " /upload " , methods = [ " POST " ] )
@ EditB ook.route( " /upload " , methods = [ " POST " ] )
@login_required_if_no_ano
@login_required_if_no_ano
@upload_required
@upload_required
def upload ( ) :
def upload ( ) :
@ -1051,7 +1072,7 @@ def upload():
if request . method == ' POST ' and ' btn-upload ' in request . files :
if request . method == ' POST ' and ' btn-upload ' in request . files :
for requested_file in request . files . getlist ( " btn-upload " ) :
for requested_file in request . files . getlist ( " btn-upload " ) :
try :
try :
modif _date = False
modif y _date = False
# create the function for sorting...
# create the function for sorting...
calibre_db . update_title_sort ( config )
calibre_db . update_title_sort ( config )
calibre_db . session . connection ( ) . connection . connection . create_function ( ' uuid4 ' , 0 , lambda : str ( uuid4 ( ) ) )
calibre_db . session . connection ( ) . connection . connection . create_function ( ' uuid4 ' , 0 , lambda : str ( uuid4 ( ) ) )
@ -1060,10 +1081,10 @@ def upload():
if error :
if error :
return error
return error
db_book , input_authors , title_dir , renamed_authors = create_book_on_upload ( modif _date, meta )
db_book , input_authors , title_dir , renamed_authors = create_book_on_upload ( modif y _date, meta )
# Comments need s book id therefore only possible after flush
# Comments need book id therefore only possible after flush
modif _date | = edit_book_comments ( Markup ( meta . description ) . unescape ( ) , db_book )
modif y _date | = edit_book_comments ( Markup ( meta . description ) . unescape ( ) , db_book )
book_id = db_book . id
book_id = db_book . id
title = db_book . title
title = db_book . title
@ -1093,24 +1114,24 @@ def upload():
if error :
if error :
flash ( error , category = " error " )
flash ( error , category = " error " )
link = ' <a href= " {} " > {} </a> ' . format ( url_for ( ' web.show_book ' , book_id = book_id ) , escape ( title ) )
link = ' <a href= " {} " > {} </a> ' . format ( url_for ( ' web.show_book ' , book_id = book_id ) , escape ( title ) )
upload T ext = _ ( u " File %(file)s uploaded " , file = link )
upload _t ext = _ ( u " File %(file)s uploaded " , file = link )
WorkerThread . add ( current_user . name , TaskUpload ( upload T ext, escape ( title ) ) )
WorkerThread . add ( current_user . name , TaskUpload ( upload _t ext, escape ( title ) ) )
if len ( request . files . getlist ( " btn-upload " ) ) < 2 :
if len ( request . files . getlist ( " btn-upload " ) ) < 2 :
if current_user . role_edit ( ) or current_user . role_admin ( ) :
if current_user . role_edit ( ) or current_user . role_admin ( ) :
resp = { " location " : url_for ( ' edit book.edit_book' , book_id = book_id ) }
resp = { " location " : url_for ( ' edit - book.edit_book' , book_id = book_id ) }
return Response ( json . dumps ( resp ) , mimetype = ' application/json ' )
return Response ( json . dumps ( resp ) , mimetype = ' application/json ' )
else :
else :
resp = { " location " : url_for ( ' web.show_book ' , book_id = book_id ) }
resp = { " location " : url_for ( ' web.show_book ' , book_id = book_id ) }
return Response ( json . dumps ( resp ) , mimetype = ' application/json ' )
return Response ( json . dumps ( resp ) , mimetype = ' application/json ' )
except ( OperationalError , IntegrityError ) as e :
except ( OperationalError , IntegrityError ) as e :
calibre_db . session . rollback ( )
calibre_db . session . rollback ( )
log . error ( " Database error: %s" , e )
log . error _or_exception ( " Database error: {}" . format ( e ) )
flash ( _ ( u " Database error: %(error)s . " , error = e ) , category = " error " )
flash ( _ ( u " Database error: %(error)s . " , error = e . orig ) , category = " error " )
return Response ( json . dumps ( { " location " : url_for ( " web.index " ) } ) , mimetype = ' application/json ' )
return Response ( json . dumps ( { " location " : url_for ( " web.index " ) } ) , mimetype = ' application/json ' )
@ editb ook.route( " /admin/book/convert/<int:book_id> " , methods = [ ' POST ' ] )
@ EditB ook.route( " /admin/book/convert/<int:book_id> " , methods = [ ' POST ' ] )
@login_required_if_no_ano
@login_required_if_no_ano
@edit_required
@edit_required
def convert_bookformat ( book_id ) :
def convert_bookformat ( book_id ) :
@ -1120,7 +1141,7 @@ def convert_bookformat(book_id):
if ( book_format_from is None ) or ( book_format_to is None ) :
if ( book_format_from is None ) or ( book_format_to is None ) :
flash ( _ ( u " Source or destination format for conversion missing " ) , category = " error " )
flash ( _ ( u " Source or destination format for conversion missing " ) , category = " error " )
return redirect ( url_for ( ' edit book.edit_book' , book_id = book_id ) )
return redirect ( url_for ( ' edit - book.edit_book' , book_id = book_id ) )
log . info ( ' converting: book id: %s from: %s to: %s ' , book_id , book_format_from , book_format_to )
log . info ( ' converting: book id: %s from: %s to: %s ' , book_id , book_format_from , book_format_to )
rtn = helper . convert_book_format ( book_id , config . config_calibre_dir , book_format_from . upper ( ) ,
rtn = helper . convert_book_format ( book_id , config . config_calibre_dir , book_format_from . upper ( ) ,
@ -1132,28 +1153,31 @@ def convert_bookformat(book_id):
category = " success " )
category = " success " )
else :
else :
flash ( _ ( u " There was an error converting this book: %(res)s " , res = rtn ) , category = " error " )
flash ( _ ( u " There was an error converting this book: %(res)s " , res = rtn ) , category = " error " )
return redirect ( url_for ( ' edit book.edit_book' , book_id = book_id ) )
return redirect ( url_for ( ' edit - book.edit_book' , book_id = book_id ) )
@editbook.route ( " /ajax/getcustomenum/<int:c_id> " )
@EditBook.route ( " /ajax/getcustomenum/<int:c_id> " )
@login_required
@login_required
def table_get_custom_enum ( c_id ) :
def table_get_custom_enum ( c_id ) :
ret = list ( )
ret = list ( )
cc = ( calibre_db . session . query ( db . Custom _ Columns)
cc = ( calibre_db . session . query ( db . Custom Columns)
. filter ( db . Custom _ Columns. id == c_id )
. filter ( db . Custom Columns. id == c_id )
. filter ( db . Custom _ Columns. datatype . notin_ ( db . cc_exceptions ) ) . one_or_none ( ) )
. filter ( db . Custom Columns. datatype . notin_ ( db . cc_exceptions ) ) . one_or_none ( ) )
ret . append ( { ' value ' : " " , ' text ' : " " } )
ret . append ( { ' value ' : " " , ' text ' : " " } )
for idx , en in enumerate ( cc . get_display_dict ( ) [ ' enum_values ' ] ) :
for idx , en in enumerate ( cc . get_display_dict ( ) [ ' enum_values ' ] ) :
ret . append ( { ' value ' : en , ' text ' : en } )
ret . append ( { ' value ' : en , ' text ' : en } )
return json . dumps ( ret )
return json . dumps ( ret )
@ editb ook.route( " /ajax/editbooks/<param> " , methods = [ ' POST ' ] )
@ EditB ook.route( " /ajax/editbooks/<param> " , methods = [ ' POST ' ] )
@login_required_if_no_ano
@login_required_if_no_ano
@edit_required
@edit_required
def edit_list_book ( param ) :
def edit_list_book ( param ) :
vals = request . form . to_dict ( )
vals = request . form . to_dict ( )
book = calibre_db . get_book ( vals [ ' pk ' ] )
book = calibre_db . get_book ( vals [ ' pk ' ] )
sort_param = " "
# ret = ""
# ret = ""
try :
if param == ' series_index ' :
if param == ' series_index ' :
edit_book_series_index ( vals [ ' value ' ] , book )
edit_book_series_index ( vals [ ' value ' ] , book )
ret = Response ( json . dumps ( { ' success ' : True , ' newValue ' : book . series_index } ) , mimetype = ' application/json ' )
ret = Response ( json . dumps ( { ' success ' : True , ' newValue ' : book . series_index } ) , mimetype = ' application/json ' )
@ -1188,7 +1212,7 @@ def edit_list_book(param):
ret = Response ( json . dumps ( { ' success ' : True , ' newValue ' : book . author_sort } ) ,
ret = Response ( json . dumps ( { ' success ' : True , ' newValue ' : book . author_sort } ) ,
mimetype = ' application/json ' )
mimetype = ' application/json ' )
elif param == ' title ' :
elif param == ' title ' :
sort = book . sort
sort _param = book . sort
handle_title_on_edit ( book , vals . get ( ' value ' , " " ) )
handle_title_on_edit ( book , vals . get ( ' value ' , " " ) )
helper . update_dir_structure ( book . id , config . config_calibre_dir )
helper . update_dir_structure ( book . id , config . config_calibre_dir )
ret = Response ( json . dumps ( { ' success ' : True , ' newValue ' : book . title } ) ,
ret = Response ( json . dumps ( { ' success ' : True , ' newValue ' : book . title } ) ,
@ -1204,12 +1228,16 @@ def edit_list_book(param):
elif param == ' authors ' :
elif param == ' authors ' :
input_authors , __ , renamed = handle_author_on_edit ( book , vals [ ' value ' ] , vals . get ( ' checkA ' , None ) == " true " )
input_authors , __ , renamed = handle_author_on_edit ( book , vals [ ' value ' ] , vals . get ( ' checkA ' , None ) == " true " )
helper . update_dir_structure ( book . id , config . config_calibre_dir , input_authors [ 0 ] , renamed_author = renamed )
helper . update_dir_structure ( book . id , config . config_calibre_dir , input_authors [ 0 ] , renamed_author = renamed )
ret = Response ( json . dumps ( { ' success ' : True ,
ret = Response ( json . dumps ( {
' success ' : True ,
' newValue ' : ' & ' . join ( [ author . replace ( ' | ' , ' , ' ) for author in input_authors ] ) } ) ,
' newValue ' : ' & ' . join ( [ author . replace ( ' | ' , ' , ' ) for author in input_authors ] ) } ) ,
mimetype = ' application/json ' )
mimetype = ' application/json ' )
elif param == ' is_archived ' :
elif param == ' is_archived ' :
change_archived_books ( book . id , vals [ ' value ' ] == " True " )
is_archived = change_archived_books ( book . id , vals [ ' value ' ] == " True " ,
ret = " "
message = " Book {} archive bit set to: {} " . format ( book . id , vals [ ' value ' ] ) )
if is_archived :
kobo_sync_status . remove_synced_book ( book . id )
return " "
elif param == ' read_status ' :
elif param == ' read_status ' :
ret = helper . edit_book_read_status ( book . id , vals [ ' value ' ] == " True " )
ret = helper . edit_book_read_status ( book . id , vals [ ' value ' ] == " True " )
if ret :
if ret :
@ -1227,19 +1255,22 @@ def edit_list_book(param):
else :
else :
return _ ( " Parameter not found " ) , 400
return _ ( " Parameter not found " ) , 400
book . last_modified = datetime . utcnow ( )
book . last_modified = datetime . utcnow ( )
try :
calibre_db . session . commit ( )
calibre_db . session . commit ( )
# revert change for sort if automatic fields link is deactivated
# revert change for sort if automatic fields link is deactivated
if param == ' title ' and vals . get ( ' checkT ' ) == " false " :
if param == ' title ' and vals . get ( ' checkT ' ) == " false " :
book . sort = sort
book . sort = sort _param
calibre_db . session . commit ( )
calibre_db . session . commit ( )
except ( OperationalError , IntegrityError ) as e :
except ( OperationalError , IntegrityError ) as e :
calibre_db . session . rollback ( )
calibre_db . session . rollback ( )
log . error ( " Database error: %s " , e )
log . error_or_exception ( " Database error: {} " . format ( e ) )
ret = Response ( json . dumps ( { ' success ' : False ,
' msg ' : ' Database error: {} ' . format ( e . orig ) } ) ,
mimetype = ' application/json ' )
return ret
return ret
@ editb ook.route( " /ajax/sort_value/<field>/<int:bookid> " )
@ EditB ook.route( " /ajax/sort_value/<field>/<int:bookid> " )
@login_required
@login_required
def get_sorted_entry ( field , bookid ) :
def get_sorted_entry ( field , bookid ) :
if field in [ ' title ' , ' authors ' , ' sort ' , ' author_sort ' ] :
if field in [ ' title ' , ' authors ' , ' sort ' , ' author_sort ' ] :
@ -1256,7 +1287,7 @@ def get_sorted_entry(field, bookid):
return " "
return " "
@ editb ook.route( " /ajax/simulatemerge " , methods = [ ' POST ' ] )
@ EditB ook.route( " /ajax/simulatemerge " , methods = [ ' POST ' ] )
@login_required
@login_required
@edit_required
@edit_required
def simulate_merge_list_book ( ) :
def simulate_merge_list_book ( ) :
@ -1265,14 +1296,14 @@ def simulate_merge_list_book():
to_book = calibre_db . get_book ( vals [ 0 ] ) . title
to_book = calibre_db . get_book ( vals [ 0 ] ) . title
vals . pop ( 0 )
vals . pop ( 0 )
if to_book :
if to_book :
for book_id in vals :
from_book = [ ]
from_book = [ ]
for book_id in vals :
from_book . append ( calibre_db . get_book ( book_id ) . title )
from_book . append ( calibre_db . get_book ( book_id ) . title )
return json . dumps ( { ' to ' : to_book , ' from ' : from_book } )
return json . dumps ( { ' to ' : to_book , ' from ' : from_book } )
return " "
return " "
@ editb ook.route( " /ajax/mergebooks " , methods = [ ' POST ' ] )
@ EditB ook.route( " /ajax/mergebooks " , methods = [ ' POST ' ] )
@login_required
@login_required
@edit_required
@edit_required
def merge_list_book ( ) :
def merge_list_book ( ) :
@ -1285,8 +1316,9 @@ def merge_list_book():
if to_book :
if to_book :
for file in to_book . data :
for file in to_book . data :
to_file . append ( file . format )
to_file . append ( file . format )
to_name = helper . get_valid_filename ( to_book . title , chars = 96 ) + ' - ' + \
to_name = helper . get_valid_filename ( to_book . title ,
helper . get_valid_filename ( to_book . authors [ 0 ] . name , chars = 96 )
chars = 96 ) + ' - ' + helper . get_valid_filename ( to_book . authors [ 0 ] . name ,
chars = 96 )
for book_id in vals :
for book_id in vals :
from_book = calibre_db . get_book ( book_id )
from_book = calibre_db . get_book ( book_id )
if from_book :
if from_book :
@ -1309,14 +1341,15 @@ def merge_list_book():
return " "
return " "
@ editb ook.route( " /ajax/xchange " , methods = [ ' POST ' ] )
@ EditB ook.route( " /ajax/xchange " , methods = [ ' POST ' ] )
@login_required
@login_required
@edit_required
@edit_required
def table_xchange_author_title ( ) :
def table_xchange_author_title ( ) :
vals = request . get_json ( ) . get ( ' xchange ' )
vals = request . get_json ( ) . get ( ' xchange ' )
edited_books_id = False
if vals :
if vals :
for val in vals :
for val in vals :
modif _date = False
modif y _date = False
book = calibre_db . get_book ( val )
book = calibre_db . get_book ( val )
authors = book . title
authors = book . title
book . authors = calibre_db . order_authors ( [ book ] )
book . authors = calibre_db . order_authors ( [ book ] )
@ -1328,7 +1361,7 @@ def table_xchange_author_title():
input_authors , authorchange , renamed = handle_author_on_edit ( book , authors )
input_authors , authorchange , renamed = handle_author_on_edit ( book , authors )
if authorchange or title_change :
if authorchange or title_change :
edited_books_id = book . id
edited_books_id = book . id
modif _date = True
modif y _date = True
if config . config_use_google_drive :
if config . config_use_google_drive :
gdriveutils . updateGdriveCalibreFromLocal ( )
gdriveutils . updateGdriveCalibreFromLocal ( )
@ -1336,13 +1369,13 @@ def table_xchange_author_title():
if edited_books_id :
if edited_books_id :
helper . update_dir_structure ( edited_books_id , config . config_calibre_dir , input_authors [ 0 ] ,
helper . update_dir_structure ( edited_books_id , config . config_calibre_dir , input_authors [ 0 ] ,
renamed_author = renamed )
renamed_author = renamed )
if modif _date:
if modif y _date:
book . last_modified = datetime . utcnow ( )
book . last_modified = datetime . utcnow ( )
try :
try :
calibre_db . session . commit ( )
calibre_db . session . commit ( )
except ( OperationalError , IntegrityError ) as e :
except ( OperationalError , IntegrityError ) as e :
calibre_db . session . rollback ( )
calibre_db . session . rollback ( )
log . error ( " Database error: %s " , e )
log . error _or_exception ( " Database error: %s " , e )
return json . dumps ( { ' success ' : False } )
return json . dumps ( { ' success ' : False } )
if config . config_use_google_drive :
if config . config_use_google_drive :