Improvements for logfile viewer

Fix for tornado-server with deactivated accesslog doesn't log to normal log anymore
Merge from master for unique user ids, get_metadata,
fix Goodreads integration
Update Translation (merge NL, update DE)
pull/958/head
Ozzieisaacs 6 years ago
parent cc8a431532
commit 32af660f86

@ -62,12 +62,6 @@ except ImportError:
# except ImportError: # except ImportError:
# feature_support['rar'] = False # feature_support['rar'] = False
'''try:
import ldap
feature_support['ldap'] = True
except ImportError:
feature_support['ldap'] = False'''
try: try:
from oauth_bb import oauth_check from oauth_bb import oauth_check
feature_support['oauth'] = True feature_support['oauth'] = True
@ -399,14 +393,14 @@ def configuration_helper(origin):
flash(_(u'Please enter a LDAP provider, port, DN and user object identifier'), category="error") flash(_(u'Please enter a LDAP provider, port, DN and user object identifier'), category="error")
return render_title_template("config_edit.html", content=config, origin=origin, return render_title_template("config_edit.html", content=config, origin=origin,
gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError, gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
goodreads=goodreads_support, title=_(u"Basic Configuration"), feature_support=feature_support, title=_(u"Basic Configuration"),
page="config") page="config")
elif not to_save["config_ldap_serv_username"] or not to_save["config_ldap_serv_password"]: elif not to_save["config_ldap_serv_username"] or not to_save["config_ldap_serv_password"]:
ub.session.commit() ub.session.commit()
flash(_(u'Please enter a LDAP service account and password'), category="error") flash(_(u'Please enter a LDAP service account and password'), category="error")
return render_title_template("config_edit.html", content=config, origin=origin, return render_title_template("config_edit.html", content=config, origin=origin,
gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError, gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
goodreads=goodreads_support, title=_(u"Basic Configuration"), feature_support=feature_support, title=_(u"Basic Configuration"),
page="config") page="config")
else: else:
content.config_use_ldap = 1 content.config_use_ldap = 1
@ -439,7 +433,7 @@ def configuration_helper(origin):
flash(_(u'Certfile location is not valid, please enter correct path'), category="error") flash(_(u'Certfile location is not valid, please enter correct path'), category="error")
return render_title_template("config_edit.html", content=config, origin=origin, return render_title_template("config_edit.html", content=config, origin=origin,
gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError, gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
goodreads=goodreads_support, title=_(u"Basic Configuration"), feature_support=feature_support, title=_(u"Basic Configuration"),
page="config") page="config")
# Remote login configuration # Remote login configuration
@ -576,9 +570,6 @@ def new_user():
to_save = request.form.to_dict() to_save = request.form.to_dict()
content.default_language = to_save["default_language"] content.default_language = to_save["default_language"]
content.mature_content = "Show_mature_content" in to_save content.mature_content = "Show_mature_content" in to_save
dat = datetime.strptime("1.1.2019", "%d.%m.%Y")
content.id = int(time.time()*100)
# val= int(uuid.uuid4())
if "locale" in to_save: if "locale" in to_save:
content.locale = to_save["locale"] content.locale = to_save["locale"]
@ -800,19 +791,27 @@ def reset_password(user_id):
@login_required @login_required
@admin_required @admin_required
def view_logfile(): def view_logfile():
perpage_p = {0:"30",1:"40",2:"100"} logfiles = {}
for key, value in perpage_p.items(): logfiles[0] = logger.get_logfile(config.config_logfile)
print(key) logfiles[1] = logger.get_accesslogfile(config.config_access_logfile)
print(value) return render_title_template("logviewer.html",title=_(u"Logfile viewer"), accesslog_enable=config.config_access_log,
return render_title_template("logviewer.html",title=_(u"Logfile viewer"), perpage_p=perpage_p, perpage = 30, logfiles=logfiles, page="logfile")
page="logfile")
@admi.route("/ajax/accesslog") @admi.route("/ajax/log/<int:logtype>")
@login_required @login_required
@admin_required @admin_required
def send_logfile(): def send_logfile(logtype):
return send_from_directory(constants.BASE_DIR,"access.log") if logtype == 1:
logfile = logger.get_accesslogfile(config.config_access_logfile)
return send_from_directory(os.path.dirname(logfile),
os.path.basename(logfile))
if logtype == 0:
logfile = logger.get_logfile(config.config_logfile)
return send_from_directory(os.path.dirname(logfile),
os.path.basename(logfile))
else:
return ""
@admi.route("/get_update_status", methods=['GET']) @admi.route("/get_update_status", methods=['GET'])

