Résultats de recherche pour json

Php Json Header

Entêtes

Toujours mettre ces en-têtes pour renvoyer du Php au format JSON + s’assurer qu’il n’y aura pas de problème de cache

header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Content-type: application/json');

Exemple complet fonctionnel

<?php
$phrase1=new stdClass();
$phrase1->composition=array('Nom commun', 'Aux + Verbe 3èmePS', 'CC Lieu');
$phrase1->id=12;
$phrase2=new stdClass();
$phrase2->composition=array('Nom commun', 'CC Temps', 'CC Lieu', 'Aux + Verbe 3èmePS');
$phrase2->id=18;
$retour=new stdClass();
$retour->phrases=array($phrase1, $phrase2);
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Content-type: application/json');
echo json_encode($retour);

ExtJS : comment envoyer une form au format JSON ?

Je viens de passer 4 heures à chercher comment envoyer, avec ExtJS, une forme au format JSON.

Ce qui suit ne fonctionne pas :

form.submit({
    type: 'ajax',
    headers: {
        'Content-Type': 'application/json'
    },
    url: '/json/destination.php',
    jsonData: data,
    params: {
        mode: 'update'
    },
    success: function(form, action) {
        /* ok !! */
    },
    failure: function(form, action) {
        /* gérer les erreurs */
    }
});

Si vous essayez d’utiliser la fonction « submit » alors vous risquez, comme moi peut être, de ne pas y arriver.
La solution est :

  • récupérer soi même les données via getValues() ;
  • les encoder au format JSON ;
  • les envoyer avec la méthode Ext.Ajax.request().

Voici un exemple de code qui fonctionne :

var data = Ext.JSON.encode({ data: form.getValues(false) }); 
Ext.Ajax.request({
    headers: {
        'Content-Type': 'application/json'
    },
    url: '/json/destination.php',
    method : 'POST',
    jsonData : data,
    params : {
        mode: 'update'
    },
    success: function(form, action) {
        /* ok !! */
    },
    failure: function(form, action) {
        /* gérer les erreurs */
    }   
});

J’ai perdu 4 heures là dessus, alors si je vous en fais gagner 3, n’oubliez pas de me « flattr » 😉

Flex et JSON

Cette petite astuce va peut-être vous faire gagner du temps si vous débutez et vous voulez écrire rapidement quelque chose :
Cet article écrit ici est très pratique et explique très rapidement comment utiliser JSON et Flex.
Malheureusement c’est il n’explique pas clairement une chose :
Il faut installer la corelib de Adobe pour avoir JSON.
Voici comment faire : téléchargez la corelib d’Adobe ici.
Puis vous le décompressez dans le répertoire que vous voulez. Moi j’ai choisi le plus près d’Adobe, donc dans le répertoire des programmes, section Adobe :

C:\Program Files\Adobe\Flex3.0 - corelib\bin

J’ai crée un répertoire au nom explicite :

Flex3.0 - corelib

Donc j’ai décompressé la totale ici :

C:\Program Files\Adobe\Flex3.0 - corelib

Ensuite, sous Flex, vous créez un nouveau projet, vous faites tout le code que vous voulez, mais il ne faut surtout pas oublier d’y adjoindre le core dès que vous voulez du JSON. Il suffit de cliquer avec le bouton droit de la souris sur le nom du projet, de choisir propriétés (properties), et là une fenêtre s’ouvre, choisissez Flex Build Path et une fenêtre à côté avec deux onglets va s’afficher : choisissez Library Path, et là choisissez le bouton Add SWC (Ajout un fichier SWC) et allez cherche ce fichier binaire :

C:\Program Files\Adobe\Flex3.0 - corelib\bin\corelib.swc

Et voilà !
Dans votre source il ne vous reste plus qu’à faire l’import :

import com.adobe.serialization.json.JSON;

