Commandes systèmes
==================

Ce tutoriel explique comment ajouter des actions lançant des commandes système.

Premier exemple : commande simple sans arguments
------------------------------------------------

Je veux une action permettant l'éxécution de la commande "echo 'toto' > /tmp/toto.test.ead2"
sur le module scribe.

Ajout d'une action
~~~~~~~~~~~~~~~~~~

Dans le répertoire ead2/backend/actions/scribe/ j'ajoute un fichier echo.py::

    # -*- coding: UTF-8 -*-
    """ Exécution de echo """
    from ead2.backend.actions.lib.main import Cmd
    class Echo(Cmd):
        name = "cmd_echo"
        cmd_template = "/bin/echo 'toto' > /tmp/toto.test.ead2"
        cmd_libelle = "Lancez echo toto"

La classe Cmd éxécute la commande et renvoie le retour de la commande (avec gestion de l'erreur)

- l'attribut name servira pour référencer l'action (il doit être unique).
- l'attribut cmd_libelle sera utilisé pour le bouton lançant l'action

.. _enregistrement-action:

Enregistrement de l'action
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ajouter la référence pour l'import du fichier d'action dans le fichier ead2/backend/config/actions_scribe.cfg::

    scribe/echo

Les actions du fichier echo.py seront importées.

Ajoutez la permission pour l'action cmd_echo dans le fichier ead2/backend/config/perm_scribe.ini dans la section [permissions]::

    cmd_echo=admin

Admin aura droit à l'action cmd_echo.

Référencez l'action cmd_echo auprès de la console dans le fichier ead2/backend/config/cmd.py::

    {'scribe':[..., 'cmd_echo'],
                ...}

La console sait alors qu'elle doit appeler le bouton pour l'action cmd_echo.
Lancez la commande ::

    service ead-server restart

.. note::

    Il est inutil de créer un nouveau fichier .py pour rajouter une action (plusieurs actions peuvent être placer dans le même fichier)

Deuxième exemple : commande avec arguments système
--------------------------------------------------

Sur scribe, je veux lancer la commande ls sur le répertoire de l'utilisateur (/home/workgroups/premièrelettredulogin/login)

Dans le répertoire ead2/backend/actions/scribe/ j'ajoute un fichier ls.py::

    # -*- coding: UTF-8 -*-
    from ead2.backend.actions.lib.main import Cmd
    class Ls(Cmd):
        name = "cmd_ls"
        # propriété de la commande à éxécuter
        cmd_template = "/bin/ls -al /home/%(lettre)s/%(login)s"
        cmd_libelle = "Lister votre répertoire perso"

        def cmd_args(self):
            login = self.user_description['name']
            lettre = login[0]
            return dict(login=login,
                        lettre=lettre)

La fonction cmd_args renvoie un dictionnaire qui est utilisé pour lancer la commande,
cmd = cmd_template % self.cmd_args()
user_description est une variable automatiquement remplie au lancement de l'action.

Pour l'enregistrement voyez le premier exemple attention l'action se nomme désormais cmd_ls et non cmd_echo.


Troisième exemple : commande avec arguments donnés par l'utilisateur (utilisation de formulaire)
------------------------------------------------------------------------------------------------

Sur scribe, je veux lancer la commande ls sur un chemin donné par l'utilisateur.

.. warning::

    Rappelons que l'éxécution de commande système avec des paramètres données par l'utilisateur est soumise à des risques non négligeables.

Dans le répertoire ead2/backend/actions/scribe/ j'ajoute un fichier ls_user.py::

    # -*- coding: UTF-8 -*-
    from ead2.backend.actions.lib.main import Cmd
    from ead2.backend.actions.lib.widgets import ajax, main as M, form as F
    from ead2.backend.actions import tools

On importe les librairies pour la construction du formulaire(form) et la construction du bouton(ajax et main)
On crée notre classe::

    class LsUser(Cmd):
        name = "cmd_ls_user"
        # propriété de la commande à éxécuter
        cmd_template = "/bin/ls -al '%(path)s'"
        cmd_libelle = "Lister un répertoire"

        form_id = "form_path"
        form_result = Dict(default={}, doc='', keys=[form_id])
        widget_templates = ['main', 'form', 'formselect', 'listlist', 'checklist']
        template = "cmd_ls_user"

- L'attribut form_id est l'id html du formulaire que l'on va utiliser.
- L'attribut form_result permet de réceptionner un formulaire validé, dans notre cas le formulaire aura pour id form_id.
- L'attribut widget_templates spécifie les librairies cheetah nécessaire pour la templatisation de notre widget.
- L'attribut template spécifie le template utilisée pour mettre en forme notre bouton et formulaire.

Ajoutons les méthodes pour la gestion de notre formulaire, renvoie des données du formulaire::

    def form(self):
        path_input = F.Input(name="path", libelle="chemin à lister", required=True)
        return dict(path_input=path_input, form_id=self.form_id)

Modifions le bouton pour qu'il valide le formulaire::

    def btn(self):
        href = ajax.valid(self.server_nb, self.name, [self.form_id], container="consolereturn", execution='true')
        libelle = self.cmd_libelle
        return M.Submit(href=href,
                        libelle=libelle,
                        icone="/image/cmd.png",
                       _class="consolebtn")

Le lien href valide le formulaire form_id, passe l'argument execution avec pour valeur true et renvoie le résultat dans le container "console_return".

Récupération des arguments de la commande::

    def cmd_args(self):
        result_form = self.form_result.get(self.form_id, {})
        result_form = tools.format_form_result(result_form)
        path = result_form.get('path', None)
        # Ici on testera notre path
        return dict(path=path)

La méthode form_result permet de formatter les données de formulaire pour qu'elles soient sous une forme plus pratique,
:ref:`valid-form`
Maintenant on doit rédiger notre template cmd_ls_user.tmpl que l'on placera dans ead2/backend/template/::

    ## import de widgets
    ## (doivent etre passer en params dans l'execute de l'action associe)
    #extends ead2.frontend.web.template.main
    #implements respond
    #extends ead2.frontend.web.template.form
    #implements respond
    #extends ead2.frontend.web.template.formselect
    #implements respond
    #extends ead2.frontend.web.template.listlist
    #implements respond
    #if $is_defined('btn'):
    $main().make_div_btn($btn)
    #end if
    #if $is_defined('path_input') and $is_defined('form_id')
    <form id="$form_id" onsubmit="return false">
        $form().make_input($path_input)
    </form>
    #end if
    #if $is_defined('setmessage')
    <script>
    $setmessage
    </script>
    #end if

Pour plus d'informations sur la syntaxe des templates cheetah, reportez vous à la section :ref:`widgets`.
Il reste maintenant à réferencer notre action. :ref:`enregistrement-action`