@ -82,6 +82,14 @@ def _absolute_log_file(log_file, default_log_file):
return default_log_file return default_log_file
def get_logfile(log_file):
return _absolute_log_file(log_file, DEFAULT_LOG_FILE)
def get_accesslogfile(log_file):
return _absolute_log_file(log_file, DEFAULT_ACCESS_LOG)
def setup(log_file, log_level=None): def setup(log_file, log_level=None):
''' '''
Configure the logging output. Configure the logging output.

@ -88,7 +88,7 @@ def register_user_with_oauth(user=None):
if len(all_oauth.keys()) == 0: if len(all_oauth.keys()) == 0:
return return
if user is None: if user is None:
flash(_(u"Register with %s" % ", ".join(list(all_oauth.values()))), category="success") flash(_(u"Register with %(provider)s", provider=", ".join(list(all_oauth.values()))), category="success")
else: else:
for oauth in all_oauth.keys(): for oauth in all_oauth.keys():
# Find this OAuth token in the database, or create it # Find this OAuth token in the database, or create it

@ -70,6 +70,9 @@ class WebServer:
log_name = "gevent.access" if _GEVENT else "tornado.access" log_name = "gevent.access" if _GEVENT else "tornado.access"
formatter = logger.ACCESS_FORMATTER_GEVENT if _GEVENT else logger.ACCESS_FORMATTER_TORNADO formatter = logger.ACCESS_FORMATTER_GEVENT if _GEVENT else logger.ACCESS_FORMATTER_TORNADO
self.access_logger = logger.create_access_log(config.config_access_logfile, log_name, formatter) self.access_logger = logger.create_access_log(config.config_access_logfile, log_name, formatter)
else:
if not _GEVENT:
logger.get('tornado.access').disabled = True
certfile_path = config.get_config_certfile() certfile_path = config.get_config_certfile()
keyfile_path = config.get_config_keyfile() keyfile_path = config.get_config_keyfile()

@ -145,3 +145,14 @@ input.pill:not(:checked) + label .glyphicon {
max-height:300px; max-height:300px;
overflow-y: auto; overflow-y: auto;
} }
div.log {
font-family: Courier New;
font-size: 12px;
box-sizing: border-box;
height: 700px;
overflow-y: scroll;
border: 1px solid #ddd;
white-space: nowrap;
padding: 0.5em;
}

