From 1eaef253e3c3436668379409472d27d45b7fd2b6 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 5 Oct 2008 19:01:26 +0000 Subject: [PATCH 01/16] --- tools/start_yaws.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/start_yaws.sh b/tools/start_yaws.sh index 87e6e4e..8b9311e 100755 --- a/tools/start_yaws.sh +++ b/tools/start_yaws.sh @@ -1,3 +1,3 @@ -#!/bin/bash +#!/bin/bash # screen est utilisé par exemple pour lancé une version de preproduction et permettre de la faire tourner après un délog -screen -S yawspreprod yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../var/BD/" -I debian_yaws_dev +yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../var/BD/" -I debian_yaws_dev -- 2.45.2 From 8ee1535f5594573931ddaebee77bf6148a5358cb Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Mon, 6 Oct 2008 08:21:00 +0000 Subject: [PATCH 02/16] REPORT de la branche 1.1 (459->476) --- js/betterjs.js | 1 + js/client.js | 6 +- js/formateur.js | 4 +- js/fragment.js | 8 +- js/pageMinichat/commandes.js | 41 +++- js/pageMinichat/conversation.js | 43 +++- js/pageMinichat/conversations.js | 6 +- js/pageMinichat/pageMinichat.js | 32 ++- js/util.js | 18 +- modules/Makefile | 6 +- modules/erl/euphorik_bd.erl | 116 +++++------ modules/erl/euphorik_bd_admin.erl | 194 +++++++++++++----- .../erl/euphorik_minichat_conversation.erl | 53 +++-- modules/erl/euphorik_protocole.erl | 2 +- modules/erl/euphorik_test.erl | 54 +++-- modules/include/euphorik_bd.hrl | 12 +- styles/1/euphorik.css | 10 + styles/1/pageMinichat.css | 20 ++ styles/2/euphorik.css | 9 + styles/2/pageMinichat.css | 12 ++ tools/mise_en_prod.erl | 40 +++- tools/start_yaws.sh | 3 +- tools/tools.rb | 47 +++-- 23 files changed, 488 insertions(+), 249 deletions(-) diff --git a/js/betterjs.js b/js/betterjs.js index 69788d8..d982030 100644 --- a/js/betterjs.js +++ b/js/betterjs.js @@ -1,3 +1,4 @@ +// coding: utf-8 // tout un tas d'améliorations de JavaScript ;) diff --git a/js/client.js b/js/client.js index 49f7749..c378075 100644 --- a/js/client.js +++ b/js/client.js @@ -26,7 +26,7 @@ euphorik.Client = function(util, communication) { this.communication = communication; this.cookie = null; - this.regexCookie = /^cookie=([^;]*)/; + this.regexCookie = /cookie=([^;]*)/; // données personnels this.resetDonneesPersonnelles(); @@ -295,7 +295,7 @@ euphorik.Client.prototype.getJSONEnregistrement = function(login, password) { }; /** - * Connexion. Réalisée de manière synchrone. + * Connexion. Réalisé de manière synchrone. */ euphorik.Client.prototype.connexion = function(action, messageJson) { var thisClient = this; @@ -369,7 +369,7 @@ euphorik.Client.prototype.flush = function(async) { if (!this.authentifie()) { return false; } - + var thisClient = this; var ok = true; diff --git a/js/formateur.js b/js/formateur.js index 4b74d44..eba6c5a 100644 --- a/js/formateur.js +++ b/js/formateur.js @@ -28,7 +28,7 @@ euphorik.Formateur = function() { this.regexUrl = new RegExp("(?:(?:" + this.protocoles + ")://|www\\.)[^ ]*", "gi"); this.regexImg = new RegExp("^.*?\\.(gif|jpg|png|jpeg|bmp|tiff)$", "i"); - this.regexDomaine = new RegExp("^(?:(?:" + this.protocoles + ")://|www\\.).*?([^/.]+\\.[^/.]+)(?:$|/).*$", "i"); + this.regexDomaine = new RegExp("^(?:(?:" + this.protocoles + ")://)(.*?)(?:$|/).*$", "i"); this.regexTestProtocoleExiste = new RegExp("^(?:" + this.protocoles + ")://.*$", "i"); this.regexNomProtocole = new RegExp("^(.*?)://"); }; @@ -124,7 +124,7 @@ euphorik.Formateur.prototype.traiterWikiSyntaxe = function(m) { /** * Renvoie une version courte de l'url. - * par exemple : http://en.wikipedia.org/wiki/Yakov_Smirnoff devient wikipedia.org + * par exemple : http://en.wikipedia.org/wiki/Yakov_Smirnoff devient en.wikipedia.org */ euphorik.Formateur.prototype.getShort = function(url) { var estUneImage = false; diff --git a/js/fragment.js b/js/fragment.js index ef087f4..4ffbf8f 100644 --- a/js/fragment.js +++ b/js/fragment.js @@ -21,12 +21,18 @@ */ Fragment = function() { var thisFragment = this; + // remplacement des codes de type %22 (en hexa) + var replaceHtmlCode = function(str) { + return str.replace(/%(\d\d)/g, function(text, code) { + return String.fromCharCode(parseInt(code, 16)); + }); + }; this.fragments = {}; if (!window.location.hash) { return; } try { - var fragmentsStr = window.location.hash.slice(1).split(";"); + var fragmentsStr = replaceHtmlCode(window.location.hash.slice(1)).split(";"); fragmentsStr.each(function(i, tuple) { tuple = tuple.split("="); thisFragment.fragments[tuple[0]] = JSON.parse(tuple[1]); diff --git a/js/pageMinichat/commandes.js b/js/pageMinichat/commandes.js index f49ce9a..014b9bb 100644 --- a/js/pageMinichat/commandes.js +++ b/js/pageMinichat/commandes.js @@ -27,14 +27,30 @@ * /nick * Modifie le pseudo courant */ -euphorik.Commandes = function(client) { +euphorik.Commandes = function(client, pageMinichat, util, formateur) { + var thisCommandes = this; + this.client = client; + this.pageMinichat = pageMinichat; + this.util = util; + this.formateur = formateur; + + // construction du texte d'aide (liste des commandes) de manière statique + this.texteAide = "

Commandes

    "; + objectEach( + euphorik.Commandes.liste, + function(nom, commande) { + thisCommandes.texteAide += "
  • " + thisCommandes.formateur.traitementComplet(commande.usage) + " : " + thisCommandes.formateur.traitementComplet(commande.description) + "
  • "; + } + ); + this.texteAide += "
