Fix plugins enablement code
[cascardo/ipsilon.git] / ipsilon / admin / common.py
index 5928763..b9dfbf4 100755 (executable)
@@ -20,6 +20,7 @@
 import cherrypy
 from ipsilon.util.page import Page
 from ipsilon.util.page import admin_protect
+from ipsilon.util.plugin import PluginObject
 
 
 class AdminPage(Page):
@@ -34,33 +35,29 @@ class AdminPage(Page):
         self.auth_protect = True
 
 
-class AdminPluginPage(AdminPage):
+class AdminPluginConfig(AdminPage):
 
-    def __init__(self, obj, site, parent):
-        super(AdminPluginPage, self).__init__(site, form=True)
-        self._obj = obj
-        self.title = '%s plugin' % obj.name
-        self.url = '%s/%s' % (parent.url, obj.name)
+    def __init__(self, po, site, parent):
+        super(AdminPluginConfig, self).__init__(site, form=True)
+        self._po = po
+        self.title = '%s plugin' % po.name
+        self.url = '%s/%s' % (parent.url, po.name)
         self.facility = parent.facility
         self.menu = [parent]
         self.back = parent.url
 
         # Get the defaults
-        self.plugin_config = obj.get_config_desc()
-        if not self.plugin_config:
-            self.plugin_config = dict()
-
-        # Now overlay the actual config
-        for option in self.plugin_config:
-            self.plugin_config[option][2] = obj.get_config_value(option)
+        options = po.get_config_desc()
+        if options is None:
+            options = dict()
 
         self.options_order = []
-        if hasattr(obj, 'conf_opt_order'):
-            self.options_order = obj.conf_opt_order
+        if hasattr(po, 'conf_opt_order'):
+            self.options_order = po.conf_opt_order
 
         # append any undefined options
         add = []
-        for k in self.plugin_config.keys():
+        for k in options.keys():
             if k not in self.options_order:
                 add.append(k)
         if len(add):
@@ -68,14 +65,18 @@ class AdminPluginPage(AdminPage):
             for k in add:
                 self.options_order.append(k)
 
-    @admin_protect
-    def GET(self, *args, **kwargs):
+    def root_with_msg(self, message=None, message_type=None):
         return self._template('admin/plugin_config.html', title=self.title,
-                              name='admin_%s_%s_form' % (self.facility,
-                                                         self._obj.name),
                               menu=self.menu, action=self.url, back=self.back,
+                              message=message, message_type=message_type,
+                              name='admin_%s_%s_form' % (self.facility,
+                                                         self._po.name),
                               options_order=self.options_order,
-                              options=self.plugin_config)
+                              plugin=self._po)
+
+    @admin_protect
+    def GET(self, *args, **kwargs):
+        return self.root_with_msg()
 
     @admin_protect
     def POST(self, *args, **kwargs):
@@ -84,17 +85,22 @@ class AdminPluginPage(AdminPage):
         message_type = "info"
         new_values = dict()
 
+        # Get the defaults
+        options = self._po.get_config_desc()
+        if options is None:
+            options = dict()
+
         for key, value in kwargs.iteritems():
-            if key in self.plugin_config:
-                if value != self.plugin_config[key][2]:
+            if key in options:
+                if value != self._po.get_config_value(key):
                     cherrypy.log.error("Storing [%s]: %s = %s" %
-                                       (self._obj.name, key, value))
+                                       (self._po.name, key, value))
                     new_values[key] = value
 
         if len(new_values) != 0:
             # First we try to save in the database
             try:
-                self._obj.save_plugin_config(self.facility, new_values)
+                self._po.save_plugin_config(self.facility, new_values)
                 message = "New configuration saved."
                 message_type = "success"
             except Exception:  # pylint: disable=broad-except
@@ -102,29 +108,191 @@ class AdminPluginPage(AdminPage):
                 message_type = "error"
 
             # And only if it succeeds we change the live object
-            for name, value in new_values.items():
-                self._obj.set_config_value(name, value)
-                self.plugin_config[name][2] = value
+            self._po.refresh_plugin_config(self.facility)
 