Puis de vous en servir. Voilà un exemple :

  1. Déclaration de la fonction appelée lorsque le chargement est terminé :
      private function aggravationsJSON(event:ResultEvent):void {
       var rawData:String = String(event.result);
       var test:String = JSON.decode(rawData);
       var aggravations:Array = JSON.decode(rawData) as Array;
       // puis plein de code à vous de développer !
      }
    
  2. Enfin la déclaration d’un service avec deux paramètres :
    1. part, valeur = 578 ;
    2. tagg, valeur = 1.
     <mx:HTTPService id="sportsRequest" url="../aggravations.php"
      useProxy="false" method="GET" resultFormat="text"
      result="aggravationsJSON(event)">
      <mx:request xmlns="">
       <part>578</part>
       <tagg>1</tagg>
      </mx:request>
     </mx:HTTPService>

En espérant qu’avec ce morceau de code et l’aide, vous puissiez avancer un peu plus vite !

Linux php : ajout de json

Json est une extension pour JavaScript et php.
Ajout de l’extension Json : il faut aller la récupérer sur le site du créateur (http://aurore.net/), la compiler (make), l’installer (make install), et ensuite, ce qui n’est pas précisé (sauf ici), aller voir dans le fichier php.ini qui est très souvent dans /etc, où se situe le répertoire des extensions extension_dir, c’est sûrement, ici aussi, extension_dir = "/usr/lib".
Il suffit alors de copier le fichier json.so généré dans le répertoire des extensions, ici /usr/lib.
Rien de plus simple !
Résumé très rapide (il faut faire quelques manips en plus, mais le plus important est là) :

  1. wget http://aurore.net/projects/php-json/php-json-ext-1.2.1.tar.bz2
  2. tar -xvf php-json-ext-1.2.1.tar.bz2
  3. cd php-json-ext-1.2.1/
  4. ./configure ; make ; make install
  5. cp /usr/local/lib/php/extensions/no-debug-non-zts-20050922/json.so /usr/lib

IUT : jQuery à rendre

A rendre pour le 18 mars au plus tard


Faites un fichier README.txt et déposez-le ici


Sujet

Ce que vous voulez tant que c’est dans le cadre de ce que l’on a vu. Vous avez tout le Web comme inspiration !
N’oubliez pas de me donner le nom et le mot de passe pour se connecter !

Voici les fonctionnalités obligatoires :

  • Connexion + déconnexion (vu en cours)
  • Effets jQuery sur les éléments
  • Appels JSON : au moins deux appels en plus de ceux vus en cours

Sujets possibles

  1. Site de partage de photos
  2. Site de cocktails (cf ci-dessus)
  3. e-rated : site d’appréciations (selon des sujets, à définir)
  4. Ask-a-question : site où l’on pose des questions sur des sujets divers, et des gens répondent
  5. Write-a-book-together : site où l’on se connecte et où on peut écrire un livre à plusieurs
  6. A-maze-ing : site où l’on peut se ballader dans un labyrinthe et essayer d’en trouver la sortie
  7. Wedding-couple-site : site où l’on uploade + partage des photos de mariage + livre de commandes
  8. Playing-cards-collection : site où on scanne + échange des cartes (Magic the gathering)
  9. Polls-and-surveys : site de création de sondages (= QCM)
  10. Poems-generator : faire un cadavre exquis qui génère des poèmes + possibilité pour les utilisateurs de les noter / d’ajouter des mots
  11. Turn-by-turn : faire un jeu multijoueurs en tour par tour (jeu de cartes, de poker, ou de plateau etc)
  12. The-future-of-post-it : faire un carnet de choses à faire pour les utilisateurs, qui envoie des mails de rappels de ces choses à des dates données
  13. Gift-ideas : un site où l’on va faire des idées de cadeaux / suggérer des idées de cadeaux + les noter (les meilleurs ressortent en premier)
  14. Le-bon-recoin : refaire le bon coin en plus simple
  15. Chat-with-someone : site de chat/discussion
  16. Suggest-crawlers : site de suggestions : on clique sur un mot, il en suggère plein d’autres avec + définitions / liens de sites pour chacuns
  17. Tv-fans : site de présentations + notes d’émissions télé

Sujet imposé si vous n’avez pas d’idée

Cocktails : on se connecte, on a une liste d’éléments (récupérés en JSON) disponibles, on coche ceux qui nous intéressent, on valide, c’est envoyé, et le retour en JSON affiche les cocktails qu’il est possible de faire avec ce que l’on a coché.

Ce que vous devez rendre

Idéalement

Une Url vers un site Web (utilisez Alwaysdata par exemple)

Si vous n’avez pas le choix

Les fichiers source de votre projet

Pour favoriser votre organisation

  • Utilisez ce que l’on a vu en cours (Google boilerplate)
  • Librairies autorisées

    Interdiction d’utiliser une librairie JavaScript qui ne vienne pas des sites autorisés précédemment

    Retard

    Après le dimanche 18 mars minuit

    Fin de semaine de notre dernier cours, soit dimanche à minuit. Passé ce délai ce sera 1 pt par 2 heures de retard (je prendrai en compte la date de réception du mail).
    Pour ceux qui essaient vraiment d’aller jusqu’à la dernière minute, toute heure entamée est comptée comme une heure complète. Exemple : un point en moins si je le reçois le lundi 3 avril à 00:01.
    N’oubliez pas de me donner le nom et le mot de passe pour se connecter !

    Avertissements

    • Copie sur une autre personne (« je se savais pas comment implémenter telle ou telle fonctionnalité dont j’avais besoin pour aller plus loin, je l’ai copiée sur un autre »), deux cas se distinguent :
      • si la personne est clairement nommée, cette fonctionnalité ne sera pas prise en compte dans la notation (= 0 pour cette fonctionnalité) ;
      • si la personne est clairement nommée, et qu’il y a une amélioration de la fonctionnalité : note pour la fonctionnalité divisée par 2 (uniquement la moitié du travail a été faite) ;
      • 0 aux deux personnes sinon ;
    • Si je m’aperçois que vous avez bêtement copié collé des sources Internet, je vous convoquerai pour vous demander de m’expliquer la fonctionnalité, et deux cas se distinguent :
      • si vous ne savez pas m’expliquer le code alors 0 ;
      • si vous savez m’expliquer tout le code alors votre note totale sera divisée par vous + le nombre de contributeurs à ce projet, ce qui se rapprochera certainement de 0 aussi.

    Voici un exemple de ce que vous pouvez faire, si vous choisissez le projet cocktails.

Django / jQuery / Select2 / autocomplete

Voici un tutoriel sur quelque chose qui m’a pris plusieurs jours à réaliser « proprement » et encore, ça n’est pas si propre, mais c’est le mieux que je puisse faire actuellement, en termes de rapport « propreté / temps passé » raisonnable.

Voici l’idée : je veux qu’on puisse commencer à taper quelques lettres dans un champ, et que ce dernier aille demander en AJAX/JSON si jamais il y a des tags « connus ». Si c’est le cas, le retour renvoie une liste, qui s’ouvre, et l’utilisateur peut choisir dans cette liste en descendant avec les flèches. S’il n’y a aucun retour, l’utilisateur peut aller au bout, et envoyer son formulaire, et c’est là que la magie intervient : plus tard, s’il revient sur le formulaire, il pourra taper quelques lettres, et on lui proposera le champ en question ! Mieux ! Il peut séparer les champs par une virgule, et donc taper plusieurs choix. Exactement comme lorsqu’on commence à entrer le nom d’un destinataire sur gmail. La classe non ?

J’ai voulu faire cela pour plein de tags, mais le client pour lequel je faisais cela n’a pas réellement compris l’intérêt et m’a demandé de faire une liste de choix « fixes » que l’utilisateur peut cocher. Bref, no comment.

Donc voici comment j’ai procédé (je ne dis pas que c’est la meilleure façon, il y en a sûrement d’autres, mais vous pouvez vous en inspirer) :
– création d’un modèle Tag qui a la langue (selon les langues, pas le même Tag) :
– dériver un type de champ de base Django forms.TypedChoiceField afin de permettre une liste de choix, mais qui sera valide de deux manières : il faut surcharger les méthodes qui convertissent les valeurs de retour de ce champ, afin :
    – soit d’essayer de lire une liste d’entiers, séparés par des virgules, qui sont les ids des champs,
    – soit pour chaque champ qui ne peut pas être converti en entier, appeler une méthode « custom_tag« , qui va ajouter le tag en base de données puis renvoyer un entier = pk du tag ajouté
– créer un Widget custom dans lequel on passera une classe spéciale destinée au JavaScript qui recherchera cette classe
– en JavaScript (mon ami de toujours, qui fait que je passe 20% du temps sur Django à m’amuser et 80% du temps sur l’habillage Web à rager et/ou bidouiller), faire une routine qui va chercher les widgets définis au-dessus et y appliquer le select2 tel que défini dans la documentation
– faire une vue destinée de recherche qui prend un paramètre, et renvoie les résultats trouvés, c’est pour remplir les demandes d’AJAX de select2. Elle doit renvoyer un tableau « résultat » et une variable « total » qui est simplement le « length » de « résultat ».

C’est tout… enfin tout… on se comprend !

Mais en pratique, une fois que tout est mis en place, il suffit de déclarer dans n’importe quel formulaire un champ ainsi, et on aura un champ entièrement dynamique, qui s’auto-alimentera avec le temps. Extrêmement pratique :


    a = _("Emails:")
    emails = TagTypedChoiceField(
        label=a, required=False,
        custom_tag=add_tag_to_languages,
        widget=Select2Widget(attrs={
            'title': a,
            'placeholder': _("type an email"),
            'multiple': 'multiple',
            'data-select2-json': reverse_lazy(
                'co_branding_json_tags_emails',
                kwargs={'company': 'ubisoft'}),
            'class': 'form-control form-control select2'}),
        error_messages=e,
        choices=self.get_list_tags(Tag.TYPE_EMAIL))

cheatsheet » Django

Django aide-mémoire

Templating

Héritage du parent {% block menu %}
{{ block.super }}
{% endblock %}

Astuces

Afficher des messages uniques à l’utilisateur
Ex: « Merci de vous être inscrit » etc.
Infrastructure des messages

SQL

Requête directe

Lancer la console python (Tools » Python console),
puis taper :
from django.db import connection
cursor = connection.cursor()
cursor.execute("PRAGMA table_info(langue)")
for c in cursor.fetchall():
    print(c)


Autre exemple :
from django.db import connection
cursor = connection.cursor()
cursor.execute("delete from app_persongame where person_id=1")
cursor.fetchall()
cursor.execute("update app_persongame set state=1 where person_id=2")
cursor.fetchall()

Sauvegarde / restauration

Lancer via manage.py ([CTRL] + [ALT] + r sous PyCharm) :
Sauvegarde : dumpdata -o data.json
Restauration : loaddata data.json

Multilangue

Créer tous les fichiers en ignorant mes librairies tierces :
makemessages --locale fr --locale en --ignore third_party
Multilangue JavaScript : préciser le domaine
makemessages -d djangojs -i third_party --locale fr --locale en
Ne pas oublier : compilemessages … et de redémarrer le serveur !

Multilangue : chaînes custom

Dupliquer le dossier locale hors de vos applications (= je le fais dans le dossier principal), exemple :
locale »»»» locale_unity
Modifier LOCALE_PATHS du fichier settings.py comme suit :
LOCALE_PATHS = (
    os.path.join(BASE_DIR, 'locale'),
    os.path.join(BASE_DIR, 'locale_unity'),
)
Modifiez les fichiers .po concernés.
Ne pas oublier : compilemessages … et de redémarrer le serveur !

Multilangue / JavaScript

Declaration dans urls.py

Attention, ici « app » = dossier d’une application qu’on veut traduire, moi je les appelle souvent « app ». :

from django.views.i18n import javascript_catalog, JavaScriptCatalog

js_info_dict = {
    'packages': ('app',)
}

urlpatterns = [
    url(r'^i18n/', include('django.conf.urls.i18n')),
    # blabla
]
urlpatterns += i18n_patterns(
    url(r'^jsi18n/$', javascript_catalog, js_info_dict,
        name='javascript_catalog'),
    # blabla
)

Inclure les fichiers js dans la page HTML

<script src="{% url 'javascript_catalog' %}"></script>

Ajouter aussi le fichier personnel où je mets ma fonction « raccourci » pour la traduction :
<script src="{% static 'js/globals.js' %}"></script>

Ma fonction « raccourci » pour la traduction :
function _(a) {
    return gettext(a);
}

Extraction des chaines et traduction

Très important : récupérer les chaines en précisant le domaine djangojs :
makemessages -d djangojs -i third_party --locale fr --locale en

À partir de là, deux fichiers de traduction : le classique django.po et le nouveau djangojs.po.

Exemple de code JavaScript qui fera partie des chaînes à traduire

$('#menu').empty().append(
    $('<h5 />').html(_('Waiting...'))
);

Installation

Python 2.7

virtualenv venvpython2.7/
source venvpython2.7/bin/activate
pip install --upgrade pip
pip install 'django==1.8'
mkdir htdocs
cd htdocs

Python 3.6

virtualenv -p /usr/local/bin/python3.6 venvpython3.6
source venvpython3.6/bin/activate
pip install --upgrade pip
pip install 'django==1.11'

Installez django_markdown_app au lieu de django_markdown (car c’est le successeur, django_markdown n’est plus maintenu !)

pip install django_markdown_app
pip install django-compressor
pip install python3-openid
pip install pytz
mkdir htdocs
cd htdocs

PostgreSQL

Création d’un utilisateur + mot de passe

Être root. De là, taper :
sudo -i -u postgres
psql [nom base de donnees]
CREATE USER interro WITH PASSWORD 'i';
Très important : lui donner tous les droits sur la base :
GRANT ALL PRIVILEGES ON DATABASE "interro" to interro;
Et si l’utilisateur existe déjà :
ALTER USER interro WITH PASSWORD 'i';

Changement d’owner des tables

Se connecter à la base. Allez je mets la commande Windows :
"\Program Files\PostgreSQL\9.5\bin\psql.exe" -U postgres interro
. De là, taper (j’ai bien mis en gras le nom de l’utilisateur à qui on donne les tables) :
SELECT 'ALTER TABLE '|| schemaname || '.' || tablename ||'
OWNER TO interro;' FROM pg_tables
WHERE NOT schemaname IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename;

Et PostgreSQL va sortir une floppée de « ALTER TABLE...« , il suffit juste de les copier/coller dans le prompt pour les appliquer.

Vues Login / logout

– Créer l’URL de login :
url(r'^login/$', LoginView.as_view(), name='login'),

– Créer la vue LoginView
from django.contrib.auth import views

class LoginView(views.LoginView):
    template_name = 'login.html'

    def __init__(self):
        pass

– Créer l’URL de logout :
url(r'^logout/$', LogoutView.as_view(), name='logout'),

– Créer la vue LogoutView
from django.contrib.auth import views

class LogoutView(views.LogoutView):

    def __init__(self):
        self.next_page = '/'

<form action="{% url 'login' %}" method="post" accept-charset="utf-8">
    {% csrf_token %}
    {% for field in form %}
        <label>{{ field.label }}</label>
        {% if field.errors %}
            {{ field.errors }}
        {% endif %}
        {{ field }}
    {% endfor %}
    <input type="hidden" name="next" value="{{ next }}" />
    <input class="button small" type="submit" value="Submit"/>
</form>

lua : avantages et inconvénients

Résumé

Je viens de créer ma première application Web en lua.

Pour ceux qui ne savent pas ce que c’est : google est votre ami, mais pour résumer :

Je commence par les inconvénients parce qu’ils sont tellement particuliers qu’il faut les avoir en tête avant d’aller plus loin. Si jamais ça ne vous rebute pas trop, lisez les avantages et ce sera à vous de juger, si, en mettant le tout sur votre balance, ça penche plus vers le positif ou vers le négatif.

En résumé, tous les avantages qui suivent font que, même s’il faut pas mal se débrouiller au début parce qu’il manque beaucoup d’outils « déjà faits », au final le langage est tellement lisible qu’on arrive assez rapidement à se faire ses outils, et en allant un peu plus loin, la maintenance (qui est la chose la plus coûteuse sur les grosses applications) se retrouve améliorée au lieu d’être dégradée. Après, c’est un constat qui n’engage que moi, mais de très grosses applications, notamment nmap tournent d’ores et déjà avec une liste faramineuse de plugins, tous écrits en lua, et facilement compréhensibles.

Inconvénients

Voici les inconvénients de base, qui ne sont pas propres au langage :

  • il faut tout faire soi-même :
    • aucune gestion avancée des fichiers (de base, sans aucun module complémentaire, il ne sait même pas dire si un fichier existe ou pas)
    • côté Web, aucune gestion des sessions
    • côté Web, rien de base en ce qui concerne le json (j’ai plus d’une demi journée à chercher une implémentation entièrement potable de json)

Voici les inconvénients du langage même :

  • Il ne connait pas les classes d’origine, il faut faire un hack pour « simuler » des classes
  • Par conséquence, il n’y a aucune notion d’héritage, à moins de hacker là aussi.
  • Tous les entiers sont des flottants par défaut
  • Aucune possibilité de trace simple. Si on veut remonter dans la pile d’appels, on ne peut sortir qu’une seule ligne (on précise le niveau de la pile)
  • Toutes les variables sont globales par défaut, sauf si on précise systématiquement local
  • La syntaxe permet des horreurs innommables : si jamais on ne passe qu’un seul paramètre, les parenthèses ne sont pas obligatoires, ce qui donne quelque chose de possible comme : mafonction{a=12,b=13}
  • Les séparateurs ne sont pas clairement définis – et c’est volontaire pour permettre plus de liberté, donc on peut écrire ceci : local a = { b=15; c=23 } ou ceci : local a = { b=15, c=23 }. Imaginez le problème… On voit déjà qu’en Php, en laissant un peu de liberté, on arrive à un bazar gigantesque à l’échelle planétaire, je vous raconte même pas ce qu’il est possible de faire ici
  • Les packages en tant que tel n’existent pas, et il faut là aussi faire des bidouilles pour « simuler » des packages
  • Il y a ici aussi, comme en JavaScript, la notion de « closure » afin de pouvoir faire sortir des variables hors d’un contexte d’où elles ne sont pas censées sortir. Certains voient les closures comme un avantage, moi qui ait programmé en C – et un peu en C++ – je vois les closures comme une solution pour pallier à un défaut du langage, en bidouillant.
  • Le signe différent n’existe pas sous la forme classique <> ou encore != mais il s’écrit ainsi : ~=
  • Pour supprimer une variable (unset() en Php), il faut la mettre à nil. Bizarre. Supprimer l’indice 12 : a[12] = nil
  • Attention tenez vous bien j’ai gardé le pire pour la fin : les indices des tableaux commencent à 1. Ce n’est pas une blague. En C, C++, Java, JavaScript, Python, bref, dans tous les langages que je connais, les indices de tableau commencent à 0, et là non, ils commencent à 1. C’est à la limite la seule et unique chose qui me rebute énormément tellement c’est problématique, car, de plus, une des grosses forces mises en avant du lua, c’est le fait qu’il gère extrêmement bien les tables. Oui, mais les indices des tableaux commencent à 1.

Avantages

Je ne sais pas pourquoi, mais lua me plaît. Et je pense que tous les développeurs qui aiment bien ce langage sont un peu comme moi. Il a énormément d’inconvénients, pourtant il des côtés tellement pratiques qu’au final, on l’aime bien. Un peu comme moi (…).

Parmi les avantages que j’apprécie particulièrement :

  • Pas d’accolades ouvrantes / fermantes, mais juste le début d’une déclaration (function, if, ou for), et la fin avec un end. C’est juste plus lisible qu’ouvrir des accolades et fermer des accolades (et croyez moi, je m’y connais bien dans ce domaine !)
  • Les assignations multiples : il est possible d’assigner plusieurs choses en une seule ligne, et ça reste lisible (j’insiste sur ce dernier point : ça reste lisible). Exemple concret : a, b = b, a;. Ce code va inverser les deux valeurs.
  • Même chose que précédemment mais pour les fonctions : elles peuvent renvoyer plusieurs valeurs, et par là même, on peut faire plusieurs assignations et ça reste lisible. Exemple simple : x, y = getCoordonneesJoueur(); ou plus classique handle, error = ouvrirFichier(nomfichier). Avec ce dernier code, si handle vaut nil alors on affiche error qui est rempli.
  • Machine virtuelle : il tourne systématiquement dans une machine virtuelle, ce qui implique par là même une impossibilité technique de défaillance, et c’est vous-même qui précisez, pour les modules qui tourneront, quelles sont les fonctions sont accessibles – ou pas. Si la NASA se sert activement de LUA ce n’est pas pour rien. Ce qui me permet d’enchaîner sur le point suivant.
  • Un des gros intérêts est de pouvoir créer des plugins, les lire et les interpréter, un peu comme en Php, eval(). Comme ces plugins sont dans une machine virtuelle très stable et éprouvée, vous pouvez mettre en place un système de plugins très performant, efficace et stable. Rien que le fait de pouvoir faire cela peut être une motivation pour apprendre le lua, car il y a très peu de langages qui tournent de manière aussi sécurisée, et aussi rapidement que lua (voire aucun).

NodeJS et MongoDB : requête « JOIN » fonctionnelle

// Exemple copié collé et adapté sur stackoverflow :              
// http://stackoverflow.com/questions/15630770/node-js-check-if-path-is-file-or-directory
// http://stackoverflow.com/questions/7268033/basic-static-file-server-in-nodejs 
//                                                                               
var http = require('http'),                                            
    url = require('url'),                          
    fs = require('fs'),                            
    mongoose = require('mongoose'),                
    fileSystem = require('fs'),                    
    path = require('path');                        
var mimeTypes = {                                                                
    "html": "text/html",                 
    "jpeg": "image/jpeg",                
    "jpg": "image/jpeg",                 
    "png": "image/png",                  
    "js": "text/javascript",             
    "css": "text/css"};                  
                                                                                 
var server;                                                                      
var Schema = mongoose.Schema;                                                    
                                                                                 
mongoose.connect('mongodb://localhost/test');                          
var db = mongoose.connection;                                                    
                                                                                 
var creneauSchema = new Schema({                                                 
    libelle:    String,                                      
    date_debut: { type: Date, default: Date.now },           
    date_fin:   { type: Date, default: Date.now },           
    heure_debut: Number,                                     
    duree: Number,                                           
    creneauxJours_id: { type: Schema.Types.ObjectId, ref: 'CreneauJours' }
});                                                                              
var Creneau = db.model('Creneau', creneauSchema);                      
                                                                                 
var creneauJoursSchema = new Schema({                                            
    jours_semaine: [Number]                                  
});                                                                              
var CreneauJours = db.model('CreneauJours', creneauJoursSchema);       
                                                                                 
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {                                          
    console.log('DB connexion reussie');           
    //var cj = new CreneauJours({                            
    //    jours_semaine: [1,2,3,4,5]                         
    //});                                                    
    //cj.save(function (err) {                               
    //    if (err) { return console.log(err); }              
    //    console.log('Écriture réussie');
    //    var c = new Creneau({                              
    //        libelle: "Après midi à 16 heures",
    //        date_debut: new Date(2010, 1, 1),              
    //        date_fin:   new Date(2020, 1, 1),              
    //        heure_debut: 16,                               
    //        duree: 120,                                    
    //        creneauxJours_id: cj._id                       
    //    });                                                
    //    c.save(function (err) {                            
    //        if (err) { return console.log(err); }          
    //        console.log('Écriture 2 réussie');
    //    });                                                
    //});                                                    
    //return;                                                
                                                                                 
    server = http.createServer(function (request, response) {
        if (request.url=='/creneaux') {
            console.log("> JSON");
            Creneau  
            .find({})
            .select('_id libelle date_debut date_fin heure_debut duree creneauxJours_id')
            .populate('creneauxJours_id')
            .exec(function (err, c) {
                if (err) {
                    return console.log(err);
                }
                console.log(c);
                var retour='[';
                for (var i = 0; i < c.length; i++) {
                    retour += '{'
                        + 'id:' + JSON.stringify(c[i]._id)+', '
                        + 'libelle:' + JSON.stringify(c[i].libelle)+', '
                        + 'date_debut:' + c[i].date_debut+', '
                        + 'date_fin:' + c[i].date_fin+', '
                        + 'heure_debut:' + c[i].heure_debut+', '
                        + 'duree:' + c[i].duree+', '
                        + 'jours:[' + c[i].creneauxJours_id.jours_semaine + ']'
                        + '},';
                };
                /* Enlever la dernière virgule : */
                retour=retour.substr(0, retour.length-1)+']';
                response.writeHead(200, {
                    'Cache-Control': 'no-cache, must-revalidate',
                    'Expires': 'Mon, 26 Jul 1997 05:00:00 GMT',
                    'Content-type': 'application/json'
                });
                response.end(retour);
            });      
            // Stopper tout traitement :
            return;  
        }                                
        var uri = url.parse(request.url).pathname;
        var filename = path.join(process.cwd(), uri);
        console.log("> " + filename);
        fs.exists(filename, function(exists) {
            if ((!exists) || (fs.lstatSync(filename).isDirectory())) {
                console.log(">> fichier inexistant : " + filename);
                response.writeHead(200, {'Content-Type': 'text/plain'});
                response.write('404 Not Found\n');
                response.end();
                // Stopper tout traitement :
                return;
            }        
            var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
            response.writeHead(200, {'Content-Type':mimeType});
                                                                                 
            var fileStream = fs.createReadStream(filename);
            fileStream.pipe(response);
        });                              
                                                                                 
    });                                                      
    // Listen on port 8000, IP defaults to 127.0.0.1         
    server.listen(8000);                                     
    // Put a friendly message on the terminal                
    console.log("Server running at http://127.0.0.1:8000/");
});

