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())
|
||||
|
||||
|
||||
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")
|
||||
@flask_login.login_required
|
||||
def stats():
|
||||
@ -89,8 +95,7 @@ def stats():
|
||||
authors = calibre_db.session.query(db.Authors).count()
|
||||
categorys = calibre_db.session.query(db.Tags).count()
|
||||
series = calibre_db.session.query(db.Series).count()
|
||||
_VERSIONS['ebook converter'] = _(converter.get_calibre_version())
|
||||
_VERSIONS['unrar'] = _(converter.get_unrar_version())
|
||||
_VERSIONS['kepubify'] = _(converter.get_kepubify_version())
|
||||
return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=_VERSIONS,
|
||||
return render_title_template('stats.html', bookcounter=counter, authorcounter=authors, versions=collect_stats(),
|
||||
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 .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash
|
||||
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()
|
||||
|
||||
@ -218,7 +219,8 @@ def edit_domain(allow):
|
||||
@admin_required
|
||||
def add_domain(allow):
|
||||
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:
|
||||
new_domain = ub.Registration(domain=domain_name, allow=allow)
|
||||
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_string(to_save, "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_string(to_save, "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
|
||||
|
||||
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_UNAUTHENTICATE:
|
||||
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:
|
||||
if not config.config_ldap_serv_username:
|
||||
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.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)
|
||||
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'),
|
||||
gdriveError)
|
||||
|
||||
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)
|
||||
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'),
|
||||
gdriveError)
|
||||
|
||||
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)
|
||||
return reboot_required, None
|
||||
|
||||
@ -617,7 +625,10 @@ def _configuration_update_helper():
|
||||
to_save = request.form.to_dict()
|
||||
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:
|
||||
db_change |= _config_string(to_save, "config_calibre_dir")
|
||||
|
||||
@ -1028,6 +1039,27 @@ def send_logfile(logtype):
|
||||
else:
|
||||
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'])
|
||||
@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 re
|
||||
import shutil
|
||||
import glob
|
||||
import time
|
||||
import zipfile
|
||||
import json
|
||||
import unicodedata
|
||||
from datetime import datetime, timedelta
|
||||
from tempfile import gettempdir
|
||||
@ -32,14 +35,12 @@ from tempfile import gettempdir
|
||||
import requests
|
||||
from babel.dates import format_datetime
|
||||
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_login import current_user
|
||||
from sqlalchemy.sql.expression import true, false, and_, text
|
||||
from werkzeug.datastructures import Headers
|
||||
from werkzeug.security import generate_password_hash
|
||||
from . import calibre_db
|
||||
from .tasks.convert import TaskConvert
|
||||
|
||||
try:
|
||||
from urllib.parse import quote
|
||||
@ -59,6 +60,8 @@ try:
|
||||
except ImportError:
|
||||
use_PIL = False
|
||||
|
||||
from . import calibre_db
|
||||
from .tasks.convert import TaskConvert
|
||||
from . import logger, config, get_locale, db, ub
|
||||
from . import gdriveutils as gd
|
||||
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)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
@ -132,14 +132,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h2>{{_('Administration')}}</h2>
|
||||
<div class="row form-group">
|
||||
<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>
|
||||
<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="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>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
@ -12,7 +12,18 @@
|
||||
<label for="log0">{{_('Show Access Log: ')}}</label>{{logfiles[1]}}</div>
|
||||
{% endif %}
|
||||
</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>
|
||||
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<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
|
||||
PyPDF2==1.26.0,<1.27.0
|
||||
pytz>=2016.10
|
||||
requests>=2.11.1,<2.24.0
|
||||
requests>=2.11.1,<2.26.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
|
||||
unidecode>=0.04.19,<1.2.0
|
||||
|
Loading…
Reference in New Issue
Block a user