Commit 70da46b0 authored by Ozzieisaacs's avatar Ozzieisaacs

Merge branch 'master' into Develop

parents 1e03a2ae 32b7b392
...@@ -54,7 +54,7 @@ Optionally, to enable on-the-fly conversion from one ebook format to another whe ...@@ -54,7 +54,7 @@ Optionally, to enable on-the-fly conversion from one ebook format to another whe
[Download and install](https://calibre-ebook.com/download) the Calibre desktop program for your platform and enter the folder including program name (normally /opt/calibre/ebook-convert, or C:\Program Files\calibre\ebook-convert.exe) in the field "calibre's converter tool" on the setup page. [Download and install](https://calibre-ebook.com/download) the Calibre desktop program for your platform and enter the folder including program name (normally /opt/calibre/ebook-convert, or C:\Program Files\calibre\ebook-convert.exe) in the field "calibre's converter tool" on the setup page.
[Download](https://github.com/geek1011/kepubify/releases/tag/v3.1.2) Kepubify tool for your platform and place the binary starting with `kepubify` in Linux: `\opt\kepubify` Windows: `C:\Program Files\kepubify`. [Download](https://github.com/pgaskin/kepubify/releases/latest) Kepubify tool for your platform and place the binary starting with `kepubify` in Linux: `\opt\kepubify` Windows: `C:\Program Files\kepubify`.
## Docker Images ## Docker Images
......
...@@ -82,6 +82,12 @@ _VERSIONS = OrderedDict( ...@@ -82,6 +82,12 @@ _VERSIONS = OrderedDict(
_VERSIONS.update(uploader.get_versions()) _VERSIONS.update(uploader.get_versions())
def collect_stats():
_VERSIONS['ebook converter'] = _(converter.get_calibre_version())
_VERSIONS['unrar'] = _(converter.get_unrar_version())
_VERSIONS['kepubify'] = _(converter.get_kepubify_version())
return _VERSIONS
@about.route("/stats") @about.route("/stats")
@flask_login.login_required @flask_login.login_required
def stats(): def stats():
...@@ -89,8 +95,7 @@ def stats(): ...@@ -89,8 +95,7 @@ def stats():
authors = calibre_db.session.query(db.Authors).count() authors = calibre_db.session.query(db.Authors).count()
categorys = calibre_db.session.query(db.Tags).count() categorys = calibre_db.session.query(db.Tags).count()
series = calibre_db.session.query(db.Series).count() series = calibre_db.session.query(db.Series).count()
_VERSIONS['ebook converter'] = _(converter.get_calibre_version()) return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=collect_stats(),
_VERSIONS['unrar'] = _(converter.get_unrar_version())
_VERSIONS['kepubify'] = _(converter.get_kepubify_version())
return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=_VERSIONS,
categorycounter=categorys, seriecounter=series, title=_(u"Statistics"), page="stat") categorycounter=categorys, seriecounter=series, title=_(u"Statistics"), page="stat")
...@@ -41,7 +41,8 @@ from . import constants, logger, helper, services ...@@ -41,7 +41,8 @@ from . import constants, logger, helper, services
from . import db, calibre_db, ub, web_server, get_locale, config, updater_thread, babel, gdriveutils from . import db, calibre_db, ub, web_server, get_locale, config, updater_thread, babel, gdriveutils
from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash
from .gdriveutils import is_gdrive_ready, gdrive_support from .gdriveutils import is_gdrive_ready, gdrive_support
from .web import admin_required, render_title_template, before_request, unconfigured, login_required_if_no_ano from .web import admin_required, render_title_template, before_request, unconfigured
from . import debug_info
log = logger.create() log = logger.create()
...@@ -131,8 +132,9 @@ def admin(): ...@@ -131,8 +132,9 @@ def admin():
allUser = ub.session.query(ub.User).all() allUser = ub.session.query(ub.User).all()
email_settings = config.get_mail_settings() email_settings = config.get_mail_settings()
kobo_support = feature_support['kobo'] and config.config_kobo_sync
return render_title_template("admin.html", allUser=allUser, email=email_settings, config=config, commit=commit, return render_title_template("admin.html", allUser=allUser, email=email_settings, config=config, commit=commit,
feature_support=feature_support, feature_support=feature_support, kobo_support=kobo_support,
title=_(u"Admin page"), page="admin") title=_(u"Admin page"), page="admin")
...@@ -217,7 +219,8 @@ def edit_domain(allow): ...@@ -217,7 +219,8 @@ def edit_domain(allow):
@admin_required @admin_required
def add_domain(allow): def add_domain(allow):
domain_name = request.form.to_dict()['domainname'].replace('*', '%').replace('?', '_').lower() domain_name = request.form.to_dict()['domainname'].replace('*', '%').replace('?', '_').lower()
check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name).filter(ub.Registration.allow == allow).first() check = ub.session.query(ub.Registration).filter(ub.Registration.domain == domain_name)\
.filter(ub.Registration.allow == allow).first()
if not check: if not check:
new_domain = ub.Registration(domain=domain_name, allow=allow) new_domain = ub.Registration(domain=domain_name, allow=allow)
ub.session.add(new_domain) ub.session.add(new_domain)
...@@ -547,12 +550,14 @@ def _configuration_logfile_helper(to_save, gdriveError): ...@@ -547,12 +550,14 @@ def _configuration_logfile_helper(to_save, gdriveError):
reboot_required |= _config_int(to_save, "config_log_level") reboot_required |= _config_int(to_save, "config_log_level")
reboot_required |= _config_string(to_save, "config_logfile") reboot_required |= _config_string(to_save, "config_logfile")
if not logger.is_valid_logfile(config.config_logfile): if not logger.is_valid_logfile(config.config_logfile):
return reboot_required, _configuration_result(_('Logfile Location is not Valid, Please Enter Correct Path'), gdriveError) return reboot_required, \
_configuration_result(_('Logfile Location is not Valid, Please Enter Correct Path'), gdriveError)
reboot_required |= _config_checkbox_int(to_save, "config_access_log") reboot_required |= _config_checkbox_int(to_save, "config_access_log")
reboot_required |= _config_string(to_save, "config_access_logfile") reboot_required |= _config_string(to_save, "config_access_logfile")
if not logger.is_valid_logfile(config.config_access_logfile): if not logger.is_valid_logfile(config.config_access_logfile):
return reboot_required, _configuration_result(_('Access Logfile Location is not Valid, Please Enter Correct Path'), gdriveError) return reboot_required, \
_configuration_result(_('Access Logfile Location is not Valid, Please Enter Correct Path'), gdriveError)
return reboot_required, None return reboot_required, None
def _configuration_ldap_helper(to_save, gdriveError): def _configuration_ldap_helper(to_save, gdriveError):
...@@ -584,28 +589,32 @@ def _configuration_ldap_helper(to_save, gdriveError): ...@@ -584,28 +589,32 @@ def _configuration_ldap_helper(to_save, gdriveError):
if config.config_ldap_authentication > constants.LDAP_AUTH_ANONYMOUS: if config.config_ldap_authentication > constants.LDAP_AUTH_ANONYMOUS:
if config.config_ldap_authentication > constants.LDAP_AUTH_UNAUTHENTICATE: if config.config_ldap_authentication > constants.LDAP_AUTH_UNAUTHENTICATE:
if not config.config_ldap_serv_username or not bool(config.config_ldap_serv_password): if not config.config_ldap_serv_username or not bool(config.config_ldap_serv_password):
return reboot_required, _configuration_result('Please Enter a LDAP Service Account and Password', gdriveError) return reboot_required, _configuration_result('Please Enter a LDAP Service Account and Password',
gdriveError)
else: else:
if not config.config_ldap_serv_username: if not config.config_ldap_serv_username:
return reboot_required, _configuration_result('Please Enter a LDAP Service Account', gdriveError) return reboot_required, _configuration_result('Please Enter a LDAP Service Account', gdriveError)
if config.config_ldap_group_object_filter: if config.config_ldap_group_object_filter:
if config.config_ldap_group_object_filter.count("%s") != 1: if config.config_ldap_group_object_filter.count("%s") != 1:
return reboot_required, _configuration_result(_('LDAP Group Object Filter Needs to Have One "%s" Format Identifier'), return reboot_required, \
_configuration_result(_('LDAP Group Object Filter Needs to Have One "%s" Format Identifier'),
gdriveError) gdriveError)
if config.config_ldap_group_object_filter.count("(") != config.config_ldap_group_object_filter.count(")"): if config.config_ldap_group_object_filter.count("(") != config.config_ldap_group_object_filter.count(")"):
return reboot_required, _configuration_result(_('LDAP Group Object Filter Has Unmatched Parenthesis'), return reboot_required, _configuration_result(_('LDAP Group Object Filter Has Unmatched Parenthesis'),
gdriveError) gdriveError)
if config.config_ldap_user_object.count("%s") != 1: if config.config_ldap_user_object.count("%s") != 1:
return reboot_required, _configuration_result(_('LDAP User Object Filter needs to Have One "%s" Format Identifier'), return reboot_required, \
_configuration_result(_('LDAP User Object Filter needs to Have One "%s" Format Identifier'),
gdriveError) gdriveError)
if config.config_ldap_user_object.count("(") != config.config_ldap_user_object.count(")"): if config.config_ldap_user_object.count("(") != config.config_ldap_user_object.count(")"):
return reboot_required, _configuration_result(_('LDAP User Object Filter Has Unmatched Parenthesis'), return reboot_required, _configuration_result(_('LDAP User Object Filter Has Unmatched Parenthesis'),
gdriveError) gdriveError)
if config.config_ldap_cert_path and not os.path.isfile(config.config_ldap_cert_path): if config.config_ldap_cert_path and not os.path.isfile(config.config_ldap_cert_path):
return reboot_required, _configuration_result(_('LDAP Certificate Location is not Valid, Please Enter Correct Path'), return reboot_required, \
_configuration_result(_('LDAP Certificate Location is not Valid, Please Enter Correct Path'),
gdriveError) gdriveError)
return reboot_required, None return reboot_required, None
...@@ -616,7 +625,10 @@ def _configuration_update_helper(): ...@@ -616,7 +625,10 @@ def _configuration_update_helper():
to_save = request.form.to_dict() to_save = request.form.to_dict()
gdriveError = None gdriveError = None
to_save['config_calibre_dir'] = re.sub('[\\/]metadata\.db$', '', to_save['config_calibre_dir'], flags=re.IGNORECASE) to_save['config_calibre_dir'] = re.sub('[\\/]metadata\.db$',
'',
to_save['config_calibre_dir'],
flags=re.IGNORECASE)
try: try:
db_change |= _config_string(to_save, "config_calibre_dir") db_change |= _config_string(to_save, "config_calibre_dir")
...@@ -1027,6 +1039,27 @@ def send_logfile(logtype): ...@@ -1027,6 +1039,27 @@ def send_logfile(logtype):
else: else:
return "" return ""
@admi.route("/admin/logdownload/<int:logtype>")
@login_required
@admin_required
def download_log(logtype):
if logtype == 0:
file_name = logger.get_logfile(config.config_logfile)
elif logtype == 1:
file_name = logger.get_accesslogfile(config.config_access_logfile)
else:
abort(404)
if logger.is_valid_logfile(file_name):
return debug_info.assemble_logfiles(file_name)
abort(404)
@admi.route("/admin/debug")
@login_required
@admin_required
def download_debug():
return debug_info.send_debug()
@admi.route("/get_update_status", methods=['GET']) @admi.route("/get_update_status", methods=['GET'])
@login_required @login_required
......
...@@ -62,14 +62,12 @@ def _cover_processing(tmp_file_name, img, extension): ...@@ -62,14 +62,12 @@ def _cover_processing(tmp_file_name, img, extension):
im.save(tmp_bytesio, format='JPEG') im.save(tmp_bytesio, format='JPEG')
img = tmp_bytesio.getvalue() img = tmp_bytesio.getvalue()
prefix = os.path.dirname(tmp_file_name) if not img:
if img: return None
tmp_cover_name = prefix + '/cover.jpg'
image = open(tmp_cover_name, 'wb') tmp_cover_name = os.path.join(os.path.dirname(tmp_file_name), 'cover.jpg')
image.write(img) with open(tmp_cover_name, 'wb') as f:
image.close() f.write(img)
else:
tmp_cover_name = None
return tmp_cover_name return tmp_cover_name
......
# -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2012-2019 cervinko, idalin, SiphonSquirrel, ouzklcn, akushsky,
# OzzieIsaacs, bodybybuddha, jkrehm, matthazinski, janeczku
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import shutil
import glob
import zipfile
import json
import io
import os
from flask import send_file
from . import logger, config
from .about import collect_stats
log = logger.create()
def assemble_logfiles(file_name):
log_list = glob.glob(file_name + '*')
wfd = io.StringIO()
for f in log_list:
with open(f, 'r') as fd:
shutil.copyfileobj(fd, wfd)
return send_file(wfd,
as_attachment=True,
attachment_filename=os.path.basename(file_name))
def send_debug():
file_list = glob.glob(logger.get_logfile(config.config_logfile) + '*')
file_list.extend(glob.glob(logger.get_accesslogfile(config.config_access_logfile) + '*'))
memory_zip = io.BytesIO()
with zipfile.ZipFile(memory_zip, 'w', compression=zipfile.ZIP_DEFLATED) as zf:
zf.writestr('libs.txt', json.dumps(collect_stats()))
for fp in file_list:
zf.write(fp, os.path.basename(fp))
memory_zip.seek(0)
return send_file(memory_zip,
as_attachment=True,
attachment_filename="Calibre-Web-debug-pack.zip")
...@@ -405,7 +405,7 @@ def edit_book_languages(languages, book, upload=False): ...@@ -405,7 +405,7 @@ def edit_book_languages(languages, book, upload=False):
# the book it's language is set to the filter language # the book it's language is set to the filter language
if input_l[0] != current_user.filter_language() and current_user.filter_language() != "all": if input_l[0] != current_user.filter_language() and current_user.filter_language() != "all":
input_l[0] = calibre_db.session.query(db.Languages). \ input_l[0] = calibre_db.session.query(db.Languages). \
filter(db.Languages.lang_code == current_user.filter_language()).first() filter(db.Languages.lang_code == current_user.filter_language()).first().lang_code
# Remove duplicates # Remove duplicates
input_l = helper.uniq(input_l) input_l = helper.uniq(input_l)
return modify_database_object(input_l, book.languages, db.Languages, calibre_db.session, 'languages') return modify_database_object(input_l, book.languages, db.Languages, calibre_db.session, 'languages')
......
...@@ -66,11 +66,11 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension): ...@@ -66,11 +66,11 @@ def get_epub_info(tmp_file_path, original_file_name, original_file_extension):
tmp = p.xpath('dc:%s/text()' % s, namespaces=ns) tmp = p.xpath('dc:%s/text()' % s, namespaces=ns)
if len(tmp) > 0: if len(tmp) > 0:
if s == 'creator': if s == 'creator':
epub_metadata[s] = ' & '.join(split_authors(p.xpath('dc:%s/text()' % s, namespaces=ns))) epub_metadata[s] = ' & '.join(split_authors(tmp))
elif s == 'subject': elif s == 'subject':
epub_metadata[s] = ', '.join(p.xpath('dc:%s/text()' % s, namespaces=ns)) epub_metadata[s] = ', '.join(tmp)
else: else:
epub_metadata[s] = p.xpath('dc:%s/text()' % s, namespaces=ns)[0] epub_metadata[s] = tmp[0]
else: else:
epub_metadata[s] = u'Unknown' epub_metadata[s] = u'Unknown'
......
...@@ -24,7 +24,10 @@ import io ...@@ -24,7 +24,10 @@ import io
import mimetypes import mimetypes
import re import re
import shutil import shutil
import glob
import time import time
import zipfile
import json
import unicodedata import unicodedata
from datetime import datetime, timedelta from datetime import datetime, timedelta
from tempfile import gettempdir from tempfile import gettempdir
...@@ -32,14 +35,12 @@ from tempfile import gettempdir ...@@ -32,14 +35,12 @@ from tempfile import gettempdir
import requests import requests
from babel.dates import format_datetime from babel.dates import format_datetime
from babel.units import format_unit from babel.units import format_unit
from flask import send_from_directory, make_response, redirect, abort, url_for from flask import send_from_directory, make_response, redirect, abort, url_for, send_file
from flask_babel import gettext as _ from flask_babel import gettext as _
from flask_login import current_user from flask_login import current_user
from sqlalchemy.sql.expression import true, false, and_, text from sqlalchemy.sql.expression import true, false, and_, text
from werkzeug.datastructures import Headers from werkzeug.datastructures import Headers
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
from . import calibre_db
from .tasks.convert import TaskConvert
try: try:
from urllib.parse import quote from urllib.parse import quote
...@@ -59,6 +60,8 @@ try: ...@@ -59,6 +60,8 @@ try:
except ImportError: except ImportError:
use_PIL = False use_PIL = False
from . import calibre_db
from .tasks.convert import TaskConvert
from . import logger, config, get_locale, db, ub from . import logger, config, get_locale, db, ub
from . import gdriveutils as gd from . import gdriveutils as gd
from .constants import STATIC_DIR as _STATIC_DIR from .constants import STATIC_DIR as _STATIC_DIR
...@@ -824,3 +827,4 @@ def get_download_link(book_id, book_format, client): ...@@ -824,3 +827,4 @@ def get_download_link(book_id, book_format, client):
return do_download_file(book, book_format, client, data1, headers) return do_download_file(book, book_format, client, data1, headers)
else: else:
abort(404) abort(404)
...@@ -119,7 +119,11 @@ def redirect_or_proxy_request(): ...@@ -119,7 +119,11 @@ def redirect_or_proxy_request():
def convert_to_kobo_timestamp_string(timestamp): def convert_to_kobo_timestamp_string(timestamp):
return timestamp.strftime("%Y-%m-%dT%H:%M:%SZ") try:
return timestamp.strftime("%Y-%m-%dT%H:%M:%SZ")
except AttributeError as exc:
log.debug("Timestamp not valid: {}".format(exc))
return datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
@kobo.route("/v1/library/sync") @kobo.route("/v1/library/sync")
......
...@@ -637,18 +637,18 @@ div[aria-label="Edit/Delete book"] > .btn > span:hover { ...@@ -637,18 +637,18 @@ div[aria-label="Edit/Delete book"] > .btn > span:hover {
color: var(--color-primary) color: var(--color-primary)
} }
.book { /* .book {
width: 225px; width: 225px;
max-width: 225px; max-width: 225px;
position: relative !important; position: relative !important;
left: auto !important; left: auto !important;
top: auto !important; top: auto !important;
-webkit-transform: none !important; -webkit-transform: none !important;
-ms-transform: none !important; -ms-transform: none !important;
transform: none !important; transform: none !important;
min-width: 225px; min-width: 225px;
display: block display: block
} } */
#infscr-loading img, body > div.container-fluid > div > div.col-sm-10 > div.discover > div.isotope:after, body > div.container-fluid > div > div.col-sm-10 > div.discover > div.isotope:before { #infscr-loading img, body > div.container-fluid > div > div.col-sm-10 > div.discover > div.isotope:after, body > div.container-fluid > div > div.col-sm-10 > div.discover > div.isotope:before {
display: none display: none
......
...@@ -253,7 +253,7 @@ $(function () { ...@@ -253,7 +253,7 @@ $(function () {
} }
function dbSearchBook (title) { function dbSearchBook (title) {
var apikey = "0df993c66c0c636e29ecbb5344252a4a"; var apikey = "054022eaeae0b00e0fc068c0c0a2102a";
$.ajax({ $.ajax({
url: douban + dbSearch + "?apikey=" + apikey + "&q=" + title + "&fields=all&count=10", url: douban + dbSearch + "?apikey=" + apikey + "&q=" + title + "&fields=all&count=10",
type: "GET", type: "GET",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -172,20 +172,36 @@ $(function() { ...@@ -172,20 +172,36 @@ $(function() {
layoutMode : "fitColumns" layoutMode : "fitColumns"
}); });
if ($(".load-more").length && $(".next").length) {
var $loadMore = $(".load-more .row").infiniteScroll({ var $loadMore = $(".load-more .row").infiniteScroll({
debug: false, debug: false,
// selector for the paged navigation (it will be hidden) // selector for the paged navigation (it will be hidden)
path : ".next", path : ".next",
// selector for the NEXT link (to page 2) // selector for the NEXT link (to page 2)
append : ".load-more .book" append : ".load-more .book"
//animate : true, # ToDo: Reenable function //animate : true, # ToDo: Reenable function
//extraScrollPx: 300 //extraScrollPx: 300
}); });
$loadMore.on( "append.infiniteScroll", function( event, response, path, data ) { $loadMore.on( "append.infiniteScroll", function( event, response, path, data ) {
$(".pagination").addClass("hidden"); if ($("body").hasClass("blur")) {
$(".load-more .row").isotope( "appended", $(data), null ); $(".pagination").addClass("hidden").html(() => $(response).find(".pagination").html());
}); }
$(".load-more .row").isotope( "appended", $(data), null );
});
// fix for infinite scroll on CaliBlur Theme (#981)
if ($("body").hasClass("blur")) {
$(".col-sm-10").bind("scroll", function () {
if (
$(this).scrollTop() + $(this).innerHeight() >=
$(this)[0].scrollHeight
) {
$loadMore.infiniteScroll("loadNextPage");
window.history.replaceState({}, null, $loadMore.infiniteScroll("getAbsolutePath"));
}
});
}
}
$("#restart").click(function() { $("#restart").click(function() {
$.ajax({ $.ajax({
......
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
<div class="col-xs-6 col-sm-6">{{_('Port')}}</div> <div class="col-xs-6 col-sm-6">{{_('Port')}}</div>
<div class="col-xs-6 col-sm-6">{{config.config_port}}</div> <div class="col-xs-6 col-sm-6">{{config.config_port}}</div>
</div> </div>
{% if feature_support['kobo'] and config.config_port != config.config_external_port %} {% if kobo_support and config.config_port != config.config_external_port %}
<div class="row"> <div class="row">
<div class="col-xs-6 col-sm-6">{{_('External Port')}}</div> <div class="col-xs-6 col-sm-6">{{_('External Port')}}</div>
<div class="col-xs-6 col-sm-6">{{config.config_external_port}}</div> <div class="col-xs-6 col-sm-6">{{config.config_external_port}}</div>
...@@ -132,14 +132,16 @@ ...@@ -132,14 +132,16 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row form-group">
<div class="col"> <h2>{{_('Administration')}}</h2>
<h2>{{_('Administration')}}</h2> <div class="btn btn-default"><a id="debug" href="{{url_for('admin.download_debug')}}">{{_('Download Debug Package')}}</a></div>
<div class="btn btn-default"><a id="logfile" href="{{url_for('admin.view_logfile')}}">{{_('View Logs')}}</a></div> <div class="btn btn-default"><a id="logfile" href="{{url_for('admin.view_logfile')}}">{{_('View Logs')}}</a></div>
</div>
<div class="row form-group">
<div class="btn btn-default" id="restart_database" data-toggle="modal" data-target="#StatusDialog">{{_('Reconnect Calibre Database')}}</div> <div class="btn btn-default" id="restart_database" data-toggle="modal" data-target="#StatusDialog">{{_('Reconnect Calibre Database')}}</div>
<div class="btn btn-default" id="admin_restart" data-toggle="modal" data-target="#RestartDialog">{{_('Restart')}}</div> <div class="btn btn-default" id="admin_restart" data-toggle="modal" data-target="#RestartDialog">{{_('Restart')}}</div>
<div class="btn btn-default" id="admin_stop" data-toggle="modal" data-target="#ShutdownDialog">{{_('Shutdown')}}</div> <div class="btn btn-default" id="admin_stop" data-toggle="modal" data-target="#ShutdownDialog">{{_('Shutdown')}}</div>
</div>
</div> </div>
<div class="row"> <div class="row">
......
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for format in entry.data %} {% for format in entry.data %}
{% if format.format|lower == 'mp3' %} {% if format.format|lower in g.constants.EXTENSIONS_AUDIO %}
<span class="glyphicon glyphicon-music"></span> <span class="glyphicon glyphicon-music"></span>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
......
...@@ -104,7 +104,7 @@ ...@@ -104,7 +104,7 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for format in entry.data %} {% for format in entry.data %}
{% if format.format|lower == 'mp3' %} {% if format.format|lower in g.constants.EXTENSIONS_AUDIO %}
<span class="glyphicon glyphicon-music"></span> <span class="glyphicon glyphicon-music"></span>
{% endif %} {% endif %}
{%endfor%} {%endfor%}
......
...@@ -166,7 +166,7 @@ ...@@ -166,7 +166,7 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if pagination.has_next %} {% if pagination.has_next %}
<li class="page-item page-next"><a class="page-link" aria-label="next page" href="{{ (pagination.page + 1)|url_for_other_page <li class="page-item page-next"><a class="page-link next" aria-label="next page" href="{{ (pagination.page + 1)|url_for_other_page
}}">{{_('Next')}} &raquo;</a></li> }}">{{_('Next')}} &raquo;</a></li>
{% endif %} {% endif %}
</div> </div>
......
...@@ -12,7 +12,18 @@ ...@@ -12,7 +12,18 @@
<label for="log0">{{_('Show Access Log: ')}}</label>{{logfiles[1]}}</div> <label for="log0">{{_('Show Access Log: ')}}</label>{{logfiles[1]}}</div>
{% endif %} {% endif %}
</div> </div>
<div class="row">
<div class="col-xs-6 col-sm-7">
{% if log_enable %}
<div class="btn btn-default"><a id="log_file" href="{{url_for('admin.download_log', logtype=0)}}">{{_('Download Calibre-Web Log')}}</a></div>
{% endif %}
{% if accesslog_enable %}
<div class="btn btn-default"><a id="log_file" href="{{url_for('admin.download_log', logtype=1)}}">{{_('Download Access Log')}}</a></div>
{% endif %}
</div>
</div>
<div id="renderer" class="log"></div> <div id="renderer" class="log"></div>
{% endblock %} {% endblock %}
{% block js %} {% block js %}
<script src="{{ url_for('static', filename='js/logviewer.js') }}"></script> <script src="{{ url_for('static', filename='js/logviewer.js') }}"></script>
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for format in entry.data %} {% for format in entry.data %}
{% if format.format|lower == 'mp3' %} {% if format.format|lower in g.constants.EXTENSIONS_AUDIO %}
<span class="glyphicon glyphicon-music"></span> <span class="glyphicon glyphicon-music"></span>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -227,7 +227,7 @@ class Updater(threading.Thread): ...@@ -227,7 +227,7 @@ class Updater(threading.Thread):
os.sep + 'vendor', os.sep + 'calibre-web.log', os.sep + '.git', os.sep + 'client_secrets.json', os.sep + 'vendor', os.sep + 'calibre-web.log', os.sep + '.git', os.sep + 'client_secrets.json',
os.sep + 'gdrive_credentials', os.sep + 'settings.yaml', os.sep + 'venv', os.sep + 'virtualenv', os.sep + 'gdrive_credentials', os.sep + 'settings.yaml', os.sep + 'venv', os.sep + 'virtualenv',
os.sep + 'access.log', os.sep + 'access.log1', os.sep + 'access.log2', os.sep + 'access.log', os.sep + 'access.log1', os.sep + 'access.log2',
os.sep + '.calibre-web.log.swp' os.sep + '.calibre-web.log.swp', os.sep + '_sqlite3.so'
) )
additional_path = self.is_venv() additional_path = self.is_venv()
if additional_path: if additional_path:
......
...@@ -293,6 +293,7 @@ def edit_required(f): ...@@ -293,6 +293,7 @@ def edit_required(f):
def before_request(): def before_request():
if current_user.is_authenticated: if current_user.is_authenticated:
confirm_login() confirm_login()
g.constants = constants
g.user = current_user g.user = current_user
g.allow_registration = config.config_public_reg g.allow_registration = config.config_public_reg
g.allow_anonymous = config.config_anonbrowse g.allow_anonymous = config.config_anonbrowse
...@@ -314,7 +315,7 @@ def import_ldap_users(): ...@@ -314,7 +315,7 @@ def import_ldap_users():
try: try:
new_users = services.ldap.get_group_members(config.config_ldap_group_name) new_users = services.ldap.get_group_members(config.config_ldap_group_name)
except (services.ldap.LDAPException, TypeError, AttributeError, KeyError) as e: except (services.ldap.LDAPException, TypeError, AttributeError, KeyError) as e:
log.debug(e) log.exception(e)
showtext['text'] = _(u'Error: %(ldaperror)s', ldaperror=e) showtext['text'] = _(u'Error: %(ldaperror)s', ldaperror=e)
return json.dumps(showtext) return json.dumps(showtext)
if not new_users: if not new_users:
......
This diff is collapsed.
...@@ -8,8 +8,8 @@ Flask>=1.0.2,<1.2.0 ...@@ -8,8 +8,8 @@ Flask>=1.0.2,<1.2.0
iso-639>=0.4.5,<0.5.0 iso-639>=0.4.5,<0.5.0
PyPDF2==1.26.0,<1.27.0 PyPDF2==1.26.0,<1.27.0
pytz>=2016.10 pytz>=2016.10
requests>=2.11.1,<2.24.0 requests>=2.11.1,<2.26.0
SQLAlchemy>=1.3.0,<1.4.0 SQLAlchemy>=1.3.0,<1.4.0
tornado>=4.1,<6.1 tornado>=4.1,<6.2
Wand>=0.4.4,<0.6.0 Wand>=0.4.4,<0.6.0
unidecode>=0.04.19,<1.2.0 unidecode>=0.04.19,<1.2.0
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment