Handle changing ComplexList options
[cascardo/ipsilon.git] / ipsilon / admin / common.py
old mode 100755 (executable)
new mode 100644 (file)
index 0177402..4e92d1f
@@ -1,5 +1,3 @@
-#!/usr/bin/python
-#
 # Copyright (C) 2014  Simo Sorce <simo@redhat.com>
 #
 # see file 'COPYING' for use and warranty information
@@ -23,6 +21,11 @@ from ipsilon.util.page import admin_protect
 from ipsilon.util import config as pconfig
 
 
+ADMIN_STATUS_OK = "success"
+ADMIN_STATUS_ERROR = "danger"
+ADMIN_STATUS_WARN = "warning"
+
+
 class AdminError(Exception):
     def __init__(self, message):
         super(AdminError, self).__init__(message)
@@ -63,6 +66,67 @@ class AdminPluginConfig(AdminPage):
                                                          self._po.name),
                               config=self._po.get_config_obj())
 
+    def get_complex_list_value(self, 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
+
     @admin_protect
     def GET(self, *args, **kwargs):
         return self.root_with_msg()
@@ -73,7 +137,7 @@ class AdminPluginConfig(AdminPage):
         if self._po.is_readonly:
             return self.root_with_msg(
                 message="Configuration is marked Read-Only",
-                message_type="warning")
+                message_type=ADMIN_STATUS_WARN)
 
         message = "Nothing was modified."
         message_type = "info"
@@ -97,6 +161,12 @@ class AdminPluginConfig(AdminPage):
                         aname = '%s_%s' % (name, a)
                         if aname in kwargs:
                             value.append(a)
+                elif type(option) is pconfig.ComplexList:
+                    value = self.get_complex_list_value(name,
+                                                        option.get_value(),
+                                                        **kwargs)
+                    if value is None:
+                        continue
                 else:
                     continue
 
@@ -111,10 +181,10 @@ class AdminPluginConfig(AdminPage):
             try:
                 self._po.save_plugin_config(new_db_values)
                 message = "New configuration saved."
-                message_type = "success"
+                message_type = ADMIN_STATUS_OK
             except Exception:  # pylint: disable=broad-except
                 message = "Failed to save data!"
-                message_type = "error"
+                message_type = ADMIN_STATUS_ERROR
 
             # Then refresh the actual objects
             self._po.refresh_plugin_config()
@@ -136,24 +206,18 @@ class AdminPluginsOrder(AdminPage):
     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):
 
         if self._site[self.facility].is_readonly:
             return self.parent.root_with_msg(
                 message="Configuration is marked Read-Only",
-                message_type="warning")
+                message_type=ADMIN_STATUS_WARN)
 
         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(',')
@@ -178,18 +242,25 @@ class AdminPluginsOrder(AdminPage):
                     self._site[self.facility].refresh_enabled()
 
                     message = "New configuration saved."
-                    message_type = "success"
+                    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 = "error"
+                    message_type = ADMIN_STATUS_ERROR
 
                 except Exception, e:  # pylint: disable=broad-except
                     message = "Failed to save data!"
-                    message_type = "error"
+                    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):
@@ -218,15 +289,19 @@ class AdminPlugins(AdminPage):
     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:
@@ -259,12 +334,13 @@ class AdminPlugins(AdminPage):
         try:
             obj = self._get_plugin_obj(plugin)
         except AdminError, e:
-            return self.root_with_msg(str(e), "warning")
+            return self.root_with_msg(str(e), ADMIN_STATUS_WARN)
         if not obj.is_enabled:
             obj.enable()
             obj.save_enabled_state()
             msg = "Plugin %s enabled" % obj.name
-        return self.root_with_msg(msg, "success")
+        return self.root_with_msg(msg, ADMIN_STATUS_OK,
+                                  changed={obj.name: 'enabled'})
     enable.public_function = True
 
     @admin_protect
@@ -273,12 +349,13 @@ class AdminPlugins(AdminPage):
         try:
             obj = self._get_plugin_obj(plugin)
         except AdminError, e:
-            return self.root_with_msg(str(e), "warning")
+            return self.root_with_msg(str(e), ADMIN_STATUS_WARN)
         if obj.is_enabled:
             obj.disable()
             obj.save_enabled_state()
             msg = "Plugin %s disabled" % obj.name
-        return self.root_with_msg(msg, "success")
+        return self.root_with_msg(msg, ADMIN_STATUS_OK,
+                                  changed={obj.name: 'disabled'})
     disable.public_function = True
 
 
@@ -319,5 +396,5 @@ class Admin(AdminPage):
         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