-#!/usr/bin/python
-#
# Copyright (C) 2014 Simo Sorce <simo@redhat.com>
#
# see file 'COPYING' for use and warranty information
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import cherrypy
+import logging
from ipsilon.util.page import Page
from ipsilon.util.page import admin_protect
+from ipsilon.util.endpoint import allow_iframe
from ipsilon.util import config as pconfig
def __init__(self, *args, **kwargs):
super(AdminPage, self).__init__(*args, **kwargs)
- self.default_headers.update({
- 'Cache-Control': 'no-cache, must-revalidate',
- 'Pragma': 'no-cache',
- 'Expires': 'Thu, 01 Dec 1994 16:00:00 GMT',
- })
self.auth_protect = True
self.back = parent.url
def root_with_msg(self, message=None, message_type=None):
- return self._template('admin/plugin_config.html', title=self.title,
+ return self._template('admin/option_config.html', title=self.title,
menu=self.menu, action=self.url, back=self.back,
message=message, message_type=message_type,
name='admin_%s_%s_form' % (self.facility,
aname = '%s_%s' % (name, a)
if aname in kwargs:
value.append(a)
+ elif type(option) is pconfig.ComplexList:
+ value = get_complex_list_value(name,
+ option.get_value(),
+ **kwargs)
+ if value is None:
+ continue
+ elif type(option) is pconfig.MappingList:
+ value = get_mapping_list_value(name,
+ option.get_value(),
+ **kwargs)
+ if value is None:
+ continue
else:
continue
if value != option.get_value():
cherrypy.log.error("Storing [%s]: %s = %s" %
- (self._po.name, name, value))
+ (self._po.name, name, value),
+ severity=logging.DEBUG)
option.set_value(value)
new_db_values[name] = option.export_value()
self._po.save_plugin_config(new_db_values)
message = "New configuration saved."
message_type = ADMIN_STATUS_OK
- except Exception: # pylint: disable=broad-except
+ except Exception as e: # pylint: disable=broad-except
+ self.error('Failed to save data: %s' % e)
message = "Failed to save data!"
message_type = ADMIN_STATUS_ERROR
def GET(self, *args, **kwargs):
return self.parent.root_with_msg()
- def _get_enabled_list(self):
- cur = list()
- for p in self._site[self.facility].available.values():
- if p.is_enabled:
- cur.append(p.name)
- return cur
-
@admin_protect
def POST(self, *args, **kwargs):
message = "Nothing was modified."
message_type = "info"
- cur_enabled = self._get_enabled_list()
+ changed = None
+ cur_enabled = self._site[self.facility].enabled
if 'order' in kwargs:
order = kwargs['order'].split(',')
message = "New configuration saved."
message_type = ADMIN_STATUS_OK
+ changed = dict()
+ self.debug('%s -> %s' % (cur_enabled, new_order))
+ for i in range(0, len(cur_enabled)):
+ if cur_enabled[i] != new_order[i]:
+ changed[cur_enabled[i]] = 'reordered'
+
except ValueError, e:
message = str(e)
message_type = ADMIN_STATUS_ERROR
- except Exception, e: # pylint: disable=broad-except
+ except Exception as e: # pylint: disable=broad-except
+ self.error('Failed to save data: %s' % e)
message = "Failed to save data!"
message_type = ADMIN_STATUS_ERROR
return self.parent.root_with_msg(message=message,
- message_type=message_type)
+ message_type=message_type,
+ changed=changed)
class AdminPlugins(AdminPage):
self.order = None
parent.add_subtree(name, self)
+ if self._site[facility] is None:
+ return
+
for plugin in self._site[facility].available:
- cherrypy.log.error('Admin info plugin: %s' % plugin)
+ cherrypy.log.error('Admin info plugin: %s' % plugin,
+ severity=logging.DEBUG)
obj = self._site[facility].available[plugin]
page = AdminPluginConfig(obj, self._site, self)
if hasattr(obj, 'admin'):
def save_enabled_plugins(self, names):
self._site[self.facility].save_enabled(names)
- def root_with_msg(self, message=None, message_type=None):
+ def root_with_msg(self, message=None, message_type=None, changed=None):
plugins = self._site[self.facility]
+ if changed is None:
+ changed = dict()
+
targs = {'title': self.title,
'menu': self._master.menu,
'message': message,
'message_type': message_type,
'available': plugins.available,
'enabled': plugins.enabled,
+ 'changed': changed,
'baseurl': self.url,
'newurl': self.url}
if self.order:
except AdminError, e:
return self.root_with_msg(str(e), ADMIN_STATUS_WARN)
if not obj.is_enabled:
- obj.enable()
+ try:
+ obj.enable()
+ except Exception as e: # pylint: disable=broad-except
+ return self.root_with_msg(str(e), ADMIN_STATUS_WARN)
obj.save_enabled_state()
msg = "Plugin %s enabled" % obj.name
- return self.root_with_msg(msg, ADMIN_STATUS_OK)
+ return self.root_with_msg(msg, ADMIN_STATUS_OK,
+ changed={obj.name: 'enabled'})
enable.public_function = True
@admin_protect
except AdminError, e:
return self.root_with_msg(str(e), ADMIN_STATUS_WARN)
if obj.is_enabled:
- obj.disable()
+ try:
+ obj.disable()
+ except Exception as e: # pylint: disable=broad-except
+ return self.root_with_msg(str(e), ADMIN_STATUS_WARN)
obj.save_enabled_state()
msg = "Plugin %s disabled" % obj.name
- return self.root_with_msg(msg, ADMIN_STATUS_OK)
+ return self.root_with_msg(msg, ADMIN_STATUS_OK,
+ changed={obj.name: 'disabled'})
disable.public_function = True
return urls
@admin_protect
+ @allow_iframe
def scheme(self):
cherrypy.response.headers.update({'Content-Type': 'image/svg+xml'})
urls = self.get_menu_urls()
# pylint: disable=star-args
- return self._template('admin/ipsilon-scheme.svg', **urls)
+ return str(self._template('admin/ipsilon-scheme.svg', **urls))
scheme.public_function = True
+
+
+def get_complex_list_value(name, old_value, **kwargs):
+ delete = list()
+ change = dict()
+ for key, val in kwargs.iteritems():
+ if not key.startswith(name):
+ continue
+ n = key[len(name):]
+ if len(n) == 0 or n[0] != ' ':
+ continue
+ try:
+ index, field = n[1:].split('-')
+ except ValueError:
+ continue
+ if field == 'delete':
+ delete.append(int(index))
+ elif field == 'name':
+ change[int(index)] = val
+
+ if len(delete) == 0 and len(change) == 0:
+ return None
+
+ value = old_value
+
+ # remove unwanted changes
+ for i in delete:
+ if i in change:
+ del change[i]
+
+ # perform requested changes
+ for index, val in change.iteritems():
+ val_list = val.split('/')
+ stripped = list()
+ for v in val_list:
+ stripped.append(v.strip())
+ if len(stripped) == 1:
+ stripped = stripped[0]
+ if len(value) <= index:
+ value.extend([None]*(index + 1 - len(value)))
+ value[index] = stripped
+
+ if len(value[index]) == 0:
+ value[index] = None
+
+ # the previous loop may add 'None' entries
+ # if any still exists mark them to be deleted
+ for i in xrange(0, len(value)):
+ if value[i] is None:
+ delete.append(i)
+
+ # remove duplicates and set in reverse order
+ delete = list(set(delete))
+ delete.sort(reverse=True)
+
+ for i in delete:
+ if len(value) > i:
+ del value[i]
+
+ if len(value) == 0:
+ value = None
+ return value
+
+
+def get_mapping_list_value(name, old_value, **kwargs):
+ delete = list()
+ change = dict()
+ for key, val in kwargs.iteritems():
+ if not key.startswith(name):
+ continue
+ n = key[len(name):]
+ if len(n) == 0 or n[0] != ' ':
+ continue
+ try:
+ index, field = n[1:].split('-')
+ except ValueError:
+ continue
+ if field == 'delete':
+ delete.append(int(index))
+ else:
+ i = int(index)
+ if i not in change:
+ change[i] = dict()
+ change[i][field] = val
+
+ if len(delete) == 0 and len(change) == 0:
+ return None
+
+ value = old_value
+
+ # remove unwanted changes
+ for i in delete:
+ if i in change:
+ del change[i]
+
+ # perform requested changes
+ for index, fields in change.iteritems():
+ for k in 'from', 'to':
+ if k in fields:
+ val = fields[k]
+ val_list = val.split('/')
+ stripped = list()
+ for v in val_list:
+ stripped.append(v.strip())
+ if len(stripped) == 1:
+ stripped = stripped[0]
+ if len(value) <= index:
+ value.extend([None]*(index + 1 - len(value)))
+ if value[index] is None:
+ value[index] = [None, None]
+ if k == 'from':
+ i = 0
+ else:
+ i = 1
+ value[index][i] = stripped
+
+ # eliminate incomplete/incorrect entries
+ if value[index] is not None:
+ if ((len(value[index]) != 2 or
+ value[index][0] is None or
+ len(value[index][0]) == 0 or
+ value[index][1] is None or
+ len(value[index][1]) == 0)):
+ value[index] = None
+
+ # the previous loop may add 'None' entries
+ # if any still exists mark them to be deleted
+ for i in xrange(0, len(value)):
+ if value[i] is None:
+ delete.append(i)
+
+ # remove duplicates and set in reverse order
+ delete = list(set(delete))
+ delete.sort(reverse=True)
+
+ for i in delete:
+ if len(value) > i:
+ del value[i]
+
+ if len(value) == 0:
+ value = None
+ return value