#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Isomer - The distributed application framework
# ==============================================
# Copyright (C) 2011-2020 Heiko 'riot' Weinen <riot@c-base.org> and others.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Module: Configurator
=====================
"""
from isomer.events.client import send
from isomer.events.system import reload_configuration
from isomer.component import ConfigurableComponent, authorized_event, handler
from isomer.schemata.component import ComponentConfigSchemaTemplate as Schema
from isomer.database import ValidationError
from isomer.logger import error, warn
from formal import model_factory
[docs]class getlist(authorized_event):
"""A client requires a schema to validate data or display a form"""
roles = ["admin"]
[docs]class get(authorized_event):
"""A client requires a schema to validate data or display a form"""
roles = ["admin"]
[docs]class put(authorized_event):
"""A client requires a schema to validate data or display a form"""
roles = ["admin"]
[docs]class Configurator(ConfigurableComponent):
"""
Provides a common configuration interface for all Isomer components.
(You're probably looking at it right now)
"""
channel = "isomer-web"
configprops = {}
[docs] def __init__(self, *args):
super(Configurator, self).__init__("CONF", *args)
[docs] @handler(getlist)
def getlist(self, event):
"""Processes configuration list requests
:param event:
"""
try:
componentlist = model_factory(Schema).find({})
data = []
for comp in componentlist:
try:
data.append(
{
"name": comp.name,
"uuid": comp.uuid,
"class": comp.componentclass,
"active": comp.active,
"present": comp.name in self.names
}
)
except AttributeError:
self.log(
"Bad component without component class encountered:", lvl=warn
)
self.log(comp.serializablefields(), pretty=True, lvl=warn)
data = sorted(data, key=lambda x: x["name"])
response = {
"component": "isomer.ui.configurator",
"action": "getlist",
"data": data,
}
self.fireEvent(send(event.client.uuid, response))
return
except Exception as e:
self.log("List error: ", e, type(e), lvl=error, exc=True)
[docs] @handler(put)
def put(self, event):
"""Store a given configuration"""
self.log("Configuration put request ", event.user)
try:
component = model_factory(Schema).find_one({"uuid": event.data["uuid"]})
component.update(event.data)
component.save()
response = {
"component": "isomer.ui.configurator",
"action": "put",
"data": True,
}
self.log("Updated component configuration:", component.name)
self.fireEvent(reload_configuration(component.name))
except (KeyError, ValueError, ValidationError, PermissionError) as e:
response = {
"component": "isomer.ui.configurator",
"action": "put",
"data": False,
}
self.log(
"Storing component configuration failed: ",
type(e),
e,
exc=True,
lvl=error,
)
self.fireEvent(send(event.client.uuid, response))
return
[docs] @handler(get)
def get(self, event):
"""Get a stored configuration"""
try:
comp = event.data["uuid"]
except KeyError:
comp = None
if not comp:
self.log("Invalid get request without schema or component", lvl=error)
return
self.log("Config data get request for ", event.data, "from", event.user)
component = model_factory(Schema).find_one({"uuid": comp})
response = {
"component": "isomer.ui.configurator",
"action": "get",
"data": component.serializablefields(),
}
self.fireEvent(send(event.client.uuid, response))