mirror of
https://github.com/janeczku/calibre-web
synced 2026-05-03 20:21:25 +00:00
Merge branch 'Develop'
# Conflicts: # test/Calibre-Web TestSummary_Linux.html
This commit is contained in:
@@ -25,7 +25,8 @@ import sys
|
||||
import os
|
||||
import mimetypes
|
||||
|
||||
from flask import Flask
|
||||
from flask import Flask, request
|
||||
from flask.sessions import SecureCookieSessionInterface
|
||||
from .MyLoginManager import MyLoginManager
|
||||
from flask_principal import Principal
|
||||
|
||||
@@ -114,8 +115,14 @@ if limiter_present:
|
||||
else:
|
||||
limiter = None
|
||||
|
||||
class ScriptNameSessionInterface(SecureCookieSessionInterface):
|
||||
def get_cookie_path(self, app):
|
||||
# Called once per response, after request context exists
|
||||
return app.wsgi_app.script_name.rstrip("/") or "/"
|
||||
|
||||
|
||||
def create_app():
|
||||
app.session_interface = ScriptNameSessionInterface()
|
||||
if csrf:
|
||||
csrf.init_app(app)
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ from flask import abort
|
||||
from flask import current_app
|
||||
from flask import flash
|
||||
from flask import g
|
||||
from flask import has_app_context
|
||||
from flask import redirect
|
||||
from flask import request
|
||||
from flask import session
|
||||
@@ -469,7 +468,7 @@ class LoginManager:
|
||||
config = current_app.config
|
||||
cookie_name = config.get("REMEMBER_COOKIE_NAME", COOKIE_NAME)
|
||||
domain = config.get("REMEMBER_COOKIE_DOMAIN")
|
||||
path = config.get("REMEMBER_COOKIE_PATH", "/")
|
||||
path = config.get("REMEMBER_COOKIE_PATH", current_app.wsgi_app.script_name)
|
||||
|
||||
secure = config.get("REMEMBER_COOKIE_SECURE", COOKIE_SECURE)
|
||||
httponly = config.get("REMEMBER_COOKIE_HTTPONLY", COOKIE_HTTPONLY)
|
||||
@@ -520,36 +519,5 @@ class LoginManager:
|
||||
config = current_app.config
|
||||
cookie_name = config.get("REMEMBER_COOKIE_NAME", COOKIE_NAME)
|
||||
domain = config.get("REMEMBER_COOKIE_DOMAIN")
|
||||
path = config.get("REMEMBER_COOKIE_PATH", "/")
|
||||
path = config.get("REMEMBER_COOKIE_PATH", current_app.wsgi_app.script_name)
|
||||
response.delete_cookie(cookie_name, domain=domain, path=path)
|
||||
|
||||
@property
|
||||
def _login_disabled(self):
|
||||
"""Legacy property, use app.config['LOGIN_DISABLED'] instead."""
|
||||
import warnings
|
||||
|
||||
warnings.warn(
|
||||
"'_login_disabled' is deprecated and will be removed in"
|
||||
" Flask-Login 0.7. Use 'LOGIN_DISABLED' in 'app.config'"
|
||||
" instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
if has_app_context():
|
||||
return current_app.config.get("LOGIN_DISABLED", False)
|
||||
return False
|
||||
|
||||
@_login_disabled.setter
|
||||
def _login_disabled(self, newvalue):
|
||||
"""Legacy property setter, use app.config['LOGIN_DISABLED'] instead."""
|
||||
import warnings
|
||||
|
||||
warnings.warn(
|
||||
"'_login_disabled' is deprecated and will be removed in"
|
||||
" Flask-Login 0.7. Use 'LOGIN_DISABLED' in 'app.config'"
|
||||
" instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
current_app.config["LOGIN_DISABLED"] = newvalue
|
||||
|
||||
@@ -47,7 +47,7 @@ def get_sidebar_config(kwargs=None):
|
||||
if current_user.role_admin():
|
||||
sidebar.append({"glyph": "glyphicon-download", "text": _('Downloaded Books'), "link": 'web.download_list',
|
||||
"id": "download", "visibility": constants.SIDEBAR_DOWNLOAD, 'public': (not current_user.is_anonymous),
|
||||
"page": "download", "show_text": _('Show Downloaded Books'),
|
||||
"page": "download", "show_text": _('Show Downloaded Books'), "no_param":True,
|
||||
"config_show": content})
|
||||
else:
|
||||
sidebar.append({"glyph": "glyphicon-download", "text": _('Downloaded Books'), "link": 'web.books_list',
|
||||
@@ -69,27 +69,27 @@ def get_sidebar_config(kwargs=None):
|
||||
"visibility": constants.SIDEBAR_RANDOM, 'public': True, "page": "discover",
|
||||
"show_text": _('Show Random Books'), "config_show": True})
|
||||
sidebar.append({"glyph": "glyphicon-inbox", "text": _('Categories'), "link": 'web.category_list', "id": "cat",
|
||||
"visibility": constants.SIDEBAR_CATEGORY, 'public': True, "page": "category",
|
||||
"visibility": constants.SIDEBAR_CATEGORY, 'public': True, "page": "category", "no_param":True,
|
||||
"show_text": _('Show Category Section'), "config_show": True})
|
||||
sidebar.append({"glyph": "glyphicon-bookmark", "text": _('Series'), "link": 'web.series_list', "id": "serie",
|
||||
"visibility": constants.SIDEBAR_SERIES, 'public': True, "page": "series",
|
||||
"visibility": constants.SIDEBAR_SERIES, 'public': True, "page": "series", "no_param":True,
|
||||
"show_text": _('Show Series Section'), "config_show": True})
|
||||
sidebar.append({"glyph": "glyphicon-user", "text": _('Authors'), "link": 'web.author_list', "id": "author",
|
||||
"visibility": constants.SIDEBAR_AUTHOR, 'public': True, "page": "author",
|
||||
"visibility": constants.SIDEBAR_AUTHOR, 'public': True, "page": "author", "no_param":True,
|
||||
"show_text": _('Show Author Section'), "config_show": True})
|
||||
sidebar.append(
|
||||
{"glyph": "glyphicon-text-size", "text": _('Publishers'), "link": 'web.publisher_list', "id": "publisher",
|
||||
"visibility": constants.SIDEBAR_PUBLISHER, 'public': True, "page": "publisher",
|
||||
"visibility": constants.SIDEBAR_PUBLISHER, 'public': True, "page": "publisher", "no_param":True,
|
||||
"show_text": _('Show Publisher Section'), "config_show":True})
|
||||
sidebar.append({"glyph": "glyphicon-flag", "text": _('Languages'), "link": 'web.language_overview', "id": "lang",
|
||||
"visibility": constants.SIDEBAR_LANGUAGE, 'public': (current_user.filter_language() == 'all'),
|
||||
"page": "language",
|
||||
"page": "language", "no_param":True,
|
||||
"show_text": _('Show Language Section'), "config_show": True})
|
||||
sidebar.append({"glyph": "glyphicon-star-empty", "text": _('Ratings'), "link": 'web.ratings_list', "id": "rate",
|
||||
"visibility": constants.SIDEBAR_RATING, 'public': True,
|
||||
"visibility": constants.SIDEBAR_RATING, 'public': True, "no_param":True,
|
||||
"page": "rating", "show_text": _('Show Ratings Section'), "config_show": True})
|
||||
sidebar.append({"glyph": "glyphicon-file", "text": _('File formats'), "link": 'web.formats_list', "id": "format",
|
||||
"visibility": constants.SIDEBAR_FORMAT, 'public': True,
|
||||
"visibility": constants.SIDEBAR_FORMAT, 'public': True, "no_param":True,
|
||||
"page": "format", "show_text": _('Show File Formats Section'), "config_show": True})
|
||||
sidebar.append(
|
||||
{"glyph": "glyphicon-folder-open", "text": _('Archived Books'), "link": 'web.books_list', "id": "archived",
|
||||
@@ -98,8 +98,8 @@ def get_sidebar_config(kwargs=None):
|
||||
if not simple:
|
||||
sidebar.append(
|
||||
{"glyph": "glyphicon-th-list", "text": _('Books List'), "link": 'web.books_table', "id": "list",
|
||||
"visibility": constants.SIDEBAR_LIST, 'public': (not current_user.is_anonymous), "page": "list",
|
||||
"show_text": _('Show Books List'), "config_show": content})
|
||||
"visibility": constants.SIDEBAR_LIST, 'public': (not current_user.is_anonymous),
|
||||
"show_text": _('Show Books List'), "config_show": content, "no_param":True})
|
||||
g.shelves_access = ub.session.query(ub.Shelf).filter(
|
||||
or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == current_user.id)).order_by(ub.Shelf.name).all()
|
||||
|
||||
|
||||
@@ -61,11 +61,13 @@ class ReverseProxied(object):
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
self.proxied = False
|
||||
self.script_name = "/"
|
||||
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
|
||||
if script_name:
|
||||
self.proxied = True
|
||||
environ['SCRIPT_NAME'] = script_name
|
||||
path_info = environ.get('PATH_INFO', '')
|
||||
self.script_name = script_name
|
||||
if path_info and path_info.startswith(script_name):
|
||||
environ['PATH_INFO'] = path_info[len(script_name):]
|
||||
|
||||
|
||||
50
cps/shelf.py
50
cps/shelf.py
@@ -102,6 +102,52 @@ def add_to_shelf(shelf_id, book_id):
|
||||
return "", 204
|
||||
|
||||
|
||||
@shelf.route("/shelf/massremove/<int:shelf_id>", methods=["POST"])
|
||||
@user_login_required
|
||||
def search_from_shelf(shelf_id):
|
||||
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
|
||||
if shelf is None:
|
||||
log.error("Invalid shelf specified: {}".format(shelf_id))
|
||||
flash(_("Invalid shelf specified"), category="error")
|
||||
return redirect(url_for('web.index'))
|
||||
|
||||
if not check_shelf_edit_permissions(shelf):
|
||||
log.warning("You are not allowed to remove a book from the shelf".format(shelf.name))
|
||||
flash(_("You are not allowed to remove a book from the shelf"), category="error")
|
||||
return redirect(url_for('web.index'))
|
||||
|
||||
if current_user.id in ub.searched_ids and ub.searched_ids[current_user.id]:
|
||||
books_from_shelf = list()
|
||||
books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).all()
|
||||
if books_in_shelf:
|
||||
book_ids = [book_id.book_id for book_id in books_in_shelf]
|
||||
for searchid in ub.searched_ids[current_user.id]:
|
||||
if searchid in book_ids:
|
||||
books_from_shelf.append(searchid)
|
||||
else:
|
||||
log.error("No Books are part of {}".format(shelf.name))
|
||||
flash(_("No Books are part of the shelf: %(name)s", name=shelf.name), category="error")
|
||||
return redirect(url_for('web.index'))
|
||||
|
||||
# maxOrder = ub.session.query(func.max(ub.BookShelf.order)).filter(ub.BookShelf.shelf == shelf_id).first()[0] or 0
|
||||
|
||||
for book in books_from_shelf:
|
||||
ub.session.delete(ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).filter(
|
||||
ub.BookShelf.book_id == book).first())
|
||||
shelf.last_modified = datetime.now(timezone.utc)
|
||||
try:
|
||||
ub.session.commit()
|
||||
flash(_("Books have been removed from shelf: %(sname)s", sname=shelf.name), category="success")
|
||||
except (OperationalError, InvalidRequestError) as e:
|
||||
ub.session.rollback()
|
||||
log.error_or_exception("Settings Database error: {}".format(e))
|
||||
flash(_("Oops! Database Error: %(error)s.", error=e.orig), category="error")
|
||||
else:
|
||||
log.error("Could not remove books from shelf: {}".format(shelf.name))
|
||||
flash(_("Could not remove books from shelf: %(sname)s", sname=shelf.name), category="error")
|
||||
return redirect(url_for('web.index'))
|
||||
|
||||
|
||||
@shelf.route("/shelf/massadd/<int:shelf_id>", methods=["POST"])
|
||||
@user_login_required
|
||||
def search_to_shelf(shelf_id):
|
||||
@@ -120,9 +166,7 @@ def search_to_shelf(shelf_id):
|
||||
books_for_shelf = list()
|
||||
books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).all()
|
||||
if books_in_shelf:
|
||||
book_ids = list()
|
||||
for book_id in books_in_shelf:
|
||||
book_ids.append(book_id.book_id)
|
||||
book_ids = [book_id.book_id for book_id in books_in_shelf]
|
||||
for searchid in ub.searched_ids[current_user.id]:
|
||||
if searchid not in book_ids:
|
||||
books_for_shelf.append(searchid)
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
<li class="nav-head hidden-xs">{{_('Browse')}}</li>
|
||||
{% for element in sidebar %}
|
||||
{% if current_user.check_visibility(element['visibility']) and element['public'] %}
|
||||
<li id="nav_{{element['id']}}" {% if page == element['page'] %}class="active"{% endif %}><a href="{{url_for(element['link'], data=element['page'], sort_param='stored')}}"><span class="glyphicon {{element['glyph']}}"></span> {{_(element['text'])}}</a></li>
|
||||
<li id="nav_{{element['id']}}" {% if page == element['page'] %}class="active"{% endif %}><a href="{% if element['no_param'] %}{{url_for(element['link'], data=element['page'])}}{%else%}{{url_for(element['link'], data=element['page'], sort_param='stored')}}{% endif %}"><span class="glyphicon {{element['glyph']}}"></span> {{_(element['text'])}}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if current_user.is_authenticated or g.allow_anonymous %}
|
||||
|
||||
@@ -24,6 +24,20 @@
|
||||
{%endfor%}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group" role="group" aria-label="Remove from shelves">
|
||||
<button id="remove-from-shelf" type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-list"></span> {{_('Remove from shelf')}}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul id="remove-from-shelves" class="dropdown-menu" aria-labelledby="add-to-shelf">
|
||||
{% for shelf in g.shelves_access %}
|
||||
{% if not shelf.is_public or current_user.role_edit_shelfs() %}
|
||||
<li><a class="postAction" role="button" data-action="{{ url_for('shelf.search_from_shelf', shelf_id=shelf.id) }}"> {{shelf.name}}{% if shelf.is_public == 1 %} {{_('(Public)')}}{% endif %}</a></li>
|
||||
{% endif %}
|
||||
{%endfor%}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user