wiki:Version2/Tutoriales/Consola_Web/Tutorial_2_Acciones_en_Panel_Contextual

Version 5 (modified by adelcastillo, 9 years ago) (diff)

--

Introducción

Este es el segundo tutorial de la saga de tutoriales sobre Opengnsys 2 referentes a cómo implementar plugins para la Consola Web. Puedes acceder a la [Version2 página que lista todos los tutoriales] o al tutorial anterior: Tutorial 1: Hello World.

Este segundo tutorial se basa en el anterior, por tanto es preciso haberlo comprendido para poder continuar. En el primer tutorial conseguimos que en el Panel Principal se mostrase la acción "hello", a la que si accedíamos veíamos una página con el estilo de la consola web y en la que el área de contenido mostraba el mensaje "Hello World". Es un tutorial muy sencillo conceptual, ente pero sirve para introducir al desarrollador las nociones básicas de cómo funciona el sistema de plugins de la consola web:

  • La estructura de ficheros y directorios: todo plugin tiene su directorio en pluginmanager/plugins/<nombre del plugin>, el código principal del plugin va en __init__.py, la información básica sobre el plugin en plugin.conf y los templates en el subdirectorio templates/.
  • En __init__.py definimos nuestra clase Plugin que hereda de PluginBase y en la que redifinimos las funciones que sean necesarias.
  • El desarrollo se basa en el framework web.py: templates en html mezclado con python, urls del plugin definidas en un array "self.urls" dentro de la clase Plugin, clases que funcionan como vistas y que llaman a los templates con parámetros de entrada, etc.

En este segundo tutorial añadiremos a nuestro plugin una nueva acción que aparecerá en el Panel Contextual del navegador de la consola cuando se esté mostrando un ordenador o una unidad organizativa. En la página asociada a la acción mostraremos un mensaje que diga "Hello Computer <computerName>!" si se trata de un ordenador, o "Hello Organizative Unit <ouName>!" si se trata de una unidad organizativa. Como hemos dicho, nos basaremos en el del plugin del tutorial 1.

Creando la acción

Podríamos reutilizar la acción "hello" que ya tenemos definida, pero ilustrar cómo separar código que realiza acciones diferentes, crearemos una nueva acción, que hemos de declarar en plugin.conf añadiendole el siguiente código:

[action/hello_entity]
description = Displays the text Hello entity! referred to either an Organizative Unit or a Computer
human_name = Say hello to this
appear_in_main_panel = No

Efectivamente, vamos a usar la misma acción para mostrar el mensaje tanto si se trata de una Unidad Organizativa o un Ordenador, dado que la acción es concepturalmente la misma, pero sobre entidades diferentes. Ahora viene el quid de la cuestión, el código de __init__.py:

'''
Hello World! plugin example
'''

from ..pluginbase import PluginBase
import hello

class Plugin(PluginBase):
    '''
    '''
    def enable(self):
        self.actions_for_url = ('navigator/(computer|ou)/(.*)', 'hello_entity')
        self.urls = ('action/hello', hello.HelloView,
            'action/hello_entity/(computer|ou)/(.*)', hello.HelloEntityView)

De acuerdo, he de reconocer que no es totalmente intuitivo lo que está ocurriendo ahora: voy a intentar explicarlo. Hemos redefinido (por defecto en PluginBase está definida como un array vacío) la variable self.actions_for_url. Es una lista de pares, parecida a self.urls. En esta lista definimos en qué urls vamos a insertar qué acción. Sólo definimos un par, que dice que en las urls que comiencen con 'navigator/computer/' o 'navigator/ou/' vamos a meter la acción 'hello_entity', mediante expresiones regulares.

Cuando aparece una acción en el panel contextual, necesitamos que aparezca con cierta información. Por ejemplo, tendrá un título, que será el human_name definido para esa acción en plugin.conf anteriormente. También necesita una url, que es la url que llevará acabo dicha acción. Y ¿donde definimos las urls de nuestro plugin? en self.urls. Precisamente eso es lo que hemos hecho. Hemos dicho que cuando se acceda dentro de nuestro plugin (es decir con el prefijo 'plugin/hello_world/') a la url 'action/hello_entity/ou/.*' o 'action/hello_entity/computer/.*', se maneje dicha url por la vista HelloEntityView que está en el fichero hello.py (hello.HelloEntityView).

