src/westferry/constants.py
westferry_backend_PYTHON = \
- src/westferry/backend/__version__.py
+ src/westferry/backend/__init__.py \
+ src/westferry/backend/__version__.py \
+ src/westferry/backend/base.py \
+ src/westferry/backend/graphs.py \
+ src/westferry/backend/main.py \
+ src/westferry/backend/system.py
westferry_backenddir = $(pythondir)/westferry/backend
westferry_handlers_PYTHON = \
src/westferry/handlers/__init__.py \
+ src/westferry/handlers/analytics.py \
src/westferry/handlers/base.py \
src/westferry/handlers/index.py
src/westferry/backend/__version__.py
+src/westferry/handlers/analytics.py
src/westferry/handlers/base.py
src/westferry/__init__.py
import tornado.web
+from . import backend
from . import handlers
from . import ui
# Initialise the web application
tornado.web.Application.__init__(self, handlers=h, **settings)
+
+ @property
+ def backend(self):
+ if not hasattr(self, "_backend"):
+ self._backend = backend.Backend()
+
+ return self._backend
--- /dev/null
+#!/usr/bin/python3
+###############################################################################
+# #
+# Westferry - The IPFire web user interface #
+# Copyright (C) 2015 IPFire development team #
+# #
+# 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/>. #
+# #
+###############################################################################
+
+from .main import Backend
--- /dev/null
+#!/usr/bin/python3
+###############################################################################
+# #
+# Westferry - The IPFire web user interface #
+# Copyright (C) 2015 IPFire development team #
+# #
+# 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/>. #
+# #
+###############################################################################
+
+class BaseBackend(object):
+ def __init__(self, backend):
+ self.backend = backend
--- /dev/null
+#!/usr/bin/python3
+###############################################################################
+# #
+# Westferry - The IPFire web user interface #
+# Copyright (C) 2015 IPFire development team #
+# #
+# 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 collecty.client
+
+from . import base
+
+class GraphsBackend(base.BaseBackend):
+ @property
+ def collecty(self):
+ """
+ Returns a CollectyClient object which is created
+ when it is needed.
+ """
+ if not hasattr(self, "_collecty"):
+ self._collecty = collecty.client.CollectyClient()
+
+ return self._collecty
+
+ def generate_graph(self, template_name, **kwargs):
+ assert self.template_exists(template_name)
+
+ # Remove all keys with value None
+ # dbus cannot marshall None and when None is set, we assume
+ # that the default is selected, so we can simply remove the
+ # setting.
+ for key in kwargs.copy():
+ if kwargs[key] is None:
+ del kwargs[key]
+
+ return self.collecty.generate_graph(template_name, **kwargs)
+
+ def template_exists(self, template_name):
+ """
+ Returns True if a template with the given name exists
+ """
+ return template_name in self.collecty.list_templates()
--- /dev/null
+#!/usr/bin/python3
+###############################################################################
+# #
+# Westferry - The IPFire web user interface #
+# Copyright (C) 2015 IPFire development team #
+# #
+# 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/>. #
+# #
+###############################################################################
+
+from .__version__ import VERSION
+
+from . import graphs
+from . import system
+
+class Backend(object):
+ version = VERSION
+
+ def __init__(self):
+ self.graphs = graphs.GraphsBackend(self)
+ self.system = system.SystemBackend(self)
--- /dev/null
+#!/usr/bin/python3
+###############################################################################
+# #
+# Westferry - The IPFire web user interface #
+# Copyright (C) 2015 IPFire development team #
+# #
+# 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 socket
+
+from . import base
+
+class SystemBackend(base.BaseBackend):
+ @property
+ def hostname(self):
+ """
+ Returns the hostname of this system
+ """
+ return socket.gethostname()
###############################################################################
from . import base
+from . import analytics
from . import index
def get_handlers():
--- /dev/null
+#!/usr/bin/python3
+###############################################################################
+# #
+# Westferry - The IPFire web user interface #
+# Copyright (C) 2015 IPFire development team #
+# #
+# 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 datetime
+import collecty.client
+import mimetypes
+import tornado.web
+
+from . import base
+
+class GraphExportHandler(base.BaseHandler):
+ VALID_INTERVALS = ("hour", "day", "month", "week", "year")
+ DEFAULT_INTERVAL = "day"
+
+ SUPPORTED_FORMATS = ("pdf", "png", "svg")
+
+ url = r"/graph/([\w\-]+)(?:/([\w\d]+))?.(%s)" % "|".join(SUPPORTED_FORMATS)
+
+ def get(self, template_name, object_id, format):
+ # Get the requested dimensions of the image
+ height = self.get_argument_int("height", None)
+ width = self.get_argument_int("width", None)
+
+ # Get the requested interval
+ interval = self.get_argument("interval", self.DEFAULT_INTERVAL)
+ if interval and not interval in self.VALID_INTERVALS:
+ raise tornado.web.HTTPError(400, _("Invalid interval: %s") % interval)
+
+ # Generate the graph image
+ g = self.backend.graphs.generate_graph(template_name, object_id=object_id,
+ format=format.upper(), height=height, width=width, interval=interval)
+
+ # Set the HTTP headers
+ self._make_headers(format, template_name, object_id)
+
+ # Deliver the content
+ self.finish(g)
+
+ def _make_headers(self, extension, template_name, object_id):
+ # Determine the mime type
+ mimetype = mimetypes.types_map.get(".%s" % extension, "application/octet-stream")
+ self.set_header("Content-Type", mimetype)
+
+ # Add the timestamp when this graph was generated
+ now = datetime.datetime.now()
+
+ # Put together the filename (for downloads)
+ filename = [self.backend.system.hostname, template_name, object_id, now.isoformat()]
+ filename = "%s.%s" % ("-".join((e for e in filename if e)), extension)
+
+ if extension == "pdf":
+ self.set_header("Content-Disposition", "attachment; filename=%s" % filename)
+ else:
+ self.set_header("Content-Disposition", "inline; filename=%s" % filename)
class BaseHandler(tornado.web.RequestHandler, metaclass=HandlerRegistration):
url = None
+
+ @property
+ def backend(self):
+ """
+ Shortcut to access the backend
+ """
+ return self.application.backend
+
+ def get_argument_int(self, name, *args, **kwargs):
+ val = self.get_argument(name, *args, **kwargs)
+
+ if val is None:
+ return
+
+ try:
+ return int(val)
+ except ValueError:
+ raise tornado.web.HTTPError(400,
+ _("Invalid type for '%s', expected integer") % name)