Amélioration de la gestion des pièces jointes dans iTop

Dans la gestion des demandes IT, il est essentiel de garantir que toutes les informations et documents nécessaires soient attachés aux tickets tout au long de leur cycle de vie. iTop offre nativement la possibilité d’ajouter des pièces jointes aux objets, mais il ne permet pas toujours d’imposer ou de faciliter cet ajout à des moments clés du processus.

Lorsqu’un ticket passe d’un statut à un autre via une transition, il peut être nécessaire de fournir un justificatif (ex. un document de validation, une capture d’écran, un rapport). Cependant, dans iTop standard, cette action n’est pas proposée au niveau des transitions. L’agent qui veut renvoyer une pièce jointe et mettre en attente le ticket utilisateur doit effectuer une première action d’ajout de pièce jointe et une deuxième action de mise en attente du ticket.

L’extension Attachment on Transition répond à cette problématique en ajoutant dynamiquement un module de gestion des fichiers lorsque certaines transitions spécifiques sont déclenchées.

Table des matières

  1. Préambule : respect des bonnes pratiques iTop
  2. Injection dynamique du module de pièce jointe
  3. Détection des transitions et appel AJAX
  4. Instanciation de la classe de rendu des pièces jointes
  5. Spécificité iTop 2.7

1. Préambule : Respect des bonnes pratiques iTop

Dans cet article nous allons détailler tout le processus de création d’une extension répondant à la problématique des pièces jointes lors des transitions.
Nous vous proposons ici un tutoriel pas à pas qui permet de rendre compte des différents enjeux techniques concernant le développement d’une extension iTop. D’un côté nous montrerons comment nous pouvons utiliser les différentes interfaces et classes pré-existantes, et de l’autre nous expliquerons comment maintenir les évolutions apportées dans le logiciel au gré des montées de versions.

iTop – Ajout de pièce jointe automatique lors de la transition

1.1 Rappel des bases et prérequis

Avant de commencer à développer une extension iTop – comme ici pour gérer les pièces jointes sur une transition – il est essentiel de bien maîtriser les principes fondamentaux de personnalisation d’iTop.

📚 Se former avec les ressources officielles

Pour garantir la qualité, la compatibilité et la maintenabilité de votre développement, nous vous recommandons vivement de consulter les ressources suivantes fournies par Combodo (éditeur d’iTop) :

⚙️ Exemple d’extension de départ

Dans notre cas, nous partons d’une structure d’extension iTop classique :

📂 Exemple d’arborescence :

/itsm-factory-attachment-on-transition/
├── assets/
├── doc/
├── src/
├── templates/
├── vendor/

├── datamodel.attachment-on-transition.php
├── module.attachment-on-transition.php
└── README.md

💡 Cette structure de base sera progressivement enrichie tout au long du tutoriel avec les éléments nécessaires à l’injection du module d’attachement dans les formulaires de transition.

2. Injection dynamique du module de pièce jointe

L’extension repose sur une logique en deux étapes :

  • Un script JavaScript qui détecte les transitions de ticket et déclenche un appel AJAX pour charger dynamiquement le module de gestion des pièces jointes.
  • Un script PHP qui répond à l’appel AJAX et renvoie les données du module de fichiers joints.
  • Un autre script qui traite le formulaire de transition ainsi modifié.

Pour mettre en œuvre nous devons utiliser deux interfaces d’iTop permettant de surcharger des fonctions pré-existantes, iApplicationUIExtension et iPageUIBlockExtension. Les interfaces mises à disposition pour customiser iTop sont disponibles dans ce lien de documentation Extensibility interfaces [iTop Documentation]. iPageUIBlockExtension est nécessaire depuis la 3.2 pour faire intervenir le script javascript (NB: Pour les versions antérieurs notamment la version 2.7 d’iTop merci de vous reporter à la fin de cet article).

