mirror of
https://github.com/janeczku/calibre-web.git
synced 2024-11-28 08:58:41 +02:00
Fix for #768 (If email server is configured, admins can send user passwords, also domains can be denied from registration)
Fixes from tests Fix response opds with read/unread changed db_reconnect Changed output for error 500 (now including error message) Fix in task queue after 20 messages
This commit is contained in:
parent
b586a32843
commit
513ac6cfb4
38
cps/admin.py
38
cps/admin.py
@ -190,10 +190,10 @@ def update_view_configuration():
|
||||
return view_configuration()
|
||||
|
||||
|
||||
@admi.route("/ajax/editdomain", methods=['POST'])
|
||||
@admi.route("/ajax/editdomain/<int:allow>", methods=['POST'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def edit_domain():
|
||||
def edit_domain(allow):
|
||||
# POST /post
|
||||
# name: 'username', //name of field (column in db)
|
||||
# pk: 1 //primary key (record id)
|
||||
@ -206,14 +206,14 @@ def edit_domain():
|
||||
return ""
|
||||
|
||||
|
||||
@admi.route("/ajax/adddomain", methods=['POST'])
|
||||
@admi.route("/ajax/adddomain/<int:allow>", methods=['POST'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def add_domain():
|
||||
def add_domain(allow):
|
||||
domain_name = request.form.to_dict()['domainname'].replace('*', '%').replace('?', '_').lower()
|
||||
check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name).first()
|
||||
check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name).filter(ub.Registration.allow == allow).first()
|
||||
if not check:
|
||||
new_domain = ub.Registration(domain=domain_name)
|
||||
new_domain = ub.Registration(domain=domain_name, allow=allow)
|
||||
ub.session.add(new_domain)
|
||||
ub.session.commit()
|
||||
return ""
|
||||
@ -227,18 +227,18 @@ def delete_domain():
|
||||
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="%.%")
|
||||
if not ub.session.query(ub.Registration).filter(ub.Registration.allow==1).count():
|
||||
new_domain = ub.Registration(domain="%.%",allow=1)
|
||||
ub.session.add(new_domain)
|
||||
ub.session.commit()
|
||||
return ""
|
||||
|
||||
|
||||
@admi.route("/ajax/domainlist")
|
||||
@admi.route("/ajax/domainlist/<int:allow>")
|
||||
@login_required
|
||||
@admin_required
|
||||
def list_domain():
|
||||
answer = ub.session.query(ub.Registration).all()
|
||||
def list_domain(allow):
|
||||
answer = ub.session.query(ub.Registration).filter(ub.Registration.allow == allow).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("'", '"'))
|
||||
@ -605,6 +605,7 @@ def edit_user(user_id):
|
||||
else:
|
||||
flash(_(u"Found an existing account for this e-mail address."), category="error")
|
||||
return render_title_template("user_edit.html", translations=translations, languages=languages,
|
||||
mail_configured = config.get_mail_server_configured(),
|
||||
new_user=0, content=content, downloads=downloads, registered_oauth=oauth_check,
|
||||
title=_(u"Edit User %(nick)s", nick=content.nickname), page="edituser")
|
||||
if "nickname" in to_save and to_save["nickname"] != content.nickname:
|
||||
@ -616,11 +617,11 @@ def edit_user(user_id):
|
||||
return render_title_template("user_edit.html",
|
||||
translations=translations,
|
||||
languages=languages,
|
||||
mail_configured=config.get_mail_server_configured(),
|
||||
new_user=0, content=content,
|
||||
downloads=downloads,
|
||||
registered_oauth=oauth_check,
|
||||
title=_(u"Edit User %(nick)s",
|
||||
nick=content.nickname),
|
||||
title=_(u"Edit User %(nick)s", nick=content.nickname),
|
||||
page="edituser")
|
||||
|
||||
if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail:
|
||||
@ -633,21 +634,27 @@ def edit_user(user_id):
|
||||
flash(_(u"An unknown error occured."), category="error")
|
||||
return render_title_template("user_edit.html", translations=translations, languages=languages, new_user=0,
|
||||
content=content, downloads=downloads, registered_oauth=oauth_check,
|
||||
mail_configured=config.get_mail_server_configured(),
|
||||
title=_(u"Edit User %(nick)s", nick=content.nickname), page="edituser")
|
||||
|
||||
|
||||
@admi.route("/admin/resetpassword/<int:user_id>")
|
||||
@login_required
|
||||
@admin_required
|
||||
def reset_password(user_id):
|
||||
def reset_user_password(user_id):
|
||||
if not config.config_public_reg:
|
||||
abort(404)
|
||||
if current_user is not None and current_user.is_authenticated:
|
||||
ret, message = reset_password(user_id)
|
||||
if ret == 1:
|
||||
log.debug(u"Password for user %(user)s reset", user=message)
|
||||
flash(_(u"Password for user %(user)s reset", user=message), category="success")
|
||||
else:
|
||||
elif ret == 0:
|
||||
log.error(u"An unknown error occurred. Please try again later.")
|
||||
flash(_(u"An unknown error occurred. Please try again later."), category="error")
|
||||
else:
|
||||
log.error(u"Please configure the SMTP mail settings first...")
|
||||
flash(_(u"Please configure the SMTP mail settings first..."), category="error")
|
||||
return redirect(url_for('admin.admin'))
|
||||
|
||||
|
||||
@ -681,6 +688,7 @@ def send_logfile(logtype):
|
||||
@admi.route("/get_update_status", methods=['GET'])
|
||||
@login_required_if_no_ano
|
||||
def get_update_status():
|
||||
log.info(u"Update status requested")
|
||||
return updater_thread.get_available_updates(request.method, locale=get_locale())
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ class _Settings(_Base):
|
||||
__tablename__ = 'settings'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
mail_server = Column(String, default='mail.example.org')
|
||||
mail_server = Column(String, default=constants.DEFAULT_MAIL_SERVER)
|
||||
mail_port = Column(Integer, default=25)
|
||||
mail_use_ssl = Column(SmallInteger, default=0)
|
||||
mail_login = Column(String, default='mail@example.com')
|
||||
@ -189,6 +189,10 @@ class _ConfigSQL(object):
|
||||
def get_mail_settings(self):
|
||||
return {k:v for k, v in self.__dict__.items() if k.startswith('mail_')}
|
||||
|
||||
def get_mail_server_configured(self):
|
||||
return not bool(self.mail_server == constants.DEFAULT_MAIL_SERVER)
|
||||
|
||||
|
||||
def set_from_dictionary(self, dictionary, field, convertor=None, default=None):
|
||||
'''Possibly updates a field of this object.
|
||||
The new value, if present, is grabbed from the given dictionary, and optionally passed through a convertor.
|
||||
|
@ -94,6 +94,7 @@ LOGIN_LDAP = 1
|
||||
LOGIN_OAUTH = 2
|
||||
# LOGIN_OAUTH_GOOGLE = 3
|
||||
|
||||
DEFAULT_MAIL_SERVER = "mail.example.org"
|
||||
|
||||
DEFAULT_PASSWORD = "admin123"
|
||||
DEFAULT_PORT = 8083
|
||||
@ -105,6 +106,7 @@ except ValueError:
|
||||
del env_CALIBRE_PORT
|
||||
|
||||
|
||||
|
||||
EXTENSIONS_AUDIO = {'mp3', 'm4a', 'm4b'}
|
||||
EXTENSIONS_CONVERT = {'pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit', 'lrf', 'txt', 'htmlz', 'rtf', 'odt'}
|
||||
EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx',
|
||||
|
10
cps/db.py
10
cps/db.py
@ -33,7 +33,7 @@ from sqlalchemy.ext.declarative import declarative_base
|
||||
session = None
|
||||
cc_exceptions = ['datetime', 'comments', 'float', 'composite', 'series']
|
||||
cc_classes = {}
|
||||
|
||||
engine = None
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
@ -288,7 +288,7 @@ class Books(Base):
|
||||
|
||||
@property
|
||||
def atom_timestamp(self):
|
||||
return (self.timestamp or '').replace(' ', 'T')
|
||||
return (self.timestamp.strftime('%Y-%m-%dT%H:%M:%S+00:00') or '')
|
||||
|
||||
class Custom_Columns(Base):
|
||||
__tablename__ = 'custom_columns'
|
||||
@ -327,6 +327,7 @@ def update_title_sort(config, conn=None):
|
||||
|
||||
def setup_db(config):
|
||||
dispose()
|
||||
global engine
|
||||
|
||||
if not config.config_calibre_dir:
|
||||
config.invalidate()
|
||||
@ -428,3 +429,8 @@ def dispose():
|
||||
if name.startswith("custom_column_") or name.startswith("books_custom_column_"):
|
||||
if table is not None:
|
||||
Base.metadata.remove(table)
|
||||
|
||||
def reconnect_db(config):
|
||||
session.close()
|
||||
engine.dispose()
|
||||
setup_db(config)
|
||||
|
@ -125,7 +125,7 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False):
|
||||
if not resend:
|
||||
text += "Your new account at Calibre-Web has been created. Thanks for joining us!\r\n"
|
||||
text += "Please log in to your account using the following informations:\r\n"
|
||||
text += "User name: %s\n" % user_name
|
||||
text += "User name: %s\r\n" % user_name
|
||||
text += "Password: %s\r\n" % default_password
|
||||
text += "Don't forget to change your password after first login.\r\n"
|
||||
text += "Sincerely\r\n\r\n"
|
||||
@ -416,6 +416,8 @@ def reset_password(user_id):
|
||||
existing_user = ub.session.query(ub.User).filter(ub.User.id == user_id).first()
|
||||
password = generate_random_password()
|
||||
existing_user.password = generate_password_hash(password)
|
||||
if not config.get_mail_server_configured():
|
||||
return (2, None)
|
||||
try:
|
||||
ub.session.commit()
|
||||
send_registration_mail(existing_user.email, existing_user.nickname, password, True)
|
||||
@ -699,9 +701,13 @@ def speaking_language(languages=None):
|
||||
# from https://code.luasoftware.com/tutorials/flask/execute-raw-sql-in-flask-sqlalchemy/
|
||||
def check_valid_domain(domain_text):
|
||||
domain_text = domain_text.split('@', 1)[-1].lower()
|
||||
sql = "SELECT * FROM registration WHERE :domain LIKE domain;"
|
||||
sql = "SELECT * FROM registration WHERE (:domain LIKE domain and allow = 1);"
|
||||
result = ub.session.query(ub.Registration).from_statement(text(sql)).params(domain=domain_text).all()
|
||||
return len(result)
|
||||
if not len(result):
|
||||
return False
|
||||
sql = "SELECT * FROM registration WHERE (:domain LIKE domain and allow = 0);"
|
||||
result = ub.session.query(ub.Registration).from_statement(text(sql)).params(domain=domain_text).all()
|
||||
return not len(result)
|
||||
|
||||
|
||||
# Orders all Authors in the list according to authors sort
|
||||
|
13
cps/opds.py
13
cps/opds.py
@ -276,7 +276,7 @@ def feed_languages(book_id):
|
||||
isoLanguages.get(part3=entry.languages[index].lang_code).name)'''
|
||||
return render_xml_template('feed.xml', entries=entries, pagination=pagination)
|
||||
|
||||
@opds.route("/opds/shelfindex/", defaults={'public': 0})
|
||||
@opds.route("/opds/shelfindex", defaults={'public': 0})
|
||||
@opds.route("/opds/shelfindex/<string:public>")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_shelfindex(public):
|
||||
@ -378,15 +378,16 @@ def render_xml_template(*args, **kwargs):
|
||||
def feed_get_cover(book_id):
|
||||
return get_book_cover(book_id)
|
||||
|
||||
@opds.route("/opds/readbooks/")
|
||||
@opds.route("/opds/readbooks")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_read_books():
|
||||
off = request.args.get("offset") or 0
|
||||
return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True)
|
||||
result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True)
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination)
|
||||
|
||||
|
||||
@opds.route("/opds/unreadbooks/")
|
||||
@opds.route("/opds/unreadbooks")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_unread_books():
|
||||
off = request.args.get("offset") or 0
|
||||
return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True)
|
||||
result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True)
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination)
|
||||
|
@ -19,21 +19,41 @@
|
||||
|
||||
$(function() {
|
||||
|
||||
$("#domain_submit").click(function(event) {
|
||||
$("#domain_allow_submit").click(function(event) {
|
||||
event.preventDefault();
|
||||
$("#domain_add").ajaxForm();
|
||||
$("#domain_add_allow").ajaxForm();
|
||||
$(this).closest("form").submit();
|
||||
$.ajax ({
|
||||
method:"get",
|
||||
url: window.location.pathname + "/../../ajax/domainlist",
|
||||
url: window.location.pathname + "/../../ajax/domainlist/1",
|
||||
async: true,
|
||||
timeout: 900,
|
||||
success:function(data) {
|
||||
$("#domain-table").bootstrapTable("load", data);
|
||||
$("#domain-allow-table").bootstrapTable("load", data);
|
||||
}
|
||||
});
|
||||
});
|
||||
$("#domain-table").bootstrapTable({
|
||||
$("#domain-allow-table").bootstrapTable({
|
||||
formatNoMatches: function () {
|
||||
return "";
|
||||
},
|
||||
striped: false
|
||||
});
|
||||
$("#domain_deny_submit").click(function(event) {
|
||||
event.preventDefault();
|
||||
$("#domain_add_deny").ajaxForm();
|
||||
$(this).closest("form").submit();
|
||||
$.ajax ({
|
||||
method:"get",
|
||||
url: window.location.pathname + "/../../ajax/domainlist/0",
|
||||
async: true,
|
||||
timeout: 900,
|
||||
success:function(data) {
|
||||
$("#domain-deny-table").bootstrapTable("load", data);
|
||||
}
|
||||
});
|
||||
});
|
||||
$("#domain-deny-table").bootstrapTable({
|
||||
formatNoMatches: function () {
|
||||
return "";
|
||||
},
|
||||
@ -50,14 +70,22 @@ $(function() {
|
||||
$("#DeleteDomain").modal("hide");
|
||||
$.ajax({
|
||||
method:"get",
|
||||
url: window.location.pathname + "/../../ajax/domainlist",
|
||||
url: window.location.pathname + "/../../ajax/domainlist/1",
|
||||
async: true,
|
||||
timeout: 900,
|
||||
success:function(data) {
|
||||
$("#domain-table").bootstrapTable("load", data);
|
||||
$("#domain-allow-table").bootstrapTable("load", data);
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
method:"get",
|
||||
url: window.location.pathname + "/../../ajax/domainlist/0",
|
||||
async: true,
|
||||
timeout: 900,
|
||||
success:function(data) {
|
||||
$("#domain-deny-table").bootstrapTable("load", data);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
//triggered when modal is about to be shown
|
||||
$("#DeleteDomain").on("show.bs.modal", function(e) {
|
||||
|
@ -41,22 +41,40 @@
|
||||
</form>
|
||||
{% if g.allow_registration %}
|
||||
<h2>{{_('Allowed domains for registering')}}</h2>
|
||||
<table class="table table-no-bordered" id="domain-table" data-url="{{url_for('admin.list_domain')}}" data-id-field="id" data-show-header="false" data-editable-mode="inline">
|
||||
<form id="domain_add_allow" action="{{ url_for('admin.add_domain',allow=1)}}" method="POST">
|
||||
<div class="form-group required">
|
||||
<label for="domainname_allow">{{_('Add Domain')}}</label>
|
||||
<input type="text" class="form-control" name="domainname" id="domainname_allow" >
|
||||
</div>
|
||||
<button id="domain_allow_submit" class="btn btn-default">{{_('Add')}}</button>
|
||||
</form>
|
||||
<table class="table table-no-bordered" id="domain-allow-table" data-url="{{url_for('admin.list_domain', allow=1)}}" data-id-field="id" data-show-header="false" data-editable-mode="inline">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="domain" id="domain-allow" data-editable-type="text" data-editable-url="{{ url_for('admin.edit_domain', allow = 1)}}" data-editable="true" data-editable-title="{{_('Enter domainname')}}"></th>
|
||||
<th data-field="id" id="id-allow" data-visible="false"></th>
|
||||
<th data-align="right" data-formatter="TableActions"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<h2>{{_('Denied domains for registering')}}</h2>
|
||||
<table class="table table-no-bordered" id="domain-deny-table" data-url="{{url_for('admin.list_domain', allow=0)}}" data-id-field="id" data-show-header="false" data-editable-mode="inline">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="domain" id="domain" data-editable-type="text" data-editable-url="{{ url_for('admin.edit_domain')}}" data-editable="true" data-editable-title="{{_('Enter domainname')}}"></th>
|
||||
<th data-field="id" id="id" data-visible="false"></th>
|
||||
<th data-field="domain" id="domain-deny" data-editable-type="text" data-editable-url="{{ url_for('admin.edit_domain', allow = 0)}}" data-editable="true" data-editable-title="{{_('Enter domainname')}}"></th>
|
||||
<th data-field="id" id="id-deny" data-visible="false"></th>
|
||||
<th data-align="right" data-formatter="TableActions"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<form id="domain_add" action="{{ url_for('admin.add_domain')}}" method="POST">
|
||||
<form id="domain_add_deny" action="{{ url_for('admin.add_domain',allow=0)}}" method="POST">
|
||||
<div class="form-group required">
|
||||
<label for="domainname">{{_('Add Domain')}}</label>
|
||||
<input type="text" class="form-control" name="domainname" id="domainname" >
|
||||
<label for="domainname_deny">{{_('Add Domain')}}</label>
|
||||
<input type="text" class="form-control" name="domainname" id="domainname_deny" >
|
||||
</div>
|
||||
<button id="domain_submit" class="btn btn-default">{{_('Add')}}</button>
|
||||
<button id="domain_deny_submit" class="btn btn-default">{{_('Add')}}</button>
|
||||
</form>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -14,15 +14,14 @@
|
||||
<input type="email" class="form-control" name="email" id="email" value="{{ content.email if content.email != None }}" autocomplete="off">
|
||||
</div>
|
||||
{% if ( g.user and g.user.role_passwd() or g.user.role_admin() ) and not content.role_anonymous() %}
|
||||
{% if g.user and g.user.role_admin() and g.allow_registration and not new_user and not profile %}
|
||||
<div class="btn btn-default" id="resend_password"><a href="{{url_for('admin.reset_password', user_id = content.id) }}">{{_('Reset user Password')}}</a></div>
|
||||
{% else %}
|
||||
{% if g.user and g.user.role_admin() and not new_user and not profile and ( mail_configured and content.email if content.email != None %}
|
||||
<div class="btn btn-default" id="resend_password"><a href="{{url_for('admin.reset_user_password', user_id = content.id) }}">{{_('Reset user Password')}}</a></div>
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<label for="password">{{_('Password')}}</label>
|
||||
<input type="password" class="form-control" name="password" id="password" value="" autocomplete="off">
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<label for="kindle_mail">{{_('Kindle E-Mail')}}</label>
|
||||
<input type="email" class="form-control" name="kindle_mail" id="kindle_mail" value="{{ content.kindle_mail if content.kindle_mail != None }}">
|
||||
|
17
cps/ub.py
17
cps/ub.py
@ -297,6 +297,7 @@ class Registration(Base):
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
domain = Column(String)
|
||||
allow = Column(Integer)
|
||||
|
||||
def __repr__(self):
|
||||
return u"<Registration('{0}')>".format(self.domain)
|
||||
@ -332,24 +333,32 @@ def migrate_Database(session):
|
||||
if not engine.dialect.has_table(engine.connect(), "registration"):
|
||||
ReadBook.__table__.create(bind=engine)
|
||||
conn = engine.connect()
|
||||
conn.execute("insert into registration (domain) values('%.%')")
|
||||
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
||||
session.commit()
|
||||
try:
|
||||
session.query(exists().where(Registration.allow)).scalar()
|
||||
session.commit()
|
||||
except exc.OperationalError: # Database is not compatible, some columns are missing
|
||||
conn = engine.connect()
|
||||
conn.execute("ALTER TABLE registration ADD column 'allow' INTEGER")
|
||||
conn.execute("update registration set 'allow' = 1")
|
||||
session.commit()
|
||||
# Handle table exists, but no content
|
||||
cnt = session.query(Registration).count()
|
||||
if not cnt:
|
||||
conn = engine.connect()
|
||||
conn.execute("insert into registration (domain) values('%.%')")
|
||||
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
||||
session.commit()
|
||||
try:
|
||||
session.query(exists().where(BookShelf.order)).scalar()
|
||||
except exc.OperationalError: # Database is not compatible, some rows are missing
|
||||
except exc.OperationalError: # Database is not compatible, some columns are missing
|
||||
conn = engine.connect()
|
||||
conn.execute("ALTER TABLE book_shelf_link ADD column 'order' INTEGER DEFAULT 1")
|
||||
session.commit()
|
||||
try:
|
||||
create = False
|
||||
session.query(exists().where(User.sidebar_view)).scalar()
|
||||
except exc.OperationalError: # Database is not compatible, some rows are missing
|
||||
except exc.OperationalError: # Database is not compatible, some columns are missing
|
||||
conn = engine.connect()
|
||||
conn.execute("ALTER TABLE user ADD column `sidebar_view` Integer DEFAULT 1")
|
||||
session.commit()
|
||||
|
58
cps/web.py
58
cps/web.py
@ -43,7 +43,7 @@ from werkzeug.exceptions import default_exceptions
|
||||
from werkzeug.datastructures import Headers
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
|
||||
from . import constants, logger, isoLanguages, services, worker
|
||||
from . import constants, config, logger, isoLanguages, services, worker
|
||||
from . import searched_ids, lm, babel, db, ub, config, get_locale, app
|
||||
from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download
|
||||
from .helper import common_filters, get_search_results, fill_indexpage, speaking_language, check_valid_domain, \
|
||||
@ -93,12 +93,11 @@ def error_http(error):
|
||||
|
||||
|
||||
def internal_error(error):
|
||||
__, __, tb = sys.exc_info()
|
||||
return render_template('http_error.html',
|
||||
error_code="Internal Server Error",
|
||||
error_name=str(error),
|
||||
issue=True,
|
||||
error_stack=traceback.format_tb(tb),
|
||||
error_stack=traceback.format_exc().split("\n"),
|
||||
instance=config.config_calibre_web_title
|
||||
), 500
|
||||
|
||||
@ -791,9 +790,7 @@ def get_tasks_status():
|
||||
|
||||
@app.route("/reconnect")
|
||||
def reconnect():
|
||||
db.session.close()
|
||||
db.engine.dispose()
|
||||
db.setup_db()
|
||||
db.reconnect_db(config)
|
||||
return json.dumps({})
|
||||
|
||||
@web.route("/search", methods=["GET"])
|
||||
@ -985,10 +982,7 @@ def render_read_books(page, are_read, as_xml=False, order=None):
|
||||
entries, random, pagination = fill_indexpage(page, db.Books, db_filter, order)
|
||||
|
||||
if as_xml:
|
||||
xml = render_title_template('feed.xml', entries=entries, pagination=pagination)
|
||||
response = make_response(xml)
|
||||
response.headers["Content-Type"] = "application/xml; charset=utf-8"
|
||||
return response
|
||||
return entries, pagination
|
||||
else:
|
||||
if are_read:
|
||||
name = _(u'Read Books') + ' (' + str(len(readBookIds)) + ')'
|
||||
@ -1041,8 +1035,7 @@ def download_link(book_id, book_format):
|
||||
@login_required
|
||||
@download_required
|
||||
def send_to_kindle(book_id, book_format, convert):
|
||||
settings = config.get_mail_settings()
|
||||
if settings.get("mail_server", "mail.example.org") == "mail.example.org":
|
||||
if not config.get_mail_server_configured():
|
||||
flash(_(u"Please configure the SMTP mail settings first..."), category="error")
|
||||
elif current_user.kindle_mail:
|
||||
result = send_mail(book_id, book_format, convert, current_user.kindle_mail, config.config_calibre_dir,
|
||||
@ -1067,16 +1060,19 @@ def register():
|
||||
abort(404)
|
||||
if current_user is not None and current_user.is_authenticated:
|
||||
return redirect(url_for('web.index'))
|
||||
if not config.get_mail_server_configured():
|
||||
flash(_(u"E-Mail server is not configured, please contact your administrator!"), category="error")
|
||||
return render_title_template('register.html', title=_(u"register"), page="register")
|
||||
|
||||
if request.method == "POST":
|
||||
to_save = request.form.to_dict()
|
||||
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"].lower()).first()
|
||||
|
||||
if not existing_user and not existing_email:
|
||||
content = ub.User()
|
||||
# content.password = generate_password_hash(to_save["password"])
|
||||
@ -1116,10 +1112,12 @@ def register():
|
||||
@web.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if not config.db_configured:
|
||||
log.debug(u"Redirect to initial configuration")
|
||||
return redirect(url_for('admin.basic_configuration'))
|
||||
if current_user is not None and current_user.is_authenticated:
|
||||
return redirect(url_for('web.index'))
|
||||
if config.config_login_type == constants.LOGIN_LDAP and not services.ldap:
|
||||
log.error(u"Cannot activate LDAP authentication")
|
||||
flash(_(u"Cannot activate LDAP authentication"), category="error")
|
||||
if request.method == "POST":
|
||||
form = request.form.to_dict()
|
||||
@ -1129,10 +1127,12 @@ def login():
|
||||
login_result = services.ldap.bind_user(form['username'], form['password'])
|
||||
if login_result:
|
||||
login_user(user, remember=True)
|
||||
log.debug(u"You are now logged in as: '%s'", user.nickname)
|
||||
flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname),
|
||||
category="success")
|
||||
return redirect_back(url_for("web.index"))
|
||||
if login_result is None:
|
||||
log.error('Could not login. LDAP server down, please contact your administrator')
|
||||
flash(_(u"Could not login. LDAP server down, please contact your administrator"), category="error")
|
||||
else:
|
||||
ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr)
|
||||
@ -1147,6 +1147,7 @@ def login():
|
||||
flash(_(u"New Password was send to your email address"), category="info")
|
||||
log.info('Password reset for user "%s" IP-adress: %s', form['username'], ipAdress)
|
||||
else:
|
||||
log.info(u"An unknown error occurred. Please try again later.")
|
||||
flash(_(u"An unknown error occurred. Please try again later."), category="error")
|
||||
else:
|
||||
flash(_(u"Please enter valid username to reset password"), category="error")
|
||||
@ -1154,18 +1155,16 @@ def login():
|
||||
else:
|
||||
if user and check_password_hash(str(user.password), form['password']) and user.nickname != "Guest":
|
||||
login_user(user, remember=True)
|
||||
log.debug(u"You are now logged in as: '%s'", user.nickname)
|
||||
flash(_(u"You are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success")
|
||||
return redirect_back(url_for("web.index"))
|
||||
else:
|
||||
log.info('Login failed for user "%s" IP-adress: %s', form['username'], ipAdress)
|
||||
flash(_(u"Wrong Username or Password"), category="error")
|
||||
settings = config.get_mail_settings()
|
||||
mail_configured = bool(settings.get("mail_server", "mail.example.org") != "mail.example.org")
|
||||
|
||||
next_url = url_for('web.index')
|
||||
|
||||
return render_title_template('login.html', title=_(u"login"), next_url=next_url, config=config,
|
||||
mail = mail_configured, page="login")
|
||||
mail = config.get_mail_server_configured(), page="login")
|
||||
|
||||
|
||||
@web.route('/logout')
|
||||
@ -1175,6 +1174,7 @@ def logout():
|
||||
logout_user()
|
||||
if feature_support['oauth'] and (config.config_login_type == 2 or config.config_login_type == 3):
|
||||
logout_oauth_user()
|
||||
log.debug(u"User logged out")
|
||||
return redirect(url_for('web.login'))
|
||||
|
||||
|
||||
@ -1186,7 +1186,7 @@ def remote_login():
|
||||
ub.session.commit()
|
||||
|
||||
verify_url = url_for('web.verify_token', token=auth_token.auth_token, _external=true)
|
||||
|
||||
log.debug(u"Remot Login request with token: %s", auth_token.auth_token)
|
||||
return render_title_template('remote_login.html', title=_(u"login"), token=auth_token.auth_token,
|
||||
verify_url=verify_url, page="remotelogin")
|
||||
|
||||
@ -1200,6 +1200,7 @@ def verify_token(token):
|
||||
# Token not found
|
||||
if auth_token is None:
|
||||
flash(_(u"Token not found"), category="error")
|
||||
log.error(u"Remote Login token not found")
|
||||
return redirect(url_for('web.index'))
|
||||
|
||||
# Token expired
|
||||
@ -1208,6 +1209,7 @@ def verify_token(token):
|
||||
ub.session.commit()
|
||||
|
||||
flash(_(u"Token has expired"), category="error")
|
||||
log.error(u"Remote Login token expired")
|
||||
return redirect(url_for('web.index'))
|
||||
|
||||
# Update token with user information
|
||||
@ -1216,6 +1218,7 @@ def verify_token(token):
|
||||
ub.session.commit()
|
||||
|
||||
flash(_(u"Success! Please return to your device"), category="success")
|
||||
log.debug(u"Remote Login token for userid %s verified", auth_token.user_id)
|
||||
return redirect(url_for('web.index'))
|
||||
|
||||
|
||||
@ -1251,6 +1254,7 @@ def token_verified():
|
||||
ub.session.commit()
|
||||
|
||||
data['status'] = 'success'
|
||||
log.debug(u"Remote Login for userid %s succeded", user.id)
|
||||
flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success")
|
||||
|
||||
response = make_response(json.dumps(data, ensure_ascii=False))
|
||||
@ -1278,8 +1282,6 @@ def profile():
|
||||
downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first())
|
||||
else:
|
||||
ub.delete_download(book.book_id)
|
||||
# ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete()
|
||||
# ub.session.commit()
|
||||
if request.method == "POST":
|
||||
to_save = request.form.to_dict()
|
||||
current_user.random_books = 0
|
||||
@ -1332,14 +1334,16 @@ def profile():
|
||||
except IntegrityError:
|
||||
ub.session.rollback()
|
||||
flash(_(u"Found an existing account for this e-mail address."), category="error")
|
||||
log.debug(u"Found an existing account for this e-mail address.")
|
||||
return render_title_template("user_edit.html", content=current_user, downloads=downloads,
|
||||
translations=translations,
|
||||
title=_(u"%(name)s's profile", name=current_user.nickname), page="me",
|
||||
registered_oauth=oauth_check, oauth_status=oauth_status)
|
||||
flash(_(u"Profile updated"), category="success")
|
||||
log.debug(u"Profile updated")
|
||||
return render_title_template("user_edit.html", translations=translations, profile=1, languages=languages,
|
||||
content=current_user, downloads=downloads, title= _(u"%(name)s's profile",
|
||||
name=current_user.nickname),
|
||||
content=current_user, downloads=downloads,
|
||||
title= _(u"%(name)s's profile", name=current_user.nickname),
|
||||
page="me", registered_oauth=oauth_check, oauth_status=oauth_status)
|
||||
|
||||
|
||||
@ -1353,6 +1357,7 @@ def read_book(book_id, book_format):
|
||||
book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
|
||||
if not book:
|
||||
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
|
||||
log.debug(u"Error opening eBook. File does not exist or file is not accessible:")
|
||||
return redirect(url_for("web.index"))
|
||||
|
||||
# check if book has bookmark
|
||||
@ -1362,20 +1367,25 @@ def read_book(book_id, book_format):
|
||||
ub.Bookmark.book_id == book_id,
|
||||
ub.Bookmark.format == book_format.upper())).first()
|
||||
if book_format.lower() == "epub":
|
||||
log.debug(u"Start epub reader for %d", book_id)
|
||||
return render_title_template('read.html', bookid=book_id, title=_(u"Read a Book"), bookmark=bookmark)
|
||||
elif book_format.lower() == "pdf":
|
||||
log.debug(u"Start pdf reader for %d", book_id)
|
||||
return render_title_template('readpdf.html', pdffile=book_id, title=_(u"Read a Book"))
|
||||
elif book_format.lower() == "txt":
|
||||
log.debug(u"Start txt reader for %d", book_id)
|
||||
return render_title_template('readtxt.html', txtfile=book_id, title=_(u"Read a Book"))
|
||||
else:
|
||||
for fileExt in ["mp3", "m4b", "m4a"]:
|
||||
if book_format.lower() == fileExt:
|
||||
entries = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
|
||||
log.debug(u"Start mp3 listening for %d", book_id)
|
||||
return render_title_template('listenmp3.html', mp3file=book_id, audioformat=book_format.lower(),
|
||||
title=_(u"Read a Book"), entry=entries, bookmark=bookmark)
|
||||
for fileExt in ["cbr", "cbt", "cbz"]:
|
||||
if book_format.lower() == fileExt:
|
||||
all_name = str(book_id)
|
||||
log.debug(u"Start comic reader for %d", book_id)
|
||||
return render_title_template('readcbr.html', comicfile=all_name, title=_(u"Read a Book"),
|
||||
extension=fileExt)
|
||||
# if feature_support['rar']:
|
||||
@ -1386,6 +1396,7 @@ def read_book(book_id, book_format):
|
||||
# if book_format.lower() == fileext:
|
||||
# return render_title_template('readcbr.html', comicfile=book_id,
|
||||
# extension=fileext, title=_(u"Read a Book"), book=book)
|
||||
log.debug(u"Error opening eBook. File does not exist or file is not accessible:")
|
||||
flash(_(u"Error opening eBook. File does not exist or file is not accessible."), category="error")
|
||||
return redirect(url_for("web.index"))
|
||||
|
||||
@ -1418,7 +1429,7 @@ def show_book(book_id):
|
||||
matching_have_read_book = getattr(entries, 'custom_column_'+str(config.config_read_column))
|
||||
have_read = len(matching_have_read_book) > 0 and matching_have_read_book[0].value
|
||||
except KeyError:
|
||||
log.error("Custom Column No.%d is not exisiting in calibre database", config.config_read_column)
|
||||
log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column)
|
||||
have_read = None
|
||||
|
||||
else:
|
||||
@ -1440,5 +1451,6 @@ def show_book(book_id):
|
||||
is_xhr=request.is_xhr, title=entries.title, books_shelfs=book_in_shelfs,
|
||||
have_read=have_read, kindle_list=kindle_list, reader_list=reader_list, page="book")
|
||||
else:
|
||||
log.debug(u"Error opening eBook. File does not exist or file is not accessible:")
|
||||
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
|
||||
return redirect(url_for("web.index"))
|
||||
|
@ -231,7 +231,7 @@ class WorkerThread(threading.Thread):
|
||||
self.queue.pop(index)
|
||||
self.UIqueue.pop(index)
|
||||
# if we are deleting entries before the current index, adjust the index
|
||||
if index <= self.current and index:
|
||||
if index <= self.current and self.current:
|
||||
self.current -= 1
|
||||
self.last = len(self.queue)
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user