Unified wording Calibre-Web
Replaced one table on admin page, deleted password column
Removed spaces on layout page
Removed uesless commit calls during db migration
Implementation of registering by email
This commit is contained in:
OzzieIsaacs
2018-08-24 15:48:09 +02:00
parent f6ab724020
commit cedc183987
38 changed files with 3868 additions and 2577 deletions

View File

@ -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):
@ -186,8 +186,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
@ -288,10 +288,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
@ -322,7 +322,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)
@ -339,9 +339,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
@ -472,7 +473,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:
@ -894,6 +895,68 @@ 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()
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():
@ -1997,27 +2060,35 @@ 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 email is not allowed to register"), category="error")
app.logger.info('Registering failed for user "' + to_save['nickname'] + '" EMailadress: ' + 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 email was send to your email account."), category="success")
return redirect(url_for('login'))
else:
flash(_(u"This username or email address is already in use."), category="error")
@ -2135,7 +2206,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
@ -2462,6 +2533,10 @@ def profile():
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.config_public_reg and not check_valid_domain(to_save["email"]):
flash(_(u"Email 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
@ -2607,7 +2682,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
@ -2635,6 +2710,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:
@ -2645,7 +2721,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
@ -2769,7 +2844,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)
@ -2794,10 +2869,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,
@ -2819,7 +2894,12 @@ def new_user():
title=_(u"Add new user"))
content.password = generate_password_hash(to_save["password"])
content.nickname = to_save["nickname"]
content.email = to_save["email"]
if config.config_public_reg and not check_valid_domain(to_save["email"]):
flash(_(u"Email 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"]
content.default_language = to_save["default_language"]
content.mature_content = "show_mature_content" in to_save
content.theme = int(to_save["theme"])
@ -2890,22 +2970,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"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")
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"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"])
@ -2917,9 +2998,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()
@ -3047,6 +3128,27 @@ 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
@ -3297,7 +3399,8 @@ 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()
@ -3339,9 +3442,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")