Le script est contenu dans les assets de l’extension et l’interface dans le fichier php main.attachment-transition.php. Il sera appelé grâce à l’interface iPageUiBlocExtension.
Nous ajouterons également un script php de réception de notre requête asynchrone ajax-attachment-transition.php.
iApplicationUIExtension est l’interface qui sera chargée de modifier le fonctionnement de la validation du formulaire pour charger et ajouter la pièce jointe sur itop lié au bon objet en l’occurrence le ticket en transition. Elle interviendra également dans le fichier main.attachment-transition.php.

Voici donc notre objectif de structure finale :

Structure extension attachment Fin

3. Détection des transitions et appel AJAX

3.1 Logique du script JS

Notre script JavaScript intégré dans les pages de transition désirée détecte le stimulus de transition (ev_pending) et déclenche une requête AJAX pour charger le module d’attachement. Les points logiques de constructions du script sont les suivants :

Détection de la transition : Le script récupère la valeur du stimulus (ev_pending) via l’URL.

Requête asynchrone : Elle envoie les paramètres (classe, ID de l’objet, identifiant de transaction) au script PHP ajax-attachment-transition.php.

Injection du module : En cas de succès, la réponse HTML est injectée dans la page au niveau du champ pending_reason.

3.2 Détail du script JS

var urlParams = new URLSearchParams(window.location.search);
var baseUrl = `${window.location.protocol}//${window.location.host}`;
if (urlParams.has(‘stimulus’)) {
    const stimulusValue = urlParams.get(‘stimulus’);
    switch (stimulusValue) {
        case ‘ev_pending’:
                $.ajax({
                    url: `${baseUrl}/pages/exec.php?exec_module=itsm-factory-attachment-on-transition&exec_page=ajax-attachment-transition.php`,
                    data: {
                        sObjClass: urlParams.get(‘class’),
                        iObjKey: urlParams.get(‘id’),
                        sTransactionId: $(‘input[name= »sTransactionId »]’).val()
                    },
                    dataType: ‘html’,
                    success: function (data) {
                        //console.log(data);
                        $(‘div[data-attribute-code= »pending_reason »]’).append(data);
                    },
                    error: function (xhr, status, error) {
                        console.error(‘Erreur lors de la requête AJAX’, error);
                    }
                });
            break;
        default:
            break;
    }
}

itsm-factory-attachment-on-transition/assets/js/attachment.js

Notons ici un point important la construction du lien vers notre page ajax qui passe par exec.php afin d’effectuer les vérifications de sécurité nécessaire. Ceci correspond à une recommandation de sécurité empêchant l’accès aux pages .php présentes dans les modules du répertoire env-production, répertoire contenant tous le modules actifs de votre iTop.

Voici à quoi ressemble tout lien générique à destination d’une page d’extension itop.

${baseUrl}/pages/exec.php?exec_module=${extensionName}&exec_page=${extensionPageName}      

itsm-factory-attachment-on-transition/assets/js/attachment.js

3.3 Injection du script JS sur les pages souhaitées

Pour injecter le script nous utilisons dans la page main.attachment-transition. php l’interface iPageUiBlocExtension de cette façon :

class AttachmentPopup implements iPageUIBlockExtension
{
    public function GetBannerBlock() {}
    public function GetHeaderBlock()
    {
        $aConfig = MetaModel::GetModuleSetting(‘itsm-factory-attachment-on-transition’, ‘attachment-transition’, array());
        if ($aConfig[‘mode’] === true) {
            $sStimulus = utils::ReadParam(‘stimulus’,  », false, ‘raw_data’);
            $sObjClass = utils::ReadParam(‘class’,  », false, ‘raw_data’);
            $iObjKey = utils::ReadParam(‘id’,  », false, ‘raw_data’);
           
            $aTransition = $aConfig[‘transitions’];
            if (in_array($sStimulus, $aTransition)) {
                $sTransactionId = utils::GetUploadTempId();
                $aAttachmentsDeleted = utils::ReadParam(‘attachments_deleted’, array());
                $oBlock = new UIContentBlock();
                $oAddInput = InputUIBlockFactory::MakeForHidden(‘sTransactionId’, $sTransactionId);
                $oBlock->AddSubBlock($oAddInput);
                $oBlock->AddJsFileRelPath(‘env-production/itsm-factory-attachment-on-transition/assets/js/attachment.js’);
                return $oBlock;
            }
        }
    }
    public function GetFooterBlock() {}
}
itsm-factory-attachment-on-transition/main.attachment-on-transition.php

