mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-25 02:57:22 +00:00
Merge branch 'master' into Develop
# Conflicts: # cps/editbooks.py
This commit is contained in:
commit
87c415830f
@ -470,6 +470,10 @@ def _configuration_update_helper():
|
||||
|
||||
_config_int("config_updatechannel")
|
||||
|
||||
# Reverse proxy login configuration
|
||||
_config_checkbox("config_allow_reverse_proxy_header_login")
|
||||
_config_string("config_reverse_proxy_login_header_name")
|
||||
|
||||
# GitHub OAuth configuration
|
||||
if config.config_login_type == constants.LOGIN_OAUTH:
|
||||
active_oauths = 0
|
||||
|
@ -111,6 +111,9 @@ class _Settings(_Base):
|
||||
|
||||
config_updatechannel = Column(Integer, default=constants.UPDATE_STABLE)
|
||||
|
||||
config_reverse_proxy_login_header_name = Column(String)
|
||||
config_allow_reverse_proxy_header_login = Column(Boolean, default=False)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__class__.__name__
|
||||
|
||||
@ -264,8 +267,7 @@ class _ConfigSQL(object):
|
||||
for k, v in self.__dict__.items():
|
||||
if k[0] == '_':
|
||||
continue
|
||||
if hasattr(s, k): # and getattr(s, k, None) != v:
|
||||
# log.debug("_Settings save '%s' = %r", k, v)
|
||||
if hasattr(s, k):
|
||||
setattr(s, k, v)
|
||||
|
||||
log.debug("_ConfigSQL updating storage")
|
||||
@ -293,7 +295,13 @@ def _migrate_table(session, orm_class):
|
||||
if sys.version_info < (3, 0):
|
||||
if isinstance(column.default.arg,unicode):
|
||||
column.default.arg = column.default.arg.encode('utf-8')
|
||||
column_default = "" if column.default is None else ("DEFAULT %r" % column.default.arg)
|
||||
if column.default is None:
|
||||
column_default = ""
|
||||
else:
|
||||
if isinstance(column.default.arg, bool):
|
||||
column_default = ("DEFAULT %r" % int(column.default.arg))
|
||||
else:
|
||||
column_default = ("DEFAULT %r" % column.default.arg)
|
||||
alter_table = "ALTER TABLE %s ADD COLUMN `%s` %s %s" % (orm_class.__tablename__,
|
||||
column_name,
|
||||
column.type,
|
||||
|
@ -656,10 +656,16 @@ def upload():
|
||||
db_language = db.Languages(input_language)
|
||||
db.session.add(db_language)
|
||||
|
||||
# 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
|
||||
if db_language != current_user.filter_language() and current_user.filter_language() != "all":
|
||||
db_language = db.session.query(db.Languages).\
|
||||
filter(db.Languages.lang_code == current_user.filter_language()).first()
|
||||
|
||||
# combine path and normalize path from windows systems
|
||||
path = os.path.join(author_dir, title_dir).replace('\\', '/')
|
||||
db_book = db.Books(title, "", db_author.sort, datetime.datetime.now(), datetime.datetime(101, 1, 1),
|
||||
series_index, datetime.datetime.now(), path, has_cover, db_author, [], db_language)
|
||||
series_index, datetime.datetime.now(), path, has_cover, db_author, [], db_language)
|
||||
db_book.authors.append(db_author)
|
||||
if db_series:
|
||||
db_book.series.append(db_series)
|
||||
@ -688,8 +694,10 @@ def upload():
|
||||
# save data to database, reread data
|
||||
db.session.commit()
|
||||
db.update_title_sort(config)
|
||||
book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
|
||||
# upload book to gdrive if necessary and add "(bookid)" to folder name
|
||||
# Reread book. It's important not to filter the result, as it could have language which hide it from
|
||||
# current users view (tags are not stored/extracted from metadata and could also be limited)
|
||||
book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
|
||||
# upload book to gdrive if nesseccary and add "(bookid)" to folder name
|
||||
if config.config_use_google_drive:
|
||||
gdriveutils.updateGdriveCalibreFromLocal()
|
||||
error = helper.update_dir_stucture(book.id, config.config_calibre_dir)
|
||||
|
20
cps/shelf.py
20
cps/shelf.py
@ -30,6 +30,7 @@ from sqlalchemy.sql.expression import func, or_, and_
|
||||
|
||||
from . import logger, ub, searched_ids, db
|
||||
from .web import render_title_template
|
||||
from .helper import common_filters
|
||||
|
||||
|
||||
shelf = Blueprint('shelf', __name__)
|
||||
@ -281,16 +282,10 @@ def show_shelf(shelf_type, shelf_id):
|
||||
if shelf:
|
||||
page = "shelf.html" if shelf_type == 1 else 'shelfdown.html'
|
||||
|
||||
books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).order_by(
|
||||
ub.BookShelf.order.asc()).all()
|
||||
for book in books_in_shelf:
|
||||
cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
|
||||
if cur_book:
|
||||
result.append(cur_book)
|
||||
else:
|
||||
log.info('Not existing book %s in %s deleted', book.book_id, shelf)
|
||||
ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete()
|
||||
ub.session.commit()
|
||||
books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id)\
|
||||
.order_by(ub.BookShelf.order.asc()).all()
|
||||
books_list = [ b.book_id for b in books_in_shelf]
|
||||
result = db.session.query(db.Books).filter(db.Books.id.in_(books_list)).filter(common_filters()).all()
|
||||
return render_title_template(page, entries=result, title=_(u"Shelf: '%(name)s'", name=shelf.name),
|
||||
shelf=shelf, page="shelf")
|
||||
else:
|
||||
@ -322,9 +317,8 @@ def order_shelf(shelf_id):
|
||||
if shelf:
|
||||
books_in_shelf2 = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id) \
|
||||
.order_by(ub.BookShelf.order.asc()).all()
|
||||
for book in books_in_shelf2:
|
||||
cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
|
||||
result.append(cur_book)
|
||||
books_list = [ b.book_id for b in books_in_shelf2]
|
||||
result = db.session.query(db.Books).filter(db.Books.id.in_(books_list)).filter(common_filters()).all()
|
||||
return render_title_template('shelf_order.html', entries=result,
|
||||
title=_(u"Change order of Shelf: '%(name)s'", name=shelf.name),
|
||||
shelf=shelf, page="shelforder")
|
||||
|
@ -1,4 +1,7 @@
|
||||
{% extends "layout.html" %}
|
||||
{% macro display_bool_setting(setting_value) -%}
|
||||
{% if setting_value %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}
|
||||
{%- endmacro %}
|
||||
{% block body %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
@ -23,11 +26,11 @@
|
||||
<td>{{user.email}}</td>
|
||||
<td>{{user.kindle_mail}}</td>
|
||||
<td>{{user.downloads.count()}}</td>
|
||||
<td class="hidden-xs">{% if user.role_admin() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
|
||||
<td class="hidden-xs">{% if user.role_download() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
|
||||
<td class="hidden-xs">{% if user.role_viewer() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
|
||||
<td class="hidden-xs">{% if user.role_upload() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
|
||||
<td class="hidden-xs">{% if user.role_edit() %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</td>
|
||||
<td class="hidden-xs">{{ display_bool_setting(user.role_admin()) }}</td>
|
||||
<td class="hidden-xs">{{ display_bool_setting(user.role_download()) }}</td>
|
||||
<td class="hidden-xs">{{ display_bool_setting(user.role_viewer()) }}</td>
|
||||
<td class="hidden-xs">{{ display_bool_setting(user.role_upload()) }}</td>
|
||||
<td class="hidden-xs">{{ display_bool_setting(user.role_edit()) }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@ -83,20 +86,30 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-sm-7">{{_('Uploading')}}</div>
|
||||
<div class="col-xs-6 col-sm-5">{% if config.config_uploading %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</div>
|
||||
<div class="col-xs-6 col-sm-5">{{ display_bool_setting(config.config_uploading) }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-sm-7">{{_('Anonymous browsing')}}</div>
|
||||
<div class="col-xs-6 col-sm-5">{% if config.config_anonbrowse %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</div>
|
||||
<div class="col-xs-6 col-sm-5">{{ display_bool_setting(config.config_anonbrowse) }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-sm-7">{{_('Public registration')}}</div>
|
||||
<div class="col-xs-6 col-sm-5">{% if config.config_public_reg %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</div>
|
||||
<div class="col-xs-6 col-sm-5">{{ display_bool_setting(config.config_public_reg) }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-sm-7">{{_('Remote login')}}</div>
|
||||
<div class="col-xs-6 col-sm-5">{% if config.config_remote_login %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</div>
|
||||
<div class="col-xs-6 col-sm-5">{{ display_bool_setting(config.config_remote_login) }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-sm-7">{{_('Reverse proxy login')}}</div>
|
||||
<div class="col-xs-6 col-sm-5">{{ display_bool_setting(config.config_allow_reverse_proxy_header_login) }}</div>
|
||||
</div>
|
||||
{% if config.config_allow_reverse_proxy_header_login %}
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-sm-7">{{_('Reverse proxy header name')}}</div>
|
||||
<div class="col-xs-6 col-sm-5">{{ config.config_reverse_proxy_login_header_name }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="btn btn-default"><a id="basic_config" href="{{url_for('admin.configuration')}}">{{_('Basic Configuration')}}</a></div>
|
||||
<div class="btn btn-default"><a id="view_config" href="{{url_for('admin.view_configuration')}}">{{_('UI Configuration')}}</a></div>
|
||||
|
@ -204,7 +204,7 @@
|
||||
</select>
|
||||
</div>
|
||||
{% if feature_support['ldap'] %}
|
||||
<div data-related="login-settings-1">
|
||||
<div data-related="login-settings-1">
|
||||
<div class="form-group">
|
||||
<label for="config_ldap_provider_url">{{_('LDAP Server Host Name or IP Address')}}</label>
|
||||
<input type="text" class="form-control" id="config_ldap_provider_url" name="config_ldap_provider_url" value="{% if config.config_ldap_provider_url != None %}{{ config.config_ldap_provider_url }}{% endif %}" autocomplete="off">
|
||||
@ -275,6 +275,16 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="config_allow_reverse_proxy_header_login" name="config_allow_reverse_proxy_header_login" data-control="reverse-proxy-login-settings" {% if config.config_allow_reverse_proxy_header_login %}checked{% endif %}>
|
||||
<label for="config_allow_reverse_proxy_header_login">{{_('Allow Reverse Proxy Authentication')}}</label>
|
||||
</div>
|
||||
<div data-related="reverse-proxy-login-settings">
|
||||
<div class="form-group">
|
||||
<label for="config_reverse_proxy_login_header_name">{{_('Reverse Proxy Header Name')}}</label>
|
||||
<input type="text" class="form-control" id="config_reverse_proxy_login_header_name" name="config_reverse_proxy_login_header_name" value="{% if config.config_reverse_proxy_login_header_name != None %}{{ config.config_reverse_proxy_login_header_name }}{% endif %}" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
31
cps/web.py
31
cps/web.py
@ -114,14 +114,35 @@ web = Blueprint('web', __name__)
|
||||
log = logger.create()
|
||||
|
||||
# ################################### Login logic and rights management ###############################################
|
||||
def _fetch_user_by_name(username):
|
||||
return ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == username.lower()).first()
|
||||
|
||||
@lm.user_loader
|
||||
def load_user(user_id):
|
||||
return ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first()
|
||||
|
||||
|
||||
@lm.header_loader
|
||||
def load_user_from_header(header_val):
|
||||
@lm.request_loader
|
||||
def load_user_from_request(request):
|
||||
auth_header = request.headers.get("Authorization")
|
||||
if auth_header:
|
||||
user = load_user_from_auth_header(auth_header)
|
||||
if user:
|
||||
return user
|
||||
|
||||
if config.config_allow_reverse_proxy_header_login:
|
||||
rp_header_name = config.config_reverse_proxy_login_header_name
|
||||
if rp_header_name:
|
||||
rp_header_username = request.headers.get(rp_header_name)
|
||||
if rp_header_username:
|
||||
user = _fetch_user_by_name(rp_header_username)
|
||||
if user:
|
||||
return user
|
||||
|
||||
return
|
||||
|
||||
|
||||
def load_user_from_auth_header(header_val):
|
||||
if header_val.startswith('Basic '):
|
||||
header_val = header_val.replace('Basic ', '', 1)
|
||||
basic_username = basic_password = ''
|
||||
@ -131,7 +152,7 @@ def load_user_from_header(header_val):
|
||||
basic_password = header_val.split(':')[1]
|
||||
except TypeError:
|
||||
pass
|
||||
user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == basic_username.lower()).first()
|
||||
user = _fetch_user_by_name(basic_username)
|
||||
if user and check_password_hash(str(user.password), basic_password):
|
||||
return user
|
||||
return
|
||||
@ -789,7 +810,9 @@ def get_tasks_status():
|
||||
|
||||
@app.route("/reconnect")
|
||||
def reconnect():
|
||||
db.reconnect_db(config)
|
||||
db.session.close()
|
||||
db.engine.dispose()
|
||||
db.setup_db(config)
|
||||
return json.dumps({})
|
||||
|
||||
@web.route("/search", methods=["GET"])
|
||||
|
Loading…
Reference in New Issue
Block a user