do not forget previous selections during en-/disable help
use png instead of gif for en-/disable help icons download of complete log file is possible prevent the "plugin_manager" from disabling itself
This commit is contained in:
parent
00ebd07293
commit
11fba98cda
|
@ -7,6 +7,7 @@ Text {
|
||||||
ShowAll = Show all messages
|
ShowAll = Show all messages
|
||||||
AtLeastWarnings = Show warnings and errors
|
AtLeastWarnings = Show warnings and errors
|
||||||
OnlyErrors = Show errors only
|
OnlyErrors = Show errors only
|
||||||
|
DownloadLogFile = Download complete log
|
||||||
AgeOfEvent = Time passed
|
AgeOfEvent = Time passed
|
||||||
EventText = Description
|
EventText = Description
|
||||||
TimeUnits {
|
TimeUnits {
|
||||||
|
|
|
@ -27,6 +27,7 @@ __revision__ = "$Id"
|
||||||
import cryptobox.plugins.base
|
import cryptobox.plugins.base
|
||||||
import re
|
import re
|
||||||
import datetime
|
import datetime
|
||||||
|
import cherrypy
|
||||||
|
|
||||||
LOG_LEVELS = [ 'DEBUG', 'INFO', 'NOTICE', 'WARNING', 'ERROR' ]
|
LOG_LEVELS = [ 'DEBUG', 'INFO', 'NOTICE', 'WARNING', 'ERROR' ]
|
||||||
|
|
||||||
|
@ -68,10 +69,24 @@ class logs(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
level = None
|
level = None
|
||||||
for (index, line) in enumerate(self.__filter_log_content(lines, size, level)):
|
for (index, line) in enumerate(self.__filter_log_content(lines, size, level)):
|
||||||
self.__set_line_hdf_data(self.hdf_prefix + "Content.%d" % index, line)
|
self.__set_line_hdf_data(self.hdf_prefix + "Content.%d" % index, line)
|
||||||
self.hdf[self.hdf_prefix + "Destination"] = self.cbox.prefs["Log"]["Destination"].lower()
|
self.hdf[self.hdf_prefix + "Destination"] = \
|
||||||
|
self.cbox.prefs["Log"]["Destination"].lower()
|
||||||
return "show_log"
|
return "show_log"
|
||||||
|
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def download(self, **kargs):
|
||||||
|
"""Download the complete log file
|
||||||
|
|
||||||
|
**kargs are necessary - we have to ignore 'weblang' and so on ...
|
||||||
|
"""
|
||||||
|
log_file = self.__get_log_destination_file()
|
||||||
|
if log_file is None:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return cherrypy.lib.cptools.serveFile(log_file, disposition="attachment", name="cryptobox_logfile.txt")
|
||||||
|
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
"""The current status includes the log configuration details.
|
"""The current status includes the log configuration details.
|
||||||
"""
|
"""
|
||||||
|
@ -122,7 +137,7 @@ class logs(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
if not match:
|
if not match:
|
||||||
## we could not parse the line - just return the text without meta info
|
## we could not parse the line - just return the text without meta info
|
||||||
return
|
return
|
||||||
## matching was successfully - we can parse the line for details
|
## matching was successful - we can parse the line for details
|
||||||
## calculate time difference of log line (aka: age of event)
|
## calculate time difference of log line (aka: age of event)
|
||||||
try:
|
try:
|
||||||
(year, month, day, hour, minute) = match.group(
|
(year, month, day, hour, minute) = match.group(
|
||||||
|
@ -159,21 +174,31 @@ class logs(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def __get_log_destination_file(self):
|
||||||
|
"""For non-file log destinations return 'None' and output a warning
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if self.cbox.prefs["Log"]["Destination"].upper() == "FILE":
|
||||||
|
import os
|
||||||
|
return os.path.abspath(self.cbox.prefs["Log"]["Details"])
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
except KeyError:
|
||||||
|
self.cbox.log.error(
|
||||||
|
"could not evaluate one of the following config settings: "
|
||||||
|
+ "[Log]->Destination or [Log]->Details")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def __get_log_data(self, lines=None, max_size=None):
|
def __get_log_data(self, lines=None, max_size=None):
|
||||||
"""get the most recent log entries of the log file
|
"""get the most recent log entries of the log file
|
||||||
|
|
||||||
the maximum number and size of these entries can be limited by
|
the maximum number and size of these entries can be limited by
|
||||||
'lines' and 'max_size'
|
'lines' and 'max_size'
|
||||||
"""
|
"""
|
||||||
# return nothing if the currently selected log output is not a file
|
log_file = self.__get_log_destination_file()
|
||||||
try:
|
## return nothing if the currently selected log output is not a file
|
||||||
if self.cbox.prefs["Log"]["Destination"].upper() != "FILE":
|
if log_file is None:
|
||||||
return []
|
|
||||||
log_file = self.cbox.prefs["Log"]["Details"]
|
|
||||||
except KeyError:
|
|
||||||
self.cbox.log.error(
|
|
||||||
"could not evaluate one of the following config settings: "
|
|
||||||
+ "[Log]->Destination or [Log]->Details")
|
|
||||||
return []
|
return []
|
||||||
try:
|
try:
|
||||||
fdesc = open(log_file, "r")
|
fdesc = open(log_file, "r")
|
||||||
|
|
|
@ -64,6 +64,10 @@
|
||||||
/with ?><?cs /loop ?><?cs
|
/with ?><?cs /loop ?><?cs
|
||||||
/if ?>
|
/if ?>
|
||||||
</table>
|
</table>
|
||||||
|
<?cs call:print_form_header("download-log", "downloads/logs") ?>
|
||||||
|
<button type="submit" value="refresh"><?cs
|
||||||
|
var:html_escape(Lang.Plugins.logs.Text.DownloadLogFile) ?></button>
|
||||||
|
</form>
|
||||||
<?cs else ?>
|
<?cs else ?>
|
||||||
<?cs call:hint("Plugins.logs.EmptyLog") ?>
|
<?cs call:hint("Plugins.logs.EmptyLog") ?>
|
||||||
<?cs /if ?>
|
<?cs /if ?>
|
||||||
|
|
|
@ -56,6 +56,7 @@ Python code interface:
|
||||||
never get called with an invalid device)
|
never get called with an invalid device)
|
||||||
- the python module which contains the plugin's class should also contain a class called
|
- the python module which contains the plugin's class should also contain a class called
|
||||||
'unittests' - it should inherit WebInterfaceTestClass.WebInterfaceTestClass
|
'unittests' - it should inherit WebInterfaceTestClass.WebInterfaceTestClass
|
||||||
|
- method "download" is exposed as "downloads/PLUGINNAME"
|
||||||
|
|
||||||
|
|
||||||
Language file structure:
|
Language file structure:
|
||||||
|
|
|
@ -139,6 +139,10 @@ class plugin_manager(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
(vis_type, ) = pattern.match(key).groups()
|
(vis_type, ) = pattern.match(key).groups()
|
||||||
if vis_type:
|
if vis_type:
|
||||||
setting["visibility"].append(vis_type)
|
setting["visibility"].append(vis_type)
|
||||||
|
## the plugin_manager _must_ always be visible
|
||||||
|
if (self.get_name() == name) and (not setting["visibility"]):
|
||||||
|
## reset to default
|
||||||
|
setting["visibility"] = self.plugin_visibility[:]
|
||||||
if args.has_key("%s_auth" % name):
|
if args.has_key("%s_auth" % name):
|
||||||
setting["requestAuth"] = True
|
setting["requestAuth"] = True
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -147,6 +147,13 @@ class CryptoBoxPlugin:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def download(self, **kargs):
|
||||||
|
"""Deliver a downloadable file - by default return nothing
|
||||||
|
"""
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def get_icon(self, image=None, **kargs):
|
def get_icon(self, image=None, **kargs):
|
||||||
"""return the image data of the icon of the plugin
|
"""return the image data of the icon of the plugin
|
||||||
|
|
|
@ -58,6 +58,22 @@ class PluginIconHandler:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PluginDownloadHandler:
|
||||||
|
"""deliver downloadable files of available plugins via cherrypy
|
||||||
|
|
||||||
|
the state (enabled/disabled) and the require-auth setting is ignored
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, plugins):
|
||||||
|
for plugin in plugins.get_plugins():
|
||||||
|
if not plugin:
|
||||||
|
continue
|
||||||
|
plname = plugin.get_name()
|
||||||
|
## expose the get_icon function of this plugin
|
||||||
|
setattr(self, plname, plugin.download)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebInterfaceSites:
|
class WebInterfaceSites:
|
||||||
"""handle all http requests and render pages
|
"""handle all http requests and render pages
|
||||||
|
|
||||||
|
@ -91,6 +107,9 @@ class WebInterfaceSites:
|
||||||
## publish plugin icons
|
## publish plugin icons
|
||||||
self.icons = PluginIconHandler(self.__plugin_manager)
|
self.icons = PluginIconHandler(self.__plugin_manager)
|
||||||
self.icons.exposed = True
|
self.icons.exposed = True
|
||||||
|
## publish plugin downloads
|
||||||
|
self.downloads = PluginDownloadHandler(self.__plugin_manager)
|
||||||
|
self.downloads.exposed = True
|
||||||
## announce that the server started up
|
## announce that the server started up
|
||||||
self.setup()
|
self.setup()
|
||||||
|
|
||||||
|
@ -206,7 +225,7 @@ class WebInterfaceSites:
|
||||||
## invalid base64 string
|
## invalid base64 string
|
||||||
pass
|
pass
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
## no cherrypy response header defined
|
## no cherrypy request header defined
|
||||||
pass
|
pass
|
||||||
auth_dict = self.cbox.prefs.user_db["admins"]
|
auth_dict = self.cbox.prefs.user_db["admins"]
|
||||||
if user in auth_dict.keys():
|
if user in auth_dict.keys():
|
||||||
|
@ -245,6 +264,7 @@ class WebInterfaceSites:
|
||||||
return self.return_plugin_action(
|
return self.return_plugin_action(
|
||||||
self.__plugin_manager.get_plugin("disks"))(**param_dict)
|
self.__plugin_manager.get_plugin("disks"))(**param_dict)
|
||||||
|
|
||||||
|
|
||||||
def new_http_error_handler(self, error_code, message):
|
def new_http_error_handler(self, error_code, message):
|
||||||
"""handle http errors gracefully
|
"""handle http errors gracefully
|
||||||
|
|
||||||
|
|
|
@ -175,8 +175,7 @@ def:reload_link(attr, value) ?><?cs
|
||||||
?><?cs # do not keep _all_ params - just the necessary ones
|
?><?cs # do not keep _all_ params - just the necessary ones
|
||||||
otherwise it could happen, that a previous action is repeated
|
otherwise it could happen, that a previous action is repeated
|
||||||
accidently by reloading - or given passwords can be exposed in the url
|
accidently by reloading - or given passwords can be exposed in the url
|
||||||
?><?cs if:(name(attrs) == "weblang") || (name(attrs) == "device") ||
|
?><?cs if:(name(attrs) != "action") && (name(attrs) != "store") ?><?cs
|
||||||
(name(attrs) == "help") ?><?cs
|
|
||||||
set:Temp[name(attrs)] = attrs ?><?cs /if
|
set:Temp[name(attrs)] = attrs ?><?cs /if
|
||||||
?><?cs /each
|
?><?cs /each
|
||||||
?><?cs if:attr != "" ?><?cs set:Temp[attr] = value ?><?cs /if
|
?><?cs if:attr != "" ?><?cs set:Temp[attr] = value ?><?cs /if
|
||||||
|
@ -201,12 +200,12 @@ def:help_link() ?><?cs
|
||||||
<a href="<?cs call:reload_link("help","0") ?>"
|
<a href="<?cs call:reload_link("help","0") ?>"
|
||||||
title="<?cs var:html_escape(Lang.Button.DisableHelp) ?>">
|
title="<?cs var:html_escape(Lang.Button.DisableHelp) ?>">
|
||||||
<?cs var:html_escape(Lang.Button.DisableHelp) ?><?cs
|
<?cs var:html_escape(Lang.Button.DisableHelp) ?><?cs
|
||||||
set:icon_file = "icon_get_help_disable.gif" ?><?cs
|
set:icon_file = "icon_get_help_disable.png" ?><?cs
|
||||||
else ?>
|
else ?>
|
||||||
<a href="<?cs call:reload_link("help","1") ?>"
|
<a href="<?cs call:reload_link("help","1") ?>"
|
||||||
title="<?cs var:html_escape(Lang.Button.EnableHelp) ?>">
|
title="<?cs var:html_escape(Lang.Button.EnableHelp) ?>">
|
||||||
<?cs var:html_escape(Lang.Button.EnableHelp) ?><?cs
|
<?cs var:html_escape(Lang.Button.EnableHelp) ?><?cs
|
||||||
set:icon_file = "icon_get_help.gif" ?><?cs
|
set:icon_file = "icon_get_help.png" ?><?cs
|
||||||
/if ?>
|
/if ?>
|
||||||
<img class="message_symbol" src="cryptobox-misc/<?cs var:icon_file ?>" alt="icon: help" />
|
<img class="message_symbol" src="cryptobox-misc/<?cs var:icon_file ?>" alt="icon: help" />
|
||||||
</a></div><?cs
|
</a></div><?cs
|
||||||
|
|
Loading…
Reference in a new issue