Pour tout objet traditionnel dans iTop, nous utilisons DisplayBareProperties afin de pouvoir surcharger l’affichage de l’objet. Mais dans le cas des transitions sur les tickets en 3.2 l’objet n’est plus présent sur la page de transition nous avons seulement son formulaire.

3.4 Utilisation du fichier de configuration d'iTop

Ici nous utilisons une solution de contournement pour pouvoir injecter le script au bon endroit. Effectivement nous utilisons la classe permettant de surcharger n’importe quelle page du site (iPageUIBlockExtenstion) et nous précisons que nous ne retournons le block contenant notre script JS uniquement si nous avons les bons paramètres définis en fichier de configuration, correspondant aux paramètres de l’URL de la page.

  • le statut d’activation du module
  • la ou les transitions concernées
‘itop-factory-attachment-on-transition’ => array(
‘attachment-transition’ => array(
‘mode’ => true,
‘transitions’ => array(‘ev_pending’, ‘ev_resolve’)
),
),
conf/production/config-itop.php

4. Instanciation de la classe de rendu des pièce jointe

4.1 Construction du module des pièces jointes

Le script ajax-attachment-transition.php récupère les informations de l’objet en cours et génère dynamiquement le module d’attachement des fichiers.

Validation des paramètres : Vérifie que l’ID de l’objet et l’ID de transaction sont valides.
Création du module : Utilise AttachmentsRendererFactory pour générer la liste des pièces jointes liées au ticket.
Affichage dynamique : Retourne l’HTML qui sera injecté via la requête AJAX.

    $sObjClass = utils::ReadParam(‘sObjClass’, ‘UserRequest’, false, ‘string’);
    $iObjKey = utils::ReadParam(‘iObjKey’, 0, false, ‘integer’); 
    $sTransactionId = utils::ReadParam(‘sTransactionId’,  », false, ‘string’);
 
    if ($iObjKey!=0 && !\utils::IsNullOrEmptyString($sTransactionId))
    {
        $oPage->add(‘<div class= »ibo-field ibo-field-small »>’);
        $oPage->add(‘<div class= »ibo-field–label »><span>’.Dict::S(‘Attachments:FieldsetTitle’).'</span></div>’);
        $oAttachmentsRenderer = AttachmentsRendererFactory::GetInstance($oPage, $sObjClass, $iObjKey, $sTransactionId);
        $oAttachmentsRenderer->RenderEditAttachmentsList();
        $response = $oAttachmentsRenderer;
        $oPage->add(‘</div>’);
        $oPage->output();
    }

Cette partie n’a rien de difficile mais comporte des points de difficulté lorsque vous essayez de la créer la toute première fois sans avoir connaissance des tenants et des aboutissants des particularités d’iTop.

4.2 Considérations sur la création des modules approprié dans iTop

L’une des difficultés majeures lors de la création d’une extension iTop réside dans la conception des blocs HTML/PHP à injecter dynamiquement via une réponse AJAX.

Il ne s’agit pas simplement d’afficher du contenu, mais de s’intégrer proprement à l’interface native d’iTop, en respectant son ergonomie et ses mécanismes internes.

🔎 Pourquoi cette étape est délicate ?

Plutôt que de créer de zéro des composants HTML ou JS, il est préférable de réutiliser les classes de rendu existantes fournies par iTop. Cela garantit :

  • une meilleure compatibilité avec les versions futures d’iTop

  • une cohérence visuelle avec l’interface

  • une maintenance facilitée

🗂️ Où chercher les bons éléments de rendu ?

Voici les principaux répertoires à explorer dans le code source d’iTop pour identifier les blocs réutilisables :

Répertoire Description
datamodels/ Contient les définitions des objets manipulables (CMDB, tickets, utilisateurs, etc.) – utile pour comprendre les attributs disponibles.
applications/ Gère la logique applicative, souvent utilisée pour des traitements non liés directement à la CMDB.
core/ Cœur du système iTop. ⚠️ À ne pas modifier. Il est fortement déconseillé d’y intervenir pour des raisons de stabilité et de maintenabilité.
source/ _(v3.2+) Nouveau répertoire introduit avec iTop 3.2. Il regroupe la majorité des composants UI modernes, tels que les blocs UIContentBlock, les InputUIBlockFactory, etc. C’est la source principale à explorer pour tout développement d’interface utilisateur.

4.3 Conseils de debuggage des requêtes asynchrones.

Afin de débugger les pages php requêter de façon asynchrone il est très utiles de faire appel à IssueLog::Info($sString).

IssueLog::Info(« Stimulus détecté : $sStimulus pour l’objet $sObjClass avec l’ID $iObjKey »);

Vérifier que les issue_log sont bien activés dans le fichier de configuration d’iTop et consulter log/php-errors.log.

5. Spécificité iTop 2.7

5.1 Injection du script JS via OnDisplayProperties

Dans la version 2.7 d’iTop nous n’avons plus besoin de requêter une page php en asynchrone puisque l’objet de demande utilisateur est présent sur la page de la transition. On peut donc directement instancier la classe de gestion des pièces-jointes sur la transition en surchargeant la méthode OnDisplayBareProperties.

public function OnDisplayProperties($oObject, WebPage $oPage, $bEditMode = false)
    {
        if ($oObject instanceof UserRequest) {
            $sStimulus = utils::ReadParam(‘stimulus’,  », false, ‘raw_data’);
            $sObjClass = utils::ReadParam(‘class’,  », false, ‘raw_data’);
            $iObjKey = utils::ReadParam(‘id’,  », false, ‘raw_data’);
            $sTransactionId = utils::GetUploadTempId();
            $aTransition = MetaModel::GetModuleSetting(‘attachment-on-transition’, ‘transitions’,  »);
            if (in_array($sStimulus, $aTransition)) {
               
                $aAttachmentsDeleted = utils::ReadParam(‘attachments_deleted’, array());
                $oAttachmentsRenderer = AttachmentsRendererFactory::GetInstance($oPage, $sObjClass, $iObjKey, $sTransactionId);
                $oPage->add(‘<fieldset>
                <legend>Pièces jointes</legend><div id= »AttachmentsContent »>’);
                $oAttachmentsRenderer->RenderEditAttachmentsList();
                $oPage->add(‘</div></fieldset>’);
                $oPage->add_ready_script(
                    <<<JS
                    if ($(‘[data-attribute-code= »public_log »]:first’).length>0) {
                        $(‘[data-attribute-code= »public_log »]:first’).prepend($(‘fieldset>#AttachmentsContent>div#AttachmentsListContainer’).parent().parent());
                    } else {
                        $(‘#apply_stimulus>table’).append($(‘fieldset>#AttachmentsContent>div#AttachmentsListContainer’).parent().parent())
                    }                        
JS
                );
            }
        }
    }

Conclusion : Une extension qui renforce l’expertise ITSM

L’extension Attachment on Transition démontre tout le potentiel de personnalisation d’iTop pour répondre à des besoins métiers concrets et récurrents : garantir la traçabilité documentaire lors de chaque transition de ticket.

En intégrant intelligemment les pièces jointes dans le cycle de vie des demandes, cette extension :

  • améliore l’expérience agent en réduisant les manipulations manuelles,

  • fiabilise les processus ITIL (mise en attente, validation, résolution…),

  • et renforce la conformité et l’auditabilité des échanges avec les utilisateurs.

Son implémentation, mêlant front-end (JavaScript) et back-end (PHP via interfaces extensibles), illustre également l’expertise technique que nous mobilisons chez ITSM Factory pour transformer iTop en un véritable outil de gestion ITSM sur mesure.