mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-26 01:50:31 +00:00
Added function to download debug information
This commit is contained in:
parent
4081895a78
commit
32b7b39223
13
cps/about.py
13
cps/about.py
@ -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():
|
|||||||
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")
|
||||||
|
|
||||||
|
|
||||||
|
50
cps/admin.py
50
cps/admin.py
@ -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()
|
||||||
|
|
||||||
@ -218,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)
|
||||||
@ -548,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):
|
||||||
@ -585,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
|
||||||
|
|
||||||
@ -617,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")
|
||||||
|
|
||||||
@ -1028,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
|
||||||
|
55
cps/debug_info.py
Normal file
55
cps/debug_info.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# -*- 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")
|
@ -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
|
|||||||
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:
|
|||||||
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):
|
|||||||
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)
|
||||||
|
|
||||||
|
@ -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">
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user