Merge branch 'master' of https://github.com/janeczku/calibre-web into ebookconvert-any
This commit is contained in:
+213
-81
@@ -2,9 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
try:
|
||||
from googleapiclient.errors import HttpError
|
||||
# gdrive_support = True
|
||||
except ImportError:
|
||||
# gdrive_support = False
|
||||
pass
|
||||
|
||||
try:
|
||||
@@ -87,6 +85,7 @@ except ImportError:
|
||||
|
||||
import time
|
||||
import server
|
||||
import random
|
||||
|
||||
current_milli_time = lambda: int(round(time.time() * 1000))
|
||||
|
||||
@@ -94,7 +93,8 @@ current_milli_time = lambda: int(round(time.time() * 1000))
|
||||
# Global variables
|
||||
gdrive_watch_callback_token = 'target=calibreweb-watch_files'
|
||||
|
||||
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx', 'fb2'])
|
||||
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx',
|
||||
'fb2'}
|
||||
|
||||
def md5(fname):
|
||||
hash_md5 = hashlib.md5()
|
||||
@@ -136,9 +136,9 @@ class ReverseProxied(object):
|
||||
scheme = environ.get('HTTP_X_SCHEME', '')
|
||||
if scheme:
|
||||
environ['wsgi.url_scheme'] = scheme
|
||||
server = environ.get('HTTP_X_FORWARDED_SERVER', '')
|
||||
if server:
|
||||
environ['HTTP_HOST'] = server
|
||||
servr = environ.get('HTTP_X_FORWARDED_SERVER', '')
|
||||
if servr:
|
||||
environ['HTTP_HOST'] = servr
|
||||
return self.app(environ, start_response)
|
||||
|
||||
|
||||
@@ -185,8 +185,8 @@ db.setup_db()
|
||||
|
||||
|
||||
def is_gdrive_ready():
|
||||
return os.path.exists(os.path.join(config.get_main_dir,'settings.yaml')) and \
|
||||
os.path.exists(os.path.join(config.get_main_dir,'gdrive_credentials'))
|
||||
return os.path.exists(os.path.join(config.get_main_dir, 'settings.yaml')) and \
|
||||
os.path.exists(os.path.join(config.get_main_dir, 'gdrive_credentials'))
|
||||
|
||||
|
||||
@babel.localeselector
|
||||
@@ -287,10 +287,10 @@ class Pagination(object):
|
||||
def has_next(self):
|
||||
return self.page < self.pages
|
||||
|
||||
# right_edge: last right_edges count of all pages are shown as number, means, if 10 pages are paginated -> 9,10 shown
|
||||
# left_edge: first left_edges count of all pages are shown as number -> 1,2 shown
|
||||
# left_current: left_current count below current page are shown as number, means if current page 5 -> 3,4 shown
|
||||
# left_current: right_current count above current page are shown as number, means if current page 5 -> 6,7 shown
|
||||
# right_edge: last right_edges count of all pages are shown as number, means, if 10 pages are paginated -> 9,10 shwn
|
||||
# left_edge: first left_edges count of all pages are shown as number -> 1,2 shwn
|
||||
# left_current: left_current count below current page are shown as number, means if current page 5 -> 3,4 shwn
|
||||
# left_current: right_current count above current page are shown as number, means if current page 5 -> 6,7 shwn
|
||||
def iter_pages(self, left_edge=2, left_current=2,
|
||||
right_current=4, right_edge=2):
|
||||
last = 0
|
||||
@@ -321,7 +321,7 @@ def remote_login_required(f):
|
||||
return f(*args, **kwargs)
|
||||
if request.is_xhr:
|
||||
data = {'status': 'error', 'message': 'Forbidden'}
|
||||
response = make_response(json.dumps(data, ensure_ascii=false))
|
||||
response = make_response(json.dumps(data, ensure_ascii=False))
|
||||
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
||||
return response, 403
|
||||
abort(403)
|
||||
@@ -338,9 +338,10 @@ def url_for_other_page(page):
|
||||
args['page'] = page
|
||||
return url_for(request.endpoint, **args)
|
||||
|
||||
|
||||
# shortentitles to at longest nchar, shorten longer words if necessary
|
||||
@app.template_filter('shortentitle')
|
||||
def shortentitle_filter(s,nchar=20):
|
||||
def shortentitle_filter(s, nchar=20):
|
||||
text = s.split()
|
||||
res = "" # result
|
||||
suml = 0 # overall length
|
||||
@@ -471,7 +472,7 @@ def common_filters():
|
||||
|
||||
|
||||
# Creates for all stored languages a translated speaking name in the array for the UI
|
||||
def speaking_language(languages = None):
|
||||
def speaking_language(languages=None):
|
||||
if not languages:
|
||||
languages = db.session.query(db.Languages).all()
|
||||
for lang in languages:
|
||||
@@ -486,17 +487,17 @@ def speaking_language(languages = None):
|
||||
# Fill indexpage with all requested data from database
|
||||
def fill_indexpage(page, database, db_filter, order, *join):
|
||||
if current_user.show_detail_random():
|
||||
random = db.session.query(db.Books).filter(common_filters())\
|
||||
randm = db.session.query(db.Books).filter(common_filters())\
|
||||
.order_by(func.random()).limit(config.config_random_books)
|
||||
else:
|
||||
random = false
|
||||
randm = false()
|
||||
off = int(int(config.config_books_per_page) * (page - 1))
|
||||
pagination = Pagination(page, config.config_books_per_page,
|
||||
len(db.session.query(database)
|
||||
.filter(db_filter).filter(common_filters()).all()))
|
||||
entries = db.session.query(database).join(*join,isouter=True).filter(db_filter)\
|
||||
.filter(common_filters()).order_by(*order).offset(off).limit(config.config_books_per_page).all()
|
||||
return entries, random, pagination
|
||||
return entries, randm, pagination
|
||||
|
||||
|
||||
# Modifies different Database objects, first check if elements have to be added to database, than check
|
||||
@@ -893,6 +894,73 @@ def get_email_status_json():
|
||||
return response
|
||||
|
||||
|
||||
|
||||
# checks if domain is in database (including wildcards)
|
||||
# example SELECT * FROM @TABLE WHERE 'abcdefg' LIKE Name;
|
||||
# from https://code.luasoftware.com/tutorials/flask/execute-raw-sql-in-flask-sqlalchemy/
|
||||
def check_valid_domain(domain_text):
|
||||
# result = session.query(Notification).from_statement(text(sql)).params(id=5).all()
|
||||
#ToDo: check possible SQL injection
|
||||
domain_text = domain_text.split('@',1)[-1].lower()
|
||||
sql = "SELECT * FROM registration WHERE '%s' LIKE domain;" % domain_text
|
||||
result = ub.session.query(ub.Registration).from_statement(text(sql)).all()
|
||||
return len(result)
|
||||
|
||||
''' POST /post
|
||||
{
|
||||
name: 'username', //name of field (column in db)
|
||||
pk: 1 //primary key (record id)
|
||||
value: 'superuser!' //new value
|
||||
}'''
|
||||
@app.route("/ajax/editdomain", methods=['POST'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def edit_domain():
|
||||
vals = request.form.to_dict()
|
||||
answer = ub.session.query(ub.Registration).filter(ub.Registration.id == vals['pk']).first()
|
||||
# domain_name = request.args.get('domain')
|
||||
answer.domain = vals['value'].replace('*','%').replace('?','_').lower()
|
||||
ub.session.commit()
|
||||
return ""
|
||||
|
||||
@app.route("/ajax/adddomain", methods=['POST'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def add_domain():
|
||||
domain_name = request.form.to_dict()['domainname'].replace('*','%').replace('?','_').lower()
|
||||
check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name).first()
|
||||
if not check:
|
||||
new_domain = ub.Registration(domain=domain_name)
|
||||
ub.session.add(new_domain)
|
||||
ub.session.commit()
|
||||
return ""
|
||||
|
||||
@app.route("/ajax/deletedomain", methods=['POST'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def delete_domain():
|
||||
domain_id = request.form.to_dict()['domainid'].replace('*','%').replace('?','_').lower()
|
||||
ub.session.query(ub.Registration).filter(ub.Registration.id == domain_id).delete()
|
||||
ub.session.commit()
|
||||
# If last domain was deleted, add all domains by default
|
||||
if not ub.session.query(ub.Registration).count():
|
||||
new_domain = ub.Registration(domain="%.%")
|
||||
ub.session.add(new_domain)
|
||||
ub.session.commit()
|
||||
return ""
|
||||
|
||||
@app.route("/ajax/domainlist")
|
||||
@login_required
|
||||
@admin_required
|
||||
def list_domain():
|
||||
answer = ub.session.query(ub.Registration).all()
|
||||
json_dumps = json.dumps([{"domain":r.domain.replace('%','*').replace('_','?'),"id":r.id} for r in answer])
|
||||
js=json.dumps(json_dumps.replace('"', "'")).lstrip('"').strip('"')
|
||||
response = make_response(js.replace("'",'"'))
|
||||
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
||||
return response
|
||||
|
||||
|
||||
@app.route("/get_authors_json", methods=['GET', 'POST'])
|
||||
@login_required_if_no_ano
|
||||
def get_authors_json():
|
||||
@@ -1076,7 +1144,7 @@ def hot_books(page):
|
||||
random = db.session.query(db.Books).filter(common_filters())\
|
||||
.order_by(func.random()).limit(config.config_random_books)
|
||||
else:
|
||||
random = false
|
||||
random = false()
|
||||
off = int(int(config.config_books_per_page) * (page - 1))
|
||||
all_books = ub.session.query(ub.Downloads, ub.func.count(ub.Downloads.book_id)).order_by(
|
||||
ub.func.count(ub.Downloads.book_id).desc()).group_by(ub.Downloads.book_id)
|
||||
@@ -1996,30 +2064,38 @@ def register():
|
||||
|
||||
if request.method == "POST":
|
||||
to_save = request.form.to_dict()
|
||||
if not to_save["nickname"] or not to_save["email"] or not to_save["password"]:
|
||||
if not to_save["nickname"] or not to_save["email"]:
|
||||
flash(_(u"Please fill out all fields!"), category="error")
|
||||
return render_title_template('register.html', title=_(u"register"), page="register")
|
||||
|
||||
existing_user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == to_save["nickname"].lower()).first()
|
||||
existing_email = ub.session.query(ub.User).filter(ub.User.email == to_save["email"]).first()
|
||||
existing_email = ub.session.query(ub.User).filter(ub.User.email == to_save["email"].lower()).first()
|
||||
if not existing_user and not existing_email:
|
||||
content = ub.User()
|
||||
content.password = generate_password_hash(to_save["password"])
|
||||
content.nickname = to_save["nickname"]
|
||||
content.email = to_save["email"]
|
||||
content.role = config.config_default_role
|
||||
content.sidebar_view = config.config_default_show
|
||||
try:
|
||||
ub.session.add(content)
|
||||
ub.session.commit()
|
||||
except Exception:
|
||||
ub.session.rollback()
|
||||
flash(_(u"An unknown error occured. Please try again later."), category="error")
|
||||
# content.password = generate_password_hash(to_save["password"])
|
||||
if check_valid_domain(to_save["email"]):
|
||||
content.nickname = to_save["nickname"]
|
||||
content.email = to_save["email"]
|
||||
password = helper.generate_random_password()
|
||||
content.password = generate_password_hash(password)
|
||||
content.role = config.config_default_role
|
||||
content.sidebar_view = config.config_default_show
|
||||
try:
|
||||
ub.session.add(content)
|
||||
ub.session.commit()
|
||||
helper.send_registration_mail(to_save["email"],to_save["nickname"], password)
|
||||
except Exception:
|
||||
ub.session.rollback()
|
||||
flash(_(u"An unknown error occurred. Please try again later."), category="error")
|
||||
return render_title_template('register.html', title=_(u"register"), page="register")
|
||||
else:
|
||||
flash(_(u"Your e-mail is not allowed to register"), category="error")
|
||||
app.logger.info('Registering failed for user "' + to_save['nickname'] + '" e-mail adress: ' + to_save["email"])
|
||||
return render_title_template('register.html', title=_(u"register"), page="register")
|
||||
flash("Your account has been created. Please login.", category="success")
|
||||
flash(_(u"Confirmation e-mail was send to your e-mail account."), category="success")
|
||||
return redirect(url_for('login'))
|
||||
else:
|
||||
flash(_(u"This username or email address is already in use."), category="error")
|
||||
flash(_(u"This username or e-mail address is already in use."), category="error")
|
||||
return render_title_template('register.html', title=_(u"register"), page="register")
|
||||
|
||||
return render_title_template('register.html', title=_(u"register"), page="register")
|
||||
@@ -2134,7 +2210,7 @@ def token_verified():
|
||||
data['status'] = 'success'
|
||||
flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success")
|
||||
|
||||
response = make_response(json.dumps(data, ensure_ascii=false))
|
||||
response = make_response(json.dumps(data, ensure_ascii=False))
|
||||
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
||||
|
||||
return response
|
||||
@@ -2156,7 +2232,7 @@ def send_to_kindle(book_id):
|
||||
else:
|
||||
flash(_(u"There was an error sending this book: %(res)s", res=result), category="error")
|
||||
else:
|
||||
flash(_(u"Please configure your kindle email address first..."), category="error")
|
||||
flash(_(u"Please configure your kindle e-mail address first..."), category="error")
|
||||
return redirect(request.environ["HTTP_REFERER"])
|
||||
|
||||
|
||||
@@ -2363,7 +2439,7 @@ def edit_shelf(shelf_id):
|
||||
@login_required
|
||||
def delete_shelf(shelf_id):
|
||||
cur_shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
|
||||
deleted = false
|
||||
deleted = None
|
||||
if current_user.role_admin():
|
||||
deleted = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).delete()
|
||||
else:
|
||||
@@ -2456,17 +2532,21 @@ def profile():
|
||||
to_save = request.form.to_dict()
|
||||
content.random_books = 0
|
||||
if current_user.role_passwd() or current_user.role_admin():
|
||||
if to_save["password"]:
|
||||
if "password" in to_save:
|
||||
content.password = generate_password_hash(to_save["password"])
|
||||
if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail:
|
||||
content.kindle_mail = to_save["kindle_mail"]
|
||||
if to_save["email"] and to_save["email"] != content.email:
|
||||
if config.config_public_reg and not check_valid_domain(to_save["email"]):
|
||||
flash(_(u"E-mail is not from valid domain"), category="error")
|
||||
return render_title_template("user_edit.html", content=content, downloads=downloads,
|
||||
title=_(u"%(name)s's profile", name=current_user.nickname))
|
||||
content.email = to_save["email"]
|
||||
if "show_random" in to_save and to_save["show_random"] == "on":
|
||||
content.random_books = 1
|
||||
if "default_language" in to_save:
|
||||
content.default_language = to_save["default_language"]
|
||||
if to_save["locale"]:
|
||||
if "locale" in to_save:
|
||||
content.locale = to_save["locale"]
|
||||
content.sidebar_view = 0
|
||||
if "show_random" in to_save:
|
||||
@@ -2499,7 +2579,7 @@ def profile():
|
||||
ub.session.commit()
|
||||
except IntegrityError:
|
||||
ub.session.rollback()
|
||||
flash(_(u"Found an existing account for this email address."), category="error")
|
||||
flash(_(u"Found an existing account for this e-mail address."), category="error")
|
||||
return render_title_template("user_edit.html", content=content, downloads=downloads,
|
||||
title=_(u"%(name)s's profile", name=current_user.nickname))
|
||||
flash(_(u"Profile updated"), category="success")
|
||||
@@ -2606,7 +2686,7 @@ def view_configuration():
|
||||
if "show_mature_content" in to_save:
|
||||
content.config_default_show = content.config_default_show + ub.MATURE_CONTENT
|
||||
ub.session.commit()
|
||||
flash(_(u"Calibre-web configuration updated"), category="success")
|
||||
flash(_(u"Calibre-Web configuration updated"), category="success")
|
||||
config.loadSettings()
|
||||
if reboot_required:
|
||||
# db.engine.dispose() # ToDo verify correct
|
||||
@@ -2634,6 +2714,7 @@ def configuration_helper(origin):
|
||||
gdriveError=None
|
||||
db_change = False
|
||||
success = False
|
||||
filedata = None
|
||||
if gdriveutils.gdrive_support == False:
|
||||
gdriveError = _('Import of optional Google Drive requirements missing')
|
||||
else:
|
||||
@@ -2644,7 +2725,6 @@ def configuration_helper(origin):
|
||||
filedata=json.load(settings)
|
||||
if not 'web' in filedata:
|
||||
gdriveError = _('client_secrets.json is not configured for web application')
|
||||
filedata = None
|
||||
if request.method == "POST":
|
||||
to_save = request.form.to_dict()
|
||||
content = ub.session.query(ub.Settings).first() # type: ub.Settings
|
||||
@@ -2768,7 +2848,7 @@ def configuration_helper(origin):
|
||||
db.session.close()
|
||||
db.engine.dispose()
|
||||
ub.session.commit()
|
||||
flash(_(u"Calibre-web configuration updated"), category="success")
|
||||
flash(_(u"Calibre-Web configuration updated"), category="success")
|
||||
config.loadSettings()
|
||||
app.logger.setLevel(config.config_log_level)
|
||||
logging.getLogger("book_formats").setLevel(config.config_log_level)
|
||||
@@ -2793,10 +2873,10 @@ def configuration_helper(origin):
|
||||
app.logger.info('Reboot required, restarting')
|
||||
if origin:
|
||||
success = True
|
||||
if is_gdrive_ready() and gdriveutils.gdrive_support == True:
|
||||
if is_gdrive_ready() and gdriveutils.gdrive_support == True and config.config_use_google_drive == True:
|
||||
gdrivefolders=gdriveutils.listRootFolders()
|
||||
else:
|
||||
gdrivefolders=None
|
||||
gdrivefolders=list()
|
||||
return render_title_template("config_edit.html", origin=origin, success=success, content=config,
|
||||
show_authenticate_google_drive=not is_gdrive_ready(), gdrive=gdriveutils.gdrive_support,
|
||||
gdriveError=gdriveError, gdrivefolders=gdrivefolders,
|
||||
@@ -2812,13 +2892,6 @@ def new_user():
|
||||
translations = [LC('en')] + babel.list_translations()
|
||||
if request.method == "POST":
|
||||
to_save = request.form.to_dict()
|
||||
if not to_save["nickname"] or not to_save["email"] or not to_save["password"]:
|
||||
flash(_(u"Please fill out all fields!"), category="error")
|
||||
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
|
||||
title=_(u"Add new user"))
|
||||
content.password = generate_password_hash(to_save["password"])
|
||||
content.nickname = to_save["nickname"]
|
||||
content.email = to_save["email"]
|
||||
content.default_language = to_save["default_language"]
|
||||
content.mature_content = "show_mature_content" in to_save
|
||||
content.theme = int(to_save["theme"])
|
||||
@@ -2858,6 +2931,18 @@ def new_user():
|
||||
content.role = content.role + ub.ROLE_PASSWD
|
||||
if "edit_shelf_role" in to_save:
|
||||
content.role = content.role + ub.ROLE_EDIT_SHELFS
|
||||
if not to_save["nickname"] or not to_save["email"] or not to_save["password"]:
|
||||
flash(_(u"Please fill out all fields!"), category="error")
|
||||
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
|
||||
title=_(u"Add new user"))
|
||||
content.password = generate_password_hash(to_save["password"])
|
||||
content.nickname = to_save["nickname"]
|
||||
if config.config_public_reg and not check_valid_domain(to_save["email"]):
|
||||
flash(_(u"E-mail is not from valid domain"), category="error")
|
||||
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
|
||||
title=_(u"Add new user"))
|
||||
else:
|
||||
content.email = to_save["email"]
|
||||
try:
|
||||
ub.session.add(content)
|
||||
ub.session.commit()
|
||||
@@ -2865,7 +2950,7 @@ def new_user():
|
||||
return redirect(url_for('admin'))
|
||||
except IntegrityError:
|
||||
ub.session.rollback()
|
||||
flash(_(u"Found an existing account for this email address or nickname."), category="error")
|
||||
flash(_(u"Found an existing account for this e-mail address or nickname."), category="error")
|
||||
else:
|
||||
content.role = config.config_default_role
|
||||
content.sidebar_view = config.config_default_show
|
||||
@@ -2889,22 +2974,23 @@ def edit_mailsettings():
|
||||
content.mail_use_ssl = int(to_save["mail_use_ssl"])
|
||||
try:
|
||||
ub.session.commit()
|
||||
flash(_(u"Mail settings updated"), category="success")
|
||||
flash(_(u"E-mail server settings updated"), category="success")
|
||||
except Exception as e:
|
||||
flash(e, category="error")
|
||||
if "test" in to_save and to_save["test"]:
|
||||
if current_user.kindle_mail:
|
||||
result = helper.send_test_mail(current_user.kindle_mail, current_user.nickname)
|
||||
if result is None:
|
||||
flash(_(u"Test E-Mail successfully send to %(kindlemail)s", kindlemail=current_user.kindle_mail),
|
||||
flash(_(u"Test e-mail successfully send to %(kindlemail)s", kindlemail=current_user.kindle_mail),
|
||||
category="success")
|
||||
else:
|
||||
flash(_(u"There was an error sending the Test E-Mail: %(res)s", res=result), category="error")
|
||||
flash(_(u"There was an error sending the Test e-mail: %(res)s", res=result), category="error")
|
||||
else:
|
||||
flash(_(u"Please configure your kindle email address first..."), category="error")
|
||||
flash(_(u"Please configure your kindle e-mail address first..."), category="error")
|
||||
else:
|
||||
flash(_(u"E-Mail settings updated"), category="success")
|
||||
return render_title_template("email_edit.html", content=content, title=_(u"Edit mail settings"), page="mailset")
|
||||
flash(_(u"E-mail server settings updated"), category="success")
|
||||
return render_title_template("email_edit.html", content=content, title=_(u"Edit e-mail server settings"),
|
||||
page="mailset")
|
||||
|
||||
|
||||
@app.route("/admin/user/<int:user_id>", methods=["GET", "POST"])
|
||||
@@ -2916,9 +3002,9 @@ def edit_user(user_id):
|
||||
languages = speaking_language()
|
||||
translations = babel.list_translations() + [LC('en')]
|
||||
for book in content.downloads:
|
||||
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
|
||||
if downloadBook:
|
||||
downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first())
|
||||
downloadbook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
|
||||
if downloadbook:
|
||||
downloads.append(downloadbook)
|
||||
else:
|
||||
ub.delete_download(book.book_id)
|
||||
# ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete()
|
||||
@@ -3046,6 +3132,26 @@ def edit_user(user_id):
|
||||
nick=content.nickname), page="edituser")
|
||||
|
||||
|
||||
@app.route("/admin/resetpassword/<int:user_id>")
|
||||
@login_required
|
||||
@admin_required
|
||||
def reset_password(user_id):
|
||||
if not config.config_public_reg:
|
||||
abort(404)
|
||||
if current_user is not None and current_user.is_authenticated:
|
||||
existing_user = ub.session.query(ub.User).filter(ub.User.id == user_id).first()
|
||||
password = helper.generate_random_password()
|
||||
existing_user.password = generate_password_hash(password)
|
||||
try:
|
||||
ub.session.commit()
|
||||
helper.send_registration_mail(existing_user.email, existing_user.nickname, password, True)
|
||||
flash(_(u"Password for user %s reset" % existing_user.nickname), category="success")
|
||||
except Exception:
|
||||
ub.session.rollback()
|
||||
flash(_(u"An unknown error occurred. Please try again later."), category="error")
|
||||
return redirect(url_for('admin'))
|
||||
|
||||
|
||||
@app.route("/admin/book/<int:book_id>", methods=['GET', 'POST'])
|
||||
@login_required_if_no_ano
|
||||
@edit_required
|
||||
@@ -3062,14 +3168,14 @@ def edit_book(book_id):
|
||||
flash(_(u"Error opening eBook. File does not exist or file is not accessible"), category="error")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
for index in range(0, len(book.languages)):
|
||||
for indx in range(0, len(book.languages)):
|
||||
try:
|
||||
book.languages[index].language_name = LC.parse(book.languages[index].lang_code).get_language_name(
|
||||
book.languages[indx].language_name = LC.parse(book.languages[indx].lang_code).get_language_name(
|
||||
get_locale())
|
||||
except Exception:
|
||||
book.languages[index].language_name = _(isoLanguages.get(part3=book.languages[index].lang_code).name)
|
||||
for author in book.authors:
|
||||
author_names.append(author.name.replace('|', ','))
|
||||
book.languages[indx].language_name = _(isoLanguages.get(part3=book.languages[indx].lang_code).name)
|
||||
for authr in book.authors:
|
||||
author_names.append(authr.name.replace('|', ','))
|
||||
|
||||
#Option for showing convertbook button
|
||||
if config.config_ebookconverter == 2:
|
||||
@@ -3097,7 +3203,7 @@ def edit_book(book_id):
|
||||
conversion_formats=allowed_conversion_formats)
|
||||
|
||||
# Update book
|
||||
edited_books_id = set()
|
||||
edited_books_id = {}
|
||||
|
||||
# Check and handle Uploaded file
|
||||
if 'btn-upload-format' in request.files:
|
||||
@@ -3107,7 +3213,8 @@ def edit_book(book_id):
|
||||
if '.' in requested_file.filename:
|
||||
file_ext = requested_file.filename.rsplit('.', 1)[-1].lower()
|
||||
if file_ext not in ALLOWED_EXTENSIONS:
|
||||
flash(_('File extension "%s" is not allowed to be uploaded to this server' % file_ext), category="error")
|
||||
flash(_('File extension "%s" is not allowed to be uploaded to this server' % file_ext),
|
||||
category="error")
|
||||
return redirect(url_for('show_book', book_id=book.id))
|
||||
else:
|
||||
flash(_('File to be uploaded must have an extension'), category="error")
|
||||
@@ -3143,10 +3250,36 @@ def edit_book(book_id):
|
||||
db.session.connection().connection.connection.create_function("title_sort", 1, db.title_sort)
|
||||
|
||||
# Queue uploader info
|
||||
uploadText=_(u"File format %s added to %s" % (file_ext.upper(),book.title))
|
||||
uploadText=_(u"File format %s added to %s" % (file_ext.upper(), book.title))
|
||||
helper.global_WorkerThread.add_upload(current_user.nickname,
|
||||
"<a href=\""+ url_for('show_book', book_id=book.id) +"\">"+ uploadText + "</a>")
|
||||
"<a href=\"" + url_for('show_book', book_id=book.id) + "\">" + uploadText + "</a>")
|
||||
|
||||
if 'btn-upload-cover' in request.files:
|
||||
requested_file = request.files['btn-upload-cover']
|
||||
# check for empty request
|
||||
if requested_file.filename != '':
|
||||
file_ext = requested_file.filename.rsplit('.', 1)[-1].lower()
|
||||
# file_name = book.path.rsplit('/', 1)[-1]
|
||||
filepath = os.path.normpath(os.path.join(config.config_calibre_dir, book.path))
|
||||
saved_filename = os.path.join(filepath, 'cover.' + file_ext)
|
||||
|
||||
# check if file path exists, otherwise create it, copy file to calibre path and delete temp file
|
||||
if not os.path.exists(filepath):
|
||||
try:
|
||||
os.makedirs(filepath)
|
||||
except OSError:
|
||||
flash(_(u"Failed to create path for cover %s (Permission denied)." % filepath), category="error")
|
||||
return redirect(url_for('show_book', book_id=book.id))
|
||||
try:
|
||||
requested_file.save(saved_filename)
|
||||
# im=Image.open(saved_filename)
|
||||
book.has_cover = 1
|
||||
except OSError:
|
||||
flash(_(u"Failed to store cover-file %s." % saved_filename), category="error")
|
||||
return redirect(url_for('show_book', book_id=book.id))
|
||||
except IOError:
|
||||
flash(_(u"Cover-file is not a valid image file" % saved_filename), category="error")
|
||||
return redirect(url_for('show_book', book_id=book.id))
|
||||
to_save = request.form.to_dict()
|
||||
|
||||
try:
|
||||
@@ -3316,13 +3449,14 @@ def edit_book(book_id):
|
||||
else:
|
||||
input_tags = to_save[cc_string].split(',')
|
||||
input_tags = list(map(lambda it: it.strip(), input_tags))
|
||||
modify_database_object(input_tags, getattr(book, cc_string), db.cc_classes[c.id], db.session, 'custom')
|
||||
modify_database_object(input_tags, getattr(book, cc_string), db.cc_classes[c.id], db.session,
|
||||
'custom')
|
||||
db.session.commit()
|
||||
if config.config_use_google_drive:
|
||||
gdriveutils.updateGdriveCalibreFromLocal()
|
||||
author_names = []
|
||||
for author in book.authors:
|
||||
author_names.append(author.name)
|
||||
for authr in book.authors:
|
||||
author_names.append(authr.name)
|
||||
if "detail_view" in to_save:
|
||||
return redirect(url_for('show_book', book_id=book.id))
|
||||
else:
|
||||
@@ -3358,9 +3492,7 @@ def upload():
|
||||
if file_ext not in ALLOWED_EXTENSIONS:
|
||||
flash(
|
||||
_('File extension "%s" is not allowed to be uploaded to this server' %
|
||||
file_ext),
|
||||
category="error"
|
||||
)
|
||||
file_ext), category="error")
|
||||
return redirect(url_for('index'))
|
||||
else:
|
||||
flash(_('File to be uploaded must have an extension'), category="error")
|
||||
@@ -3369,12 +3501,12 @@ def upload():
|
||||
# extract metadata from file
|
||||
meta = uploader.upload(requested_file)
|
||||
title = meta.title
|
||||
author = meta.author
|
||||
authr = meta.author
|
||||
tags = meta.tags
|
||||
series = meta.series
|
||||
series_index = meta.series_id
|
||||
title_dir = helper.get_valid_filename(title)
|
||||
author_dir = helper.get_valid_filename(author)
|
||||
author_dir = helper.get_valid_filename(authr)
|
||||
filepath = os.path.join(config.config_calibre_dir, author_dir, title_dir)
|
||||
saved_filename = os.path.join(filepath, title_dir + meta.extension.lower())
|
||||
|
||||
@@ -3403,11 +3535,11 @@ def upload():
|
||||
move(meta.cover, os.path.join(filepath, "cover.jpg"))
|
||||
|
||||
# handle authors
|
||||
is_author = db.session.query(db.Authors).filter(db.Authors.name == author).first()
|
||||
is_author = db.session.query(db.Authors).filter(db.Authors.name == authr).first()
|
||||
if is_author:
|
||||
db_author = is_author
|
||||
else:
|
||||
db_author = db.Authors(author, helper.get_sorted_author(author), "")
|
||||
db_author = db.Authors(authr, helper.get_sorted_author(authr), "")
|
||||
db.session.add(db_author)
|
||||
|
||||
# handle series
|
||||
|
||||
Reference in New Issue
Block a user