NodeJS qui sert des fichiers et accède à MongoDB

// Exemple copié collé et adapté sur stackoverflow :
// http://stackoverflow.com/questions/15630770/node-js-check-if-path-is-file-or-directory
// http://stackoverflow.com/questions/7268033/basic-static-file-server-in-nodejs
//
var http = require('http'),
    url = require('url'),
    fs = require('fs'),
    mongoose = require('mongoose'),
    fileSystem = require('fs'),
    path = require('path');
var mimeTypes = {
    "html": "text/html",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "png": "image/png",
    "js": "text/javascript",
    "css": "text/css"};

var server;
var Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;

var personneSchema = new Schema({
  nom: String,
  prenom: String
});
var Personne = db.model('Personne', personneSchema);

db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
    console.log('DB connexion reussie');
    server = http.createServer(function (request, response) {
        if (request.url=='/personnes') {
            console.log("> JSON");
            Personne.find({}).select('nom prenom').exec(function (err, p) {
                if (err) {
                    return console.log(err);
                }
                var retour='[';
                for (var i = 0; i < p.length; i++) {
                    retour+='{'+ p[i].nom+', '+p[i].prenom+'},';
                };
                retour=retour.substr(0, retour.length-2)+']';
                response.writeHead(200, {
                    'Cache-Control': 'no-cache, must-revalidate',
                    'Expires': 'Mon, 26 Jul 1997 05:00:00 GMT',
                    'Content-type': 'application/json'
                });
                response.end(retour);
            });
            // Stopper tout traitement :
            return;
        }
        var uri = url.parse(request.url).pathname;
        var filename = path.join(process.cwd(), uri);
        console.log("> " + filename);
        fs.exists(filename, function(exists) {
            if ((!exists) || (fs.lstatSync(filename).isDirectory())) {
                console.log(">> fichier inexistant : " + filename);
                response.writeHead(200, {'Content-Type': 'text/plain'});
                response.write('404 Not Found\n');
                response.end();
                // Stopper tout traitement :
                return;
            }
            var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
            response.writeHead(200, {'Content-Type':mimeType});

            var fileStream = fs.createReadStream(filename);
            fileStream.pipe(response);
        });

        //var p = new Personne({
        // nom: 'Pons',
        // prenom: 'Olivier'
        //});
        //p.save(function (err) {
        // if (err) {
        // return console.log(err);
        // }
        // var query = Personne.find();
        // query.select('nom prenom');
        // query.exec(function (err, p) {
        // if (err) return console.log(err);
        // for (var i = 0; i < p.length; i++) {
        // console.log(p[i].nom+' '+p[i].prenom);
        // };
        // console.log('Nombre total d\'enregistrements : '+p.length);
        // });
        //})
    });
    // Listen on port 8000, IP defaults to 127.0.0.1
    server.listen(8000);
    // Put a friendly message on the terminal
    console.log("Server running at http://127.0.0.1:8000/");
});