"; }; euphorik.Commandes.statut = {ok : 0, pas_une_commande : 1, erreur_commande : 2}; euphorik.Commandes.liste = { "nick" : { + description : "Change le pseudo courant", usage : "/nick ", exec : function(args, client) { @@ -47,7 +63,15 @@ euphorik.Commandes.liste = { return [euphorik.Commandes.statut.ok, '']; } - } + }, + "cpf" : { + description : "Envoie le message \"C'est pas faux\"", + usage : "/cpf", + exec : function(args, client, pageMinichat) { + pageMinichat.envoyerMessage("C'est pas faux"); + return [euphorik.Commandes.statut.ok, '']; + } + } }; /** @@ -68,9 +92,20 @@ euphorik.Commandes.prototype.exec = function(chaine) { if (nomCommande === "") { return [euphorik.Commandes.statut.erreur_commande, 'La commande est vide']; } + // commandes spéciales pour afficher l'aide : "?", "h", "help", "aide" + if (nomCommande === "?" || nomCommande === "h" || nomCommande === "help" || nomCommande === "aide") { + this.util.messageDialogue( + this.texteAide, + euphorik.Util.messageType.informatif, + {"fermer" : function(){}}, + false, + -1 + ); + return [euphorik.Commandes.statut.ok, '']; + } if (euphorik.Commandes.liste.hasOwnProperty(nomCommande)) { - return euphorik.Commandes.liste[nomCommande].exec(args, this.client); + return euphorik.Commandes.liste[nomCommande].exec(args, this.client, this.pageMinichat); } return [euphorik.Commandes.statut.erreur_commande, 'La commande /' + nomCommande + ' est inconnue']; diff --git a/js/pageMinichat/conversation.js b/js/pageMinichat/conversation.js index 2810b1b..acd7d67 100644 --- a/js/pageMinichat/conversation.js +++ b/js/pageMinichat/conversation.js @@ -244,15 +244,22 @@ euphorik.Conversation.prototype.flush = function() { var messagePair = (this.idDernierMessageAffiche === 0 ? true : ($("#" + this.getId() + " .messages div:" + (reverse ? "first" : "last")).attr("class").search("messagePair") === -1) - ); + ); + + // permet d'itérer sur les nouveaux messages à afficher + var pourChaqueNouveauMessage = function(f) { + thisConversation.messages.each(function(i, mess) { + if (mess.id > thisConversation.idDernierMessageAffiche) { + f(mess); + } + }); + }; // construction de l'XHTML des messages - var XHTML = ""; - this.messages.each(function(i, mess) { - if (mess.id > thisConversation.idDernierMessageAffiche) { - XHTML += mess.XHTML(messagePair, thisConversation.getId()); - messagePair = !messagePair; - } + var XHTML = ""; + pourChaqueNouveauMessage(function(mess) { + XHTML += mess.XHTML(messagePair, thisConversation.getId()); + messagePair = !messagePair; }); var DOM = $(XHTML); @@ -274,11 +281,25 @@ euphorik.Conversation.prototype.flush = function() { } else { $("#" + this.getId() + " .messages .message").slice(0, nbMessagesAffiche - this.nbMessageMax).remove(); } - } + } + + // met à jour la classe des messages auquels repondent les nouveaux messages + // dans le cas où ce message appartient au client courant (c'est un peu de la triche) TODO : ya mieux ? + pourChaqueNouveauMessage(function(mess) { + if (mess.auteurId === thisConversation.client.id) { + objectEach(mess.repondA, function(messId) { + var mess = thisConversation.messagesParId[messId]; + if (mess) { + mess.clientARepondu = true; + $("#conversations #" + mess.getId(thisConversation.getId())).addClass("repondu") + } + }); + } + }); if (this.messages.length > 0) { this.idDernierMessageAffiche = this.messages[this.messages.length-1].id; - } + } // met à jour la racine de la conversation this.majRacine(); @@ -326,7 +347,7 @@ euphorik.Conversation.prototype.attacherEventsSurMessage = function(element) { // donne le focus à la ligne de saisie $("form input.message").focus(); }).hover(function() { // affiche les outils liées au message - var top = $(this).offset().top + var top = $(this).offset().top; var left = $(this).offset().left + $(this).outerWidth() - thisConversation.util.outilsMessage.outerWidth(); $(".extraire", thisConversation.util.outilsMessage).unbind(); $(".extraireCompletement", thisConversation.util.outilsMessage).unbind(); @@ -336,7 +357,7 @@ euphorik.Conversation.prototype.attacherEventsSurMessage = function(element) { thisConversation.util.infoBulle("Extraction de la conversation complète", $(".extraireCompletement", thisConversation.util.outilsMessage)); thisConversation.util.outilsMessage.css("top", top).css("left", left).prependTo(this).show(); }, function() { - thisConversation.util.outilsMessage.hide() + thisConversation.util.outilsMessage.hide(); }); // mise en évidence de la conversation diff --git a/js/pageMinichat/conversations.js b/js/pageMinichat/conversations.js index b99e092..94236c1 100644 --- a/js/pageMinichat/conversations.js +++ b/js/pageMinichat/conversations.js @@ -63,11 +63,11 @@ euphorik.Conversations.prototype.toggleMessageRepond = function(mess) { euphorik.Conversations.prototype.mettreAJourFragment = function() { conv = []; for(var i = 1; i < this.conversations.length; i++) { - conv.push(this.conversations[i].racine.id) + conv.push(this.conversations[i].racine.id); } this.fragment.setVal("conv", conv); this.fragment.write(); -} +}; /** * Enlève tous les messages auquel l'utilisateur souhaite répondre. @@ -195,7 +195,7 @@ euphorik.Conversations.prototype.getJSONrafraichirMessages = function() { }; euphorik.Conversations.prototype.getJSONConversations = function() { - var thisConversations = this + var thisConversations = this; var clientConv = []; this.client.conversations.each(function(i, conv) { diff --git a/js/pageMinichat/pageMinichat.js b/js/pageMinichat/pageMinichat.js index f11dea4..b71efea 100755 --- a/js/pageMinichat/pageMinichat.js +++ b/js/pageMinichat/pageMinichat.js @@ -25,7 +25,7 @@ euphorik.PageMinichat = function(client, formateur, util, communication) { this.formateur = formateur; this.util = util; this.communication = communication; - this.commandes = new euphorik.Commandes(this.client); + this.commandes = new euphorik.Commandes(this.client, this, this.util, this.formateur); // permet d'éviter d'envoyer plusieurs messages simultanément en pressant // rapidement sur "enter" par exemple @@ -163,7 +163,7 @@ euphorik.PageMinichat.prototype.charger = function() { var retCommandes = thisPage.commandes.exec(message); switch (retCommandes[0]) { case euphorik.Commandes.statut.pas_une_commande : - thisPage.envoyerMessage($("form#posterMessage input.pseudo").val(), message); + thisPage.envoyerMessage(message); break; case euphorik.Commandes.statut.erreur_commande : thisPage.util.messageDialogue(retCommandes[1], euphorik.Util.messageType.erreur); @@ -213,18 +213,23 @@ euphorik.PageMinichat.prototype.chargerConversationsFragment = function() { } catch(e) { ;; console.log(e) } -} +}; euphorik.PageMinichat.prototype.decharger = function() { this.conversations.comet.stopAttenteCourante(); $("body #smiles").remove(); - this.fragment.delVal("conv") + this.fragment.delVal("conv"); }; -euphorik.PageMinichat.prototype.envoyerMessage = function(pseudo, message) { - var thisPageMinichat = this; +/** + * Envoie un nouve message donné, le pseudo utilisé est celui se trouvant + * dans la zone de saisie (form#posterMessage input.pseudo). + */ +euphorik.PageMinichat.prototype.envoyerMessage = function(message) { + var thisPageMinichat = this; + var pseudo = $("form#posterMessage input.pseudo").val(); // (un pseudo vide est autorisé) pseudo = this.formateur.filtrerInputPseudo(pseudo); @@ -239,6 +244,8 @@ euphorik.PageMinichat.prototype.envoyerMessage = function(pseudo, message) { this.util.messageDialogue("Le message est vide"); return; } + + this.client.pseudo = pseudo; if (!this.client.authentifie()) { if (!this.client.enregistrement()) { @@ -247,8 +254,6 @@ euphorik.PageMinichat.prototype.envoyerMessage = function(pseudo, message) { } } - this.client.pseudo = pseudo; - // évite le double post if (this.envoieMessageEnCours) { this.util.messageDialogue("Message en cours d'envoie..."); @@ -260,17 +265,6 @@ euphorik.PageMinichat.prototype.envoyerMessage = function(pseudo, message) { "put_message", this.getJSONMessage(pseudo, message), function() { - // TODO : revoir cette partie - // met à jour la classe des messages auquel repond celui ci (c'est un peu de la triche) TODO : ya mieux ? - objectEach(thisPageMinichat.conversations.messagesRepond, function(messId) { - thisPageMinichat.conversations.conversations.each(function(i, conv) { - var mess = conv.messagesParId[messId]; - if (mess) { - mess.clientARepondu = true; - $("#conversations #" + mess.getId(conv.getId())).addClass("repondu") - } - }); - }); $("form#posterMessage input.message").val(""); thisPageMinichat.conversations.enleverMessagesRepond(); thisPageMinichat.envoieMessageEnCours = false; diff --git a/js/util.js b/js/util.js index c859831..f5fca3f 100644 --- a/js/util.js +++ b/js/util.js @@ -43,14 +43,16 @@ euphorik.Util.messageType = {informatif: 0, question: 1, erreur: 2}; * @param message le message (string) * @param type voir 'messageType'. par défaut messageType.informatif * @param les boutons sous la forme d'un objet ou les clefs sont les labels des boutons - * et les valeurs les fonctions executées lorsqu'un bouton est activé. - * @param formate faut-il formaté le message ? true par défaut + * et les valeurs les fonctions executées lorsqu'un bouton est activé. + * Lorsqu'un bouton est activé le message se ferme. + * @param formate faut-il formaté le message ? true par défaut + * @param temps le temps d'affichage du message en seconde, -1 pour une durée infinie */ -euphorik.Util.prototype.messageDialogue = function(message, type, boutons, formate) { +euphorik.Util.prototype.messageDialogue = function(message, type, boutons, formate, temps) { var thisUtil = this; type = type || euphorik.Util.messageType.informatif; - formate = formate || true; + formate = formate === undefined ? true : formate; if (this.timeoutMessageDialogue) { clearTimeout(this.timeoutMessageDialogue); @@ -58,7 +60,7 @@ euphorik.Util.prototype.messageDialogue = function(message, type, boutons, forma var fermer = function() { $("#info").slideUp(100); }; fermer(); - + $("#info .message").html(!thisUtil.formateur || !formate ? message : thisUtil.formateur.traitementComplet(message)); switch(type) { @@ -72,8 +74,10 @@ euphorik.Util.prototype.messageDialogue = function(message, type, boutons, forma $("#info .boutons").append("
" + nom + "
").find("div:last").click(bouton).click(fermer); }); - $("#info").slideDown(200); - this.timeoutMessageDialogue = setTimeout(fermer, euphorik.conf.tempsAffichageMessageDialogue); + $("#info").slideDown(200); + if (temps !== -1) { + this.timeoutMessageDialogue = setTimeout(fermer, temps || euphorik.conf.tempsAffichageMessageDialogue); + } }; euphorik.Util.positionTypeX = {gauche: 0, gaucheRecouvrement: 1, centre: 2, droiteRecouvrement: 3, droite: 4}; diff --git a/modules/Makefile b/modules/Makefile index 0a77892..859cc56 100755 --- a/modules/Makefile +++ b/modules/Makefile @@ -41,7 +41,7 @@ $(rep_ebin)/euphorik_bd.beam: $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik erlc $(erlc_params) # Module pour la mise à jour de la BD -$(rep_ebin)/euphorik_bd_admin.beam: $(rep_erl)/euphorik_bd_admin.erl $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl +$(rep_ebin)/euphorik_bd_admin.beam: $(rep_erl)/euphorik_bd_admin.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl erlc $(erlc_params) # Module permettant l'extraction des conversations du minichat @@ -61,7 +61,7 @@ $(rep_ebin)/euphorik_protocole.beam: $(rep_erl)/euphorik_protocole.erl $(rep_inc # erlc $(erlc_params) # Module effectuant periodiquement certaines tâches -$(rep_ebin)/euphorik_daemon.beam: $(rep_erl)/euphorik_daemon.erl $(rep_include)/euphorik_defines.hrl $(rep_erl)/euphorik_bd_admin.erl +$(rep_ebin)/euphorik_daemon.beam: $(rep_erl)/euphorik_daemon.erl $(rep_include)/euphorik_defines.hrl erlc $(erlc_params) # Module avec plein de bordel dedant @@ -69,7 +69,7 @@ $(rep_ebin)/euphorik_common.beam: $(rep_erl)/euphorik_common.erl erlc $(erlc_params) # Module dédié au tests -$(rep_ebin)/euphorik_test.beam: $(rep_erl)/euphorik_test.erl $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik_bd.hrl +$(rep_ebin)/euphorik_test.beam: $(rep_erl)/euphorik_test.erl $(rep_include)/euphorik_bd.hrl erlc $(erlc_params) # Suppression des modules compilés diff --git a/modules/erl/euphorik_bd.erl b/modules/erl/euphorik_bd.erl index 81a36a0..4fecb73 100755 --- a/modules/erl/euphorik_bd.erl +++ b/modules/erl/euphorik_bd.erl @@ -46,7 +46,6 @@ % messages : nouveau_message/3, nouveau_message_sys/1, - nouveau_message_sys/2, messages/1, messages/2, messages/3, @@ -78,7 +77,6 @@ troll_by_id/1, current_troll/0, elire_troll/0, - message_id_associe/1, % utiles : resultat_transaction/1 @@ -277,13 +275,16 @@ user_by_mess(Id) -> nouveau_message(Mess, Auteur_id, Repond_A_ids) -> % regarde si les id 'Repond_A' existent F = fun() -> - Repond_a = lists:map( - fun(Repond_a_id) -> - [M] = mnesia:wread({minichat, Repond_a_id}), - M - end, + Repond_a = lists:foldr( + fun(Repond_a_id, Acc) -> + case mnesia:read({minichat, Repond_a_id}) of + [M] -> [M | Acc]; + _ -> Acc % le message n'est pas trouvé + end + end, + [], Repond_A_ids - ), + ), Racine_id = case Repond_a of [] -> undefined; [M | _] -> @@ -295,16 +296,16 @@ nouveau_message(Mess, Auteur_id, Repond_A_ids) -> _ -> {erreur, "Les messages ne font pas partie de la même conversation"} end - end, - case Racine_id of - {erreur, E} -> {erreur, E}; - _ -> - % est-ce que l'auteur existe ? - case mnesia:wread({user, Auteur_id}) of - [#user{profile = Profile} = Auteur] -> - if length(Repond_a) =/= length(Repond_A_ids) -> - {erreur, "Un ou plusieurs messages introuvable"}; - true -> + end, + if length(Repond_a) =/= length(Repond_A_ids) -> + {erreur, "Un ou plusieurs messages introuvable"}; + true -> + case Racine_id of + {erreur, E} -> {erreur, E}; + _ -> + % est-ce que l'auteur existe ? + case mnesia:wread({user, Auteur_id}) of + [#user{profile = Profile} = Auteur] -> % comparaison entre la date du dernier poste et maintenant (gestion du flood) Now = now(), Delta = euphorik_common:delta_date_ms(Auteur#user.date_derniere_connexion, Now), @@ -332,11 +333,11 @@ nouveau_message(Mess, Auteur_id, Repond_A_ids) -> racine_id = if Racine_id =:= undefined -> Id; true -> Racine_id end }), Id - end - end; - _ -> - {erreur, "L'auteur du message est introuvable"} - end + end; + _ -> + {erreur, "L'auteur du message est introuvable"} + end + end end end, resultat_transaction(mnesia:transaction(F)). @@ -352,16 +353,11 @@ inserer_reponses(_, []) -> % Permet de créer un message système. % Renvoie l'id du message système nouveau_message_sys(Mess) -> - nouveau_message_sys(Mess, undefined). - - -% Création d'un message système lié à un troll. -nouveau_message_sys(Mess, Troll_id) -> {ok, #user{profile = Profile}} = user_by_id(0), resultat_transaction(mnesia:transaction( fun() -> Id = nouvel_id(minichat), - mnesia:write(#minichat{id = Id, auteur_id = 0, date = now(), pseudo = Profile#profile.pseudo, contenu = Mess, troll_id = Troll_id, racine_id = Id}), + mnesia:write(#minichat{id = Id, auteur_id = 0, date = now(), pseudo = Profile#profile.pseudo, contenu = Mess, racine_id = Id}), Id end )). @@ -372,26 +368,29 @@ messages(N) -> messages(N, 1). -% Renvoie N messages se trouvant sur la page P +% Renvoie N messages se trouvant sur la page P +% TODO FIXME : fonction en O(N * P) ! messages(N, P) -> - F = fun() -> - C = cursor( - qlc:keysort( - #minichat.id, - q([E#minichat{contenu = contenu_message(E)} || E <- mnesia:table(minichat)]), - [{order, descending}] - ), - [{tmpdir, ?KEY_SORT_TEMP_DIR}] - ), - if P > 1 -> qlc:next_answers(C, N * (P - 1)); - true -> ok - end, - R = qlc:next_answers(C, N), - qlc:delete_cursor(C), - R + F = fun() -> + % % #minichat{contenu = contenu_message(E)} + get_tuples_avant(minichat, reculer(minichat, mnesia:last(minichat), N * (P - 1)), N) end, - lists:reverse(resultat_transaction(mnesia:transaction(F))). - + resultat_transaction(mnesia:transaction(F)). + +get_tuples_avant(Table, Id, N) -> + get_tuples_avant(Table, Id, N, []). +get_tuples_avant(_, '$end_of_table', _, Tuples) -> Tuples; +get_tuples_avant(_, _, 0, Tuples) -> + Tuples; +get_tuples_avant(Table, Id, N, Tuples) -> + [T] = mnesia:read({Table, Id}), + get_tuples_avant(Table, mnesia:prev(Table, Id), N - 1, [T | Tuples]). + +reculer(_, '$end_of_table' = Fin, _) -> Fin; +reculer(_, Id, 0) -> Id; +reculer(Table, Id, N) -> + reculer(Table, mnesia:prev(Table, Id), N - 1). + % Renvoie les messages manquants pour la page P en sachant qu'il y a N message % par page et que le dernier message que l'on possède est Id @@ -412,9 +411,9 @@ message_by_id(Id) -> % Renvoie le contenu d'un message donnée en fonction du troll associé, à utiliser à l'intérieur d'une transaction. -% TODO : Cette fonction pourrait être remplacé par un "outer-join", est-ce possible avec qlc ? +% TODO : Cette fonction pourrait être remplacée par un "outer-join", est-ce possible avec qlc ? contenu_message(E) -> - case mnesia:read({troll, E#minichat.troll_id}) of + case mnesia:index_read(troll, E#minichat.id, #troll.id_minichat) of [] -> E#minichat.contenu; [T] -> E#minichat.contenu ++ T#troll.content end. @@ -796,26 +795,13 @@ elire_troll() -> plus_de_trolls; Trolls -> Troll = lists:nth(random:uniform(length(Trolls)), Trolls), - Troll2 = Troll#troll{date_post = now()}, - mnesia:write(Troll2), - nouveau_message_sys("Troll de la semaine : ", Troll2#troll.id) + Id_message = nouveau_message_sys("Troll de la semaine : "), + Troll2 = Troll#troll{date_post = now(), id_minichat = Id_message}, + mnesia:write(Troll2) end end ). - -% Renvoie l'id du message associé au troll dont l'id est donnée. -% Renvoie undefined si il n'y en a pas. -message_id_associe(Troll_id) -> - resultat_transaction(mnesia:transaction( - fun() -> - case e(q([M#minichat.id || M <- mnesia:table(minichat), M#minichat.troll_id =:= Troll_id]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]) of - [Id] -> Id; - _ -> undefined - end - end - )). - % Renvoie le résultat d'une transaction (en décomposant le tuple fournit) resultat_transaction({_, T}) -> diff --git a/modules/erl/euphorik_bd_admin.erl b/modules/erl/euphorik_bd_admin.erl index 62ab563..076a570 100644 --- a/modules/erl/euphorik_bd_admin.erl +++ b/modules/erl/euphorik_bd_admin.erl @@ -34,8 +34,9 @@ reset/0, update/0, - backup_text/1, - restore_text/1, + backup/1, + restore/1, + change_node_name/4, toggle_ek_master/1, print_users/0, @@ -58,7 +59,7 @@ version_bd() -> % Instructions pour créer une nouvelle base : -% $erl -sname yaws -mnesia dir '"/projets/euphorik/var/BD"' +% $erl -sname yaws -mnesia dir '"/projets/euphorik/BD"' % voir doc/installation.txt % >l(euphorik_bd). % >euphorik_bd:create(). @@ -84,6 +85,7 @@ create_tables() -> {disc_copies, [node()]} ]), mnesia:create_table(minichat, [ + {type, ordered_set}, {attributes, record_info(fields, minichat)}, {disc_copies, [node()]} ]), @@ -109,12 +111,22 @@ create_tables() -> % mis à part car lors de la reprise de données avec load_textfile les indexes ne sont pas recréés creer_indexes() -> + % commence par supprimer les anciens indexes + lists:foreach(fun(T) -> + lists:foreach(fun(P) -> + mnesia:del_table_index(T, P) + end, + mnesia:table_info(T, index) + ) + end, + ?TABLES + ), mnesia:add_table_index(minichat, auteur_id), - mnesia:add_table_index(minichat, troll_id), mnesia:add_table_index(reponse_minichat, cible), mnesia:add_table_index(user, cookie), mnesia:add_table_index(user, login), - mnesia:add_table_index(troll, date_post). + mnesia:add_table_index(troll, date_post), + mnesia:add_table_index(troll, id_minichat). % Connexion à la base de données de yaws sur overnux @@ -203,9 +215,28 @@ update(Version) -> % Applique une modification de la BD pour passer d'une version à la suivante. % crée un backup avant l'application du patch -% dans var/BD/backups nommé "backup" où et le numéro de la version. +% dans BD/backups nommé "backup" où et le numéro de la version. % 1 -> 2 patch(1) -> + % Prend un chemin vers la feuille de style de type "css/1/euphorik.css" + % et renvoie "styles/1/euphorik.css" + Transforme_css = fun("css" ++ Reste) -> + "styles" ++ Reste; + (F) -> F + end, + Traiter_message = fun(M, Racine) -> + F = fun(F, M2) -> % seul moyen à ma connaissance pour faire de la récursion dans une lambda fonction, voir : http://www.nabble.com/Auto-generated-functions-td15279499.html + % met à jour la racine de chaque message qui répond à M + lists:foreach( + fun(M3) -> + mnesia:write(M2#minichat{racine_id = Racine}), + F(F, M3) + end, + euphorik_bd:enfants(M#minichat.id) + ) + end, + F(F, M, Racine) + end, mnesia:create_table(texte, [ {attributes, record_info(fields, texte)}, {disc_copies, [node()]} @@ -215,78 +246,133 @@ patch(1) -> mnesia:transform_table( user, fun({user, Id, Cookie, Pseudo, Login, Password, Email, Date_creation, Date_derniere_connexion, Css, Nick_format, View_times, View_tooltips, Indice_flood, _Page_principale, Conversations, Ek_master, Last_ip}) -> - {user, Id, Cookie, Login, Password, {profile, Pseudo, Email, patch1_transforme_css(Css), Nick_format, View_times, View_tooltips, light, reverse, lists:map(fun({R, _}) -> {R, false} end, Conversations)}, Date_creation, Date_derniere_connexion, Indice_flood, Ek_master, Last_ip} + {user, Id, Cookie, Login, Password, {profile, Pseudo, Email, Transforme_css(Css), Nick_format, View_times, View_tooltips, light, reverse, lists:map(fun({R, _}) -> {R, false} end, Conversations)}, Date_creation, Date_derniere_connexion, Indice_flood, Ek_master, Last_ip} end, - record_info(fields, user), - user + record_info(fields, user) ), mnesia:transform_table( minichat, fun({minichat, Id, Auteur_id, Date, Pseudo, Contenu, Troll_id}) -> {minichat, Id, Auteur_id, Date, Pseudo, Contenu, Troll_id, Id} end, - record_info(fields, minichat), - minichat + record_info(fields, minichat) ), case mnesia:transaction( fun() -> % met à jour les enfants des racines % idéalement : utiliser un cursor mais je crois qu'il n'est pas possible de faire des modifs en itérant en même temps avec un cursor, a voir.. Messages = e(q([M || M <- mnesia:table(minichat), euphorik_bd:parents(M#minichat.id) =:= []]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]), - lists:foreach(fun(M) -> patch_1_traiter_message(M, M#minichat.id) end, Messages) + lists:foreach(fun(M) -> Traiter_message(M, M#minichat.id) end, Messages) end ) of {aborted, Raison} -> {erreur, Raison}; {atomic, _} -> ok - end. - + end; +% 2 -> 3 +patch(2) -> + % première étape : changer le type de la table minichat de set à ordered_set + % TODO : trouver un meilleur moyen que de passer par un backup + backup("tmp"), + create(), + restore("tmp"), + file:delete(dossier_backups() ++ "tmp"), + mnesia:transform_table( + troll, + fun({troll, Id_troll, Id_user, Date_create, Date_post, Content}) -> + % recherche le message associé s'il existe + Id_minichat = case e(q([M || M <- mnesia:table(minichat), element(7, M) =:= Id_troll]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]) of + [M] -> element(2, M); + _ -> undefined + end, + {troll, Id_troll, Id_user, Id_minichat, Date_create, Date_post, Content} + end, + record_info(fields, troll) + ), + %mnesia:del_table_index(minichat, troll_id), + mnesia:transform_table( + minichat, + fun({minichat, Id, Auteur_id, Date, Pseudo, Contenu, _Troll_id, Racine_id}) -> + {minichat, Id, Auteur_id, Date, Pseudo, Contenu, Racine_id} + end, + record_info(fields, minichat) + ), + creer_indexes(). % uniquement pour l'indice sur id_minichat de la table troll -% Prend un chemin vers la feuille de style de type "css/1/euphorik.css" -% et renvoie "styles/1/euphorik.css" -patch1_transforme_css("css" ++ Reste) -> - "styles" ++ Reste; -patch1_transforme_css(F) -> - F. - -patch_1_traiter_message(M, Racine) -> - % met à jour la racine de chaque message qui répond à M - lists:foreach( - fun(M2) -> - mnesia:write(M2#minichat{racine_id = Racine}), - patch_1_traiter_message(M2, Racine) - end, - euphorik_bd:enfants(M#minichat.id) - ). +% Renvoie le dossier dans lequel les backups sont effectué, ce dossier doit être en écriture. +dossier_backups() -> + mnesia:system_info(directory) ++ "/backups/". -% crée un backup dont le nom est fournit dans le repertoire backups qui se trouve dans le repertoire de la BD. -%backup(Nom) -> -% mnesia:backup(mnesia:system_info(directory) ++ "/backups/" ++ Nom). - -% Reviens à une version précédente de la base de données -% (les données insérées durant les versions plus récentes sont perdues) -%restore(N) -> -% mnesia:restore(fichier_backup(N), [{default_op, recreate_tables}]). +% Renvoie le fichier (avec le chemin) correspondant à la version Version, par exemple : "/var/euphorik/BD/backups/backup1" +fichier_backup(Version) when is_integer(Version) -> + dossier_backups() ++ "backup" ++ integer_to_list(Version). + +% crée un backup dont le nom est fournit dans le repertoire backups qui se trouve dans le repertoire de la BD. +backup(Fichier) -> + mnesia:backup(dossier_backups() ++ Fichier). + + +% Restaure un backup de la BD. +restore(Fichier) when is_list(Fichier) -> + mnesia:restore(dossier_backups() ++ Fichier, []); +% Reviens à une version précédente de la base de données. +% (les données insérées durant les versions plus récentes sont perdues). +restore(Version) when is_integer(Version) -> + mnesia:restore(fichier_backup(Version), []). % [{default_op, recreate_tables}]). + -% Renvoie le fichier (avec le chemin) correspondant à la version Version, par exemple : "/var/euphorik/var/BD/backups/backup1" -fichier_backup(Version) -> - mnesia:system_info(directory) ++ "/backups/" ++ if is_integer(Version) -> "backup" ++ integer_to_list(Version); true -> Version end. +% Change le nom du noeud d'un backup. +% provient d'ici : http://www.erlang.org/doc/apps/mnesia/Mnesia_chap7.html#6.9 +% From : l'ancien nom +% To : le nouveau nom +% Source : le nom du fichier de backup +% Target : le nom du fichier du nouveau backup +change_node_name(From, To, Source, Target) -> + Switch = + fun(Node) when Node == From -> To; + (Node) when Node == To -> throw({error, already_exists}); + (Node) -> Node + end, + Convert = + fun({schema, db_nodes, Nodes}, Acc) -> + {[{schema, db_nodes, lists:map(Switch,Nodes)}], Acc}; + ({schema, version, Version}, Acc) -> + {[{schema, version, Version}], Acc}; + ({schema, cookie, Cookie}, Acc) -> + {[{schema, cookie, Cookie}], Acc}; + ({schema, Tab, CreateList}, Acc) -> + Keys = [ram_copies, disc_copies, disc_only_copies], + OptSwitch = + fun({Key, Val}) -> + case lists:member(Key, Keys) of + true -> {Key, lists:map(Switch, Val)}; + false-> {Key, Val} + end + end, + {[{schema, Tab, lists:map(OptSwitch, CreateList)}], Acc}; + (Other, Acc) -> + {[Other], Acc} + end, + mnesia:traverse_backup(Source, Target, Convert, switched). -backup_text(_) -> todo. -restore_text(File) -> - mnesia:stop(), - mnesia:delete_schema([node()]), - mnesia:start(), - case mnesia:load_textfile(File) of - {atomic, ok} -> - update(), - creer_indexes(); - Erreur -> - Erreur - end. +% Obsolète +%~ backup_text(File) -> + %~ mnesia:dump_to_textfile(File). +%~ restore_text(File) -> + %~ mnesia:stop(), + %~ mnesia:delete_schema([node()]), + %~ mnesia:start(), + %~ create_tables(), + %~ case mnesia:load_textfile(File) of + %~ {atomic, ok} -> + %~ update(), + %~ creer_indexes(); + %~ Erreur -> + %~ Erreur + %~ end. toggle_ek_master(User_id) -> @@ -369,4 +455,4 @@ print_user(Id) when is_integer(Id) -> _ -> {erreur, "Id pas trouvé : " ++ integer_to_list(Id)} end. - \ No newline at end of file + diff --git a/modules/erl/euphorik_minichat_conversation.erl b/modules/erl/euphorik_minichat_conversation.erl index 2f932e2..4d0b3a8 100755 --- a/modules/erl/euphorik_minichat_conversation.erl +++ b/modules/erl/euphorik_minichat_conversation.erl @@ -31,8 +31,7 @@ % Un message est un tuple représentant le message et la liste des id % des messages auquels il répond % @type Message() = {#minichat, [int()]} -% - + -module(euphorik_minichat_conversation). -export([ @@ -40,10 +39,8 @@ ]). -include("../include/euphorik_bd.hrl"). -include("../include/euphorik_defines.hrl"). --include_lib("stdlib/include/qlc.hrl"). -import(lists, [reverse/1, any/2, map/2, sublist/3, filter/2]). -import(euphorik_bd, [resultat_transaction/1]). --import(qlc, [e/2, q/1]). -import(mnesia, [table/1, transaction/1]). @@ -111,26 +108,22 @@ mise_en_forme_conversation(Messages) -> % @spec conversations_detailees([{integer(), integer()}], integer(), integer(), integer()) -> [[{integer(), bool()}] | Conversation_detailee()] conversations_detailees(Racines, N, D, P) -> Conversations = map(fun({Racine, P_conv, Dernier}) -> conversation(Racine, N, Dernier, P_conv) end, Racines), - Conversation_principale = resultat_transaction(transaction(fun() -> - Curseur = qlc:cursor( - qlc:sort(q([E#minichat.id || E <- table(minichat)]), [{order, descending}]), - [{tmpdir, ?KEY_SORT_TEMP_DIR}] - ), - {CP, Plus} = conversation_principale(Curseur, Conversations, N, P), - qlc:delete_cursor(Curseur), + Conversation_principale = resultat_transaction(transaction(fun() -> + Dernier_id = mnesia:last(minichat), + {CP, Plus} = conversation_principale(Dernier_id, Conversations, N, P), {[M || M <- CP, M > D], Plus} % filtre en fonction de D end)), [Conversation_principale | Conversations]. -% Construit la conversation principale en fonction d'un curseur C initialement placé sur le dernier message +% Construit la conversation principale en fonction d'un id de message initialement placé sur le dernier message % et la liste de conversations. % N est le nombre de messages que l'on souhaite. % P est le numéro de la page (1, 2, 3...) -% @spec conversation_principale(qlc:QueryCursor(), [Conversation_detailee()], integer(), integer()) -> {[integer()], bool()} -conversation_principale(C, Conversations, N, P) -> +% @spec conversation_principale(integer(), [Conversation_detailee()], integer(), integer()) -> {[integer()], bool()} +conversation_principale(Id, Conversations, N, P) -> % on prend en message de plus pour savoir s'il y en a plus que ce que l'on désire - CP = reverse(conversation_principale2(C, lists:flatten(map(fun({C2, _, X, _}) -> C2 -- X end, Conversations)), N + 1, (P - 1) * N)), + CP = reverse(conversation_principale2(Id, lists:flatten(map(fun({C2, _, X, _}) -> C2 -- X end, Conversations)), N + 1, (P - 1) * N)), Plus = length(CP) =:= N + 1, { if Plus -> @@ -143,25 +136,25 @@ conversation_principale(C, Conversations, N, P) -> }. -% C est le curseur (voir ci dessus) +% Id est l'id d'un message, voir ce dessus % 'Messages' sont les messages que l'on doit enlever de la conversation % S est le nombre de messages qu'il faut sauter. -% @spec conversation_principale2(qlc:QueryCursor(), [integer()], integer(), integer()) -> [integer()] +% @spec conversation_principale2(integer(), [integer()], integer(), integer()) -> [integer()] conversation_principale2(_, _, 0, _) -> + []; +conversation_principale2('$end_of_table', _, _, _) -> []; -conversation_principale2(C, Messages, N, S) -> - case qlc:next_answers(C, 1) of - [] -> []; - [M] -> % traitement message par message (pas des plus performant :/) - Doit_etre_saute = any(fun(E) -> E == M end, Messages), - if Doit_etre_saute -> - conversation_principale2(C, Messages, N, S); % le message ne fait pas partie de la conversation - S =:= 0 -> - [M | conversation_principale2(C, Messages, N - 1, S)]; % ok : le message fait partie de la conversation - true -> - conversation_principale2(C, Messages, N, S - 1) % on n'a pas encore atteint le début de la page - end - end. +conversation_principale2(Id, Messages, N, S) -> + % traitement message par message (pas des plus performant :/) + Id_prev = mnesia:prev(minichat, Id), + Doit_etre_saute = any(fun(E) -> E == Id end, Messages), + if Doit_etre_saute -> + conversation_principale2(Id_prev, Messages, N, S); % le message ne fait pas partie de la conversation + S =:= 0 -> + [Id | conversation_principale2(Id_prev, Messages, N - 1, S)]; % ok : le message fait partie de la conversation + true -> + conversation_principale2(Id_prev, Messages, N, S - 1) % on n'a pas encore atteint le début de la page + end. % Renvoie un tuple {C, Cn, X, Plus} où diff --git a/modules/erl/euphorik_protocole.erl b/modules/erl/euphorik_protocole.erl index a34eae6..1fb3cc1 100755 --- a/modules/erl/euphorik_protocole.erl +++ b/modules/erl/euphorik_protocole.erl @@ -283,7 +283,7 @@ wait_event_page_chat(User, Racines_conversations, Message_count, Last_message_id {struct, [ {reply, "new_troll"}, {troll_id, Current#troll.id}, - {message_id, euphorik_bd:message_id_associe(Current#troll.id)}, + {message_id, Current#troll.id_minichat}, {content, Current#troll.content} ]}; _ -> diff --git a/modules/erl/euphorik_test.erl b/modules/erl/euphorik_test.erl index c1bf49b..2cbc1ec 100644 --- a/modules/erl/euphorik_test.erl +++ b/modules/erl/euphorik_test.erl @@ -22,6 +22,7 @@ -module(euphorik_test). -export([ + bench_write_minichat/1, start/2, stop/1, bench_get_messages/0, @@ -34,6 +35,7 @@ -define(INTERVALLE_MIN, 2). -define(INTERVALLE_MAX, 5). + % N est le nombre d'utilisateur % M est le nombre de message que chaque utilisateur va poster start(N, M) -> @@ -55,7 +57,7 @@ start(N, M) -> stop(Pids) -> lists:foreach(fun(Pid) -> exit(Pid, kill) end, Pids). - +% des trucs qui trainent bench_get_messages() -> T = [ {page,"chat"}, @@ -67,8 +69,6 @@ bench_get_messages() -> {conversations,{array,[]}} ], moyenne_temps(euphorik_protocole, wait_event, [T], 20). - - bench_get_messages_avec_2_conversations() -> T = [ {page,"chat"}, @@ -91,8 +91,6 @@ bench_get_messages_avec_2_conversations() -> ]}} ], moyenne_temps(euphorik_protocole, wait_event, [T], 20). - - moyenne_temps(Module, Fun, Args, N) -> moyenne_temps(Module, Fun, Args, N, N, 0). moyenne_temps(_, _, _, 0, Total, Temps_acc) -> @@ -129,9 +127,9 @@ mot_rand(L, Mot) -> % Tire au hasard de 0 à 3 messages sur les 10 derniers postés, renvoie une liste de int() % répartition : % 0 : 0.1 -% 1 : 0.7 -% 2 : 0.15 -% 3 : 0.05 +% 1 : 0.95 +% 2 : 0.04 +% 3 : 0.01 messages_id_rand() -> R = random:uniform(), if R =< 0.1 -> @@ -139,9 +137,9 @@ messages_id_rand() -> true -> Messages = lists:map(fun(#minichat{id = Id}) -> Id end, euphorik_bd:messages(8)), if - R > 0.1 andalso R =< 0.8 -> + R > 0.1 andalso R =< 0.95 -> tire_element_rand(1, Messages); - R > 0.8 andalso R =< 0.95 -> + R > 0.95 andalso R =< 0.99 -> tire_element_rand(2, Messages); true -> tire_element_rand(3, Messages) @@ -170,9 +168,8 @@ loop(User_id, M) -> % attend un temp aléatoire compris entre INTERVALLE_MIN sec et INTERVALLE_MAX sec timer:sleep(1000 * (random:uniform(?INTERVALLE_MAX - ?INTERVALLE_MIN + 1) + ?INTERVALLE_MIN - 1)), % poste un message aléatoire par une personne aléatoire répondant à des messages aléatoires - {Message, Repond_a} = {message_rand(), messages_id_rand()}, - %{Message, Repond_a} = {"blablablablablabla", []}, - io:format("~p poste ~p et repond a ~w~n", [User_id, Message, Repond_a]), + {Message, Repond_a} = {message_rand(), messages_id_rand()}, + % io:format("~p poste ~p et repond a ~w~n", [User_id, Message, Repond_a]), case euphorik_bd:nouveau_message(Message, User_id, Repond_a) of {erreur, E} -> io:format("~p : erreur : ~p~n", [User_id, E]), @@ -181,4 +178,35 @@ loop(User_id, M) -> loop(User_id, M - 1) end. + +% Permet de tester la vitesse d'écriture en fonction de la +% taille de la BD +% voir : http://erlang.org/pipermail/erlang-questions/2008-October/038697.html +bench_write_minichat(Filename) -> + Times = bench_write_minichat(1, []), + {ok, File} = file:open(Filename, [write]), + lists:foreach( + fun({Id, Time}) -> + io:format(File, "~w ~w~n", [Id, Time]) + end, + Times + ), + file:close(File). +bench_write_minichat(100000, Temps) -> Temps; +bench_write_minichat(N, Temps) -> + {T, _} = timer:tc(mnesia, transaction, [fun() -> + Id = mnesia:dirty_update_counter(counter, minichat, 1), + mnesia:write(#minichat{ + id = Id, + auteur_id = random:uniform(10000), + date = now(), + pseudo = "Test", + contenu = "Blabla blabla bla.", + racine_id = random:uniform(10000) + }) + end]), + bench_write_minichat(N + 1, if N rem 500 =:= 0 -> [{N, T} | Temps]; true -> Temps end). + + + \ No newline at end of file diff --git a/modules/include/euphorik_bd.hrl b/modules/include/euphorik_bd.hrl index 6713830..0b04c4b 100755 --- a/modules/include/euphorik_bd.hrl +++ b/modules/include/euphorik_bd.hrl @@ -1,3 +1,4 @@ +% coding: utf-8 % Copyright 2008 Grégory Burri % % This file is part of Euphorik. @@ -19,7 +20,7 @@ % Version de la BD --define(VERSION_BD, 2). +-define(VERSION_BD, 3). -define(TABLES, [counter, proprietes, minichat, reponse_minichat, user, ip_table, troll]). @@ -55,7 +56,6 @@ date, % erlang:now() pseudo, % chaine de caractère contenu, % chaine de caractère - troll_id = undefined, % l'id du troll associé correspondant racine_id = undefined % la racine, par défaut correspond à l'id du message }). @@ -69,7 +69,6 @@ }). - -record(profile, % attention : pas une table ! { pseudo = [], % string() @@ -81,7 +80,9 @@ ostentatious_master = light, % peut valoir invisible, light ou heavy. seulement pour ek_master chat_order = reverse, % peut valoir chrono ou reverse conversations = [] % [{integer(), bool}], la liste des messages correspondant au conversation {racine, reduite?} - }). + }). + + -record(user, { id, @@ -113,7 +114,8 @@ -record(troll, { id, - id_user, + id_user, + id_minichat = undefined, % l'id du message associé date_create, % erlang:now() date_post = undefined, % date à laquelle le troll est affiché sur la page principale. undefined initialement puis erlang:now() quand affiché content % chaine de caractère diff --git a/styles/1/euphorik.css b/styles/1/euphorik.css index 4db3de1..54aef62 100755 --- a/styles/1/euphorik.css +++ b/styles/1/euphorik.css @@ -22,6 +22,15 @@ body { margin: 0px; } +/***** Textile *****/ +em.leger { + font-style: italic +} +em.fort { + font-style: normal; + font-weight: bold +} + /***** Menu *****/ ul#menu { background-image: url(img/logo_fond.png); @@ -221,6 +230,7 @@ div#info .boutons div:hover { form input, form button, form select { + color: #841919; background-color: #f0df95; border: #841919 1px solid; } diff --git a/styles/1/pageMinichat.css b/styles/1/pageMinichat.css index ebfadcf..de908dd 100755 --- a/styles/1/pageMinichat.css +++ b/styles/1/pageMinichat.css @@ -9,6 +9,18 @@ vertical-align: middle; } +/***** L'aide sur les commandes *****/ +#aideCommandes h1 { + font-size: 14px; + font-weight: bold; +} +#aideCommandes .usage { + font-weight: bold; +} +#aideCommandes li { + list-style-type: none; +} + /***** La boite de sélection des smiles *****/ #smiles { text-align: center; @@ -59,6 +71,14 @@ top: 77px; line-height: 32px; } + +#page.minichat #trollCourant a:link, #page.minichat #trollCourant a:visited { + color: #f85b31; +} + #page.minichat #trollCourant a:hover, #page.minichat #trollCourant a:active { + color: #f87e5d; +} + #page.minichat #trollCourant .troll { cursor: pointer; font-style: italic diff --git a/styles/2/euphorik.css b/styles/2/euphorik.css index 52f959f..261d8b3 100755 --- a/styles/2/euphorik.css +++ b/styles/2/euphorik.css @@ -25,6 +25,15 @@ body { margin-top: 40px; } +/***** Textile *****/ +em.leger { + font-style: italic +} +em.fort { + font-style: normal; + font-weight: bold +} + /***** Menu *****/ ul#menu { padding-left: 300px; diff --git a/styles/2/pageMinichat.css b/styles/2/pageMinichat.css index 633ff61..67b4d58 100755 --- a/styles/2/pageMinichat.css +++ b/styles/2/pageMinichat.css @@ -11,6 +11,18 @@ vertical-align: middle; } +/***** L'aide sur les commandes *****/ +#aideCommandes h1 { + font-size: 14px; + font-weight: bold; +} +#aideCommandes .usage { + font-weight: bold; +} +#aideCommandes li { + list-style-type: none; +} + /***** La boite de sélection des smiles *****/ #smiles { text-align: center; diff --git a/tools/mise_en_prod.erl b/tools/mise_en_prod.erl index 2b9cb17..933aceb 100755 --- a/tools/mise_en_prod.erl +++ b/tools/mise_en_prod.erl @@ -5,13 +5,39 @@ % Recharge les modules de euphorik et met à jour la BD. % TODO : construire le nom du noeud en fonction du nom de l'host -main(_) -> +hote() -> + '@overnux'. + +% le premier argument est le nom du noeud est peut valoir : +% - yaws : noeud de production +% - yaws_dev : noeud de pre-production +main([Nom_node]) when Nom_node =:= "yaws"; Nom_node =:= "yaws_dev" -> + Node = list_to_atom(Nom_node ++ atom_to_list(hote())), net_kernel:start([flynux, shortnames]), io:format("rechargement des modules..~n"), - _Pid = spawn_link(yaws@overnux, euphorik_daemon, reload_euphorik, []), - receive - {'EXIT', _, _} -> - io:format("mise à jour de la BD..~n"), - spawn(yaws@overnux, euphorik_bd_admin, update, []) - end. + rpc:call(Node, euphorik_daemon, reload_euphorik, []), + if Nom_node =:= "yaws_dev" -> copier_bd(Node); + true -> true + end, + io:format("mise à jour de la BD..~n"), + rpc:call(Node, euphorik_bd_admin, update, []); +main(_) -> + io:format("Usage : mise_en_prod.erl "), + halt(1). +% Copie la bd du noeud de production +copier_bd(Node) -> + io:format("Copie de la BD de production vers le noeude pre-production~n"), + Fichier = "/tmp/backup_ek_tmp", + Fichier2 = "/tmp/backup_ek_tmp2", + rpc:call(yaws@overnux, mnesia, backup, [Fichier]), + rpc:call(Node, euphorik_bd_admin, change_node_name, [yaws@overnux, yaws_dev@overnux, Fichier, Fichier2]), + rpc:call(Node, mnesia, restore, [Fichier2, [{default_op, recreate_tables}]]), + rpc:call(yaws@overnux, file, delete, [Fichier]), + rpc:call(Node, file, delete, [Fichier2]). + + + + + + diff --git a/tools/start_yaws.sh b/tools/start_yaws.sh index 8b9311e..d812137 100755 --- a/tools/start_yaws.sh +++ b/tools/start_yaws.sh @@ -1,3 +1,4 @@ #!/bin/bash +# coding: utf-8 # screen est utilisé par exemple pour lancé une version de preproduction et permettre de la faire tourner après un délog -yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../var/BD/" -I debian_yaws_dev +yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../var/BD/" -I debian_yaws_dev diff --git a/tools/tools.rb b/tools/tools.rb index 11570dd..b437687 100644 --- a/tools/tools.rb +++ b/tools/tools.rb @@ -49,15 +49,16 @@ class VerifJS def verifierRecur(dossier) Dir.foreach(dossier){|fichier| - if fichier != '.' and fichier != '..' and File.directory?(fichier) and fichier != 'dirs' - if not verifierRecur(dossier + '/' + fichier) + cheminComplet = "#{dossier}/#{fichier}" + if fichier[0,1] != '.' and File.directory?(cheminComplet) and fichier != 'libs' + if not verifierRecur(cheminComplet) return false end elsif fichier[-3, 3] == '.js' - puts "== Vérification de #{dossier}/#{fichier} ==" + puts "== Vérification de #{cheminComplet} ==" # TODO : mettre un if pour la version windows si dessous - #system("java org.mozilla.javascript.tools.shell.Main jslint.js #{dossier}/#{fichier}") - system("rhino ./tools/jslint.js #{dossier}/#{fichier}") + #system("java org.mozilla.javascript.tools.shell.Main jslint.js #{cheminComplet}") + system("rhino ./tools/jslint.js #{cheminComplet}") # puts $?.exitstatus if $?.exitstatus > 0 return false @@ -116,7 +117,7 @@ class MiseEnProd # Effectue la mise en production. def miseEnProd copierFichiers() - maj() + maj('yaws') end # Effectue la mise en préproduction. @@ -124,6 +125,7 @@ class MiseEnProd copierFichiers() copierVAR() lancerYaws() + maj('yaws_dev') end def copierFichiers @@ -144,7 +146,7 @@ class MiseEnProd creer_rep("tools") system("rsync tools/yaws.conf #{@uri}:#{@rep}/tools") system("rsync tools/start_yaws.sh #{@uri}:#{@rep}/tools") - # TODO + system("ssh #{@uri} \"cd #{@rep}/tools; screen -d -m -S yaws_dev ./start_yaws.sh\"") end def exec(commande) @@ -159,6 +161,7 @@ class MiseEnProd end def compiler_partie_serveuse + log "compilation des modules serveur" Dir.chdir('modules') system("make") if $?.exitstatus != 0 @@ -178,6 +181,7 @@ class MiseEnProd # css, images, html, etc.. def copier_partie_statique + log "copie de la partie statique" uri = "#{@uri}:#{@rep}" system("awk '$0 !~ /prod=\"delete\"/' index.yaws | ssh #{@uri} \" cat > #{@rep}/index.yaws\"") system("rsync favicon.ico #{uri}") @@ -188,6 +192,7 @@ class MiseEnProd # minification et package des fichiers js dans euphorik.js def pack_js + log "minification, assemblage et copie du javascript" rep_js = 'js' creer_rep(rep_js) # jquery.js et euphorik.js doivent se trouve en premier @@ -217,6 +222,7 @@ class MiseEnProd end def copie_modules_serveurs + log "copie des modules du serveur" # copie des modules erlang creer_rep('modules') system("rsync -r --exclude 'euphorik_test.beam' modules/ebin #{@uri}:#{@rep}/modules") @@ -224,14 +230,24 @@ class MiseEnProd end def set_droits_fichiers + log "attribution des droits sur les fichiers" # attribution des droits exec("chmod -R g+rx .") end - def maj + # noeud : le nom du noeud sur lequel le script de mise en prod est exécuté + # Execute le script 'mise_en_prod.erl' sur le serveur afin de : + # - Recharger les modules + # - Mettre à jour la base de données + def maj(noeud) + log "rechargement des modules serveur et mise à jour de la base de données" # execution du script de mise à jour system("cat tools/mise_en_prod.erl | ssh #{@uri} \"cat > /tmp/mise_en_prod.erl\"") - system("ssh #{@uri} \"chmod u+x /tmp/mise_en_prod.erl; /tmp/mise_en_prod.erl; rm /tmp/mise_en_prod.erl\"") + system("ssh #{@uri} \"chmod u+x /tmp/mise_en_prod.erl; /tmp/mise_en_prod.erl #{noeud}; rm /tmp/mise_en_prod.erl\"") + end + + def log(message) + puts "----- #{message} -----" end end @@ -264,18 +280,7 @@ class Commande @verifJS.verifier() when 'version' @version.maj() - end - -=begin - Net::SSH.start('euphorik.ch', 'gburri') {|ssh| - output = ssh.exec!("hostname") - stdout = "" - ssh.exec!("ls -l /tmp"){|channel, stream, data| - stdout << data if stream == :stdout - } - puts stdout - } -=end + end end def afficherUsage -- 2.45.2 From cf6ef300c932f8e3f5fab7e1872d06ff44e6ba01 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Mon, 6 Oct 2008 08:21:54 +0000 Subject: [PATCH 03/16] DEL passage sur le wiki : http://dev.euphorik.ch/wiki/euk/Description --- doc/description.txt | 112 -------------------------------------------- 1 file changed, 112 deletions(-) delete mode 100644 doc/description.txt diff --git a/doc/description.txt b/doc/description.txt deleted file mode 100644 index 94eee1a..0000000 --- a/doc/description.txt +++ /dev/null @@ -1,112 +0,0 @@ -== En bref == -Euphorik est un site web communautaire principalement basé sur un système d'échange de messages instantanés. -Attention: la description ici ne correspond pas à l'état actuel du projet mais à un but à atteindre. - -== Philosophie == -Euphorik est un site communaire de niveau supérieur (un truc qui n'existe pas et qui n'existera probablement jamais). -N'importe qui peut poster des messages ou des trolls (un troll étant un super message persistant à caractère trollifique). -Il est possible de s'enregistrer pour garder son identité et sauvegarder certains paramètres. -Pas besoin d'être authentifier pour poster des messages -Il faut être enregistré pour poster des trolls (ouais bein quant on troll on assume) -Il n'y a qu'un seul canal par troll (channel au sens IRC). -Un message peut répondre à un ou plusieurs autres messages, ceci crée automatiquement des arbres de conversation (au sein d'un troll). -Ces arbres de conversation peuvent être extraient de la conversation principal et affichés séparement (toujours au sein d'un troll). -Il existe des êtres supérieures qui ont de grands pouvoirs, ce sont les EkMaster ou [EM] (les admins quoi). -L'interface doit être sobre, simple et un peu retro :) -Il est interdit d'utiliser des technos pourries comme PHP. - - -== Détails == -=== Pages === -* Main : Présente les trolls de la semaine -* Trolls : Liste un certain nombre de trolls postés par les utilisateurs. Le rafraichissement est en temps réel. Il est possible de faire une recherche par mot clef. -* People : Permet de rechercher une personne et d'afficher sa page, en particulier ses trolls. -* Profile : Permet d'accèder à ses données. C'est à partir de cette page que l'on peut poster des trolls. -* About : description du site (Faq et cie..) - -=== Le Troll === -Le troll est un message, une question, une pensée, etc, digne d'intérêt (ou pas) étant la fusion entre un topic de forum et un channel de chat. -Il existe un troll principal concernant le chat principal. -Un troll peut être édité par son auteur. -N'importe qui peut voir l'historique des éditions. -Il est possible de plusser ou moinsser un troll. -Un troll possède de 0 à n tag (mot-clef). -Les trolls sont présentés au sein d'une liste général ordrée en fonction de leur nombre de point et de leur date et aussi tant qu'on y est de la date du dernier message (genre reddit.com) -Les trolls sont également présentés sur le profile du proprio du troll (par ordre anti-chronologique) - -=== Le troll de la semaine === -Sur la page principale appelé 'chat' il existe un troll qui sera affiché une semaine appellé "troll de la semaine". -Le troll de la semaine est posté par les admins. -Les admins voient les prochains trolls en attente, le nombre en attente est limité 10. -Un admin peut ajouter un troll de la semaine. Il ne peut pas posséder plus d'un troll en attente. -Le troll de la semaine change le lundi à 3h00 du mat' s'il en existe un en attente. Il est choisi au hasard. -Les n derniers trolls des semaines précédentes sont toujours affichés de manière repliés en dessous du troll de la semaine. pour l'instant n = 4. - -=== Le message === -Un message répond à un troll et peut répondre à d'autres messages de ce troll. -Un message ne peut pas être éditer, il est possible de lui appondre une ou plusieurs corrections " +++ Correction" -un message dont l'entête est de couleur verte signfie : "un message qui me répond" -un message dont l'entête est de couleur orange signifie : "mon message" -Un message dont l'entête est de couleur bleu signifie : "un message auquel je répond" - - -=== Admin === -L'admin propose des trolls de la semaine, il a le statut de EM (EkMaster) - - -== Reflexions == -Les types d'information du plus éphémère au plus persistant. - * Plussage/moinssage - * Message - * Message (1-1) - * Blog - * Forum - * Article - * Question (1-1) | (1-n) - * Forum - * Message - * Billet (1-n) - * Blog - * Article (1-n) | (n-n) - * Wikipedia - - -Moyen de communication sur le net : - -* Réseaux sociaux (facebook et cie) - + Orienté profile - + Liste d'amis - + Possibilité de mettre des infos personnels + photos - -* Vidéo (youtube et cie) - + Orienté vidéo - -* Reddit/Digg - * Aggrégateur de news/billet de blog/article - * L'ordre des informations peut changer (en fonction de la note) - -* Blog - * Orienté billet - * Géré par une seule personne - * Système de messages - + Structuration et recherche par tag (chaque billet possède un ou plusieurs tags) - -* Forum (phpBB, vBulettin, mesDiscussions, etc.) - * Orienté sujet - * Organisation hiérachique en thémes, p.e. : Hardware/HDD - * L'ordre des sujets ne correspond pas à leur date d'écriture mais à la date du dernier message - * Edition/correction possible - * Les "réponses" ne sont pas modérer par l'auteur du sujet - - Pas de système de plussage - - Par forcément d'arbre de réponses, obligation de quoter -> bordelique - - Le topic a souvent tendance à dériver - -* Chat (http://www.phpfreechat.net, http://bouchot.org, etc..) - * Orienté message - * Ordre figé - + Scalable grace aux channels - + Communication temps réel - - Ca peut devenir le bordel, difficile de suivre - - L'information est éphemère ou difficilement réutilisable - - Aucune hiérarchie ou structure en dehors des channels - \ No newline at end of file -- 2.45.2 From e6d071afe9954bd307f2fde0091a30d275aaca86 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Mon, 6 Oct 2008 12:47:09 +0000 Subject: [PATCH 04/16] ADD futur remplacant de tools.rb --- tools/tools.erl | 140 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 tools/tools.erl diff --git a/tools/tools.erl b/tools/tools.erl new file mode 100644 index 0000000..ffab671 --- /dev/null +++ b/tools/tools.erl @@ -0,0 +1,140 @@ +#!/usr/bin/env escript +% coding: utf-8 +% Copyright 2008 Grégory Burri +% +% This file is part of Euphorik. +% +% Euphorik is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% Euphorik is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Euphorik. If not, see . + +% This file replace the old one 'tools.rb' written in a crapy language ;) +% TODO : +% - création de unit tests (voir eunit) et validation avant la mise en prod + + +main(Args) -> + file:set_cwd(".."), + case Args of + ["prod"] -> in_prod("gburri@euphorik.ch:/var/www/euphorik"); + ["pre"] -> in_preprod("gburri@euphorik.ch:/var/www/euphorik_preprod", "var/www/euphorik"); + ["js"] -> verif_js(); + ["version"] -> update_version(); + _ -> + io:format( + "Usage : ~s (prod | pre | js | version)~n" + " prod : in production~n" + " pre : in preproduction, data are copied from production~n" + " js : check the JavaScript files~n" + " version : update the version into somes files from the VERSION file", + [escript:script_name()] + ) + end. + + +% A simple fonction to log message. +log(Str) -> + io:format("===== ~s =====~n", [Str]). + + +% Execute an OS commande and print the result to stdout. +cmd(Commande_str) -> + cmd(Commande_str, []). +cmd(Commande_str, Params) -> + io:format("~s~n", [os:cmd(lists:flatten(io_lib:format(Commande_str, Params)))]). + + +-record(uri, { + host, + path % in absolute +}). + + +% Create an uri record from an uri string. +create_uri(Uri_str) -> + [Host, Path] = string:tokens(Uri_str, ":"), + #uri{host = Host, path = Path}. + + +% Update the version into somes files from the VERSION file. +update_version() -> + log("Update the version tag"), + todo. + + +% Check the JavaScript files. +verif_js() -> + todo. + + +% Start the production processus. +in_prod(Uri) -> + compile_server_part(Uri), + make_var_directory(Uri), + copy_files(Uri), + define_files_rights(Uri), + update_server(). + + +% Start the pre-production processus. +in_preprod(Uri, data_path) -> + compile_server_part(Uri), + make_var_directory(Uri), + copy_files(Uri), + define_files_rights(Uri), + start_server(), + update_server(). + + +% Compile the Erlang modules. +compile_server_part(Uri) -> + todo. + + +% Create the 'var' folder if it doesn't exist. +make_var_directory(Uri) -> + todo. + + +% Copy files from developpement env to production server. +copy_files(Uri) -> + copy_static_part(Uri), + copy_packed_js(Uri). + + +% Copy all static files like modules, styles, pages, etc. +copy_static_part(Uri) -> + %~ creer_rep('modules') + %~ system("rsync -r --exclude 'euphorik_test.beam' modules/ebin #{@uri}:#{@rep}/modules") + %~ system("rsync -r modules/include #{@uri}:#{@rep}/modules") + todo. + + +% Minify and pack JavaScript in one file then copy it to ther server. +copy_packed_js(Uri) -> + todo. + + +% Define the rights for the copied folder et files. +define_files_rights(Uri) -> + todo. + + +% Start the server if it not already started (in preproduction case only). +start_server() -> + todo. + + +% Run a erlang script to +update_server() -> + todo. + -- 2.45.2 From c0bb356766fa4cd2e724b06a1720f89a5d163680 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Mon, 6 Oct 2008 20:35:26 +0000 Subject: [PATCH 05/16] =?utf8?q?ADD=20version=20JavaScript=20de=20jsmin=20?= =?utf8?q?(=C3=A0=20la=20place=20de=20jsmin.rb)=20les=20;;=20ne=20sont=20p?= =?utf8?q?as=20encore=20g=C3=A9r=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- tools/jsmin.js | 329 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 tools/jsmin.js diff --git a/tools/jsmin.js b/tools/jsmin.js new file mode 100644 index 0000000..a49c2bf --- /dev/null +++ b/tools/jsmin.js @@ -0,0 +1,329 @@ +/* jsmin.js - 2006-08-31 +Author: Franck Marcia +This work is an adaptation of jsminc.c published by Douglas Crockford. +Permission is hereby granted to use the Javascript version under the same +conditions as the jsmin.c on which it is based. + +jsmin.c +2006-05-04 + +Copyright (c) 2002 Douglas Crockford (www.crockford.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Update: + add level: + 1: minimal, keep linefeeds if single + 2: normal, the standard algorithm + 3: agressive, remove any linefeed and doesn't take care of potential + missing semicolons (can be regressive) + store stats + jsmin.oldSize + jsmin.newSize +*/ + +String.prototype.has = function(c) { + return this.indexOf(c) > -1; +}; + +function jsmin(comment, input, level) { + + if (input === undefined) { + input = comment; + comment = ''; + level = 2; + } else if (level === undefined || level < 1 || level > 3) { + level = 2; + } + + if (comment.length > 0) { + comment += '\n'; + } + + var a = '', + b = '', + EOF = -1, + LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', + DIGITS = '0123456789', + ALNUM = LETTERS + DIGITS + '_$\\', + theLookahead = EOF; + + + /* isAlphanum -- return true if the character is a letter, digit, underscore, + dollar sign, or non-ASCII character. + */ + + function isAlphanum(c) { + return c != EOF && (ALNUM.has(c) || c.charCodeAt(0) > 126); + } + + + /* get -- return the next character. Watch out for lookahead. If the + character is a control character, translate it to a space or + linefeed. + */ + + function get() { + + var c = theLookahead; + if (get.i == get.l) { + return EOF; + } + theLookahead = EOF; + if (c == EOF) { + c = input.charAt(get.i); + ++get.i; + } + if (c >= ' ' || c == '\n') { + return c; + } + if (c == '\r') { + return '\n'; + } + return ' '; + } + + get.i = 0; + get.l = input.length; + + + /* peek -- get the next character without getting it. + */ + + function peek() { + theLookahead = get(); + return theLookahead; + } + + + /* next -- get the next character, excluding comments. peek() is used to see + if a '/' is followed by a '/' or '*'. + */ + + function next() { + + var c = get(); + if (c == '/') { + switch (peek()) { + case '/': + for (;;) { + c = get(); + if (c <= '\n') { + return c; + } + } + break; + case '*': + get(); + for (;;) { + switch (get()) { + case '*': + if (peek() == '/') { + get(); + return ' '; + } + break; + case EOF: + throw 'Error: Unterminated comment.'; + } + } + break; + default: + return c; + } + } + return c; + } + + + /* action -- do something! What you do is determined by the argument: + 1 Output A. Copy B to A. Get the next B. + 2 Copy B to A. Get the next B. (Delete A). + 3 Get the next B. (Delete B). + action treats a string as a single character. Wow! + action recognizes a regular expression if it is preceded by ( or , or =. + */ + + function action(d) { + + var r = []; + + if (d == 1) { + r.push(a); + } + + if (d < 3) { + a = b; + if (a == '\'' || a == '"') { + for (;;) { + r.push(a); + a = get(); + if (a == b) { + break; + } + if (a <= '\n') { + throw 'Error: unterminated string literal: ' + a; + } + if (a == '\\') { + r.push(a); + a = get(); + } + } + } + } + + b = next(); + + if (b == '/' && '(,=:[!&|'.has(a)) { + r.push(a); + r.push(b); + for (;;) { + a = get(); + if (a == '/') { + break; + } else if (a =='\\') { + r.push(a); + a = get(); + } else if (a <= '\n') { + throw 'Error: unterminated Regular Expression literal'; + } + r.push(a); + } + b = next(); + } + + return r.join(''); + } + + + /* m -- Copy the input to the output, deleting the characters which are + insignificant to JavaScript. Comments will be removed. Tabs will be + replaced with spaces. Carriage returns will be replaced with + linefeeds. + Most spaces and linefeeds will be removed. + */ + + function m() { + + var r = []; + a = '\n'; + + r.push(action(3)); + + while (a != EOF) { + switch (a) { + case ' ': + if (isAlphanum(b)) { + r.push(action(1)); + } else { + r.push(action(2)); + } + break; + case '\n': + switch (b) { + case '{': + case '[': + case '(': + case '+': + case '-': + r.push(action(1)); + break; + case ' ': + r.push(action(3)); + break; + default: + if (isAlphanum(b)) { + r.push(action(1)); + } else { + if (level == 1 && b != '\n') { + r.push(action(1)); + } else { + r.push(action(2)); + } + } + } + break; + default: + switch (b) { + case ' ': + if (isAlphanum(a)) { + r.push(action(1)); + break; + } + r.push(action(3)); + break; + case '\n': + if (level == 1 && a != '\n') { + r.push(action(1)); + } else { + switch (a) { + case '}': + case ']': + case ')': + case '+': + case '-': + case '"': + case '\'': + if (level == 3) { + r.push(action(3)); + } else { + r.push(action(1)); + } + break; + default: + if (isAlphanum(a)) { + r.push(action(1)); + } else { + r.push(action(3)); + } + } + } + break; + default: + r.push(action(1)); + break; + } + } + } + + return r.join(''); + } + + jsmin.oldSize = input.length; + ret = m(input); + jsmin.newSize = ret.length; + + return comment + ret; + +} + +(function (a) { + if (!a[0]) { + print("Usage: jsmin.js file.js"); + quit(1); + } + var input = readFile(a[0]); + if (!input) { + print("jslint: Couldn't open file '" + a[0] + "'."); + quit(1); + } + print(jsmin(input)); +})(arguments); \ No newline at end of file -- 2.45.2 From 6d3135b870db381965b197af7d282a99f52e43d8 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Mon, 6 Oct 2008 20:41:21 +0000 Subject: [PATCH 06/16] =?utf8?q?FIX=20suppression=20des=20/;;.*$/=20(d?= =?utf8?q?=C3=A9finit=20=C3=A9tant=20un=20commentaire)=20lors=20de=20la=20?= =?utf8?q?minification=20du=20js?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- tools/jsmin.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/jsmin.js b/tools/jsmin.js index a49c2bf..55ee654 100644 --- a/tools/jsmin.js +++ b/tools/jsmin.js @@ -121,6 +121,16 @@ function jsmin(comment, input, level) { function next() { var c = get(); + + if (c === ";" && peek() === ";") { + for (;;) { + c = get(); + if (c <= '\n') { + return c; + } + } + } + if (c == '/') { switch (peek()) { case '/': -- 2.45.2 From 82aea119013e63c3d4864baea690c84f56890008 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Tue, 7 Oct 2008 07:01:10 +0000 Subject: [PATCH 07/16] MOD modification de jsmin.js pour traiter le js depuis stdin --- tools/jsmin.js | 27 ++++++++++--------- tools/{mise_en_prod.erl => update_server.erl} | 7 +---- 2 files changed, 16 insertions(+), 18 deletions(-) rename tools/{mise_en_prod.erl => update_server.erl} (98%) diff --git a/tools/jsmin.js b/tools/jsmin.js index 55ee654..95c275b 100644 --- a/tools/jsmin.js +++ b/tools/jsmin.js @@ -1,3 +1,5 @@ +#!/usr/bin/env rhino + /* jsmin.js - 2006-08-31 Author: Franck Marcia This work is an adaptation of jsminc.c published by Douglas Crockford. @@ -324,16 +326,17 @@ function jsmin(comment, input, level) { return comment + ret; } - -(function (a) { - if (!a[0]) { - print("Usage: jsmin.js file.js"); - quit(1); - } - var input = readFile(a[0]); - if (!input) { - print("jslint: Couldn't open file '" + a[0] + "'."); - quit(1); - } - print(jsmin(input)); + +importPackage(java.io); +(function (a) { + // in is a reserved javascript word, so we need to use [] for access + var readingIn = new BufferedReader(new InputStreamReader(java.lang.System["in"])); + var sInput = ""; + var str = ""; + while(str != null) { + sInput += str + '\n'; + + str = readingIn.readLine(); + } + print(jsmin(sInput)); })(arguments); \ No newline at end of file diff --git a/tools/mise_en_prod.erl b/tools/update_server.erl similarity index 98% rename from tools/mise_en_prod.erl rename to tools/update_server.erl index 933aceb..4211772 100755 --- a/tools/mise_en_prod.erl +++ b/tools/update_server.erl @@ -35,9 +35,4 @@ copier_bd(Node) -> rpc:call(Node, mnesia, restore, [Fichier2, [{default_op, recreate_tables}]]), rpc:call(yaws@overnux, file, delete, [Fichier]), rpc:call(Node, file, delete, [Fichier2]). - - - - - - + \ No newline at end of file -- 2.45.2 From 3e60e60e8c94fc5f3c84d3409823b9fb3c4ca02e Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Tue, 7 Oct 2008 09:44:15 +0000 Subject: [PATCH 08/16] --- tools/jsmin.rb | 216 ------------------------------------------------- 1 file changed, 216 deletions(-) delete mode 100644 tools/jsmin.rb diff --git a/tools/jsmin.rb b/tools/jsmin.rb deleted file mode 100644 index 83e2e40..0000000 --- a/tools/jsmin.rb +++ /dev/null @@ -1,216 +0,0 @@ -#!/usr/bin/ruby -# jsmin.rb 2007-07-20 -# Author: Uladzislau Latynski -# This work is a translation from C to Ruby of jsmin.c published by -# Douglas Crockford. Permission is hereby granted to use the Ruby -# version under the same conditions as the jsmin.c on which it is -# based. -# -# /* jsmin.c -# 2003-04-21 -# -# Copyright (c) 2002 Douglas Crockford (www.crockford.com) -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -# of the Software, and to permit persons to whom the Software is furnished to do -# so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# The Software shall be used for Good, not Evil. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -EOF = -1 -$theA = "" -$theB = "" - -# isAlphanum -- return true if the character is a letter, digit, underscore, -# dollar sign, or non-ASCII character -def isAlphanum(c) - return false if !c || c == EOF - return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || - c == '\\' || c[0] > 126) -end - -# get -- return the next character from stdin. Watch out for lookahead. If -# the character is a control character, translate it to a space or linefeed. -def get() - c = $stdin.getc - return EOF if(!c) - c = c.chr - return c if (c >= " " || c == "\n" || c.unpack("c") == EOF) - return "\n" if (c == "\r") - return " " -end - -# Get the next character without getting it. -def peek() - lookaheadChar = $stdin.getc - $stdin.ungetc(lookaheadChar) - return lookaheadChar.chr -end - -# mynext -- get the next character, excluding comments. -# peek() is used to see if a '/' is followed by a '/' or '*'. -def mynext() - c = get - # saute les commentaires (également les lignes commencant pas ;;) - - if (c == ";" and peek == ";") - while(true) - c = get - if (c[0] <= "\n"[0]) - return c - end - end - end - if (c == "/") - prochain = peek - if(prochain == "/") - while(true) - c = get - if (c[0] <= "\n"[0]) - return c - end - end - end - if(peek == "*") - get - while(true) - case get - when "*" - if (peek == "/") - get - return " " - end - when EOF - raise "Unterminated comment" - end - end - end - end - return c -end - - -# action -- do something! What you do is determined by the argument: 1 -# Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B. -# (Delete A). 3 Get the next B. (Delete B). action treats a string as a -# single character. Wow! action recognizes a regular expression if it is -# preceded by ( or , or =. -def action(a) - if(a==1) - $stdout.write $theA - end - if(a==1 || a==2) - $theA = $theB - if ($theA == "\'" || $theA == "\"") - while (true) - $stdout.write $theA - $theA = get - break if ($theA == $theB) - raise "Unterminated string literal" if ($theA <= "\n") - if ($theA == "\\") - $stdout.write $theA - $theA = get - end - end - end - end - if(a==1 || a==2 || a==3) - $theB = mynext - if ($theB == "/" && ($theA == "(" || $theA == "," || $theA == "=" || - $theA == ":" || $theA == "[" || $theA == "!" || - $theA == "&" || $theA == "|" || $theA == "?" || - $theA == "{" || $theA == "}" || $theA == ";" || - $theA == "\n")) - $stdout.write $theA - $stdout.write $theB - while (true) - $theA = get - if ($theA == "/") - break - elsif ($theA == "\\") - $stdout.write $theA - $theA = get - elsif ($theA <= "\n") - raise "Unterminated RegExp Literal" - end - $stdout.write $theA - end - $theB = mynext - end - end -end - -# jsmin -- Copy the input to the output, deleting the characters which are -# insignificant to JavaScript. Comments will be removed. Tabs will be -# replaced with spaces. Carriage returns will be replaced with linefeeds. -# Most spaces and linefeeds will be removed. -def jsmin - $theA = "\n" - action(3) - while ($theA != EOF) - case $theA - when " " - if (isAlphanum($theB)) - action(1) - else - action(2) - end - when "\n" - case ($theB) - when "{","[","(","+","-" - action(1) - when " " - action(3) - else - if (isAlphanum($theB)) - action(1) - else - action(2) - end - end - else - case ($theB) - when " " - if (isAlphanum($theA)) - action(1) - else - action(3) - end - when "\n" - case ($theA) - when "}","]",")","+","-","\"","\\", "'", '"' - action(1) - else - if (isAlphanum($theA)) - action(1) - else - action(3) - end - end - else - action(1) - end - end - end -end - -ARGV.each do |anArg| - $stdout.write "// #{anArg}\n" -end - -jsmin \ No newline at end of file -- 2.45.2 From cc397755446723c7ab82bb01927d0a36500370c6 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Tue, 7 Oct 2008 13:36:30 +0000 Subject: [PATCH 09/16] MOD maj de la page about --- pages/about.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/about.html b/pages/about.html index 71d29af..8705082 100644 --- a/pages/about.html +++ b/pages/about.html @@ -73,14 +73,14 @@ Il est aussi possible de me contacter pour avoir un accès en écriture sur le r

Outils

Comment est appelé le petit du gnou ?

-- 2.45.2 From 455f79e2ab07847ea6697e51245288832ae9fede Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Fri, 10 Oct 2008 06:27:54 +0000 Subject: [PATCH 10/16] MOD maj de l'architecture --- doc/architecture_serveur.svg | 507 ++++++++++++++++++++++++++++++----- 1 file changed, 439 insertions(+), 68 deletions(-) diff --git a/doc/architecture_serveur.svg b/doc/architecture_serveur.svg index 31b99bc..d21b5be 100644 --- a/doc/architecture_serveur.svg +++ b/doc/architecture_serveur.svg @@ -58,16 +58,18 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1.4" - inkscape:cx="406.80295" - inkscape:cy="486.20752" + inkscape:zoom="0.98994949" + inkscape:cx="399.00263" + inkscape:cy="-106.1694" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" inkscape:window-width="1280" inkscape:window-height="943" - inkscape:window-x="1308" - inkscape:window-y="48" /> + inkscape:window-x="1276" + inkscape:window-y="-4" + showborder="false" + inkscape:showpageshadow="false" /> @@ -82,27 +84,28 @@ + id="layer1" + style="display:inline"> + transform="matrix(0.621787,0,0,0.621787,365.36671,171.10017)"> + transform="matrix(0.621787,0,0,0.621787,519.6573,25.206117)"> + transform="matrix(0.621787,0,0,0.621787,426.8834,158.26367)"> + transform="matrix(0.621787,0,0,0.621787,389.93919,-3.7264928)"> + transform="matrix(0.621787,0,0,0.621787,110.70539,88.935447)"> + transform="matrix(0.621787,0,0,0.621787,152.27915,-1.1190028)"> + transform="matrix(0.621787,0,0,0.621787,154.94394,-90.77669)"> + transform="matrix(0.621787,0,0,0.621787,282.55609,-120.08951)"> client + x="230.63187" + y="-1.6234392">client + x="135.66756" + y="40.930058" /> + x="135.66939" + y="310.56885" /> Yaws + x="154.87744" + y="67.712593">Yaws Mnesia + x="152.67529" + y="337.68781">Mnesia JSON/HTTP + x="-86.317085" + y="264.35709">JSON/HTTP Utilise + x="661.0296" + y="271.66797">Utilise Web Server + x="11.603817" + y="61.664341">Web Server Application Data + id="flowPara2463" /> Version 1.* + Version 2.* + + user 1 + + user 2 + + user 3 + + user 4 + + + Yaws + + ek_requests + + ek_protocol + + ek_admin + + ek_common + + + + + + + + module : + process : + + + PostGreSQL + + client + + JSON/HTTP + + ek_bd + + mnesia + + + -- 2.45.2 From 85dc0facbc2b2de826978fac3768db7949a6b92f Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 12 Oct 2008 14:55:18 +0000 Subject: [PATCH 11/16] REPORT de la branche 1.1 : 477->494 --- doc/graphiques/maquette_1.svg | 22 +- img/waitbar.gif | Bin 0 -> 3748 bytes index.yaws | 1 + js/communication.js | 59 ++++- js/euphorik.js | 12 +- js/pageAbout.js | 9 +- js/pageAdmin.js | 204 ++++++------------ js/pageMinichat/commandes.js | 8 + js/pageMinichat/conversation.js | 4 +- js/pageStatique.js | 7 +- js/pages.js | 7 +- js/util.js | 4 +- modules/erl/euphorik_bd.erl | 30 +-- modules/erl/euphorik_bd_admin.erl | 50 ++++- .../erl/euphorik_minichat_conversation.erl | 13 +- modules/erl/euphorik_protocole.erl | 4 +- modules/erl/euphorik_requests.erl | 2 +- modules/include/euphorik_bd.hrl | 1 + styles/1/euphorik.css | 28 +++ styles/1/img/extraction.png | Bin 394 -> 397 bytes styles/1/img/extraction_complete.png | Bin 398 -> 380 bytes styles/1/img/extraction_complete_hover.png | Bin 393 -> 375 bytes styles/1/img/extraction_hover.png | Bin 392 -> 382 bytes styles/1/pageMinichat.css | 8 +- tools/start_yaws.sh | 2 +- tools/tools.rb | 9 +- 26 files changed, 262 insertions(+), 222 deletions(-) create mode 100644 img/waitbar.gif diff --git a/doc/graphiques/maquette_1.svg b/doc/graphiques/maquette_1.svg index f1491a1..650a440 100644 --- a/doc/graphiques/maquette_1.svg +++ b/doc/graphiques/maquette_1.svg @@ -29,9 +29,9 @@ objecttolerance="10" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1.8955697" - inkscape:cx="560.42433" - inkscape:cy="704.00469" + inkscape:zoom="7.5822788" + inkscape:cx="532.83563" + inkscape:cy="896.76979" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" @@ -350,18 +350,18 @@ sodipodi:nodetypes="csssccccc" inkscape:export-ydpi="138.63892" inkscape:export-xdpi="138.63892" - inkscape:export-filename="/home/gburri/projets/euphorik/img/css1/extraction.png" + inkscape:export-filename="/home/gburri/projets/euphorik/branches/1.1/styles/1/img/extraction.png" id="path3233" d="M 531.65729,145.35293 C 529.36216,145.35293 527.50104,147.21405 527.50104,149.50918 C 527.50104,151.80431 529.36216,153.66543 531.65729,153.66543 C 533.95242,153.66543 535.81354,151.80431 535.81354,149.50918 C 535.81354,147.21405 533.95242,145.35293 531.65729,145.35293 z M 530.04764,146.86648 L 534.5789,149.44579 L 530.16777,152.15985 L 530.04764,146.86648 z" - style="opacity:1;fill:#841919;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" /> + style="opacity:0.5;fill:#841919;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.20000000000000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" /> + style="opacity:0.5;fill:#ff6565;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.20000000000000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" /> + style="opacity:0.5;fill:#841919;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.20000000000000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" /> + style="opacity:0.5;fill:#ff6565;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.20000000000000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" /> )R6>ethB*_3Bw&em9yM~UFI-sWi5PPf%`?aVe!kr|_0 zg10FmA~%?(0Sbs|tVg!QU?qIfi}Khe~b|RfkfnQP8?508IU?t)DVFR5AE+s$2L1W^MJi9p*E$yN1@Zt~j|& zZ{2G1W8yOMP3Y$!Onic{X>cQV9pTm0Q}Cc~g7Y^YW)5+`b-$ofK+)vf=yQUMuF->B zciUstw$vQhy9H*6^Dj71eEaQV6y5)P%hp#{mi08e(I@J%Bj|?P!cTN3+s)R?>uW)t{O^ohpZ9@JWhRFpEzgF`a zNi8=CuahFLCYz_HqkPQWkL%=9G})*L6ZLnSp+Qm5O^b{4U~4gF!7EqJhhggcTo@E@ z{Azlv($DBRSA)^^+YgDFkG>#Yp!N-1IUIg1Y^OK+lrPrD1Me3XiAzchO}>-3GXxE~ zdnw~~CJ~(Flujn)WarwW0SLCpm5MEf(+Rs+1x{QVzl>ocsD^S&D>&R*BXN0sos2JU zcx)%7=(b3VdC!!Us`k3BhVG``=X6vXRiPY_jty&GPEPbpy`CsFva;M_eRyWgmWL-? z!gbtccvW*8RxUUDEQs+15dWG7kuFXm#D3Kq!`yny+_I_8LaL!IvgYW^V5M0o4g!OjAEy3rZgD8_Ag9fug|{dL*%@%PfBjERKcqJ6N2aj^;bQAcmTb zF#g)T=FE9eLnc*r*-lj&+c$bJFyv;K!9^eMt4DlsSf>blEap~9^0nKk7eV(f6Ydf- zz?liSY;ulWVt!WfKMIkMJSu{QqeB^2Ssaopzu4&kuN-OPX}}cmd6N3NO6@^ZKSluc z;wn2M!IL(rx|PwX>FRi<+i2KcrtGF^Z8_34HZ=~IeYEA|lum0zXY|@H+H&YqE13Rj z#oh1+TYjUR40|<9lW~EuoCWTULd-#EgkuUTKue@NgcKa~JSYyFekYokoJAmc zM`z>|!hu{{NPY>tG~2oSav78nz~U5CP(As%Koy7gsFv=aUx$z|#qtUfqNd(}TiYOP zZ!1@*I$E2Q4o@kDf@dx2(xCxa|H!x}u)%86zhBL{a{Be`4Zx-?*4r$#m9S=&+sP%7-z)*XTnQr!N$8sg z@j;Woye46v#^Z_QTb_U}+n-K8BwcwnEduQig6?`!w3a~m(dD>>EpJh*J*&Mc<9!-}deFIv5IxMxVf8x6n#M=T%U{HF-U38`|o z-JnI%Cew(k&6Hh2b?4Av_h<)YWI_gPwlIHVYW3F4dUgi0^6*17MwI z5lr!)5PVXk!6yXs`Z~YJLUXnQ@=PcHjok_UIz?nVbjJ&_}#V zaYchjC~K;vz^deux|S?admBSx(5iYaPc!R~X}X3wsl$(6j*Y&k)t__ZwB@$<@7!xa z>myDsjrd|CEbM2~1ew=IM@D>fR8f>2C=B7u{j-9DHoQuG3uc$ z3URxtvwK5pSCrZF=Dyw$*_g6?R5&&HvUdFrQ!C3Ea7c+up65_FFdm%Ys8&q>7JTD4;CS!~d=3VFxAr7H>}MB@lQs-@ z1Bkaj%*JR!J~9Sf + diff --git a/js/communication.js b/js/communication.js index 417e833..985aeed 100644 --- a/js/communication.js +++ b/js/communication.js @@ -19,13 +19,43 @@ // Regroupe la partie communication JSON client -> serveur de euphorik. // Voir : http://dev.euphorik.ch/wiki/euk/Protocole -/** - * @param funError un fonction executé lors d'un réponse 'error' de la part du serveur, peut être redéfinit pour une requête. +/** + * Les fonctions debutReq et finReq servent, par exemple, à afficher à l'utilisateur + * qu'une communication est en cours. + * @param funError un fonction executée lors d'un réponse 'error' de la part du serveur, peut être redéfinit pour une requête. + * @param funDebutReq fonction appelée au début d'une requête (facultatif) + * @param funFinReq fonction appelée à la fin d'une requête (facultatif) */ -euphorik.Communication = function(funError) { - this.funError = funError; +euphorik.Communication = function(funError, funDebutReq, funFinReq) { + this.funError = funError; + this.funDebutReq = funDebutReq; + this.funFinReq = funFinReq; +}; + +/** + * Charge un fichier depuis une url et retourne son contenu. + */ +euphorik.Communication.prototype.load = function(url) { + if (this.funDebutReq) { + this.funDebutReq(); + } + var contenu = ""; + $.ajax({async: false, url: url, success : function(page) { contenu += page; }}); + if (this.funFinReq) { + this.funFinReq(); + } + return contenu; }; - + +/** + * Effectue une requête JSON auprès du serveur. + * @param action une chaine spécifiant l'action, par exemple "put_message" + * @param json les données à envoyer associé à l'action, par exemple {"cookie" : "LKJDLAKSJBFLKASN", "nick" : "Paul", "content" : "Bonjour", "answer_to" : [] } + * @param funOk la fonction exécuté après réception des données du serveur + * @param funError la fonction exécuté si une erreur arrive (facultatif) + * @param asynchrone true pour une communication asychrone (facultatif, truepar défaut) + * @param paramsSupp un objet contenant des paramètres supplémentaire pour la fonction ajax de jQuery (facultatif) + */ euphorik.Communication.prototype.requete = function(action, json, funOk, funError, asynchrone, paramsSupp) { var thisCommunication = this; if (asynchrone === undefined) { @@ -35,7 +65,11 @@ euphorik.Communication.prototype.requete = function(action, json, funOk, funErro var mess = this.getBase(action); objectEach(json, function(nom, val) { mess[nom] = val; - }); + }); + + if (this.funDebutReq) { + this.funDebutReq(); + } paramsAjax = { async: asynchrone, @@ -44,7 +78,10 @@ euphorik.Communication.prototype.requete = function(action, json, funOk, funErro dataType: "json", data: { action : JSON.stringify(mess) }, success: - function(data) { + function(data) { + if (thisCommunication.funFinReq) { + thisCommunication.funFinReq(); + } if (data.reply === "error") { if (funError) { funError(data); @@ -54,9 +91,15 @@ euphorik.Communication.prototype.requete = function(action, json, funOk, funErro } else if (funOk) { funOk(data); } + }, + error: + function(data) { + if (thisCommunication.funFinReq) { + thisCommunication.funFinReq(); + } } }; - + if (paramsSupp) { objectEach(paramsSupp, function(nom, val) { paramsAjax[nom] = val; diff --git a/js/euphorik.js b/js/euphorik.js index 214c0f8..4d0d302 100755 --- a/js/euphorik.js +++ b/js/euphorik.js @@ -27,9 +27,13 @@ $(document).ready( var fragment = new Fragment(); var formateur = new euphorik.Formateur(); var util = new euphorik.Util(formateur); - var communication = new euphorik.Communication(function(data) { util.messageDialogue(data.error_message); }); + var communication = new euphorik.Communication( + function(data) { util.messageDialogue(data.error_message); }, + function() { $("#waitbar").show(); }, + function() { $("#waitbar").hide(); } + ); var client = new euphorik.Client(util, communication); - var pages = new euphorik.Pages(fragment); + var pages = new euphorik.Pages(fragment, communication); // connexion vers le serveur (utilise un cookie qui traine) client.connexionCookie(); @@ -61,10 +65,10 @@ $(document).ready( $("#footer .conditions").click(function(){ pages.afficherPage("conditions_utilisation"); }); pages.ajouterPage(new euphorik.PageMinichat(client, formateur, util, communication), true); - pages.ajouterPage(new euphorik.PageAdmin(client, formateur, util)); + pages.ajouterPage(new euphorik.PageAdmin(client, formateur, util, communication)); pages.ajouterPage(new euphorik.PageProfile(client, formateur, util)); pages.ajouterPage(new euphorik.PageRegister(client, formateur, util)); - pages.ajouterPage(new euphorik.PageAbout(client, formateur, util)); + pages.ajouterPage(new euphorik.PageAbout(client, formateur, util, communication)); pages.ajouterPage("conditions_utilisation"); pages.afficherPage(); diff --git a/js/pageAbout.js b/js/pageAbout.js index d51557c..733f77e 100644 --- a/js/pageAbout.js +++ b/js/pageAbout.js @@ -16,18 +16,17 @@ // You should have received a copy of the GNU General Public License // along with Euphorik. If not, see . -euphorik.PageAbout = function(client, formateur, util) { +euphorik.PageAbout = function(client, formateur, util, communication) { this.nom = "about"; this.client = client; this.formateur = formateur; - this.util = util; + this.util = util; + this.communication = communication; }; euphorik.PageAbout.prototype.contenu = function() { - var contenu = ""; - $.ajax({async: false, url: "pages/about.html", success : function(page) { contenu += page; }}); - + var contenu = this.communication.load("pages/about.html"); var email = this.util.rot13("znvygb:tert.oheev@tznvy.pbz"); return contenu.replace("{EMAIL}", "" + email + "").replace("{EMAIL_LIEN}", email); }; diff --git a/js/pageAdmin.js b/js/pageAdmin.js index fc1d51a..9ed847e 100644 --- a/js/pageAdmin.js +++ b/js/pageAdmin.js @@ -21,12 +21,13 @@ /*jslint laxbreak:true */ -euphorik.PageAdmin = function(client, formateur, util) { +euphorik.PageAdmin = function(client, formateur, util, communication) { this.nom = "admin"; this.client = client; this.formateur = formateur; this.util = util; + this.communication = communication; this.comet = new Comet("admin", euphorik.conf.versionProtocole); @@ -61,7 +62,7 @@ euphorik.PageAdmin.prototype.charger = function() { var thisPage = this; // la liste des trolls proposés par les ekMasters - this.trolls = new euphorik.Trolls(this.client, this.util, this.formateur); + this.trolls = new euphorik.Trolls(this.client, this.util, this.formateur, this.communication); this.waitEvent(); @@ -102,26 +103,13 @@ euphorik.PageAdmin.prototype.posterTroll = function() { return; } - var dataToSend = { - "header" : { "action" : "put_troll", "version" : euphorik.conf.versionProtocole }, - "cookie" : this.client.cookie, - "content" : content - }; - - jQuery.ajax({ - type: "POST", - url: "request", - dataType: "json", - data: this.util.jsonVersAction(dataToSend), - success: - function(data){ - if (data.reply === "ok") { - $("#page form#nouveauTroll input.troll").val(""); - } else if (data.reply === "error") { - thisPageAdmin.util.messageDialogue(data.error_message); - } - } - }); + this.communication.requete( + "put_troll", + {"cookie" : this.client.cookie, "content" : content}, + function(data) { + $("#page form#nouveauTroll input.troll").val(""); + } + ); }; /** @@ -133,63 +121,51 @@ euphorik.PageAdmin.prototype.majIPs = function() { } var thisPageAdmin = this; - - var dataToSend = { - "header" : { "action" : "list_banned_ips", "version" : euphorik.conf.versionProtocole }, - "cookie" : this.client.cookie - }; - - jQuery.ajax({ - type: "POST", - url: "request", - dataType: "json", - data: this.util.jsonVersAction(dataToSend), - success: - function(data) { - if (data.reply === "list_banned_ips") { - var XHTML = ""; - data.list.each(function(i, ip) { - XHTML += '
' + ip.ip + '|' + - '' + - ip.remaining_time + - '|'; - ip.users.each(function(j, user) { - XHTML += (j > 0 ? ", " : "") + - '' + thisPageAdmin.formateur.traitementComplet(user.nick) + '' + - (user.login === "" ? "" : ''); - }); - XHTML += 'débannir
'; - }); - - if (data.list.length === 0) { - XHTML += '

Aucune IP bannie

'; - } - - $("#ips").html(XHTML); - - $(".ban").each(function() { - var ip = $(".ip", this).html(); - $(".deban", this).click( - function() { - thisPageAdmin.util.messageDialogue("Êtes-vous sur de vouloir débannir l'IP ''" + ip + "'' ?", euphorik.Util.messageType.question, - {"Oui" : function() { - thisPageAdmin.deban(ip); - }, - "Non" : function(){} - } - ); + + this.communication.requete( + "list_banned_ips", + {"cookie" : this.client.cookie}, + function(data) { + var XHTML = ""; + data.list.each(function(i, ip) { + XHTML += '
' + ip.ip + '|' + + '' + + ip.remaining_time + + '|'; + ip.users.each(function(j, user) { + XHTML += (j > 0 ? ", " : "") + + '' + thisPageAdmin.formateur.traitementComplet(user.nick) + '' + + (user.login === "" ? "" : ''); + }); + XHTML += 'débannir
'; + }); + + if (data.list.length === 0) { + XHTML += '

Aucune IP bannie

'; + } + + $("#ips").html(XHTML); + + $(".ban").each(function() { + var ip = $(".ip", this).html(); + $(".deban", this).click( + function() { + thisPageAdmin.util.messageDialogue("Êtes-vous sur de vouloir débannir l'IP ''" + ip + "'' ?", euphorik.Util.messageType.question, + {"Oui" : function() { + thisPageAdmin.deban(ip); + }, + "Non" : function(){} } ); - }); - } else if (data.reply === "error") { - thisPageAdmin.util.messageDialogue(data.error_message); - } + } + ); + }); - // rafraichissement toutes les minutes (je sais c'est mal) - // le problème est le rafraichissement des temps restant de bannissement qui doit être fait du coté client - thisPageAdmin.timeoutIDmajIPs = setTimeout(function(){ thisPageAdmin.majIPs(); }, 60 * 1000); - } - }); + // rafraichissement toutes les minutes (je sais c'est mal) + // le problème est le rafraichissement des temps restant de bannissement qui doit être fait du coté client + thisPageAdmin.timeoutIDmajIPs = setTimeout(function(){ thisPageAdmin.majIPs(); }, 60 * 1000); + } + ); }; /** @@ -197,25 +173,11 @@ euphorik.PageAdmin.prototype.majIPs = function() { */ euphorik.PageAdmin.prototype.deban = function(ip) { var thisPageAdmin = this; - - var dataToSend = { - "header" : { "action" : "unban", "version" : euphorik.conf.versionProtocole }, - "cookie" : this.client.cookie, - "ip" : ip - }; - - jQuery.ajax({ - type: "POST", - url: "request", - dataType: "json", - data: this.util.jsonVersAction(dataToSend), - success: - function(data){ - if(data.reply === "error") { - thisPageAdmin.util.messageDialogue(data.error_message); - } - } - }); + + this.communication.requete( + "unban", + {"cookie" : this.client.cookie, "ip" : ip} + ); }; /** @@ -251,10 +213,11 @@ euphorik.Troll = function(content, author) { /////////////////////////////////////////////////////////////////////////////////////////////////// -euphorik.Trolls = function(client, util, formateur) { +euphorik.Trolls = function(client, util, formateur, communication) { this.client = client; this.util = util; this.formateur = formateur; + this.communication = communication; this.dernierTroll = 0; this.trolls = {}; @@ -352,51 +315,18 @@ euphorik.Trolls.prototype.supprimerTrollEvent = function(data) { }; euphorik.Trolls.prototype.modifier = function(id, content) { - var thisTrolls = this; - - var dataToSend = { - "header" : { "action" : "mod_troll", "version" : euphorik.conf.versionProtocole }, - "cookie" : this.client.cookie, - "troll_id" : id, - "content" : content - }; - - jQuery.ajax({ - type: "POST", - url: "request", - dataType: "json", - data: this.util.jsonVersAction(dataToSend), - success: - function(data) { - if (data.reply === "error") { - thisTrolls.util.messageDialogue(data.error_message); - } - } - }); + this.communication.requete( + "mod_troll", + {"cookie" : this.client.cookie, "troll_id" : id, "content" : content} + ); }; /** * Supprime un troll en fonction de son id. */ euphorik.Trolls.prototype.supprimer = function(id) { - var thisTrolls = this; - - var dataToSend = { - "header" : { "action" : "del_troll", "version" : euphorik.conf.versionProtocole }, - "cookie" : this.client.cookie, - "troll_id" : id - }; - - jQuery.ajax({ - type: "POST", - url: "request", - dataType: "json", - data: this.util.jsonVersAction(dataToSend), - success: - function(data) { - if (data.reply === "error") { - thisTrolls.util.messageDialogue(data.error_message); - } - } - }); + this.communication.requete( + "del_troll", + {"cookie" : this.client.cookie, "troll_id" : id} + ); }; diff --git a/js/pageMinichat/commandes.js b/js/pageMinichat/commandes.js index 014b9bb..3609e0d 100644 --- a/js/pageMinichat/commandes.js +++ b/js/pageMinichat/commandes.js @@ -71,6 +71,14 @@ euphorik.Commandes.liste = { pageMinichat.envoyerMessage("C'est pas faux"); return [euphorik.Commandes.statut.ok, '']; } + }, + "osef" : { + description : "Envoie le message \"On s'en fout !\"", + usage : "/osef", + exec : function(args, client, pageMinichat) { + pageMinichat.envoyerMessage("On s'en fout !"); + return [euphorik.Commandes.statut.ok, '']; + } } }; diff --git a/js/pageMinichat/conversation.js b/js/pageMinichat/conversation.js index acd7d67..60b22a6 100644 --- a/js/pageMinichat/conversation.js +++ b/js/pageMinichat/conversation.js @@ -291,11 +291,11 @@ euphorik.Conversation.prototype.flush = function() { var mess = thisConversation.messagesParId[messId]; if (mess) { mess.clientARepondu = true; - $("#conversations #" + mess.getId(thisConversation.getId())).addClass("repondu") + $("#conversations #" + mess.getId(thisConversation.getId())).addClass("repondu"); } }); } - }); + }); if (this.messages.length > 0) { this.idDernierMessageAffiche = this.messages[this.messages.length-1].id; diff --git a/js/pageStatique.js b/js/pageStatique.js index f5a4c2c..4580bf3 100644 --- a/js/pageStatique.js +++ b/js/pageStatique.js @@ -19,14 +19,13 @@ /** * Correspond à une page html statique se nommant ".html" et se trouvant dans "/pages/". */ -euphorik.PageStatique = function(nom) { +euphorik.PageStatique = function(nom, communication) { this.nom = nom; + this.communication = communication; }; euphorik.PageStatique.prototype.contenu = function() { - var contenu = ""; - $.ajax({async: false, url: "pages/" + this.nom + ".html", success : function(page) { contenu += page; }}); - return contenu; + return this.communication.load("pages/" + this.nom + ".html"); }; euphorik.PageStatique.prototype.charger = function() { diff --git a/js/pages.js b/js/pages.js index df515e6..2f0abfc 100644 --- a/js/pages.js +++ b/js/pages.js @@ -22,8 +22,9 @@ /** * Gestion des pages. */ -euphorik.Pages = function(fragment) { - this.fragment = fragment; +euphorik.Pages = function(fragment, communication) { + this.fragment = fragment; + this.communication = communication; this.pageCourante = undefined; this.pageDefaut = undefined; this.pages = {}; @@ -36,7 +37,7 @@ euphorik.Pages = function(fragment) { */ euphorik.Pages.prototype.ajouterPage = function(page, defaut) { if (typeof page === "string") { - page = new euphorik.PageStatique(page); + page = new euphorik.PageStatique(page, this.communication); } page.pages = this; // la magie des langages dynamiques : le foutoire diff --git a/js/util.js b/js/util.js index f5fca3f..4c9bd6a 100644 --- a/js/util.js +++ b/js/util.js @@ -186,9 +186,9 @@ euphorik.Util.prototype.infoBulle = function(message, element, position) { * Utilisé pour l'envoie de données avec la méthode ajax de jQuery. * Obsolète : à virer */ -euphorik.Util.prototype.jsonVersAction = function(json) { +/*euphorik.Util.prototype.jsonVersAction = function(json) { return { action : JSON.stringify(json) }; -}; +};*/ /** * Retourne un hash md5 d'une chaine, dépend de md5.js. diff --git a/modules/erl/euphorik_bd.erl b/modules/erl/euphorik_bd.erl index 4fecb73..f1d5a60 100755 --- a/modules/erl/euphorik_bd.erl +++ b/modules/erl/euphorik_bd.erl @@ -79,7 +79,8 @@ elire_troll/0, % utiles : - resultat_transaction/1 + resultat_transaction/1, + get_tuples/3 % must be in a transaction ]). -import(qlc, [e/2, q/1, cursor/2]). -include("../include/euphorik_bd.hrl"). @@ -373,23 +374,22 @@ messages(N) -> messages(N, P) -> F = fun() -> % % #minichat{contenu = contenu_message(E)} - get_tuples_avant(minichat, reculer(minichat, mnesia:last(minichat), N * (P - 1)), N) + get_tuples(minichat, mnesia:table_info(minichat, size) - N * P + 1, N) end, resultat_transaction(mnesia:transaction(F)). -get_tuples_avant(Table, Id, N) -> - get_tuples_avant(Table, Id, N, []). -get_tuples_avant(_, '$end_of_table', _, Tuples) -> Tuples; -get_tuples_avant(_, _, 0, Tuples) -> - Tuples; -get_tuples_avant(Table, Id, N, Tuples) -> - [T] = mnesia:read({Table, Id}), - get_tuples_avant(Table, mnesia:prev(Table, Id), N - 1, [T | Tuples]). -reculer(_, '$end_of_table' = Fin, _) -> Fin; -reculer(_, Id, 0) -> Id; -reculer(Table, Id, N) -> - reculer(Table, mnesia:prev(Table, Id), N - 1). +get_tuples(Table, First_id, N) -> + lists:foldr( + fun(Id, Acc) -> + case mnesia:read({Table, Id}) of + [T] -> [T | Acc]; + _ -> Acc + end + end, + [], + lists:seq(First_id, First_id + N - 1) + ). % Renvoie les messages manquants pour la page P en sachant qu'il y a N message @@ -715,7 +715,7 @@ put_troll(User_id, Content) -> Nb_troll_poste_total >= ?NB_MAX_TROLL_WAITING -> max_troll_reached; true -> - Id = nouvel_id(minichat), + Id = nouvel_id(troll), mnesia:write(#troll{id = Id, id_user = User_id, date_create = now(), content = Content}), Id end; diff --git a/modules/erl/euphorik_bd_admin.erl b/modules/erl/euphorik_bd_admin.erl index 076a570..c370618 100644 --- a/modules/erl/euphorik_bd_admin.erl +++ b/modules/erl/euphorik_bd_admin.erl @@ -217,7 +217,26 @@ update(Version) -> % crée un backup avant l'application du patch % dans BD/backups nommé "backup" où et le numéro de la version. % 1 -> 2 -patch(1) -> +patch(1) -> + % Prend un chemin vers la feuille de style de type "css/1/euphorik.css" + % et renvoie "styles/1/euphorik.css" + Transforme_css = fun("css" ++ Reste) -> + "styles" ++ Reste; + (F) -> F + end, + Traiter_message = fun(M, Racine) -> + F = fun(F, M2) -> % seul moyen à ma connaissance pour faire de la récursion dans une lambda fonction, voir : http://www.nabble.com/Auto-generated-functions-td15279499.html + % met à jour la racine de chaque message qui répond à M + lists:foreach( + fun(M3) -> + mnesia:write(M2#minichat{racine_id = Racine}), + F(F, M3) + end, + euphorik_bd:enfants(M#minichat.id) + ) + end, + F(F, M, Racine) + end, % Prend un chemin vers la feuille de style de type "css/1/euphorik.css" % et renvoie "styles/1/euphorik.css" Transforme_css = fun("css" ++ Reste) -> @@ -269,13 +288,7 @@ patch(1) -> {atomic, _} -> ok end; % 2 -> 3 -patch(2) -> - % première étape : changer le type de la table minichat de set à ordered_set - % TODO : trouver un meilleur moyen que de passer par un backup - backup("tmp"), - create(), - restore("tmp"), - file:delete(dossier_backups() ++ "tmp"), +patch(2) -> mnesia:transform_table( troll, fun({troll, Id_troll, Id_user, Date_create, Date_post, Content}) -> @@ -292,11 +305,26 @@ patch(2) -> mnesia:transform_table( minichat, fun({minichat, Id, Auteur_id, Date, Pseudo, Contenu, _Troll_id, Racine_id}) -> - {minichat, Id, Auteur_id, Date, Pseudo, Contenu, Racine_id} + {minichat, Id, Auteur_id, Date, Pseudo, Contenu, Racine_id, normal} end, record_info(fields, minichat) - ), - creer_indexes(). % uniquement pour l'indice sur id_minichat de la table troll + ), + mnesia:transaction(fun() -> + % comble les trous entre les id non-contigues + lists:foreach(fun(Id) -> + case mnesia:read({minichat, Id}) of + [] -> + {ok, #user{profile = Profile}} = euphorik_bd:user_by_id(0), + mnesia:write(#minichat{id = Id, auteur_id = 0, date = undefined, pseudo = Profile#profile.pseudo, contenu = "Comblement...", racine_id = Id, status = deleted}); + _ -> rien + end + end, + lists:seq(1, mnesia:table_info(minichat, size)) + ), + % la table troll utilise maintenant son index et pas celui de la table minichat (correction d'un vieux bug) + mnesia:write(#counter{key = troll, value = mnesia:table_info(minichat, size)}) + end), + creer_indexes(). % uniquement pour l'indice sur id_minichat de la table troll % Renvoie le dossier dans lequel les backups sont effectué, ce dossier doit être en écriture. diff --git a/modules/erl/euphorik_minichat_conversation.erl b/modules/erl/euphorik_minichat_conversation.erl index 4d0b3a8..5cf9a0a 100755 --- a/modules/erl/euphorik_minichat_conversation.erl +++ b/modules/erl/euphorik_minichat_conversation.erl @@ -109,7 +109,7 @@ mise_en_forme_conversation(Messages) -> conversations_detailees(Racines, N, D, P) -> Conversations = map(fun({Racine, P_conv, Dernier}) -> conversation(Racine, N, Dernier, P_conv) end, Racines), Conversation_principale = resultat_transaction(transaction(fun() -> - Dernier_id = mnesia:last(minichat), + Dernier_id = mnesia:table_info(minichat, size), {CP, Plus} = conversation_principale(Dernier_id, Conversations, N, P), {[M || M <- CP, M > D], Plus} % filtre en fonction de D end)), @@ -142,18 +142,17 @@ conversation_principale(Id, Conversations, N, P) -> % @spec conversation_principale2(integer(), [integer()], integer(), integer()) -> [integer()] conversation_principale2(_, _, 0, _) -> []; -conversation_principale2('$end_of_table', _, _, _) -> +conversation_principale2(0, _, _, _) -> []; conversation_principale2(Id, Messages, N, S) -> - % traitement message par message (pas des plus performant :/) - Id_prev = mnesia:prev(minichat, Id), + % traitement message par message (pas des plus performant :/) Doit_etre_saute = any(fun(E) -> E == Id end, Messages), if Doit_etre_saute -> - conversation_principale2(Id_prev, Messages, N, S); % le message ne fait pas partie de la conversation + conversation_principale2(Id - 1, Messages, N, S); % le message ne fait pas partie de la conversation S =:= 0 -> - [Id | conversation_principale2(Id_prev, Messages, N - 1, S)]; % ok : le message fait partie de la conversation + [Id | conversation_principale2(Id - 1, Messages, N - 1, S)]; % ok : le message fait partie de la conversation true -> - conversation_principale2(Id_prev, Messages, N, S - 1) % on n'a pas encore atteint le début de la page + conversation_principale2(Id - 1, Messages, N, S - 1) % on n'a pas encore atteint le début de la page end. diff --git a/modules/erl/euphorik_protocole.erl b/modules/erl/euphorik_protocole.erl index 1fb3cc1..3706f68 100755 --- a/modules/erl/euphorik_protocole.erl +++ b/modules/erl/euphorik_protocole.erl @@ -308,7 +308,7 @@ wait_event_page_chat(User, Racines_conversations, Message_count, Last_message_id {Racine_id, _, _} = Racine, case euphorik_bd:message_by_id(Racine_id) of {ok, Mess} -> - json_message(Mess, euphorik_bd:parents(Racine), User); + json_message(Mess, euphorik_bd:parents(Racine_id), User); _ -> null end @@ -744,7 +744,7 @@ json_message(Mess, Repond_a, User) -> {struct, [ {id, Mess#minichat.id}, {user_id, User_mess#user.id}, - {date, format_date(Mess#minichat.date)}, + {date, case Mess#minichat.date of undefined -> "?"; _ -> format_date(Mess#minichat.date) end}, {system, Mess#minichat.auteur_id =:= 0}, {owner, Est_proprietaire}, {answered, A_repondu_a_message}, diff --git a/modules/erl/euphorik_requests.erl b/modules/erl/euphorik_requests.erl index 1cd460a..3ec70f3 100755 --- a/modules/erl/euphorik_requests.erl +++ b/modules/erl/euphorik_requests.erl @@ -29,7 +29,7 @@ % Point d'entrée pour les requêtes AJAX sur http://www.euphorik.ch/request. -out(A) -> +out(A) -> IP = case inet:peername(A#arg.clisock) of {ok, {Adresse, _Port}} -> Adresse; _ -> inconnue diff --git a/modules/include/euphorik_bd.hrl b/modules/include/euphorik_bd.hrl index 0b04c4b..36ff1e6 100755 --- a/modules/include/euphorik_bd.hrl +++ b/modules/include/euphorik_bd.hrl @@ -57,6 +57,7 @@ pseudo, % chaine de caractère contenu, % chaine de caractère racine_id = undefined % la racine, par défaut correspond à l'id du message + status = normal % can be equal to normal, censored or deleted }). diff --git a/styles/1/euphorik.css b/styles/1/euphorik.css index 54aef62..59e8ab0 100755 --- a/styles/1/euphorik.css +++ b/styles/1/euphorik.css @@ -31,6 +31,34 @@ em.fort { font-weight: bold } +/***** Une barre de progression s'affichant lors des communications entre le client et le serveur *****/ +#waitbar { + text-align: center; + height: 16px; + width:100%; + position: fixed; + left: 0px; + top: 0px; + z-index: 500; +} +#waitbar .image { + background-image: url(../../img/waitbar.gif); + margin-top: 3px; + margin-right: 3px; + float: right; + height: 13px; + width: 105px; +} + +/***** Textile *****/ +em.leger { + font-style: italic +} +em.fort { + font-style: normal; + font-weight: bold +} + /***** Menu *****/ ul#menu { background-image: url(img/logo_fond.png); diff --git a/styles/1/img/extraction.png b/styles/1/img/extraction.png index 6140ab5dc739add4d137f88f057a7fb3883dceed..3f5828c9873009111cc01365b88b92956dd1373f 100644 GIT binary patch delta 296 zcmV+@0oVSD1C0ZaZhs0%L_t(2k&V(JPsBhF1>mo}3W7aBy5SdqfP^z7q#y{2e^lK+ zfkNX*&;(AOzyKPvhdGBrToK(~n%)Usvf1qHyv&<pI33Z%qgvxWG9Il(}w7WBnV{G5*#uKI18criE^-!)lWu zsR>~pH#kY5RiX1?i`0YwXSl}R;D1?QfzyGkNfW{WZgDu0zQ&?A_fqEryyHmc*%&W% ujITv{%+p=rcp*pfW+O;zG-&!?yY~kd%2I~2NUZk&0000L6RU4I})*;T@rBI0*N3Y**mlX z(IzWMu3RZYPhL=5}BJmYu^<*-`TYnV#-B3A=hTn}pNXI6DLBO8@KVP3QN~!Mj9^;m z+BzFM^=Lvk#UpN0Xj|y!up??h$Z(G(P6qsX+&wtMF;=)5rQUTfO}ZWs%j7;5&<%If r|K5u#-0XS$w;mCsH5wHCuig6vS4&jkmw}??00000NkvXXu0mjfbftzi diff --git a/styles/1/img/extraction_complete.png b/styles/1/img/extraction_complete.png index b4e91d6cf3c4a3c15668a4b89bc687ca0b9bd75a..9e99a89d7acccde7c57fc7c572ce1bbf439f332c 100644 GIT binary patch delta 280 zcmV+z0q6dX1N;JzZGQmyNkl$cs*l`W<;}C@0zzJUbt{^Am z5^TKZm_?ByVFcS#UM&(`H8s=I{jctCdb(PxW@FAX9AbuDykLpNP|C99b+uMw&K>$# zDPk2}oIf$gd?=;1gdWEe;0c#_3_nG@hZHUKzU>KDLn+U=!hgdg){i;QQfNqPz$*-; zyx}@@wTg!+ME?MqO~4XYvlOpXak~yoz<1o>1G~xUSv#DJIq&=ijX7`O6dQO+lYaMb zz77U(hJ(0TCM>Mx0Q)!_bKd>~_{5?O_sD7v%}QuEod9q*lybir&OG+^BQh>RL#r@v edEI~h-WN(rWD()$CB7E`0000p delta 298 zcmV+_0oDHe0*(WaZGQm^NklpE>pOPIu1j2=(zLc;<8baTTH$fD(1iuQq{daaG{@0Tpa;I;5bqdPzHO~= z9vT*+O=%S~tl+Wg-FF*TZA$CE02kPc)NO@nxFTG-Y*SkM1NgwSJno6_cPMca8fHBJ wPV1b{iq%cbHvjszmo0u3?6+GItbVI<2Q&-|Ks9yd8>-xlK-=NMyzHI|r5X<5^noHH>tXv+#E zmeG{+1|2#n<(kmqasaGwiin(XoZ=SUNOV-Ab-}1aU6<<@B?@QDZS&a z=&BXZLlM0TRNI1!ax)I)l`tS^uWHNA`Ack002ovPDHLkV1n~;f8YQB delta 293 zcmV+=0owle0*M2VZGQmzmlZ!+k*PK`F_eVk&1As%suSyRfq zo*Q&sr_Ff($twz<=O&INZn00&v)r^4#XU zg=_5fDvncVSOTCa!vP9FJs8q_l@?>~Bb4W6>}7T)PK&!GU&Xn|KuQRCUI@`x_i?Ngggj ge?~*o|GK?z0u#zftW^{|LI3~&07*qoM6N<$g3T6z8~^|S delta 292 zcmV+<0o(rm0*C{UZGQm;Nkl!%ms0tf`Kh|ZGDwt|<8nD5P-_x&rnuG6CpVS*W^sIkTpixt!DK$AGs4JVc zPR33>+7OQMfU6u@S2lCl615=|xWPS+2K;i|JvhN37C0ZJzUf|`^n5_vXZNvy&2U%! q@4cwO<&MXH8y!Jjqe0RC+Pz=Pxl|t input, +#page.minichat form#posterMessage p > span, +#page.minichat form#posterMessage p > button{ + vertical-align: middle; +} + #page.minichat.orderReverse form#posterMessage { padding-bottom: 10px; } @@ -116,7 +122,6 @@ background-image: url(img/return.png); background-repeat: no-repeat; background-position: 5px 2px; - vertical-align: top; margin-right: 5px; } #page.minichat form#posterMessage .smiles { @@ -125,7 +130,6 @@ background-image: url(../../img/bouton_smiles.png); background-repeat: no-repeat; background-position: 2px 2px; - vertical-align: top; margin-right: 5px; } /* La boite montrant les messages auquels l'utilisateur répond */ diff --git a/tools/start_yaws.sh b/tools/start_yaws.sh index d812137..216a5d1 100755 --- a/tools/start_yaws.sh +++ b/tools/start_yaws.sh @@ -1,4 +1,4 @@ #!/bin/bash # coding: utf-8 # screen est utilisé par exemple pour lancé une version de preproduction et permettre de la faire tourner après un délog -yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../var/BD/" -I debian_yaws_dev +yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../var/BD/" -I debian_yaws_dev diff --git a/tools/tools.rb b/tools/tools.rb index b437687..2992eb6 100644 --- a/tools/tools.rb +++ b/tools/tools.rb @@ -123,7 +123,6 @@ class MiseEnProd # Effectue la mise en préproduction. def miseEnPreProd copierFichiers() - copierVAR() lancerYaws() maj('yaws_dev') end @@ -137,11 +136,6 @@ class MiseEnProd set_droits_fichiers() end - # TODO - def copierVar - #TODO - end - def lancerYaws creer_rep("tools") system("rsync tools/yaws.conf #{@uri}:#{@rep}/tools") @@ -171,7 +165,8 @@ class MiseEnProd Dir.chdir('..') end - def creer_repertoire_var + def creer_repertoire_bd + log "création du répertoire de la base de données" # création du repertoire BD creer_rep('var') creer_rep('var/images') -- 2.45.2 From b17c02fb507f6841f74b5fe21399766a51710367 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 12 Oct 2008 20:34:26 +0000 Subject: [PATCH 12/16] FIX syntaxe --- modules/include/euphorik_bd.hrl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/include/euphorik_bd.hrl b/modules/include/euphorik_bd.hrl index 36ff1e6..4838b30 100755 --- a/modules/include/euphorik_bd.hrl +++ b/modules/include/euphorik_bd.hrl @@ -56,7 +56,7 @@ date, % erlang:now() pseudo, % chaine de caractère contenu, % chaine de caractère - racine_id = undefined % la racine, par défaut correspond à l'id du message + racine_id = undefined, % la racine, par défaut correspond à l'id du message status = normal % can be equal to normal, censored or deleted }). -- 2.45.2 From 0cca28444881b1a405525b10960915a638936fdd Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Wed, 15 Oct 2008 13:46:17 +0000 Subject: [PATCH 13/16] REPORT de la branche 1.1 --- VERSION | 2 +- js/euphorik.js | 4 ++-- js/pageMinichat/conversations.js | 9 +++++++-- js/util.js | 10 ++++++++++ tools/tools.rb | 4 ++-- 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 867e524..bf6d67a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.0 \ No newline at end of file +1.2.0 diff --git a/js/euphorik.js b/js/euphorik.js index 4d0d302..c1253b9 100755 --- a/js/euphorik.js +++ b/js/euphorik.js @@ -29,8 +29,8 @@ $(document).ready( var util = new euphorik.Util(formateur); var communication = new euphorik.Communication( function(data) { util.messageDialogue(data.error_message); }, - function() { $("#waitbar").show(); }, - function() { $("#waitbar").hide(); } + function() { util.showWaitBar(); }, + function() { util.hideWaitBar(); } ); var client = new euphorik.Client(util, communication); var pages = new euphorik.Pages(fragment, communication); diff --git a/js/pageMinichat/conversations.js b/js/pageMinichat/conversations.js index 94236c1..378c2a2 100644 --- a/js/pageMinichat/conversations.js +++ b/js/pageMinichat/conversations.js @@ -371,6 +371,8 @@ euphorik.Conversations.prototype.rafraichirMessages = function(vider) { conv.idDernierMessageAffiche = 0; }); } + + thisConversations.util.showWaitBar(); // pour faire patienter le user :) this.comet.waitEvent( function() { return thisConversations.getJSONrafraichirMessages(); }, @@ -387,7 +389,8 @@ euphorik.Conversations.prototype.rafraichirMessages = function(vider) { $("#trollCourant .troll a[@rel*=lightbox]").lightBox(); }, "new_messages" : - function(data) { + function(data) { + if (vider) { thisConversations.viderMessages(); } @@ -404,7 +407,9 @@ euphorik.Conversations.prototype.rafraichirMessages = function(vider) { thisConversations.afficherMessagesRepondConversations(); } - vider = false; + vider = false; + + thisConversations.util.hideWaitBar(); } } ); diff --git a/js/util.js b/js/util.js index 4c9bd6a..7ba8e60 100644 --- a/js/util.js +++ b/js/util.js @@ -117,6 +117,16 @@ euphorik.Util.prototype.afficherBoite = function(boite, cible, positionX, positi }; euphorik.Util.positionBulleType = {haut : 0, droite : 1, bas : 2, gauche : 3}; + +/** + * Affiche ou cache la barre d'attente. + */ +euphorik.Util.prototype.showWaitBar = function() { + $("#waitbar").show(); +}; +euphorik.Util.prototype.hideWaitBar = function() { + $("#waitbar").hide(); +}; /** * Affiche un info bulle lorsque le curseur survole l'élément donné. diff --git a/tools/tools.rb b/tools/tools.rb index 2992eb6..5d9f40b 100644 --- a/tools/tools.rb +++ b/tools/tools.rb @@ -79,7 +79,7 @@ class Version } # les fichiers HTML dans lesquels mettre à jour la version @fichiers = ['/pages/about.html'] - @balise = /().*?(<\/span>)/ + @balise = /().*?(<\/a>)/ end # met à jour la version dans les fichiers @fichiers @@ -89,7 +89,7 @@ class Version lines = IO.readlines(fichier) File.open(fichier, 'w') {|io| lines.each{|l| - io.write(l.sub(@balise){|m| $1 + @version + $2}) + io.write(l.sub(@balise){|m| $1 + @version + $2 + @version + $3}) } } } -- 2.45.2 From 0e175b4d9f55c91dfb7bd3c093a68ecb8947e820 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Fri, 17 Oct 2008 08:06:56 +0000 Subject: [PATCH 14/16] REPORT branche 1.1 501->501 --- modules/erl/euphorik_protocole.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/erl/euphorik_protocole.erl b/modules/erl/euphorik_protocole.erl index 3706f68..a61d0c8 100755 --- a/modules/erl/euphorik_protocole.erl +++ b/modules/erl/euphorik_protocole.erl @@ -308,7 +308,7 @@ wait_event_page_chat(User, Racines_conversations, Message_count, Last_message_id {Racine_id, _, _} = Racine, case euphorik_bd:message_by_id(Racine_id) of {ok, Mess} -> - json_message(Mess, euphorik_bd:parents(Racine_id), User); + json_message(Mess, euphorik_bd:parents_id(Racine_id), User); _ -> null end @@ -754,7 +754,7 @@ json_message(Mess, Repond_a, User) -> {content, Mess#minichat.contenu}, {root, Mess#minichat.racine_id}, {answer_to, {array, lists:map( - fun(Id_mess) -> + fun(Id_mess) -> {ok, M} = euphorik_bd:message_by_id(Id_mess), {ok, User_reponse} = euphorik_bd:user_by_mess(M#minichat.id), {struct, [{id, M#minichat.id}, {nick, M#minichat.pseudo}, {login, User_reponse#user.login}]} -- 2.45.2 From 162a9448eeaf3db6c21200de132a865112aab59e Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Fri, 17 Oct 2008 19:10:23 +0000 Subject: [PATCH 15/16] =?utf8?q?FIX=20plant=C3=A9=20lors=20du=20passage=20?= =?utf8?q?de=20la=20version=201=20=C3=A0=20la=20version=202=20des=20donn?= =?utf8?q?=C3=A9es=20mutables?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- modules/erl/euphorik_bd_admin.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/erl/euphorik_bd_admin.erl b/modules/erl/euphorik_bd_admin.erl index c370618..4a559c8 100644 --- a/modules/erl/euphorik_bd_admin.erl +++ b/modules/erl/euphorik_bd_admin.erl @@ -235,7 +235,7 @@ patch(1) -> euphorik_bd:enfants(M#minichat.id) ) end, - F(F, M, Racine) + F(F, M) end, % Prend un chemin vers la feuille de style de type "css/1/euphorik.css" % et renvoie "styles/1/euphorik.css" @@ -254,7 +254,7 @@ patch(1) -> euphorik_bd:enfants(M#minichat.id) ) end, - F(F, M, Racine) + F(F, M) end, mnesia:create_table(texte, [ {attributes, record_info(fields, texte)}, -- 2.45.2 From 7ea77e03a1191ed84719ec018635cbe4a1b44259 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Wed, 19 Nov 2008 13:49:42 +0000 Subject: [PATCH 16/16] MOD beginning of the refactoring .. ^-^ --- README | 2 +- doc/architecture_serveur.svg | 798 +++++++++++++++++--------------- js/pageMinichat/pageMinichat.js | 3 - modules/Makefile | 40 +- 4 files changed, 426 insertions(+), 417 deletions(-) diff --git a/README b/README index d598ee5..3541f66 100644 --- a/README +++ b/README @@ -1 +1 @@ -Voir : http://dev.euphorik.ch/wiki/euk/Accueil \ No newline at end of file +See : http://dev.euphorik.ch/wiki/euk/Home \ No newline at end of file diff --git a/doc/architecture_serveur.svg b/doc/architecture_serveur.svg index d21b5be..8a00377 100644 --- a/doc/architecture_serveur.svg +++ b/doc/architecture_serveur.svg @@ -58,15 +58,15 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.98994949" - inkscape:cx="399.00263" - inkscape:cy="-106.1694" + inkscape:zoom="1.4" + inkscape:cx="362.17823" + inkscape:cy="1034.0028" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" inkscape:window-width="1280" - inkscape:window-height="943" - inkscape:window-x="1276" + inkscape:window-height="945" + inkscape:window-x="-4" inkscape:window-y="-4" showborder="false" inkscape:showpageshadow="false" /> @@ -87,13 +87,12 @@ id="layer1" style="display:inline"> + style="opacity:1;fill:#2affd5;fill-opacity:1;stroke:#7a7a7a;stroke-width:1.53152299;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" + id="rect2515" + width="594.40643" + height="145.24025" + x="135.14209" + y="-129.56824" /> - client Data Version 1.* - Version 2.* - - user 1 - - user 2 - - user 3 - - user 4 - - - Yaws - - ek_requests - - ek_protocol - - ek_admin - - ek_common - - - - - - - - module : - process : - + id="tspan2519" + x="21.274195" + y="-34.15234">Web client + + + fragment + + + + formater + + + + util + + + + communication + + + + client + - PostGreSQL + style="opacity:0.62093865;fill:#aaccff;fill-opacity:1;stroke:#000000;stroke-width:0.35433072;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect2617" + width="498.57144" + height="30" + x="159.14285" + y="-115.63783" + ry="10" /> + + + pages + + + + pageChat + + + + pageAdmin + + + + pageProfile + + + + pageRegister + + + + pageAbout + - client + style="opacity:0.62093865;fill:#aaccff;fill-opacity:1;stroke:#000000;stroke-width:0.35433072;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + id="rect2619" + width="353.1095" + height="30" + x="158.28395" + y="-58.61768" + ry="10" /> + + + chat + + + + conversations + + + + message + + + + conversation + - JSON/HTTP - - ek_bd - - mnesia + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.60000002;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.47843137" + d="M 386.87041,-6.1634945 L 315.22162,-3.5972453" + id="path2669" + inkscape:connector-type="polyline" + inkscape:connection-start="#g2561" + inkscape:connection-end="#g2553" + sodipodi:nodetypes="ccc" /> + inkscape:connection-end="#g2553" + inkscape:connection-start="#rect2619" /> + inkscape:connection-start="#g2577" + inkscape:connection-end="#g2621" />
diff --git a/js/pageMinichat/pageMinichat.js b/js/pageMinichat/pageMinichat.js index b71efea..032ce41 100755 --- a/js/pageMinichat/pageMinichat.js +++ b/js/pageMinichat/pageMinichat.js @@ -30,9 +30,6 @@ euphorik.PageMinichat = function(client, formateur, util, communication) { // permet d'éviter d'envoyer plusieurs messages simultanément en pressant // rapidement sur "enter" par exemple this.envoieMessageEnCours = false; - - this.regexMessageTagMatch = /\{.*?\}>/g; - this.regexMessageTagReplace = /^(.*?\{.*?\}>)*/; }; euphorik.PageMinichat.prototype.contenu = function() { diff --git a/modules/Makefile b/modules/Makefile index 859cc56..1e68f2b 100755 --- a/modules/Makefile +++ b/modules/Makefile @@ -1,26 +1,24 @@ # coding: utf-8 -# Répertoire dans lequel se trouve les modules compilés (beam) +# For more informations about the modules listed here see : http://dev.euphorik.ch/wiki/euk/Home + +# Directory where the compiled modules will be put rep_ebin = ebin - -# Répertoire dans lequel se trouve les fichiers sources + +# Directory where the sources are rep_erl = erl - -# Répertoire dans lequel se trouve les fichier hrl (définition de record) + +# Directory which contains the hrl files (records definition) rep_include = include - -# Paramètres du compilateur -# il est possible de compiler en natif en executant : + +# Arguments for the compilator +# It's possible to compile in native mode with : # $ make NATIVE=true -# les différents tests on montrés que ca n'augmentait pas les performances -# car très lié à la base de données -# TODO : simplifier et éviter les répetitions -ifdef NATIVE +ifdef NATIVE erlc_params = +native -I $(rep_include) -o $(rep_ebin) $< else erlc_params = -I $(rep_include) -o $(rep_ebin) $< endif -# Compilation de toute l'application euphorik all: $(rep_ebin)/smtp.beam \ $(rep_ebin)/euphorik_bd.beam \ $(rep_ebin)/euphorik_minichat_conversation.beam \ @@ -32,46 +30,32 @@ $(rep_ebin)/euphorik_bd_admin.beam \ $(rep_ebin)/euphorik_common.beam \ $(rep_ebin)/euphorik_test.beam -# Module pour l'envoie d'email $(rep_ebin)/smtp.beam: $(rep_erl)/smtp.erl erlc $(erlc_params) -# Module pour la gestion des données persistante la BD $(rep_ebin)/euphorik_bd.beam: $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl erlc $(erlc_params) -# Module pour la mise à jour de la BD $(rep_ebin)/euphorik_bd_admin.beam: $(rep_erl)/euphorik_bd_admin.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl erlc $(erlc_params) -# Module permettant l'extraction des conversations du minichat $(rep_ebin)/euphorik_minichat_conversation.beam: $(rep_erl)/euphorik_minichat_conversation.erl $(rep_include)/euphorik_bd.hrl erlc $(erlc_params) -# Module traitant les requêtes AJAX du client javascript d'euphorik $(rep_ebin)/euphorik_requests.beam: $(rep_erl)/euphorik_requests.erl $(rep_include)/euphorik_defines.hrl erlc $(erlc_params) -# Module interpretant les messages XML du client $(rep_ebin)/euphorik_protocole.beam: $(rep_erl)/euphorik_protocole.erl $(rep_include)/euphorik_defines.hrl erlc $(erlc_params) - -# Module pour la génération du captcha -#$(rep_ebin)/captcha.beam: $(rep_erl)/captcha.erl -# erlc $(erlc_params) - -# Module effectuant periodiquement certaines tâches + $(rep_ebin)/euphorik_daemon.beam: $(rep_erl)/euphorik_daemon.erl $(rep_include)/euphorik_defines.hrl erlc $(erlc_params) -# Module avec plein de bordel dedant $(rep_ebin)/euphorik_common.beam: $(rep_erl)/euphorik_common.erl erlc $(erlc_params) -# Module dédié au tests $(rep_ebin)/euphorik_test.beam: $(rep_erl)/euphorik_test.erl $(rep_include)/euphorik_bd.hrl erlc $(erlc_params) -# Suppression des modules compilés clean: rm ebin/*.beam -- 2.45.2