-        return self._template('admin/plugin_config.html', title=self.title,
-                              message=message,
-                              message_type=message_type,
-                              name='admin_%s_%s_form' % (self.facility,
-                                                         self._obj.name),
-                              menu=self.menu, action=self.url,
-                              options=self.plugin_config)
+        return self.root_with_msg(message=message,
+                                  message_type=message_type)
+
+
+class AdminPluginsOrder(AdminPage):
+
+    def __init__(self, site, parent, facility):
+        super(AdminPluginsOrder, self).__init__(site, form=True)
+        self.parent = parent
+        self.facility = facility
+        self.url = '%s/order' % parent.url
+        self.menu = [parent]
+
+    @admin_protect
+    def GET(self, *args, **kwargs):
+        return self.parent.root_with_msg()
+
+    def _get_enabled_by_name(self):
+        by_name = dict()
+        for p in self._site[self.facility]['available'].values():
+            if p.is_enabled:
+                by_name[p.name] = p
+        return by_name
+
+    @admin_protect
+    def POST(self, *args, **kwargs):
+        message = "Nothing was modified."
+        message_type = "info"
+        by_name = self._get_enabled_by_name()
+
+        if 'order' in kwargs:
+            order = kwargs['order'].split(',')
+            if len(order) != 0:
+                new_names = []
+                new_plugins = []
+                try:
+                    for v in order:
+                        val = v.strip()
+                        if val not in by_name:
+                            error = "Invalid plugin name: %s" % val
+                            raise ValueError(error)
+                        new_names.append(val)
+                        new_plugins.append(by_name[val])
+                    if len(new_names) < len(by_name):
+                        for val in by_name:
+                            if val not in new_names:
+                                new_names.append(val)
+                                new_plugins.append(by_name[val])
+
+                    self.parent.save_enabled_plugins(new_names)
+                    self.parent.reorder_plugins(new_names)
+
+                    # When all is saved update also live config. The
+                    # live config is a list of the actual plugin
+                    # objects.
+                    self._site[self.facility]['enabled'] = new_plugins
+
+                    message = "New configuration saved."
+                    message_type = "success"
+
+                except ValueError, e:
+                    message = str(e)
+                    message_type = "error"
+
+                except Exception, e:  # pylint: disable=broad-except
+                    message = "Failed to save data!"
+                    message_type = "error"
+
+        return self.parent.root_with_msg(message=message,
+                                         message_type=message_type)
+
+
+class AdminPlugins(AdminPage):
+    def __init__(self, name, site, parent, facility, ordered=True):
+        super(AdminPlugins, self).__init__(site)
+        self._master = parent
+        self.name = name
+        self.title = '%s plugins' % name
+        self.url = '%s/%s' % (parent.url, name)
+        self.facility = facility
+        self.template = 'admin/plugins.html'
+        self.order = None
+        parent.add_subtree(name, self)
+
+        for plugin in self._site[facility]['available']:
+            cherrypy.log.error('Admin info plugin: %s' % plugin)
+            obj = self._site[facility]['available'][plugin]
+            page = AdminPluginConfig(obj, self._site, self)
+            if hasattr(obj, 'admin'):
+                obj.admin.mount(page)
+            self.add_subtree(plugin, page)
+
+        if ordered:
+            self.order = AdminPluginsOrder(self._site, self, facility)
+
+    def save_enabled_plugins(self, names):
+        po = PluginObject()
+        po.name = "global"
+        globalconf = dict()
+        globalconf['order'] = ','.join(names)
+        po.set_config(globalconf)
+        po.save_plugin_config(self.facility)
+
+    def reorder_plugins(self, names):
+        return
+
+    def root_with_msg(self, message=None, message_type=None):
+        plugins = self._site[self.facility]
+        enabled = []
+        if self.order:
+            for plugin in plugins['enabled']:
+                if plugin.is_enabled:
+                    enabled.append(plugin.name)
+        else:
+            for _, plugin in plugins['available'].iteritems():
+                if plugin.is_enabled:
+                    enabled.append(plugin.name)
+
+        targs = {'title': self.title,
+                 'menu': self._master.menu,
+                 'message': message,
+                 'message_type': message_type,
+                 'available': plugins['available'],
+                 'enabled': enabled,
+                 'baseurl': self.url}
+        if self.order:
+            targs['order_name'] = '%s_order_form' % self.name
+            targs['order_action'] = self.order.url
+
+        # pylint: disable=star-args
+        return self._template(self.template, **targs)
+
+    def root(self, *args, **kwargs):
+        return self.root_with_msg()
+
+    @admin_protect
+    def enable(self, plugin):
+        msg = None
+        plugins = self._site[self.facility]
+        if plugin not in plugins['available']:
+            msg = "Unknown plugin %s" % plugin
+            return self.root_with_msg(msg, "error")
+        obj = plugins['available'][plugin]
+        if not obj.is_enabled:
+            obj.enable(self._site)
+            if self.order:
+                enabled = list(x.name for x in plugins['enabled'])
+                self.save_enabled_plugins(enabled)
+            msg = "Plugin %s enabled" % obj.name
+        return self.root_with_msg(msg, "success")
+    enable.public_function = True
+
+    @admin_protect
+    def disable(self, plugin):
+        msg = None
+        plugins = self._site[self.facility]
+        if plugin not in plugins['available']:
+            msg = "Unknown plugin %s" % plugin
+            return self.root_with_msg(msg, "error")
+        obj = plugins['available'][plugin]
+        if obj.is_enabled:
+            obj.disable(self._site)
+            if self.order:
+                enabled = list(x.name for x in plugins['enabled'])
+                self.save_enabled_plugins(enabled)
+            msg = "Plugin %s disabled" % obj.name
+        return self.root_with_msg(msg, "success")
+    disable.public_function = True
 
 
 class Admin(AdminPage):
 
     def __init__(self, site, mount):
         super(Admin, self).__init__(site)
+        self.title = 'Home'
+        self.mount = mount
         self.url = '%s/%s' % (self.basepath, mount)
-        self.menu = []
+        self.menu = [self]
 
     def root(self, *args, **kwargs):
         return self._template('admin/index.html',
                               title='Configuration',
+                              baseurl=self.url,
                               menu=self.menu)
 
     def add_subtree(self, name, page):
@@ -134,3 +302,20 @@ class Admin(AdminPage):
     def del_subtree(self, name):
         self.menu.remove(self.__dict__[name])
         del self.__dict__[name]
+
+    def get_menu_urls(self):
+        urls = dict()
+        for item in self.menu:
+            name = getattr(item, 'name', None)
+            if name:
+                urls['%s_url' % name] = cherrypy.url('/%s/%s' % (self.mount,
+                                                                 name))
+        return urls
+
+    @admin_protect
+    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)
+    scheme.public_function = True