Ahora parémonos un momento más. Cuando se ejecuta una acción del Panel Contextual, queremos que dicha acción se ejecute sobre los elementos mostrados en esa página en la que estamos mostrando el panel. Queremos que la acción sea contextual. En el caso de nuestro tutorial, queremos que la vista HelloEntityView muestre un mensaje personalizado: si la acción se muestra para el ordenador fresa, el mensaje será "Hello Computer fresa!". En el sistema de plugins de opengnsys hemos resuelto cómo pasar esa información a la vista asociada a una acción mediante un "trasvase" de información de una url a otra: de la url donde se muestra la acción a la url de la acción en sí. Y además de forma flexible: el desarrollador del plugin sigue siendo quien define la url de la acción, siempre que comience con 'action/<nombre de la acción>'.

¿Cómo conseguimos esto? Fácil: cada elemento entre paréntesis en la url definida para una acción en self.actions_for_url rellena los paréntesis de la url de la acción. Suena a jeroglífico, pero en realidad es muy fácil:

  1. La url en la que se muestra una acción por ejemplo es 'navigator/computer/fresa'.
  2. La expresión regular que hemos puesto en self.actions_for_url que coincide con esa url es 'navigator/(computer|ou)/(.*)'.
  3. Por tanto la lista de elementos de los paréntesis de la expresión regular es ['computer', 'fresa']
  4. La expresión regular que define la vista asociada a la url de la acción en self.urls es 'action/hello_entity/(computer|ou)/(.*)'
  5. Rellenamos los paréntesis en esa expresión regular con ['computer', 'fresa'], y obtenemos que la url de la acción es 'action/hello_entity/computer/fresa'.

Recalcar que para que esto funcione es imprescindible utilizar una url en self.urls para la acción que sea del tipo 'action/<nombre de la acción>'.

Además los paréntesis en las expresiones regulares de las urls de self.urls indican los argumentos que recibirá la vista asociada, en este caso hello.HelloEntityView. Esto es así porque es la manera en que funciona web.py. Ahora añadiremos la clase HelloEntityView al fichero hello.py, resultando en:

'''
Hello actions
'''
from __future__ import unicode_literals
from decorators import pi18n
import web

class HelloView:
    @pi18n
    def GET(self):
        return web.ctx.render.plugins.hello_world.helloview(_('Hello World!'))

class HelloEntityView:
    @pi18n
    def GET(self, entity_type, entity_name):
        if entity_type == "computer":
            message = _("Hello Computer %s!") % entity_name
        elif entity_type == "ou":
            message = _("Hello Organizative Unit %s!") % entity_name
        return web.ctx.render.plugins.hello_world.helloview(message)

Como véis hemos hecho unos pequeños cambios. Primero, hemos importado unicode_literals del "futuro" (Python 3). Esto nos garantiza que no tendremos problemas con la codificación de las cadenas, haciendo que por defecto todas sean en UTF. También hemos modificado cómo llamamos el template: en vez de crear uno nuevo para nuestra vista, le pasamos al template la cadena que queremos mostrar y así podemos reutilizarlo. También, debido a que el plugin está internacionalizado, usamos el decorador pi18n que nos añade automáticamente la función _ dentro de la función decorada (para saber más sobre la internacionalización de los plugins lee el Tutorial 3: Internacionalización de plugins).

Por último, como dijimos antes, la función GET de nuestra vista ahora toma como parámetros aquellos elementos entre paréntesis en la url que apunta a nuestra vista en la variable self.urls de nuestro Plugin. Es decir, como la url que apunta a nuestra vista es 'navigator/(computer|ou)/(.*)', pues recibiremos por GET como primer argumento bien "computer" o "ou" ('(computer|ou)'), y como segundo argumento cualquier cosa ('(.*)'), que sabemos que será en nuestro caso el nombre del ordenador o unidad organizativa.

El template de templates/helloview.html ha sido debidamente modificado, quedando así:

$def with (message)
$var title: message
$var tab: panel
$var hierarchy = []

$message

Usando el plugin

Si ya teníamos activado el plugin y ejecutándose el servidor, tendremos que bien reiniciar el servidor o desactivar y volver a activar el plugin. Esto es necesario para forzar la recarga del mismo. Luego de hacerlo, podremos ver que siempre que naveguemos por una unidad organizativa o un ordenador, aparecerá la acción que hemos dispuesto (mostrando el texto "Say hello to this"), y al hacer clic saludará correctamente a la entidad correcta.