@ -20,16 +20,16 @@
* Douban Books api document: https://developers.douban.com/wiki/?title=book_v2 (Chinese Only) * Douban Books api document: https://developers.douban.com/wiki/?title=book_v2 (Chinese Only)
*/ */
/* global _, i18nMsg, tinymce */ /* global _, i18nMsg, tinymce */
var dbResults = []; // var dbResults = [];
var ggResults = []; var ggResults = [];
$(function () { $(function () {
var msg = i18nMsg; var msg = i18nMsg;
/*var douban = "https://api.douban.com"; /*var douban = "https://api.douban.com";
var dbSearch = "/v2/book/search";*/ var dbSearch = "/v2/book/search";*/
var dbDone = true; // var dbDone = true;
var google = "https://www.googleapis.com/"; var google = "https://www.googleapis.com";
var ggSearch = "/books/v1/volumes"; var ggSearch = "/books/v1/volumes";
var ggDone = false; var ggDone = false;
@ -56,11 +56,9 @@ $(function () {
if (showFlag === 1) { if (showFlag === 1) {
$("#meta-info").html("<ul id=\"book-list\" class=\"media-list\"></ul>"); $("#meta-info").html("<ul id=\"book-list\" class=\"media-list\"></ul>");
} }
if (ggDone && dbDone) { if (!ggDone) {
if (!ggResults && !dbResults) { $("#meta-info").html("<p class=\"text-danger\">" + msg.no_result + "</p>");
$("#meta-info").html("<p class=\"text-danger\">" + msg.no_result + "</p>"); return;
return;
}
} }
if (ggDone && ggResults.length > 0) { if (ggDone && ggResults.length > 0) {
ggResults.forEach(function(result) { ggResults.forEach(function(result) {
@ -137,7 +135,10 @@ $(function () {
dataType: "jsonp", dataType: "jsonp",
jsonp: "callback", jsonp: "callback",
success: function success(data) { success: function success(data) {
ggResults = data.items; if ("items" in data) {
ggResults = data.items;
ggDone = true;
}
}, },
complete: function complete() { complete: function complete() {
ggDone = true; ggDone = true;

@ -1,609 +1,74 @@
var threadregexp = /(?:^| - )(\[[^\]]*\]):/; /* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
* Copyright (C) 2018 OzzieIsaacs
var colors = ["#ffa", "#aaf", "#afa", "#aff", "#faf", "#aaa", "#fd8", "#f80", "#4df", "#4fc", "#76973c", "#7e56d8", "#99593d", "#37778a", "#4068fc"]; *
var screenlines = 1; * 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
var file = null; * the Free Software Foundation, either version 3 of the License, or
var text; * (at your option) any later version.
*
var current, nextFilterId = 1; * This program is distributed in the hope that it will be useful,
var shl = null; * but WITHOUT ANY WARRANTY; without even the implied warranty of
var hl = []; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
var groupwith = false; * GNU General Public License for more details.
var filterswitch = true; *
* You should have received a copy of the GNU General Public License
var selectedlineid = -1; * along with this program. If not, see <http://www.gnu.org/licenses/>.
var selectedthread = null; */
var reachedbottom = false;
var reachedtop = false; // Upon loading load the logfile for the first option (event log)
$(function() {
init(0);
function wheelscroll(event) });
{
renderincremental(event.deltaY); // After change the radio option load the corresponding log file
} $("#log_group input").on("change", function() {
var element = $("#log_group input[type='radio']:checked").val();
function keypress(event) init(element);
{ });
if (event.key == "PageDown") {
_render(screenlines - 1);
event.preventDefault(); // Handle reloading of the log file and display the content
} function init(logType) {
if (event.key == "PageUp") { var d = document.getElementById("renderer");
_render(-(screenlines - 1)); d.innerHTML = "loading ...";
event.preventDefault();
} /*var r = new XMLHttpRequest();
if (event.key == "Home" && event.ctrlKey) { r.open("GET", "/ajax/log/" + logType, true);
selectedlineid = 0; r.responseType = "text";
render(); r.onload = function() {
event.preventDefault(); var text;
} text = (r.responseText).split("\n");
if (event.key == "End" && event.ctrlKey) { $("#renderer").text("");
selectedlineid = text.length - 1; console.log(text.length);
render(); for (var i = 0; i < text.length; i++) {
event.preventDefault(); $("#renderer").append( "<div>" + _sanitize(text[i]) + "</div>" );
} }
if (event.key == "ArrowUp") { };
renderincremental(-1); r.send();*/
event.preventDefault(); $.ajax({
} url: "/ajax/log/" + logType,
if (event.key == "ArrowDown") { datatype: 'text',
renderincremental(1); cache: false
event.preventDefault(); })
} .done( function(data) {
} var text;
$("#renderer").text("");
function init(filename) { text = (data).split("\n");
document.addEventListener("wheel", wheelscroll, false); console.log(text.length);
document.addEventListener("keypress", keypress, false); for (var i = 0; i < text.length; i++) {
window.addEventListener("resize", resize, false); $("#renderer").append( "<div>" + _sanitize(text[i]) + "</div>" );
}
_resize(); });
}
var s = document.getElementById("search");
s.value = "";
selectfilter(0); function _sanitize(t) {
reload(filename); t = t
} .replace(/&/g, "&amp;")
.replace(/ /g, "&nbsp;")
function _resize() .replace(/</g, "&lt;")
{ .replace(/>/g, "&gt;");
var d = document.getElementById("renderer");
var t = document.getElementById("toobar"); return t;
screenlines = Math.floor((window.innerHeight - t.offsetHeight) / d.firstChild.offsetHeight) - 1;
}
function resize()
{
_resize();
repaint();
}
function reload(filename)
{
if (shl) shl.cache = {};
for (_hl of hl) _hl.cache = {};
var q = filename;
document.title = "Log: " + (q || "none loaded");
if (!q)
return;
var d = document.getElementById("renderer");
d.innerHTML = "loading " + q + "...";
var r = new XMLHttpRequest();
r.open("GET", "/ajax/accesslog", true);
r.responseType = 'text';
r.onload = function() {
console.log("prepare");
prepare(r.responseText);
if (selectedlineid > text.length) {
selectedlineid = -1;
}
console.log("render");
render();
};
r.send();
}
function _sanitize(t)
{
t = t
.replace(/&/g, "&amp;")
.replace(/ /g, "&nbsp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");
return t;
}
function _prepare(t)
{
// sanitization happens in render, since otherwise it eats enormous amount of memory.
/*
var t = t.split('\n');
for (var i in t) {
t[i] = _sanitize(t[i]);
}
return t;
*/
return /*_sanitize*/(t).split('\n');
}
function prepare(t)
{
text = _prepare(t);
}
function render()
{
_render(0, false); // completely redraws the view from the current scroll position
}
function repaint()
{
_render(0, true); // completely redraws the view, but centers the selected line
}
function renderincremental(difference)
{
_render(difference); // "scrolls" the view
}
function _render(increment, repaintonly)
{
var epoch = new Date();
var d = document.getElementById("renderer");
var filter = _gfilteron();
function process(i, append)
{
var t = _sanitize(text[i]);
var lhl = false;
function dohl(_hl)
{
if (_hl.cache[i] === false) {
// lhl is here unaffected
return t;
}
var t2 = t.replace(new RegExp("(" + _hl.text_r + ")", "g"), "<span style='background-color:" + _hl.color + ";'>$1</span>");
var affecting = (t != t2);
_hl.cache[i] = affecting;
lhl = lhl || (affecting && (!filter || _hl.filter));
return t2;
}
for (var h in hl)
t = dohl(hl[h]);
if (shl)
t = dohl(shl);
if (filter && !lhl && i != selectedlineid) {
return false;
}
lhl = lhl && !filter;
var div = document.createElement("div");
div.id = i;
if (lhl) div.className = 'lhl';
div.onclick = function() { selectline(this); };
div.innerHTML = t;
if (t.match(new RegExp(selectedthread, "g"))) div.className += ' thread';
if (append)
d.appendChild(div);
else
d.insertBefore(div, d.firstChild);
return true;
}
var lefttodraw = Math.floor(Math.abs(increment));
if (increment < 0) {
// scroll up
reachedbottom = false;
if (reachedtop) {
_hint("reached top of the file");
return;
}
for (var i = parseInt(d.firstChild.id) - 1; lefttodraw && i >= 0 && i < text.length; --i) {
if (process(i, false)) {
--lefttodraw;
if (d.childNodes.length > screenlines)
d.removeChild(d.lastChild);
}
}
if (lefttodraw) {
_hint("reached top of the file");
reachedtop = true;
}
} else if (increment > 0) {
// scroll down
reachedtop = false;
if (reachedbottom) {
_hint("reached bottom of the file");
return;
}
for (var i = parseInt(d.lastChild.id) + 1; lefttodraw && i < text.length; ++i) {
if (process(i, true)) {
--lefttodraw;
if (d.childNodes.length > screenlines)
d.removeChild(d.firstChild);
}
}
if (lefttodraw) {
_hint("reached bottom of the file");
reachedbottom = true;
}
} else { // == 0
// redraw all
reachedbottom = false;
reachedtop = false;
lefttodraw = screenlines;
var i = repaintonly ? parseInt(d.firstChild.id) : selectedlineid;
if (i < 0) i = 0;
d.innerHTML = "";
for (; lefttodraw && i < text.length; ++i) {
if (process(i, true)) {
--lefttodraw;
}
}
if (!repaintonly && selectedlineid > -1) {
// center the selected line in the middle of screen!
_render(-(screenlines / 2));
}
}
selectline(selectedlineid);
var now = new Date();
console.log("rendered in " + (now.getTime() - epoch.getTime()) + "ms");
var pos = document.getElementById("position");
pos.textContent = Math.round((parseInt(d.firstChild.id) / text.length) * 1000) / 10 + "%";
}
function _hint(h)
{
document.getElementById("hint").innerHTML = h;
}
function _gfilteron()
{
if (!filterswitch)
return false;
if (shl && shl.filter)
return true;
for (var h in hl)
{
if (hl[h].filter)
return true;
}
return false;
}
function _getfilterelement(filter)
{
if (filter == 0)
return document.getElementById("search");
return document.getElementById("filter" + filter);
}
function _setfilterelementstate(p0, _hl)
{
p0.style.textDecoration = _hl.filter ? "underline" : "";
}
function _triminput(t)
{
t = t
.replace(/^\s+/, "")
.replace(/\s+$/, "")
;
return t;
}
function _regexpescape(t)
{
t = t
.replace(/\\/g, "\\\\")
.replace(/\?/g, "\\?")
.replace(/\./g, "\\.")
.replace(/\+/g, "\\+")
.replace(/\*/g, "\\*")
.replace(/\^/g, "\\^")
.replace(/\$/g, "\\$")
.replace(/\(/g, "\\(")
.replace(/\)/g, "\\)")
.replace(/\[/g, "\\[")
.replace(/\]/g, "\\]")
.replace(/\|/g, "\\|")
;
return t;
}
function resetuistate()
{
groupwith = false;
_hint("");
}
function newhl(t, p, persistent)
{
return {
id: persistent ? nextFilterId++ : 0,
text: t,
text_r: _sanitize(_regexpescape(t)),
color: p ? p.color : colors[0],
filter: p ? p.filter : false,
cache: {}
};
}
function selectline(id)
{
var l0 = document.getElementById(selectedlineid);
if (l0)
l0.style.backgroundColor = "";
var l1 = null;
if (typeof(id) == "object") {
l1 = id;
id = parseInt(l1.id);
} else {
l1 = document.getElementById(id);
}
selectedlineid = id;
if (selectedlineid > -1)
_hint("line # " + (selectedlineid + 1));
if (l1) {
l1.style.background = "#faa";
}
var thread = null;
var m = text[selectedlineid].match(threadregexp);
if (m) thread = _regexpescape(_sanitize(m[1]));
if (thread != selectedthread) {
selectedthread = thread;
repaint();
}
return l1;
}
function mouseup(event)
{
if (event.ctrlKey)
return;
resetuistate();
var s = window.getSelection();
var t = _triminput(s.toString());
if (!t)
return;
s = document.getElementById("search");
s.value = t;
t = _prepare(t)[0];
shl = newhl(t, shl);
selectfilter(0);
repaint();
}
function persist()
{
resetuistate();
var dorender = false;
if (!shl)
{
_apply();
dorender = true;
}
if (!shl)
return;
selectfilter(0);
var _hl = newhl(shl.text, shl, true);
_hl.cache = shl.cache; // hope this is right, shl is updated in _apply, that always creates an empty cache
hl.push(_hl);
var p = document.getElementById("persistents");
var p0 = document.createElement("div");
p0.id = "filter" + _hl.id;
p0.className = "persistent";
p0.style.backgroundColor = _hl.color;
p0.innerHTML = _hl.text;
p0.onclick = function() {selectfilter(_hl.id)};
_setfilterelementstate(p0, _hl);
p.appendChild(p0);
_restartshl();
selectfilter(_hl.id);
if (dorender)
render();
colors.push(colors.shift());
}
function _apply()
{
s = document.getElementById("search");
var t = _triminput(s.value);
if (!t)
{
shl = null;
}
else
{
t = _prepare(t)[0];
shl = newhl(t, shl);
}
} }
function highlight()
{
resetuistate();
_apply();
repaint();
selectfilter(0);
}
function filter()
{
resetuistate();
if ((!shl && !hl.length) || (current == shl))
{
_apply();
selectfilter(0);
}
if (current) {
current.filter = !current.filter;
_setfilterelementstate(_getfilterelement(current.id), current);
if (filterswitch)
render();
else
repaint();
}
}
function group()
{
resetuistate();
// the code it self happens in selectfilter() function
if (!shl)
{
_hint("press higlight or filter first");
return;
}
if (hl.length)
{
groupwith = true;
_hint("-&gt; now select a pinned filter to group the current highlight with");
}
else
{
_hint("you have to pin a filter with the 'pin' button first");
}
}
function _restartshl()
{
var s = document.getElementById("search");
s.value = "";
s.style.backgroundColor = "";
s.style.textDecoration = "";
current = shl = null;
}
function restart()
{
resetuistate();
var filtered = _gfilteron(); // was: = current && current.filter
if (current == shl)
{
_restartshl();
}
else
{
var p0 = _getfilterelement(current.id);
for (var h in hl)
if (hl[h].id == current.id) {
hl.splice(h, 1);
break;
}
if (current.text) {
shl = newhl(current.text, current);
var s = document.getElementById("search");
s.value = current.text;
_setfilterelementstate(s, shl);
}
selectfilter(0);
var p = document.getElementById("persistents");
p.removeChild(p0);
}
if (!shl) // means: filter could not be switched back to shl or directly shl was reset
render();
}
function selectfilter(filter)
{
var el0 = _getfilterelement(current ? current.id : 0);
var el1 = _getfilterelement(filter);
el0.style.border = "";
el0.style.margin = "";
el1.style.border = "solid 2px #3ad";
el1.style.margin = "0px";
function filterbyid(id)
{
for (var h in hl)
if (hl[h].id == id)
return hl[h];
}
if (groupwith && filter)
{
el1.innerHTML += "+" + shl.text;
var _hl = filterbyid(filter);
_hl.text = ""; // not backward compatible
_hl.text_r += "|" + shl.text_r;
_hl.cache = {};
resetuistate();
_restartshl();
render();
}
else
resetuistate();
current = (filter == 0) ? shl : filterbyid(filter);
// A bit hacky redraw of the search box color :)
if (filter === 0 && shl)
{
var s = document.getElementById("search");
s.style.backgroundColor = shl.color;
}
}
function flipfilter(event)
{
filterswitch = !filterswitch;
event.target.innerHTML = (filterswitch ? "filters on" : "filters off");
render();
event.stopPropagation();
}

@ -106,7 +106,7 @@
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<h2>{{_('Administration')}}</h2> <h2>{{_('Administration')}}</h2>
<div class="btn btn-default"><a id="logfile" href="{{url_for('admin.view_logfile')}}">{{_('View Logfile')}}</a></div> <div class="btn btn-default"><a id="logfile" href="{{url_for('admin.view_logfile')}}">{{_('View Logfiles')}}</a></div>
<div class="btn btn-default" id="restart_database">{{_('Reconnect to Calibre DB')}}</div> <div class="btn btn-default" id="restart_database">{{_('Reconnect to Calibre DB')}}</div>
<div class="btn btn-default" id="admin_restart" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-Web')}}</div> <div class="btn btn-default" id="admin_restart" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-Web')}}</div>
<div class="btn btn-default" id="admin_stop" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-Web')}}</div> <div class="btn btn-default" id="admin_stop" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-Web')}}</div>

@ -1,141 +1,15 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% block body %} {% block body %}
{% block header %} <div id="log_group" class="inputs">
<style> <div><input type="radio" name="log_radio" id="log1" value="0" checked>
<label for="log0">{{_('Show Calibre-Web log')}}</label> {{logfiles[0]}}</div>
html, body { {% if accesslog_enable %}
margin: 0; <div><input type="radio" name="log_radio" id="log0" value="1">
height: 100%; <label for="log1">{{_('Show access log')}}</label> {{logfiles[1]}}</div>
overflow-y: hidden {% endif %}
} </div>
<div id="renderer" class="log"></div>
div.log {
font-family: Courier New;
font-size: 12px;
box-sizing: border-box;
height: 500px;
overflow-y: scroll;
border-style: solid;
}
div.log {
white-space: nowrap;
padding: 0.5em;
}
div.lhl {
background-color: #ffd;
}
div.thread {
background: #fdd;
}
div.persistent,
div.persistents,
div.hint {
display: inline;
cursor: pointer;
}
div.hint,
div.persistent {
font-family: Arial;
font-size: 12px;
padding: 2px;
margin: 1px;
}
div.hint {
color: gray;
font-style: italic;
}
div.button,
div.button2,
div.button_right {
display: inline;
font-weight: bold;
font-family: Arial;
font-size: 12px;
padding: 2px;
cursor: pointer;
color: #3ad;
_text-decoration: underline;
}
div.button2 {
border: solid 1px gray;
border-radius: 4px;
color: black;
text-decoration: none;
}
div.button_right {
margin-right: 1em;
float: right;
}
div.nounder {
text-decoration: none;
}
input.filebtn {
float: right;
position: relative;
}
</style>
{% endblock %}
<!--body onload="load()"-->
<div id="toobar" class="toobar">
<input class="search" id="search" type="text" onmousedown="selectfilter(0)"></input>
<div class="button2" onclick="highlight()" title="apply changes in the search box">apply</div>
<div class="button_right" onclick="flipfilter(event)" title="disable/enable selected filters">filters on</div>
<br/>
<div class="button" onclick="filter()" title="show only lines containing the phrase">filter</div>
<div class="hint" onclick="repaint()" id="hint"></div>
<div class="hint" onclick="repaint()" id="position"></div>
</div>
<div class="clear"></div>
<div class="logpaginator"><a href="{{'/logs/1'}}"><span class="glyphicon glyphicon-fast-backward"></span></a> <a href="{{ "/logs/"}}"><span class="glyphicon glyphicon-step-backward"></span></a> <a href="{{ '/logs/' }}"><span class="glyphicon glyphicon-step-forward"></span></a> <a href="{{'/logs/'}}"><span class="glyphicon glyphicon-fast-forward"></span></a></div>
<div class="logperpage">
<form id="logform1" action="" method="POST">
<label for="reversed">{{_('Reversed')}}:</label>
<input type="checkbox" name="reversed" id="reversed" onchange="this.form.submit();" {% if reversed %} checked="checked" {% endif %} />&nbsp;
<label for="perpage">{{_('Lines per page')}}:</label>
<select name="perpage" id ="perpage" onchange="this.form.submit();">
{% for key, value in perpage_p.items() %}
<option value="{{key}}"{% if value== perpage %} selected="selected" {% endif %}>{{value}}</option>
{% endfor %}
</select>
</form>
</div>
<div class="logwarn">{{warning}}</div>
<div class="clear"></div>
<div class="logdiv">
<table class="logtable" cellpadding="0" cellspacing="0">
<div id="renderer" class="log" onmouseup="mouseup(event)"><div>nothing loaded</div></div>
{% for line in log %}
<tr><td class="logline">{{line.line}}</td><td>{{line.date}}</td><td class="loglevel">{{line.level}}</td><td>{{line.message}}</td></tr>
{% endfor %}
</table>
</div>
<div class="logform">
<form id="logform2" action="" method="POST" style="width: auto">
<label for="from" style="display: inline-block; float: left; margin-right: 5px; height: 34px; line-height: 34px;">{{_('Jump to time:')}}</label>
<input style="display: inline-block; text-align: center; float: left; width: 155px;" class="form-control" type="text" name="from" id="from" size="15" value="{{from}}"/>
<input style="display: inline-block; float: left; margin-left: 5px;" class="btn btn-default" type="submit" value="{{_('Go')}}" />
</form>
</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>
<script>
$(function(){
init('access.log');
});
</script>
{% endblock %} {% endblock %}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -171,18 +171,12 @@ class UserBase:
def __repr__(self): def __repr__(self):
return '<User %r>' % self.nickname return '<User %r>' % self.nickname
# Login via LDAP method
'''@staticmethod
def try_login(username, password,config_dn, ldap_provider_url):
conn = get_ldap_connection(ldap_provider_url)
conn.simple_bind_s(
config_dn.replace("%s", username),
password)'''
# Baseclass for Users in Calibre-Web, settings which are depending on certain users are stored here. It is derived from # Baseclass for Users in Calibre-Web, settings which are depending on certain users are stored here. It is derived from
# User Base (all access methods are declared there) # User Base (all access methods are declared there)
class User(UserBase, Base): class User(UserBase, Base):
__tablename__ = 'user' __tablename__ = 'user'
__table_args__ = {'sqlite_autoincrement': True}
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
nickname = Column(String(64), unique=True) nickname = Column(String(64), unique=True)
@ -769,6 +763,34 @@ def migrate_Database():
conn.execute("ALTER TABLE Settings ADD column `config_access_log` INTEGER DEFAULT 0") conn.execute("ALTER TABLE Settings ADD column `config_access_log` INTEGER DEFAULT 0")
conn.execute("ALTER TABLE Settings ADD column `config_access_logfile` String DEFAULT ''") conn.execute("ALTER TABLE Settings ADD column `config_access_logfile` String DEFAULT ''")
session.commit() session.commit()
try:
# check if one table with autoincrement is existing (should be user table)
conn = engine.connect()
conn.execute("SELECT COUNT(*) FROM sqlite_sequence WHERE name='user'")
except exc.OperationalError:
# Create new table user_id and copy contents of table user into it
conn = engine.connect()
conn.execute("CREATE TABLE user_id (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
"nickname VARCHAR(64),"
"email VARCHAR(120),"
"role SMALLINT,"
"password VARCHAR,"
"kindle_mail VARCHAR(120),"
"locale VARCHAR(2),"
"sidebar_view INTEGER,"
"default_language VARCHAR(3),"
"mature_content BOOLEAN,"
"UNIQUE (nickname),"
"UNIQUE (email),"
"CHECK (mature_content IN (0, 1)))")
conn.execute("INSERT INTO user_id(id, nickname, email, role, password, kindle_mail,locale,"
"sidebar_view, default_language, mature_content) "
"SELECT id, nickname, email, role, password, kindle_mail, locale,"
"sidebar_view, default_language, mature_content FROM user")
# delete old user table and rename new user_id table to user:
conn.execute("DROP TABLE user")
conn.execute("ALTER TABLE user_id RENAME TO user")
session.commit()
# Remove login capability of user Guest # Remove login capability of user Guest
conn = engine.connect() conn = engine.connect()
@ -782,13 +804,6 @@ def clean_database():
session.query(RemoteAuthToken).filter(now > RemoteAuthToken.expiration).delete() session.query(RemoteAuthToken).filter(now > RemoteAuthToken.expiration).delete()
'''#get LDAP connection
def get_ldap_connection(ldap_provider_url):
conn = ldap.initialize('ldap://{}'.format(ldap_provider_url))
return conn'''
def create_default_config(): def create_default_config():
settings = Settings() settings = Settings()
settings.mail_server = "mail.example.com" settings.mail_server = "mail.example.com"

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save