Merge branch 'master' of https://github.com/janeczku/calibre-web
This commit is contained in:
commit
d856c4d78e
|
@ -16,14 +16,14 @@ To receive fixes for security vulnerabilities it is required to always upgrade t
|
|||
| V 0.6.7 |Hardcoded secret key for sessions |CVE-2020-12627 |
|
||||
| V 0.6.13|Calibre-Web Metadata cross site scripting |CVE-2021-25964|
|
||||
| V 0.6.13|Name of Shelves are only visible to users who can access the corresponding shelf Thanks to @ibarrionuevo||
|
||||
| V 0.6.13|JavaScript could get executed in the description field. Thanks to @ranjit-git ||
|
||||
| V 0.6.13|JavaScript could get executed in the description field. Thanks to @ranjit-git and Hagai Wechsler (WhiteSource)||
|
||||
| V 0.6.13|JavaScript could get executed in a custom column of type "comment" field ||
|
||||
| V 0.6.13|JavaScript could get executed after converting a book to another format with a title containing javascript code||
|
||||
| V 0.6.13|JavaScript could get executed after converting a book to another format with a username containing javascript code||
|
||||
| V 0.6.13|JavaScript could get executed in the description series, categories or publishers title||
|
||||
| V 0.6.13|JavaScript could get executed in the shelf title||
|
||||
| V 0.6.13|Login with the old session cookie after logout. Thanks to @ibarrionuevo||
|
||||
| V 0.6.14|CSRF was possible. Thanks to @mik317 ||
|
||||
| V 0.6.14|CSRF was possible. Thanks to @mik317 and Hagai Wechsler (WhiteSource) ||
|
||||
| V 0.6.14|Cross-Site Scripting vulnerability on typeahead inputs. Thanks to @notdodo||
|
||||
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ from flask_principal import Principal
|
|||
from . import config_sql, logger, cache_buster, cli, ub, db
|
||||
from .reverseproxy import ReverseProxied
|
||||
from .server import WebServer
|
||||
from .dep_check import dependency_check
|
||||
|
||||
try:
|
||||
import lxml
|
||||
|
@ -100,6 +101,7 @@ _BABEL_TRANSLATIONS = set()
|
|||
|
||||
log = logger.create()
|
||||
|
||||
|
||||
from . import services
|
||||
|
||||
db.CalibreDB.update_config(config)
|
||||
|
@ -126,7 +128,11 @@ def create_app():
|
|||
print('*** "flask-WTF" is needed for calibre-web to run. Please install it using pip: "pip install flask-WTF" ***')
|
||||
web_server.stop(True)
|
||||
sys.exit(7)
|
||||
|
||||
for res in dependency_check() + dependency_check(True):
|
||||
log.info('*** "{}" version does not fit the requirements. Should: {}, Found: {}, please consider updating. ***'
|
||||
.format(res['name'],
|
||||
res['target'],
|
||||
res['found']))
|
||||
app.wsgi_app = ReverseProxied(app.wsgi_app)
|
||||
|
||||
if os.environ.get('FLASK_DEBUG'):
|
||||
|
|
|
@ -780,7 +780,7 @@ class CalibreDB():
|
|||
|
||||
# read search results from calibre-database and return it (function is used for feed and simple search
|
||||
def get_search_results(self, term, offset=None, order=None, limit=None, *join):
|
||||
order = order or [Books.sort]
|
||||
order = order[0] or [Books.sort]
|
||||
pagination = None
|
||||
result = self.search_query(term, *join).order_by(*order).all()
|
||||
result_count = len(result)
|
||||
|
|
83
cps/dep_check.py
Normal file
83
cps/dep_check.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
import os
|
||||
import re
|
||||
|
||||
from .constants import BASE_DIR
|
||||
try:
|
||||
from importlib_metadata import version
|
||||
importlib = True
|
||||
ImportNotFound = BaseException
|
||||
except ImportError:
|
||||
importlib = False
|
||||
|
||||
|
||||
if not importlib:
|
||||
try:
|
||||
import pkg_resources
|
||||
from pkg_resources import DistributionNotFound as ImportNotFound
|
||||
pkgresources = True
|
||||
except ImportError as e:
|
||||
pkgresources = False
|
||||
|
||||
def dependency_check(optional=False):
|
||||
dep = list()
|
||||
if importlib or pkgresources:
|
||||
if optional:
|
||||
req_path = os.path.join(BASE_DIR, "optional-requirements.txt")
|
||||
else:
|
||||
req_path = os.path.join(BASE_DIR, "requirements.txt")
|
||||
if os.path.exists(req_path):
|
||||
try:
|
||||
with open(req_path, 'r') as f:
|
||||
for line in f:
|
||||
if not line.startswith('#') and not line == '\n' and not line.startswith('git'):
|
||||
res = re.match(r'(.*?)([<=>\s]+)([\d\.]+),?\s?([<=>\s]+)?([\d\.]+)?', line.strip())
|
||||
try:
|
||||
if importlib:
|
||||
dep_version = version(res.group(1))
|
||||
else:
|
||||
dep_version = pkg_resources.get_distribution(res.group(1)).version
|
||||
except ImportNotFound:
|
||||
if optional:
|
||||
continue
|
||||
else:
|
||||
return [{'name':res.group(1),
|
||||
'target': "available",
|
||||
'found': "Not available"
|
||||
}]
|
||||
|
||||
if res.group(2).strip() == "==":
|
||||
if dep_version.split('.') != res.group(3).split('.'):
|
||||
dep.append({'name': res.group(1),
|
||||
'found': dep_version,
|
||||
"target": res.group(2) + res.group(3)})
|
||||
continue
|
||||
elif res.group(2).strip() == ">=":
|
||||
if dep_version.split('.') < res.group(3).split('.'):
|
||||
dep.append({'name': res.group(1),
|
||||
'found': dep_version,
|
||||
"target": res.group(2) + res.group(3)})
|
||||
continue
|
||||
elif res.group(2).strip() == ">":
|
||||
if dep_version.split('.') <= res.group(3).split('.'):
|
||||
dep.append({'name': res.group(1),
|
||||
'found': dep_version,
|
||||
"target": res.group(2) + res.group(3)})
|
||||
continue
|
||||
if res.group(4) and res.group(5):
|
||||
if res.group(4).strip() == "<":
|
||||
if dep_version.split('.') >= res.group(5).split('.'):
|
||||
dep.append(
|
||||
{'name': res.group(1),
|
||||
'found': dep_version,
|
||||
"target": res.group(4) + res.group(5)})
|
||||
continue
|
||||
elif res.group(2).strip() == "<=":
|
||||
if dep_version.split('.') > res.group(5).split('.'):
|
||||
dep.append(
|
||||
{'name': res.group(1),
|
||||
'found': dep_version,
|
||||
"target": res.group(4) + res.group(5)})
|
||||
continue
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return dep
|
|
@ -30,6 +30,9 @@ $("#desc").click(function() {
|
|||
if (direction === 0) {
|
||||
return;
|
||||
}
|
||||
$("#asc").removeClass("active");
|
||||
$("#desc").addClass("active");
|
||||
|
||||
var page = $(this).data("id");
|
||||
$.ajax({
|
||||
method:"post",
|
||||
|
@ -50,6 +53,9 @@ $("#asc").click(function() {
|
|||
if (direction === 1) {
|
||||
return;
|
||||
}
|
||||
$("#desc").removeClass("active");
|
||||
$("#asc").addClass("active");
|
||||
|
||||
var page = $(this).data("id");
|
||||
$.ajax({
|
||||
method:"post",
|
||||
|
@ -66,6 +72,8 @@ $("#asc").click(function() {
|
|||
});
|
||||
|
||||
$("#all").click(function() {
|
||||
$(".char").removeClass("active");
|
||||
$("#all").addClass("active");
|
||||
// go through all elements and make them visible
|
||||
$list.isotope({ filter: function() {
|
||||
return true;
|
||||
|
@ -74,6 +82,9 @@ $("#all").click(function() {
|
|||
});
|
||||
|
||||
$(".char").click(function() {
|
||||
$(".char").removeClass("active");
|
||||
$(this).addClass("active");
|
||||
$("#all").removeClass("active");
|
||||
var character = this.innerText;
|
||||
$list.isotope({ filter: function() {
|
||||
return this.attributes["data-id"].value.charAt(0).toUpperCase() === character;
|
||||
|
|
|
@ -19,6 +19,7 @@ var direction = $("#asc").data('order'); // 0=Descending order; 1= ascending or
|
|||
var sort = 0; // Show sorted entries
|
||||
|
||||
$("#sort_name").click(function() {
|
||||
$("#sort_name").toggleClass("active");
|
||||
var className = $("h1").attr("Class") + "_sort_name";
|
||||
var obj = {};
|
||||
obj[className] = sort;
|
||||
|
@ -68,6 +69,9 @@ $("#desc").click(function() {
|
|||
if (direction === 0) {
|
||||
return;
|
||||
}
|
||||
$("#asc").removeClass("active");
|
||||
$("#desc").addClass("active");
|
||||
|
||||
var page = $(this).data("id");
|
||||
$.ajax({
|
||||
method:"post",
|
||||
|
@ -112,10 +116,12 @@ $("#desc").click(function() {
|
|||
|
||||
|
||||
$("#asc").click(function() {
|
||||
|
||||
if (direction === 1) {
|
||||
return;
|
||||
}
|
||||
$("#desc").removeClass("active");
|
||||
$("#asc").addClass("active");
|
||||
|
||||
var page = $(this).data("id");
|
||||
$.ajax({
|
||||
method:"post",
|
||||
|
@ -159,6 +165,8 @@ $("#asc").click(function() {
|
|||
});
|
||||
|
||||
$("#all").click(function() {
|
||||
$("#all").addClass("active");
|
||||
$(".char").removeClass("active");
|
||||
var cnt = $("#second").contents();
|
||||
$("#list").append(cnt);
|
||||
// Find count of middle element
|
||||
|
@ -176,6 +184,9 @@ $("#all").click(function() {
|
|||
});
|
||||
|
||||
$(".char").click(function() {
|
||||
$(".char").removeClass("active");
|
||||
$(this).addClass("active");
|
||||
$("#all").removeClass("active");
|
||||
var character = this.innerText;
|
||||
var count = 0;
|
||||
var index = 0;
|
||||
|
|
|
@ -28,14 +28,17 @@ $(function () {
|
|||
|
||||
function populateForm (book) {
|
||||
tinymce.get("description").setContent(book.description);
|
||||
var uniqueTags = [];
|
||||
var uniqueTags = $.map($("#tags").val().split(","), $.trim);
|
||||
if ( uniqueTags.length == 1 && uniqueTags[0] == "") {
|
||||
uniqueTags = [];
|
||||
}
|
||||
$.each(book.tags, function(i, el) {
|
||||
if ($.inArray(el, uniqueTags) === -1) uniqueTags.push(el);
|
||||
});
|
||||
var ampSeparatedAuthors = (book.authors || []).join(" & ");
|
||||
$("#bookAuthor").val(ampSeparatedAuthors);
|
||||
$("#book_title").val(book.title);
|
||||
$("#tags").val(uniqueTags.join(","));
|
||||
$("#tags").val(uniqueTags.join(", "));
|
||||
$("#rating").data("rating").setValue(Math.round(book.rating));
|
||||
if(book.cover !== null){
|
||||
$(".cover img").attr("src", book.cover);
|
||||
|
|
|
@ -151,6 +151,7 @@ class TaskConvert(CalibreTask):
|
|||
local_db.session.rollback()
|
||||
log.error("Database error: %s", e)
|
||||
local_db.session.close()
|
||||
self._handleError(error_message)
|
||||
return
|
||||
self.results['path'] = cur_book.path
|
||||
self.title = cur_book.title
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
<th>{{_('Downloads')}}</th>
|
||||
<th class="hidden-xs ">{{_('Admin')}}</th>
|
||||
<th class="hidden-xs hidden-sm">{{_('Password')}}</th>
|
||||
{% if config.config_upload %}
|
||||
<th class="hidden-xs hidden-sm">{{_('Upload')}}</th>
|
||||
{% endif %}
|
||||
<th class="hidden-xs hidden-sm">{{_('Download')}}</th>
|
||||
<th class="hidden-xs hidden-sm hidden-md">{{_('View Books')}}</th>
|
||||
<th class="hidden-xs hidden-sm hidden-md">{{_('Edit')}}</th>
|
||||
|
@ -32,7 +34,9 @@
|
|||
<td>{{user.downloads.count()}}</td>
|
||||
<td class="hidden-xs">{{ display_bool_setting(user.role_admin()) }}</td>
|
||||
<td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_passwd()) }}</td>
|
||||
{% if config.config_upload %}
|
||||
<td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_upload()) }}</td>
|
||||
{% endif %}
|
||||
<td class="hidden-xs hidden-sm">{{ display_bool_setting(user.role_download()) }}</td>
|
||||
<td class="hidden-xs hidden-sm hidden-md">{{ display_bool_setting(user.role_viewer()) }}</td>
|
||||
<td class="hidden-xs hidden-sm hidden-md">{{ display_bool_setting(user.role_edit()) }}</td>
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
<h3>{{_("In Library")}}</h3>
|
||||
{% endif %}
|
||||
<div class="filterheader hidden-xs">
|
||||
<a id="new" data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a id="old" data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
<a id="asc" data-toggle="tooltip" title="{{_('Sort title in alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='abc')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a id="desc" data-toggle="tooltip" title="{{_('Sort title in reverse alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='zyx')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a id="pub_new" data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a id="pub_old" data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
<a id="new" data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" class="btn btn-primary{% if order == "new" %} active{% endif%}" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a id="old" data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" class="btn btn-primary{% if order == "old" %} active{% endif%}" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
<a id="asc" data-toggle="tooltip" title="{{_('Sort title in alphabetical order')}}" class="btn btn-primary{% if order == "abc" %} active{% endif%}" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='abc')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a id="desc" data-toggle="tooltip" title="{{_('Sort title in reverse alphabetical order')}}" class="btn btn-primary{% if order == "zyx" %} active{% endif%}" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='zyx')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a id="pub_new" data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" class="btn btn-primary{% if order == "pubnew" %} active{% endif%}" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a id="pub_old" data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" class="btn btn-primary{% if order == "pubold" %} active{% endif%}" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
</div>
|
||||
<div class="row display-flex">
|
||||
{% if entries[0] %}
|
||||
|
|
|
@ -95,17 +95,21 @@
|
|||
<input type="checkbox" name="viewer_role" id="viewer_role" {% if conf.role_viewer() %}checked{% endif %}>
|
||||
<label for="viewer_role">{{_('Allow eBook Viewer')}}</label>
|
||||
</div>
|
||||
{% if config.config_upload %}
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="upload_role" id="upload_role" {% if conf.role_upload() %}checked{% endif %}>
|
||||
<label for="upload_role">{{_('Allow Uploads')}}</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="edit_role" id="edit_role" {% if conf.role_edit() %}checked{% endif %}>
|
||||
<input type="checkbox" name="edit_role" data-control="edit_settings" id="edit_role" {% if conf.role_edit() %}checked{% endif %}>
|
||||
<label for="edit_role">{{_('Allow Edit')}}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="delete_role" id="delete_role" {% if conf.role_delete_books() %}checked{% endif %}>
|
||||
<label for="delete_role">{{_('Allow Delete Books')}}</label>
|
||||
<div data-related="edit_settings">
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="delete_role" id="delete_role" {% if conf.role_delete_books() %}checked{% endif %}>
|
||||
<label for="delete_role">{{_('Allow Delete Books')}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="passwd_role" id="passwd_role" {% if conf.role_passwd() %}checked{% endif %}>
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
|
||||
<div class="filterheader hidden-xs">
|
||||
{% if entries.__len__() and data == 'author' %}
|
||||
<button id="sort_name" class="btn btn-primary"><b>B,A <-> A B</b></button>
|
||||
<div id="sort_name" class="btn btn-primary"><b>B,A <-> A B</b></div>
|
||||
{% endif %}
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button id="asc" data-id="series" data-order="{{ order }}" class="btn btn-primary"><span class="glyphicon glyphicon-sort-by-alphabet"></span></button>
|
||||
<button id="desc" data-id="series" class="btn btn-primary"><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></button>
|
||||
<div id="asc" data-id="series" data-order="{{ order }}" class="btn btn-primary{% if order == 1 %} active{% endif%}"><span class="glyphicon glyphicon-sort-by-alphabet"></span></div>
|
||||
<div id="desc" data-id="series" class="btn btn-primary{% if order == 0 %} active{% endif%}"><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></div>
|
||||
{% if charlist|length %}
|
||||
<button id="all" class="btn btn-primary {% if charlist|length > 9 %}hidden-sm{% endif %}">{{_('All')}}</button>
|
||||
<div id="all" class="active btn btn-primary {% if charlist|length > 9 %}hidden-sm{% endif %}">{{_('All')}}</div>
|
||||
{% endif %}
|
||||
<div class="btn-group character {% if charlist|length > 9 %}hidden-sm{% endif %}" role="group">
|
||||
{% for char in charlist%}
|
||||
<button class="btn btn-primary char">{{char.char}}</button>
|
||||
<div class="btn btn-primary char">{{char.char}}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<button class="update-view btn btn-primary" data-target="series_view" id="list-button" data-view="list">List</button>
|
||||
<div class="update-view btn btn-primary" data-target="series_view" id="list-button" data-view="list">List</div>
|
||||
</div>
|
||||
|
||||
{% if entries[0] %}
|
||||
|
@ -27,7 +27,7 @@
|
|||
<div class="cover">
|
||||
<a href="{{url_for('web.books_list', data=data, sort_param='stored', book_id=entry[0].series[0].id )}}">
|
||||
<span class="img" title="{{entry[0].series[0].name}}">
|
||||
<img src="{{ url_for('web.get_cover', book_id=entry[0].id) }}" alt="{{ entry[0].name }}"/>
|
||||
<img src="{{ url_for('web.get_cover', book_id=entry[3]) }}" alt="{{ entry[0].series[0].name }}"/>
|
||||
<span class="badge">{{entry.count}}</span>
|
||||
</span>
|
||||
</a>
|
||||
|
|
|
@ -65,18 +65,23 @@
|
|||
<div class="discover load-more">
|
||||
<h2 class="{{title}}">{{title}}</h2>
|
||||
<div class="filterheader hidden-xs">
|
||||
<a data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" id="new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" id="old" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort title in alphabetical order')}}" id="asc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='abc')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort title in reverse alphabetical order')}}" id="desc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='zyx')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort authors in alphabetical order')}}" id="auth_az" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='authaz')}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort authors in reverse alphabetical order')}}" id="auth_za" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='authza')}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" id="pub_new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" id="pub_old" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
{% if page == 'hot' %}
|
||||
<a data-toggle="tooltip" title="{{_('Sort ascending according to download count')}}" id="hot_asc" class="btn btn-primary{% if order == "hotasc" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='hotasc')}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort descending according to download count')}}" id="hot_desc" class="btn btn-primary{% if order == "hotdesc" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='hotdesc')}}"><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
{% else %}
|
||||
<a data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" id="new" class="btn btn-primary{% if order == "new" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" id="old" class="btn btn-primary{% if order == "old" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort title in alphabetical order')}}" id="asc" class="btn btn-primary{% if order == "abc" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='abc')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort title in reverse alphabetical order')}}" id="desc" class="btn btn-primary{% if order == "zyx" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='zyx')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort authors in alphabetical order')}}" id="auth_az" class="btn btn-primary{% if order == "authaz" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='authaz')}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort authors in reverse alphabetical order')}}" id="auth_za" class="btn btn-primary{% if order == "authza" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='authza')}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" id="pub_new" class="btn btn-primary{% if order == "pubnew" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" id="pub_old" class="btn btn-primary{% if order == "pubold" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
{% if page == 'series' %}
|
||||
<a data-toggle="tooltip" title="{{_('Sort ascending according to series index')}}" id="series_asc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='seriesasc')}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort descending according to series index')}}" id="series_desc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='seriesdesc')}}"><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort ascending according to series index')}}" id="series_asc" class="btn btn-primary{% if order == "seriesasc" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='seriesasc')}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a data-toggle="tooltip" title="{{_('Sort descending according to series index')}}" id="series_desc" class="btn btn-primary{% if order == "seriesdesc" %} active{% endif%}" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='seriesdesc')}}"><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="row display-flex">
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
<div class="filterheader hidden-xs">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
{% if entries.__len__() and data == 'author' %}
|
||||
<button id="sort_name" class="btn btn-primary"><b>B,A <-> A B</b></button>
|
||||
<div id="sort_name" class="btn btn-primary"><b>B,A <-> A B</b></div>
|
||||
{% endif %}
|
||||
<button id="asc" data-order="{{ order }}" data-id="{{ data }}" class="btn btn-primary"><span class="glyphicon glyphicon-sort-by-alphabet"></span></button>
|
||||
<button id="desc" data-id="{{ data }}" class="btn btn-primary"><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></button>
|
||||
<div id="asc" data-order="{{ order }}" data-id="{{ data }}" class="btn btn-primary {% if order == 1 %} active{% endif%}"><span class="glyphicon glyphicon-sort-by-alphabet"></span></div>
|
||||
<div id="desc" data-id="{{ data }}" class="btn btn-primary{% if order == 0 %} active{% endif%}"><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></div>
|
||||
{% if charlist|length %}
|
||||
<button id="all" class="btn btn-primary {% if charlist|length > 9 %}hidden-sm{% endif %}">{{_('All')}}</button>
|
||||
<div id="all" class="active btn btn-primary {% if charlist|length > 9 %}hidden-sm{% endif %}">{{_('All')}}</div>
|
||||
{% endif %}
|
||||
<div class="btn-group character {% if charlist|length > 9 %}hidden-sm{% endif %}" role="group">
|
||||
{% for char in charlist%}
|
||||
<button class="btn btn-primary char">{{char.char}}</button>
|
||||
<div class="btn btn-primary char">{{char.char}}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -26,14 +26,14 @@
|
|||
{% endif %}
|
||||
{% endif %}
|
||||
<div class="filterheader hidden-xs"><!-- ToDo: Implement filter for search results -->
|
||||
<a id="new" data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='new', query=query)}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a id="old" data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='old', query=query)}}"><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
<a id="asc" data-toggle="tooltip" title="{{_('Sort title in alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='abc', query=query)}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a id="desc" data-toggle="tooltip" title="{{_('Sort title in reverse alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='zyx', query=query)}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a id="auth_az" data-toggle="tooltip" title="{{_('Sort authors in alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='authaz', query=query)}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a id="auth_za" data-toggle="tooltip" title="{{_('Sort authors in reverse alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='authza', query=query)}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a id="pub_new" data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='pubnew', query=query)}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a id="pub_old" data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='pubold', query=query)}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
<a id="new" data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" class="btn btn-primary{% if order == "new" %} active{% endif%}" href="{{url_for('web.books_list', data=page, sort_param='new', query=query)}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a id="old" data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" class="btn btn-primary{% if order == "old" %} active{% endif%}" href="{{url_for('web.books_list', data=page, sort_param='old', query=query)}}"><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
<a id="asc" data-toggle="tooltip" title="{{_('Sort title in alphabetical order')}}" class="btn btn-primary{% if order == "abc" %} active{% endif%}" href="{{url_for('web.books_list', data=page, sort_param='abc', query=query)}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a id="desc" data-toggle="tooltip" title="{{_('Sort title in reverse alphabetical order')}}" class="btn btn-primary{% if order == "zyx" %} active{% endif%}" href="{{url_for('web.books_list', data=page, sort_param='zyx', query=query)}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a id="auth_az" data-toggle="tooltip" title="{{_('Sort authors in alphabetical order')}}" class="btn btn-primary{% if order == "authaz" %} active{% endif%}" href="{{url_for('web.books_list', data=page, sort_param='authaz', query=query)}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||
<a id="auth_za" data-toggle="tooltip" title="{{_('Sort authors in reverse alphabetical order')}}" class="btn btn-primary{% if order == "authza" %} active{% endif%}" href="{{url_for('web.books_list', data=page, sort_param='authza', query=query)}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||
<a id="pub_new" data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" class="btn btn-primary{% if order == "pubnew" %} active{% endif%}" href="{{url_for('web.books_list', data=page, sort_param='pubnew', query=query)}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||
<a id="pub_old" data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" class="btn btn-primary{% if order == "pubold" %} active{% endif%}" href="{{url_for('web.books_list', data=page, sort_param='pubold', query=query)}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -101,29 +101,33 @@
|
|||
<input type="checkbox" name="viewer_role" id="viewer_role" {% if content.role_viewer() %}checked{% endif %}>
|
||||
<label for="viewer_role">{{_('Allow eBook Viewer')}}</label>
|
||||
</div>
|
||||
{% if config.config_upload %}
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="upload_role" id="upload_role" {% if content.role_upload() %}checked{% endif %}>
|
||||
<label for="upload_role">{{_('Allow Uploads')}}</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="edit_role" id="edit_role" {% if content.role_edit() %}checked{% endif %}>
|
||||
<input type="checkbox" name="edit_role" data-control="edit_settings" id="edit_role" {% if content.role_edit() %}checked{% endif %}>
|
||||
<label for="edit_role">{{_('Allow Edit')}}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="delete_role" id="delete_role" {% if content.role_delete_books() %}checked{% endif %}>
|
||||
<label for="delete_role">{{_('Allow Delete Books')}}</label>
|
||||
<div data-related="edit_settings">
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="delete_role" id="delete_role" {% if content.role_delete_books() %}checked{% endif %}>
|
||||
<label for="delete_role">{{_('Allow Delete Books')}}</label>
|
||||
</div>
|
||||
</div>
|
||||
{% if not content.role_anonymous() %}
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="passwd_role" id="passwd_role" {% if content.role_passwd() %}checked{% endif %}>
|
||||
<label for="passwd_role">{{_('Allow Changing Password')}}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="edit_shelf_role" id="edit_shelf_role" {% if content.role_edit_shelfs() %}checked{% endif %}>
|
||||
<label for="edit_shelf_role">{{_('Allow Editing Public Shelves')}}</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if not content.role_anonymous() %}
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="passwd_role" id="passwd_role" {% if content.role_passwd() %}checked{% endif %}>
|
||||
<label for="passwd_role">{{_('Allow Changing Password')}}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="edit_shelf_role" id="edit_shelf_role" {% if content.role_edit_shelfs() %}checked{% endif %}>
|
||||
<label for="edit_shelf_role">{{_('Allow Editing Public Shelves')}}</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if kobo_support and not content.role_anonymous() %}
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="kobo_only_shelves_sync" id="kobo_only_shelves_sync" {% if content.kobo_only_shelves_sync %}checked{% endif %}>
|
||||
|
|
104
cps/web.py
104
cps/web.py
|
@ -339,7 +339,7 @@ def get_matching_tags():
|
|||
|
||||
|
||||
def get_sort_function(sort, data):
|
||||
order = [db.Books.timestamp.desc()]
|
||||
order = [db.Books.sort]
|
||||
if sort == 'stored':
|
||||
sort = current_user.get_view_property(data, 'stored')
|
||||
else:
|
||||
|
@ -364,7 +364,13 @@ def get_sort_function(sort, data):
|
|||
order = [db.Books.series_index.asc()]
|
||||
if sort == 'seriesdesc':
|
||||
order = [db.Books.series_index.desc()]
|
||||
return order
|
||||
if sort == 'hotdesc':
|
||||
order = [func.count(ub.Downloads.book_id).desc()]
|
||||
if sort == 'hotasc':
|
||||
order = [func.count(ub.Downloads.book_id).asc()]
|
||||
if sort is None:
|
||||
sort = "abc"
|
||||
return order, sort
|
||||
|
||||
|
||||
def render_books_list(data, sort, book_id, page):
|
||||
|
@ -378,7 +384,7 @@ def render_books_list(data, sort, book_id, page):
|
|||
elif data == "read":
|
||||
return render_read_books(page, True, order=order)
|
||||
elif data == "hot":
|
||||
return render_hot_books(page)
|
||||
return render_hot_books(page, order)
|
||||
elif data == "download":
|
||||
return render_downloaded_books(page, order, book_id)
|
||||
elif data == "author":
|
||||
|
@ -407,12 +413,12 @@ def render_books_list(data, sort, book_id, page):
|
|||
return render_adv_search_results(term, offset, order, config.config_books_per_page)
|
||||
else:
|
||||
website = data or "newest"
|
||||
entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, True, order,
|
||||
entries, random, pagination = calibre_db.fill_indexpage(page, 0, db.Books, True, order[0],
|
||||
db.books_series_link,
|
||||
db.Books.id == db.books_series_link.c.book,
|
||||
db.Series)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
title=_(u"Books"), page=website)
|
||||
title=_(u"Books"), page=website, order=order[1])
|
||||
|
||||
|
||||
def render_rated_books(page, book_id, order):
|
||||
|
@ -420,13 +426,13 @@ def render_rated_books(page, book_id, order):
|
|||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db.Books.ratings.any(db.Ratings.rating > 9),
|
||||
order,
|
||||
order[0],
|
||||
db.books_series_link,
|
||||
db.Books.id == db.books_series_link.c.book,
|
||||
db.Series)
|
||||
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
id=book_id, title=_(u"Top Rated Books"), page="rated")
|
||||
id=book_id, title=_(u"Top Rated Books"), page="rated", order=order[1])
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -440,16 +446,21 @@ def render_discover_books(page, book_id):
|
|||
else:
|
||||
abort(404)
|
||||
|
||||
def render_hot_books(page):
|
||||
def render_hot_books(page, order):
|
||||
if current_user.check_visibility(constants.SIDEBAR_HOT):
|
||||
if order[1] not in ['hotasc', 'hotdesc']:
|
||||
# Unary expression comparsion only working (for this expression) in sqlalchemy 1.4+
|
||||
#if not (order[0][0].compare(func.count(ub.Downloads.book_id).desc()) or
|
||||
# order[0][0].compare(func.count(ub.Downloads.book_id).asc())):
|
||||
order = [func.count(ub.Downloads.book_id).desc()], 'hotdesc'
|
||||
if current_user.show_detail_random():
|
||||
random = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()) \
|
||||
.order_by(func.random()).limit(config.config_random_books)
|
||||
else:
|
||||
random = false()
|
||||
off = int(int(config.config_books_per_page) * (page - 1))
|
||||
all_books = ub.session.query(ub.Downloads, func.count(ub.Downloads.book_id)).order_by(
|
||||
func.count(ub.Downloads.book_id).desc()).group_by(ub.Downloads.book_id)
|
||||
all_books = ub.session.query(ub.Downloads, func.count(ub.Downloads.book_id))\
|
||||
.order_by(*order[0]).group_by(ub.Downloads.book_id)
|
||||
hot_books = all_books.offset(off).limit(config.config_books_per_page)
|
||||
entries = list()
|
||||
for book in hot_books:
|
||||
|
@ -462,7 +473,7 @@ def render_hot_books(page):
|
|||
numBooks = entries.__len__()
|
||||
pagination = Pagination(page, config.config_books_per_page, numBooks)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
title=_(u"Hot Books (Most Downloaded)"), page="hot")
|
||||
title=_(u"Hot Books (Most Downloaded)"), page="hot", order=order[1])
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -483,7 +494,10 @@ def render_downloaded_books(page, order, user_id):
|
|||
0,
|
||||
db.Books,
|
||||
ub.Downloads.user_id == user_id,
|
||||
order,
|
||||
order[0],
|
||||
db.books_series_link,
|
||||
db.Books.id == db.books_series_link.c.book,
|
||||
db.Series,
|
||||
ub.Downloads, db.Books.id == ub.Downloads.book_id)
|
||||
for book in entries:
|
||||
if not calibre_db.session.query(db.Books).filter(calibre_db.common_filters()) \
|
||||
|
@ -496,7 +510,8 @@ def render_downloaded_books(page, order, user_id):
|
|||
pagination=pagination,
|
||||
id=user_id,
|
||||
title=_(u"Downloaded books by %(user)s",user=user.name),
|
||||
page="download")
|
||||
page="download",
|
||||
order=order[1])
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -505,7 +520,7 @@ def render_author_books(page, author_id, order):
|
|||
entries, __, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db.Books.authors.any(db.Authors.id == author_id),
|
||||
[order[0], db.Series.name, db.Books.series_index],
|
||||
[order[0][0], db.Series.name, db.Books.series_index],
|
||||
db.books_series_link,
|
||||
db.Books.id == db.books_series_link.c.book,
|
||||
db.Series)
|
||||
|
@ -527,7 +542,7 @@ def render_author_books(page, author_id, order):
|
|||
|
||||
return render_title_template('author.html', entries=entries, pagination=pagination, id=author_id,
|
||||
title=_(u"Author: %(name)s", name=author_name), author=author_info,
|
||||
other_books=other_books, page="author")
|
||||
other_books=other_books, page="author", order=order[1])
|
||||
|
||||
|
||||
def render_publisher_books(page, book_id, order):
|
||||
|
@ -536,12 +551,14 @@ def render_publisher_books(page, book_id, order):
|
|||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db.Books.publishers.any(db.Publishers.id == book_id),
|
||||
[db.Series.name, order[0], db.Books.series_index],
|
||||
[db.Series.name, order[0][0], db.Books.series_index],
|
||||
db.books_series_link,
|
||||
db.Books.id == db.books_series_link.c.book,
|
||||
db.Series)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id,
|
||||
title=_(u"Publisher: %(name)s", name=publisher.name), page="publisher")
|
||||
title=_(u"Publisher: %(name)s", name=publisher.name),
|
||||
page="publisher",
|
||||
order=order[1])
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -552,9 +569,9 @@ def render_series_books(page, book_id, order):
|
|||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db.Books.series.any(db.Series.id == book_id),
|
||||
[order[0]])
|
||||
[order[0][0]])
|
||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
||||
title=_(u"Series: %(serie)s", serie=name.name), page="series")
|
||||
title=_(u"Series: %(serie)s", serie=name.name), page="series", order=order[1])
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -564,10 +581,12 @@ def render_ratings_books(page, book_id, order):
|
|||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db.Books.ratings.any(db.Ratings.id == book_id),
|
||||
[order[0]])
|
||||
[order[0][0]])
|
||||
if name and name.rating <= 10:
|
||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
||||
title=_(u"Rating: %(rating)s stars", rating=int(name.rating / 2)), page="ratings")
|
||||
title=_(u"Rating: %(rating)s stars", rating=int(name.rating / 2)),
|
||||
page="ratings",
|
||||
order=order[1])
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -578,9 +597,11 @@ def render_formats_books(page, book_id, order):
|
|||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db.Books.data.any(db.Data.format == book_id.upper()),
|
||||
[order[0]])
|
||||
[order[0][0]])
|
||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
||||
title=_(u"File format: %(format)s", format=name.format), page="formats")
|
||||
title=_(u"File format: %(format)s", format=name.format),
|
||||
page="formats",
|
||||
order=order[1])
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -591,12 +612,12 @@ def render_category_books(page, book_id, order):
|
|||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db.Books.tags.any(db.Tags.id == book_id),
|
||||
[order[0], db.Series.name, db.Books.series_index],
|
||||
[order[0][0], db.Series.name, db.Books.series_index],
|
||||
db.books_series_link,
|
||||
db.Books.id == db.books_series_link.c.book,
|
||||
db.Series)
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id,
|
||||
title=_(u"Category: %(name)s", name=name.name), page="category")
|
||||
title=_(u"Category: %(name)s", name=name.name), page="category", order=order[1])
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -610,13 +631,13 @@ def render_language_books(page, name, order):
|
|||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db.Books.languages.any(db.Languages.lang_code == name),
|
||||
[order[0]])
|
||||
[order[0][0]])
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=name,
|
||||
title=_(u"Language: %(name)s", name=lang_name), page="language")
|
||||
title=_(u"Language: %(name)s", name=lang_name), page="language", order=order[1])
|
||||
|
||||
|
||||
def render_read_books(page, are_read, as_xml=False, order=None):
|
||||
order = order or []
|
||||
sort = order[0] or []
|
||||
if not config.config_read_column:
|
||||
if are_read:
|
||||
db_filter = and_(ub.ReadBook.user_id == int(current_user.id),
|
||||
|
@ -626,7 +647,7 @@ def render_read_books(page, are_read, as_xml=False, order=None):
|
|||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db_filter,
|
||||
order,
|
||||
sort,
|
||||
db.books_series_link,
|
||||
db.Books.id == db.books_series_link.c.book,
|
||||
db.Series,
|
||||
|
@ -640,7 +661,7 @@ def render_read_books(page, are_read, as_xml=False, order=None):
|
|||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||
db.Books,
|
||||
db_filter,
|
||||
order,
|
||||
sort,
|
||||
db.books_series_link,
|
||||
db.Books.id == db.books_series_link.c.book,
|
||||
db.Series,
|
||||
|
@ -663,11 +684,11 @@ def render_read_books(page, are_read, as_xml=False, order=None):
|
|||
name = _(u'Unread Books') + ' (' + str(pagination.total_count) + ')'
|
||||
pagename = "unread"
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
title=name, page=pagename)
|
||||
title=name, page=pagename, order=order[1])
|
||||
|
||||
|
||||
def render_archived_books(page, order):
|
||||
order = order or []
|
||||
def render_archived_books(page, sort):
|
||||
order = sort[0] or []
|
||||
archived_books = (
|
||||
ub.session.query(ub.ArchivedBook)
|
||||
.filter(ub.ArchivedBook.user_id == int(current_user.id))
|
||||
|
@ -687,7 +708,7 @@ def render_archived_books(page, order):
|
|||
name = _(u'Archived Books') + ' (' + str(len(archived_book_ids)) + ')'
|
||||
pagename = "archived"
|
||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
|
||||
title=name, page=pagename)
|
||||
title=name, page=pagename, order=sort[1])
|
||||
|
||||
|
||||
def render_prepare_search_form(cc):
|
||||
|
@ -732,7 +753,8 @@ def render_search_results(term, offset=None, order=None, limit=None):
|
|||
entries=entries,
|
||||
result_count=result_count,
|
||||
title=_(u"Search"),
|
||||
page="search")
|
||||
page="search",
|
||||
order=order[1])
|
||||
|
||||
|
||||
# ################################### View Books list ##################################################################
|
||||
|
@ -931,8 +953,9 @@ def series_list():
|
|||
return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist,
|
||||
title=_(u"Series"), page="serieslist", data="series", order=order_no)
|
||||
else:
|
||||
entries = calibre_db.session.query(db.Books, func.count('books_series_link').label('count')) \
|
||||
.join(db.books_series_link).join(db.Series).filter(calibre_db.common_filters()) \
|
||||
entries = calibre_db.session.query(db.Books, func.count('books_series_link').label('count'),
|
||||
func.max(db.Books.series_index), db.Books.id) \
|
||||
.join(db.books_series_link).join(db.Series).filter(calibre_db.common_filters())\
|
||||
.group_by(text('books_series_link.series')).order_by(order).all()
|
||||
charlist = calibre_db.session.query(func.upper(func.substr(db.Series.sort, 1, 1)).label('char')) \
|
||||
.join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters()) \
|
||||
|
@ -1249,7 +1272,7 @@ def extend_search_term(searchterm,
|
|||
|
||||
|
||||
def render_adv_search_results(term, offset=None, order=None, limit=None):
|
||||
order = order or [db.Books.sort]
|
||||
sort = order[0] or [db.Books.sort]
|
||||
pagination = None
|
||||
|
||||
cc = get_cc_columns(filter_config_custom_read=True)
|
||||
|
@ -1347,7 +1370,7 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
|
|||
log.debug_or_exception(ex)
|
||||
flash(_("Error on search for custom columns, please restart Calibre-Web"), category="error")
|
||||
|
||||
q = q.order_by(*order).all()
|
||||
q = q.order_by(*sort).all()
|
||||
flask_session['query'] = json.dumps(term)
|
||||
ub.store_ids(q)
|
||||
result_count = len(q)
|
||||
|
@ -1363,7 +1386,8 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
|
|||
pagination=pagination,
|
||||
entries=q[offset:limit_all],
|
||||
result_count=result_count,
|
||||
title=_(u"Advanced Search"), page="advsearch")
|
||||
title=_(u"Advanced Search"), page="advsearch",
|
||||
order=order[1])
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@ rarfile>=2.7
|
|||
scholarly>=1.2.0, <1.3
|
||||
|
||||
# other
|
||||
natsort>=2.2.0,<7.2.0
|
||||
comicapi>= 2.2.0,<2.3.0
|
||||
natsort>=2.2.0,<8.1.0
|
||||
comicapi>=2.2.0,<2.3.0
|
||||
|
||||
#Kobo integration
|
||||
jsonschema>=3.2.0,<3.3.0
|
||||
|
|
Loading…
Reference in New Issue
Block a user