Introduction

Le projet faire-simple, développé par La Netscouade, est une plateforme permettant aux usagers du service public de participer à la simplification des démarches administratives. Organisée en trois temps (proposition, co-construction, suivi de l'implémentation), elle propose de nombreuses fonctionnalités collaboratives aux membres inscrits.

Les fonctionnalités temps réel

La logique de contribution et de collaboration au sein des ateliers de co-construction est double : la participation asynchrone permet aux membres de participer, à leur rythme et selon leurs disponibilités, à la recherche de solutions, et la participation synchrone permet de sanctuariser des moments d'échanges commun, où tout le groupe se mobilise pendant une plage horaire donnée.

Dans le cadre de la mise en place de ces groupes, nous avons mis en place deux nouvelles fonctionnalités permettant aux utilisateurs de rédgier de manière collaborative et synchrone un document et de discuter ensemble en temps réel.

Les solutions techniques

Le chat

L'une des premières solutions techniques est node.js. Il existe en effet pas mal de solutions basées sur cette technologie pour intégrer facilement un module de chat drupal comme par exemple

Les deux fonctionnent avec un serveur node.js mais peuvent aussi être mise en mode AJAX, c'est-à-dire sans avoir besoin d'installer un serveur node.js, mais en diminuant grandement l'effet de temps réel.

La rédaction de document collaborativement

Cette partie peut être assurée par Etherpad qui possède aussi un module Drupal Etherpad Integration. Le problème avec ce module se situe au niveau de son statut qui est encore en développement. Il peut quand même être une bonne base de départ pour mettre en place assez rapidement Etherpad sur votre site web.

Je n'ai pas le temps !

La mise en place d'un serveur pour héberger node.js peut prendre du temps, surtout si vous n'hébergez pas forcément les sites que vous produisez. Dans notre cas, les délais étaient trop courts pour nous permettre de faire une demande à l'hébergeur afin qu'il mette en place node.js, et les coûts de maintenance indus trop importants.

Nous avons dû trouver une autre solution technique, et celle qui répond le plus à notre besoin est Firebase.

Firebase, la solution rapide et efficace

Introduction

Firebase est une API qui permet de stocker des données dans le cloud. L'avantage se situe dans le fait que ses données sont accessibles facilement et sont synchronisées en temps réel sur tous les appareils connectés. Le service firebase se charge d'héberger les données que vous allez lui confier sous forme d'un objet JSON. Tout l'intérêt de la solution est le côté temps réel. Par exemple, si une donnée est ajoutée ou mise à jour, les autres appareils connectés recevront ses données instantanément.

Utilisation de Firebase avec javascript

  1. Connexion à la base de données :
    var fb = new Firebase("https://YOUR.firebaseio.com/");
  2. Ajout de donnée dans la base :
    fb.set({ name: "Alex Wolfe" });

    La fonction set de l'objet Firebase permet d'ajouter l'objet JSON

    {
    "name" : "Alex Wolfe"
    }
  3. Lecture des données dans la base :
    fb.on("value", function(data) {
    var name = data.val() ? data.val().name : "";
    alert("My name is " + name);
    });

Cette fonction anonyme est exécutée à chaque fois qu'une nouvelle donnée est ajoutée dans la base. Ici, on peut voir l'événement value, mais il en existe plusieurs pour cibler plus précisément l'ajout, la suppression ou la mise à jour d'une donnée.

Le Chat

Dans le sujet du temps réel, ce n'est pas l'exemple de chat qui manque. Nous avons choisi de partir sur une solution avec AngularFire qui est l'association de AngularJS et de Firebase.

AngularFire va mettre à disposition des services et méthodes pour manipuler les données encore plus facilement. Par exemple le service $firebase qui peut être instancié avec la référence de Firebase. Concernant les méthodes, nous avons simplement besoin de la fonction $add() pour ajouter des messages dans Firebase, AngularFire se chargeant de récupérer les messages et de les "binder" avec le HTML.

Côté Javascript, on peut avoir:

var myApp = angular.module("chatApp", ["firebase"]);

myApp.controller('ChatController', ['$scope', '$firebase', function($scope, $firebase) {
  var ref = new Firebase(firebase_chat_url);
  // authentication
  ref.auth(token);

  // getting and sending messages
  $scope.messagesList = $firebase(ref);
  $scope.addMessage = function() {
    if ($scope.message != "") {
      $scope.messagesList.$add({name: userName, message: $scope.message});
    }
  }
}]);

Nous pouvons remarquer qu'il y a une partie d'authentification dans ce code. Comme nous pouvons le voir, il est facile de la mettre en place. Une explication plus détaillée est disponible à la fin de cet article.

Dans le HTML:

<div id="chat-block" ng-app="chatApp" ng-controller="ChatController">
  <div class="msg-box" ng-repeat="msg in messagesList">
     <em></em>: 
  </div>
  <form ng-submit="addMessage()">
      <input type="text" ng-model="message" placeholder="Message...">
      <button class="btn" type="submit">Envoyer</button>
  </form>
</div>

Le document collaboratif

Pour cette partie, nous ne sommes pas partie de zéro. Nous avons utilisé Firepad. C'est une implémentation d'un outil de rédaction de document collaboratif en temps réel avec la gestion de la présence et qui, bien sûr, utilise Firebase.

La mise en place est assez facile.

var firepadDiv = document.getElementById('firepad');
var firepadRef = new Firebase('<firebase url...>');
var codeMirror = CodeMirror(firepadDiv, { lineWrapping: true });
var firepad = Firepad.fromCodeMirror(firepadRef, codeMirror,
    { richTextShortcuts: true, richTextToolbar: true });

Après avoir créé un objet Firebase, il faut instancier l'objet CodeMirror qui est l'éditeur de texte choisi par défaut. L'appel à la fonction Firepad.fromCodeMirror va permettre de recevoir un objet Firepad sur lequel nous allons faire nos opérations.

Retour d'expérience

Les méthodes utiles

Il peut être utile de devoir récupérer ou de modifier directement le contenu du pad depuis le javascript. Deux méthodes sont utilisées pour cela.

firepad.getHtml();
firepad.setHtml(codeHTML);

Respectivement ces méthodes récupèrent le contenu du pad au format HTML et écrasent le contenu actuel avec un nouveau code HTML.

Les protocle ws:// et wss://

Les choses à prendre en compte pendant votre projet quand un client vous demande de faire du temps réel sont les navigateurs utilisés ainsi que le réseau. En effet les protocoles de WebSocket doivent être supportés par le navigateur et le protocole autorisé sur son réseau. Une page de test existe pour tester la connexion avec Firebase. N'hésitez pas à envoyer le lien à votre client pour anticiper les problèmes de compatibilités. En cas de succès la dernière ligne affichée sera "Everything looks good."

L'authentification

Il est possible de s'authentifier pour utiliser Firebase. Une authentification simple peut être faite à partir des services comme Facebook, Twitter, Github, etc... Mais il est aussi possible d'utiliser une authentification personnalisée.

Cette authentification peut être faite grâce à un token JWT. Il est important de générer ce token depuis le serveur et non directement en javascript côté client. Il est possible de mettre des données dans le token JWT qui peuvent être récupérées par la suite, comme par exemple l'ID de l'utilisateur pour savoir quelles données il peut modifier. Dans notre cas nous avons utilisé une librairie PHP pour mettre en place ce token.

La sécurité

Par défaut, si vous vous contentez du code des exemples du site Firebase, aucune notion de sécurité ne sera mise en place. Revenons sur le fonctionnement de Firebase pour notre cas. La connexion à la base ainsi que la lecture des données se fait en javascript côté client. Il est donc assez facile de récupérer le lien Firebase et créer un objet Firebase depuis la console pour ensuite aller lire les données n'importe où dans la base. Cela ne pose pas de problème si vous utilisez Firebase que pour une seule application et qu'il n'y a pas d'authentification sur votre site. Dans notre cas, nous avons utilisé une seule base Firebase pour le chat et le pad collaboratif. De plus nous avons plusieurs pads et chatrooms différents, il était donc indispensable de protéger les données en lecture et écriture.

Pour cela il existe les Security Rules. C'est un objet JSON qui va définir les droits en lecture et écriture pour chaque branche de données. Par défaut nous avons :

{
    "rules": {
        ".read": true,
        ".write": true
    }
}

Tout est autorisé par défaut. Sans changer les règles, n'importe qui pourra aller lire les données et même les modifier !